2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 Desc: Copy content of a rastport to another rastport
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 /*****************************************************************************
27 #include <proto/graphics.h>
29 AROS_LH9(void, ClipBlit
,
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
),
43 struct GfxBase
*, GfxBase
, 92, Graphics
)
46 Copies the contents of one rastport to another rastport.
47 Takes care of layered and non-layered source and destination
49 If you have a window you should always use this function instead
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
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.
100 *****************************************************************************/
104 BOOL li_locked
= FALSE
;
112 #if NEW_INTERNAL_CLIPBLIT
113 if (!OBTAIN_DRIVERDATA(srcRP
, GfxBase
))
117 /* overlapping and non-overlapping blits are handled differently. */
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
);
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
)
142 struct Rectangle Rect
;
143 struct RegionRectangle
* RR
;
145 if (!(R
= NewRectRegion(xDest
, yDest
, xDest
+ xSize
- 1, yDest
+ ySize
- 1)))
150 /* define the rectangle of the source */
152 Rect
.MaxX
= xSrc
+xSize
-1;
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 */
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
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
181 if (xs
* 2 < xSize
||
185 In this case I use a special routine to copy the rectangle
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,
203 This case is not as difficult as the overlapping
204 part can be copied first and then the other parts can
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
,
218 RR
->bounds
.MaxX
-RR
->bounds
.MinX
+1,
219 RR
->bounds
.MaxY
-RR
->bounds
.MinY
+1,
223 /* and now I invert the Region with the source rectangle */
224 if (!XorRectRegion(R
, &Rect
))
226 /* too bad! no more memory */
230 RR
= R
->RegionRectangle
;
234 dx
= R
->bounds
.MinX
+ RR
->bounds
.MinX
- xSrc
;
235 dy
= R
->bounds
.MinY
+ RR
->bounds
.MinY
- ySrc
;
237 internal_ClipBlit(srcRP
,
243 RR
->bounds
.MaxX
-RR
->bounds
.MinX
+1,
244 RR
->bounds
.MaxY
-RR
->bounds
.MinY
+1,
253 } /* if (NULL != RR)*/
256 /* they don't overlap */
257 internal_ClipBlit(srcRP
,
271 } /* if (destRP == srcRP) */
275 /* here: process the case when the source and destination rastports
278 internal_ClipBlit(srcRP
,
290 /* the way out, even in failure */
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
);
307 #if NEW_INTERNAL_CLIPBLIT
309 struct clipblit_render_data
311 struct render_special_info rsi
;
313 struct RastPort
*destRP
;
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
,
333 void internal_ClipBlit(struct RastPort
* srcRP
,
336 struct RastPort
* destRP
,
342 struct GfxBase
* GfxBase
)
344 struct clipblit_render_data data
;
345 struct Rectangle rect
;
347 data
.minterm
= minterm
;
348 data
.destRP
= destRP
;
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
);
362 void internal_ClipBlit(struct RastPort
* srcRP
,
365 struct RastPort
* destRP
,
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
;
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 */
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
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) ||
425 crY0
> (ySrc
+ySize
-1) ||
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
))
438 SrcOffsetX
= ALIGN_OFFSET(srcCR
->bounds
.MinX
);
441 bltSrcX
= xSrc
- crX0
+ SrcOffsetX
;
443 bltSrcX
= SrcOffsetX
;
446 bltSrcY
= ySrc
- crY0
;
450 srcBM
= srcCR
->BitMap
;
454 /* with superbitmap */
456 bltSrcX
= xSrc
- srcLayer
->Scroll_X
;
458 bltSrcX
= crX0
- srcLayer
->Scroll_X
;
461 bltSrcY
= ySrc
- srcLayer
->Scroll_Y
;
463 bltSrcY
= crY0
- srcLayer
->Scroll_Y
;
465 srcBM
= srcCR
->BitMap
;
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
480 bltSrcX
= srcCR
->bounds
.MinX
;
482 bltSrcX
= xSrc
+ srcLayer
->bounds
.MinX
;
485 bltSrcY
= srcCR
->bounds
.MinY
;
487 bltSrcY
= ySrc
+ srcLayer
->bounds
.MinY
;
491 destRect
.MinX
= crX0
- xSrc
+ xDest
;
493 destRect
.MinX
= xDest
;
495 if (crX1
< (xSrc
+xSize
-1))
496 destRect
.MaxX
= crX1
- xSrc
+ xDest
;
498 destRect
.MaxX
= xDest
+xSize
-1;
501 destRect
.MinY
= crY0
- ySrc
+ yDest
;
503 destRect
.MinY
= yDest
;
505 if (crY1
< (ySrc
+ySize
-1))
506 destRect
.MaxY
= crY1
- ySrc
+ yDest
;
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 */
515 useminterm
= minterm
;
519 srcCR
= srcCR
-> Next
;
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;
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
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
580 if (NULL
!= destCR
->BitMap
)
582 if (0 == (destLayer
->Flags
& LAYERSUPER
))
585 destBM
= destCR
->BitMap
;
586 DestOffsetX
= ALIGN_OFFSET(destCR
->bounds
.MinX
);
591 /* with superbitmap */
592 destBM
= destLayer
->SuperBitMap
;
593 DestOffsetX
= destCR
->bounds
.MinX
- destLayer
->bounds
.MinX
-
595 DestOffsetY
= destCR
->bounds
.MinY
- destLayer
->bounds
.MinY
-
596 destLayer
->Scroll_Y
;;
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
;
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
;
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
);
648 destCR
= destCR
-> Next
;
649 } /* while (NULL != destCR) */
650 } /* if (NULL != destRP->Layer) */
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
662 destRect
.MaxX
- destRect
.MinX
+ 1,
663 destRect
.MaxY
- destRect
.MinY
+ 1,
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.
678 if (NULL
== srcLayer
)
685 #endif /* NEW_INTERNAL_CLIPBLIT */