/* $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 <ggi/gic.h>
#include <ggi/gicaction_lazy.h>
#include <ggi/gic_confmgr.h>
#include <ggi/ggi.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#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]<miny)
miny=poly->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.xpos<min.xpos) {
min=hlp;
/* Avoid double calculation: */
if (hlp.xpos>max.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<NUMMMENPT;x++) { /* draw menu entries. */
if (curpos==x) { /* current entry */
ggiSetGCForeground(vis,black);
ggiSetGCBackground(vis,white);
} else { /* other entries */
ggiSetGCForeground(vis,white);
ggiSetGCBackground(vis,black);
}
ggiPuts(vis,xstart,ystart+10*x,menu[x]);
}
ggiFlush(vis); /* O.K. - make it seen. */
if (ggiEventPoll(vis,emAll,NULL)) { /* Wait for an event. */
/* Note, that waiting with a NULL timeout is not actually
* what the lazy recognizer is designed for, but for a menu
* that shouldn't matter.
*/
ggi_event event; /* get an event. */
ggiEventRead(vis,&event,emAll);
/* Let LibGIC evaluate it for the menu context.
*/
gicContextHandleEvent(hand, menucon, &event);
/* Now check all the ActionLazy state variables and
* act accordingly. All decisions here are binary,
* so we just compare to GIC_STATE_MIDDLE.
*/
if (gicActionLazyGetstate(&menu_next) > GIC_STATE_MIDDLE) {
if (curpos<NUMMMENPT-1) curpos++;
}
if (gicActionLazyGetstate(&menu_prev) > 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;x<numpoints;x++) {
transform_point((double *)current,&the_original_points[x],&the_points[x]);
}
/* Calculate the new normals. */
for(x=0;x<the_scene.numpolys;x++) {
int y,z;
normvec_poly(the_scene.polys+x);
midvec_poly(the_scene.polys+x);
visible_poly(the_scene.polys+x);
for(y=0;y<x;y++)
if (the_scene.polys[x].middle[2]>zorder[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;x<the_scene.numpolys;x++) {
if (the_scene.polys[x].visible>best ) {
best=the_scene.polys[x].visible;
active_face=x;
}
}
}
if (globalstate.backfaces) {
for(x=0;x<the_scene.numpolys;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]);
}
}
}
} 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;
}
syntax highlighted by Code2HTML, v. 0.9.1