|
@@ -57,6 +57,14 @@ void main() {\n\
|
|
}\n\
|
|
}\n\
|
|
";
|
|
";
|
|
|
|
|
|
|
|
+void our_CanvasAlphaMix(uint16_t* target, uint16_t* source){
|
|
|
|
+ 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;
|
|
|
|
+}
|
|
|
|
+
|
|
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){
|
|
cmsCIExyYTRIPLE srgb_primaries_pre_quantized = { {0.639998686, 0.330010138, 1.0}, {0.300003784, 0.600003357, 1.0}, {0.150002046, 0.059997204, 1.0} };
|
|
cmsCIExyYTRIPLE srgb_primaries_pre_quantized = { {0.639998686, 0.330010138, 1.0}, {0.300003784, 0.600003357, 1.0}, {0.150002046, 0.059997204, 1.0} };
|
|
cmsCIExyY d65_srgb_adobe_specs = {0.3127, 0.3290, 1.0};
|
|
cmsCIExyY d65_srgb_adobe_specs = {0.3127, 0.3290, 1.0};
|
|
@@ -148,19 +156,19 @@ void ourui_ToolsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps
|
|
|
|
|
|
laShowItem(uil,c,0,"our.tool")->Flags|=LA_UI_FLAGS_EXPAND;
|
|
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* 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");
|
|
|
|
|
|
+ laUiItem* b=laOnConditionThat(uil,c,laPropExpression(0,"our.tools.current_brush"));{
|
|
|
|
+ laShowItem(uil,c,0,"our.tools.current_brush.name");
|
|
|
|
+ OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.size")->Expand=1; laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_size",0,"text=P",0,0); OUR_ER
|
|
|
|
+ OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.transparency")->Expand=1; laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_transparency",0,"text=P",0,0); OUR_ER
|
|
|
|
+ OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.hardness")->Expand=1; laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_hardness",0,"text=P",0,0); OUR_ER
|
|
|
|
+ OUR_BR laShowItem(uil,c,0,"our.tools.current_brush.smudge")->Expand=1; laShowItemFull(uil,c,0,"our.tools.current_brush.pressure_smudge",0,"text=P",0,0); OUR_ER
|
|
|
|
+ laShowItem(uil,c,0,"our.tools.current_brush.dabs_per_size");
|
|
|
|
+ laShowItem(uil,c,0,"our.tools.current_brush.smudge_resample_length");
|
|
}laEndCondition(uil,b);
|
|
}laEndCondition(uil,b);
|
|
|
|
|
|
laShowLabel(uil,c,"Select a brush:",0,0);
|
|
laShowLabel(uil,c,"Select a brush:",0,0);
|
|
|
|
|
|
- laShowItemFull(uil,c,0,"our.brushes",0,0,0,0);
|
|
|
|
|
|
+ laShowItemFull(uil,c,0,"our.tools.brushes",0,0,0,0);
|
|
laShowItem(uil,c,0,"OUR_new_brush");
|
|
laShowItem(uil,c,0,"OUR_new_brush");
|
|
}laEndCondition(uil,bt);
|
|
}laEndCondition(uil,bt);
|
|
|
|
|
|
@@ -304,7 +312,7 @@ void our_CanvasDrawOverlay(laUiItem* ui,int h){
|
|
}
|
|
}
|
|
|
|
|
|
OurLayer* our_NewLayer(char* name){
|
|
OurLayer* our_NewLayer(char* name){
|
|
- OurLayer* l=memAcquireHyper(sizeof(OurLayer)); strSafeSet(&l->Name,name); lstPushItem(&Our->Layers, l);
|
|
|
|
|
|
+ OurLayer* l=memAcquire(sizeof(OurLayer)); strSafeSet(&l->Name,name); lstPushItem(&Our->Layers, l);
|
|
memAssignRef(Our, &Our->CurrentLayer, l);
|
|
memAssignRef(Our, &Our->CurrentLayer, l);
|
|
return l;
|
|
return l;
|
|
}
|
|
}
|
|
@@ -380,19 +388,28 @@ void our_LayerEnsureTiles(OurLayer* ol, real xmin,real xmax, real ymin,real ymax
|
|
}
|
|
}
|
|
*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){
|
|
|
|
|
|
+void our_TileTextureToImage(OurTexTile* ot, int SX, int SY, int composite){
|
|
|
|
+ if(!ot->Texture) return;
|
|
int bufsize=sizeof(uint16_t)*OUR_TEX_TILE_W_USE*OUR_TEX_TILE_W_USE*4;
|
|
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;
|
|
ot->Data=malloc(bufsize); int seam=OUR_TEX_TILE_SEAM; int width=OUR_TEX_TILE_W_USE;
|
|
tnsBindTexture(ot->Texture);
|
|
tnsBindTexture(ot->Texture);
|
|
glPixelStorei(GL_PACK_ALIGNMENT, 2);
|
|
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);
|
|
- int acc=0,read=0;
|
|
|
|
- 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);
|
|
|
|
|
|
+ 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]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }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);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
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;
|
|
int pl=(SX!=0)?OUR_TEX_TILE_SEAM:0, pr=((SX+OUR_TEX_TILE_W_USE)!=Our->ImageW)?OUR_TEX_TILE_SEAM:0;
|
|
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 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;
|
|
int bufsize=sizeof(uint16_t)*(OUR_TEX_TILE_W+pl+pr)*(OUR_TEX_TILE_W+pu+pb)*4;
|
|
@@ -424,11 +441,32 @@ int our_LayerEnsureImageBuffer(OurLayer* ol, int OnlyCalculate){
|
|
}
|
|
}
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
-void our_LayerToImageBuffer(OurLayer* ol){
|
|
|
|
|
|
+int our_CanvasEnsureImageBuffer(){
|
|
|
|
+ int x=INT_MAX,y=INT_MAX,w=-INT_MAX,h=-INT_MAX;
|
|
|
|
+ for(OurLayer* l=Our->Layers.pFirst;l;l=l->Item.pNext){
|
|
|
|
+ our_LayerEnsureImageBuffer(l,1);
|
|
|
|
+ if(Our->ImageX<x) x=Our->ImageX; if(Our->ImageY<y) y=Our->ImageY;
|
|
|
|
+ if(Our->ImageW>w) w=Our->ImageW; if(Our->ImageH>h) h=Our->ImageH;
|
|
|
|
+ }
|
|
|
|
+ if(w<0||h<0) return 0;
|
|
|
|
+ Our->ImageX=x; Our->ImageY=y; Our->ImageW=w; Our->ImageH=h;
|
|
|
|
+ if(Our->ImageBuffer) free(Our->ImageBuffer);
|
|
|
|
+ Our->ImageBuffer = calloc(Our->ImageW*4,Our->ImageH*sizeof(uint16_t));
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+void our_CanvasFillImageBufferBackground(){
|
|
|
|
+ int count=Our->ImageW*Our->ImageH;
|
|
|
|
+ Our->BColorU16[0]=Our->BackgroundColor[0]*65535; Our->BColorU16[1]=Our->BackgroundColor[1]*65535;
|
|
|
|
+ Our->BColorU16[2]=Our->BackgroundColor[2]*65535; Our->BColorU16[3]=65535;
|
|
|
|
+ for(int i=0;i<count;i++){
|
|
|
|
+ uint16_t* p=&Our->ImageBuffer[i*4]; tnsVectorSet4v(p,Our->BColorU16);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+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 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;
|
|
for(int col=0;col<OUR_TEX_TILES_PER_ROW;col++){ if(!ol->TexTiles[row][col]) continue;
|
|
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;
|
|
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;
|
|
- our_TileTextureToImage(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY);
|
|
|
|
|
|
+ our_TileTextureToImage(ol->TexTiles[row][col], sx-Our->ImageX, sy-Our->ImageY, composite);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -440,18 +478,31 @@ void our_LayerToTexture(OurLayer* ol){
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+void our_GetFinalDimension(int UseFrame, int* x, int* y, int* w, int* h){
|
|
|
|
+ if(UseFrame){ *x=Our->X; *y=Our->Y; *w=Our->W; *h=Our->H; }
|
|
|
|
+ else{ *x=Our->ImageX; *y=Our->ImageY; *w=Our->ImageW; *h=Our->ImageH; }
|
|
|
|
+ printf("%d %d %d %d, %d %d %d %d\n",Our->X, Our->Y, Our->W, Our->H,Our->ImageX, Our->ImageY, Our->ImageW, Our->ImageH);
|
|
|
|
+}
|
|
|
|
+uint16_t* our_GetFinalRow(int UseFrame, int row, int x, int y, int w, int h, uint16_t* temp){
|
|
|
|
+ if(!UseFrame) return &Our->ImageBuffer[Our->ImageW*(Our->ImageH-row-1)*4];
|
|
|
|
+ int userow=(h-row-1)-(Our->ImageY-(y-h));
|
|
|
|
+ if(userow<0 || userow>=Our->ImageH){ for(int i=0;i<w;i++){ tnsVectorSet4v(&temp[i*4],Our->BColorU16); } return temp; }
|
|
|
|
+ int sstart=x>Our->ImageX?x-Our->ImageX:0, tstart=x>Our->ImageX?0:Our->ImageX-x;
|
|
|
|
+ int slen=(x+w>Our->ImageX+Our->ImageW)?(Our->ImageW-sstart):(Our->ImageW-sstart-(Our->ImageX+Our->ImageW-x-w));
|
|
|
|
+ for(int i=0;i<sstart;i++){ tnsVectorSet4v(&temp[i*4],Our->BColorU16); }
|
|
|
|
+ for(int i=sstart+slen;i<w;i++){ tnsVectorSet4v(&temp[i*4],Our->BColorU16); }
|
|
|
|
+ memcpy(&temp[tstart*4],&Our->ImageBuffer[(Our->ImageW*(userow)+sstart)*4],slen*sizeof(uint16_t)*4);
|
|
|
|
+ return temp;
|
|
|
|
+}
|
|
static void _our_png_write(png_structp png_ptr, png_bytep data, png_size_t length){
|
|
static void _our_png_write(png_structp png_ptr, png_bytep data, png_size_t length){
|
|
OurLayerWrite* LayerWrite=png_get_io_ptr(png_ptr);
|
|
OurLayerWrite* LayerWrite=png_get_io_ptr(png_ptr);
|
|
arrEnsureLength(&LayerWrite->data,LayerWrite->NextData+length,&LayerWrite->MaxData,sizeof(unsigned char));
|
|
arrEnsureLength(&LayerWrite->data,LayerWrite->NextData+length,&LayerWrite->MaxData,sizeof(unsigned char));
|
|
memcpy(&LayerWrite->data[LayerWrite->NextData], data, length);
|
|
memcpy(&LayerWrite->data[LayerWrite->NextData], data, length);
|
|
LayerWrite->NextData+=length;
|
|
LayerWrite->NextData+=length;
|
|
}
|
|
}
|
|
-int our_LayerExportPNG(OurLayer* l, FILE* fp, int WriteToBuffer, void** buf, int* sizeof_buf){
|
|
|
|
- if(!l||(!fp&&!WriteToBuffer)) return 0;
|
|
|
|
-
|
|
|
|
- if(!our_LayerEnsureImageBuffer(l, 0)) return 0;
|
|
|
|
-
|
|
|
|
- our_LayerToImageBuffer(l);
|
|
|
|
|
|
+int our_ImageExportPNG(FILE* fp, int WriteToBuffer, void** buf, int* sizeof_buf, int UseFrame){
|
|
|
|
+ if((!fp)&&(!WriteToBuffer)) return 0;
|
|
|
|
+ if(!Our->ImageBuffer) return 0;
|
|
|
|
|
|
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0);
|
|
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0);
|
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
|
@@ -464,8 +515,10 @@ int our_LayerExportPNG(OurLayer* l, FILE* fp, int WriteToBuffer, void** buf, int
|
|
}else{
|
|
}else{
|
|
png_init_io(png_ptr, fp);
|
|
png_init_io(png_ptr, fp);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ int X,Y,W,H; our_GetFinalDimension(UseFrame, &X,&Y,&W,&H);
|
|
|
|
|
|
- png_set_IHDR(png_ptr, info_ptr,Our->ImageW,Our->ImageH,16,PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);
|
|
|
|
|
|
+ png_set_IHDR(png_ptr, info_ptr,W,H,16,PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);
|
|
// Should not set gamma, we should set either srgb chunk or iccp. Gimp bug: https://gitlab.gnome.org/GNOME/gimp/-/issues/5363
|
|
// Should not set gamma, we should set either srgb chunk or iccp. Gimp bug: https://gitlab.gnome.org/GNOME/gimp/-/issues/5363
|
|
// But we still include a gamma 1.0 for convenience in OurPaint internal layer reading.
|
|
// But we still include a gamma 1.0 for convenience in OurPaint internal layer reading.
|
|
//png_set_gAMA(png_ptr,info_ptr,0.45455);
|
|
//png_set_gAMA(png_ptr,info_ptr,0.45455);
|
|
@@ -478,8 +531,11 @@ int our_LayerExportPNG(OurLayer* l, FILE* fp, int WriteToBuffer, void** buf, int
|
|
png_write_info(png_ptr, info_ptr);
|
|
png_write_info(png_ptr, info_ptr);
|
|
png_set_swap(png_ptr);
|
|
png_set_swap(png_ptr);
|
|
|
|
|
|
- for(int i=0;i<Our->ImageH;i++){
|
|
|
|
- png_write_row(png_ptr, (png_const_bytep)&Our->ImageBuffer[Our->ImageW*(Our->ImageH-i-1)*4]);
|
|
|
|
|
|
+ uint16_t* temp_row=calloc(W,sizeof(uint16_t)*4);
|
|
|
|
+
|
|
|
|
+ for(int i=0;i<H;i++){
|
|
|
|
+ uint16_t* final=our_GetFinalRow(UseFrame,i,X,Y,W,H,temp_row);
|
|
|
|
+ png_write_row(png_ptr, (png_const_bytep)final);
|
|
}
|
|
}
|
|
|
|
|
|
png_write_end(png_ptr, info_ptr);
|
|
png_write_end(png_ptr, info_ptr);
|
|
@@ -795,9 +851,11 @@ int ourmod_ExportLayer(laOperator* a, laEvent* e){
|
|
OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
|
|
OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
|
|
if (a->ConfirmData){
|
|
if (a->ConfirmData){
|
|
if (a->ConfirmData->StrData){
|
|
if (a->ConfirmData->StrData){
|
|
|
|
+ if(!our_LayerEnsureImageBuffer(ol, 0)) return LA_FINISHED;
|
|
FILE* fp=fopen(a->ConfirmData->StrData,"wb");
|
|
FILE* fp=fopen(a->ConfirmData->StrData,"wb");
|
|
if(!fp) return LA_FINISHED;
|
|
if(!fp) return LA_FINISHED;
|
|
- our_LayerExportPNG(Our->CurrentLayer, fp, 0, 0, 0);
|
|
|
|
|
|
+ our_LayerToImageBuffer(ol, 0);
|
|
|
|
+ our_ImageExportPNG(fp, 0, 0, 0, 0);
|
|
fclose(fp);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
@@ -823,22 +881,45 @@ int ourmod_ImportLayer(laOperator* a, laEvent* e){
|
|
}
|
|
}
|
|
return LA_RUNNING;
|
|
return LA_RUNNING;
|
|
}
|
|
}
|
|
|
|
+int ourinv_ExportImage(laOperator* a, laEvent* e){
|
|
|
|
+ OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
|
|
|
|
+ laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
|
|
|
|
+ return LA_RUNNING;
|
|
|
|
+}
|
|
|
|
+int ourmod_ExportImage(laOperator* a, laEvent* e){
|
|
|
|
+ OurLayer* ol=a->This?a->This->EndInstance:0; if(!ol) ol=Our->CurrentLayer; if(!ol) return LA_FINISHED;
|
|
|
|
+ if (a->ConfirmData){
|
|
|
|
+ if (a->ConfirmData->StrData){
|
|
|
|
+ if(!our_CanvasEnsureImageBuffer()) return LA_FINISHED;
|
|
|
|
+ FILE* fp=fopen(a->ConfirmData->StrData,"wb");
|
|
|
|
+ if(!fp) return LA_FINISHED;
|
|
|
|
+ our_CanvasFillImageBufferBackground();
|
|
|
|
+ for(OurLayer* l=Our->Layers.pLast;l;l=l->Item.pPrev){
|
|
|
|
+ our_LayerToImageBuffer(ol, 1);
|
|
|
|
+ }
|
|
|
|
+ our_ImageExportPNG(fp, 0, 0, 0, Our->ShowBorder);
|
|
|
|
+ fclose(fp);
|
|
|
|
+ }
|
|
|
|
+ return LA_FINISHED;
|
|
|
|
+ }
|
|
|
|
+ return LA_RUNNING;
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
int ourinv_NewBrush(laOperator* a, laEvent* e){
|
|
int ourinv_NewBrush(laOperator* a, laEvent* e){
|
|
- our_NewBrush("Our Brush",15,0.95,9,0.5,0.5,5,0,0,0,0); laNotifyUsers("our.brushes");
|
|
|
|
|
|
+ our_NewBrush("Our Brush",15,0.95,9,0.5,0.5,5,0,0,0,0); laNotifyUsers("our.tools.brushes");
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
int ourinv_RemoveBrush(laOperator* a, laEvent* e){
|
|
int ourinv_RemoveBrush(laOperator* a, laEvent* e){
|
|
OurBrush* b=a->This?a->This->EndInstance:0; if(!b) return LA_CANCELED;
|
|
OurBrush* b=a->This?a->This->EndInstance:0; if(!b) return LA_CANCELED;
|
|
- our_RemoveLayer(b); laNotifyUsers("our.brushes");
|
|
|
|
|
|
+ our_RemoveLayer(b); laNotifyUsers("our.tools.brushes");
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
int ourinv_MoveBrush(laOperator* a, laEvent* e){
|
|
int ourinv_MoveBrush(laOperator* a, laEvent* e){
|
|
OurBrush* b=a->This?a->This->EndInstance:0; if(!b) return LA_CANCELED;
|
|
OurBrush* b=a->This?a->This->EndInstance:0; if(!b) return LA_CANCELED;
|
|
char* direction=strGetArgumentString(a->ExtraInstructionsP,"direction");
|
|
char* direction=strGetArgumentString(a->ExtraInstructionsP,"direction");
|
|
- if(strSame(direction,"up")&&b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
|
|
|
|
- elif(b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
|
|
|
|
|
|
+ if(strSame(direction,"up")&&b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
|
|
|
|
+ elif(b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
|
|
return LA_FINISHED;
|
|
return LA_FINISHED;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -860,9 +941,9 @@ int ourmod_Paint(laOperator* a, laEvent* e){
|
|
int tl,tr,tu,tb;
|
|
int tl,tr,tu,tb;
|
|
if(our_PaintGetDabs(ob,l,ex->CanvasLastX,ex->CanvasLastY,x,y,ex->LastPressure,e->Pressure,&tl,&tr,&tu,&tb)){
|
|
if(our_PaintGetDabs(ob,l,ex->CanvasLastX,ex->CanvasLastY,x,y,ex->LastPressure,e->Pressure,&tl,&tr,&tu,&tb)){
|
|
our_PaintDoDabsWithSmudgeSegments(l,tl,tr,tu,tb);
|
|
our_PaintDoDabsWithSmudgeSegments(l,tl,tr,tu,tb);
|
|
|
|
+ laNotifyUsers("our.canvas"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
|
|
}
|
|
}
|
|
ex->CanvasLastX=x;ex->CanvasLastY=y;ex->LastPressure=e->Pressure;
|
|
ex->CanvasLastX=x;ex->CanvasLastY=y;ex->LastPressure=e->Pressure;
|
|
- laNotifyUsers("our.canvas");
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return LA_RUNNING;
|
|
return LA_RUNNING;
|
|
@@ -874,7 +955,7 @@ int ourmod_Crop(laOperator* a, laEvent* e){
|
|
if(e->Type==LA_MOUSEMOVE||e->Type==LA_L_MOUSE_DOWN){
|
|
if(e->Type==LA_MOUSEMOVE||e->Type==LA_L_MOUSE_DOWN){
|
|
real x,y; our_UiToCanvas(&ex->Base,e,&x,&y);
|
|
real x,y; our_UiToCanvas(&ex->Base,e,&x,&y);
|
|
our_DoCropping(ex,x,y);
|
|
our_DoCropping(ex,x,y);
|
|
- laNotifyUsers("our.canvas");
|
|
|
|
|
|
+ laNotifyUsers("our.canvas"); laMarkMemChanged(Our->CanvasSaverDummyList.pFirst);
|
|
}
|
|
}
|
|
|
|
|
|
return LA_RUNNING;
|
|
return LA_RUNNING;
|
|
@@ -910,6 +991,9 @@ int ourmod_PickColor(laOperator* a, laEvent* e){
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+void ourget_CanvasIdentifier(void* unused, char* buf, char** ptr){
|
|
|
|
+ *ptr="Main canvas";
|
|
|
|
+}
|
|
void* ourget_FirstLayer(void* unused, void* unused1){
|
|
void* ourget_FirstLayer(void* unused, void* unused1){
|
|
return Our->Layers.pFirst;
|
|
return Our->Layers.pFirst;
|
|
}
|
|
}
|
|
@@ -927,7 +1011,9 @@ void ourset_LayerTileStart(OurLayer* l, int* xy){
|
|
}
|
|
}
|
|
void* ourget_LayerImage(OurLayer* l, int* r_size, int* r_is_copy){
|
|
void* ourget_LayerImage(OurLayer* l, int* r_size, int* r_is_copy){
|
|
void* buf=0;
|
|
void* buf=0;
|
|
- if(our_LayerExportPNG(l,0,1,&buf,r_size)){ *r_is_copy=1; return buf; }
|
|
|
|
|
|
+ if(!our_LayerEnsureImageBuffer(l, 0)){ *r_is_copy=0; return 0; }
|
|
|
|
+ our_LayerToImageBuffer(l, 0);
|
|
|
|
+ if(our_ImageExportPNG(0,1,&buf,r_size, 0)){ *r_is_copy=1; return buf; }
|
|
*r_is_copy=0; return buf;
|
|
*r_is_copy=0; return buf;
|
|
}
|
|
}
|
|
void ourset_LayerImage(OurLayer* l, void* data, int size){
|
|
void ourset_LayerImage(OurLayer* l, void* data, int size){
|
|
@@ -939,8 +1025,8 @@ void ourset_LayerMove(OurLayer* l, int move){
|
|
elif(move>0 && l->Item.pNext){ lstMoveDown(&Our->Layers, l); laNotifyUsers("our.canvas.layers"); }
|
|
elif(move>0 && l->Item.pNext){ lstMoveDown(&Our->Layers, l); laNotifyUsers("our.canvas.layers"); }
|
|
}
|
|
}
|
|
void ourset_BrushMove(OurBrush* b, int move){
|
|
void ourset_BrushMove(OurBrush* b, int move){
|
|
- if(move<0 && b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
|
|
|
|
- elif(move>0 && b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.brushes"); }
|
|
|
|
|
|
+ if(move<0 && b->Item.pPrev){ lstMoveUp(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
|
|
|
|
+ elif(move>0 && b->Item.pNext){ lstMoveDown(&Our->Brushes, b); laNotifyUsers("our.tools.brushes"); }
|
|
}
|
|
}
|
|
void ourset_BackgroundColor(void* unused, real* arr){
|
|
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");
|
|
@@ -966,6 +1052,11 @@ void ourset_LayoutPosition(OurLayer* l, int* xy){
|
|
void ourreset_Canvas(OurPaint* op){
|
|
void ourreset_Canvas(OurPaint* op){
|
|
while(op->Layers.pFirst){ our_RemoveLayer(op->Layers.pFirst); }
|
|
while(op->Layers.pFirst){ our_RemoveLayer(op->Layers.pFirst); }
|
|
}
|
|
}
|
|
|
|
+void ourpropagate_Tools(OurPaint* p, laUDF* udf, int force){
|
|
|
|
+ for(OurBrush* b=p->Brushes.pFirst;b;b=b->Item.pNext){
|
|
|
|
+ if(force || !laget_InstanceActiveUDF(b)){ laset_InstanceUDF(b, udf); }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
#define OUR_ADD_PRESSURE_SWITCH(p)\
|
|
#define OUR_ADD_PRESSURE_SWITCH(p)\
|
|
laAddEnumItemAs(p,"NONE","None","Not using pressure",0,0);\
|
|
laAddEnumItemAs(p,"NONE","None","Not using pressure",0,0);\
|
|
@@ -976,6 +1067,8 @@ void ourui_MenuButtons(laUiList *uil, laPropPack *pp, laPropPack *actinst, laCol
|
|
muil = laMakeMenuPage(uil, c, "File");{
|
|
muil = laMakeMenuPage(uil, c, "File");{
|
|
mc = laFirstColumn(muil);
|
|
mc = laFirstColumn(muil);
|
|
laShowLabel(muil, mc, "Our Paint", 0, 0);
|
|
laShowLabel(muil, mc, "Our Paint", 0, 0);
|
|
|
|
+ laShowItem(muil, mc, 0, "OUR_export_image");
|
|
|
|
+ laShowSeparator(muil,mc);
|
|
laShowItem(muil, mc, 0, "OUR_export_layer");
|
|
laShowItem(muil, mc, 0, "OUR_export_layer");
|
|
laShowItem(muil, mc, 0, "OUR_import_layer");
|
|
laShowItem(muil, mc, 0, "OUR_import_layer");
|
|
laui_DefaultMenuButtonsFileEntries(muil,pp,actinst,extracol,0);
|
|
laui_DefaultMenuButtonsFileEntries(muil,pp,actinst,extracol,0);
|
|
@@ -998,6 +1091,7 @@ void ourRegisterEverything(){
|
|
laCreateOperatorType("OUR_move_brush","Move Brush","Remove this brush",0,0,0,ourinv_MoveBrush,0,0,0);
|
|
laCreateOperatorType("OUR_move_brush","Move Brush","Remove this brush",0,0,0,ourinv_MoveBrush,0,0,0);
|
|
laCreateOperatorType("OUR_action","Action","Doing action on a layer",0,0,0,ourinv_Action,ourmod_Action,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);
|
|
laCreateOperatorType("OUR_pick","Pick color","Pick color on the widget",0,0,0,ourinv_PickColor,ourmod_PickColor,0,LA_EXTRA_TO_PANEL);
|
|
|
|
+ laCreateOperatorType("OUR_export_image","Export Image","Export the image",0,0,0,ourinv_ExportImage,ourmod_ExportImage,L'🖼',0);
|
|
|
|
|
|
laRegisterUiTemplate("panel_canvas", "Canvas", ourui_CanvasPanel, 0, 0,"Our Paint");
|
|
laRegisterUiTemplate("panel_canvas", "Canvas", ourui_CanvasPanel, 0, 0,"Our Paint");
|
|
laRegisterUiTemplate("panel_layers", "Layers", ourui_LayersPanel, 0, 0,0);
|
|
laRegisterUiTemplate("panel_layers", "Layers", ourui_LayersPanel, 0, 0,0);
|
|
@@ -1009,8 +1103,7 @@ void ourRegisterEverything(){
|
|
|
|
|
|
pc=laAddPropertyContainer("our_paint","Our Paint","OurPaint main",0,0,sizeof(OurPaint),0,0,1);
|
|
pc=laAddPropertyContainer("our_paint","Our Paint","OurPaint main",0,0,sizeof(OurPaint),0,0,1);
|
|
laAddSubGroup(pc,"canvas","Canvas","OurPaint canvas","our_canvas",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
|
|
laAddSubGroup(pc,"canvas","Canvas","OurPaint canvas","our_canvas",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
|
|
- laAddSubGroup(pc,"brushes","Brushes","Brushes","our_brush",0,0,ourui_Brush,offsetof(OurPaint,CurrentBrush),0,0,0,0,0,0,offsetof(OurPaint,Brushes),0);
|
|
|
|
- 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);
|
|
|
|
|
|
+ laAddSubGroup(pc,"tools","Tools","OurPaint tools","our_tools",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
|
|
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,3,0,0,0,0,0,0,0,LA_PROP_IS_LINEAR_SRGB);
|
|
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,3,0,0,0,0,0,0,0,LA_PROP_IS_LINEAR_SRGB);
|
|
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,LA_PROP_IS_LINEAR_SRGB);
|
|
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,LA_PROP_IS_LINEAR_SRGB);
|
|
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);
|
|
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);
|
|
@@ -1020,6 +1113,12 @@ void ourRegisterEverything(){
|
|
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);
|
|
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,"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'🖼');
|
|
laAddEnumItemAs(p,"TRUE","Yes","Show border on the canvas",OUR_TOOL_CROP,L'🖼');
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ pc=laAddPropertyContainer("our_tools","Our Tools","OurPaint tools",0,0,sizeof(OurPaint),0,0,1);
|
|
|
|
+ laPropContainerExtraFunctions(pc,0,0,0,ourpropagate_Tools,0);
|
|
|
|
+ laAddSubGroup(pc,"brushes","Brushes","Brushes","our_brush",0,0,ourui_Brush,offsetof(OurPaint,CurrentBrush),0,0,0,0,0,0,offsetof(OurPaint,Brushes),0);
|
|
|
|
+ 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);
|
|
|
|
|
|
pc=laAddPropertyContainer("our_brush","Our Brush","OurPaint brush",0,0,sizeof(OurBrush),0,0,2);
|
|
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);
|
|
laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurBrush,Name),0,0,0,0,LA_AS_IDENTIFIER);
|
|
@@ -1043,12 +1142,14 @@ void ourRegisterEverything(){
|
|
|
|
|
|
pc=laAddPropertyContainer("our_canvas","Our Canvas","OurPaint canvas",0,0,sizeof(OurPaint),0,0,1);
|
|
pc=laAddPropertyContainer("our_canvas","Our Canvas","OurPaint canvas",0,0,sizeof(OurPaint),0,0,1);
|
|
laPropContainerExtraFunctions(pc,0,ourreset_Canvas,0,0,0);
|
|
laPropContainerExtraFunctions(pc,0,ourreset_Canvas,0,0,0);
|
|
|
|
+ Our->CanvasSaverDummyProp=laPropContainerManageable(pc, offsetof(OurPaint,CanvasSaverDummyList));
|
|
|
|
+ laAddStringProperty(pc,"identifier","Identifier","Canvas identifier placeholder",0,0,0,0,0,0,0,ourget_CanvasIdentifier,0,0,0);
|
|
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,"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);
|
|
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,"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);
|
|
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,2);
|
|
|
|
|
|
+ pc=laAddPropertyContainer("our_layer","Our Layer","OurPaint layer",0,0,sizeof(OurLayer),0,0,1);
|
|
laPropContainerExtraFunctions(pc,ourbeforefree_Layer,ourbeforefree_Layer,0,0,0);
|
|
laPropContainerExtraFunctions(pc,ourbeforefree_Layer,ourbeforefree_Layer,0,0,0);
|
|
laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurLayer,Name),0,0,0,0,LA_AS_IDENTIFIER);
|
|
laAddStringProperty(pc,"name","Name","Name of the layer",0,0,0,0,1,offsetof(OurLayer,Name),0,0,0,0,LA_AS_IDENTIFIER);
|
|
laAddIntProperty(pc,"__move","Move Slider","Move Slider",LA_WIDGET_HEIGHT_ADJUSTER,0,0,0,0,0,0,0,0,0,ourset_LayerMove,0,0,0,0,0,0,0,0,0);
|
|
laAddIntProperty(pc,"__move","Move Slider","Move Slider",LA_WIDGET_HEIGHT_ADJUSTER,0,0,0,0,0,0,0,0,0,ourset_LayerMove,0,0,0,0,0,0,0,0,0);
|
|
@@ -1070,7 +1171,10 @@ void ourRegisterEverything(){
|
|
|
|
|
|
laSetMenuBarTemplates(ourui_MenuButtons, laui_DefaultMenuExtras, "OurPaint v0.1");
|
|
laSetMenuBarTemplates(ourui_MenuButtons, laui_DefaultMenuExtras, "OurPaint v0.1");
|
|
|
|
|
|
- laSaveProp("our");
|
|
|
|
|
|
+ laSaveProp("our.canvas");
|
|
|
|
+ laSaveProp("our.tools");
|
|
|
|
+
|
|
|
|
+ laGetSaverDummy(Our,Our->CanvasSaverDummyProp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|