implement frame buffer fetch extension for iOS, change composition on stroke drawing and commit, add rename layer dialog

This commit is contained in:
2017-08-09 09:59:39 +01:00
parent eb4cf07162
commit e134ba553d
14 changed files with 415 additions and 92 deletions

View File

@@ -14,11 +14,15 @@
@interface View : NSOpenGLView @interface View : NSOpenGLView
{ {
CVDisplayLinkRef dl; CVDisplayLinkRef dl;
NSOpenGLContext* glctx;
_CGLContextObject* cgl;
bool gl_ready;
} }
- (void)terminateGL; - (void)terminateGL;
@end @implementation View @end @implementation View
- (instancetype)initWithFrame:(NSRect)frameRect - (instancetype)initWithFrame:(NSRect)frameRect
{ {
gl_ready = false;
NSOpenGLPixelFormatAttribute attrs[] = NSOpenGLPixelFormatAttribute attrs[] =
{ {
NSOpenGLPFADoubleBuffer, NSOpenGLPFADoubleBuffer,
@@ -57,14 +61,18 @@
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(dl, cglContext, cglPixelFormat); CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(dl, cglContext, cglPixelFormat);
CGLEnable([self.openGLContext CGLContextObj], kCGLCECrashOnRemovedFunctions);
// Activate the display link // Activate the display link
CVDisplayLinkStart(dl); CVDisplayLinkStart(dl);
CGLEnable([self.openGLContext CGLContextObj], kCGLCECrashOnRemovedFunctions); cgl = [[self openGLContext] CGLContextObj];
glctx = [self openGLContext];
CGLLockContext([[self openGLContext] CGLContextObj]); CGLLockContext([[self openGLContext] CGLContextObj]);
App::I.init(); App::I.init();
CGLUnlockContext([[self openGLContext] CGLContextObj]); CGLUnlockContext([[self openGLContext] CGLContextObj]);
gl_ready = true;
} }
- (void)terminateGL - (void)terminateGL
@@ -90,24 +98,23 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
double now = hostTime / _timeFreq; double now = hostTime / _timeFreq;
// this will not update unless 1/30th of a second has passed since the last update // this will not update unless 1/30th of a second has passed since the last update
if ( now < _prevTime + (1.0 / 30.0) ) if ( now < _prevTime + (1.0 / 30.0) && App::I.redraw )
{ {
// Add your drawing codes here
[[self openGLContext] makeCurrentContext];
// We draw on a secondary thread through the display link // We draw on a secondary thread through the display link
// When resizing the view, -reshape is called automatically on the main // When resizing the view, -reshape is called automatically on the main
// thread. Add a mutex around to avoid the threads accessing the context // thread. Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing // simultaneously when resizing
CGLLockContext([[self openGLContext] CGLContextObj]); [glctx makeCurrentContext];
CGLLockContext([glctx CGLContextObj]);
App::I.clear(); App::I.clear();
App::I.update(now - _prevTime); App::I.update(now - _prevTime);
//[[self openGLContext] flushBuffer]; //[[self openGLContext] flushBuffer];
// returning NO will cause the layer to NOT be redrawn // returning NO will cause the layer to NOT be redrawn
CGLFlushDrawable([[self openGLContext] CGLContextObj]); CGLFlushDrawable([glctx CGLContextObj]);
CGLUnlockContext([[self openGLContext] CGLContextObj]); CGLUnlockContext([glctx CGLContextObj]);
return NO; return NO;
} }
else else
@@ -130,21 +137,21 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
- (void)drawRect:(NSRect)dirtyRect - (void)drawRect:(NSRect)dirtyRect
{ {
NSLog(@"drawRect"); NSLog(@"drawRect");
// Add your drawing codes here
[[self openGLContext] makeCurrentContext];
// We draw on a secondary thread through the display link // We draw on a secondary thread through the display link
// When resizing the view, -reshape is called automatically on the main // When resizing the view, -reshape is called automatically on the main
// thread. Add a mutex around to avoid the threads accessing the context // thread. Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing // simultaneously when resizing
CGLLockContext([[self openGLContext] CGLContextObj]); [glctx makeCurrentContext];
CGLLockContext(cgl);
App::I.update(0); App::I.update(0);
//[[self openGLContext] flushBuffer]; //[[self openGLContext] flushBuffer];
// returning NO will cause the layer to NOT be redrawn // returning NO will cause the layer to NOT be redrawn
CGLFlushDrawable([[self openGLContext] CGLContextObj]); CGLFlushDrawable(cgl);
CGLUnlockContext([[self openGLContext] CGLContextObj]); CGLUnlockContext(cgl);
} }
- (void)reshape - (void)reshape

View File

@@ -7,6 +7,7 @@
// //
#import "AppDelegate.h" #import "AppDelegate.h"
#include "app.h"
@interface AppDelegate () @interface AppDelegate ()
@@ -32,10 +33,12 @@
- (void)applicationWillEnterForeground:(UIApplication *)application { - (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
App::I.redraw = true;
} }
- (void)applicationDidBecomeActive:(UIApplication *)application { - (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
App::I.redraw = true;
} }
- (void)applicationWillTerminate:(UIApplication *)application { - (void)applicationWillTerminate:(UIApplication *)application {

View File

@@ -165,6 +165,34 @@
</border> </border>
</layout> </layout>
<!-- Dialog Relane Layer -->
<layout id="dialog-layer-rename">
<border positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center">
<border thickness="1" border-color=".2" pad="3">
<border width="400" height="30" color=".2 .2 .2 .9" dir="row" align="center" justify="center">
<text text="Rename Layer" font-face="arial" font-size="11"></text>
</border>
<border width="400" color="0 0 0 .9" pad="10" dir="col">
<node dir="row">
<text text="New name: " font-face="arial" font-size="11"/>
<text-input id="txt-input" width="100" height="20" color=".3"/>
</node>
<node height="40" grow="1" dir="row" align="flex-end" justify="flex-end">
<button id="btn-ok" text="Rename Layer" width="100" height="30" margin="0 10 0 0"/>
<button id="btn-cancel" text="Cancel" width="60" height="30" pad="10"/>
</node>
</border>
</border>
</border>
</layout>
<layout id="dialog-open-item">
<node dir="row">
<image-texture id="thumb-tex" width="64" height="64"/>
<text text="Longer description for the error or the message." font-face="arial" font-size="11"></text>
</node>
</layout>
<!-- Open Dialog Popup --> <!-- Open Dialog Popup -->
<layout id="dialog-open"> <layout id="dialog-open">
<border positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center"> <border positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center">
@@ -173,9 +201,10 @@
<text text="Open PanoPainter Project" font-face="arial" font-size="11"></text> <text text="Open PanoPainter Project" font-face="arial" font-size="11"></text>
</border> </border>
<border width="400" color="0 0 0 .9" pad="10" dir="col"> <border width="400" color="0 0 0 .9" pad="10" dir="col">
<image-texture id="thumb-tex" width="64" height="64"/> <ref id="dialog-open-item" />
<text text="Longer description for the error or the message." font-face="arial" font-size="11"></text> <ref id="dialog-open-item" />
<text-input width="100" height="100" color=".3"/> <ref id="dialog-open-item" />
<!--<text-input width="100" height="100" color=".3"/>-->
<node height="40" grow="1" dir="row" align="flex-end" justify="flex-end"> <node height="40" grow="1" dir="row" align="flex-end" justify="flex-end">
<button id="btn-ok" text="Open Project" width="100" height="30" margin="0 10 0 0"/> <button id="btn-ok" text="Open Project" width="100" height="30" margin="0 10 0 0"/>
<button id="btn-cancel" text="Cancel" width="60" height="30" pad="10"/> <button id="btn-cancel" text="Cancel" width="60" height="30" pad="10"/>
@@ -307,11 +336,15 @@
<!--layers menu--> <!--layers menu-->
<layout id="layers-menu"> <layout id="layers-menu">
<popup-menu positioning="absolute" position="100 100" width="150" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col"> <popup-menu positioning="absolute" position="100 100" width="250" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<button-custom id="clear-grids" height="30" align="center" color=".2" pad="0 0 0 10" dir="row"> <button-custom id="clear-grids" height="30" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="add" width="20"/> <icon icon="add" width="20"/>
<text text="Clear grids" margin="0 0 0 5" font-face="arial" font-size="11"/> <text text="Clear grids" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom> </button-custom>
<button-custom id="layer-rename" height="30" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="application_edit" width="20"/>
<text id="menu-label" text="Rename Layer" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
</popup-menu> </popup-menu>
</layout> </layout>

View File

@@ -158,6 +158,9 @@
AD95AEC71E41EDEC002DD03A /* pch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD95AEC51E41EDEC002DD03A /* pch.cpp */; }; AD95AEC71E41EDEC002DD03A /* pch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD95AEC51E41EDEC002DD03A /* pch.cpp */; };
ADB1C3DA1EA3A156009A65BD /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADB1C3D81EA3A156009A65BD /* event.cpp */; }; ADB1C3DA1EA3A156009A65BD /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADB1C3D81EA3A156009A65BD /* event.cpp */; };
ADB61C821E3D38450093280F /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADB61C801E3D38450093280F /* util.cpp */; }; ADB61C821E3D38450093280F /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADB61C801E3D38450093280F /* util.cpp */; };
ADC6F4621F3AFF2C004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; };
ADC6F4631F3AFF2D004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; };
ADC6F4641F3AFF2E004177FA /* node_dialog_layer_rename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */; };
ADD7D26F1EBF9AE300D5A897 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D26E1EBF9AE300D5A897 /* main.m */; }; ADD7D26F1EBF9AE300D5A897 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D26E1EBF9AE300D5A897 /* main.m */; };
ADD7D2721EBF9AE300D5A897 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */; }; ADD7D2721EBF9AE300D5A897 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */; };
ADD7D2791EBF9AE300D5A897 /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2781EBF9AE300D5A897 /* GameViewController.m */; }; ADD7D2791EBF9AE300D5A897 /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2781EBF9AE300D5A897 /* GameViewController.m */; };
@@ -319,10 +322,12 @@
ADB1C3DB1EA531B0009A65BD /* keymap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keymap.h; sourceTree = "<group>"; }; ADB1C3DB1EA531B0009A65BD /* keymap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keymap.h; sourceTree = "<group>"; };
ADB61C801E3D38450093280F /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = util.cpp; sourceTree = "<group>"; }; ADB61C801E3D38450093280F /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = util.cpp; sourceTree = "<group>"; };
ADB61C811E3D38450093280F /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = util.h; sourceTree = "<group>"; }; ADB61C811E3D38450093280F /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = util.h; sourceTree = "<group>"; };
ADC6F4601F3AFA2A004177FA /* node_dialog_layer_rename.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = node_dialog_layer_rename.h; sourceTree = "<group>"; };
ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = node_dialog_layer_rename.cpp; sourceTree = "<group>"; };
ADD7D26B1EBF9AE300D5A897 /* PanoPainter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanoPainter.app; sourceTree = BUILT_PRODUCTS_DIR; }; ADD7D26B1EBF9AE300D5A897 /* PanoPainter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanoPainter.app; sourceTree = BUILT_PRODUCTS_DIR; };
ADD7D26E1EBF9AE300D5A897 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; ADD7D26E1EBF9AE300D5A897 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
ADD7D2701EBF9AE300D5A897 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; ADD7D2701EBF9AE300D5A897 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = AppDelegate.m; sourceTree = "<group>"; };
ADD7D2771EBF9AE300D5A897 /* GameViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameViewController.h; sourceTree = "<group>"; }; ADD7D2771EBF9AE300D5A897 /* GameViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameViewController.h; sourceTree = "<group>"; };
ADD7D2781EBF9AE300D5A897 /* GameViewController.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = GameViewController.m; sourceTree = "<group>"; }; ADD7D2781EBF9AE300D5A897 /* GameViewController.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = GameViewController.m; sourceTree = "<group>"; };
ADD7D27B1EBF9AE300D5A897 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; ADD7D27B1EBF9AE300D5A897 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
@@ -421,6 +426,8 @@
AD10635C1EC7ADFA002A525F /* node_color_quad.h */, AD10635C1EC7ADFA002A525F /* node_color_quad.h */,
AD10635D1EC7ADFA002A525F /* node_dialog_open.cpp */, AD10635D1EC7ADFA002A525F /* node_dialog_open.cpp */,
AD10635E1EC7ADFA002A525F /* node_dialog_open.h */, AD10635E1EC7ADFA002A525F /* node_dialog_open.h */,
ADC6F4611F3AFA2B004177FA /* node_dialog_layer_rename.cpp */,
ADC6F4601F3AFA2A004177FA /* node_dialog_layer_rename.h */,
AD10635F1EC7ADFA002A525F /* node_icon.cpp */, AD10635F1EC7ADFA002A525F /* node_icon.cpp */,
AD1063601EC7ADFA002A525F /* node_icon.h */, AD1063601EC7ADFA002A525F /* node_icon.h */,
AD1063611EC7ADFA002A525F /* node_image_texture.cpp */, AD1063611EC7ADFA002A525F /* node_image_texture.cpp */,
@@ -754,6 +761,7 @@
AD0E5CC61ECC72AD00C35669 /* node_panel_layer.cpp in Sources */, AD0E5CC61ECC72AD00C35669 /* node_panel_layer.cpp in Sources */,
AD0E5CBA1ECC72AD00C35669 /* node_button_custom.cpp in Sources */, AD0E5CBA1ECC72AD00C35669 /* node_button_custom.cpp in Sources */,
AD0E5CC31ECC72AD00C35669 /* node_message_box.cpp in Sources */, AD0E5CC31ECC72AD00C35669 /* node_message_box.cpp in Sources */,
ADC6F4631F3AFF2D004177FA /* node_dialog_layer_rename.cpp in Sources */,
AD0E5CC41ECC72AD00C35669 /* node_panel_brush.cpp in Sources */, AD0E5CC41ECC72AD00C35669 /* node_panel_brush.cpp in Sources */,
AD0E5CBC1ECC72AD00C35669 /* node_canvas.cpp in Sources */, AD0E5CBC1ECC72AD00C35669 /* node_canvas.cpp in Sources */,
AD0E5CD01ECC72AD00C35669 /* action.cpp in Sources */, AD0E5CD01ECC72AD00C35669 /* action.cpp in Sources */,
@@ -813,6 +821,7 @@
AD1063851EC7ADFA002A525F /* node_dialog_open.cpp in Sources */, AD1063851EC7ADFA002A525F /* node_dialog_open.cpp in Sources */,
AD58E0681E2A7741006ACC15 /* image.cpp in Sources */, AD58E0681E2A7741006ACC15 /* image.cpp in Sources */,
AD0E11A11ECA619F00CDA6BB /* jpgd.cpp in Sources */, AD0E11A11ECA619F00CDA6BB /* jpgd.cpp in Sources */,
ADC6F4641F3AFF2E004177FA /* node_dialog_layer_rename.cpp in Sources */,
AD1063901EC7ADFA002A525F /* node_slider.cpp in Sources */, AD1063901EC7ADFA002A525F /* node_slider.cpp in Sources */,
AD0E11981ECA20F200CDA6BB /* app_layout.cpp in Sources */, AD0E11981ECA20F200CDA6BB /* app_layout.cpp in Sources */,
AD58E0771E3421F2006ACC15 /* Yoga.c in Sources */, AD58E0771E3421F2006ACC15 /* Yoga.c in Sources */,
@@ -836,6 +845,7 @@
AD0E11A51ECA61B900CDA6BB /* jpgd.cpp in Sources */, AD0E11A51ECA61B900CDA6BB /* jpgd.cpp in Sources */,
ADD7D29E1EBF9E1C00D5A897 /* shape.cpp in Sources */, ADD7D29E1EBF9E1C00D5A897 /* shape.cpp in Sources */,
ADD7D2901EBF9E1C00D5A897 /* canvas_modes.cpp in Sources */, ADD7D2901EBF9E1C00D5A897 /* canvas_modes.cpp in Sources */,
ADC6F4621F3AFF2C004177FA /* node_dialog_layer_rename.cpp in Sources */,
AD10639A1EC7AE92002A525F /* node_canvas.cpp in Sources */, AD10639A1EC7AE92002A525F /* node_canvas.cpp in Sources */,
ADD7D2A31EBFA06F00D5A897 /* tinyxml2.cpp in Sources */, ADD7D2A31EBFA06F00D5A897 /* tinyxml2.cpp in Sources */,
AD10639B1EC7AE92002A525F /* node_checkbox.cpp in Sources */, AD10639B1EC7AE92002A525F /* node_checkbox.cpp in Sources */,

