1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Simple DirectMedia Layer
19 cflags exec
("sdl-config", "--cflags")
20 ldflags
(exec
("sdl-config", "--libs"), "-lSDL_image -lSDL_ttf")
29 #include <SDL/SDL_syswm.h>
30 #include <SDL/SDL_image.h>
31 #include <SDL/SDL_ttf.h>
34 # Represent a screen surface
35 extern class SDLDisplay `{SDL_Surface *`}
38 redef type I: SDLImage
40 # Initialize a surface with width and height
41 new (w, h: Int) import enable_mouse_motion_events `{
42 SDL_Init(SDL_INIT_VIDEO);
45 printf
("TTF_Init: %s\n", TTF_GetError());
49 SDL_Surface *self = SDL_SetVideoMode(w
, h
, 24, SDL_HWSURFACE);
51 if (!SDLDisplay_enable_mouse_motion_events(self)) {
52 /* ignores mousemotion
for performance reasons
*/
53 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
59 # Indicates wether we want the SDL mouse motion event (or only clicks).
60 # Disabled by defaut for performance reason. To activate, redef this method
62 fun enable_mouse_motion_events: Bool do return false
66 if (SDL_WasInit(SDL_INIT_VIDEO))
73 redef fun finish `{ SDL_Flip(self); `}
75 # Clear the entire window with given RGB color (integer values)
76 fun clear_int
(r
, g
, b
: Int) `{
77 SDL_FillRect(self, NULL, SDL_MapRGB(self->format,r,g,b));
80 redef fun width
`{ return self->w; `}
81 redef fun height `{ return self->h; `}
83 # Fill a rectangle with given color
84 fun fill_rect
(rect
: SDLRectangle, r
, g
, b
: Int) `{
85 SDL_FillRect(self, rect, SDL_MapRGB(self->format,r,g,b));
88 redef fun clear
(r
, g
, b
) `{
93 SDL_FillRect(self, NULL, SDL_MapRGB(self->format,ri,gi,bi));
96 # SDL events since the last call to this method
97 fun events
: Sequence[SDLInputEvent]
99 var events
= new Array[SDLInputEvent]
101 var new_event
= poll_event
102 if new_event
== null then break
108 private fun poll_event
: nullable SDLInputEvent import SDLKeyEvent, SDLMouseButtonEvent, SDLMouseMotionEvent, SDLQuitEvent, NativeString.to_s
, SDLMouseButtonEvent.as(nullable SDLInputEvent), SDLMouseMotionEvent.as(nullable SDLInputEvent), SDLKeyEvent.as(nullable SDLInputEvent), SDLQuitEvent.as(nullable SDLInputEvent) `{
113 if (SDL_PollEvent(&event))
115 switch (event.type) {
119 printf("The \"%s\" key was pressed!\n",
120 SDL_GetKeyName(event.key.keysym.sym));
123 return SDLKeyEvent_as_nullable_SDLInputEvent(
124 new_SDLKeyEvent(NativeString_to_s(
125 SDL_GetKeyName(event.key.keysym.sym)),
126 event.type==SDL_KEYDOWN));
128 case SDL_MOUSEMOTION:
130 printf("Mouse moved by %d,%d to (%d,%d)\n",
131 event.motion.xrel, event.motion.yrel,
132 event.motion.x, event.motion.y);
135 return SDLMouseMotionEvent_as_nullable_SDLInputEvent(
136 new_SDLMouseMotionEvent(event.motion.x, event.motion.y,
137 event.motion.xrel, event.motion.yrel, SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1)));
139 case SDL_MOUSEBUTTONDOWN:
140 case SDL_MOUSEBUTTONUP:
142 printf("Mouse button \"%d\" pressed at (%d,%d)\n",
143 event.button.button, event.button.x, event.button.y);
145 return SDLMouseButtonEvent_as_nullable_SDLInputEvent(
146 new_SDLMouseButtonEvent(event.button.x, event.button.y,
147 event.button.button, event.type == SDL_MOUSEBUTTONDOWN));
151 printf("Quit event\n");
153 return SDLQuitEvent_as_nullable_SDLInputEvent(new_SDLQuitEvent());
157 return null_SDLInputEvent();
160 # Set the position of the cursor to x,y
161 fun warp_mouse
(x
,y
: Int) `{ SDL_WarpMouse(x, y); `}
163 # Show or hide the cursor
164 fun show_cursor=(val: Bool) `{ SDL_ShowCursor(val? SDL_ENABLE: SDL_DISABLE); `}
166 # Is the cursor visible?
167 fun show_cursor
: Bool `{ return SDL_ShowCursor(SDL_QUERY); `}
169 # Grab or release the input
170 fun grab_input=(val: Bool) `{ SDL_WM_GrabInput(val? SDL_GRAB_ON: SDL_GRAB_OFF); `}
172 # Is the input grabbed?
173 fun grab_input
: Bool `{ return SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON; `}
175 # Are instances of `SDLMouseMotionEvent` ignored?
176 fun ignore_mouse_motion_events: Bool `{
177 return SDL_EventState(SDL_MOUSEMOTION, SDL_QUERY);
180 # Do not raise instances of `SDLMouseMotionEvent` if `val
`
181 fun ignore_mouse_motion_events=(val: Bool) `{
182 SDL_EventState(SDL_MOUSEMOTION, val
? SDL_IGNORE: SDL_ENABLE);
185 # Does `self` has the mouse focus?
186 fun mouse_focus: Bool `{ return SDL_GetAppState() & SDL_APPMOUSEFOCUS; `}
188 # Does `self` has the input focus?
189 fun input_focus
: Bool `{ return SDL_GetAppState() & SDL_APPINPUTFOCUS; `}
192 # Basic Drawing figures
193 extern class SDLDrawable `{SDL_Surface*`}
196 redef type I
: SDLImage
198 redef fun blit
(img
, x
, y
) do native_blit
(img
, x
.to_i
, y
.to_i
)
199 private fun native_blit
(img
: I
, x
, y
: Int) `{
206 SDL_BlitSurface(img, NULL, self, &dst);
209 redef fun blit_centered
(img
, x
, y
)
211 x
= x
- img
.width
/ 2
212 y
= y
- img
.height
/ 2
218 extern class SDLImage
222 # Import image from a file
223 new from_file
(path
: String) import String.to_cstring
`{
224 SDL_Surface *image = IMG_Load(String_to_cstring(path));
228 # Copy of an existing SDLImage
229 new copy_of
(image
: SDLImage) `{
230 SDL_Surface *new_image = SDL_CreateRGBSurface(
231 image->flags, image->w, image->h, 24,
239 SDL_BlitSurface(image, NULL, new_image, &dst);
244 # Save the image into the specified file
245 fun save_to_file
(path
: String) import String.to_cstring
`{ `}
247 # Destroy the image and free the memory
248 redef fun destroy `{ SDL_FreeSurface(self); `}
250 redef fun width
`{ return self->w; `}
251 redef fun height `{ return self->h; `}
253 fun is_ok
: Bool do return not address_is_null
255 # Returns a reference to the pixels of the texture
256 fun pixels
: NativeCByteArray `{ return self->pixels; `}
258 # Mask for the alpha value of each pixel
259 fun amask: Int `{ return self->format->Amask; `}
263 extern class SDLRectangle `{SDL_Rect*`}
264 # Constructor with x,y positions width and height of the rectangle
265 new (x: Int, y: Int, w: Int, h: Int) `{
266 SDL_Rect *rect
= malloc
(sizeof
(SDL_Rect));
274 fun x=(v: Int) `{ self->x = (Sint16)v; `}
275 fun x
: Int `{ return self->x; `}
277 fun y=(v: Int) `{ self->y = (Sint16)v; `}
278 fun y
: Int `{ return self->y; `}
280 fun w=(v: Int) `{ self->w = (Uint16)v; `}
281 fun w
: Int `{ return self->w; `}
283 fun h=(v: Int) `{ self->h = (Uint16)v; `}
284 fun h
: Int `{ return self->h; `}
287 interface SDLInputEvent
291 # MouseEvent class containing the cursor position
299 redef fun is_move do return false
302 # MouseButtonEvent used to get information when a button is pressed/depressed
303 class SDLMouseButtonEvent
310 # Is this event raised by the left button?
311 fun is_left_button: Bool do return button == 1
313 # Is this event raised by the right button?
314 fun is_right_button: Bool do return button == 3
316 # Is this event raised by the middle button?
317 fun is_middle_button: Bool do return button == 2
319 # Is this event raised by the wheel going down?
320 fun is_down_wheel: Bool do return button == 4
322 # Is this event raised by the wheel going up?
323 fun is_up_wheel: Bool do return button == 5
325 # Is this event raised by the wheel?
326 fun is_wheel: Bool do return is_down_wheel or is_up_wheel
328 init (x, y: Float, button: Int, pressed: Bool)
333 self.pressed = pressed
339 return "MouseButtonEvent button {button} down at {x}, {y}"
341 return "MouseButtonEvent button {button} up at {x}, {y}"
346 # MouseMotionEvent to get the cursor position when the mouse is moved
347 class SDLMouseMotionEvent
355 redef fun is_move do return true
357 init (x, y, rel_x, rel_y: Float, pressed: Bool)
363 self.pressed = pressed
366 redef fun to_s do return "MouseMotionEvent at {x}, {y}"
369 # SDLKeyEvent for when a key is pressed
379 if name.length == 1 then return name.chars.first
386 return "KeyboardEvent key {name} down"
388 return "KeyboardEvent key {name} up"
392 # Return true if the key is down, false otherwise
393 redef fun is_down do return down
395 # Return true if the key is the up arrow
396 redef fun is_arrow_up do return name == "up"
397 # Return true if the key is the left arrow
398 redef fun is_arrow_left do return name == "left"
399 # Return true if the key is the down arrow
400 redef fun is_arrow_down do return name == "down"
401 # Return true if the key is the right arrow
402 redef fun is_arrow_right do return name == "right"
411 fun delay `{ SDL_Delay(self); `}
414 # Class to load and use TTF_Font
415 extern class SDLFont `{TTF_Font *`}
416 # Load a font with a specified name and size
417 new (name: String, points: Int) import String.to_cstring `{
418 char
* cname
= String_to_cstring(name
);
420 TTF_Font *font
= TTF_OpenFont(cname
, (int
)points
);
422 printf
("TTF_OpenFont: %s\n", TTF_GetError());
429 fun destroy `{ TTF_CloseFont(self); `}
431 # Create a String with the specified color, return an SDLImage
432 fun render
(text
: String, r
, g
, b
: Int): SDLImage import String.to_cstring
`{
434 SDL_Surface *text_surface;
441 ctext = String_to_cstring(text);
442 if(!(text_surface=TTF_RenderText_Blended(self, ctext, color)))
444 fprintf(stderr, "SDL TFF error: %s\n", TTF_GetError());
451 # TODO reactivate fun below when updating libsdl_ttf to 2.0.10 or above
452 #fun outline: Int # TODO check to make inline/nitside only
453 #fun outline=(v: Int) is extern
455 #fun kerning: Bool is extern
456 #fun kerning=(v: Bool) is extern
458 # Maximum pixel height of all glyphs of this font.
460 return TTF_FontHeight(self);
464 return TTF_FontAscent(self);
468 return TTF_FontDescent(self);
471 # Get the recommended pixel height of a rendered line of text of the loaded font. This is usually larger than the Font.height.
472 fun line_skip
: Int `{
473 return TTF_FontLineSkip(self);
476 # Return true is the font used fixed width for each char
477 fun is_fixed_width
: Bool `{
478 return TTF_FontFaceIsFixedWidth(self);
481 # Return the family name of the font
482 fun family_name
: nullable String import String.to_cstring
, String.as nullable `{
483 char *fn = TTF_FontFaceFamilyName(self);
486 return null_String();
488 return String_as_nullable(NativeString_to_s(fn));
491 # Return the style name of the font
492 fun style_name
: nullable String import String.to_cstring
, String.as nullable `{
493 char *sn = TTF_FontFaceStyleName(self);
496 return null_String();
498 return String_as_nullable(NativeString_to_s(sn));
501 # Return the estimated width of a String if used with the current font
502 fun width_of
(text
: String): Int import NativeString.to_s
`{
503 char *ctext = String_to_cstring(text);
505 if (TTF_SizeText(self, ctext, &w, NULL))
507 fprintf(stderr, "SDL TFF error: %s\n", TTF_GetError());
515 # Information on the SDL window
516 # Used in other modules to get window handle
517 extern class SDLSystemWindowManagerInfo `{SDL_SysWMinfo *`}
520 SDL_SysWMinfo *val
= malloc
(sizeof
(SDL_SysWMinfo));
522 SDL_VERSION(&val-
>version
);
524 if(SDL_GetWMInfo(val
) <= 0) {
525 printf
("Unable to get window handle");
532 # Returns the handle of this window on a X11 window system
533 fun x11_window_handle: Pointer `{
534 return (void
*)self-
>info
.x11
.window
;