implement heightmap grid
This commit is contained in:
@@ -247,6 +247,7 @@
|
||||
<text text="Grids" font-face="arial" font-size="11" color="1 1 1 1"/>
|
||||
</border>
|
||||
<border color=".3" pad="5" dir="col" width="100%">
|
||||
|
||||
<border color=".2" height="20" justify="center" align="center"><text text="Ground" font-face="arial" font-size="11"/></border>
|
||||
<node dir="row">
|
||||
<node width="30%" dir="col">
|
||||
@@ -262,7 +263,8 @@
|
||||
<node height="20" pad="1" width="100%"><slider-h id="grid-ground-height" value="0.5"/></node>
|
||||
</border>
|
||||
</node>
|
||||
<border color=".2" height="20" justify="center" align="center"><text text="Box" font-face="arial" font-size="11"/></border>
|
||||
|
||||
<!--<border color=".2" height="20" justify="center" align="center"><text text="Box" font-face="arial" font-size="11"/></border>
|
||||
<node dir="row">
|
||||
<node width="30%" dir="col">
|
||||
<node height="20" justify="center"><text text="Opacity" font-face="arial" font-size="11"/></node>
|
||||
@@ -276,8 +278,32 @@
|
||||
<node height="20" pad="1" width="100%"><slider-h id="grid-box-height" value="0.5"/></node>
|
||||
<node height="20" pad="1" width="100%"><slider-h id="grid-box-depth" value="0.5"/></node>
|
||||
</border>
|
||||
</node>-->
|
||||
|
||||
<border color=".2" height="20" justify="center" align="center"><text text="Box" font-face="arial" font-size="11"/></border>
|
||||
<border color="1" align="center" pad="5" margin="0 0 5 0">
|
||||
<image-texture id="grid-heightmap-preview" width="100%" grow="1" height="100" aspect-ratio="1"/>
|
||||
</border>
|
||||
<node dir="row">
|
||||
<node width="30%" dir="col">
|
||||
<node height="20" justify="center"><text text="File" font-face="arial" font-size="11"/></node>
|
||||
<node height="20" justify="center"><text text="Height" font-face="arial" font-size="11"/></node>
|
||||
<node height="20" justify="center"><text text="Offset" font-face="arial" font-size="11"/></node>
|
||||
</node>
|
||||
<border dir="col" align="center" grow="1" width="1" flood-events="1">
|
||||
<node height="20" pad="1" width="100%" dir="row">
|
||||
<node width="20" grow="1" pad="0" margin="0 0 0 2" dir="row">
|
||||
<button id="grid-heightmap-load" text="..." width="40" height="20"></button>
|
||||
<button id="grid-heightmap-clear" text="Clear" width="50" height="20"></button>
|
||||
<button id="grid-heightmap-reload" text="Reload" width="50" height="20"></button>
|
||||
</node>
|
||||
</node>
|
||||
<node height="20" pad="1" width="100%"><slider-h id="grid-heightmap-height" value="0.5"/></node>
|
||||
<node height="20" pad="1" width="100%"><slider-h id="grid-heightmap-offset" value="0.0"/></node>
|
||||
</border>
|
||||
</node>
|
||||
</border>
|
||||
|
||||
</border>
|
||||
</node>
|
||||
</layout>
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
}
|
||||
void flip();
|
||||
void create() { m_data = std::make_unique<uint8_t[]>(size()); }
|
||||
Image resize(int w, int h);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<NodeSliderH>("grid-ground-scale");
|
||||
m_groud_value = find<NodeSliderH>("grid-ground-value");
|
||||
m_groud_height = find<NodeSliderH>("grid-ground-height");
|
||||
m_box_opacity = find<NodeSliderH>("grid-box-opacity");
|
||||
m_box_width = find<NodeSliderH>("grid-box-width");
|
||||
m_box_height = find<NodeSliderH>("grid-box-height");
|
||||
m_box_depth = find<NodeSliderH>("grid-box-depth");
|
||||
//m_box_opacity = find<NodeSliderH>("grid-box-opacity");
|
||||
//m_box_width = find<NodeSliderH>("grid-box-width");
|
||||
//m_box_height = find<NodeSliderH>("grid-box-height");
|
||||
//m_box_depth = find<NodeSliderH>("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<NodeImageTexture>("grid-heightmap-preview");
|
||||
m_hm_load = find<NodeButton>("grid-heightmap-load");
|
||||
m_hm_offset = find<NodeSliderH>("grid-heightmap-offset");
|
||||
m_hm_height = find<NodeSliderH>("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);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
109
engine/shape.cpp
109
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<GLuint[]>(idx_size);
|
||||
auto vertices = std::make_unique<vertex_t[]>(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];
|
||||
|
||||
@@ -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<GLushort[]>(div * div * 6 + 8);
|
||||
auto vertices = std::make_unique<vertex_t[]>((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<typename T>
|
||||
T get_attribute(T def_val)
|
||||
{
|
||||
auto ret = attribs.find(def_val.id);
|
||||
if (ret == attribs.end())
|
||||
return def_val;
|
||||
return *reinterpret_cast<T*>(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
|
||||
|
||||
@@ -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*/)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user