View File

@@ -14,6 +14,7 @@
#include "node_panel_color.h" #include "node_panel_color.h"
#include "node_panel_stroke.h" #include "node_panel_stroke.h"
#include "node_canvas.h" #include "node_canvas.h"
#include "node_dialog_layer_rename.h"
#if defined(__OBJC__) && defined(__IOS__) #if defined(__OBJC__) && defined(__IOS__)
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>

View File

@@ -131,9 +131,9 @@ void App::initLayout()
{ {
button->on_click = [this](Node*) { button->on_click = [this](Node*) {
CanvasModePen* mode = (CanvasModePen*)canvas->m_canvas->modes[(int)Canvas::kCanvasMode::Draw][0]; CanvasModePen* mode = (CanvasModePen*)canvas->m_canvas->modes[(int)Canvas::kCanvasMode::Draw][0];
if (mode) if (mode && canvas->m_canvas->m_current_mode == Canvas::kCanvasMode::Draw)
{ {
mode->m_picking = true; mode->m_picking = !mode->m_picking;
} }
}; };
} }
@@ -376,6 +376,35 @@ void App::initLayout()
popup->mouse_release(); popup->mouse_release();
popup->destroy(); popup->destroy();
}; };
popup->find<NodeButtonCustom>("layer-rename")->on_click = [this](Node*) {
// load thumbnail test
auto open_dialog = std::make_shared<NodeDialogLayerRename>();
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->m_current_layer->set_name(open_dialog->get_name().c_str());
open_dialog->destroy();
};
popup->mouse_release();
popup->destroy();
};
if (layers->m_current_layer)
popup->find<NodeButtonCustom>("layer-rename")->
find<NodeText>("menu-label")->
set_text(("Rename Layer " + layers->m_current_layer->m_label_text).c_str());
else
popup->find<NodeButtonCustom>("layer-rename")->
find<NodeText>("menu-label")->
set_text("Rename Layer (Select a layer)");
}; };
} }
if (auto* toolbar = layout[main_id]->find<Node>("toolbar")) if (auto* toolbar = layout[main_id]->find<Node>("toolbar"))

