almost
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Fri, 19 Aug 2016 23:03:56 +0000 (02:03 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Fri, 19 Aug 2016 23:03:56 +0000 (02:03 +0300)
.gitignore [new file with mode: 0644]
Makefile
src/fbevents.c [new file with mode: 0644]
src/fbevents.h [new file with mode: 0644]
src/fbgfx.c
src/fbgfx.h
src/main.c
src/tunnel.c [new file with mode: 0644]
src/tunnel.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1dded00
--- /dev/null
@@ -0,0 +1,3 @@
+*.o
+*.d
+fbgfx
index 7882958..cf6bb9d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ obj = $(src:.c=.o)
 bin = fbgfx
 
 CFLAGS = -pedantic -Wall -g
+LDFLAGS = -limago -lm
 
 $(bin): $(obj)
        $(CC) -o $@ $(obj) $(LDFLAGS)
diff --git a/src/fbevents.c b/src/fbevents.c
new file mode 100644 (file)
index 0000000..1522a58
--- /dev/null
@@ -0,0 +1,84 @@
+#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;
+}
diff --git a/src/fbevents.h b/src/fbevents.h
new file mode 100644 (file)
index 0000000..5feecbe
--- /dev/null
@@ -0,0 +1,13 @@
+#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_ */
index 4b96eeb..d7fe862 100644 (file)
@@ -1,5 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <errno.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
@@ -14,6 +16,8 @@ static void *vmem;
 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)
 {
@@ -42,10 +46,29 @@ static void cleanup(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)
@@ -53,18 +76,39 @@ 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);
+}
index 6c18d7f..134de2f 100644 (file)
@@ -4,5 +4,8 @@
 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_ */
index 9d73367..8752567 100644 (file)
@@ -1,19 +1,71 @@
 #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)
+{
+}
diff --git a/src/tunnel.c b/src/tunnel.c
new file mode 100644 (file)
index 0000000..a348431
--- /dev/null
@@ -0,0 +1,68 @@
+#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));*/
+               }
+       }
+}
diff --git a/src/tunnel.h b/src/tunnel.h
new file mode 100644 (file)
index 0000000..c4337e1
--- /dev/null
@@ -0,0 +1,8 @@
+#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_ */