Start work on editor

This commit is contained in:
KP 2024-07-24 03:17:46 -05:00
parent 0b41057244
commit 4865df8fd9
16 changed files with 273 additions and 311 deletions

View file

@ -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.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.y = (v_texcoord.y)+u_campos.z/1000.0; //mod(u_campos.z/1024.0, 10.0);
tc.x *= 64.0; tc.x *= 1000.0;
tc.y *= 64.0; tc.y *= 1000.0;
vec4 tex = texture(u_texture, tc); vec4 tex = texture(u_texture, tc);
vec3 norm = normalize(v_normal); vec3 norm = normalize(v_normal);
@ -59,27 +59,4 @@ void main()
float a = dist(v_position.xy, vec2(0.0, 0.0)) * 2.0f; float a = dist(v_position.xy, vec2(0.0, 0.0)) * 2.0f;
v_output = vec4(tex.rgb, tex.a - a); 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);
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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}}

View file

@ -1,15 +1,14 @@
[00:48:43 AM] Info: Starting... [03:16:52 AM] Info: Starting...
KP3D version 2 KP3D version 2
=============================== ===============================
Copyright (C) kpworld.xyz 2018-2024 Copyright (C) kpworld.xyz 2018-2024
Contact me! @kp_cftsz Contact me! @kp_cftsz
[00:48:43 AM] Info: Initializing SDL [03:16:52 AM] Info: Initializing SDL
[00:48:43 AM] Info: Initializing OpenGL [03:16:52 AM] Info: Initializing OpenGL
[00:48:43 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23 [03:16:52 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23
[00:48:43 AM] Info: Initializing GLEW [03:16:52 AM] Info: Initializing GLEW
[00:48:43 AM] Info: Initializing SDL_mixer [03:16:52 AM] Info: Initializing SDL_mixer
[00:48:43 AM] Info: Reticulating splines... [03:16:52 AM] Info: Reticulating splines...
[00:48:43 AM] Info: Ready! [03:16:52 AM] Info: Ready!
[00:50:29 AM] Info: Stopping...

View file

@ -50,102 +50,13 @@ std::vector<std::vector<Vec2>> SplitComplexPolygon(std::vector<Vec2> polygon)
output.push_back(polygon_excerpt); output.push_back(polygon_excerpt);
} }
return output; return output;
} }
std::vector<std::vector<Vec2>> ClipPolygonHoles(std::vector<Vec2> polygon, std::vector<std::vector<Vec2>> holes) std::vector<std::vector<Vec2>> ClipPolygonHoles(std::vector<Vec2> polygon, std::vector<std::vector<Vec2>> holes)
{ {
if (holes.empty()) // 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 };
}
for (std::vector<Vec2>& 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}; 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<std::vector<Vec2>> output;
for (auto& o: clipper_output)
{
std::vector<Vec2> 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
} }
} // namespace kp3d } // namespace kp3d

View file

