/* ================= Mod_LoadSpriteModel ================= */ void Mod_LoadSpriteModel(model_t *mod, void *buffer, const char *loadname) { int i; msprite_t *psprite; int numframes; int size; dspriteframetype_t *pframetype; dsprite_t *pin = (dsprite_t *)buffer; #ifdef MSB_FIRST int version = LittleLong(pin->version); #else int version = (pin->version); #endif if (version != SPRITE_VERSION) Sys_Error("%s: %s has wrong version number (%i should be %i)", __func__, mod->name, version, SPRITE_VERSION); #ifdef MSB_FIRST numframes = LittleLong(pin->numframes); #else numframes = (pin->numframes); #endif size = sizeof(*psprite) + numframes * sizeof(psprite->frames[0]); psprite = (msprite_t*)Hunk_AllocName(size, loadname); mod->cache.data = psprite; #ifdef MSB_FIRST psprite->type = LittleLong(pin->type); psprite->maxwidth = LittleLong(pin->width); psprite->maxheight = LittleLong(pin->height); psprite->beamlength = LittleFloat(pin->beamlength); mod->synctype = (synctype_t)LittleLong(pin->synctype); #else psprite->type = (pin->type); psprite->maxwidth = (pin->width); psprite->maxheight = (pin->height); psprite->beamlength = (pin->beamlength); mod->synctype = (synctype_t)(pin->synctype); #endif psprite->numframes = numframes; mod->mins[0] = mod->mins[1] = -psprite->maxwidth / 2; mod->maxs[0] = mod->maxs[1] = psprite->maxwidth / 2; mod->mins[2] = -psprite->maxheight / 2; mod->maxs[2] = psprite->maxheight / 2; // // load the frames // if (numframes < 1) Sys_Error("%s: Invalid # of frames: %d", __func__, numframes); mod->numframes = numframes; mod->flags = 0; pframetype = (dspriteframetype_t *)(pin + 1); for (i = 0; i < numframes; i++) { spriteframetype_t frametype; #ifdef MSB_FIRST frametype = (spriteframetype_t)LittleLong(pframetype->type); #else frametype = (spriteframetype_t)(pframetype->type); #endif psprite->frames[i].type = frametype; if (frametype == SPR_SINGLE) { pframetype = (dspriteframetype_t *) Mod_LoadSpriteFrame(pframetype + 1, &psprite->frames[i].frameptr, loadname, i); } else { pframetype = (dspriteframetype_t *) Mod_LoadSpriteGroup(pframetype + 1, &psprite->frames[i].frameptr, loadname, i); } } mod->type = mod_sprite; }
/* ================= Mod_LoadAliasModel ================= */ void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i, j; dmdl_t *pinmodel, *pheader; dstvert_t *pinst, *poutst; dtriangle_t *pintri, *pouttri; daliasframe_t *pinframe, *poutframe; int *pincmd, *poutcmd; int version; pinmodel = (dmdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end)); // byte swap the header fields and sanity check for (i=0 ; i<sizeof(dmdl_t)/4 ; i++) ((int *)pheader)[i] = LittleLong (((int *)buffer)[i]); if (pheader->skinheight > MAX_LBM_HEIGHT) ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); if (pheader->num_xyz <= 0) ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name); if (pheader->num_xyz > MAX_VERTS) ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name); if (pheader->num_st <= 0) ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name); if (pheader->num_tris <= 0) ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name); if (pheader->num_frames <= 0) ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name); // // load base s and t vertices (not used in gl version) // pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st); poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st); for (i=0 ; i<pheader->num_st ; i++) { poutst[i].s = LittleShort (pinst[i].s); poutst[i].t = LittleShort (pinst[i].t); } // // load triangle lists // pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris); pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris); for (i=0 ; i<pheader->num_tris ; i++) { for (j=0 ; j<3 ; j++) { pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]); pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]); } } // // load the frames // for (i=0 ; i<pheader->num_frames ; i++) { pinframe = (daliasframe_t *) ((byte *)pinmodel + pheader->ofs_frames + i * pheader->framesize); poutframe = (daliasframe_t *) ((byte *)pheader + pheader->ofs_frames + i * pheader->framesize); memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name)); for (j=0 ; j<3 ; j++) { poutframe->scale[j] = LittleFloat (pinframe->scale[j]); poutframe->translate[j] = LittleFloat (pinframe->translate[j]); } // verts are all 8 bit, so no swapping needed memcpy (poutframe->verts, pinframe->verts, pheader->num_xyz*sizeof(dtrivertx_t)); } mod->type = mod_alias; // // load the glcmds // pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds); poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds); for (i=0 ; i<pheader->num_glcmds ; i++) poutcmd[i] = LittleLong (pincmd[i]); // register all skins memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins, pheader->num_skins*MAX_SKINNAME); for (i=0 ; i<pheader->num_skins ; i++) { mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME , it_skin); } mod->mins[0] = -32; mod->mins[1] = -32; mod->mins[2] = -32; mod->maxs[0] = 32; mod->maxs[1] = 32; mod->maxs[2] = 32; }
/* ================= Mod_LoadSpriteModel ================= */ void Mod_LoadSpriteModel (model_t *mod, void *buffer) { int i; int version; dsprite_t *pin; msprite_t *psprite; int numframes; int size; dspriteframetype_t *pframetype; pin = (dsprite_t *)buffer; version = LittleLong (pin->version); if (version != SPRITE_VERSION) Sys_Error ("%s has wrong version number " "(%i should be %i)", mod->name, version, SPRITE_VERSION); numframes = LittleLong (pin->numframes); size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); psprite = Hunk_AllocName (size, loadname); mod->cache.data = psprite; psprite->type = LittleLong (pin->type); psprite->maxwidth = LittleLong (pin->width); psprite->maxheight = LittleLong (pin->height); psprite->beamlength = LittleFloat (pin->beamlength); mod->synctype = LittleLong (pin->synctype); psprite->numframes = numframes; mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; mod->mins[2] = -psprite->maxheight/2; mod->maxs[2] = psprite->maxheight/2; // // load the frames // if (numframes < 1) Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); mod->numframes = numframes; pframetype = (dspriteframetype_t *)(pin + 1); for (i=0 ; i<numframes ; i++) { spriteframetype_t frametype; frametype = LittleLong (pframetype->type); psprite->frames[i].type = frametype; if (frametype == SPR_SINGLE) { pframetype = (dspriteframetype_t *) Mod_LoadSpriteFrame (pframetype + 1, &psprite->frames[i].frameptr, i); } else { pframetype = (dspriteframetype_t *) Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i); } } mod->type = mod_sprite; }
/* =============== ParseTriSurf =============== */ static void ParseTriSurf( dsurface_t *ds, mapVert_t *verts, msurface_t *surf, int *indexes, world_t &worldData, int index ) { srfTriangles_t *tri; int i, j, k; int numVerts, numIndexes; // get fog volume surf->fogIndex = LittleLong( ds->fogNum ) + 1; if (index && !surf->fogIndex && tr.world && tr.world->globalFog != -1) { surf->fogIndex = worldData.globalFog; } // get shader surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapsVertex, ds->lightmapStyles, ds->vertexStyles, worldData ); if ( r_singleShader->integer && !surf->shader->sky ) { surf->shader = tr.defaultShader; } numVerts = LittleLong( ds->numVerts ); numIndexes = LittleLong( ds->numIndexes ); if ( numVerts >= SHADER_MAX_VERTEXES ) { Com_Error(ERR_DROP, "ParseTriSurf: verts > MAX (%d > %d) on misc_model %s", numVerts, SHADER_MAX_VERTEXES, surf->shader->name ); } if ( numIndexes >= SHADER_MAX_INDEXES ) { Com_Error(ERR_DROP, "ParseTriSurf: indices > MAX (%d > %d) on misc_model %s", numIndexes, SHADER_MAX_INDEXES, surf->shader->name ); } tri = (srfTriangles_t *) Z_Malloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) + numIndexes * sizeof( tri->indexes[0] ), TAG_HUNKMISCMODELS, qfalse ); tri->dlightBits = 0; //JIC tri->surfaceType = SF_TRIANGLES; tri->numVerts = numVerts; tri->numIndexes = numIndexes; tri->verts = (drawVert_t *)(tri + 1); tri->indexes = (int *)(tri->verts + tri->numVerts ); surf->data = (surfaceType_t *)tri; // copy vertexes verts += LittleLong( ds->firstVert ); ClearBounds( tri->bounds[0], tri->bounds[1] ); for ( i = 0 ; i < numVerts ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) { tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] ); } AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] ); for ( j = 0 ; j < 2 ; j++ ) { tri->verts[i].st[j] = LittleFloat( verts[i].st[j] ); for(k=0;k<MAXLIGHTMAPS;k++) { tri->verts[i].lightmap[k][j] = LittleFloat( verts[i].lightmap[k][j] ); } } for(k=0;k<MAXLIGHTMAPS;k++) { R_ColorShiftLightingBytes( verts[i].color[k], tri->verts[i].color[k] ); } } // copy indexes indexes += LittleLong( ds->firstIndex ); for ( i = 0 ; i < numIndexes ; i++ ) { tri->indexes[i] = LittleLong( indexes[i] ); if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) { Com_Error( ERR_DROP, "Bad index in triangle surface" ); } } }
static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) { int i, j, k, l; mdrHeader_t *pinmodel, *mdr; mdrFrame_t *frame; mdrLOD_t *lod, *curlod; mdrSurface_t *surf, *cursurf; mdrTriangle_t *tri, *curtri; mdrVertex_t *v, *curv; mdrWeight_t *weight, *curweight; mdrTag_t *tag, *curtag; int size; shader_t *sh; pinmodel = (mdrHeader_t *)buffer; pinmodel->version = LittleLong(pinmodel->version); if (pinmodel->version != MDR_VERSION) { ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION); return qfalse; } size = LittleLong(pinmodel->ofsEnd); if(size > filesize) { ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name); return qfalse; } mod->type = MOD_MDR; pinmodel->numFrames = LittleLong(pinmodel->numFrames); pinmodel->numBones = LittleLong(pinmodel->numBones); pinmodel->ofsFrames = LittleLong(pinmodel->ofsFrames); // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4. if(pinmodel->ofsFrames < 0) { // mdrFrame_t is larger than mdrCompFrame_t: size += pinmodel->numFrames * sizeof(frame->name); // now add enough space for the uncompressed bones. size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t))); } mod->dataSize += size; mod->md4 = mdr = ri.Hunk_Alloc( size, h_low ); // Copy all the values over from the file and fix endian issues in the process, if necessary. mdr->ident = LittleLong(pinmodel->ident); mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above. Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name)); mdr->numFrames = pinmodel->numFrames; mdr->numBones = pinmodel->numBones; mdr->numLODs = LittleLong(pinmodel->numLODs); mdr->numTags = LittleLong(pinmodel->numTags); // We don't care about offset values, we'll generate them ourselves while loading. mod->numLods = mdr->numLODs; if ( mdr->numFrames < 1 ) { ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name); return qfalse; } /* The first frame will be put into the first free space after the header */ frame = (mdrFrame_t *)(mdr + 1); mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr); if (pinmodel->ofsFrames < 0) { mdrCompFrame_t *cframe; // compressed model... cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames); for(i = 0; i < mdr->numFrames; i++) { for(j = 0; j < 3; j++) { frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]); frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]); frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]); } frame->radius = LittleFloat(cframe->radius); frame->name[0] = '\0'; // No name supplied in the compressed version. for(j = 0; j < mdr->numBones; j++) { for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++) { // Do swapping for the uncompressing functions. They seem to use shorts // values only, so I assume this will work. Never tested it on other // platforms, though. ((unsigned short *)(cframe->bones[j].Comp))[k] = LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] ); } /* Now do the actual uncompressing */ MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp); } // Next Frame... cframe = (mdrCompFrame_t *) &cframe->bones[j]; frame = (mdrFrame_t *) &frame->bones[j]; } } else { mdrFrame_t *curframe; // uncompressed model... // curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames); // swap all the frames for ( i = 0 ; i < mdr->numFrames ; i++) { for(j = 0; j < 3; j++) { frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]); frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]); frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]); } frame->radius = LittleFloat(curframe->radius); Q_strncpyz(frame->name, curframe->name, sizeof(frame->name)); for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) { ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] ); } curframe++; frame++; } } // frame should now point to the first free address after all frames. lod = (mdrLOD_t *) frame; mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr); curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs)); // swap all the LOD's for ( l = 0 ; l < mdr->numLODs ; l++) { lod->numSurfaces = LittleLong(curlod->numSurfaces); // swap all the surfaces surf = (mdrSurface_t *) (lod + 1); lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod); cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces)); for ( i = 0 ; i < lod->numSurfaces ; i++) { // first do some copying stuff surf->ident = SF_MDR; Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); surf->ofsHeader = (byte *) mdr - (byte *) surf; surf->numVerts = LittleLong(cursurf->numVerts); surf->numTriangles = LittleLong(cursurf->numTriangles); // numBoneReferences and BoneReferences generally seem to be unused // now do the checks that may fail. if ( surf->numVerts > SHADER_MAX_VERTEXES ) { ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i)", mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); return qfalse; } if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i)", mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); return qfalse; } // lowercase the surface name so skin compares are faster Q_strlwr( surf->name ); // register the shaders sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); if ( sh->defaultShader ) { surf->shaderIndex = 0; } else { surf->shaderIndex = sh->index; } // now copy the vertexes. v = (mdrVertex_t *) (surf + 1); surf->ofsVerts = (int)((byte *) v - (byte *) surf); curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts)); for(j = 0; j < surf->numVerts; j++) { v->normal[0] = LittleFloat(curv->normal[0]); v->normal[1] = LittleFloat(curv->normal[1]); v->normal[2] = LittleFloat(curv->normal[2]); v->texCoords[0] = LittleFloat(curv->texCoords[0]); v->texCoords[1] = LittleFloat(curv->texCoords[1]); v->numWeights = LittleLong(curv->numWeights); weight = &v->weights[0]; curweight = &curv->weights[0]; // Now copy all the weights for(k = 0; k < v->numWeights; k++) { weight->boneIndex = LittleLong(curweight->boneIndex); weight->boneWeight = LittleFloat(curweight->boneWeight); weight->offset[0] = LittleFloat(curweight->offset[0]); weight->offset[1] = LittleFloat(curweight->offset[1]); weight->offset[2] = LittleFloat(curweight->offset[2]); weight++; curweight++; } v = (mdrVertex_t *) weight; curv = (mdrVertex_t *) curweight; } // we know the offset to the triangles now: tri = (mdrTriangle_t *) v; surf->ofsTriangles = (int)((byte *) tri - (byte *) surf); curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles)); for(j = 0; j < surf->numTriangles; j++) { tri->indexes[0] = LittleLong(curtri->indexes[0]); tri->indexes[1] = LittleLong(curtri->indexes[1]); tri->indexes[2] = LittleLong(curtri->indexes[2]); tri++; curtri++; } // tri now points to the end of the surface. surf->ofsEnd = (byte *) tri - (byte *) surf; surf = (mdrSurface_t *) tri; // find the next surface. cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd)); } // surf points to the next lod now. lod->ofsEnd = (int)((byte *) surf - (byte *) lod); lod = (mdrLOD_t *) surf; // find the next LOD. curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd)); } // lod points to the first tag now, so update the offset too. tag = (mdrTag_t *) lod; mdr->ofsTags = (int)((byte *) tag - (byte *) mdr); curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags)); for (i = 0 ; i < mdr->numTags ; i++) { tag->boneIndex = LittleLong(curtag->boneIndex); Q_strncpyz(tag->name, curtag->name, sizeof(tag->name)); tag++; curtag++; } // And finally we know the offset to the end. mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr); // phew! we're done. return qtrue; }
/* ============= SwapBSPFile Byte swaps all data in a bsp file. ============= */ void SwapBSPFile( void ) { int i; // models SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) ); // shaders (don't swap the name) for ( i = 0 ; i < numShaders ; i++ ) { dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags ); dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags ); } // planes SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) ); // nodes SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) ); // leafs SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) ); // leaffaces SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) ); // leafbrushes SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) ); // brushes SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) ); // brushsides SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) ); // vis ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] ); ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] ); // drawverts (don't swap colors ) for ( i = 0 ; i < numDrawVerts ; i++ ) { drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] ); drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] ); drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] ); drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] ); drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] ); drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] ); drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] ); drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] ); drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] ); drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] ); } // drawindexes SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) ); // drawsurfs SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) ); // fogs for ( i = 0 ; i < numFogs ; i++ ) { dfogs[i].brushNum = LittleLong( dfogs[i].brushNum ); dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide ); } // TODO: swap MoHAA structs }
/* =============== ParseFace =============== */ static void ParseFace( dsurface_t *ds, mapVert_t *verts, msurface_t *surf, int *indexes, byte *&pFaceDataBuffer, world_t &worldData, int index ) { int i, j, k; srfSurfaceFace_t *cv; int numPoints, numIndexes; int lightmapNum[MAXLIGHTMAPS]; int sfaceSize, ofsIndexes; for(i=0;i<MAXLIGHTMAPS;i++) { lightmapNum[i] = LittleLong( ds->lightmapNum[i] ); if (lightmapNum[i] >= 0) { lightmapNum[i] += worldData.startLightMapIndex; } } // get fog volume surf->fogIndex = LittleLong( ds->fogNum ) + 1; if (index && !surf->fogIndex && tr.world && tr.world->globalFog != -1) { surf->fogIndex = worldData.globalFog; } // get shader value surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum, ds->lightmapStyles, ds->vertexStyles, worldData ); if ( r_singleShader->integer && !surf->shader->sky ) { surf->shader = tr.defaultShader; } numPoints = LittleLong( ds->numVerts ); numIndexes = LittleLong( ds->numIndexes ); // create the srfSurfaceFace_t sfaceSize = ( intptr_t ) &((srfSurfaceFace_t *)0)->points[numPoints]; ofsIndexes = sfaceSize; sfaceSize += sizeof( int ) * numIndexes; cv = (srfSurfaceFace_t *) pFaceDataBuffer;//Hunk_Alloc( sfaceSize ); pFaceDataBuffer += sfaceSize; // :-) cv->surfaceType = SF_FACE; cv->numPoints = numPoints; cv->numIndices = numIndexes; cv->ofsIndices = ofsIndexes; verts += LittleLong( ds->firstVert ); for ( i = 0 ; i < numPoints ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) { cv->points[i][j] = LittleFloat( verts[i].xyz[j] ); } for ( j = 0 ; j < 2 ; j++ ) { cv->points[i][3+j] = LittleFloat( verts[i].st[j] ); for(k=0;k<MAXLIGHTMAPS;k++) { cv->points[i][VERTEX_LM+j+(k*2)] = LittleFloat( verts[i].lightmap[k][j] ); } } for(k=0;k<MAXLIGHTMAPS;k++) { R_ColorShiftLightingBytes( verts[i].color[k], (byte *)&cv->points[i][VERTEX_COLOR+k] ); } } indexes += LittleLong( ds->firstIndex ); for ( i = 0 ; i < numIndexes ; i++ ) { ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] ); } // take the plane information from the lightmap vector for ( i = 0 ; i < 3 ; i++ ) { cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); } cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal ); SetPlaneSignbits( &cv->plane ); cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); surf->data = (surfaceType_t *)cv; }
/* ================= 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; }
/* ================= Mod_LoadAliasModel ================= */ void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i; mdl_t *pmodel, *pinmodel; stvert_t *pstverts, *pinstverts; aliashdr_t *pheader; mtriangle_t *ptri; dtriangle_t *pintriangles; int version, numframes, numskins; int size; daliasframetype_t *pframetype; daliasskintype_t *pskintype; maliasskindesc_t *pskindesc; int skinsize; int start, end, total; start = Hunk_LowMark (); pinmodel = (mdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); // // allocate space for a working header, plus all the data except the frames, // skin and group info // size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0]) + sizeof (mdl_t) + LittleLong (pinmodel->numverts) * sizeof (stvert_t) + LittleLong (pinmodel->numtris) * sizeof (mtriangle_t); pheader = Hunk_AllocName (size, loadname); pmodel = (mdl_t *) ((byte *)&pheader[1] + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0])); // mod->cache.data = pheader; mod->flags = LittleLong (pinmodel->flags); // // endian-adjust and copy the data, starting with the alias model header // pmodel->boundingradius = LittleFloat (pinmodel->boundingradius); pmodel->numskins = LittleLong (pinmodel->numskins); pmodel->skinwidth = LittleLong (pinmodel->skinwidth); pmodel->skinheight = LittleLong (pinmodel->skinheight); if (pmodel->skinheight > MAX_LBM_HEIGHT) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); pmodel->numverts = LittleLong (pinmodel->numverts); if (pmodel->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); if (pmodel->numverts > MAXALIASVERTS) Sys_Error ("model %s has too many vertices", mod->name); pmodel->numtris = LittleLong (pinmodel->numtris); if (pmodel->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); pmodel->numframes = LittleLong (pinmodel->numframes); pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; mod->synctype = LittleLong (pinmodel->synctype); mod->numframes = pmodel->numframes; for (i=0 ; i<3 ; i++) { pmodel->scale[i] = LittleFloat (pinmodel->scale[i]); pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); } numskins = pmodel->numskins; numframes = pmodel->numframes; if (pmodel->skinwidth & 0x03) Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4"); pheader->model = (byte *)pmodel - (byte *)pheader; // // load the skins // skinsize = pmodel->skinheight * pmodel->skinwidth; if (numskins < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); pskintype = (daliasskintype_t *)&pinmodel[1]; pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), loadname); pheader->skindesc = (byte *)pskindesc - (byte *)pheader; for (i=0 ; i<numskins ; i++) { aliasskintype_t skintype; skintype = LittleLong (pskintype->type); pskindesc[i].type = skintype; if (skintype == ALIAS_SKIN_SINGLE) { pskintype = (daliasskintype_t *) Mod_LoadAliasSkin (pskintype + 1, &pskindesc[i].skin, skinsize, pheader); } else { pskintype = (daliasskintype_t *) Mod_LoadAliasSkinGroup (pskintype + 1, &pskindesc[i].skin, skinsize, pheader); } } // // set base s and t vertices // pstverts = (stvert_t *)&pmodel[1]; pinstverts = (stvert_t *)pskintype; pheader->stverts = (byte *)pstverts - (byte *)pheader; for (i=0 ; i<pmodel->numverts ; i++) { pstverts[i].onseam = LittleLong (pinstverts[i].onseam); // put s and t in 16.16 format pstverts[i].s = LittleLong (pinstverts[i].s) << 16; pstverts[i].t = LittleLong (pinstverts[i].t) << 16; } // // set up the triangles // ptri = (mtriangle_t *)&pstverts[pmodel->numverts]; pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts]; pheader->triangles = (byte *)ptri - (byte *)pheader; for (i=0 ; i<pmodel->numtris ; i++) { int j; ptri[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j=0 ; j<3 ; j++) { ptri[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // // load the frames // if (numframes < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris]; for (i=0 ; i<numframes ; i++) { aliasframetype_t frametype; frametype = LittleLong (pframetype->type); pheader->frames[i].type = frametype; if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i].frame, pmodel->numverts, &pheader->frames[i].bboxmin, &pheader->frames[i].bboxmax, pheader, pheader->frames[i].name); } else { pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i].frame, pmodel->numverts, &pheader->frames[i].bboxmin, &pheader->frames[i].bboxmax, pheader, pheader->frames[i].name); } } mod->type = mod_alias; // FIXME: do this right mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; // // move the complete, relocatable alias model to the cache // end = Hunk_LowMark (); total = end - start; Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy (mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); }
static bool R_LoadMd3Lod( idRenderModel* mod, int lod, const void* buffer, const char* mod_name ) { md3Header_t* pinmodel = ( md3Header_t* )buffer; int version = LittleLong( pinmodel->version ); if ( version != MD3_VERSION ) { common->Printf( S_COLOR_YELLOW "R_LoadMD3: %s has wrong version (%i should be %i)\n", mod_name, version, MD3_VERSION ); return false; } mod->type = MOD_MESH3; int size = LittleLong( pinmodel->ofsEnd ); mod->q3_dataSize += size; mod->q3_md3[ lod ].header = ( md3Header_t* )Mem_Alloc( size ); Com_Memcpy( mod->q3_md3[ lod ].header, buffer, LittleLong( pinmodel->ofsEnd ) ); LL( mod->q3_md3[ lod ].header->ident ); LL( mod->q3_md3[ lod ].header->version ); LL( mod->q3_md3[ lod ].header->numFrames ); LL( mod->q3_md3[ lod ].header->numTags ); LL( mod->q3_md3[ lod ].header->numSurfaces ); LL( mod->q3_md3[ lod ].header->ofsFrames ); LL( mod->q3_md3[ lod ].header->ofsTags ); LL( mod->q3_md3[ lod ].header->ofsSurfaces ); LL( mod->q3_md3[ lod ].header->ofsEnd ); if ( mod->q3_md3[ lod ].header->numFrames < 1 ) { common->Printf( S_COLOR_YELLOW "R_LoadMD3: %s has no frames\n", mod_name ); return false; } bool fixRadius = false; if ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) && ( strstr( mod->name,"sherman" ) || strstr( mod->name, "mg42" ) ) ) { fixRadius = true; } // swap all the frames md3Frame_t* frame = ( md3Frame_t* )( ( byte* )mod->q3_md3[ lod ].header + mod->q3_md3[ lod ].header->ofsFrames ); for ( int i = 0; i < mod->q3_md3[ lod ].header->numFrames; i++, frame++ ) { frame->radius = LittleFloat( frame->radius ); if ( fixRadius ) { frame->radius = 256; for ( int j = 0; j < 3; j++ ) { frame->bounds[ 0 ][ j ] = 128; frame->bounds[ 1 ][ j ] = -128; frame->localOrigin[ j ] = LittleFloat( frame->localOrigin[ j ] ); } } // Hack for Bug using plugin generated model else if ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) && frame->radius == 1 ) { frame->radius = 256; for ( int j = 0; j < 3; j++ ) { frame->bounds[ 0 ][ j ] = 128; frame->bounds[ 1 ][ j ] = -128; frame->localOrigin[ j ] = LittleFloat( frame->localOrigin[ j ] ); } } else { for ( int 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 ] ); } } } // swap all the tags md3Tag_t* tag = ( md3Tag_t* )( ( byte* )mod->q3_md3[ lod ].header + mod->q3_md3[ lod ].header->ofsTags ); for ( int i = 0; i < mod->q3_md3[ lod ].header->numTags * mod->q3_md3[ lod ].header->numFrames; i++, tag++ ) { for ( int j = 0; j < 3; j++ ) { tag->origin[ j ] = LittleFloat( tag->origin[ j ] ); tag->axis[ 0 ][ j ] = LittleFloat( tag->axis[ 0 ][ j ] ); tag->axis[ 1 ][ j ] = LittleFloat( tag->axis[ 1 ][ j ] ); tag->axis[ 2 ][ j ] = LittleFloat( tag->axis[ 2 ][ j ] ); } } // swap all the surfaces mod->q3_md3[ lod ].surfaces = new idSurfaceMD3[ mod->q3_md3[ lod ].header->numSurfaces ]; md3Surface_t* surf = ( md3Surface_t* )( ( byte* )mod->q3_md3[ lod ].header + mod->q3_md3[ lod ].header->ofsSurfaces ); for ( int i = 0; i < mod->q3_md3[ lod ].header->numSurfaces; i++ ) { mod->q3_md3[ lod ].surfaces[ i ].SetMd3Data( surf ); LL( surf->ident ); LL( surf->flags ); LL( surf->numFrames ); LL( surf->numShaders ); LL( surf->numTriangles ); LL( surf->ofsTriangles ); LL( surf->numVerts ); LL( surf->ofsShaders ); LL( surf->ofsSt ); LL( surf->ofsXyzNormals ); LL( surf->ofsEnd ); if ( surf->numVerts > SHADER_MAX_VERTEXES ) { common->Error( "R_LoadMD3: %s has more than %i verts on a surface (%i)", mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); } if ( surf->numTriangles * 3 > SHADER_MAX_INDEXES ) { common->Error( "R_LoadMD3: %s has more than %i triangles on a surface (%i)", mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); } // lowercase the surface name so skin compares are faster String::ToLower( surf->name ); // strip off a trailing _1 or _2 // this is a crutch for q3data being a mess int Len = String::Length( surf->name ); if ( Len > 2 && surf->name[ Len - 2 ] == '_' ) { surf->name[ Len - 2 ] = 0; } // register the shaders md3Shader_t* shader = ( md3Shader_t* )( ( byte* )surf + surf->ofsShaders ); for ( int j = 0; j < surf->numShaders; j++, shader++ ) { shader_t* sh = R_FindShader( shader->name, LIGHTMAP_NONE, true ); if ( sh->defaultShader ) { shader->shaderIndex = 0; } else { shader->shaderIndex = sh->index; } } // swap all the triangles md3Triangle_t* tri = ( md3Triangle_t* )( ( byte* )surf + surf->ofsTriangles ); for ( int j = 0; j < surf->numTriangles; j++, tri++ ) { LL( tri->indexes[ 0 ] ); LL( tri->indexes[ 1 ] ); LL( tri->indexes[ 2 ] ); } // swap all the ST md3St_t* st = ( md3St_t* )( ( byte* )surf + surf->ofsSt ); for ( int j = 0; j < surf->numVerts; j++, st++ ) { st->st[ 0 ] = LittleFloat( st->st[ 0 ] ); st->st[ 1 ] = LittleFloat( st->st[ 1 ] ); } // swap all the XyzNormals md3XyzNormal_t* xyz = ( md3XyzNormal_t* )( ( byte* )surf + surf->ofsXyzNormals ); for ( int j = 0; j < surf->numVerts * surf->numFrames; j++, xyz++ ) { xyz->xyz[ 0 ] = LittleShort( xyz->xyz[ 0 ] ); xyz->xyz[ 1 ] = LittleShort( xyz->xyz[ 1 ] ); xyz->xyz[ 2 ] = LittleShort( xyz->xyz[ 2 ] ); xyz->normal = LittleShort( xyz->normal ); } // find the next surface surf = ( md3Surface_t* )( ( byte* )surf + surf->ofsEnd ); } return true; }
/** * \brief Convert map to Redux file format. * \param[in] fmaphead Map header file name. * \param[in] fmap Map file name. * \param[in] path Path to save redux map to. * \param[in] palette Pointer to palette array. * \param[in] ceilingColour Array of ceiling colours. * \param[in] musicFileName Array of music titles. * \param[in] parTimes Struct with the parTimes. * \return On success true, otherwise false. * \note Caller must free allocated data. */ PUBLIC wtBoolean MapFile_ReduxDecodeMapData( const char *fmaphead, const char *fmap, const char *path, W8 *palette, const W32 *ceilingColour, char *musicFileName[], parTimes_t *parTimes, char *format ) { W16 Rtag; W32 totalMaps; W32 i; FILE *fout; char filename[ 256 ]; W32 offset[ 3 ]; W32 offsetin[ 3 ]; W16 length[ 3 ]; W8 sig[ 5 ]; W16 w, h; char name[ 32 ]; char musicName[ 64 ]; SW32 jmp; W32 ceiling; W32 floor; W32 palOffset; W32 temp; float ftime; char *stime; W8 *data; printf( "Decoding Map Data..." ); if( ! MapFile_Setup( fmaphead, fmap, &Rtag, &totalMaps ) ) { return false; } for( i = 0 ; i < totalMaps ; ++i ) { if( fseek( map_file_handle, headerOffsets[ i ], SEEK_SET ) != 0 ) { break; } wt_snprintf( filename, sizeof( filename ), format, path, i ); fout = fopen( filename, "wb"); if( NULL == fout ) { continue; } // Get ceiling colour palOffset = (ceilingColour[ i ] & 0xff) * 3; ceiling = (palette[ palOffset ] << 16) | (palette[ palOffset + 1 ] << 8) | palette[ palOffset + 2 ]; // Get floor colour palOffset = 0x19 * 3; floor = (palette[ palOffset ] << 16 ) | (palette[ palOffset + 1 ] << 8) | palette[ palOffset + 2 ]; wt_snprintf( musicName, sizeof( musicName ), "%s/%s.ogg", DIR_MUSIC, musicFileName[ i ] ); ftime = parTimes[ i ].time; stime = parTimes[ i ].timestr; // // Read in map data // fread( &offsetin, sizeof( W32 ), 3, map_file_handle ); offsetin[ 0 ] = LittleLong( offsetin[ 0 ] ); offsetin[ 1 ] = LittleLong( offsetin[ 1 ] ); offsetin[ 2 ] = LittleLong( offsetin[ 2 ] ); fread( &length, sizeof( W16 ), 3, map_file_handle ); length[ 0 ] = LittleShort( length[ 0 ] ); length[ 1 ] = LittleShort( length[ 1 ] ); length[ 2 ] = LittleShort( length[ 2 ] ); fread( &w, sizeof( W16 ), 1, map_file_handle ); w = LittleShort( w ); fread( &h, sizeof( W16 ), 1, map_file_handle ); h = LittleShort( h ); fread( name, sizeof( W8 ), 16, map_file_handle ); fread( sig, sizeof( W8 ), 4, map_file_handle ); // // Output header // // Map file header signature fwrite( sig, sizeof( W8 ), 4, fout ); // RLE Word tag Rtag = LittleShort( Rtag ); fwrite( &Rtag, sizeof( W16 ), 1, fout ); // Max Width w = LittleShort( w ); fwrite( &w, sizeof( W16 ), 1, fout ); // Max Height h = LittleShort( h ); fwrite( &h, sizeof( W16 ), 1, fout ); // Ceiling Colour ceiling = LittleLong( ceiling ); fwrite( &ceiling, sizeof( W32 ), 1, fout ); // Floor Colour floor = LittleLong( floor ); fwrite( &floor, sizeof( W32 ), 1, fout ); // Length of layers temp = LittleShort( length[ 0 ] ); fwrite( &temp, sizeof( W16 ), 1, fout ); // Length One temp = LittleShort( length[ 1 ] ); fwrite( &temp, sizeof( W16 ), 1, fout ); // Length Two temp = LittleShort( length[ 2 ] ); fwrite( &temp, sizeof( W16 ), 1, fout ); // Length Three jmp = ftell( fout ); temp = 0; fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset One fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Two fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Three // Map name length temp = strlen( name ); fwrite( &temp, sizeof( W16 ), 1, fout ); // Music name length temp = strlen( musicName ); fwrite( &temp, sizeof( W16 ), 1, fout ); // Par time Float ftime = LittleFloat( ftime ); fwrite( &ftime, sizeof( float ), 1, fout ); // Par time string fwrite( stime, sizeof( W8 ), 5 , fout ); // Map name fwrite( name, sizeof( W8 ), strlen( name ), fout ); // Music file name fwrite( musicName, sizeof( W8 ), strlen( musicName ), fout ); data = (PW8) MM_MALLOC( length[ 0 ] ); if( data == NULL ) { continue; } offset[ 0 ] = ftell( fout ); fseek( map_file_handle, offsetin[ 0 ], SEEK_SET ); fread( data, 1, length[ 0 ], map_file_handle ); fwrite( data, 1, length[ 0 ], fout ); MM_FREE( data ); data = (PW8) MM_MALLOC( length[ 1 ] ); if( data == NULL ) { MapFile_Shutdown(); return 0; } offset[ 1 ] = ftell( fout ); fseek( map_file_handle, offsetin[ 1 ], SEEK_SET ); fread( data, 1, length[ 1 ], map_file_handle ); fwrite( data, 1, length[ 1 ], fout ); MM_FREE( data ); data = (PW8) MM_MALLOC( length[ 2 ] ); if( data == NULL ) { MapFile_Shutdown(); return 0; } offset[ 2 ] = ftell( fout ); fseek( map_file_handle, offsetin[ 2 ], SEEK_SET ); fread( data, 1, length[ 2 ], map_file_handle ); fwrite( data, 1, length[ 2 ], fout ); MM_FREE( data ); fseek( fout, jmp, SEEK_SET ); temp = LittleLong( offset[ 0 ] ); fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset One temp = LittleLong( offset[ 1 ] ); fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Two temp = LittleLong( offset[ 2 ] ); fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Three fclose( fout ); } MapFile_Shutdown(); printf( "Done\n" ); return true; }
/* ============ WriteModelFile ============ */ static void WriteModelFile (FILE *modelouthandle) { int i; dmdl_t modeltemp; int j, k; frame_t *in; daliasframe_t *out; byte buffer[MAX_VERTS*4+128]; float v; int c_on, c_off; model.ident = IDALIASHEADER; model.version = ALIAS_VERSION; model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; model.num_glcmds = numcommands; model.ofs_skins = sizeof(dmdl_t); model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; model.ofs_end = model.ofs_glcmds + model.num_glcmds*4; // // write out the model header // for (i=0 ; i<sizeof(dmdl_t)/4 ; i++) ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); // // write out the skin names // SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); // // write out the texture coordinates // c_on = c_off = 0; for (i=0 ; i<model.num_st ; i++) { base_st[i].s = LittleShort (base_st[i].s); base_st[i].t = LittleShort (base_st[i].t); } SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); // // write out the triangles // for (i=0 ; i<model.num_tris ; i++) { int j; dtriangle_t tri; for (j=0 ; j<3 ; j++) { tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); tri.index_st[j] = LittleShort (triangles[i].index_st[j]); } SafeWrite (modelouthandle, &tri, sizeof(tri)); } // // write out the frames // for (i=0 ; i<model.num_frames ; i++) { in = &g_frames[i]; out = (daliasframe_t *)buffer; strcpy (out->name, in->name); for (j=0 ; j<3 ; j++) { out->scale[j] = (in->maxs[j] - in->mins[j])/255; out->translate[j] = in->mins[j]; } for (j=0 ; j<model.num_xyz ; j++) { // all of these are byte values, so no need to deal with endianness out->verts[j].lightnormalindex = in->v[j].lightnormalindex; for (k=0 ; k<3 ; k++) { // scale to byte values & min/max check v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); // clamp, so rounding doesn't wrap from 255.6 to 0 if (v > 255.0) v = 255.0; if (v < 0) v = 0; out->verts[j].v[k] = v; } } for (j=0 ; j<3 ; j++) { out->scale[j] = LittleFloat (out->scale[j]); out->translate[j] = LittleFloat (out->translate[j]); } SafeWrite (modelouthandle, out, model.framesize); } // // write out glcmds // SafeWrite (modelouthandle, commands, numcommands*4); }
/* ================= Mod_LoadAliasModel ================= */ void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i, j; mdl_t *pinmodel; stvert_t *pinstverts; dtriangle_t *pintriangles; int version, numframes, numskins; int size; daliasframetype_t *pframetype; daliasskintype_t *pskintype; int start, end, total; start = Hunk_LowMark (); pinmodel = (mdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); // // allocate space for a working header, plus all the data except the frames, // skin and group info // size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0]); pheader = (aliashdr_t*) Hunk_AllocName (size, loadname); mod->flags = LittleLong (pinmodel->flags); // // endian-adjust and copy the data, starting with the alias model header // pheader->boundingradius = LittleFloat (pinmodel->boundingradius); pheader->numskins = LittleLong (pinmodel->numskins); pheader->skinwidth = LittleLong (pinmodel->skinwidth); pheader->skinheight = LittleLong (pinmodel->skinheight); if (pheader->skinheight > MAX_LBM_HEIGHT) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); pheader->numverts = LittleLong (pinmodel->numverts); if (pheader->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); if (pheader->numverts > MAXALIASVERTS) Sys_Error ("model %s has too many vertices", mod->name); pheader->numtris = LittleLong (pinmodel->numtris); if (pheader->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); pheader->numframes = LittleLong (pinmodel->numframes); numframes = pheader->numframes; if (numframes < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; mod->synctype = (synctype_t) LittleLong (pinmodel->synctype); mod->numframes = pheader->numframes; for (i=0 ; i<3 ; i++) { pheader->scale[i] = LittleFloat (pinmodel->scale[i]); pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); } // // load the skins // pskintype = (daliasskintype_t *)&pinmodel[1]; pskintype = (daliasskintype_t*) Mod_LoadAllSkins (pheader->numskins, pskintype); // // load base s and t vertices // pinstverts = (stvert_t *)pskintype; for (i=0 ; i<pheader->numverts ; i++) { stverts[i].onseam = LittleLong (pinstverts[i].onseam); stverts[i].s = LittleLong (pinstverts[i].s); stverts[i].t = LittleLong (pinstverts[i].t); } // // load triangle lists // pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts]; for (i=0 ; i<pheader->numtris ; i++) { triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j=0 ; j<3 ; j++) { triangles[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // // load the frames // posenum = 0; pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris]; for (i=0 ; i<numframes ; i++) { aliasframetype_t frametype; frametype = (aliasframetype_t) LittleLong (pframetype->type); if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]); } else { pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]); } } pheader->numposes = posenum; mod->type = mod_alias; // FIXME: do this right mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; // // build the draw lists // GL_MakeAliasModelDisplayLists (mod, pheader); // // move the complete, relocatable alias model to the cache // end = Hunk_LowMark (); total = end - start; Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy (mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); }
/* ================= R_LoadMDC ================= */ qboolean R_LoadMDC(model_t * mod, int lod, void *buffer, int bufferSize, const char *modName) { int i, j, k, l; mdcHeader_t *mdcModel; md3Frame_t *mdcFrame; mdcSurface_t *mdcSurf; md3Shader_t *mdcShader; md3Triangle_t *mdcTri; md3St_t *mdcst; md3XyzNormal_t *mdcxyz; mdcXyzCompressed_t *mdcxyzComp; mdcTag_t *mdcTag; mdcTagName_t *mdcTagName; mdvModel_t *mdvModel; mdvFrame_t *frame; mdvSurface_t *surf, *surface; srfTriangle_t *tri; mdvVertex_t *v; mdvSt_t *st; mdvTag_t *tag; mdvTagName_t *tagName; short *ps; int version; int size; mdcModel = (mdcHeader_t *) buffer; version = LittleLong(mdcModel->version); if(version != MDC_VERSION) { ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MDC_VERSION); return qfalse; } mod->type = MOD_MESH; size = LittleLong(mdcModel->ofsEnd); mod->dataSize += size; mdvModel = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low); LL(mdcModel->ident); LL(mdcModel->version); LL(mdcModel->numFrames); LL(mdcModel->numTags); LL(mdcModel->numSurfaces); LL(mdcModel->ofsFrames); LL(mdcModel->ofsTags); LL(mdcModel->ofsSurfaces); LL(mdcModel->ofsEnd); LL(mdcModel->ofsEnd); LL(mdcModel->flags); LL(mdcModel->numSkins); if(mdcModel->numFrames < 1) { ri.Printf(PRINT_WARNING, "R_LoadMDC: '%s' has no frames\n", modName); return qfalse; } // swap all the frames mdvModel->numFrames = mdcModel->numFrames; mdvModel->frames = frame = ri.Hunk_Alloc(sizeof(*frame) * mdcModel->numFrames, h_low); mdcFrame = (md3Frame_t *) ((byte *) mdcModel + mdcModel->ofsFrames); for(i = 0; i < mdcModel->numFrames; i++, frame++, mdcFrame++) { #if 1 // RB: ET HACK if(strstr(mod->name, "sherman") || strstr(mod->name, "mg42")) { frame->radius = 256; for(j = 0; j < 3; j++) { frame->bounds[0][j] = 128; frame->bounds[1][j] = -128; frame->localOrigin[j] = LittleFloat(mdcFrame->localOrigin[j]); } } else #endif { frame->radius = LittleFloat(mdcFrame->radius); for(j = 0; j < 3; j++) { frame->bounds[0][j] = LittleFloat(mdcFrame->bounds[0][j]); frame->bounds[1][j] = LittleFloat(mdcFrame->bounds[1][j]); frame->localOrigin[j] = LittleFloat(mdcFrame->localOrigin[j]); } } } // swap all the tags mdvModel->numTags = mdcModel->numTags; mdvModel->tags = tag = ri.Hunk_Alloc(sizeof(*tag) * (mdcModel->numTags * mdcModel->numFrames), h_low); mdcTag = (mdcTag_t *) ((byte *) mdcModel + mdcModel->ofsTags); for(i = 0; i < mdcModel->numTags * mdcModel->numFrames; i++, tag++, mdcTag++) { vec3_t angles; for(j = 0; j < 3; j++) { tag->origin[j] = (float)LittleShort(mdcTag->xyz[j]) * MD3_XYZ_SCALE; angles[j] = (float)LittleShort(mdcTag->angles[j]) * MDC_TAG_ANGLE_SCALE; } AnglesToAxis(angles, tag->axis); } mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (mdcModel->numTags), h_low); mdcTagName = (mdcTagName_t *) ((byte *) mdcModel + mdcModel->ofsTagNames); for(i = 0; i < mdcModel->numTags; i++, tagName++, mdcTagName++) { Q_strncpyz(tagName->name, mdcTagName->name, sizeof(tagName->name)); } // swap all the surfaces mdvModel->numSurfaces = mdcModel->numSurfaces; mdvModel->surfaces = surf = ri.Hunk_Alloc(sizeof(*surf) * mdcModel->numSurfaces, h_low); mdcSurf = (mdcSurface_t *) ((byte *) mdcModel + mdcModel->ofsSurfaces); for(i = 0; i < mdcModel->numSurfaces; i++) { LL(mdcSurf->ident); LL(mdcSurf->flags); LL(mdcSurf->numBaseFrames); LL(mdcSurf->numCompFrames); LL(mdcSurf->numShaders); LL(mdcSurf->numTriangles); LL(mdcSurf->ofsTriangles); LL(mdcSurf->numVerts); LL(mdcSurf->ofsShaders); LL(mdcSurf->ofsSt); LL(mdcSurf->ofsXyzNormals); LL(mdcSurf->ofsXyzNormals); LL(mdcSurf->ofsXyzCompressed); LL(mdcSurf->ofsFrameBaseFrames); LL(mdcSurf->ofsFrameCompFrames); LL(mdcSurf->ofsEnd); if(mdcSurf->numVerts > SHADER_MAX_VERTEXES) { ri.Error(ERR_DROP, "R_LoadMDC: %s has more than %i verts on a surface (%i)", modName, SHADER_MAX_VERTEXES, mdcSurf->numVerts); } if(mdcSurf->numTriangles > SHADER_MAX_TRIANGLES) { ri.Error(ERR_DROP, "R_LoadMDC: %s has more than %i triangles on a surface (%i)", modName, SHADER_MAX_TRIANGLES, mdcSurf->numTriangles); } // change to surface identifier surf->surfaceType = SF_MDV; // give pointer to model for Tess_SurfaceMDX surf->model = mdvModel; // copy surface name Q_strncpyz(surf->name, mdcSurf->name, sizeof(surf->name)); // lowercase the surface name so skin compares are faster Q_strlwr(surf->name); // strip off a trailing _1 or _2 // this is a crutch for q3data being a mess j = strlen(surf->name); if(j > 2 && surf->name[j - 2] == '_') { surf->name[j - 2] = 0; } // register the shaders /* surf->numShaders = md3Surf->numShaders; surf->shaders = shader = ri.Hunk_Alloc(sizeof(*shader) * md3Surf->numShaders, h_low); md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders); for(j = 0; j < md3Surf->numShaders; j++, shader++, md3Shader++) { shader_t *sh; sh = R_FindShader(md3Shader->name, SHADER_3D_DYNAMIC, qtrue); if(sh->defaultShader) { shader->shaderIndex = 0; } else { shader->shaderIndex = sh->index; } } */ // only consider the first shader mdcShader = (md3Shader_t *) ((byte *) mdcSurf + mdcSurf->ofsShaders); surf->shader = R_FindShader(mdcShader->name, SHADER_3D_DYNAMIC, qtrue); // swap all the triangles surf->numTriangles = mdcSurf->numTriangles; surf->triangles = tri = ri.Hunk_Alloc(sizeof(*tri) * mdcSurf->numTriangles, h_low); mdcTri = (md3Triangle_t *) ((byte *) mdcSurf + mdcSurf->ofsTriangles); for(j = 0; j < mdcSurf->numTriangles; j++, tri++, mdcTri++) { tri->indexes[0] = LittleLong(mdcTri->indexes[0]); tri->indexes[1] = LittleLong(mdcTri->indexes[1]); tri->indexes[2] = LittleLong(mdcTri->indexes[2]); } R_CalcSurfaceTriangleNeighbors(surf->numTriangles, surf->triangles); // swap all the XyzNormals mdcxyz = (md3XyzNormal_t *) ((byte *) mdcSurf + mdcSurf->ofsXyzNormals); for(j = 0; j < mdcSurf->numVerts * mdcSurf->numBaseFrames; j++, mdcxyz++) { mdcxyz->xyz[0] = LittleShort(mdcxyz->xyz[0]); mdcxyz->xyz[1] = LittleShort(mdcxyz->xyz[1]); mdcxyz->xyz[2] = LittleShort(mdcxyz->xyz[2]); mdcxyz->normal = LittleShort(mdcxyz->normal); } // swap all the XyzCompressed mdcxyzComp = (mdcXyzCompressed_t *) ((byte *) mdcSurf + mdcSurf->ofsXyzCompressed); for(j = 0; j < mdcSurf->numVerts * mdcSurf->numCompFrames; j++, mdcxyzComp++) { LL(mdcxyzComp->ofsVec); } // swap the frameBaseFrames ps = (short *)((byte *) mdcSurf + mdcSurf->ofsFrameBaseFrames); for(j = 0; j < mdcModel->numFrames; j++, ps++) { *ps = LittleShort(*ps); } // swap the frameCompFrames ps = (short *)((byte *) mdcSurf + mdcSurf->ofsFrameCompFrames); for(j = 0; j < mdcModel->numFrames; j++, ps++) { *ps = LittleShort(*ps); } surf->numVerts = mdcSurf->numVerts; surf->verts = v = ri.Hunk_Alloc(sizeof(*v) * (mdcSurf->numVerts * mdcModel->numFrames), h_low); for(j = 0; j < mdcModel->numFrames; j++) { int baseFrame; int compFrame; baseFrame = (int) *((short *)((byte *) mdcSurf + mdcSurf->ofsFrameBaseFrames) + j); mdcxyz = (md3XyzNormal_t *)((byte *) mdcSurf + mdcSurf->ofsXyzNormals + baseFrame * mdcSurf->numVerts * sizeof(md3XyzNormal_t)); if(mdcSurf->numCompFrames > 0) { compFrame = (int) *((short *)((byte *) mdcSurf + mdcSurf->ofsFrameCompFrames) + j); if(compFrame >= 0) { mdcxyzComp = (mdcXyzCompressed_t *) ((byte *) mdcSurf + mdcSurf->ofsXyzCompressed + compFrame * mdcSurf->numVerts * sizeof(mdcXyzCompressed_t)); } } for(k = 0; k < mdcSurf->numVerts; k++, v++, mdcxyz++) { v->xyz[0] = LittleShort(mdcxyz->xyz[0]) * MD3_XYZ_SCALE; v->xyz[1] = LittleShort(mdcxyz->xyz[1]) * MD3_XYZ_SCALE; v->xyz[2] = LittleShort(mdcxyz->xyz[2]) * MD3_XYZ_SCALE; if(mdcSurf->numCompFrames > 0 && compFrame >= 0) { vec3_t ofsVec; vec3_t normal; R_MDC_DecodeXyzCompressed(LittleShort(mdcxyzComp->ofsVec), ofsVec, normal); VectorAdd(v->xyz, ofsVec, v->xyz); mdcxyzComp++; } } } // swap all the ST surf->st = st = ri.Hunk_Alloc(sizeof(*st) * mdcSurf->numVerts, h_low); mdcst = (md3St_t *) ((byte *) mdcSurf + mdcSurf->ofsSt); for(j = 0; j < mdcSurf->numVerts; j++, mdcst++, st++) { st->st[0] = LittleFloat(mdcst->st[0]); st->st[1] = LittleFloat(mdcst->st[1]); } // find the next surface mdcSurf = (mdcSurface_t *) ((byte *) mdcSurf + mdcSurf->ofsEnd); surf++; } #if 1 // create VBO surfaces from md3 surfaces { growList_t vboSurfaces; srfVBOMDVMesh_t *vboSurf; byte *data; int dataSize; int dataOfs; vec4_t tmp; GLuint ofsTexCoords; GLuint ofsTangents; GLuint ofsBinormals; GLuint ofsNormals; GLuint sizeXYZ; GLuint sizeTangents; GLuint sizeBinormals; GLuint sizeNormals; int vertexesNum; int f; Com_InitGrowList(&vboSurfaces, 10); for(i = 0, surf = mdvModel->surfaces; i < mdvModel->numSurfaces; i++, surf++) { // calc tangent spaces { 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 * mdvModel->numFrames); j++, v++) { VectorClear(v->tangent); VectorClear(v->binormal); VectorClear(v->normal); } for(f = 0; f < mdvModel->numFrames; f++) { for(j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++) { v0 = surf->verts[surf->numVerts * f + tri->indexes[0]].xyz; v1 = surf->verts[surf->numVerts * f + tri->indexes[1]].xyz; v2 = surf->verts[surf->numVerts * f + tri->indexes[2]].xyz; t0 = surf->st[tri->indexes[0]].st; t1 = surf->st[tri->indexes[1]].st; t2 = surf->st[tri->indexes[2]].st; #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[surf->numVerts * f + tri->indexes[k]].tangent; VectorAdd(v, tangent, v); v = surf->verts[surf->numVerts * f + tri->indexes[k]].binormal; VectorAdd(v, binormal, v); v = surf->verts[surf->numVerts * f + tri->indexes[k]].normal; VectorAdd(v, normal, v); } } } for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) { VectorNormalize(v->tangent); VectorNormalize(v->binormal); VectorNormalize(v->normal); } } //ri.Printf(PRINT_ALL, "...calculating MDC mesh VBOs ( '%s', %i verts %i tris )\n", surf->name, surf->numVerts, surf->numTriangles); // create surface vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low); Com_AddToGrowList(&vboSurfaces, vboSurf); vboSurf->surfaceType = SF_VBO_MDVMESH; vboSurf->mdvModel = mdvModel; vboSurf->mdvSurface = surf; vboSurf->numIndexes = surf->numTriangles * 3; vboSurf->numVerts = surf->numVerts; /* vboSurf->vbo = R_CreateVBO2(va("staticWorldMesh_vertices %i", vboSurfaces.currentElements), numVerts, optimizedVerts, ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | ATTR_BINORMAL | ATTR_NORMAL | ATTR_COLOR); */ vboSurf->ibo = R_CreateIBO2(va("staticMDCMesh_IBO %s", surf->name), surf->numTriangles, surf->triangles, VBO_USAGE_STATIC); // create VBO vertexesNum = surf->numVerts; dataSize = (surf->numVerts * mdvModel->numFrames * sizeof(vec4_t) * 4) + // xyz, tangent, binormal, normal (surf->numVerts * sizeof(vec4_t)); // texcoords data = ri.Malloc(dataSize); dataOfs = 0; // feed vertex XYZ for(f = 0; f < mdvModel->numFrames; f++) { for(j = 0; j < vertexesNum; j++) { for(k = 0; k < 3; k++) { tmp[k] = surf->verts[f * vertexesNum + j].xyz[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } if(f == 0) { sizeXYZ = dataOfs; } } // feed vertex texcoords ofsTexCoords = dataOfs; for(j = 0; j < vertexesNum; j++) { for(k = 0; k < 2; k++) { tmp[k] = surf->st[j].st[k]; } tmp[2] = 0; tmp[3] = 1; Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } // feed vertex tangents ofsTangents = dataOfs; for(f = 0; f < mdvModel->numFrames; f++) { for(j = 0; j < vertexesNum; j++) { for(k = 0; k < 3; k++) { tmp[k] = surf->verts[f * vertexesNum + j].tangent[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } if(f == 0) { sizeTangents = dataOfs - ofsTangents; } } // feed vertex binormals ofsBinormals = dataOfs; for(f = 0; f < mdvModel->numFrames; f++) { for(j = 0; j < vertexesNum; j++) { for(k = 0; k < 3; k++) { tmp[k] = surf->verts[f * vertexesNum + j].binormal[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } if(f == 0) { sizeBinormals = dataOfs - ofsBinormals; } } // feed vertex normals ofsNormals = dataOfs; for(f = 0; f < mdvModel->numFrames; f++) { for(j = 0; j < vertexesNum; j++) { for(k = 0; k < 3; k++) { tmp[k] = surf->verts[f * vertexesNum + j].normal[k]; } tmp[3] = 1; Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t)); dataOfs += sizeof(vec4_t); } if(f == 0) { sizeNormals = dataOfs - ofsNormals; } } vboSurf->vbo = R_CreateVBO(va("staticMDCMesh_VBO '%s'", surf->name), data, dataSize, VBO_USAGE_STATIC); vboSurf->vbo->ofsXYZ = 0; vboSurf->vbo->ofsTexCoords = ofsTexCoords; vboSurf->vbo->ofsLightCoords = ofsTexCoords; vboSurf->vbo->ofsTangents = ofsTangents; vboSurf->vbo->ofsBinormals = ofsBinormals; vboSurf->vbo->ofsNormals = ofsNormals; vboSurf->vbo->sizeXYZ = sizeXYZ; vboSurf->vbo->sizeTangents = sizeTangents; vboSurf->vbo->sizeBinormals = sizeBinormals; vboSurf->vbo->sizeNormals = sizeNormals; ri.Free(data); } // move VBO surfaces list to hunk mdvModel->numVBOSurfaces = vboSurfaces.currentElements; mdvModel->vboSurfaces = ri.Hunk_Alloc(mdvModel->numVBOSurfaces * sizeof(*mdvModel->vboSurfaces), h_low); for(i = 0; i < mdvModel->numVBOSurfaces; i++) { mdvModel->vboSurfaces[i] = (srfVBOMDVMesh_t *) Com_GrowListElement(&vboSurfaces, i); } Com_DestroyGrowList(&vboSurfaces); } #endif return qtrue; }
int AnalyzeBSP( int argc, char **argv ) { abspHeader_t *header; int size, i, version, offset, length, lumpInt, count; char ident[ 5 ]; void *lump; float lumpFloat; char lumpString[ 1024 ], source[ 1024 ]; qboolean lumpSwap = qfalse; abspLumpTest_t *lumpTest; static abspLumpTest_t lumpTests[] = { { sizeof( bspPlane_t ), 6, "IBSP LUMP_PLANES" }, { sizeof( bspBrush_t ), 1, "IBSP LUMP_BRUSHES" }, { 8, 6, "IBSP LUMP_BRUSHSIDES" }, { sizeof( bspBrushSide_t ), 6, "RBSP LUMP_BRUSHSIDES" }, { sizeof( bspModel_t ), 1, "IBSP LUMP_MODELS" }, { sizeof( bspNode_t ), 2, "IBSP LUMP_NODES" }, { sizeof( bspLeaf_t ), 1, "IBSP LUMP_LEAFS" }, { 104, 3, "IBSP LUMP_DRAWSURFS" }, { 44, 3, "IBSP LUMP_DRAWVERTS" }, { 4, 6, "IBSP LUMP_DRAWINDEXES" }, { 128 * 128 * 3, 1, "IBSP LUMP_LIGHTMAPS" }, { 256 * 256 * 3, 1, "IBSP LUMP_LIGHTMAPS (256 x 256)" }, { 512 * 512 * 3, 1, "IBSP LUMP_LIGHTMAPS (512 x 512)" }, { 0, 0, NULL } }; /* arg checking */ if( argc < 1 ) { Sys_Printf( "Usage: q3map -analyze [-lumpswap] [-v] <mapname>\n" ); return 0; } /* process arguments */ for( i = 1; i < (argc - 1); i++ ) { /* -format map|ase|... */ if( !strcmp( argv[ i ], "-lumpswap" ) ) { Sys_Printf( "Swapped lump structs enabled\n" ); lumpSwap = qtrue; } } /* clean up map name */ strcpy( source, ExpandArg( argv[ i ] ) ); Sys_Printf( "Loading %s\n", source ); /* load the file */ size = LoadFile( source, (void**) &header ); if( size == 0 || header == NULL ) { Sys_Printf( "Unable to load %s.\n", source ); return -1; } /* analyze ident/version */ memcpy( ident, header->ident, 4 ); ident[ 4 ] = '\0'; version = LittleLong( header->version ); Sys_Printf( "Identity: %s\n", ident ); Sys_Printf( "Version: %d\n", version ); Sys_Printf( "---------------------------------------\n" ); /* analyze each lump */ for( i = 0; i < 100; i++ ) { /* call of duty swapped lump pairs */ if( lumpSwap ) { offset = LittleLong( header->lumps[ i ].length ); length = LittleLong( header->lumps[ i ].offset ); } /* standard lump pairs */ else { offset = LittleLong( header->lumps[ i ].offset ); length = LittleLong( header->lumps[ i ].length ); } /* extract data */ lump = (byte*) header + offset; lumpInt = LittleLong( (int) *((int*) lump) ); lumpFloat = LittleFloat( (float) *((float*) lump) ); memcpy( lumpString, (char*) lump, (length < 1024 ? length : 1024) ); lumpString[ 1024 ] = '\0'; /* print basic lump info */ Sys_Printf( "Lump: %d\n", i ); Sys_Printf( "Offset: %d bytes\n", offset ); Sys_Printf( "Length: %d bytes\n", length ); /* only operate on valid lumps */ if( length > 0 ) { /* print data in 4 formats */ Sys_Printf( "As hex: %08X\n", lumpInt ); Sys_Printf( "As int: %d\n", lumpInt ); Sys_Printf( "As float: %f\n", lumpFloat ); Sys_Printf( "As string: %s\n", lumpString ); /* guess lump type */ if( lumpString[ 0 ] == '{' && lumpString[ 2 ] == '"' ) Sys_Printf( "Type guess: IBSP LUMP_ENTITIES\n" ); else if( strstr( lumpString, "textures/" ) ) Sys_Printf( "Type guess: IBSP LUMP_SHADERS\n" ); else { /* guess based on size/count */ for( lumpTest = lumpTests; lumpTest->radix > 0; lumpTest++ ) { if( (length % lumpTest->radix) != 0 ) continue; count = length / lumpTest->radix; if( count < lumpTest->minCount ) continue; Sys_Printf( "Type guess: %s (%d x %d)\n", lumpTest->name, count, lumpTest->radix ); } } } Sys_Printf( "---------------------------------------\n" ); /* end of file */ if( offset + length >= size ) break; } /* last stats */ Sys_Printf( "Lump count: %d\n", i + 1 ); Sys_Printf( "File size: %d bytes\n", size ); /* return to caller */ return 0; }
static qboolean R_LoadMDX( model_t *mod, void *buffer, const char *mod_name ) { int i, j; mdxHeader_t *pinmodel, *mdx; mdxFrame_t *frame; short *bframe; mdxBoneInfo_t *bi; int version; int size; int frameSize; pinmodel = ( mdxHeader_t * ) buffer; version = LittleLong( pinmodel->version ); if ( version != MDX_VERSION ) { ri.Printf( PRINT_WARNING, "R_LoadMDX: %s has wrong version (%i should be %i)\n", mod_name, version, MDX_VERSION ); return qfalse; } mod->type = MOD_MDX; size = LittleLong( pinmodel->ofsEnd ); mod->dataSize += size; mdx = mod->mdx = ri.Hunk_Alloc( size, h_low ); memcpy( mdx, buffer, LittleLong( pinmodel->ofsEnd ) ); LL( mdx->ident ); LL( mdx->version ); LL( mdx->numFrames ); LL( mdx->numBones ); LL( mdx->ofsFrames ); LL( mdx->ofsBones ); LL( mdx->ofsEnd ); LL( mdx->torsoParent ); if ( LittleLong( 1 ) != 1 ) { // swap all the frames frameSize = ( int )( sizeof( mdxBoneFrameCompressed_t ) ) * mdx->numBones; for ( i = 0; i < mdx->numFrames; i++ ) { frame = ( mdxFrame_t * )( ( byte * ) mdx + mdx->ofsFrames + i * frameSize + i * sizeof( mdxFrame_t ) ); 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 ] ); } bframe = ( short * )( ( byte * ) mdx + mdx->ofsFrames + i * frameSize + ( ( i + 1 ) * sizeof( mdxFrame_t ) ) ); for ( j = 0; j < mdx->numBones * sizeof( mdxBoneFrameCompressed_t ) / sizeof( short ); j++ ) { ( ( short * ) bframe ) [ j ] = LittleShort( ( ( short * ) bframe ) [ j ] ); } } // swap all the bones for ( i = 0; i < mdx->numBones; i++ ) { bi = ( mdxBoneInfo_t * )( ( byte * ) mdx + mdx->ofsBones + i * sizeof( mdxBoneInfo_t ) ); LL( bi->parent ); bi->torsoWeight = LittleFloat( bi->torsoWeight ); bi->parentDist = LittleFloat( bi->parentDist ); LL( bi->flags ); } } return qtrue; }
/* ================= idRenderModelMD3::InitFromFile ================= */ void idRenderModelMD3::InitFromFile( const char *fileName ) { int i, j; md3Header_t *pinmodel; md3Frame_t *frame; md3Surface_t *surf; md3Shader_t *shader; md3Triangle_t *tri; md3St_t *st; md3XyzNormal_t *xyz; md3Tag_t *tag; void *buffer; int version; int size; name = fileName; size = fileSystem->ReadFile( fileName, &buffer, NULL ); if (!size || size<0 ) { return; } pinmodel = (md3Header_t *)buffer; version = LittleLong (pinmodel->version); if (version != MD3_VERSION) { fileSystem->FreeFile( buffer ); common->Warning( "InitFromFile: %s has wrong version (%i should be %i)", fileName, version, MD3_VERSION); return; } size = LittleLong(pinmodel->ofsEnd); dataSize += size; md3 = (md3Header_t *)Mem_Alloc( size ); memcpy (md3, buffer, LittleLong(pinmodel->ofsEnd) ); LL(md3->ident); LL(md3->version); LL(md3->numFrames); LL(md3->numTags); LL(md3->numSurfaces); LL(md3->ofsFrames); LL(md3->ofsTags); LL(md3->ofsSurfaces); LL(md3->ofsEnd); if ( md3->numFrames < 1 ) { common->Warning( "InitFromFile: %s has no frames", fileName ); fileSystem->FreeFile( buffer ); return; } // swap all the frames frame = (md3Frame_t *) ( (byte *)md3 + md3->ofsFrames ); for ( i = 0 ; i < md3->numFrames ; i++, frame++) { 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] ); } } // swap all the tags tag = (md3Tag_t *) ( (byte *)md3 + md3->ofsTags ); for ( i = 0 ; i < md3->numTags * md3->numFrames ; i++, tag++) { for ( j = 0 ; j < 3 ; j++ ) { tag->origin[j] = LittleFloat( tag->origin[j] ); tag->axis[0][j] = LittleFloat( tag->axis[0][j] ); tag->axis[1][j] = LittleFloat( tag->axis[1][j] ); tag->axis[2][j] = LittleFloat( tag->axis[2][j] ); } } // swap all the surfaces surf = (md3Surface_t *) ( (byte *)md3 + md3->ofsSurfaces ); for ( i = 0 ; i < md3->numSurfaces ; i++) { LL(surf->ident); LL(surf->flags); LL(surf->numFrames); LL(surf->numShaders); LL(surf->numTriangles); LL(surf->ofsTriangles); LL(surf->numVerts); LL(surf->ofsShaders); LL(surf->ofsSt); LL(surf->ofsXyzNormals); LL(surf->ofsEnd); if ( surf->numVerts > SHADER_MAX_VERTEXES ) { common->Error( "InitFromFile: %s has more than %i verts on a surface (%i)", fileName, SHADER_MAX_VERTEXES, surf->numVerts ); } if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { common->Error( "InitFromFile: %s has more than %i triangles on a surface (%i)", fileName, SHADER_MAX_INDEXES / 3, surf->numTriangles ); } // change to surface identifier surf->ident = 0; //SF_MD3; // lowercase the surface name so skin compares are faster int slen = (int)strlen( surf->name ); for( j = 0; j < slen; j++ ) { surf->name[j] = tolower( surf->name[j] ); } // strip off a trailing _1 or _2 // this is a crutch for q3data being a mess j = strlen( surf->name ); if ( j > 2 && surf->name[j-2] == '_' ) { surf->name[j-2] = 0; } // register the shaders shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { const idMaterial *sh; sh = declManager->FindMaterial( shader->name ); shader->shader = sh; } // swap all the triangles tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { LL(tri->indexes[0]); LL(tri->indexes[1]); LL(tri->indexes[2]); } // swap all the ST st = (md3St_t *) ( (byte *)surf + surf->ofsSt ); for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { st->st[0] = LittleFloat( st->st[0] ); st->st[1] = LittleFloat( st->st[1] ); } // swap all the XyzNormals xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals ); for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) { xyz->xyz[0] = LittleShort( xyz->xyz[0] ); xyz->xyz[1] = LittleShort( xyz->xyz[1] ); xyz->xyz[2] = LittleShort( xyz->xyz[2] ); xyz->normal = LittleShort( xyz->normal ); } // find the next surface surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd ); } fileSystem->FreeFile( buffer ); }
/* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ int CL_GetMessage (void) { int r, i; float f; if (cls.demoplayback) { // decide if it is time to grab the next message if (cls.signon == SIGNONS) // allways grab until fully connected { if (cls.timedemo) { if (host_framecount == cls.td_lastframe) return 0; // allready read this frame's message cls.td_lastframe = host_framecount; // if this is the second frame, grab the real td_starttime // so the bogus time on the first frame doesn't count if (host_framecount == cls.td_startframe + 1) cls.td_starttime = realtime; } else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) { return 0; // don't need another message yet } } // get the next message // if(intro_playing&&num_intro_msg>0&&num_intro_msg<21) // V_DarkFlash_f();//Fade into demo /* if(skip_start&&num_intro_msg>3) { while(num_intro_msg<1110) { fread (&net_message.cursize, 4, 1, cls.demofile); VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); for (i=0 ; i<3 ; i++) { r = fread (&f, 4, 1, cls.demofile); cl.mviewangles[0][i] = LittleFloat (f); } net_message.cursize = LittleLong (net_message.cursize); num_intro_msg++; if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message > MAX_MSGLEN"); r = fread (net_message.data, net_message.cursize, 1, cls.demofile); if (r != 1) { CL_StopPlayback (); return 0; } if(num_intro_msg==174|| num_intro_msg==178|| num_intro_msg==428|| num_intro_msg==553|| num_intro_msg==1012) break; } if(num_intro_msg==1110) skip_start=false; } else {*/ fread (&net_message.cursize, 4, 1, cls.demofile); VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); for (i=0 ; i<3 ; i++) { r = fread (&f, 4, 1, cls.demofile); cl.mviewangles[0][i] = LittleFloat (f); } net_message.cursize = LittleLong (net_message.cursize); num_intro_msg++; if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message > MAX_MSGLEN"); r = fread (net_message.data, net_message.cursize, 1, cls.demofile); if (r != 1) { CL_StopPlayback (); return 0; } // } // if (cls.demorecording) // CL_WriteDemoMessage (); return 1; } while (1) { r = NET_GetMessage (cls.netcon); if (r != 1 && r != 2) return r; // discard nop keepalive message if (net_message.cursize == 1 && net_message.data[0] == svc_nop) Con_Printf ("<-- server to client keepalive\n"); else break; } if (cls.demorecording) CL_WriteDemoMessage (); return r; }
static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version, const unsigned int *palette, qboolean additive) { int i, j, groupframes, realframes, x, y, origin[2], width, height; qboolean fullbright; dspriteframetype_t *pinframetype; dspriteframe_t *pinframe; dspritegroup_t *pingroup; dspriteinterval_t *pinintervals; skinframe_t *skinframe; float modelradius, interval; char name[MAX_QPATH], fogname[MAX_QPATH]; const void *startframes; int texflags = (r_mipsprites.integer ? TEXF_MIPMAP : 0) | ((gl_texturecompression.integer && gl_texturecompression_sprites.integer) ? TEXF_COMPRESS : 0) | TEXF_ISSPRITE | TEXF_PICMIP | TEXF_ALPHA | TEXF_CLAMP; modelradius = 0; if (loadmodel->numframes < 1) Host_Error ("Mod_Sprite_SharedSetup: Invalid # of frames: %d", loadmodel->numframes); // LordHavoc: hack to allow sprites to be non-fullbright fullbright = true; for (i = 0;i < MAX_QPATH && loadmodel->name[i];i++) if (loadmodel->name[i] == '!') fullbright = false; // // load the frames // startframes = datapointer; realframes = 0; for (i = 0;i < loadmodel->numframes;i++) { pinframetype = (dspriteframetype_t *)datapointer; datapointer += sizeof(dspriteframetype_t); if (LittleLong (pinframetype->type) == SPR_SINGLE) groupframes = 1; else { pingroup = (dspritegroup_t *)datapointer; datapointer += sizeof(dspritegroup_t); groupframes = LittleLong(pingroup->numframes); datapointer += sizeof(dspriteinterval_t) * groupframes; } for (j = 0;j < groupframes;j++) { pinframe = (dspriteframe_t *)datapointer; if (version == SPRITE32_VERSION) datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height) * 4; else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION) datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height); } realframes += groupframes; } loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); loadmodel->sprite.sprdata_frames = (mspriteframe_t *)Mem_Alloc(loadmodel->mempool, sizeof(mspriteframe_t) * realframes); loadmodel->num_textures = realframes; loadmodel->num_texturesperskin = 1; loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, sizeof(texture_t) * loadmodel->num_textures); datapointer = (unsigned char *)startframes; realframes = 0; for (i = 0;i < loadmodel->numframes;i++) { pinframetype = (dspriteframetype_t *)datapointer; datapointer += sizeof(dspriteframetype_t); if (LittleLong (pinframetype->type) == SPR_SINGLE) { groupframes = 1; interval = 0.1f; } else { pingroup = (dspritegroup_t *)datapointer; datapointer += sizeof(dspritegroup_t); groupframes = LittleLong(pingroup->numframes); pinintervals = (dspriteinterval_t *)datapointer; datapointer += sizeof(dspriteinterval_t) * groupframes; interval = LittleFloat(pinintervals[0].interval); if (interval < 0.01f) Host_Error("Mod_Sprite_SharedSetup: invalid interval"); } dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "frame %i", i); loadmodel->animscenes[i].firstframe = realframes; loadmodel->animscenes[i].framecount = groupframes; loadmodel->animscenes[i].framerate = 1.0f / interval; loadmodel->animscenes[i].loop = true; for (j = 0;j < groupframes;j++) { pinframe = (dspriteframe_t *)datapointer; datapointer += sizeof(dspriteframe_t); origin[0] = LittleLong (pinframe->origin[0]); origin[1] = LittleLong (pinframe->origin[1]); width = LittleLong (pinframe->width); height = LittleLong (pinframe->height); loadmodel->sprite.sprdata_frames[realframes].left = origin[0]; loadmodel->sprite.sprdata_frames[realframes].right = origin[0] + width; loadmodel->sprite.sprdata_frames[realframes].up = origin[1]; loadmodel->sprite.sprdata_frames[realframes].down = origin[1] - height; x = (int)max(loadmodel->sprite.sprdata_frames[realframes].left * loadmodel->sprite.sprdata_frames[realframes].left, loadmodel->sprite.sprdata_frames[realframes].right * loadmodel->sprite.sprdata_frames[realframes].right); y = (int)max(loadmodel->sprite.sprdata_frames[realframes].up * loadmodel->sprite.sprdata_frames[realframes].up, loadmodel->sprite.sprdata_frames[realframes].down * loadmodel->sprite.sprdata_frames[realframes].down); if (modelradius < x + y) modelradius = x + y; if (cls.state != ca_dedicated) { skinframe = NULL; // note: Nehahra's null.spr has width == 0 and height == 0 if (width > 0 && height > 0) { if (groupframes > 1) { dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j); dpsnprintf (fogname, sizeof(fogname), "%s_%i_%ifog", loadmodel->name, i, j); } else { dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i); dpsnprintf (fogname, sizeof(fogname), "%s_%ifog", loadmodel->name, i); } if (!(skinframe = R_SkinFrame_LoadExternal(name, texflags | TEXF_COMPRESS, false))) { unsigned char *pixels = (unsigned char *) Mem_Alloc(loadmodel->mempool, width*height*4); if (version == SPRITE32_VERSION) { for (x = 0;x < width*height;x++) { pixels[x*4+2] = datapointer[x*4+0]; pixels[x*4+1] = datapointer[x*4+1]; pixels[x*4+0] = datapointer[x*4+2]; pixels[x*4+3] = datapointer[x*4+3]; } } else //if (version == SPRITEHL_VERSION || version == SPRITE_VERSION) Image_Copy8bitBGRA(datapointer, pixels, width*height, palette ? palette : palette_bgra_transparent); skinframe = R_SkinFrame_LoadInternalBGRA(name, texflags, pixels, width, height, false); // texflags |= TEXF_COMPRESS; Mem_Free(pixels); } } if (skinframe == NULL) skinframe = R_SkinFrame_LoadMissing(); Mod_SpriteSetupTexture(&loadmodel->data_textures[realframes], skinframe, fullbright, additive); } if (version == SPRITE32_VERSION) datapointer += width * height * 4; else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION) datapointer += width * height; realframes++; } } modelradius = sqrt(modelradius); for (i = 0;i < 3;i++) { loadmodel->normalmins[i] = loadmodel->yawmins[i] = loadmodel->rotatedmins[i] = -modelradius; loadmodel->normalmaxs[i] = loadmodel->yawmaxs[i] = loadmodel->rotatedmaxs[i] = modelradius; } loadmodel->radius = modelradius; loadmodel->radius2 = modelradius * modelradius; }
/* ================= idFile::ReadFloat ================= */ int idFile::ReadFloat( float &value ) { int result = Read( &value, sizeof( value ) ); value = LittleFloat(value); return result; }
/* =============== ParseMesh =============== */ static void ParseMesh ( dsurface_t *ds, mapVert_t *verts, msurface_t *surf, world_t &worldData, int index) { srfGridMesh_t *grid; int i, j, k; int width, height, numPoints; MAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; int lightmapNum[MAXLIGHTMAPS]; vec3_t bounds[2]; vec3_t tmpVec; static surfaceType_t skipData = SF_SKIP; for(i=0;i<MAXLIGHTMAPS;i++) { lightmapNum[i] = LittleLong( ds->lightmapNum[i] ); if (lightmapNum[i] >= 0) { lightmapNum[i] += worldData.startLightMapIndex; } } // get fog volume surf->fogIndex = LittleLong( ds->fogNum ) + 1; if (index && !surf->fogIndex && tr.world && tr.world->globalFog != -1) { surf->fogIndex = worldData.globalFog; } // get shader value surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum, ds->lightmapStyles, ds->vertexStyles, worldData ); if ( r_singleShader->integer && !surf->shader->sky ) { surf->shader = tr.defaultShader; } // we may have a nodraw surface, because they might still need to // be around for movement clipping if ( worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { surf->data = &skipData; return; } width = LittleLong( ds->patchWidth ); height = LittleLong( ds->patchHeight ); verts += LittleLong( ds->firstVert ); numPoints = width * height; for ( i = 0 ; i < numPoints ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) { points[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); points[i].normal[j] = LittleFloat( verts[i].normal[j] ); } for ( j = 0 ; j < 2 ; j++ ) { points[i].st[j] = LittleFloat( verts[i].st[j] ); for(k=0;k<MAXLIGHTMAPS;k++) { points[i].lightmap[k][j] = LittleFloat( verts[i].lightmap[k][j] ); } } for(k=0;k<MAXLIGHTMAPS;k++) { R_ColorShiftLightingBytes( verts[i].color[k], points[i].color[k] ); } } // pre-tesseleate grid = R_SubdividePatchToGrid( width, height, points ); surf->data = (surfaceType_t *)grid; // copy the level of detail origin, which is the center // of the group of all curves that must subdivide the same // to avoid cracking for ( i = 0 ; i < 3 ; i++ ) { bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); } VectorAdd( bounds[0], bounds[1], bounds[1] ); VectorScale( bounds[1], 0.5f, grid->lodOrigin ); VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); grid->lodRadius = VectorLength( tmpVec ); }
/* ================= idFile::WriteFloat ================= */ int idFile::WriteFloat( const float value ) { float v = LittleFloat(value); return Write( &v, sizeof( v ) ); }
/* ================= R_LoadMD3 ================= */ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) { int i, j; md3Header_t *pinmodel; md3Frame_t *frame; md3Surface_t *surf; md3Shader_t *shader; md3Triangle_t *tri; md3St_t *st; md3XyzNormal_t *xyz; md3Tag_t *tag; int version; int size; pinmodel = (md3Header_t *)buffer; version = LittleLong (pinmodel->version); if (version != MD3_VERSION) { ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", mod_name, version, MD3_VERSION); return qfalse; } mod->type = MOD_MESH; size = LittleLong(pinmodel->ofsEnd); mod->dataSize += size; mod->md3[lod] = ri.Hunk_Alloc( size, h_low ); Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) ); LL(mod->md3[lod]->ident); LL(mod->md3[lod]->version); LL(mod->md3[lod]->numFrames); LL(mod->md3[lod]->numTags); LL(mod->md3[lod]->numSurfaces); LL(mod->md3[lod]->ofsFrames); LL(mod->md3[lod]->ofsTags); LL(mod->md3[lod]->ofsSurfaces); LL(mod->md3[lod]->ofsEnd); if ( mod->md3[lod]->numFrames < 1 ) { ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name ); return qfalse; } // swap all the frames frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames ); for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) { 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] ); } } // swap all the tags tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags ); for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) { for ( j = 0 ; j < 3 ; j++ ) { tag->origin[j] = LittleFloat( tag->origin[j] ); tag->axis[0][j] = LittleFloat( tag->axis[0][j] ); tag->axis[1][j] = LittleFloat( tag->axis[1][j] ); tag->axis[2][j] = LittleFloat( tag->axis[2][j] ); } } // swap all the surfaces surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces ); for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) { LL(surf->ident); LL(surf->flags); LL(surf->numFrames); LL(surf->numShaders); LL(surf->numTriangles); LL(surf->ofsTriangles); LL(surf->numVerts); LL(surf->ofsShaders); LL(surf->ofsSt); LL(surf->ofsXyzNormals); LL(surf->ofsEnd); if ( surf->numVerts > SHADER_MAX_VERTEXES ) { ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); } if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); } // change to surface identifier surf->ident = SF_MD3; // lowercase the surface name so skin compares are faster Q_strlwr( surf->name ); // strip off a trailing _1 or _2 // this is a crutch for q3data being a mess j = strlen( surf->name ); if ( j > 2 && surf->name[j-2] == '_' ) { surf->name[j-2] = 0; } // register the shaders shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { shader_t *sh; sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue ); if ( sh->defaultShader ) { shader->shaderIndex = 0; } else { shader->shaderIndex = sh->index; } } // swap all the triangles tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { LL(tri->indexes[0]); LL(tri->indexes[1]); LL(tri->indexes[2]); } // swap all the ST st = (md3St_t *) ( (byte *)surf + surf->ofsSt ); for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { st->st[0] = LittleFloat( st->st[0] ); st->st[1] = LittleFloat( st->st[1] ); } // swap all the XyzNormals xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals ); for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) { xyz->xyz[0] = LittleShort( xyz->xyz[0] ); xyz->xyz[1] = LittleShort( xyz->xyz[1] ); xyz->xyz[2] = LittleShort( xyz->xyz[2] ); xyz->normal = LittleShort( xyz->normal ); } // find the next surface surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd ); } return qtrue; }
/* ============= Sin_SwapBSPFile Byte swaps all data in a bsp file. ============= */ void Sin_SwapBSPFile( qboolean todisk ) { int i, j; sin_dmodel_t *d; // models for ( i = 0 ; i < sin_nummodels ; i++ ) { d = &sin_dmodels[i]; d->firstface = LittleLong( d->firstface ); d->numfaces = LittleLong( d->numfaces ); d->headnode = LittleLong( d->headnode ); for ( j = 0 ; j < 3 ; j++ ) { d->mins[j] = LittleFloat( d->mins[j] ); d->maxs[j] = LittleFloat( d->maxs[j] ); d->origin[j] = LittleFloat( d->origin[j] ); } } // // vertexes // for ( i = 0 ; i < sin_numvertexes ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) sin_dvertexes[i].point[j] = LittleFloat( sin_dvertexes[i].point[j] ); } // // planes // for ( i = 0 ; i < sin_numplanes ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) sin_dplanes[i].normal[j] = LittleFloat( sin_dplanes[i].normal[j] ); sin_dplanes[i].dist = LittleFloat( sin_dplanes[i].dist ); sin_dplanes[i].type = LittleLong( sin_dplanes[i].type ); } // // sin_texinfos // for ( i = 0; i < sin_numtexinfo; i++ ) { for ( j = 0 ; j < 8 ; j++ ) sin_texinfo[i].vecs[0][j] = LittleFloat( sin_texinfo[i].vecs[0][j] ); #ifdef SIN sin_texinfo[i].trans_mag = LittleFloat( sin_texinfo[i].trans_mag ); sin_texinfo[i].trans_angle = LittleLong( sin_texinfo[i].trans_angle ); sin_texinfo[i].animtime = LittleFloat( sin_texinfo[i].animtime ); sin_texinfo[i].nonlit = LittleFloat( sin_texinfo[i].nonlit ); sin_texinfo[i].translucence = LittleFloat( sin_texinfo[i].translucence ); sin_texinfo[i].friction = LittleFloat( sin_texinfo[i].friction ); sin_texinfo[i].restitution = LittleFloat( sin_texinfo[i].restitution ); sin_texinfo[i].flags = LittleUnsigned( sin_texinfo[i].flags ); #else sin_texinfo[i].value = LittleLong( sin_texinfo[i].value ); sin_texinfo[i].flags = LittleLong( sin_texinfo[i].flags ); #endif sin_texinfo[i].nexttexinfo = LittleLong( sin_texinfo[i].nexttexinfo ); } #ifdef SIN // // lightinfos // for ( i = 0; i < sin_numlightinfo; i++ ) { for ( j = 0 ; j < 3 ; j++ ) { sin_lightinfo[i].color[j] = LittleFloat( sin_lightinfo[i].color[j] ); } sin_lightinfo[i].value = LittleLong( sin_lightinfo[i].value ); sin_lightinfo[i].direct = LittleFloat( sin_lightinfo[i].direct ); sin_lightinfo[i].directangle = LittleFloat( sin_lightinfo[i].directangle ); sin_lightinfo[i].directstyle = LittleFloat( sin_lightinfo[i].directstyle ); } #endif // // faces // for ( i = 0 ; i < sin_numfaces ; i++ ) { sin_dfaces[i].texinfo = LittleShort( sin_dfaces[i].texinfo ); #ifdef SIN sin_dfaces[i].lightinfo = LittleLong( sin_dfaces[i].lightinfo ); sin_dfaces[i].planenum = LittleUnsignedShort( sin_dfaces[i].planenum ); #else sin_dfaces[i].planenum = LittleShort( sin_dfaces[i].planenum ); #endif sin_dfaces[i].side = LittleShort( sin_dfaces[i].side ); sin_dfaces[i].lightofs = LittleLong( sin_dfaces[i].lightofs ); sin_dfaces[i].firstedge = LittleLong( sin_dfaces[i].firstedge ); sin_dfaces[i].numedges = LittleShort( sin_dfaces[i].numedges ); } // // nodes // for ( i = 0 ; i < sin_numnodes ; i++ ) { sin_dnodes[i].planenum = LittleLong( sin_dnodes[i].planenum ); for ( j = 0 ; j < 3 ; j++ ) { sin_dnodes[i].mins[j] = LittleShort( sin_dnodes[i].mins[j] ); sin_dnodes[i].maxs[j] = LittleShort( sin_dnodes[i].maxs[j] ); } sin_dnodes[i].children[0] = LittleLong( sin_dnodes[i].children[0] ); sin_dnodes[i].children[1] = LittleLong( sin_dnodes[i].children[1] ); #ifdef SIN sin_dnodes[i].firstface = LittleUnsignedShort( sin_dnodes[i].firstface ); sin_dnodes[i].numfaces = LittleUnsignedShort( sin_dnodes[i].numfaces ); #else sin_dnodes[i].firstface = LittleShort( sin_dnodes[i].firstface ); sin_dnodes[i].numfaces = LittleShort( sin_dnodes[i].numfaces ); #endif } // // leafs // for ( i = 0 ; i < sin_numleafs ; i++ ) { sin_dleafs[i].contents = LittleLong( sin_dleafs[i].contents ); sin_dleafs[i].cluster = LittleShort( sin_dleafs[i].cluster ); sin_dleafs[i].area = LittleShort( sin_dleafs[i].area ); for ( j = 0 ; j < 3 ; j++ ) { sin_dleafs[i].mins[j] = LittleShort( sin_dleafs[i].mins[j] ); sin_dleafs[i].maxs[j] = LittleShort( sin_dleafs[i].maxs[j] ); } #ifdef SIN sin_dleafs[i].firstleafface = LittleUnsignedShort( sin_dleafs[i].firstleafface ); sin_dleafs[i].numleaffaces = LittleUnsignedShort( sin_dleafs[i].numleaffaces ); sin_dleafs[i].firstleafbrush = LittleUnsignedShort( sin_dleafs[i].firstleafbrush ); sin_dleafs[i].numleafbrushes = LittleUnsignedShort( sin_dleafs[i].numleafbrushes ); #else sin_dleafs[i].firstleafface = LittleShort( sin_dleafs[i].firstleafface ); sin_dleafs[i].numleaffaces = LittleShort( sin_dleafs[i].numleaffaces ); sin_dleafs[i].firstleafbrush = LittleShort( sin_dleafs[i].firstleafbrush ); sin_dleafs[i].numleafbrushes = LittleShort( sin_dleafs[i].numleafbrushes ); #endif } // // leaffaces // for ( i = 0 ; i < sin_numleaffaces ; i++ ) sin_dleaffaces[i] = LittleShort( sin_dleaffaces[i] ); // // leafbrushes // for ( i = 0 ; i < sin_numleafbrushes ; i++ ) sin_dleafbrushes[i] = LittleShort( sin_dleafbrushes[i] ); // // surfedges // for ( i = 0 ; i < sin_numsurfedges ; i++ ) sin_dsurfedges[i] = LittleLong( sin_dsurfedges[i] ); // // edges // for ( i = 0 ; i < sin_numedges ; i++ ) { #ifdef SIN sin_dedges[i].v[0] = LittleUnsignedShort( sin_dedges[i].v[0] ); sin_dedges[i].v[1] = LittleUnsignedShort( sin_dedges[i].v[1] ); #else sin_dedges[i].v[0] = LittleShort( sin_dedges[i].v[0] ); sin_dedges[i].v[1] = LittleShort( sin_dedges[i].v[1] ); #endif } // // brushes // for ( i = 0 ; i < sin_numbrushes ; i++ ) { sin_dbrushes[i].firstside = LittleLong( sin_dbrushes[i].firstside ); sin_dbrushes[i].numsides = LittleLong( sin_dbrushes[i].numsides ); sin_dbrushes[i].contents = LittleLong( sin_dbrushes[i].contents ); } // // areas // for ( i = 0 ; i < sin_numareas ; i++ ) { sin_dareas[i].numareaportals = LittleLong( sin_dareas[i].numareaportals ); sin_dareas[i].firstareaportal = LittleLong( sin_dareas[i].firstareaportal ); } // // areasportals // for ( i = 0 ; i < sin_numareaportals ; i++ ) { sin_dareaportals[i].portalnum = LittleLong( sin_dareaportals[i].portalnum ); sin_dareaportals[i].otherarea = LittleLong( sin_dareaportals[i].otherarea ); } // // brushsides // for ( i = 0 ; i < sin_numbrushsides ; i++ ) { #ifdef SIN sin_dbrushsides[i].planenum = LittleUnsignedShort( sin_dbrushsides[i].planenum ); #else sin_dbrushsides[i].planenum = LittleShort( sin_dbrushsides[i].planenum ); #endif sin_dbrushsides[i].texinfo = LittleShort( sin_dbrushsides[i].texinfo ); #ifdef SIN sin_dbrushsides[i].lightinfo = LittleLong( sin_dbrushsides[i].lightinfo ); #endif } // // visibility // if ( todisk ) { j = sin_dvis->numclusters; } else { j = LittleLong( sin_dvis->numclusters ); } sin_dvis->numclusters = LittleLong( sin_dvis->numclusters ); for ( i = 0 ; i < j ; i++ ) { sin_dvis->bitofs[i][0] = LittleLong( sin_dvis->bitofs[i][0] ); sin_dvis->bitofs[i][1] = LittleLong( sin_dvis->bitofs[i][1] ); } } //end of the function Sin_SwapBSPFile
static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { int i, j, k, lodindex; md4Header_t *pinmodel, *md4; md4Frame_t *frame; md4LOD_t *lod; md4Surface_t *surf; md4Triangle_t *tri; md4Vertex_t *v; int version; int size; shader_t *sh; int frameSize; pinmodel = (md4Header_t *)buffer; version = LittleLong (pinmodel->version); if (version != MD4_VERSION) { ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n", mod_name, version, MD4_VERSION); return qfalse; } mod->type = MOD_MD4; size = LittleLong(pinmodel->ofsEnd); mod->dataSize += size; md4 = mod->md4 = ri.Hunk_Alloc( size, h_low ); Com_Memcpy(md4, buffer, size); LL(md4->ident); LL(md4->version); LL(md4->numFrames); LL(md4->numBones); LL(md4->numLODs); LL(md4->ofsFrames); LL(md4->ofsLODs); md4->ofsEnd = size; if ( md4->numFrames < 1 ) { ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name ); return qfalse; } // we don't need to swap tags in the renderer, they aren't used // swap all the frames frameSize = (size_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] ); for ( i = 0 ; i < md4->numFrames ; i++, frame++) { frame = (md4Frame_t *) ( (byte *)md4 + md4->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] ); } for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) { ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] ); } } // swap all the LOD's lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs ); for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) { // swap all the surfaces surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces ); for ( i = 0 ; i < lod->numSurfaces ; i++) { LL(surf->ident); LL(surf->numTriangles); LL(surf->ofsTriangles); LL(surf->numVerts); LL(surf->ofsVerts); LL(surf->ofsEnd); if ( surf->numVerts > SHADER_MAX_VERTEXES ) { ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); } if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); } // change to surface identifier surf->ident = SF_MD4; // lowercase the surface name so skin compares are faster Q_strlwr( surf->name ); // register the shaders sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue ); if ( sh->defaultShader ) { surf->shaderIndex = 0; } else { surf->shaderIndex = sh->index; } // swap all the triangles tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { LL(tri->indexes[0]); LL(tri->indexes[1]); LL(tri->indexes[2]); } // swap all the vertexes // FIXME // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left // in for reference. //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12); v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts); for ( j = 0 ; j < surf->numVerts ; j++ ) { v->normal[0] = LittleFloat( v->normal[0] ); v->normal[1] = LittleFloat( v->normal[1] ); v->normal[2] = LittleFloat( v->normal[2] ); v->texCoords[0] = LittleFloat( v->texCoords[0] ); v->texCoords[1] = LittleFloat( v->texCoords[1] ); v->numWeights = LittleLong( v->numWeights ); for ( k = 0 ; k < v->numWeights ; k++ ) { v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex ); v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight ); v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] ); v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] ); v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] ); } // FIXME // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left // in for reference. //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]); } // find the next surface surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd ); } // find the next LOD lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd ); } return qtrue; }
/* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ int CL_GetMessage (void) { int r, i; float f; if (cls.demoplayback) { // decide if it is time to grab the next message if (cls.signon == SIGNONS) // allways grab until fully connected { if (cls.timedemo) { if (host_framecount == cls.td_lastframe) return 0; // allready read this frame's message cls.td_lastframe = host_framecount; // if this is the second frame, grab the real td_starttime // so the bogus time on the first frame doesn't count if (host_framecount == cls.td_startframe + 1) cls.td_starttime = realtime; } else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) { return 0; // don't need another message yet } } // get the next message Sys_FileRead(cls.demofile, &net_message.cursize, 4); VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); for (i=0 ; i<3 ; i++) { r = Sys_FileRead(cls.demofile, &f, 4) / 4; cl.mviewangles[0][i] = LittleFloat (f); } net_message.cursize = LittleLong (net_message.cursize); if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message (0x%08x) > MAX_MSGLEN (%d)", net_message.cursize, MAX_MSGLEN); r = Sys_FileRead(cls.demofile, net_message.data, net_message.cursize) / net_message.cursize; if (r != 1) { CL_StopPlayback (); return 0; } return 1; } while (1) { r = NET_GetMessage (cls.netcon); if (r != 1 && r != 2) return r; // discard nop keepalive message if (net_message.cursize == 1 && net_message.data[0] == svc_nop) Con_Printf ("<-- server to client keepalive\n"); else break; } if (cls.demorecording) CL_WriteDemoMessage (); return r; }
/* ================= Mod_LoadAliasModel ================= */ void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i, j; mdl_t *pinmodel; stvert_t *pinstverts; dtriangle_t *pintriangles; int version, numframes; int size; daliasframetype_t *pframetype; daliasskintype_t *pskintype; int start, end, total; if (!strcmp(loadmodel->name, "progs/player.mdl") || !strcmp(loadmodel->name, "progs/eyes.mdl")) { unsigned short crc; byte *p; int len; char st[40]; CRC_Init(&crc); for (len = com_filesize, p = buffer; len; len--, p++) CRC_ProcessByte(&crc, *p); sprintf(st, "%d", (int) crc); Info_SetValueForKey (cls.userinfo, !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, st, MAX_INFO_STRING); if (cls.state >= ca_connected) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); sprintf(st, "setinfo %s %d", !strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name, (int)crc); SZ_Print (&cls.netchan.message, st); } } start = Hunk_LowMark (); pinmodel = (mdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); // // allocate space for a working header, plus all the data except the frames, // skin and group info // size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0]); pheader = Hunk_AllocName (size, loadname); mod->flags = LittleLong (pinmodel->flags); // // endian-adjust and copy the data, starting with the alias model header // pheader->boundingradius = LittleFloat (pinmodel->boundingradius); pheader->numskins = LittleLong (pinmodel->numskins); pheader->skinwidth = LittleLong (pinmodel->skinwidth); pheader->skinheight = LittleLong (pinmodel->skinheight); if (pheader->skinheight > MAX_LBM_HEIGHT) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); pheader->numverts = LittleLong (pinmodel->numverts); if (pheader->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); if (pheader->numverts > MAXALIASVERTS) Sys_Error ("model %s has too many vertices", mod->name); pheader->numtris = LittleLong (pinmodel->numtris); if (pheader->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); pheader->numframes = LittleLong (pinmodel->numframes); numframes = pheader->numframes; if (numframes < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; mod->synctype = LittleLong (pinmodel->synctype); mod->numframes = pheader->numframes; for (i=0 ; i<3 ; i++) { pheader->scale[i] = LittleFloat (pinmodel->scale[i]); pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); } // // load the skins // pskintype = (daliasskintype_t *)&pinmodel[1]; pskintype = Mod_LoadAllSkins (pheader->numskins, pskintype); // // load base s and t vertices // pinstverts = (stvert_t *)pskintype; for (i=0 ; i<pheader->numverts ; i++) { stverts[i].onseam = LittleLong (pinstverts[i].onseam); stverts[i].s = LittleLong (pinstverts[i].s); stverts[i].t = LittleLong (pinstverts[i].t); } // // load triangle lists // pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts]; for (i=0 ; i<pheader->numtris ; i++) { triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j=0 ; j<3 ; j++) { triangles[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // // load the frames // posenum = 0; pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris]; for (i=0 ; i<numframes ; i++) { aliasframetype_t frametype; frametype = LittleLong (pframetype->type); if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]); } else { pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]); } } pheader->numposes = posenum; mod->type = mod_alias; // FIXME: do this right mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; // // build the draw lists // GL_MakeAliasModelDisplayLists (mod, pheader); // // move the complete, relocatable alias model to the cache // end = Hunk_LowMark (); total = end - start; Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy (mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); }
/* ============= SwapBSPFile Byte swaps all data in a bsp file. ============= */ void SwapBSPFile (qboolean todisk) { int i, j, c; dmodel_t *d; dmiptexlump_t *mtl; // models for (i=0 ; i<nummodels ; i++) { d = &dmodels[i]; for (j=0 ; j<MAX_MAP_HULLS ; j++) d->headnode[j] = LittleLong (d->headnode[j]); d->visleafs = LittleLong (d->visleafs); d->firstface = LittleLong (d->firstface); d->numfaces = LittleLong (d->numfaces); for (j=0 ; j<3 ; j++) { d->mins[j] = LittleFloat(d->mins[j]); d->maxs[j] = LittleFloat(d->maxs[j]); d->origin[j] = LittleFloat(d->origin[j]); } } // // vertexes // for (i=0 ; i<numvertexes ; i++) { for (j=0 ; j<3 ; j++) dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]); } // // planes // for (i=0 ; i<numplanes ; i++) { for (j=0 ; j<3 ; j++) dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]); dplanes[i].dist = LittleFloat (dplanes[i].dist); dplanes[i].type = LittleLong (dplanes[i].type); } // // texinfos // for (i=0 ; i<numtexinfo ; i++) { for (j=0 ; j<8 ; j++) texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]); texinfo[i].miptex = LittleLong (texinfo[i].miptex); texinfo[i].flags = LittleLong (texinfo[i].flags); } // // faces // for (i=0 ; i<numfaces ; i++) { dfaces[i].texinfo = LittleShort (dfaces[i].texinfo); dfaces[i].planenum = LittleShort (dfaces[i].planenum); dfaces[i].side = LittleShort (dfaces[i].side); dfaces[i].lightofs = LittleLong (dfaces[i].lightofs); dfaces[i].firstedge = LittleLong (dfaces[i].firstedge); dfaces[i].numedges = LittleShort (dfaces[i].numedges); } // // nodes // for (i=0 ; i<numnodes ; i++) { dnodes[i].planenum = LittleLong (dnodes[i].planenum); for (j=0 ; j<3 ; j++) { dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]); dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]); } dnodes[i].children[0] = LittleShort (dnodes[i].children[0]); dnodes[i].children[1] = LittleShort (dnodes[i].children[1]); dnodes[i].firstface = LittleShort (dnodes[i].firstface); dnodes[i].numfaces = LittleShort (dnodes[i].numfaces); } // // leafs // for (i=0 ; i<numleafs ; i++) { dleafs[i].contents = LittleLong (dleafs[i].contents); for (j=0 ; j<3 ; j++) { dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]); dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]); } dleafs[i].firstmarksurface = LittleShort (dleafs[i].firstmarksurface); dleafs[i].nummarksurfaces = LittleShort (dleafs[i].nummarksurfaces); dleafs[i].visofs = LittleLong (dleafs[i].visofs); } // // clipnodes // for (i=0 ; i<numclipnodes ; i++) { dclipnodes[i].planenum = LittleLong (dclipnodes[i].planenum); dclipnodes[i].children[0] = LittleShort (dclipnodes[i].children[0]); dclipnodes[i].children[1] = LittleShort (dclipnodes[i].children[1]); } // // miptex // if (texdatasize) { mtl = (dmiptexlump_t *)dtexdata; if (todisk) c = mtl->nummiptex; else c = LittleLong(mtl->nummiptex); mtl->nummiptex = LittleLong (mtl->nummiptex); for (i=0 ; i<c ; i++) mtl->dataofs[i] = LittleLong(mtl->dataofs[i]); } // // marksurfaces // for (i=0 ; i<nummarksurfaces ; i++) dmarksurfaces[i] = LittleShort (dmarksurfaces[i]); // // surfedges // for (i=0 ; i<numsurfedges ; i++) dsurfedges[i] = LittleLong (dsurfedges[i]); // // edges // for (i=0 ; i<numedges ; i++) { dedges[i].v[0] = LittleShort (dedges[i].v[0]); dedges[i].v[1] = LittleShort (dedges[i].v[1]); } }
/* ==================== CL_ReadDemoMessage Handles playback of demos ==================== */ void CL_ReadDemoMessage(void) { int i; float f; if (!cls.demoplayback) return; // LordHavoc: pausedemo if (cls.demopaused) return; for (;;) { // decide if it is time to grab the next message // always grab until fully connected if (cls.signon == SIGNONS) { if (cls.timedemo) { cls.td_frames++; cls.td_onesecondframes++; // if this is the first official frame we can now grab the real // td_starttime so the bogus time on the first frame doesn't // count against the final report if (cls.td_frames == 0) { cls.td_starttime = realtime; cls.td_onesecondnexttime = cl.time + 1; cls.td_onesecondrealtime = realtime; cls.td_onesecondframes = 0; cls.td_onesecondminfps = 0; cls.td_onesecondmaxfps = 0; cls.td_onesecondavgfps = 0; cls.td_onesecondavgcount = 0; } if (cl.time >= cls.td_onesecondnexttime) { double fps = cls.td_onesecondframes / (realtime - cls.td_onesecondrealtime); if (cls.td_onesecondavgcount == 0) { cls.td_onesecondminfps = fps; cls.td_onesecondmaxfps = fps; } cls.td_onesecondrealtime = realtime; cls.td_onesecondminfps = min(cls.td_onesecondminfps, fps); cls.td_onesecondmaxfps = max(cls.td_onesecondmaxfps, fps); cls.td_onesecondavgfps += fps; cls.td_onesecondavgcount++; cls.td_onesecondframes = 0; cls.td_onesecondnexttime++; } } else if (cl.time <= cl.mtime[0]) { // don't need another message yet return; } } // get the next message FS_Read(cls.demofile, &cl_message.cursize, 4); cl_message.cursize = LittleLong(cl_message.cursize); if(cl_message.cursize & DEMOMSG_CLIENT_TO_SERVER) // This is a client->server message! Ignore for now! { // skip over demo packet FS_Seek(cls.demofile, 12 + (cl_message.cursize & (~DEMOMSG_CLIENT_TO_SERVER)), SEEK_CUR); continue; } if (cl_message.cursize > cl_message.maxsize) { Con_Printf("Demo message (%i) > cl_message.maxsize (%i)", cl_message.cursize, cl_message.maxsize); cl_message.cursize = 0; CL_Disconnect(); return; } VectorCopy(cl.mviewangles[0], cl.mviewangles[1]); for (i = 0;i < 3;i++) { FS_Read(cls.demofile, &f, 4); cl.mviewangles[0][i] = LittleFloat(f); } if (FS_Read(cls.demofile, cl_message.data, cl_message.cursize) == cl_message.cursize) { MSG_BeginReading(&cl_message); CL_ParseServerMessage(); if (cls.signon != SIGNONS) Cbuf_Execute(); // immediately execute svc_stufftext if in the demo before connect! // In case the demo contains a "svc_disconnect" message if (!cls.demoplayback) return; if (cls.timedemo) return; } else { CL_Disconnect(); return; } } }
/* * Mod_LoadSkeletalModel */ void Mod_LoadSkeletalModel( model_t *mod, const model_t *parent, void *buffer, bspFormatDesc_t *unused ) { unsigned int i, j, k; size_t filesize; qbyte *pbase; size_t memsize; qbyte *pmem; iqmheader_t *header; char *texts; iqmvertexarray_t *va; iqmjoint_t *joints; bonepose_t *baseposes; iqmpose_t *poses; unsigned short *framedata; const int *inelems; elem_t *outelems; iqmmesh_t *inmesh; iqmbounds_t *inbounds; float *vposition, *vtexcoord, *vnormal, *vtangent; qbyte *vblendindices_byte, *vblendweights_byte; int *vblendindexes_int; float *vblendweights_float; mskmodel_t *poutmodel; baseposes = NULL; header = ( iqmheader_t * )buffer; // check IQM magic if( memcmp( header->magic, "INTERQUAKEMODEL", 16 ) ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s is not an Inter-Quake Model\n", mod->name ); goto error; } // check header version header->version = LittleLong( header->version ); if( header->version != IQM_VERSION ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has wrong type number (%i should be %i)\n", mod->name, header->version, IQM_VERSION ); goto error; } // byteswap header #define H_SWAP(s) (header->s = LittleLong( header->s )) H_SWAP( filesize ); H_SWAP( flags ); H_SWAP( num_text ); H_SWAP( ofs_text ); H_SWAP( num_meshes ); H_SWAP( ofs_meshes ); H_SWAP( num_vertexarrays ); H_SWAP( num_vertexes ); H_SWAP( ofs_vertexarrays ); H_SWAP( num_triangles ); H_SWAP( ofs_triangles ); H_SWAP( ofs_adjacency ); H_SWAP( num_joints ); H_SWAP( ofs_joints ); H_SWAP( num_poses ); H_SWAP( ofs_poses ); H_SWAP( num_anims ); H_SWAP( ofs_anims ); H_SWAP( num_frames ); H_SWAP( num_framechannels ); H_SWAP( ofs_frames ); H_SWAP( ofs_bounds ); H_SWAP( num_comment ); H_SWAP( ofs_comment ); H_SWAP( num_extensions ); H_SWAP( ofs_extensions ); #undef H_SWAP if( header->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1 ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has no geometry\n", mod->name ); goto error; } if( header->num_frames < 1 || header->num_anims < 1 ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has no animations\n", mod->name ); goto error; } if( header->num_joints != header->num_poses ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has an invalid number of poses: %i vs %i\n", mod->name, header->num_joints, header->num_poses ); goto error; } if( !header->ofs_bounds ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has no frame bounds\n", mod->name ); goto error; } pbase = ( qbyte * )buffer; filesize = header->filesize; // check data offsets against the filesize if( header->ofs_text + header->num_text > filesize || header->ofs_vertexarrays + header->num_vertexarrays * sizeof( iqmvertexarray_t ) > filesize || header->ofs_joints + header->num_joints * sizeof( iqmjoint_t ) > filesize || header->ofs_frames + header->num_frames * header->num_framechannels * sizeof( unsigned short ) > filesize || header->ofs_triangles + header->num_triangles * sizeof( int[3] ) > filesize || header->ofs_meshes + header->num_meshes * sizeof( iqmmesh_t ) > filesize || header->ofs_bounds + header->num_frames * sizeof( iqmbounds_t ) > filesize ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s has invalid size or offset information\n", mod->name ); goto error; } poutmodel = mod->extradata = Mod_Malloc( mod, sizeof( *poutmodel ) ); // load text texts = Mod_Malloc( mod, header->num_text + 1 ); if( header->ofs_text ) { memcpy( texts, (const char *)(pbase + header->ofs_text), header->num_text ); } texts[header->ofs_text] = '\0'; // load vertex arrays vposition = NULL; vtexcoord = NULL; vnormal = NULL; vtangent = NULL; vblendindices_byte = NULL; vblendindexes_int = NULL; vblendweights_byte = NULL; vblendweights_float = NULL; va = ( iqmvertexarray_t * )( pbase + header->ofs_vertexarrays ); for( i = 0; i < header->num_vertexarrays; i++ ) { size_t vsize; va[i].type = LittleLong( va[i].type ); va[i].flags = LittleLong( va[i].flags ); va[i].format = LittleLong( va[i].format ); va[i].size = LittleLong( va[i].size ); va[i].offset = LittleLong( va[i].offset ); vsize = header->num_vertexes*va[i].size; switch( va[i].format ) { case IQM_FLOAT: vsize *= sizeof( float ); break; case IQM_INT: case IQM_UINT: vsize *= sizeof( int ); break; case IQM_BYTE: case IQM_UBYTE: vsize *= sizeof( unsigned char ); break; default: continue; } if( va[i].offset + vsize > filesize ) { continue; } switch( va[i].type ) { case IQM_POSITION: if( va[i].format == IQM_FLOAT && va[i].size == 3 ) { vposition = ( float * )( pbase + va[i].offset ); } break; case IQM_TEXCOORD: if( va[i].format == IQM_FLOAT && va[i].size == 2 ) { vtexcoord = ( float * )( pbase + va[i].offset ); } break; case IQM_NORMAL: if( va[i].format == IQM_FLOAT && va[i].size == 3 ) { vnormal = ( float * )( pbase + va[i].offset ); } break; case IQM_TANGENT: if( va[i].format == IQM_FLOAT && va[i].size == 4 ) { vtangent = ( float * )( pbase + va[i].offset ); } break; case IQM_BLENDINDEXES: if( va[i].size != SKM_MAX_WEIGHTS ) break; if( va[i].format == IQM_BYTE || va[i].format == IQM_UBYTE ) { vblendindices_byte = ( qbyte * )( pbase + va[i].offset ); } else if( va[i].format == IQM_INT || va[i].format == IQM_UINT ) { vblendindexes_int = ( int * )( pbase + va[i].offset ); } break; case IQM_BLENDWEIGHTS: if( va[i].size != SKM_MAX_WEIGHTS ) break; if( va[i].format == IQM_UBYTE ) { vblendweights_byte = ( qbyte * )( pbase + va[i].offset ); } else if( va[i].format == IQM_FLOAT ) { vblendweights_float = ( float * )( pbase + va[i].offset ); } break; default: break; } } if( !vposition || !vtexcoord || !(vblendindices_byte || vblendindexes_int) || !(vblendweights_byte || vblendweights_float) ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s is missing vertex array data\n", mod->name ); goto error; } // load joints memsize = 0; memsize += sizeof( bonepose_t ) * header->num_joints; pmem = Mod_Malloc( mod, memsize ); baseposes = ( void * )pmem; pmem += sizeof( *baseposes ); memsize = 0; memsize += sizeof( mskbone_t ) * header->num_joints; memsize += sizeof( bonepose_t ) * header->num_joints; pmem = Mod_Malloc( mod, memsize ); poutmodel->numbones = header->num_joints; poutmodel->bones = ( void * )pmem; pmem += sizeof( *poutmodel->bones ) * poutmodel->numbones; poutmodel->invbaseposes = ( void * )pmem; pmem += sizeof( *poutmodel->invbaseposes ) * poutmodel->numbones; joints = ( iqmjoint_t * )( pbase + header->ofs_joints ); for( i = 0; i < poutmodel->numbones; i++ ) { joints[i].name = LittleLong( joints[i].name ); joints[i].parent = LittleLong( joints[i].parent ); for( j = 0; j < 3; j++ ) { joints[i].translate[j] = LittleFloat( joints[i].translate[j] ); joints[i].rotate[j] = LittleFloat( joints[i].rotate[j] ); joints[i].scale[j] = LittleFloat( joints[i].scale[j] ); } if( joints[i].parent >= (int)i ) { ri.Com_Printf( S_COLOR_RED "ERROR: %s bone[%i].parent(%i) >= %i\n", mod->name, i, joints[i].parent, i ); goto error; } poutmodel->bones[i].name = texts + joints[i].name; poutmodel->bones[i].parent = joints[i].parent; DualQuat_FromQuat3AndVector( joints[i].rotate, joints[i].translate, baseposes[i].dualquat ); // scale is unused // reconstruct invserse bone pose if( joints[i].parent >= 0 ) { bonepose_t bp, *pbp; bp = baseposes[i]; pbp = &baseposes[joints[i].parent]; DualQuat_Multiply( pbp->dualquat, bp.dualquat, baseposes[i].dualquat ); } DualQuat_Copy( baseposes[i].dualquat, poutmodel->invbaseposes[i].dualquat ); DualQuat_Invert( poutmodel->invbaseposes[i].dualquat ); } // load frames poses = ( iqmpose_t * )( pbase + header->ofs_poses ); for( i = 0; i < header->num_poses; i++ ) { poses[i].parent = LittleLong( poses[i].parent ); poses[i].mask = LittleLong( poses[i].mask ); for( j = 0; j < 10; j++ ) { poses[i].channeloffset[j] = LittleFloat( poses[i].channeloffset[j] ); poses[i].channelscale[j] = LittleFloat( poses[i].channelscale[j] ); } } memsize = 0; memsize += sizeof( mskframe_t ) * header->num_frames; memsize += sizeof( bonepose_t ) * header->num_joints * header->num_frames; pmem = Mod_Malloc( mod, memsize ); poutmodel->numframes = header->num_frames; poutmodel->frames = ( mskframe_t * )pmem; pmem += sizeof( mskframe_t ) * poutmodel->numframes; framedata = ( unsigned short * )( pbase + header->ofs_frames ); for( i = 0; i < header->num_frames; i++ ) { bonepose_t *pbp; vec3_t translate; quat_t rotate; poutmodel->frames[i].boneposes = ( bonepose_t * )pmem; pmem += sizeof( bonepose_t ) * poutmodel->numbones; for( j = 0, pbp = poutmodel->frames[i].boneposes; j < header->num_poses; j++, pbp++ ) { translate[0] = poses[j].channeloffset[0]; if( poses[j].mask & 0x01 ) translate[0] += *framedata++ * poses[j].channelscale[0]; translate[1] = poses[j].channeloffset[1]; if( poses[j].mask & 0x02 ) translate[1] += *framedata++ * poses[j].channelscale[1]; translate[2] = poses[j].channeloffset[2]; if( poses[j].mask & 0x04 ) translate[2] += *framedata++ * poses[j].channelscale[2]; rotate[0] = poses[j].channeloffset[3]; if( poses[j].mask & 0x08 ) rotate[0] += *framedata++ * poses[j].channelscale[3]; rotate[1] = poses[j].channeloffset[4]; if( poses[j].mask & 0x10 ) rotate[1] += *framedata++ * poses[j].channelscale[4]; rotate[2] = poses[j].channeloffset[5]; if( poses[j].mask & 0x20 ) rotate[2] += *framedata++ * poses[j].channelscale[5]; rotate[3] = poses[j].channeloffset[6]; if( poses[j].mask & 0x40 ) rotate[3] += *framedata++ * poses[j].channelscale[6]; if( rotate[3] > 0 ) { Vector4Inverse( rotate ); } Vector4Normalize( rotate ); // scale is unused if( poses[j].mask & 0x80 ) framedata++; if( poses[j].mask & 0x100 ) framedata++; if( poses[j].mask & 0x200 ) framedata++; DualQuat_FromQuatAndVector( rotate, translate, pbp->dualquat ); } } // load triangles memsize = 0; memsize += sizeof( *outelems ) * header->num_triangles * 3; pmem = Mod_Malloc( mod, memsize ); poutmodel->numtris = header->num_triangles; poutmodel->elems = ( elem_t * )pmem; pmem += sizeof( *outelems ) * header->num_triangles * 3; inelems = ( const int * )(pbase + header->ofs_triangles); outelems = poutmodel->elems; for( i = 0; i < header->num_triangles; i++ ) { for( j = 0; j < 3; j++ ) { outelems[j] = LittleLong( inelems[j] ); } inelems += 3; outelems += 3; } // load vertices memsize = 0; memsize += sizeof( *poutmodel->sVectorsArray ) * header->num_vertexes; // 16-bytes aligned memsize += sizeof( *poutmodel->xyzArray ) * header->num_vertexes; memsize += sizeof( *poutmodel->normalsArray ) * header->num_vertexes; memsize += sizeof( *poutmodel->stArray ) * header->num_vertexes; memsize += sizeof( *poutmodel->blendWeights ) * header->num_vertexes * SKM_MAX_WEIGHTS; memsize += sizeof( *poutmodel->blendIndices ) * header->num_vertexes * SKM_MAX_WEIGHTS; pmem = Mod_Malloc( mod, memsize ); poutmodel->numverts = header->num_vertexes; // S-vectors poutmodel->sVectorsArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->sVectorsArray ) * header->num_vertexes; if( vtangent ) { for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 4; j++ ) { poutmodel->sVectorsArray[i][j] = LittleFloat( vtangent[j] ); } vtangent += 4; } } // XYZ positions poutmodel->xyzArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->xyzArray ) * header->num_vertexes; for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 3; j++ ) { poutmodel->xyzArray[i][j] = LittleFloat( vposition[j] ); } poutmodel->xyzArray[i][3] = 1; vposition += 3; } // normals poutmodel->normalsArray = ( vec4_t * )pmem; pmem += sizeof( *poutmodel->normalsArray ) * header->num_vertexes; for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 3; j++ ) { poutmodel->normalsArray[i][j] = LittleFloat( vnormal[j] ); } poutmodel->normalsArray[i][3] = 0; vnormal += 3; } // texture coordinates poutmodel->stArray = ( vec2_t * )pmem; pmem += sizeof( *poutmodel->stArray ) * header->num_vertexes; for( i = 0; i < header->num_vertexes; i++ ) { for( j = 0; j < 2; j++ ) { poutmodel->stArray[i][j] = LittleFloat( vtexcoord[j] ); } vtexcoord += 2; } if( !vtangent ) { // if the loaded file is missing precomputed S-vectors, compute them now R_BuildTangentVectors( poutmodel->numverts, poutmodel->xyzArray, poutmodel->normalsArray, poutmodel->stArray, poutmodel->numtris, poutmodel->elems, poutmodel->sVectorsArray ); } // blend indices poutmodel->blendIndices = ( qbyte * )pmem; pmem += sizeof( *poutmodel->blendIndices ) * header->num_vertexes * SKM_MAX_WEIGHTS; if( vblendindices_byte ) { memcpy( poutmodel->blendIndices, vblendindices_byte, sizeof( qbyte ) * header->num_vertexes * SKM_MAX_WEIGHTS ); } else if( vblendindexes_int ) { for( j = 0; j < header->num_vertexes * SKM_MAX_WEIGHTS; j++ ) { poutmodel->blendIndices[j] = LittleLong( vblendindexes_int[j] ); } } // blend weights poutmodel->blendWeights = ( qbyte * )pmem; pmem += sizeof( *poutmodel->blendWeights ) * header->num_vertexes * SKM_MAX_WEIGHTS; if( vblendweights_byte ) { memcpy( poutmodel->blendWeights, vblendweights_byte, sizeof( qbyte ) * header->num_vertexes * SKM_MAX_WEIGHTS ); } else if( vblendweights_float ) { for( j = 0; j < header->num_vertexes * SKM_MAX_WEIGHTS; j++ ) { poutmodel->blendWeights[j] = LittleFloat( vblendweights_float[j] ) * 255.0f; } } // blends memsize = 0; memsize += poutmodel->numverts * ( sizeof( mskblend_t ) + sizeof( unsigned int ) ); pmem = Mod_Malloc( mod, memsize ); poutmodel->numblends = 0; poutmodel->blends = ( mskblend_t * )pmem; pmem += sizeof( *poutmodel->blends ) * poutmodel->numverts; poutmodel->vertexBlends = ( unsigned int * )pmem; vblendindices_byte = poutmodel->blendIndices; vblendweights_byte = poutmodel->blendWeights; for( i = 0; i < poutmodel->numverts; i++ ) { mskblend_t blend; for( j = 0; j < SKM_MAX_WEIGHTS; j++ ) { blend.indices[j] = vblendindices_byte[j]; blend.weights[j] = vblendweights_byte[j]; } poutmodel->vertexBlends[i] = Mod_SkeletalModel_AddBlend( poutmodel, &blend ); vblendindices_byte += SKM_MAX_WEIGHTS; vblendweights_byte += SKM_MAX_WEIGHTS; } // meshes memsize = 0; memsize += sizeof( mskmesh_t ) * header->num_meshes; memsize += sizeof( drawSurfaceSkeletal_t ) * header->num_meshes; pmem = Mod_Malloc( mod, memsize ); poutmodel->nummeshes = header->num_meshes; poutmodel->meshes = ( mskmesh_t * )pmem; pmem += sizeof( *poutmodel->meshes ) * header->num_meshes; inmesh = ( iqmmesh_t * )(pbase + header->ofs_meshes); for( i = 0; i < header->num_meshes; i++ ) { inmesh[i].name = LittleLong( inmesh[i].name ); inmesh[i].material = LittleLong( inmesh[i].material ); inmesh[i].first_vertex = LittleLong( inmesh[i].first_vertex ); inmesh[i].num_vertexes = LittleLong( inmesh[i].num_vertexes ); inmesh[i].first_triangle = LittleLong( inmesh[i].first_triangle ); inmesh[i].num_triangles = LittleLong( inmesh[i].num_triangles ); poutmodel->meshes[i].name = texts + inmesh[i].name; Mod_StripLODSuffix( poutmodel->meshes[i].name ); poutmodel->meshes[i].skin.name = texts + inmesh[i].material; poutmodel->meshes[i].skin.shader = R_RegisterSkin( poutmodel->meshes[i].skin.name ); poutmodel->meshes[i].elems = poutmodel->elems + inmesh[i].first_triangle * 3; poutmodel->meshes[i].numtris = inmesh[i].num_triangles; poutmodel->meshes[i].numverts = inmesh[i].num_vertexes; poutmodel->meshes[i].xyzArray = poutmodel->xyzArray + inmesh[i].first_vertex; poutmodel->meshes[i].normalsArray = poutmodel->normalsArray + inmesh[i].first_vertex; poutmodel->meshes[i].stArray = poutmodel->stArray + inmesh[i].first_vertex; poutmodel->meshes[i].sVectorsArray = poutmodel->sVectorsArray + inmesh[i].first_vertex; poutmodel->meshes[i].blendIndices = poutmodel->blendIndices + inmesh[i].first_vertex * SKM_MAX_WEIGHTS; poutmodel->meshes[i].blendWeights = poutmodel->blendWeights + inmesh[i].first_vertex * SKM_MAX_WEIGHTS; poutmodel->meshes[i].vertexBlends = poutmodel->vertexBlends + inmesh[i].first_vertex; // elements are always offset to start vertex 0 for each mesh outelems = poutmodel->meshes[i].elems; for( j = 0; j < poutmodel->meshes[i].numtris; j++ ) { outelems[0] -= inmesh[i].first_vertex; outelems[1] -= inmesh[i].first_vertex; outelems[2] -= inmesh[i].first_vertex; outelems += 3; } poutmodel->meshes[i].maxWeights = 1; vblendweights_byte = poutmodel->meshes[i].blendWeights; for( j = 0; j < poutmodel->meshes[i].numverts; j++ ) { for( k = 1; k < SKM_MAX_WEIGHTS && vblendweights_byte[k]; k++ ); if( k > poutmodel->meshes[i].maxWeights ) { poutmodel->meshes[i].maxWeights = k; if( k == SKM_MAX_WEIGHTS ) { break; } } vblendweights_byte += SKM_MAX_WEIGHTS; } // creating a VBO only makes sense if GLSL is present and the number of bones // we can handle on the GPU is sufficient if( glConfig.ext.vertex_buffer_object && poutmodel->numbones <= glConfig.maxGLSLBones ) { // build a static vertex buffer object for this mesh Mod_SkeletalBuildStaticVBOForMesh( &poutmodel->meshes[i] ); } } poutmodel->drawSurfs = ( drawSurfaceSkeletal_t * )pmem; pmem += sizeof( *poutmodel->drawSurfs ) * header->num_meshes; for( i = 0; i < header->num_meshes; i++ ) { poutmodel->drawSurfs[i].type = ST_SKELETAL; poutmodel->drawSurfs[i].model = mod; poutmodel->drawSurfs[i].mesh = poutmodel->meshes + i; } // bounds ClearBounds( mod->mins, mod->maxs ); inbounds = ( iqmbounds_t * )(pbase + header->ofs_bounds); for( i = 0; i < header->num_frames; i++ ) { for( j = 0; j < 3; j++ ) { inbounds[i].bbmin[j] = LittleFloat( inbounds[i].bbmin[j] ); inbounds[i].bbmax[j] = LittleFloat( inbounds[i].bbmax[j] ); } inbounds[i].radius = LittleFloat( inbounds[i].radius ); inbounds[i].xyradius = LittleFloat( inbounds[i].xyradius ); VectorCopy( inbounds[i].bbmin, poutmodel->frames[i].mins ); VectorCopy( inbounds[i].bbmax, poutmodel->frames[i].maxs ); poutmodel->frames[i].radius = inbounds[i].radius; AddPointToBounds( poutmodel->frames[i].mins, mod->mins, mod->maxs ); AddPointToBounds( poutmodel->frames[i].maxs, mod->mins, mod->maxs ); } mod->radius = RadiusFromBounds( mod->mins, mod->maxs ); mod->type = mod_skeletal; mod->registrationSequence = rsh.registrationSequence; mod->touch = &Mod_TouchSkeletalModel; R_Free( baseposes ); return; error: if( baseposes ) { R_Free( baseposes ); } mod->type = mod_bad; }