diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c new file mode 100644 index 000000000..3331180b8 --- /dev/null +++ b/engine/client/r_d3.c @@ -0,0 +1,555 @@ +#include "quakedef.h" +#ifndef SERVERONLY +#include "shader.h" +#endif + +void RMod_SetParent (mnode_t *node, mnode_t *parent); + +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; +} + +//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; +} + +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; + } +} + +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) + return true; + COM_StripExtension(mod->name, token, sizeof(token)); + buf = FS_LoadMallocFile(va("%s.proc", token)); + Mod_LoadMap_Proc(mod, buf); + BZ_Free(buf); + return true; +#endif +} \ No newline at end of file