View File

@@ -43,6 +43,49 @@ void App::initShaders()
"void main(){\n" "void main(){\n"
" frag = texture(tex, uv.xy) * vec4(1,1,1,alpha);\n" " frag = texture(tex, uv.xy) * vec4(1,1,1,alpha);\n"
"}\n"; "}\n";
// TEXTURE COMP ERASE
static const char* shader_comp_erase_f =
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n"
"uniform mediump float alpha;\n"
"uniform bool lock;\n"
"in mediump vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec4 base = texture(tex, uv.xy);\n"
" mediump vec4 stroke = texture(tex_stroke, uv.xy);\n"
" mediump float a = base.a - (stroke.a * alpha);\n"
" frag = vec4(base.rgb, clamp(a, 0.0, 1.0));\n"
"}\n";
// TEXTURE COMP DRAW
static const char* shader_comp_draw_f =
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n"
"uniform mediump float alpha;\n"
"uniform bool lock;\n"
"in mediump vec3 uv;\n"
"out mediump vec4 frag;\n"
"void main(){\n"
" mediump vec4 base = texture(tex, uv.xy);\n"
" mediump vec4 stroke = texture(tex_stroke, uv.xy);\n"
" stroke.a = stroke.a * alpha;\n"
" if (lock){\n"
" mediump float alpha_tot = stroke.a + (1.0 - stroke.a) * base.a;"
" mediump vec3 rgb = mix(base.rgb, stroke.rgb, stroke.a / alpha_tot);\n"
" frag = vec4(rgb, base.a);\n"
" } else {\n"
" mediump float alpha_tot = stroke.a + (1.0 - stroke.a) * base.a;"
" mediump vec3 rgb = mix(base.rgb, stroke.rgb, stroke.a / alpha_tot);\n"
" frag = vec4(rgb, alpha_tot);\n"
" }\n"
// " mediump float alpha_tot = stroke.a + (1.0 - stroke.a) * base.a;"
// " mediump vec3 rgb = mix(base.rgb, stroke.rgb, stroke.a / alpha_tot);\n"
// " frag = vec4(rgb, alpha_tot);\n"
"}\n";
// TEXTURE ATLAS // TEXTURE ATLAS
static const char* shader_atlas_v = static const char* shader_atlas_v =
@@ -164,26 +207,40 @@ void App::initShaders()
"}\n"; "}\n";
static const char* shader_stroke_f = static const char* shader_stroke_f =
SHADER_VERSION SHADER_VERSION
#ifdef __IOS__
"#extension GL_EXT_shader_framebuffer_fetch : enable\n"
#endif
"uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_bg;\n"
"uniform mediump vec4 col;\n" "uniform mediump vec4 col;\n"
"uniform mediump vec2 resolution;\n" "uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n" "uniform mediump float alpha;\n"
"in mediump vec2 uv;\n" "in mediump vec2 uv;\n"
#ifdef __IOS__
"inout mediump vec4 frag;\n"
#else
"out mediump vec4 frag;\n" "out mediump vec4 frag;\n"
#endif
"void main(){\n" "void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n"
" mediump vec4 fg = vec4(col.rgb, brush_alpha);\n" " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n"
#ifdef __IOS__
" mediump vec4 bg = frag;\n"
#else
" mediump vec4 bg = texture(tex_bg, uv2);\n" " mediump vec4 bg = texture(tex_bg, uv2);\n"
" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" #endif
//" if (fg.a < 1.0/255.0) { frag = bg; return; }\n"
" mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" " 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" " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
" frag = vec4(rgb, alpha_tot);\n" " frag = vec4(rgb, clamp(alpha_tot, 0.0, 1.0));\n"
"}\n"; "}\n";
// ALPHA LOCK // ALPHA LOCK
static const char* shader_stroke_lock_f = static const char* shader_stroke_lock_f =
SHADER_VERSION SHADER_VERSION
#ifdef __IOS__
"#extension GL_EXT_shader_framebuffer_fetch : enable\n"
#endif
"uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_bg;\n"
"uniform mediump sampler2D tex_mask;\n" "uniform mediump sampler2D tex_mask;\n"
@@ -191,32 +248,51 @@ void App::initShaders()
"uniform mediump vec2 resolution;\n" "uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n" "uniform mediump float alpha;\n"
"in mediump vec2 uv;\n" "in mediump vec2 uv;\n"
#ifdef __IOS__
"inout mediump vec4 frag;\n"
#else
"out mediump vec4 frag;\n" "out mediump vec4 frag;\n"
#endif
"void main(){\n" "void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n"
" mediump vec4 fg = vec4(col.rgb, brush_alpha);\n" " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n"
#ifdef __IOS__
" mediump vec4 bg = frag;\n"
#else
" mediump vec4 bg = texture(tex_bg, uv2);\n" " mediump vec4 bg = texture(tex_bg, uv2);\n"
#endif
" mediump vec4 msk = texture(tex_mask, uv2);\n" " mediump vec4 msk = texture(tex_mask, uv2);\n"
" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" //" if (fg.a < (1.0/255.0)) { return; }\n"
" mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" " 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" " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n"
" frag = vec4(rgb, min(alpha_tot, msk.a));\n" " frag = vec4(rgb, msk.a);\n"
"}\n"; "}\n";
// ERASER // ERASER
static const char* shader_stroke_erase_f = static const char* shader_stroke_erase_f =
SHADER_VERSION SHADER_VERSION
#ifdef __IOS__
"#extension GL_EXT_shader_framebuffer_fetch : enable\n"
#endif
"uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_bg;\n"
"uniform mediump vec4 col;\n" "uniform mediump vec4 col;\n"
"uniform mediump vec2 resolution;\n" "uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n" "uniform mediump float alpha;\n"
"in mediump vec2 uv;\n" "in mediump vec2 uv;\n"
#ifdef __IOS__
"inout mediump vec4 frag;\n"
#else
"out mediump vec4 frag;\n" "out mediump vec4 frag;\n"
#endif
"void main(){\n" "void main(){\n"
" mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n"
" mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n"
#ifdef __IOS__
" mediump vec4 bg = frag;\n"
#else
" mediump vec4 bg = texture(tex_bg, uv2);\n" " mediump vec4 bg = texture(tex_bg, uv2);\n"
#endif
" frag = vec4(bg.rgb, bg.a - bg.a * brush_alpha);\n" " frag = vec4(bg.rgb, bg.a - bg.a * brush_alpha);\n"
"}\n"; "}\n";
@@ -233,19 +309,36 @@ void App::initShaders()
"}"; "}";
static const char* shader_stroke_layer_f = static const char* shader_stroke_layer_f =
SHADER_VERSION SHADER_VERSION
#ifdef __IOS__
"#extension GL_EXT_shader_framebuffer_fetch : enable\n"
#endif
"uniform mediump sampler2D tex;\n" "uniform mediump sampler2D tex;\n"
"uniform mediump sampler2D tex_bg;\n" "uniform mediump sampler2D tex_bg;\n"
"uniform mediump vec2 resolution;\n" "uniform mediump vec2 resolution;\n"
"uniform mediump float alpha;\n" "uniform mediump float alpha;\n"
"uniform bool lock;\n"
"uniform bool erase;\n"
"in mediump vec2 uv;\n" "in mediump vec2 uv;\n"
#ifdef __IOS__
"inout mediump vec4 frag;\n"
#else
"out mediump vec4 frag;\n" "out mediump vec4 frag;\n"
#endif
"void main(){\n" "void main(){\n"
" mediump vec4 fg = texture(tex, uv) * vec4(1,1,1,alpha);\n" " mediump vec4 fg = texture(tex, uv) * vec4(1,1,1,alpha);\n"
#ifdef __IOS__
" mediump vec4 bg = frag;\n"
#else
" mediump vec4 bg = texture(tex_bg, uv);\n" " mediump vec4 bg = texture(tex_bg, uv);\n"
" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" #endif
" mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" //" if (fg.a < (1.0/255.0)) { frag = bg; return; }\n"
" mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" " if (erase){\n"
" frag = vec4(rgb, alpha_tot);\n" " frag = vec4(bg.rgb, bg.a - fg.a);\n"
" } else {\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, lock ? bg.a : alpha_tot);\n"
" }\n"
"}\n"; "}\n";
static const char* shader_checkerboard_v = static const char* shader_checkerboard_v =
@@ -304,6 +397,10 @@ void App::initShaders()
LOG("Failed to create shader Texture"); LOG("Failed to create shader Texture");
if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f)) if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f))
LOG("Failed to create shader TextureAlpha"); LOG("Failed to create shader TextureAlpha");
if (!ShaderManager::create(kShader::CompErase, shader_v, shader_comp_erase_f))
LOG("Failed to create shader CompErase");
if (!ShaderManager::create(kShader::CompDraw, shader_v, shader_comp_draw_f))
LOG("Failed to create shader CompDraw");
if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f)) if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f))
LOG("Failed to create shader Color"); LOG("Failed to create shader Color");
if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f)) if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f))

