diff options
author | Ian C <ianc@noddybox.co.uk> | 2011-06-09 13:46:28 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2011-06-09 13:46:28 +0000 |
commit | a9022b5972dc49d86f617a27940fafe9c4d0e7e7 (patch) | |
tree | 61405aa4ade91ed1057f863ddf118ceb38e14f8e /linux/gfx.c |
Initial import of (very old) vidoom sources.
Diffstat (limited to 'linux/gfx.c')
-rw-r--r-- | linux/gfx.c | 1013 |
1 files changed, 1013 insertions, 0 deletions
diff --git a/linux/gfx.c b/linux/gfx.c new file mode 100644 index 0000000..01c7f4a --- /dev/null +++ b/linux/gfx.c @@ -0,0 +1,1013 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Graphics functions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "gfx.h" +#include "mem.h" + +#include <stdio.h> +#include <ctype.h> +#include <limits.h> +#include <stdarg.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + + +/* ---------------------------------------- VARS +*/ +static int init=FALSE; + +static Window win=None; +static Pixmap pix=None; +static Pixmap saved=None; +static GC gc=None; +static Display *disp=NULL; +static XVisualInfo visual; +static XFontStruct *font=NULL; +static int curr_func; + +#define FONTGAP 2 +#define FONTW (font->max_bounds.rbearing - \ + font->min_bounds.lbearing) +#define FONTH (font->max_bounds.descent + \ + font->max_bounds.ascent + FONTGAP) + +static int width=0; +static int height=0; + +static int fw=0; +static int fh=0; + +static int mbuttons=3; /* Assume 3 for X11 */ + +static int dirty_min_x=0; +static int dirty_max_x=0; +static int dirty_min_y=0; +static int dirty_max_y=0; + +static char *font_names[]= + { + "6x9", + NULL + }; + +#define DIRTY(x,y) do { \ + dirty_min_x=MIN(x,dirty_min_x); \ + dirty_min_y=MIN(y,dirty_min_y); \ + dirty_max_x=MAX((x)+1,dirty_max_x); \ + dirty_max_y=MAX((y)+1,dirty_max_y); \ + } while(0) + + +/* Internal representation used for GFX_IMAGE +*/ +typedef struct + { + int w,h; + XImage *p; + } GfxImage; + +/* These are used to define the mappings between X11 scancodes and GFX keys. + Then the scancode can be used to directly index and array. +*/ +static struct + { + int is_special; + int key; + } keycode_map[sizeof(KeyCode)<< CHAR_BIT]; + +typedef struct KBuff + { + GFXKey k; + struct KBuff *next; + } KeyBuff; + +static KeyBuff *kb_head=NULL; +static KeyBuff *kb_tail=NULL; + +static struct + { + KeySym keysym; + int code; + } key_map[]= { + {XK_F1, GFX_F1}, + {XK_F2, GFX_F2}, + {XK_F3, GFX_F3}, + {XK_F4, GFX_F4}, + {XK_F5, GFX_F5}, + {XK_F6, GFX_F6}, + {XK_F7, GFX_F7}, + {XK_F8, GFX_F8}, + {XK_F9, GFX_F9}, + {XK_F10, GFX_F10}, + {XK_F11, GFX_F11}, + {XK_F12, GFX_F12}, + {XK_Escape, GFX_ESC}, + {XK_Insert, GFX_INSERT}, + {XK_Home, GFX_HOME}, + {XK_Page_Up, GFX_PGUP}, + {XK_Delete, GFX_DELETE}, + {XK_End, GFX_END}, + {XK_Page_Down, GFX_PGDN}, + {XK_Up, GFX_UP}, + {XK_Down, GFX_DOWN}, + {XK_Left, GFX_LEFT}, + {XK_Right, GFX_RIGHT}, + {XK_Return, GFX_ENTER}, + {XK_BackSpace, GFX_BACKSPACE}, + {XK_Tab, GFX_TAB}, + + {XK_VoidSymbol, -1}, + }; + +/* Types and vars for event handling +*/ +typedef enum + { + X11_GFXnone=0, + X11_GFXmouse=1, + X11_GFXmouseMove=2, + X11_GFXkey=4, + X11_GFXall=4|2|1 + } EventType; + +typedef enum + { + X11_GFXpress, X11_GFXrelease, X11_GFXmove + } MouseEventType; + +static int mouse_b=0; +static int mouse_x=0; +static int mouse_y=0; +static int is_shift=FALSE; +static int is_ctrl=FALSE; +static int is_alt=FALSE; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static unsigned long getXCol(int col) +{ + XColor pix; + + pix.red=(col&0xff0000)>>8; + pix.green=(col&0xff00); + pix.blue=(col&0xff)<<8; + pix.flags=DoRed|DoBlue|DoGreen; + + XAllocColor(disp,DefaultColormap(disp,DefaultScreen(disp)),&pix); + + return pix.pixel; +} + + +static void setXCol(int col) +{ + static int last_col=-1; + + if (col==last_col) + return; + + last_col=col; + + XSetForeground(disp,gc,getXCol(col)); +} + + +static void KeyBuffAdd(int code, char ascii, int shift, int ctrl, int alt) +{ + KeyBuff *key; + + key=Grab(sizeof *key); + + key->k.code=code; + key->k.ascii=ascii; + key->k.shift=shift; + key->k.ctrl=ctrl; + key->k.alt=alt; + key->next=NULL; + + if (!kb_head) + kb_head=kb_tail=key; + else + { + kb_tail->next=key; + kb_tail=key; + } +} + + +static void GetKey(GFXKey *key) +{ + if (kb_head) + { + KeyBuff *k=kb_head; + + *key=k->k; + + if (!(kb_head=k->next)) + kb_tail=NULL; + + Release(k); + } +} + + +static int HandleKey(XKeyEvent *key) +{ + int code; + char ascii; + + if (keycode_map[key->keycode].is_special) + { + code=keycode_map[key->keycode].key; + ascii=0; + } + else + { + char buff[2]=""; + + code=GFX_ASCII; + + XLookupString(key,buff,2,NULL,NULL); + + if (!isprint(buff[0])) + return FALSE; + + ascii=buff[0]; + } + + KeyBuffAdd(code,ascii, + key->state&ShiftMask, + key->state&ControlMask, + key->state&Mod1Mask); + + return TRUE; +} + + +static void HandleMouse(int x, int y, int b, MouseEventType type, + unsigned int state) +{ + int mask; + + mouse_x=x; + mouse_y=y; + + if (type!=X11_GFXmove) + { + switch(b) + { + case Button1: + mask=GFX_BUTLEFT; + break; + case Button2: + mask=GFX_BUTMIDDLE; + break; + case Button3: + mask=GFX_BUTRIGHT; + break; + case Button4: + mask=GFX_MSWHEELUP; + break; + case Button5: + mask=GFX_MSWHEELDOWN; + break; + default: + mask=0; + break; + } + + if (type==X11_GFXpress) + mouse_b|=mask; + else + mouse_b&=~mask; + } + + is_shift=state&ShiftMask; + is_ctrl=state&ControlMask; + is_alt=state&Mod1Mask; +} + + +static EventType Wait(EventType etype, int wait) +{ + XEvent ev; + + while(wait || XPending(disp)) + { + XNextEvent(disp,&ev); + + switch(ev.type) + { + case KeyPress: + if (HandleKey(&ev.xkey) && (etype & X11_GFXkey)) + return X11_GFXkey; + + break; + + case ButtonPress: + HandleMouse(ev.xbutton.x,ev.xbutton.y,ev.xbutton.button, + X11_GFXpress,ev.xbutton.state); + + if (etype & X11_GFXmouse) + return X11_GFXmouse; + + break; + + case ButtonRelease: + HandleMouse(ev.xbutton.x,ev.xbutton.y,ev.xbutton.button, + X11_GFXrelease,ev.xbutton.state); + + if (etype & X11_GFXmouse) + return X11_GFXmouse; + + break; + + case MotionNotify: + HandleMouse(ev.xbutton.x,ev.xbutton.y,0, + X11_GFXmove,ev.xbutton.state); + + if (etype & X11_GFXmouseMove) + return X11_GFXmouseMove; + + break; + + case Expose: + DIRTY(ev.xexpose.x,ev.xexpose.y); + DIRTY(ev.xexpose.x+ev.xexpose.width, + ev.xexpose.y+ev.xexpose.height); + + if (ev.xexpose.count==0) + GFX_redraw(); + + break; + + default: + break; + } + } + + return X11_GFXnone; +} + + + +/* ---------------------------------------- 'PRIVATE' EXPORTED FUNCTIONS +*/ +void VIDOOM_GET_GFX_VARS(Display **ret_disp, Window *ret_win, Pixmap *ret_pix, + GC *ret_gc) +{ + *ret_disp=disp; + *ret_win=win; + *ret_pix=pix; + *ret_gc=gc; +} + + +void VIDOOM_GFX_FORCE_REDRAW(void) +{ + dirty_min_x=0; + dirty_max_x=width-1; + dirty_min_y=0; + dirty_max_y=width-1; + + GFX_redraw(); +} + + +void VIDOOM_GFX_SAVE_DISPLAY(void) +{ + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + XCopyArea(disp,pix,saved,gc,0,0,width,height,0,0); +} + + +void VIDOOM_GFX_RESTORE_DISPLAY(void) +{ + XCopyArea(disp,saved,pix,gc,0,0,width,height,0,0); + VIDOOM_GFX_FORCE_REDRAW(); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); +} + + +Pixmap VIDOOM_GFX_SAVE_UNDER(int x, int y, int w, int h) +{ + Pixmap p; + + p=XCreatePixmap(disp,win,w,h,visual.depth); + XCopyArea(disp,pix,p,gc,x,y,w,h,0,0); + + return p; +} + + +void VIDOOM_GFX_RESTORE_UNDER(Pixmap p, int x, int y, int w, int h) +{ + DIRTY(x,y); + DIRTY(x+w,y+h); + XCopyArea(disp,p,pix,gc,0,0,w,h,x,y); + XFreePixmap(disp,p); +} + + +/* This is done in a *very* bad fashion.... +*/ +void VIDOOM_GFX_WAIT_FOR(pid_t pid, int *status) +{ + XEvent ev; + + while(TRUE) + { + while (XPending(disp)) + { + XNextEvent(disp,&ev); + + if (ev.type==Expose) + { + DIRTY(ev.xexpose.x,ev.xexpose.y); + DIRTY(ev.xexpose.x+ev.xexpose.width, + ev.xexpose.y+ev.xexpose.height); + + if (ev.xexpose.count==0) + GFX_redraw(); + } + } + + if (waitpid(pid,status,WNOHANG)) + return; + + /* Now, this is nasty... + */ + usleep(10000); + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void GFX_init(void) +{ + if (!init) + { + int f; + + init=TRUE; + + /* Open display and find an appropriate visual + */ + if (!(disp=XOpenDisplay(NULL))) + GFX_exit(EXIT_FAILURE,"Couldn't open X display\n"); + + if (!XMatchVisualInfo(disp,DefaultScreen(disp),32,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),24,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),16,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),15,TrueColor,&visual)) + GFX_exit(EXIT_FAILURE,"Couldn't find a TrueColor visual\n"); + + f=0; + while(font_names[f] && !font) + font=XLoadQueryFont(disp,font_names[f++]); + + if (!font) + { + font=XLoadQueryFont(disp,"fixed"); + + if (!font) + GFX_exit(EXIT_FAILURE,"Couldn't even load font fixed\n"); + } + + fw=FONTW; + fh=FONTH; + + for(f=0;f<(sizeof(KeyCode)<< CHAR_BIT);f++) + keycode_map[f].is_special=FALSE; + + f=0; + + while(key_map[f].keysym!=XK_VoidSymbol) + { + KeyCode code; + + code=XKeysymToKeycode(disp,key_map[f].keysym); + + keycode_map[code].is_special=TRUE; + keycode_map[code].key=key_map[f].code; + + f++; + } + } +} + + +void GFX_close(void) +{ + if (gc!=None) + { + XFreeGC(disp,gc); + gc=None; + } + + if (pix!=None) + { + XFreePixmap(disp,pix); + pix=None; + } + + if (saved!=None) + { + XFreePixmap(disp,saved); + saved=None; + } + + if (win!=None) + { + XDestroyWindow(disp,win); + win=None; + } +} + + +void GFX_open(int w,int h) +{ + XGCValues gc_val; + XSizeHints hint; + + if (!init) + GFX_exit(EXIT_FAILURE,"GFX_Open() called before GFX_init()\n"); + + height=h; + width=w; + + win=XCreateWindow(disp,DefaultRootWindow(disp), + 0,0,width,height,0, + visual.depth, + InputOutput, + visual.visual, + 0,NULL); + + XSelectInput + (disp,win, + KeyPressMask|ButtonPressMask|ButtonReleaseMask| + PointerMotionMask|ExposureMask); + + XStoreName(disp,win,"viDOOM " VIDOOMVER VIDOOMRELEASE); + + hint.width=hint.min_width=hint.max_width=width; + hint.height=hint.min_height=hint.max_height=height; + hint.flags=PSize|PMinSize|PMaxSize; + + XSetWMNormalHints(disp,win,&hint); + + pix=XCreatePixmap(disp,win,width,height,visual.depth); + saved=XCreatePixmap(disp,win,width,height,visual.depth); + + curr_func=gc_val.function=GXcopy; + gc_val.plane_mask=AllPlanes; + gc_val.line_width=0; + gc_val.line_style=LineSolid; + gc_val.graphics_exposures=False; + gc_val.foreground=WhitePixel(disp,DefaultScreen(disp)); + gc_val.background=BlackPixel(disp,DefaultScreen(disp)); + + gc=XCreateGC(disp,pix, + GCFunction|GCPlaneMask|GCLineWidth|GCForeground|GCBackground| + GCLineStyle|GCGraphicsExposures, + &gc_val); + + GFX_clear(BLACK); + GFX_redraw(); + + XMapWindow(disp,win); +} + + +void GFX_clear(int col) +{ + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + setXCol(col); + XFillRectangle(disp,pix,gc,0,0,width,height); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + + dirty_min_x=0; + dirty_max_x=width; + dirty_min_y=0; + dirty_max_y=height; +} + + +void GFX_redraw(void) +{ + if (dirty_max_x<dirty_min_x) + return; + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + dirty_min_x=MAX(0,dirty_min_x); + dirty_min_y=MAX(0,dirty_min_y); + dirty_max_x=MIN(width,dirty_max_x); + dirty_max_y=MIN(height,dirty_max_y); + + XCopyArea(disp,pix,win,gc, + dirty_min_x,dirty_min_y, + dirty_max_x-dirty_min_x+1,dirty_max_y-dirty_min_y+1, + dirty_min_x,dirty_min_y); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + + dirty_max_x=0; + dirty_min_x=width-1; + dirty_max_y=0; + dirty_min_y=width-1; + + XFlush(disp); +} + + +void GFX_line(int x1,int y1,int x2,int y2,int col) +{ + DIRTY(x1,y1); + DIRTY(x2,y2); + + setXCol(col); + XDrawLine(disp,pix,gc,x1,y1,x2,y2); +} + + +void GFX_plot(int x,int y,int col) +{ + DIRTY(x,y); + + setXCol(col); + XDrawPoint(disp,pix,gc,x,y); +} + + +void GFX_circle(int x,int y,int r,int col) +{ + DIRTY(x-r-1,y-r-1); + DIRTY(x+r+1,y+r+1); + + setXCol(col); + XDrawArc(disp,pix,gc,x-r,y-r,r*2,r*2,0,64*360); +} + + +void GFX_fcircle(int x,int y,int r,int col) +{ + DIRTY(x-r-1,y-r-1); + DIRTY(x+r+1,y+r+1); + + setXCol(col); + XFillArc(disp,pix,gc,x-r,y-r,r*2,r*2,0,64*360); +} + + +void GFX_rect(int x,int y,int w,int h,int col) +{ + if (w==0 && h==0) + { + GFX_plot(x,y,col); + return; + } + + w-=SGN(w); + h-=SGN(h); + + if (w<0) + { + x+=w; + w=-w; + } + + if (h<0) + { + y+=h; + h=-h; + } + + DIRTY(x,y); + DIRTY(x+w,y+h); + + setXCol(col); + XDrawRectangle(disp,pix,gc,x,y,w,h); +} + + +void GFX_frect(int x,int y,int w,int h,int col) +{ + if (w==0 && h==0) + { + GFX_plot(x,y,col); + return; + } + + if (w<0) + { + x+=(w+1); + w=-w; + } + + if (h<0) + { + y+=(h+1); + h=-h; + } + + DIRTY(x,y); + DIRTY(x+w,y+h); + + setXCol(col); + XFillRectangle(disp,pix,gc,x,y,w,h); +} + + +void GFX_set_XOR_mode(void) +{ + XSetFunction(disp,gc,curr_func=GXxor); +} + + +void GFX_clear_XOR_mode(void) +{ + XSetFunction(disp,gc,curr_func=GXcopy); +} + + +void GFX_print(int x,int y,int col,char *fmt,...) +{ + char s[1024]; + va_list va; + size_t len; + + va_start(va,fmt); + vsprintf(s,fmt,va); + va_end(va); + + len=strlen(s); + + y+=fh-FONTGAP; + + DIRTY(x,y); + DIRTY(x+fw*strlen(s),y+fh); + + setXCol(col); + XDrawString(disp,pix,gc,x,y,s,len); +} + + +int GFX_fh(void) +{ + return fh; +} + + +int GFX_fw(void) +{ + return fw; +} + + +int GFX_mouse_buttons(void) +{ + return mbuttons; +} + + +int GFX_mouse(int *x,int *y) +{ + Wait(X11_GFXall,FALSE); + + if (x) + *x=mouse_x; + + if (y) + *y=mouse_y; + + return mouse_b; +} + + +void GFX_waitkey(GFXKey *key) +{ + GFXKey ev; + + Wait(X11_GFXkey,TRUE); + GetKey(key ? key:&ev); +} + + +int GFX_key(GFXKey *key) +{ + Wait(X11_GFXall,FALSE); + + if (kb_head) + { + GetKey(key); + return TRUE; + } + else + return FALSE; +} + + +void GFX_bounce(void) +{ + GFXKey d; + + while (kb_head) + GetKey(&d); + + mouse_b=0; +} + + +void GFX_await_input(GFXEvent *ev) +{ + switch(Wait(X11_GFXkey|X11_GFXmouse,TRUE)) + { + case X11_GFXkey: + GetKey(&(ev->key)); + ev->type=GFX_KEY_EVENT; + break; + + case X11_GFXmouse: + ev->type=GFX_MOUSE_EVENT; + ev->mouse.shift=is_shift; + ev->mouse.ctrl=is_ctrl; + ev->mouse.alt=is_alt; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mouse_b; + break; + + default: + break; + } +} + + +void GFX_await_input_full(GFXEvent *ev) +{ + switch(Wait(X11_GFXall,TRUE)) + { + case X11_GFXkey: + GetKey(&(ev->key)); + ev->type=GFX_KEY_EVENT; + break; + + case X11_GFXmouse: + case X11_GFXmouseMove: + ev->type=GFX_MOUSE_EVENT; + ev->mouse.shift=is_shift; + ev->mouse.ctrl=is_ctrl; + ev->mouse.alt=is_alt; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mouse_b; + break; + + default: + break; + } +} + + +void GFX_exit(int code,char *fmt,...) +{ + va_list va; + + va_start(va,fmt); + vfprintf(stderr,fmt,va); + va_end(va); + + /* Be lazy, and leave the might of Unix to clear up, though may as well + let X know. + */ + if (disp) + XCloseDisplay(disp); + + exit(code); +} + + +GFX_IMAGE GFX_create_image(GFX_BITMAP *bm) +{ + GfxImage i; + char *data; + int x,y; + unsigned long pal[256]; + + data=Grab(bm->w*bm->h*4); + + i.p=XCreateImage(disp,visual.visual,visual.depth, + ZPixmap,0,data,bm->w,bm->h,32,4*bm->w); + + if (!i.p) + { + Release(data); + return NULL; + } + + for(x=0;x<256;x++) + pal[x]=getXCol(bm->pal[x]); + + i.w=bm->w; + i.h=bm->h; + + for(x=0;x<bm->w;x++) + for(y=0;y<bm->h;y++) + XPutPixel(i.p,x,y,pal[*(bm->data+x+y*bm->w)]); + + return Copy(&i,sizeof i); +} + + +void GFX_destroy_image(GFX_IMAGE img) +{ + GfxImage *p=img; + + if (p) + { + XDestroyImage(p->p); + Release(p); + } +} + + +void GFX_draw_image(GFX_IMAGE i, int x, int y) +{ + GfxImage *p=i; + + if (p) + { + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + XPutImage(disp,pix,gc,p->p,0,0,x,y,p->w,p->h); + + DIRTY(x,y); + DIRTY(x+p->w,y+p->h); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + } +} + + +void GFX_fill_screen(GFX_IMAGE i) +{ + GfxImage *p=i; + + if (p) + GFX_draw_image(i,(width-p->w)/2,(height-p->h)/2); +} + + +void GFX_save_screen(char *path) +{ +} + + +/* END OF FILE */ |