added Normal lines mode for perspective aligned lines

This commit is contained in:
2017-05-07 15:25:54 +01:00
parent de1ace0d63
commit b50011babf
9 changed files with 220 additions and 36 deletions

View File

@@ -437,10 +437,11 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
{
float y = AMotionEvent_getY(event, 0);
float x = AMotionEvent_getX(event, 0);
tracked = 0;
p0.id = -1;
p1.id = -1;
App::I.mouse_up(0, x, y);
if (tracked == 1)
App::I.mouse_up(0, x, y);
tracked = 0;
//LOG("first up");
return 1;
}
@@ -461,7 +462,7 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
return 1;
}
case AMOTION_EVENT_ACTION_MOVE:
if (count == 1)
if (count == 1 && tracked == 1)
{
float y = AMotionEvent_getY(event, 0);
float x = AMotionEvent_getX(event, 0);

View File

@@ -362,7 +362,8 @@
<button id="btn-erase" width="60" height="100%" margin="0 0 0 0" text="Erase"/>
<button id="btn-line" width="50" height="100%" margin="0 0 0 0" text="Line"/>
<button id="btn-cam" width="70" height="100%" margin="0 0 0 0" text="Camera"/>
<!--
<button id="btn-normal" width="70" height="100%" margin="0 0 0 0" text="Normal"/>
<!--
<button-custom id="btn-layer" width="50" height="100%" margin="0 5 0 0" thickness="1" border-color="0 0 0 1" pad="6" align="center" justify="center">
<icon width="100%" height="100%" icon="disk"/>
</button-custom>

View File

@@ -472,6 +472,7 @@ void App::initLayout()
layout[main_id]->find<NodeButton>("btn-erase")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-line")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-cam")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-normal")->set_color(color_button_normal);
Canvas::set_mode(Canvas::kCanvasMode::Draw);
};
layout[main_id]->find<NodeButton>("btn-pen")->set_color(color_button_hlight);
@@ -484,6 +485,7 @@ void App::initLayout()
layout[main_id]->find<NodeButton>("btn-erase")->set_color(color_button_hlight);
layout[main_id]->find<NodeButton>("btn-line")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-cam")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-normal")->set_color(color_button_normal);
Canvas::set_mode(Canvas::kCanvasMode::Erase);
};
}
@@ -494,6 +496,7 @@ void App::initLayout()
layout[main_id]->find<NodeButton>("btn-erase")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-line")->set_color(color_button_hlight);
layout[main_id]->find<NodeButton>("btn-cam")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-normal")->set_color(color_button_normal);
Canvas::set_mode(Canvas::kCanvasMode::Line);
};
}
@@ -504,9 +507,21 @@ void App::initLayout()
layout[main_id]->find<NodeButton>("btn-erase")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-line")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-cam")->set_color(color_button_hlight);
layout[main_id]->find<NodeButton>("btn-normal")->set_color(color_button_normal);
Canvas::set_mode(Canvas::kCanvasMode::Camera);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-normal"))
{
button->on_click = [this](Node*) {
layout[main_id]->find<NodeButton>("btn-pen")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-erase")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-line")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-cam")->set_color(color_button_normal);
layout[main_id]->find<NodeButton>("btn-normal")->set_color(color_button_hlight);
Canvas::set_mode(Canvas::kCanvasMode::Normal);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-bucket"))
{
button->on_click = [this](Node*) {

View File

@@ -8,6 +8,7 @@ std::vector<CanvasMode*> ui::Canvas::modes[] = {
{ new CanvasModePen, new CanvasModeBasicCamera },
{ new CanvasModeLine, new CanvasModeBasicCamera },
{ new CanvasModeCamera, new CanvasModeBasicCamera },
{ new CanvasModeNormal, new CanvasModeBasicCamera },
};
glm::vec3 ui::Canvas::m_plane_origin[6] = {
{ 0, 0,-1}, // front
@@ -127,32 +128,11 @@ void ui::Canvas::stroke_draw()
ShaderManager::u_vec2(kShaderUniform::Resolution, { m_width, m_height });
for (const auto& s : samples)
{
auto unproject = [](glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj, glm::vec3& out_origin, glm::vec3& out_dir) {
auto clip_space = glm::vec2(loc.x, vp.w - loc.y - 1.f) / vp.zw() * 2.f - 1.f;
auto inv = glm::inverse(proj * camera);
auto wp0 = inv * glm::vec4(clip_space, 0, 1);
auto wp1 = inv * glm::vec4(clip_space, .5, 1);
out_origin = (wp0 / wp0.w).xyz();
out_dir = glm::normalize((wp1 / wp1.w).xyz() - out_origin);
};
auto intersect = [](glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin, glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit) {
float den = glm::dot(ray_dir, plane_normal);
if (den == 0)
return false; // no intersection
float num = glm::dot(plane_origin - ray_origin, plane_normal);
float t = num / den;
if (t > 0)
out_hit = ray_origin + ray_dir * t;
else
// negative intersection
return false;
return true;
};
glm::vec3 ray_origin, ray_dir;
unproject(s.pos, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir);
point_unproject(s.pos, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir);
glm::vec3 hit;
glm::vec2 fb_pos;
if (intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit))
if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit))
{
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1);
@@ -252,6 +232,74 @@ void ui::Canvas::stroke_draw()
m_commit_delayed = false;
}
}
bool ui::Canvas::point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, int& out_plane_id)
{
point_unproject(loc, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir);
glm::vec3 hit;
glm::vec2 fb_pos;
for (int i = 0; i < 6; i++)
{
if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit))
{
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1);
if (glm::abs(plane_local.x) < 1.f && glm::abs(plane_local.y) < 1.f)
{
fb_pos.x = -(plane_local.x * 0.5f - 0.5f) * m_width;
fb_pos.y = (plane_local.y * 0.5f + 0.5f) * m_height;
hit_pos = hit;
hit_normal = m_plane_normal[i];
out_plane_id = i;
return true;
}
else continue;
}
else continue;
}
return false;
}
bool ui::Canvas::point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, int plane_id)
{
point_unproject(loc, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir);
glm::vec3 hit;
glm::vec2 fb_pos;
if (ray_intersect(ray_origin, ray_dir, m_plane_origin[plane_id],
m_plane_normal[plane_id], m_plane_tangent[plane_id], hit))
{
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[plane_id], m_plane_normal[plane_id], m_plane_tangent[plane_id]);
hit_pos = hit;
hit_normal = m_plane_normal[plane_id];
return true;
}
return false;
}
bool ui::Canvas::ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit)
{
float den = glm::dot(ray_dir, plane_normal);
if (den == 0)
return false; // no intersection
float num = glm::dot(plane_origin - ray_origin, plane_normal);
float t = num / den;
if (t > 0)
out_hit = ray_origin + ray_dir * t;
else
// negative intersection
return false;
return true;
};
void ui::Canvas::point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj,
glm::vec3& out_origin, glm::vec3& out_dir)
{
auto clip_space = glm::vec2(loc.x, vp.w - loc.y - 1.f) / vp.zw() * 2.f - 1.f;
auto inv = glm::inverse(proj * camera);
auto wp0 = inv * glm::vec4(clip_space, 0, 1);
auto wp1 = inv * glm::vec4(clip_space, .5, 1);
out_origin = (wp0 / wp0.w).xyz();
out_dir = glm::normalize((wp1 / wp1.w).xyz() - out_origin);
};
void ui::Canvas::stroke_commit()
{
if (!m_dirty || m_layers.empty())
@@ -723,6 +771,37 @@ ui::Image ui::Canvas::thumbnail_read(std::string data_path)
return std::move(thumb);
}
void ui::Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)> observer)
{
// save viewport and clear color states
GLint vp[4];
GLfloat cc[4];
glGetIntegerv(GL_VIEWPORT, vp);
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
GLboolean blend = glIsEnabled(GL_BLEND);
// prepare common states
glViewport(0, 0, m_width, m_height);
glDisable(GL_BLEND);
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .1f, 100.f);
for (int i = 0; i < 6; i++)
{
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer();
observer(plane_camera, proj);
m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer();
}
// restore viewport and clear color states
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]);
glActiveTexture(GL_TEXTURE0);
}
///////////////////////////////////////////////////////////////////////////////////////////
void ui::Layer::destroy()