@ -14,8 +14,8 @@
namespace { 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 Clipper2Lib;
using namespace kp3d; using namespace kp3d;
@ -27,12 +27,11 @@ bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) {
for (const Wall& l: inner.walls) for (const Wall& l: inner.walls)
inner_path.push_back({l.start.x, l.start.y}); inner_path.push_back({l.start.x, l.start.y});
bool completely_inside = false; bool completely_inside = false;
bool partially_inside = false; bool partially_inside = false;
int count = 0; int count = 0;
int partial_count = 0; int partial_count = 0;
for (auto& p : inner_path) for (PointD& p: inner_path)
{ {
PointInPolygonResult status = Clipper2Lib::PointInPolygon(p, outer_path); PointInPolygonResult status = Clipper2Lib::PointInPolygon(p, outer_path);
if (status == PointInPolygonResult::IsInside) if (status == PointInPolygonResult::IsInside)
@ -45,67 +44,9 @@ bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) {
if (partial_count > 0 && count > 0) if (partial_count > 0 && count > 0)
partially_inside = true; partially_inside = true;
// KP3D_LOG_INFO("COMPLETE: {}, PARTIAL: {} / {}", count, partial_count, child_path.size()); return completely_inside || (count > 0 && partial_count < 4); // stupid
if (completely_inside)
{
//s.children.push_back(&s2);
//s2.parents.push_back(s.id);
}
return completely_inside || (count > 0 && partial_count < 4);
} }
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<Vertex3D>& 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 { namespace kp3d {
@ -392,49 +333,32 @@ void Map::Init()
sectors.clear(); sectors.clear();
m_mesh.Reset(); 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"); BuildSkybox("skybox_16.jpg");
BuildGrid();
static kp3d::Texture tex, tex2, tex3, tex4; static Texture tex, tex2, tex3, tex4;
tex.Load("GRASS2.png"); tex.Load("GRASS2.png");
tex2.Load("floor0.png"); tex2.Load("floor0.png");
tex3.Load("FLAT5_7.png"); tex3.Load("FLAT5_7.png");
tex4.Load("block.png"); tex4.Load("block.png");
m_dot.Load("dot.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; Sector s;
s.ceiling.texture = ceil; s.ceiling.texture = ceil;
s.floor.texture = floor; s.floor.texture = floor;
@ -446,39 +370,29 @@ void Map::Init()
s.inverted = inverted; s.inverted = inverted;
float scl = 1.0f; float scl = 1.0f;
for (size_t i = 0; i < num_points; i++) for (size_t i = 0; i < num_points; i++)
{ s.walls.push_back(Wall{ {wall,wall,wall}, {{0, 0}}, points[i], points[(i + 1) % num_points], Wall::NO_FLAGS, (uint)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 });
}
sectors.push_back(s); sectors.push_back(s);
}; };
build_sector(&tex3, &tex, &tex2, -1.0f, 5.0f, 1, points, std::size(points)); 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, &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, 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(&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(&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); 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, // 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. // also while we're at it grab the sector areas (will be useful later) and reset old data.
std::unordered_map<int, float> sector_areas;
int i = 0; int i = 0;
for (Sector& s: sectors) for (Sector& s: sectors)
{ {
// Since we're regenerating the map, we don't want to re-use this data, it may be old. // 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.flags = Sector::NO_FLAGS;
s.parent_id = 0; s.parent_id = 0;
s.id = ++i; s.id = ++i;
// Now perform the swap + save the area // Now perform the swap + save the area
float area = 0.0f; float area = 0.0f;
for (Wall& l: s.walls) for (Wall& l: s.walls)
{ {
bool touched = l.flags & Wall::FLAG_TOUCHED; bool touched = l.flags & Wall::FLAG_TOUCHED;
@ -492,36 +406,35 @@ void Map::Init()
area += l.start.x * l.end.y; area += l.start.x * l.end.y;
area -= l.end.x * l.start.y; area -= l.end.x * l.start.y;
} }
area *= 0.5f; area *= 0.5f;
sector_areas.emplace(s.id, fabsf(area));
if (area <= 0.0f) if (area <= 0.0f)
{ {
std::reverse(s.walls.begin(), s.walls.end()); std::reverse(s.walls.begin(), s.walls.end());
for (Wall& l: s.walls) for (Wall& l: s.walls)
std::swap(l.start, l.end); std::swap(l.start, l.end);
} }
s.area = fabsf(area); s.area = fabsf(area);
} }
std::sort(sectors.begin(), sectors.end(), [](const Sector& a, const Sector& b) { // Now perform the process of "parenting" sectors; this essentially takes in our flat list of sectors and creates a hierarchy.
return a.area < b.area; std::sort(sectors.begin(), sectors.end(), [](const Sector& a, const Sector& b) { return a.area < b.area; });
}); for (Sector& sector: sectors)
for (auto& sector: sectors) { {
for (auto& potentialParent: sectors) { for (Sector& potential_parent: sectors)
if (sector.id == potentialParent.id) {
if (sector.id == potential_parent.id)
continue; continue;
if (SectorContains(potentialParent, sector)) { if (SectorContains(potential_parent, sector))
potentialParent.children.push_back(&sector); {
sector.parent_id = potentialParent.id; potential_parent.children.push_back(&sector);
sector.parent_id = potential_parent.id;
break; break;
} }
} }
} }
#if 0 #if 0
// Debug: Print out the sector hierachy
KP3D_LOG_INFO("SECTOR HIERARCHY"); KP3D_LOG_INFO("SECTOR HIERARCHY");
for (Sector& s: sectors) 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(" - {}", s.parent_id ? std::to_string(s.parent_id) : "[NO PARENT]");
KP3D_LOG_INFO(" Children: "); KP3D_LOG_INFO(" Children: ");
for (Sector* c: s.children) for (Sector* c: s.children)
{
KP3D_LOG_INFO(" - {}", c->id); KP3D_LOG_INFO(" - {}", c->id);
}
if (s.children.empty()) if (s.children.empty())
KP3D_LOG_INFO(" - [NO CHILDREN]"); KP3D_LOG_INFO(" - [NO CHILDREN]");
KP3D_LOG_INFO("-----"); KP3D_LOG_INFO("-----");
} }
#endif #endif
// Preproc // Preproc (really just part of the test map building process again)
for (Sector& s: sectors) for (Sector& s: sectors)
{ {
// KP3D_LOG_INFO("BUILDING SECTOR: {}", s.id);
// Build up "steiner points" for terrain only // 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 // 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; int num_steiners_along_xy = 50;
@ -579,47 +487,21 @@ void Map::Init()
} }
} }
} }
JoinSectors(s);
} }
for (Sector& s : sectors)
{
// Build level geometry // Build level geometry
for (Sector& s: sectors)
JoinSectors(s);
for (Sector& s: sectors)
{
BuildFlat(s, s.floor, false); BuildFlat(s, s.floor, false);
BuildFlat(s, s.ceiling, true); BuildFlat(s, s.ceiling, true);
} }
for (Sector& s : sectors) for (Sector& s: sectors)
for (Wall& ld : s.walls) for (Wall& ld: s.walls)
BuildWall(s, ld); BuildWall(s, ld);
// Go through all of the vertices and align them to a grid (very roughly; might want to revisit this later) // Invert the map on the Z axis; not doing this for any other reason besides compatibility with KP3D 1.0
#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
for (RenderBatch3D& b : m_mesh.GetBatchesRef()) for (RenderBatch3D& b : m_mesh.GetBatchesRef())
{ {
for (size_t i = 0; i < b.vertex_data.size(); i += 3) 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) 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); m_mesh.Finalize(gen_normals);
} }
@ -654,10 +537,9 @@ void Map::Render()
kp3d::Renderer3D::DrawMesh(m_mesh, m_transform); kp3d::Renderer3D::DrawMesh(m_mesh, m_transform);
kp3d::Renderer3D::PopShader(); 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); kp3d::Renderer3D::DrawBillboard(m_dot, {v.x, v.y, -v.z}, {0.1f, 0.1f}, true);
}
// Optional wireframe copy // Optional wireframe copy
if (!render_wireframe) 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.Reset();
m_skybox_data.mesh.AddBatch(&m_skybox_data.texture, skybox_vertex_data, true); m_skybox_data.mesh.AddBatch(&m_skybox_data.texture, skybox_vertex_data, true);
m_skybox_data.mesh.Finalize(); m_skybox_data.mesh.Finalize();
m_skybox_data.transform.scale = kp3d::Vec3(scale); m_skybox_data.transform.scale = Vec3(scale);
} }
void Map::RenderSkybox() void Map::RenderSkybox()
{ {
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
kp3d::Renderer3D::PushShader(kp3d::Renderer3D::GetDefaultShader()); Renderer3D::PushShader(Renderer3D::GetDefaultShader());
m_skybox_data.transform.translation = kp3d::Renderer3D::GetPrimaryCamera()->position; m_skybox_data.transform.translation = Renderer3D::GetPrimaryCamera()->position;
kp3d::Renderer3D::DrawMesh(m_skybox_data.mesh, m_skybox_data.transform); Renderer3D::DrawMesh(m_skybox_data.mesh, m_skybox_data.transform);
glEnable(GL_DEPTH_TEST); 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 } // namespace kp3d

View file

@ -6,6 +6,7 @@
#include "KP3D_Texture.h" #include "KP3D_Texture.h"
#include "KP3D_StaticMesh.h" #include "KP3D_StaticMesh.h"
#include "KP3D_Transform.h" #include "KP3D_Transform.h"
#include "KP3D_Shader.h"
namespace kp3d { namespace kp3d {
@ -81,7 +82,6 @@ struct Sector
bool inverted = false; bool inverted = false;
std::vector<Sector*> children; std::vector<Sector*> children;
std::vector<int> parents;
float area = 0.0f; float area = 0.0f;
@ -118,6 +118,9 @@ public:
void BuildSkybox(const std::string& texture_path, float scale = 128.0f); void BuildSkybox(const std::string& texture_path, float scale = 128.0f);
void RenderSkybox(); void RenderSkybox();
void BuildGrid();
void RenderGrid();
public: public:
std::vector<Sector> sectors; std::vector<Sector> sectors;
bool render_wireframe = true; bool render_wireframe = true;
@ -127,6 +130,9 @@ public:
private: private:
StaticMesh m_mesh; StaticMesh m_mesh;
StaticMesh m_grid_mesh;
Shader m_grid_shader;
Texture m_grid_texture;
Skybox m_skybox_data; Skybox m_skybox_data;
Transform m_transform; Transform m_transform;
Texture m_dot; Texture m_dot;

View file

@ -135,6 +135,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Editor.cpp" />
<ClCompile Include="src\Main.cpp" /> <ClCompile Include="src\Main.cpp" />
<ClCompile Include="src\Sandbox.cpp" /> <ClCompile Include="src\Sandbox.cpp" />
</ItemGroup> </ItemGroup>
@ -142,6 +143,7 @@
<None Include=".clang-format" /> <None Include=".clang-format" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Editor.h" />
<ClInclude Include="src\Sandbox.h" /> <ClInclude Include="src\Sandbox.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View file

@ -3,11 +3,13 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Main.cpp" /> <ClCompile Include="src\Main.cpp" />
<ClCompile Include="src\Sandbox.cpp" /> <ClCompile Include="src\Sandbox.cpp" />
<ClCompile Include="src\Editor.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include=".clang-format" /> <None Include=".clang-format" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Sandbox.h" /> <ClInclude Include="src\Sandbox.h" />
<ClInclude Include="src\Editor.h" />
</ItemGroup> </ItemGroup>
</Project> </Project>

75
Sandbox/src/Editor.cpp Normal file
View file

@ -0,0 +1,75 @@
#include "Editor.h"
#include <imgui.h>
#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();
}

20
Sandbox/src/Editor.h Normal file
View file

@ -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;
};

View file

@ -6,9 +6,10 @@
#include "Sandbox.h" #include "Sandbox.h"
std::unique_ptr<Sandbox> sandbox;
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
kp3d::Vec3 vec(1.0f, 2.0f, 3.0f); sandbox.reset(new Sandbox(kp3d::sys::InitDataDir("../Data/", false)));
return sandbox->Run();
return Sandbox(kp3d::sys::InitDataDir("../Data/", false)).Run();
} }

