Merge branch 'master' into jgrpp
# Conflicts: # src/dock_gui.cpp # src/rail_gui.cpp # src/road_gui.cpp # src/terraform_gui.cpp # src/vehicle.cpp # src/video/allegro_v.cpp # src/video/cocoa/cocoa_v.mm # src/video/dedicated_v.cpp # src/video/sdl2_v.cpp # src/video/sdl_v.cpp # src/video/win32_v.cpp
This commit is contained in:
@@ -32,10 +32,8 @@ private:
|
||||
void *pixel_buffer; ///< used for direct pixel access
|
||||
void *window_buffer; ///< Colour translation from palette to screen
|
||||
|
||||
static const int MAX_DIRTY_RECTS = 100;
|
||||
Rect dirty_rect; ///< Region of the screen that needs redrawing.
|
||||
|
||||
Rect dirty_rects[MAX_DIRTY_RECTS]; ///< dirty rectangles
|
||||
uint num_dirty_rects; ///< Number of dirty rectangles
|
||||
uint32 palette[256]; ///< Colour Palette
|
||||
|
||||
public:
|
||||
@@ -74,6 +72,9 @@ public:
|
||||
protected:
|
||||
Dimension GetScreenSize() const override;
|
||||
float GetDPIScale() override;
|
||||
void InputLoop() override;
|
||||
void Paint() override;
|
||||
void CheckPaletteAnim() override;
|
||||
|
||||
private:
|
||||
bool PollEvent();
|
||||
@@ -86,9 +87,7 @@ private:
|
||||
bool MakeWindow(int width, int height);
|
||||
|
||||
void UpdatePalette(uint first_color, uint num_colors);
|
||||
void CheckPaletteAnim();
|
||||
|
||||
void Draw(bool force_update = false);
|
||||
void BlitIndexedToView32(int left, int top, int right, int bottom);
|
||||
};
|
||||
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
#define Rect OTTDRect
|
||||
#define Point OTTDPoint
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#undef Rect
|
||||
#undef Point
|
||||
|
||||
#include "../../openttd.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../core/geometry_type.hpp"
|
||||
#include "../../core/geometry_func.hpp"
|
||||
#include "../../core/math_func.hpp"
|
||||
#include "cocoa_v.h"
|
||||
#include "cocoa_wnd.h"
|
||||
@@ -125,7 +126,7 @@ VideoDriver_Cocoa::VideoDriver_Cocoa()
|
||||
this->color_space = nullptr;
|
||||
this->cgcontext = nullptr;
|
||||
|
||||
this->num_dirty_rects = lengthof(this->dirty_rects);
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
||||
/** Stop Cocoa video driver. */
|
||||
@@ -192,13 +193,8 @@ const char *VideoDriver_Cocoa::Start(const StringList &parm)
|
||||
*/
|
||||
void VideoDriver_Cocoa::MakeDirty(int left, int top, int width, int height)
|
||||
{
|
||||
if (this->num_dirty_rects < lengthof(this->dirty_rects)) {
|
||||
dirty_rects[this->num_dirty_rects].left = left;
|
||||
dirty_rects[this->num_dirty_rects].top = top;
|
||||
dirty_rects[this->num_dirty_rects].right = left + width;
|
||||
dirty_rects[this->num_dirty_rects].bottom = top + height;
|
||||
}
|
||||
this->num_dirty_rects++;
|
||||
Rect r = {left, top, left + width, top + height};
|
||||
this->dirty_rect = BoundingRect(this->dirty_rect, r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,49 +461,39 @@ void VideoDriver_Cocoa::BlitIndexedToView32(int left, int top, int right, int bo
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw window.
|
||||
* Paint window.
|
||||
* @param force_update Whether to redraw unconditionally
|
||||
*/
|
||||
void VideoDriver_Cocoa::Draw(bool force_update)
|
||||
void VideoDriver_Cocoa::Paint()
|
||||
{
|
||||
PerformanceMeasurer framerate(PFE_VIDEO);
|
||||
|
||||
/* Check if we need to do anything */
|
||||
if (this->num_dirty_rects == 0 || [ this->window isMiniaturized ]) return;
|
||||
if (IsEmptyRect(this->dirty_rect) || [ this->window isMiniaturized ]) return;
|
||||
|
||||
if (this->num_dirty_rects >= lengthof(this->dirty_rects)) {
|
||||
this->num_dirty_rects = 1;
|
||||
this->dirty_rects[0].left = 0;
|
||||
this->dirty_rects[0].top = 0;
|
||||
this->dirty_rects[0].right = this->window_width;
|
||||
this->dirty_rects[0].bottom = this->window_height;
|
||||
/* 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
|
||||
);
|
||||
}
|
||||
|
||||
/* Build the region of dirty rectangles */
|
||||
for (uint i = 0; i < this->num_dirty_rects; i++) {
|
||||
/* 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_rects[i].left,
|
||||
this->dirty_rects[i].top,
|
||||
this->dirty_rects[i].right,
|
||||
this->dirty_rects[i].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;
|
||||
|
||||
NSRect dirtyrect;
|
||||
dirtyrect.origin.x = this->dirty_rects[i].left;
|
||||
dirtyrect.origin.y = this->window_height - this->dirty_rects[i].bottom;
|
||||
dirtyrect.size.width = this->dirty_rects[i].right - this->dirty_rects[i].left;
|
||||
dirtyrect.size.height = this->dirty_rects[i].bottom - this->dirty_rects[i].top;
|
||||
/* Notify OS X that we have new content to show. */
|
||||
[ this->cocoaview setNeedsDisplayInRect:[ this->cocoaview getVirtualRect:dirtyrect ] ];
|
||||
|
||||
/* Normally drawRect will be automatically called by Mac OS X during next update cycle,
|
||||
* and then blitting will occur. If force_update is true, it will be done right now. */
|
||||
[ this->cocoaview setNeedsDisplayInRect:[ this->cocoaview getVirtualRect:dirtyrect ] ];
|
||||
if (force_update) [ this->cocoaview displayIfNeeded ];
|
||||
}
|
||||
/* Tell the OS to get our contents to screen as soon as possible. */
|
||||
[ CATransaction flush ];
|
||||
|
||||
this->num_dirty_rects = 0;
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
||||
/** Update the palette. */
|
||||
@@ -523,7 +509,7 @@ void VideoDriver_Cocoa::UpdatePalette(uint first_color, uint num_colors)
|
||||
this->palette[i] = clr;
|
||||
}
|
||||
|
||||
this->num_dirty_rects = lengthof(this->dirty_rects);
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
/** Clear buffer to opaque black. */
|
||||
@@ -581,8 +567,8 @@ void VideoDriver_Cocoa::AllocateBackingStore()
|
||||
}
|
||||
|
||||
/* Redraw screen */
|
||||
this->num_dirty_rects = lengthof(this->dirty_rects);
|
||||
this->GameSizeChanged();
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
/** Check if palette updates need to be performed. */
|
||||
@@ -632,14 +618,33 @@ bool VideoDriver_Cocoa::PollEvent()
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoDriver_Cocoa::InputLoop()
|
||||
{
|
||||
NSUInteger cur_mods = [ NSEvent modifierFlags ];
|
||||
|
||||
bool old_ctrl_pressed = _ctrl_pressed;
|
||||
bool old_shift_pressed = _shift_pressed;
|
||||
|
||||
_ctrl_pressed = ((cur_mods & ( _settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? NSControlKeyMask : NSCommandKeyMask)) != 0) != _invert_ctrl;
|
||||
_shift_pressed = ((cur_mods & NSShiftKeyMask) != 0) != _invert_shift;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (_shift_pressed) {
|
||||
#else
|
||||
if (_tab_is_down) {
|
||||
#endif
|
||||
if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
|
||||
} else if (_fast_forward & 2) {
|
||||
_fast_forward = 0;
|
||||
}
|
||||
|
||||
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
|
||||
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
|
||||
}
|
||||
|
||||
/** Main game loop. */
|
||||
void VideoDriver_Cocoa::GameLoop()
|
||||
{
|
||||
auto cur_ticks = std::chrono::steady_clock::now();
|
||||
auto last_realtime_tick = cur_ticks;
|
||||
auto next_game_tick = cur_ticks;
|
||||
auto next_draw_tick = cur_ticks;
|
||||
|
||||
for (;;) {
|
||||
@autoreleasepool {
|
||||
|
||||
@@ -653,69 +658,10 @@ void VideoDriver_Cocoa::GameLoop()
|
||||
break;
|
||||
}
|
||||
|
||||
NSUInteger cur_mods = [ NSEvent modifierFlags ];
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (cur_mods & NSShiftKeyMask) {
|
||||
#else
|
||||
if (_tab_is_down) {
|
||||
#endif
|
||||
if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
|
||||
} else if (_fast_forward & 2) {
|
||||
_fast_forward = 0;
|
||||
}
|
||||
|
||||
cur_ticks = std::chrono::steady_clock::now();
|
||||
|
||||
/* If more than a millisecond has passed, increase the _realtime_tick. */
|
||||
if (cur_ticks - last_realtime_tick > std::chrono::milliseconds(1)) {
|
||||
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(cur_ticks - last_realtime_tick);
|
||||
IncreaseRealtimeTick(delta.count());
|
||||
last_realtime_tick += delta;
|
||||
}
|
||||
|
||||
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
|
||||
if (_fast_forward && !_pause_mode) {
|
||||
next_game_tick = cur_ticks + this->GetGameInterval();
|
||||
} else {
|
||||
next_game_tick += this->GetGameInterval();
|
||||
/* Avoid next_game_tick getting behind more and more if it cannot keep up. */
|
||||
if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks;
|
||||
}
|
||||
|
||||
::GameLoop();
|
||||
}
|
||||
|
||||
/* Prevent drawing when switching mode, as windows can be removed when they should still appear. */
|
||||
if (cur_ticks >= next_draw_tick && (_switch_mode == SM_NONE || HasModalProgress())) {
|
||||
next_draw_tick += this->GetDrawInterval();
|
||||
/* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
|
||||
if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) next_draw_tick = cur_ticks;
|
||||
|
||||
bool old_ctrl_pressed = _ctrl_pressed;
|
||||
|
||||
_ctrl_pressed = (cur_mods & ( _settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? NSControlKeyMask : NSCommandKeyMask)) != 0;
|
||||
_shift_pressed = (cur_mods & NSShiftKeyMask) != 0;
|
||||
|
||||
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
|
||||
|
||||
InputLoop();
|
||||
UpdateWindows();
|
||||
this->CheckPaletteAnim();
|
||||
|
||||
this->Draw();
|
||||
}
|
||||
|
||||
/* If we are not in fast-forward, create some time between calls to ease up CPU usage. */
|
||||
if (!_fast_forward || _pause_mode) {
|
||||
/* See how much time there is till we have to process the next event, and try to hit that as close as possible. */
|
||||
auto next_tick = std::min(next_draw_tick, next_game_tick);
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
|
||||
if (next_tick > now) {
|
||||
std::this_thread::sleep_for(next_tick - now);
|
||||
}
|
||||
if (this->Tick()) {
|
||||
this->Paint();
|
||||
}
|
||||
this->SleepTillNextTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -733,6 +679,7 @@ void VideoDriver_Cocoa::GameLoop()
|
||||
self.wantsLayer = YES;
|
||||
|
||||
self.layer.magnificationFilter = kCAFilterNearest;
|
||||
self.layer.opaque = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user