View File

@@ -71,7 +71,7 @@ public:
glm::vec3 m_cam_pos;
float m_cam_fov = 85;
enum class kCanvasMode { Draw, Erase, Line, Camera, COUNT };
enum class kCanvasMode { Draw, Erase, Line, Camera, Normal, COUNT };
kCanvasMode m_state{ kCanvasMode::Draw };
static std::vector<CanvasMode*> modes[];
std::vector<CanvasMode*>* m_mode;
@@ -106,6 +106,15 @@ public:
ui::Image thumbnail_generate(int w, int h);
ui::Image thumbnail_read(std::string data_path);
void preview_generate();
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj)>);
bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3 &out_hit);
void point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj,
glm::vec3 &out_origin, glm::vec3 &out_dir);
bool point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, int& out_plane_id);
bool point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, int plane_id);
};
class ActionStroke : public Action

View File

@@ -120,6 +120,7 @@ void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
break;
case kEventType::MouseCancel:
node->mouse_release();
m_dragging = false;
break;
default:
break;
@@ -172,6 +173,7 @@ void CanvasModeCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
canvas->m_cam_pos.xy = m_pos_start + (me->m_pos - m_drag_start) * glm::vec2(1, -1) * 0.01f;
break;
case kEventType::MouseCancel:
m_dragging = false;
node->mouse_release();
break;
default:
@@ -183,15 +185,76 @@ void CanvasModeCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
void CanvasModeNormal::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
glm::vec3 ro, rd, hit_o, hit_d;
if (canvas->point_trace(loc, ro, rd, hit_o, hit_d, m_plane_id))
{
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseUpL:
node->mouse_release();
m_dragging = false;
commit();
break;
case kEventType::MouseMove:
{
glm::vec3 ro, rd, hit_o, hit_d;
if (m_dragging && canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, m_plane_id))
{
origin = hit_o;
dir = hit_d;
m_dragging = true;
}
break;
}
case kEventType::MouseCancel:
m_dragging = false;
node->mouse_release();
break;
default:
break;
}
}
void CanvasModeNormal::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_dragging)
{
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 0, 0, 1});
static glm::vec4 AB[2];
AB[0] = {origin - dir * 10.f, 1};
AB[1] = {origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
}
}
void CanvasModeNormal::init()
{
m_line.create();
}
void CanvasModeNormal::commit()
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj){
ui::ShaderManager::use(ui::kShader::Color);
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 0, 0, 1});
static glm::vec4 AB[2];
AB[0] = {origin - dir * 10.f, 1};
AB[1] = {origin + dir * 10.f, 1 };
m_line.update_vertices(AB);
m_line.draw_stroke();
};
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2));
}

