2 Copyright © 1995-2001, 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 *****************************************************************************/
103 AROS_LIBBASE_EXT_DECL(struct GfxBase
*,GfxBase
)
105 BOOL li_locked
= FALSE
;
113 #if NEW_INTERNAL_CLIPBLIT
114 if (!OBTAIN_DRIVERDATA(srcRP
, GfxBase
))
118 /* overlapping and non-overlapping blits are handled differently. */
122 (srcRP
->Layer
!= destRP
->Layer
) &&
123 (srcRP
->Layer
->LayerInfo
== destRP
->Layer
->LayerInfo
))
125 /* If two layers which belong to the same LayerInfo (~screen)
126 have to be locked, lock first LayerInfo, otherwise there
127 is a potential deadlock problem */
128 LockLayerInfo(srcRP
->Layer
->LayerInfo
);
132 if (srcRP
->Layer
) LockLayerRom( srcRP
->Layer
);
133 if (destRP
->Layer
&& (destRP
->Layer
!= srcRP
->Layer
)) LockLayerRom(destRP
->Layer
);
135 /* Once the layers are locked there's no more need to hold the layerinfo lock */
137 if (li_locked
) UnlockLayerInfo(srcRP
->Layer
->LayerInfo
);
139 /* check for overlapping blits */
140 if ( srcRP
== destRP
)
143 struct Rectangle Rect
;
144 struct RegionRectangle
* RR
;
146 if (!(R
= NewRectRegion(xDest
, yDest
, xDest
+ xSize
- 1, yDest
+ ySize
- 1)))
151 /* define the rectangle of the source */
153 Rect
.MaxX
= xSrc
+xSize
-1;
155 Rect
.MaxY
= ySrc
+ySize
-1;
156 /* combine them to check for overlapping areas */
157 AndRectRegion(R
, &Rect
); /* this call cannot fail! */
159 RR
= R
->RegionRectangle
;
161 /* check whether they overlap */
166 It's overlapping; depending on how bad it is overlapping I
167 will have to split this up into several calls to the
168 internal ClipBlit routine
173 if (xs
< 0) xs
= -xs
;
174 if (ys
< 0) ys
= -ys
;
177 if the destination area is overlapping more than half of the
178 width or height of the source area, then it is the more
182 if (xs
* 2 < xSize
||
186 In this case I use a special routine to copy the rectangle
192 (xSrc
< xDest
) ? xSrc
: xDest
,
193 (ySrc
< yDest
) ? ySrc
: yDest
,
194 (xSrc
> xDest
) ? xSrc
+ xSize
- 1 : xDest
+ xSize
- 1,
195 (ySrc
> yDest
) ? ySrc
+ ySize
- 1 : yDest
+ ySize
- 1,
204 This case is not as difficult as the overlapping
205 part can be copied first and then the other parts can
208 /* first copy the overlapping part to its destination */
210 dx
= R
->bounds
.MinX
+ RR
->bounds
.MinX
- xSrc
;
211 dy
= R
->bounds
.MinY
+ RR
->bounds
.MinY
- ySrc
;
213 internal_ClipBlit(srcRP
,
219 RR
->bounds
.MaxX
-RR
->bounds
.MinX
+1,
220 RR
->bounds
.MaxY
-RR
->bounds
.MinY
+1,
224 /* and now I invert the Region with the source rectangle */
225 if (FALSE
== XorRectRegion(R
, &Rect
))
227 /* too bad! no more memory */
231 RR
= R
->RegionRectangle
;
235 dx
= R
->bounds
.MinX
+ RR
->bounds
.MinX
- xSrc
;
236 dy
= R
->bounds
.MinY
+ RR
->bounds
.MinY
- ySrc
;
238 internal_ClipBlit(srcRP
,
244 RR
->bounds
.MaxX
-RR
->bounds
.MinX
+1,
245 RR
->bounds
.MaxY
-RR
->bounds
.MinY
+1,
254 } /* if (NULL != RR)*/
257 /* they don't overlap */
258 internal_ClipBlit(srcRP
,
272 } /* if (destRP == srcRP) */
276 /* here: process the case when the source and destination rastports
279 internal_ClipBlit(srcRP
,
291 /* the way out, even in failure */
294 if (destRP
->Layer
&& (destRP
->Layer
!= srcRP
->Layer
)) UnlockLayerRom(destRP
->Layer
);
296 if (srcRP
->Layer
) UnlockLayerRom( srcRP
->Layer
);
298 #if NEW_INTERNAL_CLIPBLIT
299 RELEASE_DRIVERDATA(srcRP
, GfxBase
);
308 #if NEW_INTERNAL_CLIPBLIT
310 struct clipblit_render_data
312 struct render_special_info rsi
;
314 struct RastPort
*destRP
;
319 static ULONG
clipblit_render(APTR data
, LONG srcx
, LONG srcy
,
320 OOP_Object
*dstbm_obj
, OOP_Object
*dst_gc
,
321 LONG x1
, LONG y1
, LONG x2
, LONG y2
, struct GfxBase
*GfxBase
)
323 struct clipblit_render_data
*crd
= data
;
325 BltBitMapRastPort(crd
->rsi
.curbm
, x1
, y1
,
326 crd
->destRP
, crd
->xDest
+ srcx
, crd
->yDest
+ srcy
,
334 void internal_ClipBlit(struct RastPort
* srcRP
,
337 struct RastPort
* destRP
,
343 struct GfxBase
* GfxBase
)
345 struct clipblit_render_data data
;
346 struct Rectangle rect
;
348 data
.minterm
= minterm
;
349 data
.destRP
= destRP
;
355 rect
.MaxX
= xSrc
+ xSize
- 1;
356 rect
.MaxY
= ySrc
+ ySize
- 1;
358 do_render_func(srcRP
, NULL
, &rect
, clipblit_render
, &data
, TRUE
, GfxBase
);
363 void internal_ClipBlit(struct RastPort
* srcRP
,
366 struct RastPort
* destRP
,
372 struct GfxBase
* GfxBase
)
374 struct ClipRect
* srcCR
= NULL
;
375 struct ClipRect
* destCR
= NULL
;
376 struct BitMap
* srcBM
= srcRP
->BitMap
;
377 struct BitMap
* destBM
= destRP
->BitMap
;
378 struct Layer
* srcLayer
= srcRP
->Layer
;
379 struct Layer
* destLayer
= destRP
->Layer
;
380 struct Rectangle destRect
;
381 LONG bltSrcX
= 0, bltSrcY
= 0, bltDstX
, bltDstY
, bltWidth
, bltHeight
;
384 UBYTE useminterm
= 0;
387 /* nlorentz: The below did not work because bitmaps may be more than 8 bit.
388 Just setting it to 0xFFFFFFF should work fine for copying all planes
390 UBYTE MaskTab[] = {0x00, 0x01, 0x03, 0x07, 0x0F,
391 0x1F, 0x3F, 0x7F, 0xFF};
392 LONG i1 = GetBitMapAttr(srcBM , BMA_DEPTH);
393 LONG i2 = GetBitMapAttr(destBM, BMA_DEPTH);
394 bltMask = MaskTab[i1] & MaskTab[i2];
396 bltMask
= 0xFFFFFFFF;
398 if (NULL
!= srcLayer
)
399 srcCR
= srcLayer
->ClipRect
;
401 /* process all source and destination bitmaps */
405 First I look for a source bitmap that fits into the given
406 source area, then I will look for a destination bitmap to
410 /* Does the source have layers? */
411 if (NULL
!= srcRP
->Layer
)
413 while (NULL
!= srcCR
)
415 LONG crX0
, crX1
, crY0
, crY1
;
416 /* cr?? have to be coordinates related to the rastport */
417 crX0
= srcCR
->bounds
.MinX
- srcLayer
->bounds
.MinX
;
418 crX1
= srcCR
->bounds
.MaxX
- srcLayer
->bounds
.MinX
;
419 crY0
= srcCR
->bounds
.MinY
- srcLayer
->bounds
.MinY
;
420 crY1
= srcCR
->bounds
.MaxY
- srcLayer
->bounds
.MinY
;
422 /* the only case that must not happen is that
423 this ClipRect is outside the destination area. */
424 if (!(crX0
> (xSrc
+xSize
-1) ||
426 crY0
> (ySrc
+ySize
-1) ||
429 /* this cliprect contains bitmap data that need to be copied */
431 get the pointer to the bitmap structure and fill out
432 the rectangle structure that shows which part we mean to copy
434 if (NULL
!= srcCR
->BitMap
)
436 if (0 == (srcLayer
->Flags
& LAYERSUPER
))
439 SrcOffsetX
= ALIGN_OFFSET(srcCR
->bounds
.MinX
);
442 bltSrcX
= xSrc
- crX0
+ SrcOffsetX
;
444 bltSrcX
= SrcOffsetX
;
447 bltSrcY
= ySrc
- crY0
;
451 srcBM
= srcCR
->BitMap
;
455 /* with superbitmap */
457 bltSrcX
= xSrc
- srcLayer
->Scroll_X
;
459 bltSrcX
= crX0
- srcLayer
->Scroll_X
;
462 bltSrcY
= ySrc
- srcLayer
->Scroll_Y
;
464 bltSrcY
= crY0
- srcLayer
->Scroll_Y
;
466 srcBM
= srcCR
->BitMap
;
472 /* this part of the layer is not hidden. */
473 /* The source bitmap is the bitmap of the rastport */
474 srcBM
= srcRP
->BitMap
;
476 /* xSrc and ySrc are relative to the rastport of the window
477 or layer - here we have to make them absolute to the
481 bltSrcX
= srcCR
->bounds
.MinX
;
483 bltSrcX
= xSrc
+ srcLayer
->bounds
.MinX
;
486 bltSrcY
= srcCR
->bounds
.MinY
;
488 bltSrcY
= ySrc
+ srcLayer
->bounds
.MinY
;
492 destRect
.MinX
= crX0
- xSrc
+ xDest
;
494 destRect
.MinX
= xDest
;
496 if (crX1
< (xSrc
+xSize
-1))
497 destRect
.MaxX
= crX1
- xSrc
+ xDest
;
499 destRect
.MaxX
= xDest
+xSize
-1;
502 destRect
.MinY
= crY0
- ySrc
+ yDest
;
504 destRect
.MinY
= yDest
;
506 if (crY1
< (ySrc
+ySize
-1))
507 destRect
.MaxY
= crY1
- ySrc
+ yDest
;
509 destRect
.MaxY
= yDest
+ySize
-1;
511 if ((0 != (srcLayer
->Flags
& LAYERSIMPLE
) &&
512 (NULL
!= srcCR
->lobs
||
513 0 != (srcCR
->Flags
& CR_NEEDS_NO_CONCEALED_RASTERS
))))
514 useminterm
= 0x0; /* clear this area in the destination */
516 useminterm
= minterm
;
520 srcCR
= srcCR
-> Next
;
525 else /* no layer in the source rastport */
527 srcBM
= srcRP
->BitMap
;
528 destRect
.MinX
= xDest
;
529 destRect
.MinY
= yDest
;
530 destRect
.MaxX
= xDest
+xSize
-1;
531 destRect
.MaxY
= yDest
+ySize
-1;
536 useminterm
= minterm
;
540 /* Does the destination have layers */
541 if (NULL
!= destLayer
)
543 destCR
= destLayer
-> ClipRect
;
544 /* search for the first/next BitMap that is to be filled */
545 /* destRect contains the area that we want to copy to */
546 while (NULL
!= destCR
)
548 /* if the layer is a simple layer and the cliprect's flag
549 has a certain bit set or the CR is hidden, then do
551 if (!(0 != (destLayer
->Flags
& LAYERSIMPLE
) &&
552 (NULL
!= destCR
->lobs
||
553 0 != (destCR
->Flags
& CR_NEEDS_NO_CONCEALED_RASTERS
))))
555 struct Rectangle destRect2
;
556 LONG DestOffsetX
, DestOffsetY
;
558 destRect2
.MinX
= destCR
->bounds
.MinX
- destLayer
->bounds
.MinX
;
559 destRect2
.MaxX
= destCR
->bounds
.MaxX
- destLayer
->bounds
.MinX
;
560 destRect2
.MinY
= destCR
->bounds
.MinY
- destLayer
->bounds
.MinY
;
561 destRect2
.MaxY
= destCR
->bounds
.MaxY
- destLayer
->bounds
.MinY
;
564 /* does this ClipRect fit into the destination area?
565 The only case that must not happen is that it lies
566 outside of destRect */
567 if (!(destRect
.MinX
> destRect2
.MaxX
||
568 destRect
.MaxX
< destRect2
.MinX
||
569 destRect
.MinY
> destRect2
.MaxY
||
570 destRect
.MaxY
< destRect2
.MinY
))
572 LONG bltSrcX_tmp
= bltSrcX
;
573 LONG bltSrcY_tmp
= bltSrcY
;
574 bltWidth
= destRect
.MaxX
- destRect
.MinX
+ 1;
575 bltHeight
= destRect
.MaxY
- destRect
.MinY
+ 1;
578 destCR actually contains the/a part of the rectangle that
581 if (NULL
!= destCR
->BitMap
)
583 if (0 == (destLayer
->Flags
& LAYERSUPER
))
586 destBM
= destCR
->BitMap
;
587 DestOffsetX
= ALIGN_OFFSET(destCR
->bounds
.MinX
);
592 /* with superbitmap */
593 destBM
= destLayer
->SuperBitMap
;
594 DestOffsetX
= destCR
->bounds
.MinX
- destLayer
->bounds
.MinX
-
596 DestOffsetY
= destCR
->bounds
.MinY
- destLayer
->bounds
.MinY
-
597 destLayer
->Scroll_Y
;;
602 destBM
= destRP
->BitMap
;
604 DestOffsetX
= destCR
->bounds
.MinX
;
605 DestOffsetY
= destCR
->bounds
.MinY
;
608 if (destRect
.MinX
> destRect2
.MinX
)
610 bltDstX
= destRect
.MinX
- destRect2
.MinX
+ DestOffsetX
;
614 bltDstX
= DestOffsetX
;
615 bltWidth
-= (destRect2
.MinX
- destRect
.MinX
);
616 bltSrcX_tmp
+= (destRect2
.MinX
- destRect
.MinX
);
619 if (destRect
.MaxX
> destRect2
.MaxX
)
620 bltWidth
-= (destRect
.MaxX
- destRect2
.MaxX
);
622 if (destRect
.MinY
> destRect2
.MinY
)
624 bltDstY
= destRect
.MinY
- destRect2
.MinY
+ DestOffsetY
;
628 bltDstY
= DestOffsetY
;
629 bltHeight
-= (destRect2
.MinY
- destRect
.MinY
);
630 bltSrcY_tmp
+= (destRect2
.MinY
- destRect
.MinY
);
633 if (destRect
.MaxY
> destRect2
.MaxY
)
634 bltHeight
-= (destRect
.MaxY
- destRect2
.MaxY
);
649 destCR
= destCR
-> Next
;
650 } /* while (NULL != destCR) */
651 } /* if (NULL != destRP->Layer) */
654 /* the destination does not have a layer. So I copy from srcBM
655 the whole rectangle that is given in destRect to the rastport's
663 destRect
.MaxX
- destRect
.MinX
+ 1,
664 destRect
.MaxY
- destRect
.MinY
+ 1,
670 /* if the source rastport doesn't have a layer then I am done here
671 as all the blits from the one bitmap have already happened.
679 if (NULL
== srcLayer
)
686 #endif /* NEW_INTERNAL_CLIPBLIT */