-/* flyingtoasters, Copyright (c) 2003, 2004 Jamie Zawinski <jwz@jwz.org>
+/* flyingtoasters, Copyright (c) 2003-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
* bitmapped toasters won't get all huffy at us.
*/
-#include <X11/Intrinsic.h>
-
-extern XtAppContext app;
-
-#define PROGCLASS "FlyingToasters"
-#define HACK_INIT init_toasters
-#define HACK_DRAW draw_toasters
-#define HACK_RESHAPE reshape_toasters
-#define HACK_HANDLE_EVENT toaster_handle_event
-#define EVENT_MASK PointerMotionMask
-#define sws_opts xlockmore_opts
-
-#define DEF_SPEED "1.0"
-#define DEF_NTOASTERS "20"
-#define DEF_NSLICES "25"
-#define DEF_TEXTURE "True"
-
#define DEFAULTS "*delay: 30000 \n" \
"*showFPS: False \n" \
"*wireframe: False \n" \
- "*speed: " DEF_SPEED " \n" \
- "*ntoasters: " DEF_NTOASTERS "\n" \
- "*nslices: " DEF_NSLICES "\n" \
- "*texture: " DEF_TEXTURE "\n" \
/* #define DEBUG */
+# define free_toasters 0
+# define release_toasters 0
#undef countof
#define countof(x) (sizeof((x))/sizeof((*x)))
+#define DEF_SPEED "1.0"
+#define DEF_NTOASTERS "20"
+#define DEF_NSLICES "25"
+#define DEF_TEXTURE "True"
+
#undef BELLRAND
#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
#include "xlockmore.h"
#include "gltrackball.h"
-#include "xpm-ximage.h"
+#include "ximage-loader.h"
#include <ctype.h>
-#include "../images/chromesphere.xpm"
-#include "../images/toast.xpm"
+#define HAVE_TEXTURE
+#ifdef HAVE_TEXTURE
+# include "images/gen/chromesphere_png.h"
+# include "images/gen/toast_png.h"
+#endif /* HAVE_TEXTURE */
-#ifdef USE_GL /* whole file */
-
-#include <GL/glu.h>
+#ifdef USE_GL /* whole file */
#include "gllist.h"
-extern struct gllist
+extern const struct gllist
*toaster, *toaster_base, *toaster_handle, *toaster_handle2, *toaster_jet,
*toaster_knob, *toaster_slots, *toaster_wing, *toast, *toast2;
-struct gllist **all_objs[] = {
+static const struct gllist * const *all_objs[] = {
&toaster, &toaster_base, &toaster_handle, &toaster_handle2, &toaster_jet,
&toaster_knob, &toaster_slots, &toaster_wing, &toast, &toast2
};
#define GRID_DEPTH 500
-static struct { GLfloat x, y; } nice_views[] = {
+static const struct { GLfloat x, y; } nice_views[] = {
{ 0, 120 },
{ 0, -120 },
{ 12, 28 }, /* this is a list of viewer rotations that look nice. */
GLfloat view_x, view_y;
int view_steps, view_tick;
Bool auto_tracking_p;
+ int track_tick;
GLuint *dlists;
+
+# ifdef HAVE_TEXTURE
GLuint chrome_texture;
GLuint toast_texture;
+# endif
int nfloaters;
floater *floaters;
{&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
};
-ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt toasters_opts = {countof(opts), opts, countof(vars), vars, NULL};
static void
/* if we're not moving, maybe start moving. Otherwise, do nothing. */
if (! bp->auto_tracking_p)
{
- static int tick = 0;
- if (++tick < 200/speed) return;
- tick = 0;
+ if (++bp->track_tick < 200/speed) return;
+ bp->track_tick = 0;
if (! (random() % 5))
bp->auto_tracking_p = True;
else
/* Window management, etc
*/
-void
+ENTRYPOINT void
reshape_toasters (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, 0, (GLint) width, (GLint) height);
+ glViewport (0, y, (GLint) width, (GLint) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
+# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
+ {
+ int o = (int) current_device_rotation();
+ if (o != 0 && o != 180 && o != -180)
+ glScalef (1/h, 1/h, 1/h);
+ }
+# endif
+
glClear(GL_COLOR_BUFFER_BIT);
}
-Bool
-toaster_handle_event (ModeInfo *mi, XEvent *event)
+ENTRYPOINT Bool
+toasters_handle_event (ModeInfo *mi, XEvent *event)
{
toaster_configuration *bp = &bps[MI_SCREEN(mi)];
- if (event->xany.type == ButtonPress &&
- event->xbutton.button == Button1)
- {
- bp->button_down_p = True;
- gltrackball_start (bp->user_trackball,
- event->xbutton.x, event->xbutton.y,
- MI_WIDTH (mi), MI_HEIGHT (mi));
- return True;
- }
- else if (event->xany.type == ButtonRelease &&
- event->xbutton.button == Button1)
- {
- bp->button_down_p = False;
- return True;
- }
- else if (event->xany.type == ButtonPress &&
- (event->xbutton.button == Button4 ||
- event->xbutton.button == Button5))
- {
- gltrackball_mousewheel (bp->user_trackball, event->xbutton.button, 5,
- !event->xbutton.state);
- return True;
- }
- else if (event->xany.type == MotionNotify &&
- bp->button_down_p)
- {
- gltrackball_track (bp->user_trackball,
- event->xmotion.x, event->xmotion.y,
- MI_WIDTH (mi), MI_HEIGHT (mi));
- return True;
- }
+ if (gltrackball_event_handler (event, bp->user_trackball,
+ MI_WIDTH (mi), MI_HEIGHT (mi),
+ &bp->button_down_p))
+ return True;
return False;
}
+#ifdef HAVE_TEXTURE
+
static void
load_textures (ModeInfo *mi)
{
toaster_configuration *bp = &bps[MI_SCREEN(mi)];
XImage *xi;
- xi = xpm_to_ximage (mi->dpy, mi->xgwa.visual, mi->xgwa.colormap,
- chromesphere_xpm);
+ xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual,
+ chromesphere_png, sizeof(chromesphere_png));
clear_gl_error();
+#ifndef HAVE_JWZGLES /* No SPHERE_MAP yet */
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, */
- GL_UNSIGNED_INT_8_8_8_8_REV,
- xi->data);
+ xi->width, xi->height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, xi->data);
check_gl_error("texture");
+ XDestroyImage (xi);
+ xi = 0;
+#endif
- xi = xpm_to_ximage (mi->dpy, mi->xgwa.visual, mi->xgwa.colormap,
- toast_xpm);
+ xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual,
+ toast_png, sizeof(toast_png));
glGenTextures (1, &bp->toast_texture);
glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
xi->width, xi->height, 0,
- GL_RGBA,
- /* GL_UNSIGNED_BYTE, */
- GL_UNSIGNED_INT_8_8_8_8_REV,
- xi->data);
+ GL_RGBA, GL_UNSIGNED_BYTE, xi->data);
check_gl_error("texture");
-
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_2D);
+ XDestroyImage (xi);
+ xi = 0;
}
+#endif /* HAVE_TEXTURE */
-void
+
+
+ENTRYPOINT void
init_toasters (ModeInfo *mi)
{
toaster_configuration *bp;
int wire = MI_IS_WIREFRAME(mi);
int i;
- if (!bps) {
- bps = (toaster_configuration *)
- calloc (MI_NUM_SCREENS(mi), sizeof (toaster_configuration));
- if (!bps) {
- fprintf(stderr, "%s: out of memory\n", progname);
- exit(1);
- }
-
- bp = &bps[MI_SCREEN(mi)];
- }
+ MI_INIT (mi, bps);
bp = &bps[MI_SCREEN(mi)];
glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
}
+# ifdef HAVE_TEXTURE
if (!wire && do_texture)
load_textures (mi);
+# endif
- bp->user_trackball = gltrackball_init ();
+ bp->user_trackball = gltrackball_init (False);
auto_track_init (mi);
bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint));
for (i = 0; i < countof(all_objs); i++)
{
- struct gllist *gll = *all_objs[i];
- if (wire)
- gll->primitive = GL_LINE_LOOP;
+ const struct gllist *gll = *all_objs[i];
glNewList (bp->dlists[i], GL_COMPILE);
glScalef (6, 6, 6);
glBindTexture (GL_TEXTURE_2D, 0);
+ glDisable (GL_TEXTURE_2D);
if (i == BASE_TOASTER)
{
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
+#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);
+ {
+#ifndef HAVE_JWZGLES /* No SPHERE_MAP yet */
+ glEnable (GL_TEXTURE_2D);
+ glEnable (GL_TEXTURE_GEN_S);
+ glEnable (GL_TEXTURE_GEN_T);
+ 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
+ }
+# endif
}
else if (i == TOAST || i == TOAST_BITTEN)
{
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
+#ifdef HAVE_TEXTURE
if (do_texture)
- glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ {
+ glEnable (GL_TEXTURE_2D);
+ glEnable (GL_TEXTURE_GEN_S);
+ glEnable (GL_TEXTURE_GEN_T);
+ glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ }
+# endif
glMatrixMode(GL_TEXTURE);
glTranslatef(0.5, 0.5, 0);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
}
- renderList (gll);
+ renderList (gll, wire);
glMatrixMode(GL_TEXTURE);
glPopMatrix();
{
glPushMatrix();
glRotatef (180, 0, 1, 0);
+
glCallList (bp->dlists[BASE_TOASTER]);
mi->polygon_count += (*all_objs[BASE_TOASTER])->points / 3;
glPopMatrix();
-void
+ENTRYPOINT void
draw_toasters (ModeInfo *mi)
{
toaster_configuration *bp = &bps[MI_SCREEN(mi)];
if (!bp->glx_context)
return;
+ glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
+ glRotatef(current_device_rotation(), 0, 0, 1);
glRotatef(bp->view_x, 1, 0, 0);
glRotatef(bp->view_y, 0, 1, 0);
- gltrackball_rotate (bp->user_trackball);
+ /* Rotate the scene around a point that's a little deeper in. */
+ glTranslatef (0, 0, -50);
+ gltrackball_rotate (bp->user_trackball);
+ glTranslatef (0, 0, 50);
#if 0
{
glXSwapBuffers(dpy, window);
}
+XSCREENSAVER_MODULE_2 ("FlyingToasters", flyingtoasters, toasters)
+
#endif /* USE_GL */