Initial import of Lunapaint from
[AROS-Contrib.git] / gfx / lunapaint / src / core / canvas.c
blobbdd396ed1e81a40c16f06f62bb936f1da2cf7e5a
1 /****************************************************************************
2 * *
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 *
7 * *
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. *
12 * *
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. *
17 * *
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. *
21 * *
22 ****************************************************************************/
24 #include "canvas.h"
26 BOOL abortRedraw;
27 int redrawTimes;
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,
38 BOOL generateBuffers
41 int bufsize = w * h * 8;
42 int scope = w * h;
43 struct oCanvas *canv = AllocVec ( sizeof ( struct oCanvas ), MEMF_ANY );
44 canv->screenbuffer = NULL;
45 canv->buffer = 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 );
56 tmp->opacity = 100;
57 tmp->visible = TRUE;
58 tmp->name = AllocVec ( 12, MEMF_ANY|MEMF_CLEAR );
59 strcpy ( tmp->name, _(MSG_CORE_LAYER_EMPTY) );
61 // Clear the buffer
62 int i = 0; for ( ; i < scope; i++ )
63 tmp->buf[ i ] = TRANSCOLOR;
65 if ( a < span - 1 )
66 tmp->nextbuf = AllocVec ( sizeof ( struct gfxbuffer ), MEMF_ANY );
67 else tmp->nextbuf = NULL; // <- marks the end
68 tmp = tmp->nextbuf;
72 // Set variables
73 canv->width = w;
74 canv->height = h;
75 canv->zoom = 1;
76 canv->offsetx = 0;
77 canv->offsety = 0;
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;
85 canv->tmpBuf = 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;
89 return canv;
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 )
128 FreeVec ( canvas );
131 void Destroy_Buffer ( struct oCanvas *canv )
133 struct gfxbuffer *buf = canv->buffer;
134 canv->buffer = NULL;
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;
140 buf = buf->nextbuf;
141 FreeVec ( tmp );
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;
156 return;
158 i++;
159 buf = buf->nextbuf;
161 return;
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;
174 buf = buf->nextbuf;
176 return NULL;
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;
190 buf = buf->nextbuf;
192 return NULL;
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;
204 buf = buf->nextbuf;
206 return NULL;
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;
216 if ( l == layer )
217 if ( i / canvas->totalLayers == frame ) return buf;
218 buf = buf->nextbuf;
220 return NULL;
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;
232 buf = buf->nextbuf;
234 return NULL;
237 unsigned int *renderCanvas (
238 struct oCanvas *canvas, unsigned int rx, unsigned int ry,
239 unsigned int rw, unsigned int rh, BOOL Transparent
242 // Some vars
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;
250 int ryrh = ry + rh;
251 int rxrw = rx + rw;
253 // Allocate memory for temporary buffer
254 unsigned int *tempBuf = AllocVec ( zoomedWidth * ( rh * zoom ) * 4, MEMF_ANY );
255 if ( tempBuf == NULL ){ return NULL; };
257 // Start!
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 ) )
266 buf = buf->nextbuf;
267 continue;
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
291 if ( l == -1 )
293 if ( Transparent )
295 color = *( unsigned int *)&( ( struct rgba32 ){ 128, 128, 128, 0 } );
297 else
299 switch ( GlobalPrefs.LayerBackgroundMode )
301 case 1:
302 color = *( unsigned int *)&( ( struct rgba32 ){ 0, 0, 0, 255 } );
303 break;
304 case 2:
305 color = *( unsigned int *)&( ( struct rgba32 ){ 128, 128, 128, 255 } );
306 break;
307 case 3:
308 color = *( unsigned int *)&( ( struct rgba32 ){ 255, 255, 255, 255 } );
309 break;
310 default:
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 } );
317 break;
321 else
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 *)&currentBuf[ canvymul + x ];
330 // Convert 16-bit pr pixel to 8
331 int a = col2t.r / 256,
332 r = col2t.g / 256,
333 g = col2t.b / 256,
334 b = col2t.a / 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; }
343 // Mix colors
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;
348 if ( !Transparent )
349 col1.a = 255;
350 else
352 if ( ( col1.a + a ) > 255 ) col1.a = 255;
353 else col1.a += a;
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;
365 // Mix colors
366 alpha = a / 512.0;
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 );
377 if ( test != 0 )
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 )
385 col1.a += blend.a;
386 else col1.a = 255;
390 // ( we skip col1.a as we know it's 255 from the checkCol )
391 color = *( unsigned int *)&col1;
394 if ( zoom == 1 )
395 tempBuf[ YminRYrw + XminRX ] = color;
396 else
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;
408 XminRX++;
410 YminRY++;
413 if ( l >= 0 ) buf = buf->nextbuf;
415 return tempBuf;
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;
446 // Some vars
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 );
463 int y = 0, x = 0;
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++ )
499 int sy = y + ry;
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++ )
507 int sx = x + rx;
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 );
518 return TRUE;
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 ) )
529 return FALSE;
530 return TRUE;
533 void initPalette ( )
535 // Reserve memory
536 globalPalette = AllocVec ( 256 * sizeof ( unsigned int ), MEMF_ANY );
537 // Load in default palette
538 loadDefaultPalette ( );
541 void loadDefaultPalette ( )
543 BPTR myfile;
544 if ( ( myfile = Open ( "PROGDIR:default.palette", MODE_OLDFILE ) ) != NULL )
546 Read ( myfile, globalPalette, 1024 );
547 Close ( myfile );
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;
575 // New layer num
576 // Increment total layers
577 canv->totalLayers++;
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 )
596 curr = pos;
597 if ( f == canv->currentFrame && l == canv->previousLayer )
598 prev = pos;
599 pos = pos->nextbuf;
602 if ( prev == NULL || curr == NULL )
603 return;
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;
611 // New data
612 curr->buf = prev->buf;
613 curr->opacity = prev->opacity;
614 curr->visible = prev->visible;
615 curr->name = prev->name;
617 // Move old data
618 prev->buf = tmp;
619 prev->opacity = opacity;
620 prev->visible = visible;
621 prev->name = name;
623 // Set active buffer
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 )
640 curr = pos;
641 if ( f == canv->currentFrame && l == canv->previousLayer )
642 prev = pos;
643 pos = pos->nextbuf;
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 )
653 return;
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;
666 Foreground = tmp;
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 )
677 foreBuf = pos;
678 if ( f == canv->currentFrame && l == Background )
679 backBuf = pos;
680 pos = pos->nextbuf;
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;
702 // Get and set alpha
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;
708 // Blend colors
709 // TODO: Can be even more finetuned!
710 if ( col1.a != 0 && col2.a != 0 )
712 float c1 = alpha1 * ( 1 - alpha2 );
713 float c2 = 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;
722 // Copy color
723 else if ( col1.a == 0 )
725 col1 = col2;
727 //col1.a = MAXCOLOR;
729 // Set new color
730 backBuf->buf[ i ] =
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;
751 return;
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;
764 // Strip this
765 if ( l == canv->currentLayer )
767 struct gfxbuffer *tmp = *pos;
768 *pos = tmp->nextbuf;
769 // Free layer from mem
770 if ( tmp->buf != NULL )
771 FreeVec ( tmp->buf );
772 if ( tmp->name != NULL )
773 FreeVec ( tmp->name );
774 tmp->nextbuf = NULL;
775 FreeVec ( tmp );
777 else
779 struct gfxbuffer *tmp = *pos;
780 pos = &tmp->nextbuf;
784 deletelayerend:
786 // Store the new layer num
787 canv->totalLayers--;
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;
813 pos->buf = tmp;
814 canv->activebuffer = tmp;
815 return;
817 pos = pos->nextbuf;
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 );
840 int cbxX = x - cbx;
841 int cbyY = y - cby;
843 if (
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 ];
851 if ( color->r > 0 )
853 return
854 ( color->r / 256 ) << 24 |
855 ( color->g / 256 ) << 16 |
856 ( color->b / 256 ) << 8 |
857 ( color->a / 256 );
861 break;
863 case LUNA_TOOL_COLORPICKER:
864 case LUNA_TOOL_FILL:
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;
874 break;
876 case LUNA_TOOL_LINE:
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 );
887 int cbxX = x - cbx;
888 int cbyY = y - cby;
890 if (
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 ];
897 if ( color->r > 0 )
899 return
900 ( color->r / 256 ) << 24 |
901 ( color->g / 256 ) << 16 |
902 ( color->b / 256 ) << 8 |
903 ( color->a / 256 );
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
911 if (
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 ];
919 if ( color->r > 0 )
921 return
922 ( color->r / 256 ) << 24 |
923 ( color->g / 256 ) << 16 |
924 ( color->b / 256 ) << 8 |
925 ( color->a / 256 );
929 break;
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 );
942 int cbxX = x - cbx;
943 int cbyY = y - cby;
945 if (
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 ];
952 if ( color->r > 0 )
954 return
955 ( color->r / 256 ) << 24 |
956 ( color->g / 256 ) << 16 |
957 ( color->b / 256 ) << 8 |
958 ( color->a / 256 );
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
966 if (
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 ];
974 if ( color->r > 0 )
976 return
977 ( color->r / 256 ) << 24 |
978 ( color->g / 256 ) << 16 |
979 ( color->b / 256 ) << 8 |
980 ( color->a / 256 );
984 break;
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 );
998 int cbxX = x - cbx;
999 int cbyY = y - cby;
1001 if (
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
1009 if ( color->r > 0 )
1011 return
1012 ( color->r / 256 ) << 24 |
1013 ( color->g / 256 ) << 16 |
1014 ( color->b / 256 ) << 8 |
1015 ( color->a / 256 );
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
1025 if (
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 ];
1036 if ( color->r > 0 )
1038 return
1039 ( color->r / 256 ) << 24 |
1040 ( color->g / 256 ) << 16 |
1041 ( color->b / 256 ) << 8 |
1042 ( color->a / 256 );
1046 break;
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
1062 if (
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
1071 if ( color->r > 0 )
1073 return
1074 ( color->r / 256 ) << 24 |
1075 ( color->g / 256 ) << 16 |
1076 ( color->b / 256 ) << 8 |
1077 ( color->a / 256 );
1081 break;
1083 default:
1084 break;
1086 return 0;
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 );
1093 if ( *lst != NULL )
1095 new->x = ( *lst )->x;
1096 new->y = ( *lst )->y;
1097 ( *lst )->x = x;
1098 ( *lst )->y = y;
1100 else
1102 new->x = x;
1103 new->y = y;
1105 new->Next = *lst;
1106 *lst = new;
1108 void freeValueList ( struct ValueList **lst )
1110 struct ValueList *pos = *lst;
1111 while ( pos != NULL )
1113 struct ValueList *tmp = pos;
1114 pos = pos->Next;
1115 FreeVec ( tmp );
1117 *lst = NULL;