Browse Source

Width independant vertical alignment, optimize zoom

pull/736/head
Anders Jenbo 7 years ago
parent
commit
9acbcc69f9
  1. 48
      Source/cursor.cpp
  2. 343
      Source/scrollrt.cpp
  3. 4
      Source/scrollrt.h
  4. 3
      defs.h

48
Source/cursor.cpp

@ -183,7 +183,7 @@ void CheckRportal()
void CheckCursMove()
{
int i, sx, sy, fx, fy, mx, my, tx, ty, px, py, xx, yy, mi;
int i, sx, sy, fx, fy, mx, my, tx, ty, px, py, xx, yy, mi, columns, rows, xo, yo;
char bv;
BOOL flipflag, flipx, flipy;
@ -205,19 +205,19 @@ void CheckCursMove()
}
}
}
if (sy > PANEL_TOP - 1 && track_isscrolling()) {
if (sy > PANEL_TOP - 1 && MouseX >= PANEL_LEFT && MouseX < PANEL_LEFT + PANEL_WIDTH && track_isscrolling()) {
sy = PANEL_TOP - 1;
}
sx -= (SCREEN_WIDTH % 64) / 2;
sy -= (VIEWPORT_HEIGHT % 32) / 2;
if (!zoomflag) {
sx >>= 1;
sy >>= 1;
}
// Adjust by player offset
sx -= ScrollInfo._sxoff;
sy -= ScrollInfo._syoff;
// Adjust by player offset and tile grid alignment
CalcTileOffset(&xo, &yo);
sx -= ScrollInfo._sxoff - xo;
sy -= ScrollInfo._syoff - yo;
// Predict the next frame when walking to avoid input jitter
fx = plr[myplr]._pVar6 / 256;
@ -229,29 +229,23 @@ void CheckCursMove()
sy -= fy;
}
if (sx < 0) {
sx = 0;
}
if (sx >= SCREEN_WIDTH) {
sx = SCREEN_WIDTH;
}
if (sy < 0) {
sy = 0;
}
if (sy >= SCREEN_HEIGHT) {
sy = SCREEN_HEIGHT;
}
// Convert to tile grid
tx = sx >> 6; // sx / TILE_WIDTH
ty = sy >> 5; // sy / TILE_HEIGHT
px = sx & (TILE_WIDTH - 1);
py = sy & (TILE_HEIGHT - 1);
mx = ViewX;
my = ViewY;
tx = sx / TILE_WIDTH;
ty = sy / TILE_HEIGHT;
ShiftGrid(&mx, &my, tx, ty);
// Center player tile on screen
mx = ViewX + tx + ty - (zoomflag ? (SCREEN_WIDTH / TILE_WIDTH) : (SCREEN_WIDTH / 2 / TILE_WIDTH));
my = ViewY + ty - tx;
TilesInView(&columns, &rows);
ShiftGrid(&mx, &my, -columns / 2, -(rows - RowsCoveredByPanel()) / 4);
if ((columns % 2) != 0) {
my++;
}
// Shift position to match diamond grid aligment
px = sx % TILE_WIDTH;
py = sy % TILE_HEIGHT;
// Shift position to match diamond grid aligment
flipy = py < (px >> 1);

343
Source/scrollrt.cpp

