1 /****************************************************************************
3 * canvas.c -- Lunapaint, *
4 * http://developer.berlios.de/projects/lunapaintami/ *
5 * Copyright (C) 2006, 2007, Hogne Titlestad <hogga@sub-ether.org> *
6 * Copyright (C) 2009-2011 LunaPaint Development Team *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software Foundation, *
20 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ****************************************************************************/
28 struct toolLineData lineTool
;
29 struct toolBrushData brushTool
;
30 struct toolCircleData circleTool
;
31 struct toolRectData rectangleTool
;
32 struct toolClipBrushData clipbrushTool
;
35 struct oCanvas
* Init_Canvas (
36 unsigned int w
, unsigned int h
,
37 unsigned int layers
, unsigned int frames
,
41 int bufsize
= w
* h
* 8;
43 struct oCanvas
*canv
= AllocVec ( sizeof ( struct oCanvas
), MEMF_ANY
);
44 canv
->screenbuffer
= NULL
;
47 // Reserve memory for all the images in the linked list:
48 if ( generateBuffers
)
50 canv
->buffer
= AllocVec ( sizeof ( struct gfxbuffer
), MEMF_ANY
);
51 struct gfxbuffer
*tmp
= canv
->buffer
;
52 int span
= layers
* frames
;
53 int a
= 0; for ( ; a
< span
; a
++ )
55 tmp
->buf
= AllocVec ( bufsize
, MEMF_ANY
);
58 tmp
->name
= AllocVec ( 12, MEMF_ANY
|MEMF_CLEAR
);
59 strcpy ( tmp
->name
, _(MSG_CORE_LAYER_EMPTY
) );
62 int i
= 0; for ( ; i
< scope
; i
++ )
63 tmp
->buf
[ i
] = TRANSCOLOR
;
66 tmp
->nextbuf
= AllocVec ( sizeof ( struct gfxbuffer
), MEMF_ANY
);
67 else tmp
->nextbuf
= NULL
; // <- marks the end
78 canv
->currentFrame
= 0;
79 canv
->totalFrames
= frames
;
80 canv
->currentLayer
= 0;
81 canv
->previousLayer
= 0;
82 canv
->totalLayers
= layers
;
83 canv
->screenbuffer
= NULL
;
84 canv
->screenstorage
= NULL
;
86 canv
->swapbuffer
= AllocVec ( bufsize
, MEMF_ANY
);
87 int i
= 0; for ( i
= 0; i
< scope
; i
++ ) canv
->swapbuffer
[ i
] = TRANSCOLOR
;
88 canv
->winHasChanged
= TRUE
;
92 void NextFrame ( struct oCanvas
*canvas
)
94 if ( canvas
->totalFrames
> canvas
->currentFrame
+ 1 )
95 canvas
->currentFrame
++;
96 else canvas
->currentFrame
= 0;
97 setActiveBuffer ( canvas
);
100 void PrevFrame ( struct oCanvas
*canvas
)
102 if ( canvas
->currentFrame
> 0 )
103 canvas
->currentFrame
--;
104 else canvas
->currentFrame
= canvas
->totalFrames
- 1;
105 setActiveBuffer ( canvas
);
108 void Destroy_Canvas ( struct oCanvas
*canvas
)
110 globalActiveCanvas
= NULL
;
112 // Reset all pointers to data here
113 if ( canvas
->screenbuffer
!= NULL
)
114 FreeVec ( canvas
->screenbuffer
);
115 if ( canvas
->screenstorage
!= NULL
)
116 FreeVec ( canvas
->screenstorage
);
117 if ( canvas
->swapbuffer
!= NULL
)
118 FreeVec ( canvas
->swapbuffer
);
119 if ( canvas
->tmpBuf
!= NULL
)
120 FreeVec ( canvas
->tmpBuf
);
122 canvas
->activebuffer
= NULL
;
123 globalActiveWindow
->canvas
= NULL
;
125 Destroy_Buffer ( canvas
);
127 if ( canvas
!= NULL
)
131 void Destroy_Buffer ( struct oCanvas
*canv
)
133 struct gfxbuffer
*buf
= canv
->buffer
;
135 while ( buf
!= NULL
)
137 if ( buf
->name
!= NULL
) FreeVec ( buf
->name
);
138 if ( buf
->buf
!= NULL
) FreeVec ( buf
->buf
);
139 struct gfxbuffer
*tmp
= buf
;
145 void setActiveBuffer ( struct oCanvas
*canvas
)
147 if ( canvas
== NULL
) return;
148 struct gfxbuffer
*buf
= canvas
->buffer
;
149 int i
= 0; while ( buf
!= NULL
)
151 int f
= i
/ canvas
->totalLayers
;
152 int l
= i
% canvas
->totalLayers
;
153 if ( f
== canvas
->currentFrame
&& l
== canvas
->currentLayer
)
155 canvas
->activebuffer
= buf
->buf
;
164 unsigned long long int *getNextFrame ( struct oCanvas
*canvas
)
166 struct gfxbuffer
*buf
= canvas
->buffer
;
167 int target
= ( canvas
->currentFrame
+ 1 ) % canvas
->totalFrames
;
168 int size
= canvas
->totalFrames
* canvas
->totalLayers
;
169 int i
= 0; for ( ; i
< size
; i
++ )
171 int l
= i
% canvas
->totalLayers
;
172 if ( l
== canvas
->currentLayer
)
173 if ( i
/ canvas
->totalLayers
== target
) return buf
->buf
;
179 unsigned long long int *getPrevFrame ( struct oCanvas
*canvas
)
181 struct gfxbuffer
*buf
= canvas
->buffer
;
182 int target
= ( canvas
->currentFrame
- 1 );
183 if ( target
< 0 ) target
= canvas
->totalFrames
- 1;
184 int size
= canvas
->totalFrames
* canvas
->totalLayers
;
185 int i
= 0; for ( ; i
< size
; i
++ )
187 int l
= i
% canvas
->totalLayers
;
188 if ( l
== canvas
->currentLayer
)
189 if ( i
/ canvas
->totalLayers
== target
) return buf
->buf
;
195 struct gfxbuffer
*getActiveGfxbuffer ( struct oCanvas
*canvas
)
197 struct gfxbuffer
*buf
= canvas
->buffer
;
198 int size
= canvas
->totalFrames
* canvas
->totalLayers
;
199 int i
= 0; for ( ; i
< size
; i
++ )
201 int l
= i
% canvas
->totalLayers
;
202 if ( l
== canvas
->currentLayer
)
203 if ( i
/ canvas
->totalLayers
== canvas
->currentFrame
) return buf
;
209 struct gfxbuffer
*getGfxbuffer ( struct oCanvas
*canvas
, int layer
, int frame
)
211 struct gfxbuffer
*buf
= canvas
->buffer
;
212 int size
= canvas
->totalFrames
* canvas
->totalLayers
;
213 int i
= 0; for ( ; i
< size
; i
++ )
215 int l
= i
% canvas
->totalLayers
;
217 if ( i
/ canvas
->totalLayers
== frame
) return buf
;
223 struct gfxbuffer
*getGfxbufferFromList ( struct gfxbuffer
*buf
, int layer
, int frame
, int totallayers
, int totalframes
)
225 if ( buf
== NULL
) return NULL
;
226 int size
= totalframes
* totallayers
;
227 int i
= 0; for ( ; i
< size
; i
++ )
229 int f
= i
/ totallayers
;
230 int l
= i
% totallayers
;
231 if ( f
== frame
&& l
== layer
) return buf
;
237 unsigned int *renderCanvas (
238 struct oCanvas
*canvas
, unsigned int rx
, unsigned int ry
,
239 unsigned int rw
, unsigned int rh
, BOOL Transparent
243 int layerNum
= canvas
->totalLayers
;
244 int frameNum
= canvas
->totalFrames
;
245 int zoomedWidth
= rw
* canvas
->zoom
;
246 int zoom
= canvas
->zoom
;
247 int zoomZoomwidth
= zoom
* zoomedWidth
;
248 int layerNumAndTrans
= layerNum
+ 1; // with transparent layer
249 int len
= frameNum
* layerNumAndTrans
;
253 // Allocate memory for temporary buffer
254 unsigned int *tempBuf
= AllocVec ( zoomedWidth
* ( rh
* zoom
) * 4, MEMF_ANY
);
255 if ( tempBuf
== NULL
){ return NULL
; };
258 struct gfxbuffer
*buf
= canvas
->buffer
;
259 int i
= 0; for ( ; i
< len
; i
++ )
261 int l
= ( i
% layerNumAndTrans
) - 1;
262 int f
= i
/ layerNumAndTrans
;
263 // Skip irrelevant layers
264 if ( l
>= 0 && ( buf
->opacity
== 0 || !buf
->visible
) )
269 if ( f
== canvas
->currentFrame
)
271 unsigned long long int *currentBuf
= buf
->buf
;
272 unsigned long long int *onionBuf
= getPrevFrame ( canvas
);
274 int y
= ry
, YminRY
= 0; for ( ; y
< ryrh
; y
++ )
276 if ( y
>= canvas
->height
) break;
278 // Some often used calcs :-)
279 int tboffsety
= YminRY
* zoomZoomwidth
; // <- heavily optimized!
280 int canvymul
= canvas
->width
* y
;
281 int YminRYrw
= YminRY
* rw
;
283 int x
= rx
, XminRX
= 0; for ( ; x
< rxrw
; x
++ )
285 if ( x
>= canvas
->width
) break;
287 // Color that it will result in
288 unsigned int color
= 0;
290 // Make "checks" in RGBA
295 color
= *( unsigned int *)&( ( struct rgba32
){ 128, 128, 128, 0 } );
299 switch ( GlobalPrefs
.LayerBackgroundMode
)
302 color
= *( unsigned int *)&( ( struct rgba32
){ 0, 0, 0, 255 } );
305 color
= *( unsigned int *)&( ( struct rgba32
){ 128, 128, 128, 255 } );
308 color
= *( unsigned int *)&( ( struct rgba32
){ 255, 255, 255, 255 } );
312 color
= *( unsigned int *)&( ( struct rgba32
){ 128, 128, 128, 255 } );
313 int checkCol
= ( ( x
% 32 ) + ( int )( y
/ 16 ) * 16 ) % 32;
314 if ( checkCol
>= 16 )
315 color
= *( unsigned int *)&( ( struct rgba32
){ 90, 90, 90, 255 } );
323 // Get tempbuffer color and current layer color
324 int boffset
= XminRX
* zoom
+ tboffsety
;
325 struct rgba32 col1
= *( struct rgba32
*)&tempBuf
[ boffset
];
327 // Get color from current canvas buffer
328 struct rgba64 col2t
= *( struct rgba64
*)¤tBuf
[ canvymul
+ x
];
330 // Convert 16-bit pr pixel to 8
331 int a
= col2t
.r
/ 256,
337 // Apply layer opacity
338 if ( buf
->opacity
< 100 ) a
= a
/ 100.0 * buf
->opacity
;
340 // If current canvas is transparent, disregard it's colors
341 if ( a
<= 0 ){ r
= col1
.r
; g
= col1
.g
; b
= col1
.b
; a
= 0; }
344 double alpha
= a
/ 255.0;
345 col1
.r
-= ( col1
.r
- r
) * alpha
;
346 col1
.g
-= ( col1
.g
- g
) * alpha
;
347 col1
.b
-= ( col1
.b
- b
) * alpha
;
352 if ( ( col1
.a
+ a
) > 255 ) col1
.a
= 255;
356 // Add onion skin if needed
357 if ( canvas
->onion
== 1 )
359 struct rgba64 onioncol
= *( struct rgba64
*)&onionBuf
[ canvymul
+ x
];
360 r
= onioncol
.a
/ 256;
361 g
= onioncol
.b
/ 256;
362 b
= onioncol
.g
/ 256;
363 a
= onioncol
.r
/ 256;
367 col1
.r
-= ( col1
.r
- r
) * alpha
;
368 col1
.g
-= ( col1
.g
- g
) * alpha
;
369 col1
.b
-= ( col1
.b
- b
) * alpha
;
372 // Check if area needs tool preview
373 // (only when no buttons are down)
374 if ( globalCurrentTool
!= -1 && l
== canvas
->currentLayer
)
376 unsigned int test
= drawToolPreview ( x
, y
);
379 struct rgba32 blend
= *( struct rgba32
*)&test
;
380 double balph
= blend
.a
/ 255.0;
381 col1
.r
-= ( col1
.r
- blend
.b
) * balph
;
382 col1
.g
-= ( col1
.g
- blend
.g
) * balph
;
383 col1
.b
-= ( col1
.b
- blend
.r
) * balph
;
384 if ( col1
.a
+ blend
.a
< 255 )
390 // ( we skip col1.a as we know it's 255 from the checkCol )
391 color
= *( unsigned int *)&col1
;
395 tempBuf
[ YminRYrw
+ XminRX
] = color
;
398 // Zoom over on the tempBuf
399 int xzoom
= XminRX
* zoom
;
400 int yzoom
= YminRY
* zoom
;
401 int zy
= 0; for ( ; zy
< zoom
; zy
++ )
403 int zoompos
= ( yzoom
+ zy
) * zoomedWidth
+ xzoom
;
404 int zx
= 0; for ( ; zx
< zoom
; zx
++ )
405 tempBuf
[ zoompos
+ zx
] = color
;
413 if ( l
>= 0 ) buf
= buf
->nextbuf
;
418 // Scroll the canvas screen storage
419 void scrollScreenStorage ( struct oCanvas
*canvas
, int x
, int y
)
421 if ( !canvas
->screenstorage
) return;
422 unsigned int *tmpBuf
= AllocVec ( canvas
->scrStorageHeight
* canvas
->scrStorageWidth
* 4, MEMF_ANY
);
423 int sy
= 0; for ( ; sy
< canvas
->scrStorageHeight
; sy
++ )
425 int frOffsetY
= sy
* canvas
->scrStorageWidth
;
426 int toOffsetY
= ( ( sy
- y
) % canvas
->scrStorageHeight
) * canvas
->scrStorageWidth
;
427 int sx
= 0; for ( ; sx
< canvas
->scrStorageWidth
; sx
++ )
429 int toOffsetX
= ( sx
- x
) % canvas
->scrStorageWidth
;
430 tmpBuf
[ toOffsetY
+ toOffsetX
] = canvas
->screenstorage
[ frOffsetY
+ sx
];
433 FreeVec ( canvas
->screenstorage
);
434 canvas
->screenstorage
= tmpBuf
;
437 BOOL
redrawScreenbufferRect (
438 struct oCanvas
*canvas
, unsigned int rx
, unsigned int ry
, unsigned int rw
,
439 unsigned int rh
, BOOL updateStorage
442 // Get an unsigned int
443 unsigned int *tempBuf
= renderCanvas ( canvas
, rx
, ry
, rw
, rh
, FALSE
);
444 if ( tempBuf
== NULL
) return FALSE
;
447 int zoom
= canvas
->zoom
;
448 int zoomedWidth
= rw
* zoom
;
449 int zoomedHeight
= rh
* zoom
;
451 // Update screenbuffer for small blits (brush previews etc):
453 int datalen
= canvas
->visibleWidth
* canvas
->visibleHeight
;
454 int datasize
= 4 * datalen
;
455 int limitx
= zoomedWidth
< canvas
->visibleWidth
? zoomedWidth
: canvas
->visibleWidth
;
456 int limity
= zoomedHeight
< canvas
->visibleHeight
? zoomedHeight
: canvas
->visibleHeight
;
459 if ( canvas
->screenbuffer
!= NULL
)
460 FreeVec ( canvas
->screenbuffer
);
461 canvas
->screenbuffer
= AllocVec ( datasize
, MEMF_ANY
);
464 for ( ; y
< limity
; y
++ )
466 int tempzoomy
= zoomedWidth
* y
;
467 int screenzoomy
= canvas
->visibleWidth
* y
;
469 // Set resulting color in ABGR format
470 for ( x
= 0; x
< limitx
; x
++ )
472 canvas
->screenbuffer
[ screenzoomy
+ x
] = tempBuf
[ tempzoomy
+ x
];
476 // Update screen storage buffer (not while using tools)
477 if ( canvas
->winHasChanged
&& updateStorage
&& canvas
->screenbuffer
!= NULL
)
479 if ( canvas
->screenstorage
!= NULL
)
481 FreeVec ( canvas
->screenstorage
);
482 canvas
->screenstorage
= NULL
;
484 canvas
->screenstorage
= AllocVec ( datasize
, MEMF_ANY
);
485 canvas
->scrStorageWidth
= canvas
->visibleWidth
;
486 canvas
->scrStorageHeight
= canvas
->visibleHeight
;
487 memcpy ( canvas
->screenstorage
, canvas
->screenbuffer
, datasize
);
488 canvas
->winHasChanged
= FALSE
;
490 // Update only the part that's been blitted to tempBuf
491 // (except tool previews)
492 else if ( canvas
->screenstorage
&& tempBuf
)
494 rx
= rx
* zoom
- globalActiveCanvas
->offsetx
;
495 ry
= ry
* zoom
- globalActiveCanvas
->offsety
;
497 for ( y
= 0; y
< zoomedHeight
; y
++ )
500 if ( sy
< 0 || sy
>= canvas
->scrStorageHeight
) continue;
502 int syw
= sy
* canvas
->scrStorageWidth
;
503 int yw
= y
* zoomedWidth
;
505 for ( x
= 0; x
< zoomedWidth
; x
++ )
509 if ( sx
< 0 || sx
>= canvas
->scrStorageWidth
) continue;
511 canvas
->screenstorage
[ syw
+ sx
] = tempBuf
[ yw
+ x
];
516 // Free temp buffer and exit function
517 if ( tempBuf
!= NULL
) FreeVec ( tempBuf
);
521 BOOL
redrawScreenbuffer ( struct oCanvas
*canvas
)
523 int offsetx
= canvas
->offsetx
/ canvas
->zoom
;
524 int offsety
= canvas
->offsety
/ canvas
->zoom
;
525 int width
= ( canvas
->visibleWidth
+ 1 ) / canvas
->zoom
; // +1 is to draw one extra pixel if not everything
526 int height
= ( canvas
->visibleHeight
+ 1 ) / canvas
->zoom
; // fits into the visible width/height on aspect
528 if ( !redrawScreenbufferRect ( canvas
, offsetx
, offsety
, width
, height
, TRUE
) )
536 globalPalette
= AllocVec ( 256 * sizeof ( unsigned int ), MEMF_ANY
);
537 // Load in default palette
538 loadDefaultPalette ( );
541 void loadDefaultPalette ( )
544 if ( ( myfile
= Open ( "PROGDIR:default.palette", MODE_OLDFILE
) ) != NULL
)
546 Read ( myfile
, globalPalette
, 1024 );
549 else printf ( "Failed to load default palette..\n" );
552 void addLayer ( struct oCanvas
*canv
)
554 struct gfxbuffer
*pos
= canv
->buffer
;
556 // Go though each frame
557 int size
= canv
->width
* canv
->height
;
558 int f
= 0; for ( ; f
< canv
->totalFrames
; f
++ )
560 // Go to the last layer
561 int l
= 0; for ( ; l
< canv
->totalLayers
- 1; l
++ ) pos
= pos
->nextbuf
;
562 // Add new blank layer
563 struct gfxbuffer
*newlayer
= AllocVec ( sizeof ( struct gfxbuffer
), MEMF_ANY
);
564 newlayer
->buf
= AllocVec ( size
* 8, MEMF_ANY
);
565 int i
= 0; for ( ; i
< size
; i
++ ) newlayer
->buf
[ i
] = TRANSCOLOR
;
566 newlayer
->opacity
= 100;
567 newlayer
->visible
= TRUE
;
568 newlayer
->nextbuf
= pos
->nextbuf
;
569 newlayer
->name
= AllocVec ( 10, MEMF_ANY
|MEMF_CLEAR
);
570 strcpy ( newlayer
->name
, _(MSG_CORE_LAYER_NEW
) );
571 pos
->nextbuf
= newlayer
;
572 pos
= newlayer
->nextbuf
;
576 // Increment total layers
578 canv
->currentLayer
= canv
->totalLayers
- 1;
579 setActiveBuffer ( canv
);
582 void swapLayers ( struct oCanvas
*canv
)
584 struct gfxbuffer
*curr
= NULL
;
585 struct gfxbuffer
*prev
= NULL
;
586 struct gfxbuffer
*pos
= canv
->buffer
;
588 // Go through frames and layers with pos and store addy to
589 // current gfxbuffer and previous selected gfxbuffer
591 int f
= 0; for ( ; f
< canv
->totalFrames
; f
++ )
593 int l
= 0; for ( ; l
< canv
->totalLayers
; l
++ )
595 if ( f
== canv
->currentFrame
&& l
== canv
->currentLayer
)
597 if ( f
== canv
->currentFrame
&& l
== canv
->previousLayer
)
602 if ( prev
== NULL
|| curr
== NULL
)
605 // Temporarily store some values
606 unsigned long long int *tmp
= curr
->buf
;
607 char opacity
= curr
->opacity
;
608 unsigned char *name
= curr
->name
;
609 BOOL visible
= curr
->visible
;
612 curr
->buf
= prev
->buf
;
613 curr
->opacity
= prev
->opacity
;
614 curr
->visible
= prev
->visible
;
615 curr
->name
= prev
->name
;
619 prev
->opacity
= opacity
;
620 prev
->visible
= visible
;
624 setActiveBuffer ( canv
);
627 void copyLayers ( struct oCanvas
*canv
)
629 struct gfxbuffer
*curr
= NULL
;
630 struct gfxbuffer
*prev
= NULL
;
631 struct gfxbuffer
*pos
= canv
->buffer
;
633 // Go through frames and layers with pos and store addy to
634 // current gfxbuffer and previous selected gfxbuffer
635 int f
; for ( f
= 0; f
< canv
->totalFrames
; f
++ )
637 int l
; for ( l
= 0; l
< canv
->totalLayers
; l
++ )
639 if ( f
== canv
->currentFrame
&& l
== canv
->currentLayer
)
641 if ( f
== canv
->currentFrame
&& l
== canv
->previousLayer
)
646 // Copy prev buffer to current buffer
647 memcpy ( curr
->buf
, prev
->buf
, canv
->width
* canv
->height
* 8 );
650 void mergeLayers ( struct oCanvas
*canv
)
652 if ( canv
->currentLayer
== canv
->previousLayer
)
655 struct gfxbuffer
*backBuf
= NULL
;
656 struct gfxbuffer
*foreBuf
= NULL
;
657 struct gfxbuffer
*pos
= canv
->buffer
;
659 // Make sure that Foreground is the highest sortorder
660 ULONG Background
= canv
->currentLayer
;
661 ULONG Foreground
= canv
->previousLayer
;
662 if ( Foreground
< Background
)
664 ULONG tmp
= Background
;
665 Background
= Foreground
;
670 // Go through frames and layers with pos and store addy to
671 // current gfxbuffer and previous selected gfxbuffer
672 int f
= 0; for ( ; f
< canv
->totalFrames
; f
++ )
674 int l
= 0; for ( ; l
< canv
->totalLayers
; l
++ )
676 if ( f
== canv
->currentFrame
&& l
== Foreground
)
678 if ( f
== canv
->currentFrame
&& l
== Background
)
684 // Mix colors of previous selected and current gfx buffers
685 double foregroundOpacity
= foreBuf
->opacity
/ 100.0;
686 double backgroundOpacity
= backBuf
->opacity
/ 100.0;
688 int range
= canv
->width
* canv
->height
;
690 int i
= 0; for ( ; i
< range
; i
++ )
692 // Layer to act as a background
693 struct rgba64 col1
= *( struct rgba64
*)&backBuf
->buf
[ i
];
694 col1
= ( struct rgba64
){ col1
.a
, col1
.b
, col1
.g
, col1
.r
};
695 if ( backBuf
->opacity
< 100 ) col1
.a
= col1
.a
* backgroundOpacity
;
697 // Layer to act as foreground to be rendered over background
698 struct rgba64 col2
= *( struct rgba64
*)&foreBuf
->buf
[ i
];
699 col2
= ( struct rgba64
){ col2
.a
, col2
.b
, col2
.g
, col2
.r
};
700 if ( foreBuf
->opacity
< 100 ) col2
.a
= col2
.a
* foregroundOpacity
;
703 double alpha2
= col2
.a
/ MAXCOLOR_DBL
;
704 double alpha1
= col1
.a
/ MAXCOLOR_DBL
;
705 double alpham
= alpha2
> alpha1
? ( alpha2
+ ( alpha1
/ 2 ) ) : ( alpha1
+ ( alpha2
/ 2 ) );
706 if ( alpham
> 1.0 ) alpham
= 1.0;
709 // TODO: Can be even more finetuned!
710 if ( col1
.a
!= 0 && col2
.a
!= 0 )
712 float c1
= alpha1
* ( 1 - alpha2
);
714 float c1c2
= c1
+ c2
;
716 col1
.r
= ( (col1
.r
* c1
) + ( col2
.r
* c2
) ) / c1c2
;
717 col1
.g
= ( (col1
.g
* c1
) + ( col2
.g
* c2
) ) / c1c2
;
718 col1
.b
= ( (col1
.b
* c1
) + ( col2
.b
* c2
) ) / c1c2
;
720 col1
.a
= MAXCOLOR
* alpham
;
723 else if ( col1
.a
== 0 )
731 *( unsigned long long int *)&( ( struct rgba64
){ col1
.a
, col1
.b
, col1
.g
, col1
.r
} );
734 // Make sure we have 100% opacity now
735 backBuf
->opacity
= 100;
737 // Select previous layer and delete it
738 canv
->currentLayer
= Foreground
;
739 deleteLayer ( canv
);
742 void deleteLayer ( struct oCanvas
*canv
)
744 // Just clear the last remaining layer..
745 // we must have at least 1 layer!
747 if ( canv
->totalLayers
<= 1 )
749 int size
= canv
->width
* canv
->height
;
750 int i
= 0; for ( ; i
< size
; i
++ ) canv
->buffer
->buf
[ i
] = TRANSCOLOR
;
754 // Delete the active layer on all frames
756 struct gfxbuffer
**pos
= &canv
->buffer
;
758 int f
= 0; for ( ; f
< canv
->totalFrames
; f
++ )
760 int l
= 0; for ( ; l
< canv
->totalLayers
&& pos
!= NULL
; l
++ )
762 if ( *pos
== NULL
) goto deletelayerend
;
765 if ( l
== canv
->currentLayer
)
767 struct gfxbuffer
*tmp
= *pos
;
769 // Free layer from mem
770 if ( tmp
->buf
!= NULL
)
771 FreeVec ( tmp
->buf
);
772 if ( tmp
->name
!= NULL
)
773 FreeVec ( tmp
->name
);
779 struct gfxbuffer
*tmp
= *pos
;
786 // Store the new layer num
788 if ( canv
->currentLayer
>= canv
->totalLayers
)
789 canv
->currentLayer
--;
790 canv
->previousLayer
= canv
->currentLayer
;
791 setActiveBuffer ( canv
);
794 void copyToSwap ( struct oCanvas
*canv
)
796 memcpy ( canv
->swapbuffer
, canv
->activebuffer
, canv
->width
* canv
->height
* 8 );
799 void swapCanvasBuffers ( struct oCanvas
*canv
)
801 if ( globalActiveCanvas
!= NULL
)
803 struct gfxbuffer
*pos
= canv
->buffer
;
804 if ( !canv
->activebuffer
) return;
805 int f
= 0; for ( ; f
< canv
->totalFrames
; f
++ )
807 int l
= 0; for ( ; l
< canv
->totalLayers
; l
++ )
809 if ( l
== canv
->currentLayer
&& f
== canv
->currentFrame
)
811 unsigned long long int *tmp
= canv
->swapbuffer
;
812 canv
->swapbuffer
= pos
->buf
;
814 canv
->activebuffer
= tmp
;
823 unsigned int drawToolPreview ( int x
, int y
)
825 switch ( globalCurrentTool
)
828 case LUNA_TOOL_BRUSH
:
830 if ( !MouseButtonL
&& !MouseButtonR
)
833 double xoff
= 0, yoff
= 0;
834 if ( brushTool
.width
> 1 ) xoff
= brushTool
.width
/ 2.0;
835 if ( brushTool
.height
> 1 ) yoff
= brushTool
.height
/ 2.0;
837 int cbx
= ( int )( cMouseX
- xoff
);
838 int cby
= ( int )( cMouseY
- yoff
);
844 cbxX
>= 0 && cbxX
< brushTool
.width
&&
845 cbyY
>= 0 && cbyY
< brushTool
.height
848 int bufpos
= ( cbyY
* brushTool
.width
) + cbxX
;
849 struct rgba64
*color
= ( struct rgba64
*)&brushTool
.buffer
[ bufpos
];
854 ( color
->r
/ 256 ) << 24 |
855 ( color
->g
/ 256 ) << 16 |
856 ( color
->b
/ 256 ) << 8 |
863 case LUNA_TOOL_COLORPICKER
:
866 if ( !MouseButtonL
&& !MouseButtonR
)
868 if ( x
== ( int )cMouseX
&& y
== ( int )cMouseY
)
870 struct rgbData data
= paletteColorToRGB ( globalPalette
[ currColor
] );
871 return ( 255 << 24 ) | ( data
.b
<< 16 ) | ( data
.g
<< 8 ) | data
.r
;
878 if ( lineTool
.mode
== 0 )
880 double xoff
= 0, yoff
= 0;
881 if ( brushTool
.width
> 1 ) xoff
= brushTool
.width
/ 2.0;
882 if ( brushTool
.height
> 1 ) yoff
= brushTool
.height
/ 2.0;
884 int cbx
= ( int )( ( int )cMouseX
- xoff
);
885 int cby
= ( int )( ( int )cMouseY
- yoff
);
891 cbxX
>= 0 && cbxX
< brushTool
.width
&&
892 cbyY
>= 0 && cbyY
< brushTool
.height
895 int bufpos
= ( cbyY
* brushTool
.width
) + cbxX
;
896 struct rgba64
*color
= ( struct rgba64
*)&brushTool
.buffer
[ bufpos
];
900 ( color
->r
/ 256 ) << 24 |
901 ( color
->g
/ 256 ) << 16 |
902 ( color
->b
/ 256 ) << 8 |
907 if ( lineTool
.mode
== 1 )
909 // inside the lineTool.buffer the line is drawn with the offset of
910 // the brushsize / 2 to center it
912 x
>= lineTool
.ox
&& y
>= lineTool
.oy
&&
913 x
< lineTool
.ox
+ lineTool
.w
&& y
< lineTool
.oy
+ lineTool
.h
916 int dataoff
= ( ( int )( y
- lineTool
.oy
) * ( int )lineTool
.w
) + ( int )( x
- lineTool
.ox
);
917 struct rgba64
*color
= ( struct rgba64
*)&lineTool
.buffer
[ dataoff
];
922 ( color
->r
/ 256 ) << 24 |
923 ( color
->g
/ 256 ) << 16 |
924 ( color
->b
/ 256 ) << 8 |
931 case LUNA_TOOL_RECTANGLE
:
933 if ( rectangleTool
.mode
== 0 )
935 double xoff
= 0, yoff
= 0;
936 if ( brushTool
.width
> 1 ) xoff
= brushTool
.width
/ 2.0;
937 if ( brushTool
.height
> 1 ) yoff
= brushTool
.height
/ 2.0;
939 int cbx
= ( int )( ( int )cMouseX
- xoff
);
940 int cby
= ( int )( ( int )cMouseY
- yoff
);
946 cbxX
>= 0 && cbxX
< brushTool
.width
&&
947 cbyY
>= 0 && cbyY
< brushTool
.height
950 int bufpos
= ( cbyY
* brushTool
.width
) + cbxX
;
951 struct rgba64
*color
= ( struct rgba64
*)&brushTool
.buffer
[ bufpos
];
955 ( color
->r
/ 256 ) << 24 |
956 ( color
->g
/ 256 ) << 16 |
957 ( color
->b
/ 256 ) << 8 |
962 if ( rectangleTool
.mode
== 1 )
964 // inside the rectangleTool.buffer the line is drawn with the offset of
965 // the brushsize / 2 to center it
967 x
>= rectangleTool
.ox
&& y
>= rectangleTool
.oy
&&
968 x
< rectangleTool
.ox
+ rectangleTool
.w
&& y
< rectangleTool
.oy
+ rectangleTool
.h
971 int dataoff
= ( ( int )( y
- rectangleTool
.oy
) * ( int )rectangleTool
.w
) + ( int )( x
- rectangleTool
.ox
);
972 struct rgba64
*color
= ( struct rgba64
*)&rectangleTool
.buffer
[ dataoff
];
977 ( color
->r
/ 256 ) << 24 |
978 ( color
->g
/ 256 ) << 16 |
979 ( color
->b
/ 256 ) << 8 |
986 case LUNA_TOOL_CIRCLE
:
988 // Brush preview part
989 if ( circleTool
.mode
== 0 )
991 double xoff
= 0, yoff
= 0;
992 if ( brushTool
.width
> 1 ) xoff
= brushTool
.width
/ 2.0;
993 if ( brushTool
.height
> 1 ) yoff
= brushTool
.height
/ 2.0;
995 int cbx
= ( int )( ( int )cMouseX
- xoff
);
996 int cby
= ( int )( ( int )cMouseY
- yoff
);
1002 cbxX
>= 0 && cbxX
< brushTool
.width
&&
1003 cbyY
>= 0 && cbyY
< brushTool
.height
1006 int bufpos
= ( cbyY
* brushTool
.width
) + cbxX
;
1007 struct rgba64
*color
= ( struct rgba64
*)&brushTool
.buffer
[ bufpos
];
1008 // Notice the reverse alignment here
1012 ( color
->r
/ 256 ) << 24 |
1013 ( color
->g
/ 256 ) << 16 |
1014 ( color
->b
/ 256 ) << 8 |
1019 // Circle preview part
1020 if ( circleTool
.mode
== 1 )
1022 // inside the circleTool.buffer the line is drawn with the offset of
1023 // the brushsize / 2 to center it
1026 x
>= circleTool
.ox
&&
1027 y
>= circleTool
.oy
&&
1028 x
< circleTool
.ox
+ circleTool
.bufwidth
&&
1029 y
< circleTool
.oy
+ circleTool
.bufheight
1032 int dataoff
= ( ( y
- circleTool
.oy
) * circleTool
.bufwidth
) + ( x
- circleTool
.ox
);
1034 struct rgba64
*color
= ( struct rgba64
*)&circleTool
.buffer
[ dataoff
];
1039 ( color
->r
/ 256 ) << 24 |
1040 ( color
->g
/ 256 ) << 16 |
1041 ( color
->b
/ 256 ) << 8 |
1048 case LUNA_TOOL_CLIPBRUSH
:
1050 if ( clipbrushTool
.mode
== 0 )
1052 if ( x
== cMouseX
&& y
== cMouseY
)
1054 struct rgbData d
= paletteColorToRGB ( globalPalette
[ currColor
] );
1055 return ( 255 << 24 ) | ( d
.b
<< 16 ) | ( d
.g
<< 8 ) | d
.r
;
1058 if ( clipbrushTool
.mode
== 1 )
1060 // inside the rectangleTool.buffer the line is drawn with the offset of
1061 // the brushsize / 2 to center it
1063 x
>= clipbrushTool
.ox
&& y
>= clipbrushTool
.oy
&&
1064 x
< clipbrushTool
.ox
+ clipbrushTool
.w
&& y
< clipbrushTool
.oy
+ clipbrushTool
.h
1067 int dataoff
= ( ( int )( y
- clipbrushTool
.oy
) * ( int )clipbrushTool
.w
) + ( int )( x
- clipbrushTool
.ox
);
1068 struct rgba64
*color
= ( struct rgba64
*)&clipbrushTool
.buffer
[ dataoff
];
1070 // Notice the reverse alignment here
1074 ( color
->r
/ 256 ) << 24 |
1075 ( color
->g
/ 256 ) << 16 |
1076 ( color
->b
/ 256 ) << 8 |
1089 // Valuelist used to record if there is a pixel somewhere or not
1090 void addListValue ( double x
, double y
, struct ValueList
**lst
)
1092 struct ValueList
*new = AllocVec ( sizeof ( struct ValueList
), MEMF_ANY
|MEMF_CLEAR
);
1095 new->x
= ( *lst
)->x
;
1096 new->y
= ( *lst
)->y
;
1108 void freeValueList ( struct ValueList
**lst
)
1110 struct ValueList
*pos
= *lst
;
1111 while ( pos
!= NULL
)
1113 struct ValueList
*tmp
= pos
;