*/}}
Browse Source

Lock alpha and tint

YimingWu 3 weeks ago
parent
commit
28597e1e8c
4 changed files with 64 additions and 5 deletions
  1. 14 2
      ouroperations.c
  2. 2 1
      ourpaint.h
  3. 47 2
      ourshader.cpp
  4. 1 0
      ourtranslations.c

+ 14 - 2
ouroperations.c

@@ -284,7 +284,10 @@ void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
     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(&cb->PP,0));{
-            laShowLabel(uil,cl,"Mode:",0,0);laShowItem(uil,cr,0,"our.erasing");
+            b1=laBeginRow(uil,c,1,0);
+            laShowItem(uil,c,0,"our.erasing"); laShowItem(uil,c,0,"our.brush_lock")->Flags|=LA_UI_FLAGS_EXPAND;
+            laEndRow(uil,b1);
+            laShowLabel(uil,c,"Brush Settings:",0,0);
             laShowItem(uil,c,&cb->PP,"name");
             laShowItem(uil,cl,&cb->PP,"use_nodes");
 
@@ -1627,6 +1630,7 @@ void our_PaintDoDabsWithSmudgeSegments(OurLayer* l,int tl, int tr, int tu, int t
 
     glUseProgram(Our->CanvasProgram);
     glUniform1i(Our->uBrushErasing,Our->Erasing);
+    glUniform1i(Our->uBrushLock,Our->BrushLock);
     uniforms[Our->uBrushRoutineSelection]=Our->RoutineDoDabs;
     uniforms[Our->uMixRoutineSelection]=Our->SpectralMode?Our->RoutineDoMixSpectral:Our->RoutineDoMixNormal;
     glUniformSubroutinesuiv(GL_COMPUTE_SHADER,2,uniforms);
@@ -2625,6 +2629,7 @@ void ourui_ToolExtras(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColu
     laColumn *c = laFirstColumn(uil);
     laShowItemFull(uil,c,0,"our.tool",0,0,0,0)->Flags|=LA_UI_FLAGS_EXPAND|LA_UI_FLAGS_ICON;
     laShowItemFull(uil,c,0,"our.erasing",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0);
+    laShowItem(uil,c,0,"our.brush_lock")->Flags|=LA_UI_FLAGS_EXPAND|LA_UI_FLAGS_ICON;
     char str[100]; sprintf(str,"text=%s",MAIN.MenuProgramName);
     laShowItemFull(uil,c,0,"OUR_show_splash",0,str,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_NO_TOOLTIP|LA_UI_FLAGS_EXIT_WHEN_TRIGGERED;
     laShowSeparator(uil,c)->Expand=1;
@@ -2771,6 +2776,10 @@ void ourRegisterEverything(){
     p=laAddEnumProperty(pc,"erasing","Erasing","Is in erasing mode",LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(OurPaint,Erasing),0,0,0,0,0,0,0,0,0,0);
     laAddEnumItemAs(p,"FALSE","Draw","Is drawing mode",0,0);
     laAddEnumItemAs(p,"TRUE","Erase","Is erasing mode",1,0);
+    p=laAddEnumProperty(pc,"brush_lock","Lock values","Lock pixel values when applying brush dabs",0,0,0,0,0,offsetof(OurPaint,BrushLock),0,0,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(p,"NONE","Normal","Brush operates normally",0,U'🖌');
+    laAddEnumItemAs(p,"ALPHA","Alpha","Locks alpha channel",1,U'⮻');
+    laAddEnumItemAs(p,"TINT","Tint","Locks alpha channel and the brightness of the color",2,U'🌈');
     p=laAddEnumProperty(pc, "brush_page","Brush Page","Show brushes in pages",0,0,0,0,0,offsetof(OurPaint,BrushPage),0,ourset_BrushPage,0,0,0,0,0,0,0,0);
     laAddEnumItemAs(p,"ALL","~","Show all brushes",0,'~');
     laAddEnumItemAs(p,"P1","1","Show brush page 1",1,'1');
@@ -3047,11 +3056,13 @@ int ourInit(){
 
     Our->CanvasShader = glCreateShader(GL_COMPUTE_SHADER);
     const GLchar* source1 = OUR_CANVAS_SHADER;
-    glShaderSource(Our->CanvasShader, 1, &source1, NULL); glCompileShader(Our->CanvasShader);
+    char* UseContent=tnsEnsureShaderCommoms(source1,0,0);
+    glShaderSource(Our->CanvasShader, 1, &UseContent, NULL); glCompileShader(Our->CanvasShader);
     glGetShaderiv(Our->CanvasShader, GL_COMPILE_STATUS, &status);
     if (status == GL_FALSE){
         glGetShaderInfoLog(Our->CanvasShader, sizeof(error), 0, error); printf("Canvas shader error:\n%s", error); glDeleteShader(Our->CanvasShader); return 0;
     }
+    if(UseContent){ free(UseContent); }
 
     Our->CanvasProgram = glCreateProgram();
     glAttachShader(Our->CanvasProgram, Our->CanvasShader); glLinkProgram(Our->CanvasProgram);
@@ -3092,6 +3103,7 @@ int ourInit(){
     Our->uBrushForce=glGetUniformLocation(Our->CanvasProgram,"uBrushForce");
     Our->uBrushGunkyness=glGetUniformLocation(Our->CanvasProgram,"uBrushGunkyness");
     Our->uBrushErasing=glGetUniformLocation(Our->CanvasProgram,"uBrushErasing");
+    Our->uBrushLock=glGetUniformLocation(Our->CanvasProgram,"uBrushLock");
 
     Our->uBrushRoutineSelection=glGetSubroutineUniformLocation(Our->CanvasProgram, GL_COMPUTE_SHADER, "uBrushRoutineSelection");
     Our->RoutineDoDabs=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoDabs");

+ 2 - 1
ourpaint.h

@@ -341,7 +341,7 @@ STRUCTURE(OurPaint){
     real DefaultScale;
 
     int BrushPage;
-    int Tool,ActiveTool,Erasing,EventErasing;
+    int Tool,ActiveTool,Erasing,EventErasing,BrushLock;
     int LockBackground;
     int BackgroundType;
     int BackgroundRandom;
@@ -384,6 +384,7 @@ STRUCTURE(OurPaint){
     GLint uBrushRoutineSelection;
     GLint uMixRoutineSelection;
     GLint uBrushErasing;
+    GLint uBrushLock;
     GLint RoutineDoDabs;
     GLint RoutineDoSample;
     GLint RoutineDoMixNormal;

+ 47 - 2
ourshader.cpp

@@ -40,6 +40,7 @@ uniform float uBrushRecentness;
 uniform vec4 uBrushColor;
 uniform vec4 uBackgroundColor;
 uniform int uBrushErasing;
+uniform int uBrushLock;
 const vec4 p1_22=vec4(1.0/2.2,1.0/2.2,1.0/2.2,1.0/2.2);
 const vec4 p22=vec4(2.2,2.2,2.2,2.2);
 const float WGM_EPSILON=0.001f;
@@ -216,6 +217,46 @@ int dab(float d, vec2 fpx, vec4 color, float size, float hardness, float smudge,
     final=c2;
     return 1;
 }
+
+#ifndef saturate
+#define saturate(v) clamp(v, 0, 1)
+#endif
+const float HCV_EPSILON = 1e-10;
+const float HCY_EPSILON = 1e-10;
+vec3 hue_to_rgb(float hue){
+    float R = abs(hue * 6 - 3) - 1;
+    float G = 2 - abs(hue * 6 - 2);
+    float B = 2 - abs(hue * 6 - 4);
+    return saturate(vec3(R,G,B));
+}
+vec3 hcy_to_rgb(vec3 hcy){
+    const vec3 HCYwts = vec3(0.299, 0.587, 0.114);
+    vec3 RGB = hue_to_rgb(hcy.x);
+    float Z = dot(RGB, HCYwts);
+    if (hcy.z < Z) { hcy.y *= hcy.z / Z; }
+    else if (Z < 1) { hcy.y *= (1 - hcy.z) / (1 - Z); }
+    return (RGB - Z) * hcy.y + hcy.z;
+}
+vec3 rgb_to_hcv(vec3 rgb){
+    // Based on work by Sam Hocevar and Emil Persson
+    vec4 P = (rgb.g < rgb.b) ? vec4(rgb.bg, -1.0, 2.0/3.0) : vec4(rgb.gb, 0.0, -1.0/3.0);
+    vec4 Q = (rgb.r < P.x) ? vec4(P.xyw, rgb.r) : vec4(rgb.r, P.yzx);
+    float C = Q.x - min(Q.w, Q.y);
+    float H = abs((Q.w - Q.y) / (6 * C + HCV_EPSILON) + Q.z);
+    return vec3(H, C, Q.x);
+}
+vec3 rgb_to_hcy(vec3 rgb){
+    const vec3 HCYwts = vec3(0.299, 0.587, 0.114);
+    // Corrected by David Schaeffer
+    vec3 HCV = rgb_to_hcv(rgb);
+    float Y = dot(rgb, HCYwts);
+    float Z = dot(hue_to_rgb(HCV.x), HCYwts);
+    if (Y < Z) { HCV.y *= Z / (HCY_EPSILON + Y); }
+    else { HCV.y *= (1 - Z) / (HCY_EPSILON + 1 - Y); }
+    return vec3(HCV.x, HCV.y, Y);
+}
+
+
 subroutine void BrushRoutines();
 subroutine(BrushRoutines) void DoDabs(){
     ivec2 px = ivec2(gl_GlobalInvocationID.xy)+uBrushCorner;
@@ -228,8 +269,12 @@ subroutine(BrushRoutines) void DoDabs(){
     vec4 smudgec=pow(spectral_mix_unpre(pow(imageLoad(smudge_buckets,ivec2(1,0)),p1_22),pow(imageLoad(smudge_buckets,ivec2(0,0)),p1_22),uBrushRecentness),p22);
     vec4 final_color;
     dab(dd,origfpx,uBrushColor,uBrushSize,uBrushHardness,uBrushSmudge,smudgec,dabc,final_color);
-    dabc=final_color;
-    imageStore(img, px, dabc);
+    if(final_color.a>0){
+        if(uBrushLock==0){ dabc=final_color; }
+        else if(uBrushLock==1){ dabc.rgb=final_color.rgb/final_color.a*dabc.a;}
+        else if(uBrushLock==2){ vec3 xyz=rgb_to_hcy(dabc.rgb); xyz.xy=rgb_to_hcy(final_color.rgb).xy; dabc.rgb=hcy_to_rgb(xyz); }
+        imageStore(img, px, dabc);
+    }
 }
 subroutine(BrushRoutines) void DoSample(){
     ivec2 p=ivec2(gl_GlobalInvocationID.xy);

+ 1 - 0
ourtranslations.c

@@ -23,6 +23,7 @@ extern tnsMain* T;
 extern OurPaint *Our;
 
 static const char *entries[]={
+"Brush Settings:","笔刷设置:",
 "Boost","增强",
 "Transparent","透明",
 "Opaque","实色",