-void Mod_OBJ_SnapVertex(float *v)
-{
- int i;
- float a = mod_obj_vertexprecision.value;
- float b = 1.0f / a;
- v[0] -= floor(v[0] * a + 0.5f) * b;
- v[1] -= floor(v[1] * a + 0.5f) * b;
- v[2] -= floor(v[2] * a + 0.5f) * b;
-}
-
-void Mod_OBJ_ConvertBSPNode(objnode_t *objnode, mnode_t *mnodeparent)
-{
- if (objnode->children[0])
- {
- // convert to mnode_t
- mnode_t *mnode = loadmodel->brush.data_nodes + loadmodel->brush.num_nodes++;
- mnode->parent = mnodeparent;
- mnode->plane = loadmodel->brush.data_planes + loadmodel->brush.num_planes++;
- VectorCopy(objnode->normal, mnode->plane->normal);
- mnode->plane->dist = objnode->dist;
- PlaneClassify(mnode->plane);
- VectorCopy(objnode->mins, mnode->mins);
- VectorCopy(objnode->maxs, mnode->maxs);
- // push combinedsupercontents up to the parent
- if (mnodeparent)
- mnodeparent->combinedsupercontents |= mnode->combinedsupercontents;
- mnode->children[0] = Mod_OBJ_ConvertBSPNode(objnode->children[0], mnode);
- mnode->children[1] = Mod_OBJ_ConvertBSPNode(objnode->children[1], mnode);
- }
- else
- {
- // convert to mleaf_t
- mleaf_t *mleaf = loadmodel->brush.data_leafs + loadmodel->brush.num_leafs++;
- mleaf->parent = mnodeparent;
- VectorCopy(objnode->mins, mleaf->mins);
- VectorCopy(objnode->maxs, mleaf->maxs);
- mleaf->clusterindex = loadmodel->brush.num_leafs - 1;
- if (objnode->numtriangles)
- {
- objtriangle_t *triangles = objnode->triangles;
- int numtriangles = objnode->numtriangles;
- texture_t *texture;
- float edge[3][3];
- float normal[3];
- objvertex_t vertex[3];
- numsurfaces = 0;
- maxsurfaces = numtriangles;
- surfaces = NULL;
- // calculate some more data on each triangle for surface gathering
- for (i = 0;i < numtriangles;i++)
- {
- triangle = triangles + i;
- texture = loadmodel->data_textures + triangle->textureindex;
- Mod_OBJ_SnapVertex(triangle->vertex[0].v);
- Mod_OBJ_SnapVertex(triangle->vertex[1].v);
- Mod_OBJ_SnapVertex(triangle->vertex[2].v);
- TriangleNormal(triangle->vertex[0].v, triangle->vertex[1].v, triangle->vertex[2].v, normal);
- axis = 0;
- if (fabs(normal[axis]) < fabs(normal[1]))
- axis = 1;
- if (fabs(normal[axis]) < fabs(normal[2]))
- axis = 2;
- VectorClear(normal);
- normal[axis] = 1;
- triangle->axis = axis;
- VectorSubtract(triangle->vertex[1].v, triangle->vertex[0].v, edge[0]);
- VectorSubtract(triangle->vertex[2].v, triangle->vertex[1].v, edge[1]);
- VectorSubtract(triangle->vertex[0].v, triangle->vertex[2].v, edge[2]);
- CrossProduct(edge[0], normal, triangle->edgeplane[0]);
- CrossProduct(edge[1], normal, triangle->edgeplane[1]);
- CrossProduct(edge[2], normal, triangle->edgeplane[2]);
- VectorNormalize(triangle->edgeplane[0]);
- VectorNormalize(triangle->edgeplane[1]);
- VectorNormalize(triangle->edgeplane[2]);
- triangle->edgeplane[0][3] = DotProduct(triangle->edgeplane[0], triangle->vertex[0].v);
- triangle->edgeplane[1][3] = DotProduct(triangle->edgeplane[1], triangle->vertex[1].v);
- triangle->edgeplane[2][3] = DotProduct(triangle->edgeplane[2], triangle->vertex[2].v);
- triangle->surfaceindex = 0;
- // add to the combined supercontents while we're here...
- mleaf->combinedsupercontents |= texture->supercontents;
- }
- surfaceindex = 1;
- for (i = 0;i < numtriangles;i++)
- {
- // skip already-assigned triangles
- if (triangles[i].surfaceindex)
- continue;
- texture = loadmodel->data_textures + triangles[i].textureindex;
- // assign a new surface to this triangle
- triangles[i].surfaceindex = surfaceindex++;
- axis = triangles[i].axis;
- numvertices = 3;
- // find the triangle's neighbors, this can take multiple passes
- retry = true;
- while (retry)
- {
- retry = false;
- for (j = i+1;j < numtriangles;j++)
- {
- if (triangles[j].surfaceindex || triangles[j].axis != axis || triangles[j].texture != texture)
- continue;
- triangle = triangles + j;
- for (k = i;k < j;k++)
- {
- if (triangles[k].surfaceindex != surfaceindex)
- continue;
- if (VectorCompare(triangles[k].vertex[0].v, triangles[j].vertex[0].v)
- || VectorCompare(triangles[k].vertex[0].v, triangles[j].vertex[1].v)
- || VectorCompare(triangles[k].vertex[0].v, triangles[j].vertex[2].v)
- || VectorCompare(triangles[k].vertex[1].v, triangles[j].vertex[0].v)
- || VectorCompare(triangles[k].vertex[1].v, triangles[j].vertex[1].v)
- || VectorCompare(triangles[k].vertex[1].v, triangles[j].vertex[2].v)
- || VectorCompare(triangles[k].vertex[2].v, triangles[j].vertex[0].v)
- || VectorCompare(triangles[k].vertex[2].v, triangles[j].vertex[1].v)
- || VectorCompare(triangles[k].vertex[2].v, triangles[j].vertex[2].v))
- {
- // shares a vertex position
- --- FIXME ---
- }
- }
- for (k = 0;k < numvertices;k++)
- if (!VectorCompare(vertex[k].v, triangles[j].vertex[0].v) || !VectorCompare(vertex[k].v, triangles[j].vertex[1].v) || !VectorCompare(vertex[k].v, triangles[j].vertex[2].v))
- break;
- if (k == numvertices)
- break; // not a neighbor
- // this triangle is a neighbor and has the same axis and texture
- // check now if it overlaps in lightmap projection space
- triangles[j].surfaceindex;
- if (triangles[j].
- }
- }
- //triangles[i].surfaceindex = surfaceindex++;
- for (surfaceindex = 0;surfaceindex < numsurfaces;surfaceindex++)
- {
- if (surfaces[surfaceindex].texture != texture)
- continue;
- // check if any triangles already in this surface overlap in lightmap projection space
-
- {
- }
- break;
- }
- }
- // let the collision code simply use the surfaces
- mleaf->containscollisionsurfaces = mleaf->combinedsupercontents != 0;
- mleaf->numleafsurfaces = ?;
- mleaf->firstleafsurface = ?;
- }
- // push combinedsupercontents up to the parent
- if (mnodeparent)
- mnodeparent->combinedsupercontents |= mleaf->combinedsupercontents;
- }
-}
-#endif
-
-void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
-{
-#ifdef OBJWORKS
- const char *textbase = (char *)buffer, *text = textbase;
- char *s;
- char *argv[512];
- char line[1024];
- char materialname[MAX_QPATH];
- int j, index1, index2, index3, first, prev, index;
- int argc;
- int linelen;
- int numtriangles = 0;
- int maxtriangles = 131072;
- objtriangle_t *triangles = Mem_Alloc(tempmempool, maxtriangles * sizeof(*triangles));
- int linenumber = 0;
- int maxtextures = 256, numtextures = 0, textureindex = 0;
- int maxv = 1024, numv = 0;
- int maxvt = 1024, numvt = 0;
- int maxvn = 1024, numvn = 0;
- char **texturenames;
- float *v = Mem_Alloc(tempmempool, maxv * sizeof(float[3]));
- float *vt = Mem_Alloc(tempmempool, maxvt * sizeof(float[2]));
- float *vn = Mem_Alloc(tempmempool, maxvn * sizeof(float[3]));
- objvertex_t vfirst, vprev, vcurrent;
- float mins[3];
- float maxs[3];
-#if 0
- int hashindex;
- int maxverthash = 65536, numverthash = 0;
- int numhashindex = 65536;
- struct objverthash_s
- {
- struct objverthash_s *next;
- int s;
- int v;
- int vt;
- int vn;
- }
- *hash, **verthash = Mem_Alloc(tempmempool, numhashindex * sizeof(*verthash)), *verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata)), *oldverthashdata;
-#endif
-
- dpsnprintf(materialname, sizeof(materialname), "%s", loadmodel->name);
-
- loadmodel->modeldatatypestring = "OBJ";
-
- loadmodel->type = mod_obj;
- loadmodel->soundfromcenter = true;
- loadmodel->TraceBox = Mod_OBJ_TraceBox;
- loadmodel->TraceLine = Mod_OBJ_TraceLine;
- loadmodel->TracePoint = Mod_OBJ_TracePoint;
- loadmodel->PointSuperContents = Mod_OBJ_PointSuperContents;
- loadmodel->brush.TraceLineOfSight = Mod_OBJ_TraceLineOfSight;
- loadmodel->brush.SuperContentsFromNativeContents = Mod_OBJ_SuperContentsFromNativeContents;
- loadmodel->brush.NativeContentsFromSuperContents = Mod_OBJ_NativeContentsFromSuperContents;
- loadmodel->brush.GetPVS = Mod_OBJ_GetPVS;
- loadmodel->brush.FatPVS = Mod_OBJ_FatPVS;
- loadmodel->brush.BoxTouchingPVS = Mod_OBJ_BoxTouchingPVS;
- loadmodel->brush.BoxTouchingLeafPVS = Mod_OBJ_BoxTouchingLeafPVS;
- loadmodel->brush.BoxTouchingVisibleLeafs = Mod_OBJ_BoxTouchingVisibleLeafs;
- loadmodel->brush.FindBoxClusters = Mod_OBJ_FindBoxClusters;
- loadmodel->brush.LightPoint = Mod_OBJ_LightPoint;
- loadmodel->brush.FindNonSolidLocation = Mod_OBJ_FindNonSolidLocation;
- loadmodel->brush.AmbientSoundLevelsForPoint = NULL;
- loadmodel->brush.RoundUpToHullSize = NULL;
- loadmodel->brush.PointInLeaf = Mod_OBJ_PointInLeaf;
- loadmodel->Draw = R_Q1BSP_Draw;
- loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
- loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
- loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
- loadmodel->GetLightInfo = R_Q1BSP_GetLightInfo;
- loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
- loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
- loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
- loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
- loadmodel->DrawLight = R_Q1BSP_DrawLight;
-
- VectorClear(mins);
- VectorClear(maxs);
-
- // parse the OBJ text now
- for(;;)
- {
- if (!*text)
- break;
- linenumber++;
- linelen = 0;
- for (linelen = 0;text[linelen] && text[linelen] != '\r' && text[linelen] != '\n';linelen++)
- line[linelen] = text[linelen];
- line[linelen] = 0;
- for (argc = 0;argc < (int)(sizeof(argv)/sizeof(argv[0]));argc++)
- argv[argc] = "";
- argc = 0;
- s = line;
- while (*s == ' ' || *s == '\t')
- s++;
- while (*s)
- {
- argv[argc++] = s;
- while (*s > ' ')
- s++;
- if (!*s)
- break;
- *s++ = 0;
- while (*s == ' ' || *s == '\t')
- s++;
- }
- if (!argc)
- continue;
- if (argv[0][0] == '#')
- continue;
- if (!strcmp(argv[0], "v"))
- {
- if (maxv <= numv)
- {
- float *oldv = v;
- maxv *= 2;
- v = Mem_Alloc(tempmempool, maxv * sizeof(float[3]));
- if (oldv)
- {
- memcpy(v, oldv, numv * sizeof(float[3]));
- Mem_Free(oldv);
- }
- }
- v[numv*3+0] = atof(argv[1]);
- v[numv*3+1] = atof(argv[2]);
- v[numv*3+2] = atof(argv[3]);
- numv++;
- }
- else if (!strcmp(argv[0], "vt"))
- {
- if (maxvt <= numvt)
- {
- float *oldvt = vt;
- maxvt *= 2;
- vt = Mem_Alloc(tempmempool, maxvt * sizeof(float[2]));
- if (oldvt)
- {
- memcpy(vt, oldvt, numvt * sizeof(float[2]));
- Mem_Free(oldvt);
- }
- }
- vt[numvt*2+0] = atof(argv[1]);
- vt[numvt*2+1] = atof(argv[2]);
- numvt++;
- }
- else if (!strcmp(argv[0], "vn"))
- {
- if (maxvn <= numvn)
- {
- float *oldvn = vn;
- maxvn *= 2;
- vn = Mem_Alloc(tempmempool, maxvn * sizeof(float[3]));
- if (oldvn)
- {
- memcpy(vn, oldvn, numvn * sizeof(float[3]));
- Mem_Free(oldvn);
- }
- }
- vn[numvn*3+0] = atof(argv[1]);
- vn[numvn*3+1] = atof(argv[2]);
- vn[numvn*3+2] = atof(argv[3]);
- numvn++;
- }
- else if (!strcmp(argv[0], "f"))
- {
- for (j = 1;j < argc;j++)
- {
- index1 = atoi(argv[j]);
- while(argv[j][0] && argv[j][0] != '/')
- argv[j]++;
- if (argv[j][0])
- argv[j]++;
- index2 = atoi(argv[j]);
- while(argv[j][0] && argv[j][0] != '/')
- argv[j]++;
- if (argv[j][0])
- argv[j]++;
- index3 = atoi(argv[j]);
- // negative refers to a recent vertex
- // zero means not specified
- // positive means an absolute vertex index
- if (index1 < 0)
- index1 = numv - index1;
- if (index2 < 0)
- index2 = numvt - index2;
- if (index3 < 0)
- index3 = numvn - index3;
- VectorCopy(v + 3*index1, vcurrent.v);
- Vector2Copy(vt + 2*index2, vcurrent.vt);
- VectorCopy(vn + 3*index3, vcurrent.vn);
- if (numtriangles == 0)
- {
- VectorCopy(vcurrent.v, mins);
- VectorCopy(vcurrent.v, maxs);
- }
- else
- {
- mins[0] = min(mins[0], vcurrent.v[0]);
- mins[1] = min(mins[1], vcurrent.v[1]);
- mins[2] = min(mins[2], vcurrent.v[2]);
- maxs[0] = max(maxs[0], vcurrent.v[0]);
- maxs[1] = max(maxs[1], vcurrent.v[1]);
- maxs[2] = max(maxs[2], vcurrent.v[2]);
- }
- if (j == 1)
- vfirst = vcurrent;
- else if (j >= 3)
- {
- if (maxtriangles <= numtriangles)
- {
- objtriangle_t *oldtriangles = triangles;
- maxtriangles *= 2;
- triangles = Mem_Alloc(tempmempool, maxtriangles * sizeof(*triangles));
- if (oldtriangles)
- {
- memcpy(triangles, oldtriangles, maxtriangles * sizeof(*triangles));
- Mem_Free(oldtriangles);
- }
- }
- triangles[numtriangles].textureindex = textureindex;
- triangles[numtriangles].vertex[0] = vfirst;
- triangles[numtriangles].vertex[1] = vprev;
- triangles[numtriangles].vertex[2] = vcurrent;
- numtriangles++;
- }
- vprev = vcurrent;
- prev = index;
- }
- }
- else if (!strcmp(argv[0], "o") || !strcmp(argv[0], "g"))
- ;
- else if (!!strcmp(argv[0], "usemtl"))
- {
- for (i = 0;i < numtextures;i++)
- if (!strcmp(texturenames[numtextures], argv[1]))
- break;
- if (i < numtextures)
- texture = textures + i;
- else
- {
- if (maxtextures <= numtextures)
- {
- texture_t *oldtextures = textures;
- maxtextures *= 2;
- textures = Mem_Alloc(tempmempool, maxtextures * sizeof(*textures));
- if (oldtextures)
- {
- memcpy(textures, oldtextures, numtextures * sizeof(*textures));
- Mem_Free(oldtextures);
- }
- }
- textureindex = numtextures++;
- texturenames[textureindex] = Mem_Alloc(tempmempool, strlen(argv[1]) + 1);
- memcpy(texturenames[textureindex], argv[1], strlen(argv[1]) + 1);
- }
- }
- text += linelen;
- if (*text == '\r')
- text++;
- if (*text == '\n')
- text++;
- }
-
- // now that we have the OBJ data loaded as-is, we can convert it
-
- // load the textures
- loadmodel->num_textures = numtextures;
- loadmodel->data_textures = Mem_Alloc(loadmodel->mempool, loadmodel->num_textures * sizeof(texture_t));
- for (i = 0;i < numtextures;i++)
- Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i, texturenames[i], true, true, TEXF_MIPMAP | TEXF_ALPHA | (r_picmipworld.integer ? TEXF_PICMIP : 0) | TEXF_COMPRESS);
-
- // free the texturenames array since we are now done with it
- for (i = 0;i < numtextures;i++)
- {
- Mem_Free(texturenames[i]);
- texturenames[i] = NULL;
- }
- Mem_Free(texturenames);
- texturenames = NULL;
-
- // copy the model bounds, then enlarge the yaw and rotated bounds according to radius
- VectorCopy(mins, loadmodel->normalmins);
- VectorCopy(maxs, loadmodel->normalmaxs);
- dist = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
- modelyawradius = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
- modelyawradius = dist*dist+modelyawradius*modelyawradius;
- modelradius = max(fabs(loadmodel->normalmins[2]), fabs(loadmodel->normalmaxs[2]));
- modelradius = modelyawradius + modelradius * modelradius;
- modelyawradius = sqrt(modelyawradius);
- modelradius = sqrt(modelradius);
- loadmodel->yawmins[0] = loadmodel->yawmins[1] = -modelyawradius;
- loadmodel->yawmins[2] = loadmodel->normalmins[2];
- loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelyawradius;
- loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
- loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -modelradius;
- loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = modelradius;
- loadmodel->radius = modelradius;
- loadmodel->radius2 = modelradius * modelradius;
-
- // make sure the temp triangle buffer is big enough for BSP building
- maxclippedtriangles = numtriangles*4;
- if (numtriangles > 0)
- {
- clippedfronttriangles = Mem_Alloc(loadmodel->mempool, maxclippedtriangles * 2 * sizeof(objtriangle_t));
- clippedbacktriangles = clippedfronttriangles + maxclippedtriangles;
- }
-
- // generate a rough BSP tree from triangle data, we don't have to be too careful here, it only has to define the basic areas of the map
- loadmodel->brush.num_leafs = 0;
- loadmodel->brush.num_nodes = 0;
- Mem_ExpandableArray_NewArray(&nodesarray, loadmodel->mempool, sizeof(objnode_t), 1024);
- rootnode = Mod_OBJ_BSPNodeForTriangles(triangles, numtriangles, mins, maxs, &nodesarray, maxclippedtriangles, clippedfronttriangles, clippedbacktriangles);