mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-29 15:32:24 +00:00
263 lines
8 KiB
C++
263 lines
8 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 "v_video.h"
|
|
#include "cmdlib.h"
|
|
#include "hwrenderer/data/buffers.h"
|
|
#include "flatvertices.h"
|
|
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
|
#include "hw_clock.h"
|
|
#include "hw_cvars.h"
|
|
#include "hw_renderstate.h"
|
|
#include "r_videoscale.h"
|
|
#include "v_draw.h"
|
|
|
|
//===========================================================================
|
|
//
|
|
// Draws the 2D stuff. This is the version for OpenGL 3 and later.
|
|
//
|
|
//===========================================================================
|
|
|
|
CVAR(Bool, gl_aalines, false, CVAR_ARCHIVE)
|
|
|
|
void Draw2D(F2DDrawer* drawer, FRenderState& state)
|
|
{
|
|
const auto& mScreenViewport = screen->mScreenViewport;
|
|
Draw2D(drawer, state, mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
|
}
|
|
|
|
void Draw2D(F2DDrawer* drawer, FRenderState& state, int x, int y, int width, int height)
|
|
{
|
|
twoD.Clock();
|
|
|
|
state.SetViewport(x, y, width, height);
|
|
screen->mViewpoints->Set2D(state, drawer->GetWidth(), drawer->GetHeight());
|
|
|
|
state.EnableStencil(false);
|
|
state.SetStencil(0, SOP_Keep, SF_AllOn);
|
|
state.Clear(CT_Stencil);
|
|
state.EnableDepthTest(false);
|
|
state.EnableMultisampling(false);
|
|
state.EnableLineSmooth(gl_aalines);
|
|
|
|
auto &vertices = drawer->mVertices;
|
|
auto &indices = drawer->mIndices;
|
|
auto &commands = drawer->mData;
|
|
|
|
if (commands.Size() == 0)
|
|
{
|
|
twoD.Unclock();
|
|
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());
|
|
state.SetVertexBuffer(&vb);
|
|
state.EnableFog(false);
|
|
|
|
for(auto &cmd : commands)
|
|
{
|
|
if (cmd.isSpecial != SpecialDrawCommand::NotSpecial)
|
|
{
|
|
if (cmd.isSpecial == SpecialDrawCommand::EnableStencil)
|
|
{
|
|
state.EnableStencil(cmd.stencilOn);
|
|
}
|
|
else if (cmd.isSpecial == SpecialDrawCommand::SetStencil)
|
|
{
|
|
state.SetStencil(cmd.stencilOffs, cmd.stencilOp, cmd.stencilFlags);
|
|
}
|
|
else if (cmd.isSpecial == SpecialDrawCommand::ClearStencil)
|
|
{
|
|
state.Clear(CT_Stencil);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
state.SetRenderStyle(cmd.mRenderStyle);
|
|
state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed));
|
|
state.EnableFog(2); // Special 2D mode 'fog'.
|
|
state.SetScreenFade(cmd.mScreenFade);
|
|
|
|
state.SetTextureMode(cmd.mDrawMode);
|
|
|
|
int sciX, sciY, sciW, sciH;
|
|
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!
|
|
sciX = screen->ScreenToWindowX(cmd.mScissor[0]);
|
|
sciY = screen->ScreenToWindowY(cmd.mScissor[3]);
|
|
sciW = screen->ScreenToWindowX(cmd.mScissor[2]) - sciX;
|
|
sciH = screen->ScreenToWindowY(cmd.mScissor[1]) - sciY;
|
|
// If coordinates turn out negative, clip to sceen here to avoid undefined behavior.
|
|
if (sciX < 0) sciW += sciX, sciX = 0;
|
|
if (sciY < 0) sciH += sciY, sciY = 0;
|
|
}
|
|
else
|
|
{
|
|
sciX = sciY = sciW = sciH = -1;
|
|
}
|
|
state.SetScissor(sciX, sciY, sciW, sciH);
|
|
|
|
if (cmd.mSpecialColormap[0].a != 0)
|
|
{
|
|
state.SetTextureMode(TM_FIXEDCOLORMAP);
|
|
state.SetObjectColor(cmd.mSpecialColormap[0]);
|
|
state.SetAddColor(cmd.mSpecialColormap[1]);
|
|
}
|
|
state.SetFog(cmd.mColor1, 0);
|
|
state.SetColor(1, 1, 1, 1, cmd.mDesaturate);
|
|
if (cmd.mFlags & F2DDrawer::DTF_Indexed) state.SetSoftLightLevel(cmd.mLightLevel);
|
|
state.SetLightParms(0, 0);
|
|
|
|
state.AlphaFunc(Alpha_Greater, 0.f);
|
|
|
|
if (cmd.useTransform)
|
|
{
|
|
FLOATTYPE m[16] = {
|
|
0.0, 0.0, 0.0, 0.0,
|
|
0.0, 0.0, 0.0, 0.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
0.0, 0.0, 0.0, 1.0
|
|
};
|
|
for (size_t i = 0; i < 2; i++)
|
|
{
|
|
for (size_t j = 0; j < 2; j++)
|
|
{
|
|
m[4 * j + i] = (FLOATTYPE) cmd.transform.Cells[i][j];
|
|
}
|
|
}
|
|
for (size_t i = 0; i < 2; i++)
|
|
{
|
|
m[4 * 3 + i] = (FLOATTYPE) cmd.transform.Cells[i][2];
|
|
}
|
|
state.mModelMatrix.loadMatrix(m);
|
|
state.EnableModelMatrix(true);
|
|
}
|
|
|
|
if (cmd.mTexture != nullptr && cmd.mTexture->isValid())
|
|
{
|
|
auto flags = cmd.mTexture->GetUseType() >= ETextureType::Special? UF_None : cmd.mTexture->GetUseType() == ETextureType::FontChar? UF_Font : UF_Texture;
|
|
|
|
auto scaleflags = cmd.mFlags & F2DDrawer::DTF_Indexed ? CTF_Indexed : 0;
|
|
state.SetMaterial(cmd.mTexture, flags, scaleflags, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : CLAMP_XY_NOMIP, cmd.mTranslationId, -1);
|
|
state.EnableTexture(true);
|
|
|
|
// Canvas textures are stored upside down
|
|
if (cmd.mTexture->isHardwareCanvas())
|
|
{
|
|
state.mTextureMatrix.loadIdentity();
|
|
state.mTextureMatrix.scale(1.f, -1.f, 1.f);
|
|
state.mTextureMatrix.translate(0.f, 1.f, 0.0f);
|
|
state.EnableTextureMatrix(true);
|
|
}
|
|
if (cmd.mFlags & F2DDrawer::DTF_Burn)
|
|
{
|
|
state.SetEffect(EFF_BURN);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
state.EnableTexture(false);
|
|
}
|
|
|
|
if (cmd.shape2DBufInfo != nullptr)
|
|
{
|
|
state.SetVertexBuffer(&cmd.shape2DBufInfo->buffers[cmd.shape2DBufIndex]);
|
|
state.DrawIndexed(DT_Triangles, 0, cmd.shape2DIndexCount);
|
|
state.SetVertexBuffer(&vb);
|
|
if (cmd.shape2DCommandCounter == cmd.shape2DBufInfo->lastCommand)
|
|
{
|
|
cmd.shape2DBufInfo->lastCommand = -1;
|
|
if (cmd.shape2DBufInfo->bufIndex > 0)
|
|
{
|
|
cmd.shape2DBufInfo->needsVertexUpload = true;
|
|
cmd.shape2DBufInfo->buffers.Clear();
|
|
cmd.shape2DBufInfo->bufIndex = -1;
|
|
}
|
|
}
|
|
cmd.shape2DBufInfo->uploadedOnce = false;
|
|
}
|
|
else
|
|
{
|
|
switch (cmd.mType)
|
|
{
|
|
default:
|
|
case F2DDrawer::DrawTypeTriangles:
|
|
state.DrawIndexed(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount);
|
|
break;
|
|
|
|
case F2DDrawer::DrawTypeLines:
|
|
state.Draw(DT_Lines, cmd.mVertIndex, cmd.mVertCount);
|
|
break;
|
|
|
|
case F2DDrawer::DrawTypePoints:
|
|
state.Draw(DT_Points, cmd.mVertIndex, cmd.mVertCount);
|
|
break;
|
|
|
|
}
|
|
}
|
|
state.SetObjectColor(0xffffffff);
|
|
state.SetObjectColor2(0);
|
|
state.SetAddColor(0);
|
|
state.EnableTextureMatrix(false);
|
|
state.EnableModelMatrix(false);
|
|
state.SetEffect(EFF_NONE);
|
|
|
|
}
|
|
state.SetScissor(-1, -1, -1, -1);
|
|
|
|
state.SetRenderStyle(STYLE_Translucent);
|
|
state.SetVertexBuffer(screen->mVertexData);
|
|
state.EnableStencil(false);
|
|
state.SetStencil(0, SOP_Keep, SF_AllOn);
|
|
state.EnableTexture(true);
|
|
state.EnableBrightmap(true);
|
|
state.SetTextureMode(TM_NORMAL);
|
|
state.EnableFog(false);
|
|
state.SetScreenFade(1);
|
|
state.SetSoftLightLevel(255);
|
|
state.ResetColor();
|
|
drawer->mIsFirstPass = false;
|
|
twoD.Unclock();
|
|
}
|