diff --git a/Data/resources/textures/block.png b/Data/resources/textures/block.png
new file mode 100644
index 0000000..9d1ef3f
Binary files /dev/null and b/Data/resources/textures/block.png differ
diff --git a/Data/resources/textures/stem.png b/Data/resources/textures/stem.png
new file mode 100644
index 0000000..038dd0c
Binary files /dev/null and b/Data/resources/textures/stem.png differ
diff --git a/Data/sandbox-log.txt b/Data/sandbox-log.txt
index 3b722ec..05e2957 100644
--- a/Data/sandbox-log.txt
+++ b/Data/sandbox-log.txt
@@ -1,14 +1,19 @@
-[08:40:36 AM] Info: Starting...
+[02:58:42 PM] Info: Starting...
KP3D version 2
===============================
Copyright (C) kpworld.xyz 2018-2024
Contact me! @kp_cftsz
-[08:40:36 AM] Info: Initializing SDL
-[08:40:36 AM] Info: Initializing OpenGL
-[08:40:36 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23
-[08:40:36 AM] Info: Initializing GLEW
-[08:40:36 AM] Info: Initializing SDL_mixer
-[08:40:36 AM] Info: Reticulating splines...
-[08:40:37 AM] Info: Ready!
+[02:58:42 PM] Info: Initializing SDL
+[02:58:42 PM] Info: Initializing OpenGL
+[02:58:42 PM] Info: OpenGL version: 4.6.0 NVIDIA 517.70
+[02:58:42 PM] Info: Initializing GLEW
+[02:58:42 PM] Info: Initializing SDL_mixer
+[02:58:43 PM] Info: Reticulating splines...
+[02:58:43 PM] Info: Ready!
+[02:58:43 PM] Info: BUILDING SECTOR: 1
+[02:58:43 PM] Info: BUILDING SECTOR: 2
+[02:58:43 PM] Info: BUILDING SECTOR: 3
+[02:58:43 PM] Info: BUILDING SECTOR: 4
+[02:58:43 PM] Info: BUILDING SECTOR: 5
diff --git a/KP3Dii/KP3Dii.vcxproj b/KP3Dii/KP3Dii.vcxproj
index 3b31201..29bf168 100644
--- a/KP3Dii/KP3Dii.vcxproj
+++ b/KP3Dii/KP3Dii.vcxproj
@@ -151,6 +151,7 @@
+
@@ -197,6 +198,7 @@
+
diff --git a/KP3Dii/KP3Dii.vcxproj.filters b/KP3Dii/KP3Dii.vcxproj.filters
index 7f36d80..b4ef0b6 100644
--- a/KP3Dii/KP3Dii.vcxproj.filters
+++ b/KP3Dii/KP3Dii.vcxproj.filters
@@ -38,6 +38,7 @@
+
@@ -86,6 +87,7 @@
+
diff --git a/KP3Dii/src/KP3D_Map.cpp b/KP3Dii/src/KP3D_Map.cpp
index d8a5b64..37af8d4 100644
--- a/KP3Dii/src/KP3D_Map.cpp
+++ b/KP3Dii/src/KP3D_Map.cpp
@@ -2,12 +2,27 @@
#include
+#include
+
#include
#include
#include
#include "KP3D_Renderer3D.h"
#include "KP3D_Shader.h"
+#include "KP3D_Noise.h"
+
+
+
+namespace std {
+template<>
+struct hash {
+ std::size_t operator()(const kp3d::Vec3& point) const {
+ return std::hash()(point.x) ^ std::hash()(point.y) ^ std::hash()(point.z);
+ }
+};
+}
+
namespace {
@@ -28,61 +43,6 @@ bool PointInPolygon(std::vector polygon, kp3d::XYf p)
return c;
}
-Vec3 calculateCentroid(const std::vector& points) {
- Vec3 centroid = { 0.0f, 0.0f, 0.0f };
- float signedArea = 0.0f;
- float x0 = 0.0f; // Current vertex X
- float y0 = 0.0f; // Current vertex Y
- float x1 = 0.0f; // Next vertex X
- float y1 = 0.0f; // Next vertex Y
- float a = 0.0f; // Partial signed area
-
- // For all vertices except last
- for (size_t i = 0; i < points.size() - 1; ++i) {
- x0 = points[i].x;
- y0 = points[i].y;
- x1 = points[i + 1].x;
- y1 = points[i + 1].y;
- a = x0 * y1 - x1 * y0;
- signedArea += a;
- centroid.x += (x0 + x1) * a;
- centroid.y += (y0 + y1) * a;
- }
-
- // Do last vertex separately to complete the loop
- x0 = points.back().x;
- y0 = points.back().y;
- x1 = points[0].x;
- y1 = points[0].y;
- a = x0 * y1 - x1 * y0;
- signedArea += a;
- centroid.x += (x0 + x1) * a;
- centroid.y += (y0 + y1) * a;
-
- signedArea *= 0.5;
- centroid.x /= (6.0f * signedArea);
- centroid.y /= (6.0f * signedArea);
-
- return centroid;
-}
-
-
-
-// Define a hash function for Vec3
-struct Vec3Hash {
- std::size_t operator()(const Vec3& v) const {
- std::size_t h1 = std::hash{}(v.x);
- std::size_t h2 = std::hash{}(v.y);
- std::size_t h3 = std::hash{}(v.z);
-
- std::size_t hash = h1;
- hash ^= h2 + 0x9e3779b9 + (hash << 6) + (hash >> 2);
- hash ^= h3 + 0x9e3779b9 + (hash << 6) + (hash >> 2);
-
- return hash;
- }
-};
-
float Distance(XYf p1, XYf p2)
{
return sqrtf((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
@@ -99,146 +59,6 @@ bool PointInLine(float x1, float y1, float x2, float y2, float x0, float y0)
return kp3d::FloatCmp((y2 - y1) * x0 + (x1 - x2) * y0 + (x2 * y1 - x1 * y2), 0.0f, 0.0001f) && in_bounds;
}
-
-static const int SEED = 1985;
-
-static const unsigned char HASH[] = {
- 208,34,231,213,32,248,233,56,161,78,24,140,71,48,140,254,245,255,247,247,40,
- 185,248,251,245,28,124,204,204,76,36,1,107,28,234,163,202,224,245,128,167,204,
- 9,92,217,54,239,174,173,102,193,189,190,121,100,108,167,44,43,77,180,204,8,81,
- 70,223,11,38,24,254,210,210,177,32,81,195,243,125,8,169,112,32,97,53,195,13,
- 203,9,47,104,125,117,114,124,165,203,181,235,193,206,70,180,174,0,167,181,41,
- 164,30,116,127,198,245,146,87,224,149,206,57,4,192,210,65,210,129,240,178,105,
- 228,108,245,148,140,40,35,195,38,58,65,207,215,253,65,85,208,76,62,3,237,55,89,
- 232,50,217,64,244,157,199,121,252,90,17,212,203,149,152,140,187,234,177,73,174,
- 193,100,192,143,97,53,145,135,19,103,13,90,135,151,199,91,239,247,33,39,145,
- 101,120,99,3,186,86,99,41,237,203,111,79,220,135,158,42,30,154,120,67,87,167,
- 135,176,183,191,253,115,184,21,233,58,129,233,142,39,128,211,118,137,139,255,
- 114,20,218,113,154,27,127,246,250,1,8,198,250,209,92,222,173,21,88,102,219
-};
-
-static int noise2(int x, int y)
-{
- int yindex = (y + SEED) % 256;
- if (yindex < 0)
- yindex += 256;
- int xindex = (HASH[yindex] + x) % 256;
- if (xindex < 0)
- xindex += 256;
- const int result = HASH[xindex];
- return result;
-}
-
-static double lin_inter(double x, double y, double s)
-{
- return x + s * (y - x);
-}
-
-static double smooth_inter(double x, double y, double s)
-{
- return lin_inter(x, y, s * s * (3 - 2 * s));
-}
-
-static double noise2d(double x, double y)
-{
- const int x_int = floor(x);
- const int y_int = floor(y);
- const double x_frac = x - x_int;
- const double y_frac = y - y_int;
- const int s = noise2(x_int, y_int);
- const int t = noise2(x_int + 1, y_int);
- const int u = noise2(x_int, y_int + 1);
- const int v = noise2(x_int + 1, y_int + 1);
- const double low = smooth_inter(s, t, x_frac);
- const double high = smooth_inter(u, v, x_frac);
- const double result = smooth_inter(low, high, y_frac);
- return result;
-}
-
-double Perlin_Get2d(double x, double y, double freq, int depth)
-{
- double xa = x * freq;
- double ya = y * freq;
- double amp = 1.0;
- double fin = 0;
- double div = 0.0;
- for (int i = 0; i < depth; i++)
- {
- div += 256 * amp;
- fin += noise2d(xa, ya) * amp;
- amp /= 2;
- xa *= 2;
- ya *= 2;
- }
- return fin / div;
-}
-
-using namespace kp3d;
-using Point = Vec3;
-using Polygon = std::vector;
-class Plane {
-private:
- Point _normal, _v1, _v2, _v3;
- double_t _d;
-public:
- Plane(Point normal, double_t d) : _normal(normal), _d(d) {}
- Plane(Point v1, Point v2, Point v3) : _v1(v1), _v2(v2), _v3(v3) {
- //Create a plane from 3 non-colinear points (i.e. triangle)
- _normal = (v2 - v1).Cross(v3 - v1).Normalized();
- _d = -_normal.Dot(v1);
- }
- Point intersectionPoint(Point p1, Point p2) const {
- //Return the intersection point of a line passing two points and this plane
- return p1 + (p2 - p1) * (-distance(p1) / _normal.Dot(p2 - p1));
- };
- void invert() { _normal = _normal * (-1); }
- Point getNormal() const { return _normal; }
- Polygon getTriangle() const {
- vector points = { _v1, _v2, _v3 };
- return Polygon(points);
- }
- double_t distance(Point q) const { return _normal.Dot(q) + _d; }
-};
-
-Polygon SutherlandHodgman(const Polygon startingPolygon, vector clippingPlanes) {
- float epsilon = 0.000001f;
- double_t D1, D2 = 0;
- Polygon polygon = Polygon(startingPolygon);
- for (unsigned int c = 0; c < clippingPlanes.size(); c++) {
- if (polygon.empty()) { return polygon; }
- Polygon clippedPolygon = Polygon();
- vector points = polygon;
- for (unsigned int i = 0; i < points.size() - 1; i++) {
- D1 = clippingPlanes[c].distance(points[i]);
- D2 = clippingPlanes[c].distance(points[i + 1]);
- if ((D1 <= 0) && (D2 <= 0))
- {
- clippedPolygon.push_back(points[i + 1]);
- }
- else if ((D1 > 0) && ((D2 > -epsilon) && (D2 < epsilon)))
- {
- clippedPolygon.push_back(points[i + 1]);
- }
- else if (((D1 > -epsilon) && (D1 < epsilon)) && (D2 > 0))
- {
- continue;
- }
- else if ((D1 <= 0) && (D2 > 0))
- {
- clippedPolygon.push_back(clippingPlanes[c].intersectionPoint(points[i],
- points[i + 1]));
- }
- else if ((D1 > 0) && (D2 <= 0))
- {
- clippedPolygon.push_back(clippingPlanes[c].intersectionPoint(points[i],
- points[i + 1]));
- clippedPolygon.push_back(points[i + 1]);
- }
- }
- polygon = Polygon(clippedPolygon); // keep on working with the new polygon
- }
- return polygon;
-}
} // namespace
namespace kp3d {
@@ -275,6 +95,35 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
steiner_points.emplace_back(st.x, st.z);
std::vector> subsector_polygons; // unused for now
+
+ for (Sector& s : sectors)
+ {
+ if (s.id == sector.id)
+ continue;
+
+ std::vector ss;
+
+ for (Wall& l : s.walls)
+ {
+ if (PointInPolygon(sector.walls, l.start))
+ {
+ ss.push_back({l.start.x, l.start.y});
+ }
+ }
+
+ if (ss.size() == s.walls.size())
+ {
+
+ for (Wall& l : s.walls)
+ {
+ l.textures[TEX_FRONT] = nullptr;
+ l.textures[TEX_BACK] = nullptr;
+ }
+
+ subsector_polygons.push_back(ss);
+ }
+ }
+
std::vector sector_polygons;
for (Wall& l: sector.walls)
sector_polygons.emplace_back(l.start.x, l.start.y);
@@ -344,6 +193,9 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
*/
void Map::BuildQuad(Sector& sector, const Texture* texture, Vec3 pos_a, Vec3 pos_b, bool flip, bool flip_u, bool flip_v, XYf uv_offset)
{
+ if (!texture)
+ return;
+
Vec3 p1 = Vec3(pos_a.x, pos_a.y, pos_a.z);
Vec3 p2 = Vec3(pos_a.x, pos_b.y, pos_a.z);
Vec3 p3 = Vec3(pos_b.x, pos_a.y, pos_b.z);
@@ -373,32 +225,6 @@ void Map::BuildQuad(Sector& sector, const Texture* texture, Vec3 pos_a, Vec3 pos
// Test: Put points back in their original positions
float angle = atan2({ p4.z - p1.z }, { p4.x - p1.x });
-#if 0
- // Debug
- for (Vec3& p: points)
- {
- // Convert back into 3D
- p = p.Rotated({0, 1, 0}, -ToDegrees(angle));
- p.x += p1.x;
- p.z += p1.z;
- }
- for (Vec3 p: points)
- m_dots.push_back(p);
-
- // Enforce clockwise-ness
- float area = 0.0f;
- for (int i = 0; i < points.size(); i++)
- {
- Vec3 start = points[i];
- Vec3 end = points[(i + 1) % points.size()];
- area += start.x * end.y;
- area -= end.x * start.y;
- }
- area /= 2.0f;
- if (area <= 0.0f)
- std::reverse(points.begin(), points.end());
-#endif
-
points.erase(unique(points.begin(), points.end()), points.end());
std::vector> holes; // unused for now
@@ -451,72 +277,146 @@ void Map::Init()
{11, 13},
{4, 14},
{4, 12},
- {1, 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
};
BuildSkybox("skybox_16.jpg");
- static kp3d::Texture tex, tex2, tex3;
+ static kp3d::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");
- Sector s;
- s.ceiling.texture = &tex2;
- s.floor.texture = &tex;
- s.floor.base_height = -1.0f;
- s.ceiling.base_height = 5.0f;
- s.id = 1;
- s.parent_id = 0;
- float scl = 1.0f;
- for (size_t i = 0; i < std::size(points); i++)
- {
- XYf start = points[i];
- XYf end = points[(i + 1) % std::size(points)];
- start.x *= 2.0f;
- end.x *= 2.0f;
- start.y *= 2.0f;
- end.y *= 2.0f;
- s.walls.push_back(Wall{{nullptr,&tex3,nullptr,nullptr}, {{0, 0}}, start, end, Wall::NO_FLAGS, (uint) i});
- }
- sectors.push_back(s);
- // 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 * scl;
- float steiner_size = 1.0f;
- for (int i = 0; i < num_steiners_along_xy; i++)
- {
- for (int j = 0; j < num_steiners_along_xy; j++)
+ auto build_sector = [&](Texture* wall, Texture* floor, Texture* ceil, float floor_height, float ceil_height, int id, XYf* points, size_t num_points) {
+ Sector s;
+ s.ceiling.texture = ceil;
+ s.floor.texture = floor;
+ s.floor.base_height = floor_height;
+ s.ceiling.base_height = ceil_height;
+ s.id = id;
+ s.parent_id = 0;
+ float scl = 1.0f;
+ for (size_t i = 0; i < num_points; i++)
{
- // Build a Steiner point to be used in the triangulation process; with this we can get slopes, terrain, etc.
- XYf steiner_point = {((float) i * steiner_size), ((float) j * steiner_size)};
- if (!PointInPolygon(s.walls, steiner_point))
- continue;
+ XYf start = points[i];
+ XYf end = points[(i + 1) % num_points];
+ s.walls.push_back(Wall{ {nullptr,wall,nullptr,nullptr}, {{0, 0}}, start, end, Wall::NO_FLAGS, (uint)i });
+ }
+ sectors.push_back(s);
- // Since Clipper doesn't allow for duplicate points, remove any Steiner points that may have landed on a map vertex
- bool bail = false;
- for (Wall& ld: s.walls)
+ };
+
+ 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, 4.0f, 3, points3, std::size(points3));
+ build_sector(&tex4, &tex, &tex2, -1.5f, 4.0f, 4, points4, std::size(points4));
+ build_sector(&tex3, &tex, &tex2, -0.5f, 3.0f, 5, points5, std::size(points5));
+
+ 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;
+ float steiner_size = 1.0f;
+ for (int i = 0; i < num_steiners_along_xy; i++)
+ {
+ for (int j = 0; j < num_steiners_along_xy; j++)
{
- if ((FloatCmp(steiner_point.x, ld.start.x, 0.0f) && FloatCmp(steiner_point.y, ld.start.y, 0.0f)) ||
- (FloatCmp(steiner_point.x, ld.end.x, 0.0f) && FloatCmp(steiner_point.y, ld.end.y, 0.0f)))
- bail = true;
+ // Build a Steiner point to be used in the triangulation process; with this we can get slopes, terrain, etc.
+ XYf steiner_point = { ((float)i * steiner_size), ((float)j * steiner_size) };
+ if (!PointInPolygon(s.walls, steiner_point))
+ continue;
+
+ // Since Clipper doesn't allow for duplicate points, remove any Steiner points that may have landed on a map vertex
+ bool bail = false;
+ for (Wall& ld : s.walls)
+ {
+ if ((FloatCmp(steiner_point.x, ld.start.x, 0.0f) && FloatCmp(steiner_point.y, ld.start.y, 0.0f)) ||
+ (FloatCmp(steiner_point.x, ld.end.x, 0.0f) && FloatCmp(steiner_point.y, ld.end.y, 0.0f)))
+ bail = true;
+ }
+
+ if (bail)
+ continue;
+
+ float yv = PerlinNoise2D(steiner_point.x, steiner_point.y, 1.0, 10.0); // Temp
+ if (s.id == 1)
+ s.floor.steiner_points.push_back({ steiner_point.x, yv, steiner_point.y });
}
+ }
- if (bail)
- continue;
+ // Build level geometry
+ BuildFlat(s, s.floor, false);
+ BuildFlat(s, s.ceiling, true);
- float yv = Perlin_Get2d(steiner_point.x, steiner_point.y, 1.0, 10.0); // Temp
- s.floor.steiner_points.push_back({steiner_point.x, yv, steiner_point.y});
+ 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())
+ {
+ std::unordered_set unique_points;
+ 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())
+ {
+ std::unordered_set unique_points;
+ for (size_t i = 0; i < b.vertex_data.size(); i += 3)
+ {
+ std::swap(b.vertex_data[i + 1], b.vertex_data[i + 2]);
+ b.vertex_data[i].position.z = -b.vertex_data[i].position.z;
+ b.vertex_data[i+1].position.z = -b.vertex_data[i+1].position.z;
+ b.vertex_data[i+2].position.z = -b.vertex_data[i+2].position.z;
}
}
- BuildFlat(s, s.floor, false);
- BuildFlat(s, s.ceiling, true);
-
- for (Wall& ld: s.walls)
- BuildWall(s, ld);
-
+ // Finalize the mesh
m_mesh.Finalize();
}
diff --git a/KP3Dii/src/KP3D_Noise.cpp b/KP3Dii/src/KP3D_Noise.cpp
new file mode 100644
index 0000000..17f3e17
--- /dev/null
+++ b/KP3Dii/src/KP3D_Noise.cpp
@@ -0,0 +1,82 @@
+#include "KP3D_Noise.h"
+
+#include
+
+namespace {
+
+const int SEED = 1985;
+
+const unsigned char HASH[] = {
+ 208, 34, 231, 213, 32, 248, 233, 56, 161, 78, 24, 140, 71, 48, 140, 254, 245, 255, 247, 247, 40, 185, 248, 251,
+ 245, 28, 124, 204, 204, 76, 36, 1, 107, 28, 234, 163, 202, 224, 245, 128, 167, 204, 9, 92, 217, 54, 239, 174,
+ 173, 102, 193, 189, 190, 121, 100, 108, 167, 44, 43, 77, 180, 204, 8, 81, 70, 223, 11, 38, 24, 254, 210, 210,
+ 177, 32, 81, 195, 243, 125, 8, 169, 112, 32, 97, 53, 195, 13, 203, 9, 47, 104, 125, 117, 114, 124, 165, 203,
+ 181, 235, 193, 206, 70, 180, 174, 0, 167, 181, 41, 164, 30, 116, 127, 198, 245, 146, 87, 224, 149, 206, 57, 4,
+ 192, 210, 65, 210, 129, 240, 178, 105, 228, 108, 245, 148, 140, 40, 35, 195, 38, 58, 65, 207, 215, 253, 65, 85,
+ 208, 76, 62, 3, 237, 55, 89, 232, 50, 217, 64, 244, 157, 199, 121, 252, 90, 17, 212, 203, 149, 152, 140, 187,
+ 234, 177, 73, 174, 193, 100, 192, 143, 97, 53, 145, 135, 19, 103, 13, 90, 135, 151, 199, 91, 239, 247, 33, 39,
+ 145, 101, 120, 99, 3, 186, 86, 99, 41, 237, 203, 111, 79, 220, 135, 158, 42, 30, 154, 120, 67, 87, 167, 135,
+ 176, 183, 191, 253, 115, 184, 21, 233, 58, 129, 233, 142, 39, 128, 211, 118, 137, 139, 255, 114, 20, 218, 113, 154,
+ 27, 127, 246, 250, 1, 8, 198, 250, 209, 92, 222, 173, 21, 88, 102, 219};
+
+int Noise2(int x, int y)
+{
+ int yindex = (y + SEED) % 256;
+ if (yindex < 0)
+ yindex += 256;
+ int xindex = (HASH[yindex] + x) % 256;
+ if (xindex < 0)
+ xindex += 256;
+ const int result = HASH[xindex];
+ return result;
+}
+
+double LinInterp(double x, double y, double s)
+{
+ return x + s * (y - x);
+}
+
+double SmoothInterp(double x, double y, double s)
+{
+ return LinInterp(x, y, s * s * (3 - 2 * s));
+}
+
+double Noise2D(double x, double y)
+{
+ const int x_int = floor(x);
+ const int y_int = floor(y);
+ const double x_frac = x - x_int;
+ const double y_frac = y - y_int;
+ const int s = Noise2(x_int, y_int);
+ const int t = Noise2(x_int + 1, y_int);
+ const int u = Noise2(x_int, y_int + 1);
+ const int v = Noise2(x_int + 1, y_int + 1);
+ const double low = SmoothInterp(s, t, x_frac);
+ const double high = SmoothInterp(u, v, x_frac);
+ const double result = SmoothInterp(low, high, y_frac);
+ return result;
+}
+
+} // namespace
+
+namespace kp3d {
+
+double PerlinNoise2D(double x, double y, double freq, int depth)
+{
+ double xa = x * freq;
+ double ya = y * freq;
+ double amp = 1.0;
+ double fin = 0;
+ double div = 0.0;
+ for (int i = 0; i < depth; i++)
+ {
+ div += 256 * amp;
+ fin += Noise2D(xa, ya) * amp;
+ amp /= 2;
+ xa *= 2;
+ ya *= 2;
+ }
+ return fin / div;
+}
+
+} // namespace kp3d
diff --git a/KP3Dii/src/KP3D_Noise.h b/KP3Dii/src/KP3D_Noise.h
new file mode 100644
index 0000000..cf61758
--- /dev/null
+++ b/KP3Dii/src/KP3D_Noise.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "KP3D_Common.h"
+
+namespace kp3d {
+
+double PerlinNoise2D(double x, double y, double freq, int depth);
+
+}
diff --git a/KP3Dii/src/KP3D_Vec3.cpp b/KP3Dii/src/KP3D_Vec3.cpp
index 841a2e0..3f4d053 100644
--- a/KP3Dii/src/KP3D_Vec3.cpp
+++ b/KP3Dii/src/KP3D_Vec3.cpp
@@ -155,7 +155,8 @@ Vec3 Vec3::operator-() const
bool operator==(const Vec3& lhs, const Vec3& rhs)
{
- return std::tie(lhs.x, lhs.y, lhs.z) == std::tie(rhs.x, rhs.y, rhs.z);
+ return std::abs(lhs.x - rhs.x) < 1e-6 && std::abs(lhs.y - rhs.y) < 1e-6 && std::abs(lhs.z - rhs.z) < 1e-6;
+ // return std::tie(lhs.x, lhs.y, lhs.z) == std::tie(rhs.x, rhs.y, rhs.z);
}
bool operator!=(const Vec3& lhs, const Vec3& rhs)