diff --git a/Classes/framewrk/sprite.cpp b/Classes/framewrk/sprite.cpp index 7cf9f86..87a0c20 100644 --- a/Classes/framewrk/sprite.cpp +++ b/Classes/framewrk/sprite.cpp @@ -1,5 +1,8 @@ #include "frm_int.hpp" #include + +/* Widescreen support */ +#include Cspr_frame::Cspr_frame(COMP_SPRITE *dc, UINT16 w, UINT16 h, INT16 hx, INT16 hy) { } diff --git a/Classes/framewrk/video.cpp b/Classes/framewrk/video.cpp index 50c7d3e..0b08c0f 100644 --- a/Classes/framewrk/video.cpp +++ b/Classes/framewrk/video.cpp @@ -209,8 +209,10 @@ void Cvideo::swap(void) if((g_RenderMode%NUMRENDERMODES)==0) // nearest neigbour { - for (unsigned int y = 0; y < 480; y++) { - for (unsigned int x = 0; x < (640>>5); x++) { + /* Widescreen support: Use dynamic width from this->width instead of hardcoded 640 */ + unsigned int pixelsPerRow = this->width; + for (unsigned int y = 0; y < this->height; y++) { + for (unsigned int x = 0; x < (pixelsPerRow>>5); x++) { // *DestBuf++ = m_DibPalette32[*SrcPtr++]; UNROLL32 } @@ -455,6 +457,8 @@ void Cvideo::DisplayChars(unsigned char *Cijfers, int x, int y) ScreenPtr = Screen; CharsetPtr = charset + (Cijfer*36); + /* Widescreen support: Use dynamic width instead of hardcoded 640 */ + unsigned int screenWidth = this->width; for(y=0;y<6;y++) { for(x=0;x<6;x++) @@ -462,14 +466,14 @@ void Cvideo::DisplayChars(unsigned char *Cijfers, int x, int y) *ScreenPtr++ = *CharsetPtr; *ScreenPtr++ = *CharsetPtr++; } - ScreenPtr += (640-12); + ScreenPtr += (screenWidth-12); CharsetPtr-=6; for(x=0;x<6;x++) { *ScreenPtr++ = *CharsetPtr; *ScreenPtr++ = *CharsetPtr++; } - ScreenPtr += (640-12); + ScreenPtr += (screenWidth-12); } Screen+= 14; Index--; diff --git a/Classes/moonchild/globals.cpp b/Classes/moonchild/globals.cpp index 325f35a..a8bde73 100644 --- a/Classes/moonchild/globals.cpp +++ b/Classes/moonchild/globals.cpp @@ -62,12 +62,19 @@ UINT32 blackdiamondlocations[13][7]; //7 per level... 13 levels UINT32 blackdiamondcollocations[13][7]; //7 per level... 13 levels -/* editor variables */ +/* Widescreen support - 16:9 aspect ratio */ +#define MC_BASE_WIDTH 640 +#define MC_BASE_HEIGHT 480 +/* Widescreen adds 224 pixels horizontally (640 + 224 = 864, which is 16:9 with 480 height) */ +#define MC_WIDESCREEN_PADDING 112 + +/* editor variables - now dynamically sized for widescreen */ UINT16 cliptlx = 0; UINT16 cliptly = 0; -UINT16 clipbrx = 640; -UINT16 clipbry = 480; +/* clipbrx/clipbry are now dynamically set based on game mode */ +UINT16 clipbrx = MC_BASE_WIDTH + (2 * MC_WIDESCREEN_PADDING); +UINT16 clipbry = MC_BASE_HEIGHT; UINT16 sokomoved; UINT16 editflg = 0; /* we don't start of in the editor */ @@ -380,7 +387,7 @@ PREFS defprefs = { // 300, // 400, - 0,0,640,480, + 0,0,640 + (2 * MC_WIDESCREEN_PADDING),480, // Extended for widescreen PREFS_HIRES, // 'J', @@ -409,6 +416,11 @@ PREFS defprefs = { // 'a', // 'd', // 's' + + // Widescreen support fields + MC_BASE_WIDTH, + MC_BASE_HEIGHT, + MC_WIDESCREEN_PADDING }; PREFS *prefs = &defprefs; diff --git a/Classes/moonchild/mc.cpp b/Classes/moonchild/mc.cpp index 882d331..c2ef706 100644 --- a/Classes/moonchild/mc.cpp +++ b/Classes/moonchild/mc.cpp @@ -96,6 +96,12 @@ int FirstTimeShowCredzFlg; #include #include +/* Widescreen support */ +#include + +/* Widescreen menu centering offset */ +#define MC_WIDESCREEN_MENU_OFFSET_X ((GAME_FRAMEBUFFER_WIDTH - GAME_FRAMEBUFFER_BASE_WIDTH) / 2) + //#include //#include #include @@ -835,9 +841,9 @@ HEARTBEAT_FN MC_testje1(void) video->palette(titlepal); - titlepic->draw_nokey(*vidblitbuf,0,0,0,0,640,480); + titlepic->draw_nokey(*vidblitbuf,MC_WIDESCREEN_MENU_OFFSET_X,0,0,0,640,480); video->swap(); - titlepic->draw_nokey(*vidblitbuf,0,0,0,0,640,480); + titlepic->draw_nokey(*vidblitbuf,MC_WIDESCREEN_MENU_OFFSET_X,0,0,0,640,480); return (HEARTBEAT_FN) MC_testje2; @@ -899,7 +905,7 @@ HEARTBEAT_FN framework_InitGame(Cvideo *newvideo, Caudio *newaudio, Ctimer *newt video->scansync(); vidblitbuf = new Cblitbuf(video); - vidblitbuf->set_clipping(0, 0, 640, 480); + vidblitbuf->set_clipping(0, 0, GAME_FRAMEBUFFER_WIDTH, GAME_FRAMEBUFFER_HEIGHT); @@ -7136,8 +7142,8 @@ HEARTBEAT_FN MC_menu(void) keytab[CB_BACK] = 0; if (menupoint == menu1) { - titlepic->draw_nokey(*refreshpic, 0, 0, 0, 0, 640, 480); - menuleavefunc = (HEARTBEAT_FN) MC_leavemenu; + titlepic->draw_nokey(*refreshpic, MC_WIDESCREEN_MENU_OFFSET_X, 0, 0, 0, 640, 480); + menuleavefunc = (HEARTBEAT_FN) MC_leavemenu; } if (menupoint == menu12 || menupoint == menu13) { diff --git a/Classes/moonchild/objects.cpp b/Classes/moonchild/objects.cpp index 93203c9..c7b90ae 100644 --- a/Classes/moonchild/objects.cpp +++ b/Classes/moonchild/objects.cpp @@ -1,6 +1,10 @@ #include #include #include +#include + +/* Widescreen support */ +#include static void object_process(int (*process)(VG_DLL_ITEM *)); @@ -218,15 +222,22 @@ int cb_object_visualise(VG_DLL_ITEM *item) x = obj->x - curplayer->worldx - curplayer->quakex; y = obj->y - curplayer->worldy - curplayer->quakey; -#if 0 - if (x > /*curplayer->worldx*/ + 630) return 0; - if (x < 0/*curplayer->worldx*/ ) return 0; - if (y > curplayer->curmap->mapsizey + 32) return 0; -#endif + /* Widescreen support: Extended culling bounds for 16:9 aspect ratio */ + /* Use prefs screenwidth for dynamic sizing - adds padding on each side */ + INT16 screen_width = prefs->screenwidth; + + /* New widescreen culling: Only cull objects that are completely off-screen */ + /* Allow objects down to -112 on the left edge to prevent "edge freeze" */ + INT16 widescreen_left_bound = -GAME_FRAMEBUFFER_WIDESCREEN_PADDING; + if (x > screen_width) return 0; // Culled if completely past right edge + if (x < widescreen_left_bound - 32) return 0; // Culled if completely past left edge (-144) + + /* Widescreen: Apply +112px camera offset to match tile rendering */ + INT16 widescreen_cam_offset = GAME_FRAMEBUFFER_WIDESCREEN_PADDING; // +112 if (obj->blitsizex && obj->blitsizey) { - if (obj->frame->draw(*curplayer->loadedmap->blitbuf,x , y, + if (obj->frame->draw(*curplayer->loadedmap->blitbuf, x + widescreen_cam_offset, y, obj->blitstartx, obj->blitstarty, obj->blitstartx+obj->blitsizex, obj->blitstarty+obj->blitsizey)) { @@ -239,7 +250,7 @@ int cb_object_visualise(VG_DLL_ITEM *item) } else /* no size override */ { - if ( obj->frame->draw(*curplayer->loadedmap->blitbuf,x , y )) + if ( obj->frame->draw(*curplayer->loadedmap->blitbuf, x + widescreen_cam_offset, y )) { if (obj->visible<1024) obj->visible++; } diff --git a/Classes/moonchild/prefs.hpp b/Classes/moonchild/prefs.hpp index 7086f0a..32b874d 100644 --- a/Classes/moonchild/prefs.hpp +++ b/Classes/moonchild/prefs.hpp @@ -10,6 +10,12 @@ void prefs_calcvals(void); #define PREFS_LORES 0 #define PREFS_HIRES 1 +/* Widescreen support - 16:9 aspect ratio */ +#define MC_BASE_WIDTH 640 +#define MC_BASE_HEIGHT 480 +/* Widescreen adds 224 pixels horizontally (640 + 224 = 864, which is 16:9 with 480 height) */ +#define MC_WIDESCREEN_PADDING 112 + struct PREFS { UINT16 screentopx; @@ -23,6 +29,11 @@ struct PREFS UINT16 downkey; UINT16 jumpkey; UINT16 shootkey; + + /* Widescreen support - these are computed from base + padding */ + UINT16 basewidth; + UINT16 baseheight; + UINT16 widescreenpadding; }; diff --git a/Classes/moonchild/score.cpp b/Classes/moonchild/score.cpp index 5ffee92..8d12ff4 100644 --- a/Classes/moonchild/score.cpp +++ b/Classes/moonchild/score.cpp @@ -7,6 +7,13 @@ #include #include #include +#include + +/* Widescreen support: HUD anchoring offset */ +/* Original 4:3: HUD at X=70 | Widescreen: shift to align with new left edge */ +#define MC_WIDESCREEN_HUD_OFFSET_X (-112) /* Offset from original 640-based positioning */ +#define MC_WIDESCREEN_HUD_OFFSET_Y 0 /* Y stays same for 480 height */ +#define MC_HUD_BASE_X 70 // 7x9 static const char* smallfont[] = @@ -223,6 +230,14 @@ void score_display(VIEWPORT *player) UINT16 holdcnt; static UINT16 diamondknip; + /* Widescreen support: Calculate HUD offset based on actual screen width */ + INT16 hudOffsetX = 0; + if (prefs != nullptr && prefs->screenwidth > MC_HUD_BASE_X + 400) + { + /* Widescreen detected: center HUD or keep left-aligned with padding */ + hudOffsetX = (prefs->screenwidth - GAME_FRAMEBUFFER_WIDTH) / 2; + } + holdcnt = 0; if (scoreshift) scoreshift--; @@ -265,7 +280,8 @@ void score_display(VIEWPORT *player) // if (world !=3) { - frame->draw(*player->loadedmap->blitbuf,70 + (0*40) + ((sinus512[xcnt]*10)>>10) - scoreshift, 414 + ((sinus512[ycnt]*10)>>10) ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (0*40) + ((sinus512[xcnt]*10)>>10) - scoreshift, 414 + ((sinus512[ycnt]*10)>>10) ); } @@ -276,9 +292,10 @@ void score_display(VIEWPORT *player) frame = anim_setsequence(orgheart, 0, SEQ_FORCE); frame = anim_forceframe (orgheart, 16 - (player->energy >> 1)); - frame->draw(*player->loadedmap->blitbuf,70 + (1*40) + ((sinus512[xcnt]*10)>>10) - scoreshift, 414 + ((sinus512[ycnt]*10)>>10) ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (1*40) + ((sinus512[xcnt]*10)>>10) - scoreshift, 414 + ((sinus512[ycnt]*10)>>10) ); - scoreposhold[holdcnt ] = 70 + (1*40) + ((sinus512[xcnt]*10)>>10) - scoreshift + 8; + scoreposhold[holdcnt ] = hudOffsetX + 70 + (1*40) + ((sinus512[xcnt]*10)>>10) - scoreshift + 8; scoreposhold[holdcnt+1 ] = 414 + ((sinus512[ycnt]*10)>>10) + 8; holdcnt+=2; @@ -326,7 +343,7 @@ void score_display(VIEWPORT *player) frame = anim_forceframe (orgdiamond, 1); } - scoreposhold[holdcnt ] = 70 + (i*40) + ((sinus512[xcnt]*10)>>10); + scoreposhold[holdcnt ] = hudOffsetX + 70 + (i*40) + ((sinus512[xcnt]*10)>>10); scoreposhold[holdcnt+1 ] = 414 + ((sinus512[ycnt]*10)>>10) + scoreshift; holdcnt+=2; @@ -334,7 +351,8 @@ void score_display(VIEWPORT *player) { if (world !=3) { - frame->draw(*player->loadedmap->blitbuf,70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); } } else @@ -348,7 +366,8 @@ void score_display(VIEWPORT *player) frame = anim_forceframe (orgdiamond, 1); if (world !=3) { - frame->draw(*player->loadedmap->blitbuf,70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); } } else if ((i-3) == (((diamondknip-4)&31)/4)) @@ -356,7 +375,8 @@ void score_display(VIEWPORT *player) frame = anim_forceframe (orgdiamond, 1); if (world !=3) { - frame->draw(*player->loadedmap->blitbuf,70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); } } else @@ -364,7 +384,8 @@ void score_display(VIEWPORT *player) frame = anim_forceframe (orgdiamond, 0); if (world !=3) { - frame->draw(*player->loadedmap->blitbuf,70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (i*40) + ((sinus512[xcnt]*10)>>10), 414 + ((sinus512[ycnt]*10)>>10) + scoreshift ); } } } @@ -445,9 +466,10 @@ void score_display(VIEWPORT *player) frame = anim_forceframe (orgcolormond, player->newlife/2); if (world !=3) { - frame->draw(*player->loadedmap->blitbuf,70 + (11*40) + ((sinus512[xcnt]*10)>>10) + scoreshift, 414 + ((sinus512[ycnt]*10)>>10) ); + /* Widescreen: Apply HUD offset */ + frame->draw(*player->loadedmap->blitbuf, hudOffsetX + 70 + (11*40) + ((sinus512[xcnt]*10)>>10) + scoreshift, 414 + ((sinus512[ycnt]*10)>>10) ); } - scoreposhold[holdcnt ] = 70 + (11*40) + ((sinus512[xcnt]*10)>>10) + scoreshift+8; + scoreposhold[holdcnt ] = hudOffsetX + 70 + (11*40) + ((sinus512[xcnt]*10)>>10) + scoreshift+8; scoreposhold[holdcnt+1 ] = 414 + ((sinus512[ycnt]*10)>>10)+8; holdcnt+=2; diff --git a/Classes/moonchild/scroll.cpp b/Classes/moonchild/scroll.cpp index c901789..2a9fdea 100644 --- a/Classes/moonchild/scroll.cpp +++ b/Classes/moonchild/scroll.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #define WORD short @@ -22,7 +23,19 @@ void map_build(VIEWPORT *player) video->clear(0); - for (x=1; x<41; x++) + /* Widescreen support: Extended tile range for 16:9 aspect ratio */ + /* + * Original 4:3 (640px): 20 visible columns at 32px each + * Widescreen 16:9 (854px or 864px): ~27 visible columns + * Adding buffer columns for smooth scrolling on both sides + */ +#define MC_BASE_COLUMNS 20 +#define MC_WIDESCREEN_COLUMNS 27 +#define MC_COLUMNS_BUFFER 2 /* Extra columns on each side for scrolling */ +#define MC_MAX_COLUMNS (MC_WIDESCREEN_COLUMNS + (2 * MC_COLUMNS_BUFFER)) + + /* Start from -buffer to allow left edge scrolling */ + for (x = 1 - MC_COLUMNS_BUFFER; x < (1 + MC_BASE_COLUMNS + MC_COLUMNS_BUFFER); x++) { blitpatcolumn(player, x); } @@ -145,6 +158,11 @@ void scrolling(VIEWPORT *player) { INT16 spdx; INT16 spdy; + + /* Widescreen support: Dynamic camera center for 16:9 */ + /* Original hardcoded 320 was based on 640/2 - now uses prefs->screenwidth/2 */ + INT16 screen_center_x = prefs->screenwidth / 2; + INT16 screen_center_y = prefs->screenheight / 2; if (world != 2) { @@ -161,10 +179,11 @@ void scrolling(VIEWPORT *player) } else { - spdx = ((player->camx-320) - player->worldx)>>4; + /* Widescreen: Use dynamic center instead of hardcoded 320 */ + spdx = ((player->camx - screen_center_x) - player->worldx)>>4; if (spdx == 0) { - if ((player->camx-320) != player->worldx) + if ((player->camx - screen_center_x) != player->worldx) { spdx = 1; } @@ -172,10 +191,11 @@ void scrolling(VIEWPORT *player) if (spdx > player->maxspd) spdx = player->maxspd; if (spdx < -player->maxspd) spdx = -player->maxspd; - spdy = ((player->camy-240) - player->worldy)>>4; + /* Widescreen: Use dynamic center instead of hardcoded 240 */ + spdy = ((player->camy - screen_center_y) - player->worldy)>>4; if (spdy == 0) { - if ((player->camy-240) != player->worldy) + if ((player->camy - screen_center_y) != player->worldy) { spdy = 1; } @@ -262,15 +282,20 @@ void scrolling(VIEWPORT *player) } + /* Widescreen support: Allow negative camera positions to show left edge padding */ + /* Original 4:3 clamp was: player->worldx < 32 */ + /* Widescreen clamp allows: player->worldx < -GAME_FRAMEBUFFER_WIDESCREEN_PADDING */ + /* xcoord */ if (player->worldx > (player->curmap->mapsizex - prefs->screenwidth-64)) { player->worldx = (player->curmap->mapsizex - prefs->screenwidth-64); } - if (player->worldx < 32) + /* Widescreen: Allow camera to slide left to show widescreen padding */ + if (player->worldx < -GAME_FRAMEBUFFER_WIDESCREEN_PADDING) { - player->worldx = 32; + player->worldx = -GAME_FRAMEBUFFER_WIDESCREEN_PADDING; } /* ycoord */ @@ -792,6 +817,15 @@ void update(VIEWPORT *player) sm_x = (player->worldx+player->quakex) &31; sm_y = (player->worldy+player->shakey+player->quakey) &31; + /* Widescreen support: Use dynamic screen bounds from prefs */ + INT16 screen_width = prefs->screenwidth; + INT16 screen_height = prefs->screenheight; + + /* Extended tile range for widescreen: x ranges from -5 to 26 (instead of -1 to 22) */ +#define MC_WIDESCREEN_X_START -5 +#define MC_WIDESCREEN_X_END 26 +#define MC_WIDESCREEN_Y_END 18 + if ( mouserbut && editflg ) // display editpage { for (y= 0; y<17; y++) @@ -816,8 +850,9 @@ void update(VIEWPORT *player) fex = x*32+32-sm_x; fey = y*32+32-sm_y; - if (fex >= 640) fex = 640; - if (fey >= 480) fey = 480; + /* Widescreen support: Use dynamic bounds */ + if (fex >= screen_width) fex = screen_width; + if (fey >= screen_height) fey = screen_height; if (fsx >= -32 && fsx < 0) { @@ -831,7 +866,8 @@ void update(VIEWPORT *player) fsy = 0; } - if (fsx < 640 && fsy < 480 && fex >= 0 && fey >= 0) + /* Widescreen: Blitter handles horizontal offset internally */ + if (fex >= 0 && fey >= 0) { para->draw_nokey(*player1.loadedmap->blitbuf, sx, sy, fsx, fsy, fex, fey); } @@ -844,10 +880,12 @@ void update(VIEWPORT *player) { if (transmap[curpat]==1) //semi transparent { + /* Widescreen: Blitter handles horizontal offset internally */ srcblitbuf->draw(*player1.loadedmap->blitbuf, x*32-sm_x, y*32-sm_y, 0, 0, 32, 32); } else { + /* Widescreen: Blitter handles horizontal offset internally */ srcblitbuf->draw_nokey(*player1.loadedmap->blitbuf, x*32-sm_x, y*32-sm_y, 0, 0, 32, 32); } } @@ -857,32 +895,47 @@ void update(VIEWPORT *player) } } else // in game! - { - for (y= -1; y<17; y++) { - for (x=-1; x<22; x++) + INT16 map_width_tiles = player->curmap->mapsizex / 32; + + /* Widescreen: Apply +112px camera offset to shift gameplay into center of widescreen */ + INT16 widescreen_cam_offset = GAME_FRAMEBUFFER_WIDESCREEN_PADDING; // +112 + + for (y= -1; ycurmap->map[((y+of_y)*player->curmap->mapsizex/32)+(x+of_x)]; - curpat &= 0x7fff; - player->curmap->map[((y+of_y)*player->curmap->mapsizex/32)+(x+of_x)] = curpat; + for (x=MC_WIDESCREEN_X_START; x= map_width_tiles) + { + curpat = 0; // Empty sky tile for out-of-bounds columns + } + else + { + curpat = player->curmap->map[((y+of_y)*player->curmap->mapsizex/32)+col_index]; + curpat &= 0x7fff; + player->curmap->map[((y+of_y)*player->curmap->mapsizex/32)+col_index] = curpat; + } if(curpat>=nrofpats) curpat=0; if (transmap[curpat]!=2) { INT16 sx,sy,fsx,fsy,fex,fey; - sx = x*32-sm_x; + sx = x*32-sm_x + widescreen_cam_offset; sy = y*32-sm_y; - fsx = x*32-sm_x; + fsx = x*32-sm_x + widescreen_cam_offset; fsy = y*32-sm_y; - fex = x*32+32-sm_x; + fex = x*32+32-sm_x + widescreen_cam_offset; fey = y*32+32-sm_y; - if (fex >= 640) fex = 640; - if (fey >= 480) fey = 480; + /* Widescreen support: Use dynamic bounds */ + if (fex >= screen_width) fex = screen_width; + if (fey >= screen_height) fey = screen_height; if (fsx >= -32 && fsx < 0) { @@ -896,7 +949,8 @@ void update(VIEWPORT *player) fsy = 0; } - if (fsx < 640 && fsy < 480 && fex >= 0 && fey >= 0) + /* Widescreen: Camera offset applied, tiles shifted to fill left edge */ + if (fex >= 0 && fey >= 0) { para->draw_nokey(*player1.loadedmap->blitbuf, sx, sy, fsx, fsy, fex, fey); } @@ -910,11 +964,13 @@ void update(VIEWPORT *player) { if (transmap[curpat]==1) // semi transparent { - srcblitbuf->draw(*player1.loadedmap->blitbuf, x*32-sm_x, y*32-sm_y, 0, 0, 32, 32); + /* Widescreen: Camera offset shifts tiles to fill widescreen viewport */ + srcblitbuf->draw(*player1.loadedmap->blitbuf, x*32-sm_x + widescreen_cam_offset, y*32-sm_y, 0, 0, 32, 32); } else { - srcblitbuf->draw_nokey(*player1.loadedmap->blitbuf, x*32-sm_x, y*32-sm_y, 0, 0, 32, 32); + /* Widescreen: Camera offset shifts tiles to fill widescreen viewport */ + srcblitbuf->draw_nokey(*player1.loadedmap->blitbuf, x*32-sm_x + widescreen_cam_offset, y*32-sm_y, 0, 0, 32, 32); } } } @@ -1137,11 +1193,14 @@ void rebuild(VIEWPORT *player) // toggle ^= 1; // if (toggle) // { - blitpatcolumn(player, 41); + /* Widescreen: Use dynamic column count based on screenwidth */ + INT16 screen_width = prefs->screenwidth; + INT16 max_col = (screen_width / 32) + 3; /* +3 for buffer columns */ + blitpatcolumn(player, max_col); // } // else // { - blitpatcolumn(player, 1); + blitpatcolumn(player, 1 - MC_COLUMNS_BUFFER); // } #if 0 diff --git a/Classes/moonchild/scroll.hpp b/Classes/moonchild/scroll.hpp index 9f35a86..1ea2039 100644 --- a/Classes/moonchild/scroll.hpp +++ b/Classes/moonchild/scroll.hpp @@ -3,6 +3,18 @@ #include #include +#include + +/* Widescreen support - 16:9 aspect ratio */ +#define MC_BASE_WIDTH 640 +#define MC_BASE_HEIGHT 480 +/* Widescreen adds 224 pixels horizontally (640 + 224 = 864, which is 16:9 with 480 height) */ +#define MC_WIDESCREEN_PADDING 112 + +/* Tile column constants for widescreen mode */ +#define MC_BASE_COLUMNS 20 /* Original 4:3 columns at 32px each */ +#define MC_WIDESCREEN_COLUMNS 27 /* Widescreen 16:9 columns */ +#define MC_COLUMNS_BUFFER 2 /* Extra columns on each side for smooth scrolling */ struct VIEWPORT { @@ -14,7 +26,7 @@ struct VIEWPORT INT16 focusy; INT16 topx; INT16 topy; - INT16 width; + INT16 width; /* Dynamically sized for widescreen */ INT16 height; INT16 shakey; INT16 resbufnum; @@ -32,6 +44,11 @@ struct VIEWPORT MAP_DESCR *curmap; MAP_DESCR *loadedmap; BYTE *orgsurface; + + /* Widescreen support fields */ + UINT16 basewidth; /* Original game width (640) */ + UINT16 baseheight; /* Original game height (480) */ + UINT16 widescreenpadding; /* Extra pixels on each side */ }; void camera_override(VIEWPORT *player, UINT16 camx, UINT16 camy, UINT16 maxspd); diff --git a/Platform/App/PlatformConfig.h b/Platform/App/PlatformConfig.h index 9432791..ebd26d1 100644 --- a/Platform/App/PlatformConfig.h +++ b/Platform/App/PlatformConfig.h @@ -2,7 +2,13 @@ #include -constexpr int GAME_FRAMEBUFFER_WIDTH = 640; -constexpr int GAME_FRAMEBUFFER_HEIGHT = 480; +/* Widescreen support - 16:9 aspect ratio */ +/* Original 4:3: 640x480 | Widescreen 16:9: 864x480 (+224 pixels horizontally) */ +constexpr int GAME_FRAMEBUFFER_BASE_WIDTH = 640; +constexpr int GAME_FRAMEBUFFER_BASE_HEIGHT = 480; +constexpr int GAME_FRAMEBUFFER_WIDESCREEN_PADDING = 112; +constexpr int GAME_FRAMEBUFFER_WIDTH = GAME_FRAMEBUFFER_BASE_WIDTH + (2 * GAME_FRAMEBUFFER_WIDESCREEN_PADDING); +constexpr int GAME_FRAMEBUFFER_HEIGHT = GAME_FRAMEBUFFER_BASE_HEIGHT; + constexpr uint64_t GAME_FRAME_DURATION_NS_50 = 1000000000ull / 50ull; constexpr uint64_t GAME_FRAME_DURATION_NS_60 = 1000000000ull / 60ull; diff --git a/Platform/Backends/Renderer/GLESRenderer.cpp b/Platform/Backends/Renderer/GLESRenderer.cpp index eb60caa..7a75406 100644 --- a/Platform/Backends/Renderer/GLESRenderer.cpp +++ b/Platform/Backends/Renderer/GLESRenderer.cpp @@ -14,8 +14,12 @@ static const char* VERTEX_SRC = "attribute vec2 aPosition;\n" "attribute vec2 aTexCoord;\n" "varying vec2 vTexCoord;\n" + "uniform vec2 uWidescreenOffset; /* Offset to center 4:3 content in widescreen */\n" "void main() {\n" - " gl_Position = vec4(aPosition, 0.0, 1.0);\n" + " /* Widescreen: Shift the position to center the original 640 content */\n" + " vec2 shiftedPos = aPosition;\n" + " shiftedPos.x = aPosition.x + uWidescreenOffset.x;\n" + " gl_Position = vec4(shiftedPos, 0.0, 1.0);\n" " vTexCoord = aTexCoord;\n" "}\n"; @@ -102,6 +106,7 @@ bool GLESRenderer::BuildSharpBilinearProgram() LocSource = glGetUniformLocation(Program, "uSource"); LocSourceSize = glGetUniformLocation(Program, "uSourceSize"); LocScale = glGetUniformLocation(Program, "uScale"); + LocWidescreenOffset = glGetUniformLocation(Program, "uWidescreenOffset"); LocPosition = glGetAttribLocation(Program, "aPosition"); LocTexCoord = glGetAttribLocation(Program, "aTexCoord"); @@ -148,6 +153,10 @@ bool GLESRenderer::Init(IWindow* hostWindow) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + printf("Widescreen: Allocating framebuffer at %dx%d (base: %dx%d + %dx%d padding)\n", + w, h, GAME_FRAMEBUFFER_BASE_WIDTH, GAME_FRAMEBUFFER_BASE_HEIGHT, + GAME_FRAMEBUFFER_WIDESCREEN_PADDING, GAME_FRAMEBUFFER_WIDESCREEN_PADDING); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, zeros.data()); if (!BuildSharpBilinearProgram()) @@ -193,6 +202,8 @@ void GLESRenderer::Destroy() void GLESRenderer::BeginFrame() { Surface->MakeCurrent(); + /* Widescreen: Clear entire framebuffer to black, not just centered portion */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); } @@ -227,10 +238,15 @@ void GLESRenderer::DrawFrame(const unsigned char* rgbaPixels, int width, int hei const float scaleX = std::max(1, ViewportWidth / width); const float scaleY = std::max(1, ViewportHeight / height); + /* Widescreen: Calculate offset to center 640 content in 864 framebuffer */ + const float widescreenOffsetX = (GAME_FRAMEBUFFER_WIDTH - GAME_FRAMEBUFFER_BASE_WIDTH) / + static_cast(GAME_FRAMEBUFFER_WIDTH); + glUseProgram(Program); glUniform1i(LocSource, 0); glUniform2f(LocSourceSize, width, height); glUniform2f(LocScale, scaleX, scaleY); + glUniform2f(LocWidescreenOffset, widescreenOffsetX, 0.0f); glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer); glEnableVertexAttribArray(LocPosition); diff --git a/Platform/Backends/Renderer/GLESRenderer.h b/Platform/Backends/Renderer/GLESRenderer.h index 6b8fff0..7d81f7e 100644 --- a/Platform/Backends/Renderer/GLESRenderer.h +++ b/Platform/Backends/Renderer/GLESRenderer.h @@ -35,6 +35,7 @@ class GLESRenderer final : public IRenderer GLint LocSource = -1; GLint LocSourceSize = -1; GLint LocScale = -1; + GLint LocWidescreenOffset = -1; /* Widescreen centering offset uniform */ int ViewportWidth = 0; int ViewportHeight = 0; diff --git a/Platform/Backends/Renderer/OpenGLRenderer.cpp b/Platform/Backends/Renderer/OpenGLRenderer.cpp index 03205dc..99fcc53 100644 --- a/Platform/Backends/Renderer/OpenGLRenderer.cpp +++ b/Platform/Backends/Renderer/OpenGLRenderer.cpp @@ -14,8 +14,12 @@ static const char* VERTEX_SRC = "attribute vec2 aPosition;\n" "attribute vec2 aTexCoord;\n" "varying vec2 vTexCoord;\n" + "uniform vec2 uWidescreenOffset; /* Offset to center 4:3 content in widescreen */\n" "void main() {\n" - " gl_Position = vec4(aPosition, 0.0, 1.0);\n" + " /* Widescreen: Shift the position to center the original 640 content */\n" + " vec2 shiftedPos = aPosition;\n" + " shiftedPos.x = aPosition.x + uWidescreenOffset.x;\n" + " gl_Position = vec4(shiftedPos, 0.0, 1.0);\n" " vTexCoord = aTexCoord;\n" "}\n"; @@ -102,6 +106,7 @@ bool OpenGLRenderer::BuildSharpBilinearProgram() LocSource = glGetUniformLocation(Program, "uSource"); LocSourceSize = glGetUniformLocation(Program, "uSourceSize"); LocScale = glGetUniformLocation(Program, "uScale"); + LocWidescreenOffset = glGetUniformLocation(Program, "uWidescreenOffset"); LocPosition = glGetAttribLocation(Program, "aPosition"); LocTexCoord = glGetAttribLocation(Program, "aTexCoord"); @@ -139,6 +144,10 @@ bool OpenGLRenderer::Init(IWindow* hostWindow) SourceHeight = h; const std::vector zeros(w * h * 4, 0); + printf("Widescreen: Allocating framebuffer at %dx%d (base: %dx%d + %dx%d padding)\n", + w, h, GAME_FRAMEBUFFER_BASE_WIDTH, GAME_FRAMEBUFFER_BASE_HEIGHT, + GAME_FRAMEBUFFER_WIDESCREEN_PADDING, GAME_FRAMEBUFFER_WIDESCREEN_PADDING); + glGenTextures(1, &Texture); glBindTexture(GL_TEXTURE_2D, Texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -190,6 +199,8 @@ void OpenGLRenderer::Destroy() void OpenGLRenderer::BeginFrame() { Surface->MakeCurrent(); + /* Widescreen: Clear entire framebuffer to black, not just centered portion */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); } @@ -224,10 +235,16 @@ void OpenGLRenderer::DrawFrame(const unsigned char* rgbaPixels, int width, int h const float scaleX = std::max(1, ViewportWidth / width); const float scaleY = std::max(1, ViewportHeight / height); + /* Widescreen: Calculate offset to center 640 content in 864 framebuffer */ + /* Offset = (864 - 640) / 864 = 224 / 864 ≈ 0.259 */ + const float widescreenOffsetX = (GAME_FRAMEBUFFER_WIDTH - GAME_FRAMEBUFFER_BASE_WIDTH) / + static_cast(GAME_FRAMEBUFFER_WIDTH); + glUseProgram(Program); glUniform1i(LocSource, 0); glUniform2f(LocSourceSize, width, height); glUniform2f(LocScale, scaleX, scaleY); + glUniform2f(LocWidescreenOffset, widescreenOffsetX, 0.0f); glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer); glEnableVertexAttribArray(LocPosition); diff --git a/Platform/Backends/Renderer/OpenGLRenderer.h b/Platform/Backends/Renderer/OpenGLRenderer.h index 1ad266d..766d58e 100644 --- a/Platform/Backends/Renderer/OpenGLRenderer.h +++ b/Platform/Backends/Renderer/OpenGLRenderer.h @@ -35,6 +35,7 @@ class OpenGLRenderer final : public IRenderer GLint LocSource = -1; GLint LocSourceSize = -1; GLint LocScale = -1; + GLint LocWidescreenOffset = -1; /* Widescreen centering offset uniform */ int ViewportWidth = 0; int ViewportHeight = 0; diff --git a/Platform/Backends/Window/SDL3Window.cpp b/Platform/Backends/Window/SDL3Window.cpp index b78fe8f..cfa80a7 100644 --- a/Platform/Backends/Window/SDL3Window.cpp +++ b/Platform/Backends/Window/SDL3Window.cpp @@ -26,8 +26,15 @@ struct GameViewport float Height = 0.0f; }; -constexpr float GAME_WIDTH = 640.0f; -constexpr float GAME_HEIGHT = 480.0f; +/* Widescreen support - 16:9 aspect ratio */ +constexpr float GAME_BASE_WIDTH = 640.0f; +constexpr float GAME_BASE_HEIGHT = 480.0f; +/* Widescreen adds 224 pixels horizontally (640 + 224 = 864, which is 16:9 with 480 height) */ +constexpr float GAME_WIDESCREEN_PADDING = 112.0f; + +/* Default to widescreen mode for modern displays */ +constexpr float GAME_WIDTH = GAME_BASE_WIDTH + (2.0f * GAME_WIDESCREEN_PADDING); +constexpr float GAME_HEIGHT = GAME_BASE_HEIGHT; static GameViewport GetGameViewport(SDL_Window* window) {