From 53d69f98e518f9bc959f28b300041a4d8170d8c9 Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Sun, 14 Apr 2024 10:38:50 +0300 Subject: [PATCH] collision: create IBSP -> QBSP convert logic --- src/common/cmodels.c | 495 ++++++++++++++++++++++++++++++++++++- src/common/collision.c | 25 +- src/common/header/cmodel.h | 2 + 3 files changed, 499 insertions(+), 23 deletions(-) diff --git a/src/common/cmodels.c b/src/common/cmodels.c index bbc03ad5..fdd2f5d5 100644 --- a/src/common/cmodels.c +++ b/src/common/cmodels.c @@ -253,7 +253,7 @@ Mod_MaptypeName(maptype_t maptype) return maptypename; } -maptype_t +static maptype_t Mod_LoadGetRules(const dheader_t *header, const size_t **rules) { if (header->ident == IDBSPHEADER) @@ -281,27 +281,25 @@ Mod_LoadGetRules(const dheader_t *header, const size_t **rules) return map_daikatana; } } - else + else if (header->version == BSPVERSION) { *rules = idbsplumps; return map_quake2; } } - else if (header->ident == QBSPHEADER) + else if (header->ident == QBSPHEADER && header->version == BSPVERSION) { *rules = qbsplumps; return map_quake2; } - else if (header->ident == RBSPHEADER) + else if (header->ident == RBSPHEADER && header->version == BSPSINVERSION) { *rules = rbsplumps; return map_sin; } - else - { - *rules = NULL; - return map_quake2; - } + + *rules = NULL; + return map_quake2; } maptype_t @@ -381,3 +379,482 @@ Mod_LoadSurfConvertFlags(int flags, maptype_t maptype) return sflags; } + +byte * +Mod_Load2QBSP(const char *name, byte *inbuf, size_t filesize, size_t *out_len, + maptype_t *maptype) +{ + const size_t *rules = NULL; + size_t result_size; + dheader_t header, *outheader; + int s, xofs, numlumps; + qboolean error = false; + byte *outbuf; + + for (s = 0; s < sizeof(dheader_t) / 4; s++) + { + ((int *)&header)[s] = LittleLong(((int *)inbuf)[s]); + } + + result_size = sizeof(dheader_t); + + *maptype = Mod_LoadGetRules(&header, &rules); + + if (rules) + { + for (s = 0; s < HEADER_LUMPS; s++) + { + if (rules[s]) + { + if (header.lumps[s].filelen % rules[s]) + { + Com_Printf("%s: Map %s lump #%d: incorrect size %d / " YQ2_COM_PRIdS "\n", + __func__, name, s, header.lumps[s].filelen, rules[s]); + error = true; + } + + result_size += ( + qbsplumps[s] * header.lumps[s].filelen / rules[s] + ); + } + } + } + + Com_Printf("Map %s %c%c%c%c with version %d (%s)\n", + name, + (header.ident >> 0) & 0xFF, + (header.ident >> 8) & 0xFF, + (header.ident >> 16) & 0xFF, + (header.ident >> 24) & 0xFF, + header.version, Mod_MaptypeName(*maptype)); + + if (error || !rules) + { + Com_Error(ERR_DROP, "%s: Map %s has incorrect lumps", + __func__, name); + } + + /* find end of last lump */ + xofs = 0; + + numlumps = HEADER_LUMPS; + if ((header.version == BSPDKMVERSION) && + (*maptype == map_daikatana)) + { + numlumps = 21; + } + + for (s = 0; s < numlumps; s++) + { + xofs = Q_max(xofs, + (header.lumps[s].fileofs + header.lumps[s].filelen + 3) & ~3); + } + + if (xofs + sizeof(bspx_header_t) < filesize) + { + result_size += (filesize - xofs); + } + + result_size += 4; + outbuf = malloc(result_size); + outheader = (dheader_t*)outbuf; + outheader->ident = QBSPHEADER; + outheader->version = BSPVERSION; + int ofs = sizeof(dheader_t); + + /* mark offsets for all lumps */ + for (s = 0; s < HEADER_LUMPS; s++) + { + if (rules[s]) + { + outheader->lumps[s].fileofs = ofs; + outheader->lumps[s].filelen = ( + qbsplumps[s] * header.lumps[s].filelen / rules[s] + ); + ofs += outheader->lumps[s].filelen; + } + } + + if ((filesize - xofs) > 0) + { + bspx_header_t *bspx_header; + bspx_lump_t *lump; + int numlumps, i; + + ofs = ((ofs + 3) & ~3); + bspx_header = (bspx_header_t *)(outbuf + ofs); + + /* copy BSPX */ + memcpy(bspx_header, inbuf + xofs, (filesize - xofs)); + + /* fix positions */ + numlumps = LittleLong(bspx_header->numlumps); + + lump = (bspx_lump_t*)(bspx_header + 1); + for (i = 0; i < numlumps; i++, lump++) + { + int fileofs; + + /* move fileofs to correct place */ + fileofs = LittleLong(lump->fileofs); + fileofs += (ofs - xofs); + lump->fileofs = LittleLong(fileofs); + } + } + + /* Copy LUMP_ENTITIES */ + memcpy(outbuf + outheader->lumps[LUMP_ENTITIES].fileofs, + inbuf + header.lumps[LUMP_ENTITIES].fileofs, + header.lumps[LUMP_ENTITIES].filelen); + + /* Copy LUMP_PLANES */ + { + int i, count = header.lumps[LUMP_PLANES].filelen / rules[LUMP_PLANES]; + dplane_t *in, *out; + + in = (dplane_t *)(inbuf + header.lumps[LUMP_PLANES].fileofs); + out = (dplane_t *)(outbuf + outheader->lumps[LUMP_PLANES].fileofs); + + for (i = 0; i < count; i++) + { + int j; + + for (j = 0; j < 3; j++) + { + out->normal[j] = LittleFloat(in->normal[j]); + } + + out->dist = LittleFloat(in->dist); + out->type = LittleLong(in->type); + + out++; + in++; + } + } + + /* Copy LUMP_VERTEXES */ + { + int i, count = header.lumps[LUMP_VERTEXES].filelen / rules[LUMP_VERTEXES]; + dvertex_t *in, *out; + + in = (dvertex_t *)(inbuf + header.lumps[LUMP_VERTEXES].fileofs); + out = (dvertex_t *)(outbuf + outheader->lumps[LUMP_VERTEXES].fileofs); + + for (i = 0; i < count; i++) + { + int j; + + for (j = 0; j < 3; j++) + { + out->point[j] = LittleFloat(in->point[j]); + } + + out++; + in++; + } + } + + /* Copy LUMP_VISIBILITY */ + memcpy(outbuf + outheader->lumps[LUMP_VISIBILITY].fileofs, + inbuf + header.lumps[LUMP_VISIBILITY].fileofs, + header.lumps[LUMP_VISIBILITY].filelen); + + /* Copy LUMP_NODES */ + { + int i, count = header.lumps[LUMP_NODES].filelen / rules[LUMP_NODES]; + dnode_t *in; + dqnode_t *out; + + in = (dnode_t *)(inbuf + header.lumps[LUMP_NODES].fileofs); + out = (dqnode_t *)(outbuf + outheader->lumps[LUMP_NODES].fileofs); + + for (i = 0; i < count; i++) + { + int j; + + for (j = 0; j < 3; j++) + { + out->mins[j] = LittleShort(in->mins[j]); + out->maxs[3 + j] = LittleShort(in->maxs[j]); + } + + out->planenum = LittleLong(in->planenum); + out->firstface = LittleShort(in->firstface) & 0xFFFF; + out->numfaces = LittleShort(in->numfaces) & 0xFFFF; + + for (j = 0; j < 2; j++) + { + out->children[j] = LittleLong(in->children[j]); + } + + out++; + in++; + } + } + + /* Copy LUMP_TEXINFO */ + { + int i, count = header.lumps[LUMP_TEXINFO].filelen / rules[LUMP_TEXINFO]; + texinfo_t *in; + texinfo_t *out; + + in = (texinfo_t *)(inbuf + header.lumps[LUMP_TEXINFO].fileofs); + out = (texinfo_t *)(outbuf + outheader->lumps[LUMP_TEXINFO].fileofs); + + for (i = 0; i < count; i++) + { + int j; + + for (j = 0; j < 4; j++) + { + out->vecs[0][j] = LittleFloat(in->vecs[0][j]); + out->vecs[1][j] = LittleFloat(in->vecs[1][j]); + } + + out->flags = LittleLong(in->flags); + out->nexttexinfo = LittleLong(in->nexttexinfo); + strncpy(out->texture, in->texture, + Q_min(sizeof(out->texture), sizeof(in->texture))); + + out++; + in++; + } + } + + /* Copy LUMP_FACES */ + { + int i, count = header.lumps[LUMP_FACES].filelen / rules[LUMP_FACES]; + dface_t *in; + dqface_t *out; + + in = (dface_t *)(inbuf + header.lumps[LUMP_FACES].fileofs); + out = (dqface_t *)(outbuf + outheader->lumps[LUMP_FACES].fileofs); + + for (i = 0; i < count; i++) + { + out->planenum = LittleShort(in->planenum); + out->side = LittleShort(in->side); + out->firstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->texinfo = LittleShort(in->texinfo); + memcpy(out->styles, in->styles, Q_min(sizeof(out->styles), sizeof(in->styles))); + out->lightofs = LittleLong(in->lightofs) & 0xFFFFFFFF; + + out++; + in++; + } + } + + /* Copy LUMP_LIGHTING */ + memcpy(outbuf + outheader->lumps[LUMP_LIGHTING].fileofs, + inbuf + header.lumps[LUMP_LIGHTING].fileofs, + header.lumps[LUMP_LIGHTING].filelen); + + /* Copy LUMP_LEAFS */ + { + int i, count = header.lumps[LUMP_LEAFS].filelen / rules[LUMP_LEAFS]; + dleaf_t *in; + dqleaf_t *out; + + in = (dleaf_t *)(inbuf + header.lumps[LUMP_LEAFS].fileofs); + out = (dqleaf_t *)(outbuf + outheader->lumps[LUMP_LEAFS].fileofs); + + for (i = 0; i < count; i++) + { + int j; + + for (j = 0; j < 3; j++) + { + out->mins[j] = LittleShort(in->mins[j]); + out->maxs[3 + j] = LittleShort(in->maxs[j]); + } + + out->contents = LittleLong(in->contents); + out->cluster = LittleShort(in->cluster); + out->area = LittleShort(in->area); + + /* make unsigned long from signed short */ + out->firstleafface = LittleShort(in->firstleafface) & 0xFFFF; + out->numleaffaces = LittleShort(in->numleaffaces) & 0xFFFF; + out->firstleafbrush = LittleShort(in->firstleafbrush) & 0xFFFF; + out->numleafbrushes = LittleShort(in->numleafbrushes) & 0xFFFF; + + out++; + in++; + } + } + + /* Copy LUMP_LEAFFACES */ + { + int i, count = header.lumps[LUMP_LEAFFACES].filelen / rules[LUMP_LEAFFACES]; + short *in; + int *out; + + in = (short *)(inbuf + header.lumps[LUMP_LEAFFACES].fileofs); + out = (int *)(outbuf + outheader->lumps[LUMP_LEAFFACES].fileofs); + + for (i = 0; i < count; i++) + { + *out = LittleShort(*in) & 0xFFFF; + + out++; + in++; + } + } + + /* Copy LUMP_LEAFBRUSHES */ + { + int i, count = header.lumps[LUMP_LEAFBRUSHES].filelen / rules[LUMP_LEAFBRUSHES]; + short *in; + int *out; + + in = (short *)(inbuf + header.lumps[LUMP_LEAFBRUSHES].fileofs); + out = (int *)(outbuf + outheader->lumps[LUMP_LEAFBRUSHES].fileofs); + + for (i = 0; i < count; i++) + { + *out = LittleLong(*in); + + out++; + in++; + } + } + + /* Copy LUMP_EDGES */ + { + int i, count = header.lumps[LUMP_EDGES].filelen / rules[LUMP_EDGES]; + dedge_t *in; + dqedge_t *out; + + in = (dedge_t *)(inbuf + header.lumps[LUMP_EDGES].fileofs); + out = (dqedge_t *)(outbuf + outheader->lumps[LUMP_EDGES].fileofs); + + for (i = 0; i < count; i++) + { + out->v[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + + out++; + in++; + } + } + + /* Copy LUMP_SURFEDGES */ + { + int i, count = header.lumps[LUMP_SURFEDGES].filelen / rules[LUMP_SURFEDGES]; + short *in; + int *out; + + in = (short *)(inbuf + header.lumps[LUMP_SURFEDGES].fileofs); + out = (int *)(outbuf + outheader->lumps[LUMP_SURFEDGES].fileofs); + + for (i = 0; i < count; i++) + { + *out = LittleLong(*in); + + out++; + in++; + } + } + + /* Copy LUMP_MODELS */ + { + int i, count = header.lumps[LUMP_MODELS].filelen / rules[LUMP_MODELS]; + dmodel_t *in; + dmodel_t *out; + + in = (dmodel_t *)(inbuf + header.lumps[LUMP_MODELS].fileofs); + out = (dmodel_t *)(outbuf + outheader->lumps[LUMP_MODELS].fileofs); + + for (i = 0; i < count; i++) + { + int j; + + for (j = 0; j < 3; j++) + { + out->mins[j] = LittleFloat(in->mins[j]); + out->maxs[j] = LittleFloat(in->maxs[j]); + out->origin[j] = LittleFloat(in->origin[j]); + } + + out->headnode = LittleLong(in->headnode); + out->firstface = LittleLong(in->firstface); + out->numfaces = LittleLong(in->numfaces); + + out++; + in++; + } + } + + /* Copy LUMP_BRUSHES */ + { + int i, count = header.lumps[LUMP_BRUSHES].filelen / rules[LUMP_BRUSHES]; + dbrush_t *in; + dbrush_t *out; + + in = (dbrush_t *)(inbuf + header.lumps[LUMP_BRUSHES].fileofs); + out = (dbrush_t *)(outbuf + outheader->lumps[LUMP_BRUSHES].fileofs); + + for (i = 0; i < count; i++) + { + out->firstside = LittleLong(in->firstside) & 0xFFFFFFFF; + out->numsides = LittleLong(in->numsides) & 0xFFFFFFFF; + out->contents = LittleLong(in->contents); + + out++; + in++; + } + } + + /* Copy LUMP_BRUSHSIDES */ + { + int i, count = header.lumps[LUMP_BRUSHSIDES].filelen / rules[LUMP_BRUSHSIDES]; + dbrushside_t *in; + dqbrushside_t *out; + + in = (dbrushside_t *)(inbuf + header.lumps[LUMP_BRUSHSIDES].fileofs); + out = (dqbrushside_t *)(outbuf + outheader->lumps[LUMP_BRUSHSIDES].fileofs); + + for (i = 0; i < count; i++) + { + out->planenum = LittleShort(in->planenum); + out->texinfo = LittleShort(in->texinfo); + + out++; + in++; + } + } + + /* Copy LUMP_AREAS */ + { + int i, count = header.lumps[LUMP_AREAS].filelen / rules[LUMP_AREAS]; + darea_t *in; + darea_t *out; + + in = (darea_t *)(inbuf + header.lumps[LUMP_AREAS].fileofs); + out = (darea_t *)(outbuf + outheader->lumps[LUMP_AREAS].fileofs); + + for (i = 0; i < count; i++) + { + out->numareaportals = LittleLong(in->numareaportals); + out->firstareaportal = LittleLong(in->firstareaportal); + + out++; + in++; + } + } + + /* Copy LUMP_AREAPORTALS */ + { + int count = header.lumps[LUMP_AREAPORTALS].filelen / rules[LUMP_AREAPORTALS]; + dareaportal_t *in; + dareaportal_t *out; + + in = (dareaportal_t *)(inbuf + header.lumps[LUMP_AREAPORTALS].fileofs); + out = (dareaportal_t *)(outbuf + outheader->lumps[LUMP_AREAPORTALS].fileofs); + memcpy(out, in, sizeof(dareaportal_t) * count); + } + + *out_len = result_size; + return outbuf; +} diff --git a/src/common/collision.c b/src/common/collision.c index 69f4822d..52ab2e6a 100644 --- a/src/common/collision.c +++ b/src/common/collision.c @@ -2067,29 +2067,27 @@ CM_ModFreeAll(void) static void CM_LoadCachedMap(const char *name, model_t *mod) { - int i, length, hunkSize = 0; + int filelen, hunkSize = 0; const byte *cmod_base; maptype_t maptype; dheader_t header; - unsigned *buf; + size_t length; + byte *buf, *filebuf; - length = FS_LoadFile(name, (void **)&buf); + filelen = FS_LoadFile(name, (void **)&filebuf); - if (!buf || length <= 0) + if (!filebuf || filelen <= 0) { Com_Printf("%s: Couldn't load %s\n", __func__, name); return; } - mod->checksum = LittleLong(Com_BlockChecksum(buf, length)); + mod->checksum = LittleLong(Com_BlockChecksum(filebuf, filelen)); + + buf = Mod_Load2QBSP(name, (byte *)filebuf, filelen, &length, &maptype); header = *(dheader_t *)buf; - for (i = 0; i < sizeof(dheader_t) / 4; i++) - { - ((int *)&header)[i] = LittleLong(((int *)&header)[i]); - } - if ((header.ident != IDBSPHEADER) && (header.ident != RBSPHEADER) && (header.ident != QBSPHEADER)) @@ -2123,8 +2121,6 @@ CM_LoadCachedMap(const char *name, model_t *mod) __func__, name, header.version, BSPSINVERSION); } - maptype = Mod_LoadValidateLumps(name, &header); - cmod_base = (byte *)buf; /* load into heap */ @@ -2297,7 +2293,7 @@ CM_LoadCachedMap(const char *name, model_t *mod) if (!mod->map_vis) { - Com_Error(ERR_DROP, "%s: Map %s has visual clusters.", + Com_Error(ERR_DROP, "%s: Map %s has no visual clusters.", __func__, name); } @@ -2314,7 +2310,8 @@ CM_LoadCachedMap(const char *name, model_t *mod) Com_DPrintf("Allocated %d from expected %d hunk size\n", mod->extradatasize, hunkSize); - FS_FreeFile(buf); + free(buf); + FS_FreeFile(filebuf); } /* diff --git a/src/common/header/cmodel.h b/src/common/header/cmodel.h index 8a4a5efd..ead1c785 100644 --- a/src/common/header/cmodel.h +++ b/src/common/header/cmodel.h @@ -56,5 +56,7 @@ extern void Mod_LoadVisibility(const char *name, dvis_t **vis, int *numvisibilit extern void Mod_LoadPlanes(const char *name, cplane_t **planes, int *numplanes, const byte *mod_base, const lump_t *l); extern maptype_t Mod_LoadValidateLumps(const char *name, const dheader_t *header); +extern byte *Mod_Load2QBSP(const char *name, byte *in, size_t filesize, + size_t *out_len, maptype_t *maptype); #endif