added Normal lines mode for perspective aligned lines
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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*) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user