View file

@ -25,6 +25,8 @@ Sandbox::Sandbox(const std::string& path):
points.push_back({x, y}); points.push_back({x, y});
return {CELL_VOID}; return {CELL_VOID};
}}); }});
m_mode = MODE_MENU;
} }
Sandbox::~Sandbox() Sandbox::~Sandbox()
@ -37,9 +39,14 @@ void Sandbox::Update()
if (IsKeyDown(kp3d::KEY_GRAVE)) if (IsKeyDown(kp3d::KEY_GRAVE))
{ {
kp3d::console::open ^= 1; kp3d::console::open ^= 1;
SetMouseLockEnabled(!GetMouseLockEnabled()); if (GetMouseLockEnabled())
SetMouseLockEnabled(false);
KeyReset(kp3d::KEY_GRAVE); KeyReset(kp3d::KEY_GRAVE);
} }
if (kp3d::console::open || m_mode == MODE_MENU)
return;
if (IsKeyDown(kp3d::KEY_F1)) if (IsKeyDown(kp3d::KEY_F1))
{ {
map.render_wireframe ^= 1; map.render_wireframe ^= 1;
@ -95,21 +102,57 @@ void Sandbox::Update()
void Sandbox::Render() 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); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (m_mode == MODE_GAME || m_mode == MODE_EDIT)
{
// 3D scene // 3D scene
kp3d::Renderer3D::Begin(m_camera, m_projection); kp3d::Renderer3D::Begin(m_camera, m_projection);
map.Render(); map.Render();
kp3d::Renderer3D::DrawBillboard(tex, {}, {1, 1}); if (m_mode == MODE_EDIT)
editor.RenderMap();
kp3d::Renderer3D::DrawBillboard(tex, {}, { 1, 1 });
kp3d::Renderer3D::End(); kp3d::Renderer3D::End();
// 2D scene // 2D scene
kp3d::Renderer2D::Begin(); kp3d::Renderer2D::Begin();
for (auto& p: points) for (auto& p : points)
kp3d::Renderer2D::DrawTexture(tex, p.x, p.y, 50, 50); kp3d::Renderer2D::DrawTexture(tex, p.x, p.y, 50, 50);
kp3d::Renderer2D::End(); kp3d::Renderer2D::End();
if (m_mode == MODE_EDIT)
editor.RenderUI();
}
else if (m_mode == MODE_MENU)
{
RenderMenu();
}
// UI // UI
kp3d::console::Render(); 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();
}

View file

@ -1,10 +1,21 @@
#pragma once #pragma once
#include <memory>
#include <KP3D_Game.h> #include <KP3D_Game.h>
#include <KP3D_Math.h> #include <KP3D_Math.h>
#include <KP3D_Camera.h> #include <KP3D_Camera.h>
#include <KP3D_Map.h> #include <KP3D_Map.h>
#include "Editor.h"
enum Mode
{
MODE_MENU,
MODE_GAME,
MODE_EDIT
};
class Sandbox: public kp3d::Game class Sandbox: public kp3d::Game
{ {
public: public:
@ -14,13 +25,19 @@ public:
void Update() override; void Update() override;
void Render() override; void Render() override;
void RenderMenu();
public: public:
// Temp // Temp
kp3d::Map map; kp3d::Map map;
Editor editor;
private: private:
// KP3D essentials // KP3D essentials
kp3d::Mat4 m_projection; kp3d::Mat4 m_projection;
kp3d::Camera m_camera; kp3d::Camera m_camera;
int m_mode;
}; };
extern std::unique_ptr<Sandbox> sandbox;