2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Bitmap class for GDI hidd.
8 Note: this implementation ignores GC_COLMASK. Windows GDI has no way to support it,
9 however color masks seem to be not used anywhere in AROS.
12 /****************************************************************************************/
14 #define __OOP_NOATTRBASES__
20 #include <proto/oop.h>
21 #include <proto/utility.h>
22 #include <exec/alerts.h>
23 #include <aros/macros.h>
24 #include <exec/memory.h>
25 #include <exec/lists.h>
26 #include <graphics/rastport.h>
27 #include <graphics/gfx.h>
29 #include <hidd/graphics.h>
30 #include <aros/symbolsets.h>
35 #include <aros/debug.h>
37 #include LC_LIBDEFS_FILE
43 /****************************************************************************************/
45 #define AO(x) (aoHidd_BitMap_ ## x)
46 #define GOT_BM_ATTR(code) GOT_ATTR(code, aoHidd_BitMap, bitmap)
48 struct bitmapinfo_mono
50 BITMAPINFOHEADER bmiHeader
;
54 static OOP_AttrBase HiddBitMapAttrBase
;
55 static OOP_AttrBase HiddSyncAttrBase
;
56 static OOP_AttrBase HiddPixFmtAttrBase
;
57 static OOP_AttrBase HiddGDIBitMapAB
;
59 static struct OOP_ABDescr attrbases
[] =
61 { IID_Hidd_BitMap
, &HiddBitMapAttrBase
},
62 { IID_Hidd_Sync
, &HiddSyncAttrBase
},
63 { IID_Hidd_PixFmt
, &HiddPixFmtAttrBase
},
65 { IID_Hidd_GDIBitMap
, &HiddGDIBitMapAB
},
69 /****************************************************************************************/
72 #define PRINT_PLANE(bm, n, startx, xlim, ylim) \
74 ULONG start = startx / 8; \
75 ULONG xlimit = xlim / 8; \
76 ULONG ylimit = (ylim < bm.Rows) ? ylim : bm.Rows; \
77 UBYTE *plane = bm.Planes[n] + start; \
81 if (xlimit > (start - bm.BytesPerRow)) \
82 xlimit = start - bm.BytesPerRow; \
83 bug("[GDIBitMap] Plane %u data (%u pixels from %u, address 0x%p):\n", n, xlimit * 8, start * 8, plane); \
84 for (y = 0; y < ylimit; y++) { \
85 for (x = 0; x < xlimit; x++) { \
86 for (i = 0x80; i; i >>= 1) \
87 bug((plane[x] & i) ? "#" : "."); \
90 plane += bm.BytesPerRow; \
94 #define PRINT_MONO_DC(dc, startx, starty, width, height) \
98 bug("[GDIBitMap] Device context data:\n"); \
99 for (y = starty; y < height; y++) { \
100 for (x = startx; x < width; x++) { \
101 ULONG pix = GDICALL(GetPixel, dc, x, y); \
103 bug(pix ? "." : "#"); \
110 #define PRINT_PLANE(bm, n, startx, xlim, ylim)
111 #define PRINT_MONO_DC(dc, startx, starty, width, height)
114 /****************************************************************************************/
116 VOID
GDIBM__Hidd_BitMap__PutPixel(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_PutPixel
*msg
)
118 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
120 DB2(bug("[GDI] hidd.bitmap.gdibitmap::PutPixel(0x%p): (%lu, %lu) = 0x%08lX\n", o
, msg
->x
, msg
->y
, msg
->pixel
));
122 GDICALL(SetROP2
, data
->dc
, R2_COPYPEN
);
123 GDICALL(SetPixel
, data
->dc
, msg
->x
, msg
->y
, msg
->pixel
);
128 /****************************************************************************************/
130 HIDDT_Pixel
GDIBM__Hidd_BitMap__GetPixel(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_GetPixel
*msg
)
132 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
136 pixel
= GDICALL(GetPixel
, data
->dc
, msg
->x
, msg
->y
);
143 /****************************************************************************************/
145 static void FillRect(struct bitmap_data
*data
, ULONG col
, ULONG mode
, ULONG minX
, ULONG minY
, ULONG width
, ULONG height
)
148 DB2(bug("[GDI] Brush color 0x%08lX, mode 0x%08lX\n", col
, mode
));
151 br
= GDICALL(CreateSolidBrush
, col
);
153 orig_br
= GDICALL(SelectObject
, data
->dc
, br
);
154 GDICALL(PatBlt
, data
->dc
, minX
, minY
, width
, height
, mode
);
155 GDICALL(SelectObject
, data
->dc
, orig_br
);
156 GDICALL(DeleteObject
, br
);
161 /* Table of raster operations (ROPs) corresponding to AROS GC drawmodes */
162 static ULONG Fill_DrawModeTable
[] = {
172 0x00A50065, /* PDnx - not sure */
181 VOID
GDIBM__Hidd_BitMap__FillRect(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_DrawRect
*msg
)
183 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
184 ULONG col
= GC_FG(msg
->gc
);
185 ULONG mode
= Fill_DrawModeTable
[GC_DRMD(msg
->gc
)];
187 D(bug("[GDI] hidd.bitmap.gdibitmap::FillRect(0x%p, %d,%d,%d,%d)\n", o
, msg
->minX
, msg
->minY
, msg
->maxX
, msg
->maxY
));
188 FillRect(data
, col
, mode
, msg
->minX
, msg
->minY
, msg
->maxX
- msg
->minX
+ 1, msg
->maxY
- msg
->minY
+ 1);
192 /****************************************************************************************/
194 /* Raster operations for drawing primitives */
195 static ULONG R2_DrawModeTable
[] = {
197 R2_MASKPEN
, /* bitmap AND pen */
198 R2_MASKPENNOT
, /* NOT bitmap AND pen */
199 R2_COPYPEN
, /* pen */
200 R2_MASKNOTPEN
, /* bitmap AND NOT pen */
202 R2_XORPEN
, /* bitmap XOR pen */
203 R2_MERGEPEN
, /* bitmap OR pen */
204 R2_NOTMERGEPEN
, /* NOT (bitmap OR pen) */
205 R2_NOTXORPEN
, /* NOT (bitmap XOR pen) */
206 R2_NOT
, /* NOT bitmap */
207 R2_MERGEPENNOT
, /* NOT bitmap OR pen */
208 R2_NOTCOPYPEN
, /* NOT pen */
209 R2_MERGENOTPEN
, /* NOT pen OR bitmap */
210 R2_NOTMASKPEN
, /* NOT (pen AND bitmap) */
214 ULONG
GDIBM__Hidd_BitMap__DrawPixel(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_DrawPixel
*msg
)
216 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
219 DB2(bug("[GDI] hidd.bitmap.gdibitmap::DrawPixel(0x%p): (%lu, %lu)\n", o
, msg
->x
, msg
->y
));
220 col
= GC_FG(msg
->gc
);
221 mode
= R2_DrawModeTable
[GC_DRMD(msg
->gc
)];
224 GDICALL(SetROP2
, data
->dc
, mode
);
225 GDICALL(SetPixel
, data
->dc
, msg
->x
, msg
->y
, col
);
231 /****************************************************************************************/
233 /* Raster operations for copying a bitmap */
234 ULONG Copy_DrawModeTable
[] = {
236 SRCAND
, /* DSa - src AND dest */
237 SRCERASE
, /* SDna - src AND NOT dest */
238 SRCCOPY
, /* S - src */
239 0x00220326, /* DSna - NOT src AND dest */
240 0x00AA0029, /* D - dest */
241 SRCINVERT
, /* DSx - src XOR dest */
242 SRCPAINT
, /* DSo - src OR dest */
243 NOTSRCERASE
, /* DSon - NOT (src OR dest) */
244 0x00990066, /* DSxn - NOT (src XOR dest) */
245 DSTINVERT
, /* Dn - NOT dest */
246 0x00DD0228, /* SDno - src OR NOT dest */
247 NOTSRCCOPY
, /* Sn - NOT src */
248 MERGEPAINT
, /* DSno - NOT src OR dest */
249 0x007700E6, /* DSan - NOT (src AND dest) */
253 VOID
GDIBM__Hidd_BitMap__PutImage(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_PutImage
*msg
)
255 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
256 HIDDT_PixelFormat
*src_pixfmt
, *dst_pixfmt
;
258 HIDDT_StdPixFmt src_stdpf
;
260 ULONG bufmod
, bufsize
;
261 BITMAPINFOHEADER bitmapinfo
=
263 sizeof(BITMAPINFOHEADER
),
271 /* EnterFunc(bug("GDIGfx.BitMap::PutImage(pa=%p, x=%d, y=%d, w=%d, h=%d)\n",
272 msg->pixels, msg->x, msg->y, msg->width, msg->height));*/
274 switch(msg
->pixFmt
) {
275 case vHidd_StdPixFmt_Native
:
276 case vHidd_StdPixFmt_Native32
:
277 src_stdpf
= vHidd_StdPixFmt_0BGR32_Native
;
280 src_stdpf
= msg
->pixFmt
;
283 bufmod
= msg
->width
* sizeof(HIDDT_Pixel
);
284 bufsize
= bufmod
* msg
->height
;
285 buf
= AllocMem(bufsize
, MEMF_ANY
);
288 ULONG drmd
= GC_DRMD(msg
->gc
);
290 OOP_GetAttr(o
, aHidd_BitMap_GfxHidd
, (IPTR
*)&gfxhidd
);
291 src_pixfmt
= (HIDDT_PixelFormat
*)HIDD_Gfx_GetPixFmt(gfxhidd
, src_stdpf
);
292 /* DIB pixels are expected to be 0x00RRGGBB */
293 dst_pixfmt
= (HIDDT_PixelFormat
*)HIDD_Gfx_GetPixFmt(gfxhidd
, vHidd_StdPixFmt_0RGB32_Native
);
296 HIDD_BM_ConvertPixels(o
, &src
, src_pixfmt
, msg
->modulo
, &dst
, dst_pixfmt
, bufmod
,
297 msg
->width
, msg
->height
, NULL
);
298 bitmapinfo
.biWidth
= msg
->width
;
299 bitmapinfo
.biHeight
= -msg
->height
; /* Minus here means top-down bitmap */
301 GDICALL(StretchDIBits
, data
->dc
, msg
->x
, msg
->y
, msg
->width
, msg
->height
, 0, 0, msg
->width
, msg
->height
, buf
, (BITMAPINFO
*)&bitmapinfo
, DIB_RGB_COLORS
, Copy_DrawModeTable
[drmd
]);
303 FreeMem(buf
, bufsize
);
308 /****************************************************************************************/
310 /* TODO: These little stubs help to detect methods calls */
312 VOID
GDIBM__Hidd_BitMap__PutImageLUT(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_PutImageLUT
*msg
)
314 EnterFunc(bug("GDIGfx.BitMap::PutImageLUT(pa=%p, x=%d, y=%d, w=%d, h=%d)\n",
315 msg
->pixels
, msg
->x
, msg
->y
, msg
->width
, msg
->height
));
317 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
321 VOID
GDIBM__Hidd_BitMap__GetImageLUT(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_GetImageLUT
*msg
)
323 EnterFunc(bug("GDIGfx.BitMap::GetImageLUT(pa=%p, x=%d, y=%d, w=%d, h=%d)\n",
324 msg
->pixels
, msg
->x
, msg
->y
, msg
->width
, msg
->height
));
326 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
330 /****************************************************************************************/
332 VOID
GDIBM__Hidd_BitMap__GetImage(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_GetImage
*msg
)
334 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
335 HIDDT_PixelFormat
*src_pixfmt
, *dst_pixfmt
;
337 HIDDT_StdPixFmt dst_stdpf
;
338 APTR tmp_dc
, tmp_bitmap
, dc_bitmap
;
340 ULONG bufmod
, bufsize
;
341 BITMAPINFOHEADER bitmapinfo
= {
342 sizeof(BITMAPINFOHEADER
),
350 /* EnterFunc(bug("GDIGfx.BitMap::GetImage(pa=%p, x=%d, y=%d, w=%d, h=%d)\n",
351 msg->pixels, msg->x, msg->y, msg->width, msg->height));*/
353 switch(msg
->pixFmt
) {
354 case vHidd_StdPixFmt_Native
:
355 case vHidd_StdPixFmt_Native32
:
356 dst_stdpf
= vHidd_StdPixFmt_0BGR32_Native
;
359 dst_stdpf
= msg
->pixFmt
;
362 bufmod
= msg
->width
* sizeof(HIDDT_Pixel
);
363 bufsize
= bufmod
* msg
->height
;
364 buf
= AllocMem(bufsize
, MEMF_ANY
);
366 /* First we have to extract requested rectangle into temporary bitmap because GetDIBits() can limit only scan lines number */
368 tmp_dc
= GDICALL(CreateCompatibleDC
, data
->display
);
370 tmp_bitmap
= GDICALL(CreateCompatibleBitmap
, data
->display
, msg
->width
, msg
->height
);
372 dc_bitmap
= GDICALL(SelectObject
, tmp_dc
, tmp_bitmap
);
374 GDICALL(BitBlt
, tmp_dc
, 0, 0, msg
->width
, msg
->height
, data
->dc
, msg
->x
, msg
->y
, SRCCOPY
);
375 bitmapinfo
.biWidth
= msg
->width
;
376 bitmapinfo
.biHeight
= -msg
->height
; /* Minus here means top-down bitmap */
377 GDICALL(GetDIBits
, tmp_dc
, tmp_bitmap
, 0, msg
->height
, buf
, (BITMAPINFO
*)&bitmapinfo
, DIB_RGB_COLORS
);
378 GDICALL(SelectObject
, tmp_dc
, dc_bitmap
);
380 GDICALL(DeleteObject
, tmp_bitmap
);
382 GDICALL(DeleteDC
, tmp_dc
);
385 OOP_GetAttr(o
, aHidd_BitMap_GfxHidd
, (IPTR
*)&gfxhidd
);
386 /* DIB pixels will be 0x00RRGGBB) */
387 src_pixfmt
= (HIDDT_PixelFormat
*)HIDD_Gfx_GetPixFmt(gfxhidd
, vHidd_StdPixFmt_0RGB32_Native
);
388 dst_pixfmt
= (HIDDT_PixelFormat
*)HIDD_Gfx_GetPixFmt(gfxhidd
, dst_stdpf
);
391 HIDD_BM_ConvertPixels(o
, &src
, src_pixfmt
, bufmod
, &dst
, dst_pixfmt
, msg
->modulo
,
392 msg
->width
, msg
->height
, NULL
);
393 FreeMem(buf
, bufsize
);
398 /****************************************************************************************/
400 VOID
GDIBM__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
402 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
405 if (IS_GDIBM_ATTR(msg
->attrID
, idx
)) {
408 case aoHidd_GDIBitMap_DeviceContext
:
409 *msg
->storage
= (IPTR
)data
->dc
;
412 } else if (IS_BM_ATTR(msg
->attrID
, idx
)) {
415 case aoHidd_BitMap_LeftEdge
:
416 *msg
->storage
= data
->bm_left
;
418 case aoHidd_BitMap_TopEdge
:
419 *msg
->storage
= data
->bm_top
;
423 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
426 /****************************************************************************************/
428 VOID
GDIBM__Root__Set(OOP_Class
*cl
, OOP_Object
*obj
, struct pRoot_Set
*msg
)
430 struct bitmap_data
*data
= OOP_INST_DATA(cl
, obj
);
431 struct TagItem
*tag
, *tstate
;
433 BOOL change_position
= FALSE
;
435 tstate
= msg
->attrList
;
436 while((tag
= NextTagItem(&tstate
)))
438 if (IS_BM_ATTR(tag
->ti_Tag
, idx
)) {
441 case aoHidd_BitMap_LeftEdge
:
442 data
->bm_left
= tag
->ti_Data
;
443 change_position
= TRUE
;
445 case aoHidd_BitMap_TopEdge
:
446 data
->bm_top
= tag
->ti_Data
;
447 change_position
= TRUE
;
453 if (change_position
) {
454 /* Fix up position. We can completely scroll out
455 of our window into all 4 sides, but not more */
456 if (data
->bm_left
> data
->win_width
)
457 data
->bm_left
= data
->win_width
;
458 else if (data
->bm_left
< -data
->bm_width
)
459 data
->bm_left
= -data
->bm_width
;
460 if (data
->bm_top
> data
->win_height
)
461 data
->bm_top
= data
->win_height
;
462 else if (data
->bm_top
< -data
->bm_height
)
463 data
->bm_top
= -data
->bm_height
;
467 USERCALL(SetWindowPos
, data
->window
, NULL
, data
->bm_left
- 1, data
->bm_top
- 1, 0, 0, SWP_NOSIZE
|SWP_NOZORDER
);
471 OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
474 /****************************************************************************************/
476 OOP_Object
*GDIBM__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
478 OOP_Object
*friend = NULL
, *pixfmt
;
479 APTR display
, my_dc
, my_bitmap
= NULL
;
480 APTR orig_bitmap
= NULL
;
486 IPTR attrs
[num_Hidd_BitMap_Attrs
];
487 struct bitmap_data
*data
;
489 DECLARE_ATTRCHECK(bitmap
);
491 EnterFunc(bug("GDIBM::New()\n"));
492 /* Parse the attributes */
493 if (0 != OOP_ParseAttrs(msg
->attrList
, attrs
, num_Hidd_BitMap_Attrs
,
494 &ATTRCHECK(bitmap
), HiddBitMapAttrBase
))
496 D(kprintf("!!! GDIGfx::BitMap() FAILED TO PARSE ATTRS !!!\n"));
501 if (GOT_BM_ATTR(Friend
))
502 friend = (OOP_Object
*)attrs
[AO(Friend
)];
506 width
= attrs
[AO(Width
)];
507 height
= attrs
[AO(Height
)];
508 pixfmt
= (OOP_Object
*)attrs
[AO(PixFmt
)];
510 OOP_GetAttr(pixfmt
, aHidd_PixFmt_Depth
, &depth
);
512 /* Get the device context from the friend bitmap */
516 OOP_GetAttr(friend, aHidd_GDIBitMap_Drawable
, (IPTR
*)&friend_drawable
);
519 (void)friend; // Unused
522 D(bug("Creating GDI bitmap: %ldx%ldx%ld\n", width
, height
, depth
));
523 display
= (APTR
)GetTagData(aHidd_GDIBitMap_SysDisplay
, 0, msg
->attrList
);
524 modeid
= (HIDDT_ModeID
)GetTagData(aHidd_BitMap_ModeID
, vHidd_ModeID_Invalid
, msg
->attrList
);
525 /* This relies on the fact that bitmaps with aHidd_BitMap_Displayable set to TRUE always
526 also get aHidd_BitMap_ModeID with valid value. Currently this seems to be true and i
527 beleive it should stay so */
528 if (modeid
!= vHidd_ModeID_Invalid
) {
529 OOP_Object
*gfx
= (OOP_Object
*)attrs
[AO(GfxHidd
)];
530 OOP_Object
*sync
, *pixfmt
;
532 D(bug("[GDI] Display driver object: 0x%p\n", gfx
));
533 HIDD_Gfx_GetMode(gfx
, modeid
, &sync
, &pixfmt
);
534 OOP_GetAttr(sync
, aHidd_Sync_HDisp
, &win_width
);
535 OOP_GetAttr(sync
, aHidd_Sync_VDisp
, &win_height
);
536 D(bug("[GDI] Display window size: %dx%d\n", win_width
, win_height
));
540 my_dc
= GDICALL(CreateCompatibleDC
, display
);
541 D(bug("[GDI] Memory device context: 0x%p\n", my_dc
));
543 my_bitmap
= GDICALL(CreateCompatibleBitmap
, display
, (width
+ 15) & ~15, height
);
544 D(bug("[GDI] Memory bitmap: 0x%p\n", my_bitmap
));
546 orig_bitmap
= GDICALL(SelectObject
, my_dc
, my_bitmap
);
547 D(bug("[GDI] Olriginal DC bitmap: 0x%p\n", orig_bitmap
));
556 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
557 D(bug("[GDI] Object created by superclass: 0x%p\n", o
));
559 data
= OOP_INST_DATA(cl
, o
);
560 /* Get some info passed to us by the gdigfxhidd class */
562 data
->bitmap
= my_bitmap
;
563 data
->dc_bitmap
= orig_bitmap
;
564 data
->display
= display
;
566 data
->win_width
= win_width
;
567 data
->win_height
= win_height
;
568 data
->bm_width
= width
;
569 data
->bm_height
= height
;
573 ReturnPtr("GDIGfx.BitMap::New()", OOP_Object
*, o
);
574 } /* if (object allocated by superclass) */
578 GDICALL(SelectObject
, my_dc
, orig_bitmap
);
580 GDICALL(DeleteObject
, my_bitmap
);
581 GDICALL(DeleteDC
, my_dc
);
584 ReturnPtr("GDIGfx.BitMap::New()", OOP_Object
*, NULL
);
588 /****************************************************************************************/
590 VOID
GDIBM__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
592 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
594 EnterFunc(bug("GDIGfx.BitMap::Dispose()\n"));
597 if (data
->node
.mln_Pred
)
598 Remove((struct Node
*)data
);
600 NATIVECALL(GDI_PutMsg
, data
->window
, WM_CLOSE
, 0, 0);
602 GDICALL(SelectObject
, data
->dc
, data
->dc_bitmap
);
604 GDICALL(DeleteObject
, data
->bitmap
);
606 GDICALL(DeleteDC
, data
->dc
);
609 OOP_DoSuperMethod(cl
, o
, msg
);
612 ReturnVoid("GDIGfx.BitMap::Dispose");
615 /****************************************************************************************/
617 VOID
GDIBM__Hidd_BitMap__Clear(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_Clear
*msg
)
619 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
622 EnterFunc(bug("[GDI] hidd.bitmap.gdibitmap::Clear()\n"));
624 /* Get width & height from bitmap superclass */
626 OOP_GetAttr(o
, aHidd_BitMap_Width
, &width
);
627 OOP_GetAttr(o
, aHidd_BitMap_Height
, &height
);
629 FillRect(data
, GC_BG(msg
->gc
), PATCOPY
, 0, 0, width
, height
);
632 /****************************************************************************************/
634 VOID
GDIBM__Hidd_BitMap__UpdateRect(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_BitMap_UpdateRect
*msg
)
636 struct bitmap_data
*data
= OOP_INST_DATA(cl
, o
);
647 USERCALL(RedrawWindow
, data
->window
, &r
, NULL
, RDW_INVALIDATE
|RDW_UPDATENOW
);
652 /****************************************************************************************/
654 static int GDIBM_Init(LIBBASETYPEPTR LIBBASE
)
656 return OOP_ObtainAttrBases(attrbases
);
659 /****************************************************************************************/
661 static int GDIBM_Expunge(LIBBASETYPEPTR LIBBASE
)
663 OOP_ReleaseAttrBases(attrbases
);
667 /****************************************************************************************/
669 ADD2INITLIB(GDIBM_Init
, 0);
670 ADD2EXPUNGELIB(GDIBM_Expunge
, 0);