summaryrefslogtreecommitdiff
path: root/src/hackvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hackvr.c')
-rw-r--r--src/hackvr.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/hackvr.c b/src/hackvr.c
new file mode 100644
index 0000000..5cd0de1
--- /dev/null
+++ b/src/hackvr.c
@@ -0,0 +1,367 @@
+#define _POSIX_C_SOURCE 200809L //for fileno and strdup
+#define _BSD_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <stdlib.h>
+//#include <sys/select.h> //code to use select instead of non-blocking is commented out. might decide to use it later.
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+#include <X11/Xutil.h> //for size hints
+#include <time.h>
+#define __USE_GNU //for longer math constants
+#include <math.h>
+
+#include "config.h"
+#include "common.h"
+#ifdef GRAPHICAL
+#include "graphics.h"
+#endif
+
+//TODO: optimizations
+//TODO: store caches of cs_t, c2_t, and c3_t numbers.
+//TODO: don't forget to remake gophervr with this.
+//TODO: XSegment or line structs to store some shit?
+//TODO: line and triangle intersection for finding what object was clicked on
+//if I don't do hiliting I only need to calculate that upon click.
+
+//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.
+
+struct mainwin global;
+
+/* does not return the newline. */
+char *read_line_hack(FILE *fp,int len) {
+ short in;
+ char *t;
+ switch(in=fgetc(fp)) {
+ case '\n':
+ t=malloc(len+1);
+ t[len]=0;
+ return t;
+ case -1:
+ return 0;
+ default:
+ if((t=read_line_hack(fp,len+1))) t[len]=in;
+ break;
+ }
+ return t;
+}
+
+//warning: clobbers input
+//skips leading and trailing space.
+//compresses multiple spaces to one.
+//return length of array
+char **line_splitter(char *line,int *rlen) {
+ char **a;
+ int len,i=0;
+ len=1;//we're just counting how much we'll need the first loop through.
+ for(i=0;line[i] && line[i] == ' ';i++);//skip leading space
+ for(;line[i];len++) {
+ for(;line[i] && line[i] != ' ';i++);//skip rest of data
+ for(;line[i] && line[i] == ' ';i++);//skip rest of space
+ }
+ a=malloc(sizeof(char *) * len+1);
+ a[len]=0;
+ len=0;//reuse!
+ for(i=0;line[i] && line[i] == ' ';i++);//skip leading space
+ a[len]=line+i;
+ for(;;) {
+ for(;line[i] && line[i] != ' ';i++);//skip rest of data
+ if(!line[i]) break;
+ line[i++]=0;
+ for(;line[i] && line[i] == ' ';i++);//skip rest of space
+ if(!line[i]) break;
+ a[++len]=line+i;
+ }
+ a[++len]=0;
+ *rlen=len;
+ return a;
+}
+
+int load_stdin() {
+ struct c3_shape s;
+// struct c3_line l;
+ char *command;
+ char *line;
+ char *id;
+ char **a;
+ int len;
+ int ret=0;
+ int j,k,l;
+ //struct timeval timeout;
+ //fd_set master;
+ //fd_set readfs;
+ //FD_ZERO(&master);
+ //FD_ZERO(&readfs);
+ //FD_SET(0,&master);//just stdin.
+ int i;//used to store the last triangle. even though I have a global for that. >_>
+
+// printf("# entering load_stdin()\n");
+ for(i=0;global.shape[i];i++) ;//hop to the end.
+ fcntl(0,F_SETFL,O_NONBLOCK);
+ if(feof(stdin)) {
+ clearerr(stdin);
+ }
+ // readfs=master;
+ // timeout.tv_sec=0;
+ // timeout.tv_usec=1;
+ // if((j=select(1,&readfs,0,0,&timeout)) == -1) {
+ // perror("select");
+ // return 0;
+ // }
+ // if(FD_ISSET(0,&readfs)) {
+ while((line=read_line_hack(stdin,0))) {//load as long there's something to load
+ if(*line == '#') return 0;
+ //printf("# read command: %s\n",line);
+ a=line_splitter(line,&len);
+ id=a[0];
+ if(len > 1) {
+ command=a[1];
+ }
+ if(len < 2) {
+ if(!strcmp(id,"help")) {
+#ifdef GRAPHICAL
+ printf("# NOT built headless.\n");
+#else
+ printf("# built headless.\n");
+#endif
+ printf("# command format:\n");
+ printf("# some_ID_or_nick_or_username command arguments\n");
+ printf("# commands:\n");
+ printf("# deleteallexcept\n");
+ printf("# deletegroup\n");
+ printf("# assimilate\n");
+ printf("# renamegroup\n");
+ printf("# dump\n");
+ printf("# quit\n");
+ printf("# set\n");
+ printf("# addshape\n");
+ printf("# export\n");
+ printf("# scaleup\n");
+ printf("# move\n");
+ printf("# that is all.\n");
+ return 0;
+ } else {
+ printf("# ur not doing it right. '%s'\n",id);
+ return 0;
+ }
+ }
+ ret=1;
+ if(!strcmp(command,"deleteallexcept")) {
+ for(j=0;global.shape[j];j++) {//mark first. compress later.
+ if(strcmp(global.shape[j]->id,a[2])) {//TODO: memory leak!
+ //free(global.triangle[j]->id);
+ //free(global.triangle[j]);
+ global.shape[j]=0;
+ }
+ }
+ l=0;
+ for(k=0;k<j;k++) {
+ while(global.shape[l] == 0 && l < j) l++;
+ global.shape[k]=global.shape[l];
+ }
+ continue;
+ }
+ if(!strcmp(command,"deletegroup")) {
+ for(j=0;global.shape[j];j++) {//mark first. compress later.
+ if(!strcmp(global.shape[j]->id,s.id)) {//??? where is s.id supposed to be set from?
+ free(global.shape[j]->id);
+ free(global.shape[j]);
+ global.shape[j]=0;
+ }
+ }
+ l=0;
+ for(k=0;k<j;k++) {
+ while(global.shape[l] == 0 && l < j) l++;
+ global.shape[k]=global.shape[l];
+ }
+ continue;
+ }
+ if(!strcmp(command,"assimilate")) {
+ if(len == 3) {
+ for(j=0;global.shape[j];j++) {
+ if(!strcmp(global.shape[j]->id,a[2])) {
+ free(global.shape[j]->id);
+ global.shape[j]->id=strdup(id);
+ }
+ }
+ }
+ continue;
+ }
+ if(!strcmp(command,"renamegroup")) {
+ if(len == 4) {
+ for(j=0;global.shape[j];j++) {
+ if(!strcmp(global.shape[j]->id,a[2])) {
+ free(global.shape[j]->id);
+ global.shape[j]->id=strdup(a[3]);
+ }
+ }
+ }
+ continue;
+ }
+ if(!strcmp(command,"dump")) {
+ printf("%s set camera.p.x %Lf\n",global.user,camera.p.x);
+ printf("%s set camera.p.y %Lf\n",global.user,camera.p.y);
+ printf("%s set camera.p.z %Lf\n",global.user,camera.p.z);
+ printf("%s set camera.xr %d\n",global.user,camera.xr);
+ printf("%s set camera.yr %d\n",global.user,camera.yr);
+ printf("%s set camera.zr %d\n",global.user,camera.zr);
+ printf("%s set camera.zoom %Lf\n",global.user,camera.zoom);
+ continue;
+ }
+ if(!strcmp(command,"quit")) {
+ return -1;
+ }
+ if(!strcmp(command,"set")) { //set variable //TODO: add more things to this.
+ if(len != 3 && len != 4) continue;
+ if(len == 4) {
+ if(!strcmp(a[2],"camera.p.x")) camera.p.x=strtold(a[3],0);
+ else if(!strcmp(a[2],"camera.p.y")) camera.p.y=strtold(a[3],0);
+ else if(!strcmp(a[2],"camera.p.z")) camera.p.z=strtold(a[3],0);
+ else if(!strcmp(a[2],"camera.zoom")) camera.zoom=strtold(a[3],0);
+ else if(!strcmp(a[2],"camera.xr")) camera.xr=atoi(a[3]);
+ else if(!strcmp(a[2],"camera.yr")) camera.yr=atoi(a[3]);
+ else if(!strcmp(a[2],"camera.zr")) camera.zr=atoi(a[3]);
+ else printf("# unknown variable: %s\n",a[2]);
+ continue;
+ }
+ if(!strcmp(a[2],"force_redraw")) global.force_redraw^=1;
+#ifdef GRAPHICAL
+ else if(!strcmp(a[2],"red_and_blue")) { global.red_and_blue^=1; set_aspect_ratio(); }
+#endif
+ else { printf("# unknown variable: %s\n",a[2]); continue; }
+ printf("# %s toggled!\n",a[2]);
+ continue;
+ }
+ if(!strcmp(command,"addshape")) {
+ if(len > 3) {
+ global.shape[i]=malloc(sizeof(struct c3_shape));
+ global.shape[i]->id=strdup(id);
+ global.shape[i]->len=strtold(a[2],0);
+ for(j=0;j < global.shape[i]->len+(global.shape[i]->len==1);j++) {
+ global.shape[i]->p[j].x=strtold(a[(j*3)+3],0);//second arg is just for a return value. set to 0 if you don't want it.
+ global.shape[i]->p[j].y=strtold(a[(j*3)+4],0);
+ global.shape[i]->p[j].z=strtold(a[(j*3)+5],0);
+ }
+ i++;
+ global.shapes=i;
+ global.shape[i]=0;
+ } else {
+ printf("# ERROR: wrong amount of parts for addshape. got: %d expected: 11\n",len);
+ }
+ continue;
+ }
+ if(!strcmp(command,"export")) {
+ if(len > 2) {
+ for(i=0;global.shape[i];i++) {//require a[2], if not it'll segfault. derrrr, epoch.
+ if(!strcmp(global.shape[i]->id,a[2])) {
+ printf("%s addshape %d",a[2],global.shape[i]->len);
+ for(j=0;j < global.shape[i]->len+(global.shape[i]->len==1);j++) {
+ printf(" %Lf %Lf %Lf",global.shape[i]->p[j].x,global.shape[i]->p[j].y,global.shape[i]->p[j].z);
+ }
+ printf("\n");
+ }
+ }
+ }
+ continue;
+ }
+//should scaleup even be inside hackvr? seems like something an external program could do... but it wouldn't act on hackvr's state. so nevermind.
+ if(!strcmp(command,"scaleup")) {//should this scale separately so it can be a deform too?
+ for(i=0;global.shape[i];i++) {
+ if(!strcmp(global.shape[i]->id,id)) {
+ for(j=0;j < global.shape[i]->len+(global.shape[i]->len==1);j++) {
+ global.shape[i]->p[j].x*=strtold(a[2],0);
+ global.shape[i]->p[j].y*=strtold(a[2],0);
+ global.shape[i]->p[j].z*=strtold(a[2],0);
+ }
+ }
+ }
+ continue;
+ }
+ if(!strcmp(command,"move")) {
+ if(len > 4) {
+ for(i=0;global.shape[i];i++) {
+ if(!strcmp(global.shape[i]->id,id)) {
+ for(j=0;j < global.shape[i]->len+(global.shape[i]->len==1);j++) {
+ global.shape[i]->p[j].x+=strtold(a[2],0);
+ global.shape[i]->p[j].y+=strtold(a[3],0);
+ global.shape[i]->p[j].z+=strtold(a[4],0);
+ }
+ }
+ }
+ }
+ else {
+ printf("# ERROR: wrong amount of parts for move. got: %d expected: 11\n",len);
+ }
+ continue;
+ }
+ printf("# I don't know what command you're talking about. %s\n",command);
+/* if(!strcmp(command,"rotate")) {
+ for(i=0;global.shape[i];i++) {
+ global.shape[i]->p1=rotate_c3_about()
+ global.shape[i]->p2=
+ global.shape[i]->p3=
+ }
+*/
+ free(line);
+ if(a) free(a);
+ }
+ return ret;
+}
+
+int export_file(FILE *fp) {//not used yet. maybe export in obj optionally? no. that should be an external program
+// struct c3_shape *to;
+// int i;
+// for(i=0;global.shape[i];i++) {
+// to=global.shape[i];
+// printf("%s addshape %Lf %Lf %Lf %Lf %Lf %Lf %Lf %Lf %Lf\n",to->id,to->p1.x,to->p1.y,to->p1.z,to->p2.x,to->p2.y,to->p2.z,to->p3.x,to->p3.y,to->p3.z);
+// }
+ return 0;
+}
+
+int main(int argc,char *argv[]) {
+ if(argc < 2) {
+ fprintf(stderr,"usage: hackvr yourname < from_others > to_others\n");
+ return 1;
+ } else {
+ global.user=strdup(argv[1]);
+ }
+ fcntl(1,F_SETFL,O_NONBLOCK);//won't work
+ setbuf(stdin,0);
+ setbuf(stdout,0);
+ global.debug=0;
+#ifdef GRAPHICAL
+ int redraw;
+ x11_init();
+#endif
+ printf("# entering main loop\n");
+ for(;;) {
+#ifdef GRAPHICAL
+ redraw=global.force_redraw;
+ if((redraw=x11_event_handler()) == -1) {
+ return 0;
+ }
+ if(redraw && !global.headless) {
+ draw_screen(global.dpy,global.w,global.gc);
+ }
+#endif
+ switch(load_stdin()) {
+ case -1:
+ return 0;
+ break;
+ case 0:
+ break;
+ default:
+#ifdef GRAPHICAL
+ redraw=1;
+#endif
+ break;
+ }
+ }
+ return 0;
+}