*/}}

2 Commitit cc7f5c9376 ... ff5c96984e

Tekijä SHA1 Viesti Päivämäärä
  YimingWu ff5c96984e Debayer display 3 päivää sitten
  YimingWu 3419505c06 Compose rgba add with straight alpha, export fix 3 päivää sitten
3 muutettua tiedostoa jossa 233 lisäystä ja 53 poistoa
  1. 80 45
      ouroperations.c
  2. 4 2
      ourpaint.h
  3. 149 6
      ourshader.cpp

+ 80 - 45
ouroperations.c

@@ -121,35 +121,37 @@ void our_RecordUndo(OurLayer* ol, real xmin,real xmax, real ymin,real ymax,int A
 
 void our_CanvasAlphaOver(OUR_PIX_COMPACT* target, OUR_PIX_COMPACT* source, real alpha){
     real a_1=(real)(OUR_PIX_MAX-source[3]*alpha)/OUR_PIX_MAX;
-    int a=(int)(source[3])*alpha+(int)(target[3])*a_1; TNS_CLAMP(a,0,OUR_PIX_MAX);
-    int r=(int)(source[0])*alpha+(int)(target[0])*a_1; TNS_CLAMP(r,0,OUR_PIX_MAX);
-    int g=(int)(source[1])*alpha+(int)(target[1])*a_1; TNS_CLAMP(g,0,OUR_PIX_MAX);
-    int b=(int)(source[2])*alpha+(int)(target[2])*a_1; TNS_CLAMP(b,0,OUR_PIX_MAX);
+    uint32_t a=(uint32_t)(source[3])*alpha+(uint32_t)(target[3])*a_1; TNS_CLAMP(a,0,OUR_PIX_MAX);
+    uint32_t r=(uint32_t)(source[0])*alpha+(uint32_t)(target[0])*a_1; TNS_CLAMP(r,0,OUR_PIX_MAX);
+    uint32_t g=(uint32_t)(source[1])*alpha+(uint32_t)(target[1])*a_1; TNS_CLAMP(g,0,OUR_PIX_MAX);
+    uint32_t b=(uint32_t)(source[2])*alpha+(uint32_t)(target[2])*a_1; TNS_CLAMP(b,0,OUR_PIX_MAX);
     target[3]=a; target[0]=r; target[1]=g; target[2]=b;
 }
 void our_CanvasAdd(OUR_PIX_COMPACT* target, OUR_PIX_COMPACT* source, real alpha){
-    int a=((int)source[3]*alpha+(int)target[3]); TNS_CLAMP(a,0,OUR_PIX_MAX);
-    int r=((int)source[0]*alpha+(int)target[0]); TNS_CLAMP(r,0,OUR_PIX_MAX);
-    int g=((int)source[1]*alpha+(int)target[1]); TNS_CLAMP(g,0,OUR_PIX_MAX);
-    int b=((int)source[2]*alpha+(int)target[2]); TNS_CLAMP(b,0,OUR_PIX_MAX);
+    uint32_t a=((uint32_t)source[3]*alpha+(uint32_t)target[3]); TNS_CLAMP(a,0,OUR_PIX_MAX);
+    uint32_t r=((uint32_t)source[0]*alpha+(uint32_t)target[0]); TNS_CLAMP(r,0,OUR_PIX_MAX);
+    uint32_t g=((uint32_t)source[1]*alpha+(uint32_t)target[1]); TNS_CLAMP(g,0,OUR_PIX_MAX);
+    uint32_t b=((uint32_t)source[2]*alpha+(uint32_t)target[2]); TNS_CLAMP(b,0,OUR_PIX_MAX);
     target[3]=a; target[0]=r; target[1]=g; target[2]=b;
 }
 void our_CanvasAlphaOverStraight(OUR_PIX_COMPACT* target, OUR_PIX_COMPACT* source, real alpha){
     real a_1=(real)(OUR_PIX_MAX-source[3]*alpha)/OUR_PIX_MAX;
-    int a=(int)(source[3])*alpha+(int)(target[3])*a_1; TNS_CLAMP(a,0,OUR_PIX_MAX);
-    int r=((int)(source[0])*alpha*source[3]+(int)(target[0])*a_1*target[3])/(a); TNS_CLAMP(r,0,OUR_PIX_MAX);
-    int g=((int)(source[1])*alpha*source[3]+(int)(target[1])*a_1*target[3])/(a); TNS_CLAMP(g,0,OUR_PIX_MAX);
-    int b=((int)(source[2])*alpha*source[3]+(int)(target[2])*a_1*target[3])/(a); TNS_CLAMP(b,0,OUR_PIX_MAX);
+    uint64_t a=(uint64_t)(source[3])*alpha+(uint64_t)(target[3])*a_1; TNS_CLAMP(a,0,OUR_PIX_MAX);
+    uint64_t r=((uint64_t)(source[0])*alpha*source[3]+(uint64_t)(target[0])*a_1*target[3])/a; TNS_CLAMP(r,0,OUR_PIX_MAX);
+    uint64_t g=((uint64_t)(source[1])*alpha*source[3]+(uint64_t)(target[1])*a_1*target[3])/a; TNS_CLAMP(g,0,OUR_PIX_MAX);
+    uint64_t b=((uint64_t)(source[2])*alpha*source[3]+(uint64_t)(target[2])*a_1*target[3])/a; TNS_CLAMP(b,0,OUR_PIX_MAX);
     target[3]=a; target[0]=r; target[1]=g; target[2]=b;
 }
 void our_CanvasAddStraight(OUR_PIX_COMPACT* target, OUR_PIX_COMPACT* source, real alpha){
-    int a=((int)source[3]*alpha+(int)target[3]); TNS_CLAMP(a,0,OUR_PIX_MAX);
-    int r=((int)source[0]*alpha+(int)target[0]); TNS_CLAMP(r,0,OUR_PIX_MAX);
-    int g=((int)source[1]*alpha+(int)target[1]); TNS_CLAMP(g,0,OUR_PIX_MAX);
-    int b=((int)source[2]*alpha+(int)target[2]); TNS_CLAMP(b,0,OUR_PIX_MAX);
+    uint64_t a=((uint64_t)source[3]*alpha+(uint64_t)target[3]); TNS_CLAMP(a,0,OUR_PIX_MAX);
+    uint64_t r=((uint64_t)source[0]*alpha*source[3]+(uint64_t)target[0]*target[3])/a; TNS_CLAMP(r,0,OUR_PIX_MAX);
+    uint64_t g=((uint64_t)source[1]*alpha*source[3]+(uint64_t)target[1]*target[3])/a; TNS_CLAMP(g,0,OUR_PIX_MAX);
+    uint64_t b=((uint64_t)source[2]*alpha*source[3]+(uint64_t)target[2]*target[3])/a; TNS_CLAMP(b,0,OUR_PIX_MAX);
     target[3]=a; target[0]=r; target[1]=g; target[2]=b;
 }
 
+typedef void (*our_MixFuncRGBA)(OUR_PIX_COMPACT* target, OUR_PIX_COMPACT* source, real alpha);
+
 void our_InitRGBProfile(int Linear,cmsCIExyYTRIPLE* primaries_pre_quantized, void** ptr, int* psize, char* copyright, char* manufacturer, char* description){
     cmsCIExyY d65_srgb_adobe_specs = {0.3127, 0.3290, 1.0};
     cmsToneCurve*tonecurve; cmsToneCurve*curve[3];
@@ -767,6 +769,8 @@ void ourui_OurPreference(laUiList *uil, laPropPack *This, laPropPack *DetachedPr
     laShowItem(uil,cr,0,"our.preferences.canvas_default_scale");
     laShowItem(uil,cl,0,"our.preferences.show_grid");
     laShowItem(uil,cr,0,"our.preferences.multithread_write");
+    laShowLabel(uil,c,"Pigment Display Method:",0,0);
+    laShowItem(uil,c,0,"our.preferences.pigment_display_method")->Flags|=LA_UI_FLAGS_EXPAND;
     
     laShowSeparator(uil,c);
 
@@ -1146,9 +1150,9 @@ void our_CanvasDrawInit(laUiItem* ui){
     logPrint("GPU max local work group invocations %i\n", work_grp_inv);
 }
 void our_CanvasEnsureDrawBuffers(OurCanvasDraw* ocd, int W, int H){ laCanvasExtra*e=&ocd->Base;
-    int format = Our->PigmentMode?GL_RGBA16UI:GL_RGBA16F; int RealW=W,RealH=H;
+    int format = Our->PigmentMode?GL_RGBA16UI:GL_RGBA16F; int RealW=W,RealH=H,texscale=1;
     if(Our->PigmentMode){
-        glDisable(GL_BLEND); glDisable(GL_DITHER); W*=2; H*=2;
+        glDisable(GL_BLEND); glDisable(GL_DITHER); if(Our->PigmentDisplayMethod>=2){ W*=2; H*=2; texscale=2; }
     }
     if (!e->OffScr || e->OffScr->pColor[0]->Height != H || e->OffScr->pColor[0]->Width != W ||
         e->OffScr->pColor[0]->GLTexBitsType!=format){
@@ -1181,7 +1185,7 @@ void our_CanvasDrawCanvas(laBoxedTheme *bt, OurPaint *unused_c, laUiItem* ui){
     if(Our->PigmentMode){
         uint val[4]={0};
         glClearBufferuiv(GL_COLOR, 0,&val);
-        tnsEnableShaderv(Our->PigmentCompositionProgramT);
+        tnsEnableShaderv(Our->PigmentLayeringProgramT);
     }else{
         tnsClearColor(LA_COLOR3(Our->BackgroundColor),1); tnsClearAll();
         tnsUseImmShader(); tnsEnableShaderv(T->immShader);
@@ -1197,16 +1201,28 @@ void our_CanvasDrawCanvas(laBoxedTheme *bt, OurPaint *unused_c, laUiItem* ui){
     tnsFlush();
     glEnable(GL_BLEND);
 }
+void our_CanvasGetFragOffset(laUiItem* ui,int *x,int* y){
+    if(!x || !y) return; *x=0;*y=0;
+    laWindow* w=MAIN.CurrentWindow; if(!w) return;
+    if(w->MaximizedUi==ui) return;
+    laPanel* p=MAIN.CurrentPanel; if(!p) return;
+    *x=-ui->L; *y=ui->B-p->H;
+}
 void our_CanvasDrawOverlayInit(laUiItem* ui){
     int W, H; W = ui->R - ui->L; H = ui->B - ui->U;
     if(Our->PigmentMode){
+        laCanvasExtra* e=ui->Extra;
         tnsUseShader(Our->PigmentDisplayProgramT); tnsEnableShaderv(Our->PigmentDisplayProgramT);
         OurPigmentData140 pd140; our_ToPigmentData140(&Our->CanvasLight.Emission,&Our->CanvasSurface.Reflectance,&pd140);
         glBindBufferBase(GL_UNIFORM_BUFFER, Our->uboCanvasPigmentLocation, Our->uboCanvasPigment);
         glBindBuffer(GL_UNIFORM_BUFFER, Our->uboCanvasPigment);
         glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OurPigmentData140), &pd140);
         glBindBuffer(GL_UNIFORM_BUFFER, 0);
-        glUniform2ui(Our->uPigmentDisplaySize,W*2,H*2);
+        int size_multiply=(Our->PigmentDisplayMethod>=2)?2:1;
+        int ofx,ofy; our_CanvasGetFragOffset(ui,&ofx,&ofy);
+        glUniform2i(Our->uPigmentFragOffset,ofx,ofy);
+        glUniform1f(Our->uPigmentTextureScale,1.0f/e->ZoomX*(real)size_multiply);
+        glUniform1i(Our->uPigmentDisplayMode,Our->PigmentDisplayMethod);
     }else{
         tnsUseImmShader(); tnsEnableShaderv(T->immShader); tnsUniformColorMode(T->immShader,2);
         tnsUniformOutputColorSpace(T->immShader, 0); tnsUniformColorComposing(T->immShader,0,0,0,0);
@@ -1218,7 +1234,6 @@ void our_CanvasDrawOverlayInit(laUiItem* ui){
 void our_CanvasDrawOverlayTexture(laUiItem* ui){
     laCanvasExtra *e = ui->Extra; OurCanvasDraw* ocd=e;
     if(Our->PigmentMode){
-        tnsBindTexture(e->OffScr->pColor[0]);
         tnsDraw2DTextureDirectly(e->OffScr->pColor[0], ui->L, ui->U, ui->R - ui->L, ui->B - ui->U);
     }else{
         tnsDraw2DTextureDirectly(e->OffScr->pColor[0], ui->L, ui->U, ui->R - ui->L, ui->B - ui->U);
@@ -1269,7 +1284,8 @@ void our_CanvasDrawOverlay(laUiItem* ui,int h){
             for(int i=ui->U+delta;i<ui->B;i+=delta*2){ tnsVertex2d(ui->L,i); tnsVertex2d(ui->R,i); } tnsColor4d(0,0,0,0.5); tnsPackAs(GL_LINES);
             for(int i=ui->U+delta*2;i<ui->B;i+=delta*2){ tnsVertex2d(ui->L,i); tnsVertex2d(ui->R,i); } tnsColor4d(1,1,1,0.5); tnsPackAs(GL_LINES);
         }
-        char buf[128]; sprintf(buf,"%.1lf%%",100.0f/e->ZoomX);
+        int texscale=Our->PigmentMode?2:1;
+        char buf[128]; sprintf(buf,"%.1lf%%",100.0f/e->ZoomX*texscale);
         tnsDrawStringAuto(buf,colork,ui->L+LA_M+1,ui->R-LA_M,ui->B-LA_RH-LA_M+1,0);
         tnsDrawStringAuto(buf,colorw,ui->L+LA_M,ui->R-LA_M,ui->B-LA_RH-LA_M,0);
     }
@@ -1565,7 +1581,7 @@ int our_MergeLayer(OurLayer* l){
     if(Our->PigmentMode){
         Our->u=&Our->uPigment;
     }else{
-        glUseProgram(Our->CompositionProgram);
+        glUseProgram(Our->AlphaMode?Our->CompositionStraightProgram:Our->CompositionProgram);
         Our->u=&Our->uRGBA;
     }
     glUniform1i(OURU->uBlendMode, l->BlendMode);
@@ -1834,18 +1850,18 @@ void our_TileTextureToImage(OurTexTile* ot, int SX, int SY, int composite, int B
     tnsBindTexture(ot->Texture); glPixelStorei(GL_PACK_ALIGNMENT, 1);
     tnsGet2DTextureSubImage(ot->Texture, seam, seam, width, width, OUR_CANVAS_GL_FORMAT, OUR_CANVAS_DATA_FORMAT, bufsize, ot->Data);
     OUR_PIX_COMPACT* image_buffer=Our->ImageBuffer;
+    our_MixFuncRGBA mixfunc;
+    if(Our->AlphaMode){
+        if(BlendMode==OUR_BLEND_NORMAL) mixfunc=our_CanvasAlphaOverStraight;
+        elif(BlendMode==OUR_BLEND_ADD) mixfunc=our_CanvasAddStraight;
+    }else{
+        if(BlendMode==OUR_BLEND_NORMAL) mixfunc=our_CanvasAlphaOver;
+        elif(BlendMode==OUR_BLEND_ADD) mixfunc=our_CanvasAdd;
+    }
     if(composite){
         for(int row=0;row<OUR_TILE_W_USE;row++){
             for(int col=0;col<OUR_TILE_W_USE;col++){
-                if(BlendMode==OUR_BLEND_NORMAL){
-                    if(Our->AlphaMode){
-                        our_CanvasAlphaOverStraight(&image_buffer[((int64_t)(SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TILE_W_USE+col)*4],alpha);
-                    }else{
-                        our_CanvasAlphaOver(&image_buffer[((int64_t)(SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TILE_W_USE+col)*4],alpha);
-                    }
-                }elif(BlendMode==OUR_BLEND_ADD){
-                    our_CanvasAdd(&image_buffer[((int64_t)(SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TILE_W_USE+col)*4],alpha);
-                }
+                mixfunc(&image_buffer[((int64_t)(SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TILE_W_USE+col)*4],alpha);
             }
         }
     }else{
@@ -2551,8 +2567,9 @@ void our_ReadWidgetColor(laCanvasExtra*e,int x,int y){
     glReadBuffer(GL_COLOR_ATTACHMENT0);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
     if(Our->PigmentMode){
+        int texscale=1; if(Our->PigmentDisplayMethod>=2){ texscale=2; }
         u8bit pigment[32]={0}; x/=2;x*=2; y/=2; y*=2;
-        glReadPixels(x*2,y*2,2,2, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, pigment);
+        glReadPixels(x*texscale,y*texscale,2,2, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, pigment);
         printf("read:\n");
         for(int i=0;i<16;i++) { printf("%03d ", pigment[i]); } printf("\n");
         for(int i=16;i<32;i++){ printf("%03d ", pigment[i]); } printf("\n");
@@ -3843,6 +3860,9 @@ void ourget_PigmentInfo(OurPigmentData* pd,char* buf, char** copy){
 void ourset_AlphaMode(void* unused, int a){
     Our->AlphaMode=a;
 }
+void ourset_PigmentDisplayMethod(void* unused, int a){
+    Our->PigmentDisplayMethod=a; laNotifyUsers("our.canvas");
+}
 
 int ourget_CanvasVersion(void* unused){
     return OUR_VERSION_MAJOR*100+OUR_VERSION_MINOR*10+OUR_VERSION_SUB;
@@ -4278,6 +4298,11 @@ void ourRegisterEverything(){
     laAddEnumItemAs(p,"TILT","Tilt","Brush direction line follows tilt direction",1,0);
     laAddEnumItemAs(p,"TWIST","Twist","Brush direction line follows twist direction",2,0);
     laAddEnumItemAs(p,"AUTO","Auto","Brush direction line determines automatically whether to show tilt or twist",3,0);
+    p=laAddEnumProperty(pc,"pigment_display_method","Pigment Display Mode","How do display pigment canvas",0,0,0,0,0,offsetof(OurPaint,PigmentDisplayMethod),0,ourset_PigmentDisplayMethod,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(p,"SPEED","Speed","Draw the canvas with half resolution sampling",0,0);
+    laAddEnumItemAs(p,"DEBAYER","Debayer","Interpolate channels from pigment canvas to display color at pixel level resolution",1,0);
+    laAddEnumItemAs(p,"SHARP","Sharp","Using two times resolution for the view buffer to store converted color information",2,0);
+    laAddEnumItemAs(p,"QUALITY","Quality","Using two times resolution for the view buffer and do 4x supersampled debayer average",3,0);
     
     pc=laAddPropertyContainer("our_tools","Our Tools","OurPaint tools",0,0,sizeof(OurPaint),0,0,1);
     laPropContainerExtraFunctions(pc,0,0,0,ourpropagate_Tools,0);
@@ -4711,24 +4736,32 @@ int ourInit(){
 
 
     Our->CompositionShader = glCreateShader(GL_COMPUTE_SHADER);
+    Our->CompositionStraightShader = glCreateShader(GL_COMPUTE_SHADER);
     const GLchar* source2 = strSub(OUR_COMPOSITION_SHADER,"#with OUR_SHADER_COMMON",OUR_SHADER_COMMON);
-    const GLchar* sources2[]={versionstr, source2};
-    glShaderSource(Our->CompositionShader, 2, sources2, NULL); glCompileShader(Our->CompositionShader);
-    tnsCheckShaderCompileStatus(Our->CompositionShader,"Canvas");
+    const GLchar* sources2[]= {versionstr, source2};
+    const GLchar* sources2a[]={versionstr, "#define OUR_STRAIGHT_ALPHA", source2};
+    glShaderSource(Our->CompositionShader, 2, sources2, NULL);          glCompileShader(Our->CompositionShader);
+    glShaderSource(Our->CompositionStraightShader, 3, sources2a, NULL); glCompileShader(Our->CompositionStraightShader);
+    tnsCheckShaderCompileStatus(Our->CompositionShader,"Composition");
+    tnsCheckShaderCompileStatus(Our->CompositionStraightShader,"Composition Straight");
     if(source2) free(source2);
 
-    Our->CompositionProgram = glCreateProgram();
-    glAttachShader(Our->CompositionProgram, Our->CompositionShader); glLinkProgram(Our->CompositionProgram);
-    tnsCheckProgramLinkStatus(Our->CompositionProgram,"Canvas");
+    Our->CompositionProgram =         glCreateProgram();
+    Our->CompositionStraightProgram = glCreateProgram();
+    glAttachShader(Our->CompositionProgram, Our->CompositionShader);                 glLinkProgram(Our->CompositionProgram);
+    glAttachShader(Our->CompositionStraightProgram, Our->CompositionStraightShader); glLinkProgram(Our->CompositionStraightProgram);
+    tnsCheckProgramLinkStatus(Our->CompositionProgram,"Composition");
+    tnsCheckProgramLinkStatus(Our->CompositionStraightProgram,"Composition Straight");
 
-    Our->PigmentCompositionShader = glCreateShader(GL_FRAGMENT_SHADER);
+    Our->PigmentLayeringShader = glCreateShader(GL_FRAGMENT_SHADER);
     const GLchar* source3 = strSub(OUR_PIGMENT_TEXTURE_MIX_SHADER,"#with OUR_PIGMENT_COMMON",OUR_PIGMENT_COMMON);
     const GLchar* sources3[]={versionstr, source3};
-    glShaderSource(Our->PigmentCompositionShader, 2, sources3, NULL); glCompileShader(Our->PigmentCompositionShader);
-    if(!tnsCheckShaderCompileStatus(Our->PigmentCompositionShader,"Pigment Composition")) exit(0);
+    glShaderSource(Our->PigmentLayeringShader, 2, sources3, NULL); glCompileShader(Our->PigmentLayeringShader);
+    if(!tnsCheckShaderCompileStatus(Our->PigmentLayeringShader,"Pigment Layering")) exit(0);
     if(source3){free(source3);}
 
-    Our->PigmentCompositionProgramT = tnsNewShaderProgram(T->immShader->vtShaderID,Our->PigmentCompositionShader,-1);
+    Our->PigmentLayeringProgramT = tnsNewShaderProgram(T->immShader->vtShaderID,Our->PigmentLayeringShader,-1);
+
 
     Our->PigmentDisplayShader = glCreateShader(GL_FRAGMENT_SHADER);
     const GLchar* source4 = strSub(OUR_PIGMENT_TEXTURE_DISPLAY_SHADER,"#with OUR_PIGMENT_COMMON",OUR_PIGMENT_COMMON);
@@ -4741,7 +4774,9 @@ int ourInit(){
     int pid=Our->PigmentDisplayProgramT->glProgramID;
     Our->uboCanvasPigmentLocation=glGetUniformBlockIndex(pid, "CanvasPigmentBlock");
     glUniformBlockBinding(pid, Our->uboCanvasPigmentLocation, 0);
-    Our->uPigmentDisplaySize=glGetUniformLocation(pid, "display_size");
+    Our->uPigmentTextureScale=glGetUniformLocation(pid, "texture_scale");
+    Our->uPigmentDisplayMode=glGetUniformLocation(pid, "display_mode");
+    Our->uPigmentFragOffset=glGetUniformLocation(pid, "frag_offset");
 
     glGenBuffers(1, &Our->uboBrushPigment);
     glGenBuffers(1, &Our->uboCanvasPigment);
@@ -4757,7 +4792,7 @@ int ourInit(){
     Our->u = &Our->uRGBStraightA;
     ourGetUniforms(Our->CanvasStraightProgram,Our->CompositionProgram);
     Our->u = &Our->uPigment;
-    ourGetUniforms(Our->CanvasPigmentProgram,Our->PigmentCompositionProgramT->glProgramID); // XXXXX  (?)
+    ourGetUniforms(Our->CanvasPigmentProgram,Our->PigmentLayeringProgramT->glProgramID); // XXXXX  (?)
 
     Our->X=-2800/2; Our->W=2800;
     Our->Y=2400/2;  Our->H=2400;

+ 4 - 2
ourpaint.h

@@ -519,17 +519,19 @@ STRUCTURE(OurPaint){
     int UndoOnHeader;
     int SketchMode;
     int SegmentedWrite;
+    int PigmentDisplayMethod;
 
     tnsTexture* SmudgeTexture;
     GLuint CanvasShader;         GLuint CanvasProgram;
     GLuint CanvasStraightShader; GLuint CanvasStraightProgram;
     GLuint CanvasPigmentShader;  GLuint CanvasPigmentProgram;
     GLuint CompositionShader;    GLuint CompositionProgram;
+    GLuint CompositionStraightShader; GLuint CompositionStraightProgram;
     GLuint LayerShader;          GLuint LayerProgram;
     GLuint DisplayShader;        GLuint DisplayProgram;
-    GLuint PigmentCompositionShader; tnsShader* PigmentCompositionProgramT;
+    GLuint PigmentLayeringShader; tnsShader* PigmentLayeringProgramT;
     GLuint PigmentDisplayShader; tnsShader* PigmentDisplayProgramT;
-    GLuint uPigmentDisplaySize,uPigmentZoomSize;
+    GLuint uPigmentFragOffset,uPigmentTextureScale,uPigmentDisplayMode;
     GLint uboBrushPigment,uboBrushPigmentLocation;
     GLint uboCanvasPigment,uboCanvasPigmentLocation;
 

+ 149 - 6
ourshader.cpp

@@ -525,14 +525,30 @@ uniform float uAlphaBottom;
 #with OUR_SHADER_COMMON
 
 vec4 mix_over(vec4 colora, vec4 colorb){
+#ifdef OUR_STRAIGHT_ALPHA
+    colora=vec4(colora.rgb*colora.a,colora.a);
+    colorb=vec4(colorb.rgb*colorb.a,colorb.a);
+#endif
     colora=colora*uAlphaTop/uAlphaBottom;
     vec4 c; c.a=colora.a+colorb.a*(1.0f-colora.a);
     c.rgb=(colora.rgb+colorb.rgb*(1.0f-colora.a));
+#ifdef OUR_STRAIGHT_ALPHA
+    c=(c.a!=0.)?vec4(c.rgb/c.a,c.a):vec4(0.,0.,0.,0.);
+#endif
     return c;
 }
+
 vec4 add_over(vec4 colora, vec4 colorb){
+#ifdef OUR_STRAIGHT_ALPHA
+    colora=vec4(colora.rgb*colora.a,colora.a);
+    colorb=vec4(colorb.rgb*colorb.a,colorb.a);
+#endif
     colora=colora*uAlphaTop/uAlphaBottom;
-    vec4 a=colora+colorb; a.a=clamp(a.a,0.,1.); return a;
+    vec4 result=colora+colorb; result.a=clamp(result.a,0.,1.);
+#ifdef OUR_STRAIGHT_ALPHA
+    result=result.a!=0.?vec4(result.rgb/result.a,result.a):vec4(0.,0.,0.,0.);
+#endif
+    return result;
 }
 void main() {
     ivec2 px=ivec2(gl_GlobalInvocationID.xy);
@@ -608,8 +624,118 @@ uvec4 getAH(PigmentData p){ uvec4 c;
     c[2]=fl16(p.a[12],p.a[13]); c[3]=fl16w(p.a[15]); //c[3]=fl16(p.a[14],p.a[15]);
     return c;
 }
+uvec4 PixelAvg2(uvec4 a, uvec4 b){
+    uvec4 r;
+    r[0]=(((a[0]&0xffu)+(b[0]&0xffu))/2u)|((((a[0]&0xff00u)+(b[0]&0xff00u))/2u)&0xff00u);
+    r[1]=(((a[1]&0xffu)+(b[1]&0xffu))/2u)|((((a[1]&0xff00u)+(b[1]&0xff00u))/2u)&0xff00u);
+    r[2]=(((a[2]&0xffu)+(b[2]&0xffu))/2u)|((((a[2]&0xff00u)+(b[2]&0xff00u))/2u)&0xff00u);
+    r[3]=(((a[3]&0xffu)+(b[3]&0xffu))/2u)|((((a[3]&0xff00u)+(b[3]&0xff00u))/2u)&0xff00u);
+    return r;
+}
+uvec4 PixelAvg2H(uvec4 a, uvec4 b){
+    uvec4 r;
+    r[0]=(((a[0]&0xffu)+(b[0]&0xffu))/2u)|((((a[0]&0xff00u)+(b[0]&0xff00u))/2u)&0xff00u);
+    r[1]=(((a[1]&0xffu)+(b[1]&0xffu))/2u)|((((a[1]&0xff00u)+(b[1]&0xff00u))/2u)&0xff00u);
+    r[2]=(((a[2]&0xffu)+(b[2]&0xffu))/2u)|((((a[2]&0xff00u)+(b[2]&0xff00u))/2u)&0xff00u);
+    r[3]=(a[3]+b[3])/2u;
+    return r;
+}
+uvec4 PixelAvg4(uvec4 a, uvec4 b, uvec4 c, uvec4 d){
+    uvec4 r;
+    r[0]=(((a[0]&0xffu)+(b[0]&0xffu)+(c[0]&0xffu)+(d[0]&0xffu))/4u)|((((a[0]&0xff00u)+(b[0]&0xff00u)+(c[0]&0xff00u)+(d[0]&0xff00u))/4u)&0xff00u);
+    r[1]=(((a[1]&0xffu)+(b[1]&0xffu)+(c[1]&0xffu)+(d[1]&0xffu))/4u)|((((a[1]&0xff00u)+(b[1]&0xff00u)+(c[1]&0xff00u)+(d[1]&0xff00u))/4u)&0xff00u);
+    r[2]=(((a[2]&0xffu)+(b[2]&0xffu)+(c[2]&0xffu)+(d[2]&0xffu))/4u)|((((a[2]&0xff00u)+(b[2]&0xff00u)+(c[2]&0xff00u)+(d[2]&0xff00u))/4u)&0xff00u);
+    r[3]=(((a[3]&0xffu)+(b[3]&0xffu)+(c[3]&0xffu)+(d[3]&0xffu))/4u)|((((a[3]&0xff00u)+(b[3]&0xff00u)+(c[3]&0xff00u)+(d[3]&0xff00u))/4u)&0xff00u);
+    return r;
+}
+uvec4 PixelAvg4H(uvec4 a, uvec4 b, uvec4 c, uvec4 d){
+    uvec4 r;
+    r[0]=(((a[0]&0xffu)+(b[0]&0xffu)+(c[0]&0xffu)+(d[0]&0xffu))/4u)|((((a[0]&0xff00u)+(b[0]&0xff00u)+(c[0]&0xff00u)+(d[0]&0xff00u))/4u)&0xff00u);
+    r[1]=(((a[1]&0xffu)+(b[1]&0xffu)+(c[1]&0xffu)+(d[1]&0xffu))/4u)|((((a[1]&0xff00u)+(b[1]&0xff00u)+(c[1]&0xff00u)+(d[1]&0xff00u))/4u)&0xff00u);
+    r[2]=(((a[2]&0xffu)+(b[2]&0xffu)+(c[2]&0xffu)+(d[2]&0xffu))/4u)|((((a[2]&0xff00u)+(b[2]&0xff00u)+(c[2]&0xff00u)+(d[2]&0xff00u))/4u)&0xff00u);
+    r[3]=(a[3]+b[3]+c[3]+d[3])/4u;
+    return r;
+}
+uvec4 GetSubPixelH2(highp usampler2D tex, ivec2 uv, int offset){
+    if(uv.x>=textureSize(tex,0).x-offset) return texelFetch(tex,ivec2(uv.x-offset,uv.y),0);
+    if(uv.x<=offset) return texelFetch(tex,ivec2(uv.x+offset,uv.y),0);
+    uvec4 a=texelFetch(tex,ivec2(uv.x-offset,uv.y),0);
+    uvec4 b=texelFetch(tex,ivec2(uv.x+offset,uv.y),0);
+    return PixelAvg2(a,b);
+}
+uvec4 GetSubPixelH2H(highp usampler2D tex, ivec2 uv, int offset){
+    if(uv.x>=textureSize(tex,0).x-offset) return texelFetch(tex,ivec2(uv.x-offset,uv.y),0);
+    if(uv.x<=offset) return texelFetch(tex,ivec2(uv.x+offset,uv.y),0);
+    uvec4 a=texelFetch(tex,ivec2(uv.x-offset,uv.y),0);
+    uvec4 b=texelFetch(tex,ivec2(uv.x+offset,uv.y),0);
+    return PixelAvg2H(a,b);
+}
+uvec4 GetSubPixelV2(highp usampler2D tex, ivec2 uv, int offset){
+    if(uv.y>=textureSize(tex,0).y-offset) return texelFetch(tex,ivec2(uv.x,uv.y-offset),0);
+    if(uv.y<=offset) return texelFetch(tex,ivec2(uv.x,uv.y+offset),0);
+    uvec4 a=texelFetch(tex,ivec2(uv.x,uv.y-offset),0);
+    uvec4 b=texelFetch(tex,ivec2(uv.x,uv.y+offset),0);
+    return PixelAvg2(a,b);
+}
+uvec4 GetSubPixelV2H(highp usampler2D tex, ivec2 uv, int offset){
+    if(uv.y>=textureSize(tex,0).y-offset) return texelFetch(tex,ivec2(uv.x,uv.y-offset),0);
+    if(uv.y<=offset) return texelFetch(tex,ivec2(uv.x,uv.y+offset),0);
+    uvec4 a=texelFetch(tex,ivec2(uv.x,uv.y-offset),0);
+    uvec4 b=texelFetch(tex,ivec2(uv.x,uv.y+offset),0);
+    return PixelAvg2H(a,b);
+}
+uvec4 GetSubPixelX4(highp usampler2D tex, ivec2 uv, int offset){
+    if(uv.x>=textureSize(tex,0).x-offset) return GetSubPixelV2(tex,ivec2(uv.x-offset,uv.y),offset);
+    if(uv.y>=textureSize(tex,0).y-offset) return GetSubPixelH2(tex,ivec2(uv.x,uv.y-offset),offset);
+    if(uv.x<=offset) return GetSubPixelV2(tex,ivec2(uv.x+offset,uv.y),offset);
+    if(uv.y<=offset) return GetSubPixelH2(tex,ivec2(uv.x,uv.y+offset),offset);
+    uvec4 a=texelFetch(tex,ivec2(uv.x-offset,uv.y-offset),0);
+    uvec4 b=texelFetch(tex,ivec2(uv.x-offset,uv.y+offset),0);
+    uvec4 c=texelFetch(tex,ivec2(uv.x+offset,uv.y-offset),0);
+    uvec4 d=texelFetch(tex,ivec2(uv.x+offset,uv.y+offset),0);
+    return PixelAvg4(a,b,c,d);
+}
+uvec4 GetSubPixelX4H(highp usampler2D tex, ivec2 uv, int offset){
+    if(uv.x>=textureSize(tex,0).x-offset) return GetSubPixelV2(tex,ivec2(uv.x-offset,uv.y),offset);
+    if(uv.y>=textureSize(tex,0).y-offset) return GetSubPixelH2(tex,ivec2(uv.x,uv.y-offset),offset);
+    if(uv.x<=offset) return GetSubPixelV2(tex,ivec2(uv.x+offset,uv.y),offset);
+    if(uv.y<=offset) return GetSubPixelH2(tex,ivec2(uv.x,uv.y+offset),offset);
+    uvec4 a=texelFetch(tex,ivec2(uv.x-offset,uv.y-offset),0);
+    uvec4 b=texelFetch(tex,ivec2(uv.x-offset,uv.y+offset),0);
+    uvec4 c=texelFetch(tex,ivec2(uv.x+offset,uv.y-offset),0);
+    uvec4 d=texelFetch(tex,ivec2(uv.x+offset,uv.y+offset),0);
+    return PixelAvg4H(a,b,c,d);
+}
+PigmentData GetPixelDebayer(highp usampler2D tex, ivec2 uv, int offset){
+    uvec4 c[4]; int s=(uv.x%2)*2+uv.y%2;
+    c[0]=uvec4(0);
+    if(s==0){
+        c[0]=texelFetch(tex,uv,0); 
+        c[1]=GetSubPixelV2H(tex,uv,offset);
+        c[2]=GetSubPixelH2(tex,uv,offset);
+        c[3]=GetSubPixelX4H(tex,uv,offset);
+    }else if(s==1){
+        c[0]=GetSubPixelV2(tex,uv,offset);
+        c[1]=texelFetch(tex,uv,0); 
+        c[2]=GetSubPixelX4(tex,uv,offset);
+        c[3]=GetSubPixelH2H(tex,uv,offset);
+    }else if(s==2){
+        c[0]=GetSubPixelH2(tex,uv,offset);
+        c[1]=GetSubPixelX4H(tex,uv,offset);
+        c[2]=texelFetch(tex,uv,0);
+        c[3]=GetSubPixelV2H(tex,uv,offset);
+    }else{
+        c[0]=GetSubPixelX4(tex,uv,offset);
+        c[1]=GetSubPixelH2H(tex,uv,offset);
+        c[2]=GetSubPixelV2(tex,uv,offset);
+        c[3]=texelFetch(tex,uv,0);
+    }
+    PigmentData p;
+    setRL(c[0],p); setRH(c[1],p); setAL(c[2],p); setAH(c[3],p);
+    return p;
+}
 const uvec4 DB[4]=uvec4[4](uvec4(0,1,2,3),uvec4(1,0,3,2),uvec4(2,3,0,1),uvec4(3,2,1,0));
-PigmentData GetPixelDebayer(highp usampler2D tex, ivec2 uv){
+PigmentData GetPixelQuick(highp usampler2D tex, ivec2 uv){
     uvec4 c[4];
     c[0]=texelFetch(tex,uv,0); 
     c[1]=texelFetch(tex,ivec2(uv.x,uv.y+1),0);
@@ -777,7 +903,9 @@ const char OUR_PIGMENT_TEXTURE_DISPLAY_SHADER[]=R"(
 precision highp float;
 precision highp int;
 layout (binding=2) uniform highp usampler2D TexColorUI;
-uniform uvec2 display_size;
+uniform float texture_scale;
+uniform int display_mode;
+uniform ivec2 frag_offset;
 
 in vec2 fUV;
 
@@ -791,9 +919,24 @@ layout(std140) uniform CanvasPigmentBlock{
 }uCanvasPigment;
 
 void main(){
-    ivec2 iuv=ivec2(fUV*vec2(display_size)); //int xof=iuv.x%2; int yof=iuv.y%2; iuv.x-=xof; iuv.y-=yof;
-
-    PigmentData p0 = GetPixelDebayer(TexColorUI,iuv);
+    ivec2 iuv=ivec2(gl_FragCoord.xy)+frag_offset;
+    //ivec2(fUV*vec2(display_size)); //int xof=iuv.x%2; int yof=iuv.y%2; iuv.x-=xof; iuv.y-=yof;
+
+    int offset=int(texture_scale/2)*2+1;
+    PigmentData p0;
+    if(display_mode==0){
+        p0=GetPixelQuick(TexColorUI,iuv);
+    }else if(display_mode==1){
+        p0=GetPixelDebayer(TexColorUI,iuv,offset);
+    }else if(display_mode==2){
+        p0=GetPixelQuick(TexColorUI,iuv*2);
+    }else if(display_mode==3){
+                    p0=GetPixelDebayer(TexColorUI,iuv*2+ivec2(0,0),offset);
+        PigmentData p1=GetPixelDebayer(TexColorUI,iuv*2+ivec2(0,1),offset);
+        PigmentData p2=GetPixelDebayer(TexColorUI,iuv*2+ivec2(1,1),offset);
+        PigmentData p3=GetPixelDebayer(TexColorUI,iuv*2+ivec2(1,0),offset);
+        p0=PigmentMix(PigmentMix(p0,p1,0.5),PigmentMix(p2,p3,0.5),0.5);
+    }
 
     PigmentData final = PigmentOver(p0,uCanvasPigment.paper);
     vec3 pixel = to_log_srgb(PigmentToRGB(final,uCanvasPigment.light));