#include "quakedef.h" #ifdef MAP_PROC #ifndef SERVERONLY #include "shader.h" #endif void RMod_SetParent (mnode_t *node, mnode_t *parent); int D3_LeafnumForPoint (struct model_s *model, vec3_t point); #ifndef SERVERONLY qboolean Mod_LoadMap_Proc(model_t *model, char *data) { char token[256]; data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "mapProcFile003")) { Con_Printf("proc format not compatible %s\n", token); return false; } /*FIXME: add sanity checks*/ while(1) { data = COM_ParseOut(data, token, sizeof(token)); if (!data) break; else if (!strcmp(token, "model")) { batch_t *b; mesh_t *m; model_t *sub; float f; int numsurfs, surf; int numverts, v, j; int numindicies; char *vdata; data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "{")) return false; data = COM_ParseOut(data, token, sizeof(token)); sub = Mod_FindName(va("*%s", token)); data = COM_ParseOut(data, token, sizeof(token)); numsurfs = atoi(token); if (numsurfs < 0 || numsurfs > 10000) return false; b = Hunk_Alloc(sizeof(*b) * numsurfs); m = Hunk_Alloc(sizeof(*m) * numsurfs); sub->numsurfaces = numsurfs; sub->batches[0] = b; for (surf = 0; surf < numsurfs; surf++) { data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "{")) break; if (!data) return false; b[surf].meshes = 1; b[surf].mesh = (mesh_t**)&m[surf]; b[surf].lightmap = -1; data = COM_ParseOut(data, token, sizeof(token)); b[surf].shader = R_RegisterShader_Vertex(token); data = COM_ParseOut(data, token, sizeof(token)); numverts = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); numindicies = atoi(token); m[surf].numvertexes = numverts; m[surf].numindexes = numindicies; vdata = Hunk_Alloc(numverts * (sizeof(vecV_t) + sizeof(vec2_t) + sizeof(vec3_t)) + numindicies * sizeof(index_t)); m[surf].xyz_array = (vecV_t*)vdata;vdata += sizeof(vecV_t)*numverts; m[surf].st_array = (vec2_t*)vdata;vdata += sizeof(vec2_t)*numverts; m[surf].normals_array = (vec3_t*)vdata;vdata += sizeof(vec3_t)*numverts; m[surf].indexes = (index_t*)vdata; sub->mins[0] = 99999999; sub->mins[1] = 99999999; sub->mins[2] = 99999999; sub->maxs[0] = -99999999; sub->maxs[1] = -99999999; sub->maxs[2] = -99999999; for (v = 0; v < numverts; v++) { data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "(")) return false; data = COM_ParseOut(data, token, sizeof(token)); m[surf].xyz_array[v][0] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].xyz_array[v][1] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].xyz_array[v][2] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].st_array[v][0] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].st_array[v][1] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].normals_array[v][0] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].normals_array[v][1] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); m[surf].normals_array[v][2] = atof(token); for (j = 0; j < 3; j++) { f = m[surf].xyz_array[v][j]; if (f > sub->maxs[j]) sub->maxs[j] = f; else if (f < sub->mins[j]) sub->mins[j] = f; } data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, ")")) return false; } for (v = 0; v < numindicies; v++) { data = COM_ParseOut(data, token, sizeof(token)); m[surf].indexes[v] = atoi(token); } data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "}")) return false; } data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "}")) return false; sub->needload = false; sub->fromgame = fg_doom3; sub->type = mod_brush; } else if (!strcmp(token, "shadowModel")) { int numverts, v; int numindexes, i; data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "{")) return false; data = COM_ParseOut(data, token, sizeof(token)); //name data = COM_ParseOut(data, token, sizeof(token)); numverts = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); //nocaps data = COM_ParseOut(data, token, sizeof(token)); //nofrontcaps data = COM_ParseOut(data, token, sizeof(token)); numindexes = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); //planebits for (v = 0; v < numverts; v++) { data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "(")) return false; data = COM_ParseOut(data, token, sizeof(token)); //x data = COM_ParseOut(data, token, sizeof(token)); //y data = COM_ParseOut(data, token, sizeof(token)); //z data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, ")")) return false; } for (i = 0; i < numindexes; i++) { data = COM_ParseOut(data, token, sizeof(token)); } data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "}")) return false; } else if (!strcmp(token, "nodes")) { int numnodes, n; data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "{")) return false; data = COM_ParseOut(data, token, sizeof(token)); numnodes = atoi(token); model->nodes = Hunk_Alloc(sizeof(*model->nodes)*numnodes); model->planes = Hunk_Alloc(sizeof(*model->planes)*numnodes); for (n = 0; n < numnodes; n++) { data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "(")) return false; model->nodes[n].plane = &model->planes[n]; data = COM_ParseOut(data, token, sizeof(token)); model->planes[n].normal[0] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); model->planes[n].normal[1] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); model->planes[n].normal[2] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); model->planes[n].dist = atof(token); data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, ")")) return false; data = COM_ParseOut(data, token, sizeof(token)); model->nodes[n].childnum[0] = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); model->nodes[n].childnum[1] = atoi(token); } data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "}")) return false; RMod_SetParent(model->nodes, NULL); } else if (!strcmp(token, "interAreaPortals")) { int numareas; int pno, v; portal_t *p; data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "{")) return false; data = COM_ParseOut(data, token, sizeof(token)); numareas = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); model->numportals = atoi(token); model->portal = p = Hunk_Alloc(sizeof(*p) * model->numportals); for (pno = 0; pno < model->numportals; pno++, p++) { data = COM_ParseOut(data, token, sizeof(token)); p->numpoints = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); p->area[0] = atoi(token); data = COM_ParseOut(data, token, sizeof(token)); p->area[1] = atoi(token); p->points = Hunk_Alloc(sizeof(*p->points) * p->numpoints); ClearBounds(p->min, p->max); for (v = 0; v < p->numpoints; v++) { data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "(")) return false; data = COM_ParseOut(data, token, sizeof(token)); p->points[v][0] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); p->points[v][1] = atof(token); data = COM_ParseOut(data, token, sizeof(token)); p->points[v][2] = atof(token); p->points[v][3] = 1; AddPointToBounds(p->points[v], p->min, p->max); data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, ")")) return false; } } data = COM_ParseOut(data, token, sizeof(token)); if (strcmp(token, "}")) return false; } else { Con_Printf("unexpected token %s\n", token); return false; } } return true; } static qboolean D3_PolyBounds(vec_t result[4], int count, vec4_t *vlist) { qboolean ret = false; int i; vec4_t tempv, v; /*inverted*/ result[0] = 10000; result[1] = -10000; result[2] = 10000; result[3] = -10000; for (i = 0; i < count; i++) { Matrix4_Transform4(r_refdef.m_view, vlist[i], tempv); Matrix4_Transform4(r_refdef.m_projection, tempv, v); v[0] /= v[3]; v[1] /= v[3]; // if (v[2] < 0) // continue; if (result[0] > v[0]) result[0] = v[0]; if (result[1] < v[0]) result[1] = v[0]; if (result[2] > v[1]) result[2] = v[1]; if (result[3] < v[1]) result[3] = v[1]; ret = true; } return ret; } qboolean R_CullBox (vec3_t mins, vec3_t maxs); static int walkno; /*convert each portal to a 2d box, because its much much simpler than true poly clipping*/ void D3_WalkPortal(model_t *mod, int start, vec_t bounds[4], unsigned char *vis) { int i; portal_t *p; int side; vec_t newbounds[4]; vis[start>>3] |= 1<<(start&7); for (i = 0; i < mod->numportals; i++) { p = mod->portal+i; if (p->walkno == walkno) continue; if (p->area[0] == start) side = 0; else if (p->area[1] == start) side = 1; else continue; R_CullBox(p->min, p->max); if (!D3_PolyBounds(newbounds, p->numpoints, p->points)) { p->walkno = walkno; continue; } /*new poly was to the right of it, or fully to the left*/ if (newbounds[1] <= bounds[0] || newbounds[0] >= bounds[1]) continue; if (newbounds[3] <= bounds[2] || newbounds[2] >= bounds[3]) continue; if (newbounds[0] < bounds[0]) newbounds[0] = bounds[0]; if (newbounds[1] > bounds[1]) newbounds[1] = bounds[1]; if (newbounds[2] < bounds[2]) newbounds[2] = bounds[2]; if (newbounds[3] > bounds[3]) newbounds[3] = bounds[3]; /*FIXME: clip the new bounds to the old bounds*/ p->walkno = walkno; D3_WalkPortal(mod, p->area[!side], newbounds, vis); } } unsigned char *D3_CalcVis(model_t *mod, vec3_t org) { int start; static unsigned char vis[256]; vec_t newbounds[4]; start = D3_LeafnumForPoint(mod, org); /*figure out which area we're in*/ if (start < 0) { /*outside the world, just make it all visible, and take the fps hit*/ memset(vis, 255, 4); return vis; } else if (r_novis.value) return vis; else { memset(vis, 0, 4); /*make a bounds the size of the view*/ newbounds[0] = -1; newbounds[1] = 1; newbounds[2] = -1; newbounds[3] = 1; walkno++; D3_WalkPortal(mod, start, newbounds, vis); // Con_Printf("%x %x %x %x\n", vis[0], vis[1], vis[2], vis[3]); return vis; } } /*emits static entities, one for each area, which is only visible if that area is in the vis*/ void D3_GenerateAreas(model_t *mod) { entity_t *ent; int area; for (area = 0; area < 256*8; area++) { if (cl.num_statics == cl_max_static_entities) { cl_max_static_entities += 16; cl_static_entities = BZ_Realloc(cl_static_entities, sizeof(*cl_static_entities) * cl_max_static_entities); } ent = &cl_static_entities[cl.num_statics].ent; cl_static_entities[cl.num_statics].mdlidx = 0; memset(ent, 0, sizeof(*ent)); ent->model = Mod_FindName(va("*_area%i", area)); ent->scale = 1; AngleVectors(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]); VectorInverse(ent->axis[1]); ent->shaderRGBAf[0] = 1; ent->shaderRGBAf[1] = 1; ent->shaderRGBAf[2] = 1; ent->shaderRGBAf[3] = 1; /*put it in that area*/ cl_static_entities[cl.num_statics].pvscache.num_leafs = 1; cl_static_entities[cl.num_statics].pvscache.leafnums[0] = area; if (ent->model && !ent->model->needload) cl.num_statics++; else break; } } #endif //edict system as opposed to q2 game dll system. void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs) { } qbyte *D3_LeafPVS (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize) { return buffer; } int D3_LeafnumForPoint (struct model_s *model, vec3_t point) { float p; int c; mnode_t *node; node = model->nodes; while(1) { p = DotProduct(point, node->plane->normal) + node->plane->dist; c = node->childnum[p<0]; if (c <= 0) return -1-c; node = model->nodes + c; } return 0; } unsigned int D3_FatPVS (struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge) { return 0; } void D3_StainNode (struct mnode_s *node, float *parms) { } qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, struct trace_s *trace) { trace->fraction = 0; VectorCopy(p1, trace->endpos); trace->allsolid = true; trace->startsolid = true; trace->ent = NULL; return false; } unsigned int D3_PointContents (struct model_s *model, vec3_t axis[3], vec3_t p) { return FTECONTENTS_SOLID; } void D3_LightPointValues (struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { VectorClear(res_diffuse); VectorClear(res_ambient); VectorClear(res_dir); res_dir[2] = 1; } qboolean D3_EdictInFatPVS (struct model_s *model, struct pvscache_s *edict, qbyte *pvsbuffer) { int i; for (i = 0; i < edict->num_leafs; i++) if (pvsbuffer[edict->leafnums[i]>>3] & (1u<<(edict->leafnums[i]&7))) return true; return false; } qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf) { char token[256]; buf = COM_ParseOut(buf, token, sizeof(token)); if (strcmp(token, "CM")) return false; buf = COM_ParseOut(buf, token, sizeof(token)); if (atof(token) != 1.0) return false; /*load up the .map so we can get some entities (anyone going to bother making a qc mod compatible with this?)*/ COM_StripExtension(mod->name, token, sizeof(token)); mod->entities = FS_LoadMallocFile(va("%s.map", token)); mod->funcs.FindTouchedLeafs = D3_FindTouchedLeafs; mod->funcs.Trace = D3_Trace; mod->funcs.PointContents = D3_PointContents; mod->funcs.FatPVS = D3_FatPVS; mod->funcs.LeafnumForPoint = D3_LeafnumForPoint; mod->funcs.StainNode = D3_StainNode; mod->funcs.LightPointValues = D3_LightPointValues; mod->funcs.EdictInFatPVS = D3_EdictInFatPVS; mod->fromgame = fg_doom3; /*that's the physics sorted*/ #ifndef SERVERONLY if (!isDedicated) { COM_StripExtension(mod->name, token, sizeof(token)); buf = FS_LoadMallocFile(va("%s.proc", token)); Mod_LoadMap_Proc(mod, buf); BZ_Free(buf); } #endif return true; } #endif