From 32778cdbb9482ba527014325e0c04d9a50c8e632 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Tue, 6 Oct 2020 06:28:51 +0200 Subject: [PATCH] Perfectly align all resolutions --- CMakeLists.txt | 3 +- Source/cursor.cpp | 32 +++++--- Source/diablo.cpp | 2 + Source/scrollrt.cpp | 84 ++++++++++++++------ Source/scrollrt.h | 6 ++ SourceT/scrollrt_test.cpp | 161 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 SourceT/scrollrt_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 98e200699..6c6b05696 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,7 +338,8 @@ if(RUN_TESTS) SourceT/drlg_l3_test.cpp SourceT/drlg_l4_test.cpp SourceT/effects_test.cpp - SourceT/file_util_test.cpp) + SourceT/file_util_test.cpp + SourceT/scrollrt_test.cpp) endif() add_executable(${BIN_TARGET} WIN32 MACOSX_BUNDLE ${devilutionx_SRCS}) diff --git a/Source/cursor.cpp b/Source/cursor.cpp index 3747f0277..ea45d189b 100644 --- a/Source/cursor.cpp +++ b/Source/cursor.cpp @@ -244,26 +244,32 @@ void CheckCursMove() sy -= fy; } + // Convert to tile grid + mx = ViewX; + my = ViewY; + TilesInView(&columns, &rows); + int lrow = rows - RowsCoveredByPanel(); - // When both columns and rows are even or odd vertical alignment must be done using a screen offset - if (zoomflag && (columns & 1) == (rows & 1)) { - sy -= TILE_HEIGHT / 2; + // Center player tile on screen + ShiftGrid(&mx, &my, -columns / 2, -lrow / 2); + + // Align grid + if ((columns & 1) == 0 && (lrow & 1) == 0) { + sy += TILE_HEIGHT / 2; + } else if (columns & 1 && lrow & 1) { + sx -= TILE_WIDTH / 2; + } else if (columns & 1 && (lrow & 1) == 0) { + my++; + } + + if (!zoomflag) { + sy -= TILE_HEIGHT / 4; } - // Convert to tile grid - mx = ViewX; - my = ViewY; tx = sx / TILE_WIDTH; ty = sy / TILE_HEIGHT; ShiftGrid(&mx, &my, tx, ty); - // Shift player row to one that can be centered with out pixel offset - if ((columns & 1) != 0) { - my++; - } - - // Center player tile on screen - ShiftGrid(&mx, &my, -columns / 2, -(rows - RowsCoveredByPanel()) / 4); // Shift position to match diamond grid aligment px = sx % TILE_WIDTH; diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 9bd483836..6d53647bc 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -237,6 +237,7 @@ void run_game_loop(unsigned int uMsg) void start_game(unsigned int uMsg) { zoomflag = TRUE; + CalcViewportGeometry(); cineflag = FALSE; InitCursor(); InitLightTable(); @@ -1179,6 +1180,7 @@ void PressChar(int vkey) case 'Z': case 'z': zoomflag = !zoomflag; + CalcViewportGeometry(); return; case 'S': case 's': diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index d943d11b6..135b01d66 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -930,7 +930,7 @@ int RowsCoveredByPanel() return 0; } - int rows = PANEL_HEIGHT / TILE_HEIGHT * 2; + int rows = PANEL_HEIGHT / TILE_HEIGHT; if (!zoomflag) { rows /= 2; } @@ -952,7 +952,7 @@ void CalcTileOffset(int *offsetX, int *offsetY) y = VIEWPORT_HEIGHT % TILE_HEIGHT; } else { x = (SCREEN_WIDTH / 2) % TILE_WIDTH; - y = (VIEWPORT_HEIGHT / 2 + TILE_HEIGHT / 2) % TILE_HEIGHT; + y = (VIEWPORT_HEIGHT / 2) % TILE_HEIGHT; } if (x) @@ -975,8 +975,8 @@ void TilesInView(int *rcolumns, int *rrows) if (SCREEN_WIDTH % TILE_WIDTH) { columns++; } - int rows = VIEWPORT_HEIGHT / (TILE_HEIGHT / 2); - if (VIEWPORT_HEIGHT % (TILE_HEIGHT / 2)) { + int rows = VIEWPORT_HEIGHT / TILE_HEIGHT; + if (VIEWPORT_HEIGHT % TILE_HEIGHT) { rows++; } @@ -991,12 +991,62 @@ void TilesInView(int *rcolumns, int *rrows) } rows /= 2; } - rows++; // Cover lower edge saw tooth, right edge accounted for in scrollrt_draw() *rcolumns = columns; *rrows = rows; } +int tileOffsetX; +int tileOffsetY; +int tileShiftX; +int tileShiftY; +int tileColums; +int tileRows; + +void CalcViewportGeometry() +{ + int xo, yo; + tileShiftX = 0; + tileShiftY = 0; + + // Adjust by player offset and tile grid alignment + CalcTileOffset(&xo, &yo); + tileOffsetX = 0 - xo; + tileOffsetY = 0 - yo - 1 + TILE_HEIGHT / 2; + + TilesInView(&tileColums, &tileRows); + int lrow = tileRows - RowsCoveredByPanel(); + + // Center player tile on screen + ShiftGrid(&tileShiftX, &tileShiftY, -tileColums / 2, -lrow / 2); + + tileRows *= 2; + + // Align grid + if ((tileColums & 1) == 0) { + tileShiftY--; // Shift player row to one that can be centered with out pixel offset + if ((lrow & 1) == 0) { + // Offset tile to vertically align the player when both rows and colums are even + tileRows++; + tileOffsetY -= TILE_HEIGHT / 2; + } + } else if (tileColums & 1 && lrow & 1) { + // Offset tile to vertically align the player when both rows and colums are odd + ShiftGrid(&tileShiftX, &tileShiftY, 0, -1); + tileRows++; + tileOffsetY -= TILE_HEIGHT / 2; + } + + // Slightly lower the zoomed view + if (!zoomflag) { + tileOffsetY += TILE_HEIGHT / 4; + if (yo < TILE_HEIGHT / 4) + tileRows++; + } + + tileRows++; // Cover lower edge saw tooth, right edge accounted for in scrollrt_draw() +} + /** * @brief Configure render and process screen rows * @param x Center of view in dPiece coordinate @@ -1004,7 +1054,7 @@ void TilesInView(int *rcolumns, int *rrows) */ static void DrawGame(int x, int y) { - int i, sx, sy, columns, rows, xo, yo; + int sx, sy, columns, rows; // Limit rendering to the view area if (zoomflag) @@ -1013,24 +1063,14 @@ static void DrawGame(int x, int y) gpBufEnd = &gpBuffer[BUFFER_WIDTH * (VIEWPORT_HEIGHT / 2 + SCREEN_Y)]; // Adjust by player offset and tile grid alignment - CalcTileOffset(&xo, &yo); - sx = ScrollInfo._sxoff - xo + SCREEN_X; - sy = ScrollInfo._syoff - yo + SCREEN_Y + (TILE_HEIGHT / 2 - 1); + sx = ScrollInfo._sxoff + tileOffsetX + SCREEN_X; + sy = ScrollInfo._syoff + tileOffsetY + SCREEN_Y; - // Center player tile on screen - TilesInView(&columns, &rows); - // Shift player row to one that can be centered with out pixel offset - if ((columns & 1) == 0) { - y--; - } - ShiftGrid(&x, &y, -columns / 2, -(rows - RowsCoveredByPanel()) / 4); + columns = tileColums; + rows = tileRows; - // When both columns and rows are even or odd vertical alignment must be done using a screen offset - if (zoomflag && (columns & 1) == (rows & 1)) { - ShiftGrid(&x, &y, 0, -1); - rows += 2; - sy -= TILE_HEIGHT / 2; - } + x += tileShiftX; + y += tileShiftY; // Skip rendering parts covered by the panels if (PANELS_COVER) { diff --git a/Source/scrollrt.h b/Source/scrollrt.h index 5052e6830..ff7f07583 100644 --- a/Source/scrollrt.h +++ b/Source/scrollrt.h @@ -23,6 +23,11 @@ extern int cel_foliage_active; extern int level_piece_id; extern void (*DrawPlrProc)(int, int, int, int, int, BYTE *, int, int, int, int); +extern int tileOffsetX; +extern int tileOffsetY; +extern int tileShiftX; +extern int tileShiftY; + void ClearCursor(); void DrawMissile(int x, int y, int sx, int sy, BOOL pre); void DrawDeadPlayer(int x, int y, int sx, int sy); @@ -30,6 +35,7 @@ void ShiftGrid(int *x, int *y, int horizontal, int vertical); int RowsCoveredByPanel(); void CalcTileOffset(int *offsetX, int *offsetY); void TilesInView(int *columns, int *rows); +void CalcViewportGeometry(); void DrawView(int StartX, int StartY); void ClearScreenBuffer(); #ifdef _DEBUG diff --git a/SourceT/scrollrt_test.cpp b/SourceT/scrollrt_test.cpp new file mode 100644 index 000000000..cf3914a91 --- /dev/null +++ b/SourceT/scrollrt_test.cpp @@ -0,0 +1,161 @@ +#include +#include "all.h" +#include "ui_fwd.h" + +// TilesInView + +TEST(Scrool_rt, calc_tiles_in_view_original) +{ + dvl::screenWidth = 640; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight - 128; + dvl::zoomflag = true; + int columns = 0; + int rows = 0; + dvl::TilesInView(&columns, &rows); + EXPECT_EQ(columns, 10); + EXPECT_EQ(rows, 11); +} + +TEST(Scrool_rt, calc_tiles_in_view_original_zoom) +{ + dvl::screenWidth = 640; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight - 128; + dvl::zoomflag = false; + int columns = 0; + int rows = 0; + dvl::TilesInView(&columns, &rows); + EXPECT_EQ(columns, 5); + EXPECT_EQ(rows, 6); +} + +TEST(Scrool_rt, calc_tiles_in_view_960_540) +{ + dvl::screenWidth = 960; + dvl::screenHeight = 540; + dvl::viewportHeight = dvl::screenHeight; + dvl::zoomflag = true; + int columns = 0; + int rows = 0; + dvl::TilesInView(&columns, &rows); + EXPECT_EQ(columns, 15); + EXPECT_EQ(rows, 17); +} + +TEST(Scrool_rt, calc_tiles_in_view_640_512) +{ + dvl::screenWidth = 640; + dvl::screenHeight = 512; + dvl::viewportHeight = dvl::screenHeight - 128; + dvl::zoomflag = true; + int columns = 0; + int rows = 0; + dvl::TilesInView(&columns, &rows); + EXPECT_EQ(columns, 10); + EXPECT_EQ(rows, 12); +} + + +TEST(Scrool_rt, calc_tiles_in_view_768_480_zoom) +{ + dvl::screenWidth = 768; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight; + dvl::zoomflag = false; + int columns = 0; + int rows = 0; + dvl::TilesInView(&columns, &rows); + EXPECT_EQ(columns, 6); + EXPECT_EQ(rows, 8); +} + +// CalcTileOffset + +TEST(Scrool_rt, calc_tile_offset_original) +{ + dvl::screenWidth = 640; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight - 128; + dvl::zoomflag = true; + int x = 0; + int y = 0; + dvl::CalcTileOffset(&x, &y); + EXPECT_EQ(x, 0); + EXPECT_EQ(y, 0); +} + +TEST(Scrool_rt, calc_tile_offset_original_zoom) +{ + dvl::screenWidth = 640; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight - 128; + dvl::zoomflag = false; + int x = 0; + int y = 0; + dvl::CalcTileOffset(&x, &y); + EXPECT_EQ(x, 0); + EXPECT_EQ(y, 8); +} + +TEST(Scrool_rt, calc_tile_offset_960_540) +{ + dvl::screenWidth = 960; + dvl::screenHeight = 540; + dvl::viewportHeight = dvl::screenHeight; + dvl::zoomflag = true; + int x = 0; + int y = 0; + dvl::CalcTileOffset(&x, &y); + EXPECT_EQ(x, 0); + EXPECT_EQ(y, 2); +} + +TEST(Scrool_rt, calc_tile_offset_853_480) +{ + dvl::screenWidth = 853; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight; + dvl::zoomflag = true; + int x = 0; + int y = 0; + dvl::CalcTileOffset(&x, &y); + EXPECT_EQ(x, 21); + EXPECT_EQ(y, 0); +} + +TEST(Scrool_rt, calc_tile_offset_768_480_zoom) +{ + dvl::screenWidth = 768; + dvl::screenHeight = 480; + dvl::viewportHeight = dvl::screenHeight; + dvl::zoomflag = false; + int x = 0; + int y = 0; + dvl::CalcTileOffset(&x, &y); + EXPECT_EQ(x, 0); + EXPECT_EQ(y, 8); +} + +// RowsCoveredByPanel + +TEST(Scrool_rt, calc_tiles_covered_by_panel_original) +{ + dvl::screenWidth = 640; + dvl::zoomflag = true; + EXPECT_EQ(dvl::RowsCoveredByPanel(), 0); +} + +TEST(Scrool_rt, calc_tiles_covered_by_panel_960) +{ + dvl::screenWidth = 960; + dvl::zoomflag = true; + EXPECT_EQ(dvl::RowsCoveredByPanel(), 4); +} + +TEST(Scrool_rt, calc_tiles_covered_by_panel_960_zoom) +{ + dvl::screenWidth = 960; + dvl::zoomflag = false; + EXPECT_EQ(dvl::RowsCoveredByPanel(), 2); +}