diff --git a/src/p_setup.c b/src/p_setup.c index b74bf83a2398ea3725a7e758a724fe6909ca79f4..a0eb52bc89ff625a4aa6401b7b9aa93f8a01f93d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1476,6 +1476,208 @@ typedef enum { NT_UNSUPPORTED } nodetype_t; +static void P_LoadExtendedNodes(UINT8 *data, nodetype_t nodetype) +{ + size_t i, j, k; + INT16 m; + + /// Extended node formats feature additional vertexes; useful for OpenGL, but totally useless in gamelogic. + UINT32 orivtx, xtrvtx; + orivtx = READUINT32(data); + xtrvtx = READUINT32(data); + + if (numvertexes != orivtx) /// If native vertex count doesn't match node original vertex count, bail out (broken data?). + { + CONS_Alert(CONS_WARNING, "Vertex count in map data and nodes differ!\n"); + return; + } + + if (xtrvtx) /// If extra vertexes were generated, reallocate the vertex array and fix the pointers. + { + line_t *ld = lines; + size_t oldpos = (size_t)vertexes; + ssize_t offset; + numvertexes += xtrvtx; + vertexes = Z_Realloc(vertexes, numvertexes*sizeof(*vertexes), PU_LEVEL, NULL); + offset = ((size_t)vertexes) - oldpos; + + for (i = 0, ld = lines; i < numlines; i++, ld++) + { + ld->v1 = (vertex_t*)((size_t)ld->v1 + offset); + ld->v2 = (vertex_t*)((size_t)ld->v2 + offset); + } + } + + // Read vertex data. + for (i = orivtx; i < numvertexes; i++) + { + vertexes[i].x = READFIXED(data); + vertexes[i].y = READFIXED(data); + } + + // Subsectors + numsubsectors = READUINT32(data); + subsectors = Z_Calloc(numsubsectors*sizeof(*subsectors), PU_LEVEL, NULL); + + for (i = 0; i < numsubsectors; i++) + subsectors[i].numlines = READUINT32(data); + + // Segs + numsegs = READUINT32(data); + segs = Z_Calloc(numsegs*sizeof(*segs), PU_LEVEL, NULL); + + for (i = 0, k = 0; i < numsubsectors; i++) + { + subsectors[i].firstline = k; + + switch (nodetype) + { + case NT_XGLN: + for (m = 0; m < subsectors[i].numlines; m++, k++) + { + UINT16 linenum; + UINT32 vert; + vert = READUINT32(data); + segs[k].v1 = &vertexes[vert]; + if (m == 0) + segs[k + subsectors[i].numlines - 1].v2 = &vertexes[vert]; + else + segs[k - 1].v2 = segs[k].v1; + data += 4;// partner; can be ignored by software renderer; + linenum = READUINT16(data); + if (linenum == 0xFFFF) + { + segs[k].glseg = true; + segs[k].linedef = NULL; + } + else + { + segs[k].glseg = false; + segs[k].linedef = &lines[linenum]; + } + segs[k].side = READUINT8(data); + } + break; + + case NT_XGL3: + for (m = 0; m < subsectors[i].numlines; m++, k++) + { + UINT32 linenum; + UINT32 vert; + vert = READUINT32(data); + segs[k].v1 = &vertexes[vert]; + if (m == 0) + segs[k + subsectors[i].numlines - 1].v2 = &vertexes[vert]; + else + segs[k - 1].v2 = segs[k].v1; + data += 4;// partner; can be ignored by software renderer; + linenum = READUINT32(data); + if (linenum == 0xFFFFFFFF) + { + segs[k].glseg = true; + segs[k].linedef = NULL; + } + else + { + segs[k].glseg = false; + segs[k].linedef = NULL; + } + segs[k].side = READUINT8(data); + } + break; + + case NT_XNOD: + for (m = 0; m < subsectors[i].numlines; m++, k++) + { + segs[k].v1 = &vertexes[READUINT32(data)]; + segs[k].v2 = &vertexes[READUINT32(data)]; + segs[k].linedef = &lines[READUINT16(data)]; + segs[k].side = READUINT8(data); + } + break; + + default: + return; + } + } + + { + INT32 side; + seg_t *li; + + for (i = 0, li = segs; i < numsegs; i++, li++) + { + vertex_t *v1 = li->v1; + vertex_t *v2 = li->v2; + li->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); + li->offset = FixedHypot(v1->x - li->linedef->v1->x, v1->y - li->linedef->v1->y); + side = li->side; + li->sidedef = &sides[li->linedef->sidenum[side]]; + + li->frontsector = sides[li->linedef->sidenum[side]].sector; + if (li->linedef->flags & ML_TWOSIDED) + li->backsector = sides[li->linedef->sidenum[side ^ 1]].sector; + else + li->backsector = 0; + + segs[i].numlights = 0; + segs[i].rlights = NULL; + } + } + + // Nodes + numnodes = READINT32(data); + nodes = Z_Calloc(numnodes*sizeof(*nodes), PU_LEVEL, NULL); + if (nodetype == NT_XGL3) + { + UINT32 x, y, dx, dy; + UINT32 c0, c1; + node_t *mn; + for (i = 0, mn = nodes; i < numnodes; i++, mn++) + { + // Splitter. + x = READINT32(data); + y = READINT32(data); + dx = READINT32(data); + dy = READINT32(data); + mn->x = x; + mn->y = y; + mn->dx = dx; + mn->dy = dy; + + // Bounding boxes and children. + for (j = 0; j < 2; j++) + for (k = 0; k < 4; k++) + mn->bbox[j][k] = READINT16(data) << FRACBITS; + c0 = READUINT32(data); + c1 = READUINT32(data); + mn->children[0] = ShrinkNodeID(c0); /// \todo Use UINT32 for node children in a future, instead? + mn->children[1] = ShrinkNodeID(c1); + } + } + else + { + UINT32 c0, c1; + node_t *mn; + for (i = 0, mn = nodes; i < numnodes; i++, mn++) + { + // Splitter. + mn->x = READINT16(data) << FRACBITS; + mn->y = READINT16(data) << FRACBITS; + mn->dx = READINT16(data) << FRACBITS; + mn->dy = READINT16(data) << FRACBITS; + // Bounding boxes and children. + for (j = 0; j < 2; j++) + for (k = 0; k < 4; k++) + mn->bbox[j][k] = READINT16(data) << FRACBITS; + c0 = READUINT32(data); + c1 = READUINT32(data); + mn->children[0] = ShrinkNodeID(c0); /// \todo Use UINT32 for node children in a future, instead? + mn->children[1] = ShrinkNodeID(c1); + } + } +} + static void P_LoadMapBSP(const virtres_t *virt) { virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); @@ -1555,207 +1757,7 @@ static void P_LoadMapBSP(const virtres_t *virt) case NT_XNOD: case NT_XGLN: case NT_XGL3: - { - size_t i, j, k; - INT16 m; - UINT8* data = virtnodes->data + 4; - - /// Extended node formats feature additional vertexes; useful for OpenGL, but totally useless in gamelogic. - UINT32 orivtx, xtrvtx; - orivtx = READUINT32(data); - xtrvtx = READUINT32(data); - - if (numvertexes != orivtx) /// If native vertex count doesn't match node original vertex count, bail out (broken data?). - { - CONS_Alert(CONS_WARNING, "Vertex count in map data and nodes differ!\n"); - return; - } - - if (xtrvtx) /// If extra vertexes were generated, reallocate the vertex array and fix the pointers. - { - line_t* ld = lines; - size_t oldpos = (size_t) vertexes; - ssize_t offset; - numvertexes+= xtrvtx; - vertexes = Z_Realloc(vertexes, numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - offset = ((size_t) vertexes) - oldpos; - - for (i = 0, ld = lines; i < numlines; i++, ld++) - { - ld->v1 = (vertex_t*) ((size_t) ld->v1 + offset); - ld->v2 = (vertex_t*) ((size_t) ld->v2 + offset); - } - } - - // Read vertex data. - for (i = orivtx; i < numvertexes; i++) - { - vertexes[i].x = READFIXED(data); - vertexes[i].y = READFIXED(data); - } - - // Subsectors - numsubsectors = READUINT32(data); - subsectors = Z_Calloc(numsubsectors * sizeof (*subsectors), PU_LEVEL, NULL); - - for (i = 0; i < numsubsectors; i++) - subsectors[i].numlines = READUINT32(data); - - // Segs - numsegs = READUINT32(data); - segs = Z_Calloc(numsegs * sizeof (*segs), PU_LEVEL, NULL); - - for (i = 0, k = 0; i < numsubsectors; i++) - { - subsectors[i].firstline = k; - - switch (nodetype) - { - case NT_XGLN: - for (m = 0; m < subsectors[i].numlines; m++, k++) - { - UINT16 linenum; - UINT32 vert; - vert = READUINT32(data); - segs[k].v1 = &vertexes[vert]; - if (m == 0) - segs[k + subsectors[i].numlines - 1].v2 = &vertexes[vert]; - else - segs[k - 1].v2 = segs[k].v1; - data += 4;// partner; can be ignored by software renderer; - linenum = READUINT16(data); - if (linenum == 0xFFFF) - { - segs[k].glseg = true; - segs[k].linedef = NULL; - } - else - { - segs[k].glseg = false; - segs[k].linedef = &lines[linenum]; - } - segs[k].side = READUINT8(data); - } - break; - - case NT_XGL3: - for (m = 0; m < subsectors[i].numlines; m++, k++) - { - UINT32 linenum; - UINT32 vert; - vert = READUINT32(data); - segs[k].v1 = &vertexes[vert]; - if (m == 0) - segs[k + subsectors[i].numlines - 1].v2 = &vertexes[vert]; - else - segs[k - 1].v2 = segs[k].v1; - data += 4;// partner; can be ignored by software renderer; - linenum = READUINT32(data); - if (linenum == 0xFFFFFFFF) - { - segs[k].glseg = true; - segs[k].linedef = NULL; - } - else - { - segs[k].glseg = false; - segs[k].linedef = NULL; - } - segs[k].side = READUINT8(data); - } - break; - - case NT_XNOD: - for (m = 0; m < subsectors[i].numlines; m++, k++) - { - segs[k].v1 = &vertexes[READUINT32(data)]; - segs[k].v2 = &vertexes[READUINT32(data)]; - segs[k].linedef = &lines[READUINT16(data)]; - segs[k].side = READUINT8(data); - } - break; - - default: - return; - } - } - - { - INT32 side; - seg_t *li; - - for (i = 0, li = segs; i < numsegs; i++, li++) - { - vertex_t *v1 = li->v1; - vertex_t *v2 = li->v2; - li->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); - li->offset = FixedHypot(v1->x - li->linedef->v1->x, v1->y - li->linedef->v1->y); - side = li->side; - li->sidedef = &sides[li->linedef->sidenum[side]]; - - li->frontsector = sides[li->linedef->sidenum[side]].sector; - if (li->linedef->flags & ML_TWOSIDED) - li->backsector = sides[li->linedef->sidenum[side^1]].sector; - else - li->backsector = 0; - - segs[i].numlights = 0; - segs[i].rlights = NULL; - } - } - - // Nodes - numnodes = READINT32(data); - nodes = Z_Calloc(numnodes * sizeof (*nodes), PU_LEVEL, NULL); - if (nodetype == NT_XGL3) - { - UINT32 x, y, dx, dy; - UINT32 c0, c1; - node_t *mn; - for (i = 0, mn = nodes; i < numnodes; i++, mn++) - { - // Splitter. - x = READINT32(data); - y = READINT32(data); - dx = READINT32(data); - dy = READINT32(data); - mn->x = x; - mn->y = y; - mn->dx = dx; - mn->dy = dy; - - // Bounding boxes and children. - for (j = 0; j < 2; j++) - for (k = 0; k < 4; k++) - mn->bbox[j][k] = READINT16(data)<<FRACBITS; - c0 = READUINT32(data); - c1 = READUINT32(data); - mn->children[0] = ShrinkNodeID(c0); /// \todo Use UINT32 for node children in a future, instead? - mn->children[1] = ShrinkNodeID(c1); - } - } - else - { - UINT32 c0, c1; - node_t *mn; - for (i = 0, mn = nodes; i < numnodes; i++, mn++) - { - // Splitter. - mn->x = READINT16(data)<<FRACBITS; - mn->y = READINT16(data)<<FRACBITS; - mn->dx = READINT16(data)<<FRACBITS; - mn->dy = READINT16(data)<<FRACBITS; - // Bounding boxes and children. - for (j = 0; j < 2; j++) - for (k = 0; k < 4; k++) - mn->bbox[j][k] = READINT16(data)<<FRACBITS; - c0 = READUINT32(data); - c1 = READUINT32(data); - mn->children[0] = ShrinkNodeID(c0); /// \todo Use UINT32 for node children in a future, instead? - mn->children[1] = ShrinkNodeID(c1); - } - } - } + P_LoadExtendedNodes(virtnodes->data + 4, nodetype); break; default: CONS_Alert(CONS_WARNING, "Unsupported BSP format detected.\n");