From: havoc Date: Fri, 18 Jul 2003 17:24:44 +0000 (+0000) Subject: now loads q3 bsp (but can't render it or collide with it, so don't try it) X-Git-Tag: xonotic-v0.1.0preview~6522 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=b2c6992a06f2c837b2da24ebe16685101954533e;p=xonotic%2Fdarkplaces.git now loads q3 bsp (but can't render it or collide with it, so don't try it) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3285 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/model_brush.c b/model_brush.c index bfe485fd..a0a3a5b3 100644 --- a/model_brush.c +++ b/model_brush.c @@ -3262,19 +3262,51 @@ void Mod_Q2BSP_Load(model_t *mod, void *buffer) Mod_Q2BSP_LoadModels(&header->lumps[Q2LUMP_MODELS]); } + static void Mod_Q3BSP_LoadEntities(lump_t *l) { + const char *data; + char key[128], value[4096]; + float v[3]; + loadmodel->brushq3.num_lightgrid_cellsize[0] = 64; + loadmodel->brushq3.num_lightgrid_cellsize[1] = 64; + loadmodel->brushq3.num_lightgrid_cellsize[2] = 128; if (!l->filelen) return; loadmodel->brush.entities = Mem_Alloc(loadmodel->mempool, l->filelen); memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen); + data = loadmodel->brush.entities; + // some Q3 maps override the lightgrid_cellsize with a worldspawn key + if (data && COM_ParseToken(&data) && com_token[0] == '{') + { + while (1) + { + if (!COM_ParseToken(&data)) + break; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strcpy(key, com_token + 1); + else + strcpy(key, com_token); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + if (!COM_ParseToken(&data)) + break; // error + strcpy(value, com_token); + if (!strcmp("gridsize", key)) + { + if (sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3 && v[0] != 0 && v[1] != 0 && v[2] != 0) + VectorCopy(v, loadmodel->brushq3.num_lightgrid_cellsize); + } + } + } } static void Mod_Q3BSP_LoadTextures(lump_t *l) { -/* - d_t *in; - m_t *out; + q3dtexture_t *in; + q3mtexture_t *out; int i, count; in = (void *)(mod_base + l->fileofs); @@ -3283,20 +3315,24 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_textures = out; + loadmodel->brushq3.num_textures = count; for (i = 0;i < count;i++, in++, out++) { + strncpy(out->name, in->name, sizeof(out->name) - 1); + out->surfaceflags = LittleLong(in->surfaceflags); + out->contents = LittleLong(in->contents); + + out->number = i; + Mod_LoadSkinFrame(&out->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true); } -*/ } static void Mod_Q3BSP_LoadPlanes(lump_t *l) { -/* - d_t *in; - m_t *out; + q3dplane_t *in; + mplane_t *out; int i, count; in = (void *)(mod_base + l->fileofs); @@ -3305,328 +3341,571 @@ static void Mod_Q3BSP_LoadPlanes(lump_t *l) count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_planes = out; + loadmodel->brushq3.num_planes = count; for (i = 0;i < count;i++, in++, out++) { + out->normal[0] = LittleLong(in->normal[0]); + out->normal[1] = LittleLong(in->normal[1]); + out->normal[2] = LittleLong(in->normal[2]); + out->dist = LittleLong(in->dist); + PlaneClassify(out); } -*/ } -static void Mod_Q3BSP_LoadNodes(lump_t *l) +static void Mod_Q3BSP_LoadBrushSides(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dbrushside_t *in; + q3mbrushside_t *out; + int i, n, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadBrushSides: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_brushsides = out; + loadmodel->brushq3.num_brushsides = count; for (i = 0;i < count;i++, in++, out++) { + n = LittleLong(in->planeindex); + if (n < 0 || n >= loadmodel->brushq3.num_planes) + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid planeindex %i (%i planes)\n", n, loadmodel->brushq3.num_planes); + out->plane = loadmodel->brushq3.data_planes + n; + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->brushq3.num_textures) + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid textureindex %i (%i textures)\n", n, loadmodel->brushq3.num_textures); + out->texture = loadmodel->brushq3.data_textures + n; } -*/ } -static void Mod_Q3BSP_LoadLeafs(lump_t *l) +static void Mod_Q3BSP_LoadBrushes(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dbrush_t *in; + q3mbrush_t *out; + int i, n, c, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadLeafs: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadBrushes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_brushes = out; + loadmodel->brushq3.num_brushes = count; for (i = 0;i < count;i++, in++, out++) { + n = LittleLong(in->firstbrushside); + c = LittleLong(in->numbrushsides); + if (n < 0 || n + c > loadmodel->brushq3.num_brushsides) + Host_Error("Mod_Q3BSP_LoadBrushes: invalid brushside range %i : %i (%i brushsides)\n", n, n + c, loadmodel->brushq3.num_brushsides); + out->firstbrushside = loadmodel->brushq3.data_brushsides + n; + out->numbrushsides = c; + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->brushq3.num_textures) + Host_Error("Mod_Q3BSP_LoadBrushes: invalid textureindex %i (%i textures)\n", n, loadmodel->brushq3.num_textures); + out->texture = loadmodel->brushq3.data_textures + n; } -*/ } -static void Mod_Q3BSP_LoadLeafFaces(lump_t *l) +static void Mod_Q3BSP_LoadEffects(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3deffect_t *in; + q3meffect_t *out; + int i, n, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadEffects: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_effects = out; + loadmodel->brushq3.num_effects = count; for (i = 0;i < count;i++, in++, out++) { + strncpy(out->shadername, in->shadername, sizeof(out->shadername) - 1); + n = LittleLong(in->brushindex); + if (n < 0 || n >= loadmodel->brushq3.num_brushes) + Host_Error("Mod_Q3BSP_LoadEffects: invalid brushindex %i (%i brushes)\n", n, loadmodel->brushq3.num_brushes); + out->brush = loadmodel->brushq3.data_brushes + n; + out->unknown = LittleLong(in->unknown); } -*/ } -static void Mod_Q3BSP_LoadLeafBrushes(lump_t *l) +static void Mod_Q3BSP_LoadVertices(lump_t *l) { -/* - d_t *in; - m_t *out; + q3dvertex_t *in; int i, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); - out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - - loadmodel-> = out; - loadmodel->num = count; - - for (i = 0;i < count;i++, in++, out++) - { + Host_Error("Mod_Q3BSP_LoadVertices: funny lump size in %s",loadmodel->name); + loadmodel->brushq3.num_vertices = count = l->filelen / sizeof(*in); + loadmodel->brushq3.data_vertex3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3])); + loadmodel->brushq3.data_texturetexcoord2f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[2])); + loadmodel->brushq3.data_lightmaptexcoord2f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[2])); + loadmodel->brushq3.data_svector3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3])); + loadmodel->brushq3.data_tvector3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3])); + loadmodel->brushq3.data_normal3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3])); + loadmodel->brushq3.data_color4f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[4])); + + for (i = 0;i < count;i++, in++) + { + loadmodel->brushq3.data_vertex3f[i * 3 + 0] = LittleFloat(in->origin3f[0]); + loadmodel->brushq3.data_vertex3f[i * 3 + 1] = LittleFloat(in->origin3f[1]); + loadmodel->brushq3.data_vertex3f[i * 3 + 2] = LittleFloat(in->origin3f[2]); + loadmodel->brushq3.data_texturetexcoord2f[i * 2 + 0] = LittleFloat(in->texcoord2f[0]); + loadmodel->brushq3.data_texturetexcoord2f[i * 2 + 1] = LittleFloat(in->texcoord2f[1]); + loadmodel->brushq3.data_lightmaptexcoord2f[i * 2 + 0] = LittleFloat(in->lightmap2f[0]); + loadmodel->brushq3.data_lightmaptexcoord2f[i * 2 + 1] = LittleFloat(in->lightmap2f[1]); + // svector/tvector are calculated later in face loading + loadmodel->brushq3.data_svector3f[i * 3 + 0] = 0; + loadmodel->brushq3.data_svector3f[i * 3 + 1] = 0; + loadmodel->brushq3.data_svector3f[i * 3 + 2] = 0; + loadmodel->brushq3.data_tvector3f[i * 3 + 0] = 0; + loadmodel->brushq3.data_tvector3f[i * 3 + 1] = 0; + loadmodel->brushq3.data_tvector3f[i * 3 + 2] = 0; + loadmodel->brushq3.data_normal3f[i * 3 + 0] = LittleFloat(in->normal3f[0]); + loadmodel->brushq3.data_normal3f[i * 3 + 1] = LittleFloat(in->normal3f[1]); + loadmodel->brushq3.data_normal3f[i * 3 + 2] = LittleFloat(in->normal3f[2]); + loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 3] = in->color4ub[3] * (1.0f / 255.0f); } -*/ } -static void Mod_Q3BSP_LoadModels(lump_t *l) +static void Mod_Q3BSP_LoadTriangles(lump_t *l) { -/* - d_t *in; - m_t *out; + int *in; + int *out; int i, count; in = (void *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadModels: funny lump size in %s",loadmodel->name); + if (l->filelen % sizeof(int[3])) + Host_Error("Mod_Q3BSP_LoadTriangles: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.num_triangles = count / 3; + loadmodel->brushq3.data_element3i = out; + loadmodel->brushq3.data_neighbor3i = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); for (i = 0;i < count;i++, in++, out++) { + *out = LittleLong(*in); + if (*out < 0 || *out >= loadmodel->brushq3.num_vertices) + Host_Error("Mod_Q3BSP_LoadTriangles: invalid vertexindex %i (%i vertices)\n", *out, loadmodel->brushq3.num_vertices); } -*/ } -static void Mod_Q3BSP_LoadBrushes(lump_t *l) +static void Mod_Q3BSP_LoadLightmaps(lump_t *l) { -/* - d_t *in; - m_t *out; + q3dlightmap_t *in; + rtexture_t **out; int i, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadBrushes: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadLightmaps: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_lightmaps = out; + loadmodel->brushq3.num_lightmaps = count; for (i = 0;i < count;i++, in++, out++) - { - } -*/ + *out = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), 128, 128, in->rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL); } -static void Mod_Q3BSP_LoadBrushSides(lump_t *l) +static void Mod_Q3BSP_LoadFaces(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dface_t *in; + q3mface_t *out; + int i, j, n, count, invalidelements, patchsize[2]; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadBrushSides: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadFaces: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_faces = out; + loadmodel->brushq3.num_faces = count; for (i = 0;i < count;i++, in++, out++) { + // check face type first + out->type = LittleLong(in->type); + if (out->type != Q3FACETYPE_POLYGON + && out->type != Q3FACETYPE_PATCH + && out->type != Q3FACETYPE_MESH + && out->type != Q3FACETYPE_FLARE) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, n); + out->type = 0; // error + continue; + } + + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->brushq3.num_textures) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->brushq3.num_textures); + out->type = 0; // error + continue; + n = 0; + } + out->texture = loadmodel->brushq3.data_textures + n; + n = LittleLong(in->effectindex); + if (n < -1 || n >= loadmodel->brushq3.num_effects) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects); + n = -1; + } + if (n == -1) + out->effect = NULL; + else + out->effect = loadmodel->brushq3.data_effects + n; + n = LittleLong(in->lightmapindex); + if (n < -1 || n >= loadmodel->brushq3.num_lightmaps) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps); + n = -1; + } + if (n == -1) + out->lightmaptexture = NULL; + else + out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n]; + + out->firstvertex = LittleLong(in->firstvertex); + out->numvertices = LittleLong(in->numvertices); + out->firstelement = LittleLong(in->firstelement); + out->numelements = LittleLong(in->numelements); + out->numtriangles = out->numelements / 3; + if (out->firstvertex < 0 || out->firstvertex + out->numvertices > loadmodel->brushq3.num_vertices) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, out->firstvertex, out->firstvertex + out->numvertices, loadmodel->brushq3.num_vertices); + out->type = 0; // error + continue; + } + if (out->firstelement < 0 || out->firstelement + out->numelements > loadmodel->brushq3.num_triangles * 3) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, out->firstelement, out->firstelement + out->numelements, loadmodel->brushq3.num_triangles * 3); + out->type = 0; // error + continue; + } + if (out->numtriangles * 3 != out->numelements) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, out->numelements); + out->type = 0; // error + continue; + } + switch(out->type) + { + case Q3FACETYPE_POLYGON: + case Q3FACETYPE_MESH: + out->data_vertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3; + out->data_texturetexcoord2f = loadmodel->brushq3.data_texturetexcoord2f + out->firstvertex * 2; + out->data_lightmaptexcoord2f = loadmodel->brushq3.data_lightmaptexcoord2f + out->firstvertex * 2; + out->data_svector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3; + out->data_tvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3; + out->data_normal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3; + out->data_color4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4; + out->data_element3i = loadmodel->brushq3.data_element3i + out->firstelement; + out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement; + break; + case Q3FACETYPE_PATCH: + patchsize[0] = LittleLong(in->specific.patch.patchsize[0]); + patchsize[1] = LittleLong(in->specific.patch.patchsize[1]); + if (patchsize[0] < 1 || patchsize[1] < 1) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]); + out->type = 0; // error + continue; + } + // FIXME: convert patch to triangles here! + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_PATCH not supported (yet)\n", i, out->texture->name); + out->type = 0; + continue; + break; + case Q3FACETYPE_FLARE: + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name); + out->type = 0; + continue; + break; + } + for (j = 0, invalidelements = 0;j < out->numelements;j++) + if (out->data_element3i[j] < 0 || out->data_element3i[j] >= out->numvertices) + invalidelements++; + if (invalidelements) + { + Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->contents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, out->type, out->texture->name, out->texture->surfaceflags, out->texture->contents, out->firstvertex, out->numvertices, out->firstelement, out->numelements); + for (j = 0;j < out->numelements;j++) + { + Con_Printf(" %i", out->data_element3i[j]); + if (out->data_element3i[j] < 0 || out->data_element3i[j] >= out->numvertices) + out->data_element3i[j] = 0; + } + Con_Printf("\n"); + } } -*/ } -static void Mod_Q3BSP_LoadVertices(lump_t *l) +static void Mod_Q3BSP_LoadModels(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dmodel_t *in; + q3mmodel_t *out; + int i, j, n, c, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadVertices: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadModels: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_models = out; + loadmodel->brushq3.num_models = count; for (i = 0;i < count;i++, in++, out++) { + for (j = 0;j < 3;j++) + { + out->mins[j] = LittleFloat(in->mins[j]); + out->maxs[j] = LittleFloat(in->maxs[j]); + } + n = LittleLong(in->firstface); + c = LittleLong(in->numfaces); + if (n < 0 || n + c > loadmodel->brushq3.num_faces) + Host_Error("Mod_Q3BSP_LoadModels: invalid face range %i : %i (%i faces)\n", n, n + c, loadmodel->brushq3.num_faces); + out->firstface = loadmodel->brushq3.data_faces + n; + out->numfaces = c; + n = LittleLong(in->firstbrush); + c = LittleLong(in->numbrushes); + if (n < 0 || n + c > loadmodel->brushq3.num_brushes) + Host_Error("Mod_Q3BSP_LoadModels: invalid brush range %i : %i (%i brushes)\n", n, n + c, loadmodel->brushq3.num_brushes); + out->firstbrush = loadmodel->brushq3.data_brushes + n; + out->numbrushes = c; } -*/ } -static void Mod_Q3BSP_LoadTriangles(lump_t *l) +static void Mod_Q3BSP_LoadLeafBrushes(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + int *in; + q3mbrush_t **out; + int i, n, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadTriangles: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_leafbrushes = out; + loadmodel->brushq3.num_leafbrushes = count; for (i = 0;i < count;i++, in++, out++) { + n = LittleLong(*in); + if (n < 0 || n >= loadmodel->brushq3.num_brushes) + Host_Error("Mod_Q3BSP_LoadLeafBrushes: invalid brush index %i (%i brushes)\n", n, loadmodel->brushq3.num_brushes); + *out = loadmodel->brushq3.data_brushes + n; } -*/ } -static void Mod_Q3BSP_LoadEffects(lump_t *l) +static void Mod_Q3BSP_LoadLeafFaces(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + int *in; + q3mface_t **out; + int i, n, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadEffects: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_leaffaces = out; + loadmodel->brushq3.num_leaffaces = count; for (i = 0;i < count;i++, in++, out++) { + n = LittleLong(*in); + if (n < 0 || n >= loadmodel->brushq3.num_faces) + Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)\n", n, loadmodel->brushq3.num_faces); + *out = loadmodel->brushq3.data_faces + n; } -*/ } -static void Mod_Q3BSP_LoadFaces(lump_t *l) +static void Mod_Q3BSP_LoadLeafs(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dleaf_t *in; + q3mleaf_t *out; + int i, j, n, c, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadFaces: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadLeafs: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_leafs = out; + loadmodel->brushq3.num_leafs = count; for (i = 0;i < count;i++, in++, out++) { + out->isnode = false; + out->parent = NULL; + out->clusterindex = LittleLong(in->clusterindex); + out->areaindex = LittleLong(in->areaindex); + for (j = 0;j < 3;j++) + { + // yes the mins/maxs are ints + out->mins[j] = LittleLong(in->mins[j]); + out->maxs[j] = LittleLong(in->maxs[j]); + } + n = LittleLong(in->firstleafface); + c = LittleLong(in->numleaffaces); + if (n < 0 || n + c > loadmodel->brushq3.num_leaffaces) + Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafface range %i : %i (%i leaffaces)\n", n, n + c, loadmodel->brushq3.num_leaffaces); + out->firstleafface = loadmodel->brushq3.data_leaffaces + n; + out->numleaffaces = c; + n = LittleLong(in->firstleafbrush); + c = LittleLong(in->numleafbrushes); + if (n < 0 || n + c > loadmodel->brushq3.num_leafbrushes) + Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafbrush range %i : %i (%i leafbrushes)\n", n, n + c, loadmodel->brushq3.num_leafbrushes); + out->firstleafbrush = loadmodel->brushq3.data_leafbrushes + n; + out->numleafbrushes = c; } -*/ } -static void Mod_Q3BSP_LoadLightmaps(lump_t *l) +static void Mod_Q3BSP_LoadNodes_RecursiveSetParent(q3mnode_t *node, q3mnode_t *parent) { -/* - d_t *in; - m_t *out; - int i, count; + if (node->parent) + Host_Error("Mod_Q3BSP_LoadNodes_RecursiveSetParent: runaway recursion\n"); + node->parent = parent; + if (node->isnode) + { + Mod_Q3BSP_LoadNodes_RecursiveSetParent(node->children[0], node); + Mod_Q3BSP_LoadNodes_RecursiveSetParent(node->children[1], node); + } +} + +static void Mod_Q3BSP_LoadNodes(lump_t *l) +{ + q3dnode_t *in; + q3mnode_t *out; + int i, j, n, count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadLightmaps: funny lump size in %s",loadmodel->name); + Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.data_nodes = out; + loadmodel->brushq3.num_nodes = count; for (i = 0;i < count;i++, in++, out++) { + out->isnode = true; + out->parent = NULL; + n = LittleLong(in->planeindex); + if (n < 0 || n >= loadmodel->brushq3.num_planes) + Host_Error("Mod_Q3BSP_LoadNodes: invalid planeindex %i (%i planes)\n", n, loadmodel->brushq3.num_planes); + out->plane = loadmodel->brushq3.data_planes + n; + for (j = 0;j < 2;j++) + { + n = LittleLong(in->childrenindex[j]); + if (n >= 0) + { + if (n >= loadmodel->brushq3.num_nodes) + Host_Error("Mod_Q3BSP_LoadNodes: invalid child node index %i (%i nodes)\n", n, loadmodel->brushq3.num_nodes); + out->children[j] = loadmodel->brushq3.data_nodes + n; + } + else + { + n = 1 - n; + if (n >= loadmodel->brushq3.num_leafs) + Host_Error("Mod_Q3BSP_LoadNodes: invalid child leaf index %i (%i leafs)\n", n, loadmodel->brushq3.num_leafs); + out->children[j] = (q3mnode_t *)(loadmodel->brushq3.data_leafs + n); + } + } + // we don't load the mins/maxs } -*/ + + // set the parent pointers + Mod_Q3BSP_LoadNodes_RecursiveSetParent(loadmodel->brushq3.data_nodes, NULL); } static void Mod_Q3BSP_LoadLightGrid(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dlightgrid_t *in; + q3dlightgrid_t *out; + int count; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error("Mod_Q3BSP_LoadLightGrid: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); + loadmodel->brushq3.num_lightgrid_scale[0] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[0]; + loadmodel->brushq3.num_lightgrid_scale[1] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[1]; + loadmodel->brushq3.num_lightgrid_scale[2] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[2]; + loadmodel->brushq3.num_lightgrid_imins[0] = ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]); + loadmodel->brushq3.num_lightgrid_imins[1] = ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]); + loadmodel->brushq3.num_lightgrid_imins[2] = ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]); + loadmodel->brushq3.num_lightgrid_imaxs[0] = floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]); + loadmodel->brushq3.num_lightgrid_imaxs[1] = floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]); + loadmodel->brushq3.num_lightgrid_imaxs[2] = floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]); + loadmodel->brushq3.num_lightgrid_isize[0] = loadmodel->brushq3.num_lightgrid_imaxs[0] - loadmodel->brushq3.num_lightgrid_imins[0] + 1; + loadmodel->brushq3.num_lightgrid_isize[1] = loadmodel->brushq3.num_lightgrid_imaxs[1] - loadmodel->brushq3.num_lightgrid_imins[1] + 1; + loadmodel->brushq3.num_lightgrid_isize[2] = loadmodel->brushq3.num_lightgrid_imaxs[2] - loadmodel->brushq3.num_lightgrid_imins[2] + 1; + count = loadmodel->brushq3.num_lightgrid_isize[0] * loadmodel->brushq3.num_lightgrid_isize[1] * loadmodel->brushq3.num_lightgrid_isize[2]; + if (l->filelen < count * (int)sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)\n", l->filelen, count * sizeof(*in), loadmodel->brushq3.num_lightgrid_dimensions[0], loadmodel->brushq3.num_lightgrid_dimensions[1], loadmodel->brushq3.num_lightgrid_dimensions[2]); + if (l->filelen != count * (int)sizeof(*in)) + Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i\n", count * sizeof(*in), l->filelen); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + loadmodel->brushq3.data_lightgrid = out; + loadmodel->brushq3.num_lightgrid = count; - loadmodel-> = out; - loadmodel->num = count; + // no swapping or validation necessary + memcpy(out, in, count * (int)sizeof(*out)); - for (i = 0;i < count;i++, in++, out++) - { - } -*/ + Matrix4x4_CreateScale3(&loadmodel->brushq3.num_lightgrid_indexfromworld, loadmodel->brushq3.num_lightgrid_scale[0], loadmodel->brushq3.num_lightgrid_scale[1], loadmodel->brushq3.num_lightgrid_scale[2]); + Matrix4x4_ConcatTranslate(&loadmodel->brushq3.num_lightgrid_indexfromworld, -loadmodel->brushq3.num_lightgrid_imins[0] * loadmodel->brushq3.num_lightgrid_cellsize[0], -loadmodel->brushq3.num_lightgrid_imins[1] * loadmodel->brushq3.num_lightgrid_cellsize[1], -loadmodel->brushq3.num_lightgrid_imins[2] * loadmodel->brushq3.num_lightgrid_cellsize[2]); } static void Mod_Q3BSP_LoadPVS(lump_t *l) { -/* - d_t *in; - m_t *out; - int i, count; + q3dpvs_t *in; + int totalchains; in = (void *)(mod_base + l->fileofs); - if (l->filelen % sizeof(*in)) + if (l->filelen < 9) Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name); - count = l->filelen / sizeof(*in); - out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); - loadmodel-> = out; - loadmodel->num = count; + loadmodel->brushq3.num_pvsclusters = LittleLong(in->numclusters); + loadmodel->brushq3.num_pvschainlength = LittleLong(in->chainlength); + if (loadmodel->brushq3.num_pvschainlength < ((loadmodel->brushq3.num_pvsclusters + 7) / 8)) + Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brushq3.num_pvschainlength, loadmodel->brushq3.num_pvsclusters); + totalchains = loadmodel->brushq3.num_pvschainlength * loadmodel->brushq3.num_pvsclusters; + if (l->filelen < totalchains + (int)sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)\n", loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.num_pvschainlength, totalchains + sizeof(*in), l->filelen); - for (i = 0;i < count;i++, in++, out++) - { - } -*/ + loadmodel->brushq3.data_pvschains = Mem_Alloc(loadmodel->mempool, totalchains); + memcpy(loadmodel->brushq3.data_pvschains, (qbyte *)(in + 1), totalchains); } void Mod_Q3BSP_Load(model_t *mod, void *buffer) { int i; q3dheader_t *header; - Host_Error("Mod_Q3BSP_Load: not yet implemented\n"); mod->type = mod_brushq2; @@ -3651,7 +3930,6 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) Mod_Q3BSP_LoadEntities(&header->lumps[Q3LUMP_ENTITIES]); Mod_Q3BSP_LoadTextures(&header->lumps[Q3LUMP_TEXTURES]); Mod_Q3BSP_LoadPlanes(&header->lumps[Q3LUMP_PLANES]); - Mod_Q3BSP_LoadNodes(&header->lumps[Q3LUMP_NODES]); Mod_Q3BSP_LoadBrushSides(&header->lumps[Q3LUMP_BRUSHSIDES]); Mod_Q3BSP_LoadBrushes(&header->lumps[Q3LUMP_BRUSHES]); Mod_Q3BSP_LoadEffects(&header->lumps[Q3LUMP_EFFECTS]); @@ -3663,13 +3941,14 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) Mod_Q3BSP_LoadLeafBrushes(&header->lumps[Q3LUMP_LEAFBRUSHES]); Mod_Q3BSP_LoadLeafFaces(&header->lumps[Q3LUMP_LEAFFACES]); Mod_Q3BSP_LoadLeafs(&header->lumps[Q3LUMP_LEAFS]); + Mod_Q3BSP_LoadNodes(&header->lumps[Q3LUMP_NODES]); Mod_Q3BSP_LoadLightGrid(&header->lumps[Q3LUMP_LIGHTGRID]); Mod_Q3BSP_LoadPVS(&header->lumps[Q3LUMP_PVS]); } void Mod_IBSP_Load(model_t *mod, void *buffer) { - int i = LittleLong(* ((int *)buffer)); + int i = LittleLong(((int *)buffer)[1]); if (i == Q3BSPVERSION) Mod_Q3BSP_Load(mod,buffer); else if (i == Q2BSPVERSION) diff --git a/model_brush.h b/model_brush.h index 83f11d2d..5772df21 100644 --- a/model_brush.h +++ b/model_brush.h @@ -668,7 +668,7 @@ q3deffect_t; #define Q3FACETYPE_POLYGON 1 // common #define Q3FACETYPE_PATCH 2 // common #define Q3FACETYPE_MESH 3 // common -#define Q3FACETYPE_BILLBOARD 4 // rare (is this ever used?) +#define Q3FACETYPE_FLARE 4 // rare (is this ever used?) typedef struct { @@ -679,19 +679,71 @@ typedef struct int numvertices; int firstelement; int numelements; - int lightmapindex; - int lightmap_base[2]; // only needed by lighting util - int lightmap_size[2]; // only needed by lighting util - float lightmap_origin[3]; // only needed by lighting util - float lightmap_vectors[2][3]; // only needed by lighting util - float normal[3]; // only needed by lighting util - int patchsize[2]; // size for Q3FACETYPE_PATCH + int lightmapindex; // -1 if none + int lightmap_base[2]; + int lightmap_size[2]; + union + { + struct + { + // corrupt or don't care + int blah[14]; + } + unknown; + struct + { + // Q3FACETYPE_POLYGON + // polygon is simply a convex polygon, renderable as a mesh + float lightmap_origin[3]; + float lightmap_vectors[2][3]; + float normal[3]; + int unused1[2]; + } + polygon; + struct + { + // Q3FACETYPE_PATCH + // patch renders as a bezier mesh, with adjustable tesselation + // level (optionally based on LOD using the bbox and polygon + // count to choose a tesselation level) + // note: multiple patches may have the same bbox to cause them to + // be LOD adjusted together as a group + int unused1[3]; + float mins[3]; // LOD bbox + float maxs[3]; // LOD bbox + int unused2[3]; + int patchsize[2]; // dimensions of vertex grid + } + patch; + struct + { + // Q3FACETYPE_MESH + // mesh renders as simply a triangle mesh + int unused1[3]; + float mins[3]; + float maxs[3]; + int unused2[5]; + } + mesh; + struct + { + // Q3FACETYPE_FLARE + // flare renders as a simple sprite at origin, no geometry + // exists, nor does it have a radius, a cvar controls the radius + // and another cvar controls distance fade + // (they were not used in Q3 I'm told) + float origin[3]; + int unused1[11]; + } + flare; + } + specific; } q3dface_t; typedef struct { - unsigned char rgb[128][128][3]; + unsigned char rgb[128*128*3]; } q3dlightmap_t; diff --git a/model_shared.h b/model_shared.h index 0265d892..e9027c9e 100644 --- a/model_shared.h +++ b/model_shared.h @@ -243,8 +243,8 @@ q3mtexture_t; typedef struct q3mnode_s { int isnode; // true - struct mplane_s *plane; struct q3mnode_s *parent; + struct mplane_s *plane; struct q3mnode_s *children[2]; } q3mnode_t; @@ -252,14 +252,15 @@ q3mnode_t; typedef struct q3mleaf_s { int isnode; // false + struct q3mnode_s *parent; int clusterindex; int areaindex; - vec3_t mins[3]; - vec3_t maxs[3]; int numleaffaces; - struct q3mface_s **leaffaces; + struct q3mface_s **firstleafface; int numleafbrushes; - struct q3mbrush_s **leafbrushes; + struct q3mbrush_s **firstleafbrush; + vec3_t mins; + vec3_t maxs; } q3mleaf_t; @@ -268,16 +269,16 @@ typedef struct q3mmodel_s vec3_t mins; vec3_t maxs; int numfaces; - struct q3mface_s *faces; + struct q3mface_s *firstface; int numbrushes; - struct q3mbrush_s *brushes; + struct q3mbrush_s *firstbrush; } q3mmodel_t; typedef struct q3mbrush_s { - int numsides; - struct q3mbrushside_s *sides; + int numbrushsides; + struct q3mbrushside_s *firstbrushside; struct q3mtexture_s *texture; } q3mbrush_t; @@ -301,6 +302,7 @@ typedef struct q3mface_s { struct q3mtexture_s *texture; struct q3meffect_s *effect; + rtexture_t *lightmaptexture; int type; int firstvertex; int numvertices; @@ -315,6 +317,9 @@ typedef struct q3mface_s float *data_tvector3f; float *data_normal3f; float *data_color4f; + int numtriangles; + int *data_element3i; + int *data_neighbor3i; } q3mface_t; @@ -332,6 +337,12 @@ typedef struct model_brushq3_s int num_leafs; q3mleaf_t *data_leafs; + int num_leafbrushes; + q3mbrush_t **data_leafbrushes; + + int num_leaffaces; + q3mface_t **data_leaffaces; + int num_models; q3mmodel_t *data_models; // each submodel gets its own model struct so this is different for each. @@ -347,6 +358,8 @@ typedef struct model_brushq3_s float *data_vertex3f; float *data_texturetexcoord2f; float *data_lightmaptexcoord2f; + float *data_svector3f; + float *data_tvector3f; float *data_normal3f; float *data_color4f; @@ -355,18 +368,30 @@ typedef struct model_brushq3_s int *data_neighbor3i; int num_effects; - q3meffect_t data_effects; + q3meffect_t *data_effects; int num_faces; q3mface_t *data_faces; // lightmap textures int num_lightmaps; - rtexture_t *data_lightmaps; - - // transform world coordinates to lightgrid index + rtexture_t **data_lightmaps; + + // voxel light data with directional shading + int num_lightgrid; + q3dlightgrid_t *data_lightgrid; + // size of each cell (may vary by map, typically 64 64 128) + float num_lightgrid_cellsize[3]; + // 1.0 / num_lightgrid_cellsize + float num_lightgrid_scale[3]; + // dimensions of the world model in lightgrid cells + int num_lightgrid_imins[3]; + int num_lightgrid_imaxs[3]; + int num_lightgrid_isize[3]; + // indexing/clamping + int num_lightgrid_dimensions[3]; + // transform modelspace coordinates to lightgrid index matrix4x4_t num_lightgrid_indexfromworld; - q3dlightgrid_t *data_lightgrid_cells; // pvs int num_pvsclusters;