implement heightmap grid

This commit is contained in:
2018-08-07 19:45:38 +02:00
parent 16c04c433f
commit f941fc4254
11 changed files with 257 additions and 65 deletions

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ public:
}
void flip();
void create() { m_data = std::make_unique<uint8_t[]>(size()); }
Image resize(int w, int h);
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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*/)

View File

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