|
@@ -81,12 +81,31 @@ void main() {\n\
|
|
}\n\
|
|
}\n\
|
|
";
|
|
";
|
|
|
|
|
|
|
|
+const char OUR_COMPOSITION_SHADER[]="#version 430\n\
|
|
|
|
+layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;\n\
|
|
|
|
+layout(rgba16, binding = 0) uniform image2D top;\n\
|
|
|
|
+layout(rgba16, binding = 1) uniform image2D bottom;\n\
|
|
|
|
+uniform int uMode;\n\
|
|
|
|
+vec4 mix_over(vec4 colora, vec4 colorb){\n\
|
|
|
|
+ vec4 c; c.a=colora.a+colorb.a*(1-colora.a);\n\
|
|
|
|
+ c.rgb=(colora.rgb+colorb.rgb*(1-colora.a));\n\
|
|
|
|
+ return c;\n\
|
|
|
|
+}\n\
|
|
|
|
+void main() {\n\
|
|
|
|
+ ivec2 px=ivec2(gl_GlobalInvocationID.xy);\n\
|
|
|
|
+ vec4 c1=imageLoad(top,px); vec4 c2=imageLoad(bottom,px);\n\
|
|
|
|
+ imageStore(bottom,px,mix_over(c1,c2));\n\
|
|
|
|
+ imageStore(top,px,vec4(0,0,0,0));\n\
|
|
|
|
+}";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void our_LayerEnsureTiles(OurLayer* ol, real xmin,real xmax, real ymin,real ymax, int Aligned, int *tl, int *tr, int* tu, int* tb);
|
|
|
|
+void our_LayerEnsureTileDirect(OurLayer* ol, int col, int row);
|
|
|
|
+void our_RecordUndo(OurLayer* ol, real xmin,real xmax, real ymin,real ymax,int Aligned,int Push);
|
|
|
|
+
|
|
void our_CanvasAlphaMix(uint16_t* target, uint16_t* source){
|
|
void our_CanvasAlphaMix(uint16_t* target, uint16_t* source){
|
|
real a_1=(real)(65535-source[3])/65535;
|
|
real a_1=(real)(65535-source[3])/65535;
|
|
- target[3]=source[3]+target[3]*a_1;
|
|
|
|
- target[0]=source[0]+target[0]*a_1;
|
|
|
|
- target[1]=source[1]+target[1]*a_1;
|
|
|
|
- target[2]=source[2]+target[2]*a_1;
|
|
|
|
|
|
+ target[3]=source[3]+target[3]*a_1; target[0]=source[0]+target[0]*a_1; target[1]=source[1]+target[1]*a_1; target[2]=source[2]+target[2]*a_1;
|
|
}
|
|
}
|
|
|
|
|
|
void our_InitsRGBProfile(int Linear, void** ptr, int* psize, char* copyright, char* manufacturer, char* description){
|
|
void our_InitsRGBProfile(int Linear, void** ptr, int* psize, char* copyright, char* manufacturer, char* description){
|
|
@@ -150,8 +169,17 @@ void ourui_LayersPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProp
|
|
laShowItem(uil,c,0,"OUR_new_layer");
|
|
laShowItem(uil,c,0,"OUR_new_layer");
|
|
}laEndCondition(uil,b);
|
|
}laEndCondition(uil,b);
|
|
|
|
|
|
- laShowItemFull(uil,c,0,"our.canvas.layers",0,0,0,0);
|
|
|
|
|
|
+ laUiItem* lui=laShowItemFull(uil,c,0,"our.canvas.layers",0,0,0,0);
|
|
|
|
+
|
|
|
|
+ b=laOnConditionThat(uil,c,laPropExpression(0,"our.canvas.current_layer"));{
|
|
|
|
+ laUiItem* b1=laBeginRow(uil,c,0,0);
|
|
|
|
+ laShowItem(uil,c,&lui->PP,"remove")->Flags|=LA_UI_FLAGS_ICON;
|
|
|
|
+ laShowItem(uil,c,&lui->PP,"merge");
|
|
|
|
+ laShowSeparator(uil,c)->Expand=1;
|
|
|
|
+ laEndRow(uil,b1);
|
|
|
|
+ }laEndCondition(uil,b);
|
|
|
|
|
|
|
|
+ laShowSeparator(uil,c);
|
|
b=laBeginRow(uil,c,0,0);
|
|
b=laBeginRow(uil,c,0,0);
|
|
laShowLabel(uil,c,"Background",0,0)->Expand=1;
|
|
laShowLabel(uil,c,"Background",0,0)->Expand=1;
|
|
laShowItemFull(uil,c,0,"our.canvas.background_color",LA_WIDGET_FLOAT_COLOR,0,0,0);
|
|
laShowItemFull(uil,c,0,"our.canvas.background_color",LA_WIDGET_FLOAT_COLOR,0,0,0);
|
|
@@ -255,13 +283,13 @@ void our_CanvasDrawTextures(){
|
|
tnsUseImmShader; tnsEnableShaderv(T->immShader);
|
|
tnsUseImmShader; tnsEnableShaderv(T->immShader);
|
|
for(OurLayer* l=Our->Layers.pLast;l;l=l->Item.pPrev){
|
|
for(OurLayer* l=Our->Layers.pLast;l;l=l->Item.pPrev){
|
|
int any=0;
|
|
int any=0;
|
|
- for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){
|
|
if(!l->TexTiles[row]) continue;
|
|
if(!l->TexTiles[row]) continue;
|
|
- for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){
|
|
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){
|
|
if(!l->TexTiles[row][col] || !l->TexTiles[row][col]->Texture) continue;
|
|
if(!l->TexTiles[row][col] || !l->TexTiles[row][col]->Texture) continue;
|
|
int sx=l->TexTiles[row][col]->l,sy=l->TexTiles[row][col]->b;
|
|
int sx=l->TexTiles[row][col]->l,sy=l->TexTiles[row][col]->b;
|
|
- real pad=(real)OUR_TEX_TILE_SEAM/OUR_TEX_TILE_W; int seam=OUR_TEX_TILE_SEAM;
|
|
|
|
- tnsDraw2DTextureArg(l->TexTiles[row][col]->Texture,sx+seam,sy+OUR_TEX_TILE_W-seam,OUR_TEX_TILE_W-seam*2,-OUR_TEX_TILE_W+seam*2,0,pad,pad,pad,pad);
|
|
|
|
|
|
+ real pad=(real)OUR_TILE_SEAM/OUR_TILE_W; int seam=OUR_TILE_SEAM;
|
|
|
|
+ tnsDraw2DTextureArg(l->TexTiles[row][col]->Texture,sx+seam,sy+OUR_TILE_W-seam,OUR_TILE_W-seam*2,-OUR_TILE_W+seam*2,0,pad,pad,pad,pad);
|
|
any=1;
|
|
any=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -272,17 +300,17 @@ void our_CanvasDrawTiles(){
|
|
OurLayer* l=Our->CurrentLayer; if(!l) return;
|
|
OurLayer* l=Our->CurrentLayer; if(!l) return;
|
|
tnsUseImmShader; tnsEnableShaderv(T->immShader); tnsUniformUseTexture(T->immShader,0,0); tnsUseNoTexture();
|
|
tnsUseImmShader; tnsEnableShaderv(T->immShader); tnsUniformUseTexture(T->immShader,0,0); tnsUseNoTexture();
|
|
int any=0;
|
|
int any=0;
|
|
- for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){
|
|
if(!l->TexTiles[row]) continue;
|
|
if(!l->TexTiles[row]) continue;
|
|
- for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){
|
|
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){
|
|
if(!l->TexTiles[row][col] || !l->TexTiles[row][col]->Texture) continue;
|
|
if(!l->TexTiles[row][col] || !l->TexTiles[row][col]->Texture) continue;
|
|
int sx=l->TexTiles[row][col]->l,sy=l->TexTiles[row][col]->b;
|
|
int sx=l->TexTiles[row][col]->l,sy=l->TexTiles[row][col]->b;
|
|
- //tnsVertex2d(sx, sy); tnsVertex2d(sx+OUR_TEX_TILE_W,sy);
|
|
|
|
- //tnsVertex2d(sx+OUR_TEX_TILE_W, sy+OUR_TEX_TILE_W); tnsVertex2d(sx,sy+OUR_TEX_TILE_W);
|
|
|
|
|
|
+ //tnsVertex2d(sx, sy); tnsVertex2d(sx+OUR_TILE_W,sy);
|
|
|
|
+ //tnsVertex2d(sx+OUR_TILE_W, sy+OUR_TILE_W); tnsVertex2d(sx,sy+OUR_TILE_W);
|
|
//tnsColor4dv(laAccentColor(LA_BT_NORMAL));
|
|
//tnsColor4dv(laAccentColor(LA_BT_NORMAL));
|
|
//tnsPackAs(GL_TRIANGLE_FAN);
|
|
//tnsPackAs(GL_TRIANGLE_FAN);
|
|
- tnsVertex2d(sx, sy); tnsVertex2d(sx+OUR_TEX_TILE_W,sy);
|
|
|
|
- tnsVertex2d(sx+OUR_TEX_TILE_W, sy+OUR_TEX_TILE_W); tnsVertex2d(sx,sy+OUR_TEX_TILE_W);
|
|
|
|
|
|
+ tnsVertex2d(sx, sy); tnsVertex2d(sx+OUR_TILE_W,sy);
|
|
|
|
+ tnsVertex2d(sx+OUR_TILE_W, sy+OUR_TILE_W); tnsVertex2d(sx,sy+OUR_TILE_W);
|
|
tnsColor4dv(laAccentColor(LA_BT_TEXT));
|
|
tnsColor4dv(laAccentColor(LA_BT_TEXT));
|
|
tnsPackAs(GL_LINE_LOOP);
|
|
tnsPackAs(GL_LINE_LOOP);
|
|
}
|
|
}
|
|
@@ -395,8 +423,8 @@ OurLayer* our_NewLayer(char* name){
|
|
return l;
|
|
return l;
|
|
}
|
|
}
|
|
void ourbeforefree_Layer(OurLayer* l){
|
|
void ourbeforefree_Layer(OurLayer* l){
|
|
- for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){ if(!l->TexTiles[row]) continue;
|
|
|
|
- for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){ if(!l->TexTiles[row][col]) continue;
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){ if(!l->TexTiles[row]) continue;
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){ if(!l->TexTiles[row][col]) continue;
|
|
if(l->TexTiles[row][col]->Texture) tnsDeleteTexture(l->TexTiles[row][col]->Texture); l->TexTiles[row][col]->Texture=0;
|
|
if(l->TexTiles[row][col]->Texture) tnsDeleteTexture(l->TexTiles[row][col]->Texture); l->TexTiles[row][col]->Texture=0;
|
|
if(l->TexTiles[row][col]->Data) free(l->TexTiles[row][col]->Data); l->TexTiles[row][col]->Data=0;
|
|
if(l->TexTiles[row][col]->Data) free(l->TexTiles[row][col]->Data); l->TexTiles[row][col]->Data=0;
|
|
if(l->TexTiles[row][col]->FullData) free(l->TexTiles[row][col]->FullData); l->TexTiles[row][col]->FullData=0;
|
|
if(l->TexTiles[row][col]->FullData) free(l->TexTiles[row][col]->FullData); l->TexTiles[row][col]->FullData=0;
|
|
@@ -406,11 +434,38 @@ void ourbeforefree_Layer(OurLayer* l){
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void our_RemoveLayer(OurLayer* l){
|
|
void our_RemoveLayer(OurLayer* l){
|
|
- strSafeDestroy(&l->Name); lstRemoveItem(&Our->Layers, l);
|
|
|
|
|
|
+ strSafeDestroy(&l->Name);
|
|
if(Our->CurrentLayer==l){ OurLayer* nl=l->Item.pPrev?l->Item.pPrev:l->Item.pNext; memAssignRef(Our, &Our->CurrentLayer, nl); }
|
|
if(Our->CurrentLayer==l){ OurLayer* nl=l->Item.pPrev?l->Item.pPrev:l->Item.pNext; memAssignRef(Our, &Our->CurrentLayer, nl); }
|
|
|
|
+ lstRemoveItem(&Our->Layers, l);
|
|
ourbeforefree_Layer(l);
|
|
ourbeforefree_Layer(l);
|
|
memLeave(l);
|
|
memLeave(l);
|
|
}
|
|
}
|
|
|
|
+int our_MergeLayer(OurLayer* l){
|
|
|
|
+ OurLayer* ol=l->Item.pNext; if(!ol) return 0; int xmin=INT_MAX,xmax=-INT_MAX,ymin=INT_MAX,ymax=-INT_MAX; int seam=OUR_TILE_SEAM;
|
|
|
|
+ glUseProgram(Our->CompositionProgram);
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){ if(!l->TexTiles[row]) continue;// Should not happen.
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){ if(!l->TexTiles[row][col]) continue; OurTexTile*t=l->TexTiles[row][col];
|
|
|
|
+ int tl,tr,tu,tb; our_LayerEnsureTileDirect(ol,row,col);
|
|
|
|
+ OurTexTile*ot=ol->TexTiles[row][col]; if(!ot) continue;
|
|
|
|
+ glBindImageTexture(0, t->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
|
|
|
|
+ glBindImageTexture(1, ot->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
|
|
|
|
+ glDispatchCompute(32,32,1);
|
|
|
|
+ xmin=TNS_MIN2(xmin,t->l+seam);xmax=TNS_MAX2(xmax,t->r-seam); ymin=TNS_MIN2(ymin,t->b+seam);ymax=TNS_MAX2(ymax,t->u-seam);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
|
|
|
+
|
|
|
|
+ if(xmin>xmax||ymin>ymax) return 0;
|
|
|
|
+
|
|
|
|
+ our_RecordUndo(l,xmin,xmax,ymin,ymax,1,0);
|
|
|
|
+ our_RecordUndo(ol,xmin,xmax,ymin,ymax,1,0);
|
|
|
|
+ our_RemoveLayer(l);
|
|
|
|
+ laRecordDifferences(0,"our.canvas.layers");laRecordDifferences(0,"our.canvas.current_layer");
|
|
|
|
+ laPushDifferences("Merge layers",0);
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
OurBrush* our_NewBrush(char* name, real Size, real Hardness, real DabsPerSize, real Transparency, real Smudge, real SmudgeResampleLength,
|
|
OurBrush* our_NewBrush(char* name, real Size, real Hardness, real DabsPerSize, real Transparency, real Smudge, real SmudgeResampleLength,
|
|
int PressureSize, int PressureHardness, int PressureTransparency, int PressureSmudge){
|
|
int PressureSize, int PressureHardness, int PressureTransparency, int PressureSmudge){
|
|
OurBrush* b=memAcquireHyper(sizeof(OurBrush)); strSafeSet(&b->Name,name); lstAppendItem(&Our->Brushes, b);
|
|
OurBrush* b=memAcquireHyper(sizeof(OurBrush)); strSafeSet(&b->Name,name); lstAppendItem(&Our->Brushes, b);
|
|
@@ -445,13 +500,13 @@ void our_TileEnsureUndoBuffer(OurTexTile* t, real xmin,real xmax, real ymin,real
|
|
int bufsize=cols*4*rows*sizeof(uint16_t);
|
|
int bufsize=cols*4*rows*sizeof(uint16_t);
|
|
t->CopyBuffer=calloc(1,bufsize);
|
|
t->CopyBuffer=calloc(1,bufsize);
|
|
for(int row=0;row<rows;row++){
|
|
for(int row=0;row<rows;row++){
|
|
- memcpy(&t->CopyBuffer[row*cols*4],&t->FullData[((+row+t->cb)*OUR_TEX_TILE_W+t->cl)*4],sizeof(uint16_t)*4*cols);
|
|
|
|
|
|
+ memcpy(&t->CopyBuffer[row*cols*4],&t->FullData[((+row+t->cb)*OUR_TILE_W+t->cl)*4],sizeof(uint16_t)*4*cols);
|
|
}
|
|
}
|
|
uint16_t* temp=malloc(bufsize);
|
|
uint16_t* temp=malloc(bufsize);
|
|
tnsBindTexture(t->Texture);
|
|
tnsBindTexture(t->Texture);
|
|
glGetTextureSubImage(t->Texture->GLTexHandle, 0, t->cl, t->cb, 0, cols,rows,1, GL_RGBA, GL_UNSIGNED_SHORT, bufsize, temp);
|
|
glGetTextureSubImage(t->Texture->GLTexHandle, 0, t->cl, t->cb, 0, cols,rows,1, GL_RGBA, GL_UNSIGNED_SHORT, bufsize, temp);
|
|
for(int row=0;row<rows;row++){
|
|
for(int row=0;row<rows;row++){
|
|
- memcpy(&t->FullData[((+row+t->cb)*OUR_TEX_TILE_W+t->cl)*4],&temp[row*cols*4],sizeof(uint16_t)*4*cols);
|
|
|
|
|
|
+ memcpy(&t->FullData[((+row+t->cb)*OUR_TILE_W+t->cl)*4],&temp[row*cols*4],sizeof(uint16_t)*4*cols);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void our_TileSwapBuffers(OurTexTile* t, uint16_t* data, int IsRedo, int l, int r, int u, int b){
|
|
void our_TileSwapBuffers(OurTexTile* t, uint16_t* data, int IsRedo, int l, int r, int u, int b){
|
|
@@ -459,8 +514,8 @@ void our_TileSwapBuffers(OurTexTile* t, uint16_t* data, int IsRedo, int l, int r
|
|
uint16_t* temp=malloc(bufsize);
|
|
uint16_t* temp=malloc(bufsize);
|
|
memcpy(temp,data,bufsize);
|
|
memcpy(temp,data,bufsize);
|
|
for(int row=0;row<rows;row++){
|
|
for(int row=0;row<rows;row++){
|
|
- memcpy(&data[row*cols*4],&t->FullData[((+row+b)*OUR_TEX_TILE_W+l)*4],sizeof(uint16_t)*4*cols);
|
|
|
|
- memcpy(&t->FullData[((+row+b)*OUR_TEX_TILE_W+l)*4],&temp[row*cols*4],sizeof(uint16_t)*4*cols);
|
|
|
|
|
|
+ memcpy(&data[row*cols*4],&t->FullData[((+row+b)*OUR_TILE_W+l)*4],sizeof(uint16_t)*4*cols);
|
|
|
|
+ memcpy(&t->FullData[((+row+b)*OUR_TILE_W+l)*4],&temp[row*cols*4],sizeof(uint16_t)*4*cols);
|
|
}
|
|
}
|
|
tnsBindTexture(t->Texture);
|
|
tnsBindTexture(t->Texture);
|
|
glGetError();
|
|
glGetError();
|
|
@@ -471,12 +526,14 @@ void our_TileSwapBuffers(OurTexTile* t, uint16_t* data, int IsRedo, int l, int r
|
|
}
|
|
}
|
|
void ourundo_Tiles(OurUndo* undo){
|
|
void ourundo_Tiles(OurUndo* undo){
|
|
for(OurUndoTile* ut=undo->Tiles.pFirst;ut;ut=ut->Item.pNext){
|
|
for(OurUndoTile* ut=undo->Tiles.pFirst;ut;ut=ut->Item.pNext){
|
|
|
|
+ our_LayerEnsureTileDirect(undo->Layer,ut->row,ut->col);
|
|
our_TileSwapBuffers(undo->Layer->TexTiles[ut->row][ut->col], ut->CopyData, 0, ut->l, ut->r, ut->u, ut->b);
|
|
our_TileSwapBuffers(undo->Layer->TexTiles[ut->row][ut->col], ut->CopyData, 0, ut->l, ut->r, ut->u, ut->b);
|
|
}
|
|
}
|
|
laNotifyUsers("our.canvas");
|
|
laNotifyUsers("our.canvas");
|
|
}
|
|
}
|
|
void ourredo_Tiles(OurUndo* undo){
|
|
void ourredo_Tiles(OurUndo* undo){
|
|
for(OurUndoTile* ut=undo->Tiles.pFirst;ut;ut=ut->Item.pNext){
|
|
for(OurUndoTile* ut=undo->Tiles.pFirst;ut;ut=ut->Item.pNext){
|
|
|
|
+ our_LayerEnsureTileDirect(undo->Layer,ut->row,ut->col);
|
|
our_TileSwapBuffers(undo->Layer->TexTiles[ut->row][ut->col], ut->CopyData, 0, ut->l, ut->r, ut->u, ut->b);
|
|
our_TileSwapBuffers(undo->Layer->TexTiles[ut->row][ut->col], ut->CopyData, 0, ut->l, ut->r, ut->u, ut->b);
|
|
}
|
|
}
|
|
laNotifyUsers("our.canvas");
|
|
laNotifyUsers("our.canvas");
|
|
@@ -487,13 +544,21 @@ void ourundo_Free(OurUndo* undo,int FromLeft){
|
|
memFree(undo);
|
|
memFree(undo);
|
|
}
|
|
}
|
|
#define OUR_XXYY_TO_COL_ROW_RANGE\
|
|
#define OUR_XXYY_TO_COL_ROW_RANGE\
|
|
- l=(int)(floor(OUR_TEX_TILE_CTR+(xmin-OUR_TEX_TILE_SEAM)/OUR_TEX_TILE_W_USE+0.5));\
|
|
|
|
- r=(int)(floor(OUR_TEX_TILE_CTR+(xmax+OUR_TEX_TILE_SEAM)/OUR_TEX_TILE_W_USE+0.5));\
|
|
|
|
- u=(int)(floor(OUR_TEX_TILE_CTR+(ymax+OUR_TEX_TILE_SEAM)/OUR_TEX_TILE_W_USE+0.5));\
|
|
|
|
- b=(int)(floor(OUR_TEX_TILE_CTR+(ymin-OUR_TEX_TILE_SEAM)/OUR_TEX_TILE_W_USE+0.5));
|
|
|
|
-void our_RecordUndo(OurLayer* ol, real xmin,real xmax, real ymin,real ymax){
|
|
|
|
|
|
+ l=(int)(floor(OUR_TILE_CTR+(xmin-OUR_TILE_SEAM)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ r=(int)(floor(OUR_TILE_CTR+(xmax+OUR_TILE_SEAM)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ u=(int)(floor(OUR_TILE_CTR+(ymax+OUR_TILE_SEAM)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ b=(int)(floor(OUR_TILE_CTR+(ymin-OUR_TILE_SEAM)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ TNS_CLAMP(l,0,OUR_TILES_PER_ROW-1); TNS_CLAMP(r,0,OUR_TILES_PER_ROW-1); TNS_CLAMP(u,0,OUR_TILES_PER_ROW-1); TNS_CLAMP(b,0,OUR_TILES_PER_ROW-1);
|
|
|
|
+#define OUR_XXYY_TO_COL_ROW_ALIGNED\
|
|
|
|
+ l=(int)(floor(OUR_TILE_CTR+(xmin)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ r=(int)(floor(OUR_TILE_CTR+(xmax-1)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ u=(int)(floor(OUR_TILE_CTR+(ymax-1)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ b=(int)(floor(OUR_TILE_CTR+(ymin)/OUR_TILE_W_USE+0.5));\
|
|
|
|
+ TNS_CLAMP(l,0,OUR_TILES_PER_ROW-1); TNS_CLAMP(r,0,OUR_TILES_PER_ROW-1); TNS_CLAMP(u,0,OUR_TILES_PER_ROW-1); TNS_CLAMP(b,0,OUR_TILES_PER_ROW-1);
|
|
|
|
+void our_RecordUndo(OurLayer* ol, real xmin,real xmax, real ymin,real ymax,int Aligned,int Push){
|
|
if(xmax<xmin || ymax<ymin) return;
|
|
if(xmax<xmin || ymax<ymin) return;
|
|
- int l,r,u,b; OUR_XXYY_TO_COL_ROW_RANGE;
|
|
|
|
|
|
+ int l,r,u,b;
|
|
|
|
+ if(Aligned){ OUR_XXYY_TO_COL_ROW_ALIGNED }else{ OUR_XXYY_TO_COL_ROW_RANGE; }
|
|
OurUndo* undo=memAcquire(sizeof(OurUndo)); undo->Layer=ol;
|
|
OurUndo* undo=memAcquire(sizeof(OurUndo)); undo->Layer=ol;
|
|
for(int row=b;row<=u;row++){ if(!ol->TexTiles[row]) continue;// Should not happen.
|
|
for(int row=b;row<=u;row++){ if(!ol->TexTiles[row]) continue;// Should not happen.
|
|
for(int col=l;col<=r;col++){ if(!ol->TexTiles[row][col]) continue; OurTexTile*t=ol->TexTiles[row][col];
|
|
for(int col=l;col<=r;col++){ if(!ol->TexTiles[row][col]) continue; OurTexTile*t=ol->TexTiles[row][col];
|
|
@@ -509,84 +574,76 @@ void our_RecordUndo(OurLayer* ol, real xmin,real xmax, real ymin,real ymax){
|
|
if(!undo->Tiles.pFirst){ memFree(undo); return; /*unlikely;*/ }
|
|
if(!undo->Tiles.pFirst){ memFree(undo); return; /*unlikely;*/ }
|
|
laFreeNewerDifferences();
|
|
laFreeNewerDifferences();
|
|
laRecordCustomDifferences(undo,ourundo_Tiles,ourredo_Tiles,ourundo_Free);
|
|
laRecordCustomDifferences(undo,ourundo_Tiles,ourredo_Tiles,ourundo_Free);
|
|
- laPushDifferences("Paint",0);
|
|
|
|
|
|
+ if(Push){ laPushDifferences("Paint",0); }
|
|
|
|
+}
|
|
|
|
+void our_LayerEnsureTileDirect(OurLayer* ol, int row, int col){
|
|
|
|
+ if(!ol->TexTiles[row]){ol->TexTiles[row]=memAcquireSimple(sizeof(OurTexTile*)*OUR_TILES_PER_ROW);}
|
|
|
|
+ if(ol->TexTiles[row][col]) return;
|
|
|
|
+ ol->TexTiles[row][col]=memAcquireSimple(sizeof(OurTexTile));
|
|
|
|
+ OurTexTile*t=ol->TexTiles[row][col];
|
|
|
|
+ t->Texture=tnsCreate2DTexture(GL_RGBA16,OUR_TILE_W,OUR_TILE_W,0);
|
|
|
|
+ int sx=((real)col-OUR_TILE_CTR-0.5)*OUR_TILE_W_USE,sy=((real)row-OUR_TILE_CTR-0.5)*OUR_TILE_W_USE;
|
|
|
|
+ t->l=sx-OUR_TILE_SEAM,t->b=sy-OUR_TILE_SEAM; t->r=t->l+OUR_TILE_W; t->u=t->b+OUR_TILE_W;
|
|
|
|
+ uint16_t initColor[]={0,0,0,0};
|
|
|
|
+ glClearTexImage(t->Texture->GLTexHandle, 0, GL_RGBA, GL_UNSIGNED_SHORT, 0);
|
|
|
|
+ t->FullData=calloc(OUR_TILE_W*4,OUR_TILE_W*sizeof(uint16_t));
|
|
}
|
|
}
|
|
void our_LayerEnsureTiles(OurLayer* ol, real xmin,real xmax, real ymin,real ymax, int Aligned, int *tl, int *tr, int* tu, int* tb){
|
|
void our_LayerEnsureTiles(OurLayer* ol, real xmin,real xmax, real ymin,real ymax, int Aligned, int *tl, int *tr, int* tu, int* tb){
|
|
int l,r,u,b;
|
|
int l,r,u,b;
|
|
- if(Aligned){
|
|
|
|
- l=(int)(floor(OUR_TEX_TILE_CTR+(xmin)/OUR_TEX_TILE_W_USE+0.5));
|
|
|
|
- r=(int)(floor(OUR_TEX_TILE_CTR+(xmax-1)/OUR_TEX_TILE_W_USE+0.5));
|
|
|
|
- u=(int)(floor(OUR_TEX_TILE_CTR+(ymax-1)/OUR_TEX_TILE_W_USE+0.5));
|
|
|
|
- b=(int)(floor(OUR_TEX_TILE_CTR+(ymin)/OUR_TEX_TILE_W_USE+0.5));
|
|
|
|
- }else{
|
|
|
|
- OUR_XXYY_TO_COL_ROW_RANGE;
|
|
|
|
- }
|
|
|
|
- TNS_CLAMP(l,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
- TNS_CLAMP(r,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
- TNS_CLAMP(u,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
- TNS_CLAMP(b,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
|
|
+ if(Aligned){ OUR_XXYY_TO_COL_ROW_ALIGNED }else{ OUR_XXYY_TO_COL_ROW_RANGE; }
|
|
for(int row=b;row<=u;row++){
|
|
for(int row=b;row<=u;row++){
|
|
- if(!ol->TexTiles[row]){ol->TexTiles[row]=memAcquireSimple(sizeof(OurTexTile*)*OUR_TEX_TILES_PER_ROW);}
|
|
|
|
for(int col=l;col<=r;col++){
|
|
for(int col=l;col<=r;col++){
|
|
- if(ol->TexTiles[row][col]) continue;
|
|
|
|
- ol->TexTiles[row][col]=memAcquireSimple(sizeof(OurTexTile));
|
|
|
|
- OurTexTile*t=ol->TexTiles[row][col];
|
|
|
|
- t->Texture=tnsCreate2DTexture(GL_RGBA16,OUR_TEX_TILE_W,OUR_TEX_TILE_W,0);
|
|
|
|
- int sx=((real)col-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE,sy=((real)row-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE;
|
|
|
|
- t->l=sx-OUR_TEX_TILE_SEAM,t->b=sy-OUR_TEX_TILE_SEAM; t->r=t->l+OUR_TEX_TILE_W; t->u=t->b+OUR_TEX_TILE_W;
|
|
|
|
- uint16_t initColor[]={0,0,0,0};
|
|
|
|
- glClearTexImage(t->Texture->GLTexHandle, 0, GL_RGBA, GL_UNSIGNED_SHORT, 0);
|
|
|
|
- t->FullData=calloc(OUR_TEX_TILE_W*4,OUR_TEX_TILE_W*sizeof(uint16_t));
|
|
|
|
|
|
+ our_LayerEnsureTileDirect(ol,row,col);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*tl=l; *tr=r; *tu=u; *tb=b;
|
|
*tl=l; *tr=r; *tu=u; *tb=b;
|
|
}
|
|
}
|
|
void our_TileTextureToImage(OurTexTile* ot, int SX, int SY, int composite){
|
|
void our_TileTextureToImage(OurTexTile* ot, int SX, int SY, int composite){
|
|
if(!ot->Texture) return;
|
|
if(!ot->Texture) return;
|
|
- int bufsize=sizeof(uint16_t)*OUR_TEX_TILE_W_USE*OUR_TEX_TILE_W_USE*4;
|
|
|
|
- ot->Data=malloc(bufsize); int seam=OUR_TEX_TILE_SEAM; int width=OUR_TEX_TILE_W_USE;
|
|
|
|
|
|
+ int bufsize=sizeof(uint16_t)*OUR_TILE_W_USE*OUR_TILE_W_USE*4;
|
|
|
|
+ ot->Data=malloc(bufsize); int seam=OUR_TILE_SEAM; int width=OUR_TILE_W_USE;
|
|
tnsBindTexture(ot->Texture); glPixelStorei(GL_PACK_ALIGNMENT, 2);
|
|
tnsBindTexture(ot->Texture); glPixelStorei(GL_PACK_ALIGNMENT, 2);
|
|
glGetTextureSubImage(ot->Texture->GLTexHandle, 0, seam, seam, 0, width, width,1, GL_RGBA, GL_UNSIGNED_SHORT, bufsize, ot->Data);
|
|
glGetTextureSubImage(ot->Texture->GLTexHandle, 0, seam, seam, 0, width, width,1, GL_RGBA, GL_UNSIGNED_SHORT, bufsize, ot->Data);
|
|
if(composite){
|
|
if(composite){
|
|
- for(int row=0;row<OUR_TEX_TILE_W_USE;row++){
|
|
|
|
- for(int col=0;col<OUR_TEX_TILE_W_USE;col++){
|
|
|
|
- our_CanvasAlphaMix(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TEX_TILE_W_USE+col)*4]);
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILE_W_USE;row++){
|
|
|
|
+ for(int col=0;col<OUR_TILE_W_USE;col++){
|
|
|
|
+ our_CanvasAlphaMix(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX+col)*4], &ot->Data[(row*OUR_TILE_W_USE+col)*4]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
}else{
|
|
- for(int row=0;row<OUR_TEX_TILE_W_USE;row++){
|
|
|
|
- memcpy(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX)*4],&ot->Data[(row*OUR_TEX_TILE_W_USE)*4],sizeof(uint16_t)*4*OUR_TEX_TILE_W_USE);
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILE_W_USE;row++){
|
|
|
|
+ memcpy(&Our->ImageBuffer[((SY+row)*Our->ImageW+SX)*4],&ot->Data[(row*OUR_TILE_W_USE)*4],sizeof(uint16_t)*4*OUR_TILE_W_USE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free(ot->Data); ot->Data=0;
|
|
free(ot->Data); ot->Data=0;
|
|
}
|
|
}
|
|
void our_TileImageToTexture(OurTexTile* ot, int SX, int SY){
|
|
void our_TileImageToTexture(OurTexTile* ot, int SX, int SY){
|
|
if(!ot->Texture) return;
|
|
if(!ot->Texture) return;
|
|
- int pl=(SX!=0)?OUR_TEX_TILE_SEAM:0, pr=((SX+OUR_TEX_TILE_W_USE)!=Our->ImageW)?OUR_TEX_TILE_SEAM:0;
|
|
|
|
- int pu=(SY!=0)?OUR_TEX_TILE_SEAM:0, pb=((SY+OUR_TEX_TILE_W_USE)!=Our->ImageH)?OUR_TEX_TILE_SEAM:0;
|
|
|
|
- int bufsize=sizeof(uint16_t)*(OUR_TEX_TILE_W+pl+pr)*(OUR_TEX_TILE_W+pu+pb)*4;
|
|
|
|
- ot->Data=malloc(bufsize); int width=OUR_TEX_TILE_W_USE+pl+pr, height=OUR_TEX_TILE_W_USE+pu+pb;
|
|
|
|
|
|
+ int pl=(SX!=0)?OUR_TILE_SEAM:0, pr=((SX+OUR_TILE_W_USE)!=Our->ImageW)?OUR_TILE_SEAM:0;
|
|
|
|
+ int pu=(SY!=0)?OUR_TILE_SEAM:0, pb=((SY+OUR_TILE_W_USE)!=Our->ImageH)?OUR_TILE_SEAM:0;
|
|
|
|
+ int bufsize=sizeof(uint16_t)*(OUR_TILE_W+pl+pr)*(OUR_TILE_W+pu+pb)*4;
|
|
|
|
+ ot->Data=malloc(bufsize); int width=OUR_TILE_W_USE+pl+pr, height=OUR_TILE_W_USE+pu+pb;
|
|
for(int row=0;row<height;row++){
|
|
for(int row=0;row<height;row++){
|
|
memcpy(&ot->Data[((row)*width)*4],&Our->ImageBuffer[((SY+row-pu)*Our->ImageW+SX-pl)*4],sizeof(uint16_t)*4*width);
|
|
memcpy(&ot->Data[((row)*width)*4],&Our->ImageBuffer[((SY+row-pu)*Our->ImageW+SX-pl)*4],sizeof(uint16_t)*4*width);
|
|
}
|
|
}
|
|
if(!our_BufferAnythingVisible(ot->Data, bufsize/sizeof(uint16_t)/4)){ tnsDeleteTexture(ot->Texture); ot->Texture=0; }
|
|
if(!our_BufferAnythingVisible(ot->Data, bufsize/sizeof(uint16_t)/4)){ tnsDeleteTexture(ot->Texture); ot->Texture=0; }
|
|
else{
|
|
else{
|
|
tnsBindTexture(ot->Texture);
|
|
tnsBindTexture(ot->Texture);
|
|
- glTexSubImage2D(GL_TEXTURE_2D, 0, OUR_TEX_TILE_SEAM-pl, OUR_TEX_TILE_SEAM-pu, width, height, GL_RGBA, GL_UNSIGNED_SHORT, ot->Data);
|
|
|
|
|
|
+ glTexSubImage2D(GL_TEXTURE_2D, 0, OUR_TILE_SEAM-pl, OUR_TILE_SEAM-pu, width, height, GL_RGBA, GL_UNSIGNED_SHORT, ot->Data);
|
|
}
|
|
}
|
|
free(ot->Data); ot->Data=0;
|
|
free(ot->Data); ot->Data=0;
|
|
}
|
|
}
|
|
int our_LayerEnsureImageBuffer(OurLayer* ol, int OnlyCalculate){
|
|
int our_LayerEnsureImageBuffer(OurLayer* ol, int OnlyCalculate){
|
|
int l=1000,r=-1000,u=-1000,b=1000; int any=0;
|
|
int l=1000,r=-1000,u=-1000,b=1000; int any=0;
|
|
- for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
|
|
if(row<b) b=row; if(row>u) u=row;
|
|
if(row<b) b=row; if(row>u) u=row;
|
|
- for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
if(col<l) l=col; if(col>r) r=col; any++;
|
|
if(col<l) l=col; if(col>r) r=col; any++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!any) return 0;
|
|
if(!any) return 0;
|
|
- Our->ImageW = OUR_TEX_TILE_W_USE*(r-l+1); Our->ImageH = OUR_TEX_TILE_W_USE*(u-b+1);
|
|
|
|
- Our->ImageX =((real)l-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE; Our->ImageY=((real)b-OUR_TEX_TILE_CTR-0.5)*OUR_TEX_TILE_W_USE;
|
|
|
|
|
|
+ Our->ImageW = OUR_TILE_W_USE*(r-l+1); Our->ImageH = OUR_TILE_W_USE*(u-b+1);
|
|
|
|
+ Our->ImageX =((real)l-OUR_TILE_CTR-0.5)*OUR_TILE_W_USE; Our->ImageY=((real)b-OUR_TILE_CTR-0.5)*OUR_TILE_W_USE;
|
|
if(!OnlyCalculate){
|
|
if(!OnlyCalculate){
|
|
if(Our->ImageBuffer) free(Our->ImageBuffer);
|
|
if(Our->ImageBuffer) free(Our->ImageBuffer);
|
|
Our->ImageBuffer = calloc(Our->ImageW*4,Our->ImageH*sizeof(uint16_t));
|
|
Our->ImageBuffer = calloc(Our->ImageW*4,Our->ImageH*sizeof(uint16_t));
|
|
@@ -615,17 +672,17 @@ void our_CanvasFillImageBufferBackground(){
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void our_LayerToImageBuffer(OurLayer* ol, int composite){
|
|
void our_LayerToImageBuffer(OurLayer* ol, int composite){
|
|
- for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
|
|
|
|
- for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
|
|
- int sx=ol->TexTiles[row][col]->l+OUR_TEX_TILE_SEAM,sy=ol->TexTiles[row][col]->b+OUR_TEX_TILE_SEAM;
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
|
|
+ int sx=ol->TexTiles[row][col]->l+OUR_TILE_SEAM,sy=ol->TexTiles[row][col]->b+OUR_TILE_SEAM;
|
|
our_TileTextureToImage(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY, composite);
|
|
our_TileTextureToImage(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY, composite);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void our_LayerToTexture(OurLayer* ol){
|
|
void our_LayerToTexture(OurLayer* ol){
|
|
- for(int row=0;row<OUR_TEX_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
|
|
|
|
- for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
|
|
- int sx=ol->TexTiles[row][col]->l+OUR_TEX_TILE_SEAM,sy=ol->TexTiles[row][col]->b+OUR_TEX_TILE_SEAM;
|
|
|
|
|
|
+ for(int row=0;row<OUR_TILES_PER_ROW;row++){ if(!ol->TexTiles[row]) continue;
|
|
|
|
+ for(int col=0;col<OUR_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
|
|
+ int sx=ol->TexTiles[row][col]->l+OUR_TILE_SEAM,sy=ol->TexTiles[row][col]->b+OUR_TILE_SEAM;
|
|
our_TileImageToTexture(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY);
|
|
our_TileImageToTexture(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -699,12 +756,12 @@ int our_ImageExportPNG(FILE* fp, int WriteToBuffer, void** buf, int* sizeof_buf,
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
void our_EnsureImageBufferOnRead(OurLayer*l, int W, int H, int UseOffsets, int StartX, int StartY){
|
|
void our_EnsureImageBufferOnRead(OurLayer*l, int W, int H, int UseOffsets, int StartX, int StartY){
|
|
- int tw=W/OUR_TEX_TILE_W_USE, th=H/OUR_TEX_TILE_W_USE;
|
|
|
|
- int w=tw*OUR_TEX_TILE_W_USE, h=th*OUR_TEX_TILE_W_USE;
|
|
|
|
- if(w<W){ tw+=1; w+=OUR_TEX_TILE_W_USE; } if(h<H){ th+=1; h+=OUR_TEX_TILE_W_USE; }
|
|
|
|
|
|
+ int tw=W/OUR_TILE_W_USE, th=H/OUR_TILE_W_USE;
|
|
|
|
+ int w=tw*OUR_TILE_W_USE, h=th*OUR_TILE_W_USE;
|
|
|
|
+ if(w<W){ tw+=1; w+=OUR_TILE_W_USE; } if(h<H){ th+=1; h+=OUR_TILE_W_USE; }
|
|
|
|
|
|
- int ix=UseOffsets?StartX:(-tw/2*OUR_TEX_TILE_W_USE-OUR_TEX_TILE_W_USE/2);
|
|
|
|
- int iy=UseOffsets?StartY:(th/2*OUR_TEX_TILE_W_USE+OUR_TEX_TILE_W_USE/2);
|
|
|
|
|
|
+ int ix=UseOffsets?StartX:(-tw/2*OUR_TILE_W_USE-OUR_TILE_W_USE/2);
|
|
|
|
+ int iy=UseOffsets?StartY:(th/2*OUR_TILE_W_USE+OUR_TILE_W_USE/2);
|
|
int tl,tr,tu,tb;
|
|
int tl,tr,tu,tb;
|
|
our_LayerEnsureTiles(l,ix,ix+W,iy-H,iy,1,&tl,&tr,&tu,&tb);
|
|
our_LayerEnsureTiles(l,ix,ix+W,iy-H,iy,1,&tl,&tr,&tu,&tb);
|
|
our_LayerEnsureImageBuffer(l, 0);
|
|
our_LayerEnsureImageBuffer(l, 0);
|
|
@@ -930,7 +987,7 @@ void our_PaintDoDabs(OurLayer* l,int tl, int tr, int tu, int tb, int Start, int
|
|
glBindImageTexture(0, ott->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
|
|
glBindImageTexture(0, ott->Texture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
|
|
int sx=l->TexTiles[row][col]->l,sy=l->TexTiles[row][col]->b;
|
|
int sx=l->TexTiles[row][col]->l,sy=l->TexTiles[row][col]->b;
|
|
for(int i=Start;i<End;i++){
|
|
for(int i=Start;i<End;i++){
|
|
- our_PaintDoDab(&Our->Dabs[i],sx,sx+OUR_TEX_TILE_W,sy,sy+OUR_TEX_TILE_W);
|
|
|
|
|
|
+ our_PaintDoDab(&Our->Dabs[i],sx,sx+OUR_TILE_W,sy,sy+OUR_TILE_W);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -958,10 +1015,10 @@ void our_PaintDoDabsWithSmudgeSegments(OurLayer* l,int tl, int tr, int tu, int t
|
|
if(oss->Resample || Our->CurrentBrush->SmudgeRestart){
|
|
if(oss->Resample || Our->CurrentBrush->SmudgeRestart){
|
|
glUniformSubroutinesuiv(GL_COMPUTE_SHADER,1,&Our->RoutineDoSample);
|
|
glUniformSubroutinesuiv(GL_COMPUTE_SHADER,1,&Our->RoutineDoSample);
|
|
int x=Our->Dabs[oss->Start].X, y=Our->Dabs[oss->Start].Y; float ssize=Our->Dabs[oss->Start].Size+1.5;
|
|
int x=Our->Dabs[oss->Start].X, y=Our->Dabs[oss->Start].Y; float ssize=Our->Dabs[oss->Start].Size+1.5;
|
|
- int colmax=(int)(floor(OUR_TEX_TILE_CTR+(float)(x+ssize)/OUR_TEX_TILE_W_USE+0.5)); TNS_CLAMP(colmax,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
- int rowmax=(int)(floor(OUR_TEX_TILE_CTR+(float)(y+ssize)/OUR_TEX_TILE_W_USE+0.5)); TNS_CLAMP(rowmax,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
- int colmin=(int)(floor(OUR_TEX_TILE_CTR+(float)(x-ssize)/OUR_TEX_TILE_W_USE+0.5)); TNS_CLAMP(colmin,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
- int rowmin=(int)(floor(OUR_TEX_TILE_CTR+(float)(y-ssize)/OUR_TEX_TILE_W_USE+0.5)); TNS_CLAMP(rowmin,0,OUR_TEX_TILES_PER_ROW-1);
|
|
|
|
|
|
+ int colmax=(int)(floor(OUR_TILE_CTR+(float)(x+ssize)/OUR_TILE_W_USE+0.5)); TNS_CLAMP(colmax,0,OUR_TILES_PER_ROW-1);
|
|
|
|
+ int rowmax=(int)(floor(OUR_TILE_CTR+(float)(y+ssize)/OUR_TILE_W_USE+0.5)); TNS_CLAMP(rowmax,0,OUR_TILES_PER_ROW-1);
|
|
|
|
+ int colmin=(int)(floor(OUR_TILE_CTR+(float)(x-ssize)/OUR_TILE_W_USE+0.5)); TNS_CLAMP(colmin,0,OUR_TILES_PER_ROW-1);
|
|
|
|
+ int rowmin=(int)(floor(OUR_TILE_CTR+(float)(y-ssize)/OUR_TILE_W_USE+0.5)); TNS_CLAMP(rowmin,0,OUR_TILES_PER_ROW-1);
|
|
glBindImageTexture(1, Our->SmudgeTexture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
|
|
glBindImageTexture(1, Our->SmudgeTexture->GLTexHandle, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16);
|
|
for(int col=colmin;col<=colmax;col++){
|
|
for(int col=colmin;col<=colmax;col++){
|
|
for(int row=rowmin;row<=rowmax;row++){
|
|
for(int row=rowmin;row<=rowmax;row++){
|
|
@@ -1039,18 +1096,29 @@ void our_DoCropping(OurCanvasDraw* cd, real x, real y){
|
|
|
|
|
|
int ourinv_NewLayer(laOperator* a, laEvent* e){
|
|
int ourinv_NewLayer(laOperator* a, laEvent* e){
|
|
our_NewLayer("Our Layer"); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
|
|
our_NewLayer("Our Layer"); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
|
|
|
|
+ laRecordDifferences(0,"our.canvas.layers");laRecordDifferences(0,"our.canvas.current_layer");
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
int ourinv_RemoveLayer(laOperator* a, laEvent* e){
|
|
int ourinv_RemoveLayer(laOperator* a, laEvent* e){
|
|
OurLayer* l=a->This?a->This->EndInstance:0; if(!l) return LA_CANCELED;
|
|
OurLayer* l=a->This?a->This->EndInstance:0; if(!l) return LA_CANCELED;
|
|
our_RemoveLayer(l); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
|
|
our_RemoveLayer(l); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
|
|
|
|
+ laRecordDifferences(0,"our.canvas.layers");laRecordDifferences(0,"our.canvas.current_layer");
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
int ourinv_MoveLayer(laOperator* a, laEvent* e){
|
|
int ourinv_MoveLayer(laOperator* a, laEvent* e){
|
|
- OurLayer* l=a->This?a->This->EndInstance:0; if(!l) return LA_CANCELED;
|
|
|
|
|
|
+ OurLayer* l=a->This?a->This->EndInstance:0; if(!l) return LA_CANCELED; int changed=0;
|
|
char* direction=strGetArgumentString(a->ExtraInstructionsP,"direction");
|
|
char* direction=strGetArgumentString(a->ExtraInstructionsP,"direction");
|
|
- if(strSame(direction,"up")&&l->Item.pPrev){ lstMoveUp(&Our->Layers, l); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst); }
|
|
|
|
- elif(l->Item.pNext){ lstMoveDown(&Our->Layers, l); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst); }
|
|
|
|
|
|
+ if(strSame(direction,"up")&&l->Item.pPrev){ lstMoveUp(&Our->Layers, l); changed=1; }
|
|
|
|
+ elif(l->Item.pNext){ lstMoveDown(&Our->Layers, l); changed=1; }
|
|
|
|
+ if(changed){ laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst); laRecordDifferences(0,"our.canvas.layers"); }
|
|
|
|
+ return LA_FINISHED;
|
|
|
|
+}
|
|
|
|
+int ourchk_MergeLayer(laPropPack *This, laStringSplitor *ss){
|
|
|
|
+ OurLayer* l=This->EndInstance; if(!l || !l->Item.pNext) return 0; return 1;
|
|
|
|
+}
|
|
|
|
+int ourinv_MergeLayer(laOperator* a, laEvent* e){
|
|
|
|
+ OurLayer* l=a->This?a->This->EndInstance:0; if(!l || !l->Item.pNext) return LA_CANCELED;
|
|
|
|
+ if(our_MergeLayer(l)){ laNotifyUsers("our.canvas"); laNotifyUsers("our.canvas.layers"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst); }
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
int ourinv_ExportLayer(laOperator* a, laEvent* e){
|
|
int ourinv_ExportLayer(laOperator* a, laEvent* e){
|
|
@@ -1171,7 +1239,7 @@ int ourinv_Action(laOperator* a, laEvent* e){
|
|
int ourmod_Paint(laOperator* a, laEvent* e){
|
|
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;
|
|
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){
|
|
if(e->Type==LA_L_MOUSE_UP || e->Type==LA_R_MOUSE_DOWN || e->Type==LA_ESCAPE_DOWN){
|
|
- our_RecordUndo(l,Our->xmin,Our->xmax,Our->ymin,Our->ymax); ex->HideBrushCircle=0; laShowCursor();
|
|
|
|
|
|
+ our_RecordUndo(l,Our->xmin,Our->xmax,Our->ymin,Our->ymax,0,1); ex->HideBrushCircle=0; laShowCursor();
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1335,6 +1403,7 @@ void ourRegisterEverything(){
|
|
laCreateOperatorType("OUR_new_layer","New Layer","Create a new layer",0,0,0,ourinv_NewLayer,0,'+',0);
|
|
laCreateOperatorType("OUR_new_layer","New Layer","Create a new layer",0,0,0,ourinv_NewLayer,0,'+',0);
|
|
laCreateOperatorType("OUR_remove_layer","Remove Layer","Remove this layer",0,0,0,ourinv_RemoveLayer,0,L'🗴',0);
|
|
laCreateOperatorType("OUR_remove_layer","Remove Layer","Remove this layer",0,0,0,ourinv_RemoveLayer,0,L'🗴',0);
|
|
laCreateOperatorType("OUR_move_layer","Move Layer","Remove this layer",0,0,0,ourinv_MoveLayer,0,0,0);
|
|
laCreateOperatorType("OUR_move_layer","Move Layer","Remove this layer",0,0,0,ourinv_MoveLayer,0,0,0);
|
|
|
|
+ laCreateOperatorType("OUR_merge_layer","Merge Layer","Merge this layer with the layer below it",ourchk_MergeLayer,0,0,ourinv_MergeLayer,0,0,0);
|
|
laCreateOperatorType("OUR_export_layer","Export Layer","Export this layer",0,0,0,ourinv_ExportLayer,ourmod_ExportLayer,L'🖫',0);
|
|
laCreateOperatorType("OUR_export_layer","Export Layer","Export this layer",0,0,0,ourinv_ExportLayer,ourmod_ExportLayer,L'🖫',0);
|
|
laCreateOperatorType("OUR_import_layer","Import Layer","Import a PNG into a layer",0,0,0,ourinv_ImportLayer,ourmod_ImportLayer,L'🗁',0);
|
|
laCreateOperatorType("OUR_import_layer","Import Layer","Import a PNG into a layer",0,0,0,ourinv_ImportLayer,ourmod_ImportLayer,L'🗁',0);
|
|
laCreateOperatorType("OUR_new_brush","New Brush","Create a new brush",0,0,0,ourinv_NewBrush,0,'+',0);
|
|
laCreateOperatorType("OUR_new_brush","New Brush","Create a new brush",0,0,0,ourinv_NewBrush,0,'+',0);
|
|
@@ -1435,7 +1504,8 @@ void ourRegisterEverything(){
|
|
laAddRawProperty(pc,"image","Image","The image data of this tile",0,0,ourget_LayerImage,ourset_LayerImage,LA_UDF_ONLY);
|
|
laAddRawProperty(pc,"image","Image","The image data of this tile",0,0,ourget_LayerImage,ourset_LayerImage,LA_UDF_ONLY);
|
|
laAddOperatorProperty(pc,"move","Move","Move Layer","OUR_move_layer",0,0);
|
|
laAddOperatorProperty(pc,"move","Move","Move Layer","OUR_move_layer",0,0);
|
|
laAddOperatorProperty(pc,"remove","Remove","Remove layer","OUR_remove_layer",L'🗴',0);
|
|
laAddOperatorProperty(pc,"remove","Remove","Remove layer","OUR_remove_layer",L'🗴',0);
|
|
-
|
|
|
|
|
|
+ laAddOperatorProperty(pc,"merge","Merge","Merge Layer","OUR_merge_layer",L'🠳',0);
|
|
|
|
+
|
|
laCanvasTemplate* ct=laRegisterCanvasTemplate("our_CanvasDraw", "our_canvas", ourextramod_Canvas, our_CanvasDrawCanvas, our_CanvasDrawOverlay, our_CanvasDrawInit, la_CanvasDestroy);
|
|
laCanvasTemplate* ct=laRegisterCanvasTemplate("our_CanvasDraw", "our_canvas", ourextramod_Canvas, our_CanvasDrawCanvas, our_CanvasDrawOverlay, our_CanvasDrawInit, la_CanvasDestroy);
|
|
pc = laCanvasHasExtraProps(ct,sizeof(OurCanvasDraw),2);
|
|
pc = laCanvasHasExtraProps(ct,sizeof(OurCanvasDraw),2);
|
|
km = &ct->KeyMapper;
|
|
km = &ct->KeyMapper;
|
|
@@ -1463,13 +1533,15 @@ void ourRegisterEverything(){
|
|
laSaveProp("our.canvas");
|
|
laSaveProp("our.canvas");
|
|
laSaveProp("our.tools");
|
|
laSaveProp("our.tools");
|
|
|
|
|
|
|
|
+ laAddRootDBInst("our.canvas");
|
|
|
|
+
|
|
laGetSaverDummy(Our,Our->CanvasSaverDummyProp);
|
|
laGetSaverDummy(Our,Our->CanvasSaverDummyProp);
|
|
|
|
|
|
laSetFrameCallbacks(ourPreFrame,0,0);
|
|
laSetFrameCallbacks(ourPreFrame,0,0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-void ourInit(){
|
|
|
|
|
|
+int ourInit(){
|
|
Our=memAcquire(sizeof(OurPaint));
|
|
Our=memAcquire(sizeof(OurPaint));
|
|
|
|
|
|
ourRegisterEverything();
|
|
ourRegisterEverything();
|
|
@@ -1481,25 +1553,33 @@ void ourInit(){
|
|
Our->SmudgeTexture=tnsCreate2DTexture(GL_RGBA16,256,1,0);
|
|
Our->SmudgeTexture=tnsCreate2DTexture(GL_RGBA16,256,1,0);
|
|
|
|
|
|
Our->CanvasShader = glCreateShader(GL_COMPUTE_SHADER);
|
|
Our->CanvasShader = glCreateShader(GL_COMPUTE_SHADER);
|
|
- const GLchar* source = OUR_CANVAS_SHADER;
|
|
|
|
- glShaderSource(Our->CanvasShader, 1, &source, NULL);
|
|
|
|
- glCompileShader(Our->CanvasShader);
|
|
|
|
|
|
+ const GLchar* source1 = OUR_CANVAS_SHADER;
|
|
|
|
+ glShaderSource(Our->CanvasShader, 1, &source1, NULL); glCompileShader(Our->CanvasShader);
|
|
glGetShaderiv(Our->CanvasShader, GL_COMPILE_STATUS, &status);
|
|
glGetShaderiv(Our->CanvasShader, GL_COMPILE_STATUS, &status);
|
|
if (status == GL_FALSE){
|
|
if (status == GL_FALSE){
|
|
- glGetShaderInfoLog(Our->CanvasShader, sizeof(error), 0, error);
|
|
|
|
- printf("Compute shader error:\n%s", error);
|
|
|
|
- glDeleteShader(Our->CanvasShader);
|
|
|
|
- return -1;
|
|
|
|
|
|
+ glGetShaderInfoLog(Our->CanvasShader, sizeof(error), 0, error); printf("Canvas shader error:\n%s", error); glDeleteShader(Our->CanvasShader); return 0;
|
|
}
|
|
}
|
|
|
|
|
|
Our->CanvasProgram = glCreateProgram();
|
|
Our->CanvasProgram = glCreateProgram();
|
|
- glAttachShader(Our->CanvasProgram, Our->CanvasShader);
|
|
|
|
- glLinkProgram(Our->CanvasProgram);
|
|
|
|
|
|
+ glAttachShader(Our->CanvasProgram, Our->CanvasShader); glLinkProgram(Our->CanvasProgram);
|
|
glGetProgramiv(Our->CanvasProgram, GL_LINK_STATUS, &status);
|
|
glGetProgramiv(Our->CanvasProgram, GL_LINK_STATUS, &status);
|
|
if (status == GL_FALSE){
|
|
if (status == GL_FALSE){
|
|
- glGetProgramInfoLog(Our->CanvasProgram, sizeof(error), 0, error);
|
|
|
|
- printf("Shader Linking error:\n%s", error);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ glGetProgramInfoLog(Our->CanvasProgram, sizeof(error), 0, error); printf("Canvas program Linking error:\n%s", error); return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Our->CompositionShader = glCreateShader(GL_COMPUTE_SHADER);
|
|
|
|
+ const GLchar* source2 = OUR_COMPOSITION_SHADER;
|
|
|
|
+ glShaderSource(Our->CompositionShader, 1, &source2, NULL); glCompileShader(Our->CompositionShader);
|
|
|
|
+ glGetShaderiv(Our->CompositionShader, GL_COMPILE_STATUS, &status);
|
|
|
|
+ if (status == GL_FALSE){
|
|
|
|
+ glGetShaderInfoLog(Our->CompositionShader, sizeof(error), 0, error); printf("Composition shader error:\n%s", error); glDeleteShader(Our->CompositionShader); return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Our->CompositionProgram = glCreateProgram();
|
|
|
|
+ glAttachShader(Our->CompositionProgram, Our->CompositionShader); glLinkProgram(Our->CompositionProgram);
|
|
|
|
+ glGetProgramiv(Our->CompositionProgram, GL_LINK_STATUS, &status);
|
|
|
|
+ if (status == GL_FALSE){
|
|
|
|
+ glGetProgramInfoLog(Our->CompositionProgram, sizeof(error), 0, error); printf("Composition program Linking error:\n%s", error); return 0;
|
|
}
|
|
}
|
|
|
|
|
|
Our->uBrushCorner=glGetUniformLocation(Our->CanvasProgram,"uBrushCorner");
|
|
Our->uBrushCorner=glGetUniformLocation(Our->CanvasProgram,"uBrushCorner");
|
|
@@ -1517,15 +1597,20 @@ void ourInit(){
|
|
Our->RoutineDoDabs=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoDabs");
|
|
Our->RoutineDoDabs=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoDabs");
|
|
Our->RoutineDoSample=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoSample");
|
|
Our->RoutineDoSample=glGetSubroutineIndex(Our->CanvasProgram, GL_COMPUTE_SHADER, "DoSample");
|
|
|
|
|
|
|
|
+ Our->uMode=glGetUniformLocation(Our->CompositionProgram,"uMode");
|
|
|
|
+
|
|
Our->X=-2800/2; Our->W=2800;
|
|
Our->X=-2800/2; Our->W=2800;
|
|
Our->Y=2400/2; Our->H=2400;
|
|
Our->Y=2400/2; Our->H=2400;
|
|
Our->BorderAlpha=0.6;
|
|
Our->BorderAlpha=0.6;
|
|
|
|
|
|
Our->LockRadius=1;
|
|
Our->LockRadius=1;
|
|
|
|
+ Our->EnableBrushCircle=1;
|
|
|
|
|
|
Our->PenID=-1;
|
|
Our->PenID=-1;
|
|
Our->EraserID=-1;
|
|
Our->EraserID=-1;
|
|
|
|
|
|
tnsEnableShaderv(T->immShader);
|
|
tnsEnableShaderv(T->immShader);
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
|
|
|