diff --git a/src/d3d/rwd3d9.h b/src/d3d/rwd3d9.h index aa716f6..1bdbca0 100644 --- a/src/d3d/rwd3d9.h +++ b/src/d3d/rwd3d9.h @@ -55,9 +55,11 @@ void *createVertexDeclaration(VertexElement *elements); void destroyVertexDeclaration(void *delaration); uint32 getDeclaration(void *declaration, VertexElement *elements); -void drawInst(d3d9::InstanceDataHeader *header, d3d9::InstanceData *inst); +void drawInst_simple(d3d9::InstanceDataHeader *header, d3d9::InstanceData *inst); // Emulate PS2 GS alpha test FB_ONLY case: failed alpha writes to frame- but not to depth buffer void drawInst_GSemu(d3d9::InstanceDataHeader *header, InstanceData *inst); +// This one switches between the above two depending on render state; +void drawInst(d3d9::InstanceDataHeader *header, d3d9::InstanceData *inst); diff --git a/src/gl/gl3device.cpp b/src/gl/gl3device.cpp index a3a70f5..bd1b704 100644 --- a/src/gl/gl3device.cpp +++ b/src/gl/gl3device.cpp @@ -128,6 +128,7 @@ struct RwStateCache { uint32 alphaTestEnable; uint32 alphaFunc; bool32 textureAlpha; + bool32 blendEnable; uint32 srcblend, destblend; uint32 zwrite; uint32 ztest; @@ -135,6 +136,11 @@ struct RwStateCache { uint32 fogEnable; float32 fogStart; float32 fogEnd; + + // emulation of PS2 GS + bool32 gsalpha; + uint32 gsalpharef; + RwRasterStateCache texstage[MAXNUMSTAGES]; }; static RwStateCache rwStateCache; @@ -157,6 +163,21 @@ static uint32 blendMap[] = { GL_SRC_ALPHA_SATURATE, }; +void +setAlphaBlend(bool32 enable) +{ + if(rwStateCache.blendEnable != enable){ + rwStateCache.blendEnable = enable; + (enable ? glEnable : glDisable)(GL_BLEND); + } +} + +bool32 +getAlphaBlend(void) +{ + return rwStateCache.blendEnable; +} + static void setDepthTest(bool32 enable) { @@ -224,7 +245,7 @@ setVertexAlpha(bool32 enable) { if(rwStateCache.vertexAlpha != enable){ if(!rwStateCache.textureAlpha){ - (enable ? glEnable : glDisable)(GL_BLEND); + setAlphaBlend(enable); setAlphaTest(enable); } rwStateCache.vertexAlpha = enable; @@ -343,7 +364,7 @@ setRasterStageOnly(uint32 stage, Raster *raster) if(alpha != rwStateCache.textureAlpha){ rwStateCache.textureAlpha = alpha; if(!rwStateCache.vertexAlpha){ - (alpha ? glEnable : glDisable)(GL_BLEND); + setAlphaBlend(alpha); setAlphaTest(alpha); } } @@ -392,7 +413,7 @@ setRasterStage(uint32 stage, Raster *raster) if(alpha != rwStateCache.textureAlpha){ rwStateCache.textureAlpha = alpha; if(!rwStateCache.vertexAlpha){ - (alpha ? glEnable : glDisable)(GL_BLEND); + setAlphaBlend(alpha); setAlphaTest(alpha); } } @@ -492,6 +513,11 @@ setRenderState(int32 state, void *pvalue) stateDirty = 1; } break; + case GSALPHATEST: + rwStateCache.gsalpha = value; + break; + case GSALPHATESTREF: + rwStateCache.gsalpharef = value; } } @@ -551,6 +577,12 @@ getRenderState(int32 state) case ALPHATESTREF: val = (uint32)(uniformState.alphaRef*255.0f); break; + case GSALPHATEST: + val = rwStateCache.gsalpha; + break; + case GSALPHATESTREF: + val = rwStateCache.gsalpharef; + break; default: val = 0; } @@ -568,13 +600,16 @@ resetRenderState(void) uniformState.fogEnd = 0.0f; uniformState.fogRange = 0.0f; uniformState.fogColor = { 1.0f, 1.0f, 1.0f, 1.0f }; + rwStateCache.gsalpha = 0; + rwStateCache.gsalpharef = 128; stateDirty = 1; rwStateCache.vertexAlpha = 0; rwStateCache.textureAlpha = 0; - glDisable(GL_BLEND); rwStateCache.alphaTestEnable = 0; + rwStateCache.blendEnable = 0; + glDisable(GL_BLEND); rwStateCache.srcblend = BLENDSRCALPHA; rwStateCache.destblend = BLENDINVSRCALPHA; glBlendFunc(blendMap[rwStateCache.srcblend], blendMap[rwStateCache.destblend]); diff --git a/src/gl/gl3matfx.cpp b/src/gl/gl3matfx.cpp index 8f9ecba..f341fb8 100644 --- a/src/gl/gl3matfx.cpp +++ b/src/gl/gl3matfx.cpp @@ -85,9 +85,7 @@ matfxDefaultRender(InstanceDataHeader *header, InstanceData *inst) rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF); - flushCache(); - glDrawElements(header->primType, inst->numIndex, - GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset); + drawInst(header, inst); } static Frame *lastEnvFrame; @@ -152,9 +150,7 @@ matfxEnvRender(InstanceDataHeader *header, InstanceData *inst, MatFX::Env *env) rw::SetRenderState(VERTEXALPHA, 1); rw::SetRenderState(SRCBLEND, BLENDONE); - flushCache(); - glDrawElements(header->primType, inst->numIndex, - GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset); + drawInst(header, inst); rw::SetRenderState(SRCBLEND, BLENDSRCALPHA); } diff --git a/src/gl/gl3render.cpp b/src/gl/gl3render.cpp index 4d6039e..21b32e3 100644 --- a/src/gl/gl3render.cpp +++ b/src/gl/gl3render.cpp @@ -19,7 +19,58 @@ namespace rw { namespace gl3 { -#define MAX_LIGHTS 8 +#define MAX_LIGHTS + +void +drawInst_simple(InstanceDataHeader *header, InstanceData *inst) +{ + flushCache(); + glDrawElements(header->primType, inst->numIndex, + GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset); +} + +// Emulate PS2 GS alpha test FB_ONLY case: failed alpha writes to frame- but not to depth buffer +void +drawInst_GSemu(InstanceDataHeader *header, InstanceData *inst) +{ + uint32 hasAlpha; + int alphafunc, alpharef, gsalpharef; + int zwrite; + hasAlpha = getAlphaBlend(); + if(hasAlpha){ + zwrite = rw::GetRenderState(rw::ZWRITEENABLE); + alphafunc = rw::GetRenderState(rw::ALPHATESTFUNC); + if(zwrite){ + alpharef = rw::GetRenderState(rw::ALPHATESTREF); + gsalpharef = rw::GetRenderState(rw::GSALPHATESTREF); + + SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL); + SetRenderState(rw::ALPHATESTREF, gsalpharef); + drawInst_simple(header, inst); + SetRenderState(rw::ALPHATESTFUNC, rw::ALPHALESS); + SetRenderState(rw::ZWRITEENABLE, 0); + drawInst_simple(header, inst); + SetRenderState(rw::ZWRITEENABLE, 1); + SetRenderState(rw::ALPHATESTFUNC, alphafunc); + SetRenderState(rw::ALPHATESTREF, alpharef); + }else{ + SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAALWAYS); + drawInst_simple(header, inst); + SetRenderState(rw::ALPHATESTFUNC, alphafunc); + } + }else + drawInst_simple(header, inst); +} + +void +drawInst(InstanceDataHeader *header, InstanceData *inst) +{ + if(rw::GetRenderState(rw::GSALPHATEST)) + drawInst_GSemu(header, inst); + else + drawInst_simple(header, inst); +} + void setAttribPointers(AttribDesc *attribDescs, int32 numAttribs) @@ -102,9 +153,7 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF); - flushCache(); - glDrawElements(header->primType, inst->numIndex, - GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset); + drawInst(header, inst); inst++; } disableAttribPointers(header->attribDesc, header->numAttribs); diff --git a/src/gl/gl3skin.cpp b/src/gl/gl3skin.cpp index 182bfb3..f9c3132 100644 --- a/src/gl/gl3skin.cpp +++ b/src/gl/gl3skin.cpp @@ -309,9 +309,7 @@ skinRenderCB(Atomic *atomic, InstanceDataHeader *header) rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF); - flushCache(); - glDrawElements(header->primType, inst->numIndex, - GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset); + drawInst(header, inst); inst++; } disableAttribPointers(header->attribDesc, header->numAttribs); diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index 665b2d2..b7a1022 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -171,10 +171,11 @@ int32 setLights(WorldLights *lightData); // per Mesh void setTexture(int32 n, Texture *tex); +void setAlphaBlend(bool32 enable); +bool32 getAlphaBlend(void); uint32 bindTexture(uint32 texid); - void flushCache(void); #endif @@ -194,6 +195,13 @@ void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header); void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header); int32 lightingCB(Atomic *atomic); +void drawInst_simple(InstanceDataHeader *header, InstanceData *inst); +// Emulate PS2 GS alpha test FB_ONLY case: failed alpha writes to frame- but not to depth buffer +void drawInst_GSemu(InstanceDataHeader *header, InstanceData *inst); +// This one switches between the above two depending on render state; +void drawInst(InstanceDataHeader *header, InstanceData *inst); + + void *destroyNativeData(void *object, int32, int32); ObjPipeline *makeDefaultPipeline(void);