#include #include #include "entity.h" #include "SDL.h" #include #include "sdl-common.h" static int window_created = FALSE; static gint sdl_refresh (ENode * node, EBuf * attr, EBuf * value); /* Normalizes a rectangle so it is contained within the screen. * If a rectangle is outside the screen it will be shrunk to fit * inside the screen. */ inline void normalize_rect(SDL_Surface * screen, SDL_Rect * rect) { if (0 > rect->x) { rect->x = 0; } if (rect->x > screen->w) { rect->x = screen->w; } if ((rect->x + rect->w) > screen->w) { rect->w = screen->w - rect->x; } if (0 > rect->y ) { rect->y = 0; } if (rect->y > screen->h ) { rect->y = screen->h; } if ((rect->y + rect->h) > screen->h) { rect->h = screen->h - rect->y; } } /* A traditional sdl mainloop for those who want it. */ static gint sdl_traditional_mainloop (gpointer data) { SDL_Event event; Uint8 *keys; sdl_refresh (data, NULL, NULL); SDL_PollEvent (&event); if ( event.type == SDL_QUIT ) { /* Death to us here. */ SDL_Quit (); exit(0); /* ondelete happens .*/ } keys = SDL_GetKeyState(NULL); if ( keys[SDLK_ESCAPE] == SDL_PRESSED ) { SDL_Quit(); exit(0); } return TRUE; } /**sdl_refresh * Does the actual drawing. */ static gint sdl_refresh (ENode * node, EBuf * attr, EBuf * value) { SDL_Surface *screen = NULL; sdl_item * item = NULL; GPtrArray * item_list = NULL; static SDL_Rect rects[2048]; int refresh_counter = 0; int array_length = 0; int counter = 0; /* Get our SDL surface */ screen = enode_get_kv (node, "surface"); /* Get item list. */ item_list = enode_get_kv (node, "item_list"); if (NULL != item_list) { array_length = item_list->len; } /* If we can get a valid screen, attempt to render to it. */ if (NULL != screen) { if ( SDL_MUSTLOCK (screen) ) { if ( SDL_LockSurface (screen) < 0 ) { /* bad things are happening. */ return FALSE; } } /* Step through our refresh needed items. */ for (counter = 0 ; counter needs_refresh) { switch (item->type) { case SDL_SPRITE: sdl_sprite_render (&rects[refresh_counter], screen, item); break; case SDL_RECTANGLE: sdl_rectangle_render (&rects[refresh_counter], screen, item); break; } normalize_rect(screen, &rects[refresh_counter]); refresh_counter++; } } /* Update SDL Window. */ if ( SDL_MUSTLOCK (screen) ) { SDL_UnlockSurface (screen); } if (0 < refresh_counter) /* Have something to update. */ { /* Update the screen. */ SDL_UpdateRects (screen, refresh_counter, &(rects[0])); } return TRUE; } /* No surface to write to. */ return FALSE; } /**sdl_abort_check * Does the SDL event handling for abort checking. */ gint sdl_abort_check (gpointer data) { SDL_Event event; Uint8 *keys; SDL_PollEvent (&event); if ( event.type == SDL_QUIT ) { /* Death to us here. */ SDL_Quit (); exit(0); /* ondelete happens .*/ } keys = SDL_GetKeyState(NULL); if ( keys[SDLK_ESCAPE] == SDL_PRESSED ) { SDL_Quit(); exit(0); } return TRUE; } static void sdl_window_destroy (ENode * node) { } static void rendsdl_window_render (ENode * node) { gchar * width_str = NULL; gchar * height_str = NULL; gchar * refresh_interval = NULL; int width = 0; int height = 0; int bitmask = 0; char * is_true = NULL; SDL_Surface *screen = NULL; GPtrArray * garray = NULL; if (window_created == FALSE) /* No windows created yet. */ { /* Get the size of the window. */ width_str = enode_attrib_str (node, "width", NULL); height_str = enode_attrib_str (node, "height", NULL); if (NULL == width_str || NULL == height_str ) { return; } width = atoi (width_str); height = atoi (height_str); is_true = enode_attrib_str (node, "fullscreen", NULL); if ((NULL != is_true) && (0 == strcmp ("true", is_true))) { bitmask = SDL_FULLSCREEN; } /* Store the enode. */ enode_set_kv (node, "node", node); /* Initialize the display . */ screen = SDL_SetVideoMode (width, height, 0, SDL_HWSURFACE|bitmask); if (NULL != screen)/* Store the surface. */ { enode_set_kv (node, "surface", screen); } /* Setup our item array. */ garray = g_ptr_array_new (); if (NULL != garray) { enode_set_kv (node, "item_list", garray); } /* Looking for a refresh interval which mean traditional mainloop. */ refresh_interval = enode_attrib_str (node, "refresh", NULL); /* If they want a traditional mainloop. */ if (NULL != refresh_interval) { /* So events won't be lost. */ g_timeout_add (atoi (refresh_interval), sdl_traditional_mainloop, node); } else { /* Setup the saftey abort callback. */ g_idle_add (sdl_abort_check, node); } /* Only allow one SDL window per program. */ window_created = TRUE; } } /* SDL renderer initalization.*/ void renderer_init (RendererFlags flags) { Element *element; ElementAttr *e_attr; if (flags & RENDERER_INIT) { /* Initialize the SDL library */ if ( SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0 ) { /* Warn here. */ fprintf(stderr, "SDL init failed\n"); fprintf(stderr, "SDL error:%s\n", SDL_GetError()); } } if (flags & RENDERER_REGISTER) { /*mainloop_register ("sdl_poll_events", sdl_poll_events, NULL, NULL);*/ /* Register sdl-window. */ element = g_new0 (Element, 1); element->render_func = rendsdl_window_render; element->destroy_func = sdl_window_destroy; element->parent_func = NULL; element->tag = "sdl-window"; element->description = "Create a new SDL window."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "fullscreen"; e_attr->description = "Fullscreen boolean"; e_attr->value_desc = "boolean"; e_attr->possible_values = "true,false"; e_attr->set_attr_func = NULL; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "width"; e_attr->description = "Width of the window"; e_attr->value_desc = "integer"; e_attr->possible_values = "-1,*"; e_attr->set_attr_func = NULL; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "height"; e_attr->description = "Height of the window."; e_attr->value_desc = "integer"; e_attr->possible_values = "-1,*"; e_attr->set_attr_func = NULL; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "refresh"; e_attr->description = "Refresh interval in milliseconds."; e_attr->value_desc = "integer"; e_attr->possible_values = "-1,*"; e_attr->set_attr_func = NULL; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "_refresh"; e_attr->description = "A force refresh"; e_attr->value_desc = "integer"; e_attr->possible_values = "*"; e_attr->set_attr_func = sdl_refresh; element_register_attrib (element, e_attr); /* End sdl-window register. */ /* Register other renders here. */ sdl_sprite_register(); sdl_rectangle_register(); sdl_mouse_register(); sdl_keys_register(); } }