summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorepoch <epoch@hacking.allowed.org>2018-02-03 22:35:44 -0600
committerepoch <epoch@hacking.allowed.org>2018-02-03 22:35:44 -0600
commitb8e79deb5b362cf572a31be7cba75a6c6f602358 (patch)
tree5b5cd23e2c889f55de6542ce9e7625eee899f6b5 /src
parent664bf529ba8d5c2a74698065cfa81521300cea5a (diff)
downloadhackvr-b8e79deb5b362cf572a31be7cba75a6c6f602358.tar.gz
hackvr-b8e79deb5b362cf572a31be7cba75a6c6f602358.zip
framebuffer support
Diffstat (limited to 'src')
-rw-r--r--src/graphics_cs_fb.c577
-rw-r--r--src/graphics_fb.h44
l---------src/hackvr_fb.c1
3 files changed, 622 insertions, 0 deletions
diff --git a/src/graphics_cs_fb.c b/src/graphics_cs_fb.c
new file mode 100644
index 0000000..9885bd6
--- /dev/null
+++ b/src/graphics_cs_fb.c
@@ -0,0 +1,577 @@
+#define _POSIX_C_SOURCE 200809L //for fileno and strdup
+#include <stdio.h>
+#include <fcntl.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <time.h>
+
+#include "config.h"
+#include "common.h"
+#include "graphics_c3.h"//not needed?
+#include "graphics_fb.h"
+#include "graphics_cs.h"
+
+//typedef float real; //think this conflicts?
+
+//TODO: will have to make some pixmaps get resized when the window does.
+//for now set them to be as big as you think you'll ever resize the window to.
+
+//#define SKYRULE 90
+//#define SKYW (WIDTH*5)
+//#define SKYH (HEIGHT/2)
+
+//Pixmap skypixmap;
+//char sky[SKYH][SKYW];
+
+extern struct global global;
+extern struct gra_global gra_global;
+struct fb_global fb_global;
+
+#ifdef GRAPHICAL
+
+/*
+struct plane {
+ c3_t p;
+ real xr;
+ real yr;
+ real zr;
+}
+
+void calculate_shape_color(c3_s_t s,real d) {
+//given: at least 3 points on a plane.
+//needed: angles of the plane.
+//
+ xa=
+ ya=
+ za=
+ for(i=0;i<;i++) {
+ s.p.x
+ }
+}
+*/
+
+void set_luminosity_color(int lum) {//need to come up with a good range for this.
+ fb_global.current_color=((200-lum) << 16) | ((200-lum) << 8) | lum;
+}
+
+void draw_cs_point(int x,int y) {//this should write to a backbuffer then I can memcopy it over.
+ unsigned int i=y * fb_global.info.xres + x;
+ if(x > fb_global.info.xres) return;
+ if(y > fb_global.info.yres) return;
+ if(i > fb_global.fblen) return;
+ switch(fb_global.draw_mode) {
+ case DRAW_MODE_COPY:
+ fb_global.backbuf[i]=fb_global.current_color;
+ break;
+ case DRAW_MODE_OR:
+ fb_global.backbuf[i] |= fb_global.current_color;
+ break;
+ case DRAW_MODE_AND:
+ fb_global.backbuf[i] &= fb_global.current_color;
+ break;
+ case DRAW_MODE_CLEAR:
+ fb_global.backbuf[i]=0;
+ break;
+ default:
+ printf("# derp. unknown draw_mode %d\n",fb_global.draw_mode);
+ break;
+ }
+}
+
+void draw_cs_line(cs_t p1,cs_t p2) {//error somewhere in here. derp...
+ int x,y;
+ real m;
+ int b;
+ int xd,yd;
+ if(p1.x == p2.x) {
+ for(y=min(p1.y,p2.y);y<max(p1.y,p2.y);y++) {
+ draw_cs_point(p1.x,y);
+ }
+ }
+ if(p1.y == p2.y) {
+ for(x=min(p1.x,p2.x);x<max(p1.x,p2.x);x++) {
+ draw_cs_point(x,p1.y);
+ }
+ }
+ xd=p1.x<p2.x?1:-1;
+ yd=p1.y<p2.y?1:-1;
+ if(max(p1.x,p2.x)-min(p1.x,p2.x) >= max(p1.y,p2.y)-min(p1.y,p2.y)) { //loop over x. like normal math. :P y=mx+b stuff.
+ m=((real)(p1.y-p2.y))/((real)(p1.x-p2.x));
+ b=(int)((real)p1.y - (m * (real)p1.x));
+ for(x=p1.x;x!=p2.x;x+=xd) {
+ y=(int)(m * (real)x + (real)b);
+ draw_cs_point(x,y);
+ }
+ } else { //loop over y
+ m=((real)(p1.x-p2.x))/((real)(p1.y-p2.y));
+ b=(int)((real)p1.x - (m * (real)p1.y));
+ for(y=p1.y;y!=p2.y;y+=yd) {
+ x=(int)(m * (real)y + (real)b);
+ draw_cs_point(x,y);
+ }
+ }
+ //now for the fun part.
+}
+
+void draw_cs_text(cs_t p,char *text) {
+/* char t[256];
+ int direction,ascent,descent;
+ XFontStruct *font=XLoadQueryFont(x11_global.dpy,"fixed");
+ XCharStruct overall;
+ snprintf(t,sizeof(t)-1,"%s",text);
+ XTextExtents(font,text,strlen(text),&direction,&ascent,&descent,&overall);
+ XDrawString(x11_global.dpy,x11_global.backbuffer,x11_global.backgc,p.x,p.y+(descent+ascent),text,strlen(text));*/
+}
+
+void draw_cs_shape(cs_s_t s) {//this is implemented as draw_cs_line... hrm. it could be moved up to graphics.c? probl no.
+ //test in here whether a mouse click is within this shape's... bounding box? sure.
+ cs_s_t bb;//bounding box
+ int minx=s.p[0].x;
+ int miny=s.p[0].y;
+ int maxx=s.p[0].x;
+ int maxy=s.p[0].y;
+ int h;
+ int i;//all cs shapes can have 1, 2, or 3+ points. guess I gotta do that logic here too.
+ switch(s.len) {
+ case 1:
+ //circle
+ h=max(s.p[0].x,s.p[1].x)-min(s.p[0].x,s.p[1].x);
+ //XDrawArc(x11_global.dpy,x11_global.backbuffer,x11_global.backgc,s.p[0].x-h,s.p[0].y-h,h*2,h*2,0,360*64);
+ break;
+ default:
+ for(i=0;i<s.len+(s.len==1);i++) {//this shape is closed!
+ minx=(s.p[i].x<minx)?s.p[i].x:minx;
+ miny=(s.p[i].y<miny)?s.p[i].y:miny;
+ maxx=(s.p[i].x>maxx)?s.p[i].x:maxx;
+ maxy=(s.p[i].y>maxy)?s.p[i].y:maxy;
+ draw_cs_line(s.p[i],s.p[(i+1)%(s.len+(s.len==1))]);
+ }
+ if(gra_global.mousex >= minx &&
+ gra_global.mousey >= miny &&
+ gra_global.mousex <= maxx &&
+ gra_global.mousey <= maxy) {
+ if(gra_global.buttonpressed) {//if we're inside the bounding box let's make SOMETHING happen.
+ printf("%s action %s\n",global.user,s.id);
+ }
+ if(!strncmp(s.id,"term",4)) {
+ gra_global.input_mode=1;
+ }
+ bb.id=strdup("boundingbox");
+ bb.len=4;
+ bb.p[0].x=minx;
+ bb.p[0].y=miny;
+ bb.p[1].x=minx;
+ bb.p[1].y=maxy;
+ bb.p[2].x=maxx;
+ bb.p[2].y=maxy;
+ bb.p[3].x=maxx;
+ bb.p[3].y=miny;
+ draw_cs_filled_shape(bb);
+ free(bb.id);
+ }
+ break;
+ }
+}
+
+int x_from_y(cs_t p1,cs_t p2,int y) {//get the value of x given a y within a line.
+ real m;
+ int b;
+ int x;
+// y=mx+b MAGIC
+ if(p1.x == p2.x) return p1.x;//if this happens then we have a verticle line and can just shortcut this shit.
+ if(p1.y == p2.y) {//if this happens we have a horizontal line we're trying to find the X of based on a 'y' that probably isn't in the line...
+ return 0;
+ }//return p1.x;//WE SHOULD NOT GET HERE. fuck if I know.
+// y=mx+b
+// y-b=mx
+// x=(y-b)/m
+// b=y-mx
+ m=((real)(p1.y-p2.y))/((real)(p1.x-p2.x));
+ b=(int)((real)p1.y - (m * (real)p1.x));
+ x=(int)(((real)(y-b))/m);
+ if(!x) printf("x == %d y=%d m=%f b=%d\n",x,y,m,b);
+ return x;
+}
+
+void draw_cs_filled_shape(cs_s_t s) {//no circle handling atm. and only convex polygons.
+ int maxmax=0;
+ int minmin=0;
+ cs_t p1;
+ cs_t p2;
+ int i;
+ int y;
+ for(i=0;i<s.len;i++) {//find the minimum and maximum points. minmin is smallest x and y. maxmax is biggest x and y.
+ if(s.p[i].y < s.p[minmin].y || (s.p[i].y == s.p[minmin].y && s.p[i].x < s.p[minmin].x)) minmin=i;
+ if(s.p[i].y > s.p[maxmax].y || (s.p[i].y==s.p[maxmax].y && s.p[i].x > s.p[maxmax].x)) maxmax=i;
+ }
+ int a1=minmin;
+ int a2=(minmin+1)%s.len;
+ int b1=minmin;
+ int b2=(minmin+s.len-1)%s.len;
+ for(y=s.p[minmin].y;y<s.p[maxmax].y;y++) {//loop from minimum y to maximum y.
+ //now we need to trace lines from minmin to what minmin connects to. minmin+1 and minmin-1
+ while(y == s.p[a2].y) { a1=a2; a2=(a2+1)%s.len; }
+ while(y == s.p[b2].y) { b1=b2; b2=(b2+s.len-1)%s.len; }
+ if(s.p[a1].y != s.p[a2].y) p1=(cs_t){x_from_y(s.p[a1],s.p[a2],y),y};
+ if(s.p[b1].y != s.p[b2].y) p2=(cs_t){x_from_y(s.p[b1],s.p[b2],y),y};
+ draw_cs_line(p1,p2);//the two y values are always the same here.
+ }
+}
+/*
+void draw_cs_filled_shape(cs_s_t s) {
+ int h;
+ int i;
+ //XPoint Xp[s.len+(s.len==1)];
+ for(i=0;i<s.len+(s.len==1);i++) {
+ //Xp[i]=(XPoint){s.p[i].x,s.p[i].y};
+ }
+ switch(s.len) {
+ case 1:
+ h=max(s.p[0].y,s.p[1].y)-min(s.p[0].y,s.p[1].y);
+ h=max(s.p[0].x,s.p[1].x)-min(s.p[0].x,s.p[0].x);
+ //XFillArc(x11_global.dpy,x11_global.backbuffer,x11_global.backgc,s.p[0].x-h,s.p[0].y-h,h*2,h*2,0,360*64);
+ break;
+ default:
+ //XFillPolygon(x11_global.dpy,x11_global.backbuffer,x11_global.backgc,Xp,s.len,Convex,CoordModeOrigin);
+ break;
+ }
+}*/
+
+//should I do clipping in each graphics lib or make graphics.c just have clipping stuff?
+void clear_backbuffer() {
+ //XCopyArea(x11_global.dpy,x11_global.cleanbackbuffer,x11_global.backbuffer,x11_global.gc,0,0,gra_global.width,gra_global.height,0,0);
+ memset(fb_global.backbuf,0,fb_global.fblen);
+}
+
+void set_clipping_rectangle(int x,int y,int width,int height) {
+ //XRectangle cliprect;
+ //cliprect.x=0;
+ //cliprect.y=0;
+ //cliprect.width=width;
+ //cliprect.height=height;
+ //XSetClipRectangles(x11_global.dpy,x11_global.backgc,x,y,&cliprect,1,Unsorted);
+}
+
+void draw_mode_copy() {
+ fb_global.draw_mode=DRAW_MODE_COPY;
+}
+
+void draw_mode_and() {
+ fb_global.draw_mode=DRAW_MODE_AND;
+}
+
+void draw_mode_or() {
+ fb_global.draw_mode=DRAW_MODE_OR;
+}
+
+void red_and_blue_magic() {
+ draw_mode_or();
+}
+
+//void draw_sky() {
+// XCopyArea(x11_global.dpy,skypixmap,x11_global.backbuffer,x11_global.backgc,((global.camera.yr.d*5)+SKYW)%SKYW,0,WIDTH,gra_global.height/2,0,0);
+//}
+
+void set_ansi_color(int i) {
+ fb_global.current_color=(i&4?0xff0000:0x0) | (i&2 ?0xff00:0x0) | (i&1?0xff:0x0);// :D
+}
+
+void set_color() {
+ fb_global.current_color=0x00ff00;
+}
+
+void set_color_red() {
+ fb_global.current_color=0xff0000;
+}
+
+void set_color_blue() {
+ fb_global.current_color=0x0000ff;
+}
+
+void flipscreen() {
+ memcpy(fb_global.buf,fb_global.backbuf,fb_global.fblen);//
+}
+
+void set_aspect_ratio() {
+ //XSizeHints *hints=XAllocSizeHints();
+ //hints->min_aspect.x=AR_W*(gra_global.split_screen / (gra_global.red_and_blue ? gra_global.split_screen : 1));
+ //hints->min_aspect.y=AR_H;
+ //hints->max_aspect.x=AR_W*(gra_global.split_screen / (gra_global.red_and_blue ? gra_global.split_screen : 1));
+ //hints->max_aspect.y=AR_H;
+ //hints->flags |= PAspect;
+ //XSetWMNormalHints(x11_global.dpy,x11_global.w,hints);
+ //XFree(hints);
+}
+
+void set_demands_attention() {
+ //XWMHints *hints=XGetWMHints(x11_global.dpy,x11_global.w);
+ //if(!hints) hints=XAllocWMHints();
+ //hints->flags |= XUrgencyHint;
+ //XSetWMHints(x11_global.dpy,x11_global.w,hints);
+ //XFree(hints);
+}
+
+#endif
+
+int graphics_sub_init() {
+ int i;
+ int x,y;
+ fb_global.fb=open("/dev/fb0",O_RDWR);
+ fb_global.kb=open("/dev/input/event0",O_RDWR);
+ memset(fb_global.keystate,0,sizeof(fb_global.keystate));
+ fcntl(fb_global.kb,F_SETFL,O_NONBLOCK);
+ assert(fb_global.fb > 0);
+ assert( 0 == ioctl(fb_global.fb,FBIOGET_VSCREENINFO,&fb_global.info));
+ fb_global.fblen = 4 * fb_global.info.xres * fb_global.info.yres;
+ fb_global.buf = mmap(NULL,fb_global.fblen,PROT_READ | PROT_WRITE,MAP_SHARED, fb_global.fb,0);
+ fb_global.backbuf = malloc(fb_global.fblen);
+ assert(fb_global.buf != MAP_FAILED);
+ //now... how to generate 200 greys....
+ //heh.
+ for(x=0;x<fb_global.info.xres;x++) {
+ for(y=0;y<fb_global.info.yres;y++) {
+ fb_global.current_color=rand();
+ draw_cs_point(x,y);
+ }
+ }
+ flipscreen();
+ gra_global.width=fb_global.info.xres;
+ gra_global.height=fb_global.info.yres;
+ return 0;
+}
+
+/* this need a framebuffer equivalent
+ for(i=0;i<=100;i++) {
+ snprintf(tmp,sizeof(tmp),"gray%d",i);
+ XAllocNamedColor(x11_global.dpy,x11_global.color_map,tmp,&x11_global.colors[i],&x11_global.colors[i]);
+ }
+ return 0;//we're fine
+}
+*/
+
+// printf(" %d <-- len\t:code:%d\tvalue:%d\ttype:%d\n",l,ie.code,ie.value,ie.type);
+
+#define KEY_IS_DOWN(a) (fb_global.keystate[a/8] & (1<< (a % 8)))
+
+int graphics_event_handler(int world_changed) { //should calling draw_screen be in here?
+ int redraw=0;
+ char line[2048];
+ char line2[1025];
+ int len;
+ struct input_event ie;
+ memset(&ie,0,sizeof(ie));
+ int l;
+ real tmpx;
+ real tmpz;
+ radians tmprad;
+ radians tmprad2;
+ int i;
+ //update the keystates...
+ ioctl(fb_global.kb,EVIOCGKEY(sizeof(fb_global.keystate)),fb_global.keystate);//update keystate
+ if(KEY_IS_DOWN(KEY_ESC)) exit(0);
+ if(KEY_IS_DOWN(KEY_ENTER)) {
+ snprintf(line,sizeof(line)-1,"%s action %s\n",global.user,global.selected_object);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_UP)) {
+ tmprad=d2r((degrees){global.camera.r.y.d});//if the angle is 0...
+ tmprad2=d2r((degrees){global.camera.r.y.d});
+ tmpx=WALK_SPEED*sin(tmprad.r);//cos(0)==1
+ tmpz=WALK_SPEED*cos(tmprad2.r);//sin(0)==0
+ snprintf(line,sizeof(line)-1,"%s move %f 0 %f\n",global.user,tmpx,tmpz);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_DOWN)) {
+ tmprad=d2r((degrees){global.camera.r.y.d+180});
+ tmprad2=d2r((degrees){global.camera.r.y.d+180});
+ tmpx=WALK_SPEED*sin(tmprad.r);
+ tmpz=WALK_SPEED*cos(tmprad2.r);
+ snprintf(line,sizeof(line)-1,"%s move %f 0 %f\n",global.user,tmpx,tmpz);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_LEFT)) {
+ tmprad=d2r((degrees){global.camera.r.y.d+90});
+ tmprad2=d2r((degrees){global.camera.r.y.d+90});
+ tmpx=WALK_SPEED*sin(tmprad.r);
+ tmpz=WALK_SPEED*cos(tmprad2.r);
+ snprintf(line,sizeof(line)-1,"%s move %f 0 %f\n",global.user,tmpx,tmpz);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_RIGHT)) {
+ tmprad=d2r((degrees){global.camera.r.y.d+270});
+ tmprad2=d2r((degrees){global.camera.r.y.d+270});
+ tmpx=WALK_SPEED*sin(tmprad.r);
+ tmpz=WALK_SPEED*cos(tmprad2.r);
+ snprintf(line,sizeof(line)-1,"%s move %f 0 %f\n",global.user,tmpx,tmpz);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_W)) {
+ snprintf(line,sizeof(line)-1,"%s move 0 1 0\n",global.user);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_S)) {
+ snprintf(line,sizeof(line)-1,"%s move 0 -1 0\n",global.user);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_R)) {
+ snprintf(line,sizeof(line)-1,"%s rotate %d 0 0\n",global.user,global.camera.r.x.d+ROTATE_STEP);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_Y)) {
+ snprintf(line,sizeof(line)-1,"%s rotate %d 0 0\n",global.user,global.camera.r.x.d-ROTATE_STEP);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_Q)) {
+ snprintf(line,sizeof(line)-1,"%s rotate 0 %d 0\n",global.user,global.camera.r.y.d+ROTATE_STEP);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_E)) {
+ snprintf(line,sizeof(line)-1,"%s rotate 0 %d 0\n",global.user,global.camera.r.y.d-ROTATE_STEP);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_U)) {
+ snprintf(line,sizeof(line)-1,"%s rotate 0 0 %d\n",global.user,global.camera.r.z.d+ROTATE_STEP);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_O)) {
+ snprintf(line,sizeof(line)-1,"%s rotate 0 0 %d\n",global.user,global.camera.r.z.d-ROTATE_STEP);
+ selfcommand(line);
+ }
+ if(KEY_IS_DOWN(KEY_P)) gra_global.split+=.1;
+ if(KEY_IS_DOWN(KEY_L)) gra_global.split-=.1;
+ if(KEY_IS_DOWN(KEY_Z)) global.zoom+=1;
+ if(KEY_IS_DOWN(KEY_X)) {
+ global.zoom-=1;
+ if(global.zoom < 1) global.zoom=1;
+ }
+ if(KEY_IS_DOWN(KEY_C)) global.mmz*=1.1;
+ if(KEY_IS_DOWN(KEY_V)) global.mmz/=1.1;
+ if(KEY_IS_DOWN(KEY_H)) global.split+=1;
+ if(KEY_IS_DOWN(KEY_J)) global.split-=1;
+ if(KEY_IS_DOWN(KEY_6)) gra_global.maxshapes+=10;
+ if(KEY_IS_DOWN(KEY_7)) gra_global.maxshapes-=10;
+ if(KEY_IS_DOWN(KEY_D)) global.debug ^= 1;
+ if(KEY_IS_DOWN(KEY_F)) global.derp ^= 1;
+ if(KEY_IS_DOWN(KEY_M)) {
+ gra_global.drawminimap += 1;
+ gra_global.drawminimap %= 4;
+ }
+ if(KEY_IS_DOWN(KEY_A)) gra_global.drawsky ^= 1;
+ if(KEY_IS_DOWN(KEY_3)) {
+ gra_global.draw3d += 1;
+ gra_global.draw3d %= 4;
+ }
+//LONG comment. then rest of function. don't end it too early, derp.
+/*
+ }
+ break;
+ default:
+ switch(sym) {
+ case XK_Return:
+ strcpy(line,"\n");
+ len=1;
+ break;
+ case XK_Left://hack. probably just replace this with printf()s
+ strcpy(line,"\x1b[D");
+ len=3;
+ break;
+ case XK_Right:
+ strcpy(line,"\x1b[C");
+ len=3;
+ break;
+ case XK_Down:
+ strcpy(line,"\x1b[B");
+ len=3;
+ break;
+ case XK_Up:
+ strcpy(line,"\x1b[A");
+ len=3;
+ break;
+ default:
+ len=XLookupString(xkey,line,1023,NULL,NULL);
+ break;
+ }
+ for(i=0;i/2 < len;i++) line2[i]="0123456789abcdef"[(line[i/2]>>(4*(1-(i%2)))) % 16];
+ line2[i]=0;
+ printf("%s data %s\n",global.user,line2);
+ break;
+ }
+
+ //then do stuff based on what keystates are set.
+ //... loop over the whole array?
+ //have an array of deltas?
+ //what sets mask?
+ char motionnotify=0;
+ unsigned int mask;
+ if(global.beep) {
+ global.beep=0;
+ XBell(x11_global.dpy,1000);
+ set_demands_attention();
+ }
+ while(XPending(x11_global.dpy)) {//these are taking too long?
+ XNextEvent(x11_global.dpy, &e);
+// fprintf(stderr,"# handling event with type: %d\n",e.type);
+ switch(e.type) {
+// case Expose:
+// if(e.xexpose.count == 0) redraw=1;
+// break;
+ case MotionNotify:
+ if(global.debug >= 2) fprintf(stderr,"# MotionNotify\n");
+ motionnotify=1;
+ break;
+ case ButtonPress:
+ if(global.debug >= 2) fprintf(stderr,"# ButtonPress\n");
+ redraw=1;
+ gra_global.buttonpressed=e.xbutton.button;//what's this for? mouse?
+ break;
+ case ButtonRelease:
+ if(global.debug >= 2) fprintf(stderr,"# ButtonRelease\n");
+ redraw=1;
+ gra_global.buttonpressed=0;//what's this for???
+ break;
+ case ConfigureNotify:
+ if(global.debug >= 2) fprintf(stderr,"# ConfigureNotify\n");
+ redraw=1;
+ XGetGeometry(x11_global.dpy,x11_global.w,&root,&global.x,&global.y,&gra_global.width,&gra_global.height,&gra_global.border_width,&gra_global.depth);
+ if(gra_global.height * AR_W / AR_H != gra_global.width / (gra_global.split_screen / (gra_global.red_and_blue ? gra_global.split_screen : 1))) {
+ // height / AR_H * AR_W = width / (ss / (rab ? ss : 1))
+ if(global.debug >= 2) {
+ fprintf(stderr,"# %d != %d for some reason. probably your WM not respecting aspect ratio hints or calculating based on them differently. (would cause an off-by-one or so)\n",gra_global.height * AR_W / AR_H , gra_global.width / (gra_global.split_screen / (gra_global.red_and_blue ? gra_global.split_screen : 1)));
+ }
+ if(gra_global.width / (gra_global.red_and_blue ? 1 : gra_global.split_screen) * AR_H / AR_W < gra_global.height) {
+ gra_global.height=gra_global.width / (gra_global.red_and_blue ? 1 : gra_global.split_screen) * AR_H / AR_W;
+ } else {
+ gra_global.width=gra_global.height * AR_W / AR_H * (gra_global.red_and_blue ? 1 : gra_global.split_screen);
+ }
+ }
+ gra_global.mapxoff=gra_global.width/(gra_global.split_screen / (gra_global.red_and_blue ? gra_global.split_screen : 1))/2;
+ gra_global.mapyoff=gra_global.height/2;
+ break;
+ case KeyPress:
+ if(global.debug >= 2) fprintf(stderr,"# KeyPress\n");
+ redraw=1;
+ x11_keypress_handler(&e.xkey,gra_global.mousex,gra_global.mousey);
+ break;
+ default:
+// fprintf(stderr,"# received unknown event with type: %d\n",e.type);
+ break;
+ }
+ }
+ if(motionnotify) {
+ XQueryPointer(x11_global.dpy,x11_global.w,&root,&child,&gra_global.rmousex,&gra_global.rmousey,&gra_global.mousex,&gra_global.mousey,&mask);
+ redraw=1;
+ }
+*/
+ if(redraw || world_changed) {
+ gra_global.input_mode=0;
+ draw_screen();//includes its own flip.
+ }
+ return 1;//redraw;
+}
diff --git a/src/graphics_fb.h b/src/graphics_fb.h
new file mode 100644
index 0000000..d6e8d7c
--- /dev/null
+++ b/src/graphics_fb.h
@@ -0,0 +1,44 @@
+#ifndef _HACKVR_GRAPHICS_FB_H_
+#define _HACKVR_GRAPHICS_FB_H_
+
+//find this with trial and error or X11 log or... I don't care.
+#define FB_KEYB "/dev/input/event0"
+
+#include <linux/input.h>
+
+#define DRAW_MODE_CLEAR 0x0
+#define DRAW_MODE_AND 0x1
+#define DRAW_MODE_COPY 0x3
+#define DRAW_MODE_OR 0x7
+
+struct fb_global {
+ int fb;
+ int kb;
+ int draw_mode;
+ unsigned int current_color;
+ unsigned int *backbuf;
+ struct fb_var_screeninfo info;
+ unsigned int *buf;
+ unsigned int fblen;
+ char keystate[KEY_MAX/8+1];
+};
+
+#endif
+#if 0
+#define GXclear 0x0 /* 0 */
+#define GXand 0x1 /* src AND dst */
+#define GXandReverse 0x2 /* src AND NOT dst */
+#define GXcopy 0x3 /* src */
+#define GXandInverted 0x4 /* NOT src AND dst */
+#define GXnoop 0x5 /* dst */
+#define GXxor 0x6 /* src XOR dst */
+#define GXor 0x7 /* src OR dst */
+#define GXnor 0x8 /* NOT src AND NOT dst */
+#define GXequiv 0x9 /* NOT src XOR dst */
+#define GXinvert 0xa /* NOT dst */
+#define GXorReverse 0xb /* src OR NOT dst */
+#define GXcopyInverted 0xc /* NOT src */
+#define GXorInverted 0xd /* NOT src OR dst */
+#define GXnand 0xe /* NOT src OR NOT dst */
+#define GXset 0xf /* 1 */
+#endif
diff --git a/src/hackvr_fb.c b/src/hackvr_fb.c
new file mode 120000
index 0000000..e4c9ddd
--- /dev/null
+++ b/src/hackvr_fb.c
@@ -0,0 +1 @@
+hackvr.c \ No newline at end of file