*/}}
소스 검색

Smudge okay and border

Yiming Wu 1 년 전
부모
커밋
58db2ab41e
3개의 변경된 파일170개의 추가작업 그리고 41개의 파일을 삭제
  1. 149 40
      ouroperations.c
  2. 1 1
      ourpaint.c
  3. 20 0
      ourpaint.h

+ 149 - 40
ouroperations.c

@@ -6,8 +6,8 @@ extern tnsMain* T;
 
 const char OUR_CANVAS_SHADER[]="#version 430\n\
 layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;\n\
-layout(rgba8, binding = 0) uniform image2D img;\n\
-layout(rgba8, binding = 1) coherent uniform image2D smudge_buckets;\n\
+layout(rgba16, binding = 0) uniform image2D img;\n\
+layout(rgba16, binding = 1) coherent uniform image2D smudge_buckets;\n\
 uniform ivec2 uBrushCorner;\n\
 uniform vec2 uBrushCenter;\n\
 uniform float uBrushSize;\n\
@@ -23,12 +23,16 @@ vec4 mix_over(vec4 colora, vec4 colorb){\n\
 float erase(float a, float target_a, float eraser_a){\n\
     return mix(a,target_a,eraser_a);\n\
 }\n\
+vec4 alpha_mix(vec4 c1, vec4 c2, float fac){\n\
+    return vec4(mix(c1.rgb*c1.a,c2.rgb*c2.a,fac)/(c1.a*(1-fac)+c2.a*fac+1e-3),mix(c1.a,c2.a,fac));\n\
+}\n\
 int dab(float d, vec4 color, float size, float hardness, float smudge, vec4 smudge_color, vec4 last_color, out vec4 final){\n\
-    vec4 cc; cc.rgb=mix(color,smudge_color,smudge*smudge_color.a).rgb;\n\
+    vec4 cc=color;\n\
     float fac=(1-pow(d/size,1+1/(1-hardness)));\n\
-    cc.a=clamp(mix(color.a,smudge_color.a,smudge)*fac,0,1);\n\
-    final=mix_over(cc,last_color);\n\
-    final.a=erase(final.a,mix(color.a,smudge_color.a,smudge),fac*smudge*(1-color.a));\n\
+    cc.a=color.a*fac*(1-smudge+1e-5);\n\
+    vec4 c1=mix_over(cc,last_color);\n\
+    vec4 c2=alpha_mix(c1,smudge_color,smudge*fac*color.a);\n\
+    final=c2;\n\
     return 1;\n\
 }\n\
 subroutine void BrushRoutines();\n\
@@ -110,26 +114,40 @@ void ourui_Brush(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laC
         laEndRow(uil,b);
     }laEndCondition(uil,b1);
 }
-void ourui_BrushesPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
-    laColumn* c=laFirstColumn(uil);
+void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil); laColumn* cl,*cr; laSplitColumn(uil,c,0.5); cl=laLeftColumn(c,0);cr=laRightColumn(c,0);
     laUiItem* b1;
 #define OUR_BR b1=laBeginRow(uil,c,0,0);
 #define OUR_ER laEndRow(uil,b1);
 
