/* ** 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 "gl_load.h" #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" #include "flatvertices.h" #include "build.h" #include "v_video.h" #include "hw_renderstate.h" #include "hw_viewpointbuffer.h" #include "gl_renderstate.h" extern int16_t numshades; extern TArray matrixArray; //=========================================================================== // // 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 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); screen->mViewpoints->Set2D(OpenGLRenderer::gl_RenderState, xdim, ydim); 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(); } auto tex = cmd.mTexture; if (tex != nullptr && tex->isValid()) { auto tex = cmd.mTexture; SetFadeDisable(true); SetShade(0, numshades); SetTexture(TileFiles.GetTileIndex(tex), tex, cmd.mTranslationId, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : CLAMP_XY); EnableBlend(!(cmd.mRenderStyle.Flags & STYLEF_Alpha1)); UseColorOnly(false); } else { UseColorOnly(true); } switch (cmd.mType) { case F2DDrawer::DrawTypeTriangles: DrawElement(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount, renderState); break; case F2DDrawer::DrawTypeLines: DrawElement(DT_Lines, cmd.mVertIndex, cmd.mVertCount, renderState); 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.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); matrixArray.Resize(1); renderState.Apply(polymostShader, lastState); // actually set the desired state before returning. } static int32_t tint_blood_r = 0, tint_blood_g = 0, tint_blood_b = 0; extern PalEntry palfadergb; void DrawFullscreenBlends() { // These get prepended to the 2D drawer so they must be submitted in reverse order of drawing. if (tint_blood_r | tint_blood_g | tint_blood_b) { PalEntry color2(255, std::max(-tint_blood_r, 0), std::max(-tint_blood_g, 0), std::max(-tint_blood_b, 0)); twod->AddColorOnlyQuad(0, 0, twod->GetWidth(), twod->GetHeight(), color2, &LegacyRenderStyles[STYLE_Subtract], true); PalEntry color(255, std::max(tint_blood_r, 0), std::max(tint_blood_g, 0), std::max(tint_blood_b, 0)); twod->AddColorOnlyQuad(0, 0, twod->GetWidth(), twod->GetHeight(), color, &LegacyRenderStyles[STYLE_Add], true); } if (palfadergb.a > 0) { twod->AddColorOnlyQuad(0, 0, twod->GetWidth(), twod->GetHeight(), palfadergb, &LegacyRenderStyles[STYLE_Translucent], true); } } void DrawRateStuff(); void Draw2D(F2DDrawer* drawer, FRenderState& state) { ::DrawFullscreenBlends(); DrawRateStuff(); GLInterface.Draw2D(twod); } void videoTintBlood(int32_t r, int32_t g, int32_t b) { tint_blood_r = r; tint_blood_g = g; tint_blood_b = b; }