diff options
Diffstat (limited to 'modules/libscroll/libscroll.c')
-rw-r--r-- | modules/libscroll/libscroll.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/modules/libscroll/libscroll.c b/modules/libscroll/libscroll.c new file mode 100644 index 0000000..6f15582 --- /dev/null +++ b/modules/libscroll/libscroll.c @@ -0,0 +1,494 @@ +/* + * Copyright © 2006-2016 SplinterGU (Fenix/Bennugd) + * Copyright © 2002-2006 Fenix Team (Fenix) + * Copyright © 1999-2002 José Luis Cebrián Pagüe (Fenix) + * + * 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 <stdio.h> +#include <stdlib.h> + +#include "bgddl.h" +#include "dlvaracc.h" + +#include "libgrbase.h" +#include "libblit.h" +#include "librender.h" +#include "libvideo.h" +#include "resolution.h" + +#include "libscroll.h" + +#include "libscroll_exports.h" + +/* --------------------------------------------------------------------------- */ + +/* Indicadores de bloqueo */ +#define GRAPH_HWRAP 1 +#define GRAPH_VWRAP 2 +#define BACK_HWRAP 4 +#define BACK_VWRAP 8 + +/* --------------------------------------------------------------------------- */ + +int scrolls_objects[ 10 ] = { 0 }; + +scrolldata scrolls[ 10 ] ; + +/* --------------------------------------------------------------------------- */ + +/* Locals */ + +enum { + CTYPE = 0, + CNUMBER, + PROCESS_ID, + STATUS, + COORDX, + COORDY, + COORDZ, + RESOLUTION +}; + +/* Globals */ + +enum { + SCROLLS = 0 +}; + +/* --------------------------------------------------------------------------- */ + +DLVARFIXUP __bgdexport( libscroll, locals_fixup )[] = +{ + /* Nombre de variable global, puntero al dato, tamaño del elemento, cantidad de elementos */ + { "ctype" , NULL, -1, -1 }, + { "cnumber" , NULL, -1, -1 }, + { "id", NULL, -1, -1 }, + { "reserved.status", NULL, -1, -1 }, + { "x" , NULL, -1, -1 }, + { "y" , NULL, -1, -1 }, + { "z" , NULL, -1, -1 }, + { "resolution" , NULL, -1, -1 }, + { NULL , NULL, -1, -1 } +}; + +/* --------------------------------------------------------------------------- */ + +DLVARFIXUP __bgdexport( libscroll, globals_fixup )[] = +{ + /* Nombre de variable global, puntero al dato, tamaño del elemento, cantidad de elementos */ + { "scroll" , NULL, -1, -1 }, + { NULL , NULL, -1, -1 } +}; + +/* --------------------------------------------------------------------------- */ + +static void draw_scroll( int n, REGION * clip ); +static int info_scroll( int n, REGION * clip, int * z, int * drawme ); + +/* --------------------------------------------------------------------------- */ + +void scroll_region( int n, REGION * r ) +{ + if ( n < 0 || n > 9 ) return ; + + /* Corrected from x,y... to posx,posy... so out_region works fine */ + r->x -= scrolls[n].posx0 ; + r->y -= scrolls[n].posy0 ; + r->x2 -= scrolls[n].posx0 ; + r->y2 -= scrolls[n].posy0 ; +} + +/* --------------------------------------------------------------------------- */ + +void scroll_start( int n, int fileid, int graphid, int backid, int region, int flags, int destfile, int destid ) +{ + SCROLL_EXTRA_DATA * data; + + if ( n >= 0 && n <= 9 ) + { + if ( region < 0 || region > 31 ) region = 0 ; + + scrolls[n].active = 1 ; + scrolls[n].fileid = fileid ; + scrolls[n].graphid = graphid ; + scrolls[n].backid = backid ; + scrolls[n].region = ®ions[region] ; + scrolls[n].flags = flags ; + scrolls[n].destfile = destfile; + scrolls[n].destid = destid; + + data = &(( SCROLL_EXTRA_DATA * ) &GLODWORD( libscroll, SCROLLS ) )[n] ; + + data->reserved[0] = ( int32_t ) &scrolls[n]; /* First reserved dword point to internal scrolldata struct */ + + if ( scrolls_objects[n] ) gr_destroy_object( scrolls_objects[n] ); + scrolls_objects[n] = ( int )gr_new_object( 0, info_scroll, draw_scroll, n ); + } +} + +/* --------------------------------------------------------------------------- */ + +void scroll_stop( int n ) +{ + if ( n >= 0 && n <= 9 ) + { + if ( scrolls_objects[n] ) + { + gr_destroy_object( scrolls_objects[n] ); + scrolls_objects[n] = 0; + scrolls[n].active = 0 ; + } + } +} + +/* --------------------------------------------------------------------------- */ + +void scroll_update( int n ) +{ + int x0, y0, x1, y1, cx, cy, w, h, speed ; + + REGION bbox; + GRAPH * gr, * graph, * back; + + SCROLL_EXTRA_DATA * data; + + if ( n < 0 || n > 9 ) return ; + + if ( !scrolls[n].active || !scrolls[n].region || !scrolls[n].graphid ) return ; + + graph = scrolls[n].graphid ? bitmap_get( scrolls[n].fileid, scrolls[n].graphid ) : 0 ; + back = scrolls[n].backid ? bitmap_get( scrolls[n].fileid, scrolls[n].backid ) : 0 ; + + if ( !graph ) return ; // El fondo de scroll no existe + if ( scrolls[n].backid && !back ) return ; // Grafico no existe + + data = &(( SCROLL_EXTRA_DATA * ) &GLODWORD( libscroll, SCROLLS ) )[n] ; + + w = scrolls[n].region->x2 - scrolls[n].region->x + 1 ; + h = scrolls[n].region->y2 - scrolls[n].region->y + 1 ; + + scrolls[n].z = data->z ; + scrolls[n].ratio = data->ratio ; + scrolls[n].camera = instance_get( data->camera ) ; + scrolls[n].speed = data->speed ; + + if ( data->follows < 0 || data->follows > 9 ) + scrolls[n].follows = 0 ; + else + scrolls[n].follows = &scrolls[data->follows] ; + + if ( data->region1 < 0 || data->region1 > 31 ) + scrolls[n].region1 = 0 ; + else + scrolls[n].region1 = ®ions[data->region1] ; + + if ( data->region2 < 0 || data->region2 > 31 ) + scrolls[n].region2 = 0 ; + else + scrolls[n].region2 = ®ions[data->region2] ; + + /* Actualiza las variables globales (perseguir la camara, etc) */ + + if ( scrolls[n].follows ) + { + if ( scrolls[n].ratio ) + { + data->x0 = scrolls[n].follows->x0 * 100 / scrolls[n].ratio ; + data->y0 = scrolls[n].follows->y0 * 100 / scrolls[n].ratio ; + } + else + { + data->x0 = scrolls[n].follows->x0 ; + data->y0 = scrolls[n].follows->y0 ; + } + } + + if ( scrolls[n].camera ) + { + /* Mira a ver si entra dentro de la region 1 o 2 */ + + speed = scrolls[n].speed ; + if ( scrolls[n].speed == 0 ) speed = 9999999 ; + + /* Update speed */ + + if (( gr = instance_graph( scrolls[n].camera ) ) ) + { + instance_get_bbox( scrolls[n].camera, gr, &bbox ); + + x0 = bbox.x - data->x0 ; + y0 = bbox.y - data->y0 ; + x1 = bbox.x2 - data->x0 ; + y1 = bbox.y2 - data->y0 ; + + if ( scrolls[n].region1 && + ( + x0 < scrolls[n].region1->x2 && y0 < scrolls[n].region1->y2 && + x1 > scrolls[n].region1->x && y1 > scrolls[n].region1->y + ) + ) + { + speed = 0 ; + } + else + if ( scrolls[n].region2 ) + { + if ( x0 > scrolls[n].region2->x2 ) speed = ( x0 - scrolls[n].region2->x2 ); + if ( y0 > scrolls[n].region2->y2 ) speed = ( y0 - scrolls[n].region2->y2 ); + if ( x1 < scrolls[n].region2->x ) speed = ( scrolls[n].region2->x - x1 ); + if ( y1 < scrolls[n].region2->y ) speed = ( scrolls[n].region2->y - y1 ); + } + } + + /* Forzar a que esté en el centro de la ventana */ + + cx = LOCDWORD( libscroll, scrolls[n].camera, COORDX ) ; + cy = LOCDWORD( libscroll, scrolls[n].camera, COORDY ) ; + + RESOLXY( libscroll, scrolls[n].camera, cx, cy ); + + cx -= w / 2 ; + cy -= h / 2 ; + + if ( data->x0 < cx ) data->x0 = MIN( data->x0 + speed, cx ) ; + if ( data->y0 < cy ) data->y0 = MIN( data->y0 + speed, cy ) ; + if ( data->x0 > cx ) data->x0 = MAX( data->x0 - speed, cx ) ; + if ( data->y0 > cy ) data->y0 = MAX( data->y0 - speed, cy ) ; + } + + /* Scrolls no cíclicos y posición del background */ + + if ( graph ) + { + if ( !( scrolls[n].flags & GRAPH_HWRAP ) ) data->x0 = MAX( 0, MIN( data->x0, ( int )graph->width - w ) ) ; + if ( !( scrolls[n].flags & GRAPH_VWRAP ) ) data->y0 = MAX( 0, MIN( data->y0, ( int )graph->height - h ) ) ; + } + + if ( scrolls[n].ratio ) + { + data->x1 = data->x0 * 100 / scrolls[n].ratio ; + data->y1 = data->y0 * 100 / scrolls[n].ratio ; + } + + if ( back ) + { + if ( !( scrolls[n].flags & BACK_HWRAP ) ) data->x1 = MAX( 0, MIN( data->x1, ( int )back->width - w ) ) ; + if ( !( scrolls[n].flags & BACK_VWRAP ) ) data->y1 = MAX( 0, MIN( data->y1, ( int )back->height - h ) ) ; + } + + /* Actualiza la posición del scroll según las variables globales */ + + scrolls[n].posx0 = data->x0 ; + scrolls[n].posy0 = data->y0 ; + scrolls[n].x0 = data->x0 % ( int32_t ) graph->width ; + scrolls[n].y0 = data->y0 % ( int32_t ) graph->height ; + + if ( scrolls[n].x0 < 0 ) scrolls[n].x0 += graph->width ; + if ( scrolls[n].y0 < 0 ) scrolls[n].y0 += graph->height ; + + if ( back ) + { + scrolls[n].x1 = data->x1 % ( int32_t ) back->width ; + scrolls[n].y1 = data->y1 % ( int32_t ) back->height ; + if ( scrolls[n].x1 < 0 ) scrolls[n].x1 += back->width ; + if ( scrolls[n].y1 < 0 ) scrolls[n].y1 += back->height ; + } +} + +/* --------------------------------------------------------------------------- */ + +static int compare_instances( const void * ptr1, const void * ptr2 ) +{ + const INSTANCE * i1 = *( const INSTANCE ** )ptr1 ; + const INSTANCE * i2 = *( const INSTANCE ** )ptr2 ; + + int ret = LOCDWORD( libscroll, i2, COORDZ ) - LOCDWORD( libscroll, i1, COORDZ ); + + return !ret ? LOCDWORD( libscroll, i1, PROCESS_ID ) - LOCDWORD( libscroll, i2, PROCESS_ID ) : ret; +} + +/* --------------------------------------------------------------------------- */ + +void scroll_draw( int n, REGION * clipping ) +{ + int nproc, x, y, cx, cy ; + + static INSTANCE ** proclist = 0; + static int proclist_reserved = 0; + int proclist_count; + REGION r; + int status; + + GRAPH * graph, * back, * dest = NULL; + + SCROLL_EXTRA_DATA * data; + INSTANCE * i; + + if ( n < 0 || n > 9 ) return ; + + if ( !scrolls[n].active || !scrolls[n].region || !scrolls[n].graphid ) return ; + + graph = scrolls[n].graphid ? bitmap_get( scrolls[n].fileid, scrolls[n].graphid ) : NULL ; + back = scrolls[n].backid ? bitmap_get( scrolls[n].fileid, scrolls[n].backid ) : NULL ; + + if ( !graph ) return ; // El fondo de scroll no existe + if ( scrolls[n].backid && !back ) return ; // Grafico no existe + + dest = scrolls[n].destid ? bitmap_get( scrolls[n].destfile, scrolls[n].destid ) : NULL ; + + data = &(( SCROLL_EXTRA_DATA * ) & GLODWORD( libscroll, SCROLLS ) )[n] ; + + /* Dibuja el fondo */ + + r = *scrolls[n].region; + if ( !dest && clipping ) region_union( &r, clipping ); + + if ( back ) + { + if ( back->ncpoints > 0 && back->cpoints[0].x >= 0 ) + { + cx = back->cpoints[0].x ; + cy = back->cpoints[0].y ; + } + else + { + cx = back->width / 2 ; + cy = back->height / 2 ; + } + + y = scrolls[n].region->y - scrolls[n].y1 ; + + while ( y < scrolls[n].region->y2 ) + { + x = scrolls[n].region->x - scrolls[n].x1 ; + while ( x < scrolls[n].region->x2 ) + { + gr_blit( dest, &r, x + cx, y + cy, data->flags2, back ) ; + x += back->width ; + } + y += back->height ; + } + } + + /* Dibuja el primer plano */ + + if ( graph->ncpoints > 0 && graph->cpoints[0].x >= 0 ) + { + cx = graph->cpoints[0].x ; + cy = graph->cpoints[0].y ; + } + else + { + cx = graph->width / 2 ; + cy = graph->height / 2 ; + } + + y = scrolls[n].region->y - scrolls[n].y0 ; + while ( y < scrolls[n].region->y2 ) + { + x = scrolls[n].region->x - scrolls[n].x0 ; + while ( x < scrolls[n].region->x2 ) + { + gr_blit( dest, &r, x + cx, y + cy, data->flags1, graph ) ; + x += graph->width ; + } + y += graph->height ; + } + + /* Crea una lista ordenada de instancias a dibujar */ + + i = first_instance ; + proclist_count = 0 ; + while ( i ) + { + if ( LOCDWORD( libscroll, i, CTYPE ) == C_SCROLL && + ( + (( status = LOCDWORD( libscroll, i, STATUS ) ) & ~STATUS_WAITING_MASK ) == STATUS_RUNNING || + ( status & ~STATUS_WAITING_MASK ) == STATUS_FROZEN + ) + ) + { + if ( LOCDWORD( libscroll, i, CNUMBER ) && !( LOCDWORD( libscroll, i, CNUMBER ) & ( 1 << n ) ) ) + { + i = i->next ; + continue ; + } + + if ( proclist_count == proclist_reserved ) + { + proclist_reserved += 16 ; + proclist = ( INSTANCE ** ) realloc( proclist, sizeof( INSTANCE * ) * proclist_reserved ) ; + } + + proclist[proclist_count++] = i ; + } + i = i->next ; + } + + if ( proclist_count ) + { + /* Ordena la listilla */ + + qsort( proclist, proclist_count, sizeof( INSTANCE * ), compare_instances ) ; + + /* Visualiza los procesos */ + + for ( nproc = 0 ; nproc < proclist_count ; nproc++ ) + { + x = LOCDWORD( libscroll, proclist[nproc], COORDX ) ; + y = LOCDWORD( libscroll, proclist[nproc], COORDY ) ; + + RESOLXY( libscroll, proclist[nproc], x, y ); + + draw_instance_at( proclist[nproc], &r, x - scrolls[n].posx0 + scrolls[n].region->x, y - scrolls[n].posy0 + scrolls[n].region->y, dest ) ; + } + } +} + +/* --------------------------------------------------------------------------- */ + +static void draw_scroll( int n, REGION * clip ) +{ + scroll_draw( n, clip ) ; +} + +/* --------------------------------------------------------------------------- */ + +static int info_scroll( int n, REGION * clip, int * z, int * drawme ) +{ + * z = scrolls[n].z; + * drawme = 1; + * clip = * scrolls[n].region; + scroll_update( n ); + + // Force clean map (need optimization) + if ( scrolls[n].destid ) gr_clear_region( bitmap_get( scrolls[n].destfile, scrolls[n].destid ), scrolls[n].region ); + + return 1; +} + +/* --------------------------------------------------------------------------- */ |