aboutsummaryrefslogtreecommitdiff
path: root/modules/librender/g_object.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/librender/g_object.c')
-rw-r--r--modules/librender/g_object.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/modules/librender/g_object.c b/modules/librender/g_object.c
new file mode 100644
index 0000000..63dcb16
--- /dev/null
+++ b/modules/librender/g_object.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright © 2006-2016 SplinterGU (Fenix/Bennugd)
+ *
+ * This file is part of Bennu - Game Development
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "librender.h"
+
+/* --------------------------------------------------------------------------- */
+
+static int sequencer = 0;
+
+CONTAINER * sorted_object_list = NULL;
+
+/* --------------------------------------------------------------------------- */
+
+CONTAINER * search_container( int key )
+{
+ CONTAINER * ctr = NULL;
+
+ if ( !sorted_object_list ) return NULL;
+
+ for ( ctr = sorted_object_list; ctr && ctr->key > key; ctr = ctr->next );
+
+ if ( ctr && ctr->key == key ) return ctr;
+
+ return NULL;
+}
+
+/* --------------------------------------------------------------------------- */
+
+CONTAINER * get_container( int key )
+{
+ CONTAINER * ctr = NULL, * prev_ctr = NULL, * new_ctr = NULL;
+
+ if ( sorted_object_list )
+ {
+ for ( ctr = sorted_object_list; ctr && ctr->key > key; ctr = ctr->next )
+ {
+ prev_ctr = ctr;
+ }
+ if ( ctr && ctr->key == key ) return ctr;
+ }
+
+ new_ctr = ( CONTAINER * ) malloc( sizeof( CONTAINER ) );
+ if ( !new_ctr ) return NULL;
+
+ new_ctr->key = key;
+ new_ctr->first_in_key = NULL;
+
+ if ( ctr == sorted_object_list )
+ {
+ if ( !sorted_object_list )
+ {
+ /* Only happen "!sorted_object_list" when "ctr == sorted_object_list" (NULL) */
+ sorted_object_list = new_ctr;
+ new_ctr->next = NULL;
+ new_ctr->prev = NULL;
+
+ return new_ctr;
+ }
+
+ sorted_object_list = new_ctr;
+ }
+
+ if ( ctr )
+ {
+ new_ctr->next = ctr;
+ new_ctr->prev = ctr->prev;
+ if ( ctr->prev ) ctr->prev->next = new_ctr;
+ ctr->prev = new_ctr;
+ }
+ else
+ {
+ // prev_ctr implicit exist
+ new_ctr->next = NULL;
+ new_ctr->prev = prev_ctr;
+ prev_ctr->next = new_ctr;
+ }
+
+ return new_ctr;
+}
+
+/* --------------------------------------------------------------------------- */
+
+void destroy_container( CONTAINER * ctr )
+{
+ if ( ctr->next ) ctr->next->prev = ctr->prev;
+ if ( ctr->prev ) ctr->prev->next = ctr->next;
+ if ( ctr == sorted_object_list ) sorted_object_list = ctr->next ;
+
+ free( ctr );
+}
+
+/* --------------------------------------------------------------------------- */
+/*
+ * FUNCTION : gr_new_object
+ *
+ * Register a visible object with a Z coordinate to be drawn
+ * by an user-defined function.
+ *
+ * If your DLL does some screen operations, you should register
+ * a draw-type hook or an object. Any access to the screen
+ * surface outside those are invalid.
+ *
+ * PARAMS :
+ * z Z value of the object to be drawn
+ * info Pointer to the object information function
+ * (fills bounding box, returns 1 if changed since last frame)
+ * draw Pointer to the object drawing function
+ * what User-defined parameter that will be passed to "draw"
+ *
+ * RETURN VALUE :
+ * An integer ID that uniquely identifies the object,
+ * or 0 if not enough memory
+ */
+
+int gr_new_object( int z, OBJ_INFO * info, OBJ_DRAW * draw, void * what )
+{
+ CONTAINER * ctr ;
+ OBJECT * object = ( OBJECT * ) malloc( sizeof( OBJECT ) );
+
+ if ( !object ) return 0;
+
+ ctr = get_container( z );
+ if ( !ctr )
+ {
+ free( object );
+ return 0;
+ }
+
+ object->z = z;
+ object->info = info;
+ object->draw = draw;
+ object->what = what;
+ object->ready = 0;
+ object->bbox.x = -2;
+ object->bbox.y = -2;
+ object->bbox.x2 = -2;
+ object->bbox.y2 = -2;
+ object->bbox_saved.x = -2;
+ object->bbox_saved.y = -2;
+ object->bbox_saved.x2 = -2;
+ object->bbox_saved.y2 = -2;
+ object->seq = 0;
+ object->prev = NULL;
+
+ if ( ctr->first_in_key )
+ {
+ ctr->first_in_key->prev = object;
+ object->next = ctr->first_in_key;
+ }
+ else
+ {
+ object->next = NULL;
+ }
+
+ ctr->first_in_key = object;
+
+ return ( int ) object;
+}
+
+/* --------------------------------------------------------------------------- */
+/*
+ * FUNCTION : gr_destroy_object
+ *
+ * Unregister and remove a given object created by gr_new_object from memory
+ *
+ * PARAMS :
+ * id ID returned by gr_new_object
+ *
+ * RETURN VALUE :
+ * None
+ */
+
+void gr_destroy_object( int id )
+{
+ CONTAINER * ctr ;
+ OBJECT * object = ( OBJECT * ) id ;
+
+ if ( !object ) return ;
+
+ ctr = search_container( object->z );
+ if ( !ctr ) return;
+
+ if ( object->next ) object->next->prev = object->prev;
+ if ( object->prev ) object->prev->next = object->next;
+ if ( object == ctr->first_in_key ) ctr->first_in_key = object->next;
+ if ( !ctr->first_in_key ) destroy_container( ctr );
+
+ /* Rects */
+ if ( object->bbox.x >= 0 || object->bbox.y >= 0 || object->bbox.x2 >= 0 || object->bbox.y2 >= 0 )
+ gr_mark_rect( object->bbox.x, object->bbox.y, object->bbox.x2 - object->bbox.x + 1, object->bbox.y2 - object->bbox.y + 1 );
+
+ free( object );
+}
+
+/* --------------------------------------------------------------------------- */
+
+void gr_update_objects_mark_rects( int restore, int dump )
+{
+ CONTAINER * ctr = NULL, * next_ctr, * fix_ctr;
+ OBJECT * object, * next_object ;
+ int ready, key;
+
+ if ( !sorted_object_list ) return ;
+
+ sequencer++;
+
+ next_ctr = sorted_object_list;
+ while (( ctr = next_ctr ) )
+ {
+ /* Get Next Container */
+ next_ctr = ctr->next ;
+
+ key = ctr->key;
+
+ next_object = ctr->first_in_key;
+ while (( object = next_object ) )
+ {
+ next_object = object->next ;
+
+ if ( object->seq != sequencer )
+ {
+ /* Mark object as already proceed */
+ object->seq = sequencer;
+
+ /* Update key & get_info */
+ ready = object->ready;
+
+ /* NOTE: Returned bbox must be ordered !!! */
+ object->changed = ( *object->info )( object->what, &object->bbox, &object->z, &object->ready );
+
+ /* Move to correct container */
+ if ( object->z != key )
+ {
+ /* Remove from list */
+ if ( object->next ) object->next->prev = object->prev;
+ if ( object->prev ) object->prev->next = object->next;
+ if ( object == ctr->first_in_key ) ctr->first_in_key = object->next;
+
+ if ( !ctr->first_in_key ) destroy_container( ctr );
+
+ /* Get new or exist container */
+ fix_ctr = get_container( object->z );
+ if ( !fix_ctr ) continue; /* Error */
+
+ /* Put new object first */
+ if ( fix_ctr->first_in_key ) fix_ctr->first_in_key->prev = object;
+
+ object->prev = NULL;
+ object->next = fix_ctr->first_in_key;
+
+ fix_ctr->first_in_key = object;
+ }
+
+ if (
+ ( object->z != key ) ||
+ ( object->ready ^ ready ) ||
+ object->changed ||
+ object->bbox.x2 != object->bbox_saved.x2 || object->bbox.x != object->bbox_saved.x ||
+ object->bbox.y2 != object->bbox_saved.y2 || object->bbox.y != object->bbox_saved.y
+ )
+ {
+ if ( restore == 0 )
+ gr_mark_rect( object->bbox_saved.x, object->bbox_saved.y, object->bbox_saved.x2 - object->bbox_saved.x + 1, object->bbox_saved.y2 - object->bbox_saved.y + 1 );
+
+ object->bbox_saved = object->bbox ;
+ }
+
+ if (
+ !object->ready ||
+ object->bbox.x2 < 0 || object->bbox.x > scr_width - 1 ||
+ object->bbox.y2 < 0 || object->bbox.y > scr_height - 1 ) continue;
+
+ if ( dump == 0 && object->changed && ( object->bbox.x >= 0 || object->bbox.y >= 0 || object->bbox.x2 >= 0 || object->bbox.y2 >= 0 ) )
+ {
+ gr_mark_rect( object->bbox.x, object->bbox.y, object->bbox.x2 - object->bbox.x + 1, object->bbox.y2 - object->bbox.y + 1 );
+ }
+ }
+ }
+ }
+}
+
+/* --------------------------------------------------------------------------- */
+
+void gr_draw_objects( REGION * updaterects, int count )
+{
+ CONTAINER * ctr = NULL;
+ OBJECT * object;
+ REGION * prect;
+ int n;
+
+ ctr = sorted_object_list;
+ while ( ctr )
+ {
+ object = ctr->first_in_key;
+ while ( object )
+ {
+ if ( object->ready )
+ {
+ prect = updaterects;
+ for ( n = count; n--; prect++ )
+ {
+ if (
+ object->bbox.x2 < prect->x || object->bbox.x > prect->x2 ||
+ object->bbox.y2 < prect->y || object->bbox.y > prect->y2
+ )
+ continue;
+ ( *object->draw )( object->what, prect ) ;
+ }
+ }
+ object = object->next ;
+ }
+ ctr = ctr->next ;
+ }
+}
+
+/* --------------------------------------------------------------------------- */
+
+void gr_draw_objects_complete( void )
+{
+ CONTAINER * ctr = NULL;
+ OBJECT * object;
+
+ ctr = sorted_object_list;
+ while ( ctr )
+ {
+ object = ctr->first_in_key;
+ while ( object )
+ {
+ if ( object->ready )
+ ( *object->draw )( object->what, NULL ) ;
+ object = object->next ;
+ }
+ ctr = ctr->next ;
+ }
+}
+
+/* --------------------------------------------------------------------------- */