View File

@@ -81,9 +81,11 @@ void ui::Canvas::pick_update(int plane)
{ {
// copy to tmp2 for layer blending // copy to tmp2 for layer blending
glActiveTexture(GL_TEXTURE0); // TODO: maybe remove this line glActiveTexture(GL_TEXTURE0); // TODO: maybe remove this line
#ifndef __IOS__
m_tex2[i].bind(); m_tex2[i].bind();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height);
m_tex2[i].unbind(); m_tex2[i].unbind();
#endif
m_layers[layer_index].m_rtt[i].bindTexture(); m_layers[layer_index].m_rtt[i].bindTexture();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
@@ -122,12 +124,12 @@ glm::vec4 ui::Canvas::pick_get(glm::vec2 canvas_loc)
glm::vec3 ray_dir; glm::vec3 ray_dir;
glm::vec3 hit_pos; glm::vec3 hit_pos;
glm::vec3 hit_normal; glm::vec3 hit_normal;
glm::vec2 fb_pos;
int plane_id; int plane_id;
if (point_trace(canvas_loc, ray_origin, ray_dir, hit_pos, hit_normal, plane_id)) if (point_trace(canvas_loc, ray_origin, ray_dir, hit_pos, fb_pos, hit_normal, plane_id))
{ {
pick_update(plane_id); pick_update(plane_id);
glm::vec2 fbpos = (hit_pos.xy() * 0.5f + 0.5f) * glm::vec2(m_width, m_height); int i = (int)fb_pos.x + (int)fb_pos.y * m_width;
int i = (int)fbpos.x + (int)fbpos.y * m_width;
return glm::vec4(m_pick_data[plane_id][i]) / 255.f; return glm::vec4(m_pick_data[plane_id][i]) / 255.f;
} }
return {0,0,0,1}; return {0,0,0,1};
@@ -229,21 +231,21 @@ void ui::Canvas::stroke_draw()
else else
{ {
glDisable(GL_BLEND); glDisable(GL_BLEND);
if (m_state == kCanvasMode::Erase) // if (0 && m_state == kCanvasMode::Erase)
{ // {
ShaderManager::use(ui::kShader::StrokeErase); // ShaderManager::use(ui::kShader::StrokeErase);
//ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); // //ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
} // }
else if(m_layers[m_current_layer_idx].m_alpha_locked) // else if(m_layers[m_current_layer_idx].m_alpha_locked)
{ // {
ShaderManager::use(kShader::StrokeLock); // ShaderManager::use(kShader::StrokeLock);
ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); // ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
ShaderManager::u_int(kShaderUniform::TexMask, 2); // alpha mask // ShaderManager::u_int(kShaderUniform::TexMask, 2); // alpha mask
glActiveTexture(GL_TEXTURE2); // glActiveTexture(GL_TEXTURE2);
m_layers[m_current_layer_idx].m_rtt[i].bindTexture(); // m_layers[m_current_layer_idx].m_rtt[i].bindTexture();
glActiveTexture(GL_TEXTURE1); // glActiveTexture(GL_TEXTURE1);
} // }
else // else
{ {
ShaderManager::use(ui::kShader::Stroke); ShaderManager::use(ui::kShader::Stroke);
ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color); ShaderManager::u_vec4(kShaderUniform::Col, m_brush.m_tip_color);
@@ -311,10 +313,12 @@ void ui::Canvas::stroke_draw()
glm::vec2 pad(1); glm::vec2 pad(1);
glm::ivec2 tex_pos = glm::clamp(glm::floor(bb_min) - pad , { 0, 0 }, { m_width, m_height }); glm::ivec2 tex_pos = glm::clamp(glm::floor(bb_min) - pad , { 0, 0 }, { m_width, m_height });
glm::ivec2 tex_sz = glm::clamp(glm::ceil(bb_sz ) + pad*2.f, { 0, 0 }, (glm::vec2)(glm::ivec2(m_width, m_height) - tex_pos)); glm::ivec2 tex_sz = glm::clamp(glm::ceil(bb_sz ) + pad*2.f, { 0, 0 }, (glm::vec2)(glm::ivec2(m_width, m_height) - tex_pos));
#ifndef __IOS__
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
tex_pos.x, tex_pos.y, tex_pos.x, tex_pos.y,
tex_pos.x, tex_pos.y, tex_pos.x, tex_pos.y,
tex_sz.x, tex_sz.y); tex_sz.x, tex_sz.y);
#endif
m_dirty_box[i].xy = glm::min(m_dirty_box[i].xy(), (glm::vec2)tex_pos); m_dirty_box[i].xy = glm::min(m_dirty_box[i].xy(), (glm::vec2)tex_pos);
m_dirty_box[i].zw = glm::max(m_dirty_box[i].zw(), (glm::vec2)(tex_pos + tex_sz)); m_dirty_box[i].zw = glm::max(m_dirty_box[i].zw(), (glm::vec2)(tex_pos + tex_sz));
@@ -358,11 +362,10 @@ void ui::Canvas::stroke_draw()
} }
} }
bool ui::Canvas::point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, bool ui::Canvas::point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, int& out_plane_id) glm::vec3& hit_pos, glm::vec2& fb_pos, glm::vec3& hit_normal, int& out_plane_id)
{ {
point_unproject(loc, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir); point_unproject(loc, { 0, 0, m_box.zw }, m_mv, m_proj, ray_origin, ray_dir);
glm::vec3 hit; glm::vec3 hit;
glm::vec2 fb_pos;
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit)) if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit))
@@ -450,7 +453,7 @@ void ui::Canvas::stroke_commit()
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
m_dirty_box[i] = glm::vec4(0, 0, m_width, m_height); // reset bounding box //m_dirty_box[i] = glm::vec4(0, 0, m_width, m_height); // reset bounding box
if (!m_dirty_face[i]) if (!m_dirty_face[i])
continue; // no stroke on this face, skip it continue; // no stroke on this face, skip it
@@ -483,21 +486,53 @@ void ui::Canvas::stroke_commit()
m_sampler_bg.bind(1); m_sampler_bg.bind(1);
if (m_state == kCanvasMode::Erase) if (m_state == kCanvasMode::Erase)
{ {
ShaderManager::use(ui::kShader::Texture); ui::ShaderManager::use(kShader::CompErase);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
glActiveTexture(GL_TEXTURE0);
m_tex2[i].bind();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].bindTexture();
m_plane.draw_fill();
m_tmp[i].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_tex2[i].unbind();
} }
else else
{ {
ShaderManager::use(ui::kShader::StrokeLayer); ui::ShaderManager::use(kShader::CompDraw);
ShaderManager::u_int(kShaderUniform::TexBG, 1); ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity); ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
glActiveTexture(GL_TEXTURE0);
m_tex2[i].bind();
glActiveTexture(GL_TEXTURE1);
m_tmp[i].bindTexture();
m_plane.draw_fill();
m_tmp[i].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_tex2[i].unbind();
} }
ShaderManager::u_int(kShaderUniform::Tex, 0); // else
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); // {
m_plane.draw_fill(); // ShaderManager::use(ui::kShader::StrokeLayer);
m_sampler.unbind(); // ShaderManager::u_int(kShaderUniform::TexBG, 1);
m_sampler_bg.unbind(); // ShaderManager::u_int(kShaderUniform::Lock, m_layers[m_current_layer_idx].m_alpha_locked);
m_tex2[i].unbind(); // ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
m_tmp[i].unbindTexture(); //
// ShaderManager::u_int(kShaderUniform::Tex, 0);
// ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
// m_plane.draw_fill();
// m_sampler.unbind();
// m_sampler_bg.unbind();
// m_tex2[i].unbind();
// m_tmp[i].unbindTexture();
// }
m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer(); m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer();
} }
@@ -539,15 +574,15 @@ void ui::Canvas::stroke_start(glm::vec2 point, float pressure, const ui::Brush&
m_dirty_box[i] = glm::vec4(m_width, m_height, 0, 0); // reset bounding box m_dirty_box[i] = glm::vec4(m_width, m_height, 0, 0); // reset bounding box
m_dirty_face[i] = false; m_dirty_face[i] = false;
if (m_state == kCanvasMode::Erase) // if (m_state == kCanvasMode::Erase || m_layers[m_current_layer_idx].m_alpha_locked)
{ // {
m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer(); // m_layers[m_current_layer_idx].m_rtt[i].bindFramebuffer();
m_tmp[i].bindTexture(); // m_tmp[i].bindTexture();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height); // glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height);
m_tmp[i].unbindTexture(); // m_tmp[i].unbindTexture();
m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer(); // m_layers[m_current_layer_idx].m_rtt[i].unbindFramebuffer();
} // }
else // else
{ {
m_tmp[i].bindFramebuffer(); m_tmp[i].bindFramebuffer();
m_tmp[i].clear({ 0, 0, 0, 0 }); m_tmp[i].clear({ 0, 0, 0, 0 });

View File

@@ -82,6 +82,7 @@ public:
kCanvasMode m_state{ kCanvasMode::Draw }; kCanvasMode m_state{ kCanvasMode::Draw };
static std::vector<CanvasMode*> modes[]; static std::vector<CanvasMode*> modes[];
std::vector<CanvasMode*>* m_mode = nullptr; std::vector<CanvasMode*>* m_mode = nullptr;
kCanvasMode m_current_mode = kCanvasMode::Draw;
static void set_mode(kCanvasMode mode) static void set_mode(kCanvasMode mode)
{ {
if (I->m_mode) if (I->m_mode)
@@ -89,6 +90,7 @@ public:
m->leave(); m->leave();
I->m_mode = &modes[(int)mode]; I->m_mode = &modes[(int)mode];
I->m_state = mode; I->m_state = mode;
I->m_current_mode = mode;
} }
std::vector<Layer::Snapshot> m_layers_snapshot; std::vector<Layer::Snapshot> m_layers_snapshot;
@@ -126,7 +128,7 @@ public:
void point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj, void point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj,
glm::vec3 &out_origin, glm::vec3 &out_dir); glm::vec3 &out_origin, glm::vec3 &out_dir);
bool point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, bool point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, int& out_plane_id); glm::vec3& hit_pos, glm::vec2& fb_pos, glm::vec3& hit_normal, int& out_plane_id);
bool point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir, bool point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, glm::vec2& hit_fb_pos, int plane_id); glm::vec3& hit_pos, glm::vec3& hit_normal, glm::vec2& hit_fb_pos, int plane_id);
}; };

