diff --git a/README.md b/README.md index cc19851a..2691298d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ State: * base1: correct wall light, broken model light * base2: correct wall light, broken model light, broken lift * q64/outpost: no known issies - * mguhub: loaded, transparent walls + * mguhub: loaded, transparent walls and broken logic for surface fall in next maps * GL3/GLES3: * base1: broken wall light, broken model light * base2: broken wall light, broken model light, broken lift @@ -28,7 +28,7 @@ State: * base1: correct wall light, broken model light * base2: correct wall light, broken model light, broken lift * q64/outpost: no known issies - * mguhub: loaded, transparent walls + * mguhub: loaded, transparent walls and broken logic for surface fall in next maps Goals (none of it finished): * Single player support diff --git a/src/client/refresh/gl1/gl1_model.c b/src/client/refresh/gl1/gl1_model.c index c0c5b37f..aee5a601 100644 --- a/src/client/refresh/gl1/gl1_model.c +++ b/src/client/refresh/gl1/gl1_model.c @@ -327,8 +327,7 @@ static void Mod_CalcSurfaceExtents(model_t *loadmodel, msurface_t *s) { float mins[2], maxs[2], val; - int i, j, e; - mvertex_t *v; + int i; mtexinfo_t *tex; int bmins[2], bmaxs[2]; @@ -339,6 +338,9 @@ Mod_CalcSurfaceExtents(model_t *loadmodel, msurface_t *s) for (i = 0; i < s->numedges; i++) { + int e, j; + mvertex_t *v; + e = loadmodel->surfedges[s->firstedge + i]; if (e >= 0) diff --git a/src/client/refresh/vk/vk_model.c b/src/client/refresh/vk/vk_model.c index b79c5f08..447c5555 100644 --- a/src/client/refresh/vk/vk_model.c +++ b/src/client/refresh/vk/vk_model.c @@ -260,7 +260,7 @@ CalcSurfaceExtents(model_t *loadmodel, msurface_t *s) } static int -calcTexinfoAndFacesSize(const lump_t *fl, const byte *mod_base, const lump_t *tl) +calcTexinfoAndFacesSize(const byte *mod_base, const lump_t *fl, const lump_t *tl) { dface_t* face_in = (void *)(mod_base + fl->fileofs); texinfo_t* texinfo_in = (void *)(mod_base + tl->fileofs); @@ -335,7 +335,83 @@ calcTexinfoAndFacesSize(const lump_t *fl, const byte *mod_base, const lump_t *tl return ret; } -// Extension to support lightmaps that aren't tied to texture scale. +static int +calcTexinfoAndQFacesSize(const byte *mod_base, const lump_t *fl, const lump_t *tl) +{ + dqface_t* face_in = (void *)(mod_base + fl->fileofs); + texinfo_t* texinfo_in = (void *)(mod_base + tl->fileofs); + + if (fl->filelen % sizeof(*face_in) || tl->filelen % sizeof(*texinfo_in)) + { + // will error out when actually loading it + return 0; + } + + int ret = 0; + + int face_count = fl->filelen / sizeof(*face_in); + int texinfo_count = tl->filelen / sizeof(*texinfo_in); + + { + // out = Hunk_Alloc(count * sizeof(*out)); + int baseSize = face_count * sizeof(msurface_t); + baseSize = (baseSize + 31) & ~31; + ret += baseSize; + + int ti_size = texinfo_count * sizeof(mtexinfo_t); + ti_size = (ti_size + 31) & ~31; + ret += ti_size; + } + + int numWarpFaces = 0; + + for (int surfnum = 0; surfnum < face_count; surfnum++, face_in++) + { + int numverts = LittleLong(face_in->numedges); + int ti = LittleLong(face_in->texinfo); + if ((ti < 0) || (ti >= texinfo_count)) + { + return 0; // will error out + } + int texFlags = LittleLong(texinfo_in[ti].flags); + + /* set the drawing flags */ + if (texFlags & SURF_WARP) + { + if (numverts > 60) + return 0; // will error out in R_SubdividePolygon() + + // Vk_SubdivideSurface(out, loadmodel); /* cut up polygon for warps */ + // for each (pot. recursive) call to R_SubdividePolygon(): + // sizeof(vkpoly_t) + ((numverts - 4) + 2) * VERTEXSIZE*sizeof(float) + + // this is tricky, how much is allocated depends on the size of the surface + // which we don't know (we'd need the vertices etc to know, but we can't load + // those without allocating...) + // so we just count warped faces and use a generous estimate below + + ++numWarpFaces; + } + else + { + // Vk_BuildPolygonFromSurface(out); + // => poly = Hunk_Alloc(sizeof(vkpoly_t) + (numverts - 4) * VERTEXSIZE*sizeof(float)); + int polySize = sizeof(vkpoly_t) + (numverts - 4) * VERTEXSIZE*sizeof(float); + polySize = (polySize + 31) & ~31; + ret += polySize; + } + } + + // yeah, this is a bit hacky, but it looks like for each warped face + // 256-55000 bytes are allocated (usually on the lower end), + // so just assume 48k per face to be safe + ret += numWarpFaces * 49152; + ret += 5000000; // and 5MB extra just in case + + return ret; +} + +/* Extension to support lightmaps that aren't tied to texture scale. */ static int Mod_LoadBSPXDecoupledLM(const dlminfo_t* lminfos, int surfnum, msurface_t *out) { @@ -398,11 +474,6 @@ SetSurfaceLighting(model_t *loadmodel, msurface_t *out, byte *styles, int lighto } } -/* -================= -Mod_LoadFaces -================= -*/ static void Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, const bspx_header_t *bspx_header) @@ -437,9 +508,7 @@ Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, for (surfnum = 0; surfnum < count; surfnum++, in++, out++) { - int side; - int ti; - int planenum; + int side, ti, planenum; out->firstedge = LittleLong(in->firstedge); out->numedges = LittleShort(in->numedges); @@ -500,6 +569,130 @@ Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, out->extents[i] = 16384; out->texturemins[i] = -8192; } + + Vk_SubdivideSurface(out, loadmodel); // cut up polygon for warps + } + + if (r_fixsurfsky->value) + { + if (out->texinfo->flags & SURF_SKY) + { + out->flags |= SURF_DRAWSKY; + } + } + + /* create lightmaps and polygons */ + if (!(out->texinfo->flags & (SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP))) + { + Vk_CreateSurfaceLightmap(out); + } + + if (!(out->texinfo->flags & SURF_WARP)) + { + Vk_BuildPolygonFromSurface(out, loadmodel); + } + } + + Vk_EndBuildingLightmaps(); +} + +static void +Mod_LoadQFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, + const bspx_header_t *bspx_header) +{ + int i, count, surfnum, lminfosize, lightofs; + const dlminfo_t *lminfos; + msurface_t *out; + dqface_t *in; + + in = (void *)(mod_base + l->fileofs); + + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc(count * sizeof(*out)); + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + lminfos = Mod_LoadBSPXFindLump(bspx_header, "DECOUPLED_LM", &lminfosize, mod_base); + if (lminfos != NULL && lminfosize / sizeof(dlminfo_t) != loadmodel->numsurfaces) { + R_Printf(PRINT_ALL, "%s: [%s] decoupled_lm size %ld does not match surface count %d\n", + __func__, loadmodel->name, lminfosize / sizeof(dlminfo_t), loadmodel->numsurfaces); + lminfos = NULL; + } + + Vk_BeginBuildingLightmaps(loadmodel); + + for (surfnum = 0; surfnum < count; surfnum++, in++, out++) + { + int side, ti, planenum; + + out->firstedge = LittleLong(in->firstedge); + out->numedges = LittleLong(in->numedges); + + if (out->numedges < 3) + { + ri.Sys_Error(ERR_DROP, "%s: Surface with %d edges", + __func__, out->numedges); + } + out->flags = 0; + out->polys = NULL; + + planenum = LittleLong(in->planenum); + side = LittleLong(in->side); + + if (side) + { + out->flags |= SURF_PLANEBACK; + } + + if (planenum < 0 || planenum >= loadmodel->numplanes) + { + ri.Sys_Error(ERR_DROP, "%s: Incorrect %d planenum.", + __func__, planenum); + } + out->plane = loadmodel->planes + planenum; + + ti = LittleLong(in->texinfo); + + if ((ti < 0) || (ti >= loadmodel->numtexinfo)) + { + ri.Sys_Error(ERR_DROP, "%s: bad texinfo number", + __func__); + } + + out->texinfo = loadmodel->texinfo + ti; + + lightofs = Mod_LoadBSPXDecoupledLM(lminfos, surfnum, out); + if (lightofs < 0) { + memcpy(out->lmvecs, out->texinfo->vecs, sizeof(out->lmvecs)); + out->lmshift = DEFAULT_LMSHIFT; + out->lmvlen[0] = 1.0f; + out->lmvlen[1] = 1.0f; + + CalcSurfaceExtents(loadmodel, out); + + lightofs = in->lightofs; + } + + SetSurfaceLighting(loadmodel, out, in->styles, lightofs); + + /* set the drawing flags */ + if (out->texinfo->flags & SURF_WARP) + { + out->flags |= SURF_DRAWTURB; + + for (i = 0; i < 2; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + Vk_SubdivideSurface(out, loadmodel); // cut up polygon for warps } @@ -571,19 +764,54 @@ Mod_LoadLeafs(model_t *loadmodel, const byte *mod_base, const lump_t *l) ri.Sys_Error(ERR_DROP, "%s: wrong marksurfaces position in %s", __func__, loadmodel->name); } + } +} - // gl underwater warp -#if 0 - if (out->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_THINWATER) ) +static void +Mod_LoadQLeafs(model_t *loadmodel, const byte *mod_base, const lump_t *l) +{ + dqleaf_t *in; + mleaf_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc(count * sizeof(*out)); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for (i = 0; i < count; i++, in++, out++) + { + unsigned firstleafface; + + for (j = 0; j < 3; j++) { - for (j=0 ; jnummarksurfaces ; j++) - { - out->firstmarksurface[j]->flags |= SURF_UNDERWATER; - for (poly = out->firstmarksurface[j]->polys ; poly ; poly=poly->next) - poly->flags |= SURF_UNDERWATER; - } + out->minmaxs[j] = LittleFloat(in->mins[j]); + out->minmaxs[3 + j] = LittleFloat(in->maxs[j]); + } + + out->contents = LittleLong(in->contents); + out->cluster = LittleLong(in->cluster); + out->area = LittleLong(in->area); + + // make unsigned long from signed short + firstleafface = LittleLong(in->firstleafface) & 0xFFFF; + out->nummarksurfaces = LittleLong(in->numleaffaces) & 0xFFFF; + + out->firstmarksurface = loadmodel->marksurfaces + firstleafface; + if ((firstleafface + out->nummarksurfaces) > loadmodel->nummarksurfaces) + { + ri.Sys_Error(ERR_DROP, "%s: wrong marksurfaces position in %s", + __func__, loadmodel->name); } -#endif } } @@ -624,6 +852,42 @@ Mod_LoadMarksurfaces(model_t *loadmodel, const byte *mod_base, const lump_t *l) } } +static void +Mod_LoadQMarksurfaces(model_t *loadmodel, const byte *mod_base, const lump_t *l) +{ + int i, count; + int *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + + if (l->filelen % sizeof(*in)) + { + ri.Sys_Error(ERR_DROP, "%s: funny lump size in %s", + __func__, loadmodel->name); + } + + count = l->filelen / sizeof(*in); + out = Hunk_Alloc(count * sizeof(*out)); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for (i = 0; i < count; i++) + { + int j; + j = LittleLong(in[i]); + + if ((j < 0) || (j >= loadmodel->numsurfaces)) + { + ri.Sys_Error(ERR_DROP, "%s: bad surface number", + __func__); + } + + out[i] = loadmodel->surfaces + j; + } +} + // calculate the size that Hunk_Alloc(), called by Mod_Load*() from Mod_LoadBrushModel(), // will use (=> includes its padding), so we'll know how big the hunk needs to be static int calcLumpHunkSize(const lump_t *l, int inSize, int outSize) @@ -644,13 +908,8 @@ static int calcLumpHunkSize(const lump_t *l, int inSize, int outSize) return size; } -/* -================= -Mod_LoadBrushModel -================= -*/ static void -Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) +Mod_LoadBrushModel(model_t *mod, const void *buffer, int modfilelen) { const bspx_header_t *bspx_header; byte *mod_base; @@ -659,6 +918,14 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) header = (dheader_t *)buffer; + i = LittleLong(header->ident); + + if (i != IDBSPHEADER && i != QDBSPHEADER) + { + ri.Sys_Error(ERR_DROP, "%s: %s has wrong ident (%i should be %i)", + __func__, mod->name, i, IDBSPHEADER); + } + i = LittleLong(header->version); if (i != BSPVERSION && i != BSPDKMVERSION) @@ -678,18 +945,41 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) // calculate the needed hunksize from the lumps int hunkSize = 0; hunkSize += calcLumpHunkSize(&header->lumps[LUMP_VERTEXES], sizeof(dvertex_t), sizeof(mvertex_t)); - hunkSize += calcLumpHunkSize(&header->lumps[LUMP_EDGES], sizeof(dedge_t), sizeof(medge_t)); + if (header->ident == IDBSPHEADER) + { + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_EDGES], sizeof(dedge_t), sizeof(medge_t)); + } + else + { + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_EDGES], sizeof(dedge_t), sizeof(medge_t)); + } hunkSize += sizeof(medge_t) + 31; // for count+1 in Mod_LoadEdges() int surfEdgeCount = (header->lumps[LUMP_SURFEDGES].filelen+sizeof(int)-1)/sizeof(int); if(surfEdgeCount < MAX_MAP_SURFEDGES) // else it errors out later anyway hunkSize += calcLumpHunkSize(&header->lumps[LUMP_SURFEDGES], sizeof(int), sizeof(int)); hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LIGHTING], 1, 1); hunkSize += calcLumpHunkSize(&header->lumps[LUMP_PLANES], sizeof(dplane_t), sizeof(cplane_t)*2); - hunkSize += calcTexinfoAndFacesSize(&header->lumps[LUMP_FACES], mod_base, &header->lumps[LUMP_TEXINFO]); - hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFFACES], sizeof(short), sizeof(msurface_t *)); // yes, out is indeed a pointer! + if (header->ident == IDBSPHEADER) + { + hunkSize += calcTexinfoAndFacesSize(mod_base, &header->lumps[LUMP_FACES], &header->lumps[LUMP_TEXINFO]); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFFACES], sizeof(short), sizeof(msurface_t *)); // yes, out is indeed a pointer! + } + else + { + hunkSize += calcTexinfoAndQFacesSize(mod_base, &header->lumps[LUMP_FACES], &header->lumps[LUMP_TEXINFO]); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFFACES], sizeof(int), sizeof(msurface_t *)); // yes, out is indeed a pointer! + } hunkSize += calcLumpHunkSize(&header->lumps[LUMP_VISIBILITY], 1, 1); - hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFS], sizeof(dleaf_t), sizeof(mleaf_t)); - hunkSize += calcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dnode_t), sizeof(mnode_t)); + if (header->ident == IDBSPHEADER) + { + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFS], sizeof(dleaf_t), sizeof(mleaf_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dnode_t), sizeof(mnode_t)); + } + else + { + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_LEAFS], sizeof(dqleaf_t), sizeof(mleaf_t)); + hunkSize += calcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dqnode_t), sizeof(mnode_t)); + } hunkSize += calcLumpHunkSize(&header->lumps[LUMP_MODELS], sizeof(dmodel_t), sizeof(model_t)); mod->extradata = Hunk_Begin(hunkSize); @@ -702,8 +992,16 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) /* load into heap */ Mod_LoadVertexes(mod->name, &mod->vertexes, &mod->numvertexes, mod_base, &header->lumps[LUMP_VERTEXES], 0); - Mod_LoadEdges(mod->name, &mod->edges, &mod->numedges, - mod_base, &header->lumps[LUMP_EDGES], 1); + if (header->ident == IDBSPHEADER) + { + Mod_LoadEdges(mod->name, &mod->edges, &mod->numedges, + mod_base, &header->lumps[LUMP_EDGES], 1); + } + else + { + Mod_LoadQEdges(mod->name, &mod->edges, &mod->numedges, + mod_base, &header->lumps[LUMP_EDGES], 1); + } Mod_LoadSurfedges(mod->name, &mod->surfedges, &mod->numsurfedges, mod_base, &header->lumps[LUMP_SURFEDGES], 0); Mod_LoadLighting(&mod->lightdata, mod_base, &header->lumps[LUMP_LIGHTING]); @@ -712,13 +1010,31 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) Mod_LoadTexinfo(mod->name, &mod->texinfo, &mod->numtexinfo, mod_base, &header->lumps[LUMP_TEXINFO], (findimage_t)Vk_FindImage, r_notexture, 0); - Mod_LoadFaces(mod, mod_base, &header->lumps[LUMP_FACES], bspx_header); - Mod_LoadMarksurfaces(mod, mod_base, &header->lumps[LUMP_LEAFFACES]); + if (header->ident == IDBSPHEADER) + { + Mod_LoadFaces(mod, mod_base, &header->lumps[LUMP_FACES], bspx_header); + Mod_LoadMarksurfaces(mod, mod_base, &header->lumps[LUMP_LEAFFACES]); + } + else + { + Mod_LoadQFaces(mod, mod_base, &header->lumps[LUMP_FACES], bspx_header); + Mod_LoadQMarksurfaces(mod, mod_base, &header->lumps[LUMP_LEAFFACES]); + } Mod_LoadVisibility(&mod->vis, mod_base, &header->lumps[LUMP_VISIBILITY]); - Mod_LoadLeafs(mod, mod_base, &header->lumps[LUMP_LEAFS]); - Mod_LoadNodes(mod->name, mod->planes, mod->numplanes, mod->leafs, - mod->numleafs, &mod->nodes, &mod->numnodes, mod_base, - &header->lumps[LUMP_NODES]); + if (header->ident == IDBSPHEADER) + { + Mod_LoadLeafs(mod, mod_base, &header->lumps[LUMP_LEAFS]); + Mod_LoadNodes(mod->name, mod->planes, mod->numplanes, mod->leafs, + mod->numleafs, &mod->nodes, &mod->numnodes, mod_base, + &header->lumps[LUMP_NODES]); + } + else + { + Mod_LoadQLeafs(mod, mod_base, &header->lumps[LUMP_LEAFS]); + Mod_LoadQNodes(mod->name, mod->planes, mod->numplanes, mod->leafs, + mod->numleafs, &mod->nodes, &mod->numnodes, mod_base, + &header->lumps[LUMP_NODES]); + } Mod_LoadSubmodels (mod, mod_base, &header->lumps[LUMP_MODELS]); mod->numframes = 2; /* regular and alternate animation */ } @@ -851,6 +1167,8 @@ Mod_ForName (const char *name, model_t *parent_model, qboolean crash) break; case IDBSPHEADER: + /* fall through */ + case QDBSPHEADER: Mod_LoadBrushModel(mod, buf, modfilelen); break; @@ -875,12 +1193,8 @@ Mod_ForName (const char *name, model_t *parent_model, qboolean crash) } /* -===================== -RE_BeginRegistration - -Specifies the model that will be used as the world -===================== -*/ + * Specifies the model that will be used as the world + */ void RE_BeginRegistration (char *model) { @@ -905,6 +1219,7 @@ RE_BeginRegistration (char *model) } r_worldmodel = Mod_ForName(fullname, NULL, true); + if (r_worldmodel != models_known) ri.Sys_Error(ERR_DROP, "%s: Loaded a brush model after the world", __func__); @@ -1004,13 +1319,8 @@ Mod_Modellist_f (void) R_Printf(PRINT_ALL, "Used %d of %d models%s.\n", used, mod_max, freeup ? ", has free space" : ""); } -/* -===================== -RE_EndRegistration - -===================== -*/ -void RE_EndRegistration (void) +void +RE_EndRegistration (void) { int i; model_t *mod; @@ -1021,7 +1331,7 @@ void RE_EndRegistration (void) return; } - for (i = 0, mod = models_known ; i < mod_numknown; i++, mod++) + for (i = 0, mod = models_known; i < mod_numknown; i++, mod++) { if (!mod->name[0]) {