New bitmap method SetRGBConversionFunction which can be used to
[tangerine.git] / rom / graphics / clipblit.c
blob4106781c50b91babdc78d5a701c5f65f79a262a8
1 /*
2 Copyright © 1995-2001, 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
103 AROS_LIBBASE_EXT_DECL(struct GfxBase *,GfxBase)
105 BOOL li_locked = FALSE;
108 FIX_GFXCOORD(xSrc);
109 FIX_GFXCOORD(ySrc);
110 FIX_GFXCOORD(xDest);
111 FIX_GFXCOORD(yDest);
113 #if NEW_INTERNAL_CLIPBLIT
114 if (!OBTAIN_DRIVERDATA(srcRP, GfxBase))
115 return;
116 #endif
118 /* overlapping and non-overlapping blits are handled differently. */
120 if (srcRP->Layer &&
121 destRP->Layer &&
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);
129 li_locked = TRUE;
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 )
142 struct Region * R;
143 struct Rectangle Rect;
144 struct RegionRectangle * RR;
146 if (!(R = NewRectRegion(xDest, yDest, xDest + xSize - 1, yDest + ySize - 1)))
148 goto exit;
151 /* define the rectangle of the source */
152 Rect.MinX = xSrc;
153 Rect.MaxX = xSrc+xSize-1;
154 Rect.MinY = ySrc;
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 */
162 if (NULL != RR)
164 int xs, ys;
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
171 xs = xDest-xSrc;
172 ys = yDest-ySrc;
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
179 difficult case
182 if (xs * 2 < xSize ||
183 ys * 2 < ySize)
186 In this case I use a special routine to copy the rectangle
189 MoveRaster(srcRP,
190 xSrc - xDest,
191 ySrc - yDest,
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,
196 FALSE,
197 GfxBase);
199 else
201 LONG dx, dy;
204 This case is not as difficult as the overlapping
205 part can be copied first and then the other parts can
206 be copied.
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,
214 xSrc + dx,
215 ySrc + dy,
216 srcRP,
217 xDest + dx,
218 yDest + dy,
219 RR->bounds.MaxX-RR->bounds.MinX+1,
220 RR->bounds.MaxY-RR->bounds.MinY+1,
221 minterm,
222 GfxBase);
224 /* and now I invert the Region with the source rectangle */
225 if (FALSE == XorRectRegion(R, &Rect))
227 /* too bad! no more memory */
228 DisposeRegion(R);
229 goto exit;
231 RR = R->RegionRectangle;
233 while (NULL != RR)
235 dx = R->bounds.MinX + RR->bounds.MinX - xSrc;
236 dy = R->bounds.MinY + RR->bounds.MinY - ySrc;
238 internal_ClipBlit(srcRP,
239 xSrc + dx,
240 ySrc + dy,
241 srcRP,
242 xDest + dx,
243 yDest + dy,
244 RR->bounds.MaxX-RR->bounds.MinX+1,
245 RR->bounds.MaxY-RR->bounds.MinY+1,
246 minterm,
247 GfxBase);
248 RR = RR->Next;
250 } /* while */
254 } /* if (NULL != RR)*/
255 else
257 /* they don't overlap */
258 internal_ClipBlit(srcRP,
259 xSrc,
260 ySrc,
261 srcRP,
262 xDest,
263 yDest,
264 xSize,
265 ySize,
266 minterm,
267 GfxBase);
270 DisposeRegion(R);
272 } /* if (destRP == srcRP) */
273 else
276 /* here: process the case when the source and destination rastports
277 are different */
279 internal_ClipBlit(srcRP,
280 xSrc,
281 ySrc,
282 destRP,
283 xDest,
284 yDest,
285 xSize,
286 ySize,
287 minterm,
288 GfxBase);
291 /* the way out, even in failure */
292 exit:
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);
300 #endif
302 return;
304 AROS_LIBFUNC_EXIT
306 } /* ClipBlit */
308 #if NEW_INTERNAL_CLIPBLIT
310 struct clipblit_render_data
312 struct render_special_info rsi;
313 ULONG minterm;
314 struct RastPort *destRP;
315 LONG xDest;
316 LONG yDest;
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,
327 x2 - x1 + 1,
328 y2 - y1 + 1,
329 crd->minterm);
331 return 0;
334 void internal_ClipBlit(struct RastPort * srcRP,
335 LONG xSrc,
336 LONG ySrc,
337 struct RastPort * destRP,
338 LONG xDest,
339 LONG yDest,
340 LONG xSize,
341 LONG ySize,
342 UBYTE minterm,
343 struct GfxBase * GfxBase)
345 struct clipblit_render_data data;
346 struct Rectangle rect;
348 data.minterm = minterm;
349 data.destRP = destRP;
350 data.xDest = xDest;
351 data.yDest = yDest;
353 rect.MinX = xSrc;
354 rect.MinY = ySrc;
355 rect.MaxX = xSrc + xSize - 1;
356 rect.MaxY = ySrc + ySize - 1;
358 do_render_func(srcRP, NULL, &rect, clipblit_render, &data, TRUE, GfxBase);
361 #else
363 void internal_ClipBlit(struct RastPort * srcRP,
364 LONG xSrc,
365 LONG ySrc,
366 struct RastPort * destRP,
367 LONG xDest,
368 LONG yDest,
369 LONG xSize,
370 LONG ySize,
371 UBYTE minterm,
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;
382 ULONG SrcOffsetX;
383 ULONG bltMask;
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 */
402 while (TRUE)
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
407 blit it into.
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) ||
425 crX1 < xSrc ||
426 crY0 > (ySrc+ySize-1) ||
427 crY1 < ySrc))
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))
438 /* no superbitmap */
439 SrcOffsetX = ALIGN_OFFSET(srcCR->bounds.MinX);
441 if (xSrc >= crX0)
442 bltSrcX = xSrc - crX0 + SrcOffsetX;
443 else
444 bltSrcX = SrcOffsetX;
446 if (ySrc > crY0)
447 bltSrcY = ySrc - crY0;
448 else
449 bltSrcY = 0;
451 srcBM = srcCR->BitMap;
453 else
455 /* with superbitmap */
456 if (xSrc >= crX0)
457 bltSrcX = xSrc - srcLayer->Scroll_X;
458 else
459 bltSrcX = crX0 - srcLayer->Scroll_X;
461 if (ySrc >= crY0)
462 bltSrcY = ySrc - srcLayer->Scroll_Y;
463 else
464 bltSrcY = crY0 - srcLayer->Scroll_Y;
466 srcBM = srcCR->BitMap;
470 else
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
478 screen's rastport*/
480 if (xSrc <= crX0)
481 bltSrcX = srcCR->bounds.MinX;
482 else
483 bltSrcX = xSrc + srcLayer->bounds.MinX;
485 if (ySrc <= crY0)
486 bltSrcY = srcCR->bounds.MinY;
487 else
488 bltSrcY = ySrc + srcLayer->bounds.MinY;
491 if (crX0 > xSrc)
492 destRect.MinX = crX0 - xSrc + xDest;
493 else
494 destRect.MinX = xDest;
496 if (crX1 < (xSrc+xSize-1))
497 destRect.MaxX = crX1 - xSrc + xDest;
498 else
499 destRect.MaxX = xDest+xSize-1;
501 if (crY0 > ySrc)
502 destRect.MinY = crY0 - ySrc + yDest;
503 else
504 destRect.MinY = yDest;
506 if (crY1 < (ySrc+ySize-1))
507 destRect.MaxY = crY1 - ySrc + yDest;
508 else
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 */
515 else
516 useminterm = minterm;
518 break;
519 } /* if () */
520 srcCR = srcCR -> Next;
522 if (NULL == srcCR)
523 return;
524 } /* if() */
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;
533 bltSrcX = xSrc;
534 bltSrcY = ySrc;
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
550 nothing here! */
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
579 we have to blit to
581 if (NULL != destCR->BitMap)
583 if (0 == (destLayer->Flags & LAYERSUPER))
585 /* no superbitmap */
586 destBM = destCR->BitMap;
587 DestOffsetX = ALIGN_OFFSET(destCR->bounds.MinX);
588 DestOffsetY = 0;
590 else
592 /* with superbitmap */
593 destBM = destLayer->SuperBitMap;
594 DestOffsetX = destCR->bounds.MinX - destLayer->bounds.MinX -
595 destLayer->Scroll_X;
596 DestOffsetY = destCR->bounds.MinY - destLayer->bounds.MinY -
597 destLayer->Scroll_Y;;
600 else
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;
612 else
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;
626 else
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);
636 BltBitMap(srcBM,
637 bltSrcX_tmp,
638 bltSrcY_tmp,
639 destBM,
640 bltDstX,
641 bltDstY,
642 bltWidth,
643 bltHeight,
644 useminterm,
645 bltMask,
646 NULL);
647 } /* if (... ) */
649 destCR = destCR -> Next;
650 } /* while (NULL != destCR) */
651 } /* if (NULL != destRP->Layer) */
652 else
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
656 bitmap */
657 BltBitMap(srcBM,
658 bltSrcX,
659 bltSrcY,
660 destRP->BitMap,
661 destRect.MinX,
662 destRect.MinY,
663 destRect.MaxX - destRect.MinX + 1,
664 destRect.MaxY - destRect.MinY + 1,
665 useminterm,
666 bltMask,
667 NULL);
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.
674 if (NULL != srcCR)
675 srcCR = srcCR->Next;
676 else
677 break;
679 if (NULL == srcLayer)
680 break;
681 } /* while (TRUE) */
683 return;
686 #endif /* NEW_INTERNAL_CLIPBLIT */
688 #undef LayersBase