From 3760ce45e7072864634d16123dc0c46b829f359b Mon Sep 17 00:00:00 2001 From: Johan Talboom Date: Sat, 26 Feb 2022 19:47:17 +0100 Subject: [PATCH] Implemented quadtree generation, fixed patcher some more, quadtree now shows in all editmodes --- .github/workflows/msbuild.yml | 1 - Patcher/Patcher.cpp | 28 ++++++- browedit/MapView.Objectmode.cpp | 29 ------- browedit/MapView.cpp | 35 +++++++++ browedit/components/Rsw.cpp | 133 ++++++++++++++++++++++++-------- browedit/components/Rsw.h | 2 + browedit/math/AABB.cpp | 12 +++ browedit/math/AABB.h | 4 +- browedit/windows/MenuBar.cpp | 2 + imgui.ini | 6 +- 10 files changed, 184 insertions(+), 68 deletions(-) diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index 7866ac8..6b7ebce 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -42,7 +42,6 @@ jobs: run: | md dist xcopy /y /q BrowEdit3.exe dist\ - xcopy /y /q BrowEdit3.pdb dist\ xcopy /y /q imgui.ini dist\ xcopy /y /q lib\bugtrap\BugTrap-x64.dll dist\ xcopy /y /q /s data dist\data\ diff --git a/Patcher/Patcher.cpp b/Patcher/Patcher.cpp index 157acd9..b306b17 100644 --- a/Patcher/Patcher.cpp +++ b/Patcher/Patcher.cpp @@ -57,6 +57,18 @@ INT_PTR CALLBACK Wndproc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) txt += " (downloaded)"; if (version == currentVersion) txt += " (active)"; + + bool broken = true; + for (auto& asset : release["assets"]) + { + auto name = asset["name"].get(); + if (name.substr(name.size() - 4) == ".zip") + broken = false; + } + if (broken) + txt += " (broken)"; + + int pos = (int)SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)txt.c_str()); SendMessage(hwndList, LB_SETITEMDATA, pos, (LPARAM)i++); @@ -184,7 +196,21 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, SendMessage(hwndDialogBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessage(hwndDialogBar, PBM_SETSTEP, (WPARAM)1, 0); - auto url = release["assets"][0]["browser_download_url"].get(); + std::string url = ""; + for (auto& asset : release["assets"]) + { + auto name = asset["name"].get(); + if(name.substr(name.size()-4) == ".zip") + url = asset["browser_download_url"] .get(); + } + if (url == "") + { + MessageBox(nullptr, "Error downloading asset. Make sure this release has a zipfile", "Error downloading", MB_OK); + ShellExecute(nullptr, nullptr, release["html_url"].get().c_str(), "", nullptr, SW_SHOWDEFAULT); + EndDialog(hProgressDlg, 0); + exit(0); + return; + } auto data = net::fetch_request(net::url(std::wstring(url.begin(), url.end())), L"", L"", L"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)", [&](float p) { SendMessage(hwndDialogBar, PBM_SETPOS, (int)(p*100), 0); }); diff --git a/browedit/MapView.Objectmode.cpp b/browedit/MapView.Objectmode.cpp index 79a9800..c6ba38d 100644 --- a/browedit/MapView.Objectmode.cpp +++ b/browedit/MapView.Objectmode.cpp @@ -16,9 +16,6 @@ #include #include -extern std::vector> debugPoints; -extern std::mutex debugPointMutex; - void MapView::postRenderObjectMode(BrowEdit* browEdit) { @@ -29,23 +26,11 @@ void MapView::postRenderObjectMode(BrowEdit* browEdit) simpleShader->setUniform(SimpleShader::Uniforms::textureFac, 0.0f); - glUseProgram(0); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(glm::value_ptr(nodeRenderContext.projectionMatrix)); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(glm::value_ptr(nodeRenderContext.viewMatrix)); - glColor3f(1, 0, 0); fbo->bind(); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisable(GL_TEXTURE_2D); - //TODO: move this code up out of object mode - glPushMatrix(); - glScalef(1, -1, -1); auto gnd = map->rootNode->getComponent(); - glTranslatef(gnd->width * 5.0f, 0.0f, -gnd->height * 5.0f-10); - map->rootNode->getComponent()->quadtree->draw(quadTreeMaxLevel); - glPopMatrix(); #if 0 //visualize aabb glEnable(GL_BLEND); @@ -63,20 +48,6 @@ void MapView::postRenderObjectMode(BrowEdit* browEdit) glEnd(); #endif - static glm::vec4 color[] = { glm::vec4(1,0,0,1), glm::vec4(0,1,0,1), glm::vec4(0,0,1,1) }; - debugPointMutex.lock(); - glPointSize(10.0f); - for (auto i = 0; i < debugPoints.size(); i++) - { - glColor4fv(glm::value_ptr(color[i])); - glBegin(GL_POINTS); - for (auto& v : debugPoints[i]) - glVertex3fv(glm::value_ptr(v)); - glEnd(); - } - glPointSize(1.0f); - debugPointMutex.unlock(); - bool snap = snapToGrid; if (ImGui::GetIO().KeyShift) snap = !snap; diff --git a/browedit/MapView.cpp b/browedit/MapView.cpp index 5f306fe..03e0928 100644 --- a/browedit/MapView.cpp +++ b/browedit/MapView.cpp @@ -223,6 +223,41 @@ void MapView::render(BrowEdit* browEdit) } } + glUseProgram(0); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glm::value_ptr(nodeRenderContext.projectionMatrix)); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(glm::value_ptr(nodeRenderContext.viewMatrix)); + glColor3f(1, 0, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDisable(GL_TEXTURE_2D); + + + glLineWidth(1.0f); + //draw quadtree + glPushMatrix(); + glScalef(1, -1, -1); + auto gnd = map->rootNode->getComponent(); + glTranslatef(gnd->width * 5.0f, 0.0f, -gnd->height * 5.0f - 10); + map->rootNode->getComponent()->quadtree->draw(quadTreeMaxLevel); + glPopMatrix(); + + + //draw debug points + static glm::vec4 color[] = { glm::vec4(1,0,0,1), glm::vec4(0,1,0,1), glm::vec4(0,0,1,1) }; + debugPointMutex.lock(); + glPointSize(10.0f); + for (auto i = 0; i < debugPoints.size(); i++) + { + glColor4fv(glm::value_ptr(color[i])); + glBegin(GL_POINTS); + for (auto& v : debugPoints[i]) + glVertex3fv(glm::value_ptr(v)); + glEnd(); + } + glPointSize(1.0f); + debugPointMutex.unlock(); + fbo->unbind(); } diff --git a/browedit/components/Rsw.cpp b/browedit/components/Rsw.cpp index 228277e..7be0685 100644 --- a/browedit/components/Rsw.cpp +++ b/browedit/components/Rsw.cpp @@ -399,37 +399,62 @@ void Rsw::buildImGui(BrowEdit* browEdit) } } +extern std::vector> debugPoints; +std::vector> heights; void Rsw::recalculateQuadtree(QuadTreeNode* node) { static Gnd* gnd; +// static std::vector> heights; + bool rootNode = false; if (!node) { + rootNode = true; node = quadtree; gnd = this->node->getComponent(); - //this->node->traverse([&](Node* n) { - // auto rswModel = n->getComponent(); - // if (rswModel) - // { - // auto collider = n->getComponent(); - // auto collisions = collider->getCollisions(ray); - // for (auto& c : collisions) - // { - // node->bbox.min.y = glm::min(node->bbox.min.y, -c.y); - // node->bbox.max.y = glm::max(node->bbox.max.y, -c.y); - // } - // } - // }); - - //TODO - //make a 2d array with min/max height per cube - //iterate through all models - //per model, calculate world position per vertex - //per vertex, calculate cube and change the min/max height - //afterwards, for more accuracy, run raycast down for every ??? inside of the aabb - //AABB will not be accurate enough - } + heights.clear(); + heights.resize(gnd->width); + for (int i = 0; i < gnd->width; i++) + heights[i].resize(gnd->height, glm::vec2(99999999, -99999999)); + + debugPoints.clear(); + debugPoints.resize(2); + + this->node->traverse([&](Node* n) { + auto rswModel = n->getComponent(); + auto rsmRenderer = n->getComponent(); + if (rswModel) + { + auto collider = n->getComponent(); + auto vertices = collider->getVerticesWorldSpace(); + for (auto i = 0; i < vertices.size(); i += 3) + { + math::AABB aabb(std::span(vertices.begin() + i, 3)); + for (int x = floor(aabb.min.x / 10); x < ceil(aabb.max.x / 10); x++) + for (int y = floor(aabb.min.z / 10); y < ceil(aabb.max.z / 10); y++) + { + if (x >= 0 && x < gnd->width && y >= 0 && y < gnd->height) + { + heights[x][y].x = glm::min(heights[x][y].x, aabb.min.y); + heights[x][y].y = glm::max(heights[x][y].y, aabb.max.y); + } + } + + } + } + }); + + +#if 0 + for (auto x = 0; x < heights.size(); x++) + for (auto y = 0; y < heights[x].size(); y++) + { + debugPoints[0].push_back(glm::vec3(10*x, heights[x][y].x, 10 * y)); + debugPoints[1].push_back(glm::vec3(10 * x, heights[x][y].y, 10 * y)); + } +#endif + } //end startup for (int i = 0; i < 4; i++) if(node->children[i]) @@ -439,19 +464,20 @@ void Rsw::recalculateQuadtree(QuadTreeNode* node) { node->bbox.min.y = 99999; node->bbox.max.y = -99999; - - - float steps = glm::max(2.0f, glm::ceil((node->bbox.max.x - node->bbox.min.x) / 10)); - - for (float x = 0; x <= 1; x += 1/steps) + for (int x = gnd->width / 2 + floor(node->bbox.min.x / 10); x < gnd->width / 2 + ceil(node->bbox.max.x / 10); x++) { - for (float y = 0; y <= 1; y += 1/steps) + for (int y = gnd->height / 2 + floor(node->bbox.min.z / 10); y < gnd->height / 2 + ceil(node->bbox.max.z / 10); y++) { - auto center = glm::vec3(glm::mix(node->bbox.min.x, node->bbox.max.x, x), 0, glm::mix(node->bbox.min.z, node->bbox.max.z, y)); - math::Ray ray(glm::vec3(center.x + 5 * gnd->width, 9999, 10 * gnd->height - (center.z + 5 * gnd->height) + 10), glm::vec3(0, -1, 0)); - auto pos = gnd->rayCast(ray, false, glm::floor(ray.origin.x/10)-2, gnd->height - glm::floor(ray.origin.z / 10) - 2, glm::ceil(ray.origin.x / 10) + 2, gnd->height - glm::ceil(ray.origin.z / 10)+2); - node->bbox.min.y = glm::min(node->bbox.min.y, -pos.y); - node->bbox.max.y = glm::max(node->bbox.max.y, -pos.y); + if (x >= 0 && x < gnd->width && y >= 0 && y < gnd->height) + { + for (auto i = 0; i < 4; i++) + { + node->bbox.min.y = glm::min(gnd->cubes[x][y]->heights[i], node->bbox.min.y); + node->bbox.max.y = glm::max(gnd->cubes[x][y]->heights[i], node->bbox.max.y); + } + node->bbox.min.y = glm::min(-heights[x][heights[x].size() - 1 - y].y, node->bbox.min.y); + node->bbox.max.y = glm::max(-heights[x][heights[x].size() - 1 - y].x, node->bbox.max.y); + } } } } @@ -466,6 +492,13 @@ void Rsw::recalculateQuadtree(QuadTreeNode* node) } } + node->range[0] = (node->bbox.max - node->bbox.min) / 2.0f; + node->range[1] = node->bbox.max - node->range[0]; + + if (rootNode) + { + heights.clear(); + } } @@ -610,6 +643,40 @@ bool RswModelCollider::collidesTexture(Rsm::Mesh* mesh, const math::Ray& ray, co return false; } +std::vector RswModelCollider::getVerticesWorldSpace(Rsm::Mesh* mesh, const glm::mat4& matrix) +{ + if (!rswModel) + rswModel = node->getComponent(); + if (!rsm) + rsm = node->getComponent(); + if (!rsmRenderer) + rsmRenderer = node->getComponent(); + if (!rswModel || !rsm || !rsmRenderer) + return std::vector(); + + glm::mat4 mat = matrix; + if (mesh == nullptr) + { + mesh = rsm->rootMesh; + mat = rsmRenderer->matrixCache; + } + + glm::mat4 newMatrix = mat * rsmRenderer->renderInfo[mesh->index].matrix; + std::vector verts; + for (size_t i = 0; i < mesh->faces.size(); i++) + for (size_t ii = 0; ii < 3; ii++) + verts.push_back(newMatrix * glm::vec4(mesh->vertices[mesh->faces[i]->vertexIds[ii]],1)); + + for (size_t i = 0; i < mesh->children.size(); i++) + { + std::vector other = getVerticesWorldSpace(mesh->children[i], mat); + if (!other.empty()) + verts.insert(verts.end(), other.begin(), other.end()); + } + return verts; + +} + CubeCollider::CubeCollider(int size) : aabb(glm::vec3(-size,-size,-size), glm::vec3(size,size,size)) { begin(); diff --git a/browedit/components/Rsw.h b/browedit/components/Rsw.h index b71fd42..1033231 100644 --- a/browedit/components/Rsw.h +++ b/browedit/components/Rsw.h @@ -212,6 +212,8 @@ class RswModelCollider : public Collider bool collidesTexture(const math::Ray& ray); bool collidesTexture(Rsm::Mesh* mesh, const math::Ray& ray, const glm::mat4& matrix); + std::vector getVerticesWorldSpace(Rsm::Mesh* mesh = nullptr, const glm::mat4& matrix = glm::mat4(1.0f)); + std::vector getCollisions(const math::Ray& ray); std::vector getCollisions(Rsm::Mesh* mesh, const math::Ray& ray, const glm::mat4 &matrix); }; diff --git a/browedit/math/AABB.cpp b/browedit/math/AABB.cpp index dcb1649..3f125d8 100644 --- a/browedit/math/AABB.cpp +++ b/browedit/math/AABB.cpp @@ -7,6 +7,18 @@ math::AABB::AABB(const glm::vec3 &min, const glm::vec3 &max) : min(bounds[0]), m bounds[1] = max; } +math::AABB::AABB(const std::span& verts) : min(bounds[0]), max(bounds[1]) +{ + bounds[0] = verts[0]; + bounds[1] = verts[0]; + for (auto v : verts) + { + min = glm::min(min, v); + max = glm::max(max, v); + } +} + + /* Check if a ray has collision with this boundingbox. Thanks to http://www.cs.utah.edu/~awilliam/box/box.pdf diff --git a/browedit/math/AABB.h b/browedit/math/AABB.h index 63c21b9..199ea16 100644 --- a/browedit/math/AABB.h +++ b/browedit/math/AABB.h @@ -2,6 +2,7 @@ #include #include +#include namespace math { @@ -13,7 +14,8 @@ namespace math glm::vec3 &min; glm::vec3 &max; - AABB(const glm::vec3 &min, const glm::vec3 &max); + AABB(const glm::vec3& min, const glm::vec3& max); + AABB(const std::span &verts); bool hasRayCollision(const Ray& r, float minDistance, float maxDistance) const; static std::vector box(const glm::vec3& tl, const glm::vec3& br); diff --git a/browedit/windows/MenuBar.cpp b/browedit/windows/MenuBar.cpp index 5f6552e..b2c7b78 100644 --- a/browedit/windows/MenuBar.cpp +++ b/browedit/windows/MenuBar.cpp @@ -111,6 +111,8 @@ void BrowEdit::menuBar() ImGui::EndMenu(); } + if(ImGui::MenuItem("Calculate Quadtree", "Ctrl+Q")) + map->recalculateQuadTree(this); if (ImGui::MenuItem("Calculate lightmaps", "Ctrl+L") && !lightmapper) { lightmapper = new Lightmapper(map, this); diff --git a/imgui.ini b/imgui.ini index 0862acd..fcb8234 100644 --- a/imgui.ini +++ b/imgui.ini @@ -4,8 +4,8 @@ Size=1920,968 Collapsed=0 [Window][Undo stack] -Pos=1591,74 -Size=329,968 +Pos=1591,787 +Size=329,255 Collapsed=0 DockId=0x00000012,0 @@ -355,7 +355,7 @@ Column 0 Weight=1.0000 Column 1 Weight=1.0000 [Docking][Data] -DockSpace ID=0x6CE547E3 Window=0x4B8D8AF2 Pos=216,313 Size=1920,968 Split=X +DockSpace ID=0x6CE547E3 Window=0x4B8D8AF2 Pos=164,261 Size=1920,968 Split=X DockNode ID=0x00000006 Parent=0x6CE547E3 SizeRef=374,974 Selected=0x7DA7F56F DockNode ID=0x00000009 Parent=0x6CE547E3 SizeRef=1544,974 Split=X DockNode ID=0x00000001 Parent=0x00000009 SizeRef=1213,1094 Split=X Selected=0x573D7D87