Mixed tabs/spaces to spaces.
[AROS.git] / rom / graphics / clipblit.c
blob5a3d382225e65be35eb85197dd1bff05824768a6
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Copy content of a rastport to another rastport
6 Lang: english
7 */
9 #include <aros/debug.h>
10 #include <clib/macros.h>
11 #include <exec/memory.h>
12 #include <graphics/gfx.h>
13 #include <proto/exec.h>
14 #include <proto/layers.h>
15 #include <graphics/regions.h>
16 #include <graphics/layers.h>
17 #include <graphics/clip.h>
19 #include "graphics_intern.h"
20 #include "gfxfuncsupport.h"
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(WORD , xSrc , D0),
34 AROS_LHA(WORD , ySrc , D1),
35 AROS_LHA(struct RastPort *, destRP, A1),
36 AROS_LHA(WORD , xDest , D2),
37 AROS_LHA(WORD , yDest , D3),
38 AROS_LHA(WORD , xSize , D4),
39 AROS_LHA(WORD , 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 /* overlapping and non-overlapping blits are handled differently. */
114 if (LayersBase && srcRP->Layer &&
115 destRP->Layer &&
116 (srcRP->Layer != destRP->Layer) &&
117 (srcRP->Layer->LayerInfo == destRP->Layer->LayerInfo))
119 /* If two layers which belong to the same LayerInfo (~screen)
120 have to be locked, lock first LayerInfo, otherwise there
121 is a potential deadlock problem */
122 LockLayerInfo(srcRP->Layer->LayerInfo);
123 li_locked = TRUE;
126 if (srcRP->Layer) LockLayerRom( srcRP->Layer);
127 if (destRP->Layer && (destRP->Layer != srcRP->Layer)) LockLayerRom(destRP->Layer);
129 /* Once the layers are locked there's no more need to hold the layerinfo lock */
131 if (li_locked) UnlockLayerInfo(srcRP->Layer->LayerInfo);
133 /* check for overlapping blits */
134 if ( srcRP == destRP )
136 struct Rectangle Rect;
138 /* Combine source and destination rectangles to check for overlapping areas */
139 Rect.MinX = MAX(xSrc, xDest);
140 Rect.MinY = MAX(ySrc, yDest);
141 Rect.MaxX = MIN(xSrc + xSize - 1, xDest + xSize - 1);
142 Rect.MaxY = MIN(ySrc + ySize - 1, yDest + ySize - 1);
144 /* check whether they overlap */
145 if ((Rect.MaxX >= Rect.MinX) && (Rect.MaxY > Rect.MinY))
148 * It's overlapping; depending on how bad it is overlapping I
149 * will have to split this up into several calls to the
150 * internal ClipBlit routine.
151 * The first thing to do is to convert our Rect into Region (we'll use XOR afterwards).
153 struct Region *R = NewRegion();
154 struct RegionRectangle *RR;
155 int xs, ys;
157 if (!R)
158 goto exit;
160 if (!OrRectRegion(R, &Rect))
162 DisposeRegion(R);
163 goto exit;
166 RR = R->RegionRectangle;
168 xs = xDest-xSrc;
169 ys = yDest-ySrc;
170 if (xs < 0) xs = -xs;
171 if (ys < 0) ys = -ys;
174 if the destination area is overlapping more than half of the
175 width or height of the source area, then it is the more
176 difficult case
179 if (xs * 2 < xSize ||
180 ys * 2 < ySize)
183 In this case I use a special routine to copy the rectangle
186 MoveRaster(srcRP,
187 xSrc - xDest,
188 ySrc - yDest,
189 (xSrc < xDest) ? xSrc : xDest,
190 (ySrc < yDest) ? ySrc : yDest,
191 (xSrc > xDest) ? xSrc + xSize - 1 : xDest + xSize - 1,
192 (ySrc > yDest) ? ySrc + ySize - 1 : yDest + ySize - 1,
193 FALSE,
194 GfxBase);
196 else
198 WORD dx, dy;
201 This case is not as difficult as the overlapping
202 part can be copied first and then the other parts can
203 be copied.
205 /* first copy the overlapping part to its destination */
207 dx = R->bounds.MinX + RR->bounds.MinX - xSrc;
208 dy = R->bounds.MinY + RR->bounds.MinY - ySrc;
210 internal_ClipBlit(srcRP,
211 xSrc + dx,
212 ySrc + dy,
213 srcRP,
214 xDest + dx,
215 yDest + dy,
216 RR->bounds.MaxX-RR->bounds.MinX+1,
217 RR->bounds.MaxY-RR->bounds.MinY+1,
218 minterm,
219 GfxBase);
221 /* and now I invert the Region with the source rectangle */
222 if (!XorRectRegion(R, &Rect))
224 /* too bad! no more memory */
225 DisposeRegion(R);
226 goto exit;
228 RR = R->RegionRectangle;
230 while (NULL != RR)
232 dx = R->bounds.MinX + RR->bounds.MinX - xSrc;
233 dy = R->bounds.MinY + RR->bounds.MinY - ySrc;
235 internal_ClipBlit(srcRP,
236 xSrc + dx,
237 ySrc + dy,
238 srcRP,
239 xDest + dx,
240 yDest + dy,
241 RR->bounds.MaxX-RR->bounds.MinX+1,
242 RR->bounds.MaxY-RR->bounds.MinY+1,
243 minterm,
244 GfxBase);
245 RR = RR->Next;
247 } /* while */
251 DisposeRegion(R);
253 } /* if (src and dest overlap) */
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 } /* if (destRP == srcRP) */
270 else
273 /* here: process the case when the source and destination rastports
274 are different */
276 internal_ClipBlit(srcRP,
277 xSrc,
278 ySrc,
279 destRP,
280 xDest,
281 yDest,
282 xSize,
283 ySize,
284 minterm,
285 GfxBase);
288 /* the way out, even in failure */
289 exit:
291 if (destRP->Layer && (destRP->Layer != srcRP->Layer)) UnlockLayerRom(destRP->Layer);
292 if (srcRP->Layer) UnlockLayerRom( srcRP->Layer);
294 AROS_LIBFUNC_EXIT
296 } /* ClipBlit */
298 struct clipblit_render_data
300 struct render_special_info rsi;
301 ULONG minterm;
302 struct RastPort *destRP;
303 WORD xDest;
304 WORD yDest;
307 static ULONG clipblit_render(APTR data, WORD srcx, WORD srcy,
308 OOP_Object *dstbm_obj, OOP_Object *dst_gc,
309 struct Rectangle *rect, struct GfxBase *GfxBase)
311 struct clipblit_render_data *crd = data;
313 BltBitMapRastPort(crd->rsi.curbm, rect->MinX, rect->MinY,
314 crd->destRP, crd->xDest + srcx, crd->yDest + srcy,
315 rect->MaxX - rect->MinX + 1,
316 rect->MaxY - rect->MinY + 1,
317 crd->minterm);
319 return 0;
322 void internal_ClipBlit(struct RastPort * srcRP,
323 WORD xSrc,
324 WORD ySrc,
325 struct RastPort * destRP,
326 WORD xDest,
327 WORD yDest,
328 WORD xSize,
329 WORD ySize,
330 UBYTE minterm,
331 struct GfxBase * GfxBase)
333 struct clipblit_render_data data;
334 struct Rectangle rect;
336 data.minterm = minterm;
337 data.destRP = destRP;
338 data.xDest = xDest;
339 data.yDest = yDest;
341 rect.MinX = xSrc;
342 rect.MinY = ySrc;
343 rect.MaxX = xSrc + xSize - 1;
344 rect.MaxY = ySrc + ySize - 1;
346 do_render_func(srcRP, NULL, &rect, clipblit_render, &data, FALSE, TRUE, GfxBase);