-    laUiItem* b=laOnConditionThat(uil,c,laPropExpression(0,"our.current_brush"));{
-        laShowItem(uil,c,0,"our.current_brush.name");
-        OUR_BR laShowItem(uil,c,0,"our.current_brush.size")->Expand=1; laShowItemFull(uil,c,0,"our.current_brush.pressure_size",0,"text=P",0,0); OUR_ER
-        OUR_BR laShowItem(uil,c,0,"our.current_brush.transparency")->Expand=1;  laShowItemFull(uil,c,0,"our.current_brush.pressure_transparency",0,"text=P",0,0); OUR_ER
-        OUR_BR laShowItem(uil,c,0,"our.current_brush.hardness")->Expand=1;  laShowItemFull(uil,c,0,"our.current_brush.pressure_hardness",0,"text=P",0,0); OUR_ER
-        OUR_BR laShowItem(uil,c,0,"our.current_brush.smudge")->Expand=1; laShowItemFull(uil,c,0,"our.current_brush.pressure_smudge",0,"text=P",0,0); OUR_ER
-        laShowItem(uil,c,0,"our.current_brush.dabs_per_size");
-        laShowItem(uil,c,0,"our.current_brush.smudge_resample_length");
-    }laEndCondition(uil,b);
-
-    laShowLabel(uil,c,"Select a brush:",0,0);
-
-    laShowItemFull(uil,c,0,"our.brushes",0,0,0,0);
-    laShowItem(uil,c,0,"OUR_new_brush");
+    laShowItem(uil,c,0,"our.tool")->Flags|=LA_UI_FLAGS_EXPAND;
+    laUiItem* bt=laOnConditionThat(uil,c,laEqual(laPropExpression(0,"our.tool"),laIntExpression(OUR_TOOL_PAINT)));{
+        laUiItem* b=laOnConditionThat(uil,c,laPropExpression(0,"our.current_brush"));{
+            laShowItem(uil,c,0,"our.current_brush.name");
+            OUR_BR laShowItem(uil,c,0,"our.current_brush.size")->Expand=1; laShowItemFull(uil,c,0,"our.current_brush.pressure_size",0,"text=P",0,0); OUR_ER
+            OUR_BR laShowItem(uil,c,0,"our.current_brush.transparency")->Expand=1;  laShowItemFull(uil,c,0,"our.current_brush.pressure_transparency",0,"text=P",0,0); OUR_ER
+            OUR_BR laShowItem(uil,c,0,"our.current_brush.hardness")->Expand=1;  laShowItemFull(uil,c,0,"our.current_brush.pressure_hardness",0,"text=P",0,0); OUR_ER
+            OUR_BR laShowItem(uil,c,0,"our.current_brush.smudge")->Expand=1; laShowItemFull(uil,c,0,"our.current_brush.pressure_smudge",0,"text=P",0,0); OUR_ER
+            laShowItem(uil,c,0,"our.current_brush.dabs_per_size");
+            laShowItem(uil,c,0,"our.current_brush.smudge_resample_length");
+        }laEndCondition(uil,b);
+
+        laShowLabel(uil,c,"Select a brush:",0,0);
+
+        laShowItemFull(uil,c,0,"our.brushes",0,0,0,0);
+        laShowItem(uil,c,0,"OUR_new_brush");
+    }laEndCondition(uil,bt);
+
+    bt=laOnConditionThat(uil,c,laEqual(laPropExpression(0,"our.tool"),laIntExpression(OUR_TOOL_CROP)));{
+        laShowItemFull(uil,c,0,"our.show_border",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0);
+        laUiItem* b=laOnConditionThat(uil,c,laPropExpression(0,"our.show_border"));{
+            laShowLabel(uil,cl,"Position:",0,0); laShowItem(uil,cr,0,"our.canvas.position")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+            laShowSeparator(uil,c);
+            laShowLabel(uil,cl,"Size:",0,0); laShowItem(uil,cr,0,"our.canvas.size")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+            laShowSeparator(uil,c);
+            laShowItem(uil,c,0,"our.border_alpha");
+        }laEndCondition(uil,b);
+    }laEndCondition(uil,bt);
 }
 void ourui_ColorPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
     laColumn* c=laFirstColumn(uil);
@@ -137,7 +155,6 @@ void ourui_ColorPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
     laShowItemFull(uil,c,0,"our.current_color",LA_WIDGET_FLOAT_COLOR_HCY,0,0,0);
 }
 
