Extract canvas layer flows, pen modes, and node attributes
This commit is contained in:
@@ -22,6 +22,7 @@ set(PP_LEGACY_PAINT_DOCUMENT_SOURCES
|
||||
src/canvas.cpp
|
||||
src/canvas_actions.cpp
|
||||
src/canvas_layer.cpp
|
||||
src/legacy_canvas_layer_services.cpp
|
||||
src/legacy_canvas_stroke_commit_services.cpp
|
||||
src/legacy_canvas_stroke_live_services.cpp
|
||||
src/legacy_canvas_document_io_services.cpp
|
||||
@@ -42,6 +43,8 @@ set(PP_LEGACY_RENDERER_GL_SOURCES
|
||||
)
|
||||
|
||||
set(PP_LEGACY_UI_CORE_SOURCES
|
||||
src/legacy_ui_node_attributes.cpp
|
||||
src/legacy_ui_node_attributes.h
|
||||
src/legacy_ui_node_loader.cpp
|
||||
src/legacy_ui_node_loader.h
|
||||
src/legacy_ui_node_event.cpp
|
||||
@@ -71,6 +74,7 @@ set(PP_LEGACY_UI_CORE_SOURCES
|
||||
|
||||
set(PP_LEGACY_APP_SOURCES
|
||||
src/canvas_modes.cpp
|
||||
src/legacy_canvas_mode_pen_line.cpp
|
||||
src/legacy_canvas_mode_helpers.cpp
|
||||
src/legacy_canvas_mode_helpers.h
|
||||
src/legacy_canvas_mode_transform.cpp
|
||||
|
||||
@@ -79,10 +79,10 @@ What is still carrying too much live ownership:
|
||||
|
||||
Current hotspot files:
|
||||
|
||||
- `src/canvas.cpp`: 1490 lines
|
||||
- `src/canvas.cpp`: 1271 lines
|
||||
- `src/app_layout.cpp`: 125 lines
|
||||
- `src/canvas_modes.cpp`: 1014 lines
|
||||
- `src/node.cpp`: 995 lines
|
||||
- `src/canvas_modes.cpp`: 720 lines
|
||||
- `src/node.cpp`: 803 lines
|
||||
- `src/main.cpp`: 271 lines
|
||||
- `src/node_panel_brush.cpp`: 435 lines
|
||||
- `src/node_stroke_preview.cpp`: 751 lines
|
||||
@@ -264,11 +264,18 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
`Canvas::stroke_draw()` orchestration now also routes through
|
||||
`src/legacy_canvas_stroke_live_services.cpp` instead of staying inline in
|
||||
`src/canvas.cpp`, which materially thins another large retained live
|
||||
stroke-render pocket, while the
|
||||
stroke-render pocket, while `Canvas::layer_merge(...)`,
|
||||
`Canvas::flood_fill(...)`, and `Canvas::FloodData::apply()` now also route
|
||||
through `src/legacy_canvas_layer_services.cpp` instead of staying inline in
|
||||
`src/canvas.cpp`, which trims another coherent retained layer/fill workflow
|
||||
pocket, while the
|
||||
`CanvasModeTransform` interaction family now also routes through
|
||||
`src/legacy_canvas_mode_transform.cpp` instead of staying inline in
|
||||
`src/canvas_modes.cpp`, which materially thins another retained canvas-view
|
||||
and transform-mode execution pocket,
|
||||
and transform-mode execution pocket, while the `CanvasModePen` and
|
||||
`CanvasModeLine` interaction families now also route through
|
||||
`src/legacy_canvas_mode_pen_line.cpp` instead of staying inline in
|
||||
`src/canvas_modes.cpp`,
|
||||
while `NodePanelBrush` save/restore/scan/reload/find/get-path ownership now
|
||||
routes through `src/legacy_brush_panel_services.*` instead of staying inline
|
||||
in `src/node_panel_brush.cpp`, which trims another retained brush-workflow
|
||||
@@ -306,7 +313,9 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
about without yet moving ownership into `pp_ui_core`, while the generic
|
||||
per-frame node execution/traversal family for `restore_context`,
|
||||
`clear_context`, `update`, `update_internal`, and `tick` now also lives in
|
||||
`src/legacy_ui_node_execution.cpp`,
|
||||
`src/legacy_ui_node_execution.cpp`, while `Node::parse_attributes(...)` now
|
||||
also routes through `src/legacy_ui_node_attributes.*` instead of staying
|
||||
inline in `src/node.cpp`,
|
||||
while `Canvas` point-trace/unproject/project/camera push-pop-get-set and
|
||||
face-to-shape helpers now also route through
|
||||
`src/legacy_canvas_projection_services.*` instead of staying inline in
|
||||
|
||||
@@ -91,7 +91,7 @@ Status: In Progress
|
||||
|
||||
Why now:
|
||||
`src/canvas.cpp` is still the biggest single architectural blocker at about
|
||||
1490 lines, with `src/canvas_modes.cpp` still large at about 1014 lines.
|
||||
1271 lines, with `src/canvas_modes.cpp` still large at about 720 lines.
|
||||
|
||||
Current slice:
|
||||
- Canvas state-management helpers for picking, clear/clear-all, layer
|
||||
@@ -130,6 +130,15 @@ Current slice:
|
||||
`src/legacy_canvas_stroke_live_services.cpp` instead of staying inline in
|
||||
`src/canvas.cpp`, which materially thins another large retained live
|
||||
stroke-render pocket from the canvas shell.
|
||||
- `Canvas::layer_merge(...)`, `Canvas::flood_fill(...)`, and
|
||||
`Canvas::FloodData::apply()` now also live in
|
||||
`src/legacy_canvas_layer_services.cpp` instead of staying inline in
|
||||
`src/canvas.cpp`, which trims another coherent retained layer/fill workflow
|
||||
pocket from the live canvas shell.
|
||||
- The `CanvasModePen` and `CanvasModeLine` interaction families now also live
|
||||
in `src/legacy_canvas_mode_pen_line.cpp` instead of staying inline in
|
||||
`src/canvas_modes.cpp`, which materially thins another retained pen/line
|
||||
interaction pocket from the broader canvas/render hotspot family.
|
||||
|
||||
Write scope:
|
||||
- `src/canvas.cpp`
|
||||
@@ -728,6 +737,10 @@ Current slice:
|
||||
`src/legacy_ui_node_event.*` instead of staying inline in `src/node.cpp`,
|
||||
which materially thins the base scene-graph event shell without changing its
|
||||
public surface.
|
||||
- `Node::parse_attributes(...)` now also routes through
|
||||
`src/legacy_ui_node_attributes.*` instead of staying inline in `src/node.cpp`,
|
||||
which trims another coherent XML/Yoga attribute decoding pocket from the base
|
||||
scene-graph shell without changing its public surface.
|
||||
|
||||
Write scope:
|
||||
- `src/node.cpp`
|
||||
|
||||
237
src/canvas.cpp
237
src/canvas.cpp
@@ -1238,243 +1238,6 @@ void Canvas::stroke_start(glm::vec3 point, float pressure)
|
||||
m_mixer.unbindFramebuffer();
|
||||
m_show_tmp = true;
|
||||
}
|
||||
void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index
|
||||
{
|
||||
m_dirty = false;
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
// prepare common states
|
||||
apply_canvas_viewport(0, 0, m_width, m_height);
|
||||
apply_canvas_capability(blend_state(), false);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (!m_layers[source_idx]->face(i))
|
||||
continue; // no stroke on this face, skip it
|
||||
|
||||
m_layers[dest_idx]->rtt(i).bindFramebuffer();
|
||||
|
||||
auto& lbox = m_layers[dest_idx]->box(i);
|
||||
lbox = glm::vec4(
|
||||
glm::min(xy(m_layers[source_idx]->box(i)), xy(lbox)),
|
||||
glm::max(zw(m_layers[source_idx]->box(i)), zw(lbox))
|
||||
);
|
||||
m_layers[dest_idx]->face(i) = true;
|
||||
|
||||
// copy to tmp2 for layer blending
|
||||
set_active_texture_unit(0);
|
||||
m_tex2[i].bind();
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, m_width, m_height);
|
||||
m_tex2[i].unbind();
|
||||
|
||||
m_sampler.bind(0);
|
||||
m_sampler_nearest.bind(1);
|
||||
{
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = m_size,
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
.layer_alpha = m_layers[source_idx]->m_opacity,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = m_layers[source_idx]->m_blend_mode,
|
||||
.use_dual = false,
|
||||
.dual_alpha = 0.0f,
|
||||
.use_pattern = false,
|
||||
});
|
||||
|
||||
set_active_texture_unit(0);
|
||||
m_tex2[i].bind();
|
||||
set_active_texture_unit(1);
|
||||
m_layers[source_idx]->rtt(i).bindTexture();
|
||||
m_plane.draw_fill();
|
||||
m_layers[source_idx]->rtt(i).unbindTexture();
|
||||
set_active_texture_unit(0);
|
||||
m_tex2[i].unbind();
|
||||
}
|
||||
|
||||
m_layers[dest_idx]->rtt(i).unbindFramebuffer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Canvas::flood_fill(int layer, int plane, std::vector<glm::ivec2> pos, FloodData& plane_data,
|
||||
float threshold, glm::vec4 dest_color, std::unique_ptr<glm::vec4>& source_color)
|
||||
{
|
||||
struct adj_t
|
||||
{
|
||||
int plane;
|
||||
bool flipx;
|
||||
bool flipy;
|
||||
bool flipcoord;
|
||||
adj_t(int plane, bool flipx, bool flipy, int flipcoord) :
|
||||
plane(plane), flipx(flipx), flipy(flipy), flipcoord(flipcoord) { }
|
||||
glm::ivec2 compute(glm::ivec2 p, glm::ivec2 sz) const
|
||||
{
|
||||
glm::ivec2 ret;
|
||||
ret[flipcoord] = flipx ? sz.x - p.x : p.x;
|
||||
ret[1 - flipcoord] = flipy ? sz.y - p.y : p.y;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
LOG("flood_fill plane %d", plane);
|
||||
|
||||
auto& rtt = m_layers[layer]->rtt(plane);
|
||||
auto sz = rtt.getSize();
|
||||
|
||||
if (!plane_data.mask[plane])
|
||||
{
|
||||
plane_data.mask[plane] = std::make_unique<bool[]>((size_t)sz.x * sz.y);
|
||||
plane_data.rgb[plane] = std::unique_ptr<glm::u8vec4[]>(
|
||||
reinterpret_cast<glm::u8vec4*>(m_layers[layer]->rtt(plane).readTextureData()));
|
||||
plane_data.bb[plane] = { sz.x, sz.y, 0, 0 };
|
||||
plane_data.dirty[plane] = false;
|
||||
plane_data.layer = m_layers[layer];
|
||||
}
|
||||
auto& mask = plane_data.mask[plane];
|
||||
auto& rgb = plane_data.rgb[plane];
|
||||
|
||||
if (!source_color)
|
||||
source_color = std::make_unique<glm::vec4>(rgb[pos.back().y * sz.x + pos.back().x]);
|
||||
const glm::vec4 c = *source_color;
|
||||
|
||||
std::array<std::vector<glm::ivec2>, 4> edges;
|
||||
static const std::array<adj_t, 4> adj[6] = {
|
||||
// front
|
||||
{
|
||||
adj_t(3, 1, 0, 0),
|
||||
adj_t(4, 1, 1, 0),
|
||||
adj_t(1, 0, 0, 0),
|
||||
adj_t(5, 1, 0, 0),
|
||||
},
|
||||
// right
|
||||
{
|
||||
adj_t(0, 1, 0, 0),
|
||||
adj_t(4, 1, 0, 1),
|
||||
adj_t(2, 0, 0, 0),
|
||||
adj_t(5, 0, 0, 1),
|
||||
},
|
||||
// back
|
||||
{
|
||||
adj_t(1, 1, 0, 0),
|
||||
adj_t(4, 0, 0, 0),
|
||||
adj_t(3, 0, 0, 0),
|
||||
adj_t(5, 0, 1, 0),
|
||||
},
|
||||
// left
|
||||
{
|
||||
adj_t(2, 1, 0, 0),
|
||||
adj_t(4, 0, 1, 1),
|
||||
adj_t(0, 0, 0, 0),
|
||||
adj_t(5, 1, 1, 1),
|
||||
},
|
||||
// top
|
||||
{
|
||||
adj_t(1, 1, 1, 1),
|
||||
adj_t(0, 1, 1, 0),
|
||||
adj_t(3, 1, 0, 1),
|
||||
adj_t(2, 0, 1, 0),
|
||||
},
|
||||
// bottom
|
||||
{
|
||||
adj_t(1, 0, 0, 1),
|
||||
adj_t(2, 0, 0, 0),
|
||||
adj_t(3, 0, 1, 1),
|
||||
adj_t(0, 1, 0, 0),
|
||||
},
|
||||
};
|
||||
|
||||
auto test = [&](glm::ivec2 p, bool set_color) -> bool
|
||||
{
|
||||
int i = p.y * sz.x + p.x;
|
||||
if (p.x < 0)
|
||||
{
|
||||
edges[0].push_back(adj[plane][0].compute({ -p.x, p.y }, sz));
|
||||
return false;
|
||||
}
|
||||
else if (p.x >= sz.x)
|
||||
{
|
||||
edges[2].push_back(adj[plane][2].compute({ sz.x - p.x + 1, p.y }, sz));
|
||||
return false;
|
||||
}
|
||||
else if (p.y < 0)
|
||||
{
|
||||
edges[3].push_back(adj[plane][3].compute({ p.x, -p.y }, sz));
|
||||
return false;
|
||||
}
|
||||
else if (p.y >= sz.y)
|
||||
{
|
||||
edges[1].push_back(adj[plane][1].compute({ p.x, sz.y - p.y + 1 }, sz));
|
||||
return false;
|
||||
}
|
||||
if (!mask[i])
|
||||
{
|
||||
if (c.a == 0 && glm::abs(rgb[i].a - c.a) < threshold ||
|
||||
c.a > 0 && rgb[i].a > 0 && glm::distance(glm::vec3(c), glm::vec3(rgb[i])) < threshold)
|
||||
{
|
||||
if (set_color)
|
||||
{
|
||||
mask[i] = true;
|
||||
rgb[i] = dest_color * 255.f;
|
||||
plane_data.dirty[plane] = true;
|
||||
glm::vec2 bb_min = glm::min((glm::vec2)p, xy(plane_data.bb[plane]));
|
||||
// add 1 pixel to the end because 1 pixel has min(0) and max(1)
|
||||
glm::vec2 bb_max = glm::max((glm::vec2)p + glm::vec2(1), zw(plane_data.bb[plane]));
|
||||
plane_data.bb[plane] = { bb_min, bb_max };
|
||||
}
|
||||
pos.push_back(p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
while (!pos.empty())
|
||||
{
|
||||
auto p = pos.back();
|
||||
pos.pop_back();
|
||||
if(!test(p + glm::ivec2( 0, 0), true))
|
||||
continue;
|
||||
test(p + glm::ivec2(-1, 0), false);
|
||||
test(p + glm::ivec2(1, 0), false);
|
||||
test(p + glm::ivec2(0, 1), false);
|
||||
test(p + glm::ivec2(0, -1), false);
|
||||
//for (int x = -1; x <= 1; x++)
|
||||
// for (int y = -1; y <= 1; y++)
|
||||
// if (x != 0 && y != 0)
|
||||
// test(p + glm::ivec2(x, y), false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!edges[i].empty())
|
||||
{
|
||||
flood_fill(layer, adj[plane][i].plane, edges[i], plane_data, threshold, dest_color, source_color);
|
||||
//LOG("continue to plane %d -> %d", plane, adj[plane][i].plane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::FloodData::apply()
|
||||
{
|
||||
for (int plane = 0; plane < 6; plane++)
|
||||
{
|
||||
if (!dirty[plane])
|
||||
continue;
|
||||
auto& rtt = layer->rtt(plane);
|
||||
App::I->render_task([&]
|
||||
{
|
||||
rtt.updateRgba8(0, 0, rtt.getWidth(), rtt.getHeight(), rgb[plane].get());
|
||||
});
|
||||
layer->face(plane) = true;
|
||||
layer->box(plane) = box_union(layer->box(plane), bb[plane]);
|
||||
}
|
||||
Canvas::I->m_unsaved = true;
|
||||
}
|
||||
|
||||
void Canvas::destroy()
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "node_canvas.h"
|
||||
#include "legacy_canvas_draw_merge_services.h"
|
||||
#include "legacy_canvas_stroke_composite_services.h"
|
||||
#include "legacy_canvas_stroke_preview_services.h"
|
||||
#include "legacy_canvas_mode_helpers.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
@@ -24,317 +23,9 @@ using pp::legacy_canvas_mode::apply_canvas_mode_capability;
|
||||
using pp::legacy_canvas_mode::apply_canvas_mode_viewport;
|
||||
using pp::legacy_canvas_mode::query_canvas_mode_capability;
|
||||
using pp::legacy_canvas_mode::query_canvas_mode_read_framebuffer;
|
||||
using pp::legacy_canvas_mode::read_canvas_mode_pixel;
|
||||
using pp::legacy_canvas_mode::set_canvas_mode_active_texture_unit;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CanvasModePen::on_GestureEvent(GestureEvent* ge)
|
||||
{
|
||||
m_draw_tip = false;
|
||||
}
|
||||
|
||||
void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
m_draw_tip = App::I->draws_canvas_tip_for_input(me->m_source, me->m_type);
|
||||
m_draw_outline = true;
|
||||
|
||||
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
|
||||
return;
|
||||
|
||||
me->m_pressure = App::I->adjust_canvas_input_pressure(me->m_pressure);
|
||||
|
||||
switch (me->m_type)
|
||||
{
|
||||
case kEventType::MouseDownL:
|
||||
if (!App::I->keys[(int)kKey::KeySpacebar])
|
||||
{
|
||||
if (App::I->keys[(int)kKey::KeyAlt] || m_picking)
|
||||
{
|
||||
m_picking = true;
|
||||
Canvas::I->pick_start();
|
||||
glm::vec4 pix = Canvas::I->pick_get(loc);
|
||||
Canvas::I->m_current_brush->m_tip_color = pix;
|
||||
App::I->brush_update(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
App::I->render_task_async([loc, pr = me->m_pressure]
|
||||
{
|
||||
Canvas::I->stroke_start({ loc, 0 }, pr);
|
||||
});
|
||||
m_drawing = true;
|
||||
}
|
||||
m_dragging = true;
|
||||
node->mouse_capture();
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
if (m_dragging && !m_picking)
|
||||
{
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
App::I->render_task_async([]
|
||||
{
|
||||
Canvas::I->stroke_end();
|
||||
});
|
||||
}
|
||||
if (m_dragging && m_picking)
|
||||
{
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
glm::vec4 pix = Canvas::I->pick_get(loc);
|
||||
Canvas::I->m_current_brush->m_tip_color = pix;
|
||||
App::I->brush_update(true, false);
|
||||
Canvas::I->pick_end();
|
||||
}
|
||||
m_drawing = false;
|
||||
m_dragging = false;
|
||||
m_picking = false;
|
||||
break;
|
||||
case kEventType::MouseDownR:
|
||||
if (App::I->keys[(int)kKey::KeyAlt])
|
||||
{
|
||||
m_resizing = true;
|
||||
m_dragging = true;
|
||||
m_size_pos_start = m_cur_pos;
|
||||
auto curve = App::I->stroke->m_curves[App::I->stroke->m_tip_size];
|
||||
m_size_value_start = curve.to_slider(Canvas::I->m_current_brush->m_tip_size);
|
||||
node->mouse_capture();
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseUpR:
|
||||
if (m_dragging && m_resizing)
|
||||
{
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
m_dragging = false;
|
||||
m_resizing = false;
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (m_dragging && !m_picking && !m_resizing)
|
||||
{
|
||||
App::I->render_task_async([loc, pr=me->m_pressure]
|
||||
{
|
||||
Canvas::I->stroke_update({ loc, 0 }, pr);
|
||||
});
|
||||
}
|
||||
if (m_dragging && m_picking)
|
||||
{
|
||||
glm::vec4 pix = Canvas::I->pick_get(loc);
|
||||
Canvas::I->m_current_brush->m_tip_color = pix;
|
||||
App::I->brush_update(true, false);
|
||||
}
|
||||
if (m_dragging && m_resizing)
|
||||
{
|
||||
auto diff = m_cur_pos - m_size_pos_start;
|
||||
auto curve = App::I->stroke->m_curves[App::I->stroke->m_tip_size];
|
||||
Canvas::I->m_current_brush->m_tip_size = glm::max(curve.to_value(m_size_value_start + diff.x * 0.001f), 0.001f);
|
||||
App::I->brush_update(true, true);
|
||||
}
|
||||
m_cur_pos = loc;
|
||||
break;
|
||||
case kEventType::MouseCancel:
|
||||
if (m_dragging)
|
||||
{
|
||||
App::I->render_task_async([]
|
||||
{
|
||||
Canvas::I->stroke_cancel();
|
||||
});
|
||||
m_dragging = false;
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
}
|
||||
if (m_picking)
|
||||
m_picking = false;
|
||||
if (m_resizing)
|
||||
m_resizing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
||||
{
|
||||
if (m_draw_tip)
|
||||
{
|
||||
const auto& brush = Canvas::I->m_current_brush;
|
||||
auto pos = m_resizing ? m_size_pos_start : m_cur_pos;
|
||||
//if (App::I->keys[(int)kKey::KeyAlt] && !m_resizing)
|
||||
// pos.x = pos.x - brush->m_tip_size * .5f;
|
||||
float tip_scale_fix = 1.f / glm::tan(glm::radians(Canvas::I->m_cam_fov * 0.5f));
|
||||
float tip_angle = brush->m_tip_angle * (float)(M_PI * 2.0);
|
||||
glm::vec2 tip_scale = App::I->zoom * brush->m_tip_scale *
|
||||
glm::vec2(brush->m_tip_size * tip_scale_fix) *
|
||||
glm::vec2(brush->m_tip_flipx ? -1 : 1, brush->m_tip_flipy ? -1.f : 1.f) *
|
||||
glm::vec2((brush->m_tip_aspect <= 0.5 ? brush->m_tip_aspect * 2.f : 1.f),
|
||||
(brush->m_tip_aspect > 0.5 ? 1.f - (brush->m_tip_aspect - .5f) * 2.f : 1.f));
|
||||
glm::vec2 tip_offset = glm::vec2(0);
|
||||
auto tip_color = glm::vec4(glm::vec3(brush->m_tip_color), 1.f);
|
||||
if (Canvas::I->m_current_stroke)
|
||||
{
|
||||
const auto& s = Canvas::I->m_current_stroke->m_prev_sample;
|
||||
if (s.size > 0.f)
|
||||
{
|
||||
tip_scale = App::I->zoom * (brush->m_tip_size * tip_scale_fix) * s.scale;
|
||||
tip_angle = s.angle;
|
||||
tip_offset = s.pos - s.origin;
|
||||
tip_color = glm::vec4(s.col, s.flow);
|
||||
}
|
||||
}
|
||||
glm::u8vec4 pixel;
|
||||
std::int32_t fb_width = static_cast<std::int32_t>(App::I->width);
|
||||
std::int32_t fb_height = static_cast<std::int32_t>(App::I->height);
|
||||
if (node->m_density != 1.f)
|
||||
{
|
||||
fb_width = node->m_rtt.getWidth();
|
||||
fb_height = node->m_rtt.getHeight();
|
||||
}
|
||||
read_canvas_mode_pixel(
|
||||
static_cast<std::int32_t>((pos.x / App::I->width) * fb_width),
|
||||
static_cast<std::int32_t>(((App::I->height - pos.y - 1) / App::I->height) * fb_height),
|
||||
pixel);
|
||||
bool outline = glm::min(tip_scale.x, tip_scale.y) < 20 || m_resizing ? false : m_draw_outline;
|
||||
pp::panopainter::setup_legacy_vr_stroke_preview_shader({
|
||||
.texture_slot = 0,
|
||||
.alpha = brush->m_tip_flow * brush->m_tip_opacity,
|
||||
.draw_outline = outline,
|
||||
.color = outline ? glm::vec4(1.f - glm::vec3(pixel) / 255.f, 1.f) : tip_color,
|
||||
.mvp = glm::scale(glm::vec3(1, -1, 1)) *
|
||||
ortho *
|
||||
glm::translate(glm::vec3(pos + tip_offset, 0)) *
|
||||
glm::eulerAngleZ(tip_angle) *
|
||||
glm::scale(glm::vec3(tip_scale, 1)),
|
||||
});
|
||||
const bool blend = query_canvas_mode_capability(pp::renderer::gl::blend_state());
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), true);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
auto& tex = *brush->m_tip_texture;
|
||||
tex.bind();
|
||||
Canvas::I->m_sampler_brush.bind(0);
|
||||
Canvas::I->m_plane.draw_fill();
|
||||
tex.unbind();
|
||||
if (!blend) apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModePen::leave(kCanvasMode next)
|
||||
{
|
||||
}
|
||||
|
||||
void CanvasModePen::enter(kCanvasMode prev)
|
||||
{
|
||||
m_cur_pos = Canvas::I->m_cur_pos;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
m_draw_tip = App::I->draws_canvas_tip_for_input(me->m_source, me->m_type);
|
||||
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
|
||||
return;
|
||||
switch (me->m_type)
|
||||
{
|
||||
case kEventType::MouseDownL:
|
||||
node->mouse_capture();
|
||||
m_dragging = true;
|
||||
m_drag_start = loc;
|
||||
m_drag_pos = loc;
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
if (m_dragging)
|
||||
{
|
||||
App::I->render_task_async([=]
|
||||
{
|
||||
Canvas::I->stroke_start({ m_drag_start, 0 }, 1.f);
|
||||
Canvas::I->stroke_update({ m_drag_pos, 0 }, 1.f);
|
||||
Canvas::I->stroke_draw();
|
||||
Canvas::I->stroke_end();
|
||||
});
|
||||
}
|
||||
m_dragging = false;
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (m_dragging)
|
||||
m_drag_pos = loc;
|
||||
m_cur_pos = loc;
|
||||
break;
|
||||
case kEventType::MouseCancel:
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
m_dragging = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModeLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
||||
{
|
||||
if (m_dragging)
|
||||
{
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = Canvas::I->m_current_brush->m_tip_color,
|
||||
.mvp = ortho,
|
||||
});
|
||||
static glm::vec4 AB[2];
|
||||
AB[0] = { m_drag_start, 0, 1 };
|
||||
AB[1] = { m_drag_pos, 0, 1 };
|
||||
AB[0].y = Canvas::I->m_box.w - AB[0].y - 1; // invert Y
|
||||
AB[1].y = Canvas::I->m_box.w - AB[1].y - 1; // invert Y
|
||||
m_line.update_vertices(AB);
|
||||
m_line.draw_stroke();
|
||||
}
|
||||
else if (m_draw_tip)
|
||||
{
|
||||
const auto& brush = Canvas::I->m_current_brush;
|
||||
float tip_scale_fix = 1.f / glm::tan(glm::radians(Canvas::I->m_cam_fov * 0.5f));
|
||||
float tip_angle = brush->m_tip_angle * (float)(M_PI * 2.0);
|
||||
glm::vec2 tip_scale = App::I->zoom * brush->m_tip_scale *
|
||||
glm::vec2(brush->m_tip_size * tip_scale_fix) *
|
||||
glm::vec2(brush->m_tip_flipx ? -1 : 1, brush->m_tip_flipy ? -1.f : 1.f) *
|
||||
glm::vec2((brush->m_tip_aspect <= 0.5 ? brush->m_tip_aspect * 2.f : 1.f),
|
||||
(brush->m_tip_aspect > 0.5 ? 1.f - (brush->m_tip_aspect - .5f) * 2.f : 1.f));
|
||||
auto tip_color = glm::vec4(glm::vec3(brush->m_tip_color), 1.f);
|
||||
pp::panopainter::setup_legacy_vr_stroke_preview_shader({
|
||||
.texture_slot = 0,
|
||||
.alpha = brush->m_tip_flow * brush->m_tip_opacity,
|
||||
.draw_outline = false,
|
||||
.color = tip_color,
|
||||
.mvp = glm::scale(glm::vec3(1, -1, 1)) *
|
||||
ortho *
|
||||
glm::translate(glm::vec3(m_cur_pos, 0)) *
|
||||
glm::eulerAngleZ(tip_angle) *
|
||||
glm::scale(glm::vec3(tip_scale, 1)),
|
||||
});
|
||||
const bool blend = query_canvas_mode_capability(pp::renderer::gl::blend_state());
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), true);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
auto& tex = *brush->m_tip_texture;
|
||||
tex.bind();
|
||||
Canvas::I->m_sampler_brush.bind(0);
|
||||
Canvas::I->m_plane.draw_fill();
|
||||
tex.unbind();
|
||||
if (!blend) apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModeLine::init()
|
||||
{
|
||||
m_line.create();
|
||||
}
|
||||
|
||||
void CanvasModeLine::enter(kCanvasMode prev)
|
||||
{
|
||||
m_cur_pos = Canvas::I->m_cur_pos;
|
||||
}
|
||||
|
||||
void CanvasModeLine::leave(kCanvasMode next)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
|
||||
258
src/legacy_canvas_layer_services.cpp
Normal file
258
src/legacy_canvas_layer_services.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
#include "pch.h"
|
||||
#include "canvas.h"
|
||||
#include "app.h"
|
||||
#include "legacy_canvas_stroke_composite_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
GLenum blend_state()
|
||||
{
|
||||
return static_cast<GLenum>(pp::renderer::gl::blend_state());
|
||||
}
|
||||
|
||||
void set_active_texture_unit(std::uint32_t unit_index)
|
||||
{
|
||||
pp::legacy::ui_gl::activate_texture_unit(unit_index, "Canvas");
|
||||
}
|
||||
|
||||
void apply_canvas_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
|
||||
{
|
||||
pp::legacy::ui_gl::apply_viewport(x, y, width, height, "Canvas");
|
||||
}
|
||||
|
||||
void apply_canvas_capability(std::uint32_t state, bool enabled)
|
||||
{
|
||||
pp::legacy::ui_gl::set_capability(state, enabled, "Canvas");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index
|
||||
{
|
||||
m_dirty = false;
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
apply_canvas_viewport(0, 0, m_width, m_height);
|
||||
apply_canvas_capability(blend_state(), false);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (!m_layers[source_idx]->face(i))
|
||||
continue;
|
||||
|
||||
m_layers[dest_idx]->rtt(i).bindFramebuffer();
|
||||
|
||||
auto& lbox = m_layers[dest_idx]->box(i);
|
||||
lbox = glm::vec4(
|
||||
glm::min(xy(m_layers[source_idx]->box(i)), xy(lbox)),
|
||||
glm::max(zw(m_layers[source_idx]->box(i)), zw(lbox))
|
||||
);
|
||||
m_layers[dest_idx]->face(i) = true;
|
||||
|
||||
set_active_texture_unit(0);
|
||||
m_tex2[i].bind();
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, m_width, m_height);
|
||||
m_tex2[i].unbind();
|
||||
|
||||
m_sampler.bind(0);
|
||||
m_sampler_nearest.bind(1);
|
||||
{
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = m_size,
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
.layer_alpha = m_layers[source_idx]->m_opacity,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = m_layers[source_idx]->m_blend_mode,
|
||||
.use_dual = false,
|
||||
.dual_alpha = 0.0f,
|
||||
.use_pattern = false,
|
||||
});
|
||||
|
||||
set_active_texture_unit(0);
|
||||
m_tex2[i].bind();
|
||||
set_active_texture_unit(1);
|
||||
m_layers[source_idx]->rtt(i).bindTexture();
|
||||
m_plane.draw_fill();
|
||||
m_layers[source_idx]->rtt(i).unbindTexture();
|
||||
set_active_texture_unit(0);
|
||||
m_tex2[i].unbind();
|
||||
}
|
||||
|
||||
m_layers[dest_idx]->rtt(i).unbindFramebuffer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Canvas::flood_fill(int layer, int plane, std::vector<glm::ivec2> pos, FloodData& plane_data,
|
||||
float threshold, glm::vec4 dest_color, std::unique_ptr<glm::vec4>& source_color)
|
||||
{
|
||||
struct adj_t
|
||||
{
|
||||
int plane;
|
||||
bool flipx;
|
||||
bool flipy;
|
||||
bool flipcoord;
|
||||
adj_t(int plane, bool flipx, bool flipy, int flipcoord) :
|
||||
plane(plane), flipx(flipx), flipy(flipy), flipcoord(flipcoord) { }
|
||||
glm::ivec2 compute(glm::ivec2 p, glm::ivec2 sz) const
|
||||
{
|
||||
glm::ivec2 ret;
|
||||
ret[flipcoord] = flipx ? sz.x - p.x : p.x;
|
||||
ret[1 - flipcoord] = flipy ? sz.y - p.y : p.y;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
LOG("flood_fill plane %d", plane);
|
||||
|
||||
auto& rtt = m_layers[layer]->rtt(plane);
|
||||
auto sz = rtt.getSize();
|
||||
|
||||
if (!plane_data.mask[plane])
|
||||
{
|
||||
plane_data.mask[plane] = std::make_unique<bool[]>((size_t)sz.x * sz.y);
|
||||
plane_data.rgb[plane] = std::unique_ptr<glm::u8vec4[]>(
|
||||
reinterpret_cast<glm::u8vec4*>(m_layers[layer]->rtt(plane).readTextureData()));
|
||||
plane_data.bb[plane] = { sz.x, sz.y, 0, 0 };
|
||||
plane_data.dirty[plane] = false;
|
||||
plane_data.layer = m_layers[layer];
|
||||
}
|
||||
auto& mask = plane_data.mask[plane];
|
||||
auto& rgb = plane_data.rgb[plane];
|
||||
|
||||
if (!source_color)
|
||||
source_color = std::make_unique<glm::vec4>(rgb[pos.back().y * sz.x + pos.back().x]);
|
||||
const glm::vec4 c = *source_color;
|
||||
|
||||
std::array<std::vector<glm::ivec2>, 4> edges;
|
||||
static const std::array<adj_t, 4> adj[6] = {
|
||||
{
|
||||
adj_t(3, 1, 0, 0),
|
||||
adj_t(4, 1, 1, 0),
|
||||
adj_t(1, 0, 0, 0),
|
||||
adj_t(5, 1, 0, 0),
|
||||
},
|
||||
{
|
||||
adj_t(0, 1, 0, 0),
|
||||
adj_t(4, 1, 0, 1),
|
||||
adj_t(2, 0, 0, 0),
|
||||
adj_t(5, 0, 0, 1),
|
||||
},
|
||||
{
|
||||
adj_t(1, 1, 0, 0),
|
||||
adj_t(4, 0, 0, 0),
|
||||
adj_t(3, 0, 0, 0),
|
||||
adj_t(5, 0, 1, 0),
|
||||
},
|
||||
{
|
||||
adj_t(2, 1, 0, 0),
|
||||
adj_t(4, 0, 1, 1),
|
||||
adj_t(0, 0, 0, 0),
|
||||
adj_t(5, 1, 1, 1),
|
||||
},
|
||||
{
|
||||
adj_t(1, 1, 1, 1),
|
||||
adj_t(0, 1, 1, 0),
|
||||
adj_t(3, 1, 0, 1),
|
||||
adj_t(2, 0, 1, 0),
|
||||
},
|
||||
{
|
||||
adj_t(1, 0, 0, 1),
|
||||
adj_t(2, 0, 0, 0),
|
||||
adj_t(3, 0, 1, 1),
|
||||
adj_t(0, 1, 0, 0),
|
||||
},
|
||||
};
|
||||
|
||||
auto test = [&](glm::ivec2 p, bool set_color) -> bool
|
||||
{
|
||||
int i = p.y * sz.x + p.x;
|
||||
if (p.x < 0)
|
||||
{
|
||||
edges[0].push_back(adj[plane][0].compute({ -p.x, p.y }, sz));
|
||||
return false;
|
||||
}
|
||||
else if (p.x >= sz.x)
|
||||
{
|
||||
edges[2].push_back(adj[plane][2].compute({ sz.x - p.x + 1, p.y }, sz));
|
||||
return false;
|
||||
}
|
||||
else if (p.y < 0)
|
||||
{
|
||||
edges[3].push_back(adj[plane][3].compute({ p.x, -p.y }, sz));
|
||||
return false;
|
||||
}
|
||||
else if (p.y >= sz.y)
|
||||
{
|
||||
edges[1].push_back(adj[plane][1].compute({ p.x, sz.y - p.y + 1 }, sz));
|
||||
return false;
|
||||
}
|
||||
if (!mask[i])
|
||||
{
|
||||
if (c.a == 0 && glm::abs(rgb[i].a - c.a) < threshold ||
|
||||
c.a > 0 && rgb[i].a > 0 && glm::distance(glm::vec3(c), glm::vec3(rgb[i])) < threshold)
|
||||
{
|
||||
if (set_color)
|
||||
{
|
||||
mask[i] = true;
|
||||
rgb[i] = dest_color * 255.f;
|
||||
plane_data.dirty[plane] = true;
|
||||
glm::vec2 bb_min = glm::min((glm::vec2)p, xy(plane_data.bb[plane]));
|
||||
glm::vec2 bb_max = glm::max((glm::vec2)p + glm::vec2(1), zw(plane_data.bb[plane]));
|
||||
plane_data.bb[plane] = { bb_min, bb_max };
|
||||
}
|
||||
pos.push_back(p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
while (!pos.empty())
|
||||
{
|
||||
auto p = pos.back();
|
||||
pos.pop_back();
|
||||
if (!test(p + glm::ivec2(0, 0), true))
|
||||
continue;
|
||||
test(p + glm::ivec2(-1, 0), false);
|
||||
test(p + glm::ivec2(1, 0), false);
|
||||
test(p + glm::ivec2(0, 1), false);
|
||||
test(p + glm::ivec2(0, -1), false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!edges[i].empty())
|
||||
{
|
||||
flood_fill(layer, adj[plane][i].plane, edges[i], plane_data, threshold, dest_color, source_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::FloodData::apply()
|
||||
{
|
||||
for (int plane = 0; plane < 6; plane++)
|
||||
{
|
||||
if (!dirty[plane])
|
||||
continue;
|
||||
auto& rtt = layer->rtt(plane);
|
||||
App::I->render_task([&]
|
||||
{
|
||||
rtt.updateRgba8(0, 0, rtt.getWidth(), rtt.getHeight(), rgb[plane].get());
|
||||
});
|
||||
layer->face(plane) = true;
|
||||
layer->box(plane) = box_union(layer->box(plane), bb[plane]);
|
||||
}
|
||||
Canvas::I->m_unsaved = true;
|
||||
}
|
||||
315
src/legacy_canvas_mode_pen_line.cpp
Normal file
315
src/legacy_canvas_mode_pen_line.cpp
Normal file
@@ -0,0 +1,315 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "canvas_modes.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "canvas.h"
|
||||
#include "legacy_canvas_mode_helpers.h"
|
||||
#include "legacy_canvas_stroke_preview_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
|
||||
using pp::legacy_canvas_mode::apply_canvas_mode_capability;
|
||||
using pp::legacy_canvas_mode::query_canvas_mode_capability;
|
||||
using pp::legacy_canvas_mode::read_canvas_mode_pixel;
|
||||
using pp::legacy_canvas_mode::set_canvas_mode_active_texture_unit;
|
||||
|
||||
void CanvasModePen::on_GestureEvent(GestureEvent* ge)
|
||||
{
|
||||
m_draw_tip = false;
|
||||
}
|
||||
|
||||
void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
m_draw_tip = App::I->draws_canvas_tip_for_input(me->m_source, me->m_type);
|
||||
m_draw_outline = true;
|
||||
|
||||
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
|
||||
return;
|
||||
|
||||
me->m_pressure = App::I->adjust_canvas_input_pressure(me->m_pressure);
|
||||
|
||||
switch (me->m_type)
|
||||
{
|
||||
case kEventType::MouseDownL:
|
||||
if (!App::I->keys[(int)kKey::KeySpacebar])
|
||||
{
|
||||
if (App::I->keys[(int)kKey::KeyAlt] || m_picking)
|
||||
{
|
||||
m_picking = true;
|
||||
Canvas::I->pick_start();
|
||||
glm::vec4 pix = Canvas::I->pick_get(loc);
|
||||
Canvas::I->m_current_brush->m_tip_color = pix;
|
||||
App::I->brush_update(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
App::I->render_task_async([loc, pr = me->m_pressure]
|
||||
{
|
||||
Canvas::I->stroke_start({ loc, 0 }, pr);
|
||||
});
|
||||
m_drawing = true;
|
||||
}
|
||||
m_dragging = true;
|
||||
node->mouse_capture();
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
if (m_dragging && !m_picking)
|
||||
{
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
App::I->render_task_async([] {
|
||||
Canvas::I->stroke_end();
|
||||
});
|
||||
}
|
||||
if (m_dragging && m_picking)
|
||||
{
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
glm::vec4 pix = Canvas::I->pick_get(loc);
|
||||
Canvas::I->m_current_brush->m_tip_color = pix;
|
||||
App::I->brush_update(true, false);
|
||||
Canvas::I->pick_end();
|
||||
}
|
||||
m_drawing = false;
|
||||
m_dragging = false;
|
||||
m_picking = false;
|
||||
break;
|
||||
case kEventType::MouseDownR:
|
||||
if (App::I->keys[(int)kKey::KeyAlt])
|
||||
{
|
||||
m_resizing = true;
|
||||
m_dragging = true;
|
||||
m_size_pos_start = m_cur_pos;
|
||||
auto curve = App::I->stroke->m_curves[App::I->stroke->m_tip_size];
|
||||
m_size_value_start = curve.to_slider(Canvas::I->m_current_brush->m_tip_size);
|
||||
node->mouse_capture();
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseUpR:
|
||||
if (m_dragging && m_resizing)
|
||||
{
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
m_dragging = false;
|
||||
m_resizing = false;
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (m_dragging && !m_picking && !m_resizing)
|
||||
{
|
||||
App::I->render_task_async([loc, pr=me->m_pressure]
|
||||
{
|
||||
Canvas::I->stroke_update({ loc, 0 }, pr);
|
||||
});
|
||||
}
|
||||
if (m_dragging && m_picking)
|
||||
{
|
||||
glm::vec4 pix = Canvas::I->pick_get(loc);
|
||||
Canvas::I->m_current_brush->m_tip_color = pix;
|
||||
App::I->brush_update(true, false);
|
||||
}
|
||||
if (m_dragging && m_resizing)
|
||||
{
|
||||
auto diff = m_cur_pos - m_size_pos_start;
|
||||
auto curve = App::I->stroke->m_curves[App::I->stroke->m_tip_size];
|
||||
Canvas::I->m_current_brush->m_tip_size = glm::max(curve.to_value(m_size_value_start + diff.x * 0.001f), 0.001f);
|
||||
App::I->brush_update(true, true);
|
||||
}
|
||||
m_cur_pos = loc;
|
||||
break;
|
||||
case kEventType::MouseCancel:
|
||||
if (m_dragging)
|
||||
{
|
||||
App::I->render_task_async([] {
|
||||
Canvas::I->stroke_cancel();
|
||||
});
|
||||
m_dragging = false;
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
}
|
||||
if (m_picking)
|
||||
m_picking = false;
|
||||
if (m_resizing)
|
||||
m_resizing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
||||
{
|
||||
if (m_draw_tip)
|
||||
{
|
||||
const auto& brush = Canvas::I->m_current_brush;
|
||||
auto pos = m_resizing ? m_size_pos_start : m_cur_pos;
|
||||
//if (App::I->keys[(int)kKey::KeyAlt] && !m_resizing)
|
||||
// pos.x = pos.x - brush->m_tip_size * .5f;
|
||||
float tip_scale_fix = 1.f / glm::tan(glm::radians(Canvas::I->m_cam_fov * 0.5f));
|
||||
float tip_angle = brush->m_tip_angle * (float)(M_PI * 2.0);
|
||||
glm::vec2 tip_scale = App::I->zoom * brush->m_tip_scale *
|
||||
glm::vec2(brush->m_tip_size * tip_scale_fix) *
|
||||
glm::vec2(brush->m_tip_flipx ? -1 : 1, brush->m_tip_flipy ? -1.f : 1.f) *
|
||||
glm::vec2((brush->m_tip_aspect <= 0.5 ? brush->m_tip_aspect * 2.f : 1.f),
|
||||
(brush->m_tip_aspect > 0.5 ? 1.f - (brush->m_tip_aspect - .5f) * 2.f : 1.f));
|
||||
glm::vec2 tip_offset = glm::vec2(0);
|
||||
auto tip_color = glm::vec4(glm::vec3(brush->m_tip_color), 1.f);
|
||||
if (Canvas::I->m_current_stroke)
|
||||
{
|
||||
const auto& s = Canvas::I->m_current_stroke->m_prev_sample;
|
||||
if (s.size > 0.f)
|
||||
{
|
||||
tip_scale = App::I->zoom * (brush->m_tip_size * tip_scale_fix) * s.scale;
|
||||
tip_angle = s.angle;
|
||||
tip_offset = s.pos - s.origin;
|
||||
tip_color = glm::vec4(s.col, s.flow);
|
||||
}
|
||||
}
|
||||
glm::u8vec4 pixel;
|
||||
std::int32_t fb_width = static_cast<std::int32_t>(App::I->width);
|
||||
std::int32_t fb_height = static_cast<std::int32_t>(App::I->height);
|
||||
if (node->m_density != 1.f)
|
||||
{
|
||||
fb_width = node->m_rtt.getWidth();
|
||||
fb_height = node->m_rtt.getHeight();
|
||||
}
|
||||
read_canvas_mode_pixel(
|
||||
static_cast<std::int32_t>((pos.x / App::I->width) * fb_width),
|
||||
static_cast<std::int32_t>(((App::I->height - pos.y - 1) / App::I->height) * fb_height),
|
||||
pixel);
|
||||
bool outline = glm::min(tip_scale.x, tip_scale.y) < 20 || m_resizing ? false : m_draw_outline;
|
||||
pp::panopainter::setup_legacy_vr_stroke_preview_shader({
|
||||
.texture_slot = 0,
|
||||
.alpha = brush->m_tip_flow * brush->m_tip_opacity,
|
||||
.draw_outline = outline,
|
||||
.color = outline ? glm::vec4(1.f - glm::vec3(pixel) / 255.f, 1.f) : tip_color,
|
||||
.mvp = glm::scale(glm::vec3(1, -1, 1)) *
|
||||
ortho *
|
||||
glm::translate(glm::vec3(pos + tip_offset, 0)) *
|
||||
glm::eulerAngleZ(tip_angle) *
|
||||
glm::scale(glm::vec3(tip_scale, 1)),
|
||||
});
|
||||
const bool blend = query_canvas_mode_capability(pp::renderer::gl::blend_state());
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), true);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
auto& tex = *brush->m_tip_texture;
|
||||
tex.bind();
|
||||
Canvas::I->m_sampler_brush.bind(0);
|
||||
Canvas::I->m_plane.draw_fill();
|
||||
tex.unbind();
|
||||
if (!blend) apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModePen::leave(kCanvasMode next)
|
||||
{
|
||||
}
|
||||
|
||||
void CanvasModePen::enter(kCanvasMode prev)
|
||||
{
|
||||
m_cur_pos = Canvas::I->m_cur_pos;
|
||||
}
|
||||
|
||||
void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
m_draw_tip = App::I->draws_canvas_tip_for_input(me->m_source, me->m_type);
|
||||
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
|
||||
return;
|
||||
switch (me->m_type)
|
||||
{
|
||||
case kEventType::MouseDownL:
|
||||
node->mouse_capture();
|
||||
m_dragging = true;
|
||||
m_drag_start = loc;
|
||||
m_drag_pos = loc;
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
if (m_dragging)
|
||||
{
|
||||
App::I->render_task_async([=]
|
||||
{
|
||||
Canvas::I->stroke_start({ m_drag_start, 0 }, 1.f);
|
||||
Canvas::I->stroke_update({ m_drag_pos, 0 }, 1.f);
|
||||
Canvas::I->stroke_draw();
|
||||
Canvas::I->stroke_end();
|
||||
});
|
||||
}
|
||||
m_dragging = false;
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (m_dragging)
|
||||
m_drag_pos = loc;
|
||||
m_cur_pos = loc;
|
||||
break;
|
||||
case kEventType::MouseCancel:
|
||||
pp::panopainter::release_legacy_mouse_capture(*node);
|
||||
m_dragging = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModeLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
||||
{
|
||||
if (m_dragging)
|
||||
{
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = Canvas::I->m_current_brush->m_tip_color,
|
||||
.mvp = ortho,
|
||||
});
|
||||
static glm::vec4 AB[2];
|
||||
AB[0] = { m_drag_start, 0, 1 };
|
||||
AB[1] = { m_drag_pos, 0, 1 };
|
||||
AB[0].y = Canvas::I->m_box.w - AB[0].y - 1; // invert Y
|
||||
AB[1].y = Canvas::I->m_box.w - AB[1].y - 1; // invert Y
|
||||
m_line.update_vertices(AB);
|
||||
m_line.draw_stroke();
|
||||
}
|
||||
else if (m_draw_tip)
|
||||
{
|
||||
const auto& brush = Canvas::I->m_current_brush;
|
||||
float tip_scale_fix = 1.f / glm::tan(glm::radians(Canvas::I->m_cam_fov * 0.5f));
|
||||
float tip_angle = brush->m_tip_angle * (float)(M_PI * 2.0);
|
||||
glm::vec2 tip_scale = App::I->zoom * brush->m_tip_scale *
|
||||
glm::vec2(brush->m_tip_size * tip_scale_fix) *
|
||||
glm::vec2(brush->m_tip_flipx ? -1 : 1, brush->m_tip_flipy ? -1.f : 1.f) *
|
||||
glm::vec2((brush->m_tip_aspect <= 0.5 ? brush->m_tip_aspect * 2.f : 1.f),
|
||||
(brush->m_tip_aspect > 0.5 ? 1.f - (brush->m_tip_aspect - .5f) * 2.f : 1.f));
|
||||
auto tip_color = glm::vec4(glm::vec3(brush->m_tip_color), 1.f);
|
||||
pp::panopainter::setup_legacy_vr_stroke_preview_shader({
|
||||
.texture_slot = 0,
|
||||
.alpha = brush->m_tip_flow * brush->m_tip_opacity,
|
||||
.draw_outline = false,
|
||||
.color = tip_color,
|
||||
.mvp = glm::scale(glm::vec3(1, -1, 1)) *
|
||||
ortho *
|
||||
glm::translate(glm::vec3(m_cur_pos, 0)) *
|
||||
glm::eulerAngleZ(tip_angle) *
|
||||
glm::scale(glm::vec3(tip_scale, 1)),
|
||||
});
|
||||
const bool blend = query_canvas_mode_capability(pp::renderer::gl::blend_state());
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), true);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
auto& tex = *brush->m_tip_texture;
|
||||
tex.bind();
|
||||
Canvas::I->m_sampler_brush.bind(0);
|
||||
Canvas::I->m_plane.draw_fill();
|
||||
tex.unbind();
|
||||
if (!blend) apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModeLine::init()
|
||||
{
|
||||
m_line.create();
|
||||
}
|
||||
|
||||
void CanvasModeLine::enter(kCanvasMode prev)
|
||||
{
|
||||
m_cur_pos = Canvas::I->m_cur_pos;
|
||||
}
|
||||
|
||||
void CanvasModeLine::leave(kCanvasMode next)
|
||||
{
|
||||
}
|
||||
207
src/legacy_ui_node_attributes.cpp
Normal file
207
src/legacy_ui_node_attributes.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "pch.h"
|
||||
#include "legacy_ui_node_attributes.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "node.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
void parse_legacy_ui_node_attribute(Node& node, kAttribute ka, const tinyxml2::XMLAttribute* attr)
|
||||
{
|
||||
switch (ka)
|
||||
{
|
||||
case kAttribute::id:
|
||||
node.m_nodeID_s = attr->Value();
|
||||
node.m_nodeID = const_hash(attr->Value());
|
||||
break;
|
||||
case kAttribute::Width:
|
||||
if (strcmp(attr->Value(), "auto") == 0)
|
||||
{
|
||||
YGNodeStyleSetWidth(node.y_node, YGUndefined);
|
||||
YGNodeStyleSetWidthPercent(node.y_node, YGUndefined);
|
||||
node.auto_width = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strchr(attr->Value(), '%'))
|
||||
YGNodeStyleSetWidthPercent(node.y_node, attr->FloatValue());
|
||||
else
|
||||
YGNodeStyleSetWidth(node.y_node, attr->FloatValue());
|
||||
node.auto_width = false;
|
||||
}
|
||||
break;
|
||||
case kAttribute::MinWidth:
|
||||
YGNodeStyleSetMinWidth(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::MaxWidth:
|
||||
YGNodeStyleSetMaxWidth(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Height:
|
||||
if (strcmp(attr->Value(), "auto") == 0)
|
||||
{
|
||||
YGNodeStyleSetHeight(node.y_node, YGUndefined);
|
||||
YGNodeStyleSetHeightPercent(node.y_node, YGUndefined);
|
||||
node.auto_height = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strchr(attr->Value(), '%'))
|
||||
YGNodeStyleSetHeightPercent(node.y_node, attr->FloatValue());
|
||||
else
|
||||
YGNodeStyleSetHeight(node.y_node, attr->FloatValue());
|
||||
node.auto_height = false;
|
||||
}
|
||||
break;
|
||||
case kAttribute::MinHeight:
|
||||
YGNodeStyleSetMinHeight(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::MaxHeight:
|
||||
YGNodeStyleSetMaxHeight(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Grow:
|
||||
YGNodeStyleSetFlexGrow(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Shrink:
|
||||
YGNodeStyleSetFlexShrink(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::FlexDir:
|
||||
{
|
||||
YGFlexDirection dir = YGFlexDirectionRow;
|
||||
if (strcmp("col", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionColumn;
|
||||
else if (strcmp("col-reverse", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionColumnReverse;
|
||||
else if (strcmp("row", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionRow;
|
||||
else if (strcmp("row-reverse", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionRowReverse;
|
||||
YGNodeStyleSetFlexDirection(node.y_node, dir);
|
||||
break;
|
||||
}
|
||||
case kAttribute::FlexWrap:
|
||||
YGNodeStyleSetFlexWrap(node.y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap);
|
||||
break;
|
||||
case kAttribute::Justify:
|
||||
{
|
||||
YGJustify v = YGJustifyFlexStart;
|
||||
if (strcmp("center", attr->Value()) == 0)
|
||||
v = YGJustifyCenter;
|
||||
else if (strcmp("flex-start", attr->Value()) == 0)
|
||||
v = YGJustifyFlexStart;
|
||||
else if (strcmp("flex-end", attr->Value()) == 0)
|
||||
v = YGJustifyFlexEnd;
|
||||
else if (strcmp("space-around", attr->Value()) == 0)
|
||||
v = YGJustifySpaceAround;
|
||||
else if (strcmp("space-between", attr->Value()) == 0)
|
||||
v = YGJustifySpaceBetween;
|
||||
YGNodeStyleSetJustifyContent(node.y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Align:
|
||||
{
|
||||
YGAlign v = YGAlignStretch;
|
||||
if (strcmp("stretch", attr->Value()) == 0)
|
||||
v = YGAlignStretch;
|
||||
else if (strcmp("flex-start", attr->Value()) == 0)
|
||||
v = YGAlignFlexStart;
|
||||
else if (strcmp("flex-end", attr->Value()) == 0)
|
||||
v = YGAlignFlexEnd;
|
||||
else if (strcmp("center", attr->Value()) == 0)
|
||||
v = YGAlignCenter;
|
||||
YGNodeStyleSetAlignItems(node.y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Positioning:
|
||||
{
|
||||
YGPositionType v = YGPositionTypeRelative;
|
||||
if (strcmp("relative", attr->Value()) == 0)
|
||||
v = YGPositionTypeRelative;
|
||||
else if (strcmp("absolute", attr->Value()) == 0)
|
||||
v = YGPositionTypeAbsolute;
|
||||
YGNodeStyleSetPositionType(node.y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Position:
|
||||
{
|
||||
glm::vec4 v;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
|
||||
if (n == 2)
|
||||
{
|
||||
YGNodeStyleSetPosition(node.y_node, YGEdgeLeft, v.x);
|
||||
YGNodeStyleSetPosition(node.y_node, YGEdgeTop, v.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeLeft, v.x);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeTop, v.y);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeRight, v.z);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeBottom, v.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kAttribute::Padding:
|
||||
{
|
||||
glm::vec4 pad;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w);
|
||||
if (n == 1)
|
||||
{
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeRight, pad.x);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeBottom, pad.x);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeLeft, pad.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeRight, pad.y);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeBottom, pad.z);
|
||||
YGNodeStyleSetPadding(node.y_node, YGEdgeLeft, pad.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kAttribute::Margin:
|
||||
{
|
||||
glm::vec4 pad;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w);
|
||||
if (n == 1)
|
||||
{
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeRight, pad.x);
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeBottom, pad.x);
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeLeft, pad.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeRight, pad.y);
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeBottom, pad.z);
|
||||
YGNodeStyleSetMargin(node.y_node, YGEdgeLeft, pad.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kAttribute::FloodEvents:
|
||||
node.m_flood_events = attr->BoolValue();
|
||||
break;
|
||||
case kAttribute::MouseCapture:
|
||||
node.m_force_mouse_capture = attr->BoolValue();
|
||||
break;
|
||||
case kAttribute::AspectRatio:
|
||||
YGNodeStyleSetAspectRatio(node.y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::RTL:
|
||||
if (strcmp("rtl", attr->Value()) == 0)
|
||||
node.SetRTL(YGDirectionRTL);
|
||||
else if (strcmp("ltr", attr->Value()) == 0)
|
||||
node.SetRTL(YGDirectionLTR);
|
||||
else if (strcmp("inherit", attr->Value()) == 0)
|
||||
node.SetRTL(YGDirectionInherit);
|
||||
else
|
||||
{
|
||||
LOG("Attribute %s for RTL unrecognized", attr->Value());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
17
src/legacy_ui_node_attributes.h
Normal file
17
src/legacy_ui_node_attributes.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace tinyxml2 {
|
||||
class XMLAttribute;
|
||||
}
|
||||
|
||||
class Node;
|
||||
|
||||
enum class kAttribute : uint16_t;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
void parse_legacy_ui_node_attribute(Node& node, kAttribute ka, const tinyxml2::XMLAttribute* attr);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
196
src/node.cpp
196
src/node.cpp
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "log.h"
|
||||
#include "legacy_ui_node_attributes.h"
|
||||
#include "legacy_ui_node_event.h"
|
||||
#include "legacy_ui_node_loader.h"
|
||||
#include "node.h"
|
||||
@@ -832,200 +833,7 @@ YGDirection Node::GetRTL()
|
||||
|
||||
void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
|
||||
{
|
||||
switch (ka)
|
||||
{
|
||||
case kAttribute::id:
|
||||
m_nodeID_s = attr->Value();
|
||||
m_nodeID = const_hash(attr->Value());
|
||||
break;
|
||||
case kAttribute::Width:
|
||||
if (strcmp(attr->Value(), "auto") == 0)
|
||||
{
|
||||
YGNodeStyleSetWidth(y_node, YGUndefined);
|
||||
YGNodeStyleSetWidthPercent(y_node, YGUndefined);
|
||||
auto_width = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strchr(attr->Value(), '%'))
|
||||
YGNodeStyleSetWidthPercent(y_node, attr->FloatValue());
|
||||
else
|
||||
YGNodeStyleSetWidth(y_node, attr->FloatValue());
|
||||
auto_width = false;
|
||||
}
|
||||
break;
|
||||
case kAttribute::MinWidth:
|
||||
YGNodeStyleSetMinWidth(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::MaxWidth:
|
||||
YGNodeStyleSetMaxWidth(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Height:
|
||||
if (strcmp(attr->Value(), "auto") == 0)
|
||||
{
|
||||
YGNodeStyleSetHeight(y_node, YGUndefined);
|
||||
YGNodeStyleSetHeightPercent(y_node, YGUndefined);
|
||||
auto_height = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strchr(attr->Value(), '%'))
|
||||
YGNodeStyleSetHeightPercent(y_node, attr->FloatValue());
|
||||
else
|
||||
YGNodeStyleSetHeight(y_node, attr->FloatValue());
|
||||
auto_height = false;
|
||||
}
|
||||
break;
|
||||
case kAttribute::MinHeight:
|
||||
YGNodeStyleSetMinHeight(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::MaxHeight:
|
||||
YGNodeStyleSetMaxHeight(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Grow:
|
||||
YGNodeStyleSetFlexGrow(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::Shrink:
|
||||
YGNodeStyleSetFlexShrink(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::FlexDir:
|
||||
{
|
||||
YGFlexDirection dir = YGFlexDirectionRow;
|
||||
if (strcmp("col", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionColumn;
|
||||
else if (strcmp("col-reverse", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionColumnReverse;
|
||||
else if (strcmp("row", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionRow;
|
||||
else if (strcmp("row-reverse", attr->Value()) == 0)
|
||||
dir = YGFlexDirectionRowReverse;
|
||||
YGNodeStyleSetFlexDirection(y_node, dir);
|
||||
break;
|
||||
}
|
||||
case kAttribute::FlexWrap:
|
||||
YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap);
|
||||
break;
|
||||
case kAttribute::Justify:
|
||||
{
|
||||
YGJustify v = YGJustifyFlexStart;
|
||||
if (strcmp("center", attr->Value()) == 0)
|
||||
v = YGJustifyCenter;
|
||||
else if (strcmp("flex-start", attr->Value()) == 0)
|
||||
v = YGJustifyFlexStart;
|
||||
else if (strcmp("flex-end", attr->Value()) == 0)
|
||||
v = YGJustifyFlexEnd;
|
||||
else if (strcmp("space-around", attr->Value()) == 0)
|
||||
v = YGJustifySpaceAround;
|
||||
else if (strcmp("space-between", attr->Value()) == 0)
|
||||
v = YGJustifySpaceBetween;
|
||||
YGNodeStyleSetJustifyContent(y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Align:
|
||||
{
|
||||
YGAlign v = YGAlignStretch;
|
||||
if (strcmp("stretch", attr->Value()) == 0)
|
||||
v = YGAlignStretch;
|
||||
else if (strcmp("flex-start", attr->Value()) == 0)
|
||||
v = YGAlignFlexStart;
|
||||
else if (strcmp("flex-end", attr->Value()) == 0)
|
||||
v = YGAlignFlexEnd;
|
||||
else if (strcmp("center", attr->Value()) == 0)
|
||||
v = YGAlignCenter;
|
||||
YGNodeStyleSetAlignItems(y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Positioning:
|
||||
{
|
||||
YGPositionType v = YGPositionTypeRelative;
|
||||
if (strcmp("relative", attr->Value()) == 0)
|
||||
v = YGPositionTypeRelative;
|
||||
else if (strcmp("absolute", attr->Value()) == 0)
|
||||
v = YGPositionTypeAbsolute;
|
||||
YGNodeStyleSetPositionType(y_node, v);
|
||||
break;
|
||||
}
|
||||
case kAttribute::Position:
|
||||
{
|
||||
glm::vec4 v;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
|
||||
if (n == 2)
|
||||
{
|
||||
YGNodeStyleSetPosition(y_node, YGEdgeLeft, v.x);
|
||||
YGNodeStyleSetPosition(y_node, YGEdgeTop, v.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeLeft, v.x);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeTop, v.y);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeRight, v.z);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeBottom, v.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kAttribute::Padding:
|
||||
{
|
||||
glm::vec4 pad;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w);
|
||||
if (n == 1)
|
||||
{
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.x);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.x);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeRight, pad.y);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeBottom, pad.z);
|
||||
YGNodeStyleSetPadding(y_node, YGEdgeLeft, pad.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kAttribute::Margin:
|
||||
{
|
||||
glm::vec4 pad;
|
||||
int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w);
|
||||
if (n == 1)
|
||||
{
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.x);
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.x);
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeTop, pad.x);
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeRight, pad.y);
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeBottom, pad.z);
|
||||
YGNodeStyleSetMargin(y_node, YGEdgeLeft, pad.w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kAttribute::FloodEvents:
|
||||
m_flood_events = attr->BoolValue();
|
||||
break;
|
||||
case kAttribute::MouseCapture:
|
||||
m_force_mouse_capture = attr->BoolValue();
|
||||
break;
|
||||
case kAttribute::AspectRatio:
|
||||
YGNodeStyleSetAspectRatio(y_node, attr->FloatValue());
|
||||
break;
|
||||
case kAttribute::RTL:
|
||||
if (strcmp("rtl", attr->Value()) == 0)
|
||||
SetRTL(YGDirectionRTL);
|
||||
else if (strcmp("ltr", attr->Value()) == 0)
|
||||
SetRTL(YGDirectionLTR);
|
||||
else if (strcmp("inherit", attr->Value()) == 0)
|
||||
SetRTL(YGDirectionInherit);
|
||||
else
|
||||
{
|
||||
LOG("Attribute %s for RTL unrecognized", attr->Value());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pp::panopainter::parse_legacy_ui_node_attribute(*this, ka, attr);
|
||||
}
|
||||
|
||||
void Node::load_internal(const tinyxml2::XMLElement* x_node, bool skip_children /*= false*/)
|
||||
|
||||
Reference in New Issue
Block a user