2 * sdl.hidd - SDL graphics/sound/keyboard for AROS hosted
3 * Copyright (c) 2007 Robert Norris. All rights reserved.
4 * Copyright (c) 2010-2015 The AROS Development Team. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the same terms as AROS itself.
10 #include <hidd/hidd.h>
11 #include <hidd/graphics.h>
12 #include <utility/tagitem.h>
15 #include <proto/alib.h>
16 #include <proto/exec.h>
17 #include <proto/oop.h>
18 #include <proto/utility.h>
27 #include "sdl_intern.h"
30 #include <aros/debug.h>
32 #define LIBBASE (&xsd)
34 static const SDL_Rect mode_1600_1200
= { .w
= 1600, .h
= 1200 };
35 static const SDL_Rect mode_1280_1024
= { .w
= 1280, .h
= 1024 };
36 static const SDL_Rect mode_1280_960
= { .w
= 1280, .h
= 960 };
37 static const SDL_Rect mode_1152_864
= { .w
= 1152, .h
= 864 };
38 static const SDL_Rect mode_1024_768
= { .w
= 1024, .h
= 768 };
39 static const SDL_Rect mode_800_600
= { .w
= 800, .h
= 600 };
41 static const SDL_Rect
*default_modes
[] = {
51 OOP_Object
*SDLGfx__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
) {
52 const SDL_VideoInfo
*info
;
53 const SDL_PixelFormat
*pixfmt
;
55 char driver
[128] = "";
58 const SDL_Rect
**modes
;
59 struct TagItem
*pftags
= NULL
;
62 struct TagItem
**synctags
, *modetags
, *msgtags
;
63 struct pRoot_New supermsg
;
66 S(SDL_VideoDriverName
, driver
, sizeof(driver
));
67 kprintf("sdlgfx: using %s driver\n", driver
);
69 info
= SP(SDL_GetVideoInfo
);
71 D(bug("[sdl] window manager: %savailable\n", info
->wm_available
? "" : "not "));
72 D(bug("[sdl] hardware surfaces: %savailable\n", info
->hw_available
? "" : "not "));
74 LIBBASE
->use_hwsurface
= info
->hw_available
? TRUE
: FALSE
;
75 surftype
= LIBBASE
->use_hwsurface
? SDL_HWSURFACE
: SDL_SWSURFACE
;
77 D(bug("[sdl] colour model: %s\n", pixfmt
->palette
== NULL
? "truecolour" : "palette"));
78 if (pixfmt
->palette
== NULL
) {
79 D(bug("[sdl] colour mask: alpha=0x%08x red=0x%08x green=0x%08x blue=0x%08x\n", pixfmt
->Amask
, pixfmt
->Rmask
, pixfmt
->Gmask
, pixfmt
->Bmask
, pixfmt
->Amask
));
80 D(bug("[sdl] colour shift: alpha=%d red=%d green=%d blue=%d\n", pixfmt
->Ashift
, pixfmt
->Rshift
, pixfmt
->Gshift
, pixfmt
->Bshift
, pixfmt
->Ashift
));
83 if (pixfmt
->palette
!= NULL
) {
84 /* XXX deal with palette (CLUT) modes */
88 /* select an appropriate AROS pixel format based on the SDL format */
89 int stdpixfmt
= vHidd_StdPixFmt_Unknown
;
90 int alpha_shift
, red_shift
, green_shift
, blue_shift
;
92 if (pixfmt
->BitsPerPixel
== 32) {
93 if (pixfmt
->Amask
== 0x000000ff && pixfmt
->Rmask
== 0x0000ff00 &&
94 pixfmt
->Gmask
== 0x00ff0000 && pixfmt
->Bmask
== 0xff000000) {
95 stdpixfmt
= vHidd_StdPixFmt_ARGB32
;
102 else if (pixfmt
->Amask
== 0xff000000 && pixfmt
->Rmask
== 0x00ff0000 &&
103 pixfmt
->Gmask
== 0x0000ff00 && pixfmt
->Bmask
== 0x000000ff) {
104 stdpixfmt
= vHidd_StdPixFmt_BGRA32
;
111 else if (pixfmt
->Amask
== 0xff000000 && pixfmt
->Rmask
== 0x000000ff &&
112 pixfmt
->Gmask
== 0x0000ff00 && pixfmt
->Bmask
== 0x00ff0000) {
113 stdpixfmt
= vHidd_StdPixFmt_RGBA32
;
120 else if (pixfmt
->Amask
== 0x000000ff && pixfmt
->Rmask
== 0xff000000 &&
121 pixfmt
->Gmask
== 0x00ff0000 && pixfmt
->Bmask
== 0x0000ff00) {
122 stdpixfmt
= vHidd_StdPixFmt_ABGR32
;
129 else if (pixfmt
->Amask
== 0x00000000 && pixfmt
->Rmask
== 0x0000ff00 &&
130 pixfmt
->Gmask
== 0x00ff0000 && pixfmt
->Bmask
== 0xff000000) {
131 stdpixfmt
= vHidd_StdPixFmt_0RGB32
;
138 else if (pixfmt
->Amask
== 0x00000000 && pixfmt
->Rmask
== 0x00ff0000 &&
139 pixfmt
->Gmask
== 0x0000ff00 && pixfmt
->Bmask
== 0x000000ff) {
140 stdpixfmt
= vHidd_StdPixFmt_BGR032
;
147 else if (pixfmt
->Amask
== 0x00000000 && pixfmt
->Rmask
== 0x000000ff &&
148 pixfmt
->Gmask
== 0x0000ff00 && pixfmt
->Bmask
== 0x00ff0000) {
149 stdpixfmt
= vHidd_StdPixFmt_RGB032
;
156 else if (pixfmt
->Amask
== 0x00000000 && pixfmt
->Rmask
== 0xff000000 &&
157 pixfmt
->Gmask
== 0x00ff0000 && pixfmt
->Bmask
== 0x0000ff00) {
158 stdpixfmt
= vHidd_StdPixFmt_0BGR32
;
166 else if (pixfmt
->BitsPerPixel
== 24) {
168 vHidd_StdPixFmt_RGB24
169 vHidd_StdPixFmt_BGR24
173 else if (pixfmt
->BitsPerPixel
== 16) {
175 vHidd_StdPixFmt_RGB16
176 vHidd_StdPixFmt_RGB16_LE
177 vHidd_StdPixFmt_BGR16
178 vHidd_StdPixFmt_BGR16_LE
182 else if (pixfmt
->BitsPerPixel
== 15) {
184 vHidd_StdPixFmt_RGB15,
185 vHidd_StdPixFmt_RGB15_LE,
186 vHidd_StdPixFmt_BGR15,
187 vHidd_StdPixFmt_BGR15_LE,
191 if (stdpixfmt
== vHidd_StdPixFmt_Unknown
) {
192 stdpixfmt
= vHidd_StdPixFmt_Native
;
193 alpha_shift
= pixfmt
->Ashift
;
194 red_shift
= pixfmt
->Rshift
;
195 green_shift
= pixfmt
->Gshift
;
196 blue_shift
= pixfmt
->Bshift
;
199 D(bug("[sdl] selected pixel format %d\n", stdpixfmt
));
202 aHidd_PixFmt_ColorModel
, vHidd_ColorModel_TrueColor
,
203 aHidd_PixFmt_RedShift
, red_shift
,
204 aHidd_PixFmt_GreenShift
, green_shift
,
205 aHidd_PixFmt_BlueShift
, blue_shift
,
206 aHidd_PixFmt_AlphaShift
, alpha_shift
,
207 aHidd_PixFmt_RedMask
, pixfmt
->Rmask
,
208 aHidd_PixFmt_GreenMask
, pixfmt
->Gmask
,
209 aHidd_PixFmt_BlueMask
, pixfmt
->Bmask
,
210 aHidd_PixFmt_AlphaMask
, pixfmt
->Amask
,
211 aHidd_PixFmt_Depth
, pixfmt
->BitsPerPixel
,
212 aHidd_PixFmt_BitsPerPixel
, pixfmt
->BitsPerPixel
,
213 aHidd_PixFmt_BytesPerPixel
, pixfmt
->BytesPerPixel
,
214 aHidd_PixFmt_StdPixFmt
, stdpixfmt
,
215 aHidd_PixFmt_BitMapType
, vHidd_BitMapType_Chunky
219 modes
= SP(SDL_ListModes
, NULL
, surftype
| LIBBASE
->use_fullscreen
? SDL_FULLSCREEN
: 0);
220 D(bug("[sdl] available modes:"));
226 if (modes
== (const SDL_Rect
**) -1) {
227 D(bug(" (default)"));
228 modes
= default_modes
;
230 for (nmodes
= 0; modes
[nmodes
] != NULL
&& modes
[nmodes
]->w
!= 0; nmodes
++)
231 D(bug(" %dx%d", modes
[nmodes
]->w
, modes
[nmodes
]->h
));
235 D(bug("[sdl] building %d mode sync items\n", nmodes
));
237 tagpool
= CreatePool(MEMF_CLEAR
, 1024, 128);
239 synctags
= AllocPooled(tagpool
, sizeof(struct TagItem
*) * (nmodes
+1));
241 for (i
= 0; i
< nmodes
; i
++) {
242 /* remove modes larger than the current screen res */
243 if (modes
[i
]->w
> info
->current_w
|| modes
[i
]->h
> info
->current_h
) {
248 synctags
[i
] = AllocPooled(tagpool
, sizeof(struct TagItem
) * 4);
249 synctags
[i
][0].ti_Tag
= aHidd_Sync_HDisp
; synctags
[i
][0].ti_Data
= modes
[i
]->w
;
250 synctags
[i
][1].ti_Tag
= aHidd_Sync_VDisp
; synctags
[i
][1].ti_Data
= modes
[i
]->h
;
251 synctags
[i
][2].ti_Tag
= aHidd_Sync_Description
; synctags
[i
][2].ti_Data
= (IPTR
)"SDL:%hx%v";
252 synctags
[i
][3].ti_Tag
= TAG_DONE
;
255 modetags
= AllocPooled(tagpool
, sizeof(struct TagItem
) * (nmodes
+2));
257 modetags
[0].ti_Tag
= aHidd_Gfx_PixFmtTags
; modetags
[0].ti_Data
= (IPTR
) pftags
;
259 for (i
= 0; i
< nmodes
; i
++) {
260 if (synctags
[i
] == NULL
) {
261 modetags
[1+i
].ti_Tag
= TAG_IGNORE
;
265 modetags
[1+i
].ti_Tag
= aHidd_Gfx_SyncTags
;
266 modetags
[1+i
].ti_Data
= (IPTR
) synctags
[i
];
269 modetags
[1+i
].ti_Tag
= TAG_DONE
;
272 aHidd_Gfx_ModeTags
, (IPTR
)modetags
,
273 aHidd_Name
, (IPTR
)"sdl.monitor",
274 aHidd_HardwareName
, (IPTR
)"Simple DirectMedia Layer",
275 aHidd_ProducerName
, (IPTR
)"SDL development team (http://libsdl.org/credits.php)",
276 TAG_MORE
, (IPTR
)msg
->attrList
279 supermsg
.mID
= msg
->mID
;
280 supermsg
.attrList
= msgtags
;
282 D(bug("[sdl] hidd tags built, calling supermethod\n"));
284 o
= (OOP_Object
*) OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) &supermsg
);
289 D(bug("[sdl] supermethod failed, bailing out\n"));
293 return (OOP_Object
*) o
;
296 VOID
SDLGfx__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
) {
299 D(bug("[sdl] SDLGfx::Dispose\n"));
301 s
= SP(SDL_GetVideoSurface
);
303 D(bug("[sdl] freeing existing video surface\n"));
304 SV(SDL_FreeSurface
, s
);
307 OOP_DoSuperMethod(cl
, o
, msg
);
312 VOID
SDLGfx__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
316 if (IS_GFX_ATTR(msg
->attrID
, idx
))
320 case aoHidd_Gfx_IsWindowed
:
321 *msg
->storage
= TRUE
;
324 case aoHidd_Gfx_DriverName
:
325 *msg
->storage
= (IPTR
)"SDL";
329 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
332 VOID
SDLGfx__Root__Set(OOP_Class
*cl
, OOP_Object
*obj
, struct pRoot_Set
*msg
)
334 struct TagItem
*tag
, *tstate
;
337 tstate
= msg
->attrList
;
338 while((tag
= NextTagItem(&tstate
)))
340 if (IS_GFX_ATTR(tag
->ti_Tag
, idx
)) {
343 case aoHidd_Gfx_ActiveCallBack
:
344 xsd
.cb
= (void *)tag
->ti_Data
;
347 case aoHidd_Gfx_ActiveCallBackData
:
348 xsd
.cbdata
= (void *)tag
->ti_Data
;
353 OOP_DoSuperMethod(cl
, obj
, (OOP_Msg
)msg
);
356 OOP_Object
*SDLGfx__Hidd_Gfx__CreateObject(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_CreateObject
*msg
) {
357 OOP_Object
*object
= NULL
;
359 if (msg
->cl
== LIBBASE
->basebm
)
361 struct TagItem
*msgtags
;
362 struct pHidd_Gfx_CreateObject supermsg
;
363 struct gfxdata
*data
= OOP_INST_DATA(cl
, o
);
365 D(bug("[sdl] SDLGfx::CreateObject, UtilityBase is 0x%p\n", UtilityBase
));
367 if (GetTagData(aHidd_BitMap_ModeID
, vHidd_ModeID_Invalid
, msg
->attrList
) != vHidd_ModeID_Invalid
) {
368 D(bug("[sdl] bitmap with valid mode, we can handle it\n"));
371 aHidd_BitMap_ClassPtr
, (IPTR
) LIBBASE
->bmclass
,
372 TAG_MORE
, (IPTR
) msg
->attrList
374 D(bug("[sdl] ClassPtr is 0x%p\n", LIBBASE
->bmclass
));
376 msgtags
= msg
->attrList
;
378 supermsg
.mID
= msg
->mID
;
379 supermsg
.cl
= msg
->cl
;
380 supermsg
.attrList
= msgtags
;
382 D(bug("[sdl] Calling DoSuperMethod()\n"));
383 object
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) &supermsg
);
385 if (GetTagData(aHidd_BitMap_FrameBuffer
, FALSE
, msg
->attrList
))
386 data
->framebuffer
= object
;
388 D(bug("[sdl] Created bitmap 0x%p\n", object
));
391 object
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
396 VOID
SDLGfx__Hidd_Gfx__CopyBox(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_CopyBox
*msg
) {
397 struct SDL_Surface
*src
= NULL
;
398 struct SDL_Surface
*dest
= NULL
;
399 struct SDL_Rect srect
, drect
;
401 D(bug("[sdl] SDLGfx::CopyBox\n"));
403 OOP_GetAttr(msg
->src
, aHidd_SDLBitMap_Surface
, (IPTR
*)&src
);
404 OOP_GetAttr(msg
->dest
, aHidd_SDLBitMap_Surface
, (IPTR
*)&dest
);
406 if (src
== NULL
|| dest
== NULL
) {
407 D(bug("[sdl] missing a surface: src is 0x%08x, dest is 0x%08x. letting the superclass deal with it\n", src
, dest
));
409 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
416 srect
.w
= msg
->width
;
417 srect
.h
= msg
->height
;
419 drect
.x
= msg
->destX
;
420 drect
.y
= msg
->destY
;
422 D(bug("[sdl] blitting %dx%d rect from src 0x%08x [%d,%d] to dest 0x%08x [%d,%d]\n", msg
->width
, msg
->height
, src
, msg
->srcX
, msg
->srcY
, dest
, msg
->destX
, msg
->destY
));
424 S(SDL_BlitSurface
, src
, &srect
, dest
, &drect
);
429 OOP_Object
*SDLGfx__Hidd_Gfx__Show(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_Show
*msg
)
431 struct gfxdata
*data
= OOP_INST_DATA(cl
, o
);
432 struct pHidd_Gfx_Show mymsg
= {msg
->mID
, msg
->bitMap
, 0};
435 /* Resetting SDL onscreen surface will destroy its old contents.
436 Copy back old bitmap data if there's one and if asked to do so */
437 if (data
->shownbm
&& (msg
->flags
& fHidd_Gfx_Show_CopyBack
)) {
441 OOP_GetAttr(data
->framebuffer
, aHidd_BitMap_Width
, &width
);
442 OOP_GetAttr(data
->framebuffer
, aHidd_BitMap_Height
, &height
);
444 OOP_GetAttr(data
->framebuffer
, aHidd_BitMap_ColorMap
, (IPTR
*)&colmap
);
445 OOP_GetAttr(colmap
, aHidd_ColorMap_NumEntries
, &numentries
);
447 /* We need also to copy colormap (palette) */
448 for (i
= 0; i
< numentries
; i
++) {
451 HIDD_CM_GetColor(colmap
, i
, &col
);
452 HIDD_BM_SetColors(data
->shownbm
, &col
, i
, 1);
455 /* Our CopyBox() happily ignores the GC, so set it to NULL and don't bother */
456 HIDD_Gfx_CopyBox(o
, data
->framebuffer
, 0, 0, data
->shownbm
, 0, 0, width
, height
, NULL
);
459 /* Set up new onscreen surface if there's a new bitmap to show.
460 This will change resolution */
462 HIDDT_ModeID modeid
= vHidd_ModeID_Invalid
;
464 OOP_Object
*sync
, *pixfmt
;
466 struct TagItem bmtags
[] = {
467 {aHidd_SDLBitMap_Surface
, 0},
468 {aHidd_BitMap_Width
, 0},
469 {aHidd_BitMap_Height
, 0},
470 {aHidd_BitMap_PixFmt
, 0},
474 /* Ask ModeID from our bitmap */
475 OOP_GetAttr(msg
->bitMap
, aHidd_BitMap_ModeID
, &modeid
);
476 if (modeid
== vHidd_ModeID_Invalid
)
479 HIDD_Gfx_GetMode(o
, modeid
, &sync
, &pixfmt
);
480 OOP_GetAttr(sync
, aHidd_Sync_HDisp
, &width
);
481 OOP_GetAttr(sync
, aHidd_Sync_VDisp
, &height
);
482 OOP_GetAttr(pixfmt
, aHidd_PixFmt_Depth
, &depth
);
484 /* Set up new onscreen surface */
485 s
= SP(SDL_SetVideoMode
, width
, height
, depth
,
486 (LIBBASE
->use_hwsurface
? SDL_HWSURFACE
| SDL_HWPALETTE
: SDL_SWSURFACE
) |
487 (LIBBASE
->use_fullscreen
? SDL_FULLSCREEN
: 0) |
492 /* Tell new parameters to the framebuffer object */
493 bmtags
[0].ti_Data
= (IPTR
)s
;
494 bmtags
[1].ti_Data
= width
;
495 bmtags
[2].ti_Data
= height
;
496 bmtags
[3].ti_Data
= (IPTR
)pixfmt
;
497 OOP_SetAttrs(data
->framebuffer
, bmtags
);
500 data
->shownbm
= msg
->bitMap
;
502 /* Framebuffer contents has been destroyed, so call superclass without fHidd_Gfx_Show_CopyBack */
503 return (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)&mymsg
);
506 static struct OOP_MethodDescr SDLGfx_Root_descr
[] = {
507 {(OOP_MethodFunc
)SDLGfx__Root__New
, moRoot_New
},
508 {(OOP_MethodFunc
)SDLGfx__Root__Dispose
, moRoot_Dispose
},
509 {(OOP_MethodFunc
)SDLGfx__Root__Get
, moRoot_Get
},
510 {(OOP_MethodFunc
)SDLGfx__Root__Set
, moRoot_Set
},
513 #define NUM_SDLGfx_Root_METHODS 4
515 static struct OOP_MethodDescr SDLGfx_Hidd_Gfx_descr
[] = {
516 {(OOP_MethodFunc
)SDLGfx__Hidd_Gfx__CreateObject
, moHidd_Gfx_CreateObject
},
517 {(OOP_MethodFunc
)SDLGfx__Hidd_Gfx__Show
, moHidd_Gfx_Show
},
518 {(OOP_MethodFunc
)SDLGfx__Hidd_Gfx__CopyBox
, moHidd_Gfx_CopyBox
},
521 #define NUM_SDLGfx_Hidd_Gfx_METHODS 3
523 struct OOP_InterfaceDescr SDLGfx_ifdescr
[] = {
524 {SDLGfx_Root_descr
, IID_Root
, NUM_SDLGfx_Root_METHODS
},
525 {SDLGfx_Hidd_Gfx_descr
, IID_Hidd_Gfx
, NUM_SDLGfx_Hidd_Gfx_METHODS
},