View File

@@ -76,6 +76,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{ {
m_picking = true; m_picking = true;
canvas->pick_start(); canvas->pick_start();
//canvas->m_show_tmp = true;
} }
else else
{ {
@@ -93,6 +94,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
if (m_dragging && m_picking) if (m_dragging && m_picking)
{ {
node->mouse_release(); node->mouse_release();
//canvas->m_show_tmp = false;
glm::vec4 pix = canvas->pick_get(loc); glm::vec4 pix = canvas->pick_get(loc);
auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2])); auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2]));
@@ -230,7 +232,8 @@ void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{ {
node->mouse_capture(); node->mouse_capture();
glm::vec3 ro, rd, hit_o, hit_d; glm::vec3 ro, rd, hit_o, hit_d;
if (canvas->point_trace(loc, ro, rd, hit_o, hit_d, m_plane_id)) glm::vec2 fb_pos;
if (canvas->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, m_plane_id))
{ {
m_lines.push_back({ hit_o, hit_d }); m_lines.push_back({ hit_o, hit_d });
origin = hit_o; origin = hit_o;
@@ -418,8 +421,9 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
case kEventType::MouseMove: case kEventType::MouseMove:
{ {
glm::vec3 ro, rd, hit_o, hit_d; glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 fb_pos;
int plane_id; int plane_id;
if (m_dragging && canvas->point_trace(loc, ro, rd, hit_o, hit_d, plane_id)) if (m_dragging && canvas->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, plane_id))
{ {
ui::Shape::vertex_t v; ui::Shape::vertex_t v;
v.pos = glm::vec4(hit_o, 1); v.pos = glm::vec4(hit_o, 1);

View File

@@ -2,6 +2,8 @@
#include "log.h" #include "log.h"
#include "node_canvas.h" #include "node_canvas.h"
#define RES 1024
Node* NodeCanvas::clone_instantiate() const Node* NodeCanvas::clone_instantiate() const
{ {
return new NodeCanvas(); return new NodeCanvas();
@@ -11,7 +13,7 @@ void NodeCanvas::init()
{ {
m_mouse_ignore = false; m_mouse_ignore = false;
m_canvas = std::make_unique<ui::Canvas>(); m_canvas = std::make_unique<ui::Canvas>();
m_canvas->create(512, 512); m_canvas->create(RES, RES);
m_sampler.create(GL_NEAREST); m_sampler.create(GL_NEAREST);
m_face_plane.create<1>(2, 2); m_face_plane.create<1>(2, 2);
m_line.create(); m_line.create();
@@ -25,7 +27,7 @@ void NodeCanvas::init()
void NodeCanvas::restore_context() void NodeCanvas::restore_context()
{ {
Node::restore_context(); Node::restore_context();
m_canvas->create(512, 512); m_canvas->create(RES, RES);
m_sampler.create(GL_NEAREST); m_sampler.create(GL_NEAREST);
m_face_plane.create<1>(2, 2); m_face_plane.create<1>(2, 2);
m_canvas->snapshot_restore(); m_canvas->snapshot_restore();
@@ -75,6 +77,7 @@ void NodeCanvas::draw()
m_sampler.bind(0); m_sampler.bind(0);
m_sampler.bind(1);
auto blend = glIsEnabled(GL_BLEND); auto blend = glIsEnabled(GL_BLEND);
glEnable(GL_BLEND); glEnable(GL_BLEND);
@@ -88,31 +91,60 @@ void NodeCanvas::draw()
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp); ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
m_face_plane.draw_fill(); m_face_plane.draw_fill();
ui::ShaderManager::use(kShader::TextureAlpha);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
for (auto layer_index : m_canvas->m_order) for (auto layer_index : m_canvas->m_order)
{ {
if (m_canvas->m_layers[layer_index].m_opacity == .0f) if (m_canvas->m_layers[layer_index].m_opacity == .0f)
continue; continue;
int z = m_canvas->m_order.size() - layer_index; int z = (int)m_canvas->m_order.size() - layer_index;
auto plane_mvp_z = proj * camera * glm::scale(glm::vec3(z)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1)); auto plane_mvp_z = proj * camera * glm::scale(glm::vec3(z)) * m_canvas->m_plane_transform[plane_index] * glm::translate(glm::vec3(0, 0, -1));
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
if (!(m_canvas->m_state == ui::Canvas::kCanvasMode::Erase && if (m_canvas->m_state == ui::Canvas::kCanvasMode::Erase && m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index))
{ {
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity); ui::ShaderManager::use(kShader::CompErase);
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture(); ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
m_face_plane.draw_fill(); ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
m_canvas->m_layers[layer_index].m_rtt[plane_index].unbindTexture(); ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
} }
if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index) else if(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
{ {
ui::ShaderManager::u_float(kShaderUniform::Alpha, ui::ShaderManager::use(kShader::CompDraw);
m_canvas->m_current_stroke->m_brush.m_tip_opacity * m_canvas->m_layers[layer_index].m_opacity); ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
}
else
{
ui::ShaderManager::use(kShader::TextureAlpha);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
}
ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
ui::ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[m_canvas->m_current_layer_idx].m_alpha_locked);
// if (!(m_canvas->m_state == ui::Canvas::kCanvasMode::Erase &&
// m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index))
{
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
glActiveTexture(GL_TEXTURE1);
m_canvas->m_tmp[plane_index].bindTexture(); m_canvas->m_tmp[plane_index].bindTexture();
m_face_plane.draw_fill(); m_face_plane.draw_fill();
m_canvas->m_tmp[plane_index].unbindTexture(); m_canvas->m_tmp[plane_index].unbindTexture();
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].unbindTexture();
} }
// if (m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
// {
// ui::ShaderManager::use(kShader::TextureAlpha);
// ui::ShaderManager::u_int(kShaderUniform::Tex, 0);
// ui::ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
// ui::ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
// ui::ShaderManager::u_float(kShaderUniform::Alpha,
// m_canvas->m_current_stroke->m_brush.m_tip_opacity * m_canvas->m_layers[layer_index].m_opacity);
// m_canvas->m_tmp[plane_index].bindTexture();
// m_face_plane.draw_fill();
// m_canvas->m_tmp[plane_index].unbindTexture();
// }
} }
} }
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);

View File

@@ -0,0 +1,47 @@
#include "pch.h"
#include "log.h"
#include "node_dialog_layer_rename.h"
#include "canvas.h"
#include "node_image_texture.h"
Node* NodeDialogLayerRename::clone_instantiate() const
{
return new NodeDialogLayerRename();
}
void NodeDialogLayerRename::clone_finalize(Node* dest) const
{
NodeDialogLayerRename* n = static_cast<NodeDialogLayerRename*>(dest);
n->init_controls();
}
void NodeDialogLayerRename::init()
{
auto tpl = static_cast<const NodeBorder*>(init_template("dialog-layer-rename"));
m_color = tpl->m_color;
m_border_color = tpl->m_border_color;;
m_thinkness = tpl->m_thinkness;;
init_controls();
}
void NodeDialogLayerRename::init_controls()
{
btn_ok = find<NodeButton>("btn-ok");
btn_cancel = find<NodeButton>("btn-cancel");
input = find<NodeTextInput>("txt-input");
btn_cancel->on_click = [this](Node*) {
destroy();
};
}
void NodeDialogLayerRename::loaded()
{
// ui::Image thumb = ui::Canvas::I->thumbnail_read(data_path);
// auto image_tex = find<NodeImageTexture>("thumb-tex");
// image_tex->tex.create(thumb);
}
std::string NodeDialogLayerRename::get_name()
{
return input ? input->m_string : "";
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "node_border.h"
#include "node_button.h"
#include "node_text_input.h"
class NodeDialogLayerRename : public NodeBorder
{
public:
NodeButton* btn_cancel;
NodeButton* btn_ok;
NodeTextInput* input;
std::string data_path;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
void init_controls();
virtual void loaded() override;
std::string get_name();
};

View File

@@ -10,6 +10,8 @@ enum class kShaderUniform : uint16_t
TexFG = const_hash("tex_fg"), TexFG = const_hash("tex_fg"),
TexBG = const_hash("tex_bg"), TexBG = const_hash("tex_bg"),
TexMask = const_hash("tex_mask"), TexMask = const_hash("tex_mask"),
TexStroke = const_hash("tex_stroke"),
Lock = const_hash("lock"),
Col = const_hash("col"), Col = const_hash("col"),
Tof = const_hash("tof"), Tof = const_hash("tof"),
Tsz = const_hash("tsz"), Tsz = const_hash("tsz"),
@@ -23,16 +25,18 @@ enum class kShader : uint16_t
ColorQuad = const_hash("color-quad"), ColorQuad = const_hash("color-quad"),
ColorHue = const_hash("color-hue"), ColorHue = const_hash("color-hue"),
Texture = const_hash("texture"), Texture = const_hash("texture"),
TextureAlpha = const_hash("texture-alpha"), TextureAlpha= const_hash("texture-alpha"),
CompErase = const_hash("comp-erase"),
CompDraw = const_hash("comp-draw"),
UVs = const_hash("uvs"), UVs = const_hash("uvs"),
Font = const_hash("font"), Font = const_hash("font"),
Atlas = const_hash("atlas"), Atlas = const_hash("atlas"),
Stroke = const_hash("stroke"), Stroke = const_hash("stroke"),
StrokeLock = const_hash("stroke-lock"), StrokeLock = const_hash("stroke-lock"),
StrokeErase = const_hash("stroke-erase"), StrokeErase = const_hash("stroke-erase"),
StrokeLayer = const_hash("stroke-layer"), StrokeLayer = const_hash("stroke-layer"),
Checkerboard= const_hash("checkerboard"), Checkerboard= const_hash("checkerboard"),
Equirect = const_hash("equirect"), Equirect = const_hash("equirect"),
}; };
class Shader class Shader
@@ -67,4 +71,4 @@ public:
static void invalidate(); static void invalidate();
}; };
} }