diff --git a/data/layout.xml b/data/layout.xml
index e1ea914..f2e635d 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -247,6 +247,7 @@
+
@@ -262,7 +263,8 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/engine/image.cpp b/engine/image.cpp
index e3679a2..416b074 100644
--- a/engine/image.cpp
+++ b/engine/image.cpp
@@ -46,3 +46,36 @@ void Image::flip()
}
std::swap(m_data, flipped);
}
+
+ui::Image ui::Image::resize(int w, int h)
+{
+ Image ret;
+ ret.create(w, h);
+ auto temp = (glm::u8vec4*)ret.data();
+ auto pixels = (glm::u8vec4*)data();
+ float x_ratio = ((float)(width - 1)) / w;
+ float y_ratio = ((float)(height - 1)) / h;
+ float x_diff, y_diff, ya, yb;
+ int offset = 0;
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ int x = (int)(x_ratio * j);
+ int y = (int)(y_ratio * i);
+ x_diff = (x_ratio * j) - x;
+ y_diff = (y_ratio * i) - y;
+ int index = y * width + x;
+
+ // range is 0 to 255 thus bitwise AND with 0xff
+ glm::vec4 A = pixels[index];
+ glm::vec4 B = pixels[index + 1];
+ glm::vec4 C = pixels[index + width];
+ glm::vec4 D = pixels[index + width + 1];
+
+ // Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh
+ glm::vec4 gray = A*(1 - x_diff)*(1 - y_diff) + B * (x_diff)*(1 - y_diff) +
+ C * (y_diff)*(1 - x_diff) + D * (x_diff*y_diff);
+ temp[offset++] = glm::clamp(gray, glm::vec4(0), glm::vec4(255));
+ }
+ }
+ return ret;
+}
diff --git a/engine/image.h b/engine/image.h
index f4e44ae..dda4d34 100644
--- a/engine/image.h
+++ b/engine/image.h
@@ -26,6 +26,7 @@ public:
}
void flip();
void create() { m_data = std::make_unique(size()); }
+ Image resize(int w, int h);
};
}
diff --git a/engine/node_canvas.cpp b/engine/node_canvas.cpp
index 30ef596..2a8d085 100644
--- a/engine/node_canvas.cpp
+++ b/engine/node_canvas.cpp
@@ -275,24 +275,45 @@ void NodeCanvas::draw()
for (auto& mode : ui::Canvas::modes[(int)ui::Canvas::kCanvasMode::Grid])
mode->on_Draw(ortho_proj, proj, camera);
- int grid_divs = glm::floor(App::I.grid->m_groud_scale->get_value() * 100);
- if (grid_divs != m_grid_divs && (grid_divs % 2) == 0)
- {
- m_grid_divs = grid_divs;
- m_grid.create(1, 1, grid_divs);
- }
- float grid_scale = m_grid_divs * 0.01f;
- ui::ShaderManager::use(kShader::Color);
- ui::ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(
- glm::vec3(App::I.grid->m_groud_value->get_value()),
- App::I.grid->m_groud_opacity->get_value()));
- ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera
- * glm::translate(glm::vec3(0, (App::I.grid->m_groud_height->get_value() - 0.5f) * 2.f, 0))
- * glm::eulerAngleX(glm::radians(90.f))
- * glm::scale(glm::vec3(grid_scale, grid_scale, 1))
- );
- m_grid.draw_stroke();
+ if (App::I.grid->m_groud_opacity->get_value() > 0.f)
+ {
+ // DRAW GRIDS
+ ui::ShaderManager::use(kShader::Color);
+
+ // ground grid
+ int grid_divs = glm::floor(App::I.grid->m_groud_scale->get_value() * 100);
+ if (grid_divs != m_grid_divs && (grid_divs % 2) == 0)
+ {
+ m_grid_divs = grid_divs;
+ m_grid.create(1, 1, grid_divs);
+ }
+ float grid_scale = m_grid_divs * 0.01f;
+
+ ui::ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(
+ glm::vec3(App::I.grid->m_groud_value->get_value()),
+ App::I.grid->m_groud_opacity->get_value()));
+ ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera
+ * glm::translate(glm::vec3(0, (App::I.grid->m_groud_height->get_value() - 0.5f) * 2.f, 0))
+ * glm::eulerAngleX(glm::radians(90.f))
+ * glm::scale(glm::vec3(grid_scale, grid_scale, 1))
+ );
+ //m_grid.draw_stroke();
+ App::I.grid->m_hm_plane.draw_stroke();
+ }
+
+ // box grid
+ // ceiling
+// ui::ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(
+// glm::vec3(App::I.grid->m_groud_value->get_value()),
+// App::I.grid->m_box_opacity->get_value()));
+// ui::ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera
+// * glm::translate(glm::vec3(0, (App::I.grid->m_groud_height->get_value() + App::I.grid->m_box_height->get_value() - 0.5f) * 2.f, 0))
+// * glm::eulerAngleX(glm::radians(90.f))
+// * glm::scale(glm::vec3(grid_scale, grid_scale, 1))
+// );
+// m_grid.draw_stroke();
+
//ui::ShaderManager::use(kShader::Equirect);
//ui::ShaderManager::u_mat4(kShaderUniform::MVP, glm::scale(glm::vec3(.5, .5, 1)));
diff --git a/engine/node_image_texture.cpp b/engine/node_image_texture.cpp
index 840aaa0..93709e2 100644
--- a/engine/node_image_texture.cpp
+++ b/engine/node_image_texture.cpp
@@ -20,13 +20,14 @@ void NodeImageTexture::draw()
{
using namespace ui;
tex.bind();
- NodeImage::m_sampler.bind(0);
+ auto& sampler = tex.has_mips ? NodeImage::m_sampler : NodeImage::m_sampler_mips;
+ sampler.bind(0);
glEnable(GL_BLEND);
ui::ShaderManager::use(kShader::Texture);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
NodeImage::m_plane.draw_fill();
- NodeImage::m_sampler.unbind();
+ sampler.unbind();
tex.unbind();
glDisable(GL_BLEND);
}
diff --git a/engine/node_panel_grid.cpp b/engine/node_panel_grid.cpp
index bef48c8..ba4bfeb 100644
--- a/engine/node_panel_grid.cpp
+++ b/engine/node_panel_grid.cpp
@@ -2,6 +2,8 @@
#include "log.h"
#include "node_panel_grid.h"
#include "canvas.h"
+#include "app.h"
+#include "image.h"
Node* NodePanelGrid::clone_instantiate() const
{
@@ -26,8 +28,36 @@ void NodePanelGrid::init_controls()
m_groud_scale = find("grid-ground-scale");
m_groud_value = find("grid-ground-value");
m_groud_height = find("grid-ground-height");
- m_box_opacity = find("grid-box-opacity");
- m_box_width = find("grid-box-width");
- m_box_height = find("grid-box-height");
- m_box_depth = find("grid-box-depth");
+ //m_box_opacity = find("grid-box-opacity");
+ //m_box_width = find("grid-box-width");
+ //m_box_height = find("grid-box-height");
+ //m_box_depth = find("grid-box-depth");
+
+ auto update_hm = [this](Node* target, float v) {
+ m_hm_plane.create(1, 1, m_hm_image, -m_hm_height->get_value());
+ };
+
+ m_hm_preview = find("grid-heightmap-preview");
+ m_hm_load = find("grid-heightmap-load");
+ m_hm_offset = find("grid-heightmap-offset");
+ m_hm_height = find("grid-heightmap-height");
+
+ m_hm_height->on_value_changed = update_hm;
+ m_hm_preview->SetHeight(0);
+
+ //m_hm_plane.create(1, 1);
+
+ m_hm_load->on_click = [this](Node*) {
+ App::I.pick_image([this](std::string path) {
+ ui::Image img;
+ img.load(path);
+ m_hm_image = img.resize(128, 128);
+ m_hm_preview->tex.create(m_hm_image);
+ m_hm_preview->tex.create_mipmaps();
+ auto sz = m_hm_preview->tex.size();
+ m_hm_preview->SetAspectRatio(sz.x / sz.y);
+ m_hm_plane.create(1, 1, m_hm_image, -m_hm_height->get_value());
+ m_hm_preview->SetHeight(100);
+ });
+ };
}
diff --git a/engine/node_panel_grid.h b/engine/node_panel_grid.h
index 68c7953..da0aeb2 100644
--- a/engine/node_panel_grid.h
+++ b/engine/node_panel_grid.h
@@ -5,6 +5,10 @@
#include "brush.h"
#include "node_checkbox.h"
#include "node_combobox.h"
+#include "node_image_texture.h"
+#include "node_button.h"
+#include "shape.h"
+#include "image.h"
class NodePanelGrid : public Node
{
@@ -17,7 +21,13 @@ public:
NodeSliderH* m_box_width;
NodeSliderH* m_box_height;
NodeSliderH* m_box_depth;
-
+ NodeImageTexture* m_hm_preview;
+ NodeButton* m_hm_load;
+ NodeSliderH* m_hm_offset;
+ NodeSliderH* m_hm_height;
+ ui::HeightmapPlane m_hm_plane;
+ ui::Image m_hm_image;
+
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
diff --git a/engine/shape.cpp b/engine/shape.cpp
index 6bea13a..948ac4f 100644
--- a/engine/shape.cpp
+++ b/engine/shape.cpp
@@ -4,7 +4,21 @@
using namespace ui;
-bool Shape::create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize)
+bool ui::Shape::create_buffers(GLushort * idx, GLvoid * vertices, int isize, int vsize)
+{
+ index_type = GL_UNSIGNED_SHORT;
+ create_buffers_imp(idx, vertices, isize, vsize);
+ return false;
+}
+
+bool ui::Shape::create_buffers(GLuint* idx, GLvoid * vertices, int isize, int vsize)
+{
+ index_type = GL_UNSIGNED_INT;
+ create_buffers_imp(idx, vertices, isize, vsize);
+ return false;
+}
+
+bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsize)
{
use_idx = true;
@@ -80,6 +94,8 @@ bool Shape::create_buffers(GLvoid* vertices, int vsize)
}
void Shape::draw_fill() const
{
+ if (count[0] == 0) return;
+
GLenum type = GL_TRIANGLES;
if (count[0] == 1)
type = GL_POINTS;
@@ -88,7 +104,7 @@ void Shape::draw_fill() const
#if USE_VBO
glBindVertexArray(arrays[0]);
if (use_idx)
- glDrawElements(type, count[0], GL_UNSIGNED_SHORT, ioff[0]);
+ glDrawElements(type, count[0], index_type, ioff[0]);
else
glDrawArrays(type, 0, count[0]);
glBindVertexArray(0);
@@ -113,13 +129,15 @@ void Shape::draw_fill() const
}
void Shape::draw_stroke() const
{
+ if (count[0] == 0) return;
+
GLenum type = GL_LINES;
if (count[1] == 1)
type = GL_POINTS;
#if USE_VBO
glBindVertexArray(arrays[1]);
if (use_idx)
- glDrawElements(type, count[1], GL_UNSIGNED_SHORT, ioff[1]);
+ glDrawElements(type, count[1], index_type, ioff[1]);
else
glDrawArrays(type, 0, count[1]);
glBindVertexArray(0);
@@ -219,17 +237,82 @@ void Plane::create_impl(float w, float h, int div, GLushort *idx, Shape::vertex_
*idx++ = y;
*idx++ = y + div * (div + 1);
}
-//
-// // outline indices
-// *idx++ = 0; // A
-// *idx++ = (div+1)*(div); // B
-// *idx++ = (div+1)*(div); // B
-// *idx++ = (div+1)*(div+1)-1; // C
-// *idx++ = (div+1)*(div+1)-1; // C
-// *idx++ = div; // D
-// *idx++ = div; // D
-// *idx++ = 0; // A
}
+
+bool ui::HeightmapPlane::create(float w, float h, const Image& img, float scale)
+{
+ int div = img.width - 1; // TODO: handle height also
+ int idx_size = (div * div * 6) + (div * (div + 1) * 4);
+ int vertices_size = (div + 1)*(div + 1);
+ auto idx = std::make_unique(idx_size);
+ auto vertices = std::make_unique(vertices_size);
+
+ count[0] = div * div * 6;
+ count[1] = div * (div + 1) * 4;
+ ioff[0] = (GLvoid*)0;
+ ioff[1] = (GLvoid*)(count[0] * sizeof(GLuint));
+
+ auto pv = vertices.get();
+ auto pi = idx.get();
+ auto px = (glm::u8vec4*)img.data();
+
+ const float dx = w / div;
+ const float dy = h / div;
+ const float ox = -w * 0.5f;
+ const float oy = -h * 0.5f;
+ for (int y = 0; y <= div; y++)
+ {
+ for (int x = 0; x <= div; x++)
+ {
+ vertex_t v;
+ v.pos.x = ox + dx * (float)x;
+ v.pos.y = oy + dy * (float)y;
+ v.pos.z = (*px++).r / 255.f * scale;
+ v.pos.w = 1;
+ v.uvs = glm::vec2(x, y) / (float)div;
+ *pv++ = v;
+ }
+ }
+
+ // generate indices
+ for (int y = 0; y < div; y++)
+ {
+ int i = y * (div + 1);
+ for (int x = 0; x < div; x++)
+ {
+ *pi++ = i;
+ *pi++ = i + div + 1;
+ *pi++ = i + div + 2;
+ *pi++ = i;
+ *pi++ = i + div + 2;
+ *pi++ = i + 1;
+ i++;
+ }
+ }
+
+ // generate indices
+ for (int y = 0; y <= div; y++)
+ {
+ int i = y * (div + 1);
+ for (int x = 0; x <= div; x++)
+ {
+ if (x < div)
+ {
+ *pi++ = y * (div + 1) + x;
+ *pi++ = y * (div + 1) + x + 1;
+ }
+
+ if (y < div)
+ {
+ *pi++ = y * (div + 1) + x;
+ *pi++ = (y + 1) * (div + 1) + x;
+ }
+ }
+ }
+
+ return create_buffers(idx.get(), vertices.get(), sizeof(GLuint) * idx_size, sizeof(vertex_t) * vertices_size);
+}
+
void ui::Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const glm::vec2* uvs2)
{
static vertex_t vertices[4];
diff --git a/engine/shape.h b/engine/shape.h
index fa9b2a1..ce4f305 100644
--- a/engine/shape.h
+++ b/engine/shape.h
@@ -1,4 +1,5 @@
#pragma once
+#include "image.h"
enum class kShapeType : uint16_t
{
@@ -17,10 +18,13 @@ protected:
GLuint arrays[2]{ 0, 0 };
GLuint count[2]{ 0, 0 };
GLvoid* ioff[2]{ 0, 0 };
+ GLenum index_type = 0;
bool use_idx = true;
+ bool create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsize);
public:
struct vertex_t { glm::vec4 pos; glm::vec2 uvs; glm::vec2 uvs2; };
- bool create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize);
+ bool create_buffers(GLushort* idx, GLvoid* vertices, int isize, int vsize);
+ bool create_buffers(GLuint* idx, GLvoid* vertices, int isize, int vsize);
bool create_buffers(GLvoid* vertices, int vsize);
void draw_fill() const;
void draw_stroke() const;
@@ -116,31 +120,12 @@ public:
return create_buffers(idx.get(), vertices.get(), sizeof(GLushort) * idx_size, sizeof(vertex_t) * vertices_size);
}
void update_vertices(const glm::vec4* data, const glm::vec2* uvs = nullptr, const glm::vec2* uvs2 = nullptr);
-/*
- bool create(att::Divisions divisions, att::Width w, att::Height h)
- {
- const int div = divisions.value;
- auto idx = std::make_unique(div * div * 6 + 8);
- auto vertices = std::make_unique((div + 1)*(div + 1));
- create_impl(w.value, h.value, div, idx.get(), vertices.get());
- return create_buffers(idx.get(), vertices.get(), sizeof(idx), sizeof(vertices));
- }
- template
- T get_attribute(T def_val)
- {
- auto ret = attribs.find(def_val.id);
- if (ret == attribs.end())
- return def_val;
- return *reinterpret_cast(ret->second.get());
- }
- bool create_attrib() override
- {
- const auto w = get_attribute(att::Width(0));
- const auto h = get_attribute(att::Height(0));
- const auto d = get_attribute(att::Divisions(1));
- return create(d, w, h);
- }
- */
+};
+
+class HeightmapPlane : public Shape
+{
+public:
+ bool create(float w, float h, const Image& img, float scale);
};
class RectShape : public Shape
diff --git a/engine/texture.cpp b/engine/texture.cpp
index 312282c..39b93ff 100644
--- a/engine/texture.cpp
+++ b/engine/texture.cpp
@@ -65,6 +65,7 @@ void Texture2D::create_mipmaps()
bind();
glGenerateMipmap(GL_TEXTURE_2D);
unbind();
+ has_mips = true;
}
void Texture2D::assign(GLuint tex, int w/* = -1*/, int h/* = -1*/, GLuint internal_format/* = GL_RGBA8*/, GLuint format/* = GL_RGBA*/)
diff --git a/engine/texture.h b/engine/texture.h
index e0ada03..db1448c 100644
--- a/engine/texture.h
+++ b/engine/texture.h
@@ -9,6 +9,7 @@ class Texture2D
GLint m_format = 0;
GLint m_iformat = 0;
public:
+ bool has_mips = false;
bool create(int width, int height, GLint internal_format = GL_RGBA8, GLint format = GL_RGBA, const uint8_t* data = nullptr);
bool create(const ui::Image& img);
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);