summaryrefslogtreecommitdiff
path: root/src/gl/gl3skin.cpp
diff options
context:
space:
mode:
authorclaude-bot <[email protected]>2026-07-13 12:40:03 +0000
committerclaude-bot <[email protected]>2026-07-13 12:40:03 +0000
commit847962910f0bff071f3bf07c9abb87764fb6cac3 (patch)
treeddcd429e134c7fd5f72ddc97ced175de8d66fcd0 /src/gl/gl3skin.cpp
downloadlibrw-847962910f0bff071f3bf07c9abb87764fb6cac3.tar.gz
librw-847962910f0bff071f3bf07c9abb87764fb6cac3.zip
Import aap/librw @ masterHEADmaster
Snapshot for re3/reVC vendoring, per @lzcnt. Source: https://github.com/aap/librw (master).
Diffstat (limited to 'src/gl/gl3skin.cpp')
-rw-r--r--src/gl/gl3skin.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/gl/gl3skin.cpp b/src/gl/gl3skin.cpp
new file mode 100644
index 0000000..6b69bbd
--- /dev/null
+++ b/src/gl/gl3skin.cpp
@@ -0,0 +1,366 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#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"
+
+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<<n)){
+ for(a = attribs; a->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);
+ }
+
+#ifdef RW_GL_USE_VAOS
+ glBindVertexArray(header->vao);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
+#endif
+ glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
+ glBufferData(GL_ARRAY_BUFFER, header->totalNumVertex*attribs[0].stride,
+ header->vertexBuffer, GL_STATIC_DRAW);
+#ifdef RW_GL_USE_VAOS
+ setAttribPointers(header->attribDesc, header->numAttribs);
+ glBindVertexArray(0);
+#endif
+}
+
+void
+skinUninstanceCB(Geometry *geo, InstanceDataHeader *header)
+{
+ assert(0 && "can't uninstance");
+}
+
+static float skinMatrices[64*16];
+
+void
+uploadSkinMatrices(Atomic *a)
+{
+ int i;
+ Skin *skin = Skin::get(a->geometry);
+ Matrix *m = (Matrix*)skinMatrices;
+ HAnimHierarchy *hier = Skin::getHierarchy(a);
+
+ if(hier){
+ Matrix *invMats = (Matrix*)skin->inverseMatrices;
+ Matrix tmp;
+
+ assert(skin->numBones == hier->numNodes);
+ if(hier->flags & HAnimHierarchy::LOCALSPACEMATRICES){
+ for(i = 0; i < hier->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 < hier->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 < skin->numBones; i++){
+ m->setIdentity();
+ m++;
+ }
+ }
+ setUniform(u_boneMatrices, skinMatrices);
+}
+
+void
+skinRenderCB(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;
+
+ 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();
+ }
+
+ 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, 64);
+
+ 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
+
+}
+}
+