-
 void our_CanvasDrawTextures(){
     tnsUseImmShader; tnsEnableShaderv(T->immShader); tnsUniformUseTexture(T->immShader,0,0); tnsUseNoTexture();
     for(OurLayer* l=Our->Layers.pLast;l;l=l->Item.pPrev){
@@ -154,7 +171,6 @@ void our_CanvasDrawTextures(){
         if(any) tnsFlush();
     }
 }
-
 void our_CanvasDrawTiles(){
     OurLayer* l=Our->CurrentLayer; if(!l) return;
     tnsUseImmShader; tnsEnableShaderv(T->immShader); tnsUniformUseTexture(T->immShader,0,0); tnsUseNoTexture();
@@ -175,7 +191,21 @@ void our_CanvasDrawTiles(){
         }
     }
     if(any) tnsFlush();
-
+}
+void our_CanvasDrawCropping(OurCanvasDraw* ocd){
+    tnsUseImmShader; tnsEnableShaderv(T->immShader); tnsUniformUseTexture(T->immShader,0,0); tnsUseNoTexture();
+    tnsColor4d(0,0,0,Our->BorderAlpha);
+    tnsVertex2d(-1e6,Our->Y); tnsVertex2d(1e6,Our->Y); tnsVertex2d(-1e6,1e6); tnsVertex2d(1e6,1e6); tnsPackAs(GL_TRIANGLE_FAN);
+    tnsVertex2d(-1e6,Our->Y); tnsVertex2d(Our->X,Our->Y); tnsVertex2d(Our->X,Our->Y-Our->H); tnsVertex2d(-1e6,Our->Y-Our->H); tnsPackAs(GL_TRIANGLE_FAN);
+    tnsVertex2d(1e6,Our->Y); tnsVertex2d(Our->X+Our->W,Our->Y); tnsVertex2d(Our->X+Our->W,Our->Y-Our->H); tnsVertex2d(1e6,Our->Y-Our->H); tnsPackAs(GL_TRIANGLE_FAN);
+    tnsVertex2d(-1e6,Our->Y-Our->H); tnsVertex2d(1e6,Our->Y-Our->H); tnsVertex2d(-1e6,-1e6); tnsVertex2d(1e6,-1e6); tnsPackAs(GL_TRIANGLE_FAN);
+
+    if(Our->Tool==OUR_TOOL_CROP){
+        tnsColor4dv(laAccentColor(LA_BT_TEXT));
+        tnsVertex2d(Our->X,Our->Y); tnsVertex2d(Our->X+Our->W,Our->Y); tnsVertex2d(Our->X+Our->W,Our->Y-Our->H); tnsVertex2d(Our->X,Our->Y-Our->H);
+        tnsPackAs(GL_LINE_LOOP);
+        glLineWidth(3); tnsFlush(); glLineWidth(1);
+    }
 }
 
 
@@ -230,6 +260,7 @@ void our_CanvasDrawCanvas(laBoxedTheme *bt, OurPaint *unused_c, laUiItem* ui){
     tnsClearColor(LA_COLOR3(Our->BackgroundColor),1); tnsClearAll();
     //if(ocd->ShowTiles){ our_CanvasDrawTiles(); }
     our_CanvasDrawTextures();
+    if(Our->ShowBorder){ our_CanvasDrawCropping(ocd); }
 
     //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
 }
@@ -270,9 +301,9 @@ void our_LayerEnsureTiles(OurLayer* ol, real xmin,real xmax, real ymin,real ymax
         for(int col=l;col<=r;col++){
             if(ol->TexTiles[row][col]) continue;
             ol->TexTiles[row][col]=memAcquireSimple(sizeof(OurTexTile));
-            ol->TexTiles[row][col]->Texture=tnsCreate2DTexture(GL_RGBA8,OUR_TEX_TILE_W,OUR_TEX_TILE_W,0);
-            float initColor[]={0,0,0,0};
-            glClearTexImage(ol->TexTiles[row][col]->Texture->GLTexHandle, 0, GL_BGRA, GL_UNSIGNED_BYTE, &initColor);
+            ol->TexTiles[row][col]->Texture=tnsCreate2DTexture(GL_RGBA16,OUR_TEX_TILE_W,OUR_TEX_TILE_W,0);
+            uint16_t initColor[]={0,0,0,0};
+            glClearTexImage(ol->TexTiles[row][col]->Texture->GLTexHandle, 0, GL_RGBA, GL_UNSIGNED_SHORT, 0);
         }
     }
     *tl=l; *tr=r; *tu=u; *tb=b;
