Support software renderer upscaling engine-side in sdlayer and sdlayer12 with various scaling factors (beyond just pixel doubling).

When glsurface is available, use GL to upscale the render buffer.
Additionally, fix build issues with sdlayer12 introduced by GLAD changes (r6656).

git-svn-id: https://svn.eduke32.com/eduke32@6939 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
pogokeen 2018-07-14 21:36:44 +00:00
parent 1b932fddaf
commit 1df7127609
27 changed files with 475 additions and 357 deletions

View file

@ -940,6 +940,8 @@ ifeq ($(PLATFORM),WINDOWS)
LIBS += -lmingwex -lgdi32 -lpthread
ifeq ($(RENDERTYPE),WIN)
LIBS += -ldxguid
else ifeq ($(SDL_TARGET),1)
LIBS += -ldxguid -lmingw32 -limm32 -lole32 -loleaut32 -lversion
else
LIBS += -ldxguid_sdl -lmingw32 -limm32 -lole32 -loleaut32 -lversion
endif

View file

@ -192,6 +192,7 @@ engine_objs := \
osd.cpp \
pragmas.cpp \
scriptfile.cpp \
softsurface.cpp \
mmulti_null.cpp \
mutex.cpp \
xxhash.c \

View file

@ -141,6 +141,7 @@
<ClInclude Include="..\..\source\build\include\scriptfile.h" />
<ClInclude Include="..\..\source\build\include\sdlayer.h" />
<ClInclude Include="..\..\source\build\include\sdl_inc.h" />
<ClInclude Include="..\..\source\build\include\softsurface.h" />
<ClInclude Include="..\..\source\build\include\startwin.editor.h" />
<ClInclude Include="..\..\source\build\include\texcache.h" />
<ClInclude Include="..\..\source\build\include\tilepacker.h" />
@ -300,6 +301,7 @@
<ClCompile Include="..\..\source\build\src\sdlayer12.cpp" />
<ClCompile Include="..\..\source\build\src\sdlkeytrans.cpp" />
<ClCompile Include="..\..\source\build\src\smalltextfont.cpp" />
<ClCompile Include="..\..\source\build\src\softsurface.cpp" />
<ClCompile Include="..\..\source\build\src\startgtk.editor.cpp" />
<ClCompile Include="..\..\source\build\src\startwin.editor.cpp" />
<ClCompile Include="..\..\source\build\src\texcache.cpp" />

View file

@ -579,6 +579,9 @@
<ClInclude Include="..\..\source\build\include\tilepacker.h">
<Filter>build\headers</Filter>
</ClInclude>
<ClInclude Include="..\..\source\build\include\softsurface.h">
<Filter>build\headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\build\src\a-c.cpp">
@ -1031,6 +1034,9 @@
<ClCompile Include="..\..\source\build\src\tilepacker.cpp">
<Filter>build\source</Filter>
</ClCompile>
<ClCompile Include="..\..\source\build\src\softsurface.cpp">
<Filter>build\source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="msvc.mak">

View file

@ -184,6 +184,7 @@ ENGINE_OBJS= \
$(ENGINE_OBJ)\winbits.$o \
$(ENGINE_OBJ)\xxhash.$o \
$(ENGINE_OBJ)\screenshot.$o \
$(ENGINE_OBJ)\softsurface.$o \
$(ENGINE_OBJ)\mhk.$o \
$(ENGINE_OBJ)\pngwrite.$o \
$(ENGINE_OBJ)\miniz.$o \

View file

@ -663,7 +663,7 @@ EXTERN int16_t thewall[MAXWALLSB];
EXTERN uspritetype *tspriteptr[MAXSPRITESONSCREEN + 1];
EXTERN int32_t wx1, wy1, wx2, wy2;
EXTERN int32_t xdim, ydim, numpages;
EXTERN int32_t xdim, ydim, numpages, upscalefactor;
EXTERN int32_t yxaspect, viewingrange;
EXTERN intptr_t *ylookup;
@ -1055,7 +1055,7 @@ intptr_t tileCreate(int16_t tilenume, int32_t xsiz, int32_t ysiz);
void tileCopySection(int32_t tilenume1, int32_t sx1, int32_t sy1, int32_t xsiz, int32_t ysiz, int32_t tilenume2, int32_t sx2, int32_t sy2);
void squarerotatetile(int16_t tilenume);
int32_t videoSetGameMode(char davidoption, int32_t daxdim, int32_t daydim, int32_t dabpp);
int32_t videoSetGameMode(char davidoption, int32_t daupscaledxdim, int32_t daupscaledydim, int32_t dabpp, int32_t daupscalefactor);
void videoNextPage(void);
void videoSetCorrectedAspect();
void videoSetViewableArea(int32_t x1, int32_t y1, int32_t x2, int32_t y2);

View file

@ -1,5 +1,5 @@
/*
* glsurface.cpp
* glsurface.h
* A 32-bit rendering surface that can quickly blit 8-bit paletted buffers implemented in OpenGL.
*
* Copyright © 2018, Alex Dawson. All rights reserved.
@ -15,7 +15,7 @@
// glsurface will still render at the full size of the screen.
// If a surface already exists, glsurface_destroy() will be automatically called before re-initializing.
// Returns whether or not the glsurface could be successfully initialized.
bool glsurface_initialize(vec2_t inputBufferResolution);
bool glsurface_initialize(vec2_t bufferResolution);
// Destroy an existing surface.
void glsurface_destroy();

View file

@ -0,0 +1,47 @@
/*
* softsurface.h
* An 8-bit rendering surface that can quickly upscale and blit 8-bit paletted buffers to an external 32-bit screen buffer.
*
* Copyright © 2018, Alex Dawson. All rights reserved.
*/
#ifndef SOFTSURFACE_H_
#define SOFTSURFACE_H_
#include "compat.h"
// Initialize the softsurface with the Software renderer's buffer resolution.
// If the Software renderer's resolution and the actual resolution don't match,
// softsurface will still render at the full size of the screen.
// If a surface already exists, softsurface_destroy() will be automatically called before re-initializing.
// Returns whether or not the softsurface could be successfully initialized.
bool softsurface_initialize(vec2_t bufferResolution,
vec2_t destBufferResolution);
// Destroy an existing surface.
void softsurface_destroy();
// Sets the palette to contain the RGBA byte buffer pointed to by pPalette.
// destRedMask/destGreenMask/destBlueMask mask the bits that represent each colour component in the destination buffer's pixel format.
// If the surface is not initialized, the function returns immediately.
void softsurface_setPalette(void* pPalette,
uint32_t destRedMask,
uint32_t destGreenMask,
uint32_t destBlueMask);
// Returns a pointer to the start of the surface's 8-bit pixel buffer
// Returns NULL if the surface is not initialized.
uint8_t* softsurface_getBuffer();
// Returns the resolution of the surface's buffer
vec2_t softsurface_getBufferResolution();
// Returns the resolution of the destination buffer
vec2_t softsurface_getDestinationBufferResolution();
// Blit the surface's pixel buffer to the destination buffer using the palette set with softsurface_setPalette().
// If the surface is not initialized, the function returns immediately.
void softsurface_blitBuffer(uint32_t* destBuffer,
uint32_t destBpp);
#endif /* SOFTSURFACE_H_ */

View file

