diff --git a/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj b/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj
index 1dd39b2..699023e 100644
--- a/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj
+++ b/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj
@@ -167,6 +167,7 @@ xcopy /y /i /s $(ProjectDir)..\lib\glew-2.2.0\bin\Release\x64\*.dll $(OutDir)
+
diff --git a/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj.filters b/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj.filters
index 9c6df42..81b8bef 100644
--- a/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj.filters
+++ b/OpenGL_Flightsim/OpenGL_Flightsim.vcxproj.filters
@@ -75,6 +75,9 @@
Source Files
+
+ Source Files
+
diff --git a/OpenGL_Flightsim/src/app.cpp b/OpenGL_Flightsim/src/app.cpp
index bc39cce..e44ed1a 100644
--- a/OpenGL_Flightsim/src/app.cpp
+++ b/OpenGL_Flightsim/src/app.cpp
@@ -112,7 +112,7 @@ void App::init()
#if 1
#endif
#if 1
- m_clipmap = new Clipmap();
+ m_clipmap = new GeometryClipmap();
m_clipmap->visible = true;
m_scene->add(m_clipmap);
#endif
diff --git a/OpenGL_Flightsim/src/app.h b/OpenGL_Flightsim/src/app.h
index ece6078..dbd1ef6 100644
--- a/OpenGL_Flightsim/src/app.h
+++ b/OpenGL_Flightsim/src/app.h
@@ -60,7 +60,7 @@ class App
// physics
Airplane* m_flightmodel;
phi::RigidBody* m_terrain;
- Clipmap* m_clipmap;
+ GeometryClipmap* m_clipmap;
void init_airplane();
void init_flightmodel();
diff --git a/OpenGL_Flightsim/src/collider.h b/OpenGL_Flightsim/src/collider.h
index accf8f2..bc4bb57 100644
--- a/OpenGL_Flightsim/src/collider.h
+++ b/OpenGL_Flightsim/src/collider.h
@@ -35,9 +35,9 @@ struct Sphere : public Collider {
};
struct Heightmap : public Collider {
- const Clipmap* terrain = nullptr;
+ const GeometryClipmap* terrain = nullptr;
- Heightmap(Clipmap* terrain_) : terrain(terrain_) {}
+ Heightmap(GeometryClipmap* terrain_) : terrain(terrain_) {}
bool test(const phi::Transform* tf, const Collider* other, const phi::Transform* other_tf,
phi::Collision* info) const override;
diff --git a/OpenGL_Flightsim/src/terrain.cpp b/OpenGL_Flightsim/src/terrain.cpp
new file mode 100644
index 0000000..1954d76
--- /dev/null
+++ b/OpenGL_Flightsim/src/terrain.cpp
@@ -0,0 +1,264 @@
+#include "terrain.h"
+
+TextureCLipmap::TextureCLipmap() {}
+
+Seam::Seam(int columns, float size)
+{
+ int rows = 1;
+ index_count = columns;
+
+ std::vector vertices;
+
+ int x;
+ for (x = 0; x < columns; x++) {
+ vertices.push_back({x * size, 0.0f, 0 * size});
+ vertices.push_back({x * size + size / 2.0f, size, 0 * size});
+ vertices.push_back({x * size + size, 0.0f, 0 * size});
+ }
+
+ vao.bind();
+ vbo.buffer(&vertices[0], vertices.size() * sizeof(vertices[0]));
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+
+ vao.unbind();
+}
+
+void Seam::bind() { vao.bind(); }
+
+void Seam::unbind() { vao.unbind(); }
+
+void Seam::draw()
+{
+ bind();
+ glDrawArrays(GL_TRIANGLES, 0, 3 * index_count);
+ unbind();
+}
+
+Block::Block(int width, int height, float segment_size)
+{
+ std::vector vertices;
+ std::vector indices;
+
+ for (int y = 0; y <= width; y++) {
+ for (int x = 0; x <= height; x++) {
+ vertices.push_back({x * segment_size, 0.0f, y * segment_size});
+ }
+ }
+
+ for (int r = 0; r < width; r++) {
+ for (int c = 0; c < height + 1; c++) {
+ auto i0 = (r + 0) * (height + 1) + c;
+ indices.push_back(i0);
+
+ auto i1 = (r + 1) * (height + 1) + c;
+ indices.push_back(i1);
+ }
+ indices.push_back(primitive_restart); // restart primitive
+ }
+
+ index_count = indices.size();
+
+ assert(indices.size() > 0 && vertices.size() > 0);
+
+ vao.bind();
+
+ vbo.buffer(&vertices[0], vertices.size() * sizeof(vertices[0]));
+ ebo.buffer(&indices[0], indices.size() * sizeof(indices[0]));
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+
+ vao.unbind();
+}
+
+void Block::bind() { vao.bind(); }
+
+void Block::unbind() { vao.unbind(); }
+
+void Block::draw()
+{
+ bind();
+ glDrawElements(GL_TRIANGLE_STRIP, index_count, GL_UNSIGNED_INT, 0);
+ unbind();
+}
+
+GeometryClipmap::GeometryClipmap(int levels_, int segments_)
+ : segment_size(2.0f),
+ levels(levels_),
+ segments(segments_),
+ terrain_size(MAX_TILE_SIZE / ZOOM_FACTOR),
+ shader("shaders/terrain"),
+ heightmap_image(PATH + "height.png"),
+ heightmap(heightmap_image, params),
+ normalmap(PATH + "normal.png", params),
+ terrain(PATH + "texture.png", params),
+ terrain_0(),
+ tile(segments, segments, segment_size),
+ col_fixup(2, segments, segment_size),
+ row_fixup(segments, 2, segment_size),
+ horizontal(2 * segments + 2, 1, segment_size),
+ vertical(1, 2 * segments + 2, segment_size),
+ center(2 * segments + 2, 2 * segments + 2, segment_size),
+ seam(2 * segments + 2, segment_size * 2)
+{
+ std::cout << "terrain_size = " << terrain_size << " m" << std::endl;
+
+ auto fog = gfx::rgb(0x5e5e6e);
+ auto color = glm::vec4(fog, 1.0f);
+
+ auto p = pixel_from_height(2561.0f);
+
+ terrain.bind();
+ terrain.set_parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ terrain.set_parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ terrain.set_parameter(GL_TEXTURE_BORDER_COLOR, glm::value_ptr(color));
+
+ heightmap.bind();
+ heightmap.set_parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ heightmap.set_parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ heightmap.set_parameter(GL_TEXTURE_BORDER_COLOR, glm::value_ptr(glm::vec4(pixel_from_height(0.0f), 1.0f)));
+}
+
+void GeometryClipmap::draw_self(gfx::RenderContext& context)
+{
+ if (context.shadow_pass) {
+ return;
+ }
+ auto camera_pos = context.camera->get_world_position();
+ float height = camera_pos.y;
+ auto camera_pos_xy = glm::vec2(camera_pos.x, camera_pos.z);
+
+ // TODO: select proper texture LOD
+ glm::vec2 origin = camera_pos_xy - glm::vec2(terrain_size / 2);
+
+ shader.bind();
+ shader.set_uniform("u_Heightmap", 2);
+ shader.set_uniform("u_Normalmap", 3);
+ shader.set_uniform("u_Texture_01", 4);
+ shader.set_uniform("u_FogColor", context.fog_color);
+ shader.set_uniform("u_View", context.camera->get_view_matrix());
+ shader.set_uniform("u_CameraPos", context.camera->get_world_position());
+ shader.set_uniform("u_Projection", context.camera->get_projection_matrix());
+ shader.set_uniform("u_TerrainSize", terrain_size);
+ shader.set_uniform("u_Shadowmap", 5);
+ shader.set_uniform("u_LightSpaceMatrix", context.light_space_matrix);
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_PRIMITIVE_RESTART);
+ glPrimitiveRestartIndex(primitive_restart);
+
+ int min_level = 1; // depends on camera height
+
+ for (int level = min_level; level <= levels; level++) {
+ const int rows = 5, columns = 5;
+ float scale = std::pow(2.0f, level);
+ float next_scale = std::pow(2.0f, level + 2);
+ float scaled_segment_size = segment_size * scale;
+ float tile_size = segments * scaled_segment_size;
+ glm::vec2 snapped = glm::floor(camera_pos_xy / next_scale) * next_scale;
+ auto base = calc_base(level, camera_pos_xy);
+
+ shader.set_uniform("u_Scale", scale);
+ shader.set_uniform("u_SegmentSize", scaled_segment_size);
+ shader.set_uniform("u_Level", static_cast(level) / levels);
+
+#if 1
+ // don't render lots of detail if we are very high up
+ if (tile_size * 5 < height * 2.5) {
+ min_level = level + 1;
+ continue;
+ }
+#endif
+
+ heightmap.bind(2);
+ normalmap.bind(3);
+ terrain.bind(4);
+ context.depth_map->bind(5);
+
+#if 1
+ if (level == min_level) {
+ shader.set_uniform("u_Model", transform_matrix(base + glm::vec2(tile_size, tile_size), scale));
+ center.draw();
+ } else { // not at base level
+ auto prev_base = calc_base(level - 1, camera_pos_xy);
+ auto diff = glm::abs(base - prev_base);
+
+ auto l_offset = glm::vec2(tile_size, tile_size);
+ if (diff.x == tile_size) {
+ l_offset.x += (2 * segments + 1) * scaled_segment_size;
+ }
+ shader.set_uniform("u_Model", transform_matrix(base + l_offset, scale));
+ horizontal.draw();
+
+ auto v_offset = glm::vec2(tile_size, tile_size);
+ if (diff.y == tile_size) {
+ v_offset.y += (2 * segments + 1) * scaled_segment_size;
+ }
+
+ shader.set_uniform("u_Model", transform_matrix(base + v_offset, scale));
+ vertical.draw();
+ }
+#endif
+#if 1
+ glm::vec2 offset(0.0f);
+ for (int row = 0; row < rows; row++) {
+ offset.y = 0;
+ for (int column = 0; column < columns; column++) {
+ if (row == 0 || row == rows - 1 || column == 0 || column == columns - 1) {
+ auto tile_pos = base + offset;
+ shader.set_uniform("u_Model", transform_matrix(tile_pos, scale));
+
+ if ((column != 2) && (row != 2)) {
+ if (column == 0 && row == 0) // east
+ {
+ shader.set_uniform("u_Model", transform_matrix(tile_pos, scale));
+ seam.draw();
+ } else if (column == columns - 1 && row == rows - 1) // west
+ {
+ shader.set_uniform("u_Model", transform_matrix(tile_pos + glm::vec2(tile_size), scale, 180.0f));
+ seam.draw();
+ } else if (column == columns - 1 && row == 0) // south
+ {
+ shader.set_uniform("u_Model", transform_matrix(tile_pos + glm::vec2(0, tile_size), scale, 90.0f));
+ seam.draw();
+ } else if (column == 0 && row == rows - 1) // north
+ {
+ shader.set_uniform("u_Model", transform_matrix(tile_pos + glm::vec2(tile_size, 0), scale, -90.0f));
+ seam.draw();
+ }
+
+ shader.set_uniform("u_Model", transform_matrix(tile_pos, scale));
+ tile.draw();
+ } else if (column == 2) {
+ col_fixup.draw();
+ } else if (row == 2) {
+ row_fixup.draw();
+ }
+ }
+
+ if (column == 2) {
+ offset.y += 2 * scaled_segment_size;
+ } else {
+ offset.y += tile_size;
+ }
+ }
+
+ if (row == 2) {
+ offset.x += 2 * scaled_segment_size;
+ } else {
+ offset.x += tile_size;
+ }
+ }
+#endif
+
+ heightmap.unbind();
+ normalmap.unbind();
+ terrain.unbind();
+ }
+
+ glDisable(GL_CULL_FACE);
+
+ shader.unbind();
+}
diff --git a/OpenGL_Flightsim/src/terrain.h b/OpenGL_Flightsim/src/terrain.h
index 5dc15d3..5440fe8 100644
--- a/OpenGL_Flightsim/src/terrain.h
+++ b/OpenGL_Flightsim/src/terrain.h
@@ -12,8 +12,8 @@ const std::string PATH = "assets/textures/terrain/data/9/268/178/";
const int ZOOM_FACTOR = 1;
#elif (DATA_SRC == 2)
const std::string PATH = "assets/textures/terrain/data/10/536/356/";
-///const std::string PATH = "assets/textures/terrain/data/10/536/360/";
-//const std::string PATH = "assets/textures/terrain/debug/";
+/// const std::string PATH = "assets/textures/terrain/data/10/536/360/";
+// const std::string PATH = "assets/textures/terrain/debug/";
const int ZOOM_FACTOR = 2;
#elif (DATA_SRC == 3)
const std::string PATH = "assets/textures/terrain/data/11/1072/712/";
@@ -40,21 +40,19 @@ inline float height_from_pixel(const glm::vec3& rgb)
return (pixel.r * 256.0f + pixel.g + pixel.b / 256.0f) - 32768.0f;
}
-
inline glm::vec3 pixel_from_height(float height)
{
- // TODO
- const float c = 32768.0f;
- glm::vec3 pixel(0.0f);
-
- double decodedHeight = height + 32768;
- int redDec = static_cast(decodedHeight / 256);
- int greenDec = static_cast(decodedHeight) % 256;
- //int blueDec = static_cast((decodedHeight * 256 - greenDec - redDec * 256) / 65536);
- int blueDec = static_cast(((decodedHeight * 256) - (greenDec * 256) - (redDec * 65536)) / 256);
+ // TODO
+ const float c = 32768.0f;
+ glm::vec3 pixel(0.0f);
+ double decodedHeight = height + 32768;
+ int redDec = static_cast(decodedHeight / 256);
+ int greenDec = static_cast(decodedHeight) % 256;
+ // int blueDec = static_cast((decodedHeight * 256 - greenDec - redDec * 256) / 65536);
+ int blueDec = static_cast(((decodedHeight * 256) - (greenDec * 256) - (redDec * 65536)) / 256);
- return pixel / 256.0f;
+ return pixel / 256.0f;
}
inline float scale(float input_val, float in_min, float in_max, float out_min, float out_max)
@@ -77,39 +75,10 @@ struct Seam {
gfx::gl::VertexArrayObject vao;
size_t index_count;
- Seam(int columns, float size)
- {
- int rows = 1;
- index_count = columns;
-
- std::vector vertices;
-
- int x;
- for (x = 0; x < columns; x++) {
- vertices.push_back({x * size, 0.0f, 0 * size});
- vertices.push_back({x * size + size / 2.0f, size, 0 * size});
- vertices.push_back({x * size + size, 0.0f, 0 * size});
- }
-
- vao.bind();
- vbo.buffer(&vertices[0], vertices.size() * sizeof(vertices[0]));
-
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
-
- vao.unbind();
- }
-
- void bind() { vao.bind(); }
-
- void unbind() { vao.unbind(); }
-
- void draw()
- {
- bind();
- glDrawArrays(GL_TRIANGLES, 0, 3 * index_count);
- unbind();
- }
+ Seam(int columns, float size);
+ void bind();
+ void unbind();
+ void draw();
};
struct Block {
@@ -118,248 +87,37 @@ struct Block {
gfx::gl::VertexArrayObject vao;
size_t index_count;
- Block(int width, int height, float segment_size)
- {
- std::vector vertices;
- std::vector indices;
-
- for (int y = 0; y <= width; y++) {
- for (int x = 0; x <= height; x++) {
- vertices.push_back({x * segment_size, 0.0f, y * segment_size});
- }
- }
-
- for (int r = 0; r < width; r++) {
- for (int c = 0; c < height + 1; c++) {
- auto i0 = (r + 0) * (height + 1) + c;
- indices.push_back(i0);
-
- auto i1 = (r + 1) * (height + 1) + c;
- indices.push_back(i1);
- }
- indices.push_back(primitive_restart); // restart primitive
- }
-
- index_count = indices.size();
-
- assert(indices.size() > 0 && vertices.size() > 0);
-
- vao.bind();
-
- vbo.buffer(&vertices[0], vertices.size() * sizeof(vertices[0]));
- ebo.buffer(&indices[0], indices.size() * sizeof(indices[0]));
-
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
-
- vao.unbind();
- }
-
- void bind() { vao.bind(); }
+ Block(int width, int height, float segment_size);
+ void bind();
+ void unbind();
+ void draw();
+};
- void unbind() { vao.unbind(); }
+// A texture clipmap is a way of represinting a texture of arbitrary size
+class TextureCLipmap
+{
+ public:
+ TextureCLipmap();
- void draw()
- {
- bind();
- glDrawElements(GL_TRIANGLE_STRIP, index_count, GL_UNSIGNED_INT, 0);
- unbind();
- }
+ private:
+ gfx::gl::Texture m_texture;
};
// Geometry Clipmap
// https://developer.nvidia.com/gpugems/gpugems2/part-i-geometric-complexity/chapter-2-terrain-rendering-using-gpu-based-geometry
// https://mikejsavage.co.uk/blog/geometry-clipmaps.html
-class Clipmap : public gfx::Object3D
+class GeometryClipmap : public gfx::Object3D
{
public:
- Clipmap(int levels_ = 12, int segments_ = 16)
- : segment_size(2.0f),
- levels(levels_),
- segments(segments_),
- terrain_size(MAX_TILE_SIZE / ZOOM_FACTOR),
- shader("shaders/terrain"),
- heightmap_image(PATH + "height.png"),
- heightmap(heightmap_image, params),
- normalmap(PATH + "normal.png", params),
- terrain(PATH + "texture.png", params),
- terrain_0(),
- tile(segments, segments, segment_size),
- col_fixup(2, segments, segment_size),
- row_fixup(segments, 2, segment_size),
- horizontal(2 * segments + 2, 1, segment_size),
- vertical(1, 2 * segments + 2, segment_size),
- center(2 * segments + 2, 2 * segments + 2, segment_size),
- seam(2 * segments + 2, segment_size * 2)
- {
- std::cout << "terrain_size = " << terrain_size << " m" << std::endl;
-
- auto fog = gfx::rgb(0x5e5e6e);
- auto color = glm::vec4(fog, 1.0f);
-
- auto p = pixel_from_height(2561.0f);
-
- terrain.bind();
- terrain.set_parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- terrain.set_parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- terrain.set_parameter(GL_TEXTURE_BORDER_COLOR, glm::value_ptr(color));
-
- heightmap.bind();
- heightmap.set_parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- heightmap.set_parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- heightmap.set_parameter(GL_TEXTURE_BORDER_COLOR, glm::value_ptr(glm::vec4(pixel_from_height(0.0f), 1.0f)));
-
-
-
- }
+ GeometryClipmap(int levels_ = 12, int segments_ = 16);
+
float get_terrain_height(const glm::vec2 pos) const { return sample_heightmap(heightmap_image, pos, terrain_size); }
float get_terrain_size() const { return terrain_size; }
- void draw_self(gfx::RenderContext& context) override
- {
- if (context.shadow_pass) {
- return;
- }
- auto camera_pos = context.camera->get_world_position();
- float height = camera_pos.y;
- auto camera_pos_xy = glm::vec2(camera_pos.x, camera_pos.z);
-
- // TODO: select proper texture LOD
- glm::vec2 origin = camera_pos_xy - glm::vec2(terrain_size / 2);
-
- shader.bind();
- shader.set_uniform("u_Heightmap", 2);
- shader.set_uniform("u_Normalmap", 3);
- shader.set_uniform("u_Texture_01", 4);
- shader.set_uniform("u_FogColor", context.fog_color);
- shader.set_uniform("u_View", context.camera->get_view_matrix());
- shader.set_uniform("u_CameraPos", context.camera->get_world_position());
- shader.set_uniform("u_Projection", context.camera->get_projection_matrix());
- shader.set_uniform("u_TerrainSize", terrain_size);
- shader.set_uniform("u_Shadowmap", 5);
- shader.set_uniform("u_LightSpaceMatrix", context.light_space_matrix);
-
-
- glEnable(GL_CULL_FACE);
- glEnable(GL_PRIMITIVE_RESTART);
- glPrimitiveRestartIndex(primitive_restart);
-
- int min_level = 1; // depends on camera height
-
- for (int level = min_level; level <= levels; level++) {
- const int rows = 5, columns = 5;
- float scale = std::pow(2.0f, level);
- float next_scale = std::pow(2.0f, level + 2);
- float scaled_segment_size = segment_size * scale;
- float tile_size = segments * scaled_segment_size;
- glm::vec2 snapped = glm::floor(camera_pos_xy / next_scale) * next_scale;
- auto base = calc_base(level, camera_pos_xy);
-
- shader.set_uniform("u_Scale", scale);
- shader.set_uniform("u_SegmentSize", scaled_segment_size);
- shader.set_uniform("u_Level", static_cast(level) / levels);
-
-#if 1
- // don't render lots of detail if we are very high up
- if (tile_size * 5 < height * 2.5) {
- min_level = level + 1;
- continue;
- }
-#endif
-
- heightmap.bind(2);
- normalmap.bind(3);
- terrain.bind(4);
- context.depth_map->bind(5);
-
-#if 1
- if (level == min_level) {
- shader.set_uniform("u_Model", transform_matrix(base + glm::vec2(tile_size, tile_size), scale));
- center.draw();
- } else { // not at base level
- auto prev_base = calc_base(level - 1, camera_pos_xy);
- auto diff = glm::abs(base - prev_base);
-
- auto l_offset = glm::vec2(tile_size, tile_size);
- if (diff.x == tile_size) {
- l_offset.x += (2 * segments + 1) * scaled_segment_size;
- }
- shader.set_uniform("u_Model", transform_matrix(base + l_offset, scale));
- horizontal.draw();
-
- auto v_offset = glm::vec2(tile_size, tile_size);
- if (diff.y == tile_size) {
- v_offset.y += (2 * segments + 1) * scaled_segment_size;
- }
-
- shader.set_uniform("u_Model", transform_matrix(base + v_offset, scale));
- vertical.draw();
- }
-#endif
-#if 1
- glm::vec2 offset(0.0f);
- for (int row = 0; row < rows; row++) {
- offset.y = 0;
- for (int column = 0; column < columns; column++) {
- if (row == 0 || row == rows - 1 || column == 0 || column == columns - 1) {
- auto tile_pos = base + offset;
- shader.set_uniform("u_Model", transform_matrix(tile_pos, scale));
-
- if ((column != 2) && (row != 2)) {
- if (column == 0 && row == 0) // east
- {
- shader.set_uniform("u_Model", transform_matrix(tile_pos, scale));
- seam.draw();
- } else if (column == columns - 1 && row == rows - 1) // west
- {
- shader.set_uniform("u_Model", transform_matrix(tile_pos + glm::vec2(tile_size), scale, 180.0f));
- seam.draw();
- } else if (column == columns - 1 && row == 0) // south
- {
- shader.set_uniform("u_Model", transform_matrix(tile_pos + glm::vec2(0, tile_size), scale, 90.0f));
- seam.draw();
- } else if (column == 0 && row == rows - 1) // north
- {
- shader.set_uniform("u_Model", transform_matrix(tile_pos + glm::vec2(tile_size, 0), scale, -90.0f));
- seam.draw();
- }
-
- shader.set_uniform("u_Model", transform_matrix(tile_pos, scale));
- tile.draw();
- } else if (column == 2) {
- col_fixup.draw();
- } else if (row == 2) {
- row_fixup.draw();
- }
- }
-
- if (column == 2) {
- offset.y += 2 * scaled_segment_size;
- } else {
- offset.y += tile_size;
- }
- }
-
- if (row == 2) {
- offset.x += 2 * scaled_segment_size;
- } else {
- offset.x += tile_size;
- }
- }
-#endif
-
- heightmap.unbind();
- normalmap.unbind();
- terrain.unbind();
- }
-
- glDisable(GL_CULL_FACE);
-
- shader.unbind();
- }
-
+ void draw_self(gfx::RenderContext& context) override;
+
private:
const float segment_size;
const int levels;
@@ -370,12 +128,7 @@ class Clipmap : public gfx::Object3D
gfx::Image heightmap_image;
gfx::gl::Texture heightmap, normalmap, terrain, terrain_0;
- Block tile;
- Block center;
- Block col_fixup;
- Block row_fixup;
- Block horizontal;
- Block vertical;
+ Block tile, center, col_fixup, row_fixup, horizontal, vertical;
Seam seam;
glm::vec2 calc_base(int level, glm::vec2 camera_pos)