/* 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 ------------------------------------------------------------------------- _Very_ basic 3D preview */ static const char rcs_id[]="$Id$"; #include "config.h" #include "globals.h" #include "editvar.h" #include "map.h" #include "gfx.h" #include #include /* ---------------------------------------- LOCAL DATA */ #define POLY 0 #define SPHERE 1 typedef struct { int type; Point p[4]; Point c; int r; int z; int col; void *next; } Poly; static int draw_things=FALSE; static int fade=0; static int roll; static int pitch; static int px,py,pz; static Poly *plist=NULL; /* ---------------------------------------- POLY LIST FUNCTIONS */ static void NewPList(void) { Poly *p; while (plist) { p=plist; plist=plist->next; Release(p); } } static void AddPList(Poly *p) { Poly *np; Poly *l; if (p->col<0x101010) return; np=Copy(p,sizeof(Poly)); if (!plist) { plist=np; np->next=NULL; return; } else { if (np->z>=plist->z) { np->next=plist; plist=np; return; } l=plist; while(l) { if (np->zz) { if (!l->next) { l->next=np; np->next=NULL; return; } } else { np->next=l->next; l->next=np; return; } l=l->next; } } /* It shouldn't be possible to reach here!! */ Release(np); } /* ---------------------------------------- LOCAL FUNCTIONS */ static void Transform (int x, int y, int z, int *rx, int *ry, int *rz) { y=-y; *rx=x-px; *ry=y-py; *rz=z-pz; Rotate(0,0,rx,rz,roll); Rotate(0,0,ry,rz,pitch); } static void Project (int x, int y, int z, int to_x, int to_z, Point *p) { double dx,dy,sc; if ((z<1)&&(to_z<1)) { p->x=-1; p->y=-1; } if (z<1) z=1; dx=(double)x; dy=(double)y; sc=(double)z/400.0; p->x=(int)(dx/sc)+SCRW/2; p->y=(int)(dy/sc)+SCRH/2; } static int Fade(int col, int z) { int r,g,b,f; f=z/(16/fade); r=(col&0xff0000)>>16; g=(col&0xff00)>>8; b=col&0xff; r=MAX(r-f,0); g=MAX(g-f,0); b=MAX(b-f,0); return(V_RGB(r,g,b)); } static void DoPoly(EditVert *v1, EditVert *v2, int low, int high) { int x[4],y[4],z[4]; int zt; int f; int ok; Poly p; Transform(v1->v.x,low,v1->v.y,&x[0],&y[0],&z[0]); Transform(v1->v.x,high,v1->v.y,&x[1],&y[1],&z[1]); Transform(v2->v.x,high,v2->v.y,&x[2],&y[2],&z[2]); Transform(v2->v.x,low,v2->v.y,&x[3],&y[3],&z[3]); ok=FALSE; for(f=0;f<4;f++) if (z[f]>0) ok=TRUE; if (ok) { p.type=POLY; zt=0; p.z=999999; for(f=0;f<4;f++) { Project(x[f],y[f],z[f],x[(f+1)%4],z[(f+1)%4],&p.p[f]); zt+=z[f]; p.z=MIN(p.z,z[f]); } if (fade) p.col=Fade(WHITE,p.z); else p.col=WHITE; AddPList(&p); } } static void DoThing(EditThing *t,int tz) { int x,y,z; int r; Poly p; Point rp; int col; Transform(t->t.x,tz,t->t.y,&x,&y,&z); if (z<1) return; p.type=SPHERE; r=ThingRadius(t->t.type,&col); Project(x,y-r,z,x,z,&p.c); Project(x+r,y-r,z,x+r,z,&rp); p.r=rp.x-p.c.x; p.z=z; if (p.r<1) p.r=1; if (fade) p.col=Fade(RED,z); else p.col=col; AddPList(&p); } /* ---------------------------------------- EXPORTED FUNCTIONS */ void EditPreview3D(void) { int done; int redraw; GFXKey k; int rd; px=0; py=0; pz=0; roll=0; pitch=0; done=FALSE; redraw=TRUE; rd=FALSE; while(!done) { if ((redraw)||(rd)) { EditThing *t; EditLine *l; EditSect *s,*sl; int f; int low,high; int sn; Poly *p; rd=FALSE; GFX_clear(BLACK); NewPList(); for(f=0;(fsr->sector))) if ((l->sl)&&(sl=GETSECT(l->sl->sector))) { if (s->s.floor!=sl->s.floor) { low=MIN(s->s.floor,sl->s.floor); high=MAX(s->s.floor,sl->s.floor); DoPoly(l->v[0],l->v[1],low,high); } if (s->s.ceiling!=sl->s.ceiling) { low=MIN(s->s.ceiling,sl->s.ceiling); high=MAX(s->s.ceiling,sl->s.ceiling); DoPoly(l->v[0],l->v[1],low,high); } } else DoPoly(l->v[0],l->v[1],s->s.floor,s->s.ceiling); rd=GFX_key(&k); } if (draw_things) for(f=0;(ft.x,t->t.y); if ((sn!=-1)&&(s=GETSECT(sn))) high=s->s.floor; else high=0; if (hexen_mode) high+=t->t.z; DoThing(t,high); } rd=GFX_key(&k); } p=plist; while((p)&&(!rd)) { switch(p->type) { case POLY: for(f=0;f<4;f++) GFX_line(p->p[f].x,p->p[f].y, p->p[(f+1)%4].x,p->p[(f+1)%4].y,p->col); break; case SPHERE: GFX_fcircle(p->c.x,p->c.y,p->r,p->col); break; } p=p->next; rd=GFX_key(&k); } GFX_frect(0,0,SCRW,FH*2,BLUE); GFX_print(0,0,WHITE,"Pos: %d,%d,%d Roll: %d Pitch : %d %s", px,py,pz,roll,pitch,rd ? "Draw interrupted" : "Draw done"); if (fade) GFX_print(0,FH,WHITE,"Fade: Intensity %d",fade); else GFX_print(0,FH,WHITE,"Fade: off"); GFX_print(SCRW/2,FH,WHITE,"Things: %s",draw_things ? "On":"Off"); GFX_redraw(); } if (!rd) GFX_waitkey(&k); redraw=TRUE; if (k.code==GFX_ASCII) switch(toupper(k.ascii)) { case 'T': draw_things=!draw_things; break; default: redraw=FALSE; break; } else switch(k.code) { case GFX_ESC: done=TRUE; break; case GFX_LEFT: if (k.alt) { pz+=(int)(cos(RAD(roll-90))*(k.shift ? 128 : 64)); px+=(int)(sin(RAD(roll-90))*(k.shift ? 128 : 64)); } else roll=(roll+360-(k.shift ? 15:5))%360; break; case GFX_RIGHT: if (k.alt) { pz+=(int)(cos(RAD(roll+90))*(k.shift ? 128 : 64)); px+=(int)(sin(RAD(roll+90))*(k.shift ? 128 : 64)); } else roll=(roll+(k.shift ? 15:5))%360; break; case GFX_UP: pz+=(int)(cos(RAD(roll))*(k.shift ? 128 : 64)); px+=(int)(sin(RAD(roll))*(k.shift ? 128 : 64)); break; case GFX_DOWN: pz-=(int)(cos(RAD(roll))*(k.shift ? 128 : 64)); px-=(int)(sin(RAD(roll))*(k.shift ? 128 : 64)); break; case GFX_END: pitch=0; break; case GFX_PGDN: if (k.shift) pitch=MAX(pitch-5,-90); else py-=64; break; case GFX_PGUP: if (k.shift) pitch=MIN(pitch+5,90); else py+=64; break; case GFX_ENTER: fade=(fade+1)%3; break; default: redraw=FALSE; break; } } FullRedraw(); } /* END OF FILE */