@ -110,10 +110,10 @@ static void drawlinegl(int32_t x1, int32_t y1, int32_t x2, int32_t y2, palette_t
{
// setpolymost2dview(); // JBF 20040205: more efficient setup
glViewport(0, 0, xres, yres);
glViewport(0, 0, xdim, ydim);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, xres, yres, 0, -1, 1);
glOrtho(0, xdim, ydim, 0, -1, 1);
if (videoGetRenderMode() == REND_POLYMER)
{
glMatrixMode(GL_MODELVIEW);
@ -274,7 +274,7 @@ int32_t editorDraw2dLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int col
swaplong(&y1, &y2);
}
if (x1 >= xres || x2 < 0)
if (x1 >= xdim || x2 < 0)
return 0;
if (x1 < 0)
@ -283,10 +283,10 @@ int32_t editorDraw2dLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int col
x1 = 0;
}
if (x2 >= xres)
if (x2 >= xdim)
{
if (d.y) y2 += scale(xres-1-x2, d.y, d.x);
x2 = xres-1;
if (d.y) y2 += scale(xdim-1-x2, d.y, d.x);
x2 = xdim-1;
}
if ((d.x < 0 && d.y >= 0) || (d.y < 0 && d.x >= 0))
@ -301,14 +301,14 @@ int32_t editorDraw2dLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int col
if (y1 < 0)
{
if (d.x)
x1 = clamp(x1 + scale(0 - y1, d.x, d.y), 0, xres - 1);
x1 = clamp(x1 + scale(0 - y1, d.x, d.y), 0, xdim - 1);
y1 = 0;
}
if (y2 >= ydim16)
{
if (d.x)
x2 = clamp(x2 + scale(ydim16-1-y2, d.x, d.y), 0, xres-1);
x2 = clamp(x2 + scale(ydim16-1-y2, d.x, d.y), 0, xdim-1);
y2 = ydim16-1;
}
@ -319,7 +319,7 @@ int32_t editorDraw2dLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int col
}
//if (ox1||ox2||oy1||oy2)
// if (x1<0||x1>=xres || y2<0||y2>=yres)
// if (x1<0||x1>=xdim || y2<0||y2>=ydim)
// attach_here();
d.x = klabs(x2-x1)+1;
@ -450,9 +450,9 @@ void editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char c
}
if (r < 0) r = -r;
if (x1+r < 0 || y1+r < 0 || x1-r >= xres || y1-r >= ydim16) return;
if (x1+r < 0 || y1+r < 0 || x1-r >= xdim || y1-r >= ydim16) return;
uint32_t const uxres = xres, uydim16 = ydim16;
uint32_t const uxdim = xdim, uydim16 = ydim16;
/*
* d
@ -473,13 +473,13 @@ void editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char c
if (drawlinepat == 0xffffffff || drawlinepat & pow2long[(++patc)&31])
{
if ((uint32_t) y1 < uydim16 && (uint32_t) (x1+r) < uxres)
if ((uint32_t) y1 < uydim16 && (uint32_t) (x1+r) < uxdim)
drawpixel((char *) (p+r), col); // a
if ((uint32_t) x1 < uxres && (uint32_t) (y1+r) < uydim16)
if ((uint32_t) x1 < uxdim && (uint32_t) (y1+r) < uydim16)
drawpixel((char *) (p+(r*bytesperline)), col); // b
if ((uint32_t) y1 < uydim16 && (uint32_t) (x1-r) < uxres)
if ((uint32_t) y1 < uydim16 && (uint32_t) (x1-r) < uxdim)
drawpixel((char *) (p-r), col); // c
if ((uint32_t) x1 < uxres && (uint32_t) (y1-r) < uydim16)
if ((uint32_t) x1 < uxdim && (uint32_t) (y1-r) < uydim16)
drawpixel((char *) (p-(r*bytesperline)), col); // d
}
@ -510,21 +510,21 @@ void editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char c
if (drawlinepat & pow2long[(++patc) & 31])
{
if ((uint32_t) (x1 + yp) < uxres && (uint32_t) (y1 + xp) < uydim16)
if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
drawpixel_safe((char *) (p + yp + xpbpl), col); // 1
if ((uint32_t) (x1 + xp) < uxres && (uint32_t) (y1 + yp) < uydim16)
if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
drawpixel_safe((char *) (p + xp + ypbpl), col); // 2
if ((uint32_t) (x1 - xp) < uxres && (uint32_t) (y1 + yp) < uydim16)
if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
drawpixel_safe((char *) (p - xp + ypbpl), col); // 3
if ((uint32_t) (x1 - yp) < uxres && (uint32_t) (y1 + xp) < uydim16)
if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
drawpixel_safe((char *) (p - yp + xpbpl), col); // 4
if ((uint32_t) (x1 - yp) < uxres && (uint32_t) (y1 - xp) < uydim16)
if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
drawpixel_safe((char *) (p - yp - xpbpl), col); // 5
if ((uint32_t) (x1 - xp) < uxres && (uint32_t) (y1 - yp) < uydim16)
if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
drawpixel_safe((char *) (p - xp - ypbpl), col); // 6
if ((uint32_t) (x1 + xp) < uxres && (uint32_t) (y1 - yp) < uydim16)
if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
drawpixel_safe((char *) (p + xp - ypbpl), col); // 7
if ((uint32_t) (x1 + yp) < uxres && (uint32_t) (y1 - xp) < uydim16)
if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
drawpixel_safe((char *) (p + yp - xpbpl), col); // 8
}
} while (yp > xp);
@ -553,21 +553,21 @@ void editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char c
int32_t const ypbpl = yp*bytesperline;
int32_t const xpbpl = xp*bytesperline;
if ((uint32_t) (x1 + yp) < uxres && (uint32_t) (y1 + xp) < uydim16)
if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
drawpixel_safe((char *) (p + yp + xpbpl), col); // 1
if ((uint32_t) (x1 + xp) < uxres && (uint32_t) (y1 + yp) < uydim16)
if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
drawpixel_safe((char *) (p + xp + ypbpl), col); // 2
if ((uint32_t) (x1 - xp) < uxres && (uint32_t) (y1 + yp) < uydim16)
if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
drawpixel_safe((char *) (p - xp + ypbpl), col); // 3
if ((uint32_t) (x1 - yp) < uxres && (uint32_t) (y1 + xp) < uydim16)
if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
drawpixel_safe((char *) (p - yp + xpbpl), col); // 4
if ((uint32_t) (x1 - yp) < uxres && (uint32_t) (y1 - xp) < uydim16)
if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
drawpixel_safe((char *) (p - yp - xpbpl), col); // 5
if ((uint32_t) (x1 - xp) < uxres && (uint32_t) (y1 - yp) < uydim16)
if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
drawpixel_safe((char *) (p - xp - ypbpl), col); // 6
if ((uint32_t) (x1 + xp) < uxres && (uint32_t) (y1 - yp) < uydim16)
if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
drawpixel_safe((char *) (p + xp - ypbpl), col); // 7
if ((uint32_t) (x1 + yp) < uxres && (uint32_t) (y1 - xp) < uydim16)
if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
drawpixel_safe((char *) (p + yp - xpbpl), col); // 8
} while (yp > xp);
@ -579,7 +579,7 @@ void editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char c
//
void clear2dscreen(void)
{
int32_t const clearsz = (ydim16 <= yres - STATUS2DSIZ2) ? yres - STATUS2DSIZ2 : yres;
int32_t const clearsz = (ydim16 <= ydim - STATUS2DSIZ2) ? ydim - STATUS2DSIZ2 : ydim;
videoBeginDrawing(); //{{{
Bmemset((char *) frameplace, 0, bytesperline*clearsz);
videoEndDrawing(); //}}}
@ -1380,11 +1380,11 @@ void polymostSet2dView(void)
#ifdef USE_OPENGL
if (videoGetRenderMode() < REND_POLYMOST) return;
glViewport(0, 0, xres, yres);
glViewport(0, 0, xdim, ydim);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, xres, yres, 0, -1, 1);
glOrtho(0, xdim, ydim, 0, -1, 1);
if (videoGetRenderMode() == REND_POLYMER)
{

View file

@ -128,8 +128,8 @@ int32_t mouseReadAbs(vec2_t * const pResult, vec2_t const * const pInput)
int32_t const xwidth = max(scale(240<<16, xdim, ydim), 320<<16);
pResult->x = scale(pInput->x, xwidth, xdim) - ((xwidth>>1) - (320<<15));
pResult->y = scale(pInput->y, 200<<16, ydim);
pResult->x = scale(pInput->x, xwidth, xres) - ((xwidth>>1) - (320<<15));
pResult->y = scale(pInput->y, 200<<16, yres);
return 1;
}

View file

@ -279,7 +279,7 @@ int32_t osdcmd_restartvid(osdfuncparm_t const * const UNUSED(parm))
if (!in3dmode()) return OSDCMD_OK;
videoResetMode();
if (videoSetGameMode(fullscreen,xdim,ydim,bpp))
if (videoSetGameMode(fullscreen,xres,yres,bpp,upscalefactor))
OSD_Printf("restartvid: Reset failed...\n");
return OSDCMD_OK;
@ -288,7 +288,7 @@ int32_t osdcmd_restartvid(osdfuncparm_t const * const UNUSED(parm))
static int32_t osdcmd_vidmode(osdfuncparm_t const * const parm)
{
int32_t newx = xdim, newy = ydim, newbpp = bpp, newfullscreen = fullscreen;
int32_t newx = xres, newy = yres, newbpp = bpp, newfullscreen = fullscreen;
#ifdef USE_OPENGL
int32_t tmp;
#endif
@ -335,7 +335,7 @@ static int32_t osdcmd_vidmode(osdfuncparm_t const * const parm)
return OSDCMD_OK;
}
if (videoSetGameMode(newfullscreen,newx,newy,newbpp))
if (videoSetGameMode(newfullscreen,newx,newy,newbpp,upscalefactor))
OSD_Printf("vidmode: Mode change failed!\n");
xdimgame = newx;
@ -769,7 +769,7 @@ int app_main(int argc, char const * const * argv)
g_videoBrightness = 0.0;
videoSetPalette(0,0,0);
if (videoSetGameMode(fullscreen, xdim2d, ydim2d, 8) < 0)
if (videoSetGameMode(fullscreen, xdim2d, ydim2d, 8, upscalefactor) < 0)
{
CallExtUnInit();
engineUnInit();
@ -792,7 +792,7 @@ int app_main(int argc, char const * const * argv)
}
else
{
if (videoSetGameMode(fullscreen, xdimgame, ydimgame, bppgame) < 0)
if (videoSetGameMode(fullscreen, xdimgame, ydimgame, bppgame, upscalefactor) < 0)
{
CallExtUnInit();
engineUnInit();
@ -8269,7 +8269,7 @@ CANCEL:
fixspritesectors();
if (videoSetGameMode(fullscreen,xdimgame,ydimgame,bppgame) < 0)
if (videoSetGameMode(fullscreen,xdimgame,ydimgame,bppgame,upscalefactor) < 0)
{
initprintf("%d * %d not supported in this graphics mode\n",xdim,ydim);
CallExtUnInit();

View file

@ -21,6 +21,7 @@
#include "baselayer.h"
#include "scriptfile.h"
#include "softsurface.h"
#ifdef USE_OPENGL
# include "glad/glad.h"
# include "glsurface.h"
@ -2336,8 +2337,8 @@ static inline void wallmosts_finish(int16_t *mostbuf, int32_t z1, int32_t z2,
#if 0
// enable for paranoia:
ix1 = clamp(ix1, 0, xres-1);
ix2 = clamp(ix2, 0, xres-1);
ix1 = clamp(ix1, 0, xdim-1);
ix2 = clamp(ix2, 0, xdim-1);
if (ix2-ix1 < 0)
swaplong(&ix1, &ix2);
#endif
@ -6518,13 +6519,13 @@ static void dorotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t
// bound clipping rectangle to screen
if (cx1 < 0) cx1 = 0;
else if (cx1 > xres-1) cx1 = xres-1;
else if (cx1 > xdim-1) cx1 = xdim-1;
if (cy1 < 0) cy1 = 0;
else if (cy1 > yres-1) cy1 = yres-1;
else if (cy1 > ydim-1) cy1 = ydim-1;
if (cx2 < 0) cx2 = 0;
else if (cx2 > xres-1) cx2 = xres-1;
else if (cx2 > xdim-1) cx2 = xdim-1;
if (cy2 < 0) cy2 = 0;
else if (cy2 > yres-1) cy2 = yres-1;
else if (cy2 > ydim-1) cy2 = ydim-1;
xsiz = tilesiz[picnum].x;
ysiz = tilesiz[picnum].y;
@ -9826,11 +9827,21 @@ static void videoAllocateBuffers(void)
ysavecnt = YSAVES;
nodesperline = tabledivide32_noinline(YSAVES, ydim);
#ifdef USE_OPENGL
extern char nogl;
if (videoGetRenderMode() == REND_CLASSIC && !nogl)
#ifdef RENDERTYPESDL
if (videoGetRenderMode() == REND_CLASSIC)
{
glsurface_initialize({xdim, ydim});
# ifdef USE_OPENGL
extern char nogl;
if (!nogl)
{
glsurface_initialize({ xdim, ydim });
}
else
# endif
{
softsurface_initialize({ xdim, ydim },
{ xres, yres });
}
}
#endif
}
@ -9863,7 +9874,7 @@ static void PolymostProcessVoxels(void)
//
// JBF: davidoption now functions as a windowed-mode flag (0 == windowed, 1 == fullscreen)
extern char videomodereset;
int32_t videoSetGameMode(char davidoption, int32_t daxdim, int32_t daydim, int32_t dabpp)
int32_t videoSetGameMode(char davidoption, int32_t daupscaledxdim, int32_t daupscaledydim, int32_t dabpp, int32_t daupscalefactor)
{
int32_t j;
@ -9872,11 +9883,11 @@ int32_t videoSetGameMode(char davidoption, int32_t daxdim, int32_t daydim, int32
if (nogl) dabpp = 8;
#endif
daxdim = max(320, daxdim);
daydim = max(200, daydim);
daupscaledxdim = max(320, daupscaledxdim);
daupscaledydim = max(200, daupscaledydim);
if (in3dmode() && videomodereset == 0 &&
(davidoption == fullscreen) && (xdim == daxdim) && (ydim == daydim) && (bpp == dabpp))
if (in3dmode() && videomodereset == 0 && (davidoption == fullscreen) &&
(xres == daupscaledxdim) && (yres == daupscaledydim) && (bpp == dabpp) && (upscalefactor == daupscalefactor))
return 0;
Bstrcpy(kensmessage,"!!!! BUILD engine&tools programmed by Ken Silverman of E.G. RI."
@ -9891,7 +9902,7 @@ int32_t videoSetGameMode(char davidoption, int32_t daxdim, int32_t daydim, int32
j = bpp;
g_lastpalettesum = 0;
if (videoSetMode(daxdim,daydim,dabpp,davidoption) < 0) return -1;
if (videoSetMode(daupscaledxdim,daupscaledydim,dabpp,davidoption) < 0) return -1;
// Workaround possible bugs in the GL driver
makeasmwriteable();
@ -9901,14 +9912,25 @@ int32_t videoSetGameMode(char davidoption, int32_t daxdim, int32_t daydim, int32
else rendmode = REND_CLASSIC;
#endif
xdim = daxdim;
ydim = daydim;
upscalefactor = max(1, min(tabledivide32(yres, 200), daupscalefactor));
//POGOTODO: Polymost/Polymer could work with upscaling with a couple more changes
int32_t scalefactor = upscalefactor;
#ifdef RENDERTYPESDL
if (bpp != 8)
#endif
{
scalefactor = 1;
}
xdim = daupscaledxdim/scalefactor;
ydim = daupscaledydim/scalefactor;
#ifdef USE_OPENGL
fxdim = (float) daxdim;
fydim = (float) daydim;
fxdim = (float) xdim;
fydim = (float) ydim;
#endif
OSD_ResizeDisplay(xdim, ydim);
videoAllocateBuffers();
#ifdef HIGH_PRECISION_SPRITE
@ -12297,7 +12319,7 @@ void videoClearScreen(int32_t dacol)
#endif
videoBeginDrawing(); //{{{
Bmemset((void *)frameplace,dacol,bytesperline*yres);
Bmemset((void *)frameplace,dacol,bytesperline*ydim);
videoEndDrawing(); //}}}
//nextpage();
@ -12761,20 +12783,22 @@ void videoSet2dMode(int32_t daxdim, int32_t daydim)
ydim = yres;
#ifdef USE_OPENGL
fxdim = (float) xres;
fydim = (float) yres;
fxdim = (float) xdim;
fydim = (float) ydim;
rendmode = REND_CLASSIC;
#endif
OSD_ResizeDisplay(xdim, ydim);
videoAllocateBuffers();
ydim16 = yres - STATUS2DSIZ2;
halfxdim16 = xres >> 1;
midydim16 = ydim16 >> 1; // scale(200,yres,480);
ydim16 = ydim - STATUS2DSIZ2;
halfxdim16 = xdim >> 1;
midydim16 = ydim16 >> 1; // scale(200,ydim,480);
videoBeginDrawing(); //{{{
Bmemset((char *)frameplace, 0, yres*bytesperline);
Bmemset((char *)frameplace, 0, ydim*bytesperline);
videoEndDrawing(); //}}}
}

View file

@ -56,14 +56,14 @@ static GLuint compileShader(GLenum shaderType, const char* const source)
return shaderID;
}
bool glsurface_initialize(vec2_t inputBufferResolution)
bool glsurface_initialize(vec2_t bufferResolution)
{
if (buffer)
glsurface_destroy();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
bufferRes = inputBufferResolution;
bufferRes = bufferResolution;
buffer = Xaligned_alloc(16, bufferRes.x * bufferRes.y);
glGenBuffers(1, &quadVertsID);

View file

@ -8,10 +8,6 @@
#include "a.h"
#include "xxhash.h"
#ifdef USE_OPENGL
# include "glsurface.h"
#endif
uint8_t *basepaltable[MAXBASEPALS] = { palette };
uint8_t basepalreset=1;
uint8_t curbasepal;
@ -742,7 +738,6 @@ void videoSetPalette(char dabrightness, uint8_t dapalid, uint8_t flags)
if (palsumdidchange || newpalettesum != g_lastpalettesum)
{
glsurface_setPalette(curpalettefaded);
// if ((flags&1) == 0)
videoUpdatePalette(0, 256);
}
@ -826,7 +821,6 @@ void videoFadePalette(uint8_t r, uint8_t g, uint8_t b, uint8_t offset)
if (newpalettesum != lastpalettesum || newpalettesum != g_lastpalettesum)
{
glsurface_setPalette(curpalettefaded);
videoUpdatePalette(0, 256);
}

View file

@ -924,7 +924,7 @@ void polymer_glinit(void)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(windowxy1.x, yres-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
glViewport(windowxy1.x, ydim-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
// texturing
glEnable(GL_TEXTURE_2D);
@ -2029,7 +2029,7 @@ static void polymer_displayrooms(const int16_t dacursectnum)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[0].fbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(windowxy1.x, yres-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
glViewport(windowxy1.x, ydim-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

View file

@ -1503,7 +1503,7 @@ static void resizeglcheck(void)
glox1 = (float)windowxy1.x; gloy1 = (float)windowxy1.y;
glox2 = (float)windowxy2.x; gloy2 = (float)windowxy2.y;
glViewport(windowxy1.x-(fovcorrect/2), yres-(windowxy2.y+1),
glViewport(windowxy1.x-(fovcorrect/2), ydim-(windowxy2.y+1),
ourxdimen+fovcorrect, windowxy2.y-windowxy1.y+1);
glMatrixMode(GL_PROJECTION);
@ -6950,7 +6950,7 @@ void polymost_dorotatespritemodel(int32_t sx, int32_t sy, int32_t z, int16_t a,
tspr.cstat = globalorientation = (dastat&RS_TRANS1) | ((dastat&RS_TRANS2)<<4) | ((dastat&RS_YFLIP)<<1);
if ((dastat&(RS_AUTO|RS_NOCLIP)) == RS_AUTO)
glViewport(windowxy1.x, yres-(windowxy2.y+1), windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
glViewport(windowxy1.x, ydim-(windowxy2.y+1), windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
else
{
glViewport(0, 0, xdim, ydim);
@ -7870,7 +7870,7 @@ static int32_t osdcmd_cvar_set_polymost(osdfuncparm_t const * const parm)
{
texcache_invalidate();
videoResetMode();
if (videoSetGameMode(fullscreen,xdim,ydim,bpp))
if (videoSetGameMode(fullscreen,xres,yres,bpp,upscalefactor))
OSD_Printf("restartvid: Reset failed...\n");
}

View file

@ -13,6 +13,7 @@
#include "engine_priv.h"
#include "palette.h"
#include "softsurface.h"
#ifdef USE_OPENGL
# include "glad/glad.h"
# include "glbuild.h"
@ -37,7 +38,6 @@
# include "wiibits.h"
# include <ogc/lwp.h>
# include <ogc/lwp_watchdog.h>
# define SDL_DISABLE_8BIT_BUFFER
#endif
#if SDL_MAJOR_VERSION != 1
@ -69,18 +69,10 @@ char quitevent=0, appactive=1, novideo=0;
// video
static SDL_Surface *sdl_surface/*=NULL*/;
#if !defined SDL_DISABLE_8BIT_BUFFER
static SDL_Surface *sdl_buffersurface=NULL;
#else
# define sdl_buffersurface sdl_surface
#endif
#if SDL_MAJOR_VERSION==2
static SDL_Palette *sdl_palptr=NULL;
static SDL_Window *sdl_window=NULL;
static SDL_GLContext sdl_context=NULL;
static SDL_Texture *sdl_texture=NULL;
static SDL_Renderer *sdl_renderer=NULL;
#endif
int32_t xres=-1, yres=-1, bpp=0, fullscreen=0, bytesperline;
@ -99,7 +91,9 @@ char nogl=0;
#endif
static int32_t vsync_renderlayer;
int32_t maxrefreshfreq=0;
#if SDL_MAJOR_VERSION==2
static uint32_t currentVBlankInterval=0;
#endif
// last gamma, contrast, brightness
static float lastvidgcb[3];
@ -547,7 +541,7 @@ int32_t videoSetVsync(int32_t newSync)
vsync_renderlayer = newSync;
videoResetMode();
if (videoSetGameMode(fullscreen, xdim, ydim, bpp))
if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
OSD_Printf("restartvid: Reset failed...\n");
}
@ -675,10 +669,12 @@ void uninitsystem(void)
#endif
#ifdef USE_OPENGL
# if SDL_MAJOR_VERSION!=1
SDL_GL_UnloadLibrary();
#ifdef POLYMER
# endif
# ifdef POLYMER
unloadglulibrary();
#endif
# endif
#endif
}
@ -1265,33 +1261,15 @@ int32_t videoCheckMode(int32_t *x, int32_t *y, int32_t c, int32_t fs, int32_t fo
return nearest;
}
static int32_t needpalupdate;
static SDL_Color sdlayer_pal[256];
static void destroy_window_resources()
{
#if !defined SDL_DISABLE_8BIT_BUFFER
if (sdl_buffersurface)
SDL_FreeSurface(sdl_buffersurface);
sdl_buffersurface = NULL;
#endif
/* We should NOT destroy the window surface. This is done automatically
when SDL_DestroyWindow or SDL_SetVideoMode is called. */
#if SDL_MAJOR_VERSION == 2
if (sdl_renderer && sdl_texture && sdl_surface)
SDL_FreeSurface(sdl_surface);
sdl_surface = NULL;
if (sdl_context)
SDL_GL_DeleteContext(sdl_context);
sdl_context = NULL;
if (sdl_texture)
SDL_DestroyTexture(sdl_texture);
sdl_texture = NULL;
if (sdl_renderer)
SDL_DestroyRenderer(sdl_renderer);
sdl_renderer = NULL;
if (sdl_window)
SDL_DestroyWindow(sdl_window);
sdl_window = NULL;
@ -1425,10 +1403,7 @@ void sdlayer_setvideomode_opengl(void)
int32_t setvideomode_sdlcommon(int32_t *x, int32_t *y, int32_t c, int32_t fs, int32_t *regrab)
{
if ((fs == fullscreen) && (*x == xres) && (*y == yres) && (c == bpp) && !videomodereset)
{
OSD_ResizeDisplay(xres, yres);
return 0;
}
if (videoCheckMode(x, y, c, fs, 0) < 0)
return -1;
@ -1461,7 +1436,11 @@ int32_t setvideomode_sdlcommon(int32_t *x, int32_t *y, int32_t c, int32_t fs, in
if ((fs == fullscreen) && (*x == xres) && (*y == yres) && (bpp != 0) && !videomodereset)
return 0;
}
else
#endif
{
softsurface_destroy();
}
// clear last gamma/contrast/brightness so that it will be set anew
lastvidgcb[0] = lastvidgcb[1] = lastvidgcb[2] = 0.0f;
@ -1488,7 +1467,6 @@ void setvideomode_sdlcommonpost(int32_t x, int32_t y, int32_t c, int32_t fs, int
lockcount = 0;
modechange = 1;
videomodereset = 0;
OSD_ResizeDisplay(xres, yres);
// save the current system gamma to determine if gamma is available
#ifndef EDUKE32_GLES
@ -1537,55 +1515,6 @@ void setrefreshrate(void)
currentVBlankInterval = 1000/newmode.refresh_rate;
}
static void sdl_trycreaterenderer_fail(char const * const failurepoint)
{
initprintf("Falling back to SDL_GetWindowSurface: %s failed: %s\n", failurepoint, SDL_GetError());
SDL_DestroyRenderer(sdl_renderer);
sdl_renderer = NULL;
}
static void sdl_trycreaterenderer(int32_t const x, int32_t const y)
{
int const flags = SDL_RENDERER_ACCELERATED | (vsync_renderlayer ? SDL_RENDERER_PRESENTVSYNC : 0);
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, flags);
if (!sdl_renderer)
{
sdl_trycreaterenderer_fail("SDL_CreateRenderer");
return;
}
SDL_RendererInfo sdl_rendererinfo;
SDL_GetRendererInfo(sdl_renderer, &sdl_rendererinfo);
if (sdl_rendererinfo.flags & SDL_RENDERER_SOFTWARE) // this would be useless
{
initprintf("Falling back to SDL_GetWindowSurface: software SDL_Renderer \"%s\" provides no benefit.\n", sdl_rendererinfo.name);
SDL_DestroyRenderer(sdl_renderer);
sdl_renderer = NULL;
return;
}
initprintf("Trying SDL_Renderer \"%s\"\n", sdl_rendererinfo.name);
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, x, y);
if (!sdl_texture)
{
sdl_trycreaterenderer_fail("SDL_CreateTexture");
return;
}
sdl_surface = SDL_CreateRGBSurface(0, x, y, 32, 0, 0, 0, 0);
if (!sdl_surface)
{
SDL_DestroyTexture(sdl_texture);
sdl_texture = NULL;
sdl_trycreaterenderer_fail("SDL_CreateRGBSurface");
return;
}
}
int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
{
int32_t regrab = 0, ret;
@ -1684,8 +1613,6 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
setrefreshrate();
sdl_trycreaterenderer(x, y);
if (!sdl_surface)
{
sdl_surface = SDL_GetWindowSurface(sdl_window);
@ -1693,19 +1620,6 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
SDL2_VIDEO_ERR("SDL_GetWindowSurface");
}
#if !defined SDL_DISABLE_8BIT_BUFFER
sdl_buffersurface = SDL_CreateRGBSurface(0, x, y, c, 0, 0, 0, 0);
if (!sdl_buffersurface)
SDL2_VIDEO_ERR("SDL_CreateRGBSurface");
#endif
if (!sdl_palptr)
sdl_palptr = SDL_AllocPalette(256);
if (SDL_SetSurfacePalette(sdl_buffersurface, sdl_palptr) < 0)
initprintf("SDL_SetSurfacePalette failed: %s\n", SDL_GetError());
SDL_SetWindowFullscreen(sdl_window, ((fs & 1) ? SDL_WINDOW_FULLSCREEN : 0));
}
@ -1752,6 +1666,7 @@ void videoBeginDrawing(void)
if (offscreenrendering) return;
#ifdef USE_OPENGL
if (!nogl)
{
frameplace = (intptr_t)glsurface_getBuffer();
@ -1763,16 +1678,13 @@ void videoBeginDrawing(void)
}
return;
}
#endif
if (SDL_MUSTLOCK(sdl_buffersurface)) SDL_LockSurface(sdl_buffersurface);
frameplace = (intptr_t)sdl_buffersurface->pixels;
if (sdl_buffersurface->pitch != bytesperline || modechange)
frameplace = (intptr_t)softsurface_getBuffer();
if (modechange)
{
bytesperline = sdl_buffersurface->pitch;
bytesperline = xdim;
calc_ylookup(bytesperline, ydim);
modechange=0;
}
}
@ -1794,10 +1706,6 @@ void videoEndDrawing(void)
if (!offscreenrendering) frameplace = 0;
if (lockcount == 0) return;
lockcount = 0;
if (offscreenrendering || !nogl) return;
if (SDL_MUSTLOCK(sdl_buffersurface)) SDL_UnlockSurface(sdl_buffersurface);
}
//
@ -1854,27 +1762,11 @@ void videoShowFrame(int32_t w)
while (lockcount) videoEndDrawing();
}
// deferred palette updating
if (needpalupdate)
{
if (SDL_SetPaletteColors(sdl_palptr, sdlayer_pal, 0, 256) < 0)
initprintf("SDL_SetPaletteColors failed: %s\n", SDL_GetError());
needpalupdate = 0;
}
if (SDL_MUSTLOCK(sdl_surface)) SDL_LockSurface(sdl_surface);
softsurface_blitBuffer((uint32_t*) sdl_surface->pixels, sdl_surface->format->BitsPerPixel);
if (SDL_MUSTLOCK(sdl_surface)) SDL_UnlockSurface(sdl_surface);
#if !defined SDL_DISABLE_8BIT_BUFFER
SDL_BlitSurface(sdl_buffersurface, NULL, sdl_surface, NULL);
#endif
if (sdl_renderer && sdl_texture)
{
SDL_UpdateTexture(sdl_texture, NULL, sdl_surface->pixels, sdl_surface->pitch);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
SDL_RenderPresent(sdl_renderer);
}
else if (SDL_UpdateWindowSurface(sdl_window))
if (SDL_UpdateWindowSurface(sdl_window))
{
// If a fullscreen X11 window is minimized then this may be required.
// FIXME: What to do if this fails...
@ -1888,21 +1780,24 @@ void videoShowFrame(int32_t w)
//
int32_t videoUpdatePalette(int32_t start, int32_t num)
{
UNREFERENCED_PARAMETER(start);
UNREFERENCED_PARAMETER(num);
if (bpp > 8)
return 0; // no palette in opengl
Bmemcpy(sdlayer_pal, curpalettefaded, 256 * 4);
for (native_t i = start, n = num; n > 0; i++, n--)
curpalettefaded[i].f =
#if SDL_MAJOR_VERSION == 1
sdlayer_pal[i].unused
#else
sdlayer_pal[i].a
#ifdef USE_OPENGL
if (!nogl)
glsurface_setPalette(curpalettefaded);
else
#endif
= 0;
needpalupdate = 1;
{
if (sdl_surface)
softsurface_setPalette(curpalettefaded,
sdl_surface->format->Rmask,
sdl_surface->format->Gmask,
sdl_surface->format->Bmask);
}
return 0;
}

View file

@ -26,7 +26,7 @@ int32_t videoSetVsync(int32_t newSync)
vsync_renderlayer = newSync;
videoResetMode();
if (videoSetGameMode(fullscreen, xdim, ydim, bpp))
if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
OSD_Printf("restartvid: Reset failed...\n");
return newSync;
@ -251,12 +251,8 @@ void videoGetModes(void)
pf.BitsPerPixel = cdepths[j];
pf.BytesPerPixel = cdepths[j] >> 3;
#if !defined SDL_DISABLE_8BIT_BUFFER
// We convert paletted contents to non-paletted
modes = SDL_ListModes((cdepths[j] == 8) ? NULL : &pf, SURFACE_FLAGS | SDL_FULLSCREEN);
#else
modes = SDL_ListModes(&pf, SURFACE_FLAGS | SDL_FULLSCREEN);
#endif
if (modes == (SDL_Rect **)0)
{
@ -325,7 +321,14 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
#endif
ret = setvideomode_sdlcommon(&x, &y, c, fs, &regrab);
if (ret != 1) return ret;
if (ret != 1)
{
if (ret == 0)
{
setvideomode_sdlcommonpost(x, y, c, fs, regrab);
}
return ret;
}
// restore gamma before we change video modes if it was changed
if (sdl_surface && gammabrightness)
@ -340,7 +343,7 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
initprintf("Setting video mode %dx%d (%d-bpp %s)\n", x, y, c, ((fs & 1) ? "fullscreen" : "windowed"));
#ifdef USE_OPENGL
if (c > 8)
if (c > 8 || !nogl)
{
int32_t i, j, multisamplecheck = (glmultisample > 0);
@ -395,34 +398,21 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
initprintf("Unable to set video mode!\n");
return -1;
}
#ifdef _WIN32
loadglextensions();
#endif
} while (multisamplecheck--);
gladLoadGLLoader(SDL_GL_GetProcAddress);
}
else
#endif // defined USE_OPENGL
{
#if !defined SDL_DISABLE_8BIT_BUFFER
// We convert paletted contents to non-paletted
sdl_surface = SDL_SetVideoMode(x, y, 0, SURFACE_FLAGS | ((fs & 1) ? SDL_FULLSCREEN : 0));
#else
sdl_surface = SDL_SetVideoMode(x, y, c, SURFACE_FLAGS | ((fs & 1) ? SDL_FULLSCREEN : 0));
#endif
if (!sdl_surface)
{
initprintf("Unable to set video mode!\n");
return -1;
}
#if !defined SDL_DISABLE_8BIT_BUFFER
sdl_buffersurface = SDL_CreateRGBSurface(SURFACE_FLAGS, x, y, c, 0, 0, 0, 0);
if (!sdl_buffersurface)
{
initprintf("Unable to set video mode: SDL_CreateRGBSurface failed: %s\n", SDL_GetError());
return -1;
}
#endif
}
setvideomode_sdlcommonpost(x, y, c, fs, regrab);
@ -438,10 +428,17 @@ void videoShowFrame(int32_t w)
UNREFERENCED_PARAMETER(w);
#ifdef USE_OPENGL
if (bpp > 8)
if (!nogl)
{
if (palfadedelta)
fullscreen_tint_gl(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
if (bpp > 8)
{
if (palfadedelta)
fullscreen_tint_gl(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
}
else
{
glsurface_blitBuffer();
}
SDL_GL_SwapBuffers();
return;
@ -456,16 +453,10 @@ void videoShowFrame(int32_t w)
while (lockcount) videoEndDrawing();
}
// deferred palette updating
if (needpalupdate)
{
SDL_SetColors(sdl_buffersurface, sdlayer_pal, 0, 256);
needpalupdate = 0;
}
if (SDL_MUSTLOCK(sdl_surface)) SDL_LockSurface(sdl_surface);
softsurface_blitBuffer((uint32_t*) sdl_surface->pixels, sdl_surface->format->BitsPerPixel);
if (SDL_MUSTLOCK(sdl_surface)) SDL_UnlockSurface(sdl_surface);
#if !defined SDL_DISABLE_8BIT_BUFFER
SDL_BlitSurface(sdl_buffersurface, NULL, sdl_surface, NULL);
#endif
SDL_Flip(sdl_surface);
}

View file

@ -0,0 +1,207 @@
/*
* softsurface.cpp
* An 8-bit rendering surface that can quickly upscale and blit 8-bit paletted buffers to an external 32-bit buffer.
*
* Copyright © 2018, Alex Dawson. All rights reserved.
*/
#include "softsurface.h"
#include "pragmas.h"
#include "build.h"
static uint8_t* buffer;
static vec2_t bufferRes;
static vec2_t destBufferRes;
static uint32_t xScale16;
static uint32_t yScale16;
static uint32_t recXScale16;
static uint32_t pPal[256];
// lookup table to find the source position within a scanline
static uint16_t* scanPosLookupTable;
static uint32_t roundUp(uint32_t num, uint32_t multiple)
{
return (num+multiple-1)/multiple * multiple;
}
static uint32_t countTrailingZeros(uint32_t u)
{
#if (defined __GNUC__ && __GNUC__>=3) || defined __clang__
return __builtin_ctz(u);
#elif defined _MSC_VER
uint32_t result;
_BitScanForward(&result, u);
return result;
#else
uint32_t last = u;
for (; u != 0; last = u, u >>= 1);
return last;
#endif
}
bool softsurface_initialize(vec2_t bufferResolution,
vec2_t destBufferResolution)
{
if (buffer)
softsurface_destroy();
bufferRes = bufferResolution;
destBufferRes = destBufferResolution;
xScale16 = divscale16(destBufferRes.x, bufferRes.x);
yScale16 = divscale16(destBufferRes.y, bufferRes.y);
recXScale16 = divscale16(bufferRes.x, destBufferRes.x);
// allocate one continuous block of memory large enough to hold the buffer, the palette,
// and the scanPosLookupTable while maintaining alignment for each
uint32_t bufferSize = roundUp(bufferRes.x * bufferRes.y, 16);
buffer = (uint8_t*) Xaligned_alloc(16, bufferSize + sizeof(uint16_t)*destBufferRes.x);
scanPosLookupTable = (uint16_t*) (buffer + bufferSize);
// calculate the scanPosLookupTable for horizontal scaling
uint32_t incr = recXScale16;
for (int32_t i = 0; i < destBufferRes.x; ++i)
{
scanPosLookupTable[i] = incr >> 16;
incr += recXScale16;
}
return true;
}
void softsurface_destroy()
{
if (!buffer)
return;
ALIGNED_FREE_AND_NULL(buffer);
scanPosLookupTable = 0;
xScale16 = 0;
yScale16 = 0;
recXScale16 = 0;
bufferRes = {};
destBufferRes = {};
}
void softsurface_setPalette(void* pPalette,
uint32_t destRedMask,
uint32_t destGreenMask,
uint32_t destBlueMask)
{
if (!buffer)
return;
if (!pPalette)
return;
uint32_t destRedShift = countTrailingZeros(destRedMask);
uint32_t destRedLoss = 8 - countTrailingZeros((destRedMask>>destRedShift)+1);
uint32_t destGreenShift = countTrailingZeros(destGreenMask);
uint32_t destGreenLoss = 8 - countTrailingZeros((destGreenMask>>destGreenShift)+1);
uint32_t destBlueShift = countTrailingZeros(destBlueMask);
uint32_t destBlueLoss = 8 - countTrailingZeros((destBlueMask>>destBlueShift)+1);
uint8_t* pUI8Palette = (uint8_t*) pPalette;
for (int i = 0; i < 256; ++i)
{
pPal[i] = ((pUI8Palette[sizeof(uint32_t)*i] >> destRedLoss << destRedShift) & destRedMask) |
((pUI8Palette[sizeof(uint32_t)*i+1] >> destGreenLoss << destGreenShift) & destGreenMask) |
((pUI8Palette[sizeof(uint32_t)*i+2] >> destBlueLoss << destBlueShift) & destBlueMask);
}
}
uint8_t* softsurface_getBuffer()
{
return buffer;
}
vec2_t softsurface_getBufferResolution()
{
return bufferRes;
}
vec2_t softsurface_getDestinationBufferResolution()
{
return destBufferRes;
}
#define BLIT(x) pDst[x] = *((UINTTYPE*)(pPal+pSrc[pScanPos[x]]))
#define BLIT2(x) BLIT(x); BLIT(x+1)
#define BLIT4(x) BLIT2(x); BLIT2(x+2)
#define BLIT8(x) BLIT4(x); BLIT4(x+4)
#define BLIT16(x) BLIT8(x); BLIT8(x+8)
#define BLIT32(x) BLIT16(x); BLIT16(x+16)
#define BLIT64(x) BLIT32(x); BLIT32(x+32)
template <typename UINTTYPE>
void softsurface_blitBufferInternal(UINTTYPE* destBuffer)
{
const uint8_t* __restrict pSrc = buffer;
UINTTYPE* __restrict pDst = destBuffer;
const UINTTYPE* const pEnd = destBuffer+destBufferRes.x*mulscale16(yScale16, bufferRes.y);
uint32_t remainder = 0;
while (pDst < pEnd)
{
uint16_t* __restrict pScanPos = scanPosLookupTable;
UINTTYPE* const pScanEnd = pDst+destBufferRes.x;
while (pDst < pScanEnd-64)
{
BLIT64(0);
pDst += 64;
pScanPos += 64;
}
while (pDst < pScanEnd)
{
BLIT(0);
++pDst;
++pScanPos;
}
pSrc += bufferRes.x;
static const uint32_t MASK16 = (1<<16)-1;
uint32_t linesCopied = 1;
uint32_t linesToCopy = yScale16+remainder;
remainder = linesToCopy & MASK16;
linesToCopy = (linesToCopy >> 16)-1;
const UINTTYPE* const __restrict pScanLineSrc = pDst-destBufferRes.x;
while (linesToCopy)
{
uint32_t lines = min(linesCopied, linesToCopy);
memcpy(pDst, pScanLineSrc, sizeof(UINTTYPE)*lines*destBufferRes.x);
pDst += lines*destBufferRes.x;
linesToCopy -= lines;
}
}
}
void softsurface_blitBuffer(uint32_t* destBuffer,
uint32_t destBpp)
{
if (!buffer)
return;
if (!destBuffer)
return;
switch (destBpp)
{
case 15:
softsurface_blitBufferInternal<uint16_t>((uint16_t*) destBuffer);
break;
case 16:
softsurface_blitBufferInternal<uint16_t>((uint16_t*) destBuffer);
break;
case 24:
softsurface_blitBufferInternal<uint32_t>(destBuffer);
break;
case 32:
softsurface_blitBufferInternal<uint32_t>(destBuffer);
break;
default:
return;
}
}

View file

@ -1592,10 +1592,7 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
int32_t modenum;
if ((fs == fullscreen) && (x == xres) && (y == yres) && (c == bpp) && !videomodereset)
{
OSD_ResizeDisplay(xres,yres);
return 0;
}
modenum = videoCheckMode(&x,&y,c,fs,0);
if (modenum < 0) return -1;
@ -1637,7 +1634,6 @@ int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
if (inp) AcquireInputDevices(1);
modechange=1;
videomodereset = 0;
OSD_ResizeDisplay(xres,yres);
return 0;
}
@ -3190,7 +3186,6 @@ static BOOL CreateAppWindow(int32_t modenum)
//bytesperline = width;
modechange = 1;
OSD_ResizeDisplay(xres,yres);
UpdateWindow(hWindow);
@ -3522,7 +3517,7 @@ static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
}
realfs = fullscreen;
silentvideomodeswitch = 1;
videoSetGameMode(!fullscreen,xdim,ydim,bpp);
videoSetGameMode(!fullscreen,xres,yres,bpp,upscalefactor);
ShowWindow(hWindow, SW_MINIMIZE);
}
else if (appactive && realfs)
@ -3535,7 +3530,7 @@ static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
ShowWindow(hWindow, SW_RESTORE);
SetForegroundWindow(hWindow);
SetFocus(hWindow);
videoSetGameMode(realfs,xdim,ydim,bpp);
videoSetGameMode(realfs,xres,yres,bpp,upscalefactor);
silentvideomodeswitch = 0;
realfs = 0;
}