@ -767,15 +767,15 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy)
* @param y dPiece coordinate
* @param sx Back buffer coordinate
* @param sy Back buffer coordinate
* @param blocks Number of rows
* @param chunks Tile in a row
* @param rows Number of rows
* @param columns Tile in a row
*/
static void scrollrt_drawFloor(int x, int y, int sx, int sy, int blocks, int chunks)
static void scrollrt_drawFloor(int x, int y, int sx, int sy, int rows, int columns)
{
assert(gpBuffer);
for (int i = 0; i < (blocks << 1); i++) {
for (int j = 0; j < chunks ; j++) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (x >= 0 && x < MAXDUNX && y >= 0 && y < MAXDUNY) {
level_piece_id = dPiece[x][y];
if (level_piece_id != 0) {
@ -787,24 +787,22 @@ static void scrollrt_drawFloor(int x, int y, int sx, int sy, int blocks, int chu
} else {
world_draw_black_tile(sx, sy);
}
x++;
y--;
ShiftGrid(&x, &y, 1, 0);
sx += TILE_WIDTH;
}
// Return to start of row
x -= chunks;
y += chunks;
sx -= chunks * TILE_WIDTH;
sy += TILE_HEIGHT / 2;
ShiftGrid(&x, &y, -columns, 0);
sx -= columns * TILE_WIDTH;
// Jump to next row
sy += TILE_HEIGHT / 2;
if (i & 1) {
x++;
chunks--;
columns--;
sx += TILE_WIDTH / 2;
} else {
y++;
chunks++;
columns++;
sx -= TILE_WIDTH / 2;
}
}
@ -819,15 +817,19 @@ static void scrollrt_drawFloor(int x, int y, int sx, int sy, int blocks, int chu
* @param y dPiece coordinate
* @param sx Back buffer coordinate
* @param sy Back buffer coordinate
* @param blocks Number of rows
* @param chunks Tile in a row
* @param rows Number of rows
* @param columns Tile in a row
*/
static void scrollrt_draw(int x, int y, int sx, int sy, int blocks, int chunks)
static void scrollrt_draw(int x, int y, int sx, int sy, int rows, int columns)
{
assert(gpBuffer);
for (int i = 0; i < (blocks << 1); i++) {
for (int j = 0; j < chunks ; j++) {
// Keep evaluating until MicroTiles can't affect screen
rows += MicroTileLen;
memset(dRendered, 0, sizeof(dRendered));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns ; j++) {
if (x >= 0 && x < MAXDUNX && y >= 0 && y < MAXDUNY) {
if (x + 1 < MAXDUNX && y - 1 >= 0 && sx + TILE_WIDTH <= SCREEN_X + SCREEN_WIDTH) {
// Render objects behind walls first to prevent sprites, that are moving
@ -844,171 +846,255 @@ static void scrollrt_draw(int x, int y, int sx, int sy, int blocks, int chunks)
scrollrt_draw_dungeon(x, y, sx, sy);
}
}
x++;
y--;
ShiftGrid(&x, &y, 1, 0);
sx += TILE_WIDTH;
}
// Return to start of row
x -= chunks;
y += chunks;
sx -= chunks * TILE_WIDTH;
sy += TILE_HEIGHT / 2;
ShiftGrid(&x, &y, -columns, 0);
sx -= columns * TILE_WIDTH;
// Jump to next row
sy += TILE_HEIGHT / 2;
if (i & 1) {
x++;
chunks--;
columns--;
sx += TILE_WIDTH / 2;
} else {
y++;
chunks++;
columns++;
sx -= TILE_WIDTH / 2;
}
}
}
/**
* @brief Configure render and process screen rows
* @param x Center of view in dPiece coordinate
* @param y Center of view in dPiece coordinate
* @brief Scale up the rendered part of the back buffer to take up the full view
*/
static void DrawGame(int x, int y)
static void Zoom()
{
int i, sx, sy, chunks, blocks;
int wdt, nSrcOff, nDstOff;
int wdt = SCREEN_WIDTH / 2;
int nSrcOff = SCREENXY(SCREEN_WIDTH / 2 - 1, VIEWPORT_HEIGHT / 2 - 1);
int nDstOff = SCREENXY(SCREEN_WIDTH - 1, VIEWPORT_HEIGHT - 1);
if (PANELS_COVER) {
if (chrflag || questlog) {
wdt >>= 1;
nSrcOff -= wdt;
} else if (invflag || sbookflag) {
wdt >>= 1;
nSrcOff -= wdt;
nDstOff -= SPANEL_WIDTH;
}
}
sx = (SCREEN_WIDTH % TILE_WIDTH) / 2;
sy = (VIEWPORT_HEIGHT % TILE_HEIGHT) / 2;
BYTE *src = &gpBuffer[nSrcOff];
BYTE *dst = &gpBuffer[nDstOff];
if (zoomflag) {
chunks = ceil(SCREEN_WIDTH / TILE_WIDTH);
blocks = ceil(VIEWPORT_HEIGHT / TILE_HEIGHT);
for (int hgt = 0; hgt < VIEWPORT_HEIGHT / 2; hgt++) {
for (int i = 0; i < wdt; i++) {
*dst-- = *src;
*dst-- = *src;
src--;
}
memcpy(dst - BUFFER_WIDTH, dst, wdt * 2 + 1);
src -= BUFFER_WIDTH - wdt;
dst -= 2 * (BUFFER_WIDTH - wdt);
}
}
gpBufStart = &gpBuffer[BUFFER_WIDTH * SCREEN_Y];
gpBufEnd = &gpBuffer[BUFFER_WIDTH * (VIEWPORT_HEIGHT + SCREEN_Y)];
/**
* @brief Shifting the view area along the logical grid
* Note: this won't allow you to shift between even and odd rows
* @param horizontal Shift the screen left or right
* @param vertical Shift the screen up or down
*/
void ShiftGrid(int *x, int *y, int horizontal, int vertical)
{
*x += vertical + horizontal;
*y += vertical - horizontal;
}
/**
* @brief Gets the number of rows covered by the main panel
*/
int RowsCoveredByPanel()
{
if (SCREEN_WIDTH <= PANEL_WIDTH) {
return 0;
}
int rows = PANEL_HEIGHT / TILE_HEIGHT * 2;
if (!zoomflag) {
rows /= 2;
}
return rows;
}
/**
* @brief Calculate the offset needed for centering tiles in view area
* @param offsetX Offset in pixels
* @param offsetY Offset in pixels
*/
void CalcTileOffset(int *offsetX, int *offsetY)
{
int x, y;
if (zoomflag) {
x = SCREEN_WIDTH % TILE_WIDTH;
y = VIEWPORT_HEIGHT % TILE_HEIGHT;
} else {
sy -= TILE_HEIGHT;
x = (SCREEN_WIDTH / 2) % TILE_WIDTH;
y = (VIEWPORT_HEIGHT / 2 + TILE_HEIGHT / 2) % TILE_HEIGHT;
}
if (x)
x = (TILE_WIDTH - x) / 2;
if (y)
y = (TILE_HEIGHT - y) / 2;
chunks = ceil(SCREEN_WIDTH / 2 / TILE_WIDTH) + 1; // TODO why +1?
blocks = ceil(VIEWPORT_HEIGHT / 2 / TILE_HEIGHT);
*offsetX = x;
*offsetY = y;
}
/**
* @brief Calculate the needed diamond tile to cover the view area
* @param columns Tiles needed per row
* @param rows Both even and odd rows
*/
void TilesInView(int *rcolumns, int *rrows)
{
int columns = SCREEN_WIDTH / TILE_WIDTH;
if (SCREEN_WIDTH % TILE_WIDTH) {
columns++;
}
int rows = VIEWPORT_HEIGHT / (TILE_HEIGHT / 2);
if (VIEWPORT_HEIGHT % (TILE_HEIGHT / 2)) {
rows++;
}
gpBufStart = &gpBuffer[(-(TILE_HEIGHT / 2 + 1) + SCREEN_Y) * BUFFER_WIDTH];
gpBufEnd = &gpBuffer[((VIEWPORT_HEIGHT - TILE_HEIGHT) / 2 + SCREEN_Y) * BUFFER_WIDTH];
if (!zoomflag) {
// Half the number of tiles, rounded up
if (columns % 2) {
columns++;
}
columns /= 2;
if (rows % 2) {
rows++;
}
rows /= 2;
}
rows++; // Cover lower edge saw tooth, right edge accounted for in scrollrt_draw()
*rcolumns = columns;
*rrows = rows;
}
sx += ScrollInfo._sxoff + SCREEN_X;
sy += ScrollInfo._syoff + SCREEN_Y + TILE_HEIGHT / 2 - 1;
/**
* @brief Configure render and process screen rows
* @param x Center of view in dPiece coordinate
* @param y Center of view in dPiece coordinate
*/
static void DrawGame(int x, int y)
{
int i, sx, sy, columns, rows, xo, yo;
// Limit rendering to the view area
if (zoomflag)
gpBufEnd = &gpBuffer[BUFFER_WIDTH * (VIEWPORT_HEIGHT + SCREEN_Y)];
else
gpBufEnd = &gpBuffer[BUFFER_WIDTH * (VIEWPORT_HEIGHT / 2 + SCREEN_Y)];
// Center screen
x -= chunks;
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);
// Keep evaulating untill MicroTiles can't affect screen
blocks += ceil((double)MicroTileLen / 2);
// Center player tile on screen
TilesInView(&columns, &rows);
ShiftGrid(&x, &y, -columns / 2, -(rows - RowsCoveredByPanel()) / 4);
if ((columns % 2) == 0) {
y--;
}
// Skip rendering parts covered by the panels
if (PANELS_COVER) {
if (zoomflag) {
if (chrflag || questlog) {
x += 2;
y -= 2;
ShiftGrid(&x, &y, 2, 0);
columns -= 4;
sx += SPANEL_WIDTH - TILE_WIDTH / 2;
chunks -= 4;
}
if (invflag || sbookflag) {
x += 2;
y -= 2;
sx -= TILE_WIDTH / 2;
chunks -= 4;
ShiftGrid(&x, &y, 2, 0);
columns -= 4;
sx += -TILE_WIDTH / 2;
}
} else {
if (chrflag || questlog) {
ShiftGrid(&x, &y, 1, 0);
columns -= 2;
sx += -TILE_WIDTH / 2 / 2; // SPANEL_WIDTH accounted for in Zoom()
}
if (invflag || sbookflag) {
ShiftGrid(&x, &y, 1, 0);
columns -= 2;
sx += -TILE_WIDTH / 2 / 2;
}
}
}
switch (ScrollInfo._sdir) {
// Draw areas moving in and out of the screen
switch (ScrollInfo._sdir) {
case SDIR_N:
sy -= TILE_HEIGHT;
x--;
y--;
blocks++;
ShiftGrid(&x, &y, 0, -1);
rows += 2;
break;
case SDIR_NE:
sy -= TILE_HEIGHT;
x--;
y--;
chunks++;
blocks++;
ShiftGrid(&x, &y, 0, -1);
columns++;
rows += 2;
break;
case SDIR_E:
chunks++;
columns++;
break;
case SDIR_SE:
chunks++;
blocks++;
columns++;
rows++;
break;
case SDIR_S:
blocks++;
rows += 2;
break;
case SDIR_SW:
sx -= TILE_WIDTH;
x--;
y++;
chunks++;
blocks++;
ShiftGrid(&x, &y, -1, 0);
columns++;
rows++;
break;
case SDIR_W:
sx -= TILE_WIDTH;
x--;
y++;
chunks++;
ShiftGrid(&x, &y, -1, 0);
columns++;
break;
case SDIR_NW:
sx -= TILE_WIDTH;
sy -= TILE_HEIGHT;
x -= 2;
chunks++;
blocks++;
sx -= TILE_WIDTH / 2;
sy -= TILE_HEIGHT / 2;
x--;
columns++;
rows++;
break;
}
memset(dRendered, 0, sizeof(dRendered));
scrollrt_drawFloor(x, y, sx, sy, blocks, chunks);
scrollrt_draw(x, y, sx, sy, blocks, chunks);
scrollrt_drawFloor(x, y, sx, sy, rows, columns);
scrollrt_draw(x, y, sx, sy, rows, columns);
gpBufStart = &gpBuffer[BUFFER_WIDTH * SCREEN_Y];
// Allow rendering to the whole screen
gpBufEnd = &gpBuffer[BUFFER_WIDTH * (SCREEN_HEIGHT + SCREEN_Y)];
if (zoomflag)
return;
nSrcOff = SCREENXY(TILE_WIDTH / 2, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1));
nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2);
wdt = SCREEN_WIDTH / 2;
if (PANELS_COVER) {
if (chrflag || questlog) {
nSrcOff = SCREENXY(TILE_WIDTH / 2 + SPANEL_WIDTH / 4, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1));
nDstOff = SCREENXY(SPANEL_WIDTH, VIEWPORT_HEIGHT - 2);
wdt = (SCREEN_WIDTH - SPANEL_WIDTH) / 2;
} else if (invflag || sbookflag) {
nSrcOff = SCREENXY(TILE_WIDTH / 2 + SPANEL_WIDTH / 4, VIEWPORT_HEIGHT / 2 - (TILE_HEIGHT / 2 + 1));
nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2);
wdt = (SCREEN_WIDTH - SPANEL_WIDTH) / 2;
}
}
int hgt;
BYTE *src, *dst1, *dst2;
src = &gpBuffer[nSrcOff];
dst1 = &gpBuffer[nDstOff];
dst2 = &gpBuffer[nDstOff + BUFFER_WIDTH];
for (hgt = VIEWPORT_HEIGHT / 2; hgt != 0; hgt--, src -= BUFFER_WIDTH + wdt, dst1 -= 2 * (BUFFER_WIDTH + wdt), dst2 -= 2 * (BUFFER_WIDTH + wdt)) {
for (i = wdt; i != 0; i--) {
*dst1++ = *src;
*dst1++ = *src;
*dst2++ = *src;
*dst2++ = *src;
src++;
}
if (!zoomflag) {
Zoom();
}
}
@ -1078,6 +1164,8 @@ void DrawView(int StartX, int StartY)
DrawManaFlask();
}
extern SDL_Surface *pal_surface;
/**
* @brief Render the whole screen black
*/
@ -1085,16 +1173,15 @@ void ClearScreenBuffer()
{
lock_buf(3);
assert(gpBuffer);
assert(pal_surface != NULL);
int i;
BYTE *dst;
dst = &gpBuffer[SCREENXY(0, 0)];
for (i = 0; i < SCREEN_HEIGHT; i++, dst += BUFFER_WIDTH) {
memset(dst, 0, SCREEN_WIDTH);
}
SDL_Rect SrcRect = {
SCREEN_X,
SCREEN_Y,
SCREEN_WIDTH,
SCREEN_HEIGHT,
};
SDL_FillRect(pal_surface, &SrcRect, 0);
unlock_buf(3);
}

4
Source/scrollrt.h

@ -22,6 +22,10 @@ extern void (*DrawPlrProc)(int, int, int, int, int, BYTE *, int, int, int, int);
void ClearCursor();
void DrawMissile(int x, int y, int sx, int sy, BOOL pre);
void DrawDeadPlayer(int x, int y, int sx, int sy);
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 DrawView(int StartX, int StartY);
void ClearScreenBuffer();
#ifdef _DEBUG

3
defs.h

@ -111,9 +111,6 @@
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define ZOOM_WIDTH (SCREEN_WIDTH / 2 + TILE_WIDTH)
#define ZOOM_HEIGHT (VIEWPORT_HEIGHT / 2 + TILE_HEIGHT + TILE_HEIGHT / 2)
// If defined, use 32-bit colors instead of 8-bit [Default -> Undefined]
//#define RGBMODE

Loading…
Cancel
Save