mirror of https://github.com/OpenTTD/OpenTTD
Codechange: [OSX] Move some things from video driver to our NSView.
parent
965ce12947
commit
bd42fc94cc
|
@ -17,6 +17,8 @@
|
||||||
extern bool _cocoa_video_started;
|
extern bool _cocoa_video_started;
|
||||||
|
|
||||||
@class OTTD_CocoaWindowDelegate;
|
@class OTTD_CocoaWindowDelegate;
|
||||||
|
@class OTTD_CocoaWindow;
|
||||||
|
@class OTTD_CocoaView;
|
||||||
|
|
||||||
class VideoDriver_Cocoa : public VideoDriver {
|
class VideoDriver_Cocoa : public VideoDriver {
|
||||||
private:
|
private:
|
||||||
|
@ -40,8 +42,8 @@ public:
|
||||||
bool active; ///< Whether the window is visible
|
bool active; ///< Whether the window is visible
|
||||||
bool setup;
|
bool setup;
|
||||||
|
|
||||||
id window; ///< Pointer to window object
|
OTTD_CocoaWindow *window; ///< Pointer to window object
|
||||||
id cocoaview; ///< Pointer to view object
|
OTTD_CocoaView *cocoaview; ///< Pointer to view object
|
||||||
CGColorSpaceRef color_space; ///< Window color space
|
CGColorSpaceRef color_space; ///< Window color space
|
||||||
CGContextRef cgcontext; ///< Context reference for Quartz subdriver
|
CGContextRef cgcontext; ///< Context reference for Quartz subdriver
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include "../../openttd.h"
|
#include "../../openttd.h"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
#include "../../rev.h"
|
|
||||||
#include "../../core/geometry_type.hpp"
|
#include "../../core/geometry_type.hpp"
|
||||||
#include "cocoa_v.h"
|
#include "cocoa_v.h"
|
||||||
#include "cocoa_wnd.h"
|
#include "cocoa_wnd.h"
|
||||||
|
@ -311,111 +310,6 @@ void VideoDriver_Cocoa::GameSizeChanged()
|
||||||
::GameSizeChanged();
|
::GameSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation OTTD_QuartzView
|
|
||||||
|
|
||||||
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv
|
|
||||||
{
|
|
||||||
if (self = [ super initWithFrame:frameRect ]) {
|
|
||||||
self->driver = drv;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)acceptsFirstResponder
|
|
||||||
{
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the opaqueness of the window / screen
|
|
||||||
* @return opaqueness of window / screen
|
|
||||||
*/
|
|
||||||
- (BOOL)isOpaque
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawRect:(NSRect)invalidRect
|
|
||||||
{
|
|
||||||
if (driver->cgcontext == NULL) return;
|
|
||||||
|
|
||||||
CGContextRef viewContext = (CGContextRef)[ [ NSGraphicsContext currentContext ] graphicsPort ];
|
|
||||||
CGContextSetShouldAntialias(viewContext, FALSE);
|
|
||||||
CGContextSetInterpolationQuality(viewContext, kCGInterpolationNone);
|
|
||||||
|
|
||||||
/* The obtained 'rect' is actually a union of all dirty rects, let's ask for an explicit list of rects instead */
|
|
||||||
const NSRect *dirtyRects;
|
|
||||||
NSInteger dirtyRectCount;
|
|
||||||
[ self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount ];
|
|
||||||
|
|
||||||
/* We need an Image in order to do blitting, but as we don't touch the context between this call and drawing no copying will actually be done here */
|
|
||||||
CGImageRef fullImage = CGBitmapContextCreateImage(driver->cgcontext);
|
|
||||||
|
|
||||||
/* Calculate total area we are blitting */
|
|
||||||
uint32 blitArea = 0;
|
|
||||||
for (int n = 0; n < dirtyRectCount; n++) {
|
|
||||||
blitArea += (uint32)(dirtyRects[n].size.width * dirtyRects[n].size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This might be completely stupid, but in my extremely subjective opinion it feels faster
|
|
||||||
* The point is, if we're blitting less than 50% of the dirty rect union then it's still a good idea to blit each dirty
|
|
||||||
* rect separately but if we blit more than that, it's just cheaper to blit the entire union in one pass.
|
|
||||||
* Feel free to remove or find an even better value than 50% ... / blackis
|
|
||||||
*/
|
|
||||||
NSRect frameRect = [ self frame ];
|
|
||||||
if (blitArea / (float)(invalidRect.size.width * invalidRect.size.height) > 0.5f) {
|
|
||||||
NSRect rect = invalidRect;
|
|
||||||
CGRect clipRect;
|
|
||||||
CGRect blitRect;
|
|
||||||
|
|
||||||
blitRect.origin.x = rect.origin.x;
|
|
||||||
blitRect.origin.y = rect.origin.y;
|
|
||||||
blitRect.size.width = rect.size.width;
|
|
||||||
blitRect.size.height = rect.size.height;
|
|
||||||
|
|
||||||
clipRect.origin.x = rect.origin.x;
|
|
||||||
clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height;
|
|
||||||
|
|
||||||
clipRect.size.width = rect.size.width;
|
|
||||||
clipRect.size.height = rect.size.height;
|
|
||||||
|
|
||||||
/* Blit dirty part of image */
|
|
||||||
CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect);
|
|
||||||
CGContextDrawImage(viewContext, blitRect, clippedImage);
|
|
||||||
CGImageRelease(clippedImage);
|
|
||||||
} else {
|
|
||||||
for (int n = 0; n < dirtyRectCount; n++) {
|
|
||||||
NSRect rect = dirtyRects[n];
|
|
||||||
CGRect clipRect;
|
|
||||||
CGRect blitRect;
|
|
||||||
|
|
||||||
blitRect.origin.x = rect.origin.x;
|
|
||||||
blitRect.origin.y = rect.origin.y;
|
|
||||||
blitRect.size.width = rect.size.width;
|
|
||||||
blitRect.size.height = rect.size.height;
|
|
||||||
|
|
||||||
clipRect.origin.x = rect.origin.x;
|
|
||||||
clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height;
|
|
||||||
|
|
||||||
clipRect.size.width = rect.size.width;
|
|
||||||
clipRect.size.height = rect.size.height;
|
|
||||||
|
|
||||||
/* Blit dirty part of image */
|
|
||||||
CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect);
|
|
||||||
CGContextDrawImage(viewContext, blitRect, clippedImage);
|
|
||||||
CGImageRelease(clippedImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CGImageRelease(fullImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the video modus.
|
* Update the video modus.
|
||||||
*/
|
*/
|
||||||
|
@ -476,21 +370,10 @@ bool VideoDriver_Cocoa::MakeWindow(int width, int height)
|
||||||
[ fullscreenButton setTarget:this->window ];
|
[ fullscreenButton setTarget:this->window ];
|
||||||
}
|
}
|
||||||
|
|
||||||
char caption[50];
|
|
||||||
snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
|
|
||||||
NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption ];
|
|
||||||
[ this->window setTitle:nsscaption ];
|
|
||||||
[ this->window setMiniwindowTitle:nsscaption ];
|
|
||||||
[ nsscaption release ];
|
|
||||||
|
|
||||||
[ this->window setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
|
|
||||||
|
|
||||||
this->delegate = [ [ OTTD_CocoaWindowDelegate alloc ] initWithDriver:this ];
|
this->delegate = [ [ OTTD_CocoaWindowDelegate alloc ] initWithDriver:this ];
|
||||||
[ this->window setDelegate:this->delegate ];
|
[ this->window setDelegate:this->delegate ];
|
||||||
|
|
||||||
[ this->window setAcceptsMouseMovedEvents:YES ];
|
[ this->window center ];
|
||||||
[ this->window setViewsNeedDisplay:NO ];
|
|
||||||
[ (OTTD_CocoaWindow *)this->window center ];
|
|
||||||
[ this->window makeKeyAndOrderFront:nil ];
|
[ this->window makeKeyAndOrderFront:nil ];
|
||||||
|
|
||||||
/* Create wrapper view for text input. */
|
/* Create wrapper view for text input. */
|
||||||
|
@ -501,7 +384,7 @@ bool VideoDriver_Cocoa::MakeWindow(int width, int height)
|
||||||
this->setup = false;
|
this->setup = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
[ (NSView *)this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
|
[ this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
|
||||||
|
|
||||||
/* Create content view. */
|
/* Create content view. */
|
||||||
NSView *draw_view = [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->cocoaview bounds ] andDriver:this ];
|
NSView *draw_view = [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->cocoaview bounds ] andDriver:this ];
|
||||||
|
@ -744,4 +627,104 @@ void VideoDriver_Cocoa::CheckPaletteAnim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@implementation OTTD_QuartzView
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv
|
||||||
|
{
|
||||||
|
if (self = [ super initWithFrame:frameRect ]) {
|
||||||
|
self->driver = drv;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isOpaque
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(NSRect)invalidRect
|
||||||
|
{
|
||||||
|
if (driver->cgcontext == nullptr) return;
|
||||||
|
|
||||||
|
NSGraphicsContext *ctx = [ NSGraphicsContext currentContext ];
|
||||||
|
CGContextRef viewContext = [ ctx respondsToSelector:@selector(CGContext) ] ? [ ctx CGContext ] : (CGContextRef)[ ctx graphicsPort ];
|
||||||
|
CGContextSetShouldAntialias(viewContext, FALSE);
|
||||||
|
CGContextSetInterpolationQuality(viewContext, kCGInterpolationNone);
|
||||||
|
|
||||||
|
/* The obtained 'rect' is actually a union of all dirty rects, let's ask for an explicit list of rects instead */
|
||||||
|
const NSRect *dirtyRects;
|
||||||
|
NSInteger dirtyRectCount;
|
||||||
|
[ self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount ];
|
||||||
|
|
||||||
|
/* We need an Image in order to do blitting, but as we don't touch the context between this call and drawing no copying will actually be done here */
|
||||||
|
CGImageRef fullImage = CGBitmapContextCreateImage(driver->cgcontext);
|
||||||
|
|
||||||
|
/* Calculate total area we are blitting */
|
||||||
|
uint32 blitArea = 0;
|
||||||
|
for (int n = 0; n < dirtyRectCount; n++) {
|
||||||
|
blitArea += (uint32)(dirtyRects[n].size.width * dirtyRects[n].size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This might be completely stupid, but in my extremely subjective opinion it feels faster
|
||||||
|
* The point is, if we're blitting less than 50% of the dirty rect union then it's still a good idea to blit each dirty
|
||||||
|
* rect separately but if we blit more than that, it's just cheaper to blit the entire union in one pass.
|
||||||
|
* Feel free to remove or find an even better value than 50% ... / blackis
|
||||||
|
*/
|
||||||
|
NSRect frameRect = [ self frame ];
|
||||||
|
if (blitArea / (float)(invalidRect.size.width * invalidRect.size.height) > 0.5f) {
|
||||||
|
NSRect rect = invalidRect;
|
||||||
|
CGRect clipRect;
|
||||||
|
CGRect blitRect;
|
||||||
|
|
||||||
|
blitRect.origin.x = rect.origin.x;
|
||||||
|
blitRect.origin.y = rect.origin.y;
|
||||||
|
blitRect.size.width = rect.size.width;
|
||||||
|
blitRect.size.height = rect.size.height;
|
||||||
|
|
||||||
|
clipRect.origin.x = rect.origin.x;
|
||||||
|
clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height;
|
||||||
|
|
||||||
|
clipRect.size.width = rect.size.width;
|
||||||
|
clipRect.size.height = rect.size.height;
|
||||||
|
|
||||||
|
/* Blit dirty part of image */
|
||||||
|
CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect);
|
||||||
|
CGContextDrawImage(viewContext, blitRect, clippedImage);
|
||||||
|
CGImageRelease(clippedImage);
|
||||||
|
} else {
|
||||||
|
for (int n = 0; n < dirtyRectCount; n++) {
|
||||||
|
NSRect rect = dirtyRects[n];
|
||||||
|
CGRect clipRect;
|
||||||
|
CGRect blitRect;
|
||||||
|
|
||||||
|
blitRect.origin.x = rect.origin.x;
|
||||||
|
blitRect.origin.y = rect.origin.y;
|
||||||
|
blitRect.size.width = rect.size.width;
|
||||||
|
blitRect.size.height = rect.size.height;
|
||||||
|
|
||||||
|
clipRect.origin.x = rect.origin.x;
|
||||||
|
clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height;
|
||||||
|
|
||||||
|
clipRect.size.width = rect.size.width;
|
||||||
|
clipRect.size.height = rect.size.height;
|
||||||
|
|
||||||
|
/* Blit dirty part of image */
|
||||||
|
CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect);
|
||||||
|
CGContextDrawImage(viewContext, blitRect, clippedImage);
|
||||||
|
CGImageRelease(clippedImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CGImageRelease(fullImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
#endif /* WITH_COCOA */
|
#endif /* WITH_COCOA */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "../../openttd.h"
|
#include "../../openttd.h"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
|
#include "../../rev.h"
|
||||||
#include "cocoa_v.h"
|
#include "cocoa_v.h"
|
||||||
#include "cocoa_wnd.h"
|
#include "cocoa_wnd.h"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
|
@ -345,6 +346,15 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
|
||||||
selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
|
selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
|
||||||
|
|
||||||
self->driver = drv;
|
self->driver = drv;
|
||||||
|
|
||||||
|
[ self setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
|
||||||
|
[ self setAcceptsMouseMovedEvents:YES ];
|
||||||
|
|
||||||
|
std::string caption = std::string{"OpenTTD "} + _openttd_revision;
|
||||||
|
NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption.c_str() ];
|
||||||
|
[ self setTitle:nsscaption ];
|
||||||
|
[ self setMiniwindowTitle:nsscaption ];
|
||||||
|
[ nsscaption release ];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|
Loading…
Reference in New Issue