#include #include #include #include #include "../rwbase.h" #include "../rwerror.h" #include "../rwplg.h" #include "../rwrender.h" #include "../rwengine.h" #include "../rwpipeline.h" #include "../rwobjects.h" #include "../rwanim.h" #include "../rwplugins.h" #include "rwgl3.h" #include "rwgl3shader.h" #include "rwgl3plg.h" #include "rwgl3impl.h" extern bool moreVram; namespace rw { namespace gl3 { #ifdef RW_OPENGL static Shader *skinShader, *skinShader_noAT; //static Shader *skinShader_fullLight, *skinShader_fullLight_noAT; static int32 u_boneMatrices; void skinInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance) { AttribDesc *attribs, *a; bool isPrelit = !!(geo->flags & Geometry::PRELIT); bool hasNormals = !!(geo->flags & Geometry::NORMALS); if(!reinstance){ AttribDesc tmpAttribs[14]; uint32 stride; // // Create attribute descriptions // a = tmpAttribs; stride = 0; // Positions a->index = ATTRIB_POS; a->size = 3; a->type = GL_FLOAT; a->normalized = GL_FALSE; a->offset = stride; stride += 12; a++; // Normals // TODO: compress if(hasNormals){ a->index = ATTRIB_NORMAL; a->size = 3; a->type = GL_FLOAT; a->normalized = GL_FALSE; a->offset = stride; stride += 12; a++; } // Prelighting if(isPrelit){ a->index = ATTRIB_COLOR; a->size = 4; a->type = GL_UNSIGNED_BYTE; a->normalized = GL_TRUE; a->offset = stride; stride += 4; a++; } // Texture coordinates for(int32 n = 0; n < geo->numTexCoordSets; n++){ a->index = ATTRIB_TEXCOORDS0+n; a->size = 2; a->type = GL_FLOAT; a->normalized = GL_FALSE; a->offset = stride; stride += 8; a++; } // Weights a->index = ATTRIB_WEIGHTS; a->size = 4; a->type = GL_FLOAT; a->normalized = GL_FALSE; a->offset = stride; stride += 16; a++; // Indices a->index = ATTRIB_INDICES; a->size = 4; a->type = GL_UNSIGNED_BYTE; a->normalized = GL_FALSE; a->offset = stride; stride += 4; a++; header->numAttribs = a - tmpAttribs; for(a = tmpAttribs; a != &tmpAttribs[header->numAttribs]; a++) a->stride = stride; header->attribDesc = rwNewT(AttribDesc, header->numAttribs, MEMDUR_EVENT | ID_GEOMETRY); memcpy(header->attribDesc, tmpAttribs, header->numAttribs*sizeof(AttribDesc)); // // Allocate vertex buffer // header->vertexBuffer = rwNewT(uint8, header->totalNumVertex*stride, MEMDUR_EVENT | ID_GEOMETRY); assert(header->vbo == 0); glGenBuffers(1, &header->vbo); } Skin *skin = Skin::get(geo); attribs = header->attribDesc; // // Fill vertex buffer // uint8 *verts = header->vertexBuffer; // Positions if(!reinstance || geo->lockedSinceInst&Geometry::LOCKVERTICES){ for(a = attribs; a->index != ATTRIB_POS; a++) ; instV3d(VERT_FLOAT3, verts + a->offset, geo->morphTargets[0].vertices, header->totalNumVertex, a->stride); } // Normals if(hasNormals && (!reinstance || geo->lockedSinceInst&Geometry::LOCKNORMALS)){ for(a = attribs; a->index != ATTRIB_NORMAL; a++) ; instV3d(VERT_FLOAT3, verts + a->offset, geo->morphTargets[0].normals, header->totalNumVertex, a->stride); } // Prelighting if(isPrelit && (!reinstance || geo->lockedSinceInst&Geometry::LOCKPRELIGHT)){ for(a = attribs; a->index != ATTRIB_COLOR; a++) ; instColor(VERT_RGBA, verts + a->offset, geo->colors, header->totalNumVertex, a->stride); } // Texture coordinates for(int32 n = 0; n < geo->numTexCoordSets; n++){ if(!reinstance || geo->lockedSinceInst&(Geometry::LOCKTEXCOORDS<index != ATTRIB_TEXCOORDS0+n; a++) ; instTexCoords(VERT_FLOAT2, verts + a->offset, geo->texCoords[n], header->totalNumVertex, a->stride); } } // Weights if(!reinstance){ for(a = attribs; a->index != ATTRIB_WEIGHTS; a++) ; float *w = skin->weights; instV4d(VERT_FLOAT4, verts + a->offset, (V4d*)w, header->totalNumVertex, a->stride); } // Indices if(!reinstance){ for(a = attribs; a->index != ATTRIB_INDICES; a++) ; // not really colors of course but what the heck instColor(VERT_RGBA, verts + a->offset, (RGBA*)skin->indices, header->totalNumVertex, a->stride); } glBindBuffer(GL_ARRAY_BUFFER, header->vbo); glBufferData(GL_ARRAY_BUFFER, header->totalNumVertex*attribs[0].stride, header->vertexBuffer, GL_STATIC_DRAW); } void skinUninstanceCB(Geometry *geo, InstanceDataHeader *header) { assert(0 && "can't uninstance"); } #define MAX_BONES 24 static float skinMatrices[MAX_BONES*16]; void uploadSkinMatrices(Atomic *a) { int i; Skin *skin = Skin::get(a->geometry); Matrix *m = (Matrix*)skinMatrices; HAnimHierarchy *hier = Skin::getHierarchy(a); int numBones = skin->numBones; if (numBones > MAX_BONES) numBones = MAX_BONES; if(hier){ Matrix *invMats = (Matrix*)skin->inverseMatrices; Matrix tmp; int numNodes = hier->numNodes; if (numNodes > MAX_BONES) numNodes = MAX_BONES; if(hier->flags & HAnimHierarchy::LOCALSPACEMATRICES){ for(i = 0; i < numNodes; i++){ invMats[i].flags = 0; Matrix::mult(m, &invMats[i], &hier->matrices[i]); m++; } }else{ Matrix invAtmMat; Matrix::invert(&invAtmMat, a->getFrame()->getLTM()); for(i = 0; i < numNodes; i++){ invMats[i].flags = 0; Matrix::mult(&tmp, &hier->matrices[i], &invAtmMat); Matrix::mult(m, &invMats[i], &tmp); m++; } } }else{ for(i = 0; i < numBones; i++){ m->setIdentity(); m++; } } setUniform(u_boneMatrices, skinMatrices); } extern "C" int skin; void skinRenderCB(Atomic *atomic, InstanceDataHeader *header) { skin++; 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; uploadSkinMatrices(atomic); 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()) skinShader->use(); else skinShader_noAT->use(); // }else{ // if(getAlphaTest()) // skinShader_fullLight->use(); // else // skinShader_fullLight_noAT->use(); // } // defaultShader->use(); drawInst(header, inst); inst++; } teardownVertexInput(header); } static void* skinOpen(void *o, int32, int32) { skinGlobals.pipelines[PLATFORM_GL3] = makeSkinPipeline(); #include "shaders/simple_fs_gl.inc" #include "shaders/skin_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, skin_vert_src, nil }; const char *vs_fullLight[] = { shaderDecl, "#define DIRECTIONALS\n#define POINTLIGHTS\n#define SPOTLIGHTS\n", header_vert_src, skin_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil }; const char *fs_noAT[] = { shaderDecl, "#define NO_ALPHATEST\n", header_frag_src, simple_frag_src, nil }; skinShader = Shader::create(vs, fs); assert(skinShader); skinShader_noAT = Shader::create(vs, fs_noAT); assert(skinShader_noAT); // // skinShader_fullLight = Shader::create(vs_fullLight, fs); // assert(skinShader_fullLight); // skinShader_fullLight_noAT = Shader::create(vs_fullLight, fs_noAT); // assert(skinShader_fullLight_noAT); return o; } static void* skinClose(void *o, int32, int32) { ((ObjPipeline*)skinGlobals.pipelines[PLATFORM_GL3])->destroy(); skinGlobals.pipelines[PLATFORM_GL3] = nil; skinShader->destroy(); skinShader = nil; skinShader_noAT->destroy(); skinShader_noAT = nil; // skinShader_fullLight->destroy(); // skinShader_fullLight = nil; // skinShader_fullLight_noAT->destroy(); // skinShader_fullLight_noAT = nil; return o; } void initSkin(void) { u_boneMatrices = registerUniform("u_boneMatrices", UNIFORM_MAT4, MAX_BONES); Driver::registerPlugin(PLATFORM_GL3, 0, ID_SKIN, skinOpen, skinClose); } ObjPipeline* makeSkinPipeline(void) { ObjPipeline *pipe = ObjPipeline::create(); pipe->instanceCB = skinInstanceCB; pipe->uninstanceCB = skinUninstanceCB; pipe->renderCB = skinRenderCB; pipe->pluginID = ID_SKIN; pipe->pluginData = 1; return pipe; } #else void initSkin(void) { } #endif } }