#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("sidebar"); panels = layout[main_id]->find("panels"); canvas = layout[main_id]->find("paint-canvas"); canvas->data_path = data_path; //brushes = layout[main_id]->find("panel-brush"); //layers = layout[main_id]->find("panel-layer"); //color = layout[main_id]->find("panel-color"); //stroke = layout[main_id]->find("panel-stroke"); brushes = std::make_shared(); brushes->m_manager = &layout; brushes->init(); brushes->create(); brushes->loaded(); layers = std::make_shared(); layers->m_manager = &layout; layers->init(); layers->create(); layers->loaded(); color = std::make_shared(); color->m_manager = &layout; color->init(); color->create(); color->loaded(); stroke = std::make_shared(); 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("btn-pen")) { button->on_click = [this](Node*) { layout[main_id]->find("btn-pen")->set_color(color_button_hlight); layout[main_id]->find("btn-erase")->set_color(color_button_normal); layout[main_id]->find("btn-line")->set_color(color_button_normal); layout[main_id]->find("btn-cam")->set_color(color_button_normal); layout[main_id]->find("btn-normal")->set_color(color_button_normal); Canvas::set_mode(Canvas::kCanvasMode::Draw); }; layout[main_id]->find("btn-pen")->set_color(color_button_hlight); Canvas::set_mode(Canvas::kCanvasMode::Draw); } if (auto* button = layout[main_id]->find("btn-erase")) { button->on_click = [this](Node*) { layout[main_id]->find("btn-pen")->set_color(color_button_normal); layout[main_id]->find("btn-erase")->set_color(color_button_hlight); layout[main_id]->find("btn-line")->set_color(color_button_normal); layout[main_id]->find("btn-cam")->set_color(color_button_normal); layout[main_id]->find("btn-normal")->set_color(color_button_normal); Canvas::set_mode(Canvas::kCanvasMode::Erase); }; } if (auto* button = layout[main_id]->find("btn-line")) { button->on_click = [this](Node*) { layout[main_id]->find("btn-pen")->set_color(color_button_normal); layout[main_id]->find("btn-erase")->set_color(color_button_normal); layout[main_id]->find("btn-line")->set_color(color_button_hlight); layout[main_id]->find("btn-cam")->set_color(color_button_normal); layout[main_id]->find("btn-normal")->set_color(color_button_normal); Canvas::set_mode(Canvas::kCanvasMode::Line); }; } if (auto* button = layout[main_id]->find("btn-cam")) { button->on_click = [this](Node*) { layout[main_id]->find("btn-pen")->set_color(color_button_normal); layout[main_id]->find("btn-erase")->set_color(color_button_normal); layout[main_id]->find("btn-line")->set_color(color_button_normal); layout[main_id]->find("btn-cam")->set_color(color_button_hlight); layout[main_id]->find("btn-normal")->set_color(color_button_normal); Canvas::set_mode(Canvas::kCanvasMode::Camera); }; } if (auto* button = layout[main_id]->find("btn-normal")) { button->on_click = [this](Node*) { layout[main_id]->find("btn-pen")->set_color(color_button_normal); layout[main_id]->find("btn-erase")->set_color(color_button_normal); layout[main_id]->find("btn-line")->set_color(color_button_normal); layout[main_id]->find("btn-cam")->set_color(color_button_normal); layout[main_id]->find("btn-normal")->set_color(color_button_hlight); Canvas::set_mode(Canvas::kCanvasMode::Normal); }; } if (auto* button = layout[main_id]->find("btn-bucket")) { button->on_click = [this](Node*) { canvas->m_canvas->clear(canvas->m_brush.m_tip_color); }; } if (auto* button = layout[main_id]->find("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("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("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("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("btn-export")) { button->on_click = [this,button](Node*) { if (canvas) { canvas->m_canvas->save(data_path); } }; } if (auto* button = layout[main_id]->find("btn-open")) { button->on_click = [this,button](Node*) { if (canvas) { // load thumbnail test auto open_dialog = std::make_shared(); 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("btn-save")) { button->on_click = [this,button](Node*) { if (canvas) { canvas->m_canvas->project_save(data_path); } }; } if (auto* button = layout[main_id]->find("btn-undo")) { button->on_click = [this,button](Node*) { ActionManager::undo(); }; } if (auto* button = layout[main_id]->find("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("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("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("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("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("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("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 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(); }