/* $Id: ggidemo.c,v 1.9 2005/06/20 06:55:01 cegger Exp $ * ggidemo.c - written in 1999 by Andreas Beck becka@ggi-project.org * * This is a demonstration of LibGIC's functions and can be used as a * reference programming example. * * This software is placed in the public domain and can be used freely * for any purpose. It comes without any kind of warranty, either * expressed or implied, including, but not limited to the implied * warranties of merchantability or fitness for a particular purpose. * Use it at your own risk. the author is not responsible for any damage * or consequences raised by use or inability to use this program. */ #include #include #include #include #include #include #include #include #define inline __inline ggi_visual_t vis; int vissizex,vissizey; ggi_pixel white,black,red; int sx,sy; /* O.K. - let's steal some data and functions from the cube3d demo * Ignore all that stuff, if you want to learn about LibGIC. */ typedef double Matrix3D[3][3]; typedef double Vector3D[3]; typedef double Vector2D[2]; typedef struct { Vector3D origin; Vector2D projected; } Point3D; Point3D the_points[24]; Point3D the_original_points[24]={ { {-100, -75,-130},{0,0} }, { { 100, -75,-130},{0,0} }, { { 100, +75,-130},{0,0} }, { {-100, +75,-130},{0,0} }, { {-130, -75, 100},{0,0} }, { {-130, -75,-100},{0,0} }, { {-130, +75,-100},{0,0} }, { {-130, +75, 100},{0,0} }, { { 100, -75, 130},{0,0} }, { {-100, -75, 130},{0,0} }, { {-100, +75, 130},{0,0} }, { { 100, +75, 130},{0,0} }, { { 130, -75,-100},{0,0} }, { { 130, -75, 100},{0,0} }, { { 130, +75, 100},{0,0} }, { { 130, +75,-100},{0,0} }, { {-100,-105, +75},{0,0} }, { { 100,-105, +75},{0,0} }, { { 100,-105, -75},{0,0} }, { {-100,-105, -75},{0,0} }, { {-100, 105, -75},{0,0} }, { { 100, 105, -75},{0,0} }, { { 100, 105, +75},{0,0} }, { {-100, 105, +75},{0,0} } }; int numpoints=24; typedef struct { int numedges; Point3D *points; Vector3D normal,middle; double visible; ggi_pixel color; } Polygon3D; Polygon3D the_polys[6]={ { 4, the_points+ 0, {0,0,0}, {0,0,0}, 0, 0 }, { 4, the_points+ 4, {0,0,0}, {0,0,0}, 0, 0 }, { 4, the_points+ 8, {0,0,0}, {0,0,0}, 0, 0 }, { 4, the_points+12, {0,0,0}, {0,0,0}, 0, 0 }, { 4, the_points+16, {0,0,0}, {0,0,0}, 0, 0 }, { 4, the_points+20, {0,0,0}, {0,0,0}, 0, 0 }, }; typedef struct { int polynum; double zmiddle; } zorder3D; typedef struct { int numpolys; Polygon3D *polys; } Scene3D; Scene3D the_scene={ 6, the_polys }; Vector3D eyepos={0,0,-1000}; static inline void Matrix_times_Vector(double *mat, double *vec, double *result) { int x,y; for(x=0;x<3;x++) { result[x]=0.0; for(y=0;y<3;y++) { result[x]+=mat[x*3+y]*vec[y]; } } } static inline void Matrix_times_Matrix(double *mat, double *mat2) { int x,y,z; double result[9]; for(x=0;x<3;x++) { for(y=0;y<3;y++) { result[x+3*y]=0.0; for(z=0;z<3;z++) result[x+3*y]+=mat2[z+3*y]*mat[x+3*z]; } } memcpy(mat,result,sizeof(result)); } static inline double Matrix_Deter(double *mat) { return mat[0+3*0]*mat[1+3*1]*mat[2+3*2] + mat[1+3*0]*mat[2+3*1]*mat[0+3*2] + mat[2+3*0]*mat[0+3*1]*mat[1+3*2] - mat[2+3*0]*mat[1+3*1]*mat[0+3*2] - mat[1+3*0]*mat[0+3*1]*mat[2+3*2] - mat[0+3*0]*mat[2+3*1]*mat[1+3*2] ; } static inline double Vector_Length(double *vec) { return sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]); } static inline void Vector_VecProd(double *in1,double *in2,double *out) { out[0]= in1[1]*in2[2]-in1[2]*in2[1]; out[1]= in1[2]*in2[0]-in1[0]*in2[2]; out[2]= in1[0]*in2[1]-in1[1]*in2[0]; } static inline double Vector_ScalarProd(double *in1,double *in2) { return in1[0]*in2[0]+in1[1]*in2[1]+in1[2]*in2[2]; } static inline void Vector_Subtract(double *in1,double *in2,double *out) { out[0]= in1[0]-in2[0]; out[1]= in1[1]-in2[1]; out[2]= in1[2]-in2[2]; } static inline void Vector_Add(double *in1,double *in2,double *out) { out[0]= in1[0]+in2[0]; out[1]= in1[1]+in2[1]; out[2]= in1[2]+in2[2]; } static inline void Vector_Scale(double scale,double *in1,double *out) { out[0]= in1[0]*scale; out[1]= in1[1]*scale; out[2]= in1[2]*scale; } static inline void transform_point(double *mat,Point3D *in,Point3D *out) { Matrix_times_Vector(mat,in->origin,out->origin); out->projected[0]=out->origin[0]*(out->origin[2]+eyepos[2])/eyepos[2]+vissizex/2; /* Fixme - perspective */ out->projected[1]=out->origin[1]*(out->origin[2]+eyepos[2])/eyepos[2]+vissizey/2; } static inline void normvec_poly(Polygon3D *poly) { Vector3D v1,v2; Vector_Subtract(poly->points[1].origin,poly->points[0].origin,v1); Vector_Subtract(poly->points[2].origin,poly->points[1].origin,v2); Vector_VecProd (v1,v2,poly->normal); } static inline void visible_poly(Polygon3D *poly) { Vector3D view; Vector_Subtract(poly->middle,eyepos,view); poly->visible=Vector_ScalarProd(view,poly->normal); } static inline void midvec_poly(Polygon3D *poly) { int x; poly->middle[0]=poly->middle[1]=poly->middle[2]=0.0; x=poly->numedges; while(x--) { Vector_Add(poly->middle,poly->points[x].origin,poly->middle); } Vector_Scale(1.0/poly->numedges,poly->middle,poly->middle); } Matrix3D current={ {1.0,0.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0} }; Matrix3D speed={ {1.0,0.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0} }; /* Blit out a polygon. */ static void doblit(Polygon3D *poly,int transp) { int miny,maxy,x,lastx,y; ggi_pixel pixel; struct { int xpos,patx,paty; } min,max,hlp; miny=1000000000;maxy=-1000000000; pixel=poly->color; /* Calc min/max scanline */ x=poly->numedges; while(x--) { if (poly->points[x].projected[1]points[x].projected[1]; if (poly->points[x].projected[1]>maxy) maxy=poly->points[x].projected[1]; } if (miny<0) miny=0; if (maxy>=vissizey) maxy=vissizey-1; ggiSetGCForeground(vis, white); for(y=miny;y<=maxy;y++) { double dy1,dy2; min.xpos= 1000000000; max.xpos=-1000000000; x=poly->numedges;lastx=0; while(x--) { /* Check if we intersect an edge with that scanline */ dy1=poly->points[ x].projected[1]-y; dy2=poly->points[lastx].projected[1]-y; if ( ( dy1 > 0.0 && dy2 <= 0.0 ) || ( dy1 < 0.0 && dy2 >= 0.0 ) ) { #define MKXPOS \ hlp.xpos=((int)((poly->points[ x].projected[0]*dy2- \ poly->points[lastx].projected[0]*dy1)/ \ (dy2-dy1))) MKXPOS; if (hlp.xposmax.xpos) max=hlp; } else if (hlp.xpos>max.xpos) { max=hlp; } } lastx=x; } #undef MKXPOS if (max.xpos< 0 ) continue; if (min.xpos>=vissizex) continue; if (min.xpos==max.xpos) { if ( pixel || !transp ) ggiPutPixel(vis,min.xpos,y,pixel); } else { for(x=min.xpos;x<=max.xpos;x++) { if (x<0) continue; if (x>vissizex) break; if ( pixel || !transp ) ggiPutPixel(vis,x,y,pixel); } } } } static inline void turn_add(int ax1,int ax2,double degree) { Matrix3D turnit; memset(turnit,0,sizeof(turnit)); turnit[0] [0] = turnit[1] [1] =turnit[2][2]=1.0; turnit[ax1][ax1]= turnit[ax2][ax2]=cos(degree); turnit[ax1][ax2]=-(turnit[ax2][ax1]=sin(degree)); Matrix_times_Matrix((double *)speed,(double *)turnit); } static inline void scale(double fac) { int x; for(x=0;x<9;x++) ((double *)speed)[x]*=fac; } static inline void stop_speed(void) { memset(speed,0,sizeof(speed)); speed[0][0]=speed[1][1]=speed[2][2]=1.0; } static int align(Polygon3D *poly) { double biggest; int rc; Vector3D help; stop_speed();rc=1; biggest=Vector_Length(poly->normal); if (biggest<=1e-3) biggest=1e-3; Vector_Scale(1.0/biggest,poly->normal,help); if (fabs(help[1])>1e-3) { turn_add(1,2,0.5*help[1]); rc=0; } if (fabs(help[0])>1e-3) { turn_add(0,2,0.5*help[0]); rc=0; } if (rc && help[2]<0) { turn_add(1,2,M_PI/90); rc=0; } Vector_Subtract(poly->points[1].origin,poly->points[0].origin,help); biggest=Vector_Length(help); if (biggest<=1e-3) biggest=1e-3; Vector_Scale(1.0/biggest,help,help); if (fabs(help[1])>1e-3) { turn_add(1,0,0.5*help[1]); rc=0; } else if (help[0]<0) { turn_add(1,0,M_PI/90); rc=0; } return rc; } static void highlight_face(Polygon3D *poly) { int x,lastx; x=poly->numedges;lastx=0; while(x--) { ggiDrawLine(vis, (int)(poly->points[ x].projected[0]), (int)(poly->points[ x].projected[1]), (int)(poly->points[lastx].projected[0]), (int)(poly->points[lastx].projected[1])); lastx=x; } } /* O.K. - the following functions are for the very simple internal * configuration manager. This is an advanced topic. If you are new * to LibGIC, skip that section as well and stick to external configuration * programs like the snazzy manager for now. */ /* These are callback functions used by the LibGIC config manager code. */ /* Read an event. Simple, if you use LibGII or LibGGI. */ static int my_cfmgr_read_event(confmgr_info *info, gii_event *event, struct timeval *timeout) { if (ggiEventPoll(vis, emAll, timeout)) { ggiEventRead(vis, event, emAll); return 1; } return 0; } /* This is a useful helper function (not a callback), that is used to * set up LibGGI drawing context to use the desired colors. This is again * very simple. If you want to make something that really looks good, * have a look at the snazzy manager code. */ static void my_cfmgr_set_color(confmgr_style style, int is_box) { ggi_pixel bg, fg; switch (style) { case CONFMGR_STYLE_BACKGROUND: case CONFMGR_STYLE_SECTION_BACKGROUND: case CONFMGR_STYLE_TEST_BACKGROUND: bg = fg = black; break; case CONFMGR_STYLE_HEADING_TEXT: case CONFMGR_STYLE_ITEM_TEXT: case CONFMGR_STYLE_BINDING_TEXT: bg = black; fg = white; break; case CONFMGR_STYLE_ITEM_CURRENT: case CONFMGR_STYLE_BINDING_CURRENT: bg = black; fg = red; break; case CONFMGR_STYLE_ITEM_HIGHLIGHT: case CONFMGR_STYLE_BINDING_HIGHLIGHT: case CONFMGR_STYLE_HEADING_HIGHLIGHT: bg = red; fg = white; break; default: bg = black; fg = white; break; } if (is_box) { ggiSetGCForeground(vis, bg); } else { ggiSetGCBackground(vis, bg); ggiSetGCForeground(vis, fg); } } /* Callback to draw a box in a given style. */ static void my_cfmgr_draw_box(confmgr_info *info, confmgr_style style, int x, int y, int w, int h) { my_cfmgr_set_color(style, 1); ggiDrawBox(vis, x, y, w, h); } /* Callback to draw some text. */ static void my_cfmgr_draw_text(confmgr_info *info, confmgr_style style, confmgr_font font, int x, int y, const char *text) { my_cfmgr_set_color(style, 0); ggiPuts(vis, x, y, text); } /* That's for the test mode. Draw a bar filled up to the * degree to which state is active. */ static void my_cfmgr_draw_bar(confmgr_info *info, gic_state state, int x, int y, int w, int h) { double frac; int part; if (state == GIC_NOACTION) { ggiSetGCForeground(vis, black); ggiDrawBox(vis, x, y, w, h); return; } frac = (double) (state - GIC_STATE_MIN) / (double) (GIC_STATE_MAX - GIC_STATE_MIN); part = (int) (frac * (double) w); ggiSetGCForeground(vis, red); ggiDrawBox(vis, x, y, w, h); if (part > 0) { ggiSetGCForeground(vis, white); ggiDrawBox(vis, x, y, part, h); } } /* Do all changes that were requested up to now. * Handy for targets that are asynchronous in nature. */ static void my_cfmgr_flush(confmgr_info *info) { ggiFlush(vis); } /* Most actions you do in the config manager give a callback here, * so that you can make some noise. */ static void my_cfmgr_make_sound(confmgr_info *info, confmgr_sound sound) { /* DUMMY */ } /* This struct describes the properties of the screen and the renderers * that shall be used by teh configmanager. */ static confmgr_info my_cfmgr_info = { NULL, /* handle to be used for LibGIC: filled in later */ NULL, /* head to be configured: filled in later */ NULL, NULL, /* private stuff */ { -1, -1 }, /* screen & char sizes: filled in later */ { -1, -1 }, { -1, -1 }, 19, 19, 11, 11, /* max lengths of fields */ { 1, 1 }, /* gaps (last two filled in later) */ { -1, -1 }, { -1, -1 }, { 0, 0, 0, 0 }, /* borders */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* boxes */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, /* flags */ &my_cfmgr_read_event, /* callback API */ &my_cfmgr_draw_box, &my_cfmgr_draw_text, &my_cfmgr_draw_bar, &my_cfmgr_flush, &my_cfmgr_make_sound }; /* We have a separate second context for the menu system. * This is a "slightly" advanced topic. Don't read it now, skip down * to main(), then come back here. * It also shows, how you _call_ the confmanager. */ /* We are lazy. We just handle all that action stuff using the default * "lazy" action library. */ gicActionLazyData menu_next,menu_prev,menu_activate,menu_break; /* * The menu system for our simple application. */ static int main_menu(gic_handle_t hand, gic_context *menucon) { int xstart,ystart; int x,curpos,rc,err,reset; #define NUMMMENPT 3 const char *menu[NUMMMENPT]={ "Train Controls", " Back to Game ", " Quit Program " }; xstart=(vissizex-(14 * 8))/2; ystart=(vissizey-(NUMMMENPT*10))/2; reset=1;curpos=0;rc=-1; while(rc==-1) { if (reset) { /* we are asked to redraw all the stuff ... */ ggiSetDisplayFrame(vis,0); /* Make sure doublebuffering is disabled. */ ggiSetWriteFrame(vis,0); ggiSetGCForeground(vis,black); /* Make room */ ggiFillscreen(vis); ggiSetGCForeground(vis,white); /* Draw a border */ ggiDrawBox(vis,xstart-10,ystart-5,14*8+2*10,NUMMMENPT*10+2*5); ggiSetGCForeground(vis,black); ggiDrawBox(vis,xstart- 7,ystart-3,14*8+ 2*7,NUMMMENPT*10+2*3); gicActionLazyReset(&menu_next); /* Reset all recognizers. They might be dangling. */ gicActionLazyReset(&menu_prev); gicActionLazyReset(&menu_activate); gicActionLazyReset(&menu_break); reset=0; /* remember that we really _did_ it. */ } for(x=0;x GIC_STATE_MIDDLE) { if (curpos GIC_STATE_MIDDLE) { if (curpos) curpos--; } if (gicActionLazyGetstate(&menu_activate) > GIC_STATE_MIDDLE) { switch(curpos) { case 0: /* trainme */ err = gicConfigManager(&my_cfmgr_info); if (err < 0) { fprintf(stderr, "ERROR (%d) from config manager.\n", err); } else switch(err) { case CONFMGR_SAVE: printf("Would save config here.\n"); break; case CONFMGR_CANCEL: printf("Would reload config here.\n"); break; } reset = 1; /* We probably missed the release of the menu_activate ... * and we might have to redraw ... */ break; case 1: rc = 0; break; case 2: rc = 1; break; } } if (gicActionLazyGetstate(&menu_break)>GIC_STATE_MIDDLE) { rc=0; } } } return rc; } /* ********************************************************* ********************************************************* * O.K. - here we go for the real basic LibGIC stuff ... * ********************************************************* ********************************************************* */ /* * First we define some "actions". Actions are called, whenever a LibGIC * "feature" (that is something you want to control) changes state. * * Depending on your programming model, you will either directly use that * for callback functions or rather map the actions to a function that * posts program-events. * */ /* Programming model 1: Directly executing the requested action. * Very simple, but not always easily doable, as you might want to * interrupt running loops and such. * * Some cases where this is pretty effective are: */ /* Emergency exits that shut down everything anyway : */ static void boss_action(gic_handle_t hand, gic_actionlist *action, gic_feature *feature, gic_state newstate, gic_flag flag, int recnum) { gicClose(hand); gicExit(); ggiClose(vis); ggiExit(); printf("Hello Boss !\n"); exit(999); } /* Stuff that just fiddles with some kind of global state, like the current * motion or does something that instantaneously affects the program: */ enum directions {XPLUS,XMINUS,YPLUS,YMINUS,ZPLUS,ZMINUS,ZOOMIN,ZOOMOUT,STOP,LAST}; int directions[LAST]={XPLUS,XMINUS,YPLUS,YMINUS,ZPLUS,ZMINUS,ZOOMIN,ZOOMOUT,STOP}; static void lazy_action(gic_handle_t hand, gic_actionlist *action, gic_feature *feature, gic_state newstate, gic_flag flag, int recnum) { gicActionLazyAction(hand, action, feature, newstate, flag, recnum); } static void turn_action(gic_handle_t hand, gic_actionlist *action, gic_feature *feature, gic_state newstate,gic_flag flag,int recnum) { switch(*((int *)action->privdata)) { case XPLUS: turn_add(1,2,-M_PI/180.0*newstate/GIC_STATE_MAX); break; case XMINUS: turn_add(1,2, M_PI/180.0*newstate/GIC_STATE_MAX); break; case YPLUS: turn_add(0,2,-M_PI/180.0*newstate/GIC_STATE_MAX); break; case YMINUS: turn_add(0,2, M_PI/180.0*newstate/GIC_STATE_MAX); break; case ZPLUS: turn_add(0,1,-M_PI/180.0*newstate/GIC_STATE_MAX); break; case ZMINUS: turn_add(0,1, M_PI/180.0*newstate/GIC_STATE_MAX); break; case ZOOMIN: scale(1.01); break; case ZOOMOUT: scale(1.0/1.01); break; case STOP: stop_speed(); break; } } /* Note, that you can pretty safely have cheatcodes in your LibGIC * configuration. I hope that breaking this is about as hard/easy as * just debug-tracing the program. * The default cheat is "gabbagabbahey" in honor of the great minds that * inspired LibGIC. */ /* This is an extra cookie, computed from the entered code. While you can * easily manipulate the first cookie stored in teh LibGIC file, this is * harder, as it is here, under your control. * The first one is basically there to avoid bothering you with tons of false * calls here. */ #define CHEATCOOKIE 0x68b9d7f0 static void cheat_action(gic_handle_t hand, gic_actionlist *action, gic_feature *feature, gic_state newstate,gic_flag flag,int recnum) { #if 0 printf("Cheat: %08x\n",newstate); /* Use that to find out the cookie ... */ #endif if (newstate!=CHEATCOOKIE) return; printf("Yes - you cheated right !\n"); } /* Programming model 2: Changing some global state variables. * This is not too nice, but simple and effective and you can use a very simple * and generic action handler. */ struct globalstate { int autoactive; /* automatic activation of "frontmost" face */ int doalign; /* autoalignment in progress */ int backfaces; /* show back faces */ int transparency; /* make color 0 transparent */ int quit; /* get me out of here */ int wantmenu; /* give me a menu */ } globalstate= { 0,0,1,1,0,0 }; static void action_toggle(gic_handle_t hand, gic_actionlist *action, gic_feature *feature, gic_state newstate,gic_flag flag,int recnum) { #if 0 printf("toggle for %p %p %p : %x\n", (void *)hand, (void *)action, (void *)feature, newstate); #endif if (newstate>GIC_STATE_MIDDLE) *((int *)action->privdata)=!*((int *)action->privdata); } /* Programming model 3: Use a predefined action handling system. The "lazy" * handler is a relatively sophisticated default case handler for the * average programmer (hence the name). * Compared to model 2 it is smart about PULSED action activations and * multiple simultaneously activated Recognizers. * This is recommended for game axis and such, that are processed once per * frame. */ gicActionLazyData strafe_left,strafe_right; /* As one cannot reliably save function mappings, you need a table for * mapping between action-names (like "mynextaction") and the functions * (like my_action()) you want to be called and their "privdata" argument * which can be used to distinguish multiple different features, that * essentially call the same action function. */ gic_actionlist actionmapping[]= { /* The game context stuff */ {NULL,"boss", boss_action, NULL}, {NULL,"cheat", cheat_action, NULL}, {NULL,"strafe_left", lazy_action, &strafe_left}, {NULL,"strafe_right", lazy_action, &strafe_right}, {NULL,"turn_up", turn_action, &directions[XPLUS]}, {NULL,"turn_down", turn_action, &directions[XMINUS]}, {NULL,"turn_left", turn_action, &directions[YPLUS]}, {NULL,"turn_right", turn_action, &directions[YMINUS]}, {NULL,"tilt_left", turn_action, &directions[ZPLUS]}, {NULL,"tilt_right", turn_action, &directions[ZMINUS]}, {NULL,"zoom_in", turn_action, &directions[ZOOMIN]}, {NULL,"zoom_out", turn_action, &directions[ZOOMOUT]}, {NULL,"stop", turn_action, &directions[STOP]}, {NULL,"autoactive", action_toggle, &globalstate.autoactive}, {NULL,"doalign", action_toggle, &globalstate.doalign}, {NULL,"backfaces", action_toggle, &globalstate.backfaces}, {NULL,"transparency", action_toggle, &globalstate.transparency}, {NULL,"quit", action_toggle, &globalstate.quit}, {NULL,"menu", action_toggle, &globalstate.wantmenu}, /* The menu things */ {NULL,"menu_next", lazy_action, &menu_next}, {NULL,"menu_prev", lazy_action, &menu_prev}, {NULL,"menu_activate", lazy_action, &menu_activate}, {NULL,"menu_break", lazy_action, &menu_break}, {NULL,NULL,NULL,NULL} }; /* Now for the main routine, which rotates a 3d cube and while doing so * demonstrates how a LibGIC using program looks like. * * Much of the cruft in here comes from the cube stuff. * LibGIC specifics are marked with a / *GIC* / comment * at the start of the line. */ int main(int argc, char **argv) { /* First we define a bunch of variables we will access throughout the * main() function. Most of them are pretty meaningless loop-counters * and helper-variables. */ const char *prog; /* Make an alias for the program name */ ggi_color map; /* Helper for color mapping */ ggi_graphtype type; /* graphics type */ int depth; /* bit depth */ int err,x; /* counters and other helpers. */ int frame=-1; /* The frame we are drawing on. */ int frcnt=0; /* framecounter for profiling performace */ clock_t clk; /* clock helper for profiling */ struct timeval tv; /* timeout for polling the keyboard */ int active_face=0; /* program state. Active face of the cube */ int blink=0; /* make the active frame blink */ zorder3D *zorder; /* The mode we want. 2 frames for doublebuffering */ ggi_mode mode = { /* This will cause the default mode to be set */ 2, /* 2 frames */ {GGI_AUTO,GGI_AUTO}, /* Default size */ {GGI_AUTO,GGI_AUTO}, /* Virtual */ {0,0}, /* size in mm don't care */ GT_AUTO, /* Mode */ {GGI_AUTO,GGI_AUTO} /* Font size */ }; /* gic_handle_t is an opaque handle to any instance of LibGIC running. */ /*gic*/ gic_handle_t handle; /* gic_head is a type that stores a collection of different * "contexts". A typical application will have several contexts, * as you will want different actions to be invoked, when you * are using the cursors inside say the game engine or in a * configuration menu. */ /*gic*/ gic_head *head; /* This demo features two such contexts: */ /*gic*/ gic_context *menu,*game; /* The "real" LibGIC configuration info is read from a file. * Note, that LIbGIC configuration info is human-readable, line * oriented, and you can detect LibGIC generated lines by the * "gic:" prefix. This should allow you to insert LibGIC data * in about any style configuration file. Remember, that LibGIC * configuration data size is variable, as you can add/delete * bindings. */ /*gic*/ FILE *config; /* Get the arguments from the command line. * Set defaults for optional arguments. */ prog=*argv; argv++; argc--; if (strrchr(prog, '/') != NULL) prog=strrchr(prog, '/')+1; /* Allocate Z order array. */ if (NULL==(zorder=malloc(sizeof(zorder3D)*the_scene.numpolys))) { fprintf(stderr, "unable to allocate zorder buffer.\n"); exit(1); } /* Initialize LibGIC */ /*gic*/ if (gicInit()) { fprintf(stderr, "Unable to initialize LibGIC, exiting.\n"); exit(1); } /* Now open a gic context. This is useful for attaching a GII input to * it, opening multiple independent instances of LibGIC etc. * the argument gives the recognizers to load. Use NULL for default. * There is rarely reason to deviate from that. */ if (NULL==(handle=gicOpen(NULL))) { fprintf(stderr, "Unable to open LibGIC handle, exiting.\n"); gicExit(); exit(1); } /* Keep the handle for the configmanager. It will make use of it. */ my_cfmgr_info.handle=handle; /* Reset the state of the two Actionlib Lazy state variables. */ gicActionLazyReset(&strafe_left); gicActionLazyReset(&strafe_right); /* Open up GGI and a visual. */ if (ggiInit() != 0) { fprintf(stderr, "unable to initialize libggi, exiting.\n"); /*gic*/ gicClose(handle); /* Be nice - close it down as well.*/ gicExit(); exit(1); } vis=ggiOpen(NULL); if (vis == NULL) { fprintf(stderr, "unable to open default visual, exiting.\n"); ggiExit(); /*gic*/ gicClose(handle); /* Be nice ... */ gicExit(); exit(1); } /* Go to async-mode. */ ggiSetFlags(vis, GGIFLAG_ASYNC); /* Check and set the mode ... */ ggiCheckMode(vis,&mode); fprintf(stderr,"Suggested mode "); ggiFPrintMode(stderr,&mode); fprintf(stderr,"\n"); err=ggiSetMode(vis,&mode); /* now try it. it *should* work! */ if (err) { fprintf(stderr,"Can't set mode\n"); ggiClose(vis); ggiExit(); /*gic*/ gicClose(handle); /* Still nice ... */ gicExit(); return 2; } if (mode.frames>1) frame=0; /* We can frameflip. */ type=mode.graphtype; my_cfmgr_info.screen_size.x=vissizex=mode.visible.x; my_cfmgr_info.screen_size.y=vissizey=mode.visible.y; ggiGetCharSize(vis, &my_cfmgr_info.small_size.x, &my_cfmgr_info.small_size.y); my_cfmgr_info.big_size = my_cfmgr_info.small_size; my_cfmgr_info.item_gap = my_cfmgr_info.small_size; my_cfmgr_info.binding_gap = my_cfmgr_info.small_size; depth=GT_DEPTH(mode.graphtype); if (GT_SCHEME(mode.graphtype) == GT_PALETTE) { ggiSetColorfulPalette(vis); } map.r= map.g= map.b= 0xFFFF; white= ggiMapColor(vis, &map); map.r= map.g= map.b= 0x0; black= ggiMapColor(vis, &map); map.g= map.b= 0x0; map.r= 0xFFFF; red = ggiMapColor(vis, &map); the_polys[0].color=ggiMapColor(vis, &map); map.r=0x0000; map.g=0xffff; map.b=0x0000; the_polys[1].color=ggiMapColor(vis, &map); map.r=0x0000; map.g=0x0000; map.b=0xffff; the_polys[2].color=ggiMapColor(vis, &map); map.r=0xffff; map.g=0x0000; map.b=0xffff; the_polys[3].color=ggiMapColor(vis, &map); map.r=0xffff; map.g=0xffff; map.b=0x0000; the_polys[4].color=ggiMapColor(vis, &map); map.r=0x0000; map.g=0xffff; map.b=0xffff; the_polys[5].color=ggiMapColor(vis, &map); ggiSetGCForeground(vis, black); ggiFillscreen(vis); ggiSetGCForeground(vis, white); ggiSetGCBackground(vis, black); ggiPuts(vis,0,0,"Hold on - creating faces."); ggiFlush(vis); /* O.K. - we are up and running. Register the LibGGI input. * The JoinInputs(vis,NULL) trick is used to get at the LibGGI * internal input structures. * * This is only needed for valuators and such, where you have * to talk to the event provider Lib for persistent storage. * * As long as you use LibGII/LibGGI for input, you should call * that. If you don't - tough luck. */ /*gic*/ gicInputRegister(handle, ggiJoinInputs(vis,NULL)); /* Read in the config file. It it is not there, create it from the * compiled in default. Yes - it _is_ that simple. */ /*gic*/ config=fopen("ggidemo.gic","r"); if (!config) { config=fopen("ggidemo.gic","w"); gicWriteDefaultConfig(config); fclose(config); config=fopen("ggidemo.gic","r"); } head=gicHeadRead(handle,config); fclose(config); /* This is the head we might want to reconfigure later ... */ /*gic*/ my_cfmgr_info.head = head; /* Now look up the contexts in the head. You could as well store * individual contexts, but this is much more convenient. */ menu=gicHeadLookupContext(handle, head,"Menu context"); game=gicHeadLookupContext(handle, head,"Game context"); /*gic*/ printf("Looked up contexts game=%p menu=%p.\n", (void *)game, (void *)menu); /* We have the structure, but actions are not completely mapped yet, * as there is no way to portably store function addresses and contents * of "void *privdata". Use the mapping table shown above to re- * establish those. */ printf("(Re)mapping all events.\n"); /*gic*/ gicHeadMapActions(handle, head,actionmapping); clk=clock(); stop_speed(); scale(vissizey/150.0/1.10*0.5); /* Scale to 50% of screen */ Matrix_times_Matrix((double *)current,(double *)speed); stop_speed(); while(!globalstate.quit) { /* Take care for the blinking border */ blink=!blink; /* Calculate the new turn Matrix */ Matrix_times_Matrix((double *)current,(double *)speed); /* Now transform _all_ points. */ for(x=0;xzorder[y].zmiddle) break; for(z=x;z>y;z--) zorder[z]=zorder[z-1]; zorder[y].zmiddle=the_scene.polys[x].middle[2]; zorder[y].polynum=x; } if (globalstate.autoactive) { double best=0.0; for(x=0;xbest ) { best=the_scene.polys[x].visible; active_face=x; } } } if (globalstate.backfaces) { for(x=0;xthe_scene.polys[y].visible) { doblit( &the_scene.polys[y], globalstate.transparency); if (y==active_face) { ggiSetGCForeground(vis, blink ? black : red ); highlight_face(&the_scene.polys[y]); } } } } else { for(x=0;x<6;x++) { int y=zorder[x].polynum; if (0.0>the_scene.polys[y].visible && y==active_face) { ggiSetGCForeground(vis, blink ? black : red ); highlight_face(&the_scene.polys[y]); } } } for(x=0;x<6;x++) { int y=zorder[x].polynum; if (0.0<=the_scene.polys[y].visible) { doblit( &the_scene.polys[y], globalstate.transparency); if (y==active_face) { ggiSetGCForeground(vis, blink ? black : red ); highlight_face(&the_scene.polys[y]); } } } if (globalstate.doalign) if (align(&the_scene.polys[active_face])) globalstate.doalign=0; tv.tv_sec=tv.tv_usec=0; while(ggiEventPoll(vis,emAll,&tv)) { /* LibGIC is designed to get input from gii_events. In case you * are not using LibGII for input (why ?), you'll need to convert * to LibGII event format. The recognizers need to understand * what they shall parse ... */ ggi_event event; ggiEventRead(vis,&event,emAll); /*gic*/ gicContextHandleEvent(handle, game, &event); /* Check the state of the Lazy recognizers. */ /*gic*/ if (gicActionLazyGetstate(&strafe_left)>GIC_STATE_MIDDLE) { printf("Strafing left !\n"); } if (gicActionLazyGetstate(&strafe_right)>GIC_STATE_MIDDLE) { printf("Strafing right !\n"); } /* Check the globalstate. It might have been changed. */ if (globalstate.wantmenu) { globalstate.wantmenu=0; if (main_menu(handle,menu)) globalstate.quit=1; } /* O.K. - nothing we want to handle with LibGIC. Maybe * we parse a few events ourselves. No need for * overkill - right ? */ if (event.any.type==evKeyPress) { switch(event.key.sym) { case '0': globalstate.autoactive=0; active_face=0; break; case '1': globalstate.autoactive=0; active_face=1; break; case '2': globalstate.autoactive=0; active_face=2; break; case '3': globalstate.autoactive=0; active_face=3; break; case '4': globalstate.autoactive=0; active_face=4; break; case '5': globalstate.autoactive=0; active_face=5; break; case 'f': case 'F': printf("FPS:%f\n",(double)frcnt/(clock()-clk+1.0)*CLOCKS_PER_SEC); clk=clock();frcnt=0; break; default: #if 0 printf("Unknown command key 0x%x\n",event.key.sym); #endif break; } } } if (frame>=0) { ggiSetDisplayFrame(vis,frame); } ggiFlush(vis); frcnt++; if (frame >= 0) ggiSetWriteFrame(vis,frame=!frame); ggiSetGCForeground(vis, black); ggiFillscreen(vis); } ggiClose(vis); ggiExit(); /*gic*/ gicClose(handle); /* Close down the instance */ gicExit(); /* Close down LibGIC */ return 0; }