From d8dc877da6c3a4140969f84f0714ecd37b06d8e1 Mon Sep 17 00:00:00 2001 From: Safariminer Date: Tue, 29 Jul 2025 15:20:29 -0400 Subject: [PATCH] improved movements a bit and also added some infrastructure for UI <3 also removed some deprecated debug functions for map loading since map loading is now fast enough that it doesn't really require terminal loading bars --- .gitignore | 3 +- README.md | 8 +- gameenv/data/menus/test.wnd | 24 +++ mpfw/MPFW_Console.h | 2 + mpfw/MPFW_UI.cpp | 95 ++++++++++ mpfw/MPFW_UI.h | 41 +++++ mpfw/main.cpp | 344 +++++++++++++----------------------- mpfw/mpfw.vcxproj | 8 + mpfw/mpfw.vcxproj.filters | 27 +++ 9 files changed, 332 insertions(+), 220 deletions(-) create mode 100644 gameenv/data/menus/test.wnd create mode 100644 mpfw/MPFW_UI.cpp diff --git a/.gitignore b/.gitignore index dd6e8dc..0de5cf2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ deps x64 */x64 x86 -*/x86 \ No newline at end of file +*/x86 +gameenv/imgui.ini diff --git a/README.md b/README.md index e25e886..1af95ca 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,10 @@ ## focusing on complete id control ## Supported file types -- BSP29 (Quake maps) \ No newline at end of file +- BSP29 (Quake maps) + +## Dependencies +- raylib +- boost::asio +- imgui +- rlimgui \ No newline at end of file diff --git a/gameenv/data/menus/test.wnd b/gameenv/data/menus/test.wnd new file mode 100644 index 0000000..a8ce88a --- /dev/null +++ b/gameenv/data/menus/test.wnd @@ -0,0 +1,24 @@ + + + Test Window + + + File + + Load Test Map + map "data/maps/testmpfw.bsp" + + + Quit game + quit + + + + E1M1 + + Play + map "data/maps/fullquake/e1m1.bsp" + + + + \ No newline at end of file diff --git a/mpfw/MPFW_Console.h b/mpfw/MPFW_Console.h index a82f3ea..9e5c085 100644 --- a/mpfw/MPFW_Console.h +++ b/mpfw/MPFW_Console.h @@ -2,6 +2,7 @@ #include #include #include "MPFW_Quake.h" +#include "MPFW_UI.h" #include #include @@ -18,6 +19,7 @@ namespace MPFW { struct CommandHandlerResources { Quake::Maps::MapFile* mapQuake; OperationMode mode = MPFW; + UI::UIRenderer* ui; }; diff --git a/mpfw/MPFW_UI.cpp b/mpfw/MPFW_UI.cpp new file mode 100644 index 0000000..26f0ccf --- /dev/null +++ b/mpfw/MPFW_UI.cpp @@ -0,0 +1,95 @@ +#include "MPFW_UI.h" +#define NO_FONT_AWESOME +#include +#include +#include +#include +#include "MPFW_Console.h" + +#include + +bool testActive = true; +MPFW::UI::UIRenderer::UIRenderer() +{ + rlImGuiSetup(true); +} + +void MPFW::UI::UIRenderer::Render() +{ + if(rendererIsActive){ + rlImGuiBegin(); + + // wH = windowHandle + for (int wH = 0; wH < windows.size(); wH++) { + ImGui::Begin(windows[wH].windowTitle.c_str(), &windows[wH].active, windows[wH].menuBar.size() > 0 ? ImGuiWindowFlags_MenuBar : 0); + + if(windows[wH].menuBar.size() != 0){ + + if(ImGui::BeginMenuBar()){ + + // mH = menu handle + for (int mH = 0; mH < windows[wH].menuBar.size(); mH++) { + if(ImGui::BeginMenu(windows[wH].menuBar[mH].text.c_str())){ + for (int mIH = 0; mIH < windows[wH].menuBar[mH].children.size(); mIH++){ + if (ImGui::MenuItem(windows[wH].menuBar[mH].children[mIH].text.c_str())) { + cmh->Run(std::format("mode {}", windows[wH].menuBar[mH].children[mIH].commandMode), false); + cmh->Run(windows[wH].menuBar[mH].children[mIH].command, false); + } + } + ImGui::EndMenu(); + } + } + ImGui::EndMenuBar(); + } + } + + ImGui::End(); + } + + rlImGuiEnd(); + } + +} + + +MPFW::UI::UIRenderer::~UIRenderer() +{ +} + +void MPFW::UI::Window::LoadWindow(std::string path) +{ + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(path.c_str()); + + if (result) { + pugi::xml_node root = doc.child("window"); + + windowTitle = root.child("title").child_value(); + + + pugi::xml_node menubarRoot = root.child("menubar"); + if (menubarRoot) { + for (auto const& menu : menubarRoot.children("menu")) { + Menu m; + m.text = menu.child("title").child_value(); + for (auto const& menuItem : menu.children("item")) { + Menu mI; + mI.text = menuItem.child("title").child_value(); + mI.command = menuItem.child("command").child_value(); + if (menuItem.child("command").attribute("mode")) { + mI.commandMode = menuItem.child("command").attribute("mode").as_int(); + } + m.children.push_back(mI); + } + + menuBar.push_back(m); + } + } + + + } + else { + throw std::runtime_error("couldn't load " + path); + } + +} diff --git a/mpfw/MPFW_UI.h b/mpfw/MPFW_UI.h index dd645d8..f8e2064 100644 --- a/mpfw/MPFW_UI.h +++ b/mpfw/MPFW_UI.h @@ -1,11 +1,52 @@ #pragma once +#include +#include + namespace MPFW { + namespace Console { + class CommandHandler; + } namespace UI { + struct WindowElement { + + }; + + struct Menu { + std::string text; + std::string command = ""; int commandMode = 0; + std::vector children; + }; + + + + class Window { + public: + Window() {} + Window(std::string path) { LoadWindow(path); } + std::string windowTitle; + std::vector menuBar; + bool active = false; + + void LoadWindow(std::string path); + + ~Window() { menuBar.clear(); } + }; + + // main class that does the rendering of the UI y'know class UIRenderer { + bool cursorState = false; // false = off, true = on + public: + + UIRenderer(); + bool rendererIsActive = false; + MPFW::Console::CommandHandler* cmh; + std::vector windows; + void Render(); + ~UIRenderer(); }; diff --git a/mpfw/main.cpp b/mpfw/main.cpp index a0d5c3b..70a91c5 100644 --- a/mpfw/main.cpp +++ b/mpfw/main.cpp @@ -10,7 +10,7 @@ #include #include #include - +#include "MPFW_UI.h" // turn quake miptex into rl texture Texture2D RLMT_QUAKE(MPFW::Quake::Maps::rlMipTex rlmt) { @@ -37,40 +37,6 @@ struct ConsoleSettings { int height; }; - // this is grossly imprecise because of a lack of direct interfaces - // with the loop, but it's simple and should be performant in a -// thread -//static void __DebugCounter_Quake(MPFW::Quake::Maps::MapFile* mapFile) { -// while (mapFile->ds != MPFW::Quake::Maps::Debug::DONE) { -// switch (mapFile->ds) { -// case MPFW::Quake::Maps::Debug::HEADER: -// std::print("Reading header\n"); -// break; -// case MPFW::Quake::Maps::Debug::MODELS: -// std::print("Model {}/{}\n", mapFile->modelsCDBG, mapFile->data.header.models.size / 64); -// break; -// case MPFW::Quake::Maps::Debug::VERTICES: -// std::print("Vertex {}/{}\n", mapFile->verticesCDBG, mapFile->data.header.vertices.size / 12); -// break; -// case MPFW::Quake::Maps::Debug::EDGES: -// std::print("Edge {}/{}\n", mapFile->edgesCDBG, mapFile->data.header.edges.size / 4); -// break; -// case MPFW::Quake::Maps::Debug::TEXINFO: -// std::print("Surface {}/{}\n", mapFile->texInfoCDBG, mapFile->data.header.texinfo.size / 40); -// break; -// case MPFW::Quake::Maps::Debug::LEDGES: -// std::print("Ledge {}/{}\n", mapFile->data.ledges.size(), mapFile->data.header.ledges.size / 2); -// break; -// case MPFW::Quake::Maps::Debug::FACES: -// std::print("Face {}/{}\n", mapFile->data.faces.size(), mapFile->data.header.faces.size / 20); -// break; -// } -//#pragma warning(suppress : 4996) -// _sleep(250); -// } -//} - - void Look() { @@ -80,35 +46,57 @@ void Look() { rotation = Vector3Normalize({ rotation.x, Clamp(rotation.y - GetMouseDelta().y * GetFrameTime(), -0.99, 0.99), rotation.z }); } -void AirAccelerate(bool inAir) { - if (IsKeyDown(KEY_W)) { - velocity += hRotation * GetFrameTime() * accelFactor * (IsKeyDown(KEY_LEFT_SHIFT) ? 4 : 2); - } - if (IsKeyDown(KEY_S)) { - velocity -= hRotation * GetFrameTime() * accelFactor; - } - Vector3 sideRotation = Vector3RotateByAxisAngle(hRotation, { 0,1,0 }, DEG2RAD * 90); - if (IsKeyDown(KEY_A)) { - velocity += sideRotation * GetFrameTime() * accelFactor * (IsKeyDown(KEY_LEFT_SHIFT) ? 4 : 2); - } - if (IsKeyDown(KEY_D)) { - velocity -= sideRotation * GetFrameTime() * accelFactor * (IsKeyDown(KEY_LEFT_SHIFT) ? 4 : 2); - } - if (inAir)velocity.y -= GetFrameTime() * 2.5; - velocity.x *= 80 * GetFrameTime(); - velocity.z *= 80 * GetFrameTime(); + +// because quake can't normalize vectors like a civilized piece of software + +struct qNVec { + Vector3 vectorReturn; + float distance; +}; + +qNVec qNormalize(Vector3 v) { + qNVec retval; + retval.vectorReturn = Vector3Normalize(v); + retval.distance = Vector3Length(v); + return retval; } +Vector3 wishDir = { 0,0,0 }; +double wishSpeed; + + void Accelerate() { - if (IsKeyDown(KEY_SPACE)) velocity.y += accelFactor * 0.0025; - AirAccelerate(false); - if (velocity.y < 0) velocity.y = 0; + + double addSpeed, accelSpeed, currentSpeed; + currentSpeed = Vector3DotProduct(velocity, wishDir); + addSpeed = wishSpeed - currentSpeed; + if(addSpeed > 0){ + accelSpeed = 10 * GetFrameTime() * wishSpeed; + if (accelSpeed > addSpeed) accelSpeed = addSpeed; + velocity = Vector3Add(velocity, wishDir * accelSpeed); + } } +void AirAccelerate(Vector3 wishVelocity) { + double addSpeed, wishSpeedFunc, accelSpeed, currentSpeed; + qNVec qnv = qNormalize(wishVelocity); + wishSpeedFunc = qnv.distance; + wishVelocity = qnv.vectorReturn; + if (wishSpeedFunc > 30) wishSpeedFunc = 30; + currentSpeed = Vector3DotProduct(velocity, wishVelocity); + addSpeed = wishSpeedFunc - currentSpeed; + if (addSpeed > 0) { + accelSpeed = 10 * wishSpeed * GetFrameTime(); + if (accelSpeed > addSpeed) accelSpeed = addSpeed; + velocity = Vector3Add(velocity, wishVelocity * accelSpeed); + } + +} + #ifdef _DEBUG template @@ -193,13 +181,15 @@ int main() { SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(1280, 720, TextFormat("mpfw")); - // SetTargetFPS(60); + SetTargetFPS(60); SetExitKey(0); DisableCursor(); + MPFW::UI::UIRenderer uiRenderer; MPFW::Console::CommandHandlerResources chr; chr.mapQuake = ↦ + chr.ui = &uiRenderer; MPFW::Console::CommandHandler cmdH(&chr); @@ -209,7 +199,12 @@ int main() { cmdH.RunScript("data/cfg/startup.cfg"); + uiRenderer.cmh = &cmdH; + + MPFW::UI::Window wndw("data/menus/test.wnd"); + + uiRenderer.windows.push_back(wndw); // rlSetClipPlanes(1, INFINITY); camera.position = { 0,5,0 }; @@ -222,22 +217,72 @@ int main() { int indivFace = 0; bool consoleOn = false; std::string cmdBuf = ""; + int framebuffer = 0; while (!WindowShouldClose()) { + + + if (framebuffer < 5) { + + DisableCursor(); + framebuffer++; + } + if (IsKeyPressed(KEY_APOSTROPHE)) { consoleOn = !consoleOn; } if(!consoleOn){ Look(); - if (camera.position.y > 5) AirAccelerate(true); - else Accelerate(); - if (camera.position.y < 5) camera.position.y = 5; + Vector3 wishVel = { 0,0,0 }; + wishSpeed = 320; + + if (IsKeyDown(KEY_W)) { + wishVel += hRotation; + } + if (IsKeyDown(KEY_S)) { + wishVel -= hRotation; + } + if (IsKeyDown(KEY_A)) { + wishVel += Vector3RotateByAxisAngle(hRotation, { 0,1,0 }, 90 * DEG2RAD); + } + if (IsKeyDown(KEY_D)) { + wishVel += Vector3RotateByAxisAngle(hRotation, { 0,1,0 }, -90 * DEG2RAD); + } + + wishVel = Vector3Multiply(Vector3Normalize(wishVel), { 320, 320, 320 }); + + wishDir = Vector3Normalize(wishVel); + if (camera.position.y <= 5) { + camera.position.y = 5; + velocity.y = 0; + if(IsKeyPressed(KEY_SPACE)){ + velocity.y += 320*GetFrameTime(); + } + Accelerate(); + } + else { + AirAccelerate(wishVel); + velocity.y -= 10 * GetFrameTime(); + } if (IsKeyPressed(KEY_LEFT) && indivFace > 0) indivFace--; if (IsKeyPressed(KEY_RIGHT) && indivFace < map.data.faces.size() - 1) indivFace++; if (IsKeyPressed(KEY_F)) indivFaceMode = !indivFaceMode; + } + if (IsKeyPressed(KEY_ESCAPE)) { + if (IsCursorHidden()) { + EnableCursor(); + uiRenderer.rendererIsActive = true; + } + else { + DisableCursor(); + uiRenderer.rendererIsActive = false; + } + } + + velocity *= {GetFrameTime(), 1, GetFrameTime()}; camera.position += velocity; camera.target = camera.position + rotation; BeginDrawing(); @@ -245,177 +290,41 @@ int main() { DrawRectangleGradientV(0, 0, GetScreenWidth(), GetScreenHeight(), WHITE, LIGHTGRAY); BeginMode3D(camera); - // DrawGrid(1000, 10); - if (!indivFaceMode) { - - for (int i = 0; i < map.data.renderFaces.size(); i++) { - rlColor4ub(255, 255, 255, 255); - rlSetTexture(map.data.renderFaces[i].glTextureId); + DrawGrid(10000, 10); + + for (int i = 0; i < map.data.renderFaces.size(); i++) { + rlColor4ub(255, 255, 255, 255); + rlSetTexture(map.data.renderFaces[i].glTextureId); - for (int j = 1; j < map.data.renderFaces[i].vertices.size(); j++) { - rlBegin(RL_QUADS); // for texturing reasons because rlgl - Vector3 a = map.data.renderFaces[i].vertices[0], - b = map.data.renderFaces[i].vertices[j], - c = map.data.renderFaces[i].vertices[j - 1]; + for (int j = 1; j < map.data.renderFaces[i].vertices.size(); j++) { + rlBegin(RL_QUADS); // for texturing reasons because rlgl + Vector3 a = map.data.renderFaces[i].vertices[0], + b = map.data.renderFaces[i].vertices[j], + c = map.data.renderFaces[i].vertices[j - 1]; - Vector2 at = map.data.renderFaces[i].texCoords[0], - bt = map.data.renderFaces[i].texCoords[j], - ct = map.data.renderFaces[i].texCoords[j - 1]; + Vector2 at = map.data.renderFaces[i].texCoords[0], + bt = map.data.renderFaces[i].texCoords[j], + ct = map.data.renderFaces[i].texCoords[j - 1]; - rlTexCoord2f(at.x, at.y); - rlVertex3f(a.x, a.y, a.z); - rlTexCoord2f(bt.x, bt.y); - rlVertex3f(b.x, b.y, b.z); - rlTexCoord2f(ct.x, ct.y); - rlVertex3f(c.x, c.y, c.z); - rlVertex3f(c.x, c.y, c.z); + rlTexCoord2f(at.x, at.y); + rlVertex3f(a.x, a.y, a.z); + rlTexCoord2f(bt.x, bt.y); + rlVertex3f(b.x, b.y, b.z); + rlTexCoord2f(ct.x, ct.y); + rlVertex3f(c.x, c.y, c.z); + rlVertex3f(c.x, c.y, c.z); - rlEnd(); - } - - - } - } - else { - int i = indivFace; - - std::vector vertices; - - rlColor4ub(colors[i].r, colors[i].g, colors[i].b, colors[i].a); - rlBegin(RL_TRIANGLES); - - - - Vector3 a = MPFW::Quake::Maps::qVec2RLVec(map.data.vertices[map.data.edges[abs(map.data.ledges[map.data.faces[i].ledgeId])].vertex0]); - - - for (int k = 0; k < map.data.faces[i].ledgeNum; k++) { - if (map.data.ledges[map.data.faces[i].ledgeId + k] < 0) { - vertices.push_back(MPFW::Quake::Maps::qVec2RLVec( - map.data.vertices[ - map.data.edges[ - abs( - map.data.ledges[ - map.data.faces[i].ledgeId + k - ] - ) - ].vertex1 - ] - )); - } - else { - vertices.push_back(MPFW::Quake::Maps::qVec2RLVec( - map.data.vertices[ - map.data.edges[ - abs( - map.data.ledges[ - map.data.faces[i].ledgeId + k - ] - ) - ].vertex0 - ] - )); - } - - - DrawLine3D(MPFW::Quake::Maps::qVec2RLVec( - map.data.vertices[ - map.data.edges[ - abs( - map.data.ledges[ - map.data.faces[i].ledgeId + k - ] - ) - ].vertex0 - ] - ), - - MPFW::Quake::Maps::qVec2RLVec( - map.data.vertices[ - map.data.edges[ - abs( - map.data.ledges[ - map.data.faces[i].ledgeId + k - ] - ) - ].vertex1 - ] - ), RED); - + rlEnd(); } - rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z); - - rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z); - rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z); - - - - - rlEnd(); - rlColor4f(255, 255, 255, 255); } EndMode3D(); DrawFPS(0, 0); - if (indivFaceMode) { - - - std::vector vertices; - { - int i = indivFace; - - - rlColor4ub(colors[i].r, colors[i].g, colors[i].b, colors[i].a); - rlBegin(RL_TRIANGLES); - - - - Vector3 a = MPFW::Quake::Maps::qVec2RLVec(map.data.vertices[map.data.edges[abs(map.data.ledges[map.data.faces[i].ledgeId])].vertex0]); - - - for (int k = 0; k < map.data.faces[i].ledgeNum; k++) { - if (map.data.ledges[map.data.faces[i].ledgeId + k] < 0) { - vertices.push_back(MPFW::Quake::Maps::qVec2RLVec( - map.data.vertices[ - map.data.edges[ - abs( - map.data.ledges[ - map.data.faces[i].ledgeId + k - ] - ) - ].vertex1 - ] - )); - } - else { - vertices.push_back(MPFW::Quake::Maps::qVec2RLVec( - map.data.vertices[ - map.data.edges[ - abs( - map.data.ledges[ - map.data.faces[i].ledgeId + k - ] - ) - ].vertex0 - ] - )); - } - - - - } - - } - DrawText(TextFormat("Current face: %i", indivFace), 0, 30, 30, BLACK); - for (int i = 0; i < vertices.size(); i++) { - DrawText(TextFormat("Vertex %i : %f %f %f", i, vertices[i].x, vertices[i].y, vertices[i].z), 0, 60 + 10 * i, 10, BLACK); - } - } if (consoleOn) { DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight() / 2, {0,0,0,200}); @@ -440,9 +349,8 @@ int main() { cmdBuf = ""; } - - } + uiRenderer.Render(); EndDrawing(); } diff --git a/mpfw/mpfw.vcxproj b/mpfw/mpfw.vcxproj index f65ad46..da33f84 100644 --- a/mpfw/mpfw.vcxproj +++ b/mpfw/mpfw.vcxproj @@ -137,11 +137,19 @@ + + + + + + + + diff --git a/mpfw/mpfw.vcxproj.filters b/mpfw/mpfw.vcxproj.filters index 2ff9031..26d3348 100644 --- a/mpfw/mpfw.vcxproj.filters +++ b/mpfw/mpfw.vcxproj.filters @@ -13,6 +13,9 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {4f8f0e99-b4e5-46ed-8593-5de637bd7032} + @@ -33,6 +36,30 @@ Source Files + + ext. + + + ext. + + + ext. + + + ext. + + + ext. + + + ext. + + + Source Files + + + ext. +