diff --git a/Data/resources/shaders/fog_f.glsl b/Data/resources/shaders/.kp3d/map_grid_f.glsl similarity index 62% rename from Data/resources/shaders/fog_f.glsl rename to Data/resources/shaders/.kp3d/map_grid_f.glsl index cf97a20..1b355e4 100644 --- a/Data/resources/shaders/fog_f.glsl +++ b/Data/resources/shaders/.kp3d/map_grid_f.glsl @@ -47,8 +47,8 @@ void main() tc.x = (v_texcoord.x)+u_campos.x/1000.0; //mod(u_campos.x/1024.0, 10.0); tc.y = (v_texcoord.y)+u_campos.z/1000.0; //mod(u_campos.z/1024.0, 10.0); - tc.x *= 64.0; - tc.y *= 64.0; + tc.x *= 1000.0; + tc.y *= 1000.0; vec4 tex = texture(u_texture, tc); vec3 norm = normalize(v_normal); @@ -59,27 +59,4 @@ void main() float a = dist(v_position.xy, vec2(0.0, 0.0)) * 2.0f; v_output = vec4(tex.rgb, tex.a - a); - - - -/* - vec3 col; - vec4 tex = texture(u_texture, v_texcoord); - vec3 norm = normalize(v_normal); - vec3 dir = normalize(vec3(5.0, 0.25, -5.0) - v_position); - float diff = max(dot(norm, dir), 0.0); - float alpha = get_fog_factor(distance(u_campos, v_position)); - - vec3 diffuse = diff * vec3(0.8, 0.75, 0.7); - float ff = 1.75; - if (diffuse.x > 0.0) diffuse.x *= ff; - if (diffuse.y > 0.0) diffuse.y *= ff; - if (diffuse.z > 0.0) diffuse.z *= ff; - vec3 ambient = vec3(0.3, 0.3, 0.3); - col = (ambient + diffuse) * tex.rgb; - col *= mix(vec4(1.0), vec4(0.0f, 0.0, 0.0, 1.0), alpha-0.2).xyz; - - */ -// vec4 tex = texture(u_texture, v_texcoord); -// v_output = tex * vec4(vec3(1.5), 1.0); } diff --git a/Data/resources/shaders/fog_v.glsl b/Data/resources/shaders/.kp3d/map_grid_v.glsl similarity index 100% rename from Data/resources/shaders/fog_v.glsl rename to Data/resources/shaders/.kp3d/map_grid_v.glsl diff --git a/Data/resources/textures/.kp3d/map_grid.png b/Data/resources/textures/.kp3d/map_grid.png new file mode 100644 index 0000000..001855f Binary files /dev/null and b/Data/resources/textures/.kp3d/map_grid.png differ diff --git a/Data/resources/textures/stem.png b/Data/resources/textures/editor/stem.png similarity index 100% rename from Data/resources/textures/stem.png rename to Data/resources/textures/editor/stem.png diff --git a/Data/sandbox-cfg.json b/Data/sandbox-cfg.json index 7794bca..916bbba 100644 --- a/Data/sandbox-cfg.json +++ b/Data/sandbox-cfg.json @@ -1 +1 @@ -{"mix":{"channels":32,"chunk_size":1024,"sample_rate":44100},"sdl":{"fullscreen":0,"startup_height":768,"startup_width":1366,"title":"KP3D Sandbox","vsync":1}} +{"mix":{"channels":32,"chunk_size":1024,"sample_rate":44100},"sdl":{"fullscreen":0,"startup_height":768,"startup_width":1366,"title":"KP3Dii Sandbox","vsync":1}} diff --git a/Data/sandbox-log.txt b/Data/sandbox-log.txt index 4129b5f..bf91536 100644 --- a/Data/sandbox-log.txt +++ b/Data/sandbox-log.txt @@ -1,15 +1,14 @@ -[00:48:43 AM] Info: Starting... +[03:16:52 AM] Info: Starting... KP3D version 2 =============================== Copyright (C) kpworld.xyz 2018-2024 Contact me! @kp_cftsz -[00:48:43 AM] Info: Initializing SDL -[00:48:43 AM] Info: Initializing OpenGL -[00:48:43 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23 -[00:48:43 AM] Info: Initializing GLEW -[00:48:43 AM] Info: Initializing SDL_mixer -[00:48:43 AM] Info: Reticulating splines... -[00:48:43 AM] Info: Ready! -[00:50:29 AM] Info: Stopping... +[03:16:52 AM] Info: Initializing SDL +[03:16:52 AM] Info: Initializing OpenGL +[03:16:52 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23 +[03:16:52 AM] Info: Initializing GLEW +[03:16:52 AM] Info: Initializing SDL_mixer +[03:16:52 AM] Info: Reticulating splines... +[03:16:52 AM] Info: Ready! diff --git a/KP3Dii/src/KP3D_Geometry.cpp b/KP3Dii/src/KP3D_Geometry.cpp index 4f1eb3c..6c03816 100644 --- a/KP3Dii/src/KP3D_Geometry.cpp +++ b/KP3Dii/src/KP3D_Geometry.cpp @@ -50,102 +50,13 @@ std::vector> SplitComplexPolygon(std::vector polygon) output.push_back(polygon_excerpt); } - return output; } std::vector> ClipPolygonHoles(std::vector polygon, std::vector> holes) { - if (holes.empty()) - { - return { polygon }; - } - - for (std::vector& hole : holes) - { - polygon.push_back(polygon[0]); - for (Vec2 point: hole) - polygon.push_back(point); - polygon.push_back(hole[0]); - } - //polygon.push_back(polygon[0]); - - //polygon.erase(std::unique(polygon.begin(), polygon.end()), polygon.end()); - - return SplitComplexPolygon(polygon); - -#if 0 - using namespace Clipper2Lib; - - if (holes.empty()) - { - return {polygon}; - } - if (holes.size() > 1) - holes.pop_back(); - - //ClipperD c; - PathsD solution; - - // PolyPathD tree; - PathD complex_polygon; - for (const Vec2& v: polygon) - { - complex_polygon.push_back({v.x, v.y}); - } - // PolyTreeD cp(&tree, complex_polygon); - PathsD subjects; - subjects.push_back(complex_polygon); - PathsD clips; - KP3D_LOG_INFO("# holes: {}", holes.size()); - for (const auto& vl: holes) - { - PathD clip; - for (const Vec2& v : vl) { - clip.push_back({ v.x, v.y }); - //complex_polygon.push_back({v.x, v.y}); - } - clips.push_back(clip); - // cp.AddChild(clip); - //tree.AddChild(clip); - - } - - // tree.AddChild(complex_polygon); ? - //c.AddSubject({complex_polygon}); - //c.AddSubject(clips); - //c.AddClip(clips); - //c.AddClip(clips); - // PolyTreeD clipper_output; - //PathsD clipper_output; - //c.Execute(ClipType::Difference, FillRule::NonZero, clipper_output); - PathsD clipper_output = Difference(subjects, clips, FillRule::EvenOdd); - - std::vector> output; - - for (auto& o: clipper_output) - { - std::vector polygon_excerpt; - for (const auto& point: o) - polygon_excerpt.push_back({(float) point.x, (float) point.y}); - output.push_back(polygon_excerpt); - } - - if (output.size() > 0) - { - KP3D_LOG_INFO("Split ({}):", output.size()); - for (int i = 0; i < output.size(); i++) - KP3D_LOG_INFO("{} size: {}", i, output[i].size()); - } - - if (output.empty()) - { - return { polygon }; - } - - return output; -#endif - + // Tried doing this with Clipper but SHIT DON'T WORK! So here. You just get your input. That's all you get. Fuck you. + return {polygon}; } } // namespace kp3d diff --git a/KP3Dii/src/KP3D_Map.cpp b/KP3Dii/src/KP3D_Map.cpp index cf83e88..8250e87 100644 --- a/KP3Dii/src/KP3D_Map.cpp +++ b/KP3Dii/src/KP3D_Map.cpp @@ -14,8 +14,8 @@ namespace { -bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) { - +bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) +{ using namespace Clipper2Lib; using namespace kp3d; @@ -27,12 +27,11 @@ bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) { for (const Wall& l: inner.walls) inner_path.push_back({l.start.x, l.start.y}); - bool completely_inside = false; bool partially_inside = false; int count = 0; int partial_count = 0; - for (auto& p : inner_path) + for (PointD& p: inner_path) { PointInPolygonResult status = Clipper2Lib::PointInPolygon(p, outer_path); if (status == PointInPolygonResult::IsInside) @@ -45,67 +44,9 @@ bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) { if (partial_count > 0 && count > 0) partially_inside = true; - // KP3D_LOG_INFO("COMPLETE: {}, PARTIAL: {} / {}", count, partial_count, child_path.size()); - if (completely_inside) - { - - //s.children.push_back(&s2); - //s2.parents.push_back(s.id); - } - - return completely_inside || (count > 0 && partial_count < 4); + return completely_inside || (count > 0 && partial_count < 4); // stupid } -using namespace kp3d; - -// Function to find the barycentric coordinates of a point within a triangle -void Barycentric(const Vec2& p, const Vec2& a, const Vec2& b, const Vec2& c, float& u, float& v, float& w) { - Vec2 v0 = { b.x - a.x, b.y - a.y }; - Vec2 v1 = { c.x - a.x, c.y - a.y }; - Vec2 v2 = { p.x - a.x, p.y - a.y }; - float d00 = v0.x * v0.x + v0.y * v0.y; - float d01 = v0.x * v1.x + v0.y * v1.y; - float d11 = v1.x * v1.x + v1.y * v1.y; - float d20 = v2.x * v0.x + v2.y * v0.y; - float d21 = v2.x * v1.x + v2.y * v1.y; - float denom = d00 * d11 - d01 * d01; - v = (d11 * d20 - d01 * d21) / denom; - w = (d00 * d21 - d01 * d20) / denom; - u = 1.0f - v - w; -} - -// Function to interpolate Y value -float InterpolateY(const Vec2& p, const Vertex3D& a, const Vertex3D& b, const Vertex3D& c) { - float u, v, w; - Vec2 pa = { a.position.x, a.position.z }; - Vec2 pb = { b.position.x, b.position.z }; - Vec2 pc = { c.position.x, c.position.z }; - Barycentric(p, pa, pb, pc, u, v, w); - return u * a.position.y + v * b.position.y + w * c.position.y; -} - -// Sample floor vertices -float SampleY(const std::vector& floor_vertices, const Vec2& sample_pos) { - for (size_t i = 0; i < floor_vertices.size(); i += 3) { - const Vertex3D& v0 = floor_vertices[i]; - const Vertex3D& v1 = floor_vertices[i + 1]; - const Vertex3D& v2 = floor_vertices[i + 2]; - - Vec2 pa = { v0.position.x, v0.position.z }; - Vec2 pb = { v1.position.x, v1.position.z }; - Vec2 pc = { v2.position.x, v2.position.z }; - - // Check if the sample position is inside the triangle - float u, v, w; - Barycentric(sample_pos, pa, pb, pc, u, v, w); - if (u >= 0 && v >= 0 && w >= 0) { - return InterpolateY(sample_pos, v0, v1, v2); - } - } - return 0.0f; // Default value if the point is not found in any triangle (should not happen if inputs are correct) -} - - } namespace kp3d { @@ -392,49 +333,32 @@ void Map::Init() sectors.clear(); m_mesh.Reset(); - XYf points[7] = { - {1, 1 }, - {6, 4 }, - {11, 1 }, - {11, 13}, - {4, 14}, - {4, 12}, - {1, 12}, // Main sector - }; - - XYf points2[] = { - {4,5},{7,5},{7,6},{8,6},{8,10},{4,10} // Middle area - }; - - XYf points3[] = { - {7,5},{8,5},{8,6},{7,6} // Column (neighboring/outside middle area, not within) - }; - - XYf points4[] = { - {points3[0].x, points3[0].y + 4}, - {points3[1].x, points3[1].y + 4}, - {points3[2].x, points3[2].y + 4}, - {points3[3].x, points3[3].y + 4} // Column (within middle area) - }; - - XYf points5[] = { - {11,4},{14,4},{14,2},{16,2},{16,10},{11,10} // Neighbor of main sector - }; - - XYf points6[] = { - {1, 4},{3,4}, { 3,7 },{1,7} - }; - BuildSkybox("skybox_16.jpg"); + BuildGrid(); - static kp3d::Texture tex, tex2, tex3, tex4; + static Texture tex, tex2, tex3, tex4; tex.Load("GRASS2.png"); tex2.Load("floor0.png"); tex3.Load("FLAT5_7.png"); tex4.Load("block.png"); m_dot.Load("dot.png"); - auto build_sector = [&](Texture* wall, Texture* floor, Texture* ceil, float floor_height, float ceil_height, int id, XYf* points, size_t num_points, bool inverted = false) { + // Build a stupid little test map + // ------------------------------ + // Main sector + XYf points[7] = {{1, 1}, {6, 4}, {11, 1}, {11, 13}, {4, 14}, {4, 12}, {1, 12}}; + // Middle area + XYf points2[] = {{4, 5}, {7, 5}, {7, 6}, {8, 6}, {8, 10}, {4, 10}}; + // Column (neighboring/outside middle area, not within) + XYf points3[] = {{7, 5}, {8, 5}, {8, 6}, {7, 6}}; + // Column (within middle area) + XYf points4[] = {{points3[0].x, points3[0].y + 4}, {points3[1].x, points3[1].y + 4}, {points3[2].x, points3[2].y + 4}, {points3[3].x, points3[3].y + 4}}; + // Neighbor of main sector + XYf points5[] = {{11, 4}, {14, 4}, {14, 2}, {16, 2}, {16, 10}, {11, 10}}; + // Platform above main sector (room over room testing) + XYf points6[] = {{1, 4}, {3, 4}, {3, 7}, {1, 7}}; + auto build_sector = [&](Texture* wall, Texture* floor, Texture* ceil, float floor_height, float ceil_height, int id, XYf* points, size_t num_points, bool inverted = false) + { Sector s; s.ceiling.texture = ceil; s.floor.texture = floor; @@ -446,39 +370,29 @@ void Map::Init() s.inverted = inverted; float scl = 1.0f; for (size_t i = 0; i < num_points; i++) - { - XYf start = points[i]; - XYf end = points[(i + 1) % num_points]; - s.walls.push_back(Wall{ {wall,wall,wall}, {{0, 0}}, start, end, Wall::NO_FLAGS, (uint)i }); - } + s.walls.push_back(Wall{ {wall,wall,wall}, {{0, 0}}, points[i], points[(i + 1) % num_points], Wall::NO_FLAGS, (uint)i }); sectors.push_back(s); - }; - build_sector(&tex3, &tex, &tex2, -1.0f, 5.0f, 1, points, std::size(points)); build_sector(&tex4, &tex2, &tex2, -1.5f, 4.0f, 2, points2, std::size(points2)); build_sector(&tex4, &tex, &tex2, -1.5f, 5.0f, 3, points3, std::size(points3), true); build_sector(&tex4, &tex, &tex2, -1.5f, 4.0f, 4, points4, std::size(points4), true); - //build_sector(&tex3, &tex, &tex2, -1.2f, 3.0f, 5, points5, std::size(points5)); build_sector(&tex3, &tex, &tex2, test_u, test_l, 5, points5, std::size(points5), false); build_sector(&tex4, &tex4, &tex4, 1.0f, 1.4f, 6, points6, std::size(points6), true); - // Correct sectors with counter-clockwise linedef order using the shoelace formula, // also while we're at it grab the sector areas (will be useful later) and reset old data. - std::unordered_map sector_areas; int i = 0; for (Sector& s: sectors) { // Since we're regenerating the map, we don't want to re-use this data, it may be old. - s.parents.clear(); + s.children.clear(); s.flags = Sector::NO_FLAGS; s.parent_id = 0; s.id = ++i; // Now perform the swap + save the area float area = 0.0f; - for (Wall& l: s.walls) { bool touched = l.flags & Wall::FLAG_TOUCHED; @@ -492,36 +406,35 @@ void Map::Init() area += l.start.x * l.end.y; area -= l.end.x * l.start.y; } - area *= 0.5f; - sector_areas.emplace(s.id, fabsf(area)); - if (area <= 0.0f) { std::reverse(s.walls.begin(), s.walls.end()); for (Wall& l: s.walls) std::swap(l.start, l.end); } - s.area = fabsf(area); } - std::sort(sectors.begin(), sectors.end(), [](const Sector& a, const Sector& b) { - return a.area < b.area; - }); - for (auto& sector: sectors) { - for (auto& potentialParent: sectors) { - if (sector.id == potentialParent.id) + // Now perform the process of "parenting" sectors; this essentially takes in our flat list of sectors and creates a hierarchy. + std::sort(sectors.begin(), sectors.end(), [](const Sector& a, const Sector& b) { return a.area < b.area; }); + for (Sector& sector: sectors) + { + for (Sector& potential_parent: sectors) + { + if (sector.id == potential_parent.id) continue; - if (SectorContains(potentialParent, sector)) { - potentialParent.children.push_back(§or); - sector.parent_id = potentialParent.id; + if (SectorContains(potential_parent, sector)) + { + potential_parent.children.push_back(§or); + sector.parent_id = potential_parent.id; break; } } } #if 0 + // Debug: Print out the sector hierachy KP3D_LOG_INFO("SECTOR HIERARCHY"); for (Sector& s: sectors) { @@ -530,21 +443,16 @@ void Map::Init() KP3D_LOG_INFO(" - {}", s.parent_id ? std::to_string(s.parent_id) : "[NO PARENT]"); KP3D_LOG_INFO(" Children: "); for (Sector* c: s.children) - { KP3D_LOG_INFO(" - {}", c->id); - - } if (s.children.empty()) KP3D_LOG_INFO(" - [NO CHILDREN]"); KP3D_LOG_INFO("-----"); } #endif - // Preproc + // Preproc (really just part of the test map building process again) for (Sector& s: sectors) { - // KP3D_LOG_INFO("BUILDING SECTOR: {}", s.id); - // Build up "steiner points" for terrain only // We'll do this along a grid for now; it should be noted that this will be expected to be part of the sector data later int num_steiners_along_xy = 50; @@ -579,47 +487,21 @@ void Map::Init() } } } - - JoinSectors(s); } - for (Sector& s : sectors) + // Build level geometry + for (Sector& s: sectors) + JoinSectors(s); + for (Sector& s: sectors) { - // Build level geometry BuildFlat(s, s.floor, false); BuildFlat(s, s.ceiling, true); } - for (Sector& s : sectors) - for (Wall& ld : s.walls) + for (Sector& s: sectors) + for (Wall& ld: s.walls) BuildWall(s, ld); - // Go through all of the vertices and align them to a grid (very roughly; might want to revisit this later) -#if 0 - const float grid_size = 1.0f / (texture_scale - 1.0f), tolerance = (1.0f / texture_scale); - for (RenderBatch3D& b: m_mesh.GetBatchesRef()) - { - for (Vertex3D& v: b.vertex_data) - { - v.position.x = std::round(v.position.x / grid_size) * grid_size; - v.position.y = std::round(v.position.y / grid_size) * grid_size; - v.position.z = std::round(v.position.z / grid_size) * grid_size; - bool snapped = false; - for (const auto& unique_point: unique_points) - { - if (std::abs(v.position.x - unique_point.x) <= tolerance && - std::abs(v.position.y - unique_point.y) <= tolerance && - std::abs(v.position.z - unique_point.z) <= tolerance) - { - v.position = unique_point; - snapped = true; - break; - } - } - if (!snapped) - unique_points.insert(v.position); - } - } -#endif + // Invert the map on the Z axis; not doing this for any other reason besides compatibility with KP3D 1.0 for (RenderBatch3D& b : m_mesh.GetBatchesRef()) { for (size_t i = 0; i < b.vertex_data.size(); i += 3) @@ -637,6 +519,7 @@ void Map::Init() void Map::Rebuild(NormalGenType gen_normals) { + // This routine is really just here for me to test smooth normal generation; in the future, everything in Init() should go here m_mesh.Finalize(gen_normals); } @@ -654,10 +537,9 @@ void Map::Render() kp3d::Renderer3D::DrawMesh(m_mesh, m_transform); kp3d::Renderer3D::PopShader(); - for (Vec3 v : m_dots) - { + // Debug dots + for (Vec3 v: m_dots) kp3d::Renderer3D::DrawBillboard(m_dot, {v.x, v.y, -v.z}, {0.1f, 0.1f}, true); - } // Optional wireframe copy if (!render_wireframe) @@ -725,16 +607,43 @@ void Map::BuildSkybox(const std::string& texture_path, float scale) m_skybox_data.mesh.Reset(); m_skybox_data.mesh.AddBatch(&m_skybox_data.texture, skybox_vertex_data, true); m_skybox_data.mesh.Finalize(); - m_skybox_data.transform.scale = kp3d::Vec3(scale); + m_skybox_data.transform.scale = Vec3(scale); } void Map::RenderSkybox() { glDisable(GL_DEPTH_TEST); - kp3d::Renderer3D::PushShader(kp3d::Renderer3D::GetDefaultShader()); - m_skybox_data.transform.translation = kp3d::Renderer3D::GetPrimaryCamera()->position; - kp3d::Renderer3D::DrawMesh(m_skybox_data.mesh, m_skybox_data.transform); + Renderer3D::PushShader(Renderer3D::GetDefaultShader()); + m_skybox_data.transform.translation = Renderer3D::GetPrimaryCamera()->position; + Renderer3D::DrawMesh(m_skybox_data.mesh, m_skybox_data.transform); glEnable(GL_DEPTH_TEST); } +void Map::BuildGrid() +{ + m_grid_shader.Load(".kp3d/map_grid_v.glsl", ".kp3d/map_grid_f.glsl"); + m_grid_texture.Load(".kp3d/map_grid.png", false, kp3d::Texture::FILTER_LINEAR); + m_grid_mesh.AddBatch(&m_grid_texture, { + Vertex3D(Vec3(-0.5f, -0.5f, 0.0f), Vec2(0.0f, 1.0f)), + Vertex3D(Vec3(-0.5f, 0.5f, 0.0f), Vec2(0.0f, 0.0f)), + Vertex3D(Vec3( 0.5f, -0.5f, 0.0f), Vec2(1.0f, 1.0f)), + Vertex3D(Vec3(-0.5f, 0.5f, 0.0f), Vec2(0.0f, 0.0f)), + Vertex3D(Vec3( 0.5f, 0.5f, 0.0f), Vec2(1.0f, 0.0f)), + Vertex3D(Vec3( 0.5f, -0.5f, 0.0f), Vec2(1.0f, 1.0f)) + }, true); + m_grid_mesh.Finalize(); +} + +void Map::RenderGrid() +{ + Renderer3D::PushShader(m_grid_shader); + Vec3 camera_pos = Renderer3D::GetPrimaryCamera()->position; + camera_pos.y = 0.0f; + Transform grid_transform(camera_pos, {ToRadians(90.0f), 0.0, 0.0}, {1000.0, 1000.0, 0.0}); + glDisable(GL_CULL_FACE); + Renderer3D::DrawMesh(m_grid_mesh, grid_transform); + glEnable(GL_CULL_FACE); + Renderer3D::PopShader(); +} + } // namespace kp3d diff --git a/KP3Dii/src/KP3D_Map.h b/KP3Dii/src/KP3D_Map.h index 5be2f76..29bdc23 100644 --- a/KP3Dii/src/KP3D_Map.h +++ b/KP3Dii/src/KP3D_Map.h @@ -6,6 +6,7 @@ #include "KP3D_Texture.h" #include "KP3D_StaticMesh.h" #include "KP3D_Transform.h" +#include "KP3D_Shader.h" namespace kp3d { @@ -81,7 +82,6 @@ struct Sector bool inverted = false; std::vector children; - std::vector parents; float area = 0.0f; @@ -118,6 +118,9 @@ public: void BuildSkybox(const std::string& texture_path, float scale = 128.0f); void RenderSkybox(); + void BuildGrid(); + void RenderGrid(); + public: std::vector sectors; bool render_wireframe = true; @@ -127,6 +130,9 @@ public: private: StaticMesh m_mesh; + StaticMesh m_grid_mesh; + Shader m_grid_shader; + Texture m_grid_texture; Skybox m_skybox_data; Transform m_transform; Texture m_dot; diff --git a/Sandbox/Sandbox.vcxproj b/Sandbox/Sandbox.vcxproj index c9826ce..2aa2690 100644 --- a/Sandbox/Sandbox.vcxproj +++ b/Sandbox/Sandbox.vcxproj @@ -135,6 +135,7 @@ + @@ -142,6 +143,7 @@ + diff --git a/Sandbox/Sandbox.vcxproj.filters b/Sandbox/Sandbox.vcxproj.filters index c3b66d6..bc633e9 100644 --- a/Sandbox/Sandbox.vcxproj.filters +++ b/Sandbox/Sandbox.vcxproj.filters @@ -3,11 +3,13 @@ + + \ No newline at end of file diff --git a/Sandbox/src/Editor.cpp b/Sandbox/src/Editor.cpp new file mode 100644 index 0000000..95705d1 --- /dev/null +++ b/Sandbox/src/Editor.cpp @@ -0,0 +1,75 @@ +#include "Editor.h" + +#include + +#include "KP3D_Renderer3D.h" + +#include "Sandbox.h" + +namespace { +constexpr float MIN_DISTANCE_FROM_PLAYER = 0.1f; +constexpr float MAX_DISTANCE_FROM_PLAYER = 100.0f; +} + +Editor::Editor() +{ + m_stem.Load("editor/stem.png"); +} + +Editor::~Editor() +{ +} + +void Editor::Init() +{ +} + +void Editor::RenderMap() +{ + sandbox->map.RenderGrid(); + RenderStem({5.0f, 0.0f, 0.0f}); +} + +void Editor::RenderStem(kp3d::Vec3 position) +{ + using namespace kp3d; + Vec2 size = { + 1.0f, + (float)m_stem.GetHeight() / (float)m_stem.GetWidth() + }; + const Camera* camera = Renderer3D::GetPrimaryCamera(); + kp3d::Vec3 player_distance = position - camera->position; + float vec_distance = sqrtf( + player_distance.x * player_distance.x + + player_distance.y * player_distance.y + + player_distance.z * player_distance.z + ); + + float scale = vec_distance; + scale *= 0.1f; + + if (scale < MIN_DISTANCE_FROM_PLAYER) + scale = MIN_DISTANCE_FROM_PLAYER; + if (scale > MAX_DISTANCE_FROM_PLAYER) + scale = MAX_DISTANCE_FROM_PLAYER; + + size.x *= scale; + size.y *= scale; + + Renderer3D::DrawBillboard(m_stem, {position.x, position.y + size.y * 0.5f, position.z}, size); +} + +void Editor::RenderUI() +{ + ImGui::BeginMainMenuBar(); + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Exit")) exit(0); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); +} diff --git a/Sandbox/src/Editor.h b/Sandbox/src/Editor.h new file mode 100644 index 0000000..7f9f553 --- /dev/null +++ b/Sandbox/src/Editor.h @@ -0,0 +1,20 @@ +#pragma once + +#include "KP3D_Texture.h" +#include "KP3D_Math.h" + +class Editor +{ +public: + Editor(); + ~Editor(); + + void Init(); + void RenderMap(); + void RenderStem(kp3d::Vec3 position); + void RenderUI(); + +private: + kp3d::Texture m_stem; + +}; diff --git a/Sandbox/src/Main.cpp b/Sandbox/src/Main.cpp index 39c5334..83b9d96 100644 --- a/Sandbox/src/Main.cpp +++ b/Sandbox/src/Main.cpp @@ -6,9 +6,10 @@ #include "Sandbox.h" +std::unique_ptr sandbox; + int main(int argc, char* argv[]) { - kp3d::Vec3 vec(1.0f, 2.0f, 3.0f); - - return Sandbox(kp3d::sys::InitDataDir("../Data/", false)).Run(); + sandbox.reset(new Sandbox(kp3d::sys::InitDataDir("../Data/", false))); + return sandbox->Run(); } diff --git a/Sandbox/src/Sandbox.cpp b/Sandbox/src/Sandbox.cpp index 30f59c0..ccce8d2 100644 --- a/Sandbox/src/Sandbox.cpp +++ b/Sandbox/src/Sandbox.cpp @@ -25,6 +25,8 @@ Sandbox::Sandbox(const std::string& path): points.push_back({x, y}); return {CELL_VOID}; }}); + + m_mode = MODE_MENU; } Sandbox::~Sandbox() @@ -37,9 +39,14 @@ void Sandbox::Update() if (IsKeyDown(kp3d::KEY_GRAVE)) { kp3d::console::open ^= 1; - SetMouseLockEnabled(!GetMouseLockEnabled()); + if (GetMouseLockEnabled()) + SetMouseLockEnabled(false); KeyReset(kp3d::KEY_GRAVE); } + + if (kp3d::console::open || m_mode == MODE_MENU) + return; + if (IsKeyDown(kp3d::KEY_F1)) { map.render_wireframe ^= 1; @@ -95,21 +102,57 @@ void Sandbox::Update() void Sandbox::Render() { - glClearColor(0.0f, 0.1f, 0.3f, 1.0f); + glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // 3D scene - kp3d::Renderer3D::Begin(m_camera, m_projection); - map.Render(); - kp3d::Renderer3D::DrawBillboard(tex, {}, {1, 1}); - kp3d::Renderer3D::End(); + if (m_mode == MODE_GAME || m_mode == MODE_EDIT) + { + // 3D scene + kp3d::Renderer3D::Begin(m_camera, m_projection); + map.Render(); + if (m_mode == MODE_EDIT) + editor.RenderMap(); + kp3d::Renderer3D::DrawBillboard(tex, {}, { 1, 1 }); + kp3d::Renderer3D::End(); - // 2D scene - kp3d::Renderer2D::Begin(); - for (auto& p: points) - kp3d::Renderer2D::DrawTexture(tex, p.x, p.y, 50, 50); - kp3d::Renderer2D::End(); + // 2D scene + kp3d::Renderer2D::Begin(); + for (auto& p : points) + kp3d::Renderer2D::DrawTexture(tex, p.x, p.y, 50, 50); + kp3d::Renderer2D::End(); + + if (m_mode == MODE_EDIT) + editor.RenderUI(); + } + else if (m_mode == MODE_MENU) + { + RenderMenu(); + } // UI kp3d::console::Render(); } + +void Sandbox::RenderMenu() +{ + // SOUL utilitarian Cube 2: Sauerbraten-esque sorry ass excuse for a main menu (swag) + ImGui::SetNextWindowPos({(float) GetWidth() * 0.5f - 320.0f * 0.5f, (float) GetHeight() * 0.5f - 240.0f * 0.5f}); + ImGui::SetNextWindowSize({320, 240}); + ImGui::Begin("KP3D", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Image( + ImTextureID(tex.GetGLID()), + {ImGui::GetWindowSize().x - 20, (ImGui::GetWindowSize().x - 20) / ((float) tex.GetWidth() / (float) tex.GetHeight())} + ); + ImGui::Separator(); + if (ImGui::Button("Launch game")) + m_mode = MODE_GAME; + if (ImGui::Button("Launch editor")) + m_mode = MODE_EDIT; + ImGui::Separator(); + if (ImGui::Button("Exit")) + Exit(kp3d::SUCCESS); + ImGui::Separator(); + ImGui::Text("Version %.02f", KP3D_VERSION); + ImGui::Text("Copyright 2018-2024 kpworld.xyz"); + ImGui::End(); +} diff --git a/Sandbox/src/Sandbox.h b/Sandbox/src/Sandbox.h index 356d002..1739458 100644 --- a/Sandbox/src/Sandbox.h +++ b/Sandbox/src/Sandbox.h @@ -1,10 +1,21 @@ #pragma once +#include + #include #include #include #include +#include "Editor.h" + +enum Mode +{ + MODE_MENU, + MODE_GAME, + MODE_EDIT +}; + class Sandbox: public kp3d::Game { public: @@ -14,13 +25,19 @@ public: void Update() override; void Render() override; + void RenderMenu(); + public: // Temp kp3d::Map map; + Editor editor; private: // KP3D essentials kp3d::Mat4 m_projection; kp3d::Camera m_camera; + int m_mode; }; + +extern std::unique_ptr sandbox;