diff --git a/src/graphics/C4DrawGL.h b/src/graphics/C4DrawGL.h index 466456a19..f3e2f9bd3 100644 --- a/src/graphics/C4DrawGL.h +++ b/src/graphics/C4DrawGL.h @@ -205,11 +205,13 @@ public: virtual void PerformMultiLines(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, float width); virtual void PerformMultiTris(C4Surface* sfcTarget, const C4BltVertex* vertices, unsigned int n_vertices, const C4BltTransform* pTransform, C4TexRef* pTex, C4TexRef* pOverlay, C4TexRef* pNormal, DWORD dwOverlayClrMod); // device objects - bool InitShaders(C4GroupSet* pGroups); // load shaders from given group bool RestoreDeviceObjects(); // restore device dependent objects bool InvalidateDeviceObjects(); // free device dependent objects bool DeviceReady() { return !!pMainCtx; } bool EnsureAnyContext(); + bool InitShaders(C4GroupSet* pGroups); // load shaders from given group + C4Shader* GetSpriteShader(int ssc); + C4Shader* GetSpriteShader(bool haveBase, bool haveOverlay, bool haveNormal); protected: bool CreatePrimarySurfaces(unsigned int iXRes, unsigned int iYRes, int iColorDepth, unsigned int iMonitor); @@ -218,8 +220,6 @@ protected: virtual bool Error(const char *szMsg); bool CreateSpriteShader(C4Shader& shader, const char* name, int ssc, C4GroupSet* pGroups); - C4Shader* GetSpriteShader(int ssc); - C4Shader* GetSpriteShader(bool haveBase, bool haveOverlay, bool haveNormal); friend class C4Surface; friend class C4TexRef; diff --git a/src/landscape/C4Particles.cpp b/src/landscape/C4Particles.cpp index e05f016a4..0eadc4753 100644 --- a/src/landscape/C4Particles.cpp +++ b/src/landscape/C4Particles.cpp @@ -971,7 +971,7 @@ bool C4ParticleChunk::Exec(C4Object *obj, float timeDelta) #define glDeleteVertexArrays glDeleteVertexArraysAPPLE #endif -void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj) +void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, int texUnit) { if (particleCount == 0) return; const int stride = sizeof(C4Particle::DrawingData::Vertex); @@ -979,8 +979,6 @@ void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj) C4TexRef *textureRef = (*sourceDefinition->Gfx.GetFace().ppTex); assert(textureRef != 0 && "Particle definition had no texture assigned."); - - // use a relative offset? bool resetMatrix(false); if ((attachment & C4ATTACH_MoveRelative) && (obj != 0)) @@ -990,10 +988,7 @@ void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj) glTranslatef((float)obj->GetX(), (float)obj->GetY(), 0.0f); } - glBlendFunc(GL_SRC_ALPHA, (blitMode & C4GFXBLIT_ADDITIVE) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA); - - glActiveTexture(GL_TEXTURE0); - glClientActiveTexture(GL_TEXTURE0); + glActiveTexture(texUnit); glBindTexture(GL_TEXTURE_2D, textureRef->texName); if (!Particles.useBufferObjectWorkaround) @@ -1138,21 +1133,25 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj) pDraw->DeactivateBlitModulation(); pDraw->ResetBlitMode(); - glEnable(GL_TEXTURE_2D); - if (!Particles.usePrimitiveRestartIndexWorkaround) { glPrimitiveRestartIndex(0xffffffff); glEnable(GL_PRIMITIVE_RESTART); } - // apply zoom - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glTranslatef(cgo.X, cgo.Y, 0.0f); - glScalef(cgo.Zoom, cgo.Zoom, 1.0f); - glTranslatef(-cgo.TargetX, -cgo.TargetY, 0.0f); + // enable shader + C4ShaderCall call(pGL->GetSpriteShader(true, false, false)); + // apply zoom and upload shader uniforms + pGL->SetupMultiBlt(call, NULL, 0, 0, 0, 0); + // go to correct output position + glTranslatef(cgo.X-cgo.TargetX, cgo.Y-cgo.TargetY, 0.0f); + // allocate texture unit for particle texture, and remember allocated + // texture unit. Will be used for each particle chunk to bind + // their texture to this unit. + const GLint texUnit = call.AllocTexUnit(C4SSU_BaseTex, GL_TEXTURE_2D); + // Texture coordinates are always associated to texture unit 0, since + // there is only one set of texture coordinates + glClientActiveTexture(GL_TEXTURE0); if (Particles.useBufferObjectWorkaround) { @@ -1173,13 +1172,15 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj) } else { - (*iter)->Draw(cgo, obj); + (*iter)->Draw(cgo, obj, texUnit); ++iter; } } accessMutex.Leave(); + pGL->ResetMultiBlt(); + if (Particles.useBufferObjectWorkaround) { glDisableClientState(GL_VERTEX_ARRAY); @@ -1187,13 +1188,10 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj) glDisableClientState(GL_TEXTURE_COORD_ARRAY); } - glPopMatrix(); - if (!Particles.usePrimitiveRestartIndexWorkaround) { glDisable(GL_PRIMITIVE_RESTART); } - glDisable(GL_TEXTURE_2D); } void C4ParticleList::Clear() diff --git a/src/landscape/C4Particles.h b/src/landscape/C4Particles.h index 81e6626f2..f2d4597d8 100644 --- a/src/landscape/C4Particles.h +++ b/src/landscape/C4Particles.h @@ -360,7 +360,7 @@ public: // removes all particles void Clear(); bool Exec(C4Object *obj, float timeDelta); - void Draw(C4TargetFacet cgo, C4Object *obj); + void Draw(C4TargetFacet cgo, C4Object *obj, int texUnit); bool IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t attachment) const; bool IsEmpty() const { return !particleCount; }