define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / rom / graphics / clipblit.c
blob49c30dd6c43fd194003f461d050ba5164fa74056
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Copy content of a rastport to another rastport
6 Lang: english
7 */
8 #include <exec/memory.h>
9 #include <graphics/gfx.h>
10 #include <proto/exec.h>
11 #include <proto/layers.h>
12 #include "graphics_intern.h"
13 #include <graphics/regions.h>
14 #include <graphics/layers.h>
15 #include <graphics/clip.h>
16 #include "gfxfuncsupport.h"
18 #include <aros/debug.h>
20 #define NEW_INTERNAL_CLIPBLIT 1
22 #define LayersBase (struct LayersBase *)(GfxBase->gb_LayersBase)
24 /*****************************************************************************
26 NAME */
27 #include <proto/graphics.h>
29 AROS_LH9(void, ClipBlit,
31 /* SYNOPSIS */
32 AROS_LHA(struct RastPort *, srcRP , A0),
33 AROS_LHA(LONG , xSrc , D0),
34 AROS_LHA(LONG , ySrc , D1),
35 AROS_LHA(struct RastPort *, destRP, A1),
36 AROS_LHA(LONG , xDest , D2),
37 AROS_LHA(LONG , yDest , D3),
38 AROS_LHA(LONG , xSize , D4),
39 AROS_LHA(LONG , ySize , D5),
40 AROS_LHA(UBYTE , minterm, D6),
42 /* LOCATION */
43 struct GfxBase *, GfxBase, 92, Graphics)
45 /* FUNCTION
46 Copies the contents of one rastport to another rastport.
47 Takes care of layered and non-layered source and destination
48 rastports.
49 If you have a window you should always use this function instead
50 of BltBitMap().
52 INPUTS
53 srcRP - Copy from this RastPort.
54 xSrc, ySrc - This is the upper left corner of the area to copy.
55 destRP - Copy to this RastPort.
56 xDest, yDest - Upper left corner where to place the copy
57 xSize, ySize - The size of the area to copy
58 minterm - How to copy. Most useful values are 0x00C0 for a vanilla
59 copy, 0x0030 to invert the source and then copy or 0x0050
60 to ignore the source and just invert the destination. If
61 you want to calculate other values, then you must know that
62 channel A is set, if you are inside the rectangle, channel
63 B is the source and channel C is the destination of the
64 rectangle.
66 Bit ABC
67 0 000
68 1 001
69 2 010
70 3 011
71 4 100
72 5 101
73 6 110
74 7 111
76 So 0x00C0 means: D is set if one is inside the rectangle
77 (A is set) and B (the source) is set and cleared otherwise.
79 To fill the rectangle, you would want to set D when A is
80 set, so the value is 0x00F0.
84 RESULT
85 None
87 NOTES
89 EXAMPLE
91 BUGS
93 SEE ALSO
94 BltBitMapRastPort()
96 INTERNALS
98 HISTORY
100 *****************************************************************************/
102 AROS_LIBFUNC_INIT
104 BOOL li_locked = FALSE;
107 FIX_GFXCOORD(xSrc);
108 FIX_GFXCOORD(ySrc);
109 FIX_GFXCOORD(xDest);
110 FIX_GFXCOORD(yDest);
112 #if NEW_INTERNAL_CLIPBLIT
113 if (!OBTAIN_DRIVERDATA(srcRP, GfxBase))
114 return;
115 #endif
117 /* overlapping and non-overlapping blits are handled differently. */
119 if (srcRP->Layer &&
120 destRP->Layer &&
121 (srcRP->Layer != destRP->Layer) &&
122 (srcRP->Layer->LayerInfo == destRP->Layer->LayerInfo))
124 /* If two layers which belong to the same LayerInfo (~screen)
125 have to be locked, lock first LayerInfo, otherwise there
126 is a potential deadlock problem */
127 LockLayerInfo(srcRP->Layer->LayerInfo);
128 li_locked = TRUE;
131 if (srcRP->Layer) LockLayerRom( srcRP->Layer);
132 if (destRP->Layer && (destRP->Layer != srcRP->Layer)) LockLayerRom(destRP->Layer);
134 /* Once the layers are locked there's no more need to hold the layerinfo lock */
136 if (li_locked) UnlockLayerInfo(srcRP->Layer->LayerInfo);
138 /* check for overlapping blits */
139 if ( srcRP == destRP )
141 struct Region * R;
142 struct Rectangle Rect;
143 struct RegionRectangle * RR;
145 if (!(R = NewRectRegion(xDest, yDest, xDest + xSize - 1, yDest + ySize - 1)))
147 goto exit;
150 /* define the rectangle of the source */
151 Rect.MinX = xSrc;
152 Rect.MaxX = xSrc+xSize-1;
153 Rect.MinY = ySrc;
154 Rect.MaxY = ySrc+ySize-1;
155 /* combine them to check for overlapping areas */
156 AndRectRegion(R, &Rect); /* this call cannot fail! */
158 RR = R->RegionRectangle;
160 /* check whether they overlap */
161 if (NULL != RR)
163 int xs, ys;
165 It's overlapping; depending on how bad it is overlapping I
166 will have to split this up into several calls to the
167 internal ClipBlit routine
170 xs = xDest-xSrc;
171 ys = yDest-ySrc;
172 if (xs < 0) xs = -xs;
173 if (ys < 0) ys = -ys;
176 if the destination area is overlapping more than half of the
177 width or height of the source area, then it is the more
178 difficult case
181 if (xs * 2 < xSize ||
182 ys * 2 < ySize)
185 In this case I use a special routine to copy the rectangle
188 MoveRaster(srcRP,
189 xSrc - xDest,
190 ySrc - yDest,
191 (xSrc < xDest) ? xSrc : xDest,
192 (ySrc < yDest) ? ySrc : yDest,
193 (xSrc > xDest) ? xSrc + xSize - 1 : xDest + xSize - 1,
194 (ySrc > yDest) ? ySrc + ySize - 1 : yDest + ySize - 1,
195 FALSE,
196 GfxBase);
198 else
200 LONG dx, dy;
203 This case is not as difficult as the overlapping
204 part can be copied first and then the other parts can
205 be copied.
207 /* first copy the overlapping part to its destination */
209 dx = R->bounds.MinX + RR->bounds.MinX - xSrc;
210 dy = R->bounds.MinY + RR->bounds.MinY - ySrc;
212 internal_ClipBlit(srcRP,
213 xSrc + dx,
214 ySrc + dy,
215 srcRP,
216 xDest + dx,
217 yDest + dy,
218 RR->bounds.MaxX-RR->bounds.MinX+1,
219 RR->bounds.MaxY-RR->bounds.MinY+1,
220 minterm,
221 GfxBase);
223 /* and now I invert the Region with the source rectangle */
224 if (!XorRectRegion(R, &Rect))
226 /* too bad! no more memory */
227 DisposeRegion(R);
228 goto exit;
230 RR = R->RegionRectangle;
232 while (NULL != RR)
234 dx = R->bounds.MinX + RR->bounds.MinX - xSrc;
235 dy = R->bounds.MinY + RR->bounds.MinY - ySrc;
237 internal_ClipBlit(srcRP,
238 xSrc + dx,
239 ySrc + dy,
240 srcRP,
241 xDest + dx,
242 yDest + dy,
243 RR->bounds.MaxX-RR->bounds.MinX+1,
244 RR->bounds.MaxY-RR->bounds.MinY+1,
245 minterm,
246 GfxBase);
247 RR = RR->Next;
249 } /* while */
253 } /* if (NULL != RR)*/
254 else
256 /* they don't overlap */
257 internal_ClipBlit(srcRP,
258 xSrc,
259 ySrc,
260 srcRP,
261 xDest,
262 yDest,
263 xSize,
264 ySize,
265 minterm,
266 GfxBase);
269 DisposeRegion(R);
271 } /* if (destRP == srcRP) */
272 else
275 /* here: process the case when the source and destination rastports
276 are different */
278 internal_ClipBlit(srcRP,
279 xSrc,
280 ySrc,
281 destRP,
282 xDest,
283 yDest,
284 xSize,
285 ySize,
286 minterm,
287 GfxBase);
290 /* the way out, even in failure */
291 exit:
293 if (destRP->Layer && (destRP->Layer != srcRP->Layer)) UnlockLayerRom(destRP->Layer);
295 if (srcRP->Layer) UnlockLayerRom( srcRP->Layer);
297 #if NEW_INTERNAL_CLIPBLIT
298 RELEASE_DRIVERDATA(srcRP, GfxBase);
299 #endif
301 return;
303 AROS_LIBFUNC_EXIT
305 } /* ClipBlit */
307 #if NEW_INTERNAL_CLIPBLIT
309 struct clipblit_render_data
311 struct render_special_info rsi;
312 ULONG minterm;
313 struct RastPort *destRP;
314 LONG xDest;
315 LONG yDest;
318 static ULONG clipblit_render(APTR data, LONG srcx, LONG srcy,
319 OOP_Object *dstbm_obj, OOP_Object *dst_gc,
320 LONG x1, LONG y1, LONG x2, LONG y2, struct GfxBase *GfxBase)
322 struct clipblit_render_data *crd = data;
324 BltBitMapRastPort(crd->rsi.curbm, x1, y1,
325 crd->destRP, crd->xDest + srcx, crd->yDest + srcy,
326 x2 - x1 + 1,
327 y2 - y1 + 1,
328 crd->minterm);
330 return 0;
333 void internal_ClipBlit(struct RastPort * srcRP,
334 LONG xSrc,
335 LONG ySrc,
336 struct RastPort * destRP,
337 LONG xDest,
338 LONG yDest,
339 LONG xSize,
340 LONG ySize,
341 UBYTE minterm,
342 struct GfxBase * GfxBase)
344 struct clipblit_render_data data;
345 struct Rectangle rect;
347 data.minterm = minterm;
348 data.destRP = destRP;
349 data.xDest = xDest;
350 data.yDest = yDest;
352 rect.MinX = xSrc;
353 rect.MinY = ySrc;
354 rect.MaxX = xSrc + xSize - 1;
355 rect.MaxY = ySrc + ySize - 1;
357 do_render_func(srcRP, NULL, &rect, clipblit_render, &data, FALSE, TRUE, GfxBase);
360 #else
362 void internal_ClipBlit(struct RastPort * srcRP,
363 LONG xSrc,
364 LONG ySrc,
365 struct RastPort * destRP,
366 LONG xDest,
367 LONG yDest,
368 LONG xSize,
369 LONG ySize,
370 UBYTE minterm,
371 struct GfxBase * GfxBase)
373 struct ClipRect * srcCR = NULL;
374 struct ClipRect * destCR = NULL;
375 struct BitMap * srcBM = srcRP->BitMap;
376 struct BitMap * destBM = destRP->BitMap;
377 struct Layer * srcLayer = srcRP->Layer;
378 struct Layer * destLayer= destRP->Layer;
379 struct Rectangle destRect;
380 LONG bltSrcX = 0, bltSrcY = 0, bltDstX, bltDstY, bltWidth, bltHeight;
381 ULONG SrcOffsetX;
382 ULONG bltMask;
383 UBYTE useminterm = 0;
386 /* nlorentz: The below did not work because bitmaps may be more than 8 bit.
387 Just setting it to 0xFFFFFFF should work fine for copying all planes
389 UBYTE MaskTab[] = {0x00, 0x01, 0x03, 0x07, 0x0F,
390 0x1F, 0x3F, 0x7F, 0xFF};
391 LONG i1 = GetBitMapAttr(srcBM , BMA_DEPTH);
392 LONG i2 = GetBitMapAttr(destBM, BMA_DEPTH);
393 bltMask = MaskTab[i1] & MaskTab[i2];
395 bltMask = 0xFFFFFFFF;
397 if (NULL != srcLayer)
398 srcCR = srcLayer->ClipRect;
400 /* process all source and destination bitmaps */
401 while (TRUE)
404 First I look for a source bitmap that fits into the given
405 source area, then I will look for a destination bitmap to
406 blit it into.
409 /* Does the source have layers? */
410 if (NULL != srcRP->Layer)
412 while (NULL != srcCR)
414 LONG crX0, crX1, crY0, crY1;
415 /* cr?? have to be coordinates related to the rastport */
416 crX0 = srcCR->bounds.MinX - srcLayer->bounds.MinX;
417 crX1 = srcCR->bounds.MaxX - srcLayer->bounds.MinX;
418 crY0 = srcCR->bounds.MinY - srcLayer->bounds.MinY;
419 crY1 = srcCR->bounds.MaxY - srcLayer->bounds.MinY;
421 /* the only case that must not happen is that
422 this ClipRect is outside the destination area. */
423 if (!(crX0 > (xSrc+xSize-1) ||
424 crX1 < xSrc ||
425 crY0 > (ySrc+ySize-1) ||
426 crY1 < ySrc))
428 /* this cliprect contains bitmap data that need to be copied */
430 get the pointer to the bitmap structure and fill out
431 the rectangle structure that shows which part we mean to copy
433 if (NULL != srcCR->BitMap)
435 if (0 == (srcLayer->Flags & LAYERSUPER))
437 /* no superbitmap */
438 SrcOffsetX = ALIGN_OFFSET(srcCR->bounds.MinX);
440 if (xSrc >= crX0)
441 bltSrcX = xSrc - crX0 + SrcOffsetX;
442 else
443 bltSrcX = SrcOffsetX;
445 if (ySrc > crY0)
446 bltSrcY = ySrc - crY0;
447 else
448 bltSrcY = 0;
450 srcBM = srcCR->BitMap;
452 else
454 /* with superbitmap */
455 if (xSrc >= crX0)
456 bltSrcX = xSrc - srcLayer->Scroll_X;
457 else
458 bltSrcX = crX0 - srcLayer->Scroll_X;
460 if (ySrc >= crY0)
461 bltSrcY = ySrc - srcLayer->Scroll_Y;
462 else
463 bltSrcY = crY0 - srcLayer->Scroll_Y;
465 srcBM = srcCR->BitMap;
469 else
471 /* this part of the layer is not hidden. */
472 /* The source bitmap is the bitmap of the rastport */
473 srcBM = srcRP->BitMap;
475 /* xSrc and ySrc are relative to the rastport of the window
476 or layer - here we have to make them absolute to the
477 screen's rastport*/
479 if (xSrc <= crX0)
480 bltSrcX = srcCR->bounds.MinX;
481 else
482 bltSrcX = xSrc + srcLayer->bounds.MinX;
484 if (ySrc <= crY0)
485 bltSrcY = srcCR->bounds.MinY;
486 else
487 bltSrcY = ySrc + srcLayer->bounds.MinY;
490 if (crX0 > xSrc)
491 destRect.MinX = crX0 - xSrc + xDest;
492 else
493 destRect.MinX = xDest;
495 if (crX1 < (xSrc+xSize-1))
496 destRect.MaxX = crX1 - xSrc + xDest;
497 else
498 destRect.MaxX = xDest+xSize-1;
500 if (crY0 > ySrc)
501 destRect.MinY = crY0 - ySrc + yDest;
502 else
503 destRect.MinY = yDest;
505 if (crY1 < (ySrc+ySize-1))
506 destRect.MaxY = crY1 - ySrc + yDest;
507 else
508 destRect.MaxY = yDest+ySize-1;
510 if ((0 != (srcLayer->Flags & LAYERSIMPLE) &&
511 (NULL != srcCR->lobs ||
512 0 != (srcCR ->Flags & CR_NEEDS_NO_CONCEALED_RASTERS))))
513 useminterm = 0x0; /* clear this area in the destination */
514 else
515 useminterm = minterm;
517 break;
518 } /* if () */
519 srcCR = srcCR -> Next;
521 if (NULL == srcCR)
522 return;
523 } /* if() */
524 else /* no layer in the source rastport */
526 srcBM = srcRP->BitMap;
527 destRect.MinX = xDest;
528 destRect.MinY = yDest;
529 destRect.MaxX = xDest+xSize-1;
530 destRect.MaxY = yDest+ySize-1;
532 bltSrcX = xSrc;
533 bltSrcY = ySrc;
535 useminterm = minterm;
539 /* Does the destination have layers */
540 if (NULL != destLayer)
542 destCR = destLayer -> ClipRect;
543 /* search for the first/next BitMap that is to be filled */
544 /* destRect contains the area that we want to copy to */
545 while (NULL != destCR)
547 /* if the layer is a simple layer and the cliprect's flag
548 has a certain bit set or the CR is hidden, then do
549 nothing here! */
550 if (!(0 != (destLayer->Flags & LAYERSIMPLE) &&
551 (NULL != destCR ->lobs ||
552 0 != (destCR ->Flags & CR_NEEDS_NO_CONCEALED_RASTERS))))
554 struct Rectangle destRect2;
555 LONG DestOffsetX, DestOffsetY;
557 destRect2.MinX = destCR->bounds.MinX - destLayer->bounds.MinX;
558 destRect2.MaxX = destCR->bounds.MaxX - destLayer->bounds.MinX;
559 destRect2.MinY = destCR->bounds.MinY - destLayer->bounds.MinY;
560 destRect2.MaxY = destCR->bounds.MaxY - destLayer->bounds.MinY;
563 /* does this ClipRect fit into the destination area?
564 The only case that must not happen is that it lies
565 outside of destRect */
566 if (!(destRect.MinX > destRect2.MaxX ||
567 destRect.MaxX < destRect2.MinX ||
568 destRect.MinY > destRect2.MaxY ||
569 destRect.MaxY < destRect2.MinY ))
571 LONG bltSrcX_tmp = bltSrcX;
572 LONG bltSrcY_tmp = bltSrcY;
573 bltWidth = destRect.MaxX - destRect.MinX + 1;
574 bltHeight = destRect.MaxY - destRect.MinY + 1;
577 destCR actually contains the/a part of the rectangle that
578 we have to blit to
580 if (NULL != destCR->BitMap)
582 if (0 == (destLayer->Flags & LAYERSUPER))
584 /* no superbitmap */
585 destBM = destCR->BitMap;
586 DestOffsetX = ALIGN_OFFSET(destCR->bounds.MinX);
587 DestOffsetY = 0;
589 else
591 /* with superbitmap */
592 destBM = destLayer->SuperBitMap;
593 DestOffsetX = destCR->bounds.MinX - destLayer->bounds.MinX -
594 destLayer->Scroll_X;
595 DestOffsetY = destCR->bounds.MinY - destLayer->bounds.MinY -
596 destLayer->Scroll_Y;;
599 else
601 destBM = destRP->BitMap;
603 DestOffsetX = destCR->bounds.MinX;
604 DestOffsetY = destCR->bounds.MinY;
607 if (destRect.MinX > destRect2.MinX)
609 bltDstX = destRect.MinX - destRect2.MinX + DestOffsetX;
611 else
613 bltDstX = DestOffsetX;
614 bltWidth -= (destRect2.MinX - destRect.MinX);
615 bltSrcX_tmp += (destRect2.MinX - destRect.MinX);
618 if (destRect.MaxX > destRect2.MaxX)
619 bltWidth -= (destRect.MaxX - destRect2.MaxX);
621 if (destRect.MinY > destRect2.MinY)
623 bltDstY = destRect.MinY - destRect2.MinY + DestOffsetY;
625 else
627 bltDstY = DestOffsetY;
628 bltHeight -= (destRect2.MinY - destRect.MinY);
629 bltSrcY_tmp += (destRect2.MinY - destRect.MinY);
632 if (destRect.MaxY > destRect2.MaxY)
633 bltHeight -= (destRect.MaxY - destRect2.MaxY);
635 BltBitMap(srcBM,
636 bltSrcX_tmp,
637 bltSrcY_tmp,
638 destBM,
639 bltDstX,
640 bltDstY,
641 bltWidth,
642 bltHeight,
643 useminterm,
644 bltMask,
645 NULL);
646 } /* if (... ) */
648 destCR = destCR -> Next;
649 } /* while (NULL != destCR) */
650 } /* if (NULL != destRP->Layer) */
651 else
653 /* the destination does not have a layer. So I copy from srcBM
654 the whole rectangle that is given in destRect to the rastport's
655 bitmap */
656 BltBitMap(srcBM,
657 bltSrcX,
658 bltSrcY,
659 destRP->BitMap,
660 destRect.MinX,
661 destRect.MinY,
662 destRect.MaxX - destRect.MinX + 1,
663 destRect.MaxY - destRect.MinY + 1,
664 useminterm,
665 bltMask,
666 NULL);
669 /* if the source rastport doesn't have a layer then I am done here
670 as all the blits from the one bitmap have already happened.
673 if (NULL != srcCR)
674 srcCR = srcCR->Next;
675 else
676 break;
678 if (NULL == srcLayer)
679 break;
680 } /* while (TRUE) */
682 return;
685 #endif /* NEW_INTERNAL_CLIPBLIT */
687 #undef LayersBase