diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 54e0220992..1779a01b7a 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -440,6 +440,29 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: mem_free(pTexData); } +void CCommandProcessorFragment_OpenGL::Cmd_AlphaMask_Begin(const CCommandBuffer::CAlphaMaskBeginCommand *pCommand) +{ + glClear(GL_STENCIL_BUFFER_BIT); + glEnable(GL_STENCIL_TEST); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_ALWAYS, 1, 1); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glAlphaFunc(GL_GREATER, pCommand->m_Threshold); +} + +void CCommandProcessorFragment_OpenGL::Cmd_AlphaMask_End(const CCommandBuffer::CAlphaMaskEndCommand *pCommand) +{ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glAlphaFunc(GL_GREATER, 0); +} + +void CCommandProcessorFragment_OpenGL::Cmd_AlphaMask_Clear(const CCommandBuffer::CAlphaMaskClearCommand *pCommand) +{ + glDisable(GL_STENCIL_TEST); +} + void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::CClearCommand *pCommand) { glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); @@ -521,6 +544,9 @@ bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::CCommand case CCommandBuffer::CMD_TEXTURE_CREATE: Cmd_Texture_Create(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_TEXTURE_DESTROY: Cmd_Texture_Destroy(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_TEXTURE_UPDATE: Cmd_Texture_Update(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_ALPHAMASK_BEGIN: Cmd_AlphaMask_Begin(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_ALPHAMASK_END: Cmd_AlphaMask_End(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_ALPHAMASK_CLEAR: Cmd_AlphaMask_Clear(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_CLEAR: Cmd_Clear(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_RENDER: Cmd_Render(static_cast(pBaseCommand)); break; case CCommandBuffer::CMD_SCREENSHOT: Cmd_Screenshot(static_cast(pBaseCommand)); break; @@ -664,6 +690,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWin // set gl attributes SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); if(FsaaSamples) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 2826e918df..94cf051bf6 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -131,6 +131,9 @@ class CCommandProcessorFragment_OpenGL void Cmd_Texture_Update(const CCommandBuffer::CTextureUpdateCommand *pCommand); void Cmd_Texture_Destroy(const CCommandBuffer::CTextureDestroyCommand *pCommand); void Cmd_Texture_Create(const CCommandBuffer::CTextureCreateCommand *pCommand); + void Cmd_AlphaMask_Begin(const CCommandBuffer::CAlphaMaskBeginCommand *pCommand); + void Cmd_AlphaMask_End(const CCommandBuffer::CAlphaMaskEndCommand *pCommand); + void Cmd_AlphaMask_Clear(const CCommandBuffer::CAlphaMaskClearCommand *pCommand); void Cmd_Clear(const CCommandBuffer::CClearCommand *pCommand); void Cmd_Render(const CCommandBuffer::CRenderCommand *pCommand); void Cmd_Screenshot(const CCommandBuffer::CScreenshotCommand *pCommand); diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 266e67534e..7362664bec 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -178,6 +178,25 @@ void CGraphics_Threaded::ClipDisable() m_State.m_ClipEnable = false; } +void CGraphics_Threaded::AlphaMaskBegin(float Threshold) +{ + CCommandBuffer::CAlphaMaskBeginCommand Cmd; + Cmd.m_Threshold = Threshold; + m_pCommandBuffer->AddCommand(Cmd); +} + +void CGraphics_Threaded::AlphaMaskEnd() +{ + CCommandBuffer::CAlphaMaskEndCommand Cmd; + m_pCommandBuffer->AddCommand(Cmd); +} + +void CGraphics_Threaded::AlphaMaskClear() +{ + CCommandBuffer::CAlphaMaskClearCommand Cmd; + m_pCommandBuffer->AddCommand(Cmd); +} + void CGraphics_Threaded::BlendNone() { m_State.m_BlendMode = CCommandBuffer::BLEND_NONE; diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 98746c1260..8c2589bc26 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -78,6 +78,11 @@ class CCommandBuffer CMD_TEXTURE_DESTROY, CMD_TEXTURE_UPDATE, + // stencil commands + CMD_ALPHAMASK_BEGIN, + CMD_ALPHAMASK_END, + CMD_ALPHAMASK_CLEAR, + // rendering CMD_CLEAR, CMD_RENDER, @@ -251,6 +256,23 @@ class CCommandBuffer int m_Slot; }; + struct CAlphaMaskBeginCommand : public CCommand + { + CAlphaMaskBeginCommand() : CCommand(CMD_ALPHAMASK_BEGIN) {} + + float m_Threshold; + }; + + struct CAlphaMaskEndCommand : public CCommand + { + CAlphaMaskEndCommand() : CCommand(CMD_ALPHAMASK_END) {} + }; + + struct CAlphaMaskClearCommand : public CCommand + { + CAlphaMaskClearCommand() : CCommand(CMD_ALPHAMASK_CLEAR) {} + }; + // CCommandBuffer(unsigned CmdBufferSize, unsigned DataBufferSize) : m_CmdBuffer(CmdBufferSize), m_DataBuffer(DataBufferSize), m_pCmdBufferHead(0), m_pCmdBufferTail(0) @@ -397,6 +419,10 @@ class CGraphics_Threaded : public IEngineGraphics virtual void ClipEnable(int x, int y, int w, int h); virtual void ClipDisable(); + virtual void AlphaMaskBegin(float Threshold); + virtual void AlphaMaskEnd(); + virtual void AlphaMaskClear(); + virtual void BlendNone(); virtual void BlendNormal(); virtual void BlendAdditive(); diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 85319b1b42..a06aad983a 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -124,6 +124,10 @@ class IGraphics : public IInterface virtual void ClipEnable(int x, int y, int w, int h) = 0; virtual void ClipDisable() = 0; + virtual void AlphaMaskBegin(float Threshold = 0.5f) = 0; + virtual void AlphaMaskEnd() = 0; + virtual void AlphaMaskClear() = 0; + virtual void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) = 0; virtual void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) = 0; diff --git a/src/game/client/render.cpp b/src/game/client/render.cpp index 60359397b2..a9ceb74fbb 100644 --- a/src/game/client/render.cpp +++ b/src/game/client/render.cpp @@ -160,6 +160,17 @@ void CRenderTools::RenderTee(CAnimState *pAnim, const CTeeRenderInfo *pInfo, int // draw marking if(pInfo->m_aTextures[SKINPART_MARKING].IsValid() && !OutLine) { + // set stencil + Graphics()->AlphaMaskBegin(); + Graphics()->QuadsBegin(); + Graphics()->QuadsSetRotation(pAnim->GetBody()->m_Angle*pi*2); + Graphics()->SetColor(1, 1, 1, 1); + SelectSprite(SPRITE_TEE_BODY, 0, 0, 0); + Item = BodyItem; + Graphics()->QuadsDraw(&Item, 1); + Graphics()->QuadsEnd(); + Graphics()->AlphaMaskEnd(); + Graphics()->TextureSet(pInfo->m_aTextures[SKINPART_MARKING]); Graphics()->QuadsBegin(); Graphics()->QuadsSetRotation(pAnim->GetBody()->m_Angle*pi*2); @@ -169,6 +180,8 @@ void CRenderTools::RenderTee(CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Item = BodyItem; Graphics()->QuadsDraw(&Item, 1); Graphics()->QuadsEnd(); + + Graphics()->AlphaMaskClear(); } // draw body (in front of marking) @@ -177,7 +190,7 @@ void CRenderTools::RenderTee(CAnimState *pAnim, const CTeeRenderInfo *pInfo, int Graphics()->TextureSet(pInfo->m_aTextures[SKINPART_BODY]); Graphics()->QuadsBegin(); Graphics()->QuadsSetRotation(pAnim->GetBody()->m_Angle*pi*2); - Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + Graphics()->SetColor(pInfo->m_aColors[SKINPART_BODY].r, pInfo->m_aColors[SKINPART_BODY].g, pInfo->m_aColors[SKINPART_BODY].b, pInfo->m_aColors[SKINPART_BODY].a); for(int t = 0; t < 2; t++) { SelectSprite(t==0?SPRITE_TEE_BODY_SHADOW:SPRITE_TEE_BODY_UPPER_OUTLINE, 0, 0, 0);