Merge branch 'master' into enhanced_viewport_overlay
Notes on conflict resolution: * MarkTileDirtyByTile gained an extra param on both sides of the merge Move bridge level offset to be after zoom level param, as it's used less. * Add zoom level params to MarkBridgeDirty functions * Fix undefined behaviour in colour_index cycling in ViewportMapDraw Conflicts: src/clear_cmd.cpp src/pbs.cpp src/rail_cmd.cpp src/toolbar_gui.cpp src/train_cmd.cpp src/vehicle.cpp src/viewport.cpp src/viewport_func.h
This commit is contained in:
96
src/gfx.cpp
96
src/gfx.cpp
@@ -23,6 +23,7 @@
|
||||
#include "newgrf_debug.h"
|
||||
|
||||
#include "table/palettes.h"
|
||||
#include "table/string_colours.h"
|
||||
#include "table/sprites.h"
|
||||
#include "table/control_codes.h"
|
||||
|
||||
@@ -175,40 +176,35 @@ static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int
|
||||
|
||||
assert(width > 0);
|
||||
|
||||
if (y2 == y) {
|
||||
/* Special case: horizontal line. */
|
||||
blitter->DrawLine(video,
|
||||
Clamp(x, 0, screen_width), y,
|
||||
Clamp(x2, 0, screen_width), y2,
|
||||
screen_width, screen_height, colour, width, dash);
|
||||
return;
|
||||
}
|
||||
if (x2 == x) {
|
||||
/* Special case: vertical line. */
|
||||
blitter->DrawLine(video,
|
||||
x, Clamp(y, 0, screen_height),
|
||||
x2, Clamp(y2, 0, screen_height),
|
||||
screen_width, screen_height, colour, width, dash);
|
||||
if (y2 == y || x2 == x) {
|
||||
/* Special case: horizontal/vertical line. All checks already done in GfxPreprocessLine. */
|
||||
blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash);
|
||||
return;
|
||||
}
|
||||
|
||||
int grade_y = y2 - y;
|
||||
int grade_x = x2 - x;
|
||||
|
||||
/* Clipping rectangle. Slightly extended so we can ignore the width of the line. */
|
||||
uint extra = CeilDiv(3 * width, 4); // not less then "width * sqrt(2) / 2"
|
||||
Rect clip = { -extra, -extra, screen_width - 1 + extra, screen_height - 1 + extra };
|
||||
|
||||
/* prevent integer overflows. */
|
||||
int margin = 1;
|
||||
while (INT_MAX / abs(grade_y) < max(abs(x), abs(screen_width - x))) {
|
||||
while (INT_MAX / abs(grade_y) < max(abs(clip.left - x), abs(clip.right - x))) {
|
||||
grade_y /= 2;
|
||||
grade_x /= 2;
|
||||
margin *= 2; // account for rounding errors
|
||||
}
|
||||
|
||||
/* If the line is outside the screen on the same side at X positions 0
|
||||
* and screen_width, we don't need to draw anything. */
|
||||
int offset_0 = y - x * grade_y / grade_x;
|
||||
int offset_width = y + (screen_width - x) * grade_y / grade_x;
|
||||
if ((offset_0 > screen_height + width / 2 + margin && offset_width > screen_height + width / 2 + margin) ||
|
||||
(offset_0 < -width / 2 - margin && offset_width < -width / 2 - margin)) {
|
||||
/* Imagine that the line is infinitely long and it intersects with
|
||||
* infinitely long left and right edges of the clipping rectangle.
|
||||
* If both intersection points are outside the clipping rectangle
|
||||
* and both on the same side of it, we don't need to draw anything. */
|
||||
int left_isec_y = y + (clip.left - x) * grade_y / grade_x;
|
||||
int right_isec_y = y + (clip.right - x) * grade_y / grade_x;
|
||||
if ((left_isec_y > clip.bottom + margin && right_isec_y > clip.bottom + margin) ||
|
||||
(left_isec_y < clip.top - margin && right_isec_y < clip.top - margin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1535,10 +1531,10 @@ void UpdateCursorSize()
|
||||
CursorVars *cv = &_cursor;
|
||||
const Sprite *p = GetSprite(GB(cv->sprite, 0, SPRITE_WIDTH), ST_NORMAL);
|
||||
|
||||
cv->size.y = UnScaleByZoom(p->height, ZOOM_LVL_GUI);
|
||||
cv->size.x = UnScaleByZoom(p->width, ZOOM_LVL_GUI);
|
||||
cv->offs.x = UnScaleByZoom(p->x_offs, ZOOM_LVL_GUI);
|
||||
cv->offs.y = UnScaleByZoom(p->y_offs, ZOOM_LVL_GUI);
|
||||
cv->size.y = UnScaleGUI(p->height);
|
||||
cv->size.x = UnScaleGUI(p->width);
|
||||
cv->offs.x = UnScaleGUI(p->x_offs);
|
||||
cv->offs.y = UnScaleGUI(p->y_offs);
|
||||
|
||||
cv->dirty = true;
|
||||
}
|
||||
@@ -1606,6 +1602,56 @@ void SetAnimatedMouseCursor(const AnimCursor *table)
|
||||
SwitchAnimatedCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cursor position on mouse movement.
|
||||
* @param x New X position.
|
||||
* @param y New Y position.
|
||||
* @param queued True, if the OS queues mouse warps after pending mouse movement events.
|
||||
* False, if the warp applies instantaneous.
|
||||
* @return true, if the OS cursor position should be warped back to this->pos.
|
||||
*/
|
||||
bool CursorVars::UpdateCursorPosition(int x, int y, bool queued_warp)
|
||||
{
|
||||
/* Detecting relative mouse movement is somewhat tricky.
|
||||
* - There may be multiple mouse move events in the video driver queue (esp. when OpenTTD lags a bit).
|
||||
* - When we request warping the mouse position (return true), a mouse move event is appended at the end of the queue.
|
||||
*
|
||||
* So, when this->fix_at is active, we use the following strategy:
|
||||
* - The first movement triggers the warp to reset the mouse position.
|
||||
* - Subsequent events have to compute movement relative to the previous event.
|
||||
* - The relative movement is finished, when we receive the event matching the warp.
|
||||
*/
|
||||
|
||||
if (x == this->pos.x && y == this->pos.y) {
|
||||
/* Warp finished. */
|
||||
this->queued_warp = false;
|
||||
}
|
||||
|
||||
this->delta.x = x - (this->queued_warp ? this->last_position.x : this->pos.x);
|
||||
this->delta.y = y - (this->queued_warp ? this->last_position.y : this->pos.y);
|
||||
|
||||
this->last_position.x = x;
|
||||
this->last_position.y = y;
|
||||
|
||||
bool need_warp = false;
|
||||
if (this->fix_at) {
|
||||
if (this->delta.x != 0 || this->delta.y != 0) {
|
||||
/* Trigger warp.
|
||||
* Note: We also trigger warping again, if there is already a pending warp.
|
||||
* This makes it more tolerant about the OS or other software inbetween
|
||||
* botchering the warp. */
|
||||
this->queued_warp = queued_warp;
|
||||
need_warp = true;
|
||||
}
|
||||
} else if (this->pos.x != x || this->pos.y != y) {
|
||||
this->queued_warp = false; // Cancel warping, we are no longer confining the position.
|
||||
this->dirty = true;
|
||||
this->pos.x = x;
|
||||
this->pos.y = y;
|
||||
}
|
||||
return need_warp;
|
||||
}
|
||||
|
||||
bool ChangeResInGame(int width, int height)
|
||||
{
|
||||
return (_screen.width == width && _screen.height == height) || VideoDriver::GetInstance()->ChangeResolution(width, height);
|
||||
|
Reference in New Issue
Block a user