raze-gles/source/glbackend/hw_draw2d.cpp
Christoph Oelckers 6c6874cb0e - fixed scissoring with out of range coordinates.
Blood's status bar sets such a bogus clipping rectangle.
2020-01-05 10:21:34 +01:00

305 lines
9.2 KiB
C++

/*
** hw_draw2d.cpp
** 2d drawer Renderer interface
**
**---------------------------------------------------------------------------
** Copyright 2018-2019 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "cmdlib.h"
#include "gl_buffers.h"
#include "v_2ddrawer.h"
#include "c_cvars.h"
#include "glbackend.h"
#include "v_draw.h"
#include "palette.h"
extern int16_t numshades;
//===========================================================================
//
// Vertex buffer for 2D drawer
//
//===========================================================================
class F2DVertexBuffer
{
IVertexBuffer *mVertexBuffer;
IIndexBuffer *mIndexBuffer;
public:
F2DVertexBuffer()
{
mVertexBuffer = new OpenGLRenderer::GLVertexBuffer();
mIndexBuffer = new OpenGLRenderer::GLIndexBuffer();
static const FVertexBufferAttribute format[] = {
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(F2DDrawer::TwoDVertex, x) },
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(F2DDrawer::TwoDVertex, u) },
{ 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(F2DDrawer::TwoDVertex, color0) }
};
mVertexBuffer->SetFormat(1, 3, sizeof(F2DDrawer::TwoDVertex), format);
}
~F2DVertexBuffer()
{
delete mIndexBuffer;
delete mVertexBuffer;
}
void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount)
{
mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, false);
mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, false);
}
std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const
{
return std::make_pair(mVertexBuffer, mIndexBuffer);
}
};
//===========================================================================
//
// Draws the 2D stuff. This is the version for OpenGL 3 and later.
//
//===========================================================================
void polymost_dorotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat, uint8_t daalpha, uint8_t dablend, int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, int32_t uniqid);
void GLInstance::Draw2D(F2DDrawer *drawer)
{
VSMatrix mat(0);
SetMatrix(Matrix_View, mat.get());
SetMatrix(Matrix_ModelView, mat.get());
SetMatrix(Matrix_Detail, mat.get());
mat.ortho(0, xdim, ydim, 0, -1, 1);
SetMatrix(Matrix_Projection, mat.get());
SetViewport(0, 0, xdim, ydim);
EnableDepthTest(false);
EnableMultisampling(false);
EnableBlend(true);
EnableAlphaTest(true);
SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]);
auto &vertices = drawer->mVertices;
auto &indices = drawer->mIndices;
auto &commands = drawer->mData;
if (commands.Size() == 0)
{
return;
}
if (drawer->mIsFirstPass)
{
for (auto &v : vertices)
{
// Change from BGRA to RGBA
std::swap(v.color0.r, v.color0.b);
}
}
F2DVertexBuffer vb;
vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size());
assert(vb.GetBufferObjects().first && vb.GetBufferObjects().second);
SetVertexBuffer(vb.GetBufferObjects().first, 0, 0);
SetIndexBuffer(vb.GetBufferObjects().second);
SetFadeDisable(true);
for(auto &cmd : commands)
{
int gltrans = -1;
SetRenderStyle(cmd.mRenderStyle);
//state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed));
//state.SetTextureMode(cmd.mDrawMode);
if (cmd.mFlags & F2DDrawer::DTF_Scissor)
{
// scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates
// Note that the origin here is the lower left corner!
int sciX = screen->ScreenToWindowX(cmd.mScissor[0]);
int sciY = screen->ScreenToWindowY(cmd.mScissor[3]);
int sciW = screen->ScreenToWindowX(cmd.mScissor[2]) - sciX;
int sciH = screen->ScreenToWindowY(cmd.mScissor[1]) - sciY;
SetScissor(sciX, sciY, sciW, sciH);
}
else
{
DisableScissor();
}
//state.SetFog(cmd.mColor1, 0);
SetColor(1, 1, 1);
//state.SetColor(1, 1, 1, 1, cmd.mDesaturate);
if (cmd.mTexture != nullptr)
{
auto tex = cmd.mTexture;
if (cmd.mType == F2DDrawer::DrawTypeRotateSprite)
{
// todo: Set up hictinting. (broken as the feature is...)
SetShade(cmd.mRemapIndex >> 16, numshades);
SetFadeDisable(false);
SetTexture(0, tex, cmd.mRemapIndex & 0xffff, 4/*DAMETH_CLAMPED*/, cmd.mFlags & F2DDrawer::DTF_Wrap ? SamplerRepeat : SamplerClampXY);
EnableBlend(!(cmd.mRenderStyle.Flags & STYLEF_Alpha1));
}
else
{
SetFadeDisable(true);
SetShade(0, numshades);
SetNamedTexture(cmd.mTexture, cmd.mRemapIndex, cmd.mFlags & F2DDrawer::DTF_Wrap ? SamplerRepeat : SamplerClampXY);
EnableBlend(true);
}
UseColorOnly(false);
}
else
{
UseColorOnly(true);
}
switch (cmd.mType)
{
case F2DDrawer::DrawTypeTriangles:
case F2DDrawer::DrawTypeRotateSprite:
Draw(DT_TRIANGLES, cmd.mIndexIndex, cmd.mIndexCount);
break;
case F2DDrawer::DrawTypeLines:
Draw(DT_LINES, cmd.mVertIndex, cmd.mVertCount);
break;
case F2DDrawer::DrawTypePoints:
//Draw(DT_POINTS, cmd.mVertIndex, cmd.mVertCount);
break;
}
/*
state.SetObjectColor(0xffffffff);
state.SetObjectColor2(0);
state.SetAddColor(0);
state.EnableTextureMatrix(false);
state.SetEffect(EFF_NONE);
*/
}
//state.SetScissor(-1, -1, -1, -1);
//state.SetRenderStyle(STYLE_Translucent);
ClearBufferState();
UseColorOnly(false);
//state.EnableBrightmap(true);
//state.SetTextureMode(TM_NORMAL);
SetShade(0, numshades);
SetFadeDisable(false);
SetColor(1, 1, 1);
DisableScissor();
//drawer->mIsFirstPass = false;
EnableBlend(true);
EnableMultisampling(true);
}
void fullscreen_tint_gl(PalEntry pe)
{
// Todo: reroute to the 2D drawer
GLInterface.SetIdentityMatrix(Matrix_Projection);
GLInterface.SetIdentityMatrix(Matrix_ModelView);
GLInterface.EnableDepthTest(false);
GLInterface.EnableAlphaTest(false);
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]);
GLInterface.EnableBlend(true);
GLInterface.SetColorub (pe.r, pe.g, pe.b, pe.a);
GLInterface.UseColorOnly(true);
auto data = GLInterface.AllocVertices(3);
auto vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.UseColorOnly(false);
}
void fullscreen_tint_gl_blood(int tint_blood_r, int tint_blood_g, int tint_blood_b)
{
if (!(tint_blood_r | tint_blood_g | tint_blood_b))
return;
GLInterface.SetIdentityMatrix(Matrix_Projection);
GLInterface.SetIdentityMatrix(Matrix_ModelView);
GLInterface.EnableDepthTest(false);
GLInterface.EnableAlphaTest(false);
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Add]);
GLInterface.EnableBlend(true);
GLInterface.UseColorOnly(true);
GLInterface.SetColorub(max(tint_blood_r, 0), max(tint_blood_g, 0), max(tint_blood_b, 0), 255);
auto data = GLInterface.AllocVertices(3);
auto vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Subtract]);
GLInterface.SetColorub(max(-tint_blood_r, 0), max(-tint_blood_g, 0), max(-tint_blood_b, 0), 255);
data = GLInterface.AllocVertices(3);
vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.SetColorub(255, 255, 255, 255);
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]);
GLInterface.UseColorOnly(false);
}
static int32_t tint_blood_r = 0, tint_blood_g = 0, tint_blood_b = 0;
extern palette_t palfadergb;
extern char palfadedelta ;
void DrawFullscreenBlends()
{
if (palfadedelta) fullscreen_tint_gl(PalEntry(palfadedelta, palfadergb.r, palfadergb.g, palfadergb.b));
fullscreen_tint_gl_blood(tint_blood_r, tint_blood_g, tint_blood_b);
}
void videoTintBlood(int32_t r, int32_t g, int32_t b)
{
tint_blood_r = r;
tint_blood_g = g;
tint_blood_b = b;
}