#include #include #include #include "../rwbase.h" #include "../rwerror.h" #include "../rwplg.h" #include "../rwrender.h" #include "../rwengine.h" #include "../rwpipeline.h" #include "../rwobjects.h" #ifdef RW_OPENGL #include "rwgl3.h" #include "rwgl3shader.h" #include "rwgl3impl.h" namespace rw { namespace gl3 { #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) { AttribDesc *a; for(a = attribDescs; a != &attribDescs[numAttribs]; a++){ glEnableVertexAttribArray(a->index); glVertexAttribPointer(a->index, a->size, a->type, a->normalized, a->stride, (void*)(uint64)a->offset); } } void disableAttribPointers(AttribDesc *attribDescs, int32 numAttribs) { AttribDesc *a; for(a = attribDescs; a != &attribDescs[numAttribs]; a++) glDisableVertexAttribArray(a->index); } void setupVertexInput(InstanceDataHeader *header) { #ifdef RW_GL_USE_VAOS glBindVertexArray(header->vao); #else glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo); glBindBuffer(GL_ARRAY_BUFFER, header->vbo); setAttribPointers(header->attribDesc, header->numAttribs); #endif } void teardownVertexInput(InstanceDataHeader *header) { #ifndef RW_GL_USE_VAOS disableAttribPointers(header->attribDesc, header->numAttribs); #endif } int32 lightingCB(Atomic *atomic) { WorldLights lightData; Light *directionals[8]; Light *locals[8]; lightData.directionals = directionals; lightData.numDirectionals = 8; lightData.locals = locals; lightData.numLocals = 8; if(atomic->geometry->flags & rw::Geometry::LIGHT){ ((World*)engine->currentWorld)->enumerateLights(atomic, &lightData); if((atomic->geometry->flags & rw::Geometry::NORMALS) == 0){ // Get rid of lights that need normals when we don't have any lightData.numDirectionals = 0; lightData.numLocals = 0; } return setLights(&lightData); }else{ memset(&lightData, 0, sizeof(lightData)); return setLights(&lightData); } } void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) { Material *m; uint32 flags = atomic->geometry->flags; setWorldMatrix(atomic->getFrame()->getLTM()); int32 vsBits = lightingCB(atomic); setupVertexInput(header); InstanceData *inst = header->inst; int32 n = header->numMeshes; while(n--){ m = inst->material; setMaterial(flags, m->color, m->surfaceProps); setTexture(0, m->texture); rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF); if((vsBits & VSLIGHT_MASK) == 0){ if(getAlphaTest()) defaultShader->use(); else defaultShader_noAT->use(); }else{ if(getAlphaTest()) defaultShader_fullLight->use(); else defaultShader_fullLight_noAT->use(); } drawInst(header, inst); inst++; } teardownVertexInput(header); } } } #endif