mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: [OSX] Separate video driver into a base and a Quartz implementation.
This commit is contained in:
parent
421b599541
commit
2f25e9bdf8
|
@ -24,32 +24,18 @@ class VideoDriver_Cocoa : public VideoDriver {
|
|||
private:
|
||||
Dimension orig_res; ///< Saved window size for non-fullscreen mode.
|
||||
|
||||
int window_width; ///< Current window width in pixel
|
||||
int window_height; ///< Current window height in pixel
|
||||
int window_pitch;
|
||||
|
||||
int buffer_depth; ///< Colour depth of used frame buffer
|
||||
void *pixel_buffer; ///< used for direct pixel access
|
||||
void *window_buffer; ///< Colour translation from palette to screen
|
||||
|
||||
Rect dirty_rect; ///< Region of the screen that needs redrawing.
|
||||
|
||||
uint32 palette[256]; ///< Colour Palette
|
||||
|
||||
public:
|
||||
bool setup; ///< Window is currently being created.
|
||||
|
||||
OTTD_CocoaWindow *window; ///< Pointer to window object
|
||||
OTTD_CocoaView *cocoaview; ///< Pointer to view object
|
||||
CGColorSpaceRef color_space; ///< Window color space
|
||||
CGContextRef cgcontext; ///< Context reference for Quartz subdriver
|
||||
|
||||
OTTD_CocoaWindowDelegate *delegate; //!< Window delegate object
|
||||
|
||||
public:
|
||||
VideoDriver_Cocoa();
|
||||
|
||||
const char *Start(const StringList ¶m) override;
|
||||
void Stop() override;
|
||||
void MainLoop() override;
|
||||
|
||||
|
@ -61,40 +47,73 @@ public:
|
|||
|
||||
void EditBoxLostFocus() override;
|
||||
|
||||
const char *GetName() const override { return "cocoa"; }
|
||||
|
||||
/* --- The following methods should be private, but can't be due to Obj-C limitations. --- */
|
||||
|
||||
void GameLoop();
|
||||
|
||||
void AllocateBackingStore();
|
||||
virtual void AllocateBackingStore() = 0;
|
||||
|
||||
protected:
|
||||
Rect dirty_rect; ///< Region of the screen that needs redrawing.
|
||||
Dimension GetScreenSize() const override;
|
||||
float GetDPIScale() override;
|
||||
void InputLoop() override;
|
||||
void Paint() override;
|
||||
void CheckPaletteAnim() override;
|
||||
|
||||
private:
|
||||
bool PollEvent();
|
||||
|
||||
bool IsFullscreen();
|
||||
void GameSizeChanged();
|
||||
|
||||
const char *Initialize();
|
||||
|
||||
void UpdateVideoModes();
|
||||
|
||||
bool MakeWindow(int width, int height);
|
||||
|
||||
void UpdatePalette(uint first_color, uint num_colors);
|
||||
virtual NSView* AllocateDrawView() = 0;
|
||||
|
||||
void BlitIndexedToView32(int left, int top, int right, int bottom);
|
||||
private:
|
||||
bool PollEvent();
|
||||
|
||||
bool IsFullscreen();
|
||||
};
|
||||
|
||||
class FVideoDriver_Cocoa : public DriverFactoryBase {
|
||||
class VideoDriver_CocoaQuartz : public VideoDriver_Cocoa {
|
||||
private:
|
||||
int buffer_depth; ///< Colour depth of used frame buffer
|
||||
void *pixel_buffer; ///< used for direct pixel access
|
||||
void *window_buffer; ///< Colour translation from palette to screen
|
||||
|
||||
int window_width; ///< Current window width in pixel
|
||||
int window_height; ///< Current window height in pixel
|
||||
int window_pitch;
|
||||
|
||||
uint32 palette[256]; ///< Colour Palette
|
||||
|
||||
void BlitIndexedToView32(int left, int top, int right, int bottom);
|
||||
void UpdatePalette(uint first_color, uint num_colors);
|
||||
|
||||
public:
|
||||
FVideoDriver_Cocoa() : DriverFactoryBase(Driver::DT_VIDEO, 10, "cocoa", "Cocoa Video Driver") {}
|
||||
Driver *CreateInstance() const override { return new VideoDriver_Cocoa(); }
|
||||
CGContextRef cgcontext; ///< Context reference for Quartz subdriver
|
||||
|
||||
VideoDriver_CocoaQuartz();
|
||||
|
||||
const char *Start(const StringList ¶m) override;
|
||||
void Stop() override;
|
||||
|
||||
/** Return driver name */
|
||||
const char *GetName() const override { return "cocoa"; }
|
||||
|
||||
void AllocateBackingStore() override;
|
||||
|
||||
protected:
|
||||
void Paint() override;
|
||||
void CheckPaletteAnim() override;
|
||||
|
||||
NSView* AllocateDrawView() override;
|
||||
};
|
||||
|
||||
class FVideoDriver_CocoaQuartz : public DriverFactoryBase {
|
||||
public:
|
||||
FVideoDriver_CocoaQuartz() : DriverFactoryBase(Driver::DT_VIDEO, 10, "cocoa", "Cocoa Video Driver") {}
|
||||
Driver *CreateInstance() const override { return new VideoDriver_CocoaQuartz(); }
|
||||
};
|
||||
|
||||
#endif /* VIDEO_COCOA_H */
|
||||
|
|
|
@ -81,25 +81,9 @@ static const Dimension _default_resolutions[] = {
|
|||
{ 2560, 1440 }
|
||||
};
|
||||
|
||||
static FVideoDriver_Cocoa iFVideoDriver_Cocoa;
|
||||
|
||||
|
||||
/** Subclass of NSView for drawing to screen. */
|
||||
@interface OTTD_QuartzView : NSView {
|
||||
VideoDriver_Cocoa *driver;
|
||||
}
|
||||
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv;
|
||||
@end
|
||||
|
||||
|
||||
VideoDriver_Cocoa::VideoDriver_Cocoa()
|
||||
{
|
||||
this->window_width = 0;
|
||||
this->window_height = 0;
|
||||
this->window_pitch = 0;
|
||||
this->buffer_depth = 0;
|
||||
this->window_buffer = nullptr;
|
||||
this->pixel_buffer = nullptr;
|
||||
this->setup = false;
|
||||
|
||||
this->window = nil;
|
||||
|
@ -107,7 +91,6 @@ VideoDriver_Cocoa::VideoDriver_Cocoa()
|
|||
this->delegate = nil;
|
||||
|
||||
this->color_space = nullptr;
|
||||
this->cgcontext = nullptr;
|
||||
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
@ -124,17 +107,13 @@ void VideoDriver_Cocoa::Stop()
|
|||
[ this->cocoaview release ];
|
||||
[ this->delegate release ];
|
||||
|
||||
CGContextRelease(this->cgcontext);
|
||||
CGColorSpaceRelease(this->color_space);
|
||||
|
||||
free(this->window_buffer);
|
||||
free(this->pixel_buffer);
|
||||
|
||||
_cocoa_video_started = false;
|
||||
}
|
||||
|
||||
/** Try to start Cocoa video driver. */
|
||||
const char *VideoDriver_Cocoa::Start(const StringList &parm)
|
||||
/** Common driver initialization. */
|
||||
const char *VideoDriver_Cocoa::Initialize()
|
||||
{
|
||||
if (!MacOSVersionIsAtLeast(10, 7, 0)) return "The Cocoa video driver requires Mac OS X 10.7 or later.";
|
||||
|
||||
|
@ -147,23 +126,6 @@ const char *VideoDriver_Cocoa::Start(const StringList &parm)
|
|||
this->UpdateAutoResolution();
|
||||
this->orig_res = _cur_resolution;
|
||||
|
||||
int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||
if (bpp != 8 && bpp != 32) {
|
||||
Stop();
|
||||
return "The cocoa quartz subdriver only supports 8 and 32 bpp.";
|
||||
}
|
||||
|
||||
bool fullscreen = _fullscreen;
|
||||
if (!this->MakeWindow(_cur_resolution.width, _cur_resolution.height)) {
|
||||
Stop();
|
||||
return "Could not create window";
|
||||
}
|
||||
|
||||
if (fullscreen) this->ToggleFullscreen(fullscreen);
|
||||
|
||||
this->GameSizeChanged();
|
||||
this->UpdateVideoModes();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -217,9 +179,6 @@ bool VideoDriver_Cocoa::ChangeResolution(int w, int h)
|
|||
[ this->cocoaview setFrameSize:contentRect.size ];
|
||||
}
|
||||
|
||||
this->window_width = w;
|
||||
this->window_height = h;
|
||||
|
||||
[ (OTTD_CocoaWindow *)this->window center ];
|
||||
this->AllocateBackingStore();
|
||||
|
||||
|
@ -251,7 +210,6 @@ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
|
|||
bool VideoDriver_Cocoa::AfterBlitterChange()
|
||||
{
|
||||
this->ChangeResolution(_cur_resolution.width, _cur_resolution.height);
|
||||
this->UpdatePalette(0, 256);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -294,12 +252,6 @@ bool VideoDriver_Cocoa::IsFullscreen()
|
|||
*/
|
||||
void VideoDriver_Cocoa::GameSizeChanged()
|
||||
{
|
||||
/* Tell the game that the resolution has changed */
|
||||
_screen.width = this->window_width;
|
||||
_screen.height = this->window_height;
|
||||
_screen.pitch = this->buffer_depth == 8 ? this->window_width : this->window_pitch;
|
||||
_screen.dst_ptr = this->buffer_depth == 8 ? this->pixel_buffer : this->window_buffer;
|
||||
|
||||
/* Store old window size if we entered fullscreen mode. */
|
||||
bool fullscreen = this->IsFullscreen();
|
||||
if (fullscreen && !_fullscreen) this->orig_res = _cur_resolution;
|
||||
|
@ -392,7 +344,7 @@ bool VideoDriver_Cocoa::MakeWindow(int width, int height)
|
|||
[ this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
|
||||
|
||||
/* Create content view. */
|
||||
NSView *draw_view = [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->cocoaview bounds ] andDriver:this ];
|
||||
NSView *draw_view = this->AllocateDrawView();
|
||||
if (draw_view == nil) {
|
||||
DEBUG(driver, 0, "Could not create the drawing view.");
|
||||
this->setup = false;
|
||||
|
@ -414,171 +366,11 @@ bool VideoDriver_Cocoa::MakeWindow(int width, int height)
|
|||
|
||||
this->setup = false;
|
||||
|
||||
this->UpdatePalette(0, 256);
|
||||
this->AllocateBackingStore();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function copies 8bpp pixels to the screen buffer in 32bpp windowed mode.
|
||||
*
|
||||
* @param left The x coord for the left edge of the box to blit.
|
||||
* @param top The y coord for the top edge of the box to blit.
|
||||
* @param right The x coord for the right edge of the box to blit.
|
||||
* @param bottom The y coord for the bottom edge of the box to blit.
|
||||
*/
|
||||
void VideoDriver_Cocoa::BlitIndexedToView32(int left, int top, int right, int bottom)
|
||||
{
|
||||
const uint32 *pal = this->palette;
|
||||
const uint8 *src = (uint8*)this->pixel_buffer;
|
||||
uint32 *dst = (uint32*)this->window_buffer;
|
||||
uint width = this->window_width;
|
||||
uint pitch = this->window_pitch;
|
||||
|
||||
for (int y = top; y < bottom; y++) {
|
||||
for (int x = left; x < right; x++) {
|
||||
dst[y * pitch + x] = pal[src[y * width + x]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint window.
|
||||
* @param force_update Whether to redraw unconditionally
|
||||
*/
|
||||
void VideoDriver_Cocoa::Paint()
|
||||
{
|
||||
PerformanceMeasurer framerate(PFE_VIDEO);
|
||||
|
||||
/* Check if we need to do anything */
|
||||
if (IsEmptyRect(this->dirty_rect) || [ this->window isMiniaturized ]) return;
|
||||
|
||||
/* We only need to blit in indexed mode since in 32bpp mode the game draws directly to the image. */
|
||||
if (this->buffer_depth == 8) {
|
||||
BlitIndexedToView32(
|
||||
this->dirty_rect.left,
|
||||
this->dirty_rect.top,
|
||||
this->dirty_rect.right,
|
||||
this->dirty_rect.bottom
|
||||
);
|
||||
}
|
||||
|
||||
NSRect dirtyrect;
|
||||
dirtyrect.origin.x = this->dirty_rect.left;
|
||||
dirtyrect.origin.y = this->window_height - this->dirty_rect.bottom;
|
||||
dirtyrect.size.width = this->dirty_rect.right - this->dirty_rect.left;
|
||||
dirtyrect.size.height = this->dirty_rect.bottom - this->dirty_rect.top;
|
||||
|
||||
/* Notify OS X that we have new content to show. */
|
||||
[ this->cocoaview setNeedsDisplayInRect:[ this->cocoaview getVirtualRect:dirtyrect ] ];
|
||||
|
||||
/* Tell the OS to get our contents to screen as soon as possible. */
|
||||
[ CATransaction flush ];
|
||||
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
||||
/** Update the palette. */
|
||||
void VideoDriver_Cocoa::UpdatePalette(uint first_color, uint num_colors)
|
||||
{
|
||||
if (this->buffer_depth != 8) return;
|
||||
|
||||
for (uint i = first_color; i < first_color + num_colors; i++) {
|
||||
uint32 clr = 0xff000000;
|
||||
clr |= (uint32)_cur_palette.palette[i].r << 16;
|
||||
clr |= (uint32)_cur_palette.palette[i].g << 8;
|
||||
clr |= (uint32)_cur_palette.palette[i].b;
|
||||
this->palette[i] = clr;
|
||||
}
|
||||
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
/** Clear buffer to opaque black. */
|
||||
static void ClearWindowBuffer(uint32 *buffer, uint32 pitch, uint32 height)
|
||||
{
|
||||
uint32 fill = Colour(0, 0, 0).data;
|
||||
for (uint32 y = 0; y < height; y++) {
|
||||
for (uint32 x = 0; x < pitch; x++) {
|
||||
buffer[y * pitch + x] = fill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Resize the window. */
|
||||
void VideoDriver_Cocoa::AllocateBackingStore()
|
||||
{
|
||||
if (this->window == nil || this->cocoaview == nil || this->setup) return;
|
||||
|
||||
NSRect newframe = [ this->cocoaview getRealRect:[ this->cocoaview frame ] ];
|
||||
|
||||
this->window_width = (int)newframe.size.width;
|
||||
this->window_height = (int)newframe.size.height;
|
||||
this->window_pitch = Align(this->window_width, 16 / sizeof(uint32)); // Quartz likes lines that are multiple of 16-byte.
|
||||
this->buffer_depth = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||
|
||||
/* Create Core Graphics Context */
|
||||
free(this->window_buffer);
|
||||
this->window_buffer = malloc(this->window_pitch * this->window_height * sizeof(uint32));
|
||||
/* Initialize with opaque black. */
|
||||
ClearWindowBuffer((uint32 *)this->window_buffer, this->window_pitch, this->window_height);
|
||||
|
||||
CGContextRelease(this->cgcontext);
|
||||
this->cgcontext = CGBitmapContextCreate(
|
||||
this->window_buffer, // data
|
||||
this->window_width, // width
|
||||
this->window_height, // height
|
||||
8, // bits per component
|
||||
this->window_pitch * 4, // bytes per row
|
||||
this->color_space, // color space
|
||||
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host
|
||||
);
|
||||
|
||||
assert(this->cgcontext != NULL);
|
||||
CGContextSetShouldAntialias(this->cgcontext, FALSE);
|
||||
CGContextSetAllowsAntialiasing(this->cgcontext, FALSE);
|
||||
CGContextSetInterpolationQuality(this->cgcontext, kCGInterpolationNone);
|
||||
|
||||
if (this->buffer_depth == 8) {
|
||||
free(this->pixel_buffer);
|
||||
this->pixel_buffer = malloc(this->window_width * this->window_height);
|
||||
if (this->pixel_buffer == nullptr) usererror("Out of memory allocating pixel buffer");
|
||||
} else {
|
||||
free(this->pixel_buffer);
|
||||
this->pixel_buffer = nullptr;
|
||||
}
|
||||
|
||||
/* Redraw screen */
|
||||
this->GameSizeChanged();
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
/** Check if palette updates need to be performed. */
|
||||
void VideoDriver_Cocoa::CheckPaletteAnim()
|
||||
{
|
||||
if (_cur_palette.count_dirty != 0) {
|
||||
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
||||
|
||||
switch (blitter->UsePaletteAnimation()) {
|
||||
case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
|
||||
this->UpdatePalette(_cur_palette.first_dirty, _cur_palette.count_dirty);
|
||||
break;
|
||||
|
||||
case Blitter::PALETTE_ANIMATION_BLITTER:
|
||||
blitter->PaletteAnimate(_cur_palette);
|
||||
break;
|
||||
|
||||
case Blitter::PALETTE_ANIMATION_NONE:
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
_cur_palette.count_dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Poll and handle a single event from the OS.
|
||||
|
@ -642,9 +434,16 @@ void VideoDriver_Cocoa::GameLoop()
|
|||
}
|
||||
|
||||
|
||||
/* Subclass of OTTD_CocoaView to fix Quartz rendering */
|
||||
@interface OTTD_QuartzView : NSView {
|
||||
VideoDriver_CocoaQuartz *driver;
|
||||
}
|
||||
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_CocoaQuartz *)drv;
|
||||
@end
|
||||
|
||||
@implementation OTTD_QuartzView
|
||||
|
||||
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv
|
||||
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_CocoaQuartz *)drv
|
||||
{
|
||||
if (self = [ super initWithFrame:frameRect ]) {
|
||||
self->driver = drv;
|
||||
|
@ -693,4 +492,223 @@ void VideoDriver_Cocoa::GameLoop()
|
|||
|
||||
@end
|
||||
|
||||
|
||||
static FVideoDriver_CocoaQuartz iFVideoDriver_CocoaQuartz;
|
||||
|
||||
/** Clear buffer to opaque black. */
|
||||
static void ClearWindowBuffer(uint32 *buffer, uint32 pitch, uint32 height)
|
||||
{
|
||||
uint32 fill = Colour(0, 0, 0).data;
|
||||
for (uint32 y = 0; y < height; y++) {
|
||||
for (uint32 x = 0; x < pitch; x++) {
|
||||
buffer[y * pitch + x] = fill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VideoDriver_CocoaQuartz::VideoDriver_CocoaQuartz()
|
||||
{
|
||||
this->window_width = 0;
|
||||
this->window_height = 0;
|
||||
this->window_pitch = 0;
|
||||
this->buffer_depth = 0;
|
||||
this->window_buffer = nullptr;
|
||||
this->pixel_buffer = nullptr;
|
||||
|
||||
this->cgcontext = nullptr;
|
||||
}
|
||||
|
||||
const char *VideoDriver_CocoaQuartz::Start(const StringList ¶m)
|
||||
{
|
||||
const char *err = this->Initialize();
|
||||
if (err != nullptr) return err;
|
||||
|
||||
int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||
if (bpp != 8 && bpp != 32) {
|
||||
Stop();
|
||||
return "The cocoa quartz subdriver only supports 8 and 32 bpp.";
|
||||
}
|
||||
|
||||
bool fullscreen = _fullscreen;
|
||||
if (!this->MakeWindow(_cur_resolution.width, _cur_resolution.height)) {
|
||||
Stop();
|
||||
return "Could not create window";
|
||||
}
|
||||
|
||||
if (fullscreen) this->ToggleFullscreen(fullscreen);
|
||||
|
||||
this->GameSizeChanged();
|
||||
this->UpdateVideoModes();
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
void VideoDriver_CocoaQuartz::Stop()
|
||||
{
|
||||
this->VideoDriver_Cocoa::Stop();
|
||||
|
||||
CGContextRelease(this->cgcontext);
|
||||
|
||||
free(this->window_buffer);
|
||||
free(this->pixel_buffer);
|
||||
}
|
||||
|
||||
NSView *VideoDriver_CocoaQuartz::AllocateDrawView()
|
||||
{
|
||||
return [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->cocoaview bounds ] andDriver:this ];
|
||||
}
|
||||
|
||||
/** Resize the window. */
|
||||
void VideoDriver_CocoaQuartz::AllocateBackingStore()
|
||||
{
|
||||
if (this->window == nil || this->cocoaview == nil || this->setup) return;
|
||||
|
||||
this->UpdatePalette(0, 256);
|
||||
|
||||
NSRect newframe = [ this->cocoaview getRealRect:[ this->cocoaview frame ] ];
|
||||
|
||||
this->window_width = (int)newframe.size.width;
|
||||
this->window_height = (int)newframe.size.height;
|
||||
this->window_pitch = Align(this->window_width, 16 / sizeof(uint32)); // Quartz likes lines that are multiple of 16-byte.
|
||||
this->buffer_depth = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||
|
||||
/* Create Core Graphics Context */
|
||||
free(this->window_buffer);
|
||||
this->window_buffer = malloc(this->window_pitch * this->window_height * sizeof(uint32));
|
||||
/* Initialize with opaque black. */
|
||||
ClearWindowBuffer((uint32 *)this->window_buffer, this->window_pitch, this->window_height);
|
||||
|
||||
CGContextRelease(this->cgcontext);
|
||||
this->cgcontext = CGBitmapContextCreate(
|
||||
this->window_buffer, // data
|
||||
this->window_width, // width
|
||||
this->window_height, // height
|
||||
8, // bits per component
|
||||
this->window_pitch * 4, // bytes per row
|
||||
this->color_space, // color space
|
||||
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host
|
||||
);
|
||||
|
||||
assert(this->cgcontext != NULL);
|
||||
CGContextSetShouldAntialias(this->cgcontext, FALSE);
|
||||
CGContextSetAllowsAntialiasing(this->cgcontext, FALSE);
|
||||
CGContextSetInterpolationQuality(this->cgcontext, kCGInterpolationNone);
|
||||
|
||||
if (this->buffer_depth == 8) {
|
||||
free(this->pixel_buffer);
|
||||
this->pixel_buffer = malloc(this->window_width * this->window_height);
|
||||
if (this->pixel_buffer == nullptr) usererror("Out of memory allocating pixel buffer");
|
||||
} else {
|
||||
free(this->pixel_buffer);
|
||||
this->pixel_buffer = nullptr;
|
||||
}
|
||||
|
||||
/* Tell the game that the resolution has changed */
|
||||
_screen.width = this->window_width;
|
||||
_screen.height = this->window_height;
|
||||
_screen.pitch = this->buffer_depth == 8 ? this->window_width : this->window_pitch;
|
||||
_screen.dst_ptr = this->buffer_depth == 8 ? this->pixel_buffer : this->window_buffer;
|
||||
|
||||
/* Redraw screen */
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
this->GameSizeChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function copies 8bpp pixels from the screen buffer in 32bpp windowed mode.
|
||||
*
|
||||
* @param left The x coord for the left edge of the box to blit.
|
||||
* @param top The y coord for the top edge of the box to blit.
|
||||
* @param right The x coord for the right edge of the box to blit.
|
||||
* @param bottom The y coord for the bottom edge of the box to blit.
|
||||
*/
|
||||
void VideoDriver_CocoaQuartz::BlitIndexedToView32(int left, int top, int right, int bottom)
|
||||
{
|
||||
const uint32 *pal = this->palette;
|
||||
const uint8 *src = (uint8*)this->pixel_buffer;
|
||||
uint32 *dst = (uint32*)this->window_buffer;
|
||||
uint width = this->window_width;
|
||||
uint pitch = this->window_pitch;
|
||||
|
||||
for (int y = top; y < bottom; y++) {
|
||||
for (int x = left; x < right; x++) {
|
||||
dst[y * pitch + x] = pal[src[y * width + x]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the palette */
|
||||
void VideoDriver_CocoaQuartz::UpdatePalette(uint first_color, uint num_colors)
|
||||
{
|
||||
if (this->buffer_depth != 8) return;
|
||||
|
||||
for (uint i = first_color; i < first_color + num_colors; i++) {
|
||||
uint32 clr = 0xff000000;
|
||||
clr |= (uint32)_cur_palette.palette[i].r << 16;
|
||||
clr |= (uint32)_cur_palette.palette[i].g << 8;
|
||||
clr |= (uint32)_cur_palette.palette[i].b;
|
||||
this->palette[i] = clr;
|
||||
}
|
||||
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
void VideoDriver_CocoaQuartz::CheckPaletteAnim()
|
||||
{
|
||||
if (_cur_palette.count_dirty != 0) {
|
||||
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
||||
|
||||
switch (blitter->UsePaletteAnimation()) {
|
||||
case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
|
||||
this->UpdatePalette(_cur_palette.first_dirty, _cur_palette.count_dirty);
|
||||
break;
|
||||
|
||||
case Blitter::PALETTE_ANIMATION_BLITTER:
|
||||
blitter->PaletteAnimate(_cur_palette);
|
||||
break;
|
||||
|
||||
case Blitter::PALETTE_ANIMATION_NONE:
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
_cur_palette.count_dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Draw window */
|
||||
void VideoDriver_CocoaQuartz::Paint()
|
||||
{
|
||||
PerformanceMeasurer framerate(PFE_VIDEO);
|
||||
|
||||
/* Check if we need to do anything */
|
||||
if (IsEmptyRect(this->dirty_rect) || [ this->window isMiniaturized ]) return;
|
||||
|
||||
/* We only need to blit in indexed mode since in 32bpp mode the game draws directly to the image. */
|
||||
if (this->buffer_depth == 8) {
|
||||
BlitIndexedToView32(
|
||||
this->dirty_rect.left,
|
||||
this->dirty_rect.top,
|
||||
this->dirty_rect.right,
|
||||
this->dirty_rect.bottom
|
||||
);
|
||||
}
|
||||
|
||||
NSRect dirtyrect;
|
||||
dirtyrect.origin.x = this->dirty_rect.left;
|
||||
dirtyrect.origin.y = this->window_height - this->dirty_rect.bottom;
|
||||
dirtyrect.size.width = this->dirty_rect.right - this->dirty_rect.left;
|
||||
dirtyrect.size.height = this->dirty_rect.bottom - this->dirty_rect.top;
|
||||
|
||||
/* Notify OS X that we have new content to show. */
|
||||
[ this->cocoaview setNeedsDisplayInRect:[ this->cocoaview getVirtualRect:dirtyrect ] ];
|
||||
|
||||
/* Tell the OS to get our contents to screen as soon as possible. */
|
||||
[ CATransaction flush ];
|
||||
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
||||
#endif /* WITH_COCOA */
|
||||
|
|
Loading…
Reference in New Issue