void R_FreeSurfaceGridMesh(srfGridMesh_t *grid) { Com_Dealloc(grid->widthLodError); Com_Dealloc(grid->heightLodError); Com_Dealloc(grid->triangles); Com_Dealloc(grid->verts); Com_Dealloc(grid); }
/* ============ R_InitVBOs ============ */ void R_InitVBOs( void ) { int dataSize; byte *data; ri.Printf( PRINT_ALL, "------- R_InitVBOs -------\n" ); Com_InitGrowList( &tr.vbos, 100 ); Com_InitGrowList( &tr.ibos, 100 ); dataSize = sizeof( vec4_t ) * SHADER_MAX_VERTEXES * 11; data = Com_Allocate( dataSize ); memset( data, 0, dataSize ); tess.vbo = R_CreateVBO( "tessVertexArray_VBO", data, dataSize, VBO_USAGE_DYNAMIC ); tess.vbo->ofsXYZ = 0; tess.vbo->ofsTexCoords = tess.vbo->ofsXYZ + sizeof( tess.xyz ); tess.vbo->ofsLightCoords = tess.vbo->ofsTexCoords + sizeof( tess.texCoords ); tess.vbo->ofsTangents = tess.vbo->ofsLightCoords + sizeof( tess.lightCoords ); tess.vbo->ofsBinormals = tess.vbo->ofsTangents + sizeof( tess.tangents ); tess.vbo->ofsNormals = tess.vbo->ofsBinormals + sizeof( tess.binormals ); tess.vbo->ofsColors = tess.vbo->ofsNormals + sizeof( tess.normals ); #if !defined( COMPAT_Q3A ) && !defined( COMPAT_ET ) tess.vbo->ofsPaintColors = tess.vbo->ofsColors + sizeof( tess.colors ); tess.vbo->ofsLightDirections = tess.vbo->ofsPaintColors + sizeof( tess.paintColors ); #endif tess.vbo->sizeXYZ = sizeof( tess.xyz ); tess.vbo->sizeTangents = sizeof( tess.tangents ); tess.vbo->sizeBinormals = sizeof( tess.binormals ); tess.vbo->sizeNormals = sizeof( tess.normals ); Com_Dealloc( data ); dataSize = sizeof( tess.indexes ); data = Com_Allocate( dataSize ); memset( data, 0, dataSize ); tess.ibo = R_CreateIBO( "tessVertexArray_IBO", data, dataSize, VBO_USAGE_DYNAMIC ); Com_Dealloc( data ); R_InitUnitCubeVBO(); R_BindNullVBO(); R_BindNullIBO(); GL_CheckErrors(); }
void LoadRGBEToHalfs( const char *name, unsigned short **halfImage, int *width, int *height ) { int i, j; int w, h; float *hdrImage; float *floatbuf; unsigned short *halfbuf; #if 0 w = h = 0; LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qtrue, qtrue ); *width = w; *height = h; *ldrImage = ri.Malloc( w * h * 4 ); pixbuf = *ldrImage; floatbuf = hdrImage; for ( i = 0; i < ( w * h ); i++ ) { for ( j = 0; j < 3; j++ ) { sample[ j ] = *floatbuf++; } NormalizeColor( sample, sample ); *pixbuf++ = ( byte )( sample[ 0 ] * 255 ); *pixbuf++ = ( byte )( sample[ 1 ] * 255 ); *pixbuf++ = ( byte )( sample[ 2 ] * 255 ); *pixbuf++ = ( byte ) 255; } #else w = h = 0; LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qfalse, qtrue ); *width = w; *height = h; *halfImage = ( unsigned short * ) Com_Allocate( w * h * 3 * 6 ); halfbuf = *halfImage; floatbuf = hdrImage; for ( i = 0; i < ( w * h ); i++ ) { for ( j = 0; j < 3; j++ ) { half sample( *floatbuf++ ); *halfbuf++ = sample.bits(); } } #endif Com_Dealloc( hdrImage ); }
void CL_FreeDemoPoints(void) { if (rewindBackups) { Com_Dealloc(rewindBackups); rewindBackups = NULL; } }
/* ============ R_InitVBOs ============ */ void R_InitVBOs(void) { int dataSize; byte *data; Ren_Print("------- R_InitVBOs -------\n"); Com_InitGrowList(&tr.vbos, 100); Com_InitGrowList(&tr.ibos, 100); dataSize = sizeof(vec4_t) * SHADER_MAX_VERTEXES * 11; data = (byte *)Com_Allocate(dataSize); memset(data, 0, dataSize); tess.vbo = R_CreateVBO("tessVertexArray_VBO", data, dataSize, VBO_USAGE_DYNAMIC); tess.vbo->ofsXYZ = 0; tess.vbo->ofsTexCoords = tess.vbo->ofsXYZ + sizeof(tess.xyz); tess.vbo->ofsLightCoords = tess.vbo->ofsTexCoords + sizeof(tess.texCoords); tess.vbo->ofsTangents = tess.vbo->ofsLightCoords + sizeof(tess.lightCoords); tess.vbo->ofsBinormals = tess.vbo->ofsTangents + sizeof(tess.tangents); tess.vbo->ofsNormals = tess.vbo->ofsBinormals + sizeof(tess.binormals); tess.vbo->ofsColors = tess.vbo->ofsNormals + sizeof(tess.normals); tess.vbo->sizeXYZ = sizeof(tess.xyz); tess.vbo->sizeTangents = sizeof(tess.tangents); tess.vbo->sizeBinormals = sizeof(tess.binormals); tess.vbo->sizeNormals = sizeof(tess.normals); Com_Dealloc(data); dataSize = sizeof(tess.indexes); data = (byte *)Com_Allocate(dataSize); memset(data, 0, dataSize); tess.ibo = R_CreateIBO("tessVertexArray_IBO", data, dataSize, VBO_USAGE_DYNAMIC); Com_Dealloc(data); R_InitUnitCubeVBO(); R_BindNullVBO(); R_BindNullIBO(); GL_CheckErrors(); }
int Com_AddToGrowList(growList_t *list, void *data) { void **old; if (list->currentElements != list->maxElements) { list->elements[list->currentElements] = data; return list->currentElements++; } // grow, reallocate and move old = list->elements; if (list->maxElements < 0) { Ren_Fatal("Com_AddToGrowList: maxElements = %i", list->maxElements); } if (list->maxElements == 0) { // initialize the list to hold 100 elements Com_InitGrowList(list, 100); return Com_AddToGrowList(list, data); } list->maxElements *= 2; //Com_DPrintf("Resizing growlist to %i maxElements\n", list->maxElements); list->elements = (void **)Com_Allocate(list->maxElements * sizeof(void *)); if (!list->elements) { Ren_Drop("Growlist alloc failed"); } Com_Memcpy(list->elements, old, list->currentElements * sizeof(void *)); Com_Dealloc(old); return Com_AddToGrowList(list, data); }
void OGV_StopVideo(cinematic_t *cin) { if (cin->data) { theora_clear(&g_ogm->th_state); theora_comment_clear(&g_ogm->th_comment); theora_info_clear(&g_ogm->th_info); vorbis_dsp_clear(&g_ogm->vd); vorbis_comment_clear(&g_ogm->vc); vorbis_info_clear(&g_ogm->vi); /* must be called last (comment from vorbis example code) */ ogg_stream_clear(&g_ogm->os_audio); ogg_stream_clear(&g_ogm->os_video); ogg_sync_clear(&g_ogm->oy); Com_Dealloc(cin->data); cin->data = NULL; } }
/* ======================================================================================================================================= DL_GetString ======================================================================================================================================= */ char *DL_GetString(const char *url) { CURL *curl = NULL; CURLcode status; char *data = NULL; long code; write_result_t write_result = {NULL, 0}; if (!url) { Com_Printf(S_COLOR_RED "DL_GetString: Error - empty download URL\n"); return NULL; } DL_InitDownload(); curl = curl_easy_init(); data = (char *)Com_Allocate(GET_BUFFER_SIZE); if (!data) { goto error_get; } else { write_result.data = data; } curl_easy_setopt(curl, CURLOPT_USERAGENT, va("%s %s", APP_NAME "/" APP_VERSION, curl_version())); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DL_write_function); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&write_result); #ifdef FEATURE_OPENSSL #if 0 curl_easy_setopt(dl_request, CURLOPT_CAINFO, "./cert.crt"); #else curl_easy_setopt(dl_request, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(dl_request, CURLOPT_SSL_VERIFYPEER, 0); #endif #endif status = curl_easy_perform(curl); if (status != 0) { Com_Printf(S_COLOR_RED "DL_GetString: Error - unable to request data from %s\n", url); Com_Printf(S_COLOR_RED "DL_GetString: Error - %s\n", curl_easy_strerror(status)); goto error_get; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code != 200) { Com_Printf(S_COLOR_RED "DL_GetString: Error - server responded with code %ld\n", code); goto error_get; } curl_easy_cleanup(curl); data[write_result.pos] = '\0'; return data; error_get: if (curl) { curl_easy_cleanup(curl); } if (data) { Com_Dealloc(data); } return NULL; }
void FreeMemStream(memStream_t *s) { Com_Dealloc(s); }
static int OGV_LoadVideoFrame(cinematic_t *cin) { int r = 0; ogg_packet op; memset(&op, 0, sizeof(op)); while (!r && (ogg_stream_packetout(&g_ogm->os_video, &op))) { ogg_int64_t th_frame; theora_decode_packetin(&g_ogm->th_state, &op); th_frame = theora_granule_frame(&g_ogm->th_state, g_ogm->th_state.granulepos); if ((g_ogm->VFrameCount < th_frame && th_frame >= OGV_NextNeededVFrame(cin)) || !cin->frameBuffer[0]) { if (theora_decode_YUVout(&g_ogm->th_state, &g_ogm->th_yuvbuffer)) { continue; } if (cin->frameWidth != g_ogm->th_info.width || cin->frameHeight != g_ogm->th_info.height) { cin->frameWidth = g_ogm->th_info.width; cin->frameHeight = g_ogm->th_info.height; Com_DPrintf("Theora new resolution %dx%d\n", cin->frameWidth, cin->frameHeight); } if (cin->frameBufferSize < g_ogm->th_info.width * g_ogm->th_info.height) { cin->frameBufferSize = g_ogm->th_info.width * g_ogm->th_info.height; /* Free old output buffer */ if (cin->frameBuffer[0]) { Com_Dealloc(cin->frameBuffer[0]); cin->frameBuffer[0] = NULL; } /* Allocate the new buffer */ cin->frameBuffer[0] = (unsigned char *)Com_Allocate(cin->frameBufferSize * 4); if (cin->frameBuffer[0] == NULL) { cin->frameBufferSize = 0; r = -2; break; } } if (OGV_yuv_to_rgb24(&g_ogm->th_yuvbuffer, &g_ogm->th_info, (unsigned int *) cin->frameBuffer[0])) { r = 1; g_ogm->VFrameCount = th_frame; } else { r = -1; } } } return r; }
void FS_FreeFile( void* buffer ) { Com_Dealloc( buffer ); }
qboolean R_LoadPSK(model_t *mod, void *buffer, int bufferSize, const char *modName) { int i, j, k; memStream_t *stream = NULL; axChunkHeader_t chunkHeader; int numPoints; axPoint_t *point; axPoint_t *points = NULL; int numVertexes; axVertex_t *vertex; axVertex_t *vertexes = NULL; //int numSmoothGroups; int numTriangles; axTriangle_t *triangle; axTriangle_t *triangles = NULL; int numMaterials; axMaterial_t *material; axMaterial_t *materials = NULL; int numReferenceBones; axReferenceBone_t *refBone; axReferenceBone_t *refBones = NULL; int numWeights; axBoneWeight_t *axWeight; axBoneWeight_t *axWeights = NULL; md5Model_t *md5; md5Bone_t *md5Bone; md5Weight_t *weight; vec3_t boneOrigin; quat_t boneQuat; //mat4_t boneMat; int materialIndex, oldMaterialIndex; int numRemaining; growList_t sortedTriangles; growList_t vboVertexes; growList_t vboTriangles; growList_t vboSurfaces; int numBoneReferences; int boneReferences[MAX_BONES]; mat4_t unrealToQuake; #define DeallocAll() Com_Dealloc(materials); \ Com_Dealloc(points); \ Com_Dealloc(vertexes); \ Com_Dealloc(triangles); \ Com_Dealloc(refBones); \ Com_Dealloc(axWeights); \ FreeMemStream(stream); //MatrixSetupScale(unrealToQuake, 1, -1, 1); mat4_from_angles(unrealToQuake, 0, 90, 0); stream = AllocMemStream(buffer, bufferSize); GetChunkHeader(stream, &chunkHeader); // check indent again if (Q_stricmpn(chunkHeader.ident, "ACTRHEAD", 8)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "ACTRHEAD"); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); mod->type = MOD_MD5; mod->dataSize += sizeof(md5Model_t); md5 = mod->md5 = ri.Hunk_Alloc(sizeof(md5Model_t), h_low); // read points GetChunkHeader(stream, &chunkHeader); if (Q_stricmpn(chunkHeader.ident, "PNTS0000", 8)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "PNTS0000"); DeallocAll(); return qfalse; } if (chunkHeader.dataSize != sizeof(axPoint_t)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axPoint_t)); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); numPoints = chunkHeader.numData; points = Com_Allocate(numPoints * sizeof(axPoint_t)); for (i = 0, point = points; i < numPoints; i++, point++) { point->point[0] = MemStreamGetFloat(stream); point->point[1] = MemStreamGetFloat(stream); point->point[2] = MemStreamGetFloat(stream); #if 0 // HACK convert from Unreal coordinate system to the Quake one MatrixTransformPoint2(unrealToQuake, point->point); #endif } // read vertices GetChunkHeader(stream, &chunkHeader); if (Q_stricmpn(chunkHeader.ident, "VTXW0000", 8)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "VTXW0000"); DeallocAll(); return qfalse; } if (chunkHeader.dataSize != sizeof(axVertex_t)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axVertex_t)); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); numVertexes = chunkHeader.numData; vertexes = Com_Allocate(numVertexes * sizeof(axVertex_t)); { int tmpVertexInt = -1; // tmp vertex member values - MemStreamGet functions return -1 if they fail // now we print a warning if they do or abort if pointIndex is invalid for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++) { tmpVertexInt = MemStreamGetShort(stream); if (tmpVertexInt < 0 || tmpVertexInt >= numPoints) { ri.Printf(PRINT_ERROR, "R_LoadPSK: '%s' has vertex with point index out of range (%i while max %i)\n", modName, tmpVertexInt, numPoints); DeallocAll(); return qfalse; } vertex->pointIndex = tmpVertexInt; tmpVertexInt = MemStreamGetShort(stream); if (tmpVertexInt < 0) { Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->unknownA)\n"); } vertex->unknownA = tmpVertexInt; vertex->st[0] = MemStreamGetFloat(stream); if (vertex->st[0] == -1) { Ren_Warning("R_LoadPSK: MemStream possibly NULL or empty (vertex->st[0])\n"); } vertex->st[1] = MemStreamGetFloat(stream); if (vertex->st[1] == -1) { Ren_Warning("R_LoadPSK: MemStream possibly NULL or empty (vertex->st[1])\n"); } tmpVertexInt = MemStreamGetC(stream); if (tmpVertexInt < 0) { Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n"); } vertex->materialIndex = tmpVertexInt; tmpVertexInt = MemStreamGetC(stream); if (tmpVertexInt < 0) { Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n"); } vertex->reserved = tmpVertexInt; tmpVertexInt = MemStreamGetShort(stream); if (tmpVertexInt < 0) { Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n"); } vertex->unknownB = tmpVertexInt; #if 0 Ren_Print("R_LoadPSK: axVertex_t(%i):\n" "axVertex:pointIndex: %i\n" "axVertex:unknownA: %i\n" "axVertex::st: %f %f\n" "axVertex:materialIndex: %i\n" "axVertex:reserved: %d\n" "axVertex:unknownB: %d\n", i, vertex->pointIndex, vertex->unknownA, vertex->st[0], vertex->st[1], vertex->materialIndex, vertex->reserved, vertex->unknownB); #endif } // read triangles GetChunkHeader(stream, &chunkHeader); if (Q_stricmpn(chunkHeader.ident, "FACE0000", 8)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "FACE0000"); DeallocAll(); return qfalse; } if (chunkHeader.dataSize != sizeof(axTriangle_t)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axTriangle_t)); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); numTriangles = chunkHeader.numData; triangles = Com_Allocate(numTriangles * sizeof(axTriangle_t)); for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++) { for (j = 0; j < 3; j++) //for(j = 2; j >= 0; j--) { tmpVertexInt = MemStreamGetShort(stream); if (tmpVertexInt < 0) { Ren_Warning("R_LoadPSK: '%s' MemStream NULL or empty (triangle->indexes[%i])\n", modName, j); DeallocAll(); return qfalse; } if (tmpVertexInt >= numVertexes) { Ren_Warning("R_LoadPSK: '%s' has triangle with vertex index out of range (%i while max %i)\n", modName, tmpVertexInt, numVertexes); DeallocAll(); return qfalse; } triangle->indexes[j] = tmpVertexInt; } triangle->materialIndex = MemStreamGetC(stream); triangle->materialIndex2 = MemStreamGetC(stream); triangle->smoothingGroups = MemStreamGetLong(stream); } } // read materials GetChunkHeader(stream, &chunkHeader); if (Q_stricmpn(chunkHeader.ident, "MATT0000", 8)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "MATT0000"); DeallocAll(); return qfalse; } if (chunkHeader.dataSize != sizeof(axMaterial_t)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axMaterial_t)); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); numMaterials = chunkHeader.numData; materials = Com_Allocate(numMaterials * sizeof(axMaterial_t)); for (i = 0, material = materials; i < numMaterials; i++, material++) { MemStreamRead(stream, material->name, sizeof(material->name)); Ren_Print("R_LoadPSK: material name: '%s'\n", material->name); material->shaderIndex = MemStreamGetLong(stream); material->polyFlags = MemStreamGetLong(stream); material->auxMaterial = MemStreamGetLong(stream); material->auxFlags = MemStreamGetLong(stream); material->lodBias = MemStreamGetLong(stream); material->lodStyle = MemStreamGetLong(stream); } for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++) { if (vertex->materialIndex < 0 || vertex->materialIndex >= numMaterials) { Ren_Warning("R_LoadPSK: '%s' has vertex with material index out of range (%i while max %i)\n", modName, vertex->materialIndex, numMaterials); DeallocAll(); return qfalse; } } for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++) { if (triangle->materialIndex < 0 || triangle->materialIndex >= numMaterials) { Ren_Warning("R_LoadPSK: '%s' has triangle with material index out of range (%i while max %i)\n", modName, triangle->materialIndex, numMaterials); DeallocAll(); return qfalse; } } // read reference bones GetChunkHeader(stream, &chunkHeader); if (Q_stricmpn(chunkHeader.ident, "REFSKELT", 8)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "REFSKELT"); DeallocAll(); return qfalse; } if (chunkHeader.dataSize != sizeof(axReferenceBone_t)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axReferenceBone_t)); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); numReferenceBones = chunkHeader.numData; refBones = Com_Allocate(numReferenceBones * sizeof(axReferenceBone_t)); for (i = 0, refBone = refBones; i < numReferenceBones; i++, refBone++) { MemStreamRead(stream, refBone->name, sizeof(refBone->name)); //Ren_Print("R_LoadPSK: reference bone name: '%s'\n", refBone->name); refBone->flags = MemStreamGetLong(stream); refBone->numChildren = MemStreamGetLong(stream); refBone->parentIndex = MemStreamGetLong(stream); GetBone(stream, &refBone->bone); #if 0 Ren_Print("R_LoadPSK: axReferenceBone_t(%i):\n" "axReferenceBone_t::name: '%s'\n" "axReferenceBone_t::flags: %i\n" "axReferenceBone_t::numChildren %i\n" "axReferenceBone_t::parentIndex: %i\n" "axReferenceBone_t::quat: %f %f %f %f\n" "axReferenceBone_t::position: %f %f %f\n" "axReferenceBone_t::length: %f\n" "axReferenceBone_t::xSize: %f\n" "axReferenceBone_t::ySize: %f\n" "axReferenceBone_t::zSize: %f\n", i, refBone->name, refBone->flags, refBone->numChildren, refBone->parentIndex, refBone->bone.quat[0], refBone->bone.quat[1], refBone->bone.quat[2], refBone->bone.quat[3], refBone->bone.position[0], refBone->bone.position[1], refBone->bone.position[2], refBone->bone.length, refBone->bone.xSize, refBone->bone.ySize, refBone->bone.zSize); #endif } // read bone weights GetChunkHeader(stream, &chunkHeader); if (Q_stricmpn(chunkHeader.ident, "RAWWEIGHTS", 10)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "RAWWEIGHTS"); DeallocAll(); return qfalse; } if (chunkHeader.dataSize != sizeof(axBoneWeight_t)) { Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axBoneWeight_t)); DeallocAll(); return qfalse; } PrintChunkHeader(&chunkHeader); numWeights = chunkHeader.numData; axWeights = Com_Allocate(numWeights * sizeof(axBoneWeight_t)); for (i = 0, axWeight = axWeights; i < numWeights; i++, axWeight++) { axWeight->weight = MemStreamGetFloat(stream); axWeight->pointIndex = MemStreamGetLong(stream); axWeight->boneIndex = MemStreamGetLong(stream); #if 0 Ren_Print("R_LoadPSK: axBoneWeight_t(%i):\n" "axBoneWeight_t::weight: %f\n" "axBoneWeight_t::pointIndex %i\n" "axBoneWeight_t::boneIndex: %i\n", i, axWeight->weight, axWeight->pointIndex, axWeight->boneIndex); #endif } // // convert the model to an internal MD5 representation // md5->numBones = numReferenceBones; // calc numMeshes <number> /* numSmoothGroups = 0; for(i = 0, triangle = triangles; i < numTriangles; i++, triangle++) { if(triangle->smoothingGroups) { } } */ if (md5->numBones < 1) { Ren_Warning("R_LoadPSK: '%s' has no bones\n", modName); DeallocAll(); return qfalse; } if (md5->numBones > MAX_BONES) { Ren_Warning("R_LoadPSK: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones); DeallocAll(); return qfalse; } //Ren_Print("R_LoadPSK: '%s' has %i bones\n", modName, md5->numBones); // copy all reference bones md5->bones = ri.Hunk_Alloc(sizeof(*md5Bone) * md5->numBones, h_low); for (i = 0, md5Bone = md5->bones, refBone = refBones; i < md5->numBones; i++, md5Bone++, refBone++) { Q_strncpyz(md5Bone->name, refBone->name, sizeof(md5Bone->name)); if (i == 0) { md5Bone->parentIndex = refBone->parentIndex - 1; } else { md5Bone->parentIndex = refBone->parentIndex; } //Ren_Print("R_LoadPSK: '%s' has bone '%s' with parent index %i\n", modName, md5Bone->name, md5Bone->parentIndex); if (md5Bone->parentIndex >= md5->numBones) { DeallocAll(); Ren_Drop("R_LoadPSK: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName, md5Bone->name, md5Bone->parentIndex, md5->numBones); } for (j = 0; j < 3; j++) { boneOrigin[j] = refBone->bone.position[j]; } // I have really no idea why the .psk format stores the first quaternion with inverted quats. // Furthermore only the X and Z components of the first quat are inverted ?!?! if (i == 0) { boneQuat[0] = refBone->bone.quat[0]; boneQuat[1] = -refBone->bone.quat[1]; boneQuat[2] = refBone->bone.quat[2]; boneQuat[3] = refBone->bone.quat[3]; } else { boneQuat[0] = -refBone->bone.quat[0]; boneQuat[1] = -refBone->bone.quat[1]; boneQuat[2] = -refBone->bone.quat[2]; boneQuat[3] = refBone->bone.quat[3]; } VectorCopy(boneOrigin, md5Bone->origin); //MatrixTransformPoint(unrealToQuake, boneOrigin, md5Bone->origin); quat_copy(boneQuat, md5Bone->rotation); //QuatClear(md5Bone->rotation); #if 0 Ren_Print("R_LoadPSK: md5Bone_t(%i):\n" "md5Bone_t::name: '%s'\n" "md5Bone_t::parentIndex: %i\n" "md5Bone_t::quat: %f %f %f %f\n" "md5bone_t::position: %f %f %f\n", i, md5Bone->name, md5Bone->parentIndex, md5Bone->rotation[0], md5Bone->rotation[1], md5Bone->rotation[2], md5Bone->rotation[3], md5Bone->origin[0], md5Bone->origin[1], md5Bone->origin[2]); #endif if (md5Bone->parentIndex >= 0) { vec3_t rotated; quat_t quat; md5Bone_t *parent; parent = &md5->bones[md5Bone->parentIndex]; QuatTransformVector(parent->rotation, md5Bone->origin, rotated); //QuatTransformVector(md5Bone->rotation, md5Bone->origin, rotated); VectorAdd(parent->origin, rotated, md5Bone->origin); QuatMultiply1(parent->rotation, md5Bone->rotation, quat); quat_copy(quat, md5Bone->rotation); } MatrixSetupTransformFromQuat(md5Bone->inverseTransform, md5Bone->rotation, md5Bone->origin); mat4_inverse_self(md5Bone->inverseTransform); #if 0 Ren_Print("R_LoadPSK: md5Bone_t(%i):\n" "md5Bone_t::name: '%s'\n" "md5Bone_t::parentIndex: %i\n" "md5Bone_t::quat: %f %f %f %f\n" "md5bone_t::position: %f %f %f\n", i, md5Bone->name, md5Bone->parentIndex, md5Bone->rotation[0], md5Bone->rotation[1], md5Bone->rotation[2], md5Bone->rotation[3], md5Bone->origin[0], md5Bone->origin[1], md5Bone->origin[2]); #endif } Com_InitGrowList(&vboVertexes, 10000); for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++) { md5Vertex_t *vboVert = Com_Allocate(sizeof(*vboVert)); for (j = 0; j < 3; j++) { vboVert->position[j] = points[vertex->pointIndex].point[j]; } vboVert->texCoords[0] = vertex->st[0]; vboVert->texCoords[1] = vertex->st[1]; // find number of associated weights vboVert->numWeights = 0; for (j = 0, axWeight = axWeights; j < numWeights; j++, axWeight++) { if (axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f) { vboVert->numWeights++; } } if (vboVert->numWeights > MAX_WEIGHTS) { DeallocAll(); Ren_Drop("R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'", i, vboVert->numWeights, MAX_WEIGHTS, modName); //Ren_Warning( "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'\n", i, vboVert->numWeights, MAX_WEIGHTS, modName); } vboVert->weights = ri.Hunk_Alloc(sizeof(*vboVert->weights) * vboVert->numWeights, h_low); for (j = 0, axWeight = axWeights, k = 0; j < numWeights; j++, axWeight++) { if (axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f) { weight = ri.Hunk_Alloc(sizeof(*weight), h_low); weight->boneIndex = axWeight->boneIndex; weight->boneWeight = axWeight->weight; // FIXME? weight->offset[0] = refBones[axWeight->boneIndex].bone.xSize; weight->offset[1] = refBones[axWeight->boneIndex].bone.ySize; weight->offset[2] = refBones[axWeight->boneIndex].bone.zSize; vboVert->weights[k++] = weight; } } Com_AddToGrowList(&vboVertexes, vboVert); } ClearBounds(md5->bounds[0], md5->bounds[1]); for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++) { AddPointToBounds(points[vertex->pointIndex].point, md5->bounds[0], md5->bounds[1]); } #if 0 Ren_Print("R_LoadPSK: AABB (%i %i %i) (%i %i %i)\n", ( int ) md5->bounds[0][0], ( int ) md5->bounds[0][1], ( int ) md5->bounds[0][2], ( int ) md5->bounds[1][0], ( int ) md5->bounds[1][1], ( int ) md5->bounds[1][2]); #endif // sort triangles qsort(triangles, numTriangles, sizeof(axTriangle_t), CompareTrianglesByMaterialIndex); Com_InitGrowList(&sortedTriangles, 1000); for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++) { skelTriangle_t *sortTri = Com_Allocate(sizeof(*sortTri)); for (j = 0; j < 3; j++) { sortTri->indexes[j] = triangle->indexes[j]; sortTri->vertexes[j] = Com_GrowListElement(&vboVertexes, triangle->indexes[j]); } sortTri->referenced = qfalse; Com_AddToGrowList(&sortedTriangles, sortTri); } // calc tangent spaces #if 1 { md5Vertex_t *v0, *v1, *v2; const float *p0, *p1, *p2; const float *t0, *t1, *t2; vec3_t tangent = { 0, 0, 0 }; vec3_t binormal; vec3_t normal; for (j = 0; j < vboVertexes.currentElements; j++) { v0 = Com_GrowListElement(&vboVertexes, j); VectorClear(v0->tangent); VectorClear(v0->binormal); VectorClear(v0->normal); } for (j = 0; j < sortedTriangles.currentElements; j++) { skelTriangle_t *tri = Com_GrowListElement(&sortedTriangles, j); v0 = Com_GrowListElement(&vboVertexes, tri->indexes[0]); v1 = Com_GrowListElement(&vboVertexes, tri->indexes[1]); v2 = Com_GrowListElement(&vboVertexes, tri->indexes[2]); p0 = v0->position; p1 = v1->position; p2 = v2->position; t0 = v0->texCoords; t1 = v1->texCoords; t2 = v2->texCoords; #if 1 R_CalcTangentSpace(tangent, binormal, normal, p0, p1, p2, t0, t1, t2); #else R_CalcNormalForTriangle(normal, p0, p1, p2); R_CalcTangentsForTriangle(tangent, binormal, p0, p1, p2, t0, t1, t2); #endif for (k = 0; k < 3; k++) { float *v; v0 = Com_GrowListElement(&vboVertexes, tri->indexes[k]); v = v0->tangent; VectorAdd(v, tangent, v); v = v0->binormal; VectorAdd(v, binormal, v); v = v0->normal; VectorAdd(v, normal, v); } } for (j = 0; j < vboVertexes.currentElements; j++) { v0 = Com_GrowListElement(&vboVertexes, j); VectorNormalize(v0->tangent); VectorNormalize(v0->binormal); VectorNormalize(v0->normal); } } #else { float bb, s, t; vec3_t bary; vec3_t faceNormal; md5Vertex_t *dv[3]; for (j = 0; j < sortedTriangles.currentElements; j++) { skelTriangle_t *tri = Com_GrowListElement(&sortedTriangles, j); dv[0] = Com_GrowListElement(&vboVertexes, tri->indexes[0]); dv[1] = Com_GrowListElement(&vboVertexes, tri->indexes[1]); dv[2] = Com_GrowListElement(&vboVertexes, tri->indexes[2]); R_CalcNormalForTriangle(faceNormal, dv[0]->position, dv[1]->position, dv[2]->position); // calculate barycentric basis for the triangle bb = (dv[1]->texCoords[0] - dv[0]->texCoords[0]) * (dv[2]->texCoords[1] - dv[0]->texCoords[1]) - (dv[2]->texCoords[0] - dv[0]->texCoords[0]) * (dv[1]->texCoords[1] - dv[0]->texCoords[1]); if (fabs(bb) < 0.00000001f) { continue; } // do each vertex for (k = 0; k < 3; k++) { // calculate s tangent vector s = dv[k]->texCoords[0] + 10.0f; t = dv[k]->texCoords[1]; bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb; bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb; bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb; dv[k]->tangent[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0]; dv[k]->tangent[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1]; dv[k]->tangent[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2]; VectorSubtract(dv[k]->tangent, dv[k]->position, dv[k]->tangent); VectorNormalize(dv[k]->tangent); // calculate t tangent vector (binormal) s = dv[k]->texCoords[0]; t = dv[k]->texCoords[1] + 10.0f; bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb; bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb; bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb; dv[k]->binormal[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0]; dv[k]->binormal[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1]; dv[k]->binormal[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2]; VectorSubtract(dv[k]->binormal, dv[k]->position, dv[k]->binormal); VectorNormalize(dv[k]->binormal); // calculate the normal as cross product N=TxB #if 0 CrossProduct(dv[k]->tangent, dv[k]->binormal, dv[k]->normal); VectorNormalize(dv[k]->normal); // Gram-Schmidt orthogonalization process for B // compute the cross product B=NxT to obtain // an orthogonal basis CrossProduct(dv[k]->normal, dv[k]->tangent, dv[k]->binormal); if (DotProduct(dv[k]->normal, faceNormal) < 0) { VectorInverse(dv[k]->normal); //VectorInverse(dv[k]->tangent); //VectorInverse(dv[k]->binormal); } #else VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal); #endif } } #if 1 for (j = 0; j < vboVertexes.currentElements; j++) { dv[0] = Com_GrowListElement(&vboVertexes, j); //VectorNormalize(dv[0]->tangent); //VectorNormalize(dv[0]->binormal); VectorNormalize(dv[0]->normal); } #endif } #endif #if 0 { md5Vertex_t *v0, *v1; // do another extra smoothing for normals to avoid flat shading for (j = 0; j < vboVertexes.currentElements; j++) { v0 = Com_GrowListElement(&vboVertexes, j); for (k = 0; k < vboVertexes.currentElements; k++) { if (j == k) { continue; } v1 = Com_GrowListElement(&vboVertexes, k); if (VectorCompare(v0->position, v1->position)) { VectorAdd(v0->position, v1->normal, v0->normal); } } VectorNormalize(v0->normal); } } #endif // split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones Com_InitGrowList(&vboSurfaces, 10); materialIndex = oldMaterialIndex = -1; for (i = 0; i < numTriangles; i++) { triangle = &triangles[i]; materialIndex = triangle->materialIndex; if (materialIndex != oldMaterialIndex) { oldMaterialIndex = materialIndex; numRemaining = sortedTriangles.currentElements - i; while (numRemaining) { numBoneReferences = 0; Com_Memset(boneReferences, 0, sizeof(boneReferences)); Com_InitGrowList(&vboTriangles, 1000); for (j = i; j < sortedTriangles.currentElements; j++) { skelTriangle_t *sortTri; triangle = &triangles[j]; materialIndex = triangle->materialIndex; if (materialIndex != oldMaterialIndex) { continue; } sortTri = Com_GrowListElement(&sortedTriangles, j); if (sortTri->referenced) { continue; } if (AddTriangleToVBOTriangleList(&vboTriangles, sortTri, &numBoneReferences, boneReferences)) { sortTri->referenced = qtrue; } } for (j = 0; j < MAX_BONES; j++) { if (boneReferences[j] > 0) { Ren_Print("R_LoadPSK: referenced bone: '%s'\n", (j < numReferenceBones) ? refBones[j].name : NULL); } } if (!vboTriangles.currentElements) { Ren_Warning("R_LoadPSK: could not add triangles to a remaining VBO surface for model '%s'\n", modName); break; } // FIXME skinIndex AddSurfaceToVBOSurfacesList2(&vboSurfaces, &vboTriangles, &vboVertexes, md5, vboSurfaces.currentElements, materials[oldMaterialIndex].name, numBoneReferences, boneReferences); numRemaining -= vboTriangles.currentElements; Com_DestroyGrowList(&vboTriangles); } } } for (j = 0; j < sortedTriangles.currentElements; j++) { skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j); Com_Dealloc(sortTri); } Com_DestroyGrowList(&sortedTriangles); for (j = 0; j < vboVertexes.currentElements; j++) { md5Vertex_t *v = Com_GrowListElement(&vboVertexes, j); Com_Dealloc(v); } Com_DestroyGrowList(&vboVertexes); // move VBO surfaces list to hunk md5->numVBOSurfaces = vboSurfaces.currentElements; md5->vboSurfaces = ri.Hunk_Alloc(md5->numVBOSurfaces * sizeof(*md5->vboSurfaces), h_low); for (i = 0; i < md5->numVBOSurfaces; i++) { md5->vboSurfaces[i] = ( srfVBOMD5Mesh_t * ) Com_GrowListElement(&vboSurfaces, i); } Com_DestroyGrowList(&vboSurfaces); FreeMemStream(stream); Com_Dealloc(points); Com_Dealloc(vertexes); Com_Dealloc(triangles); Com_Dealloc(materials); Ren_Developer("%i VBO surfaces created for PSK model '%s'\n", md5->numVBOSurfaces, modName); return qtrue; }
/* ================= R_LoadMDM ================= */ qboolean R_LoadMDM( model_t *mod, void *buffer, const char *modName ) { int i, j, k; mdmHeader_t *mdm; // mdmFrame_t *frame; mdmSurface_t *mdmSurf; mdmTriangle_t *mdmTri; mdmVertex_t *mdmVertex; mdmTag_t *mdmTag; int version; // int size; shader_t *sh; int32_t *collapseMap, *collapseMapOut, *boneref, *bonerefOut; mdmModel_t *mdmModel; mdmTagIntern_t *tag; mdmSurfaceIntern_t *surf; srfTriangle_t *tri; md5Vertex_t *v; mdm = ( mdmHeader_t * ) buffer; version = LittleLong( mdm->version ); if ( version != MDM_VERSION ) { ri.Printf( PRINT_WARNING, "R_LoadMDM: %s has wrong version (%i should be %i)\n", modName, version, MDM_VERSION ); return qfalse; } mod->type = MOD_MDM; // size = LittleLong(mdm->ofsEnd); mod->dataSize += sizeof( mdmModel_t ); //mdm = mod->mdm = ri.Hunk_Alloc(size, h_low); //memcpy(mdm, buffer, LittleLong(pinmodel->ofsEnd)); mdmModel = mod->mdm = ri.Hunk_Alloc( sizeof( mdmModel_t ), h_low ); LL( mdm->ident ); LL( mdm->version ); // LL(mdm->numFrames); LL( mdm->numTags ); LL( mdm->numSurfaces ); // LL(mdm->ofsFrames); LL( mdm->ofsTags ); LL( mdm->ofsEnd ); LL( mdm->ofsSurfaces ); mdmModel->lodBias = LittleFloat( mdm->lodBias ); mdmModel->lodScale = LittleFloat( mdm->lodScale ); /* mdm->skel = RE_RegisterModel(mdm->bonesfile); if ( !mdm->skel ) { ri.Error (ERR_DROP, "R_LoadMDM: %s skeleton not found", mdm->bonesfile ); } if ( mdm->numFrames < 1 ) { ri.Printf( PRINT_WARNING, "R_LoadMDM: %s has no frames\n", modName ); return qfalse; }*/ // swap all the frames /*frameSize = (int) ( sizeof( mdmFrame_t ) ); for ( i = 0 ; i < mdm->numFrames ; i++, frame++) { frame = (mdmFrame_t *) ( (byte *)mdm + mdm->ofsFrames + i * frameSize ); frame->radius = LittleFloat( frame->radius ); for ( j = 0 ; j < 3 ; j++ ) { frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); frame->parentOffset[j] = LittleFloat( frame->parentOffset[j] ); } } */ // swap all the tags mdmModel->numTags = mdm->numTags; mdmModel->tags = tag = ri.Hunk_Alloc( sizeof( *tag ) * mdm->numTags, h_low ); mdmTag = ( mdmTag_t * )( ( byte * ) mdm + mdm->ofsTags ); for ( i = 0; i < mdm->numTags; i++, tag++ ) { int ii; Q_strncpyz( tag->name, mdmTag->name, sizeof( tag->name ) ); for ( ii = 0; ii < 3; ii++ ) { tag->axis[ ii ][ 0 ] = LittleFloat( mdmTag->axis[ ii ][ 0 ] ); tag->axis[ ii ][ 1 ] = LittleFloat( mdmTag->axis[ ii ][ 1 ] ); tag->axis[ ii ][ 2 ] = LittleFloat( mdmTag->axis[ ii ][ 2 ] ); } tag->boneIndex = LittleLong( mdmTag->boneIndex ); //tag->torsoWeight = LittleFloat( tag->torsoWeight ); tag->offset[ 0 ] = LittleFloat( mdmTag->offset[ 0 ] ); tag->offset[ 1 ] = LittleFloat( mdmTag->offset[ 1 ] ); tag->offset[ 2 ] = LittleFloat( mdmTag->offset[ 2 ] ); LL( mdmTag->numBoneReferences ); LL( mdmTag->ofsBoneReferences ); LL( mdmTag->ofsEnd ); tag->numBoneReferences = mdmTag->numBoneReferences; tag->boneReferences = ri.Hunk_Alloc( sizeof( *bonerefOut ) * mdmTag->numBoneReferences, h_low ); // swap the bone references boneref = ( int32_t * )( ( byte * ) mdmTag + mdmTag->ofsBoneReferences ); for ( j = 0, bonerefOut = tag->boneReferences; j < mdmTag->numBoneReferences; j++, boneref++, bonerefOut++ ) { *bonerefOut = LittleLong( *boneref ); } // find the next tag mdmTag = ( mdmTag_t * )( ( byte * ) mdmTag + mdmTag->ofsEnd ); } // swap all the surfaces mdmModel->numSurfaces = mdm->numSurfaces; mdmModel->surfaces = ri.Hunk_Alloc( sizeof( *surf ) * mdmModel->numSurfaces, h_low ); mdmSurf = ( mdmSurface_t * )( ( byte * ) mdm + mdm->ofsSurfaces ); for ( i = 0, surf = mdmModel->surfaces; i < mdm->numSurfaces; i++, surf++ ) { LL( mdmSurf->shaderIndex ); LL( mdmSurf->ofsHeader ); LL( mdmSurf->ofsCollapseMap ); LL( mdmSurf->numTriangles ); LL( mdmSurf->ofsTriangles ); LL( mdmSurf->numVerts ); LL( mdmSurf->ofsVerts ); LL( mdmSurf->numBoneReferences ); LL( mdmSurf->ofsBoneReferences ); LL( mdmSurf->ofsEnd ); surf->minLod = LittleLong( mdmSurf->minLod ); // change to surface identifier surf->surfaceType = SF_MDM; surf->model = mdmModel; Q_strncpyz( surf->name, mdmSurf->name, sizeof( surf->name ) ); if ( mdmSurf->numVerts > SHADER_MAX_VERTEXES ) { ri.Error( ERR_DROP, "R_LoadMDM: %s has more than %i verts on a surface (%i)", modName, SHADER_MAX_VERTEXES, mdmSurf->numVerts ); } if ( mdmSurf->numTriangles > SHADER_MAX_TRIANGLES ) { ri.Error( ERR_DROP, "R_LoadMDM: %s has more than %i triangles on a surface (%i)", modName, SHADER_MAX_TRIANGLES, mdmSurf->numTriangles ); } // register the shaders if ( mdmSurf->shader[ 0 ] ) { Q_strncpyz( surf->shader, mdmSurf->shader, sizeof( surf->shader ) ); sh = R_FindShader( surf->shader, SHADER_3D_DYNAMIC, qtrue ); if ( sh->defaultShader ) { surf->shaderIndex = 0; } else { surf->shaderIndex = sh->index; } } else { surf->shaderIndex = 0; } // swap all the triangles surf->numTriangles = mdmSurf->numTriangles; surf->triangles = ri.Hunk_Alloc( sizeof( *tri ) * surf->numTriangles, h_low ); mdmTri = ( mdmTriangle_t * )( ( byte * ) mdmSurf + mdmSurf->ofsTriangles ); for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, mdmTri++, tri++ ) { tri->indexes[ 0 ] = LittleLong( mdmTri->indexes[ 0 ] ); tri->indexes[ 1 ] = LittleLong( mdmTri->indexes[ 1 ] ); tri->indexes[ 2 ] = LittleLong( mdmTri->indexes[ 2 ] ); } // swap all the vertexes surf->numVerts = mdmSurf->numVerts; surf->verts = ri.Hunk_Alloc( sizeof( *v ) * surf->numVerts, h_low ); mdmVertex = ( mdmVertex_t * )( ( byte * ) mdmSurf + mdmSurf->ofsVerts ); for ( j = 0, v = surf->verts; j < mdmSurf->numVerts; j++, v++ ) { v->normal[ 0 ] = LittleFloat( mdmVertex->normal[ 0 ] ); v->normal[ 1 ] = LittleFloat( mdmVertex->normal[ 1 ] ); v->normal[ 2 ] = LittleFloat( mdmVertex->normal[ 2 ] ); v->texCoords[ 0 ] = LittleFloat( mdmVertex->texCoords[ 0 ] ); v->texCoords[ 1 ] = LittleFloat( mdmVertex->texCoords[ 1 ] ); v->numWeights = LittleLong( mdmVertex->numWeights ); if ( v->numWeights > MAX_WEIGHTS ) { #if 0 ri.Error( ERR_DROP, "R_LoadMDM: vertex %i requires %i instead of maximum %i weights on surface (%i) in model '%s'", j, v->numWeights, MAX_WEIGHTS, i, modName ); #else ri.Printf( PRINT_WARNING, "WARNING: R_LoadMDM: vertex %i requires %i instead of maximum %i weights on surface (%i) in model '%s'\n", j, v->numWeights, MAX_WEIGHTS, i, modName ); #endif } v->weights = ri.Hunk_Alloc( sizeof( *v->weights ) * v->numWeights, h_low ); for ( k = 0; k < v->numWeights; k++ ) { md5Weight_t *weight = ri.Hunk_Alloc( sizeof( *weight ), h_low ); weight->boneIndex = LittleLong( mdmVertex->weights[ k ].boneIndex ); weight->boneWeight = LittleFloat( mdmVertex->weights[ k ].boneWeight ); weight->offset[ 0 ] = LittleFloat( mdmVertex->weights[ k ].offset[ 0 ] ); weight->offset[ 1 ] = LittleFloat( mdmVertex->weights[ k ].offset[ 1 ] ); weight->offset[ 2 ] = LittleFloat( mdmVertex->weights[ k ].offset[ 2 ] ); v->weights[ k ] = weight; } mdmVertex = ( mdmVertex_t * ) &mdmVertex->weights[ v->numWeights ]; } // swap the collapse map surf->collapseMap = ri.Hunk_Alloc( sizeof( *collapseMapOut ) * mdmSurf->numVerts, h_low ); collapseMap = ( int32_t * )( ( byte * ) mdmSurf + mdmSurf->ofsCollapseMap ); //ri.Printf(PRINT_ALL, "collapse map for mdm surface '%s': ", surf->name); for ( j = 0, collapseMapOut = surf->collapseMap; j < mdmSurf->numVerts; j++, collapseMap++, collapseMapOut++ ) { int32_t value = LittleLong( *collapseMap ); //surf->collapseMap[j] = value; *collapseMapOut = value; //ri.Printf(PRINT_ALL, "(%i -> %i) ", j, value); } //ri.Printf(PRINT_ALL, "\n"); #if 0 ri.Printf( PRINT_ALL, "collapse map for mdm surface '%s': ", surf->name ); for ( j = 0, collapseMap = surf->collapseMap; j < mdmSurf->numVerts; j++, collapseMap++ ) { ri.Printf( PRINT_ALL, "(%i -> %i) ", j, *collapseMap ); } ri.Printf( PRINT_ALL, "\n" ); #endif // swap the bone references surf->numBoneReferences = mdmSurf->numBoneReferences; surf->boneReferences = ri.Hunk_Alloc( sizeof( *bonerefOut ) * mdmSurf->numBoneReferences, h_low ); boneref = ( int32_t * )( ( byte * ) mdmSurf + mdmSurf->ofsBoneReferences ); for ( j = 0, bonerefOut = surf->boneReferences; j < surf->numBoneReferences; j++, boneref++, bonerefOut++ ) { *bonerefOut = LittleLong( *boneref ); } // find the next surface mdmSurf = ( mdmSurface_t * )( ( byte * ) mdmSurf + mdmSurf->ofsEnd ); } // loading is done now calculate the bounding box and tangent spaces ClearBounds( mdmModel->bounds[ 0 ], mdmModel->bounds[ 1 ] ); for ( i = 0, surf = mdmModel->surfaces; i < mdmModel->numSurfaces; i++, surf++ ) { for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ ) { vec3_t tmpVert; md5Weight_t *w; VectorClear( tmpVert ); for ( k = 0, w = v->weights[ 0 ]; k < v->numWeights; k++, w++ ) { //vec3_t offsetVec; //VectorClear(offsetVec); //bone = &md5->bones[w->boneIndex]; //QuatTransformVector(bone->rotation, w->offset, offsetVec); //VectorAdd(bone->origin, offsetVec, offsetVec); VectorMA( tmpVert, w->boneWeight, w->offset, tmpVert ); } VectorCopy( tmpVert, v->position ); AddPointToBounds( tmpVert, mdmModel->bounds[ 0 ], mdmModel->bounds[ 1 ] ); } // calc tangent spaces #if 0 { const float *v0, *v1, *v2; const float *t0, *t1, *t2; vec3_t tangent; vec3_t binormal; vec3_t normal; for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ ) { VectorClear( v->tangent ); VectorClear( v->binormal ); VectorClear( v->normal ); } for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ ) { v0 = surf->verts[ tri->indexes[ 0 ] ].position; v1 = surf->verts[ tri->indexes[ 1 ] ].position; v2 = surf->verts[ tri->indexes[ 2 ] ].position; t0 = surf->verts[ tri->indexes[ 0 ] ].texCoords; t1 = surf->verts[ tri->indexes[ 1 ] ].texCoords; t2 = surf->verts[ tri->indexes[ 2 ] ].texCoords; #if 1 R_CalcTangentSpace( tangent, binormal, normal, v0, v1, v2, t0, t1, t2 ); #else R_CalcNormalForTriangle( normal, v0, v1, v2 ); R_CalcTangentsForTriangle( tangent, binormal, v0, v1, v2, t0, t1, t2 ); #endif for ( k = 0; k < 3; k++ ) { float *v; v = surf->verts[ tri->indexes[ k ] ].tangent; VectorAdd( v, tangent, v ); v = surf->verts[ tri->indexes[ k ] ].binormal; VectorAdd( v, binormal, v ); v = surf->verts[ tri->indexes[ k ] ].normal; VectorAdd( v, normal, v ); } } for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ ) { VectorNormalize( v->tangent ); VectorNormalize( v->binormal ); VectorNormalize( v->normal ); } } #else { int k; float bb, s, t; vec3_t bary; vec3_t faceNormal; md5Vertex_t *dv[ 3 ]; for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ ) { dv[ 0 ] = &surf->verts[ tri->indexes[ 0 ] ]; dv[ 1 ] = &surf->verts[ tri->indexes[ 1 ] ]; dv[ 2 ] = &surf->verts[ tri->indexes[ 2 ] ]; R_CalcNormalForTriangle( faceNormal, dv[ 0 ]->position, dv[ 1 ]->position, dv[ 2 ]->position ); // calculate barycentric basis for the triangle bb = ( dv[ 1 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 2 ]->texCoords[ 1 ] - dv[ 0 ]->texCoords[ 1 ] ) - ( dv[ 2 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 1 ]->texCoords[ 1 ] - dv[ 0 ]->texCoords[ 1 ] ); if ( fabs( bb ) < 0.00000001f ) { continue; } // do each vertex for ( k = 0; k < 3; k++ ) { // calculate s tangent vector s = dv[ k ]->texCoords[ 0 ] + 10.0f; t = dv[ k ]->texCoords[ 1 ]; bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb; dv[ k ]->tangent[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ]; dv[ k ]->tangent[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ]; dv[ k ]->tangent[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ]; VectorSubtract( dv[ k ]->tangent, dv[ k ]->position, dv[ k ]->tangent ); VectorNormalize( dv[ k ]->tangent ); // calculate t tangent vector (binormal) s = dv[ k ]->texCoords[ 0 ]; t = dv[ k ]->texCoords[ 1 ] + 10.0f; bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb; dv[ k ]->binormal[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ]; dv[ k ]->binormal[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ]; dv[ k ]->binormal[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ]; VectorSubtract( dv[ k ]->binormal, dv[ k ]->position, dv[ k ]->binormal ); VectorNormalize( dv[ k ]->binormal ); // calculate the normal as cross product N=TxB #if 0 CrossProduct( dv[ k ]->tangent, dv[ k ]->binormal, dv[ k ]->normal ); VectorNormalize( dv[ k ]->normal ); // Gram-Schmidt orthogonalization process for B // compute the cross product B=NxT to obtain // an orthogonal basis CrossProduct( dv[ k ]->normal, dv[ k ]->tangent, dv[ k ]->binormal ); if ( DotProduct( dv[ k ]->normal, faceNormal ) < 0 ) { VectorInverse( dv[ k ]->normal ); //VectorInverse(dv[k]->tangent); //VectorInverse(dv[k]->binormal); } #else //VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal); #endif } } #if 1 for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ ) { //VectorNormalize(v->tangent); //VectorNormalize(v->binormal); //VectorNormalize(v->normal); } #endif } #endif #if 0 // do another extra smoothing for normals to avoid flat shading for ( j = 0; j < surf->numVerts; j++ ) { for ( k = 0; k < surf->numVerts; k++ ) { if ( j == k ) { continue; } if ( VectorCompare( surf->verts[ j ].position, surf->verts[ k ].position ) ) { VectorAdd( surf->verts[ j ].normal, surf->verts[ k ].normal, surf->verts[ j ].normal ); } } VectorNormalize( surf->verts[ j ].normal ); } #endif } // split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones { int numRemaining; growList_t sortedTriangles; growList_t vboTriangles; growList_t vboSurfaces; int numBoneReferences; int boneReferences[ MAX_BONES ]; Com_InitGrowList( &vboSurfaces, 10 ); for ( i = 0, surf = mdmModel->surfaces; i < mdmModel->numSurfaces; i++, surf++ ) { // sort triangles Com_InitGrowList( &sortedTriangles, 1000 ); for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ ) { skelTriangle_t *sortTri = Com_Allocate( sizeof( *sortTri ) ); for ( k = 0; k < 3; k++ ) { sortTri->indexes[ k ] = tri->indexes[ k ]; sortTri->vertexes[ k ] = &surf->verts[ tri->indexes[ k ] ]; } sortTri->referenced = qfalse; Com_AddToGrowList( &sortedTriangles, sortTri ); } //qsort(sortedTriangles.elements, sortedTriangles.currentElements, sizeof(void *), CompareTrianglesByBoneReferences); #if 0 for ( j = 0; j < sortedTriangles.currentElements; j++ ) { int b[ MAX_WEIGHTS * 3 ]; skelTriangle_t *sortTri = Com_GrowListElement( &sortedTriangles, j ); for ( k = 0; k < 3; k++ ) { v = sortTri->vertexes[ k ]; for ( l = 0; l < MAX_WEIGHTS; l++ ) { b[ k * 3 + l ] = ( l < v->numWeights ) ? v->weights[ l ]->boneIndex : 9999; } qsort( b, MAX_WEIGHTS * 3, sizeof( int ), CompareBoneIndices ); //ri.Printf(PRINT_ALL, "bone indices: %i %i %i %i\n", b[k * 3 + 0], b[k * 3 + 1], b[k * 3 + 2], b[k * 3 + 3]); } } #endif numRemaining = sortedTriangles.currentElements; while ( numRemaining ) { numBoneReferences = 0; Com_Memset( boneReferences, 0, sizeof( boneReferences ) ); Com_InitGrowList( &vboTriangles, 1000 ); for ( j = 0; j < sortedTriangles.currentElements; j++ ) { skelTriangle_t *sortTri = Com_GrowListElement( &sortedTriangles, j ); if ( sortTri->referenced ) { continue; } if ( AddTriangleToVBOTriangleList( &vboTriangles, sortTri, &numBoneReferences, boneReferences ) ) { sortTri->referenced = qtrue; } } if ( !vboTriangles.currentElements ) { ri.Printf( PRINT_WARNING, "R_LoadMDM: could not add triangles to a remaining VBO surface for model '%s'\n", modName ); break; } AddSurfaceToVBOSurfacesListMDM( &vboSurfaces, &vboTriangles, mdmModel, surf, i, numBoneReferences, boneReferences ); numRemaining -= vboTriangles.currentElements; Com_DestroyGrowList( &vboTriangles ); } for ( j = 0; j < sortedTriangles.currentElements; j++ ) { skelTriangle_t *sortTri = Com_GrowListElement( &sortedTriangles, j ); Com_Dealloc( sortTri ); } Com_DestroyGrowList( &sortedTriangles ); } // move VBO surfaces list to hunk mdmModel->numVBOSurfaces = vboSurfaces.currentElements; mdmModel->vboSurfaces = ri.Hunk_Alloc( mdmModel->numVBOSurfaces * sizeof( *mdmModel->vboSurfaces ), h_low ); for ( i = 0; i < mdmModel->numVBOSurfaces; i++ ) { mdmModel->vboSurfaces[ i ] = ( srfVBOMDMMesh_t * ) Com_GrowListElement( &vboSurfaces, i ); } Com_DestroyGrowList( &vboSurfaces ); } return qtrue; }
qboolean R_LoadMD5(model_t *mod, void *buffer, int bufferSize, const char *modName) { int i, j, k; md5Model_t *md5; md5Bone_t *bone; md5Surface_t *surf; srfTriangle_t *tri; md5Vertex_t *v; md5Weight_t *weight; int version; shader_t *sh; char *buf_p = ( char * ) buffer; char *token; vec3_t boneOrigin; quat_t boneQuat; matrix_t boneMat; int numRemaining; growList_t sortedTriangles; growList_t vboTriangles; growList_t vboSurfaces; int numBoneReferences; int boneReferences[MAX_BONES]; // skip MD5Version indent string COM_ParseExt2(&buf_p, qfalse); // check version token = COM_ParseExt2(&buf_p, qfalse); version = atoi(token); if (version != MD5_VERSION) { Ren_Warning("R_LoadMD5: %s has wrong version (%i should be %i)\n", modName, version, MD5_VERSION); return qfalse; } mod->type = MOD_MD5; mod->dataSize += sizeof(md5Model_t); md5 = mod->md5 = ri.Hunk_Alloc(sizeof(md5Model_t), h_low); // skip commandline <arguments string> token = COM_ParseExt2(&buf_p, qtrue); token = COM_ParseExt2(&buf_p, qtrue); // Ren_Print("%s\n", token); // parse numJoints <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "numJoints")) { Ren_Warning("R_LoadMD5: expected 'numJoints' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); md5->numBones = atoi(token); // parse numMeshes <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "numMeshes")) { Ren_Warning("R_LoadMD5: expected 'numMeshes' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); md5->numSurfaces = atoi(token); //Ren_Print("R_LoadMD5: '%s' has %i surfaces\n", modName, md5->numSurfaces); if (md5->numBones < 1) { Ren_Warning("R_LoadMD5: '%s' has no bones\n", modName); return qfalse; } if (md5->numBones > MAX_BONES) { Ren_Warning("R_LoadMD5: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones); return qfalse; } //Ren_Print("R_LoadMD5: '%s' has %i bones\n", modName, md5->numBones); // parse all the bones md5->bones = ri.Hunk_Alloc(sizeof(*bone) * md5->numBones, h_low); // parse joints { token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "joints")) { Ren_Warning("R_LoadMD5: expected 'joints' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, "{")) { Ren_Warning("R_LoadMD5: expected '{' found '%s' in model '%s'\n", token, modName); return qfalse; } for (i = 0, bone = md5->bones; i < md5->numBones; i++, bone++) { token = COM_ParseExt2(&buf_p, qtrue); Q_strncpyz(bone->name, token, sizeof(bone->name)); //Ren_Print("R_LoadMD5: '%s' has bone '%s'\n", modName, bone->name); token = COM_ParseExt2(&buf_p, qfalse); bone->parentIndex = atoi(token); //Ren_Print("R_LoadMD5: '%s' has bone '%s' with parent index %i\n", modName, bone->name, bone->parentIndex); if (bone->parentIndex >= md5->numBones) { Ren_Drop("R_LoadMD5: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName, bone->name, bone->parentIndex, md5->numBones); } // skip ( token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, "(")) { Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName); return qfalse; } for (j = 0; j < 3; j++) { token = COM_ParseExt2(&buf_p, qfalse); boneOrigin[j] = atof(token); } // skip ) token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, ")")) { Ren_Warning("R_LoadMD5: expected ')' found '%s' in model '%s'\n", token, modName); return qfalse; } // skip ( token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, "(")) { Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName); return qfalse; } for (j = 0; j < 3; j++) { token = COM_ParseExt2(&buf_p, qfalse); boneQuat[j] = atof(token); } QuatCalcW(boneQuat); MatrixFromQuat(boneMat, boneQuat); VectorCopy(boneOrigin, bone->origin); QuatCopy(boneQuat, bone->rotation); MatrixSetupTransformFromQuat(bone->inverseTransform, boneQuat, boneOrigin); MatrixInverse(bone->inverseTransform); // skip ) token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, ")")) { Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName); return qfalse; } } // parse } token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "}")) { Ren_Warning("R_LoadMD5: expected '}' found '%s' in model '%s'\n", token, modName); return qfalse; } // parse all the surfaces if (md5->numSurfaces < 1) { Ren_Warning("R_LoadMD5: '%s' has no surfaces\n", modName); return qfalse; } //Ren_Print("R_LoadMD5: '%s' has %i surfaces\n", modName, md5->numSurfaces); md5->surfaces = ri.Hunk_Alloc(sizeof(*surf) * md5->numSurfaces, h_low); for (i = 0, surf = md5->surfaces; i < md5->numSurfaces; i++, surf++) { // parse mesh { token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "mesh")) { Ren_Warning("R_LoadMD5: expected 'mesh' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, "{")) { Ren_Warning("R_LoadMD5: expected '{' found '%s' in model '%s'\n", token, modName); return qfalse; } // change to surface identifier surf->surfaceType = SF_MD5; // give pointer to model for Tess_SurfaceMD5 surf->model = md5; // parse shader <name> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "shader")) { Ren_Warning("R_LoadMD5: expected 'shader' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); Q_strncpyz(surf->shader, token, sizeof(surf->shader)); //Ren_Print("R_LoadMD5: '%s' uses shader '%s'\n", modName, surf->shader); // FIXME .md5mesh meshes don't have surface names // lowercase the surface name so skin compares are faster //Q_strlwr(surf->name); //Ren_Print("R_LoadMD5: '%s' has surface '%s'\n", modName, surf->name); // register the shaders sh = R_FindShader(surf->shader, SHADER_3D_DYNAMIC, qtrue); if (sh->defaultShader) { surf->shaderIndex = 0; } else { surf->shaderIndex = sh->index; } // parse numVerts <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "numVerts")) { Ren_Warning("R_LoadMD5: expected 'numVerts' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); surf->numVerts = atoi(token); if (surf->numVerts > SHADER_MAX_VERTEXES) { Ren_Drop("R_LoadMD5: '%s' has more than %i verts on a surface (%i)", modName, SHADER_MAX_VERTEXES, surf->numVerts); } surf->verts = ri.Hunk_Alloc(sizeof(*v) * surf->numVerts, h_low); for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { // skip vert <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "vert")) { Ren_Warning("R_LoadMD5: expected 'vert' found '%s' in model '%s'\n", token, modName); return qfalse; } COM_ParseExt2(&buf_p, qfalse); // skip ( token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, "(")) { Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName); return qfalse; } for (k = 0; k < 2; k++) { token = COM_ParseExt2(&buf_p, qfalse); v->texCoords[k] = atof(token); } // skip ) token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, ")")) { Ren_Warning("R_LoadMD5: expected ')' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); v->firstWeight = atoi(token); token = COM_ParseExt2(&buf_p, qfalse); v->numWeights = atoi(token); if (v->numWeights > MAX_WEIGHTS) { Ren_Drop("R_LoadMD5: vertex %i requires more than %i weights on surface (%i) in model '%s'", j, MAX_WEIGHTS, i, modName); } } // parse numTris <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "numTris")) { Ren_Warning("R_LoadMD5: expected 'numTris' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); surf->numTriangles = atoi(token); if (surf->numTriangles > SHADER_MAX_TRIANGLES) { Ren_Drop("R_LoadMD5: '%s' has more than %i triangles on a surface (%i)", modName, SHADER_MAX_TRIANGLES, surf->numTriangles); } surf->triangles = ri.Hunk_Alloc(sizeof(*tri) * surf->numTriangles, h_low); for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++) { // skip tri <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "tri")) { Ren_Warning("R_LoadMD5: expected 'tri' found '%s' in model '%s'\n", token, modName); return qfalse; } COM_ParseExt2(&buf_p, qfalse); for (k = 0; k < 3; k++) { token = COM_ParseExt2(&buf_p, qfalse); tri->indexes[k] = atoi(token); } } // parse numWeights <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "numWeights")) { Ren_Warning("R_LoadMD5: expected 'numWeights' found '%s' in model '%s'\n", token, modName); return qfalse; } token = COM_ParseExt2(&buf_p, qfalse); surf->numWeights = atoi(token); surf->weights = ri.Hunk_Alloc(sizeof(*weight) * surf->numWeights, h_low); for (j = 0, weight = surf->weights; j < surf->numWeights; j++, weight++) { // skip weight <number> token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "weight")) { Ren_Warning("R_LoadMD5: expected 'weight' found '%s' in model '%s'\n", token, modName); return qfalse; } COM_ParseExt2(&buf_p, qfalse); token = COM_ParseExt2(&buf_p, qfalse); weight->boneIndex = atoi(token); token = COM_ParseExt2(&buf_p, qfalse); weight->boneWeight = atof(token); // skip ( token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, "(")) { Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName); return qfalse; } for (k = 0; k < 3; k++) { token = COM_ParseExt2(&buf_p, qfalse); weight->offset[k] = atof(token); } // skip ) token = COM_ParseExt2(&buf_p, qfalse); if (Q_stricmp(token, ")")) { Ren_Warning("R_LoadMD5: expected ')' found '%s' in model '%s'\n", token, modName); return qfalse; } } // parse } token = COM_ParseExt2(&buf_p, qtrue); if (Q_stricmp(token, "}")) { Ren_Warning("R_LoadMD5: expected '}' found '%s' in model '%s'\n", token, modName); return qfalse; } // loop trough all vertices and set up the vertex weights for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { v->weights = ri.Hunk_Alloc(sizeof(*v->weights) * v->numWeights, h_low); for (k = 0; k < v->numWeights; k++) { v->weights[k] = surf->weights + (v->firstWeight + k); } } } // loading is done now calculate the bounding box and tangent spaces ClearBounds(md5->bounds[0], md5->bounds[1]); for (i = 0, surf = md5->surfaces; i < md5->numSurfaces; i++, surf++) { for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { vec3_t tmpVert; md5Weight_t *w; VectorClear(tmpVert); for (k = 0, w = v->weights[0]; k < v->numWeights; k++, w++) { vec3_t offsetVec; bone = &md5->bones[w->boneIndex]; QuatTransformVector(bone->rotation, w->offset, offsetVec); VectorAdd(bone->origin, offsetVec, offsetVec); VectorMA(tmpVert, w->boneWeight, offsetVec, tmpVert); } VectorCopy(tmpVert, v->position); AddPointToBounds(tmpVert, md5->bounds[0], md5->bounds[1]); } // calc tangent spaces #if 1 { const float *v0, *v1, *v2; const float *t0, *t1, *t2; vec3_t tangent; vec3_t binormal; vec3_t normal; for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { VectorClear(v->tangent); VectorClear(v->binormal); VectorClear(v->normal); } for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++) { v0 = surf->verts[tri->indexes[0]].position; v1 = surf->verts[tri->indexes[1]].position; v2 = surf->verts[tri->indexes[2]].position; t0 = surf->verts[tri->indexes[0]].texCoords; t1 = surf->verts[tri->indexes[1]].texCoords; t2 = surf->verts[tri->indexes[2]].texCoords; #if 1 R_CalcTangentSpace(tangent, binormal, normal, v0, v1, v2, t0, t1, t2); #else R_CalcNormalForTriangle(normal, v0, v1, v2); R_CalcTangentsForTriangle(tangent, binormal, v0, v1, v2, t0, t1, t2); #endif for (k = 0; k < 3; k++) { float *v; v = surf->verts[tri->indexes[k]].tangent; VectorAdd(v, tangent, v); v = surf->verts[tri->indexes[k]].binormal; VectorAdd(v, binormal, v); v = surf->verts[tri->indexes[k]].normal; VectorAdd(v, normal, v); } } for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { VectorNormalize(v->tangent); VectorNormalize(v->binormal); VectorNormalize(v->normal); } } #else { int k; float bb, s, t; vec3_t bary; vec3_t faceNormal; md5Vertex_t *dv[3]; for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++) { dv[0] = &surf->verts[tri->indexes[0]]; dv[1] = &surf->verts[tri->indexes[1]]; dv[2] = &surf->verts[tri->indexes[2]]; R_CalcNormalForTriangle(faceNormal, dv[0]->position, dv[1]->position, dv[2]->position); // calculate barycentric basis for the triangle bb = (dv[1]->texCoords[0] - dv[0]->texCoords[0]) * (dv[2]->texCoords[1] - dv[0]->texCoords[1]) - (dv[2]->texCoords[0] - dv[0]->texCoords[0]) * (dv[1]->texCoords[1] - dv[0]->texCoords[1]); if (fabs(bb) < 0.00000001f) { continue; } // do each vertex for (k = 0; k < 3; k++) { // calculate s tangent vector s = dv[k]->texCoords[0] + 10.0f; t = dv[k]->texCoords[1]; bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb; bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb; bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb; dv[k]->tangent[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0]; dv[k]->tangent[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1]; dv[k]->tangent[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2]; VectorSubtract(dv[k]->tangent, dv[k]->position, dv[k]->tangent); VectorNormalize(dv[k]->tangent); // calculate t tangent vector (binormal) s = dv[k]->texCoords[0]; t = dv[k]->texCoords[1] + 10.0f; bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb; bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb; bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb; dv[k]->binormal[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0]; dv[k]->binormal[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1]; dv[k]->binormal[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2]; VectorSubtract(dv[k]->binormal, dv[k]->position, dv[k]->binormal); VectorNormalize(dv[k]->binormal); // calculate the normal as cross product N=TxB #if 0 CrossProduct(dv[k]->tangent, dv[k]->binormal, dv[k]->normal); VectorNormalize(dv[k]->normal); // Gram-Schmidt orthogonalization process for B // compute the cross product B=NxT to obtain // an orthogonal basis CrossProduct(dv[k]->normal, dv[k]->tangent, dv[k]->binormal); if (DotProduct(dv[k]->normal, faceNormal) < 0) { VectorInverse(dv[k]->normal); //VectorInverse(dv[k]->tangent); //VectorInverse(dv[k]->binormal); } #else VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal); #endif } } #if 1 for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++) { //VectorNormalize(v->tangent); //VectorNormalize(v->binormal); VectorNormalize(v->normal); } #endif } #endif #if 0 // do another extra smoothing for normals to avoid flat shading for (j = 0; j < surf->numVerts; j++) { for (k = 0; k < surf->numVerts; k++) { if (j == k) { continue; } if (VectorCompare(surf->verts[j].position, surf->verts[k].position)) { VectorAdd(surf->verts[j].normal, surf->verts[k].normal, surf->verts[j].normal); } } VectorNormalize(surf->verts[j].normal); } #endif } // split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones Com_InitGrowList(&vboSurfaces, 10); for (i = 0, surf = md5->surfaces; i < md5->numSurfaces; i++, surf++) { // sort triangles Com_InitGrowList(&sortedTriangles, 1000); for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++) { skelTriangle_t *sortTri = Com_Allocate(sizeof(*sortTri)); for (k = 0; k < 3; k++) { sortTri->indexes[k] = tri->indexes[k]; sortTri->vertexes[k] = &surf->verts[tri->indexes[k]]; } sortTri->referenced = qfalse; Com_AddToGrowList(&sortedTriangles, sortTri); } //qsort(sortedTriangles.elements, sortedTriangles.currentElements, sizeof(void *), CompareTrianglesByBoneReferences); #if 0 for (j = 0; j < sortedTriangles.currentElements; j++) { int b[MAX_WEIGHTS * 3]; skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j); for (k = 0; k < 3; k++) { v = sortTri->vertexes[k]; for (l = 0; l < MAX_WEIGHTS; l++) { b[k * 3 + l] = (l < v->numWeights) ? v->weights[l]->boneIndex : 9999; } qsort(b, MAX_WEIGHTS * 3, sizeof(int), CompareBoneIndices); //Ren_Print("bone indices: %i %i %i %i\n", b[k * 3 + 0], b[k * 3 + 1], b[k * 3 + 2], b[k * 3 + 3]); } } #endif numRemaining = sortedTriangles.currentElements; while (numRemaining) { numBoneReferences = 0; Com_Memset(boneReferences, 0, sizeof(boneReferences)); Com_InitGrowList(&vboTriangles, 1000); for (j = 0; j < sortedTriangles.currentElements; j++) { skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j); if (sortTri->referenced) { continue; } if (AddTriangleToVBOTriangleList(&vboTriangles, sortTri, &numBoneReferences, boneReferences)) { sortTri->referenced = qtrue; } } if (!vboTriangles.currentElements) { Ren_Warning("R_LoadMD5: could not add triangles to a remaining VBO surfaces for model '%s'\n", modName); Com_DestroyGrowList(&vboTriangles); break; } AddSurfaceToVBOSurfacesList(&vboSurfaces, &vboTriangles, md5, surf, i, numBoneReferences, boneReferences); numRemaining -= vboTriangles.currentElements; Com_DestroyGrowList(&vboTriangles); } for (j = 0; j < sortedTriangles.currentElements; j++) { skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j); Com_Dealloc(sortTri); } Com_DestroyGrowList(&sortedTriangles); } // move VBO surfaces list to hunk md5->numVBOSurfaces = vboSurfaces.currentElements; md5->vboSurfaces = ri.Hunk_Alloc(md5->numVBOSurfaces * sizeof(*md5->vboSurfaces), h_low); for (i = 0; i < md5->numVBOSurfaces; i++) { md5->vboSurfaces[i] = ( srfVBOMD5Mesh_t * ) Com_GrowListElement(&vboSurfaces, i); } Com_DestroyGrowList(&vboSurfaces); return qtrue; }
void JVM_Init(void) { int i; jint nVMs = 0; // number of VM's active JavaVMInitArgs vm_args; growList_t growOptions; JavaVMOption *option; JavaVMOption *options; char classPath[MAX_QPATH]; char policyPath[MAX_OSPATH]; Com_InitGrowList(&growOptions, 5); Com_Printf("------- JVM_Init() -------\n"); jvm_javaLib = Cvar_Get("jvm_javaLib", DEFAULT_JAVA_LIB, CVAR_ARCHIVE | CVAR_LATCH); jvm_useJITCompiler = Cvar_Get("jvm_useJITCompiler", "1", CVAR_INIT); jvm_useJAR = Cvar_Get("jvm_useJAR", "0", CVAR_ARCHIVE | CVAR_LATCH); jvm_remoteDebugging = Cvar_Get("jvm_remoteDebugging", "0", CVAR_ARCHIVE | CVAR_LATCH); jvm_profiling = Cvar_Get("jvm_profiling", "0", CVAR_ARCHIVE | CVAR_LATCH); jvm_verboseJNI = Cvar_Get("jvm_verboseJNI", "0", CVAR_ARCHIVE | CVAR_LATCH); jvm_verboseClass = Cvar_Get("jvm_verboseClass", "0", CVAR_ARCHIVE | CVAR_LATCH); jvm_verboseGC = Cvar_Get("jvm_verboseGC", "0", CVAR_ARCHIVE | CVAR_LATCH); jvm_policyFile = Cvar_Get("jvm_policyFile", "", CVAR_ARCHIVE | CVAR_LATCH); option = AllocOption(&growOptions); if(!jvm_useJITCompiler->integer) { Com_Printf("Disabling Java JIT support\n"); option->optionString = "-Djava.compiler=NONE"; } else { option->optionString = "-Djava.compiler=YES"; } // TODO support sv_pure if(jvm_useJAR->integer) { Com_sprintf(classPath, sizeof(classPath), "-Djava.class.path=%s", FS_BuildOSPath(Cvar_VariableString("fs_basepath"), Cvar_VariableString("fs_game"), "game.jar")); } else { Com_sprintf(classPath, sizeof(classPath), "-Djava.class.path=%s", FS_BuildOSPath(Cvar_VariableString("fs_basepath"), Cvar_VariableString("fs_game"), "classes")); } option = AllocOption(&growOptions); option->optionString = classPath; Com_Printf("Set main class path to '%s'\n", classPath); if(jvm_remoteDebugging->integer) { Com_Printf("Enabling remote debugging\n"); option = AllocOption(&growOptions); option->optionString = "-Xdebug"; option = AllocOption(&growOptions); option->optionString = "-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=y"; } if(jvm_verboseJNI->integer) { Com_Printf("Enabling verbose JNI prints\n"); option = AllocOption(&growOptions); option->optionString = "-verbose:jni"; } if(jvm_verboseClass->integer) { Com_Printf("Enabling displaying information about each class loaded.\n"); option = AllocOption(&growOptions); option->optionString = "-verbose:class"; } if(jvm_verboseGC->integer) { Com_Printf("Enabling reports on each garbage collection event.\n"); option = AllocOption(&growOptions); option->optionString = "-verbose:gc"; } #if 1 { Com_Printf("Enabling security manager\n"); option = AllocOption(&growOptions); option->optionString = "-Djava.security.manager"; } #endif if(Q_stricmp(jvm_policyFile->string, "") != 0) { Com_sprintf(policyPath, sizeof(policyPath), "-Djava.security.policy=file:%s", FS_BuildOSPath(Cvar_VariableString("fs_basepath"), Cvar_VariableString("fs_game"), jvm_policyFile->string)); option = AllocOption(&growOptions); option->optionString = policyPath; Com_Printf("Enabling '%s'\n", policyPath); } // convert growlist to array options = Com_Allocate(growOptions.currentElements * sizeof(JavaVMOption)); for(i = 0; i < growOptions.currentElements; i++) { options[i] = *(JavaVMOption*) Com_GrowListElement(&growOptions, i); } vm_args.version = JNI_VERSION_1_4; vm_args.options = options; vm_args.nOptions = growOptions.currentElements; vm_args.ignoreUnrecognized = JNI_TRUE; #if defined(USE_JAVA_DLOPEN) if(!JVM_JNI_Init()) { Com_Error(ERR_FATAL, "JNI initialization failed"); } #endif Com_Printf("Searching for existing Java VM's ..."); // look for an existing VM #if defined(USE_JAVA_DLOPEN) if(QJNI_GetCreatedJavaVMs(&javaVM, 1, &nVMs) != JNI_OK) #else if(JNI_GetCreatedJavaVMs(&javaVM, 1, &nVMs) != JNI_OK) #endif { Com_Error(ERR_FATAL, "Search for existing VM's failed"); } Com_Printf("found %i\n", nVMs); #if 1 if(nVMs > 0) { Com_Printf("Attaching to existing Java VM..."); if((*javaVM)->AttachCurrentThread(javaVM, (void **)&javaEnv, NULL)) { Com_Error(ERR_FATAL, "Couldn't attach to existing VM"); } javaVMIsOurs = qfalse; //javaVM = jvm; Com_Printf("done\n"); } else #endif { int res; Com_Printf("Creating new Java VM..."); // Create the Java VM #if defined(USE_JAVA_DLOPEN) res = QJNI_CreateJavaVM(&javaVM, (void **)&javaEnv, &vm_args); #else res = JNI_CreateJavaVM(&javaVM, (void **)&javaEnv, &vm_args); #endif if(res != JNI_OK ) { Com_Error(ERR_FATAL, "Can't create Java VM, JNI returned %i", res); } //javaVM = jvm; Com_Printf("done\n"); } if(!javaVM) { Com_Error(ERR_FATAL, "JVM_Init failed"); } // finally register the needed core modules Misc_javaRegister(); Engine_javaRegister(); CVar_javaRegister(); UserCommand_javaRegister(); // clean up allocated objects for(i = 0; i < growOptions.currentElements; i++) { option = Com_GrowListElement(&growOptions, i); Com_Dealloc(option); } Com_DestroyGrowList(&growOptions); Com_Dealloc(options); }
void Com_DestroyGrowList(growList_t *list) { Com_Dealloc(list->elements); memset(list, 0, sizeof(*list)); }
/** * @brief SND_shutdown */ void SND_shutdown(void) { Com_Dealloc(sfxScratchBuffer); Com_Dealloc(buffer); }