View File

@@ -59,13 +59,15 @@ public:
class CanvasModeNormal : public CanvasMode
{
ui::LineSegment m_line;
glm::vec3 origin;
glm::vec3 dir;
int m_plane_id;
bool m_dragging = false;
glm::vec2 m_drag_start;
glm::vec2 m_drag_pos;
public:
virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override;
virtual void on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) override;
virtual void init() override;
void commit();
};
class CanvasModeCamera : public CanvasMode

View File

@@ -1979,15 +1979,15 @@ public:
{
m_mouse_ignore = false;
m_canvas = std::make_unique<ui::Canvas>();
m_canvas->create(1024, 1024);
m_sampler.create();
m_face_plane.create<1>(2, 2);
m_line.create();
CanvasMode::node = this;
CanvasMode::canvas = m_canvas.get();
for (int i = 0; i < (int)ui::Canvas::kCanvasMode::COUNT; i++)
for (auto m : ui::Canvas::modes[i])
m->init();
m_canvas->create(1024, 1024);
m_sampler.create();
m_face_plane.create<1>(2, 2);
m_line.create();
}
virtual void restore_context() override
{
@@ -1996,12 +1996,18 @@ public:
m_sampler.create();
m_face_plane.create<1>(2, 2);
m_canvas->snapshot_restore();
CanvasMode::node = this;
CanvasMode::canvas = m_canvas.get();
for (int i = 0; i < (int)ui::Canvas::kCanvasMode::COUNT; i++)
for (auto m : ui::Canvas::modes[i])
m->init();
}
virtual void clear_context() override
{
Node::clear_context();
m_canvas->snapshot_save(data_path);
m_canvas->clear_context();
// TODO: clear CanvasMode objects
}
virtual void draw() override
{

View File

@@ -268,6 +268,14 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
auto chars = [theEvent characters];
App::I.key_up(convert_key(keyCode));
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
- (void)tabletPoint:(NSEvent *)theEvent
{
}
- (void)tabletProximity:(NSEvent *)theEvent
{
}
@end