diff --git a/resources/bspguy.cfg b/resources/bspguy.cfg index fb8a0987..a00ce7f6 100644 --- a/resources/bspguy.cfg +++ b/resources/bspguy.cfg @@ -87,4 +87,5 @@ language=EN palette=quake_1 save_cam=0 hlrad_path= -hlrad_options={map_path} \ No newline at end of file +hlrad_options={map_path} +fpslimit=100 \ No newline at end of file diff --git a/src/bsp/Bsp.cpp b/src/bsp/Bsp.cpp index 4e1b3e43..7a287061 100644 --- a/src/bsp/Bsp.cpp +++ b/src/bsp/Bsp.cpp @@ -388,37 +388,13 @@ void Bsp::get_model_vertex_bounds(int modelIdx, vec3& mins, vec3& maxs) maxs = vec3(-FLT_MAX_COORD, -FLT_MAX_COORD, -FLT_MAX_COORD); BSPMODEL& model = models[modelIdx]; - /*auto verts = getModelVerts(modelIdx); - for (auto const& s : verts) + auto rndverts = getModelVerts(modelIdx); + for (auto const& s : rndverts) { - if (s.pos.x < mins.x) - { - mins.x = s.pos.x; - } - if (s.pos.y < mins.y) - { - mins.y = s.pos.y; - } - if (s.pos.z < mins.z) - { - mins.z = s.pos.z; - } - - if (s.pos.x > maxs.x) - { - maxs.x = s.pos.x; - } - if (s.pos.y > maxs.y) - { - maxs.y = s.pos.y; - } - if (s.pos.z > maxs.z) - { - maxs.z = s.pos.z; - } + expandBoundingBox(s.pos, mins, maxs); } - */ - for (int i = 0; i < model.nFaces; i++) + + /*for (int i = 0; i < model.nFaces; i++) { BSPFACE32& face = faces[model.iFirstFace + i]; @@ -426,11 +402,11 @@ void Bsp::get_model_vertex_bounds(int modelIdx, vec3& mins, vec3& maxs) { int edgeIdx = surfedges[face.iFirstEdge + e]; BSPEDGE32& edge = edges[abs(edgeIdx)]; - int vertIdx = edgeIdx >= 0 ? edge.iVertex[1] : edge.iVertex[0]; + int vertIdx = edgeIdx < 0 ? edge.iVertex[1] : edge.iVertex[0]; expandBoundingBox(verts[vertIdx], mins, maxs); } - } + }*/ } std::vector Bsp::getModelVerts(int modelIdx) @@ -448,7 +424,7 @@ std::vector Bsp::getModelVerts(int modelIdx) { int edgeIdx = surfedges[face.iFirstEdge + e]; BSPEDGE32& edge = edges[abs(edgeIdx)]; - int vertIdx = edgeIdx >= 0 ? edge.iVertex[1] : edge.iVertex[0]; + int vertIdx = edgeIdx < 0 ? edge.iVertex[1] : edge.iVertex[0]; if (!visited.count(vertIdx)) { @@ -558,7 +534,7 @@ bool Bsp::getModelPlaneIntersectVerts(int modelIdx, const std::vector& node { int edgeIdx = surfedges[face.iFirstEdge + e]; BSPEDGE32& edge = edges[abs(edgeIdx)]; - int vertIdx = edgeIdx >= 0 ? edge.iVertex[1] : edge.iVertex[0]; + int vertIdx = edgeIdx < 0 ? edge.iVertex[1] : edge.iVertex[0]; if (verts[vertIdx] != v) { @@ -4857,7 +4833,7 @@ void Bsp::mark_face_structures(int iFace, STRUCTUSAGE* usage) { int edgeIdx = surfedges[face.iFirstEdge + e]; BSPEDGE32& edge = edges[abs(edgeIdx)]; - int vertIdx = edgeIdx >= 0 ? edge.iVertex[1] : edge.iVertex[0]; + int vertIdx = edgeIdx < 0 ? edge.iVertex[1] : edge.iVertex[0]; usage->surfEdges[face.iFirstEdge + e] = true; usage->edges[abs(edgeIdx)] = true; @@ -6676,7 +6652,6 @@ bool Bsp::leaf_add_face(int faceIdx, int leafIdx) return false; } - std::vector all_mark_surfaces; int surface_idx = 0; for (int i = 0; i < leafCount; i++) @@ -7629,7 +7604,7 @@ void Bsp::write_csg_polys(int nodeIdx, FILE* polyfile, int flipPlaneSkip, bool d { int edgeIdx = surfedges[e]; BSPEDGE32& edge = edges[abs(edgeIdx)]; - vec3 v = edgeIdx >= 0 ? verts[edge.iVertex[1]] : verts[edge.iVertex[0]]; + vec3 v = edgeIdx < 0 ? verts[edge.iVertex[1]] : verts[edge.iVertex[0]]; fprintf(polyfile, "%5.8f %5.8f %5.8f\n", v.x, v.y, v.z); } } @@ -7639,7 +7614,7 @@ void Bsp::write_csg_polys(int nodeIdx, FILE* polyfile, int flipPlaneSkip, bool d { int edgeIdx = surfedges[e]; BSPEDGE32& edge = edges[abs(edgeIdx)]; - vec3 v = edgeIdx >= 0 ? verts[edge.iVertex[1]] : verts[edge.iVertex[0]]; + vec3 v = edgeIdx < 0 ? verts[edge.iVertex[1]] : verts[edge.iVertex[0]]; fprintf(polyfile, "%5.8f %5.8f %5.8f\n", v.x, v.y, v.z); } } diff --git a/src/bsp/bsptypes.cpp b/src/bsp/bsptypes.cpp index b978c916..7c22753e 100644 --- a/src/bsp/bsptypes.cpp +++ b/src/bsp/bsptypes.cpp @@ -30,7 +30,7 @@ BSPEDGE32::BSPEDGE32(unsigned int v1, unsigned int v2) iVertex[1] = v2; } -bool BSPPLANE::update_plane(vec3 newNormal, float fdist) +bool BSPPLANE::update_plane(vec3 newNormal, float fdist, bool flip) { double fx = abs(newNormal.x); double fy = abs(newNormal.y); diff --git a/src/bsp/bsptypes.h b/src/bsp/bsptypes.h index 0dbd33ad..d957dd17 100644 --- a/src/bsp/bsptypes.h +++ b/src/bsp/bsptypes.h @@ -167,7 +167,7 @@ struct BSPPLANE int nType; // returns true if the plane was flipped - bool update_plane(vec3 newNormal, float fdist); + bool update_plane(vec3 newNormal, float fdist, bool flip = true); BSPPLANE() :vNormal(vec3()) { diff --git a/src/editor/BspRenderer.cpp b/src/editor/BspRenderer.cpp index 7ddee659..4c29baba 100644 --- a/src/editor/BspRenderer.cpp +++ b/src/editor/BspRenderer.cpp @@ -3099,7 +3099,7 @@ bool BspRenderer::pickModelPoly(vec3 start, const vec3& dir, vec3 offset, int mo { int edgeIdx = map->surfedges[e]; BSPEDGE32 edge = map->edges[abs(edgeIdx)]; - vec3& v = edgeIdx >= 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; + vec3& v = edgeIdx < 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; if (vectest != vec3() && vectest == v) { badface = true; diff --git a/src/editor/Gui.cpp b/src/editor/Gui.cpp index 805c598c..829cab08 100644 --- a/src/editor/Gui.cpp +++ b/src/editor/Gui.cpp @@ -16,6 +16,7 @@ #include #include "vis.h" #include +#include "winding.h" float g_tooltip_delay = 0.6f; // time in seconds before showing a tooltip @@ -506,7 +507,7 @@ void Gui::drawBspContexMenu() if (ImGui::MenuItem(get_localized_string(LANG_0430).c_str(), "")) { - map->models[modelIdx].vOrigin = getCenter(map->models[modelIdx].nMins, + map->models[modelIdx].vOrigin = getCenter(map->models[modelIdx].nMins, map->models[modelIdx].nMaxs); rend->refreshModel(modelIdx); pickCount++; // force gui refresh @@ -2462,7 +2463,7 @@ void Gui::drawMenuBar() if (fileSize(g_settings_path) == 0) { print_log(PRINT_RED | PRINT_INTENSITY, get_localized_string(LANG_0359)); - } + } else { glfwTerminate(); @@ -2693,8 +2694,8 @@ void Gui::drawMenuBar() if (ImGui::MenuItem("MDL to BSP (WIP)", NULL, false, app && app->pickInfo.selectedEnts.size() == 1)) { size_t ent = app->pickInfo.selectedEnts[0]; - std::set added_textures; + if (rend->renderEnts[ent].mdl) { auto mdl = rend->renderEnts[ent].mdl; @@ -2703,20 +2704,16 @@ void Gui::drawMenuBar() int modelFirstFace = map->faceCount; int modelFirstPlane = map->planeCount; int modelFaces = 0; - int lightOffset = map->lightDataLength; - - unsigned char* testlightdata = new unsigned char[map->lightDataLength + (512 * 512 * 3)]; memcpy(testlightdata, map->lightdata, map->lightDataLength); - memset(testlightdata + map->lightDataLength, 200, (512 * 512 * 3)); + memset(testlightdata + map->lightDataLength, 125, (512 * 512 * 3)); map->replace_lump(LUMP_LIGHTING, testlightdata, map->lightDataLength + (512 * 512 * 3)); vec3 mins = vec3(FLT_MAX_COORD, FLT_MAX_COORD, FLT_MAX_COORD); vec3 maxs = vec3(-FLT_MAX_COORD, -FLT_MAX_COORD, -FLT_MAX_COORD); - for (size_t group = 0; group < mdl->mdl_mesh_groups.size(); group++) { for (size_t meshid = 0; meshid < mdl->mdl_mesh_groups[group].size(); meshid++) @@ -2725,88 +2722,102 @@ void Gui::drawMenuBar() modelVert* mdlVerts = (modelVert*)mesh.buffer->get_data(); std::vector newVertIndexes; - size_t newVertCount = map->vertCount + mesh.buffer->numVerts; + + size_t startVertCount = map->vertCount; + size_t newVertCount = startVertCount + mesh.buffer->numVerts; vec3* newverts = new vec3[newVertCount]; - memcpy(newverts, map->verts, map->vertCount * sizeof(vec3)); + memcpy(newverts, map->verts, startVertCount * sizeof(vec3)); + map->replace_lump(LUMP_VERTICES, newverts, newVertCount * sizeof(vec3)); + newverts = map->verts; std::vector newuv; newuv.resize(newVertCount); int v = 0; - for (v = map->vertCount; v < newVertCount; v++) + for (v = (int)startVertCount; v < newVertCount; v++) { - newverts[v] = mdlVerts[v - map->vertCount].pos.flipUV(); - newuv[v] = { mdlVerts[v - map->vertCount].u, mdlVerts[v - map->vertCount].v }; + newverts[v] = mdlVerts[v - startVertCount].pos.flipUV(); + newuv[v] = { mdlVerts[v - startVertCount].u, mdlVerts[v - startVertCount].v }; newVertIndexes.push_back(v); expandBoundingBox(newverts[v], mins, maxs); } - size_t newdedgescount = map->edgeCount + (mesh.buffer->numVerts + 1) / 2; - - BSPEDGE32* newedges = new BSPEDGE32[newdedgescount]; - memcpy(newedges, map->edges, map->edgeCount * sizeof(BSPEDGE32)); - std::map vertToSurfedge; - bool inverse = false; - unsigned int startEdge = map->edgeCount; - { - v = 0; - for (unsigned int i = 0; i < mesh.buffer->numVerts; i += 2) - { - unsigned int v0 = i; - unsigned int v1 = (i + 1) % mesh.buffer->numVerts; - newedges[startEdge + v] = BSPEDGE32((unsigned int)newVertIndexes[v0], (unsigned int)newVertIndexes[v1]); + size_t newdedgescount = startEdge + (mesh.buffer->numVerts + 1) / 2; + BSPEDGE32* newedges = new BSPEDGE32[newdedgescount]; + memcpy(newedges, map->edges, startEdge * sizeof(BSPEDGE32)); + map->replace_lump(LUMP_EDGES, newedges, newdedgescount * sizeof(BSPEDGE32)); + newedges = map->edges; - vertToSurfedge[v0] = startEdge + v; - if (v1 > 0) - { - vertToSurfedge[v1] = -((int)(startEdge + v)); // negative = use second vert - } - v++; + v = 0; + for (unsigned int i = 0; i < mesh.buffer->numVerts; i += 2) + { + unsigned int v0 = i; + unsigned int v1 = (i + 1) % mesh.buffer->numVerts; + newedges[startEdge + v] = BSPEDGE32((unsigned int)newVertIndexes[v0], (unsigned int)newVertIndexes[v1]); + + vertToSurfedge[v0] = startEdge + v; + if (v1 > 0) + { + vertToSurfedge[v1] = -((int)(startEdge + v)); // negative = use second vert } + + v++; } + inverse = false; - size_t newsurfedges_count = map->surfedgeCount + mesh.buffer->numVerts; + + size_t startSurfedgeCount = map->surfedgeCount; + size_t newsurfedges_count = startSurfedgeCount + mesh.buffer->numVerts; int* newsurfedges = new int[newsurfedges_count]; - memcpy(newsurfedges, map->surfedges, map->surfedgeCount * sizeof(int)); + memcpy(newsurfedges, map->surfedges, startSurfedgeCount * sizeof(int)); + map->replace_lump(LUMP_SURFEDGES, newsurfedges, newsurfedges_count * sizeof(int)); + newsurfedges = map->surfedges; - for (v = map->surfedgeCount; v < newsurfedges_count; v++) + for (v = (int)startSurfedgeCount; v < newsurfedges_count; v++) { - newsurfedges[v] = (int)vertToSurfedge[v - map->surfedgeCount]; + newsurfedges[v] = vertToSurfedge[v - (int)startSurfedgeCount]; } size_t numTriangles = mesh.buffer->numVerts / 3; + modelFaces += (int)numTriangles; - modelFaces += numTriangles; - - int newFaceCount = map->faceCount + numTriangles; - + size_t startFaceCount = map->faceCount; + size_t newFaceCount = startFaceCount + numTriangles; BSPFACE32* newfaces = new BSPFACE32[newFaceCount]; - memcpy(newfaces, map->faces, map->faceCount * sizeof(BSPFACE32)); + memcpy(newfaces, map->faces, startFaceCount * sizeof(BSPFACE32)); + map->replace_lump(LUMP_FACES, newfaces, newFaceCount * sizeof(BSPFACE32)); + newfaces = map->faces; - int newPlaneCount = map->planeCount + numTriangles; + size_t startPlaneCount = map->planeCount; + size_t newPlaneCount = startPlaneCount + numTriangles; BSPPLANE* newplanes = new BSPPLANE[newPlaneCount]; - memcpy(newplanes, map->planes, map->planeCount * sizeof(BSPPLANE)); + memcpy(newplanes, map->planes, startPlaneCount * sizeof(BSPPLANE)); + map->replace_lump(LUMP_PLANES, newplanes, newPlaneCount * sizeof(BSPPLANE)); + newplanes = map->planes; - int newTexinfosCount = map->texinfoCount + numTriangles; + size_t startTexinfoCount = map->texinfoCount; + size_t newTexinfosCount = startTexinfoCount + numTriangles; BSPTEXTUREINFO* newtexinfos = new BSPTEXTUREINFO[newTexinfosCount]; - memcpy(newtexinfos, map->texinfos, map->texinfoCount * sizeof(BSPTEXTUREINFO)); - - int firstEdge = map->surfedgeCount; + memcpy(newtexinfos, map->texinfos, startTexinfoCount * sizeof(BSPTEXTUREINFO)); + map->replace_lump(LUMP_TEXINFO, newtexinfos, newTexinfosCount * sizeof(BSPTEXTUREINFO)); + newtexinfos = map->texinfos; - for (v = map->faceCount; v < newFaceCount; v++) + for (v = (int)startFaceCount; v < newFaceCount; v++) { - newfaces[v].iFirstEdge = firstEdge; + int edgeIdx = (int)(startSurfedgeCount + (v - startFaceCount) * 3); + + newfaces[v].iFirstEdge = edgeIdx; newfaces[v].nEdges = 3; - newfaces[v].iPlane = (v - map->faceCount) + map->planeCount; - newfaces[v].iTextureInfo = (v - map->faceCount) + map->texinfoCount; + newfaces[v].iPlane = (int)((v - startFaceCount) + startPlaneCount); + newfaces[v].iTextureInfo = (int)((v - startFaceCount) + startTexinfoCount); newfaces[v].nLightmapOffset = lightOffset; memset(newfaces[v].nStyles, 255, MAX_LIGHTMAPS); newfaces[v].nStyles[0] = 0; @@ -2887,26 +2898,60 @@ void Gui::drawMenuBar() BSPPLANE& plane = newplanes[newfaces[v].iPlane]; // Compute tangent and bitangent - vec3 vertex1 = newsurfedges[firstEdge] > 0 ? newverts[newedges[abs(newsurfedges[firstEdge])].iVertex[0]] - : newverts[newedges[abs(newsurfedges[firstEdge])].iVertex[1]]; - vec3 vertex2 = newsurfedges[firstEdge + 1] > 0 ? newverts[newedges[abs(newsurfedges[firstEdge + 1])].iVertex[0]] - : newverts[newedges[abs(newsurfedges[firstEdge + 1])].iVertex[1]]; - vec3 vertex3 = newsurfedges[firstEdge + 2] > 0 ? newverts[newedges[abs(newsurfedges[firstEdge + 2])].iVertex[0]] - : newverts[newedges[abs(newsurfedges[firstEdge + 2])].iVertex[1]]; + int vert_id1 = newsurfedges[edgeIdx + 0] < 0 ? newedges[abs(newsurfedges[edgeIdx + 0])].iVertex[1] + : newedges[abs(newsurfedges[edgeIdx + 0])].iVertex[0]; + vec3 vertex1 = newverts[vert_id1]; + + int vert_id2 = newsurfedges[edgeIdx + 1] < 0 ? newedges[abs(newsurfedges[edgeIdx + 1])].iVertex[1] + : newedges[abs(newsurfedges[edgeIdx + 1])].iVertex[0]; + vec3 vertex2 = newverts[vert_id2]; + + int vert_id3 = newsurfedges[edgeIdx + 2] < 0 ? newedges[abs(newsurfedges[edgeIdx + 2])].iVertex[1] + : newedges[abs(newsurfedges[edgeIdx + 2])].iVertex[0]; + vec3 vertex3 = newverts[vert_id3]; + + + + //if ((abs(vertex1.x - vertex3.x) < 0.2 && + // abs(vertex1.y - vertex3.y) < 0.2 && + // abs(vertex1.z - vertex3.z) < 0.2) || vert_id1 == vert_id3) + //{ + // print_log(PRINT_RED, "vert1 {} {} {} vert3 {} {} {} vert1_id {} vert2_id {}\n", + // vertex1.x, vertex1.y, vertex1.z, vertex3.x, vertex3.y, vertex3.z, vert_id1, + // vert_id3); + // vertex3.z += 0.2; + //} + //if ((abs(vertex2.x - vertex3.x) < 0.2 && + // abs(vertex2.y - vertex3.y) < 0.2 && + // abs(vertex2.z - vertex3.z) < 0.2) || vert_id2 == vert_id3) + //{ + // print_log(PRINT_RED, "vert2 {} {} {} vert3 {} {} {} vert1_id {} vert2_id {}\n", + // vertex2.x, vertex2.y, vertex2.z, vertex3.x, vertex3.y, vertex3.z, vert_id2, + // vert_id3); + // vertex3.z += 0.2; + //} + //if ((abs(vertex2.x - vertex1.x) < 0.2 && + // abs(vertex2.y - vertex1.y) < 0.2 && + // abs(vertex2.z - vertex1.z) < 0.2) || vert_id2 == vert_id1) + //{ + // print_log(PRINT_RED, "vert2 {} {} {} vert1 {} {} {} vert1_id {} vert2_id {}\n", + // vertex2.x, vertex2.y, vertex2.z, vertex1.x, vertex1.y, vertex1.z, vert_id2, + // vert_id1); + // vertex2.z += 0.2; + //} std::vector vertexes{}; vertexes.push_back(vertex1); vertexes.push_back(vertex2); vertexes.push_back(vertex3); - // Texture coordinates std::vector uvs{}; - uvs.push_back(newsurfedges[firstEdge] > 0 ? newuv[newedges[abs(newsurfedges[firstEdge])].iVertex[0]] - : newuv[newedges[abs(newsurfedges[firstEdge])].iVertex[1]]); - uvs.push_back(newsurfedges[firstEdge + 1] > 0 ? newuv[newedges[abs(newsurfedges[firstEdge + 1])].iVertex[0]] - : newuv[newedges[abs(newsurfedges[firstEdge + 1])].iVertex[1]]); - uvs.push_back(newsurfedges[firstEdge + 2] > 0 ? newuv[newedges[abs(newsurfedges[firstEdge + 2])].iVertex[0]] - : newuv[newedges[abs(newsurfedges[firstEdge + 2])].iVertex[1]]); + uvs.push_back(newsurfedges[edgeIdx + 0] < 0 ? newuv[newedges[abs(newsurfedges[edgeIdx + 0])].iVertex[1]] + : newuv[newedges[abs(newsurfedges[edgeIdx])].iVertex[0]]); + uvs.push_back(newsurfedges[edgeIdx + 1] < 0 ? newuv[newedges[abs(newsurfedges[edgeIdx + 1])].iVertex[1]] + : newuv[newedges[abs(newsurfedges[edgeIdx + 1])].iVertex[0]]); + uvs.push_back(newsurfedges[edgeIdx + 2] < 0 ? newuv[newedges[abs(newsurfedges[edgeIdx + 2])].iVertex[1]] + : newuv[newedges[abs(newsurfedges[edgeIdx + 2])].iVertex[0]]); /**/ for (auto& uv : uvs) { @@ -2918,43 +2963,46 @@ void Gui::drawMenuBar() uv.y *= newHeight; } - // Compute edges and delta UVs - vec3 edge1 = vertexes[1] - vertexes[0]; - vec3 edge2 = vertexes[2] - vertexes[0]; + //// Compute edges and delta UVs + //vec3 edge1 = vertexes[1] - vertexes[0]; + //vec3 edge2 = vertexes[2] - vertexes[0]; + + //vec3 normal = crossProduct(edge1, edge2).normalize(); + + //// Calculate the distance from the origin + //float dist = getDistAlongAxis(normal, vertex1); + //plane.vNormal = normal; + //plane.fDist = dist; - vec3 normal = crossProduct(edge1, edge2).normalize(); + if (!getPlaneFromVerts(vertexes, plane.vNormal, plane.fDist)) + { + // Compute edges and delta UVs + vec3 edge1 = vertexes[1] - vertexes[0]; + vec3 edge2 = vertexes[2] - vertexes[0]; + + vec3 normal = crossProduct(edge1, edge2).normalize(); - // Calculate the distance from the origin - float dist = getDistAlongAxis(normal, vertex1); - plane.vNormal = normal; - plane.fDist = dist; + // Calculate the distance from the origin + float dist = getDistAlongAxis(normal, vertex1); + plane.vNormal = normal; + plane.fDist = dist; + } newfaces[v].nPlaneSide = !plane.update_plane(plane.vNormal, plane.fDist); calculateTextureInfo(texInfo, vertexes, uvs); texInfo.iMiptex = miptex; - - firstEdge += 3; } - int oldFaceCount = map->faceCount; - - map->replace_lump(LUMP_VERTICES, newverts, newVertCount * sizeof(vec3)); - map->replace_lump(LUMP_EDGES, newedges, newdedgescount * sizeof(BSPEDGE32)); - map->replace_lump(LUMP_SURFEDGES, newsurfedges, newsurfedges_count * sizeof(int)); - map->replace_lump(LUMP_FACES, newfaces, newFaceCount * sizeof(BSPFACE32)); - map->replace_lump(LUMP_PLANES, newplanes, newPlaneCount * sizeof(BSPPLANE)); - map->replace_lump(LUMP_TEXINFO, newtexinfos, newTexinfosCount * sizeof(BSPTEXTUREINFO)); - - for (int f = oldFaceCount; f < map->faceCount; f++) + for (size_t f = startFaceCount; f < newFaceCount; f++) { int tmins[2]; int tmaxs[2]; - if (!GetFaceExtents(map, f, tmins, tmaxs)) + if (!GetFaceExtents(map, (int)f, tmins, tmaxs)) { BSPTEXTUREINFO& texInfo = newtexinfos[newfaces[f].iTextureInfo]; texInfo.vS = vec3(1.0f, 0.0f, 0.0f); - texInfo.vT = vec3(1.0f, 0.0f, 1.0f); + texInfo.vT = vec3(1.0f, 0.0f, -1.0f); } } } @@ -2969,10 +3017,20 @@ void Gui::drawMenuBar() newmodels[newModelIdx].nMins = mins; newmodels[newModelIdx].nMaxs = maxs; - newmodels[newModelIdx].vOrigin = vec3(); + newmodels[newModelIdx].vOrigin = origin; newmodels[newModelIdx].iFirstFace = modelFirstFace; newmodels[newModelIdx].nFaces = modelFaces; - newmodels[newModelIdx].nVisLeafs = 0; + newmodels[newModelIdx].nVisLeafs = 1; + + map->create_leaf(CONTENTS_EMPTY); + map->leaves[map->leafCount - 1].nMins = mins - 8.0f; + map->leaves[map->leafCount - 1].nMaxs = maxs + 8.0f; + map->leaves[map->leafCount - 1].nVisOffset = -1; + + for (int i = modelFirstFace; i < modelFirstFace + modelFaces; i++) + { + map->leaf_add_face(i, map->leafCount - 1); + } unsigned int startNode = map->nodeCount; { @@ -2981,27 +3039,7 @@ void Gui::drawMenuBar() memcpy(newNodes, map->nodes, map->nodeCount * sizeof(BSPNODE32)); int sharedSolidLeaf = 0; - int anyEmptyLeaf = 0; - for (int i = map->leafCount - 1; i >= 0; i--) - { - if (map->leaves[i].nContents == CONTENTS_EMPTY) - { - anyEmptyLeaf = i; - break; - } - } - // If emptyLeaf is still 0 (SOLID), it means the map is fully solid, so the contents wouldn't matter. - // Anyway, still setting this in case someone wants to copy the model to another map - if (anyEmptyLeaf == 0) - { - anyEmptyLeaf = map->create_leaf(CONTENTS_EMPTY); - newmodels[newModelIdx].nVisLeafs = 1; - } - else - { - newmodels[newModelIdx].nVisLeafs = 0; - } - + int anyEmptyLeaf = map->leafCount - 1; for (size_t k = 0; k < modelFaces; k++) { @@ -3010,20 +3048,14 @@ void Gui::drawMenuBar() node.iFirstFace = (int)(modelFirstFace + k); // face required for decals node.nFaces = 1; node.iPlane = (int)(modelFirstPlane + k); - //node.nMins = node.nMaxs = vec3(); - node.nMins = mins; - node.nMaxs = maxs; + node.nMins = node.nMaxs = vec3(); // node mins/maxs don't matter for submodels. Leave them at 0. int insideContents = modelFaces > 0 && k + 1 == modelFaces ? ~sharedSolidLeaf : (int)(map->nodeCount + k + 1); int outsideContents = ~anyEmptyLeaf; - bool swapNodeChildren = map->planes[node.iPlane].vNormal.x < 0 || map->planes[node.iPlane].vNormal.y < 0 || map->planes[node.iPlane].vNormal.z < 0; - /*if (swapNodeChildren) - map->planes[node.iPlane].vNormal = map->planes[node.iPlane].vNormal.invert();*/ - - // can't have negative normals on planes so children are swapped instead - if (swapNodeChildren) + // can't have negative normals on planes so children are swapped instead + if (!map->faces[node.iFirstFace].nPlaneSide) { node.iChildren[0] = insideContents; node.iChildren[1] = outsideContents; @@ -3035,7 +3067,7 @@ void Gui::drawMenuBar() } if (k + 1 == modelFaces) { - if (swapNodeChildren) + if (!map->faces[node.iFirstFace].nPlaneSide) { node.iChildren[0] = (int)(map->nodeCount + k + 1); node.iChildren[1] = (int)(map->nodeCount + k + 2); @@ -3084,7 +3116,7 @@ void Gui::drawMenuBar() rend->loadTextures(); rend->reuploadTextures(); - //map->regenerate_clipnodes(newModelIdx, -1); + map->regenerate_clipnodes(newModelIdx, -1); } } } @@ -4016,7 +4048,7 @@ void Gui::drawMenuBar() } ImGui::EndMainMenuBar(); - } + } if (ImGui::BeginViewportSideBar("BottomBar", ImGui::GetMainViewport(), ImGuiDir_Down, ImGui::GetTextLineHeightWithSpacing(), ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar)) { @@ -4053,7 +4085,7 @@ void Gui::drawMenuBar() ImGui::End(); } - } +} void Gui::drawToolbar() { @@ -5866,12 +5898,13 @@ void Gui::drawMDLWidget() void Gui::drawGOTOWidget() { - ImGui::SetNextWindowSize(ImVec2(410.f, 200.f), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSizeConstraints(ImVec2(410.f, 330.f), ImVec2(410.f, 330.f)); + ImGui::SetNextWindowSize(ImVec2(410.f, 210.f), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(410.f, 340.f), ImVec2(410.f, 340.f)); static vec3 coordinates = vec3(); static vec3 angles = vec3(); float angles_y = 0.0f; static int modelid = -1, faceid = -1, entid = -1, leafid = -1; + static bool use_model_offset = false; if (ImGui::Begin(fmt::format("{}###GOTO_WIDGET", get_localized_string(LANG_0676)).c_str(), &showGOTOWidget, 0)) { @@ -5936,12 +5969,24 @@ void Gui::drawGOTOWidget() ImGui::PushItemWidth(inputWidth); ImGui::DragInt(get_localized_string(LANG_0685).c_str(), &modelid); ImGui::DragInt(get_localized_string(LANG_0686).c_str(), &faceid); + + ImGui::SameLine(); + ImGui::Checkbox("Face of model##face_app_mdl", &use_model_offset); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted("Use model first face as offset."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + ImGui::DragInt(get_localized_string(LANG_0687).c_str(), &entid); ImGui::DragInt("Leaf", &leafid); ImGui::PopItemWidth(); if (ImGui::Button("Go to##2")) { - if (modelid >= 0 && modelid < map->modelCount) + if (modelid >= 0 && modelid < map->modelCount && faceid < 0) { app->pickMode = PICK_OBJECT; for (size_t i = 0; i < map->ents.size(); i++) @@ -5958,7 +6003,7 @@ void Gui::drawGOTOWidget() { app->pickMode = PICK_FACE; app->goToFace(map, faceid); - int modelIdx = map->get_model_from_face(faceid); + int modelIdx = use_model_offset && modelid >= 0 ? modelid : map->get_model_from_face(faceid); if (modelIdx >= 0) { for (size_t i = 0; i < map->ents.size(); i++) @@ -5970,7 +6015,14 @@ void Gui::drawGOTOWidget() } } } - app->selectFace(map, faceid); + if (use_model_offset && modelid >= 0 && modelid < map->modelCount) + { + app->selectFace(map, faceid + map->models[modelid].iFirstFace); + } + else + { + app->selectFace(map, faceid); + } } else if (leafid > 0 && leafid < (int)map->leafCount) { @@ -6309,7 +6361,7 @@ void Gui::drawTransformWidget() ImGui::Text(fmt::format("Entity origin: {} {} {}", ent->origin.x, ent->origin.y, ent->origin.z).c_str()); int modelIdx = ent->getBspModelIdx(); - + if (modelIdx >= 0) { ImGui::Text(fmt::format("Model origin: {} {} {}", map->models[modelIdx].vOrigin.x, map->models[modelIdx].vOrigin.y, map->models[modelIdx].vOrigin.z).c_str()); @@ -7133,6 +7185,11 @@ void Gui::drawSettings() { ImGui::Text(get_localized_string(LANG_0775).c_str()); ImGui::Checkbox(get_localized_string(LANG_1115).c_str(), &g_settings.vsync); + if (!g_settings.vsync) + { + ImGui::SameLine(); + ImGui::DragInt("FPS LIMIT", &g_settings.fpslimit, 5, 30, 1000, "%u"); + } ImGui::DragFloat(get_localized_string(LANG_0776).c_str(), &app->fov, 0.1f, 1.0f, 150.0f, get_localized_string(LANG_0777).c_str()); ImGui::DragFloat(get_localized_string(LANG_0778).c_str(), &app->zFar, 10.0f, -FLT_MAX_COORD, FLT_MAX_COORD, "%.0f", ImGuiSliderFlags_Logarithmic); ImGui::Separator(); @@ -9457,12 +9514,11 @@ void Gui::drawFaceEditorWidget() textureName[0] = '\0'; } } - for (int e = face.iFirstEdge; e < face.iFirstEdge + face.nEdges; e++) { int edgeIdx = map->surfedges[e]; BSPEDGE32 edge = map->edges[abs(edgeIdx)]; - vec3 v = edgeIdx >= 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; + vec3 v = edgeIdx < 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; edgeVerts.push_back(v); } } @@ -9673,7 +9729,7 @@ void Gui::drawFaceEditorWidget() int edgeIdx = map->surfedges[e]; BSPEDGE32 edge = map->edges[abs(edgeIdx)]; - vec3& vec = edgeIdx >= 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; + vec3& vec = edgeIdx < 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; for (int v = 0; v < map->vertCount; v++) { @@ -9887,7 +9943,7 @@ void Gui::drawFaceEditorWidget() { int edgeIdx = map->surfedges[e]; BSPEDGE32 edge = map->edges[abs(edgeIdx)]; - vec3& v = edgeIdx >= 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; + vec3& v = edgeIdx < 0 ? map->verts[edge.iVertex[1]] : map->verts[edge.iVertex[0]]; v = edgeVerts[vecId]; } } diff --git a/src/editor/Renderer.cpp b/src/editor/Renderer.cpp index 85505422..6ca4543c 100644 --- a/src/editor/Renderer.cpp +++ b/src/editor/Renderer.cpp @@ -475,6 +475,8 @@ void Renderer::renderLoop() double fpsTime = 0.0; double mouseTime = 0.0; + double framerateTime = 0.0; + double xpos = 0.0, ypos = 0.0; if (SelectedMap && SelectedMap->is_mdl_model) @@ -485,178 +487,182 @@ void Renderer::renderLoop() while (!glfwWindowShouldClose(window)) { - oldTime = curTime; curTime = glfwGetTime(); - g_drawFrameId++; - frame_fps++; - - if (abs(curTime - fpsTime) >= 0.50) + if (vsync != 0 || abs(curTime - framerateTime) > 1.0f / g_settings.fpslimit) { - fpsTime = curTime; - current_fps = frame_fps * 2; - frame_fps = 0; - } - mousePos = vec2((float)xpos, (float)ypos); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (abs(curTime - fpsTime) >= 0.50) + { + fpsTime = curTime; + current_fps = frame_fps * 2; + frame_fps = 0; + } - //Update keyboard / mouse state - oldLeftMouse = curLeftMouse; - curLeftMouse = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); - oldRightMouse = curRightMouse; - curRightMouse = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT); + mousePos = vec2((float)xpos, (float)ypos); - DebugKeyPressed = pressed[GLFW_KEY_F1]; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - anyCtrlPressed = pressed[GLFW_KEY_LEFT_CONTROL] || pressed[GLFW_KEY_RIGHT_CONTROL]; - anyAltPressed = pressed[GLFW_KEY_LEFT_ALT] || pressed[GLFW_KEY_RIGHT_ALT]; - anyShiftPressed = pressed[GLFW_KEY_LEFT_SHIFT] || pressed[GLFW_KEY_RIGHT_SHIFT]; + //Update keyboard / mouse state + oldLeftMouse = curLeftMouse; + curLeftMouse = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); + oldRightMouse = curRightMouse; + curRightMouse = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT); - oldControl = canControl; + DebugKeyPressed = pressed[GLFW_KEY_F1]; - canControl = /*!gui->imgui_io->WantCaptureKeyboard && */ !gui->imgui_io->WantTextInput && !gui->imgui_io->WantCaptureMouseUnlessPopupClose; + anyCtrlPressed = pressed[GLFW_KEY_LEFT_CONTROL] || pressed[GLFW_KEY_RIGHT_CONTROL]; + anyAltPressed = pressed[GLFW_KEY_LEFT_ALT] || pressed[GLFW_KEY_RIGHT_ALT]; + anyShiftPressed = pressed[GLFW_KEY_LEFT_SHIFT] || pressed[GLFW_KEY_RIGHT_SHIFT]; - updateWindowTitle(curTime); + oldControl = canControl; - int modelIdx = -1; - auto entIdx = pickInfo.GetSelectedEnts(); - Entity* ent = NULL; - if (SelectedMap && entIdx.size() && entIdx[0] < (int)SelectedMap->ents.size()) - { - ent = SelectedMap->ents[entIdx[0]]; - modelIdx = ent->getBspModelIdx(); - } + canControl = /*!gui->imgui_io->WantCaptureKeyboard && */ !gui->imgui_io->WantTextInput && !gui->imgui_io->WantCaptureMouseUnlessPopupClose; - bool updatePickCount = false; + updateWindowTitle(curTime); - if (SelectedMap && (tmpPickIdx != pickCount || tmpVertPickIdx != vertPickCount || transformTarget != tmpTransformTarget || tmpModelIdx != modelIdx)) - { - if (transformTarget != tmpTransformTarget && transformTarget == TRANSFORM_VERTEX) + int modelIdx = -1; + auto entIdx = pickInfo.GetSelectedEnts(); + Entity* ent = NULL; + if (SelectedMap && entIdx.size() && entIdx[0] < (int)SelectedMap->ents.size()) { - updateModelVerts(); - } - else if (!modelVerts.size() || tmpModelIdx != modelIdx) - { - updateModelVerts(); + ent = SelectedMap->ents[entIdx[0]]; + modelIdx = ent->getBspModelIdx(); } - if (pickMode != PICK_OBJECT) + bool updatePickCount = false; + + framerateTime = curTime; + g_drawFrameId++; + frame_fps++; + + if (SelectedMap && (tmpPickIdx != pickCount || tmpVertPickIdx != vertPickCount || transformTarget != tmpTransformTarget || tmpModelIdx != modelIdx)) { - pickInfo.selectedEnts.clear(); - for (auto& f : pickInfo.selectedFaces) + if (transformTarget != tmpTransformTarget && transformTarget == TRANSFORM_VERTEX) + { + updateModelVerts(); + } + else if (!modelVerts.size() || tmpModelIdx != modelIdx) { - int mdl = SelectedMap->get_model_from_face((int)f); - if (mdl > 0 && mdl < SelectedMap->modelCount) + updateModelVerts(); + } + + if (pickMode != PICK_OBJECT) + { + pickInfo.selectedEnts.clear(); + for (auto& f : pickInfo.selectedFaces) { - int mdl_ent = SelectedMap->get_ent_from_model(mdl); - if (mdl_ent >= 0 && mdl_ent < SelectedMap->ents.size()) + int mdl = SelectedMap->get_model_from_face((int)f); + if (mdl > 0 && mdl < SelectedMap->modelCount) { - pickInfo.AddSelectedEnt(mdl_ent); + int mdl_ent = SelectedMap->get_ent_from_model(mdl); + if (mdl_ent >= 0 && mdl_ent < SelectedMap->ents.size()) + { + pickInfo.AddSelectedEnt(mdl_ent); + } } } } - } - updatePickCount = true; - isTransformableSolid = modelIdx > 0 || (entIdx.size() && SelectedMap->ents[entIdx[0]]->getBspModelIdx() < 0); + updatePickCount = true; + isTransformableSolid = modelIdx > 0 || (entIdx.size() && SelectedMap->ents[entIdx[0]]->getBspModelIdx() < 0); - if (!isTransformableSolid && pickInfo.selectedEnts.size()) - { - if (SelectedMap && ent && ent->hasKey("classname") && - ent->keyvalues["classname"] == "worldspawn") + if (!isTransformableSolid && pickInfo.selectedEnts.size()) { - isTransformableSolid = true; + if (SelectedMap && ent && ent->hasKey("classname") && + ent->keyvalues["classname"] == "worldspawn") + { + isTransformableSolid = true; + } } - } - modelUsesSharedStructures = modelIdx >= 0 && SelectedMap->does_model_use_shared_structures(modelIdx); + modelUsesSharedStructures = modelIdx >= 0 && SelectedMap->does_model_use_shared_structures(modelIdx); - isScalingObject = transformMode == TRANSFORM_MODE_SCALE && transformTarget == TRANSFORM_OBJECT; - isMovingOrigin = transformMode == TRANSFORM_MODE_MOVE && transformTarget == TRANSFORM_ORIGIN; - isTransformingValid = (!modelUsesSharedStructures || (transformMode == TRANSFORM_MODE_MOVE && transformTarget != TRANSFORM_VERTEX)) - || (isTransformableSolid && isScalingObject); - isTransformingWorld = pickInfo.IsSelectedEnt(0) && transformTarget != TRANSFORM_OBJECT; + isScalingObject = transformMode == TRANSFORM_MODE_SCALE && transformTarget == TRANSFORM_OBJECT; + isMovingOrigin = transformMode == TRANSFORM_MODE_MOVE && transformTarget == TRANSFORM_ORIGIN; + isTransformingValid = (!modelUsesSharedStructures || (transformMode == TRANSFORM_MODE_MOVE && transformTarget != TRANSFORM_VERTEX)) + || (isTransformableSolid && isScalingObject); + isTransformingWorld = pickInfo.IsSelectedEnt(0) && transformTarget != TRANSFORM_OBJECT; - if (ent && ent->getBspModelIdx() < 0) - invalidSolid = false; - else - { - invalidSolid = !modelVerts.size() || !SelectedMap->vertex_manipulation_sync(modelIdx, modelVerts, false); - if (!invalidSolid) + if (ent && ent->getBspModelIdx() < 0) + invalidSolid = false; + else { - std::vector tmpVerts; - SelectedMap->getModelPlaneIntersectVerts(modelIdx, tmpVerts); // for vertex manipulation + scaling - - Solid modelSolid; - if (!getModelSolid(tmpVerts, SelectedMap, modelSolid)) + invalidSolid = !modelVerts.size() || !SelectedMap->vertex_manipulation_sync(modelIdx, modelVerts, false); + if (!invalidSolid) { - invalidSolid = true; + std::vector tmpVerts; + SelectedMap->getModelPlaneIntersectVerts(modelIdx, tmpVerts); // for vertex manipulation + scaling + + Solid modelSolid; + if (!getModelSolid(tmpVerts, SelectedMap, modelSolid)) + { + invalidSolid = true; + } } } } - } - setupView(); + setupView(); - drawEntConnections(); + drawEntConnections(); - isLoading = reloading; + isLoading = reloading; - for (size_t i = 0; i < mapRenderers.size(); i++) - { - if (!mapRenderers[i]) + for (size_t i = 0; i < mapRenderers.size(); i++) { - continue; - } + if (!mapRenderers[i]) + { + continue; + } - mapRenderers[i]->clearDrawCache(); + mapRenderers[i]->clearDrawCache(); - Bsp* curMap = mapRenderers[i]->map; - if (!curMap || !curMap->bsp_name.size()) - continue; + Bsp* curMap = mapRenderers[i]->map; + if (!curMap || !curMap->bsp_name.size()) + continue; - if (SelectedMap && getSelectedMap() != curMap && (!curMap->is_bsp_model || curMap->parentMap != SelectedMap)) - { - continue; - } + if (SelectedMap && getSelectedMap() != curMap && (!curMap->is_bsp_model || curMap->parentMap != SelectedMap)) + { + continue; + } - if (SelectedMap->is_mdl_model && SelectedMap->mdl) - { - matmodel.loadIdentity(); - modelShader->bind(); - modelShader->updateMatrixes(); - SelectedMap->mdl->DrawMDL(); - continue; - } + if (SelectedMap->is_mdl_model && SelectedMap->mdl) + { + matmodel.loadIdentity(); + modelShader->bind(); + modelShader->updateMatrixes(); + SelectedMap->mdl->DrawMDL(); + continue; + } - std::set modelidskip; + std::set modelidskip; - if (curMap->ents.size() && !isLoading) - { - if (curMap->is_bsp_model) + if (curMap->ents.size() && !isLoading) { - for (size_t n = 0; n < mapRenderers.size(); n++) + if (curMap->is_bsp_model) { - if (n == i) - continue; - - Bsp* anotherMap = mapRenderers[n]->map; - if (anotherMap && anotherMap->ents.size()) + for (size_t n = 0; n < mapRenderers.size(); n++) { - vec3 anotherMapOrigin = anotherMap->ents[0]->origin; - for (int s = 0; s < (int)anotherMap->ents.size(); s++) + if (n == i) + continue; + + Bsp* anotherMap = mapRenderers[n]->map; + if (anotherMap && anotherMap->ents.size()) { - Entity* tmpEnt = anotherMap->ents[s]; - if (tmpEnt && tmpEnt->hasKey("model")) + vec3 anotherMapOrigin = anotherMap->ents[0]->origin; + for (int s = 0; s < (int)anotherMap->ents.size(); s++) { - if (!modelidskip.count(s)) + Entity* tmpEnt = anotherMap->ents[s]; + if (tmpEnt && tmpEnt->hasKey("model")) { - if (basename(tmpEnt->keyvalues["model"]) == basename(curMap->bsp_path)) + if (!modelidskip.count(s)) { - modelidskip.insert(s); - curMap->ents[0]->setOrAddKeyvalue("origin", (tmpEnt->origin + anotherMapOrigin).toKeyvalueString()); - break; + if (basename(tmpEnt->keyvalues["model"]) == basename(curMap->bsp_path)) + { + modelidskip.insert(s); + curMap->ents[0]->setOrAddKeyvalue("origin", (tmpEnt->origin + anotherMapOrigin).toKeyvalueString()); + break; + } } } } @@ -664,168 +670,171 @@ void Renderer::renderLoop() } } } - } - mapRenderers[i]->render(transformTarget == TRANSFORM_VERTEX, clipnodeRenderHull); + mapRenderers[i]->render(transformTarget == TRANSFORM_VERTEX, clipnodeRenderHull); - if (!mapRenderers[i]->isFinishedLoading()) + if (!mapRenderers[i]->isFinishedLoading()) + { + isLoading = true; + } + } + + if (SelectedMap) { - isLoading = true; + if (debugClipnodes && modelIdx > 0) + { + matmodel.loadIdentity(); + vec3 offset = (SelectedMap->getBspRender()->mapOffset + (entIdx.size() ? SelectedMap->ents[entIdx[0]]->origin : vec3())).flip(); + matmodel.translate(offset.x, offset.y, offset.z); + colorShader->updateMatrixes(); + BSPMODEL& pickModel = SelectedMap->models[modelIdx]; + int currentPlane = 0; + glDisable(GL_CULL_FACE); + drawClipnodes(SelectedMap, pickModel.iHeadnodes[1], currentPlane, debugInt, pickModel.vOrigin); + glEnable(GL_CULL_FACE); + debugIntMax = currentPlane - 1; + } + + if (debugNodes && modelIdx > 0) + { + matmodel.loadIdentity(); + vec3 offset = (SelectedMap->getBspRender()->mapOffset + (entIdx.size() > 0 ? SelectedMap->ents[entIdx[0]]->origin : vec3())).flip(); + matmodel.translate(offset.x, offset.y, offset.z); + colorShader->updateMatrixes(); + BSPMODEL& pickModel = SelectedMap->models[modelIdx]; + int currentPlane = 0; + glDisable(GL_CULL_FACE); + drawNodes(SelectedMap, pickModel.iHeadnodes[0], currentPlane, debugNode, pickModel.vOrigin); + glEnable(GL_CULL_FACE); + debugNodeMax = currentPlane - 1; + } + + if (g_render_flags & RENDER_ORIGIN) + { + glDisable(GL_CULL_FACE); + matmodel.loadIdentity(); + vec3 offset = SelectedMap->getBspRender()->mapOffset; + colorShader->updateMatrixes(); + vec3 p1 = offset + vec3(-10240.0f, 0.0f, 0.0f); + vec3 p2 = offset + vec3(10240.0f, 0.0f, 0.0f); + drawLine(p1, p2, { 128, 128, 255, 255 }); + vec3 p3 = offset + vec3(0.0f, -10240.0f, 0.0f); + vec3 p4 = offset + vec3(0.0f, 10240.0f, 0.0f); + drawLine(p3, p4, { 0, 255, 0, 255 }); + vec3 p5 = offset + vec3(0.0f, 0.0f, -10240.0f); + vec3 p6 = offset + vec3(0.0f, 0.0f, 10240.0f); + drawLine(p5, p6, { 0, 0, 255, 255 }); + glEnable(GL_CULL_FACE); + } } - } - if (SelectedMap) - { - if (debugClipnodes && modelIdx > 0) + + glDepthMask(GL_FALSE); + glDepthFunc(GL_ALWAYS); + + if (entConnectionPoints && (g_render_flags & RENDER_ENT_CONNECTIONS)) { matmodel.loadIdentity(); - vec3 offset = (SelectedMap->getBspRender()->mapOffset + (entIdx.size() ? SelectedMap->ents[entIdx[0]]->origin : vec3())).flip(); - matmodel.translate(offset.x, offset.y, offset.z); colorShader->updateMatrixes(); - BSPMODEL& pickModel = SelectedMap->models[modelIdx]; - int currentPlane = 0; - glDisable(GL_CULL_FACE); - drawClipnodes(SelectedMap, pickModel.iHeadnodes[1], currentPlane, debugInt, pickModel.vOrigin); - glEnable(GL_CULL_FACE); - debugIntMax = currentPlane - 1; + entConnectionPoints->drawFull(); } - if (debugNodes && modelIdx > 0) + if (!entIdx.size()) { - matmodel.loadIdentity(); - vec3 offset = (SelectedMap->getBspRender()->mapOffset + (entIdx.size() > 0 ? SelectedMap->ents[entIdx[0]]->origin : vec3())).flip(); - matmodel.translate(offset.x, offset.y, offset.z); - colorShader->updateMatrixes(); - BSPMODEL& pickModel = SelectedMap->models[modelIdx]; - int currentPlane = 0; - glDisable(GL_CULL_FACE); - drawNodes(SelectedMap, pickModel.iHeadnodes[0], currentPlane, debugNode, pickModel.vOrigin); - glEnable(GL_CULL_FACE); - debugNodeMax = currentPlane - 1; + if (SelectedMap && SelectedMap->is_bsp_model) + { + SelectedMap->selectModelEnt(); + } } - if (g_render_flags & RENDER_ORIGIN) + if (showDragAxes && pickMode == pick_modes::PICK_OBJECT) { - glDisable(GL_CULL_FACE); - matmodel.loadIdentity(); - vec3 offset = SelectedMap->getBspRender()->mapOffset; - colorShader->updateMatrixes(); - vec3 p1 = offset + vec3(-10240.0f, 0.0f, 0.0f); - vec3 p2 = offset + vec3(10240.0f, 0.0f, 0.0f); - drawLine(p1, p2, { 128, 128, 255, 255 }); - vec3 p3 = offset + vec3(0.0f, -10240.0f, 0.0f); - vec3 p4 = offset + vec3(0.0f, 10240.0f, 0.0f); - drawLine(p3, p4, { 0, 255, 0, 255 }); - vec3 p5 = offset + vec3(0.0f, 0.0f, -10240.0f); - vec3 p6 = offset + vec3(0.0f, 0.0f, 10240.0f); - drawLine(p5, p6, { 0, 0, 255, 255 }); - glEnable(GL_CULL_FACE); + if (!movingEnt && !isTransformingWorld && entIdx.size() && (isTransformingValid || isMovingOrigin)) + { + drawTransformAxes(); + } } - } + if (modelIdx > 0 && pickMode == PICK_OBJECT) + { + if (transformTarget == TRANSFORM_VERTEX && isTransformableSolid) + { + glDisable(GL_CULL_FACE); + drawModelVerts(); + glEnable(GL_CULL_FACE); + } + if (transformTarget == TRANSFORM_ORIGIN) + { + drawModelOrigin(modelIdx); + } + } - glDepthMask(GL_FALSE); - glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LESS); + vec3 forward, right, up; + makeVectors(cameraAngles, forward, right, up); + if (!hideGui) + gui->draw(); - if (entConnectionPoints && (g_render_flags & RENDER_ENT_CONNECTIONS)) - { - matmodel.loadIdentity(); - colorShader->updateMatrixes(); - entConnectionPoints->drawFull(); - } + controls(); - if (!entIdx.size()) - { - if (SelectedMap && SelectedMap->is_bsp_model) + if (reloading && fgdFuture.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) { - SelectedMap->selectModelEnt(); + postLoadFgds(); + for (size_t i = 0; i < mapRenderers.size(); i++) + { + mapRenderers[i]->preRenderEnts(); + if (reloadingGameDir) + { + mapRenderers[i]->reloadTextures(); + } + } + reloading = reloadingGameDir = false; } - } - if (showDragAxes && pickMode == pick_modes::PICK_OBJECT) - { - if (!movingEnt && !isTransformingWorld && entIdx.size() && (isTransformingValid || isMovingOrigin)) + int glerror = glGetError(); + while (glerror != GL_NO_ERROR) { - drawTransformAxes(); + gl_errors++; +#ifndef NDEBUG + std::cout << fmt::format(fmt::runtime(get_localized_string(LANG_0905)), glerror) << std::endl; +#endif + glerror = glGetError(); } - } - if (modelIdx > 0 && pickMode == PICK_OBJECT) - { - if (transformTarget == TRANSFORM_VERTEX && isTransformableSolid) + if (updatePickCount) { - glDisable(GL_CULL_FACE); - drawModelVerts(); - glEnable(GL_CULL_FACE); + tmpModelIdx = modelIdx; + tmpTransformTarget = transformTarget; + tmpPickIdx = pickCount; + tmpVertPickIdx = vertPickCount; } - if (transformTarget == TRANSFORM_ORIGIN) - { - drawModelOrigin(modelIdx); - } - } - glDepthMask(GL_TRUE); - glDepthFunc(GL_LESS); - vec3 forward, right, up; - makeVectors(cameraAngles, forward, right, up); - if (!hideGui) - gui->draw(); + memcpy(oldPressed, pressed, sizeof(pressed)); - controls(); + glfwSwapBuffers(window); + glfwPollEvents(); - if (reloading && fgdFuture.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) - { - postLoadFgds(); - for (size_t i = 0; i < mapRenderers.size(); i++) + if (abs(curTime - mouseTime) >= 0.016) { - mapRenderers[i]->preRenderEnts(); - if (reloadingGameDir) + if (vsync != (g_settings.vsync ? 1 : 0)) { - mapRenderers[i]->reloadTextures(); + glfwSwapInterval(g_settings.vsync); + vsync = (g_settings.vsync ? 1 : 0); } - } - reloading = reloadingGameDir = false; - } - if (is_minimized || !is_focused) - { - using namespace std::chrono_literals; - std::this_thread::sleep_for(25ms); - } - - int glerror = glGetError(); - while (glerror != GL_NO_ERROR) - { - gl_errors++; -#ifndef NDEBUG - std::cout << fmt::format(fmt::runtime(get_localized_string(LANG_0905)), glerror) << std::endl; -#endif - glerror = glGetError(); - } - - if (updatePickCount) - { - tmpModelIdx = modelIdx; - tmpTransformTarget = transformTarget; - tmpPickIdx = pickCount; - tmpVertPickIdx = vertPickCount; - } + mouseTime = curTime; + glfwGetCursorPos(window, &xpos, &ypos); + } - memcpy(oldPressed, pressed, sizeof(pressed)); - glfwSwapBuffers(window); - if (abs(curTime - mouseTime) >= 0.016) - { - if (vsync != (g_settings.vsync ? 1 : 0)) + if (is_minimized || !is_focused) { - glfwSwapInterval(g_settings.vsync); - vsync = (g_settings.vsync ? 1 : 0); + using namespace std::chrono_literals; + std::this_thread::sleep_for(25ms); } - - mouseTime = curTime; - glfwPollEvents(); - glfwGetCursorPos(window, &xpos, &ypos); + oldTime = curTime; } } @@ -1108,7 +1117,7 @@ void Renderer::drawModelOrigin(int modelIdx) COLOR4 color; if (originSelected) { - color = originHovered? hoverSelectColor : selectColor; + color = originHovered ? hoverSelectColor : selectColor; } else { @@ -2103,7 +2112,7 @@ bool Renderer::transformAxisControls() int tmpmodelidx = tmpent->getBspModelIdx(); if (tmpent->getBspModelIdx() >= 0) - { + { vec3 neworigin = gridSnappingEnabled ? snapToGrid(map->models[tmpmodelidx].vOrigin) : map->models[tmpmodelidx].vOrigin; map->models[tmpmodelidx].vOrigin = neworigin; map->getBspRender()->refreshModel(tmpent->getBspModelIdx()); @@ -2575,9 +2584,22 @@ void Renderer::updateDragAxes(vec3 delta) // set origin of the axes if (transformMode == TRANSFORM_MODE_SCALE) { - if (ent && ent->isBspModel()) + if (ent && modelIdx >= 0) { - map->get_model_vertex_bounds(ent->getBspModelIdx(), entMin, entMax); + entMin = vec3(FLT_MAX_COORD, FLT_MAX_COORD, FLT_MAX_COORD); + entMax = vec3(-FLT_MAX_COORD, -FLT_MAX_COORD,-FLT_MAX_COORD); + + if (modelVerts.size()) + { + for (auto & vert : modelVerts) + { + expandBoundingBox(vert.pos, entMin, entMax); + } + } + else + { + map->get_model_vertex_bounds(modelIdx, entMin, entMax); + } vec3 modelOrigin = entMin + (entMax - entMin) * 0.5f; entMax -= modelOrigin; diff --git a/src/editor/Settings.cpp b/src/editor/Settings.cpp index f04b8316..be0d14c0 100644 --- a/src/editor/Settings.cpp +++ b/src/editor/Settings.cpp @@ -36,6 +36,7 @@ void AppSettings::loadDefault() languages.push_back("EN"); undoLevels = 64; + fpslimit = 100; verboseLogs = false; #ifndef NDEBUG @@ -415,6 +416,14 @@ void AppSettings::load() { g_settings.undoLevels = atoi(val.c_str()); } + else if (key == "fpslimit") + { + g_settings.fpslimit = atoi(val.c_str()); + if (g_settings.fpslimit < 30) + g_settings.fpslimit = 30; + if (g_settings.fpslimit > 1000) + g_settings.fpslimit = 1000; + } else if (key == "gamedir") { g_settings.gamedir = val; @@ -809,7 +818,7 @@ void AppSettings::save(std::string path) for (size_t i = 0; i < transparentEntities.size(); i++) { file << "transparent_entities=" << transparentEntities[i] << std::endl; -} + } file << "vsync=" << g_settings.vsync << std::endl; file << "mark_unused_texinfos=" << g_settings.mark_unused_texinfos << std::endl; @@ -825,6 +834,7 @@ void AppSettings::save(std::string path) file << "renders_flags=" << g_settings.render_flags << std::endl; file << "font_size=" << g_settings.fontSize << std::endl; file << "undo_levels=" << g_settings.undoLevels << std::endl; + file << "fpslimit=" << g_settings.fpslimit << std::endl; file << "savebackup=" << g_settings.backUpMap << std::endl; file << "save_crc=" << g_settings.preserveCrc32 << std::endl; file << "save_cam=" << g_settings.save_cam << std::endl; diff --git a/src/editor/Settings.h b/src/editor/Settings.h index e2d782b2..d132f277 100644 --- a/src/editor/Settings.h +++ b/src/editor/Settings.h @@ -59,6 +59,7 @@ struct AppSettings int windowY; int maximized; int undoLevels; + int fpslimit; size_t settings_tab; int render_flags; diff --git a/src/qtools/rad.cpp b/src/qtools/rad.cpp index aff21dcb..0f20fe13 100644 --- a/src/qtools/rad.cpp +++ b/src/qtools/rad.cpp @@ -275,7 +275,6 @@ bool GetFaceExtents(Bsp* bsp, int facenum, int mins_out[2], int maxs_out[2]) } } - for (int i = 0; i < 2; i++) { mins_out[i] = (int)floor(mins[i] / TEXTURE_STEP); diff --git a/src/qtools/winding.cpp b/src/qtools/winding.cpp index 7ed5ecd6..2bdc04d7 100644 --- a/src/qtools/winding.cpp +++ b/src/qtools/winding.cpp @@ -141,6 +141,23 @@ void Winding::getPlane(BSPPLANE& plane) } } +Winding::Winding(const std::vector& points, float epsilon) +{ + m_NumPoints = points.size(); + m_MaxPoints = (m_NumPoints + 3) & ~3; + m_Points = new vec3[m_NumPoints]; + + unsigned i; + for (i = 0; i < m_NumPoints && i < points.size(); i++) + { + m_Points[i] = points[i]; + } + + RemoveColinearPoints( + epsilon + ); +} + Winding::Winding(Bsp* bsp, const BSPFACE32& face, float epsilon) { int se; @@ -152,7 +169,7 @@ Winding::Winding(Bsp* bsp, const BSPFACE32& face, float epsilon) m_Points = new vec3[m_NumPoints]; unsigned i; - for (i = 0; i < face.nEdges; i++) + for (i = 0; i < m_NumPoints && i < face.nEdges; i++) { se = bsp->surfedges[face.iFirstEdge + i]; if (se < 0) diff --git a/src/qtools/winding.h b/src/qtools/winding.h index cffc8435..85a45af8 100644 --- a/src/qtools/winding.h +++ b/src/qtools/winding.h @@ -20,6 +20,7 @@ class Winding vec3* m_Points; Winding(Bsp* bsp, const BSPFACE32& face, float epsilon = ON_EPSILON); + Winding(const std::vector & points, float epsilon = ON_EPSILON); Winding(int numpoints); Winding(const BSPPLANE& plane, float epsilon = ON_EPSILON); Winding(); diff --git a/src/util/vectors.cpp b/src/util/vectors.cpp index 7e224f87..f08074c1 100644 --- a/src/util/vectors.cpp +++ b/src/util/vectors.cpp @@ -186,6 +186,17 @@ vec3 vec3::normalize(float length) return vec3(x * d, y * d, z * d); } +bool vec3::equal(vec3 to, float epsilon) +{ + if (::abs(x - to.x) >= epsilon) + return false; + if (::abs(y - to.y) >= epsilon) + return false; + if (::abs(z - to.z) >= epsilon) + return false; + return true; +} + vec3 vec3::snap(float snapSize) { float _x = std::round(x / snapSize) * snapSize; diff --git a/src/util/vectors.h b/src/util/vectors.h index 9d69043b..30256d50 100644 --- a/src/util/vectors.h +++ b/src/util/vectors.h @@ -93,6 +93,7 @@ struct vec3 vec3 snap(float snapSize); vec3 normalize_angles(); vec3 swap_xz(); + bool equal(vec3 to, float epsilon = EPSILON); float size_test(); float sizeXY_test(); vec3 abs();