#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 #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); } 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); } } #define U(i) currentShader->uniformLocations[i] void defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) { Material *m; RGBAf col; GLfloat surfProps[4]; setWorldMatrix(atomic->getFrame()->getLTM()); lightingCB(atomic); #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 InstanceData *inst = header->inst; int32 n = header->numMeshes; defaultShader->use(); while(n--){ m = inst->material; convColor(&col, &m->color); glUniform4fv(U(u_matColor), 1, (GLfloat*)&col); surfProps[0] = m->surfaceProps.ambient; surfProps[1] = m->surfaceProps.specular; surfProps[2] = m->surfaceProps.diffuse; surfProps[3] = 0.0f; glUniform4fv(U(u_surfProps), 1, surfProps); setTexture(0, m->texture); rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF); drawInst(header, inst); inst++; } #ifndef RW_GL_USE_VAOS disableAttribPointers(header->attribDesc, header->numAttribs); #endif } } } #endif