use the override options if specified
[AROS.git] / rom / graphics / fakegfxhidd.c
blob8d92b9c6767e110d131e4eb6082b047726b769de
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <string.h>
8 #include <proto/exec.h>
9 #include <proto/oop.h>
10 #include <proto/utility.h>
11 #include <oop/oop.h>
12 #include <hidd/gfx.h>
13 #include <aros/atomic.h>
14 #include <proto/arossupport.h>
16 #include "graphics_intern.h"
17 #include "fakegfxhidd.h"
19 #define DCLIP(x)
20 #define DCURS(x)
21 #define DPOS(x)
23 * DISABLE_ARGB_POINTER actually makes the software mouse pointer code to always
24 * behave like if a LUT framebuffer is used.
25 * Useful for debugging if you have only truecolor display modes.
26 * If you define this, make sure that ALWAYS_ALLOCATE_SPRITE_COLORS in
27 * intuition/intuition_intern.h is also defined.
29 #define DISABLE_ARGB_POINTER */
31 #include <aros/debug.h>
33 /******************************************************************************/
35 #define SPECIAL_LOCKING 1 /* When activated mouse cursor relevant locks are
36 treated in some kind of privileged way, by
37 inserting wait-for-sem-requests at head of
38 wait queue, instead of at tail */
40 /******************************************************************************/
42 static OOP_Class *init_fakefbclass(struct GfxBase *GfxBase);
43 static OOP_Class *init_fakegfxhiddclass (struct GfxBase *GfxBase);
45 /******************************************************************************/
47 struct gfx_data
49 OOP_Object *gfxhidd;
50 OOP_Object *framebuffer;
51 OOP_Object *fakefb;
52 OOP_Object *gc;
54 ULONG fakefb_attr;
55 IPTR fb_width;
56 IPTR fb_height;
58 OOP_Object *curs_bm;
59 OOP_Object *curs_backup;
60 UBYTE *curs_pixels;
61 HIDDT_StdPixFmt curs_pixfmt;
62 UBYTE curs_bpp;
63 BOOL curs_on;
64 LONG curs_x;
65 LONG curs_y;
66 LONG curs_xoffset;
67 LONG curs_yoffset;
68 ULONG curs_width;
69 ULONG curs_height;
70 LONG curs_maxx;
71 LONG curs_maxy;
72 struct SignalSemaphore fbsema;
73 BOOL backup_done;
75 /* baseclasses for CreateObject */
76 OOP_Class *basegc;
77 OOP_Class *basebm;
80 /******************************************************************************/
82 static void gfx_setFrameBuffer(struct GfxBase *GfxBase, struct gfx_data *data, OOP_Object *fb);
83 static VOID draw_cursor(struct gfx_data *data, BOOL draw, BOOL updaterect, struct GfxBase *GfxBase);
84 static BOOL rethink_cursor(struct gfx_data *data, struct GfxBase *GfxBase);
85 static OOP_Object *create_fake_fb(OOP_Object *framebuffer, struct gfx_data *data, struct GfxBase *GfxBase);
87 /******************************************************************************/
89 #if SPECIAL_LOCKING
91 static void FakeGfxHidd_ObtainSemaphore(struct SignalSemaphore *sigSem, BOOL urgent,
92 struct GfxBase *GfxBase)
94 struct Task *me;
96 /* Get pointer to current task */
97 me=FindTask(NULL);
99 /* Arbitrate for the semaphore structure */
100 Forbid();
103 ss_QueueCount == -1 indicates that the semaphore is
104 free, so we increment this straight away. If it then
105 equals 0, then we are the first to allocate this semaphore.
107 Note: This will need protection for SMP machines.
109 sigSem->ss_QueueCount++;
110 if( sigSem->ss_QueueCount == 0 )
112 /* We now own the semaphore. This is quick. */
113 sigSem->ss_Owner = me;
114 sigSem->ss_NestCount++;
117 /* The semaphore was in use, but was it by us? */
118 else if( sigSem->ss_Owner == me )
120 /* Yes, just increase the nesting count */
121 sigSem->ss_NestCount++;
125 Else, some other task must own it. We have
126 to set a waiting request here.
128 else
131 We need a node to mark our semaphore request. Lets use some
132 stack memory.
134 struct SemaphoreRequest sr;
135 sr.sr_Waiter = me;
138 Have to clear the signal to make sure that we don't
139 return immediately. We then add the SemReq to the
140 waiters list of the semaphore. We were the last to
141 request, so we must be the last to get the semaphore.
144 AROS_ATOMIC_AND(me->tc_SigRecvd, ~SIGF_SINGLE);
146 if (urgent)
148 AddHead((struct List *)&sigSem->ss_WaitQueue, (struct Node *)&sr);
150 else
152 AddTail((struct List *)&sigSem->ss_WaitQueue, (struct Node *)&sr);
156 Finally, we simply wait, ReleaseSemaphore() will fill in
157 who owns the semaphore.
159 Wait(SIGF_SINGLE);
162 /* All Done! */
163 Permit();
167 /******************************************************************************/
169 static void FakeGfxHidd_ReleaseSemaphore(struct SignalSemaphore *sigSem,
170 struct GfxBase *GfxBase)
172 /* Protect the semaphore structure from multiple access. */
173 Forbid();
175 /* Release one on the nest count */
176 sigSem->ss_NestCount--;
177 sigSem->ss_QueueCount--;
179 if(sigSem->ss_NestCount == 0)
182 There are two cases here. Either we are a shared
183 semaphore, or not. If we are not, make sure that the
184 correct Task is calling ReleaseSemaphore()
188 Do not try and wake anything unless there are a number
189 of tasks waiting. We do both the tests, this is another
190 opportunity to throw an alert if there is an error.
193 sigSem->ss_QueueCount >= 0
194 && sigSem->ss_WaitQueue.mlh_Head->mln_Succ != NULL
197 struct SemaphoreRequest *sr, *srn;
200 Look at the first node, but only to see whether it
201 is shared or not.
203 sr = (struct SemaphoreRequest *)sigSem->ss_WaitQueue.mlh_Head;
206 A node is shared if the ln_Name/sr_Waiter field is
207 odd (ie it has bit 1 set).
209 If the sr_Waiter field is != NULL, then this is a
210 task waiting, otherwise it is a message.
212 if( ((IPTR)sr->sr_Waiter & SM_SHARED) == SM_SHARED )
214 /* This is a shared lock, so ss_Owner == NULL */
215 sigSem->ss_Owner = NULL;
217 /* Go through all the nodes to find the shared ones */
218 ForeachNodeSafe(&sigSem->ss_WaitQueue, sr, srn)
220 srn = (struct SemaphoreRequest *)sr->sr_Link.mln_Succ;
222 if( ((IPTR)sr->sr_Waiter & SM_SHARED) == SM_SHARED )
224 Remove((struct Node *)sr);
226 /* Clear the bit, and update the owner count */
227 sr->sr_Waiter = (APTR)((IPTR)sr->sr_Waiter & ~1);
228 sigSem->ss_NestCount++;
230 /* This is a task, signal it */
231 Signal(sr->sr_Waiter, SIGF_SINGLE);
236 /* This is an exclusive lock - awaken first node */
237 else
239 /* Only awaken the first of the nodes */
240 Remove((struct Node *)sr);
241 sigSem->ss_NestCount++;
243 sigSem->ss_Owner = sr->sr_Waiter;
244 Signal(sr->sr_Waiter, SIGF_SINGLE);
247 } /* there are waiters */
248 /* Otherwise, there are not tasks waiting. */
249 else
251 sigSem->ss_Owner = NULL;
252 sigSem->ss_QueueCount = -1;
255 else if(sigSem->ss_NestCount < 0)
258 This can't happen. It means that somebody has released
259 more times than they have obtained.
261 Alert( AN_SemCorrupt );
264 /* All done. */
265 Permit();
269 /******************************************************************************/
271 #define LFB(data) FakeGfxHidd_ObtainSemaphore(&(data)->fbsema, FALSE, GfxBase)
272 #define UFB(data) FakeGfxHidd_ReleaseSemaphore(&(data)->fbsema, GfxBase)
273 #define LFB_QUICK(data) FakeGfxHidd_ObtainSemaphore(&(data)->fbsema, TRUE, GfxBase)
274 #define UFB_QUICK(data) FakeGfxHidd_ReleaseSemaphore(&(data)->fbsema, GfxBase)
276 #else /* !SPECIAL_LOCKING */
278 #define LFB(data) ObtainSemaphore(&(data)->fbsema)
279 #define UFB(data) ReleaseSemaphore(&(data)->fbsema)
280 #define LFB_QUICK(data) ObtainSemaphore(&(data)->fbsema)
281 #define UFB_QUICK(data) ReleaseSemaphore(&(data)->fbsema)
283 #endif /* SPECIAL_LOCKING */
285 /******************************************************************************/
287 #define GfxBase ((struct GfxBase *)cl->UserData)
289 static OOP_Object *gfx_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
291 /* Create a new gfxhid object */
292 OOP_Object *realgfxhidd;
293 struct gfx_data *data;
294 BOOL ok = FALSE;
296 realgfxhidd = (OOP_Object *)GetTagData(aHidd_FakeGfxHidd_RealGfxHidd, (IPTR)NULL, msg->attrList);
297 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
298 if (NULL == o)
299 return NULL;
301 data = OOP_INST_DATA(cl, o);
302 memset(data, 0, sizeof (*data));
303 InitSemaphore(&data->fbsema);
305 data->basegc = OOP_FindClass(CLID_Hidd_GC);
306 data->basebm = OOP_FindClass(CLID_Hidd_BitMap);
309 * If this is direct framebuffer driver, we draw our
310 * cursor on framebuffer bitmap.
311 * Otherwise we draw cursor on displayable bitmaps.
312 * TODO: Implement separate handling for mirrored framebuffers.
313 * In this case we actually don't need to backup pixels
314 * behind the sprite, because we can use mirror for this.
316 data->fakefb_attr = (OOP_GET(realgfxhidd, aHidd_Gfx_FrameBufferType) == vHidd_FrameBuffer_Direct) ?
317 aHidd_BitMap_FrameBuffer : aHidd_BitMap_Displayable;
319 data->gfxhidd = realgfxhidd;
321 if (NULL != data->gfxhidd)
323 struct TagItem gctags[] =
325 { TAG_DONE, 0UL }
328 data->gc = HIDD_Gfx_CreateObject(data->gfxhidd, data->basegc, gctags);
329 if (NULL != data->gc)
331 ok = TRUE;
335 if (!ok)
337 OOP_MethodID mid;
339 mid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
340 OOP_CoerceMethod(cl, o, (OOP_Msg)&mid);
343 return o;
346 static VOID gfx_dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
348 struct gfx_data *data;
350 data = OOP_INST_DATA(cl, o);
351 if (NULL != data->curs_backup)
353 OOP_DisposeObject(data->curs_backup);
354 data->curs_backup = NULL;
357 if (data->curs_pixels)
358 FreeMem(data->curs_pixels, data->curs_width * data->curs_height * 4);
360 if (NULL != data->gc)
362 OOP_DisposeObject(data->gc);
363 data->gc = NULL;
367 static void gfx_get(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
369 struct gfx_data *data = OOP_INST_DATA(cl, o);
371 if (msg->attrID == aHidd_Gfx_HWSpriteTypes) {
372 *msg->storage = vHidd_SpriteType_3Plus1|vHidd_SpriteType_DirectColor;
373 return;
376 OOP_DoMethod(data->gfxhidd, (OOP_Msg)msg);
379 static IPTR gfx_fwd(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
381 struct gfx_data *data = OOP_INST_DATA(cl, o);
383 return OOP_DoMethod(data->gfxhidd, msg);
386 static OOP_Object *gfx_createobject(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_CreateObject *msg)
388 struct gfx_data *data = OOP_INST_DATA(cl, o);
389 OOP_Object *object = NULL;
391 if (msg->cl == data->basebm)
393 /* Is the user about to create a framebuffer ? */
394 BOOL create_fb;
395 OOP_Object *realfb;
397 create_fb = (BOOL)GetTagData(data->fakefb_attr, FALSE, msg->attrList);
399 realfb = HIDD_Gfx_CreateObject(data->gfxhidd, msg->cl, msg->attrList);
401 if (realfb && create_fb)
403 object = create_fake_fb(realfb, data, GfxBase);
404 if (!object)
405 OOP_DisposeObject(realfb);
407 else
408 object = realfb;
410 else
412 object = (OOP_Object *)gfx_fwd(cl, o, (OOP_Msg)msg);
415 return object;
418 static BOOL gfx_setcursorshape(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_SetCursorShape *msg)
420 struct gfx_data *data;
421 OOP_Object *shape;
422 BOOL ok = TRUE;
424 data = OOP_INST_DATA(cl, o);
425 shape = msg->shape;
426 D(bug("[FakeGfx] SetCursorShape(0x%p)\n", shape));
428 /* Bitmap changed */
429 if (NULL == shape)
431 /* Erase the old cursor */
432 draw_cursor(data, FALSE, TRUE, GfxBase);
433 data->curs_on = FALSE;
434 data->curs_bm = NULL;
435 data->curs_x = data->curs_y = 0;
436 data->curs_maxx = data->curs_maxy = 0;
437 data->curs_width = data->curs_height = 0;
438 data->curs_xoffset = 0;
439 data->curs_yoffset = 0;
441 if (NULL != data->curs_backup)
443 OOP_DisposeObject(data->curs_backup);
444 data->curs_backup = NULL;
446 if (data->curs_pixels) {
447 FreeMem(data->curs_pixels, data->curs_width * data->curs_height * 4);
448 data->curs_pixels = NULL;
451 else
453 IPTR curs_width, curs_height;
454 APTR new_curs_pixels;
455 ULONG curs_pixels_len;
457 OOP_GetAttr(shape, aHidd_BitMap_Width, &curs_width);
458 OOP_GetAttr(shape, aHidd_BitMap_Height, &curs_height);
460 DCURS(bug("[FakeGfx] New cursor size: %lu x %lu, framebuffer 0x%p\n", curs_width, curs_height, data->framebuffer));
462 /* Create new cursor pixelbuffer. We multiply size by 4 because we want ARGB data
463 to fit in. */
464 curs_pixels_len = curs_width * curs_height * 4;
465 new_curs_pixels = AllocMem(curs_pixels_len, MEMF_ANY|MEMF_CLEAR);
466 if (!new_curs_pixels)
467 return FALSE;
469 LFB(data);
471 /* Erase the old cursor */
472 draw_cursor(data, FALSE, TRUE, GfxBase);
474 /* Now that we have disposed the old image using the old
475 backup bm, we can install the new image and backup bm before
476 rendering the new cursor.
477 Backup bitmap is recreated in rethink_cursor()
480 if (data->curs_pixels)
481 FreeMem(data->curs_pixels, data->curs_width * data->curs_height * 4);
483 data->curs_bm = shape;
484 data->curs_width = curs_width;
485 data->curs_height = curs_height;
486 data->curs_maxx = data->curs_x + curs_width - 1;
487 data->curs_maxy = data->curs_y + curs_height - 1;
488 data->curs_pixels = new_curs_pixels;
489 data->curs_xoffset = msg->xoffset;
490 data->curs_yoffset = msg->yoffset;
492 ok = rethink_cursor(data, GfxBase);
493 UFB(data);
495 draw_cursor(data, TRUE, TRUE, GfxBase);
498 return ok;
501 static BOOL gfx_setcursorpos(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_SetCursorPos *msg)
503 struct gfx_data *data;
504 IPTR xoffset = 0;
505 IPTR yoffset = 0;
507 data = OOP_INST_DATA(cl, o);
508 DPOS(bug("[FakeGfx] SetCursorPos(%d, %d)\n", msg->x, msg->y));
510 if (!data->framebuffer)
511 return TRUE;
513 /* We draw our cursor on the bitmap, so we have to convert back
514 from physical to logical coordinates */
515 OOP_GetAttr(data->framebuffer, aHidd_BitMap_LeftEdge, &xoffset);
516 OOP_GetAttr(data->framebuffer, aHidd_BitMap_TopEdge, &yoffset);
518 LFB_QUICK(data);
519 /* erase the old cursor */
520 draw_cursor(data, FALSE, TRUE, GfxBase);
522 data->curs_x = msg->x - xoffset;
523 data->curs_y = msg->y - yoffset;
524 /* Shift to the hotspot location */
525 data->curs_x += data->curs_xoffset;
526 data->curs_y += data->curs_yoffset;
527 data->curs_maxx = data->curs_x + data->curs_width - 1;
528 data->curs_maxy = data->curs_y + data->curs_height - 1;
530 draw_cursor(data, TRUE, TRUE, GfxBase);
531 UFB_QUICK(data);
532 return TRUE;
535 static VOID gfx_setcursorvisible(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_SetCursorVisible *msg)
537 struct gfx_data *data;
539 data = OOP_INST_DATA(cl, o);
541 LFB_QUICK(data);
543 if (msg->visible)
545 if (!data->curs_on)
547 data->curs_on = TRUE;
548 draw_cursor(data, TRUE, TRUE, GfxBase);
551 else
553 if (data->curs_on)
555 draw_cursor(data, FALSE, TRUE, GfxBase);
556 data->curs_on = FALSE;
560 UFB_QUICK(data);
564 #define PIXEL_INSIDE(fgh, x, y) \
565 ( ( (x) >= (fgh)->curs_x ) \
566 && ( (y) >= (fgh)->curs_y ) \
567 && ( (x) <= (fgh)->curs_maxx ) \
568 && ( (y) <= (fgh)->curs_maxy ) )
570 /* NOTE: x1, y1, x2, y2 MUST be sorted */
571 #define RECT_INSIDE(fgh, x1, y1, x2, y2) \
572 ( ( (x1) <= fgh->curs_maxx ) \
573 && ( (x2) >= fgh->curs_x ) \
574 && ( (y1) <= fgh->curs_maxy ) \
575 && ( (y2) >= fgh->curs_y ) )
577 #define WRECT_INSIDE(fgh, x1, y1, width, height) \
578 RECT_INSIDE(fgh, x1, y1, (x1) + (width) - 1, (y1) + (height) - 1)
580 static void gfx_copybox(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_CopyBox *msg)
582 struct gfx_data *data;
583 OOP_Object *src = NULL;
584 OOP_Object *dest = NULL;
585 BOOL inside = FALSE;
587 data = OOP_INST_DATA(cl, o);
588 LFB(data);
590 /* De-masquerade bitmap objects, every of which can be fakefb object */
591 OOP_GetAttr(msg->src, aHidd_FakeFB_RealBitMap, (IPTR *)&src);
592 OOP_GetAttr(msg->dest, aHidd_FakeFB_RealBitMap, (IPTR *)&dest);
593 if (!src)
594 src = msg->src;
595 if (!dest)
596 dest = msg->dest;
598 /* FIXME: other bitmap may belong to another instance of fakegfx which can be on
599 display on another monitor. In this case mouse cursor should be handled also
600 there. Needs further reengineering. */
601 if ((msg->src == data->fakefb) && WRECT_INSIDE(data, msg->srcX, msg->srcY, msg->width, msg->height))
602 inside = TRUE;
604 if ((msg->dest == data->fakefb) && WRECT_INSIDE(data, msg->destX, msg->destY, msg->width, msg->height))
605 inside = TRUE;
607 if (inside)
608 draw_cursor(data, FALSE, FALSE, GfxBase);
610 HIDD_Gfx_CopyBox(data->gfxhidd, src, msg->srcX, msg->srcY,
611 dest, msg->destX, msg->destY, msg->width, msg->height, msg->gc);
613 if (inside)
614 draw_cursor(data, TRUE, FALSE, GfxBase);
616 UFB(data);
619 static IPTR gfx_copyboxmasked(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_CopyBoxMasked *msg)
621 struct gfx_data *data;
622 OOP_Object *src = NULL;
623 OOP_Object *dest = NULL;
624 BOOL inside = FALSE;
625 BOOL ret;
627 data = OOP_INST_DATA(cl, o);
628 LFB(data);
630 /* De-masquerade bitmap objects, every of which can be fakefb object */
631 OOP_GetAttr(msg->src, aHidd_FakeFB_RealBitMap, (IPTR *)&src);
632 OOP_GetAttr(msg->dest, aHidd_FakeFB_RealBitMap, (IPTR *)&dest);
633 if (!src)
634 src = msg->src;
635 if (!dest)
636 dest = msg->dest;
639 * FIXME: other bitmap may belong to another instance of fakegfx which can be on
640 * display on another monitor. In this case mouse cursor should be handled also
641 * there. Needs further reengineering.
643 if ((msg->src == data->fakefb) && WRECT_INSIDE(data, msg->srcX, msg->srcY, msg->width, msg->height))
644 inside = TRUE;
646 if ((msg->dest == data->fakefb) && WRECT_INSIDE(data, msg->destX, msg->destY, msg->width, msg->height))
647 inside = TRUE;
649 if (inside)
650 draw_cursor(data, FALSE, FALSE, GfxBase);
652 ret = HIDD_Gfx_CopyBoxMasked(data->gfxhidd, src, msg->srcX, msg->srcY,
653 dest, msg->destX, msg->destY, msg->width, msg->height, msg->mask, msg->gc);
655 if (inside)
656 draw_cursor(data, TRUE, FALSE, GfxBase);
658 UFB(data);
660 return ret;
663 static OOP_Object *gfx_show(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_Show *msg)
665 OOP_Object *ret;
666 struct gfx_data *data;
668 data = OOP_INST_DATA(cl, o);
669 ret = msg->bitMap;
671 D(bug("[FakeGfx] Show(0x%p)\n", ret));
674 * If we are attempting to show a fake bitmap, we are working
675 * in NoFrameBuffer mode where each displayable bitmap is
676 * intercepted by us
678 if (ret && (OOP_OCLASS(ret) == CDD(GfxBase)->fakefbclass))
680 data->fakefb = ret;
681 OOP_GetAttr(msg->bitMap, aHidd_FakeFB_RealBitMap, (IPTR *)&ret);
682 D(bug("[FakeGfx] Bitmap is a fakefb object, real bitmap is 0x%p\n", ret));
685 LFB(data);
686 draw_cursor(data, FALSE, FALSE, GfxBase);
688 ret = HIDD_Gfx_Show(data->gfxhidd, ret, msg->flags);
689 D(bug("[FakeGfx] Real framebuffer object 0x%p\n", ret));
690 gfx_setFrameBuffer(GfxBase, data, ret);
691 if (NULL != ret)
692 ret = data->fakefb;
693 /* FIXME: temporary workaround: at this point Intuition has already destroyed
694 the sprite image (since the last screen was closed) but we have no information
695 about it. Perhaps FreeSpriteData() should track this down somehow and inform
696 drivers about destroyed sprites.
697 if (!msg->bitMap)
698 data->curs_bm = NULL;*/
699 rethink_cursor(data, GfxBase);
700 draw_cursor(data, TRUE, TRUE, GfxBase);
702 UFB(data);
704 D(bug("[FakeGfx] Returning 0x%p\n", ret));
705 return ret;
708 static ULONG gfx_showviewports(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
710 /* Composition is not supported here */
711 return FALSE;
714 static BOOL gfx_getmaxspritesize(OOP_Class *cl, OOP_Object *o, struct pHidd_Gfx_GetMaxSpriteSize *msg)
716 if (msg->Type & (vHidd_SpriteType_3Plus1|vHidd_SpriteType_DirectColor)) {
717 /* I hope these values are enough for everyone :) */
718 *msg->Width = 65535;
719 *msg->Height = 65535;
721 return TRUE;
722 } else
723 return FALSE;
726 /* Private non-virtual method */
727 static BOOL FakeGfx_UpdateFrameBuffer(OOP_Object *o)
729 OOP_Class *cl = OOP_OCLASS(o);
730 struct gfx_data *data = OOP_INST_DATA(cl, o);
731 BOOL ok;
733 LFB(data);
735 OOP_GetAttr(data->framebuffer, aHidd_BitMap_Width, &data->fb_width);
736 OOP_GetAttr(data->framebuffer, aHidd_BitMap_Height, &data->fb_height);
738 DCURS(bug("[FakeGfx] Changed framebuffer size: %u x %u\n", data->fb_width, data->fb_height));
740 ok = rethink_cursor(data, GfxBase);
741 UFB(data);
743 draw_cursor(data, TRUE, TRUE, GfxBase);
744 return ok;
747 struct fakefb_data
749 OOP_Object *framebuffer;
750 OOP_Object *fakegfxhidd;
753 #define FGH(data) ((struct gfx_data *)data->fakegfxhidd)
754 #define REMOVE_CURSOR(data) \
755 draw_cursor(FGH(data), FALSE, FALSE, GfxBase)
757 #define RENDER_CURSOR(data) \
758 draw_cursor(FGH(data), TRUE, FALSE, GfxBase)
761 #define BITMAP_METHOD_INIT \
762 struct fakefb_data *data; \
763 BOOL inside = FALSE; \
764 IPTR retval; \
765 struct gfx_data *fgh; \
766 data = OOP_INST_DATA(cl, o); \
767 fgh = FGH(data); \
768 LFB(fgh);
770 #define FORWARD_METHOD \
771 retval = OOP_DoMethod(data->framebuffer, (OOP_Msg)msg);
773 #define BITMAP_METHOD_EXIT \
774 if (inside) { \
775 RENDER_CURSOR(data); \
777 UFB(fgh); \
778 return retval;
780 static OOP_Object *fakefb_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
782 OOP_Object *framebuffer;
783 OOP_Object *fakegfxhidd;
785 framebuffer = (OOP_Object *)GetTagData(aHidd_FakeFB_RealBitMap, 0, msg->attrList);
786 fakegfxhidd = (OOP_Object *)GetTagData(aHidd_FakeFB_FakeGfxHidd, 0, msg->attrList);
788 if (NULL == framebuffer || NULL == fakegfxhidd)
790 D(bug("!!! FakeBM::New(): MISSING FRAMEBUFFER OR FAKE GFX HIDD !!!\n"));
791 return NULL;
794 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
795 if (NULL != o)
797 struct fakefb_data *data;
798 data = OOP_INST_DATA(cl, o);
799 data->framebuffer = framebuffer;
800 data->fakegfxhidd = fakegfxhidd;
802 return o;
805 static VOID fakefb_dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
807 struct fakefb_data *data;
808 data = OOP_INST_DATA(cl, o);
809 if (NULL != data->framebuffer)
811 OOP_DisposeObject(data->framebuffer);
812 data->framebuffer = NULL;
816 static void fakefb_get(OOP_Class *cl, OOP_Object *o, struct pRoot_Get *msg)
818 struct fakefb_data *data = OOP_INST_DATA(cl, o);
820 if (msg->attrID == aHidd_FakeFB_RealBitMap)
822 *msg->storage = (IPTR)data->framebuffer;
823 return;
825 else if (msg->attrID == aHidd_BitMap_GfxHidd)
827 *msg->storage = (IPTR)data->fakegfxhidd;
828 return;
830 else
831 OOP_DoMethod(data->framebuffer, (OOP_Msg)msg);
834 /* Intercept framebuffer mode change */
835 static IPTR fakefb_set(OOP_Class *cl, OOP_Object *o, struct pRoot_Set *msg)
837 struct fakefb_data *data = OOP_INST_DATA(cl, o);
838 IPTR ret = OOP_DoMethod(data->framebuffer, &msg->mID);
839 struct TagItem *modeid = FindTagItem(aHidd_BitMap_ModeID, msg->attrList);
841 if (modeid && ret)
843 /* Framebuffer mode change succeeded. Update fakegfx' information */
844 ret = FakeGfx_UpdateFrameBuffer(data->fakegfxhidd);
847 return ret;
850 static IPTR fakefb_getpixel(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_GetPixel *msg)
852 BITMAP_METHOD_INIT
854 if (PIXEL_INSIDE(fgh, msg->x, msg->y))
856 REMOVE_CURSOR(data);
857 inside = TRUE;
860 FORWARD_METHOD
862 BITMAP_METHOD_EXIT
865 static IPTR fakefb_putpixel(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutPixel *msg)
867 BITMAP_METHOD_INIT
869 if (PIXEL_INSIDE(fgh, msg->x, msg->y))
871 REMOVE_CURSOR(data);
872 inside = TRUE;
875 FORWARD_METHOD
877 BITMAP_METHOD_EXIT
880 static IPTR fakefb_drawpixel(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawPixel *msg)
882 BITMAP_METHOD_INIT
884 if (PIXEL_INSIDE(fgh, msg->x, msg->y))
886 REMOVE_CURSOR(data);
887 inside = TRUE;
890 FORWARD_METHOD
892 BITMAP_METHOD_EXIT
895 static IPTR fakefb_drawline(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawLine *msg)
897 register LONG x1, y1, x2, y2;
898 BITMAP_METHOD_INIT
900 if (msg->x1 < msg->x2)
902 x1 = msg->x1; x2 = msg->x2;
904 else
906 x2 = msg->x1; x1 = msg->x2;
909 if (msg->y1 < msg->y2)
911 y1 = msg->y1; y2 = msg->y2;
913 else
915 y2 = msg->y1; y1 = msg->y2;
918 /* FIXME: Maybe do some more intelligent checking for DrawLine */
919 if (RECT_INSIDE(fgh, x1, y1, x2, y2))
921 REMOVE_CURSOR(data);
922 inside = TRUE;
925 FORWARD_METHOD
927 BITMAP_METHOD_EXIT
930 static IPTR fakefb_getimage(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_GetImage *msg)
932 BITMAP_METHOD_INIT
934 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
936 REMOVE_CURSOR(data);
937 inside = TRUE;
940 FORWARD_METHOD
942 BITMAP_METHOD_EXIT
945 static IPTR fakefb_putimage(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutImage *msg)
947 BITMAP_METHOD_INIT
949 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
951 REMOVE_CURSOR(data);
952 inside = TRUE;
955 FORWARD_METHOD
957 BITMAP_METHOD_EXIT
960 static IPTR fakefb_putalphaimage(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutAlphaImage *msg)
962 BITMAP_METHOD_INIT
964 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
966 REMOVE_CURSOR(data);
967 inside = TRUE;
970 FORWARD_METHOD
972 BITMAP_METHOD_EXIT
975 static IPTR fakefb_puttemplate(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutTemplate *msg)
977 BITMAP_METHOD_INIT
979 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
981 REMOVE_CURSOR(data);
982 inside = TRUE;
985 FORWARD_METHOD
987 BITMAP_METHOD_EXIT
990 static IPTR fakefb_putalphatemplate(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutAlphaTemplate *msg)
992 BITMAP_METHOD_INIT
994 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
996 REMOVE_CURSOR(data);
997 inside = TRUE;
1000 FORWARD_METHOD
1002 BITMAP_METHOD_EXIT
1005 static IPTR fakefb_putpattern(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutPattern *msg)
1007 BITMAP_METHOD_INIT
1009 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
1011 REMOVE_CURSOR(data);
1012 inside = TRUE;
1015 FORWARD_METHOD
1017 BITMAP_METHOD_EXIT
1020 static IPTR fakefb_getimagelut(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_GetImageLUT *msg)
1022 BITMAP_METHOD_INIT
1024 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
1026 REMOVE_CURSOR(data);
1027 inside = TRUE;
1030 FORWARD_METHOD
1032 BITMAP_METHOD_EXIT
1035 static IPTR fakefb_putimagelut(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutImageLUT *msg)
1037 BITMAP_METHOD_INIT
1039 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
1041 REMOVE_CURSOR(data);
1042 inside = TRUE;
1045 FORWARD_METHOD
1047 BITMAP_METHOD_EXIT
1050 static IPTR fakefb_puttranspimagelut(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_PutTranspImageLUT *msg)
1052 BITMAP_METHOD_INIT
1054 if (WRECT_INSIDE(fgh, msg->x, msg->y, msg->width, msg->height))
1056 REMOVE_CURSOR(data);
1057 inside = TRUE;
1060 FORWARD_METHOD
1062 BITMAP_METHOD_EXIT
1065 static IPTR fakefb_drawrect(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawRect *msg)
1067 BITMAP_METHOD_INIT
1069 /* FIXME: Maybe do something clever here to see if the rectangle is drawn around the cursor */
1070 if (RECT_INSIDE(fgh, msg->minX, msg->minY, msg->maxX, msg->maxY))
1072 REMOVE_CURSOR(data);
1073 inside = TRUE;
1076 FORWARD_METHOD
1078 BITMAP_METHOD_EXIT
1081 static IPTR fakefb_fillrect(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawRect *msg)
1083 BITMAP_METHOD_INIT
1085 /* bug("BITMAP FILLRECT(%d, %d, %d, %d), (%d, %d, %d, %d, %d, %d)\n"
1086 , msg->minX, msg->minY, msg->maxX, msg->maxY
1087 , fgh->curs_x, fgh->curs_y, fgh->curs_maxx, fgh->curs_maxy
1088 , fgh->curs_width, fgh->curs_height);
1090 if (RECT_INSIDE(fgh, msg->minX, msg->minY, msg->maxX, msg->maxY))
1092 /* bug("FILLRECT: REMOVING CURSOR\n");
1094 REMOVE_CURSOR(data);
1096 inside = TRUE;
1099 FORWARD_METHOD
1101 BITMAP_METHOD_EXIT
1104 static IPTR fakefb_drawellipse(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawEllipse *msg)
1106 register LONG x1, y1, x2, y2;
1107 BITMAP_METHOD_INIT
1109 x1 = msg->x - msg->rx;
1110 y1 = msg->y - msg->ry;
1111 x2 = msg->x + msg->rx;
1112 y2 = msg->y + msg->ry;
1113 /* FIXME: Maybe do something clever here to see if the rectangle is drawn around the cursor */
1115 if (RECT_INSIDE(fgh, x1, y1, x2, y2))
1117 REMOVE_CURSOR(data);
1118 inside = TRUE;
1121 FORWARD_METHOD
1123 BITMAP_METHOD_EXIT
1126 static IPTR fakefb_fillellipse(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawEllipse *msg)
1128 register LONG x1, y1, x2, y2;
1129 BITMAP_METHOD_INIT
1131 x1 = msg->x - msg->rx;
1132 y1 = msg->y - msg->ry;
1133 x2 = msg->x + msg->rx;
1134 y2 = msg->y + msg->ry;
1136 if (RECT_INSIDE(fgh, x1, y1, x2, y2))
1138 REMOVE_CURSOR(data);
1139 inside = TRUE;
1142 FORWARD_METHOD
1144 BITMAP_METHOD_EXIT
1147 static IPTR fakefb_drawpolygon(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawPolygon *msg)
1149 BITMAP_METHOD_INIT
1150 /* FIXME: Maybe do checking here, but it probably is not worth it */
1151 REMOVE_CURSOR(data);
1152 inside = TRUE;
1154 FORWARD_METHOD
1156 BITMAP_METHOD_EXIT
1159 static IPTR fakefb_fillpolygon(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawPolygon *msg)
1161 BITMAP_METHOD_INIT
1162 /* FIXME: Maybe do checking here, but it probably is not worth it */
1163 REMOVE_CURSOR(data);
1164 inside = TRUE;
1166 FORWARD_METHOD
1168 BITMAP_METHOD_EXIT
1172 static IPTR fakefb_drawtext(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawText *msg)
1174 BITMAP_METHOD_INIT
1176 /* FIXME: Maybe do testing here, but probably not wirth it */
1177 REMOVE_CURSOR(data);
1179 FORWARD_METHOD
1181 BITMAP_METHOD_EXIT
1184 static IPTR fakefb_drawfilltext(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_DrawText *msg)
1186 BITMAP_METHOD_INIT
1188 /* FIXME: Maybe do testing here, but probably not worth it */
1189 REMOVE_CURSOR(data);
1191 FORWARD_METHOD
1193 BITMAP_METHOD_EXIT
1196 static IPTR fakefb_blitcolexp(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_BlitColorExpansion *msg)
1198 BITMAP_METHOD_INIT
1200 if (WRECT_INSIDE(fgh, msg->destX, msg->destY, msg->width, msg->height))
1202 REMOVE_CURSOR(data);
1203 inside = TRUE;
1206 FORWARD_METHOD
1208 BITMAP_METHOD_EXIT
1211 static IPTR fakefb_clear(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_Clear *msg)
1213 BITMAP_METHOD_INIT
1215 inside = TRUE;
1217 FORWARD_METHOD
1219 BITMAP_METHOD_EXIT
1223 static IPTR fakefb_fillspan(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
1225 BITMAP_METHOD_INIT
1227 REMOVE_CURSOR(data);
1228 inside = TRUE;
1230 FORWARD_METHOD
1232 BITMAP_METHOD_EXIT
1235 static IPTR fakefb_scale(OOP_Class *cl, OOP_Object *o, struct pHidd_BitMap_BitMapScale *msg)
1237 /* FIXME: should check both source and destination, similar to gfx_copybox() */
1238 BITMAP_METHOD_INIT
1240 if (WRECT_INSIDE(fgh, msg->bsa->bsa_SrcX, msg->bsa->bsa_SrcY, msg->bsa->bsa_SrcWidth, msg->bsa->bsa_SrcHeight))
1242 REMOVE_CURSOR(data);
1243 inside = TRUE;
1246 FORWARD_METHOD
1248 BITMAP_METHOD_EXIT
1251 static IPTR fakefb_fwd(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
1253 struct fakefb_data *data;
1254 data = OOP_INST_DATA(cl, o);
1255 // kill(getpid(), 19);
1256 // bug("BITMAP_FWD\n");
1257 return OOP_DoMethod(data->framebuffer, msg);
1260 #undef GfxBase
1262 static BOOL rethink_cursor(struct gfx_data *data, struct GfxBase *GfxBase)
1264 OOP_Object *pf, *cmap;
1265 IPTR fbdepth, curdepth, i;
1266 UWORD curs_base = 16;
1268 struct TagItem bmtags[] = {
1269 { aHidd_BitMap_Width , data->curs_width },
1270 { aHidd_BitMap_Height, data->curs_height },
1271 { aHidd_BitMap_Friend, (IPTR)data->framebuffer},
1272 { TAG_DONE , 0UL }
1275 D(bug("rethink_cursor(), curs_bm is 0x%p, framebuffer is 0x%p\n", data->curs_bm, data->framebuffer));
1277 /* The first thing we do is recreating a backup bitmap. We do it every time when either
1278 cursor shape changes (because new shape may have different size) or shown bitmap
1279 changes (because new bitmap may have different depth). Note that even real framebuffer
1280 object may dynamically change its characteristics.
1282 Delete the old backup bitmap first */
1283 if (NULL != data->curs_backup) {
1284 OOP_DisposeObject(data->curs_backup);
1285 D(bug("[FakeGfx] Disposed old backup bitmap\n"));
1286 data->curs_backup = NULL;
1289 /* If we have no cursor, we have nothing more to do.
1290 We also don't need new backup bitmap */
1291 if (!data->curs_bm)
1292 return TRUE;
1294 /* We may also have no framebuffer (empty display on
1295 non-framebuffer driver). Also NOP in this case */
1296 if (!data->framebuffer)
1297 return TRUE;
1299 /* Create new backup bitmap */
1300 data->curs_backup = HIDD_Gfx_CreateObject(data->gfxhidd, data->basebm, bmtags);
1301 D(bug("[FakeGfx] New backup bitmap is 0x%p\n", data->curs_backup));
1302 if (!data->curs_backup)
1303 return FALSE;
1305 OOP_GetAttr(data->framebuffer, aHidd_BitMap_PixFmt, (IPTR *)&pf);
1306 D(bug("[FakeGfx] Framebuffer pixelformat 0x%p\n", pf));
1307 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &fbdepth);
1308 D(bug("[FakeGfx] Framebuffer depth %u\n", fbdepth));
1309 OOP_GetAttr(data->curs_bm, aHidd_BitMap_ColorMap, (IPTR *)&cmap);
1310 D(bug("[FakeGfx] Cursor colormap 0x%p\n", cmap));
1311 OOP_GetAttr(data->curs_bm, aHidd_BitMap_PixFmt, (IPTR *)&pf);
1312 D(bug("[FakeGfx] Cursor pixelformat 0x%p\n", pf));
1313 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &curdepth);
1314 D(bug("[FakeGfx] Cursor depth %u\n", curdepth));
1316 #ifndef DISABLE_ARGB_POINTER
1317 /* We can get ARGB data from the pointer bitmap only
1318 on one of two cases:
1319 1) Pointer bitmap has more than 256 colors, in this case it
1320 stores ARGB data in itself.
1321 2) Pointer bitmap is a LUT bitmap with a colormap attached.
1322 In this case colormap should contain ARGB values for actual
1323 colors.
1324 Of course having ARGB data makes sense only on truecolor screens. */
1325 if ((fbdepth > 8) && ((curdepth > 8) || cmap)) {
1326 data->curs_pixfmt = vHidd_StdPixFmt_ARGB32;
1327 data->curs_bpp = 4;
1328 } else
1329 #endif
1331 data->curs_pixfmt = vHidd_StdPixFmt_LUT8;
1332 data->curs_bpp = 1;
1333 /* TODO: curs_base should be somehow synchronised with SpriteBase field of ColorMap */
1334 curs_base = (fbdepth > 4) ? 16 : (1 << fbdepth) - 8;
1336 /* If we have some good bitmap->bitmap blitting function with alpha channel support,
1337 we would not need this extra buffer and conversion for truecolor screens. */
1338 HIDD_BM_GetImage(data->curs_bm, data->curs_pixels, data->curs_width * data->curs_bpp, 0, 0, data->curs_width, data->curs_height, data->curs_pixfmt);
1339 D(bug("[FakeGfx] Obtained cursor sprite data @ 0x%p\n", data->curs_pixels));
1341 if (data->curs_pixfmt == vHidd_StdPixFmt_LUT8)
1343 for (i = 0; i < data->curs_width * data->curs_height; i++)
1345 if (data->curs_pixels[i])
1346 data->curs_pixels[i] += curs_base;
1349 return TRUE;
1352 static VOID draw_cursor(struct gfx_data *data, BOOL draw, BOOL updaterect, struct GfxBase *GfxBase)
1354 LONG width, height;
1355 LONG fbwidth, fbheight;
1356 LONG x, y;
1357 LONG w2end, h2end;
1358 ULONG xoffset = 0;
1359 ULONG yoffset = 0;
1361 struct TagItem gctags[] =
1363 { aHidd_GC_DrawMode , vHidd_GC_DrawMode_Copy },
1364 { TAG_DONE , 0UL }
1367 if (!data->curs_on)
1368 return;
1370 if (NULL == data->curs_bm || NULL == data->framebuffer)
1372 DB2(bug("!!! draw_cursor: FAKE GFX HIDD NOT PROPERLY INITIALIZED !!!\n"));
1373 DB2(bug("CURS BM: 0x%p, FB: 0x%p\n", data->curs_bm, data->framebuffer));
1374 return;
1377 fbwidth = data->fb_width;
1378 fbheight = data->fb_height;
1379 width = data->curs_width;
1380 height = data->curs_height;
1381 x = data->curs_x;
1382 y = data->curs_y;
1384 /* Do nothing if sprite went outside of bitmap */
1385 if ((x < -width) || (y < -height)) {
1386 DCURS(bug("[FakeGfx] Cursor is beyond left or top edge\n"));
1387 return;
1389 if ((x >= fbwidth) || (y >= fbheight)) {
1390 DCURS(bug("[FakeGfx] Cursor is beyond right or bottom edge\n"));
1391 return;
1394 /* Do some clipping */
1395 if (x < 0) {
1396 xoffset = -x;
1397 width += x;
1398 x = 0;
1401 if (y < 0) {
1402 yoffset = -y;
1403 height += y;
1404 y = 0;
1407 w2end = data->fb_width - width;
1408 h2end = data->fb_height - height;
1410 if (x > w2end)
1412 width -= (x - w2end);
1413 DCLIP(bug("[FakeGfx] Clipped sprite width to %d\n", width));
1416 if (y > h2end)
1418 height -= (y - h2end);
1419 DCLIP(bug("[FakeGfx] Clipped sprite height to %d\n", height));
1422 /* FIXME: clip negative coordinates */
1424 OOP_SetAttrs(data->gc, gctags);
1426 if (draw)
1428 /* Calculate origin of sprite image according to offsets */
1429 ULONG modulo = data->curs_width * data->curs_bpp;
1430 UBYTE *pixels = data->curs_pixels + yoffset * modulo + xoffset * data->curs_bpp;
1432 /* Backup under the new cursor image */
1433 // bug("BACKING UP RENDERED AREA\n");
1434 HIDD_Gfx_CopyBox(data->gfxhidd
1435 , data->framebuffer
1436 , x, y
1437 , data->curs_backup
1438 , 0, 0
1439 , width, height
1440 , data->gc
1443 data->backup_done = TRUE;
1445 DB2(bug("[FakeGfx] Rendering cursor, framebuffer 0x%p\n", data->framebuffer));
1446 /* Render the cursor image */
1447 if (data->curs_pixfmt == vHidd_StdPixFmt_ARGB32)
1448 HIDD_BM_PutAlphaImage(data->framebuffer, data->gc, pixels, modulo, x, y, width, height);
1449 else
1450 /* data->curs_bpp is always 1 here so we safely ignore it */
1451 HIDD_BM_PutTranspImageLUT(data->framebuffer, data->gc, pixels, modulo, x, y, width, height, NULL, 0);
1453 if (updaterect)
1454 HIDD_BM_UpdateRect(data->framebuffer, x, y, width, height);
1457 else
1459 /* Erase the old cursor image */
1460 if (data->backup_done)
1462 DB2(bug("[FakeGfx] Restoring cursor area, framebuffer 0x%p\n", data->framebuffer));
1463 HIDD_Gfx_CopyBox(data->gfxhidd
1464 , data->curs_backup
1465 , 0, 0
1466 , data->framebuffer
1467 , x, y
1468 , width, height
1469 , data->gc
1472 if (updaterect)
1473 HIDD_BM_UpdateRect(data->framebuffer, x, y, width, height);
1476 return;
1479 static void gfx_setFrameBuffer(struct GfxBase *GfxBase, struct gfx_data *data, OOP_Object *fb)
1481 data->framebuffer = fb;
1483 if (fb)
1485 /* Cache framebuffer size, needed by sprite rendering routine */
1486 OOP_GetAttr(fb, aHidd_BitMap_Width, &data->fb_width);
1487 OOP_GetAttr(fb, aHidd_BitMap_Height, &data->fb_height);
1489 DCURS(bug("[FakeGfx] Framebuffer size: %u x %u\n", data->fb_width, data->fb_height));
1493 static OOP_Object *create_fake_fb(OOP_Object *framebuffer, struct gfx_data *data, struct GfxBase *GfxBase)
1495 OOP_Object *fakebm;
1496 struct TagItem fakebmtags[] =
1498 { aHidd_FakeFB_RealBitMap , (IPTR)framebuffer },
1499 { aHidd_FakeFB_FakeGfxHidd , (IPTR)data },
1500 { TAG_DONE , 0UL }
1503 /* If we work with framebuffer-based driver, Show() will never be called on
1504 a fakefb object so we remember it right now */
1505 fakebm = OOP_NewObject(CDD(GfxBase)->fakefbclass, NULL, fakebmtags);
1507 if (data->fakefb_attr == aHidd_BitMap_FrameBuffer)
1509 data->fakefb = fakebm;
1510 gfx_setFrameBuffer(GfxBase, data, framebuffer);
1513 return fakebm;
1516 static OOP_Class *init_fakegfxhiddclass (struct GfxBase *GfxBase)
1518 OOP_Class *cl = NULL;
1520 struct OOP_MethodDescr root_descr[num_Root_Methods + 1] =
1522 {(IPTR (*)())gfx_new , moRoot_New },
1523 {(IPTR (*)())gfx_dispose, moRoot_Dispose },
1524 {(IPTR (*)())gfx_get , moRoot_Get },
1525 {(IPTR (*)())gfx_fwd , moRoot_Set },
1526 { NULL , 0UL }
1529 struct OOP_MethodDescr gfxhidd_descr[num_Hidd_Gfx_Methods + 1] =
1531 {(IPTR (*)())gfx_fwd , moHidd_Gfx_NominalDimensions },
1532 {(IPTR (*)())gfx_createobject , moHidd_Gfx_CreateObject },
1533 {(IPTR (*)())gfx_fwd , moHidd_Gfx_QueryModeIDs },
1534 {(IPTR (*)())gfx_fwd , moHidd_Gfx_ReleaseModeIDs },
1535 {(IPTR (*)())gfx_fwd , moHidd_Gfx_CheckMode },
1536 {(IPTR (*)())gfx_fwd , moHidd_Gfx_NextModeID },
1537 {(IPTR (*)())gfx_fwd , moHidd_Gfx_GetMode },
1538 {(IPTR (*)())gfx_fwd , moHidd_Gfx_GetPixFmt },
1539 {(IPTR (*)())gfx_setcursorshape , moHidd_Gfx_SetCursorShape },
1540 {(IPTR (*)())gfx_setcursorpos , moHidd_Gfx_SetCursorPos },
1541 {(IPTR (*)())gfx_setcursorvisible , moHidd_Gfx_SetCursorVisible },
1542 {(IPTR (*)())gfx_fwd , moHidd_Gfx_SetMode },
1543 {(IPTR (*)())gfx_show , moHidd_Gfx_Show },
1544 {(IPTR (*)())gfx_copybox , moHidd_Gfx_CopyBox },
1545 {(IPTR (*)())gfx_fwd , moHidd_Gfx_ModeProperties },
1546 {(IPTR (*)())gfx_showviewports , moHidd_Gfx_ShowViewPorts },
1547 {(IPTR (*)())gfx_fwd , moHidd_Gfx_GetSync },
1548 {(IPTR (*)())gfx_fwd , moHidd_Gfx_GetGamma },
1549 {(IPTR (*)())gfx_fwd , moHidd_Gfx_SetGamma },
1550 {(IPTR (*)())gfx_fwd , moHidd_Gfx_QueryHardware3D },
1551 {(IPTR (*)())gfx_getmaxspritesize , moHidd_Gfx_GetMaxSpriteSize },
1552 {(IPTR (*)())gfx_fwd , moHidd_Gfx_NewOverlay },
1553 {(IPTR (*)())gfx_fwd , moHidd_Gfx_DisposeOverlay },
1554 {(IPTR (*)())gfx_fwd , moHidd_Gfx_MakeViewPort },
1555 {(IPTR (*)())gfx_fwd , moHidd_Gfx_CleanViewPort },
1556 {(IPTR (*)())gfx_fwd , moHidd_Gfx_PrepareViewPorts },
1557 {(IPTR (*)())gfx_copyboxmasked , moHidd_Gfx_CopyBoxMasked },
1558 {NULL , 0UL }
1561 struct OOP_InterfaceDescr ifdescr[] =
1563 {root_descr , IID_Root , num_Root_Methods },
1564 {gfxhidd_descr , IID_Hidd_Gfx , num_Hidd_Gfx_Methods },
1565 {NULL , NULL , 0 }
1568 OOP_AttrBase MetaAttrBase = OOP_GetAttrBase(IID_Meta);
1570 struct TagItem tags[] =
1572 { aMeta_SuperID , (IPTR)CLID_Root },
1573 { aMeta_InterfaceDescr , (IPTR)ifdescr },
1574 { aMeta_InstSize , (IPTR)sizeof (struct gfx_data) },
1575 {TAG_DONE , 0UL }
1579 D(bug("INIT FAKEGFXCLASS\n"));
1581 if ((__IHidd_FakeFB = OOP_ObtainAttrBase(IID_Hidd_FakeFB)))
1583 cl = OOP_NewObject(NULL, CLID_HiddMeta, tags);
1584 if(NULL != cl)
1586 D(bug("FAKE GFX CLASS INITED\n"));
1587 cl->UserData = GfxBase;
1589 return cl;
1592 OOP_ReleaseAttrBase(IID_Hidd_FakeFB);
1595 return NULL;
1598 static OOP_Class *init_fakefbclass(struct GfxBase *GfxBase)
1600 struct OOP_MethodDescr root_descr[num_Root_Methods + 1] =
1602 {(IPTR (*)())fakefb_new , moRoot_New },
1603 {(IPTR (*)())fakefb_dispose, moRoot_Dispose },
1604 {(IPTR (*)())fakefb_get , moRoot_Get },
1605 {(IPTR (*)())fakefb_set , moRoot_Set },
1606 {NULL , 0UL }
1609 struct OOP_MethodDescr bitmap_descr[num_Hidd_BitMap_Methods + 1] =
1611 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_SetColors },
1612 {(IPTR (*)())fakefb_putpixel , moHidd_BitMap_PutPixel },
1613 {(IPTR (*)())fakefb_drawpixel , moHidd_BitMap_DrawPixel },
1614 {(IPTR (*)())fakefb_putimage , moHidd_BitMap_PutImage },
1615 {(IPTR (*)())fakefb_putalphaimage , moHidd_BitMap_PutAlphaImage },
1616 {(IPTR (*)())fakefb_puttemplate , moHidd_BitMap_PutTemplate },
1617 {(IPTR (*)())fakefb_putalphatemplate , moHidd_BitMap_PutAlphaTemplate },
1618 {(IPTR (*)())fakefb_putpattern , moHidd_BitMap_PutPattern },
1619 {(IPTR (*)())fakefb_getimage , moHidd_BitMap_GetImage },
1620 {(IPTR (*)())fakefb_getpixel , moHidd_BitMap_GetPixel },
1621 {(IPTR (*)())fakefb_drawline , moHidd_BitMap_DrawLine },
1622 {(IPTR (*)())fakefb_drawrect , moHidd_BitMap_DrawRect },
1623 {(IPTR (*)())fakefb_fillrect , moHidd_BitMap_FillRect },
1624 {(IPTR (*)())fakefb_drawellipse , moHidd_BitMap_DrawEllipse },
1625 {(IPTR (*)())fakefb_fillellipse , moHidd_BitMap_FillEllipse },
1626 {(IPTR (*)())fakefb_drawpolygon , moHidd_BitMap_DrawPolygon },
1627 {(IPTR (*)())fakefb_fillpolygon , moHidd_BitMap_FillPolygon },
1628 {(IPTR (*)())fakefb_drawtext , moHidd_BitMap_DrawText },
1629 {(IPTR (*)())fakefb_drawfilltext , moHidd_BitMap_FillText },
1630 {(IPTR (*)())fakefb_fillspan , moHidd_BitMap_FillSpan },
1631 {(IPTR (*)())fakefb_clear , moHidd_BitMap_Clear },
1632 {(IPTR (*)())fakefb_blitcolexp , moHidd_BitMap_BlitColorExpansion },
1633 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_MapColor },
1634 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_UnmapPixel },
1635 {(IPTR (*)())fakefb_putimagelut , moHidd_BitMap_PutImageLUT },
1636 {(IPTR (*)())fakefb_puttranspimagelut , moHidd_BitMap_PutTranspImageLUT },
1637 {(IPTR (*)())fakefb_getimagelut , moHidd_BitMap_GetImageLUT },
1638 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_BytesPerLine },
1639 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_ConvertPixels },
1640 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_FillMemRect8 },
1641 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_FillMemRect16 },
1642 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_FillMemRect24 },
1643 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_FillMemRect32 },
1644 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_InvertMemRect },
1645 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyMemBox8 },
1646 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyMemBox16 },
1647 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyMemBox24 },
1648 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyMemBox32 },
1649 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyLUTMemBox16 },
1650 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyLUTMemBox24 },
1651 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_CopyLUTMemBox32 },
1652 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMem32Image8 },
1653 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMem32Image16 },
1654 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMem32Image24 },
1655 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_GetMem32Image8 },
1656 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_GetMem32Image16 },
1657 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_GetMem32Image24 },
1658 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemTemplate8 },
1659 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemTemplate16 },
1660 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemTemplate24 },
1661 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemTemplate32 },
1662 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemPattern8 },
1663 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemPattern16 },
1664 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemPattern24 },
1665 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PutMemPattern32 },
1666 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_SetColorMap },
1667 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_ObtainDirectAccess },
1668 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_ReleaseDirectAccess },
1669 {(IPTR (*)())fakefb_scale , moHidd_BitMap_BitMapScale },
1670 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_PrivateSet },
1671 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_SetRGBConversionFunction },
1672 {(IPTR (*)())fakefb_fwd , moHidd_BitMap_UpdateRect },
1673 {NULL , 0UL }
1676 struct OOP_InterfaceDescr ifdescr[] =
1678 {root_descr , IID_Root , num_Root_Methods },
1679 {bitmap_descr , IID_Hidd_BitMap, num_Hidd_BitMap_Methods },
1680 {NULL , NULL , 0 }
1683 OOP_AttrBase MetaAttrBase = OOP_GetAttrBase(IID_Meta);
1685 struct TagItem tags[] =
1687 {aMeta_SuperID , (IPTR) CLID_Root },
1688 {aMeta_InterfaceDescr , (IPTR) ifdescr },
1689 {aMeta_InstSize , (IPTR) sizeof(struct fakefb_data) },
1690 {TAG_DONE , 0UL }
1693 OOP_Class *cl = NULL;
1695 if (MetaAttrBase)
1697 cl = OOP_NewObject(NULL, CLID_HiddMeta, tags);
1698 if (NULL != cl)
1699 cl->UserData = GfxBase;
1700 } /* if(MetaAttrBase) */
1702 return cl;
1705 OOP_Object *init_fakegfxhidd(OOP_Object *gfxhidd, struct GfxBase *GfxBase)
1707 struct common_driverdata *csd = CDD(GfxBase);
1709 if (!csd->fakegfxclass)
1711 /* Lazy class initialization */
1712 csd->fakegfxclass = init_fakegfxhiddclass(GfxBase);
1713 csd->fakefbclass = init_fakefbclass(GfxBase);
1715 if (!csd->fakegfxclass || !csd->fakefbclass)
1717 cleanup_fakegfxhidd(GfxBase);
1718 return NULL;
1723 return OOP_NewObjectTags(csd->fakegfxclass, NULL, aHidd_FakeGfxHidd_RealGfxHidd, gfxhidd, TAG_DONE);
1726 VOID cleanup_fakegfxhidd(struct GfxBase *GfxBase)
1728 struct common_driverdata *csd = CDD(GfxBase);
1730 if (NULL != csd->fakefbclass)
1732 OOP_DisposeObject((OOP_Object *)csd->fakefbclass);
1733 csd->fakefbclass = NULL;
1736 if (NULL != csd->fakegfxclass)
1738 OOP_DisposeObject((OOP_Object *)csd->fakegfxclass);
1739 OOP_ReleaseAttrBase(IID_Hidd_FakeFB);
1740 csd->fakegfxclass = NULL;