Files
panopainter/engine/app.cpp
2017-05-07 23:49:46 +01:00

923 lines
34 KiB
C++

#include "pch.h"
#include "log.h"
#include "app.h"
using namespace ui;
App App::I; // singleton
void App::create()
{
width = 800;
height = 500;
}
void App::clear()
{
glClearColor(.1f, .1f, .1f, 1.f);
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glClear(GL_COLOR_BUFFER_BIT);
}
void App::initShaders()
{
static const char* shader_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec4 pos;"
"in vec2 uvs;"
"out vec3 uv;"
"void main(){"
" uv = vec3(uvs, pos.w);"
" gl_Position = mvp * vec4(pos.xyz, 1.0);"
"}";
static const char* shader_f =
SHADER_VERSION
"uniform sampler2D tex;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"void main(){"
//" frag = texture(tex, uv.xy/uv.z);"
" frag = texture(tex, uv.xy);"
"}";
static const char* shader_uv_f =
SHADER_VERSION
"uniform sampler2D tex;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"void main(){"
" frag = vec4(uv.xy, 0.0, 1.0);"
"}";
// TEXTURE ALPHA
static const char* shader_alpha_f =
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform mediump float alpha;\n"
"in mediump vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" frag = texture(tex, uv.xy) * vec4(1,1,1,alpha);\n"
"}\n";
// TEXTURE ATLAS
static const char* shader_atlas_v =
SHADER_VERSION
"uniform mat4 mvp;"
"uniform vec2 tof;"
"uniform vec2 tsz;"
"in vec2 pos;"
"in vec2 uvs;"
"out vec2 uv;"
"void main(){"
" uv = tof + uvs * tsz;"
" gl_Position = mvp * vec4(pos, 0.0, 1.0);"
"}";
static const char* shader_atlas_f =
SHADER_VERSION
"uniform sampler2D tex;"
"in mediump vec2 uv;"
"out mediump vec4 frag;"
"void main(){"
" frag = texture(tex, uv);"
"}";
// SOLID COLOR
static const char* shader_color_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec4 pos;"
"void main(){"
" gl_Position = mvp * pos;"
"}";
static const char* shader_color_f =
SHADER_VERSION
"uniform mediump vec4 col;"
"out mediump vec4 frag;"
"void main(){"
" frag = col;"
"}";
// COLOR QUAD
static const char* shader_color_quad_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec4 pos;"
"in vec2 uvs;"
"out vec3 uv;"
"void main(){"
" gl_Position = mvp * pos;"
" uv = vec3(uvs, pos.w);"
"}";
static const char* shader_color_quad_f =
SHADER_VERSION
"uniform mediump vec4 col;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"void main(){"
" mediump vec4 gradient_x = mix(col, vec4(1.0, 1.0, 1.0, 1.0), uv.x);"
" frag = mix(gradient_x, vec4(0.0, 0.0, 0.0, 1.0), uv.y);"
"}";
// HUE
static const char* shader_color_hue_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec4 pos;"
"in vec2 uvs;"
"out vec3 uv;"
"void main(){"
" gl_Position = mvp * pos;"
" uv = vec3(uvs, pos.w);"
"}";
static const char* shader_color_hue_f =
SHADER_VERSION
"uniform mediump vec4 col;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"mediump vec3 hsv2rgb(mediump vec3 c) {"
" mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
" mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
" return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
"}"
"void main(){"
" frag = vec4(hsv2rgb(vec3(uv.y, 1.0, 1.0)), 1.0);"
"}";
// FONT
static const char* shader_font_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec2 pos;"
"in vec2 uvs;"
"out vec2 uv;"
"void main(){"
" uv = uvs;"
" gl_Position = mvp * vec4(pos, 0.0, 1.0);"
"}";
static const char* shader_font_f =
SHADER_VERSION
"uniform mediump sampler2D tex;"
"uniform mediump vec4 col;"
"in mediump vec2 uv;"
"out mediump vec4 frag;"
"void main(){"
" mediump float a = texture(tex, uv).r;"
" frag = vec4(col.rgb, a);"
"}";
// STROKE
static const char* shader_stroke_v =
SHADER_VERSION
"uniform mat4 mvp;\n"
"in vec4 pos;\n"
"in vec2 uvs;\n"
"out vec2 uv;\n"
"void main(){\n"
" uv = uvs;\n"
" gl_Position = mvp * vec4(pos.xyz, 1.0);\n"
"}\n";
static const char* shader_stroke_f =
SHADER_VERSION
"uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n"
"uniform mediump vec4 col;\n"
"uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n"
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n"
" mediump vec4 fg = vec4(col.rgb, brush_alpha);\n"
" mediump vec4 bg = texture(tex_bg, uv2);\n"
" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n"
" mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;"
" mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
" frag = vec4(rgb, alpha_tot);\n"
"}\n";
// ALPHA LOCK
static const char* shader_stroke_lock_f =
SHADER_VERSION
"uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n"
"uniform mediump sampler2D tex_mask;\n"
"uniform mediump vec4 col;\n"
"uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n"
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n"
" mediump vec4 fg = vec4(col.rgb, brush_alpha);\n"
" mediump vec4 bg = texture(tex_bg, uv2);\n"
" mediump vec4 msk = texture(tex_mask, uv2);\n"
" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n"
" mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;"
" mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
" frag = vec4(rgb, min(alpha_tot, msk.a));\n"
"}\n";
// ERASER
static const char* shader_stroke_erase_f =
SHADER_VERSION
"uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n"
"uniform mediump vec4 col;\n"
"uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n"
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n"
" mediump vec4 bg = texture(tex_bg, uv2);\n"
" frag = vec4(bg.rgb, bg.a - bg.a * brush_alpha);\n"
"}\n";
// STROKE LAYER BLEND
static const char* shader_stroke_layer_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec4 pos;"
"in vec2 uvs;"
"out vec2 uv;"
"void main(){"
" uv = uvs;"
" gl_Position = mvp * vec4(pos.xyz, 1.0);"
"}";
static const char* shader_stroke_layer_f =
SHADER_VERSION
"uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n"
"uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n"
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec4 fg = texture(tex, uv) * vec4(1,1,1,alpha);\n"
" mediump vec4 bg = texture(tex_bg, uv);\n"
" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n"
" mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;"
" mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
" frag = vec4(rgb, alpha_tot);\n"
"}\n";
static const char* shader_checkerboard_v =
SHADER_VERSION
"uniform mat4 mvp;\n"
"in vec4 pos;\n"
"in vec2 uvs;\n"
"out vec2 uv;\n"
"void main(){\n"
" uv = uvs;\n"
" gl_Position = mvp * vec4(pos.xyz, 1.0);\n"
"}";
static const char* shader_checkerboard_f =
SHADER_VERSION
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" const mediump vec4 c1 = vec4(1.0, 1.0, 1.0, 1.0);\n"
" const mediump vec4 c2 = vec4(0.9, 0.9, 0.9, 1.0);\n"
" mediump vec2 c = floor(fract(uv * 10.0) * 2.0);\n"
" mediump float alpha = mix(c.x, 1.0 - c.x, c.y);\n"
" frag = mix(c1, c2, alpha);\n"
"}";
static const char* shader_equirect_v =
SHADER_VERSION
"#define PI 3.1415926535897932384626433832795\n"
"#define TWO_PI 6.283185307179586476925286766559\n"
"uniform mat4 mvp;\n"
"in vec4 pos;\n"
"in vec2 uvs;\n"
"out vec2 uv;\n"
"void main(){\n"
" uv = (vec2(1.0) - uvs + vec2(0.25,0.0)) * vec2(TWO_PI, PI);\n"
" gl_Position = mvp * vec4(pos.xyz, 1.0);\n"
"}";
static const char* shader_equirect_f =
SHADER_VERSION
"uniform samplerCube tex;\n"
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump float anglex = uv.x;\n"
" mediump float angley = uv.y;\n"
" mediump float sx = sin(anglex);\n"
" mediump float cx = cos(anglex);\n"
" mediump vec3 dir = vec3(0.0, 0.0, 0.0);\n"
" dir.x = sin(angley) * cx;\n"
" dir.y = cos(angley);\n"
" dir.z = sin(angley) * sx;\n"
" frag = texture(tex, dir);\n"
"}";
LOG("initializing shaders");
if (!ShaderManager::create(kShader::Texture, shader_v, shader_f))
LOG("Failed to create shader Texture");
if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f))
LOG("Failed to create shader TextureAlpha");
if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f))
LOG("Failed to create shader Color");
if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f))
LOG("Failed to create shader ColorQuad");
if (!ShaderManager::create(kShader::ColorHue, shader_color_hue_v, shader_color_hue_f))
LOG("Failed to create shader ColorHue");
if (!ShaderManager::create(kShader::UVs, shader_v, shader_uv_f))
LOG("Failed to create shader UVs");
if (!ShaderManager::create(kShader::Font, shader_font_v, shader_font_f))
LOG("Failed to create shader Font");
if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f))
LOG("Failed to create shader Atlas");
if (!ShaderManager::create(kShader::Stroke, shader_stroke_v, shader_stroke_f))
LOG("Failed to create shader Stroke");
if (!ShaderManager::create(kShader::StrokeLock, shader_stroke_v, shader_stroke_lock_f))
LOG("Failed to create shader StrokeLock");
if (!ShaderManager::create(kShader::StrokeErase, shader_stroke_v, shader_stroke_erase_f))
LOG("Failed to create shader StrokeErase");
if (!ShaderManager::create(kShader::StrokeLayer, shader_stroke_layer_v, shader_stroke_layer_f))
LOG("Failed to create shader StrokeLayer");
if (!ShaderManager::create(kShader::Checkerboard, shader_checkerboard_v, shader_checkerboard_f))
LOG("Failed to create shader Checkerboard");
if (!ShaderManager::create(kShader::Equirect, shader_equirect_v, shader_equirect_f))
LOG("Failed to create shader Equirect");
LOG("shaders initialized");
}
void App::initAssets()
{
LOG("initializing assets");
FontManager::init();
LOG("initializing assets loading fonts");
FontManager::load(kFont::Arial_11, "data/arial.ttf", 15);
FontManager::load(kFont::Arial_30, "data/arial.ttf", 30);
LOG("initializing assets create sampler");
sampler.create(GL_NEAREST);
LOG("initializing assets load uvs texture");
if (!tex.load("data/uvs.jpg"))
LOG("error loading image");
LOG("initializing assets completed");
}
void App::initLayout()
{
LOG("initializing layout statics");
NodeBorder::static_init();
NodeImage::static_init();
NodeIcon::static_init();
NodeStrokePreview::static_init();
layout.on_loaded = [&] {
LOG("initializing layout updating after load");
layout[main_id]->update(width, height, zoom);
LOG("initializing layout components");
sidebar = layout[main_id]->find<NodeBorder>("sidebar");
panels = layout[main_id]->find<Node>("panels");
canvas = layout[main_id]->find<NodeCanvas>("paint-canvas");
canvas->data_path = data_path;
//brushes = layout[main_id]->find<NodePanelBrush>("panel-brush");
//layers = layout[main_id]->find<NodePanelLayer>("panel-layer");
//color = layout[main_id]->find<NodePanelColor>("panel-color");
//stroke = layout[main_id]->find<NodePanelStroke>("panel-stroke");
brushes = std::make_shared<NodePanelBrush>();
brushes->m_manager = &layout;
brushes->init();
brushes->create();
brushes->loaded();
layers = std::make_shared<NodePanelLayer>();
layers->m_manager = &layout;
layers->init();
layers->create();
layers->loaded();
color = std::make_shared<NodePanelColor>();
color->m_manager = &layout;
color->init();
color->create();
color->loaded();
stroke = std::make_shared<NodePanelStroke>();
stroke->m_manager = &layout;
stroke->init();
stroke->create();
stroke->loaded();
if (canvas)
{
stroke->m_canvas->m_brush.m_tip_color = color->m_color;
stroke->m_canvas->draw_stroke();
canvas->m_brush = stroke->m_canvas->m_brush;
}
brushes->on_brush_changed = [this](Node* target, int index) {
auto tid = brushes->get_texture_id(index);
stroke->m_canvas->m_brush.m_tex_id = tid;
stroke->m_canvas->draw_stroke();
canvas->m_brush = stroke->m_canvas->m_brush;
if (on_brush_select)
on_brush_select(index);
};
color->on_color_changed = [this](Node* target, glm::vec4 color) {
stroke->m_canvas->m_brush.m_tip_color = color;
// stroke->m_canvas->draw_stroke();
if (canvas)
canvas->m_brush = stroke->m_canvas->m_brush;
if (on_color_change)
on_color_change(color);
};
stroke->on_stroke_change = [this](Node*target) {
if (canvas)
canvas->m_brush = stroke->m_canvas->m_brush;
if (on_stroke_change)
on_stroke_change();
};
layers->on_layer_add = [this](Node*) {
canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str());
};
layers->on_layer_change = [this](Node*, int old_idx, int new_idx) {
canvas->m_canvas->m_current_layer_idx = canvas->m_canvas->m_order[new_idx];
};
layers->on_layer_order = [this](Node*, int old_idx, int new_idx) {
canvas->m_canvas->layer_order(old_idx, new_idx);
};
layers->on_layer_opacity_changed = [this](Node*, int idx, float value) {
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_opacity = value;
};
layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) {
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_alpha_locked = visible;
};
canvas->m_canvas->layer_add("Default");
layers->add_layer("Default");
static glm::vec4 color_button_normal{.1, .1, .1, 1};
static glm::vec4 color_button_hlight{ 1, .0, .0, 1};
if (auto* button = layout[main_id]->find<NodeButton>("btn-pen"))
{
button->on_click = [this](Node*) {
layout[main_id]->find<NodeButton>("btn-pen")->set_color(color_button_hlight);
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);
Canvas::set_mode(Canvas::kCanvasMode::Draw);
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-erase"))
{
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_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);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-line"))
{
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_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);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-cam"))
{
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_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*) {
canvas->m_canvas->clear(canvas->m_brush.m_tip_color);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-stroke"))
{
button->on_click = [this, button](Node*) {
panels->get_child_index(stroke.get()) == -1 ? panels->add_child(stroke) : panels->remove_child(stroke.get());
button->set_color(panels->get_child_index(stroke.get()) == -1 ? color_button_normal : color_button_hlight);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-brush"))
{
button->on_click = [this, button](Node*) {
panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get());
button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-color"))
{
button->on_click = [this, button](Node*) {
panels->get_child_index(color.get()) == -1 ? panels->add_child(color) : panels->remove_child(color.get());
button->set_color(panels->get_child_index(color.get()) == -1 ? color_button_normal : color_button_hlight);
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-layer"))
{
button->on_click = [this, button](Node*) {
panels->get_child_index(layers.get()) == -1 ? panels->add_child(layers) : panels->remove_child(layers.get());
button->set_color(panels->get_child_index(layers.get()) == -1 ? color_button_normal : color_button_hlight);
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-export"))
{
button->on_click = [this,button](Node*) {
if (canvas)
{
canvas->m_canvas->save(data_path);
}
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-open"))
{
button->on_click = [this,button](Node*) {
if (canvas)
{
// load thumbnail test
auto open_dialog = std::make_shared<NodeDialogOpen>();
open_dialog->m_manager = &layout;
open_dialog->data_path = data_path;
open_dialog->init();
open_dialog->create();
open_dialog->loaded();
layout[main_id]->add_child(open_dialog);
layout[main_id]->update();
open_dialog->btn_ok->on_click = [this,open_dialog](Node*)
{
layers->clear();
canvas->m_canvas->project_open(data_path);
for (auto& i : canvas->m_canvas->m_order)
layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
open_dialog->destroy();
};
}
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-save"))
{
button->on_click = [this,button](Node*) {
if (canvas)
{
canvas->m_canvas->project_save(data_path);
}
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-undo"))
{
button->on_click = [this,button](Node*) {
ActionManager::undo();
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-clear"))
{
button->on_click = [this](Node*) {
//exit(0);
if (canvas)
canvas->m_canvas->clear({ 0, 0, 0, 0 });
};
}
if (auto* button = layout[main_id]->find<NodeButton>("btn-popup"))
{
button->on_click = [this](Node*) {
msgbox = new NodeMessageBox();
msgbox->m_manager = &layout;
msgbox->init();
layout[main_id]->add_child(msgbox);
layout[main_id]->update();
};
}
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-settings"))
{
button->on_click = [this](Node*) {
settings = new NodeSettings();
settings->m_manager = &layout;
settings->init();
layout[main_id]->add_child(settings);
layout[main_id]->update();
};
}
if (auto* menu_file = layout[main_id]->find<NodeButtonCustom>("menu-file"))
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
popup = (NodePopupMenu*)layout[const_hash("file-menu")]->m_children[0]->clone();
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
layout[main_id]->update();
popup->mouse_capture();
popup->m_mouse_ignore = false;
};
}
if (auto* menu_file = layout[main_id]->find<NodeButtonCustom>("menu-edit"))
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
popup = (NodePopupMenu*)layout[const_hash("edit-menu")]->m_children[0]->clone();
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
layout[main_id]->update();
popup->mouse_capture();
popup->m_mouse_ignore = false;
};
}
if (auto* menu_file = layout[main_id]->find<NodeButtonCustom>("menu-layers"))
{
menu_file->on_click = [=](Node*) {
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
popup = (NodePopupMenu*)layout[const_hash("layers-menu")]->m_children[0]->clone();
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
layout[main_id]->add_child(popup);
layout[main_id]->update();
popup->mouse_capture();
popup->m_mouse_ignore = false;
};
}
if (auto* toolbar = layout[main_id]->find<Node>("toolbar"))
{
toolbar->m_flood_events = true;
}
};
LOG("initializing layout xml");
if (layout.m_loaded)
{
LOG("restore layout");
layout.restore_context();
if (panels->get_child_index(brushes.get()) == -1) brushes->restore_context();
if (panels->get_child_index(layers.get()) == -1) layers->restore_context();
if (panels->get_child_index(color.get()) == -1) color->restore_context();
if (panels->get_child_index(stroke.get()) == -1) stroke->restore_context();
}
else
layout.load("data/layout.xml");
LOG("initializing layout completed");
}
void App::initLog()
{
LogRemote::I.start();
}
void App::init()
{
#ifdef _WIN32
static CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
// colors: http://stackoverflow.com/questions/4053837/colorizing-text-in-the-console-with-c
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
static std::map<GLenum, int> colors = {
{ GL_DEBUG_SEVERITY_NOTIFICATION, 8 },
{ GL_DEBUG_SEVERITY_LOW, 8 },
{ GL_DEBUG_SEVERITY_MEDIUM, FOREGROUND_GREEN | FOREGROUND_INTENSITY },
{ GL_DEBUG_SEVERITY_HIGH, FOREGROUND_RED | FOREGROUND_INTENSITY },
};
if (severity == GL_DEBUG_SEVERITY_MEDIUM || severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_LOW)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors[severity]);
LOG("OPENGL: %.*s", length, message);
FlushConsoleInputBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), info.wAttributes);
//__debugbreak();
}
}, nullptr);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
#endif
LOG("GL version: %s", glGetString(GL_VERSION));
LOG("GL vendor: %s", glGetString(GL_VENDOR));
LOG("GL renderer: %s", glGetString(GL_RENDERER));
// GLint n_exts;
// glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
// for (int i = 0; i < n_exts; i++)
// {
// LOG("%s", glGetStringi(GL_EXTENSIONS, i));
// }
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
zoom = ceilf(width / 1000.f);
//glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
initShaders();
initAssets();
initLayout();
GLfloat width_range[2];
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, width_range);
LOG("GL line range: %f - %f", width_range[0], width_range[1]);
LOG("Screen Size: %f %f", width, height);
}
void App::update(float dt)
{
// update offscreen stuff
if (canvas && canvas->m_canvas)
canvas->m_canvas->stroke_draw();
//glClearColor(.1f, .1f, .1f, 1.f);
//glViewport(0, 0, (GLsizei)width, (GLsizei)height);
//glClear(GL_COLOR_BUFFER_BIT);
#ifndef __ANDROID__
layout.reload();
#endif
if (auto* main = layout[main_id])
main->update(width, height, zoom);
auto observer = [this](Node* n)
{
if (n && n->m_display)
{
auto box = n->m_clip;
glm::ivec4 c = glm::vec4((int)box.x - 1, (int)(height / zoom - box.y - box.w) - 1, (int)box.z + 2, (int)box.w + 2) * zoom;
glScissor(c.x, c.y, c.z, c.w);
n->draw();
}
};
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_SCISSOR_TEST);
if (auto* main = layout[main_id])
main->watch(observer);
//msgbox->watch(observer);
glDisable(GL_SCISSOR_TEST);
}
void App::resize(float w, float h)
{
width = w;
height = h;
if (auto* main = layout[main_id])
main->update(w , h, zoom);
}
bool App::mouse_down(int button, float x, float y)
{
MouseEvent e;
e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL;
e.m_pos = { x / zoom, y / zoom };
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::mouse_move(float x, float y)
{
MouseEvent e;
e.m_type = kEventType::MouseMove;
e.m_pos = { x / zoom, y / zoom };
kEventResult ret = kEventResult::Available;
if (auto* main = layout[main_id])
ret = main->on_event(&e);
return ret == kEventResult::Consumed;
}
bool App::mouse_up(int button, float x, float y)
{
MouseEvent e;
e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL;
e.m_pos = { x / zoom, y / zoom };
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::mouse_scroll(float x, float y, float delta)
{
MouseEvent e;
e.m_type = kEventType::MouseScroll;
e.m_pos = { x / zoom, y / zoom };
e.m_scroll_delta = delta * 0.1f;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::mouse_cancel(int button)
{
MouseEvent e;
e.m_type = kEventType::MouseCancel;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1)
{
GestureEvent e;
glm::vec2 p = glm::lerp(p0, p1, 0.5f);
e.m_type = kEventType::GestureStart;
e.m_pos = p;
e.m_distance = glm::distance(p0, p1);
gesture_p0 = p0;
gesture_p1 = p1;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1)
{
GestureEvent e;
glm::vec2 p = glm::lerp(p0, p1, 0.5f);
e.m_type = kEventType::GestureMove;
e.m_pos = p;
e.m_distance = glm::distance(p0, p1);
e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1);
e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f);
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::gesture_end()
{
GestureEvent e;
e.m_type = kEventType::GestureEnd;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::key_down(kKey key)
{
KeyEvent e;
e.m_type = kEventType::KeyDown;
e.m_key = key;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::key_up(kKey key)
{
KeyEvent e;
e.m_type = kEventType::KeyUp;
e.m_key = key;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
bool App::key_char(char key)
{
KeyEvent e;
e.m_type = kEventType::KeyChar;
e.m_char = key;
auto ret = layout[main_id]->on_event(&e);
layout[main_id]->update();
return ret == kEventResult::Consumed;
}
void App::terminate()
{
LOG("App::terminate");
TextureManager::invalidate();
ShaderManager::invalidate();
layout.clear_context();
brushes->clear_context();
layers->clear_context();
color->clear_context();
stroke->clear_context();
}