1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-06-25 22:09:35 +00:00
GLideN64/src/TexrectDrawer.cpp
Sergey Lipskiy 0e04b3f902 Fix z coordinate calculation in TexrectDrawer::addRect()
Fixed #1989, Printf debug statements broken in LLE in Multiple Debug/Prototype games.
2019-02-08 19:43:16 +07:00

485 lines
13 KiB
C++

#include <assert.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <Graphics/Context.h>
#include <Graphics/Parameters.h>
#include "DisplayWindow.h"
#include "Textures.h"
#include "RDP.h"
#include "RSP.h"
#include "VI.h"
#include "FrameBuffer.h"
#include "TexrectDrawer.h"
using namespace graphics;
TexrectDrawer::TexrectDrawer()
: m_numRects(0)
, m_otherMode(0)
, m_mux(0)
, m_ulx(0)
, m_lrx(0)
, m_uly(0)
, m_lry(0)
, m_ulx_i(0)
, m_uly_i(0)
, m_lry_i(0)
, m_Z(0)
, m_max_lrx(0)
, m_max_lry(0)
, m_stepY(0.0f)
, m_stepX(0.0f)
, m_scissor(gDPScissor())
, m_pTexture(nullptr)
, m_pBuffer(nullptr)
{}
void TexrectDrawer::init()
{
const FramebufferTextureFormats & fbTexFormats = gfxContext.getFramebufferTextureFormats();
m_FBO = gfxContext.createFramebuffer();
m_pTexture = textureCache().addFrameBufferTexture(false);
m_pTexture->format = G_IM_FMT_RGBA;
m_pTexture->clampS = 1;
m_pTexture->clampT = 1;
m_pTexture->frameBufferTexture = CachedTexture::fbOneSample;
m_pTexture->maskS = 0;
m_pTexture->maskT = 0;
m_pTexture->mirrorS = 0;
m_pTexture->mirrorT = 0;
m_pTexture->realWidth = 640;
m_pTexture->realHeight = 580;
m_pTexture->textureBytes = m_pTexture->realWidth * m_pTexture->realHeight * fbTexFormats.colorFormatBytes;
m_stepX = 2.0f / 640.0f;
m_stepY = 2.0f / 580.0f;
Context::InitTextureParams initParams;
initParams.handle = m_pTexture->name;
initParams.textureUnitIndex = textureIndices::Tex[0];
initParams.width = m_pTexture->realWidth;
initParams.height = m_pTexture->realHeight;
initParams.internalFormat = fbTexFormats.colorInternalFormat;
initParams.format = fbTexFormats.colorFormat;
initParams.dataType = fbTexFormats.colorType;
gfxContext.init2DTexture(initParams);
Context::TexParameters texParams;
texParams.handle = m_pTexture->name;
texParams.target = textureTarget::TEXTURE_2D;
texParams.textureUnitIndex = textureIndices::Tex[0];
texParams.minFilter = textureParameters::FILTER_LINEAR;
texParams.magFilter = textureParameters::FILTER_LINEAR;
gfxContext.setTextureParameters(texParams);
Context::FrameBufferRenderTarget bufTarget;
bufTarget.bufferHandle = m_FBO;
bufTarget.bufferTarget = bufferTarget::DRAW_FRAMEBUFFER;
bufTarget.attachment = bufferAttachment::COLOR_ATTACHMENT0;
bufTarget.textureTarget = textureTarget::TEXTURE_2D;
bufTarget.textureHandle = m_pTexture->name;
gfxContext.addFrameBufferRenderTarget(bufTarget);
// check if everything is OK
assert(!gfxContext.isFramebufferError());
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, ObjectHandle::defaultFramebuffer);
m_programTex.reset(gfxContext.createTexrectDrawerDrawShader());
m_programClear.reset(gfxContext.createTexrectDrawerClearShader());
m_programTex->setTextureSize(m_pTexture->realWidth, m_pTexture->realHeight);
m_vecRectCoords.reserve(256);
}
void TexrectDrawer::destroy()
{
gfxContext.deleteFramebuffer(m_FBO);
if (m_pTexture != nullptr) {
textureCache().removeFrameBufferTexture(m_pTexture);
m_pTexture = nullptr;
}
m_programTex.reset();
m_programClear.reset();
}
void TexrectDrawer::_setViewport() const
{
const u32 bufferWidth = m_pBuffer == nullptr ? VI.width : m_pBuffer->m_width;
gfxContext.setViewport(0, 0, bufferWidth, VI_GetMaxBufferHeight(bufferWidth));
}
void TexrectDrawer::_setDrawBuffer()
{
if (m_pBuffer != nullptr)
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, m_pBuffer->m_FBO);
else
frameBufferList().setCurrentDrawBuffer();
}
TexrectDrawer::iRect TexrectDrawer::_getiRect(u32 w0, u32 w1) const
{
iRect rect;
rect.ulx = _SHIFTR(w1, 12, 12);
rect.uly = _SHIFTR(w1, 0, 12);
rect.lrx = _SHIFTR(w0, 12, 12);
rect.lry = _SHIFTR(w0, 0, 12);
return rect;
}
#define COMPARE_COORDS(a, b) std::abs(a - b) <= 4
bool TexrectDrawer::_lookAhead(bool _checkCoordinates) const
{
if (RSP.LLE)
return true;
switch (GBI.getMicrocodeType()) {
case Turbo3D:
case T3DUX:
case F5Rogue:
case F5Indi_Naboo:
return true;
}
auto sideBySide = [&](u32 pc) ->bool {
const u32 w0 = *(u32*)&RDRAM[pc];
const u32 w1 = *(u32*)&RDRAM[pc + 4];
const iRect nextRect = _getiRect(w0, w1);
if (COMPARE_COORDS(m_curRect.ulx, nextRect.ulx)) {
bool sbs = COMPARE_COORDS(m_curRect.lry, nextRect.uly);
sbs |= COMPARE_COORDS(m_curRect.uly, nextRect.lry);
return sbs;
}
if (COMPARE_COORDS(m_curRect.uly, nextRect.uly)) {
bool sbs = COMPARE_COORDS(m_curRect.lrx, nextRect.ulx);
sbs |= COMPARE_COORDS(m_curRect.ulx, nextRect.lrx);
return sbs;
}
return false;
};
u32 pc = RSP.PC[RSP.PCi];
while (true) {
switch (_SHIFTR(*(u32*)&RDRAM[pc], 24, 8)) {
case G_RDPLOADSYNC:
case G_RDPPIPESYNC:
case G_RDPTILESYNC:
case G_LOADTLUT:
case G_SETTILESIZE:
case G_LOADBLOCK:
case G_LOADTILE:
case G_SETTILE:
case G_SETTIMG:
break;
case G_TEXRECT:
case G_TEXRECTFLIP:
if (_checkCoordinates)
return sideBySide(pc);
return true;
default:
return false;
}
pc += 8;
}
return false;
}
bool TexrectDrawer::addRect()
{
DisplayWindow & wnd = dwnd();
GraphicsDrawer & drawer = wnd.getDrawer();
RectVertex * pRect = drawer.m_rect;
m_curRect = _getiRect(RDP.w0, RDP.w1);
bool bDownUp = false;
if (m_numRects != 0) {
bool bContinue = false;
if (m_otherMode == gDP.otherMode._u64 && m_mux == gDP.combine.mux) {
if (COMPARE_COORDS(m_ulx_i, m_curRect.ulx)) {
bContinue = COMPARE_COORDS(m_lry_i, m_curRect.uly);
bDownUp = COMPARE_COORDS(m_uly_i, m_curRect.lry);
bContinue |= bDownUp;
}
else {
for (auto iter = m_vecRectCoords.crbegin(); iter != m_vecRectCoords.crend(); ++iter) {
if (COMPARE_COORDS(iter->x, m_curRect.ulx) && COMPARE_COORDS(iter->y, m_curRect.uly)) {
bContinue = true;
break;
}
}
}
}
if (!bContinue) {
draw();
drawer._updateStates(DrawingState::TexRect);
gfxContext.enable(enable::CULL_FACE, false);
}
}
if (m_numRects == 0) {
if (!_lookAhead(true))
return false;
m_numRects = 1;
m_pBuffer = frameBufferList().getCurrent();
m_otherMode = gDP.otherMode._u64;
m_mux = gDP.combine.mux;
m_Z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : 0.0f;
m_scissor = gDP.scissor;
m_ulx = pRect[0].x;
m_uly = pRect[0].y;
m_lrx = m_max_lrx = pRect[3].x;
m_lry = m_max_lry = pRect[3].y;
m_ulx_i = m_curRect.ulx;
m_uly_i = m_curRect.uly;
m_lry_i = m_curRect.lry;
CombinerInfo & cmbInfo = CombinerInfo::get();
cmbInfo.update();
cmbInfo.updateParameters();
gfxContext.enableDepthWrite(false);
gfxContext.enable(enable::DEPTH_TEST, false);
gfxContext.enable(enable::BLEND, false);
_setViewport();
gfxContext.setScissor((s32)gDP.scissor.ulx, (s32)gDP.scissor.uly, (s32)(gDP.scissor.lrx - gDP.scissor.ulx), (s32)(gDP.scissor.lry - gDP.scissor.uly));
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, m_FBO);
} else {
++m_numRects;
}
if (bDownUp) {
m_ulx = pRect[0].x;
m_uly = pRect[0].y;
m_ulx_i = m_curRect.ulx;
m_uly_i = m_curRect.uly;
} else {
m_lrx = pRect[3].x;
m_lry = pRect[3].y;
m_max_lrx = std::max(m_max_lrx, m_lrx);
m_max_lry = std::max(m_max_lry, m_lry);
m_lry_i = m_curRect.lry;
}
RectCoords coords;
coords.x = m_curRect.lrx;
coords.y = m_curRect.uly;
m_vecRectCoords.push_back(coords);
coords.x = m_curRect.lrx;
coords.y = m_curRect.lry;
m_vecRectCoords.push_back(coords);
Context::DrawRectParameters rectParams;
rectParams.mode = drawmode::TRIANGLE_STRIP;
rectParams.verticesCount = 4;
rectParams.vertices = pRect;
rectParams.combiner = currentCombiner();
gfxContext.drawRects(rectParams);
if (m_numRects > 1 && !_lookAhead(false))
draw();
return true;
}
void TexrectDrawer::addBackgroundRect()
{
DisplayWindow & wnd = dwnd();
GraphicsDrawer & drawer = wnd.getDrawer();
RectVertex * pRect = drawer.m_rect;
if (m_numRects == 0) {
m_numRects = 1;
m_pBuffer = frameBufferList().getCurrent();
m_otherMode = gDP.otherMode._u64;
m_mux = gDP.combine.mux;
m_Z = (gDP.otherMode.depthSource == G_ZS_PRIM) ? gDP.primDepth.z : gSP.viewport.nearz;
m_scissor = gDP.scissor;
m_ulx = pRect[0].x;
m_uly = pRect[0].y;
m_lrx = m_max_lrx = pRect[3].x;
m_lry = m_max_lry = pRect[3].y;
CombinerInfo & cmbInfo = CombinerInfo::get();
cmbInfo.update();
cmbInfo.updateParameters();
gfxContext.enableDepthWrite(false);
gfxContext.enable(enable::DEPTH_TEST, false);
gfxContext.enable(enable::BLEND, false);
_setViewport();
gfxContext.setScissor((s32)gDP.scissor.ulx, (s32)gDP.scissor.uly, (s32)(gDP.scissor.lrx - gDP.scissor.ulx), (s32)(gDP.scissor.lry - gDP.scissor.uly));
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, m_FBO);
} else {
++m_numRects;
}
m_lrx = pRect[3].x;
m_lry = pRect[3].y;
m_max_lrx = std::max(m_max_lrx, m_lrx);
m_max_lry = std::max(m_max_lry, m_lry);
Context::DrawRectParameters rectParams;
rectParams.mode = drawmode::TRIANGLE_STRIP;
rectParams.verticesCount = 4;
rectParams.vertices = pRect;
rectParams.combiner = currentCombiner();
gfxContext.drawRects(rectParams);
}
bool TexrectDrawer::draw()
{
if (m_numRects == 0)
return false;
ValueKeeper<u64> otherMode(gDP.otherMode._u64, m_otherMode);
ValueKeeper<gDPScissor> scissor(gDP.scissor, m_scissor);
DisplayWindow & wnd = dwnd();
GraphicsDrawer & drawer = wnd.getDrawer();
drawer._setBlendMode();
gDP.changed |= CHANGED_RENDERMODE; // Force update of depth compare parameters
drawer._updateDepthCompare();
int enableAlphaTest = 0;
switch (gDP.otherMode.cycleType) {
case G_CYC_COPY:
if (gDP.otherMode.alphaCompare & G_AC_THRESHOLD)
enableAlphaTest = 1;
break;
case G_CYC_1CYCLE:
case G_CYC_2CYCLE:
if (((gDP.otherMode.alphaCompare & G_AC_THRESHOLD) != 0) && (gDP.otherMode.alphaCvgSel == 0) && (gDP.otherMode.forceBlender == 0 || gDP.blendColor.a > 0))
enableAlphaTest = 1;
else if ((gDP.otherMode.alphaCompare == G_AC_DITHER) && (gDP.otherMode.alphaCvgSel == 0))
enableAlphaTest = 1;
else if (gDP.otherMode.cvgXAlpha != 0)
enableAlphaTest = 1;
break;
}
m_lrx = m_max_lrx;
m_lry = m_max_lry;
RectVertex rect[4];
f32 scaleX, scaleY;
calcCoordsScales(m_pBuffer, scaleX, scaleY);
scaleX *= 2.0f;
scaleY *= 2.0f;
const float s0 = (m_ulx + 1.0f) / scaleX / (float)m_pTexture->realWidth + 0.5f / (float)m_pTexture->realWidth;
const float t0 = (m_lry + 1.0f) / scaleY / (float)m_pTexture->realHeight;// +0.5f / (float)m_pTexture->realHeight;
const float s1 = (m_lrx + 1.0f) / scaleX / (float)m_pTexture->realWidth;
const float t1 = (m_uly + 1.0f) / scaleY / (float)m_pTexture->realHeight;
const float W = 1.0f;
drawer._updateScreenCoordsViewport(m_pBuffer);
textureCache().activateTexture(0, m_pTexture);
// Disable filtering to avoid black outlines
Context::TexParameters texParams;
texParams.handle = m_pTexture->name;
texParams.target = textureTarget::TEXTURE_2D;
texParams.textureUnitIndex = textureIndices::Tex[0];
texParams.minFilter = textureParameters::FILTER_NEAREST;
texParams.magFilter = textureParameters::FILTER_NEAREST;
gfxContext.setTextureParameters(texParams);
m_programTex->activate();
m_programTex->setEnableAlphaTest(enableAlphaTest);
rect[0].x = m_ulx;
rect[0].y = m_lry;
rect[0].z = m_Z;
rect[0].w = W;
rect[0].s0 = s0;
rect[0].t0 = t0;
rect[1].x = m_lrx;
rect[1].y = m_lry;
rect[1].z = m_Z;
rect[1].w = W;
rect[1].s0 = s1;
rect[1].t0 = t0;
rect[2].x = m_ulx;
rect[2].y = m_uly;
rect[2].z = m_Z;
rect[2].w = W;
rect[2].s0 = s0;
rect[2].t0 = t1;
rect[3].x = m_lrx;
rect[3].y = m_uly;
rect[3].z = m_Z;
rect[3].w = W;
rect[3].s0 = s1;
rect[3].t0 = t1;
drawer.updateScissor(m_pBuffer);
_setDrawBuffer();
Context::DrawRectParameters rectParams;
rectParams.mode = drawmode::TRIANGLE_STRIP;
rectParams.verticesCount = 4;
rectParams.vertices = rect;
rectParams.combiner = m_programTex.get();
gfxContext.drawRects(rectParams);
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, m_FBO);
m_programClear->activate();
const f32 ulx = std::max(-1.0f, m_ulx - m_stepX);
const f32 lrx = std::min( 1.0f, m_lrx + m_stepX);
rect[0].x = ulx;
rect[1].x = lrx;
rect[2].x = ulx;
rect[3].x = lrx;
const f32 uly = std::max(-1.0f, m_uly - m_stepY);
const f32 lry = std::min( 1.0f, m_lry + m_stepY);
rect[0].y = uly;
rect[1].y = uly;
rect[2].y = lry;
rect[3].y = lry;
_setViewport();
gfxContext.enable(enable::BLEND, false);
gfxContext.enable(enable::SCISSOR_TEST, false);
rectParams.combiner = m_programClear.get();
gfxContext.drawRects(rectParams);
gfxContext.enable(enable::SCISSOR_TEST, true);
m_pBuffer = frameBufferList().getCurrent();
_setDrawBuffer();
m_numRects = 0;
m_vecRectCoords.clear();
gDP.changed |= CHANGED_COMBINE | CHANGED_SCISSOR | CHANGED_RENDERMODE;
gSP.changed |= CHANGED_VIEWPORT | CHANGED_TEXTURE | CHANGED_GEOMETRYMODE;
return true;
}
bool TexrectDrawer::isEmpty() const
{
return m_numRects == 0;
}
bool TexrectDrawer::canContinue() const
{
return (m_numRects != 0 &&
m_otherMode == gDP.otherMode._u64 &&
m_mux == gDP.combine.mux &&
m_pBuffer == frameBufferList().getCurrent());
}