diff options
| author | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
| commit | badef32037f52f79abc1f1440b786cd71afdf270 (patch) | |
| tree | 412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/glx/winduprobot.c | |
| parent | Delete pre-6.00 files (diff) | |
| download | xscreensaver-master.tar.gz xscreensaver-master.tar.xz xscreensaver-master.zip | |
Diffstat (limited to 'hacks/glx/winduprobot.c')
| -rw-r--r-- | hacks/glx/winduprobot.c | 2504 |
1 files changed, 0 insertions, 2504 deletions
diff --git a/hacks/glx/winduprobot.c b/hacks/glx/winduprobot.c deleted file mode 100644 index 237352d..0000000 --- a/hacks/glx/winduprobot.c +++ /dev/null @@ -1,2504 +0,0 @@ -/* winduprobot, Copyright (c) 2014-2018 Jamie Zawinski <jwz@jwz.org> - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation. No representations are made about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * Draws a robot wind-up toy. - * - * I've had this little robot since I was about six years old! When the time - * came for us to throw the Cocktail Robotics Grand Challenge at DNA Lounge, I - * photographed this robot (holding a tiny martini glass) to make a flyer for - * the event. You can see that photo here: - * https://www.dnalounge.com/flyers/2014/09/14.html - * - * Then I decided to try and make award statues for the contest by modeling - * this robot and 3D-printing it (a robot on a post, with the DNA Lounge - * grommet around it.) So I learned Maya and built a model. - * - * Well, that 3D printing idea didn't work out, but since I had the model - * already, I exported it and turned it into a screen saver. - * - * The DXF files that Maya exports aren't simple enough for my dxf2gl.pl - * script to process, so the exporting process went: - * - * - Save from Maya to OBJ; - * - Import OBJ into SketchUp using - * http://www.scriptspot.com/sketchup/scripts/obj-importer - * - Clean up the model a little bit more; - * - Export to DXF with "Millimeters", "Triangles", using - * http://www.guitar-list.com/download-software/convert-sketchup-skp-files-dxf-or-stl - * - * We did eventually end up with robotic award statues, but we constructed - * them out of mass-produced wind-up robots, rather than 3D printing them: - * https://www.dnalounge.com/gallery/2014/09-14/045.html - * https://www.youtube.com/watch?v=EZF4ZAAy49g - */ - -#define LABEL_FONT "sans-serif bold 24" - -#define DEFAULTS "*delay: 20000 \n" \ - "*count: 25 \n" \ - "*showFPS: False \n" \ - "*wireframe: False \n" \ - "*labelFont: " LABEL_FONT "\n" \ - "*legColor: #AA2222" "\n" \ - "*armColor: #AA2222" "\n" \ - "*handColor: #AA2222" "\n" \ - "*crankColor: #444444" "\n" \ - "*bodyColor: #7777AA" "\n" \ - "*domeColor: #7777AA" "\n" \ - "*insideColor: #DDDDDD" "\n" \ - "*gearboxColor: #444488" "\n" \ - "*gearColor: #008877" "\n" \ - "*wheelColor: #007788" "\n" \ - "*wireColor: #006600" "\n" \ - "*groundColor: #0000FF" "\n" \ - "*textColor: #FFFFFF""\n" \ - "*textBackground: #444444""\n" \ - "*textBorderColor: #FFFF88""\n" \ - "*textLines: 10 \n" \ - "*program: xscreensaver-text\n" \ - "*usePty: False\n" - -#undef DEBUG -#define WORDBUBBLES - -# define release_robot 0 - -#define DEF_SPEED "1.0" -#define DEF_ROBOT_SIZE "1.0" -#define DEF_TEXTURE "True" -#define DEF_FADE "True" -#define DEF_OPACITY "1.0" -#define DEF_TALK "0.2" - -#include "xlockmore.h" -#include "gltrackball.h" -#include "ximage-loader.h" -#include "involute.h" -#include "sphere.h" - -#ifdef WORDBUBBLES -# include "textclient.h" -# include "texfont.h" -#endif - -#include <ctype.h> - -#ifndef HAVE_JWZGLES /* No SPHERE_MAP on iPhone */ -# define HAVE_TEXTURE -#endif - -#ifdef HAVE_TEXTURE -# include "images/gen/chromesphere_png.h" -#endif - -#ifdef USE_GL /* whole file */ - -#include "gllist.h" - -extern const struct gllist - *robot_arm_half, *robot_body_half_outside, *robot_body_half_inside, - *robot_crank_full, *robot_gearbox_half, *robot_hand_half, - *robot_leg_half, *robot_rotator_half, *robot_wireframe; - -static struct gllist *robot_dome = 0, *robot_gear = 0, *ground = 0; - -static const struct gllist * const *all_objs[] = { - &robot_arm_half, &robot_body_half_outside, &robot_body_half_inside, - &robot_crank_full, &robot_gearbox_half, &robot_hand_half, - &robot_leg_half, &robot_rotator_half, &robot_wireframe, - (const struct gllist * const *) &robot_dome, - (const struct gllist * const *) &robot_gear, - (const struct gllist * const *) &ground -}; - -#define ROBOT_ARM 0 -#define ROBOT_BODY_1 1 -#define ROBOT_BODY_2 2 -#define ROBOT_CRANK 3 -#define ROBOT_GEARBOX 4 -#define ROBOT_HAND 5 -#define ROBOT_LEG 6 -#define ROBOT_ROTATOR 7 -#define ROBOT_WIREFRAME 8 -#define ROBOT_DOME 9 -#define ROBOT_GEAR 10 -#define GROUND 11 - -typedef struct { - GLfloat x, y, z; /* position */ - GLfloat facing; /* direction of front of robot, degrees */ - GLfloat pitch; /* front/back tilt angle, degrees */ - GLfloat roll; /* left/right tilt angle, degrees */ - GLfloat speed; /* some robots are faster */ - GLfloat crank_rot; /* gear state, degrees */ - GLfloat hand_rot[2]; /* rotation of the hands, degrees */ - GLfloat hand_pos[2]; /* openness of the hands, ratio */ - GLfloat balance; /* how off-true does it walk? degrees */ - GLfloat body_transparency; /* ratio */ - int fading_p; /* -1, 0, 1 */ - -} walker; - -typedef struct { - GLXContext *glx_context; - trackball_state *user_trackball; - Bool button_down_p; - - GLuint *dlists; - GLfloat component_colors[countof(all_objs)][4]; - - int nwalkers; - walker *walkers; - - GLfloat looking_x, looking_y, looking_z; /* Where camera is aimed */ - GLfloat olooking_x, olooking_y, olooking_z; /* Where camera was aimed */ - Bool camera_tracking_p; /* Whether camera in motion */ - GLfloat tracking_ratio; - -# ifdef HAVE_TEXTURE - GLuint chrome_texture; -# endif - -# ifdef WORDBUBBLES - texture_font_data *font_data; - int bubble_tick; - text_data *tc; - char words[10240]; - int lines, max_lines; - - GLfloat text_color[4], text_bg[4], text_bd[4]; - -# endif /* WORDBUBBLES */ - - -# ifdef DEBUG - GLfloat debug_x, debug_y, debug_z; -# endif - -} robot_configuration; - -static robot_configuration *bps = NULL; - -static GLfloat speed, size, opacity; -static int do_texture, do_fade; -#ifdef WORDBUBBLES -static GLfloat talk_chance; -#endif -#ifdef DEBUG -static int debug_p; -#endif - -static XrmOptionDescRec opts[] = { - { "-speed", ".speed", XrmoptionSepArg, 0 }, - { "-size", ".robotSize", XrmoptionSepArg, 0 }, - { "-opacity", ".opacity", XrmoptionSepArg, 0 }, - { "-talk", ".talk", XrmoptionSepArg, 0 }, - {"-texture", ".texture", XrmoptionNoArg, "True" }, - {"+texture", ".texture", XrmoptionNoArg, "False" }, - {"-fade", ".fade", XrmoptionNoArg, "True" }, - {"+fade", ".fade", XrmoptionNoArg, "False" }, -#ifdef DEBUG - {"-debug", ".debug", XrmoptionNoArg, "True" }, - {"+debug", ".debug", XrmoptionNoArg, "False" }, -#endif -}; - -static argtype vars[] = { - {&speed, "speed", "Speed", DEF_SPEED, t_Float}, - {&size, "robotSize", "RobotSize", DEF_ROBOT_SIZE, t_Float}, - {&opacity, "opacity", "Opacity", DEF_OPACITY, t_Float}, - {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool}, - {&do_fade, "fade", "Fade", DEF_FADE, t_Bool}, -#ifdef WORDBUBBLES - {&talk_chance, "talk", "Talk", DEF_TALK, t_Float}, -#endif -#ifdef DEBUG - {&debug_p, "debug", "Debug", "False", t_Bool}, -#endif -}; - -ENTRYPOINT ModeSpecOpt robot_opts = { - countof(opts), opts, countof(vars), vars, NULL}; - - -/* Window management, etc - */ -ENTRYPOINT void -reshape_robot (ModeInfo *mi, int width, int height) -{ - GLfloat h = (GLfloat) height / (GLfloat) width; - int y = 0; - - if (width > height * 5) { /* tiny window: show middle */ - height = width * 9/16; - y = -height/2; - h = height / (GLfloat) width; - } - - glViewport (0, y, width, height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective (40.0, 1/h, 1.0, 250); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt( 0, 0, 30, - 0, 0, 0, - 0, 1, 0); - - glClear(GL_COLOR_BUFFER_BIT); - -# ifdef WORDBUBBLES - { - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int w = (width < 800 ? 25 : 40); - int h = 1000; - if (bp->tc) - textclient_reshape (bp->tc, w, h, w, h, - /* Passing bp->max_lines isn't actually necessary */ - 0); - } -# endif - -} - - -ENTRYPOINT Bool -robot_handle_event (ModeInfo *mi, XEvent *event) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - - if (gltrackball_event_handler (event, bp->user_trackball, - MI_WIDTH (mi), MI_HEIGHT (mi), - &bp->button_down_p)) - return True; -#ifdef DEBUG - else if (event->xany.type == KeyPress && debug_p) - { - KeySym keysym; - char c = 0; - double n[3] = { 1.0, 0.1, 0.1 }; - int s = (event->xkey.state & ShiftMask ? 10 : 1); - - XLookupString (&event->xkey, &c, 1, &keysym, 0); - - if (keysym == XK_Right) bp->debug_x += n[0] * s; - else if (keysym == XK_Left) bp->debug_x -= n[0] * s; - else if (keysym == XK_Up) bp->debug_y += n[1] * s; - else if (keysym == XK_Down) bp->debug_y -= n[1] * s; - else if (c == '=' || c == '+') bp->debug_z += n[2] * s; - else if (c == '-' || c == '_') bp->debug_z -= n[2] * s; - else if (c == ' ') bp->debug_x = bp->debug_y = bp->debug_z = 0; - else if (c == '\n' || c == '\r') - fprintf (stderr, "%.4f %.4f %.4f\n", - bp->debug_x, bp->debug_y, bp->debug_z); - else return False; - return True; - } -#endif /* DEBUG */ - - return False; -} - - -#ifdef HAVE_TEXTURE - -static void -load_textures (ModeInfo *mi) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - XImage *xi; - - xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual, - chromesphere_png, sizeof(chromesphere_png)); - clear_gl_error(); - - glGenTextures (1, &bp->chrome_texture); - glBindTexture (GL_TEXTURE_2D, bp->chrome_texture); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, - xi->width, xi->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, xi->data); - check_gl_error("texture"); - XDestroyImage (xi); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glEnable(GL_TEXTURE_2D); -} - -#endif /* HAVE_TEXTURE */ - - -static int unit_gear (ModeInfo *, GLfloat color[4]); -static int draw_ground (ModeInfo *, GLfloat color[4]); -static void init_walker (ModeInfo *, walker *); - -static void -parse_color (ModeInfo *mi, char *key, GLfloat color[4]) -{ - XColor xcolor; - char *string = get_string_resource (mi->dpy, key, "RobotColor"); - if (!XParseColor (mi->dpy, mi->xgwa.colormap, string, &xcolor)) - { - fprintf (stderr, "%s: unparsable color in %s: %s\n", progname, - key, string); - exit (1); - } - free (string); - - color[0] = xcolor.red / 65536.0; - color[1] = xcolor.green / 65536.0; - color[2] = xcolor.blue / 65536.0; - color[3] = 1; -} - - -ENTRYPOINT void -init_robot (ModeInfo *mi) -{ - robot_configuration *bp; - int wire = MI_IS_WIREFRAME(mi); - int i; - MI_INIT (mi, bps); - - bp = &bps[MI_SCREEN(mi)]; - - bp->glx_context = init_GL(mi); - - reshape_robot (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - -# ifdef HAVE_TEXTURE - if (!wire && do_texture) - load_textures (mi); -# endif - - bp->user_trackball = gltrackball_init (False); - - bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint)); - for (i = 0; i < countof(all_objs); i++) - bp->dlists[i] = glGenLists (1); - - for (i = 0; i < countof(all_objs); i++) - { - const struct gllist *gll = *all_objs[i]; - char *key = 0; - GLfloat spec1[4] = {1.00, 1.00, 1.00, 1.0}; - GLfloat spec2[4] = {0.40, 0.40, 0.70, 1.0}; - GLfloat *spec = 0; - GLfloat shiny = 20; - - glNewList (bp->dlists[i], GL_COMPILE); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - - glRotatef (-90, 1, 0, 0); - glRotatef (180, 0, 0, 1); - glScalef (6, 6, 6); - - glBindTexture (GL_TEXTURE_2D, 0); - - switch (i) { - case ROBOT_BODY_1: - key = "bodyColor"; - spec = spec1; - shiny = 128; -# ifdef HAVE_TEXTURE - if (do_texture) - { - glBindTexture (GL_TEXTURE_2D, bp->chrome_texture); - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - } -# endif - break; - case ROBOT_DOME: - key = "domeColor"; - spec = spec1; - shiny = 128; -# ifdef HAVE_TEXTURE - if (do_texture) - { - glBindTexture (GL_TEXTURE_2D, bp->chrome_texture); - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - } -# endif - break; - case ROBOT_BODY_2: - key = "insideColor"; - spec = spec2; - shiny = 128; - break; - case ROBOT_ARM: - key = "armColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_HAND: - key = "handColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_LEG: - key = "legColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_CRANK: - key = "crankColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_ROTATOR: - key = "wheelColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_GEAR: - key = "gearColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_GEARBOX: - key = "gearboxColor"; - spec = spec2; - shiny = 20; - break; - case ROBOT_WIREFRAME: - key = "wireColor"; - spec = spec2; - shiny = 20; - break; - case GROUND: - key = "groundColor"; - spec = spec2; - shiny = 20; - break; - default: - abort(); - } - - parse_color (mi, key, bp->component_colors[i]); - - glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec); - glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny); - - switch (i) { - case ROBOT_DOME: - if (! robot_dome) - robot_dome = (struct gllist *) calloc (1, sizeof(*robot_dome)); - robot_dome->points = unit_dome (32, 32, MI_IS_WIREFRAME(mi)); - break; - case ROBOT_GEAR: - if (! robot_gear) - robot_gear = (struct gllist *) calloc (1, sizeof(*robot_gear)); - robot_gear->points = unit_gear (mi, bp->component_colors[i]); - break; - case GROUND: - if (! ground) - ground = (struct gllist *) calloc (1, sizeof(*ground)); - ground->points = draw_ground (mi, bp->component_colors[i]); - break; - case ROBOT_WIREFRAME: - glLineWidth (0.3); - renderList (gll, True); - break; - default: - renderList (gll, wire); - /* glColor3f (1, 1, 1); renderListNormals (gll, 100, True); */ - /* glColor3f (1, 1, 0); renderListNormals (gll, 100, False); */ - break; - } - - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glEndList (); - } - -# ifdef DEBUG - if (debug_p) MI_COUNT(mi) = 1; -# endif - - bp->nwalkers = MI_COUNT(mi); - bp->walkers = (walker *) calloc (bp->nwalkers, sizeof (walker)); - - for (i = 0; i < bp->nwalkers; i++) - init_walker (mi, &bp->walkers[i]); - - /* Since #0 is the one we track, make sure it doesn't walk too straight. - */ - bp->walkers[0].balance *= 1.5; - -# ifdef WORDBUBBLES - bp->font_data = load_texture_font (mi->dpy, "labelFont"); - bp->max_lines = get_integer_resource (mi->dpy, "textLines", "TextLines"); - bp->tc = textclient_open (MI_DISPLAY (mi)); - - parse_color (mi, "textColor", bp->text_color); - parse_color (mi, "textBackground", bp->text_bg); - parse_color (mi, "textBorderColor", bp->text_bd); - - reshape_robot (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - -# endif /* WORDBUBBLES */ - -# ifdef DEBUG - if (!debug_p) -# endif - /* Let's tilt the floor a little. */ - gltrackball_reset (bp->user_trackball, - -0.6 + frand(1.2), - -0.6 + frand(0.2)); -} - - -static int -draw_component (ModeInfo *mi, int i) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, - bp->component_colors[i]); - glCallList (bp->dlists[i]); - return (*all_objs[i])->points / 3; -} - -static int -draw_transparent_component (ModeInfo *mi, int i, GLfloat alpha) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - int count = 0; - - if (alpha < 0) return 0; - if (alpha > 1) alpha = 1; - bp->component_colors[i][3] = alpha; - - if (wire || alpha >= 1) - return draw_component (mi, i); - - /* Draw into the depth buffer but not the frame buffer */ - glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - count += draw_component (mi, i); - - /* Now draw into the frame buffer only where there's already depth */ - glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDepthFunc (GL_EQUAL); - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - count += draw_component (mi, i); - glDepthFunc (GL_LESS); - glDisable (GL_BLEND); - return count; -} - - - -static int -draw_arm_half (ModeInfo *mi, walker *f) -{ - int count = 0; - glPushMatrix(); - count += draw_transparent_component (mi, ROBOT_ARM, f->body_transparency); - glPopMatrix(); - return count; -} - -static int -draw_hand_half (ModeInfo *mi, walker *f) -{ - int count = 0; - glPushMatrix(); - count += draw_transparent_component (mi, ROBOT_HAND, f->body_transparency); - glPopMatrix(); - return count; -} - - -/* rotation of arm: 0-360. - openness of fingers: 0.0 - 1.0. - */ -static int -draw_arm (ModeInfo *mi, walker *f, GLfloat left_p, GLfloat rot, GLfloat open) -{ - int count = 0; - GLfloat arm_x = 4766; /* distance from origin to arm axis */ - GLfloat arm_y = 12212; - - open *= 5.5; /* scale of finger range */ - -# ifdef DEBUG - if (debug_p) rot = 0; -# endif - - glPushMatrix(); - - if (! left_p) - glTranslatef (0, 0, arm_x * 2); - - glTranslatef (0, arm_y, -arm_x); /* move to origin */ - glRotatef (rot, 1, 0, 0); - glTranslatef (0, -arm_y, arm_x); /* move back */ - - glFrontFace(GL_CCW); - count += draw_arm_half (mi, f); - - glScalef (1, -1, 1); - glTranslatef (0, -arm_y * 2, 0); - glFrontFace(GL_CW); - count += draw_arm_half (mi, f); - - glPushMatrix(); - glTranslatef (0, 0, -arm_x * 2); - glScalef (1, 1, -1); - glFrontFace(GL_CCW); - count += draw_arm_half (mi, f); - - glScalef (1, -1, 1); - glTranslatef (0, -arm_y * 2, 0); - glFrontFace(GL_CW); - count += draw_arm_half (mi, f); - glPopMatrix(); - - glTranslatef (0, 0, open); - glFrontFace(GL_CW); - count += draw_hand_half (mi, f); - - glTranslatef (0, 0, -open); - glScalef (1, 1, -1); - glTranslatef (0, 0, arm_x * 2); - glFrontFace(GL_CCW); - glTranslatef (0, 0, open); - count += draw_hand_half (mi, f); - - glPopMatrix(); - return count; -} - - -static int -draw_body_half (ModeInfo *mi, walker *f, Bool inside_p) -{ - int count = 0; - int which = (inside_p ? ROBOT_BODY_2 : ROBOT_BODY_1); - glPushMatrix(); - count += draw_transparent_component (mi, which, f->body_transparency); - glPopMatrix(); - return count; -} - - -static int -draw_body (ModeInfo *mi, walker *f, Bool inside_p) -{ - int count = 0; - glPushMatrix(); - - glFrontFace(GL_CCW); - count += draw_body_half (mi, f, inside_p); - - glScalef (1, 1, -1); - glFrontFace(GL_CW); - count += draw_body_half (mi, f, inside_p); - - glPopMatrix(); - - return count; -} - - -static int -draw_gearbox_half (ModeInfo *mi) -{ - int count = 0; - glPushMatrix(); - count += draw_component (mi, ROBOT_GEARBOX); - glPopMatrix(); - return count; -} - - -static int -draw_gearbox (ModeInfo *mi) -{ - int count = 0; - glPushMatrix(); - - glFrontFace(GL_CCW); - count += draw_gearbox_half (mi); - - glScalef (1, 1, -1); - glFrontFace(GL_CW); - count += draw_gearbox_half (mi); - - glPopMatrix(); - return count; -} - - -static int -unit_gear (ModeInfo *mi, GLfloat color[4]) -{ - int wire = MI_IS_WIREFRAME(mi); - gear G = { 0, }; - gear *g = &G; - - g->r = 0.5; - g->nteeth = 16; - g->tooth_h = 0.12; - g->thickness = 0.32; - g->thickness2 = g->thickness * 0.5; - g->thickness3 = g->thickness; - g->inner_r = g->r * 0.7; - g->inner_r2 = g->r * 0.4; - g->inner_r3 = g->r * 0.1; - g->size = INVOLUTE_LARGE; - - g->color[0] = g->color2[0] = color[0]; - g->color[1] = g->color2[1] = color[1]; - g->color[2] = g->color2[2] = color[2]; - g->color[3] = g->color2[3] = color[3]; - - return draw_involute_gear (g, wire); -} - - -static int -draw_gear (ModeInfo *mi) -{ - int count = 0; - GLfloat n = 350; - glScalef (n, n, n); - count += draw_component (mi, ROBOT_GEAR); - return count; -} - - -static int -draw_crank (ModeInfo *mi, walker *f, GLfloat rot) -{ - int count = 0; - GLfloat origin = 12210.0; - - rot = -rot; - - glPushMatrix(); - - glTranslatef (0, origin, 0); /* position at origin */ - glRotatef (rot, 0, 0, 1); - - glPushMatrix(); - glRotatef (90, 1, 0, 0); - count += draw_gear (mi); - glPopMatrix(); - - glTranslatef (0, -origin, 0); /* move back */ - - glFrontFace(GL_CCW); - count += draw_component (mi, ROBOT_CRANK); - - glPopMatrix(); - - return count; -} - - -static int -draw_rotator_half (ModeInfo *mi) -{ - int count = 0; - glPushMatrix(); - count += draw_component (mi, ROBOT_ROTATOR); - glPopMatrix(); - return count; -} - - -static int -draw_rotator (ModeInfo *mi, walker *f, GLfloat rot) -{ - int count = 0; - GLfloat origin = 10093.0; - - glPushMatrix(); - - glTranslatef (0, origin, 0); /* position at origin */ - glRotatef (rot, 0, 0, 1); - - glPushMatrix(); - glRotatef (90, 1, 0, 0); - count += draw_gear (mi); - glPopMatrix(); - -# ifdef DEBUG - if (debug_p) - { - glDisable(GL_LIGHTING); - glBegin(GL_LINES); - glVertex3f(0, 0, -3000); - glVertex3f(0, 0, 3000); - glEnd(); - if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING); - } -# endif - - glTranslatef (0, -origin, 0); /* move back */ - - glFrontFace(GL_CCW); - count += draw_rotator_half (mi); - - glScalef (1, 1, -1); - glFrontFace(GL_CW); - glRotatef (180, 0, 0, 1); - glTranslatef (0, -origin * 2, 0); /* move back */ - count += draw_rotator_half (mi); - - glPopMatrix(); - return count; -} - - -static int -draw_leg_half (ModeInfo *mi) -{ - int count = 0; - glPushMatrix(); - count += draw_component (mi, ROBOT_LEG); - glPopMatrix(); - return count; -} - - -static int -draw_wireframe (ModeInfo *mi, walker *f) -{ - int wire = MI_IS_WIREFRAME(mi); - int count = 0; - GLfloat alpha = 0.6 - f->body_transparency; - if (alpha < 0) return 0; - alpha *= 0.3; - if (!wire) glDisable (GL_LIGHTING); - glPushMatrix(); - count += draw_transparent_component (mi, ROBOT_WIREFRAME, alpha); - glPopMatrix(); - if (!wire) glEnable (GL_LIGHTING); - return count; -} - - -static int -draw_leg (ModeInfo *mi, GLfloat rot, Bool left_p) -{ - int count = 0; - GLfloat x, y; - GLfloat leg_distance = 9401; /* distance from ground to leg axis */ - GLfloat rot_distance = 10110; /* distance from ground to rotator axis */ - GLfloat pin_distance = 14541; /* distance from ground to stop pin */ - GLfloat orbit_r = rot_distance - leg_distance; /* radius of rotation */ - - /* Actually it's the bottom of the pin minus its diameter, or something. */ - pin_distance -= 590; - - glPushMatrix(); - - if (left_p) - glRotatef (180, 0, 1, 0); - - if (!left_p) rot = -(rot + 180); - - rot -= 90; - - x = orbit_r * cos (-rot * M_PI / 180); - y = orbit_r * sin (-rot * M_PI / 180); - - { - /* Rotate the leg by angle B of the right A - triangle ABC, where: /: - / : - A = position of stop pin / : - D = position of rotator wheel's axis , - ~ ~ ~ - , - C = D + y , ' / : ' , - B = D + xy (leg's axis) , / : , - , / : , - So: , / : , - H = dist(A,B) , / D , - O = dist(A,C) , / : , - sin(th) = O/H , / : , - th = asin(O/H) B ~ ~ ~ ~ ~ C . - , , ' - ' - , _ _ _ , ' - */ - GLfloat Ay = pin_distance - leg_distance; - GLfloat Cx = 0, Cy = y; - GLfloat Bx = x; - GLfloat dBC = Cx - Bx; - GLfloat dAC = Cy - Ay; - GLfloat dAB = sqrt (dBC*dBC + dAC*dAC); - GLfloat th = asin (dAC / dAB); - rot = th / (M_PI / 180.0); - rot += 90; - if (dBC > 0) rot = 360-rot; - } - - glTranslatef (0, orbit_r, 0); /* position on rotator axis */ - glTranslatef (x, y, 0); - - glTranslatef (0, leg_distance, 0); /* position on leg axis */ - glRotatef(rot, 0, 0, 1); - glTranslatef (0, -leg_distance, 0); /* move back */ - - glFrontFace(GL_CCW); - count += draw_leg_half (mi); - - glScalef (-1, 1, 1); - glFrontFace(GL_CW); - count += draw_leg_half (mi); - - glPopMatrix(); - return count; -} - - -static int -draw_dome (ModeInfo *mi, walker *f) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - int which = ROBOT_DOME; - int count = 0; - GLfloat n = 8.3; - GLfloat trans = f->body_transparency; - GLfloat max = 0.7; - GLfloat dome_y = 15290; - - if (trans < 0) trans = 0; - if (trans > max) trans = max; - - if (!wire) glEnable (GL_BLEND); - - glPushMatrix(); - glTranslatef (0, dome_y, 0); - glScalef (100, 100, 100); - glRotatef (90, 1, 0, 0); - glTranslatef (0.35, 0, 0); - glScalef (n, n, n); - glFrontFace(GL_CCW); - bp->component_colors[which][3] = trans; - count += draw_component (mi, which); - glPopMatrix(); - - if (!wire) glDisable (GL_BLEND); - - return count; -} - - -/* Is this robot overlapping any other? - */ -static Bool -collision_p (ModeInfo *mi, walker *w, GLfloat extra_space) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int i; - if (MI_COUNT(mi) <= 1) return False; - - for (i = 0; i < MI_COUNT(mi); i++) - { - walker *w2 = &bp->walkers[i]; - GLfloat min = 0.75 + extra_space; - GLfloat d, dx, dy; - if (w == w2) continue; - dx = w->x - w2->x; - dy = w->y - w2->y; - d = (dx*dx + dy*dy); - if (d <= min*min) return True; - } - return False; -} - - -/* I couldn't figure out a straightforward trig solution to the - forward/backward tilting that happens as weight passes from one - foot to another, so I just built a tool to eyeball it manually. - { vertical_translation, rotation, forward_translation } - */ -static const struct { GLfloat up, rot, fwd; } wobble_profile[360] = { - { 0.0000, 0.00, 0.0000 }, /* 0 */ - { 0.0000, -0.01, 0.0025 }, - { 0.0000, -0.25, 0.0040 }, - { 0.0000, -0.41, 0.0060 }, - { 0.0000, -0.62, 0.0080 }, - { 0.0000, -0.80, 0.0095 }, - { 0.0000, -0.90, 0.0120 }, - { 0.0000, -1.10, 0.0135 }, - { 0.0000, -1.25, 0.0150 }, - { 0.0000, -1.40, 0.0175 }, - { 0.0000, -1.50, 0.0195 }, /* 10 */ - { 0.0000, -1.70, 0.0215 }, - { 0.0000, -1.80, 0.0230 }, - { 0.0000, -2.00, 0.0250 }, - { 0.0000, -2.10, 0.0270 }, - { -0.0005, -2.30, 0.0290 }, - { -0.0005, -2.50, 0.0305 }, - { -0.0005, -2.60, 0.0330 }, - { -0.0005, -2.70, 0.0330 }, - { -0.0005, -2.90, 0.0350 }, - { -0.0005, -3.00, 0.0365 }, /* 20 */ - { -0.0010, -3.20, 0.0380 }, - { -0.0005, -3.30, 0.0400 }, - { -0.0010, -3.50, 0.0420 }, - { -0.0010, -3.70, 0.0440 }, - { -0.0010, -3.80, 0.0460 }, - { -0.0010, -3.90, 0.0470 }, - { -0.0015, -4.10, 0.0500 }, - { -0.0015, -4.20, 0.0515 }, - { -0.0015, -4.40, 0.0535 }, - { -0.0015, -4.50, 0.0550 }, /* 30 */ - { -0.0015, -4.60, 0.0565 }, - { -0.0020, -4.80, 0.0585 }, - { -0.0020, -5.00, 0.0600 }, - { -0.0020, -5.10, 0.0620 }, - { -0.0025, -5.20, 0.0635 }, - { -0.0025, -5.40, 0.0655 }, - { -0.0025, -5.50, 0.0675 }, - { -0.0025, -5.60, 0.0690 }, - { -0.0030, -5.80, 0.0710 }, - { -0.0030, -5.90, 0.0720 }, /* 40 */ - { -0.0030, -6.00, 0.0740 }, - { -0.0035, -6.10, 0.0760 }, - { -0.0035, -6.30, 0.0790 }, - { -0.0040, -6.40, 0.0805 }, - { -0.0040, -6.50, 0.0820 }, - { -0.0040, -6.60, 0.0835 }, - { -0.0045, -6.80, 0.0855 }, - { -0.0045, -6.90, 0.0870 }, - { -0.0050, -7.00, 0.0885 }, - { -0.0050, -7.20, 0.0900 }, /* 50 */ - { -0.0050, -7.20, 0.0915 }, - { -0.0055, -7.40, 0.0930 }, - { -0.0055, -7.50, 0.0945 }, - { -0.0060, -7.60, 0.0960 }, - { -0.0060, -7.70, 0.0970 }, - { -0.0065, -7.80, 0.0985 }, - { -0.0060, -7.70, 0.0995 }, - { -0.0060, -7.60, 0.1010 }, - { -0.0060, -7.50, 0.1020 }, - { -0.0055, -7.30, 0.1030 }, /* 60 */ - { -0.0050, -7.10, 0.1040 }, - { -0.0050, -6.90, 0.1050 }, - { -0.0045, -6.80, 0.1065 }, - { -0.0045, -6.50, 0.1075 }, - { -0.0040, -6.40, 0.1085 }, - { -0.0040, -6.20, 0.1095 }, - { -0.0040, -6.00, 0.1105 }, - { -0.0035, -5.80, 0.1115 }, - { -0.0030, -5.50, 0.1125 }, - { -0.0030, -5.40, 0.1135 }, /* 70 */ - { -0.0030, -5.10, 0.1145 }, - { -0.0030, -4.90, 0.1150 }, - { -0.0025, -4.70, 0.1160 }, - { -0.0025, -4.40, 0.1165 }, - { -0.0025, -4.20, 0.1175 }, - { -0.0020, -3.90, 0.1180 }, - { -0.0020, -3.70, 0.1185 }, - { -0.0020, -3.40, 0.1190 }, - { -0.0020, -3.10, 0.1195 }, - { -0.0020, -2.90, 0.1200 }, /* 80 */ - { -0.0015, -2.60, 0.1200 }, - { -0.0015, -2.30, 0.1205 }, - { -0.0015, -2.00, 0.1210 }, - { -0.0015, -1.80, 0.1215 }, - { -0.0015, -1.50, 0.1215 }, - { -0.0015, -1.20, 0.1215 }, - { -0.0015, -0.90, 0.1215 }, - { -0.0015, -0.60, 0.1215 }, - { -0.0015, -0.30, 0.1215 }, - { -0.0010, 0.00, 0.1215 }, /* 90 */ - { -0.0010, 0.30, 0.1215 }, - { -0.0010, 0.60, 0.1215 }, - { -0.0010, 0.90, 0.1215 }, - { -0.0010, 1.20, 0.1215 }, - { -0.0015, 1.40, 0.1215 }, - { -0.0015, 1.70, 0.1215 }, - { -0.0015, 2.00, 0.1215 }, - { -0.0015, 2.30, 0.1215 }, - { -0.0015, 2.60, 0.1215 }, - { -0.0015, 2.80, 0.1220 }, /* 100 */ - { -0.0020, 3.10, 0.1225 }, - { -0.0020, 3.30, 0.1230 }, - { -0.0020, 3.60, 0.1235 }, - { -0.0020, 3.90, 0.1240 }, - { -0.0025, 4.10, 0.1245 }, - { -0.0025, 4.40, 0.1250 }, - { -0.0025, 4.60, 0.1260 }, - { -0.0025, 4.90, 0.1265 }, - { -0.0030, 5.10, 0.1275 }, - { -0.0030, 5.30, 0.1285 }, /* 110 */ - { -0.0035, 5.60, 0.1290 }, - { -0.0035, 5.80, 0.1300 }, - { -0.0035, 6.00, 0.1310 }, - { -0.0040, 6.20, 0.1325 }, - { -0.0040, 6.40, 0.1335 }, - { -0.0045, 6.60, 0.1345 }, - { -0.0045, 6.70, 0.1355 }, - { -0.0050, 6.90, 0.1365 }, - { -0.0050, 7.10, 0.1375 }, - { -0.0055, 7.30, 0.1390 }, /* 120 */ - { -0.0055, 7.40, 0.1400 }, - { -0.0060, 7.50, 0.1415 }, - { -0.0065, 8.00, 0.1425 }, - { -0.0065, 7.80, 0.1440 }, - { -0.0060, 7.80, 0.1455 }, - { -0.0060, 7.60, 0.1470 }, - { -0.0055, 7.50, 0.1485 }, - { -0.0055, 7.40, 0.1500 }, - { -0.0050, 7.30, 0.1515 }, - { -0.0050, 7.20, 0.1530 }, /* 130 */ - { -0.0050, 7.00, 0.1545 }, - { -0.0045, 6.90, 0.1560 }, - { -0.0045, 6.80, 0.1575 }, - { -0.0040, 6.70, 0.1590 }, - { -0.0040, 6.50, 0.1605 }, - { -0.0040, 6.40, 0.1625 }, - { -0.0035, 6.30, 0.1640 }, - { -0.0035, 6.10, 0.1655 }, - { -0.0030, 6.10, 0.1670 }, - { -0.0030, 5.90, 0.1690 }, /* 140 */ - { -0.0030, 5.70, 0.1705 }, - { -0.0025, 5.70, 0.1720 }, - { -0.0025, 5.50, 0.1740 }, - { -0.0025, 5.40, 0.1755 }, - { -0.0025, 5.20, 0.1775 }, - { -0.0020, 5.10, 0.1790 }, - { -0.0020, 5.00, 0.1810 }, - { -0.0020, 4.80, 0.1825 }, - { -0.0015, 4.70, 0.1840 }, - { -0.0015, 4.60, 0.1860 }, /* 150 */ - { -0.0015, 4.40, 0.1880 }, - { -0.0015, 4.20, 0.1900 }, - { -0.0015, 4.10, 0.1915 }, - { -0.0010, 4.00, 0.1935 }, - { -0.0010, 3.80, 0.1955 }, - { -0.0010, 3.70, 0.1970 }, - { -0.0010, 3.50, 0.1990 }, - { -0.0005, 3.40, 0.2010 }, - { -0.0010, 3.20, 0.2025 }, - { -0.0005, 3.10, 0.2045 }, /* 160 */ - { -0.0005, 2.90, 0.2065 }, - { -0.0005, 2.80, 0.2085 }, - { -0.0005, 2.60, 0.2105 }, - { -0.0005, 2.50, 0.2120 }, - { -0.0005, 2.30, 0.2140 }, - { -0.0005, 2.20, 0.2160 }, - { -0.0005, 2.00, 0.2180 }, - { 0.0000, 1.90, 0.2200 }, - { 0.0000, 1.70, 0.2220 }, - { 0.0000, 1.60, 0.2235 }, /* 170 */ - { 0.0000, 1.40, 0.2255 }, - { 0.0000, 1.30, 0.2275 }, - { 0.0000, 1.10, 0.2295 }, - { 0.0000, 0.90, 0.2315 }, - { 0.0000, 0.80, 0.2335 }, - { 0.0000, 0.60, 0.2355 }, - { 0.0000, 0.50, 0.2375 }, - { 0.0000, 0.30, 0.2395 }, - { 0.0000, 0.10, 0.2415 }, - { 0.0000, 0.00, 0.2430 }, /* 180 */ - { 0.0000, -0.10, 0.2450 }, - { 0.0000, -0.30, 0.2470 }, - { 0.0000, -0.40, 0.2490 }, - { 0.0000, -0.60, 0.2510 }, - { 0.0000, -0.80, 0.2530 }, - { 0.0000, -0.90, 0.2550 }, - { 0.0000, -1.10, 0.2570 }, - { 0.0000, -1.20, 0.2590 }, - { 0.0000, -1.40, 0.2610 }, - { 0.0000, -1.50, 0.2625 }, /* 190 */ - { 0.0000, -1.70, 0.2645 }, - { 0.0000, -1.80, 0.2665 }, - { -0.0005, -2.00, 0.2685 }, - { -0.0005, -2.10, 0.2705 }, - { -0.0005, -2.30, 0.2725 }, - { -0.0005, -2.40, 0.2740 }, - { -0.0005, -2.60, 0.2760 }, - { -0.0005, -2.80, 0.2780 }, - { -0.0005, -2.90, 0.2800 }, - { -0.0005, -3.00, 0.2820 }, /* 200 */ - { -0.0010, -3.20, 0.2835 }, - { -0.0005, -3.30, 0.2855 }, - { -0.0010, -3.50, 0.2875 }, - { -0.0010, -3.70, 0.2895 }, - { -0.0010, -3.80, 0.2910 }, - { -0.0010, -3.90, 0.2930 }, - { -0.0010, -4.00, 0.2950 }, - { -0.0015, -4.20, 0.2965 }, - { -0.0015, -4.40, 0.2985 }, - { -0.0015, -4.50, 0.3000 }, /* 210 */ - { -0.0015, -4.60, 0.3020 }, - { -0.0020, -4.80, 0.3040 }, - { -0.0020, -5.00, 0.3055 }, - { -0.0020, -5.00, 0.3075 }, - { -0.0025, -5.20, 0.3090 }, - { -0.0025, -5.30, 0.3110 }, - { -0.0025, -5.50, 0.3125 }, - { -0.0025, -5.60, 0.3140 }, - { -0.0030, -5.70, 0.3160 }, - { -0.0030, -5.90, 0.3175 }, /* 220 */ - { -0.0030, -6.00, 0.3190 }, - { -0.0035, -6.10, 0.3210 }, - { -0.0035, -6.30, 0.3225 }, - { -0.0040, -6.40, 0.3240 }, - { -0.0040, -6.50, 0.3255 }, - { -0.0040, -6.60, 0.3270 }, - { -0.0045, -6.80, 0.3290 }, - { -0.0045, -6.90, 0.3305 }, - { -0.0050, -7.00, 0.3320 }, - { -0.0050, -7.20, 0.3335 }, /* 230 */ - { -0.0050, -7.20, 0.3350 }, - { -0.0055, -7.40, 0.3365 }, - { -0.0055, -7.50, 0.3380 }, - { -0.0060, -7.60, 0.3390 }, - { -0.0060, -7.70, 0.3405 }, - { -0.0065, -7.80, 0.3420 }, - { -0.0060, -7.60, 0.3425 }, - { -0.0060, -7.50, 0.3440 }, - { -0.0055, -7.40, 0.3455 }, - { -0.0055, -7.20, 0.3470 }, /* 240 */ - { -0.0050, -7.10, 0.3480 }, - { -0.0050, -6.90, 0.3490 }, - { -0.0045, -6.80, 0.3500 }, - { -0.0045, -6.50, 0.3510 }, - { -0.0040, -6.40, 0.3520 }, - { -0.0040, -6.10, 0.3535 }, - { -0.0035, -6.00, 0.3545 }, - { -0.0035, -5.80, 0.3550 }, - { -0.0030, -5.50, 0.3560 }, - { -0.0030, -5.30, 0.3570 }, /* 250 */ - { -0.0030, -5.10, 0.3580 }, - { -0.0030, -4.90, 0.3585 }, - { -0.0025, -4.70, 0.3595 }, - { -0.0025, -4.40, 0.3600 }, - { -0.0020, -4.10, 0.3610 }, - { -0.0020, -3.90, 0.3615 }, - { -0.0020, -3.70, 0.3620 }, - { -0.0020, -3.30, 0.3625 }, - { -0.0020, -3.10, 0.3630 }, - { -0.0015, -2.80, 0.3635 }, /* 260 */ - { -0.0015, -2.60, 0.3640 }, - { -0.0015, -2.40, 0.3645 }, - { -0.0015, -2.00, 0.3645 }, - { -0.0015, -1.80, 0.3650 }, - { -0.0015, -1.40, 0.3650 }, - { -0.0015, -1.20, 0.3655 }, - { -0.0010, -0.90, 0.3655 }, - { -0.0010, -0.60, 0.3655 }, - { -0.0010, -0.30, 0.3655 }, - { -0.0010, 0.00, 0.3655 }, /* 270 */ - { -0.0010, 0.30, 0.3655 }, - { -0.0010, 0.60, 0.3655 }, - { -0.0010, 0.90, 0.3655 }, - { -0.0015, 1.10, 0.3655 }, - { -0.0015, 1.40, 0.3655 }, - { -0.0015, 1.70, 0.3655 }, - { -0.0015, 1.90, 0.3660 }, - { -0.0015, 2.20, 0.3660 }, - { -0.0015, 2.50, 0.3665 }, - { -0.0015, 2.80, 0.3670 }, /* 280 */ - { -0.0015, 3.10, 0.3675 }, - { -0.0020, 3.40, 0.3680 }, - { -0.0020, 3.70, 0.3685 }, - { -0.0020, 3.90, 0.3690 }, - { -0.0025, 4.10, 0.3695 }, - { -0.0025, 4.40, 0.3700 }, - { -0.0025, 4.60, 0.3710 }, - { -0.0025, 4.80, 0.3715 }, - { -0.0025, 5.00, 0.3730 }, - { -0.0030, 5.40, 0.3735 }, /* 290 */ - { -0.0035, 5.60, 0.3745 }, - { -0.0035, 5.80, 0.3755 }, - { -0.0035, 6.00, 0.3765 }, - { -0.0040, 6.20, 0.3775 }, - { -0.0045, 6.50, 0.3785 }, - { -0.0045, 6.60, 0.3795 }, - { -0.0045, 6.80, 0.3805 }, - { -0.0050, 7.00, 0.3815 }, - { -0.0050, 7.10, 0.3825 }, - { -0.0055, 7.20, 0.3840 }, /* 300 */ - { -0.0055, 7.40, 0.3850 }, - { -0.0060, 7.50, 0.3865 }, - { -0.0060, 7.70, 0.3875 }, - { -0.0065, 7.80, 0.3890 }, - { -0.0060, 7.80, 0.3900 }, - { -0.0060, 7.60, 0.3915 }, - { -0.0055, 7.60, 0.3930 }, - { -0.0055, 7.40, 0.3945 }, - { -0.0050, 7.30, 0.3960 }, - { -0.0050, 7.20, 0.3975 }, /* 310 */ - { -0.0050, 7.00, 0.3990 }, - { -0.0045, 6.90, 0.4005 }, - { -0.0045, 6.80, 0.4020 }, - { -0.0040, 6.70, 0.4035 }, - { -0.0040, 6.60, 0.4050 }, - { -0.0040, 6.40, 0.4065 }, - { -0.0035, 6.30, 0.4085 }, - { -0.0035, 6.20, 0.4100 }, - { -0.0030, 6.10, 0.4115 }, - { -0.0030, 5.90, 0.4130 }, /* 320 */ - { -0.0030, 5.80, 0.4150 }, - { -0.0025, 5.70, 0.4165 }, - { -0.0025, 5.50, 0.4180 }, - { -0.0025, 5.40, 0.4200 }, - { -0.0025, 5.20, 0.4215 }, - { -0.0020, 5.10, 0.4235 }, - { -0.0020, 5.00, 0.4250 }, - { -0.0020, 4.80, 0.4270 }, - { -0.0015, 4.70, 0.4285 }, - { -0.0015, 4.60, 0.4305 }, /* 330 */ - { -0.0015, 4.40, 0.4325 }, - { -0.0015, 4.20, 0.4340 }, - { -0.0015, 4.10, 0.4360 }, - { -0.0010, 4.00, 0.4375 }, - { -0.0010, 3.80, 0.4395 }, - { -0.0010, 3.70, 0.4415 }, - { -0.0010, 3.50, 0.4435 }, - { -0.0005, 3.40, 0.4450 }, - { -0.0010, 3.20, 0.4470 }, - { -0.0005, 3.10, 0.4490 }, /* 340 */ - { -0.0005, 2.90, 0.4510 }, - { -0.0005, 2.80, 0.4525 }, - { -0.0005, 2.60, 0.4545 }, - { -0.0005, 2.40, 0.4565 }, - { -0.0005, 2.30, 0.4585 }, - { -0.0005, 2.20, 0.4605 }, - { -0.0005, 2.00, 0.4620 }, - { 0.0000, 1.90, 0.4640 }, - { 0.0000, 1.70, 0.4660 }, - { 0.0000, 1.60, 0.4680 }, /* 350 */ - { 0.0000, 1.40, 0.4700 }, - { 0.0000, 1.20, 0.4720 }, - { 0.0000, 1.10, 0.4740 }, - { 0.0000, 0.90, 0.4760 }, - { 0.0000, 0.80, 0.4780 }, - { 0.0000, 0.60, 0.4795 }, - { 0.0000, 0.50, 0.4815 }, - { 0.0000, 0.30, 0.4835 }, - { 0.0000, 0.20, 0.4855 }, /* 359 */ -}; - - -/* Turn the crank by 1 degree, which moves the legs and displaces the robot. - */ -static void -tick_walker (ModeInfo *mi, walker *f) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int deg; - GLfloat th, fwd; - - if (bp->button_down_p) return; - - f->crank_rot++; - deg = ((int) (f->crank_rot + 0.5)) % 360; - -# ifdef DEBUG - if (debug_p) - { - f->crank_rot = bp->debug_x; - f->pitch = wobble_profile[deg].rot; - f->z = wobble_profile[deg].up; - } - else -# endif /* DEBUG */ - - if (deg == 0) - { - fwd = wobble_profile[deg].fwd; - f->pitch = wobble_profile[deg].rot; - f->z = wobble_profile[deg].up; - } - else - { - fwd = (wobble_profile[deg].fwd - wobble_profile[deg-1].fwd); - f->pitch += (wobble_profile[deg].rot - wobble_profile[deg-1].rot); - f->z += (wobble_profile[deg].up - wobble_profile[deg-1].up); - } - - /* Lean slightly toward the foot that is raised off the ground. */ - f->roll = -2.5 * sin ((deg - 90) * M_PI / 180); - - if (!(random() % 10)) - { - GLfloat b = f->balance / 10.0; - int s = (f->balance > 0 ? 1 : -1); - if (s < 0) b = -b; - f->facing += s * frand (b); - } - -# ifdef DEBUG - if (debug_p) fwd = 0; -# endif - - { - GLfloat ox = f->x; - GLfloat oy = f->y; - th = f->facing * M_PI / 180.0; - f->x += fwd * cos (th); - f->y += fwd * sin (th); - - /* If moving this robot would collide with another, undo the move, - recoil, and randomly turn. - */ - if (collision_p (mi, f, 0)) - { - fwd *= -1.5; - f->x = ox + fwd * cos (th); - f->y = oy + fwd * sin (th); - f->facing += frand(10) - 5; - if (! random() % 30) - f->facing += frand(90) - 45; - } - } - - - if (!do_fade || - opacity > 0.5) /* Don't bother fading if it's already transparent. */ - { - GLfloat tick = 0.002; - GLfloat linger = 3; - - /* If we're not fading, maybe start fading out. */ - if (f->fading_p == 0 && ! (random() % 40000)) - f->fading_p = -1; - -# ifdef DEBUG - if (debug_p) f->fading_p = 0; -# endif - - if (f->fading_p < 0) - { - f->body_transparency -= tick; - if (f->body_transparency <= -linger) - { - f->body_transparency = -linger; - f->fading_p = 1; - } - } - else if (f->fading_p > 0) - { - f->body_transparency += tick; - if (f->body_transparency >= opacity) - { - f->body_transparency = opacity; - f->fading_p = 0; - } - } - } -} - - -static void -init_walker (ModeInfo *mi, walker *f) -{ - int i, start_tick = random() % 360; - - f->crank_rot = 0; - f->pitch = wobble_profile[0].rot; - f->z = wobble_profile[0].up; - - f->body_transparency = opacity; - - f->hand_rot[0] = frand(180); - f->hand_pos[0] = 0.6 + frand(0.4); - f->hand_rot[1] = 180 - f->hand_rot[0]; - f->hand_pos[1] = f->hand_pos[0]; - - if (! (random() % 30)) f->hand_rot[1] += frand(10); - if (! (random() % 30)) f->hand_pos[1] = 0.6 + frand(0.4); - - f->facing = frand(360); - f->balance = frand(10) - 5; - - if (MI_COUNT(mi) == 1) - f->speed = 1.0; - else - f->speed = 0.6 + frand(0.8); - -# ifdef DEBUG - if (debug_p) - { - start_tick = 0; - f->facing = 0; - f->balance = 0; - } -# endif - - for (i = 0; i < start_tick; i++) - tick_walker (mi, f); - - /* Place them randomly, but non-overlapping. */ - for (i = 0; i < 1000; i++) - { - GLfloat range = 10; - if (MI_COUNT(mi) > 10) range += MI_COUNT(mi) / 10.0; - f->x = frand(range) - range/2; - f->y = frand(range) - range/2; - if (! collision_p (mi, f, 1.5)) - break; - } - -# ifdef DEBUG - if (debug_p) f->x = f->y = 0; -# endif - -} - - -/* Draw a robot standing in the right place, 1 unit tall. - */ -static int -draw_walker (ModeInfo *mi, walker *f, const char *tag) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - int count = 0; - glPushMatrix(); - - glTranslatef (f->y, f->z, f->x); - - { - GLfloat n = 0.01; - glScalef (n, n, n); - } - - glRotatef (90, 0, 1, 0); - glRotatef (f->facing, 0, 1, 0); - glRotatef (f->pitch, 0, 0, 1); - glRotatef (f->roll, 1, 0, 0); - - { - GLfloat n = 0.00484; /* make it 1 unit tall */ - glScalef (n, n, n); - } - - count += draw_gearbox (mi); - count += draw_crank (mi, f, f->crank_rot); - count += draw_rotator (mi, f, f->crank_rot); - count += draw_leg (mi, f->crank_rot, False); - count += draw_leg (mi, f->crank_rot, True); - count += draw_wireframe (mi, f); - - /* Draw these last, and outer shell first, to make transparency work. - The order in which things hit the depth buffer matters. - */ - if (f->body_transparency >= 0.001) - { - count += draw_arm (mi, f, True, f->hand_rot[0], f->hand_pos[0]); - count += draw_arm (mi, f, False, f->hand_rot[1], f->hand_pos[1]); - count += draw_body (mi, f, False); - count += draw_body (mi, f, True); - count += draw_dome (mi, f); - } - - if (tag) /* For debugging depth sorting: label each robot */ - { - GLfloat m[4][4]; - if (! wire) glDisable (GL_DEPTH_TEST); - glColor3f (1, 1, 1); - glPushMatrix(); - - /* Billboard rotation */ - glGetFloatv (GL_MODELVIEW_MATRIX, &m[0][0]); - m[0][0] = 1; m[1][0] = 0; m[2][0] = 0; - m[0][1] = 0; m[1][1] = 1; m[2][1] = 0; - m[0][2] = 0; m[1][2] = 0; m[2][2] = 1; - glLoadIdentity(); - glMultMatrixf (&m[0][0]); - glScalef (0.04, 0.04, 0.04); - - print_texture_string (bp->font_data, tag); - glPopMatrix(); - if (! wire) glEnable (GL_DEPTH_TEST); - } - - glPopMatrix(); - return count; -} - - -static int -draw_ground (ModeInfo *mi, GLfloat color[4]) -{ - int wire = MI_IS_WIREFRAME(mi); - GLfloat i, j, k; - - /* When using fog, iOS apparently doesn't like lines or quads that are - really long, and extend very far outside of the scene. Maybe? If the - length of the line (cells * cell_size) is greater than 25 or so, lines - that are oriented steeply away from the viewer tend to disappear - (whether implemented as GL_LINES or as GL_QUADS). - - So we do a bunch of smaller grids instead of one big one. - */ - int cells = 30; - GLfloat cell_size = 0.8; - int points = 0; - int grids = 12; - -# ifdef DEBUG - if (debug_p) return 0; -# endif - - glPushMatrix(); - - glRotatef (frand(90), 0, 0, 1); - - if (!wire) - { - GLfloat fog_color[4] = { 0, 0, 0, 1 }; - - glLineWidth (4); - glEnable (GL_LINE_SMOOTH); - glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - - glFogi (GL_FOG_MODE, GL_EXP2); - glFogfv (GL_FOG_COLOR, fog_color); - glFogf (GL_FOG_DENSITY, 0.015); - glFogf (GL_FOG_START, -cells/2 * cell_size * grids); - glEnable (GL_FOG); - } - - glColor4fv (color); - glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); - - glTranslatef (-cells * grids * cell_size / 2, - -cells * grids * cell_size / 2, 0); - - for (j = 0; j < grids; j++) - { - glPushMatrix(); - for (k = 0; k < grids; k++) - { - glBegin (GL_LINES); - for (i = -cells/2; i < cells/2; i++) - { - GLfloat a = i * cell_size; - GLfloat b = cells/2 * cell_size; - glVertex3f (a, -b, 0); glVertex3f (a, b, 0); points++; - glVertex3f (-b, a, 0); glVertex3f (b, a, 0); points++; - } - glEnd(); - glTranslatef (cells * cell_size, 0, 0); - } - glPopMatrix(); - glTranslatef (0, cells * cell_size, 0); - } - - if (!wire) - { - glDisable (GL_LINE_SMOOTH); - glDisable (GL_BLEND); - glDisable (GL_FOG); - } - - glPopMatrix(); - - return points; -} - - -/* If the target robot (robot #0) has moved too far from the point at which - the camera is aimed, then initiate an animation to move the observer to - the new spot. - - Because of the jerky forward motion of the robots, just always focusing - on the center of the robot looks terrible, so instead we let them walk - a little out of the center of the frame, and then catch up. - */ -static void -look_at_center (ModeInfo *mi) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - GLfloat target_x = bp->walkers[0].x; - GLfloat target_y = bp->walkers[0].y; - GLfloat target_z = 0.8; /* Look a little bit above his head */ - GLfloat max_dist = 2.5 / size; - -# ifdef DEBUG - if (debug_p) return; -# endif - - if (max_dist < 1) max_dist = 1; - if (max_dist > 10) max_dist = 10; - - if (bp->camera_tracking_p) - { - GLfloat r = (1 - cos (bp->tracking_ratio * M_PI)) / 2; - bp->looking_x = bp->olooking_x + r * (target_x - bp->olooking_x); - bp->looking_y = bp->olooking_y + r * (target_y - bp->olooking_y); - bp->looking_z = bp->olooking_z + r * (target_z - bp->olooking_z); - - bp->tracking_ratio += 0.02; - if (bp->tracking_ratio >= 1) - { - bp->camera_tracking_p = False; - bp->olooking_x = bp->looking_x; - bp->olooking_y = bp->looking_y; - bp->olooking_z = bp->looking_z; - } - } - - if (! bp->camera_tracking_p) - { - GLfloat dist = - sqrt ((target_x - bp->looking_x) * (target_x - bp->looking_x) + - (target_y - bp->looking_y) * (target_y - bp->looking_y) + - (target_z - bp->looking_z) * (target_z - bp->looking_z)); - - if (dist > max_dist) - { - bp->camera_tracking_p = True; - bp->tracking_ratio = 0; - bp->olooking_x = bp->looking_x; - bp->olooking_y = bp->looking_y; - bp->olooking_z = bp->looking_z; - } - } - - glTranslatef (-bp->looking_y, -bp->looking_z, -bp->looking_x); - -# if 0 /* DEBUG */ - { - GLfloat th; - glPushMatrix(); - glColor3f(1, 0, 0); - glTranslatef (target_y, target_z, target_x); - glBegin(GL_LINES); - glVertex3f(0, -target_z, 0); - glVertex3f(0, 1, 0); - glVertex3f(-0.1, 0, -0.1); - glVertex3f( 0.1, 0, 0.1); - glVertex3f(-0.1, 0, 0.1); - glVertex3f( 0.1, 0, -0.1); - glEnd(); - glPopMatrix(); - - glPushMatrix(); - glColor3f(0, 1, 0); - glTranslatef (bp->looking_y, bp->looking_z, bp->looking_x); - glRotatef (30, 0, 1, 0); - glBegin(GL_LINES); - glVertex3f(0, -bp->looking_z, 0); - glVertex3f(0, 1, 0); - glVertex3f(-0.1, 0, -0.1); - glVertex3f( 0.1, 0, 0.1); - glVertex3f(-0.1, 0, 0.1); - glVertex3f( 0.1, 0, -0.1); - glEnd(); - glPopMatrix(); - - glPushMatrix(); - glColor3f(0, 0, 1); - glTranslatef (bp->olooking_y, bp->olooking_z, bp->olooking_x); - glRotatef (60, 0, 1, 0); - glBegin(GL_LINES); - glVertex3f(0, -bp->olooking_z, 0); - glVertex3f(0, 1, 0); - glVertex3f(-0.1, 0, -0.1); - glVertex3f( 0.1, 0, 0.1); - glVertex3f(-0.1, 0, 0.1); - glVertex3f( 0.1, 0, -0.1); - glEnd(); - - glTranslatef (0, -bp->olooking_z, 0); - glBegin (GL_LINE_LOOP); - for (th = 0; th < M_PI * 2; th += 0.1) - glVertex3f (bp->olooking_y + max_dist * cos(th), 0, - bp->olooking_x + max_dist * sin(th)); - glEnd(); - glPopMatrix(); - } -# endif /* DEBUG */ -} - - -#ifdef WORDBUBBLES - -/* Draw a cartoony word bubble. - W and H are the inside size, for text. - Origin is at bottom left. - The bubble frame and arrow are outside that. - */ -static void -draw_bubble_box (ModeInfo *mi, - GLfloat width, GLfloat height, - GLfloat corner_radius, - GLfloat arrow_h, GLfloat arrow_x, - GLfloat fg[4], GLfloat bg[4]) -{ - -# define CORNER_POINTS 16 - GLfloat outline_points[ (CORNER_POINTS + 2) * 4 + 8 ][3]; - int i = 0; - GLfloat th; - GLfloat tick = M_PI / 2 / CORNER_POINTS; - - GLfloat arrow_w = arrow_h / 2; - GLfloat arrow_x2 = MAX(0, MIN(width - arrow_w, arrow_x)); - - GLfloat w2 = MAX(arrow_w, width - corner_radius * 1.10); - GLfloat h2 = MAX(0, height - corner_radius * 1.28); - GLfloat x2 = (width - w2) / 2; - GLfloat y2 = (height - h2) / 2; - /* A B C D */ - GLfloat xa = x2 -corner_radius; /* E _------------_ */ - GLfloat xb = x2; /* D /__| |__\ */ - GLfloat xc = xb + w2; /* | | | | */ - GLfloat xd = xc + corner_radius; /* C |__| EF |__| */ - GLfloat xe = xb + arrow_x2; /* B \_|_________|_/ */ - GLfloat xf = xe + arrow_w; /* A \| */ - - GLfloat ya = y2 - (corner_radius + arrow_h); - GLfloat yb = y2 - corner_radius; - GLfloat yc = y2; - GLfloat yd = yc + h2; - GLfloat ye = yd + corner_radius; - - GLfloat z = 0; - - /* Let the lines take precedence over the fills. */ - glEnable (GL_POLYGON_OFFSET_FILL); - glPolygonOffset (1.0, 1.0); - - glColor4fv (bg); - glFrontFace(GL_CW); - - /* top left corner */ - - glBegin (GL_TRIANGLE_FAN); - glVertex3f (xb, yd, 0); - for (th = 0; th < M_PI/2 + tick; th += tick) - { - GLfloat x = xb - corner_radius * cos(th); - GLfloat y = yd + corner_radius * sin(th); - glVertex3f (x, y, z); - outline_points[i][0] = x; - outline_points[i][1] = y; - outline_points[i][2] = z; - i++; - } - glEnd(); - - /* top edge */ - outline_points[i][0] = xc; - outline_points[i][1] = ye; - outline_points[i][2] = z; - i++; - - /* top right corner */ - - glBegin (GL_TRIANGLE_FAN); - glVertex3f (xc, yd, 0); - for (th = M_PI/2; th > -tick; th -= tick) - { - GLfloat x = xc + corner_radius * cos(th); - GLfloat y = yd + corner_radius * sin(th); - glVertex3f (x, y, z); - outline_points[i][0] = x; - outline_points[i][1] = y; - outline_points[i][2] = z; - i++; - } - glEnd(); - - /* right edge */ - outline_points[i][0] = xd; - outline_points[i][1] = yc; - outline_points[i][2] = z; - i++; - - /* bottom right corner */ - - glBegin (GL_TRIANGLE_FAN); - glVertex3f (xc, yc, 0); - for (th = 0; th < M_PI/2 + tick; th += tick) - { - GLfloat x = xc + corner_radius * cos(th); - GLfloat y = yc - corner_radius * sin(th); - glVertex3f (x, y, z); - outline_points[i][0] = x; - outline_points[i][1] = y; - outline_points[i][2] = z; - i++; - } - glEnd(); - - /* bottom right edge */ - outline_points[i][0] = xf; - outline_points[i][1] = yb; - outline_points[i][2] = z; - i++; - - /* arrow triangle */ - glFrontFace(GL_CW); - glBegin (GL_TRIANGLES); - - /* bottom arrow point */ - outline_points[i][0] = xf; - outline_points[i][1] = yb; - outline_points[i][2] = z; - glVertex3f (outline_points[i][0], - outline_points[i][1], - outline_points[i][2]); - i++; - - /* bottom right edge */ - outline_points[i][0] = xf; - outline_points[i][1] = ya; - outline_points[i][2] = z; - glVertex3f (outline_points[i][0], - outline_points[i][1], - outline_points[i][2]); - i++; - - outline_points[i][0] = xe; - outline_points[i][1] = yb; - outline_points[i][2] = z; - glVertex3f (outline_points[i][0], - outline_points[i][1], - outline_points[i][2]); - i++; - glEnd(); - - - /* bottom left corner */ - - glBegin (GL_TRIANGLE_FAN); - glVertex3f (xb, yc, 0); - for (th = M_PI/2; th > -tick; th -= tick) - { - GLfloat x = xb - corner_radius * cos(th); - GLfloat y = yc - corner_radius * sin(th); - glVertex3f (x, y, z); - outline_points[i][0] = x; - outline_points[i][1] = y; - outline_points[i][2] = z; - i++; - } - glEnd(); - - glFrontFace(GL_CCW); - - /* left edge */ - outline_points[i][0] = xa; - outline_points[i][1] = yd; - outline_points[i][2] = z; - i++; - - glFrontFace(GL_CW); - glBegin (GL_QUADS); - /* left box */ - glVertex3f (xa, yd, z); - glVertex3f (xb, yd, z); - glVertex3f (xb, yc, z); - glVertex3f (xa, yc, z); - - /* center box */ - glVertex3f (xb, ye, z); - glVertex3f (xc, ye, z); - glVertex3f (xc, yb, z); - glVertex3f (xb, yb, z); - - /* right box */ - glVertex3f (xc, yd, z); - glVertex3f (xd, yd, z); - glVertex3f (xd, yc, z); - glVertex3f (xc, yc, z); - - glEnd(); - - glLineWidth (2.8); - glColor4fv (fg); - - glBegin (GL_LINE_LOOP); - while (i > 0) - glVertex3fv (outline_points[--i]); - glEnd(); - - glDisable (GL_POLYGON_OFFSET_FILL); -} - - -static void -draw_label (ModeInfo *mi, walker *f, GLfloat y_off, GLfloat scale, - const char *label) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int wire = MI_IS_WIREFRAME(mi); - GLfloat m[4][4]; - - if (scale == 0) return; - - if (!wire) - glDisable (GL_LIGHTING); /* don't light fonts */ - - glPushMatrix(); - - /* First, we translate the origin to the center of the robot. - - Then we retrieve the prevailing modelview matrix, which - includes any rotation, wandering, and user-trackball-rolling - of the scene. - - We set the top 3x3 cells of that matrix to be the identity - matrix. This removes all rotation from the matrix, while - leaving the translation alone. This has the effect of - leaving the prevailing coordinate system perpendicular to - the camera view: were we to draw a square face, it would - be in the plane of the screen. - - Now we translate by `size' toward the viewer -- so that the - origin is *just in front* of the ball. - - Then we draw the label text, allowing the depth buffer to - do its work: that way, labels on atoms will be occluded - properly when other atoms move in front of them. - - This technique (of neutralizing rotation relative to the - observer, after both rotations and translations have been - applied) is known as "billboarding". - */ - - if (f) - glTranslatef(f->y, 0, f->x); /* get matrix */ - - glTranslatef (0, y_off, 0); - - glGetFloatv (GL_MODELVIEW_MATRIX, &m[0][0]); /* load rot. identity */ - m[0][0] = 1; m[1][0] = 0; m[2][0] = 0; - m[0][1] = 0; m[1][1] = 1; m[2][1] = 0; - m[0][2] = 0; m[1][2] = 0; m[2][2] = 1; - glLoadIdentity(); /* reset modelview */ - glMultMatrixf (&m[0][0]); /* replace with ours */ - - glTranslatef (0, 0, 0.1); /* move toward camera */ - - glRotatef (current_device_rotation(), 0, 0, 1); /* right side up */ - - { - XCharStruct e; - int cw, ch, w, h, ascent, descent; - GLfloat s; - GLfloat max = 24; /* max point size to avoid pixellated text */ - - /* Let the font be much larger on iPhone */ - if (mi->xgwa.height <= 640 || mi->xgwa.width <= 640) - max *= 3; - - texture_string_metrics (bp->font_data, "X", &e, &ascent, &descent); - cw = e.width; - ch = ascent + descent; - s = 1.0 / ch; - if (ch > max) s *= max/ch; - - s *= scale; - - texture_string_metrics (bp->font_data, label, &e, 0, 0); - w = e.width; - h = e.ascent + e.descent; - - glScalef (s, s, 1); - glTranslatef (-w/2, h*2/3 + (cw * 7), 0); - - glPushMatrix(); - glTranslatef (0, -h + (ch * 1.2), -0.1); - draw_bubble_box (mi, w, h, - ch * 2, /* corner radius */ - ch * 2.5, /* arrow height */ - w / 2 - cw * 8, /* arrow x */ - bp->text_bd, bp->text_bg); - glPopMatrix(); - - glColor4fv (bp->text_color); - glTranslatef (0, ch/2, 0); - print_texture_string (bp->font_data, label); - } - - glPopMatrix(); - - /* More efficient to always call glEnable() with correct values - than to call glPushAttrib()/glPopAttrib(), since reading - attributes from GL does a round-trip and stalls the pipeline. - */ - if (!wire) - glEnable (GL_LIGHTING); -} - - -static void -fill_words (ModeInfo *mi) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - char *p = bp->words + strlen(bp->words); - char *c; - int lines = 0; - int max = bp->max_lines; - - /* Fewer lines on iPhone */ - if ((mi->xgwa.height <= 640 || mi->xgwa.width <= 640) && - max > 4) - max = 4; - - for (c = bp->words; c < p; c++) - if (*c == '\n') - lines++; - - while (p < bp->words + sizeof(bp->words) - 1 && - lines < max) - { - int c = textclient_getc (bp->tc); - if (c == '\n') - lines++; - if (c > 0) - *p++ = (char) c; - else - break; - } - *p = 0; - - bp->lines = lines; -} - - -static void -bubble (ModeInfo *mi) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int duration = 200; - GLfloat fade = 0.015; - int chance = (talk_chance <= 0.0 ? 0 : - talk_chance >= 0.99 ? 1 : - (1-talk_chance) * 1000); - GLfloat scale; - char *s0 = strdup (bp->words); - char *s = s0; - int L; - - while (*s == '\n') s++; - L = strlen(s); - while (L > 0 && (s[L-1] == '\n' || s[L-1] == ' ' || s[L-1] == '\t')) - s[--L] = 0; - if (! *s) goto DONE; - -# ifdef DEBUG - if (debug_p) goto DONE; -# endif - - if (chance <= 0) goto DONE; - - if (bp->bubble_tick > 0) - { - bp->bubble_tick--; - if (! bp->bubble_tick) - *bp->words = 0; - } - - if (! bp->bubble_tick) - { - if (!(random() % chance)) - bp->bubble_tick = duration; - else - goto DONE; - } - - scale = (bp->bubble_tick < duration * fade - ? bp->bubble_tick / (duration * fade) - : (bp->bubble_tick > duration * (1 - fade) - ? 1 - ((bp->bubble_tick - duration * (1 - fade)) - / (duration * fade)) - : 1)); - - draw_label (mi, &bp->walkers[0], 1.5, scale, s); - - DONE: - free (s0); -} -#endif /* WORDBUBBLES */ - - - -typedef struct { - int i; - GLdouble d; -} depth_sorter; - -static int -cmp_depth_sorter (const void *aa, const void *bb) -{ - const depth_sorter *a = (depth_sorter *) aa; - const depth_sorter *b = (depth_sorter *) bb; - return (a->d == b->d ? 0 : a->d < b->d ? -1 : 1); -} - - -ENTRYPOINT void -draw_robot (ModeInfo *mi) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - Display *dpy = MI_DISPLAY(mi); - Window window = MI_WINDOW(mi); - int wire = MI_IS_WIREFRAME(mi); - GLfloat robot_size; - depth_sorter *sorted; - int i; - - if (!bp->glx_context) - return; - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_CULL_FACE); - - if (!wire) - { - GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0}; -/* GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};*/ - GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0}; - GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; - GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0}; - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb); - glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); - glLightfv(GL_LIGHT0, GL_SPECULAR, spc); - - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - glPushMatrix (); - - glRotatef (current_device_rotation(), 0, 0, 1); /* right side up */ - gltrackball_rotate (bp->user_trackball); - - glTranslatef (0, -20, 0); /* Move the horizon down the screen */ - - robot_size = size * 7; - glScalef (robot_size, robot_size, robot_size); - look_at_center (mi); - - glPushMatrix(); - glScalef (1/robot_size, 1/robot_size, 1/robot_size); - glCallList (bp->dlists[GROUND]); - glPopMatrix(); - -# ifdef WORDBUBBLES - fill_words (mi); - bubble (mi); -# endif - -#ifdef DEBUG - if (debug_p) - { - glTranslatef (0, -1.2, 0); - glScalef (3, 3, 3); - glRotatef (-43.5, 0, 0, 1); - glRotatef (-90, 0, 1, 0); - - /* glTranslatef (bp->debug_z, bp->debug_y, 0); */ - - glPushMatrix(); - if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING); - if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D); - - glBegin(GL_LINES); - glVertex3f(-10, 0, 0); glVertex3f(10, 0, 0); - glVertex3f(0, -10, 0); glVertex3f(0, 10, 0); - glVertex3f(0, 0, -10); glVertex3f(0, 0, 10); - glEnd(); - - glTranslatef (-0.5, 0, -0.5); - - glColor3f (1, 0, 0); - glBegin (GL_LINE_LOOP); - glVertex3f (0, 0, 0); glVertex3f (0, 0, 1); - glVertex3f (0, 1, 1); glVertex3f (0, 1, 0); - glEnd(); - - glBegin (GL_LINE_LOOP); - glVertex3f (1, 0, 0); glVertex3f (1, 0, 1); - glVertex3f (1, 1, 1); glVertex3f (1, 1, 0); - glEnd(); - -# if 1 - glColor3f (0.5, 0.5, 0.5); - glFrontFace (GL_CCW); - glBegin (GL_QUADS); - /* glVertex3f (0, 1, 0); glVertex3f (0, 1, 1); */ - /* glVertex3f (1, 1, 1); glVertex3f (1, 1, 0); */ - glVertex3f (0, 0, 0); glVertex3f (0, 0, 1); - glVertex3f (1, 0, 1); glVertex3f (1, 0, 0); - glEnd(); - - glFrontFace (GL_CW); - glBegin (GL_QUADS); - glVertex3f (0, 1, 0); glVertex3f (0, 1, 1); - glVertex3f (1, 1, 1); glVertex3f (1, 1, 0); - glVertex3f (0, 0, 0); glVertex3f (0, 0, 1); - glVertex3f (1, 0, 1); glVertex3f (1, 0, 0); - glEnd(); -# endif - - glColor3f (1, 0, 0); - glBegin (GL_LINES); - glVertex3f (0, 0, 0); glVertex3f (1, 0, 0); - glVertex3f (0, 0, 1); glVertex3f (1, 0, 1); - glVertex3f (0, 1, 0); glVertex3f (1, 1, 0); - glVertex3f (0, 1, 1); glVertex3f (1, 1, 1); - - glVertex3f (0, 0, 0); glVertex3f (1, 0, 1); - glVertex3f (0, 0, 1); glVertex3f (1, 0, 0); - glVertex3f (0, 1, 0); glVertex3f (1, 1, 1); - glVertex3f (0, 1, 1); glVertex3f (1, 1, 0); - glEnd(); - - if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING); - if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D); - - glPopMatrix(); - } - -# endif /* DEBUG */ - - /* For transparency to work right, we have to draw the robots from - back to front, from the perspective of the observer. So project - the origin of the robot to screen coordinates, and sort that by Z. - */ - sorted = (depth_sorter *) calloc (bp->nwalkers, sizeof (*sorted)); - { - GLdouble m[16], p[16]; - GLint v[4]; - glGetDoublev (GL_MODELVIEW_MATRIX, m); - glGetDoublev (GL_PROJECTION_MATRIX, p); - glGetIntegerv (GL_VIEWPORT, v); - - for (i = 0; i < bp->nwalkers; i++) - { - GLdouble x, y, z; - walker *f = &bp->walkers[i]; - gluProject (f->y, f->z, f->x, m, p, v, &x, &y, &z); - sorted[i].i = i; - sorted[i].d = -z; - } - qsort (sorted, i, sizeof(*sorted), cmp_depth_sorter); - } - - - mi->polygon_count = 0; - for (i = 0; i < bp->nwalkers; i++) - { - int ii = sorted[i].i; - walker *f = &bp->walkers[ii]; - int ticks = 22 * speed * f->speed; - int max = 180; - char tag[1024]; - *tag = 0; - - if (ticks < 1) ticks = 1; - if (ticks > max) ticks = max; - -# ifdef DEBUG - if (debug_p) - sprintf (tag, "%.4f, %.4f, %.4f", - bp->debug_x, bp->debug_y, bp->debug_z); - else - { -# if 1 - /* sprintf (tag + strlen(tag), " %d\n", ii); */ - sprintf (tag + strlen(tag), " %d\n", bp->nwalkers - i - 1); - /* sprintf (tag + strlen(tag), "%.03f\n", sorted[i].d); */ -# endif - } - -# endif /* DEBUG */ - - mi->polygon_count += draw_walker (mi, f, tag); - - for (ii = 0; ii < ticks; ii++) - tick_walker (mi, f); - } - free (sorted); - - glPopMatrix (); - - if (mi->fps_p) do_fps (mi); - glFinish(); - - glXSwapBuffers(dpy, window); -} - -ENTRYPOINT void -free_robot (ModeInfo *mi) -{ - robot_configuration *bp = &bps[MI_SCREEN(mi)]; - int i; - - if (!bp->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); - - if (bp->user_trackball) gltrackball_free (bp->user_trackball); - if (bp->walkers) free (bp->walkers); - if (robot_dome) free (robot_dome); - robot_dome = 0; - if (robot_gear) free (robot_gear); - robot_gear = 0; - if (ground) free (ground); - ground = 0; - -# ifdef WORDBUBBLES - if (bp->tc) textclient_close (bp->tc); - if (bp->font_data) free_texture_font (bp->font_data); -# endif - -# ifdef HAVE_TEXTURE - if (bp->chrome_texture) glDeleteTextures(1, &bp->chrome_texture); -# endif - if (bp->dlists) { - for (i = 0; i < countof(all_objs); i++) - if (glIsList(bp->dlists[i])) glDeleteLists(bp->dlists[i], 1); - free (bp->dlists); - } -} - -XSCREENSAVER_MODULE_2 ("WindupRobot", winduprobot, robot) - -#endif /* USE_GL */ |
