#include <unistd.h>
#include <stdlib.h>
#include "entity.h"
#include "SDL.h"
#include <glib.h>
#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 <array_length; counter++)
{
/* Render. */
item = g_ptr_array_index (item_list, counter);
if (TRUE == item->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();
}
}
syntax highlighted by Code2HTML, v. 0.9.1