/* ================= RE_LoadWorldMap Called directly from cgame ================= */ void RE_LoadWorldMap_Actual( const char *name, world_t &worldData, int index ) { dheader_t *header; byte *buffer = NULL; qboolean loadedSubBSP = qfalse; if ( tr.worldMapLoaded && !index ) { Com_Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" ); } // set default sun direction to be used if it isn't // overridden by a shader if (!index) { skyboxportal = 0; tr.sunDirection[0] = 0.45f; tr.sunDirection[1] = 0.3f; tr.sunDirection[2] = 0.9f; VectorNormalize( tr.sunDirection ); tr.worldMapLoaded = qtrue; // clear tr.world so if the level fails to load, the next // try will not look at the partially loaded version tr.world = NULL; } // check for cached disk file from the server first... // if (ri.gpvCachedMapDiskImage()) { if (!strcmp(name, ri.gsCachedMapDiskImage())) { // we should always get here, if inside the first IF... // buffer = (byte *)ri.gpvCachedMapDiskImage(); } else { // this should never happen (ie renderer loading a different map than the server), but just in case... // // assert(0); // Z_Free(gpvCachedMapDiskImage); // gpvCachedMapDiskImage = NULL; //rww - this is a valid possibility now because of sub-bsp loading.\ //it's alright, just keep the current cache loadedSubBSP = qtrue; } } tr.worldDir[0] = '\0'; if (buffer == NULL) { // still needs loading... // ri.FS_ReadFile( name, (void **)&buffer ); if ( !buffer ) { Com_Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name); } } memset( &worldData, 0, sizeof( worldData ) ); Q_strncpyz( worldData.name, name, sizeof( worldData.name ) ); Q_strncpyz( tr.worldDir, name, sizeof( tr.worldDir ) ); Q_strncpyz( worldData.baseName, COM_SkipPath( worldData.name ), sizeof( worldData.name ) ); COM_StripExtension( worldData.baseName, worldData.baseName, sizeof( worldData.baseName ) ); COM_StripExtension( tr.worldDir, tr.worldDir, sizeof( tr.worldDir ) ); c_gridVerts = 0; header = (dheader_t *)buffer; fileBase = (byte *)header; header->version = LittleLong (header->version); if ( header->version != BSP_VERSION ) { Com_Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", name, header->version, BSP_VERSION); } // swap all the lumps for (size_t i=0 ; i<sizeof(dheader_t)/4 ; i++) { ((int *)header)[i] = LittleLong ( ((int *)header)[i]); } // load into heap R_LoadShaders( &header->lumps[LUMP_SHADERS], worldData ); R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS], name, worldData ); R_LoadPlanes (&header->lumps[LUMP_PLANES], worldData); R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES], worldData, index ); R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES], worldData, index ); R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES], worldData); R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS], worldData); R_LoadSubmodels (&header->lumps[LUMP_MODELS], worldData, index); R_LoadVisibility( &header->lumps[LUMP_VISIBILITY], worldData ); if (!index) { R_LoadEntities( &header->lumps[LUMP_ENTITIES], worldData ); R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID], worldData ); R_LoadLightGridArray( &header->lumps[LUMP_LIGHTARRAY], worldData ); // only set tr.world now that we know the entire level has loaded properly tr.world = &worldData; } if (ri.gpvCachedMapDiskImage() && !loadedSubBSP) { // For the moment, I'm going to keep this disk image around in case we need it to respawn. // No problem for memory, since it'll only be a NZ ptr if we're not low on physical memory // ( ie we've got > 96MB). // // So don't do this... // // Z_Free( gpvCachedMapDiskImage ); // gpvCachedMapDiskImage = NULL; } else { ri.FS_FreeFile( buffer ); } }
/* =============== 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; }
/* ================= Netchan_Process Returns qfalse if the message should not be processed due to being out of order or a fragment. Msg must be large enough to hold MAX_MSGLEN, because if this is the final fragment of a multi-part message, the entire thing will be copied out. ================= */ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { int sequence, sequence_ack; //int qport; int fragmentStart, fragmentLength; qboolean fragmented; // get sequence numbers MSG_BeginReading( msg ); sequence = MSG_ReadLong( msg ); sequence_ack = MSG_ReadLong( msg ); // check for fragment information if ( sequence & FRAGMENT_BIT ) { sequence &= ~FRAGMENT_BIT; fragmented = qtrue; } else { fragmented = qfalse; } // read the qport if we are a server if ( chan->sock == NS_SERVER ) { /*qport = */MSG_ReadShort( msg ); } // read the fragment information if ( fragmented ) { fragmentStart = MSG_ReadShort( msg ); fragmentLength = MSG_ReadShort( msg ); } else { fragmentStart = 0; // stop warning message fragmentLength = 0; } if ( showpackets->integer ) { if ( fragmented ) { Com_Printf( "%s recv %4i : s=%i ack=%i fragment=%i,%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence , sequence_ack , fragmentStart, fragmentLength ); } else { Com_Printf( "%s recv %4i : s=%i ack=%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence , sequence_ack ); } } // // discard out of order or duplicated packets // if ( sequence <= chan->incomingSequence ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Out of order packet %i at %i\n" , NET_AdrToString( chan->remoteAddress ) , sequence , chan->incomingSequence ); } return qfalse; } // // dropped packets don't keep the message from being used // chan->dropped = sequence - (chan->incomingSequence+1); if ( chan->dropped > 0 ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Dropped %i packets at %i\n" , NET_AdrToString( chan->remoteAddress ) , chan->dropped , sequence ); } } // // if this is the final framgent of a reliable message, // bump incoming_reliable_sequence // if ( fragmented ) { // make sure we if ( sequence != chan->fragmentSequence ) { chan->fragmentSequence = sequence; chan->fragmentLength = 0; } // if we missed a fragment, dump the message if ( fragmentStart != chan->fragmentLength ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Dropped a message fragment\n" , NET_AdrToString( chan->remoteAddress ) , sequence); } // we can still keep the part that we have so far, // so we don't need to clear chan->fragmentLength return qfalse; } // copy the fragment to the fragment buffer if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize || chan->fragmentLength + fragmentLength > (int)sizeof( chan->fragmentBuffer ) ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf ("%s:illegal fragment length\n" , NET_AdrToString (chan->remoteAddress ) ); } return qfalse; } memcpy( chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength ); chan->fragmentLength += fragmentLength; // if this wasn't the last fragment, don't process anything if ( fragmentLength == FRAGMENT_SIZE ) { return qfalse; } if ( chan->fragmentLength > msg->maxsize ) { Com_Printf( "%s:fragmentLength %i > msg->maxsize\n" , NET_AdrToString (chan->remoteAddress ), chan->fragmentLength ); return qfalse; } // copy the full message over the partial fragment // make sure the sequence number is still there *(int *)msg->data = LittleLong( sequence ); memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); msg->cursize = chan->fragmentLength + 4; chan->fragmentLength = 0; msg->readcount = 4; // past the sequence number return qtrue; } // // the message can now be read from the current message pointer // chan->incomingSequence = sequence; chan->incomingAcknowledged = sequence_ack; return qtrue; }
/* ================= 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] = (mdvModel_t*)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 = (mdvFrame_t*)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 = (mdvTag_t*)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 = (mdvTagName_t*)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 = (mdvSurface_t*)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 = (srfTriangle_t*)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 = (mdvVertex_t*)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 = (mdvSt_t*)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 defined(USE_D3D10) // TODO #else #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 = (srfVBOMDVMesh_t*)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 = (byte*)ri.Hunk_AllocateTempMemory(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.Hunk_FreeTempMemory(data); } // move VBO surfaces list to hunk mdvModel->numVBOSurfaces = vboSurfaces.currentElements; mdvModel->vboSurfaces = (srfVBOMDVMesh_t**)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 #endif // USE_D3D10 return qtrue; }
/* ================= R_LoadFogs ================= */ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump, world_t &worldData, int index ) { int i; fog_t *out; dfog_t *fogs; dbrush_t *brushes, *brush; dbrushside_t *sides; int count, brushesCount, sidesCount; int sideNum; int planeNum; shader_t *shader; float d; int firstSide=0; int lightmaps[MAXLIGHTMAPS] = { LIGHTMAP_NONE } ; fogs = (dfog_t *)(fileBase + l->fileofs); if (l->filelen % sizeof(*fogs)) { Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); } count = l->filelen / sizeof(*fogs); // create fog strucutres for them worldData.numfogs = count + 1; worldData.fogs = (fog_t *)Hunk_Alloc ( (worldData.numfogs+1)*sizeof(*out), qtrue); worldData.globalFog = -1; out = worldData.fogs + 1; // Copy the global fog from the main world into the bsp instance if(index) { if(tr.world && (tr.world->globalFog != -1)) { // Use the nightvision fog slot worldData.fogs[worldData.numfogs] = tr.world->fogs[tr.world->globalFog]; worldData.globalFog = worldData.numfogs; worldData.numfogs++; } } if ( !count ) { return; } brushes = (dbrush_t *)(fileBase + brushesLump->fileofs); if (brushesLump->filelen % sizeof(*brushes)) { Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); } brushesCount = brushesLump->filelen / sizeof(*brushes); sides = (dbrushside_t *)(fileBase + sidesLump->fileofs); if (sidesLump->filelen % sizeof(*sides)) { Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); } sidesCount = sidesLump->filelen / sizeof(*sides); for ( i=0 ; i<count ; i++, fogs++) { out->originalBrushNumber = LittleLong( fogs->brushNum ); if (out->originalBrushNumber == -1) { if(index) { Com_Error (ERR_DROP, "LoadMap: global fog not allowed in bsp instances - %s", worldData.name); } VectorSet(out->bounds[0], MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD); VectorSet(out->bounds[1], MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD); worldData.globalFog = i + 1; } else { if ( (unsigned)out->originalBrushNumber >= (unsigned)brushesCount ) { Com_Error( ERR_DROP, "fog brushNumber out of range" ); } brush = brushes + out->originalBrushNumber; firstSide = LittleLong( brush->firstSide ); if ( (unsigned)firstSide > (unsigned)(sidesCount - 6) ) { Com_Error( ERR_DROP, "fog brush sideNumber out of range" ); } // brushes are always sorted with the axial sides first sideNum = firstSide + 0; planeNum = LittleLong( sides[ sideNum ].planeNum ); out->bounds[0][0] = -worldData.planes[ planeNum ].dist; sideNum = firstSide + 1; planeNum = LittleLong( sides[ sideNum ].planeNum ); out->bounds[1][0] = worldData.planes[ planeNum ].dist; sideNum = firstSide + 2; planeNum = LittleLong( sides[ sideNum ].planeNum ); out->bounds[0][1] = -worldData.planes[ planeNum ].dist; sideNum = firstSide + 3; planeNum = LittleLong( sides[ sideNum ].planeNum ); out->bounds[1][1] = worldData.planes[ planeNum ].dist; sideNum = firstSide + 4; planeNum = LittleLong( sides[ sideNum ].planeNum ); out->bounds[0][2] = -worldData.planes[ planeNum ].dist; sideNum = firstSide + 5; planeNum = LittleLong( sides[ sideNum ].planeNum ); out->bounds[1][2] = worldData.planes[ planeNum ].dist; } // get information from the shader for fog parameters shader = R_FindShader( fogs->shader, lightmaps, stylesDefault, qtrue ); assert(shader->fogParms); if (!shader->fogParms) {//bad shader!! out->parms.color[0] = 1.0f; out->parms.color[1] = 0.0f; out->parms.color[2] = 0.0f; out->parms.depthForOpaque = 250.0f; } else { out->parms = *shader->fogParms; } out->colorInt = ColorBytes4 ( out->parms.color[0], out->parms.color[1], out->parms.color[2], 1.0 ); d = out->parms.depthForOpaque < 1 ? 1 : out->parms.depthForOpaque; out->tcScale = 1.0f / ( d * 8 ); // set the gradient vector sideNum = LittleLong( fogs->visibleSide ); if ( sideNum == -1 ) { out->hasSurface = qfalse; } else { out->hasSurface = qtrue; planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum ); VectorSubtract( vec3_origin, worldData.planes[ planeNum ].normal, out->surface ); out->surface[3] = -worldData.planes[ planeNum ].dist; } out++; } if (!index) { // Initialise the last fog so we can use it with the LA Goggles // NOTE: We are might appear to be off the end of the array, but we allocated an extra memory slot above but [purposely] didn't // increment the total world numFogs to match our array size VectorSet(out->bounds[0], MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD); VectorSet(out->bounds[1], MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD); out->originalBrushNumber = -1; out->parms.color[0] = 0.0f; out->parms.color[1] = 0.0f; out->parms.color[2] = 0.0f; out->parms.depthForOpaque = 0.0f; out->colorInt = 0x00000000; out->tcScale = 0.0f; out->hasSurface = false; } }
/* ================= VM_LoadQVM Load a .qvm file ================= */ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc, qboolean unpure) { int dataLength; int i; char filename[MAX_QPATH]; union { vmHeader_t *h; void *v; } header; // load the image Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name ); Com_VPrintf( "Loading vm file %s...\n", filename ); //Com_VPrintf FS_ReadFileDir(filename, vm->searchPath, unpure, &header.v, qfalse); if ( !header.h ) { Com_Printf( "Failed.\n" ); VM_Free( vm ); Com_Printf( S_COLOR_YELLOW "Warning: Couldn't open VM file %s\n", filename ); return NULL; } // show where the qvm was loaded from if ( com_verbose->integer ) FS_Which(filename, vm->searchPath); if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) { Com_VPrintf( "...which has vmMagic VM_MAGIC_VER2\n" ); //Com_VPrintf // byte swap the header for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) { ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] ); } // validate if ( header.h->jtrgLength < 0 || header.h->bssLength < 0 || header.h->dataLength < 0 || header.h->litLength < 0 || header.h->codeLength <= 0 ) { VM_Free(vm); FS_FreeFile(header.v); Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename); return NULL; } } else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) { // byte swap the header // sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) { ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] ); } // validate if ( header.h->bssLength < 0 || header.h->dataLength < 0 || header.h->litLength < 0 || header.h->codeLength <= 0 ) { VM_Free(vm); FS_FreeFile(header.v); Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename); return NULL; } } else { VM_Free( vm ); FS_FreeFile(header.v); Com_Printf(S_COLOR_YELLOW "Warning: %s does not have a recognisable " "magic number in its header\n", filename); return NULL; } // round up to next power of 2 so all data operations can // be mask protected dataLength = header.h->dataLength + header.h->litLength + header.h->bssLength; for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) { } dataLength = 1 << i; if(alloc) { // allocate zero filled space for initialized and uninitialized data vm->dataBase = Hunk_Alloc(dataLength, h_high); vm->dataMask = dataLength - 1; } else { // clear the data, but make sure we're not clearing more than allocated if(vm->dataMask + 1 != dataLength) { VM_Free(vm); FS_FreeFile(header.v); Com_Printf(S_COLOR_YELLOW "Warning: Data region size of %s not matching after " "VM_Restart()\n", filename); return NULL; } Com_Memset(vm->dataBase, 0, dataLength); } // copy the intialized data Com_Memcpy( vm->dataBase, (byte *)header.h + header.h->dataOffset, header.h->dataLength + header.h->litLength ); // byte swap the longs for ( i = 0 ; i < header.h->dataLength ; i += 4 ) { *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) ); } if(header.h->vmMagic == VM_MAGIC_VER2) { int previousNumJumpTableTargets = vm->numJumpTableTargets; header.h->jtrgLength &= ~0x03; vm->numJumpTableTargets = header.h->jtrgLength >> 2; Com_VPrintf("Loading %d jump table targets\n", vm->numJumpTableTargets); if(alloc) { vm->jumpTableTargets = Hunk_Alloc(header.h->jtrgLength, h_high); } else { if(vm->numJumpTableTargets != previousNumJumpTableTargets) { VM_Free(vm); FS_FreeFile(header.v); Com_Printf(S_COLOR_YELLOW "Warning: Jump table size of %s not matching after " "VM_Restart()\n", filename); return NULL; } Com_Memset(vm->jumpTableTargets, 0, header.h->jtrgLength); } Com_Memcpy(vm->jumpTableTargets, (byte *) header.h + header.h->dataOffset + header.h->dataLength + header.h->litLength, header.h->jtrgLength); // byte swap the longs for ( i = 0 ; i < header.h->jtrgLength ; i += 4 ) { *(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) ); } }
static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeakerType) { FStrifeDialogueNode *node; Speech speech; char fullsound[16]; const PClass *type; int j; node = new FStrifeDialogueNode; lump->Read (&speech, sizeof(speech)); // Byte swap all the ints in the original data speech.SpeakerType = LittleLong(speech.SpeakerType); speech.DropType = LittleLong(speech.DropType); speech.Link = LittleLong(speech.Link); // Assign the first instance of a conversation as the default for its // actor, so newly spawned actors will use this conversation by default. type = GetStrifeType (speech.SpeakerType); node->SpeakerType = type; if ((signed)(speech.SpeakerType) >= 0 && prevSpeakerType != speech.SpeakerType) { if (type != NULL) { ClassRoots[type->TypeName] = StrifeDialogues.Size(); } DialogueRoots[speech.SpeakerType] = StrifeDialogues.Size(); prevSpeakerType = speech.SpeakerType; } // Convert the rest of the data to our own internal format. node->Dialogue = ncopystring (speech.Dialogue); // The speaker's portrait, if any. speech.Dialogue[0] = 0; //speech.Backdrop[8] = 0; node->Backdrop = TexMan.CheckForTexture (speech.Backdrop, FTexture::TEX_MiscPatch); // The speaker's voice for this node, if any. speech.Backdrop[0] = 0; //speech.Sound[8] = 0; mysnprintf (fullsound, countof(fullsound), "svox/%s", speech.Sound); node->SpeakerVoice = fullsound; // The speaker's name, if any. speech.Sound[0] = 0; //speech.Name[16] = 0; node->SpeakerName = ncopystring (speech.Name); // The item the speaker should drop when killed. node->DropType = GetStrifeType (speech.DropType); // Items you need to have to make the speaker use a different node. node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { node->ItemCheck[j].Item = GetStrifeType (speech.ItemCheck[j]); node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = speech.Link; node->Children = NULL; ParseReplies (&node->Children, &speech.Responses[0]); return node; }
/* =============== R_LoadSurfaces =============== */ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump, world_t &worldData, int index ) { dsurface_t *in; msurface_t *out; mapVert_t *dv; int *indexes; int count; int numFaces, numMeshes, numTriSurfs, numFlares; int i; numFaces = 0; numMeshes = 0; numTriSurfs = 0; numFlares = 0; in = (dsurface_t *)(fileBase + surfs->fileofs); if (surfs->filelen % sizeof(*in)) Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); count = surfs->filelen / sizeof(*in); dv = (mapVert_t *)(fileBase + verts->fileofs); if (verts->filelen % sizeof(*dv)) Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); indexes = (int *)(fileBase + indexLump->fileofs); if ( indexLump->filelen % sizeof(*indexes)) Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); out = (struct msurface_s *) Hunk_Alloc ( count * sizeof(*out), qtrue ); worldData.surfaces = out; worldData.numsurfaces = count; // new bit, the face code on our biggest map requires over 15,000 mallocs, which was no problem on the hunk, // bit hits the zone pretty bad (even the tagFree takes about 9 seconds for that many memblocks), // so special-case pre-alloc enough space for this data (the patches etc can stay as they are)... // int iFaceDataSizeRequired = 0; for ( i = 0 ; i < count ; i++, in++) { switch ( LittleLong( in->surfaceType ) ) { case MST_PLANAR: int sfaceSize = ( intptr_t ) &((srfSurfaceFace_t *)0)->points[LittleLong(in->numVerts)]; sfaceSize += sizeof( int ) * LittleLong(in->numIndexes); iFaceDataSizeRequired += sfaceSize; break; } } in -= count; // back it up, ready for loop-proper // since this ptr is to hunk data, I can pass it in and have it advanced without worrying about losing // the original alloc ptr... // byte *pFaceDataBuffer = (byte *)Hunk_Alloc( iFaceDataSizeRequired, qtrue ); // now do regular loop... // for ( i = 0 ; i < count ; i++, in++, out++ ) { switch ( LittleLong( in->surfaceType ) ) { case MST_PATCH: ParseMesh ( in, dv, out, worldData, index ); numMeshes++; break; case MST_TRIANGLE_SOUP: ParseTriSurf( in, dv, out, indexes, worldData, index ); numTriSurfs++; break; case MST_PLANAR: ParseFace( in, dv, out, indexes, pFaceDataBuffer, worldData, index ); numFaces++; break; case MST_FLARE: ParseFlare( in, dv, out, indexes, worldData, index ); numFlares++; break; default: Com_Error( ERR_DROP, "Bad surfaceType" ); } } ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", numFaces, numMeshes, numTriSurfs, numFlares ); }
/* ==================== RE_RegisterModel Loads in a model for the given name Zero will be returned if the model fails to load. An entry will be retained for failed models as an optimization to prevent disk rescanning if they are asked for again. ==================== */ qhandle_t RE_RegisterModel(const char *name) { model_t *mod; byte *buffer; int bufferLen = 0; int lod; int ident; qboolean loaded; qhandle_t hModel; int numLoaded; if (!name || !name[0]) { ri.Printf(PRINT_DEVELOPER, "RE_RegisterModel: NULL name\n"); return 0; } else { ri.Printf(PRINT_DEVELOPER, "RE_RegisterModel model: %s\n", name); } if (strlen(name) >= MAX_QPATH) { Com_Printf("Model name exceeds MAX_QPATH\n"); return 0; } // search the currently loaded models for (hModel = 1; hModel < tr.numModels; hModel++) { mod = tr.models[hModel]; if (!strcmp(mod->name, name)) { if (mod->type == MOD_BAD) { return 0; } return hModel; } } // allocate a new model_t if ((mod = R_AllocModel()) == NULL) { ri.Printf(PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); return 0; } // only set the name after the model has been successfully loaded Q_strncpyz(mod->name, name, sizeof(mod->name)); // make sure the render thread is stopped R_SyncRenderThread(); mod->numLods = 0; // load the files numLoaded = 0; if (strstr(name, ".mds") || strstr(name, ".mdm") || strstr(name, ".mdx") || strstr(name, ".md5mesh") || strstr(name, ".psk")) { // try loading skeletal file loaded = qfalse; bufferLen = ri.FS_ReadFile(name, (void **)&buffer); if (buffer) { loadmodel = mod; ident = LittleLong(*(unsigned *)buffer); #if 0 if (ident == MDS_IDENT) { loaded = R_LoadMDS(mod, buffer, name); } else #endif if (ident == MDM_IDENT) { loaded = R_LoadMDM(mod, buffer, name); } else if (ident == MDX_IDENT) { loaded = R_LoadMDX(mod, buffer, name); } #if defined(USE_REFENTITY_ANIMATIONSYSTEM) if (!Q_stricmpn((const char *)buffer, "MD5Version", 10)) { loaded = R_LoadMD5(mod, buffer, bufferLen, name); } else if (!Q_stricmpn((const char *)buffer, PSK_IDENTSTRING, PSK_IDENTLEN)) { loaded = R_LoadPSK(mod, buffer, bufferLen, name); } #endif ri.FS_FreeFile(buffer); } if (loaded) { // make sure the VBO glState entries are save R_BindNullVBO(); R_BindNullIBO(); return mod->index; } } for (lod = MD3_MAX_LODS - 1; lod >= 0; lod--) { char filename[1024]; buffer = NULL; strcpy(filename, name); if (lod != 0) { char namebuf[80]; if (strrchr(filename, '.')) { *strrchr(filename, '.') = 0; } sprintf(namebuf, "_%d.md3", lod); strcat(filename, namebuf); } filename[strlen(filename) - 1] = 'c'; // try MDC first if (ri.FS_FOpenFileRead(filename, NULL, qfalse)) { ri.FS_ReadFile(filename, (void **)&buffer); } if (!buffer) { filename[strlen(filename) - 1] = '3'; // try MD3 second if (ri.FS_FOpenFileRead(filename, NULL, qfalse)) { ri.FS_ReadFile(filename, (void **)&buffer); } if (!buffer) { continue; } } loadmodel = mod; ident = LittleLong(*(unsigned *)buffer); if (ident != MD3_IDENT && ident != MDC_IDENT) { ri.Printf(PRINT_WARNING, "RE_RegisterModel: unknown fileid for %s\n", name); ri.FS_FreeFile(buffer); goto fail; } if (ident == MD3_IDENT) { loaded = R_LoadMD3(mod, lod, buffer, bufferLen, name); } else if (ident == MDC_IDENT) { loaded = R_LoadMDC(mod, lod, buffer, bufferLen, name); } ri.FS_FreeFile(buffer); if (!loaded) { if (lod == 0) { goto fail; } else { break; } } else { // make sure the VBO glState entries are save R_BindNullVBO(); R_BindNullIBO(); mod->numLods++; numLoaded++; // if we have a valid model and are biased // so that we won't see any higher detail ones, // stop loading them // if ( lod <= r_lodbias->integer ) { // break; // } } } // make sure the VBO glState entries are save R_BindNullVBO(); R_BindNullIBO(); if (numLoaded) { // duplicate into higher lod spots that weren't // loaded, in case the user changes r_lodbias on the fly for (lod--; lod >= 0; lod--) { mod->numLods++; mod->mdv[lod] = mod->mdv[lod + 1]; } return mod->index; } #ifdef _DEBUG else { ri.Printf(PRINT_WARNING, "couldn't load '%s'\n", name); } #endif fail: // we still keep the model_t around, so if the model name is asked for // again, we won't bother scanning the filesystem mod->type = MOD_BAD; // make sure the VBO glState entries are save R_BindNullVBO(); R_BindNullIBO(); return 0; }
/* ================= R_LoadMDX ================= */ 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 = (mdxHeader_t *)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; }
/* * record <demoname> * Begins recording a demo from the current position */ void CL_Record_f(void) { char name[MAX_OSPATH]; byte buf_data[MAX_MSGLEN]; sizebuf_t buf; int i; int len; entity_state_t *ent; entity_state_t nullstate; if (Cmd_Argc() != 2) { Com_Printf("record <demoname>\n"); return; } if (cls.demorecording) { Com_Printf("Already recording.\n"); return; } if (cls.state != ca_active) { Com_Printf("You must be in a level to record.\n"); return; } Com_sprintf(name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1)); Com_Printf("recording to %s.\n", name); FS_CreatePath(name); cls.demofile = fopen(name, "wb"); if (!cls.demofile) { Com_Printf("ERROR: couldn't open.\n"); return; } cls.demorecording = true; /* don't start saving messages until a non-delta compressed message is received */ cls.demowaiting = true; /* write out messages to hold the startup information */ SZ_Init(&buf, buf_data, sizeof(buf_data)); /* send the serverdata */ MSG_WriteByte(&buf, svc_serverdata); MSG_WriteLong(&buf, PROTOCOL_VERSION); MSG_WriteLong(&buf, 0x10000 + cl.servercount); MSG_WriteByte(&buf, 1); /* demos are always attract loops */ MSG_WriteString(&buf, cl.gamedir); MSG_WriteShort(&buf, cl.playernum); MSG_WriteString(&buf, cl.configstrings[CS_NAME]); /* configstrings */ for (i = 0; i < MAX_CONFIGSTRINGS; i++) { if (cl.configstrings[i][0]) { if (buf.cursize + strlen(cl.configstrings[i]) + 32 > buf.maxsize) { len = LittleLong(buf.cursize); fwrite(&len, 4, 1, cls.demofile); fwrite(buf.data, buf.cursize, 1, cls.demofile); buf.cursize = 0; } MSG_WriteByte(&buf, svc_configstring); MSG_WriteShort(&buf, i); MSG_WriteString(&buf, cl.configstrings[i]); } } /* baselines */ memset(&nullstate, 0, sizeof(nullstate)); for (i = 0; i < MAX_EDICTS; i++) { ent = &cl_entities[i].baseline; if (!ent->modelindex) { continue; } if (buf.cursize + 64 > buf.maxsize) { len = LittleLong(buf.cursize); fwrite(&len, 4, 1, cls.demofile); fwrite(buf.data, buf.cursize, 1, cls.demofile); buf.cursize = 0; } MSG_WriteByte(&buf, svc_spawnbaseline); MSG_WriteDeltaEntity(&nullstate, &cl_entities[i].baseline, &buf, true, true); } MSG_WriteByte(&buf, svc_stufftext); MSG_WriteString(&buf, "precache\n"); /* write it to the demo file */ len = LittleLong(buf.cursize); fwrite(&len, 4, 1, cls.demofile); fwrite(buf.data, buf.cursize, 1, cls.demofile); }
/* ================= 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\n", 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; }
/* * NET_TCP_GetPacket */ static int NET_TCP_GetPacket( const socket_t *socket, netadr_t *address, msg_t *message ) { int ret; uint8_t buffer[MAX_PACKETLEN + 4]; int len; assert( socket && socket->open && socket->connected && socket->type == SOCKET_TCP ); assert( address ); assert( message ); // peek the message to see if the whole packet is ready ret = recv( socket->handle, (char*)buffer, sizeof( buffer ), MSG_PEEK ); if( ret == SOCKET_ERROR ) { NET_SetErrorStringFromLastError( "recv" ); if( Sys_NET_GetLastError() == NET_ERR_WOULDBLOCK ) // would block return 0; return -1; } if( ret < 4 ) // the length information is not yet received return 0; memcpy( &len, buffer, 4 ); len = LittleLong( len ); if( len > MAX_PACKETLEN || len > (int)message->maxsize ) { NET_SetErrorString( "Oversized packet" ); return -1; } if( ret < len + 4 ) // the whole packet is not yet ready return 0; // ok we have the whole packet ready, get it // read the 4 byte header ret = NET_TCP_Get( socket, NULL, buffer, 4 ); if( ret == -1 ) return -1; if( ret != 4 ) { NET_SetErrorString( "Couldn't read the whole packet" ); return -1; } ret = NET_TCP_Get( socket, NULL, message->data, len ); if( ret == SOCKET_ERROR ) return -1; if( ret != (int)len ) { NET_SetErrorString( "Couldn't read the whole packet" ); return -1; } *address = socket->remoteAddress; message->readcount = 0; message->cursize = ret; return true; }
/* =============== 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; 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 ); }
static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeakerType) { FStrifeDialogueNode *node; TeaserSpeech speech; char fullsound[16]; const PClass *type; int j; node = new FStrifeDialogueNode; lump->Read (&speech, sizeof(speech)); // Byte swap all the ints in the original data speech.SpeakerType = LittleLong(speech.SpeakerType); speech.DropType = LittleLong(speech.DropType); // Assign the first instance of a conversation as the default for its // actor, so newly spawned actors will use this conversation by default. type = GetStrifeType (speech.SpeakerType); node->SpeakerType = type; if ((signed)speech.SpeakerType >= 0 && prevSpeakerType != speech.SpeakerType) { if (type != NULL) { ClassRoots[type->TypeName] = StrifeDialogues.Size(); } DialogueRoots[speech.SpeakerType] = StrifeDialogues.Size(); prevSpeakerType = speech.SpeakerType; } // Convert the rest of the data to our own internal format. node->Dialogue = ncopystring (speech.Dialogue); // The Teaser version doesn't have portraits. node->Backdrop.SetInvalid(); // The speaker's voice for this node, if any. if (speech.VoiceNumber != 0) { mysnprintf (fullsound, countof(fullsound), "svox/voc%u", speech.VoiceNumber); node->SpeakerVoice = fullsound; } else { node->SpeakerVoice = 0; } // The speaker's name, if any. speech.Dialogue[0] = 0; //speech.Name[16] = 0; node->SpeakerName = ncopystring (speech.Name); // The item the speaker should drop when killed. node->DropType = GetStrifeType (speech.DropType); // Items you need to have to make the speaker use a different node. node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { node->ItemCheck[j].Item = NULL; node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = 0; node->Children = NULL; ParseReplies (&node->Children, &speech.Responses[0]); return node; }
/* =============== 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 void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) { FStrifeDialogueReply *reply; int j, k; // Byte swap first. for (j = 0; j < 5; ++j) { responses[j].GiveType = LittleLong(responses[j].GiveType); responses[j].Link = LittleLong(responses[j].Link); responses[j].Log = LittleLong(responses[j].Log); for (k = 0; k < 3; ++k) { responses[j].Item[k] = LittleLong(responses[j].Item[k]); responses[j].Count[k] = LittleLong(responses[j].Count[k]); } } for (j = 0; j < 5; ++j) { Response *rsp = &responses[j]; // If the reply has no text and goes nowhere, then it doesn't // need to be remembered. if (rsp->Reply[0] == 0 && rsp->Link == 0) { continue; } reply = new FStrifeDialogueReply; // The next node to use when this reply is chosen. reply->NextNode = rsp->Link; // The message to record in the log for this reply. reply->LogNumber = rsp->Log; reply->LogString = NULL; // The item to receive when this reply is used. reply->GiveType = GetStrifeType (rsp->GiveType); reply->ActionSpecial = 0; // Do you need anything special for this reply to succeed? reply->ItemCheck.Resize(3); for (k = 0; k < 3; ++k) { reply->ItemCheck[k].Item = GetStrifeType (rsp->Item[k]); reply->ItemCheck[k].Amount = rsp->Count[k]; } // If the first item check has a positive amount required, then // add that to the reply string. Otherwise, use the reply as-is. reply->Reply = copystring (rsp->Reply); reply->NeedsGold = (rsp->Count[0] > 0); // QuickYes messages are shown when you meet the item checks. // QuickNo messages are shown when you don't. if (rsp->Yes[0] == '_' && rsp->Yes[1] == 0) { reply->QuickYes = NULL; } else { reply->QuickYes = ncopystring (rsp->Yes); } if (reply->ItemCheck[0].Item != 0) { reply->QuickNo = ncopystring (rsp->No); } else { reply->QuickNo = NULL; } reply->Next = *replyptr; *replyptr = reply; replyptr = &reply->Next; } }
/* ================= R_LoadNodesAndLeafs ================= */ static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump, world_t &worldData) { int i, j, p; dnode_t *in; dleaf_t *inLeaf; mnode_t *out; int numNodes, numLeafs; in = (dnode_t *)(fileBase + nodeLump->fileofs); if (nodeLump->filelen % sizeof(dnode_t) || leafLump->filelen % sizeof(dleaf_t) ) { Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name); } numNodes = nodeLump->filelen / sizeof(dnode_t); numLeafs = leafLump->filelen / sizeof(dleaf_t); out = (struct mnode_s *) Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), qtrue ); worldData.nodes = out; worldData.numnodes = numNodes + numLeafs; worldData.numDecisionNodes = numNodes; // load nodes for ( i=0 ; i<numNodes; i++, in++, out++) { for (j=0 ; j<3 ; j++) { out->mins[j] = LittleLong (in->mins[j]); out->maxs[j] = LittleLong (in->maxs[j]); } p = LittleLong(in->planeNum); out->plane = worldData.planes + p; out->contents = CONTENTS_NODE; // differentiate from leafs for (j=0 ; j<2 ; j++) { p = LittleLong (in->children[j]); if (p >= 0) out->children[j] = worldData.nodes + p; else out->children[j] = worldData.nodes + numNodes + (-1 - p); } } // load leafs inLeaf = (dleaf_t *)(fileBase + leafLump->fileofs); for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++) { for (j=0 ; j<3 ; j++) { out->mins[j] = LittleLong (inLeaf->mins[j]); out->maxs[j] = LittleLong (inLeaf->maxs[j]); } out->cluster = LittleLong(inLeaf->cluster); out->area = LittleLong(inLeaf->area); if ( out->cluster >= worldData.numClusters ) { worldData.numClusters = out->cluster + 1; } out->firstmarksurface = worldData.marksurfaces + LittleLong(inLeaf->firstLeafSurface); out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); } // chain decendants R_SetParent (worldData.nodes, NULL); }
/* ============== Cmd_Mip $mip filename x y width height <OPTIONS> must be multiples of sixteen SURF_WINDOW ============== */ void Cmd_Mip (void) { int x,y,xl,yl,xh,yh,w,h; byte *screen_p, *source; int linedelta; miptex_t *qtex; int miplevel, mipstep; int xx, yy, pix; int count; int flags, value, contents; mipparm_t *mp; char lumpname[64]; byte *lump_p; char filename[1024]; char animname[64]; GetToken (false); strcpy (lumpname, token); GetToken (false); xl = atoi (token); GetToken (false); yl = atoi (token); GetToken (false); w = atoi (token); GetToken (false); h = atoi (token); if ( (w & 15) || (h & 15) ) Error ("line %i: miptex sizes must be multiples of 16", scriptline); flags = 0; contents = 0; value = 0; animname[0] = 0; // get optional flags and values while (TokenAvailable ()) { GetToken (false); for (mp=mipparms ; mp->name ; mp++) { if (!strcmp(mp->name, token)) { switch (mp->type) { case pt_animvalue: GetToken (false); // specify the next animation frame strcpy (animname, token); break; case pt_flags: flags |= mp->flags; break; case pt_contents: contents |= mp->flags; break; case pt_flagvalue: flags |= mp->flags; GetToken (false); // specify the light value value = atoi(token); break; } break; } } if (!mp->name) Error ("line %i: unknown parm %s", scriptline, token); } sprintf (filename, "%stextures/%s/%s.wal", gamedir, mip_prefix, lumpname); if (g_release) return; // textures are only released by $maps xh = xl+w; yh = yl+h; qtex = malloc (sizeof(miptex_t) + w*h*2); memset (qtex, 0, sizeof(miptex_t)); qtex->width = LittleLong(w); qtex->height = LittleLong(h); qtex->flags = LittleLong(flags); qtex->contents = LittleLong(contents); qtex->value = LittleLong(value); sprintf (qtex->name, "%s/%s", mip_prefix, lumpname); if (animname[0]) sprintf (qtex->animname, "%s/%s", mip_prefix, animname); lump_p = (byte *)(&qtex->value+1); screen_p = byteimage + yl*byteimagewidth + xl; linedelta = byteimagewidth - w; source = lump_p; qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex); for (y=yl ; y<yh ; y++) { for (x=xl ; x<xh ; x++) { pix = *screen_p++; if (pix == 255) pix = 1; // should never happen *lump_p++ = pix; } screen_p += linedelta; } // // subsample for greater mip levels // d_red = d_green = d_blue = 0; // no distortion yet for (miplevel = 1 ; miplevel<4 ; miplevel++) { qtex->offsets[miplevel] = LittleLong(lump_p - (byte *)qtex); mipstep = 1<<miplevel; for (y=0 ; y<h ; y+=mipstep) { for (x = 0 ; x<w ; x+= mipstep) { count = 0; for (yy=0 ; yy<mipstep ; yy++) for (xx=0 ; xx<mipstep ; xx++) { pixdata[count] = source[ (y+yy)*w + x + xx ]; count++; } *lump_p++ = AveragePixels (count); } } } // // dword align the size // while ((int)lump_p&3) *lump_p++ = 0; // // write it out // printf ("writing %s\n", filename); SaveFile (filename, (byte *)qtex, lump_p - (byte *)qtex); free (qtex); }
void R_LoadBMP( const char *name, byte **pic, int *width, int *height ) { int columns, rows; unsigned numPixels; byte *pixbuf; int row, column; byte *buf_p; byte *end; union { byte *b; void *v; } buffer; int length; BMPHeader_t bmpHeader; byte *bmpRGBA; *pic = NULL; if(width) *width = 0; if(height) *height = 0; // // load the file // length = ri.FS_ReadFile( ( char * ) name, &buffer.v); if (!buffer.b || length < 0) { return; } if (length < 54) { ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name ); } buf_p = buffer.b; end = buffer.b + length; bmpHeader.id[0] = *buf_p++; bmpHeader.id[1] = *buf_p++; bmpHeader.fileSize = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.width = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.height = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.planes = LittleShort( * ( short * ) buf_p ); buf_p += 2; bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p ); buf_p += 2; bmpHeader.compression = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.hRes = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.vRes = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.colors = LittleLong( * ( int * ) buf_p ); buf_p += 4; bmpHeader.importantColors = LittleLong( * ( int * ) buf_p ); buf_p += 4; if ( bmpHeader.bitsPerPixel == 8 ) { if (buf_p + sizeof(bmpHeader.palette) > end) ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name ); Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); buf_p += sizeof(bmpHeader.palette); } if (buffer.b + bmpHeader.bitmapDataOffset > end) { ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name ); } buf_p = buffer.b + bmpHeader.bitmapDataOffset; if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) { ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); } if ( bmpHeader.fileSize != length ) { ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name ); } if ( bmpHeader.compression != 0 ) { ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); } if ( bmpHeader.bitsPerPixel < 8 ) { ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); } switch ( bmpHeader.bitsPerPixel ) { case 8: case 16: case 24: case 32: break; default: ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name ); break; } columns = bmpHeader.width; rows = bmpHeader.height; if ( rows < 0 ) rows = -rows; numPixels = columns * rows; if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF || ((numPixels * 4) / columns) / 4 != rows) { ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name); } if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end) { ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name); } if ( width ) *width = columns; if ( height ) *height = rows; bmpRGBA = ri.Malloc( numPixels * 4 ); *pic = bmpRGBA; for ( row = rows-1; row >= 0; row-- ) { pixbuf = bmpRGBA + row*columns*4; for ( column = 0; column < columns; column++ ) { unsigned char red, green, blue, alpha; int palIndex; unsigned short shortPixel; switch ( bmpHeader.bitsPerPixel ) { case 8: palIndex = *buf_p++; *pixbuf++ = bmpHeader.palette[palIndex][2]; *pixbuf++ = bmpHeader.palette[palIndex][1]; *pixbuf++ = bmpHeader.palette[palIndex][0]; *pixbuf++ = 0xff; break; case 16: shortPixel = * ( unsigned short * ) pixbuf; pixbuf += 2; *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7; *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2; *pixbuf++ = ( shortPixel & ( 31 ) ) << 3; *pixbuf++ = 0xff; break; case 24: blue = *buf_p++; green = *buf_p++; red = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *buf_p++; green = *buf_p++; red = *buf_p++; alpha = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alpha; break; } } } ri.FS_FreeFile( buffer.v ); }
/* ================= Mod_LoadAliasModel ================= */ qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length) { dmd2header_t header; dmd2frame_t *src_frame; //dmd2trivertx_t *src_vert; dmd2triangle_t *src_tri; dmd2stvert_t *src_st; maliasframe_t *dst_frame; //maliasvert_t *dst_vert; maliastri_t *dst_tri; maliasst_t *dst_st; char skinname[MAX_QPATH]; char *src_skin; int i, j; qerror_t ret; if (length < sizeof(header)) { return Q_ERR_FILE_TOO_SMALL; } // byte swap the header header = *(dmd2header_t *)rawdata; for (i = 0; i < sizeof(header) / 4; i++) { ((uint32_t *)&header)[i] = LittleLong(((uint32_t *)&header)[i]); } // validate the header ret = MOD_ValidateMD2(&header, length); if (ret) { if (ret == Q_ERR_TOO_FEW) { // empty models draw nothing model->type = MOD_EMPTY; return Q_ERR_SUCCESS; } return ret; } Hunk_Begin(&model->hunk, 0x400000); model->type = MOD_ALIAS; // load triangle indices model->tris = MOD_Malloc(header.num_tris * sizeof(maliastri_t)); model->numtris = header.num_tris; src_tri = (dmd2triangle_t *)((byte *)rawdata + header.ofs_tris); dst_tri = model->tris; for (i = 0; i < header.num_tris; i++, src_tri++, dst_tri++) { for (j = 0; j < 3; j++) { unsigned idx_xyz = LittleShort(src_tri->index_xyz[j]); unsigned idx_st = LittleShort(src_tri->index_st[j]); if (idx_xyz >= header.num_xyz || idx_st >= header.num_st) { ret = Q_ERR_BAD_INDEX; goto fail; } dst_tri->index_xyz[j] = idx_xyz; dst_tri->index_st[j] = idx_st; } } // load base s and t vertices model->sts = MOD_Malloc(header.num_st * sizeof(maliasst_t)); model->numsts = header.num_st; src_st = (dmd2stvert_t *)((byte *)rawdata + header.ofs_st); dst_st = model->sts; for (i = 0; i < header.num_st; i++, src_st++, dst_st++) { dst_st->s = (int16_t)LittleShort(src_st->s); dst_st->t = (int16_t)LittleShort(src_st->t); } // load the frames model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t)); model->numframes = header.num_frames; model->numverts = header.num_xyz; src_frame = (dmd2frame_t *)((byte *)rawdata + header.ofs_frames); dst_frame = model->frames; for (i = 0; i < header.num_frames; i++, dst_frame++) { for (j = 0; j < 3; j++) { dst_frame->scale[j] = LittleFloat(src_frame->scale[j]); dst_frame->translate[j] = LittleFloat(src_frame->translate[j]); } // verts are all 8 bit, so no swapping needed dst_frame->verts = MOD_Malloc(header.num_xyz * sizeof(maliasvert_t)); // TODO: check normal indices memcpy(dst_frame->verts, src_frame->verts, header.num_xyz * sizeof(maliasvert_t)); src_frame = (dmd2frame_t *)((byte *)src_frame + header.framesize); } // register all skins src_skin = (char *)rawdata + header.ofs_skins; for (i = 0; i < header.num_skins; i++) { if (!Q_memccpy(skinname, src_skin, 0, sizeof(skinname))) { ret = Q_ERR_STRING_TRUNCATED; goto fail; } FS_NormalizePath(skinname, skinname); model->skins[i] = IMG_Find(skinname, IT_SKIN); src_skin += MD2_MAX_SKINNAME; } model->numskins = header.num_skins; Hunk_End(&model->hunk); return Q_ERR_SUCCESS; fail: Hunk_Free(&model->hunk); return ret; }
/* ================= Netchan_Process Returns qfalse if the message should not be processed due to being out of order or a fragment. Msg must be large enough to hold MAX_MSGLEN, because if this is the final fragment of a multi-part message, the entire thing will be copied out. ================= */ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { int sequence; int qport; int fragmentStart, fragmentLength; qboolean fragmented; // XOR unscramble all data in the packet after the header // Netchan_UnScramblePacket( msg ); // get sequence numbers MSG_BeginReadingOOB( msg ); sequence = MSG_ReadLong( msg ); // check for fragment information if ( sequence & FRAGMENT_BIT ) { sequence &= ~FRAGMENT_BIT; fragmented = qtrue; } else { fragmented = qfalse; } // read the qport if we are a server if ( chan->sock == NS_SERVER ) { qport = MSG_ReadShort( msg ); } // read the fragment information if ( fragmented ) { fragmentStart = MSG_ReadShort( msg ); fragmentLength = MSG_ReadShort( msg ); } else { fragmentStart = 0; // stop warning message fragmentLength = 0; } if ( showpackets->integer ) { if ( fragmented ) { Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence , fragmentStart, fragmentLength ); } else { Com_Printf( "%s recv %4i : s=%i\n" , netsrcString[ chan->sock ] , msg->cursize , sequence ); } } // // discard out of order or duplicated packets // if ( sequence <= chan->incomingSequence ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Out of order packet %i at %i\n" , NET_AdrToString( chan->remoteAddress ) , sequence , chan->incomingSequence ); } return qfalse; } // // dropped packets don't keep the message from being used // chan->dropped = sequence - (chan->incomingSequence+1); if ( chan->dropped > 0 ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Dropped %i packets at %i\n" , NET_AdrToString( chan->remoteAddress ) , chan->dropped , sequence ); } } // // if this is the final framgent of a reliable message, // bump incoming_reliable_sequence // if ( fragmented ) { // TTimo // make sure we add the fragments in correct order // either a packet was dropped, or we received this one too soon // we don't reconstruct the fragments. we will wait till this fragment gets to us again // (NOTE: we could probably try to rebuild by out of order chunks if needed) if ( sequence != chan->fragmentSequence ) { chan->fragmentSequence = sequence; chan->fragmentLength = 0; } // if we missed a fragment, dump the message if ( fragmentStart != chan->fragmentLength ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf( "%s:Dropped a message fragment\n" , NET_AdrToString( chan->remoteAddress ) , sequence); } // we can still keep the part that we have so far, // so we don't need to clear chan->fragmentLength return qfalse; } // copy the fragment to the fragment buffer if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize || chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) { if ( showdrop->integer || showpackets->integer ) { Com_Printf ("%s:illegal fragment length\n" , NET_AdrToString (chan->remoteAddress ) ); } return qfalse; } Com_Memcpy( chan->fragmentBuffer + chan->fragmentLength, msg->data + msg->readcount, fragmentLength ); chan->fragmentLength += fragmentLength; // if this wasn't the last fragment, don't process anything if ( fragmentLength == FRAGMENT_SIZE ) { return qfalse; } if ( chan->fragmentLength > msg->maxsize ) { Com_Printf( "%s:fragmentLength %i > msg->maxsize\n" , NET_AdrToString (chan->remoteAddress ), chan->fragmentLength ); return qfalse; } // copy the full message over the partial fragment // make sure the sequence number is still there *(int *)msg->data = LittleLong( sequence ); Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); msg->cursize = chan->fragmentLength + 4; chan->fragmentLength = 0; msg->readcount = 4; // past the sequence number msg->bit = 32; // past the sequence number // TTimo // clients were not acking fragmented messages chan->incomingSequence = sequence; return qtrue; } // // the message can now be read from the current message pointer // chan->incomingSequence = sequence; return qtrue; }
bspFile_t *BSP_Load( const char *name ) { union { int *i; void *v; } buf; int i; int length; bspFile_t *bspFile = NULL; int freeSlot = -1; #ifndef BSPC if ( !name || !name[0] ) { Com_Error( ERR_DROP, "BSP_Load: NULL name" ); } #endif // check if already loaded for ( i = 0; i < MAX_BSP_FILES; i++ ) { if ( !bsp_loadedFiles[i] ) { if ( freeSlot == -1 ) { freeSlot = i; } continue; } if ( !Q_stricmp( bsp_loadedFiles[i]->name, name ) ) { bsp_loadedFiles[i]->references++; return bsp_loadedFiles[i]; } } if ( freeSlot == -1 ) { Com_Error( ERR_DROP, "No free slot to load BSP '%s'", name ); } // // load the file // #ifndef BSPC length = FS_ReadFile( name, &buf.v ); #else length = LoadQuakeFile((quakefile_t *) name, &buf.v); #endif if ( !buf.i ) { // File not found. return NULL; } // // check formats // for ( i = 0; i < numBspFormats; i++ ) { bspFile = bspFormats[i]->loadFunction( bspFormats[i], name, buf.v, length ); if ( bspFile ) { break; } } if ( i == numBspFormats ) { int ident = LittleLong( buf.i[0] ); int version = LittleLong( buf.i[1] ); Com_Error( ERR_DROP, "Unsupported BSP %s: ident %c%c%c%c, version %d", name, ident & 0xff, ( ident >> 8 ) & 0xff, ( ident >> 16 ) & 0xff, ( ident >> 24 ) & 0xff, version ); }
//--------------------------------------------------------------------------- // CROFFSystem::InitROFF2 // Handles stuffing the roff data in the CROFF object for version 2 // // INPUTS: // pass in the file data and the object to stuff the data into. // // RETURN: // returns initialization success or failure //--------------------------------------------------------------------------- qboolean CROFFSystem::InitROFF2( unsigned char *data, CROFF *obj ) { int i; TROFF2Header *hdr = (TROFF2Header *)data; obj->mROFFEntries = LittleLong(hdr->mCount); obj->mMoveRotateList = new TROFF2Entry[LittleLong(hdr->mCount)]; obj->mFrameTime = LittleLong(hdr->mFrameRate); obj->mLerp = 1000 / LittleLong(hdr->mFrameRate); obj->mNumNoteTracks = LittleLong(hdr->mNumNotes); if ( obj->mMoveRotateList != 0 ) { // Step past the header to get to the goods TROFF2Entry *roff_data = ( TROFF2Entry *)&hdr[1]; // Copy all of the goods into our ROFF cache for ( i = 0; i < LittleLong(hdr->mCount); i++ ) { #ifdef Q3_BIG_ENDIAN obj->mMoveRotateList[i].mOriginOffset[0] = LittleFloat(roff_data[i].mOriginOffset[0]); obj->mMoveRotateList[i].mOriginOffset[1] = LittleFloat(roff_data[i].mOriginOffset[1]); obj->mMoveRotateList[i].mOriginOffset[2] = LittleFloat(roff_data[i].mOriginOffset[2]); obj->mMoveRotateList[i].mRotateOffset[0] = LittleFloat(roff_data[i].mRotateOffset[0]); obj->mMoveRotateList[i].mRotateOffset[1] = LittleFloat(roff_data[i].mRotateOffset[1]); obj->mMoveRotateList[i].mRotateOffset[2] = LittleFloat(roff_data[i].mRotateOffset[2]); #else VectorCopy( roff_data[i].mOriginOffset, obj->mMoveRotateList[i].mOriginOffset ); VectorCopy( roff_data[i].mRotateOffset, obj->mMoveRotateList[i].mRotateOffset ); #endif obj->mMoveRotateList[i].mStartNote = LittleLong(roff_data[i].mStartNote); obj->mMoveRotateList[i].mNumNotes = LittleLong(roff_data[i].mNumNotes); } FixBadAngles(obj); if (obj->mNumNoteTracks) { size_t size = 0; char *ptr, *start; ptr = start = (char *)&roff_data[i]; for(i=0;i<obj->mNumNoteTracks;i++) { size += strlen(ptr) + 1; ptr += strlen(ptr) + 1; } obj->mNoteTrackIndexes = new char *[obj->mNumNoteTracks]; ptr = obj->mNoteTrackIndexes[0] = new char[size]; memcpy(obj->mNoteTrackIndexes[0], start, size); for(i=1;i<obj->mNumNoteTracks;i++) { ptr += strlen(ptr) + 1; obj->mNoteTrackIndexes[i] = ptr; } } } else { return qfalse; } return qtrue; }
// ===================================================================================== // TEX_InitFromWad // ===================================================================================== bool TEX_InitFromWad() { int i, j; wadinfo_t wadinfo; char szTmpWad[1024]; // arbitrary, but needs to be large. char* pszWadFile; const char* pszWadroot; wadpath_t* currentwad; Log("\n"); // looks cleaner szTmpWad[0] = 0; pszWadroot = getenv("WADROOT"); #ifdef HLCSG_AUTOWAD autowad_UpdateUsedWads(); #endif // for eachwadpath for (i = 0; i < g_iNumWadPaths; i++) { FILE* texfile; // temporary used in this loop bool bExcludeThisWad = false; currentwad = g_pWadPaths[i]; pszWadFile = currentwad->path; #ifdef HLCSG_AUTOWAD #ifdef _DEBUG Log("[dbg] Attempting to parse wad: '%s'\n", pszWadFile); #endif if (g_bWadAutoDetect && !currentwad->usedtextures) continue; #ifdef _DEBUG Log("[dbg] Parsing wad\n"); #endif #endif texfiles[nTexFiles] = fopen(pszWadFile, "rb"); #ifdef SYSTEM_WIN32 if (!texfiles[nTexFiles]) { // cant find it, maybe this wad file has a hard code drive if (pszWadFile[1] == ':') { pszWadFile += 2; // skip past the drive texfiles[nTexFiles] = fopen(pszWadFile, "rb"); } } #endif if (!texfiles[nTexFiles] && pszWadroot) { char szTmp[_MAX_PATH]; char szFile[_MAX_PATH]; char szSubdir[_MAX_PATH]; ExtractFile(pszWadFile, szFile); ExtractFilePath(pszWadFile, szTmp); ExtractFile(szTmp, szSubdir); // szSubdir will have a trailing separator safe_snprintf(szTmp, _MAX_PATH, "%s" SYSTEM_SLASH_STR "%s%s", pszWadroot, szSubdir, szFile); texfiles[nTexFiles] = fopen(szTmp, "rb"); #ifdef SYSTEM_POSIX if (!texfiles[nTexFiles]) { // if we cant find it, Convert to lower case and try again strlwr(szTmp); texfiles[nTexFiles] = fopen(szTmp, "rb"); } #endif } if (!texfiles[nTexFiles]) { // still cant find it, error out Fatal(assume_COULD_NOT_FIND_WAD, "Could not open wad file %s", pszWadFile); continue; } // look and see if we're supposed to include the textures from this WAD in the bsp. WadInclude_i it; for (it = g_WadInclude.begin(); it != g_WadInclude.end(); it++) { if (stristr(pszWadFile, it->c_str())) { Log("Including Wadfile: %s\n", pszWadFile); bExcludeThisWad = true; // wadincluding this one s_WadIncludeMap[nTexFiles] = true; break; } } if (!bExcludeThisWad) { Log("Using Wadfile: %s\n", pszWadFile); safe_snprintf(szTmpWad, 1024, "%s%s;", szTmpWad, pszWadFile); } // temp assignment to make things cleaner: texfile = texfiles[nTexFiles]; // read in this wadfiles information SafeRead(texfile, &wadinfo, sizeof(wadinfo)); // make sure its a valid format if (strncmp(wadinfo.identification, "WAD2", 4) && strncmp(wadinfo.identification, "WAD3", 4)) { Log(" - "); Error("%s isn't a Wadfile!", pszWadFile); } wadinfo.numlumps = LittleLong(wadinfo.numlumps); wadinfo.infotableofs = LittleLong(wadinfo.infotableofs); // read in lump if (fseek(texfile, wadinfo.infotableofs, SEEK_SET)) Warning("fseek to %d in wadfile %s failed\n", wadinfo.infotableofs, pszWadFile); // memalloc for this lump lumpinfo = (lumpinfo_t*)realloc(lumpinfo, (nTexLumps + wadinfo.numlumps) * sizeof(lumpinfo_t)); // for each texlump for (j = 0; j < wadinfo.numlumps; j++, nTexLumps++) { SafeRead(texfile, &lumpinfo[nTexLumps], (sizeof(lumpinfo_t) - sizeof(int)) ); // iTexFile is NOT read from file if (!TerminatedString(lumpinfo[nTexLumps].name, MAXWADNAME)) { lumpinfo[nTexLumps].name[MAXWADNAME - 1] = 0; Log(" - "); Warning("Unterminated texture name : wad[%s] texture[%d] name[%s]\n", pszWadFile, nTexLumps, lumpinfo[nTexLumps].name); } CleanupName(lumpinfo[nTexLumps].name, lumpinfo[nTexLumps].name); lumpinfo[nTexLumps].filepos = LittleLong(lumpinfo[nTexLumps].filepos); lumpinfo[nTexLumps].disksize = LittleLong(lumpinfo[nTexLumps].disksize); lumpinfo[nTexLumps].iTexFile = nTexFiles; if (lumpinfo[nTexLumps].disksize > MAX_TEXTURE_SIZE) { Log(" - "); Warning("Larger than expected texture (%d bytes): '%s'", lumpinfo[nTexLumps].disksize, lumpinfo[nTexLumps].name); } } // AJM: this feature is dependant on autowad. :( // CONSIDER: making it standard? #ifdef HLCSG_AUTOWAD { double percused = ((float)(currentwad->usedtextures) / (float)(g_numUsedTextures)) * 100; Log(" - Contains %i used texture%s, %2.2f percent of map (%d textures in wad)\n", currentwad->usedtextures, currentwad->usedtextures == 1 ? "" : "s", percused, wadinfo.numlumps); } #endif nTexFiles++; hlassume(nTexFiles < MAX_TEXFILES, assume_MAX_TEXFILES); } //Log("num of used textures: %i\n", g_numUsedTextures); // AJM: Tommy suggested i add this warning message in, and it certianly doesnt // hurt to be cautious. Especially one of the possible side effects he mentioned was svc_bad if (nTexFiles > 8) { Log("\n"); Warning("More than 8 wadfiles are in use. (%i)\n" "This may be harmless, and if no strange side effects are occurring, then\n" "it can safely be ignored. However, if your map starts exhibiting strange\n" "or obscure errors, consider this as suspect.\n" , nTexFiles); } // sort texlumps in memory by name qsort((void*)lumpinfo, (size_t) nTexLumps, sizeof(lumpinfo[0]), lump_sorter_by_name); SetKeyValue(&g_entities[0], "wad", szTmpWad); Log("\n"); CheckFatal(); return true; }