RenderablePicoModel::RenderablePicoModel (picoModel_t* mod) { // Get the number of surfaces to create const int nSurf = PicoGetModelNumSurfaces(mod); // Create a RenderablePicoSurface for each surface in the structure for (int n = 0; n < nSurf; ++n) { // Retrieve the surface, discarding it if it is null or non-triangulated (?) picoSurface_t* surf = PicoGetModelSurface(mod, n); if (surf == 0 || PicoGetSurfaceType(surf) != PICO_TRIANGLES) continue; // Fix the normals of the surface (?) PicoFixSurfaceNormals(surf); // Create the RenderablePicoSurface object and add it to the vector RenderablePicoSurface rSurf = RenderablePicoSurface(surf); _surfVec.push_back(rSurf); // Extend the model AABB to include the surface's AABB aabb_extend_by_aabb(_localAABB, rSurf.localAABB()); } const int nShaders = PicoGetModelNumShaders(mod); for (int n = 0; n < nShaders; n++) { const picoShader_t *shader = PicoGetModelShader(mod, n); if (shader) { modelSkinList.push_back(shader->name); } } std::stringstream polyCountStream; const int polyCount = getPolyCount(); polyCountStream << polyCount; polyCountStr = polyCountStream.str(); std::stringstream surfaceCountStream; const int surfaceCount = getSurfaceCount(); surfaceCountStream << surfaceCount; surfaceCountStr = surfaceCountStream.str(); std::stringstream vertexCountStream; const int vertexCount = getVertexCount(); vertexCountStream << vertexCount; vertexCountStr = vertexCountStream.str(); }
void CPicoModel::load( const char *name, const int frame ){ CPicoSurface *surf; picoSurface_t *pSurface; int i; m_name = new char[strlen( name ) + 1]; strcpy( m_name,name ); m_frame = frame; if ( !( m_pModel = PicoLoadModel( m_name, frame ) ) ) { int len = strlen( m_name ); // Try loading an mdc if md3 fails and vice-versa (fixme: only do this for games with mdc support) if ( !strcmp( m_name + len - 4, ".md3" ) ) { m_name[len - 1] = 'c'; m_pModel = PicoLoadModel( m_name, frame ); } else if ( !strcmp( m_name + len - 4, ".mdc" ) ) { m_name[len - 1] = '3'; m_pModel = PicoLoadModel( m_name, frame ); } } if ( m_pModel ) { m_children = g_ptr_array_new(); aabb_clear( &m_BBox ); for ( i = 0; i < PicoGetModelNumSurfaces( m_pModel ); i++ ) { pSurface = PicoGetModelSurface( m_pModel,i ); surf = new CPicoSurface( pSurface ); g_ptr_array_add( m_children, surf ); aabb_extend_by_aabb( &m_BBox, surf->GetAABB() ); } } else { m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; } m_parents = g_ptr_array_new(); }
void CPicoModel::Reload( void ){ CPicoSurface *surf; picoSurface_t *pSurface; int i; unsigned int j; // Get rid of the old model if ( m_pModel ) { for ( j = 0; j < m_children->len; j++ ) { ( (CPicoSurface*)m_children->pdata[j] )->DecRef(); g_ptr_array_remove_index_fast( m_children, j ); } } // And reload it m_pModel = PicoLoadModel( m_name, m_frame ); if ( m_pModel ) { m_children = g_ptr_array_new(); aabb_clear( &m_BBox ); for ( i = 0; i < PicoGetModelNumSurfaces( m_pModel ); i++ ) { pSurface = PicoGetModelSurface( m_pModel,i ); surf = new CPicoSurface( pSurface ); g_ptr_array_add( m_children, surf ); aabb_extend_by_aabb( &m_BBox, surf->GetAABB() ); } } else { m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; } for ( j = 0; j < m_parents->len; j++ ) { ( (CPicoParent*)m_parents->pdata[j] )->UpdateShaders(); } }
/* _ms3d_load: * loads a milkshape3d model file. */ static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){ picoModel_t *model; unsigned char *bufptr, *bufptr0; int shaderRefs[ MS3D_MAX_GROUPS ]; int numGroups; int numMaterials; // unsigned char *ptrToGroups; int numVerts; unsigned char *ptrToVerts; int numTris; unsigned char *ptrToTris; int i,k,m; /* create new pico model */ model = PicoNewModel(); if ( model == NULL ) { return NULL; } /* do model setup */ PicoSetModelFrameNum( model, frameNum ); PicoSetModelName( model, fileName ); PicoSetModelFileName( model, fileName ); bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize ); memcpy( bufptr, buffer, bufSize ); /* skip header */ bufptr += sizeof( TMsHeader ); /* get number of vertices */ bufptr = GetWord( bufptr,&numVerts ); ptrToVerts = bufptr; #ifdef DEBUG_PM_MS3D printf( "NumVertices: %d\n",numVerts ); #endif /* swap verts */ for ( i = 0; i < numVerts; i++ ) { TMsVertex *vertex; vertex = (TMsVertex *)bufptr; bufptr += sizeof( TMsVertex ); vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] ); vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] ); vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] ); #ifdef DEBUG_PM_MS3D_EX_ printf( "Vertex: x: %f y: %f z: %f\n", msvd[i]->vertex[0], msvd[i]->vertex[1], msvd[i]->vertex[2] ); #endif } /* get number of triangles */ bufptr = GetWord( bufptr,&numTris ); ptrToTris = bufptr; #ifdef DEBUG_PM_MS3D printf( "NumTriangles: %d\n",numTris ); #endif /* swap tris */ for ( i = 0; i < numTris; i++ ) { TMsTriangle *triangle; triangle = (TMsTriangle *)bufptr; bufptr += sizeof( TMsTriangle ); triangle->flags = _pico_little_short( triangle->flags ); /* run through all tri verts */ for ( k = 0; k < 3; k++ ) { /* swap tex coords */ triangle->s[ k ] = _pico_little_float( triangle->s[ k ] ); triangle->t[ k ] = _pico_little_float( triangle->t[ k ] ); /* swap fields */ triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] ); triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] ); triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] ); triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] ); /* check for out of range indices */ if ( triangle->vertexIndices[ k ] >= numVerts ) { _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 ); PicoFreeModel( model ); _pico_free( bufptr0 ); return NULL; /* yuck */ } } } /* get number of groups */ bufptr = GetWord( bufptr,&numGroups ); // ptrToGroups = bufptr; #ifdef DEBUG_PM_MS3D printf( "NumGroups: %d\n",numGroups ); #endif /* run through all groups in model */ for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ ) { picoSurface_t *surface; TMsGroup *group; group = (TMsGroup *)bufptr; bufptr += sizeof( TMsGroup ); /* we ignore hidden groups */ if ( group->flags & MS3D_HIDDEN ) { bufptr += ( group->numTriangles * 2 ) + 1; continue; } /* forced null term of group name */ group->name[ 31 ] = '\0'; /* create new pico surface */ surface = PicoNewSurface( model ); if ( surface == NULL ) { PicoFreeModel( model ); _pico_free( bufptr0 ); return NULL; } /* do surface setup */ PicoSetSurfaceType( surface,PICO_TRIANGLES ); PicoSetSurfaceName( surface,group->name ); /* process triangle indices */ for ( k = 0; k < group->numTriangles; k++ ) { TMsTriangle *triangle; unsigned int triangleIndex; /* get triangle index */ bufptr = GetWord( bufptr,(int *)&triangleIndex ); /* get ptr to triangle data */ triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) ); /* run through triangle vertices */ for ( m = 0; m < 3; m++ ) { TMsVertex *vertex; unsigned int vertexIndex; picoVec2_t texCoord; /* get ptr to vertex data */ vertexIndex = triangle->vertexIndices[ m ]; vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) ); /* store vertex origin */ PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz ); /* store vertex color */ PicoSetSurfaceColor( surface,0,vertexIndex,white ); /* store vertex normal */ PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] ); /* store current face vertex index */ PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex ); /* get texture vertex coord */ texCoord[ 0 ] = triangle->s[ m ]; texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */ /* store texture vertex coord */ PicoSetSurfaceST( surface,0,vertexIndex,texCoord ); } } /* store material */ shaderRefs[ i ] = *bufptr++; #ifdef DEBUG_PM_MS3D printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles ); #endif } /* get number of materials */ bufptr = GetWord( bufptr,&numMaterials ); #ifdef DEBUG_PM_MS3D printf( "NumMaterials: %d\n",numMaterials ); #endif /* run through all materials in model */ for ( i = 0; i < numMaterials; i++ ) { picoShader_t *shader; picoColor_t ambient,diffuse,specular; TMsMaterial *material; int k; material = (TMsMaterial *)bufptr; bufptr += sizeof( TMsMaterial ); /* null term strings */ material->name [ 31 ] = '\0'; material->texture [ 127 ] = '\0'; material->alphamap[ 127 ] = '\0'; /* ltrim strings */ _pico_strltrim( material->name ); _pico_strltrim( material->texture ); _pico_strltrim( material->alphamap ); /* rtrim strings */ _pico_strrtrim( material->name ); _pico_strrtrim( material->texture ); _pico_strrtrim( material->alphamap ); /* create new pico shader */ shader = PicoNewShader( model ); if ( shader == NULL ) { PicoFreeModel( model ); _pico_free( bufptr0 ); return NULL; } /* scale shader colors */ for ( k = 0; k < 4; k++ ) { ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 ); diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 ); specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 ); } /* set shader colors */ PicoSetShaderAmbientColor( shader,ambient ); PicoSetShaderDiffuseColor( shader,diffuse ); PicoSetShaderSpecularColor( shader,specular ); /* set shader transparency */ PicoSetShaderTransparency( shader,material->transparency ); /* set shader shininess (0..127) */ PicoSetShaderShininess( shader,material->shininess ); /* set shader name */ PicoSetShaderName( shader,material->name ); /* set shader texture map name */ PicoSetShaderMapName( shader,material->texture ); #ifdef DEBUG_PM_MS3D printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap ); #endif } /* assign shaders to surfaces */ for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ ) { picoSurface_t *surface; picoShader_t *shader; /* sanity check */ if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS || shaderRefs[ i ] < 0 ) { continue; } /* get surface */ surface = PicoGetModelSurface( model,i ); if ( surface == NULL ) { continue; } /* get shader */ shader = PicoGetModelShader( model,shaderRefs[ i ] ); if ( shader == NULL ) { continue; } /* assign shader */ PicoSetSurfaceShader( surface,shader ); #ifdef DEBUG_PM_MS3D printf( "Mapped: %d ('%s') to %d (%s)\n", shaderRefs[i],shader->name,i,surface->name ); #endif } /* return allocated pico model */ _pico_free( bufptr0 ); return model; // return NULL; }
static void PopulateWithPicoModel(int castShadows, picoModel_t * model, matrix_t transform) { int i, j, k, numSurfaces, numIndexes; picoSurface_t *surface; picoShader_t *shader; picoVec_t *xyz, *st; picoIndex_t *indexes; traceInfo_t ti; traceWinding_t tw; /* dummy check */ if(model == NULL || transform == NULL) return; /* get info */ numSurfaces = PicoGetModelNumSurfaces(model); /* walk the list of surfaces in this model and fill out the info structs */ for(i = 0; i < numSurfaces; i++) { /* get surface */ surface = PicoGetModelSurface(model, i); if(surface == NULL) continue; /* only handle triangle surfaces initially (fixme: support patches) */ if(PicoGetSurfaceType(surface) != PICO_TRIANGLES) continue; /* get shader (fixme: support shader remapping) */ shader = PicoGetSurfaceShader(surface); if(shader == NULL) continue; ti.si = ShaderInfoForShader(PicoGetShaderName(shader)); if(ti.si == NULL) continue; /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */ if((ti.si->compileFlags & C_NODRAW)) continue; if((ti.si->compileFlags & C_TRANSLUCENT) && !(ti.si->compileFlags & C_ALPHASHADOW) && !(ti.si->compileFlags & C_LIGHTFILTER)) continue; /* setup trace info */ ti.castShadows = castShadows; ti.surfaceNum = -1; ti.skipGrid = qtrue; // also ignore picomodels when skipping patches /* setup trace winding */ memset(&tw, 0, sizeof(tw)); tw.infoNum = AddTraceInfo(&ti); tw.numVerts = 3; /* get info */ numIndexes = PicoGetSurfaceNumIndexes(surface); indexes = PicoGetSurfaceIndexes(surface, 0); /* walk the triangle list */ for(j = 0; j < numIndexes; j += 3, indexes += 3) { for(k = 0; k < 3; k++) { xyz = PicoGetSurfaceXYZ(surface, indexes[k]); st = PicoGetSurfaceST(surface, 0, indexes[k]); VectorCopy(xyz, tw.v[k].xyz); Vector2Copy(st, tw.v[k].st); MatrixTransformPoint2(transform, tw.v[k].xyz); } FilterTraceWindingIntoNodes_r(&tw, headNodeNum); } } }
void InsertModel(char *name, int frame, matrix_t transform, matrix_t nTransform, remap_t * remap, shaderInfo_t * celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle) { int i, j, k, s, numSurfaces; matrix_t identity; picoModel_t *model; picoShader_t *shader; picoSurface_t *surface; shaderInfo_t *si; mapDrawSurface_t *ds; bspDrawVert_t *dv; char *picoShaderName; char shaderName[MAX_QPATH]; picoVec_t *xyz, *normal, *st; byte *color; picoIndex_t *indexes; remap_t *rm, *glob; double normalEpsilon_save; double distanceEpsilon_save; /* get model */ model = LoadModel(name, frame); if(model == NULL) return; /* handle null matrix */ if(transform == NULL) { MatrixIdentity(identity); transform = identity; } /* create transform matrix for normals */ #if 0 MatrixCopy(transform, nTransform); if(MatrixInverse(nTransform)) { Sys_FPrintf(SYS_VRB, "WARNING: Can't invert model transform matrix, using transpose instead\n"); MatrixTranspose(transform, nTransform); } #endif /* fix bogus lightmap scale */ if(lightmapScale <= 0.0f) lightmapScale = 1.0f; /* fix bogus shade angle */ if(shadeAngle <= 0.0f) shadeAngle = 0.0f; /* each surface on the model will become a new map drawsurface */ numSurfaces = PicoGetModelNumSurfaces(model); //% Sys_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces ); for(s = 0; s < numSurfaces; s++) { /* get surface */ surface = PicoGetModelSurface(model, s); if(surface == NULL) continue; /* only handle triangle surfaces initially (fixme: support patches) */ if(PicoGetSurfaceType(surface) != PICO_TRIANGLES) continue; /* fix the surface's normals */ PicoFixSurfaceNormals(surface); /* allocate a surface (ydnar: gs mods) */ ds = AllocDrawSurface(SURFACE_TRIANGLES); ds->entityNum = eNum; ds->castShadows = castShadows; ds->recvShadows = recvShadows; /* get shader name */ shader = PicoGetSurfaceShader(surface); if(shader == NULL) picoShaderName = ""; else picoShaderName = PicoGetShaderName(shader); /* handle shader remapping */ glob = NULL; for(rm = remap; rm != NULL; rm = rm->next) { if(rm->from[0] == '*' && rm->from[1] == '\0') glob = rm; else if(!Q_stricmp(picoShaderName, rm->from)) { Sys_FPrintf(SYS_VRB, "Remapping %s to %s\n", picoShaderName, rm->to); picoShaderName = rm->to; glob = NULL; break; } } if(glob != NULL) { Sys_FPrintf(SYS_VRB, "Globbing %s to %s\n", picoShaderName, glob->to); picoShaderName = glob->to; } /* shader renaming for sof2 */ if(renameModelShaders) { strcpy(shaderName, picoShaderName); StripExtension(shaderName); if(spawnFlags & 1) strcat(shaderName, "_RMG_BSP"); else strcat(shaderName, "_BSP"); si = ShaderInfoForShader(shaderName); } else { si = ShaderInfoForShader(picoShaderName); // Tr3B: HACK to support the messy Doom 3 materials provided by .ASE files if(!si->explicitDef) { picoShaderName = PicoGetShaderMapName(shader); Q_strncpyz(shaderName, picoShaderName, sizeof(shaderName)); StripExtension(shaderName); i = 0; while(shaderName[i]) { if(shaderName[i] == '\\') shaderName[i] = '/'; i++; } if(strstr(shaderName, "base/")) { si = ShaderInfoForShader(strstr(shaderName, "base/") + strlen("base/")); Sys_FPrintf(SYS_WRN, "WARNING: Applied .ASE material loader HACK to '%s' -> '%s'\n", picoShaderName, si->shader); } } } /* set shader */ ds->shaderInfo = si; /* force to meta? */ if((si != NULL && si->forceMeta) || (spawnFlags & 4)) /* 3rd bit */ ds->type = SURFACE_FORCED_META; /* fix the surface's normals (jal: conditioned by shader info) */ //if(!(spawnFlags & 64) && (shadeAngle == 0.0f || ds->type != SURFACE_FORCED_META)) // PicoFixSurfaceNormals(surface); /* set sample size */ if(lightmapSampleSize > 0.0f) ds->sampleSize = lightmapSampleSize; /* set lightmap scale */ if(lightmapScale > 0.0f) ds->lightmapScale = lightmapScale; /* set shading angle */ if(shadeAngle > 0.0f) ds->shadeAngleDegrees = shadeAngle; /* set particulars */ ds->numVerts = PicoGetSurfaceNumVertexes(surface); ds->verts = safe_malloc(ds->numVerts * sizeof(ds->verts[0])); memset(ds->verts, 0, ds->numVerts * sizeof(ds->verts[0])); ds->numIndexes = PicoGetSurfaceNumIndexes(surface); ds->indexes = safe_malloc(ds->numIndexes * sizeof(ds->indexes[0])); memset(ds->indexes, 0, ds->numIndexes * sizeof(ds->indexes[0])); /* copy vertexes */ for(i = 0; i < ds->numVerts; i++) { /* get vertex */ dv = &ds->verts[i]; /* xyz and normal */ xyz = PicoGetSurfaceXYZ(surface, i); VectorCopy(xyz, dv->xyz); MatrixTransformPoint2(transform, dv->xyz); normal = PicoGetSurfaceNormal(surface, i); VectorCopy(normal, dv->normal); MatrixTransformNormal2(nTransform, dv->normal); VectorNormalize2(dv->normal, dv->normal); /* ydnar: tek-fu celshading support for flat shaded shit */ if(flat) { dv->st[0] = si->stFlat[0]; dv->st[1] = si->stFlat[1]; } /* ydnar: gs mods: added support for explicit shader texcoord generation */ else if(si->tcGen) { /* project the texture */ dv->st[0] = DotProduct(si->vecs[0], dv->xyz); dv->st[1] = DotProduct(si->vecs[1], dv->xyz); } /* normal texture coordinates */ else { st = PicoGetSurfaceST(surface, 0, i); dv->st[0] = st[0]; dv->st[1] = st[1]; } /* set lightmap/color bits */ color = PicoGetSurfaceColor(surface, 0, i); dv->paintColor[0] = color[0] / 255.0f; dv->paintColor[1] = color[1] / 255.0f; dv->paintColor[2] = color[2] / 255.0f; dv->paintColor[3] = color[3] / 255.0f; for(j = 0; j < MAX_LIGHTMAPS; j++) { dv->lightmap[j][0] = 0.0f; dv->lightmap[j][1] = 0.0f; dv->lightColor[j][0] = 255; dv->lightColor[j][1] = 255; dv->lightColor[j][2] = 255; dv->lightColor[j][3] = 255; } } /* copy indexes */ indexes = PicoGetSurfaceIndexes(surface, 0); for(i = 0; i < ds->numIndexes; i++) ds->indexes[i] = indexes[i]; /* set cel shader */ ds->celShader = celShader; /* ydnar: giant hack land: generate clipping brushes for model triangles */ if(si->clipModel || (spawnFlags & 2)) /* 2nd bit */ { vec3_t points[4], backs[3]; vec4_t plane, reverse, pa, pb, pc; /* temp hack */ if(!si->clipModel && (((si->compileFlags & C_TRANSLUCENT) && !(si->compileFlags & C_COLLISION)) || !(si->compileFlags & C_SOLID))) continue; /* walk triangle list */ for(i = 0; i < ds->numIndexes; i += 3) { /* overflow hack */ AUTOEXPAND_BY_REALLOC(mapplanes, (nummapplanes + 64) << 1, allocatedmapplanes, 1024); /* make points and back points */ for(j = 0; j < 3; j++) { /* get vertex */ dv = &ds->verts[ds->indexes[i + j]]; /* copy xyz */ VectorCopy(dv->xyz, points[j]); VectorCopy(dv->xyz, backs[j]); /* find nearest axial to normal and push back points opposite */ /* note: this doesn't work as well as simply using the plane of the triangle, below */ for(k = 0; k < 3; k++) { if(fabs(dv->normal[k]) >= fabs(dv->normal[(k + 1) % 3]) && fabs(dv->normal[k]) >= fabs(dv->normal[(k + 2) % 3])) { backs[j][k] += dv->normal[k] < 0.0f ? 64.0f : -64.0f; break; } } } VectorCopy(points[0], points[3]); // for cyclic usage /* make plane for triangle */ // div0: add some extra spawnflags: // 0: snap normals to axial planes for extrusion // 8: extrude with the original normals // 16: extrude only with up/down normals (ideal for terrain) // 24: extrude by distance zero (may need engine changes) if(PlaneFromPoints(plane, points[0], points[1], points[2], qtrue)) { vec3_t bestNormal; float backPlaneDistance = 2; if(spawnFlags & 8) // use a DOWN normal { if(spawnFlags & 16) { // 24: normal as is, and zero width (broken) VectorCopy(plane, bestNormal); } else { // 8: normal as is VectorCopy(plane, bestNormal); } } else { if(spawnFlags & 16) { // 16: UP/DOWN normal VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); } else { // 0: axial normal if(fabs(plane[0]) > fabs(plane[1])) // x>y if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0); else // x>y, z>=y if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0); else // z>=x, x>y VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); else // y>=x if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0); else // z>=y, y>=x VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); } } /* build a brush */ buildBrush = AllocBrush(48); buildBrush->entityNum = mapEntityNum; buildBrush->original = buildBrush; buildBrush->contentShader = si; buildBrush->compileFlags = si->compileFlags; buildBrush->contentFlags = si->contentFlags; buildBrush->generatedClipBrush = qtrue; normalEpsilon_save = normalEpsilon; distanceEpsilon_save = distanceEpsilon; if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here { buildBrush->detail = qfalse; // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model) if(normalEpsilon > 0) normalEpsilon = 0; if(distanceEpsilon > 0) distanceEpsilon = 0; } else buildBrush->detail = qtrue; /* regenerate back points */ for(j = 0; j < 3; j++) { /* get vertex */ dv = &ds->verts[ds->indexes[i + j]]; // shift by some units VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit } /* make back plane */ VectorScale(plane, -1.0f, reverse); reverse[3] = -plane[3]; if((spawnFlags & 24) != 24) reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance; // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane) if(PlaneFromPoints(pa, points[2], points[1], backs[1], qtrue) && PlaneFromPoints(pb, points[1], points[0], backs[0], qtrue) && PlaneFromPoints(pc, points[0], points[2], backs[2], qtrue)) { /* set up brush sides */ buildBrush->numsides = 5; buildBrush->sides[0].shaderInfo = si; for(j = 1; j < buildBrush->numsides; j++) buildBrush->sides[j].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works buildBrush->sides[0].planenum = FindFloatPlane(plane, plane[3], 3, points); buildBrush->sides[1].planenum = FindFloatPlane(pa, pa[3], 2, &points[1]); // pa contains points[1] and points[2] buildBrush->sides[2].planenum = FindFloatPlane(pb, pb[3], 2, &points[0]); // pb contains points[0] and points[1] buildBrush->sides[3].planenum = FindFloatPlane(pc, pc[3], 2, &points[2]); // pc contains points[2] and points[0] (copied to points[3] buildBrush->sides[4].planenum = FindFloatPlane(reverse, reverse[3], 3, backs); } else { free(buildBrush); continue; } normalEpsilon = normalEpsilon_save; distanceEpsilon = distanceEpsilon_save; /* add to entity */ if(CreateBrushWindings(buildBrush)) { AddBrushBevels(); //% EmitBrushes( buildBrush, NULL, NULL ); buildBrush->next = entities[mapEntityNum].brushes; entities[mapEntityNum].brushes = buildBrush; entities[mapEntityNum].numBrushes++; } else free(buildBrush); } } } } }
picoModel_t *LoadModel(char *name, int frame) { int i; picoModel_t *model, **pm; /* init */ if(numPicoModels <= 0) memset(picoModels, 0, sizeof(picoModels)); /* dummy check */ if(name == NULL || name[0] == '\0') return NULL; /* try to find existing picoModel */ model = FindModel(name, frame); if(model != NULL) return model; /* none found, so find first non-null picoModel */ pm = NULL; for(i = 0; i < MAX_MODELS; i++) { if(picoModels[i] == NULL) { pm = &picoModels[i]; break; } } /* too many picoModels? */ if(pm == NULL) Error("MAX_MODELS (%d) exceeded, there are too many model files referenced by the map.", MAX_MODELS); /* attempt to parse model */ *pm = PicoLoadModel((char *)name, frame); /* if loading failed, make a bogus model to silence the rest of the warnings */ if(*pm == NULL) { /* allocate a new model */ *pm = PicoNewModel(); if(*pm == NULL) return NULL; /* set data */ PicoSetModelName(*pm, name); PicoSetModelFrameNum(*pm, frame); } /* debug code */ #if 0 { int numSurfaces, numVertexes; picoSurface_t *ps; Sys_Printf("Model %s\n", name); numSurfaces = PicoGetModelNumSurfaces(*pm); for(i = 0; i < numSurfaces; i++) { ps = PicoGetModelSurface(*pm, i); numVertexes = PicoGetSurfaceNumVertexes(ps); Sys_Printf("Surface %d has %d vertexes\n", i, numVertexes); } } #endif /* set count */ if(*pm != NULL) numPicoModels++; /* return the picoModel */ return *pm; }