View file

@ -187,10 +187,10 @@ void G_HandleSpecialKeys(void)
if (g_networkMode != NET_DEDICATED_SERVER && ALT_IS_PRESSED && KB_KeyPressed(sc_Enter))
{
if (videoSetGameMode(!ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP))
if (videoSetGameMode(!ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP,ud.detail))
{
OSD_Printf(OSD_ERROR "Failed setting fullscreen video mode.\n");
if (videoSetGameMode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP))
if (videoSetGameMode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP, ud.detail))
G_GameExit("Failed to recover from failure to set fullscreen video mode.\n");
}
else ud.config.ScreenMode = !ud.config.ScreenMode;
@ -281,7 +281,7 @@ void G_GameExit(const char *msg)
g_mostConcurrentPlayers > 1 && g_player[myconnectindex].ps->gm&MODE_GAME && GTFLAGS(GAMETYPE_SCORESHEET) && *msg == ' ')
{
G_BonusScreen(1);
videoSetGameMode(ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP);
videoSetGameMode(ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP,ud.detail);
}
// shareware and TEN screens
@ -772,7 +772,6 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio)
int32_t floorZ, ceilZ;
int32_t tiltcx, tiltcy, tiltcs=0; // JBF 20030807
int pixelDoubling = 0;
int const vr = divscale22(1, sprite[pPlayer->i].yrepeat + 28);
int screenTilting = (videoGetRenderMode() == REND_CLASSIC && ((ud.screen_tilting && pPlayer->rotscrnang
#ifdef SPLITSCREEN_MOD_HACKS
@ -896,12 +895,6 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio)
#endif
pPlayer->orotscrnang = pPlayer->rotscrnang;
}
else if (ud.detail && videoGetRenderMode()==REND_CLASSIC)
{
pixelDoubling = 1;
g_halveScreenArea = 1;
G_UpdateScreenArea();
}
if (pPlayer->newowner < 0)
{
@ -1107,39 +1100,6 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio)
walock[TILE_TILT] = 199;
}
}
else if (pixelDoubling)
{
Bassert(g_halfScreen.xdimen!=0);
g_halveScreenArea = 0;
G_UpdateScreenArea();
videoBeginDrawing();
{
uint8_t *const f = (uint8_t *)frameplace;
const int32_t x1=g_halfScreen.x1, y1=g_halfScreen.y1;
const int32_t xd=g_halfScreen.xdimen, yd=g_halfScreen.ydimen;
int32_t dx, dy;
// Commented out: naive, per-byte access version.
// Live: optimized version: may access memory unaligned, relies
// on little-endian byte ordering.
for (dy=2*yd-1; dy>=0; dy--)
// for (dx=2*xd-1; dx>=0; dx--)
for (dx=2*xd-4; dx>=0; dx-=4)
{
const int32_t ylsrc = ylookup[y1+(dy>>1)];
const int32_t yldst = ylookup[y1+dy];
// f[yldst+x1+dx] = f[ylsrc+x1+(dx>>1)];
uint8_t pixr = f[ylsrc+x1+((dx+3)>>1)];
uint8_t pixl = f[ylsrc+x1+((dx+1)>>1)];
B_BUF32(&f[yldst+x1+dx], pixl|(pixl<<8)|(pixr<<16)|(pixr<<24));
}
}
videoEndDrawing();
}
}
G_RestoreInterpolations();
@ -6549,7 +6509,7 @@ int app_main(int argc, char const * const * argv)
if (g_networkMode != NET_DEDICATED_SERVER)
{
if (videoSetGameMode(ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP) < 0)
if (videoSetGameMode(ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP,ud.detail) < 0)
{
vec2_t const res[] = {
{ ud.config.ScreenWidth, ud.config.ScreenHeight }, { 800, 600 }, { 640, 480 }, { 320, 240 },
@ -6567,7 +6527,7 @@ int app_main(int argc, char const * const * argv)
int resIdx = 0;
int bppIdx = 0;
while (videoSetGameMode(0, res[resIdx].x, res[resIdx].y, bpp[bppIdx]) < 0)
while (videoSetGameMode(0, res[resIdx].x, res[resIdx].y, bpp[bppIdx], ud.detail) < 0)
{
initprintf("Failure setting video mode %dx%dx%d windowed! Attempting safer mode...\n", res[resIdx].x, res[resIdx].y,
bpp[bppIdx]);

View file

@ -308,8 +308,8 @@ void __fastcall VM_SetUserdef(int32_t const labelNum, int32_t const lParm2, int3
case USERDEFS_M_RESPAWN_INVENTORY: ud.m_respawn_inventory = iSet; break;
case USERDEFS_M_RECSTAT: ud.m_recstat = iSet; break;
case USERDEFS_M_MONSTERS_OFF: ud.m_monsters_off = iSet; break;
// REMINDER: must implement "boolean" setters like this in Lunatic, too.
case USERDEFS_DETAIL: ud.detail = !!iSet; break;
// REMINDER: must implement "boolean" setters like "!!iSet" in Lunatic, too.
case USERDEFS_DETAIL: ud.detail = clamp(iSet, 1, 16); break;
case USERDEFS_M_FFIRE: ud.m_ffire = iSet; break;
case USERDEFS_FFIRE: ud.ffire = iSet; break;
case USERDEFS_M_PLAYER_SKILL: ud.m_player_skill = iSet; break;

View file

@ -548,8 +548,11 @@ static MenuLink_t MEO_DISPLAYSETUP_COLORCORR = { MENU_COLCORR, MA_Advance, };
static MenuEntry_t ME_DISPLAYSETUP_COLORCORR = MAKE_MENUENTRY( "Color Correction", &MF_Redfont, &MEF_BigOptionsRt, &MEO_DISPLAYSETUP_COLORCORR, Link );
static MenuOption_t MEO_DISPLAYSETUP_PIXELDOUBLING = MAKE_MENUOPTION( &MF_Redfont, &MEOS_OffOn, &ud.detail );
static MenuEntry_t ME_DISPLAYSETUP_PIXELDOUBLING = MAKE_MENUENTRY( "Pixel Doubling:", &MF_Redfont, &MEF_BigOptionsRt, &MEO_DISPLAYSETUP_PIXELDOUBLING, Option );
static char const *MEOSN_DISPLAYSETUP_UPSCALING[] = { "None", "2x", "4x", "8x", "16x", };
static int32_t MEOSV_DISPLAYSETUP_UPSCALING[] = { 1, 2, 4, 8, 16, };
static MenuOptionSet_t MEOS_DISPLAYSETUP_UPSCALING = MAKE_MENUOPTIONSET( MEOSN_DISPLAYSETUP_UPSCALING, MEOSV_DISPLAYSETUP_UPSCALING, 0x0 );
static MenuOption_t MEO_DISPLAYSETUP_UPSCALING = MAKE_MENUOPTION( &MF_Redfont, &MEOS_DISPLAYSETUP_UPSCALING, &ud.detail );
static MenuEntry_t ME_DISPLAYSETUP_UPSCALING = MAKE_MENUENTRY( "Upscaling:", &MF_Redfont, &MEF_BigOptionsRt, &MEO_DISPLAYSETUP_UPSCALING, Option );
#ifndef EDUKE32_ANDROID_MENU
@ -733,7 +736,7 @@ static MenuEntry_t *MEL_DISPLAYSETUP[] = {
&ME_DISPLAYSETUP_VIDEOSETUP,
&ME_DISPLAYSETUP_ASPECTRATIO,
#endif
&ME_DISPLAYSETUP_PIXELDOUBLING,
&ME_DISPLAYSETUP_UPSCALING,
};
#ifdef USE_OPENGL
@ -1992,7 +1995,7 @@ static void Menu_Pre(MenuID_t cm)
MenuEntry_DisableOnCondition(&ME_VIDEOSETUP_FULLSCREEN, !(resolution[nr].flags & RES_FS));
MenuEntry_DisableOnCondition(&ME_VIDEOSETUP_APPLY,
(xdim == resolution[nr].xdim && ydim == resolution[nr].ydim &&
(xres == resolution[nr].xdim && yres == resolution[nr].ydim &&
videoGetRenderMode() == newrendermode && fullscreen == newfullscreen
&& vsync == newvsync
)
@ -3031,7 +3034,7 @@ static void Menu_EntryLinkActivate(MenuEntry_t *entry)
if (entry == &ME_VIDEOSETUP_APPLY)
{
resolution_t p = { xdim, ydim, fullscreen, bpp, 0 };
resolution_t p = { xres, yres, fullscreen, bpp, 0 };
int32_t prend = videoGetRenderMode();
int32_t pvsync = vsync;
@ -3041,9 +3044,9 @@ static void Menu_EntryLinkActivate(MenuEntry_t *entry)
int32_t nrend = newrendermode;
int32_t nvsync = newvsync;
if (videoSetGameMode(n.flags, n.xdim, n.ydim, n.bppmax) < 0)
if (videoSetGameMode(n.flags, n.xdim, n.ydim, n.bppmax, upscalefactor) < 0)
{
if (videoSetGameMode(p.flags, p.xdim, p.ydim, p.bppmax) < 0)
if (videoSetGameMode(p.flags, p.xdim, p.ydim, p.bppmax, upscalefactor) < 0)
{
videoSetRenderMode(prend);
G_GameExit("Failed restoring old video mode.");
@ -3061,8 +3064,8 @@ static void Menu_EntryLinkActivate(MenuEntry_t *entry)
videoSetRenderMode(nrend);
vsync = videoSetVsync(nvsync);
ud.config.ScreenMode = fullscreen;
ud.config.ScreenWidth = xdim;
ud.config.ScreenHeight = ydim;
ud.config.ScreenWidth = xres;
ud.config.ScreenHeight = yres;
ud.config.ScreenBPP = bpp;
}
else if (entry == &ME_SOUND_RESTART)
@ -3271,6 +3274,13 @@ static void Menu_EntryOptionDidModify(MenuEntry_t *entry)
entry == &ME_PLAYER_COLOR ||
entry == &ME_PLAYER_TEAM)
G_UpdatePlayerFromMenu();
else if (entry == &ME_DISPLAYSETUP_UPSCALING)
{
if (in3dmode())
{
videoSetGameMode(fullscreen, xres, yres, bpp, ud.detail);
}
}
#ifdef USE_OPENGL
else if (entry == &ME_DISPLAYSETUP_ANISOTROPY || entry == &ME_DISPLAYSETUP_TEXFILTER)
gltexapplyprops();
@ -3290,7 +3300,7 @@ static void Menu_EntryOptionDidModify(MenuEntry_t *entry)
if (domodechange)
{
videoResetMode();
if (videoSetGameMode(fullscreen, xdim, ydim, bpp))
if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
OSD_Printf("restartvid: Reset failed...\n");
onvideomodechange(ud.config.ScreenBPP>8);
G_RefreshLights();
@ -4048,7 +4058,7 @@ static void Menu_AboutToStartDisplaying(Menu_t * m)
newresolution = 0;
for (size_t i = 0; i < MAXVALIDMODES; ++i)
{
if (resolution[i].xdim == xdim && resolution[i].ydim == ydim)
if (resolution[i].xdim == xres && resolution[i].ydim == yres)
{
newresolution = i;
break;

View file

@ -420,7 +420,7 @@ int32_t osdcmd_restartvid(osdfuncparm_t const * const UNUSED(parm))
{
UNREFERENCED_CONST_PARAMETER(parm);
videoResetMode();
if (videoSetGameMode(ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP))
if (videoSetGameMode(ud.config.ScreenMode,ud.config.ScreenWidth,ud.config.ScreenHeight,ud.config.ScreenBPP,ud.detail))
G_GameExit("restartvid: Reset failed...\n");
onvideomodechange(ud.config.ScreenBPP>8);
G_UpdateScreenArea();
@ -471,10 +471,10 @@ static int32_t osdcmd_vidmode(osdfuncparm_t const * const parm)
break;
}
if (videoSetGameMode(newfs,newwidth,newheight,newbpp))
if (videoSetGameMode(newfs,newwidth,newheight,newbpp,upscalefactor))
{
initprintf("vidmode: Mode change failed!\n");
if (videoSetGameMode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP))
if (videoSetGameMode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP, upscalefactor))
G_GameExit("vidmode: Reset failed!\n");
}
ud.config.ScreenBPP = newbpp;
@ -1490,7 +1490,14 @@ static int32_t osdcmd_cvar_set_game(osdfuncparm_t const * const parm)
if (r != OSDCMD_OK) return r;
if (!Bstrcasecmp(parm->name, "r_size"))
if (!Bstrcasecmp(parm->name, "r_upscalefactor"))
{
if (in3dmode())
{
videoSetGameMode(fullscreen, xres, yres, bpp, ud.detail);
}
}
else if (!Bstrcasecmp(parm->name, "r_size"))
{
ud.statusbarmode = (ud.screen_size < 8);
G_UpdateScreenArea();
@ -1709,7 +1716,7 @@ int32_t registerosdcommands(void)
{ "r_shadows", "enable/disable sprite and model shadows", (void *)&ud.shadows, CVAR_BOOL, 0, 1 },
{ "r_size", "change size of viewable area", (void *)&ud.screen_size, CVAR_INT|CVAR_FUNCPTR, 0, 64 },
{ "r_rotatespritenowidescreen", "pass bit 1024 to all CON rotatesprite calls", (void *)&g_rotatespriteNoWidescreen, CVAR_BOOL|CVAR_FUNCPTR, 0, 1 },
{ "r_pixeldoubling", "enable/disable pixel doubling in the software renderer", (void *) &ud.detail, CVAR_BOOL, 0, 1 },
{ "r_upscalefactor", "increase performance by rendering at upscalefactor less than the screen resolution and upscale to the full resolution in the software renderer", (void *)&ud.detail, CVAR_INT|CVAR_FUNCPTR, 1, 16 },
{ "r_precache", "enable/disable the pre-level caching routine", (void *)&ud.config.useprecache, CVAR_BOOL, 0, 1 },
{ "r_ambientlight", "sets the global map light level",(void *)&r_ambientlight, CVAR_FLOAT|CVAR_FUNCPTR, 0, 10 },

View file

@ -30,9 +30,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# include "lunatic_game.h"
#endif
halfdimen_t g_halfScreen;
int32_t g_halveScreenArea = 0;
static int32_t g_whichPalForPlayer = 9;
static uint8_t precachehightile[2][MAXTILES>>3];
@ -566,19 +563,6 @@ void G_UpdateScreenArea(void)
y2 = ud.returnvar[2];
}
if (g_halveScreenArea)
{
int32_t ourxdimen=x2-x1, ourydimen=y2-y1;
g_halfScreen.x1 = x1;
g_halfScreen.y1 = y1;
g_halfScreen.xdimen = (ourxdimen>>1);
g_halfScreen.ydimen = (ourydimen>>1);
x2 = x1 + (ourxdimen>>1);
y2 = y1 + (ourydimen>>1);
}
videoSetViewableArea(x1,y1,x2-1,y2-1);
}
@ -1772,7 +1756,7 @@ int G_EnterLevel(int gameMode)
FX_StopAllSounds();
S_ClearSoundLocks();
FX_SetReverb(0);
videoSetGameMode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP);
videoSetGameMode(ud.config.ScreenMode, ud.config.ScreenWidth, ud.config.ScreenHeight, ud.config.ScreenBPP, upscalefactor);
}
if (Menu_HaveUserMap())

View file

@ -27,14 +27,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
extern "C" {
#endif
typedef struct {
int32_t x1, y1;
int32_t xdimen, ydimen;
} halfdimen_t;
extern halfdimen_t g_halfScreen;
extern int32_t g_halveScreenArea;
extern int32_t g_levelTextTime;
extern int32_t voting,vote_map,vote_episode;
extern palette_t CrosshairColors;

View file

@ -1212,7 +1212,7 @@ void G_DisplayRest(int32_t smoothratio)
int32_t a = VM_OnEventWithReturn(EVENT_DISPLAYPOINTER, g_player[screenpeek].ps->i, screenpeek, CROSSHAIR);
if ((unsigned) a < MAXTILES)
{
vec2_t pointerpos = { ud.returnvar[0], ud.returnvar[1] };
vec2_t pointerpos = { tabledivide32(ud.returnvar[0], upscalefactor), tabledivide32(ud.returnvar[1], upscalefactor) };
uint8_t pointer_pal = CROSSHAIR_PAL;
uint32_t pointer_o = 1|2;
uint32_t pointer_scale = 65536;