/* ================= RB_AddIQMSurfaces Compute vertices for this model surface ================= */ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { srfIQModel_t *surf = (srfIQModel_t *)surface; iqmData_t *data = surf->data; float jointMats[IQM_MAX_JOINTS * 12]; int i; vec4_t *outXYZ; uint32_t *outNormal; #ifdef USE_VERT_TANGENT_SPACE uint32_t *outTangent; #endif vec2_t (*outTexCoord)[2]; vec4_t *outColor; int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; float backlerp = backEnd.currentEntity->e.backlerp; int *tri; glIndex_t *ptr; glIndex_t base; RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); outXYZ = &tess.xyz[tess.numVertexes]; outNormal = &tess.normal[tess.numVertexes]; #ifdef USE_VERT_TANGENT_SPACE outTangent = &tess.tangent[tess.numVertexes]; #endif outTexCoord = &tess.texCoords[tess.numVertexes]; outColor = &tess.vertexColors[tess.numVertexes]; // compute interpolated joint matrices if ( data->num_poses > 0 ) { ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); } // transform vertexes and fill other data for( i = 0; i < surf->num_vertexes; i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { int j, k; float vtxMat[12]; float nrmMat[9]; int vtx = i + surf->first_vertex; float blendWeights[4]; int numWeights; for ( numWeights = 0; numWeights < 4; numWeights++ ) { if ( data->blendWeightsType == IQM_FLOAT ) blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; else blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; if ( blendWeights[numWeights] <= 0 ) break; } if ( data->num_poses == 0 || numWeights == 0 ) { // no blend joint, use identity matrix. Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); } else { // compute the vertex matrix by blending the up to // four blend weights Com_Memset( vtxMat, 0, 12 * sizeof (float) ); for( j = 0; j < numWeights; j++ ) { for( k = 0; k < 12; k++ ) { vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; } } } // compute the normal matrix as transpose of the adjoint // of the vertex matrix nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; (*outXYZ)[0] = vtxMat[ 0] * data->positions[3*vtx+0] + vtxMat[ 1] * data->positions[3*vtx+1] + vtxMat[ 2] * data->positions[3*vtx+2] + vtxMat[ 3]; (*outXYZ)[1] = vtxMat[ 4] * data->positions[3*vtx+0] + vtxMat[ 5] * data->positions[3*vtx+1] + vtxMat[ 6] * data->positions[3*vtx+2] + vtxMat[ 7]; (*outXYZ)[2] = vtxMat[ 8] * data->positions[3*vtx+0] + vtxMat[ 9] * data->positions[3*vtx+1] + vtxMat[10] * data->positions[3*vtx+2] + vtxMat[11]; (*outXYZ)[3] = 1.0f; { vec3_t normal; vec4_t tangent; normal[0] = DotProduct(&nrmMat[0], &data->normals[3*vtx]); normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]); normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]); R_VaoPackNormal((byte *)outNormal, normal); #ifdef USE_VERT_TANGENT_SPACE tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]); tangent[1] = DotProduct(&nrmMat[3], &data->tangents[4*vtx]); tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]); tangent[3] = data->tangents[4*vtx+3]; R_VaoPackTangent((byte *)outTangent++, tangent); #endif } (*outColor)[0] = data->colors[4*vtx+0] / 255.0f; (*outColor)[1] = data->colors[4*vtx+1] / 255.0f; (*outColor)[2] = data->colors[4*vtx+2] / 255.0f; (*outColor)[3] = data->colors[4*vtx+3] / 255.0f; } tri = data->triangles + 3 * surf->first_triangle; ptr = &tess.indexes[tess.numIndexes]; base = tess.numVertexes; for( i = 0; i < surf->num_triangles; i++ ) { *ptr++ = base + (*tri++ - surf->first_vertex); *ptr++ = base + (*tri++ - surf->first_vertex); *ptr++ = base + (*tri++ - surf->first_vertex); } tess.numIndexes += 3 * surf->num_triangles; tess.numVertexes += surf->num_vertexes; }
/* ============ R_CreateVao2 ============ */ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *indexes) { vao_t *vao; int i; byte *data; int dataSize; int dataOfs; int glUsage = GL_STATIC_DRAW; if(!numVertexes || !numIndexes) return NULL; if(strlen(name) >= MAX_QPATH) { ri.Error(ERR_DROP, "R_CreateVao2: \"%s\" is too long", name); } if ( tr.numVaos == MAX_VAOS ) { ri.Error( ERR_DROP, "R_CreateVao2: MAX_VAOS hit"); } R_IssuePendingRenderCommands(); vao = tr.vaos[tr.numVaos] = ri.Hunk_Alloc(sizeof(*vao), h_low); tr.numVaos++; memset(vao, 0, sizeof(*vao)); Q_strncpyz(vao->name, name, sizeof(vao->name)); // since these vertex attributes are never altered, interleave them vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; #ifdef USE_VERT_TANGENT_SPACE vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; #endif vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; vao->attribs[ATTR_INDEX_POSITION ].count = 3; vao->attribs[ATTR_INDEX_NORMAL ].count = 4; vao->attribs[ATTR_INDEX_TANGENT ].count = 4; vao->attribs[ATTR_INDEX_TEXCOORD ].count = 2; vao->attribs[ATTR_INDEX_LIGHTCOORD ].count = 2; vao->attribs[ATTR_INDEX_COLOR ].count = 4; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; vao->attribs[ATTR_INDEX_TEXCOORD ].type = glRefConfig.packedTexcoordDataType; vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = glRefConfig.packedTexcoordDataType; vao->attribs[ATTR_INDEX_COLOR ].type = glRefConfig.packedColorDataType; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz); vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(uint32_t); #ifdef USE_VERT_TANGENT_SPACE vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(uint32_t); #endif vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize; vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize; vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += glRefConfig.packedColorDataSize; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(uint32_t); vao->attribs[ATTR_INDEX_POSITION ].stride = dataSize; vao->attribs[ATTR_INDEX_NORMAL ].stride = dataSize; vao->attribs[ATTR_INDEX_TANGENT ].stride = dataSize; vao->attribs[ATTR_INDEX_TEXCOORD ].stride = dataSize; vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = dataSize; vao->attribs[ATTR_INDEX_COLOR ].stride = dataSize; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = dataSize; if (glRefConfig.vertexArrayObject) { qglGenVertexArrays(1, &vao->vao); qglBindVertexArray(vao->vao); } // create VBO dataSize *= numVertexes; data = ri.Hunk_AllocateTempMemory(dataSize); dataOfs = 0; for (i = 0; i < numVertexes; i++) { // xyz memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); dataOfs += sizeof(verts[i].xyz); // normal dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].normal); #ifdef USE_VERT_TANGENT_SPACE // tangent dataOfs += R_VaoPackTangent(data + dataOfs, verts[i].tangent); #endif // texcoords dataOfs += R_VaoPackTexCoord(data + dataOfs, verts[i].st); // lightmap texcoords dataOfs += R_VaoPackTexCoord(data + dataOfs, verts[i].lightmap); // colors dataOfs += R_VaoPackColors(data + dataOfs, verts[i].vertexColors); // light directions dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].lightdir); } vao->vertexesSize = dataSize; qglGenBuffers(1, &vao->vertexesVBO); qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); qglBufferData(GL_ARRAY_BUFFER, vao->vertexesSize, data, glUsage); // create IBO vao->indexesSize = numIndexes * sizeof(glIndex_t); qglGenBuffers(1, &vao->indexesIBO); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vao->indexesSize, indexes, glUsage); Vao_SetVertexPointers(vao); glState.currentVao = vao; GL_CheckErrors(); ri.Hunk_FreeTempMemory(data); return vao; }