--- /dev/null
+*.o
+*.d
+fbgfx
bin = fbgfx
CFLAGS = -pedantic -Wall -g
+LDFLAGS = -limago -lm
$(bin): $(obj)
$(CC) -o $@ $(obj) $(LDFLAGS)
--- /dev/null
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "fbevents.h"
+
+static struct termios orig_state;
+static int term_fd = -1; /* tty file descriptor */
+
+static void (*keyb_func)(int, int, void*);
+static void *keyb_cls;
+static void (*mbutton_func)(int, int, int, int, void*);
+static void *mbutton_cls;
+static void (*mmotion_func)(int, int, void*);
+static void *mmotion_cls;
+
+
+int fbev_init(void)
+{
+ struct termios tstate;
+
+ if((term_fd = open("/dev/tty", O_RDWR)) == -1) {
+ perror("failed to open tty");
+ return -1;
+ }
+ fcntl(term_fd, F_SETFL, fcntl(term_fd, F_GETFL) | O_NONBLOCK);
+
+ if(tcgetattr(term_fd, &tstate) == -1) {
+ perror("failed to retrieve tty attribs");
+ close(term_fd);
+ return -1;
+ }
+ orig_state = tstate;
+
+ cfmakeraw(&tstate);
+ if(tcsetattr(term_fd, TCSANOW, &tstate) == -1) {
+ close(term_fd);
+ return -1;
+ }
+ return 0;
+}
+
+void fbev_shutdown(void)
+{
+ if(term_fd >= 0) {
+ tcsetattr(term_fd, TCSANOW, &orig_state);
+ close(term_fd);
+ term_fd = -1;
+ }
+}
+
+void fbev_update(void)
+{
+ char buf[64];
+ int i, sz;
+ assert(term_fd >= 0);
+
+ while((sz = read(term_fd, buf, 64)) > 0) {
+ if(keyb_func) {
+ for(i=0; i<sz; i++) {
+ keyb_func(buf[i], 1, keyb_cls);
+ }
+ }
+ }
+}
+
+void fbev_keyboard(void (*func)(int, int, void*), void *cls)
+{
+ keyb_func = func;
+ keyb_cls = cls;
+}
+
+void fbev_mbutton(void (*func)(int, int, int, int, void*), void *cls)
+{
+ mbutton_func = func;
+ mbutton_cls = cls;
+}
+
+void fbev_mmotion(void (*func)(int, int, void*), void *cls)
+{
+ mmotion_func = func;
+ mmotion_cls = cls;
+}
--- /dev/null
+#ifndef FBEVENTS_H_
+#define FBEVENTS_H_
+
+int fbev_init(void);
+void fbev_shutdown(void);
+
+void fbev_update(void);
+
+void fbev_keyboard(void (*func)(int, int, void*), void *cls);
+void fbev_mbutton(void (*func)(int, int, int, int, void*), void *cls);
+void fbev_mmotion(void (*func)(int, int, void*), void *cls);
+
+#endif /* FBEVENTS_H_ */
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
static int vmem_size;
static struct fb_fix_screeninfo finfo;
static struct fb_var_screeninfo vinfo;
+static struct fb_var_screeninfo saved_vinfo;
+static int saved_vinfo_valid;
static int init(void)
{
void *fbgfx_set_video_mode(int x, int y, int depth)
{
+ struct fb_var_screeninfo new_vinfo;
+
if(init() == -1) {
return 0;
}
- return 0;
+
+ ioctl(fd, FBIOGET_VSCREENINFO, &new_vinfo);
+ new_vinfo.xres = x;
+ new_vinfo.yres = y;
+ new_vinfo.bits_per_pixel = depth;
+
+ if(ioctl(fd, FBIOPUT_VSCREENINFO, &new_vinfo) == -1) {
+ fprintf(stderr, "failed to set video mode %dx%d %dbpp: %s\n", x, y, depth, strerror(errno));
+ return 0;
+ }
+
+ if(vmem) {
+ munmap(vmem, vmem_size);
+ vmem = 0;
+ vmem_size = 0;
+ }
+
+ return fbgfx_get_video_mode(0, 0, 0);
}
void *fbgfx_get_video_mode(int *xptr, int *yptr, int *depthptr)
if(init() == -1) {
return 0;
}
- if(vmem) return vmem;
ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
vmem_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
- if((vmem = mmap(0, vmem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
- fprintf(stderr, "failed to map video memory\n");
- vmem = 0;
- return 0;
+ if(!vmem) {
+ if((vmem = mmap(0, vmem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
+ fprintf(stderr, "failed to map video memory\n");
+ vmem = 0;
+ return 0;
+ }
}
- *xptr = vinfo.xres;
- *yptr = vinfo.yres;
- *depthptr = vinfo.bits_per_pixel;
+ if(xptr) *xptr = vinfo.xres;
+ if(yptr) *yptr = vinfo.yres;
+ if(depthptr) *depthptr = vinfo.bits_per_pixel;
return vmem;
}
+
+void fbgfx_save_video_mode(void)
+{
+ if(init() == -1) {
+ return;
+ }
+
+ if(ioctl(fd, FBIOGET_VSCREENINFO, &saved_vinfo) == -1) {
+ return;
+ }
+ saved_vinfo_valid = 1;
+}
+
+void fbgfx_restore_video_mode(void)
+{
+ if(init() == -1 || !saved_vinfo_valid) {
+ return;
+ }
+ ioctl(fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
+}
void *fbgfx_set_video_mode(int x, int y, int depth);
void *fbgfx_get_video_mode(int *xptr, int *yptr, int *depthptr);
+void fbgfx_save_video_mode(void);
+void fbgfx_restore_video_mode(void);
+
#endif /* FBGFX_H_ */
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include "fbgfx.h"
+#include "fbevents.h"
+#include "tunnel.h"
+
+static void keyboard(int key, int pressed, void *cls);
+static void mouse(int bn, int pressed, int x, int y, void *cls);
+static void motion(int x, int y, void *cls);
-static unsigned char *vmem;
+static void *vmem;
static int xsz, ysz, depth;
+static int quit;
+
+
int main(void)
{
- if(!(vmem = fbgfx_get_video_mode(&xsz, &ysz, &depth))) {
+ fbgfx_save_video_mode();
+ if(!(vmem = fbgfx_set_video_mode(800, 600, 16))) {
return 1;
}
- printf("current video mode: %dx%d %dbpp\n", xsz, ysz, depth);
+ fbgfx_get_video_mode(&xsz, &ysz, &depth);
+ if(depth != 16) {
+ goto end;
+ }
+ if(fbev_init() == -1) {
+ goto end;
+ }
+ fbev_keyboard(keyboard, 0);
+ fbev_mbutton(mouse, 0);
+ fbev_mmotion(motion, 0);
+
+ if(init_tunnel(xsz, ysz) == -1) {
+ goto end;
+ }
- /*memset(vmem, 0xff, xsz * ysz * depth / 8);*/
+ for(;;) {
+ fbev_update();
+ if(quit) break;
+
+ draw_tunnel(vmem);
+ }
+end:
+ destroy_tunnel();
+ fbev_shutdown();
+ fbgfx_restore_video_mode();
return 0;
}
+
+static void keyboard(int key, int pressed, void *cls)
+{
+ if(!pressed) return;
+
+ switch(key) {
+ case 27:
+ case 'q':
+ case 'Q':
+ exit(0);
+ }
+}
+
+static void mouse(int bn, int pressed, int x, int y, void *cls)
+{
+}
+
+static void motion(int x, int y, void *cls)
+{
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <imago2.h>
+#include "tunnel.h"
+
+static int xsz, ysz;
+static unsigned int *tunnel_map;
+
+
+int init_tunnel(int x, int y)
+{
+ int i, j;
+ unsigned int *tmap;
+
+ xsz = x;
+ ysz = y;
+
+ printf("precalculating tunnel map...\n");
+
+ if(!(tunnel_map = malloc(xsz * ysz * sizeof *tunnel_map))) {
+ fprintf(stderr, "failed to allocate tunnel map\n");
+ return -1;
+ }
+ tmap = tunnel_map;
+
+ for(i=0; i<ysz; i++) {
+ float y = 2.0 * (float)i / (float)ysz - 0.5;
+ for(j=0; j<xsz; j++) {
+ float x = 2.0 * (float)j / (float)xsz - 0.5;
+ float tu = atan2(y, x) / M_PI * 0.5 + 0.5;
+ float tv = sqrt(x*x + y*y);
+
+ int tx = (int)(tu * 65535.0) & 0xffff;
+ int ty = (int)(tv * 65535.0) & 0xffff;
+
+ *tmap++ = (tx << 16) | ty;
+ }
+ }
+
+ return 0;
+}
+
+void destroy_tunnel(void)
+{
+ free(tunnel_map);
+}
+
+void draw_tunnel(unsigned short *pixels)
+{
+ int i, j, r, g, b;
+ unsigned int *tmap = tunnel_map;
+
+ for(i=0; i<ysz; i++) {
+ for(j=0; j<xsz; j++) {
+ unsigned int tx = (*tmap >> 16) & 0xffff;
+ unsigned int ty = *tmap & 0xffff;
+ ++tmap;
+
+ r = tx >> 8;
+ g = ty >> 8;
+
+ *pixels++ = ((((r >> 3) & 0x1f) << 11) |
+ (((g >> 2) & 0x3f) << 5));/* |
+ ((b >> 3) & 0x1f));*/
+ }
+ }
+}
--- /dev/null
+#ifndef TUNNEL_H_
+#define TUNNEL_H_
+
+int init_tunnel(int x, int y);
+void destroy_tunnel(void);
+void draw_tunnel(unsigned short *pixels);
+
+#endif /* TUNNEL_H_ */