@@ -341,7 +372,7 @@ void our_PaintDoDabs(OurLayer* l,int tl, int tr, int tu, int tb, int Start, int
     for(int row=tb;row<=tu;row++){
         for(int col=tl;col<=tr;col++){
             OurTexTile* ott=l->TexTiles[row][col];
-            glBindImageTexture(0, ott->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
+            glBindImageTexture(0, ott->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
             int sx=((real)col-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_SEAM,sy=((real)row-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_SEAM;
             for(int i=Start;i<End;i++){
                 our_PaintDoDab(&Our->Dabs[i],sx,sx+OUR_TEX_TILE_W,sy,sy+OUR_TEX_TILE_W);
@@ -371,9 +402,9 @@ void our_PaintDoDabsWithSmudgeSegments(OurLayer* l,int tl, int tr, int tu, int t
             float x=Our->Dabs[oss->Start].X, y=Our->Dabs[oss->Start].Y;
             int col=(int)(floor(OUR_TEX_TILE_CTR+x/OUR_TEX_TILE_W_USE+0.5)); TNS_CLAMP(col,0,OUR_TEX_TILES_PER_ROW-1);
             int row=(int)(floor(OUR_TEX_TILE_CTR+y/OUR_TEX_TILE_W_USE+0.5)); TNS_CLAMP(row,0,OUR_TEX_TILES_PER_ROW-1);
-            glBindImageTexture(0, l->TexTiles[row][col]->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
+            glBindImageTexture(0, l->TexTiles[row][col]->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
             int sx=((real)col-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_SEAM,sy=((real)row-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_SEAM;
-            glBindImageTexture(1, Our->SmudgeTexture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
+            glBindImageTexture(1, Our->SmudgeTexture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
             our_PaintDoSample(x,y,sx,sy);
             Our->CurrentBrush->SmudgeRestart=0;
         }
@@ -383,7 +414,7 @@ void our_PaintDoDabsWithSmudgeSegments(OurLayer* l,int tl, int tr, int tu, int t
         for(int row=tb;row<=tu;row++){
             for(int col=tl;col<=tr;col++){
                 OurTexTile* ott=l->TexTiles[row][col];
-                tnsBindTexture(ott->Texture); glBindImageTexture(0, ott->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
+                tnsBindTexture(ott->Texture); glBindImageTexture(0, ott->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
                 int sx=((real)col-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_SEAM,sy=((real)row-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_SEAM;
                 for(int i=oss->Start;i<oss->End;i++){
                     our_PaintDoDab(&Our->Dabs[i],sx,sx+OUR_TEX_TILE_W,sy,sy+OUR_TEX_TILE_W);
@@ -405,6 +436,32 @@ void our_ReadWidgetColor(laCanvasExtra*e,int x,int y){
     Our->CurrentColor[2]=(real)color[2]/255*a;
 }
 
+void our_StartCropping(OurCanvasDraw* cd){
+    if(cd->CanvasDownX<Our->X){
+        if(cd->CanvasDownY<Our->Y-Our->H){ cd->AtCrop=OUR_AT_CROP_BL; }
+        elif(cd->CanvasDownY>=Our->Y-Our->H&&cd->CanvasDownY<=Our->Y){ cd->AtCrop=OUR_AT_CROP_L; }
+        elif(cd->CanvasDownY>Our->Y){ cd->AtCrop=OUR_AT_CROP_UL; }
+    }elif(cd->CanvasDownX>=Our->X&&cd->CanvasDownX<=Our->X+Our->W){
+        if(cd->CanvasDownY<Our->Y-Our->H){ cd->AtCrop=OUR_AT_CROP_B; }
+        elif(cd->CanvasDownY>=Our->Y-Our->H&&cd->CanvasDownY<=Our->Y){ cd->AtCrop=OUR_AT_CROP_CENTER; }
+        elif(cd->CanvasDownY>Our->Y){ cd->AtCrop=OUR_AT_CROP_U; }
+    }elif(cd->CanvasDownX>Our->X+Our->W){
+        if(cd->CanvasDownY<Our->Y-Our->H){ cd->AtCrop=OUR_AT_CROP_BR; }
+        elif(cd->CanvasDownY>=Our->Y-Our->H&&cd->CanvasDownY<=Our->Y){ cd->AtCrop=OUR_AT_CROP_R; }
+        elif(cd->CanvasDownY>Our->Y){ cd->AtCrop=OUR_AT_CROP_UR; }
+    }
+}
+void our_DoCropping(OurCanvasDraw* cd, real x, real y){
+    int dx=x-cd->CanvasLastX, dy=y-cd->CanvasLastY;
+    if(cd->AtCrop==OUR_AT_CROP_B||cd->AtCrop==OUR_AT_CROP_BL||cd->AtCrop==OUR_AT_CROP_BR){ Our->H-=dy; }
+    if(cd->AtCrop==OUR_AT_CROP_U||cd->AtCrop==OUR_AT_CROP_UL||cd->AtCrop==OUR_AT_CROP_UR){ Our->Y+=dy; Our->H+=dy; }
+    if(cd->AtCrop==OUR_AT_CROP_L||cd->AtCrop==OUR_AT_CROP_BL||cd->AtCrop==OUR_AT_CROP_UL){ Our->X+=dx; Our->W-=dx; }
+    if(cd->AtCrop==OUR_AT_CROP_R||cd->AtCrop==OUR_AT_CROP_BR||cd->AtCrop==OUR_AT_CROP_UR){ Our->W+=dx; }
+    if(cd->AtCrop==OUR_AT_CROP_CENTER){ Our->Y+=dy; Our->X+=dx; }
+    if(Our->W<32) Our->W=32; if(Our->H<32) Our->H=32; 
+    cd->CanvasLastX+=dx; cd->CanvasLastY+=dy;
+}
+
 int ourinv_NewLayer(laOperator* a, laEvent* e){
     our_NewLayer("Our Layer"); laNotifyUsers("our.canvas.layers");
     return LA_FINISHED;
@@ -438,15 +495,17 @@ int ourinv_MoveBrush(laOperator* a, laEvent* e){
     return LA_FINISHED;
 }
 
-int ourinv_Paint(laOperator* a, laEvent* e){
+int ourinv_Action(laOperator* a, laEvent* e){
     OurLayer* l=Our->CurrentLayer; OurCanvasDraw *ex = a->This?a->This->EndInstance:0; OurBrush* ob=Our->CurrentBrush; if(!l||!ex||!ob) return LA_CANCELED;
     our_PaintResetBrushState(ob);
     real x,y; our_UiToCanvas(&ex->Base,e,&x,&y); ex->CanvasLastX=x;ex->CanvasLastY=y;ex->LastPressure=e->Pressure;
+    ex->CanvasDownX=x; ex->CanvasDownY=y;
+    Our->ActiveTool=Our->Tool;
+    if(Our->ActiveTool==OUR_TOOL_CROP){ if(!Our->ShowBorder) return LA_FINISHED; our_StartCropping(ex); }
     return LA_RUNNING;
 }
 int ourmod_Paint(laOperator* a, laEvent* e){
     OurLayer* l=Our->CurrentLayer; OurCanvasDraw *ex = a->This?a->This->EndInstance:0; OurBrush* ob=Our->CurrentBrush; if(!l||!ex||!ob) return LA_CANCELED;
-
     if(e->Type==LA_L_MOUSE_UP || e->Type==LA_R_MOUSE_DOWN || e->Type==LA_ESCAPE_DOWN){ return LA_FINISHED; }
 
     if(e->Type==LA_MOUSEMOVE||e->Type==LA_L_MOUSE_DOWN){
@@ -461,6 +520,29 @@ int ourmod_Paint(laOperator* a, laEvent* e){
 
     return LA_RUNNING;
 }
+int ourmod_Crop(laOperator* a, laEvent* e){
+    OurLayer* l=Our->CurrentLayer; OurCanvasDraw *ex = a->This?a->This->EndInstance:0; OurBrush* ob=Our->CurrentBrush; if(!l||!ex||!ob) return LA_CANCELED;
+    if(e->Type==LA_L_MOUSE_UP || e->Type==LA_R_MOUSE_DOWN || e->Type==LA_ESCAPE_DOWN){ return LA_FINISHED; }
+
+    if(e->Type==LA_MOUSEMOVE||e->Type==LA_L_MOUSE_DOWN){
+        real x,y; our_UiToCanvas(&ex->Base,e,&x,&y);
+        our_DoCropping(ex,x,y);
+        laNotifyUsers("our.canvas");
+    }
+
+    return LA_RUNNING;
+}
+int ourmod_Action(laOperator* a, laEvent* e){
+    OurCanvasDraw *ex = a->This?a->This->EndInstance:0; if(!ex) return LA_CANCELED;
+    switch(Our->ActiveTool){
+    case OUR_TOOL_PAINT: OurLayer* l=Our->CurrentLayer; OurBrush* ob=Our->CurrentBrush; if(!l||!ob) return LA_CANCELED;
+        return ourmod_Paint(a,e);
+    case OUR_TOOL_CROP:
+        return ourmod_Crop(a,e);
+    default: return LA_FINISHED;
+    }
+    return LA_RUNNING;
+}
 int ourinv_PickColor(laOperator* a, laEvent* e){
     OurLayer* l=Our->CurrentLayer; OurCanvasDraw *ex = a->This?a->This->EndInstance:0; OurBrush* ob=Our->CurrentBrush; if(!l||!ex||!ob) return LA_CANCELED;
     laUiItem* ui=ex->Base.ParentUi;
@@ -499,8 +581,22 @@ void ourset_BrushMove(OurBrush* b, int move){
     elif(move>0 && b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
 }
 void ourset_BackgroundColor(void* unused, real* arr){
-    memcpy(Our->BackgroundColor, arr, sizeof(real)*3);
-    laNotifyUsers("our.canvas");
+    memcpy(Our->BackgroundColor, arr, sizeof(real)*3); laNotifyUsers("our.canvas");
+}
+void ourset_BorderAlpha(void* unused, real a){
+    Our->BorderAlpha=a; laNotifyUsers("our.canvas");
+}
+void ourset_Tool(void* unused, int a){
+    Our->Tool=a; laNotifyUsers("our.canvas");
+}
+void ourset_ShowBorder(void* unused, int a){
+    Our->ShowBorder=a; laNotifyUsers("our.canvas");
+}
+void ourset_CanvasSize(void* unused, int* wh){
+    Our->W=wh[0]; Our->H=wh[1]; if(Our->W<32) Our->W=32; if(Our->H<32) Our->H=32; laNotifyUsers("our.canvas");
+}
+void ourset_CanvasPosition(void* unused, int* xy){
+    Our->X=xy[0]; Our->Y=xy[1]; laNotifyUsers("our.canvas");
 }
 
 #define OUR_ADD_PRESSURE_SWITCH(p)\
@@ -516,12 +612,12 @@ void ourRegisterEverything(){
     laCreateOperatorType("OUR_new_brush","New Brush","Create a new brush",0,0,0,ourinv_NewBrush,0,'+',0);
     laCreateOperatorType("OUR_remove_brush","Remove Brush","Remove this brush",0,0,0,ourinv_RemoveBrush,0,L'🗴',0);
     laCreateOperatorType("OUR_move_brush","Move Brush","Remove this brush",0,0,0,ourinv_MoveBrush,0,0,0);
-    laCreateOperatorType("OUR_paint","Paint","Paint on a layer",0,0,0,ourinv_Paint,ourmod_Paint,0,LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("OUR_action","Action","Doing action on a layer",0,0,0,ourinv_Action,ourmod_Action,0,LA_EXTRA_TO_PANEL);
     laCreateOperatorType("OUR_pick","Pick color","Pick color on the widget",0,0,0,ourinv_PickColor,ourmod_PickColor,0,LA_EXTRA_TO_PANEL);
 
     laRegisterUiTemplate("panel_canvas", "Canvas", ourui_CanvasPanel, 0, 0,"Our Paint");
     laRegisterUiTemplate("panel_layers", "Layers", ourui_LayersPanel, 0, 0,0);
-    laRegisterUiTemplate("panel_brushes", "Brushes", ourui_BrushesPanel, 0, 0,0);
+    laRegisterUiTemplate("panel_tools", "Tools", ourui_ToolsPanel, 0, 0,0);
     laRegisterUiTemplate("panel_color", "Color", ourui_ColorPanel, 0, 0,0);
     
     pc=laDefineRoot();
@@ -533,6 +629,13 @@ void ourRegisterEverything(){
     laAddSubGroup(pc,"current_brush","Current Brush","Current brush","our_brush",0,0,0,offsetof(OurPaint,CurrentBrush),ourget_FirstBrush,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
     laAddFloatProperty(pc,"current_color","Current Color","Current color used to paint",0,0,0,1,0,0.05,0.8,0,offsetof(OurPaint,CurrentColor),0,0,4,0,0,0,0,0,0,0,0);
     laAddFloatProperty(pc,"background_color","Background Color","Background color of the canvas",0,0,0,1,0,0.05,0.8,0,offsetof(OurPaint,BackgroundColor),0,0,3,0,0,0,0,ourset_BackgroundColor,0,0,0);
+    laAddFloatProperty(pc,"border_alpha","Border Alpha","Alpha of the border region around the canvas",0,0,0,1,0,0.05,0.5,0,offsetof(OurPaint,BorderAlpha),0,0,0,0,0,0,0,ourset_BorderAlpha,0,0,0);
+    p=laAddEnumProperty(pc,"tool","Tool","Tool to use on the canvas",0,0,0,0,0,offsetof(OurPaint,Tool),0,ourset_Tool,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(p,"PAINT","Paint","Paint stuff on the canvas",OUR_TOOL_PAINT,L'🖌');
+    laAddEnumItemAs(p,"CROP","Cropping","Crop the focused region",OUR_TOOL_CROP,L'🖼');
+    p=laAddEnumProperty(pc,"show_border","Show Border","Whether to show border on the canvas",0,0,0,0,0,offsetof(OurPaint,ShowBorder),0,ourset_ShowBorder,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(p,"FALSE","No","Dont' show border on the canvas",OUR_TOOL_PAINT,L'🖌');
+    laAddEnumItemAs(p,"TRUE","Yes","Show border on the canvas",OUR_TOOL_CROP,L'🖼');
     
     pc=laAddPropertyContainer("our_brush","Our Brush","OurPaint brush",0,0,sizeof(OurBrush),0,0,2);
     laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurBrush,Name),0,0,0,0,LA_AS_IDENTIFIER);
@@ -557,6 +660,8 @@ void ourRegisterEverything(){
     pc=laAddPropertyContainer("our_canvas","Our Canvas","OurPaint canvas",0,0,sizeof(OurPaint),0,0,1);
     laAddSubGroup(pc,"layers","Layers","Layers","our_layer",0,0,ourui_Layer,offsetof(OurPaint,CurrentLayer),0,0,0,0,0,0,offsetof(OurPaint,Layers),0);
     laAddSubGroup(pc,"current_layer","Current Layer","Current layer","our_layer",0,0,0,offsetof(OurPaint,CurrentLayer),ourget_FirstLayer,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);
+    laAddIntProperty(pc,"size","Size","Size of the cropping area",0,"X,Y","px",0,0,0,2400,0,offsetof(OurPaint,W),0,0,2,0,0,0,0,ourset_CanvasSize,0,0,0);
+    laAddIntProperty(pc,"position","Position","Position of the cropping area",0,"X,Y","px",0,0,0,2400,0,offsetof(OurPaint,X),0,0,2,0,0,0,0,ourset_CanvasPosition,0,0,0);
 
     pc=laAddPropertyContainer("our_layer","Our Layer","OurPaint layer",0,0,sizeof(OurLayer),0,0,1);
     laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurLayer,Name),0,0,0,0,LA_AS_IDENTIFIER);
@@ -572,7 +677,7 @@ void ourRegisterEverything(){
     laAssignNewKey(km, 0, "LA_2d_view_zoom", LA_KM_SEL_UI_EXTRA, 0, LA_MOUSE_WHEEL_UP, 0, "direction=in");
     laAssignNewKey(km, 0, "LA_2d_view_move", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT, LA_L_MOUSE_DOWN, 0, 0);
     laAssignNewKey(km, 0, "LA_2d_view_move", LA_KM_SEL_UI_EXTRA, 0, LA_M_MOUSE_DOWN, 0, 0);
-    laAssignNewKey(km, 0, "OUR_paint", LA_KM_SEL_UI_EXTRA, 0, LA_L_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "OUR_action", LA_KM_SEL_UI_EXTRA, 0, LA_L_MOUSE_DOWN, 0, 0);
     laAssignNewKey(km, 0, "OUR_pick", LA_KM_SEL_UI_EXTRA, 0, LA_R_MOUSE_DOWN, 0, 0);
 }
 
@@ -584,7 +689,7 @@ void ourInit(){
 
     char error[1024]; int status;
 
-    Our->SmudgeTexture=tnsCreate2DTexture(GL_RGBA,256,1,0);
+    Our->SmudgeTexture=tnsCreate2DTexture(GL_RGBA16,256,1,0);
 
     Our->CanvasShader = glCreateShader(GL_COMPUTE_SHADER);
     const GLchar* source = OUR_CANVAS_SHADER;
@@ -619,6 +724,10 @@ void ourInit(){
     Our->RoutineDoDabs=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoDabs");
     Our->RoutineDoSample=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoSample");
 
+    Our->X=-2800/2; Our->W=2800;
+    Our->Y=2400/2;  Our->H=2400;
+    Our->BorderAlpha=0.6;
+
     tnsEnableShaderv(T->immShader);
 }
 

+ 1 - 1
ourpaint.c

@@ -21,7 +21,7 @@ int main(int argc, char *argv[]){
     laBlock* br=b->B2;
     laSplitBlockVertical(br,0.6);
     laCreatePanel(br->B1, "panel_color");
-    laCreatePanel(br->B1, "panel_brushes");
+    laCreatePanel(br->B1, "panel_tools");
     laCreatePanel(br->B2, "panel_layers");
 
     laStartWindow(w);

+ 20 - 0
ourpaint.h

@@ -1,9 +1,21 @@
 #include "la_5.h"
 
+#define OUR_AT_CROP_CENTER 0
+#define OUR_AT_CROP_L 1
+#define OUR_AT_CROP_R 2
+#define OUR_AT_CROP_U 3
+#define OUR_AT_CROP_B 4
+#define OUR_AT_CROP_UL 5
+#define OUR_AT_CROP_UR 6
+#define OUR_AT_CROP_BL 7
+#define OUR_AT_CROP_BR 8
+
 STRUCTURE(OurCanvasDraw){
     laCanvasExtra Base;
     int ShowTiles;
+    int AtCrop;
     real CanvasLastX,CanvasLastY;
+    real CanvasDownX,CanvasDownY;
     real LastPressure;
 };
 
@@ -51,6 +63,9 @@ STRUCTURE(OurDab){
     float Color[4];
 };
 
+#define OUR_TOOL_PAINT 0
+#define OUR_TOOL_CROP 1
+
 STRUCTURE(OurPaint){
     real pad;
 
@@ -61,6 +76,10 @@ STRUCTURE(OurPaint){
     OurBrush*    CurrentBrush;
     OurDab* Dabs; int NextDab,MaxDab;
 
+    int Tool,ActiveTool;
+    int X,Y,W,H; //border
+    int ShowBorder,UseBorder;
+
     tnsTexture* SmudgeTexture;
     GLuint CanvasShader;
     GLuint CanvasProgram;
@@ -76,6 +95,7 @@ STRUCTURE(OurPaint){
 
     real CurrentColor[4];
     real BackgroundColor[3];
+    real BorderAlpha;
 };
 
 void ourInit();