mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
Fixed logic for clearing bottom layer. Added new functions to 2D renderer interface. Avoid drawing top and bottom surfaces when no layers are present there. Added some comments to tile
This commit is contained in:
parent
5d048958b9
commit
9249eaa29f
|
@ -28,7 +28,6 @@
|
|||
* ----------
|
||||
* - Is there a better way to handle the overscan regions in wide screen mode?
|
||||
* Is clearing two thin viewports better than one big clear?
|
||||
* - Layer priorities in Spikeout attract mode might not be totally correct.
|
||||
* - Are v-scroll values 9 or 10 bits? (Does it matter?) Lost World seems to
|
||||
* have some scrolling issues.
|
||||
* - A proper shut-down function is needed! OpenGL might not be available when
|
||||
|
@ -72,8 +71,12 @@
|
|||
*
|
||||
* Bits 'pqrs' control the color depth of layers B', B, A', and A,
|
||||
* respectively. If set, the layer's pattern data is encoded as 4 bits,
|
||||
* otherwise the pixels are 8 bits. Bits 'tuvw' form a 4-bit priority code. The
|
||||
* other bits are unused or unknown.
|
||||
* otherwise the pixels are 8 bits.
|
||||
*
|
||||
* Bits 'tuvw' control priority for layers B', B, A', and A, respectively,
|
||||
* which is also the relative ordering of the layers from bottom to top. For
|
||||
* each layer, if its bit is clear, it will be drawn below the 3D layer,
|
||||
* otherwise it is drawn on top.
|
||||
*
|
||||
* The remaining registers are described where appropriate further below.
|
||||
*
|
||||
|
@ -416,16 +419,19 @@ static void DrawLayer(uint32_t *pixels, int layerNum, const uint32_t *vram, cons
|
|||
int pixelOffset = -hFine;
|
||||
int extraTile = (hFine != 0) ? 1 : 0; // h-scrolling requires part of 63rd tile
|
||||
|
||||
// First tile may be clipped
|
||||
int tx = 0;
|
||||
DrawTileLine<bits, alphaTest, true>(line, pixelOffset, nameTable[(hTile ^ 1) & 63], vFine, vram, palette, mask);
|
||||
++hTile;
|
||||
pixelOffset += 8;
|
||||
// Middle tiles will not be clipped
|
||||
for (tx = 1; tx < (62 - 1 + extraTile); tx++)
|
||||
{
|
||||
DrawTileLine<bits, alphaTest, false>(line, pixelOffset, nameTable[(hTile ^ 1) & 63], vFine, vram, palette, mask);
|
||||
++hTile;
|
||||
pixelOffset += 8;
|
||||
}
|
||||
// Last tile may be clipped
|
||||
DrawTileLine<bits, alphaTest, true>(line, pixelOffset, nameTable[(hTile ^ 1) & 63], vFine, vram, palette, mask);
|
||||
++hTile;
|
||||
pixelOffset += 8;
|
||||
|
@ -436,20 +442,22 @@ static void DrawLayer(uint32_t *pixels, int layerNum, const uint32_t *vram, cons
|
|||
}
|
||||
}
|
||||
|
||||
bool CRender2D::DrawTilemaps(uint32_t *pixelsBottom, uint32_t *pixelsTop)
|
||||
std::pair<bool, bool> CRender2D::DrawTilemaps(uint32_t *pixelsBottom, uint32_t *pixelsTop)
|
||||
{
|
||||
unsigned priority = (m_regs[0x20/4] >> 8) & 0xF;
|
||||
|
||||
// Render bottom layers
|
||||
bool nothingDrawn = true;
|
||||
for (int layerNum = 3; layerNum >= 0; layerNum--)
|
||||
bool noBottomSurface = true;
|
||||
static const int bottomOrder[4] = { 3, 2, 1, 0 };
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int layerNum = bottomOrder[i];
|
||||
bool is4Bit = (m_regs[0x20/4] & (1 << (12 + layerNum))) != 0;
|
||||
bool enabled = (m_regs[0x60/4 + layerNum] & 0x80000000) != 0;
|
||||
bool selected = (priority & (1 << layerNum)) == 0;
|
||||
if (enabled && selected)
|
||||
{
|
||||
if (nothingDrawn)
|
||||
if (noBottomSurface)
|
||||
{
|
||||
if (is4Bit)
|
||||
DrawLayer<4, false>(pixelsBottom, layerNum, m_vram, m_regs, m_palette[layerNum / 2]);
|
||||
|
@ -463,23 +471,25 @@ bool CRender2D::DrawTilemaps(uint32_t *pixelsBottom, uint32_t *pixelsTop)
|
|||
else
|
||||
DrawLayer<8, true>(pixelsBottom, layerNum, m_vram, m_regs, m_palette[layerNum / 2]);
|
||||
}
|
||||
nothingDrawn = false;
|
||||
noBottomSurface = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (nothingDrawn)
|
||||
ClearLayer(pixelsBottom);
|
||||
|
||||
// Render top layers
|
||||
nothingDrawn = true;
|
||||
for (int layerNum = 3; layerNum >= 0; layerNum--)
|
||||
// NOTE: layer ordering is different according to MAME (which has 3, 2, 0, 1
|
||||
// for top layer). Until I see evidence that this is correct and not a typo,
|
||||
// I will assume consistent layer ordering.
|
||||
bool noTopSurface = true;
|
||||
static const int topOrder[4] = { 3, 2, 1, 0 };
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int layerNum = topOrder[i];
|
||||
bool is4Bit = (m_regs[0x20/4] & (1 << (12 + layerNum))) != 0;
|
||||
bool enabled = (m_regs[0x60/4 + layerNum] & 0x80000000) != 0;
|
||||
bool selected = (priority & (1 << layerNum)) != 0;
|
||||
if (enabled && selected)
|
||||
{
|
||||
if (nothingDrawn)
|
||||
if (noTopSurface)
|
||||
{
|
||||
if (is4Bit)
|
||||
DrawLayer<4, false>(pixelsTop, layerNum, m_vram, m_regs, m_palette[layerNum / 2]);
|
||||
|
@ -493,15 +503,12 @@ bool CRender2D::DrawTilemaps(uint32_t *pixelsBottom, uint32_t *pixelsTop)
|
|||
else
|
||||
DrawLayer<8, true>(pixelsTop, layerNum, m_vram, m_regs, m_palette[layerNum / 2]);
|
||||
}
|
||||
nothingDrawn = false;
|
||||
noTopSurface = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (nothingDrawn)
|
||||
ClearLayer(pixelsTop);
|
||||
|
||||
// Indicate whether color buffer must be cleared because of no bottom layer
|
||||
return nothingDrawn;
|
||||
// Indicate whether top and bottom surfaces have to be rendered
|
||||
return std::pair<bool, bool>(!noTopSurface, !noBottomSurface);
|
||||
}
|
||||
|
||||
|
||||
|
@ -566,30 +573,48 @@ void CRender2D::Setup2D(bool isBottom, bool clearAll)
|
|||
glLoadIdentity();
|
||||
}
|
||||
|
||||
// Bottom layers
|
||||
void CRender2D::BeginFrame(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CRender2D::PreRenderFrame(void)
|
||||
{
|
||||
// Update all layers
|
||||
bool clear = DrawTilemaps(m_bottomSurface, m_topSurface);
|
||||
m_surfaces_present = DrawTilemaps(m_bottomSurface, m_topSurface);
|
||||
glActiveTexture(GL_TEXTURE0); // texture unit 0
|
||||
glBindTexture(GL_TEXTURE_2D, m_texID[0]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 496, 384, GL_RGBA, GL_UNSIGNED_BYTE, m_topSurface);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texID[1]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 496, 384, GL_RGBA, GL_UNSIGNED_BYTE, m_bottomSurface);
|
||||
|
||||
// Display bottom surface
|
||||
Setup2D(true, clear);
|
||||
if (!clear)
|
||||
if (m_surfaces_present.first)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_texID[0]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 496, 384, GL_RGBA, GL_UNSIGNED_BYTE, m_topSurface);
|
||||
}
|
||||
if (m_surfaces_present.second)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_texID[1]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 496, 384, GL_RGBA, GL_UNSIGNED_BYTE, m_bottomSurface);
|
||||
}
|
||||
}
|
||||
|
||||
void CRender2D::RenderFrameBottom(void)
|
||||
{
|
||||
// Display bottom surface if anything was drawn there, else clear everything
|
||||
Setup2D(true, m_surfaces_present.second == false);
|
||||
if (m_surfaces_present.second)
|
||||
DisplaySurface(1, 0.0);
|
||||
}
|
||||
|
||||
// Top layers
|
||||
void CRender2D::RenderFrameTop(void)
|
||||
{
|
||||
// Display top surface only if it exists
|
||||
if (m_surfaces_present.first)
|
||||
{
|
||||
Setup2D(false, false);
|
||||
glEnable(GL_BLEND);
|
||||
DisplaySurface(0, -0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void CRender2D::EndFrame(void)
|
||||
{
|
||||
// Display top surface
|
||||
Setup2D(false, false);
|
||||
glEnable(GL_BLEND);
|
||||
DisplaySurface(0, -0.5);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,31 @@ public:
|
|||
* drawing anything.
|
||||
*/
|
||||
void BeginFrame(void);
|
||||
|
||||
/*
|
||||
* PreRenderFrame(void):
|
||||
*
|
||||
* Draws the all top layers (above 3D graphics) and bottom layers (below 3D
|
||||
* graphics) but does not yet display them. May send data to the GPU.
|
||||
*/
|
||||
void PreRenderFrame(void);
|
||||
|
||||
/*
|
||||
* RenderFrameBottom(void):
|
||||
*
|
||||
* Overwrites the color buffer with bottom surface that was pre-rendered by
|
||||
* the last call to PreRenderFrame().
|
||||
*/
|
||||
void RenderFrameBottom(void);
|
||||
|
||||
/*
|
||||
* RenderFrameTop(void):
|
||||
*
|
||||
* Draws the top surface (if it exists) that was pre-rendered by the last
|
||||
* call to PreRenderFrame(). Previously drawn graphics layers will be visible
|
||||
* through transparent regions.
|
||||
*/
|
||||
void RenderFrameTop(void);
|
||||
|
||||
/*
|
||||
* EndFrame(void):
|
||||
|
@ -144,7 +169,7 @@ public:
|
|||
|
||||
private:
|
||||
// Private member functions
|
||||
bool DrawTilemaps(uint32_t *destBottom, uint32_t *destTop);
|
||||
std::pair<bool, bool> DrawTilemaps(uint32_t *destBottom, uint32_t *destTop);
|
||||
void DisplaySurface(int surface, GLfloat z);
|
||||
void Setup2D(bool isBottom, bool clearAll);
|
||||
|
||||
|
@ -169,6 +194,9 @@ private:
|
|||
GLuint m_fragmentShader; // fragment shader
|
||||
GLuint m_textureMapLoc; // location of "textureMap" uniform
|
||||
|
||||
// PreRenderFrame() tracks which surfaces exist in current frame
|
||||
std::pair<bool, bool> m_surfaces_present = std::pair<bool, bool>(false, false);
|
||||
|
||||
// Buffers
|
||||
uint8_t *m_memoryPool = 0; // all memory is allocated here
|
||||
uint32_t *m_topSurface = 0; // 512x384x32bpp pixel surface for top layers
|
||||
|
|
|
@ -2139,7 +2139,10 @@ void CModel3::RenderFrame(void)
|
|||
// Render frame
|
||||
TileGen.BeginFrame();
|
||||
GPU.BeginFrame();
|
||||
TileGen.PreRenderFrame();
|
||||
TileGen.RenderFrameBottom();
|
||||
GPU.RenderFrame();
|
||||
TileGen.RenderFrameTop();
|
||||
GPU.EndFrame();
|
||||
TileGen.EndFrame();
|
||||
}
|
||||
|
|
|
@ -243,6 +243,21 @@ void CTileGen::BeginFrame(void)
|
|||
Render2D->BeginFrame();
|
||||
}
|
||||
|
||||
void CTileGen::PreRenderFrame(void)
|
||||
{
|
||||
Render2D->PreRenderFrame();
|
||||
}
|
||||
|
||||
void CTileGen::RenderFrameBottom(void)
|
||||
{
|
||||
Render2D->RenderFrameBottom();
|
||||
}
|
||||
|
||||
void CTileGen::RenderFrameTop(void)
|
||||
{
|
||||
Render2D->RenderFrameTop();
|
||||
}
|
||||
|
||||
void CTileGen::EndFrame(void)
|
||||
{
|
||||
Render2D->EndFrame();
|
||||
|
|
|
@ -88,16 +88,51 @@ public:
|
|||
*
|
||||
* Prepares to render a new frame. Must be called once per frame prior to
|
||||
* drawing anything and must only access read-only snapshots and variables
|
||||
* since it may be running in a separate thread.
|
||||
* since it may be running in a separate thread.
|
||||
*
|
||||
* Invokes the underlying 2D renderer.
|
||||
*/
|
||||
void BeginFrame(void);
|
||||
|
||||
/*
|
||||
* PreRenderFrame(void):
|
||||
*
|
||||
* Draws the all top layers (above 3D graphics) and bottom layers (below 3D
|
||||
* graphics) but does not yet display them. May send data to the GPU.
|
||||
*
|
||||
* Invokes the equivalent method in the underlying 2D renderer.
|
||||
*/
|
||||
void PreRenderFrame(void);
|
||||
|
||||
/*
|
||||
* RenderFrameBottom(void):
|
||||
*
|
||||
* Overwrites the color buffer with bottom surface that was pre-rendered by
|
||||
* the last call to PreRenderFrame().
|
||||
*
|
||||
* Invokes the equivalent method in the underlying 2D renderer.
|
||||
*/
|
||||
void RenderFrameBottom(void);
|
||||
|
||||
/*
|
||||
* RenderFrameTop(void):
|
||||
*
|
||||
* Draws the top surface (if it exists) that was pre-rendered by the last
|
||||
* call to PreRenderFrame(). Previously drawn graphics layers will be visible
|
||||
* through transparent regions.
|
||||
*
|
||||
* Invokes the equivalent method in the underlying 2D renderer.
|
||||
*/
|
||||
void RenderFrameTop(void);
|
||||
|
||||
/*
|
||||
* EndFrame(void):
|
||||
*
|
||||
* Signals the end of rendering for this frame. Must be called last during
|
||||
* the frame and must only access read-only snapshots and variables since it
|
||||
* may be running in a separate thread.
|
||||
*
|
||||
* Invokes the equivalent method in the underlying 2D renderer.
|
||||
*/
|
||||
void EndFrame(void);
|
||||
|
||||
|
|
Loading…
Reference in a new issue