├── README ├── src ├── common │ ├── l3dslib.h │ ├── trilib.h │ ├── threads.h │ ├── scriplib.h │ ├── mdfour.h │ ├── lbmlib.h │ ├── polylib.h │ ├── mathlib.h │ ├── bspfile.h │ ├── mathlib.c │ ├── cmdlib.h │ ├── trilib.c │ ├── mdfour.c │ ├── scriplib.c │ ├── l3dslib.c │ ├── threads.c │ ├── qfiles.h │ └── polylib.c ├── qbsp3 │ ├── nodraw.c │ ├── leakfile.c │ ├── glfile.c │ ├── tree.c │ ├── textures.c │ ├── prtfile.c │ ├── qbsp.h │ ├── qbsp3.c │ └── writebsp.c ├── bspinfo │ └── bspinfo.c ├── qdata │ ├── qdata.h │ ├── tables.c │ ├── sprites.c │ ├── anorms.h │ └── qdata.c ├── qvis3 │ └── vis.h └── qrad3 │ ├── qrad.h │ ├── trace.c │ └── patches.c └── Makefile /README: -------------------------------------------------------------------------------- 1 | Those are the Quake II map tools, fixed to work on unixoid platform like 2 | FreeBSD and Linux. ATTENTION: This code is totaly untested and may not 3 | work! Do not complain if there are any problems! Patches (or even better 4 | pull requests) and success reports are welcome. :) 5 | -------------------------------------------------------------------------------- /src/common/l3dslib.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // 24 | // l3dslib.h: header file for loading triangles from a 3DS triangle file 25 | // 26 | void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles); 27 | 28 | -------------------------------------------------------------------------------- /src/common/trilib.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // 24 | // trilib.h: header file for loading triangles from an Alias triangle file 25 | // 26 | #define MAXTRIANGLES 2048 27 | 28 | typedef struct { 29 | vec3_t verts[3]; 30 | } triangle_t; 31 | 32 | void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles); 33 | 34 | -------------------------------------------------------------------------------- /src/common/threads.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | extern int numthreads; 24 | 25 | void ThreadSetDefault (void); 26 | int GetThreadWork (void); 27 | void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)); 28 | void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)); 29 | void ThreadLock (void); 30 | void ThreadUnlock (void); 31 | 32 | -------------------------------------------------------------------------------- /src/qbsp3/nodraw.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qbsp.h" 24 | 25 | vec3_t draw_mins, draw_maxs; 26 | qboolean drawflag; 27 | 28 | void Draw_ClearWindow (void) 29 | { 30 | } 31 | 32 | //============================================================ 33 | 34 | #define GLSERV_PORT 25001 35 | 36 | 37 | void GLS_BeginScene (void) 38 | { 39 | } 40 | 41 | void GLS_Winding (winding_t *w, int code) 42 | { 43 | } 44 | 45 | void GLS_EndScene (void) 46 | { 47 | } 48 | -------------------------------------------------------------------------------- /src/common/scriplib.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // scriplib.h 24 | 25 | #ifndef __CMDLIB__ 26 | #include "cmdlib.h" 27 | #endif 28 | 29 | #define MAXTOKEN 1024 30 | 31 | extern char token[MAXTOKEN]; 32 | extern char *scriptbuffer,*script_p,*scriptend_p; 33 | extern int grabbed; 34 | extern int scriptline; 35 | extern qboolean endofscript; 36 | 37 | 38 | void LoadScriptFile (char *filename); 39 | void ParseFromMemory (char *buffer, int size); 40 | 41 | qboolean GetToken (qboolean crossline); 42 | void UnGetToken (void); 43 | qboolean TokenAvailable (void); 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/common/mdfour.h: -------------------------------------------------------------------------------- 1 | /* 2 | mdfour.h 3 | 4 | an implementation of MD4 designed for use in the SMB authentication 5 | protocol 6 | 7 | Copyright (C) Andrew Tridgell 1997-1998 8 | 9 | This program is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU General Public License 11 | as published by the Free Software Foundation; either version 2 12 | of the License, or (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17 | 18 | See the GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program; if not, write to: 22 | 23 | Free Software Foundation, Inc. 24 | 59 Temple Place - Suite 330 25 | Boston, MA 02111-1307, USA 26 | */ 27 | 28 | #ifndef _MDFOUR_H 29 | #define _MDFOUR_H 30 | 31 | #ifndef int32 32 | #define int32 int 33 | #endif 34 | 35 | #if SIZEOF_INT > 4 36 | #define LARGE_INT32 37 | #endif 38 | 39 | #ifndef uint32 40 | #define uint32 unsigned int32 41 | #endif 42 | 43 | struct mdfour { 44 | uint32 A, B, C, D; 45 | uint32 totalN; 46 | }; 47 | 48 | void mdfour_begin(struct mdfour *md); // old: MD4Init 49 | void mdfour_update(struct mdfour *md, unsigned char *in, int n); //old: MD4Update 50 | void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final 51 | void mdfour(unsigned char *out, unsigned char *in, int n); 52 | 53 | #endif // _MDFOUR_H 54 | 55 | -------------------------------------------------------------------------------- /src/common/lbmlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // piclib.h 24 | 25 | 26 | void LoadLBM (char *filename, byte **picture, byte **palette); 27 | void WriteLBMfile (char *filename, byte *data, int width, int height 28 | , byte *palette); 29 | void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height); 30 | void WritePCXfile (char *filename, byte *data, int width, int height 31 | , byte *palette); 32 | 33 | // loads / saves either lbm or pcx, depending on extension 34 | void Load256Image (char *name, byte **pixels, byte **palette, 35 | int *width, int *height); 36 | void Save256Image (char *name, byte *pixels, byte *palette, 37 | int width, int height); 38 | 39 | 40 | void LoadTGA (char *filename, byte **pixels, int *width, int *height); 41 | -------------------------------------------------------------------------------- /src/bspinfo/bspinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "cmdlib.h" 24 | #include "mathlib.h" 25 | #include "bspfile.h" 26 | 27 | void main (int argc, char **argv) 28 | { 29 | int i; 30 | char source[1024]; 31 | int size; 32 | FILE *f; 33 | 34 | if (argc == 1) 35 | Error ("usage: bspinfo bspfile [bspfiles]"); 36 | 37 | for (i=1 ; i 29 | 30 | #ifdef DOUBLEVEC_T 31 | typedef double vec_t; 32 | #else 33 | typedef float vec_t; 34 | #endif 35 | typedef vec_t vec3_t[3]; 36 | 37 | #define SIDE_FRONT 0 38 | #define SIDE_ON 2 39 | #define SIDE_BACK 1 40 | #define SIDE_CROSS -2 41 | 42 | #define Q_PI 3.14159265358979323846 43 | 44 | extern vec3_t vec3_origin; 45 | 46 | #define EQUAL_EPSILON 0.001 47 | 48 | qboolean VectorCompare (vec3_t v1, vec3_t v2); 49 | 50 | #define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) 51 | #define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} 52 | #define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} 53 | #define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} 54 | #define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} 55 | #define VectorClear(x) {x[0] = x[1] = x[2] = 0;} 56 | #define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];} 57 | 58 | vec_t Q_rint (vec_t in); 59 | vec_t _DotProduct (vec3_t v1, vec3_t v2); 60 | void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); 61 | void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); 62 | void _VectorCopy (vec3_t in, vec3_t out); 63 | void _VectorScale (vec3_t v, vec_t scale, vec3_t out); 64 | 65 | double VectorLength(vec3_t v); 66 | 67 | void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc); 68 | 69 | void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); 70 | vec_t VectorNormalize (vec3_t in, vec3_t out); 71 | vec_t ColorNormalize (vec3_t in, vec3_t out); 72 | void VectorInverse (vec3_t v); 73 | 74 | void ClearBounds (vec3_t mins, vec3_t maxs); 75 | void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/qdata/qdata.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // qdata.h 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "cmdlib.h" 33 | #include "scriplib.h" 34 | #include "mathlib.h" 35 | #include "trilib.h" 36 | #include "lbmlib.h" 37 | #include "threads.h" 38 | #include "l3dslib.h" 39 | #include "bspfile.h" 40 | 41 | void Cmd_Modelname (void); 42 | void Cmd_Base (void); 43 | void Cmd_Cd (void); 44 | void Cmd_Origin (void); 45 | void Cmd_ScaleUp (void); 46 | void Cmd_Frame (void); 47 | void Cmd_Modelname (void); 48 | void Cmd_Skin (void); 49 | void Cmd_Skinsize (void); 50 | void FinishModel (void); 51 | 52 | void Cmd_Inverse16Table( void ); 53 | 54 | void Cmd_SpriteName (void); 55 | void Cmd_Load (void); 56 | void Cmd_SpriteFrame (void); 57 | void FinishSprite (void); 58 | 59 | void Cmd_Grab (void); 60 | void Cmd_Raw (void); 61 | void Cmd_Mip (void); 62 | void Cmd_Environment (void); 63 | void Cmd_Colormap (void); 64 | 65 | void Cmd_File (void); 66 | void Cmd_Dir (void); 67 | void Cmd_StartWad (void); 68 | void Cmd_EndWad (void); 69 | void Cmd_Mippal (void); 70 | void Cmd_Mipdir (void); 71 | void Cmd_Alphalight (void); 72 | 73 | void Cmd_Video (void); 74 | 75 | void RemapZero (byte *pixels, byte *palette, int width, int height); 76 | 77 | void ReleaseFile (char *filename); 78 | 79 | extern byte *byteimage, *lbmpalette; 80 | extern int byteimagewidth, byteimageheight; 81 | 82 | extern qboolean g_release; // don't grab, copy output data to new tree 83 | extern char g_releasedir[1024]; // c:\quake2\baseq2, etc 84 | extern qboolean g_archive; // don't grab, copy source data to new tree 85 | extern qboolean do3ds; 86 | extern char g_only[256]; // if set, only grab this cd 87 | extern qboolean g_skipmodel; // set true when a cd is not g_only 88 | 89 | extern char *trifileext; 90 | -------------------------------------------------------------------------------- /src/qbsp3/leakfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qbsp.h" 24 | 25 | /* 26 | ============================================================================== 27 | 28 | LEAF FILE GENERATION 29 | 30 | Save out name.line for qe3 to read 31 | ============================================================================== 32 | */ 33 | 34 | 35 | /* 36 | ============= 37 | LeakFile 38 | 39 | Finds the shortest possible chain of portals 40 | that leads from the outside leaf to a specifically 41 | occupied leaf 42 | ============= 43 | */ 44 | void LeakFile (tree_t *tree) 45 | { 46 | vec3_t mid; 47 | FILE *linefile; 48 | char filename[1024]; 49 | node_t *node; 50 | int count; 51 | 52 | if (!tree->outside_node.occupied) 53 | return; 54 | 55 | qprintf ("--- LeakFile ---\n"); 56 | 57 | // 58 | // write the points to the file 59 | // 60 | sprintf (filename, "%s.lin", source); 61 | linefile = fopen (filename, "w"); 62 | if (!linefile) 63 | Error ("Couldn't open %s\n", filename); 64 | 65 | count = 0; 66 | node = &tree->outside_node; 67 | while (node->occupied > 1) 68 | { 69 | int next; 70 | portal_t *p, *nextportal; 71 | node_t *nextnode; 72 | int s; 73 | 74 | // find the best portal exit 75 | next = node->occupied; 76 | for (p=node->portals ; p ; p = p->next[!s]) 77 | { 78 | s = (p->nodes[0] == node); 79 | if (p->nodes[s]->occupied 80 | && p->nodes[s]->occupied < next) 81 | { 82 | nextportal = p; 83 | nextnode = p->nodes[s]; 84 | next = nextnode->occupied; 85 | } 86 | } 87 | node = nextnode; 88 | WindingCenter (nextportal->winding, mid); 89 | fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); 90 | count++; 91 | } 92 | // add the occupant center 93 | GetVectorForKey (node->occupant, "origin", mid); 94 | 95 | fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); 96 | qprintf ("%5i point linefile\n", count+1); 97 | 98 | fclose (linefile); 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/qbsp3/glfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qbsp.h" 24 | 25 | int c_glfaces; 26 | 27 | int PortalVisibleSides (portal_t *p) 28 | { 29 | int fcon, bcon; 30 | 31 | if (!p->onnode) 32 | return 0; // outside 33 | 34 | fcon = p->nodes[0]->contents; 35 | bcon = p->nodes[1]->contents; 36 | 37 | // same contents never create a face 38 | if (fcon == bcon) 39 | return 0; 40 | 41 | // FIXME: is this correct now? 42 | if (!fcon) 43 | return 1; 44 | if (!bcon) 45 | return 2; 46 | return 0; 47 | } 48 | 49 | void OutputWinding (winding_t *w, FILE *glview) 50 | { 51 | static int level = 128; 52 | vec_t light; 53 | int i; 54 | 55 | fprintf (glview, "%i\n", w->numpoints); 56 | level+=28; 57 | light = (level&255)/255.0; 58 | for (i=0 ; inumpoints ; i++) 59 | { 60 | fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n", 61 | w->p[i][0], 62 | w->p[i][1], 63 | w->p[i][2], 64 | light, 65 | light, 66 | light); 67 | } 68 | fprintf (glview, "\n"); 69 | } 70 | 71 | /* 72 | ============= 73 | OutputPortal 74 | ============= 75 | */ 76 | void OutputPortal (portal_t *p, FILE *glview) 77 | { 78 | winding_t *w; 79 | int sides; 80 | 81 | sides = PortalVisibleSides (p); 82 | if (!sides) 83 | return; 84 | 85 | c_glfaces++; 86 | 87 | w = p->winding; 88 | 89 | if (sides == 2) // back side 90 | w = ReverseWinding (w); 91 | 92 | OutputWinding (w, glview); 93 | 94 | if (sides == 2) 95 | FreeWinding(w); 96 | } 97 | 98 | /* 99 | ============= 100 | WriteGLView_r 101 | ============= 102 | */ 103 | void WriteGLView_r (node_t *node, FILE *glview) 104 | { 105 | portal_t *p, *nextp; 106 | 107 | if (node->planenum != PLANENUM_LEAF) 108 | { 109 | WriteGLView_r (node->children[0], glview); 110 | WriteGLView_r (node->children[1], glview); 111 | return; 112 | } 113 | 114 | // write all the portals 115 | for (p=node->portals ; p ; p=nextp) 116 | { 117 | if (p->nodes[0] == node) 118 | { 119 | OutputPortal (p, glview); 120 | nextp = p->next[0]; 121 | } 122 | else 123 | nextp = p->next[1]; 124 | } 125 | } 126 | 127 | /* 128 | ============= 129 | WriteGLView 130 | ============= 131 | */ 132 | void WriteGLView (tree_t *tree, char *source) 133 | { 134 | char name[1024]; 135 | FILE *glview; 136 | 137 | c_glfaces = 0; 138 | sprintf (name, "%s%s.gl",outbase, source); 139 | printf ("Writing %s\n", name); 140 | 141 | glview = fopen (name, "w"); 142 | if (!glview) 143 | Error ("Couldn't open %s", name); 144 | WriteGLView_r (tree->headnode, glview); 145 | fclose (glview); 146 | 147 | printf ("%5i c_glfaces\n", c_glfaces); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /src/common/bspfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qfiles.h" 24 | 25 | 26 | extern int nummodels; 27 | extern dmodel_t dmodels[MAX_MAP_MODELS]; 28 | 29 | extern int visdatasize; 30 | extern byte dvisdata[MAX_MAP_VISIBILITY]; 31 | extern dvis_t *dvis; 32 | 33 | extern int lightdatasize; 34 | extern byte dlightdata[MAX_MAP_LIGHTING]; 35 | 36 | extern int entdatasize; 37 | extern char dentdata[MAX_MAP_ENTSTRING]; 38 | 39 | extern int numleafs; 40 | extern dleaf_t dleafs[MAX_MAP_LEAFS]; 41 | 42 | extern int numplanes; 43 | extern dplane_t dplanes[MAX_MAP_PLANES]; 44 | 45 | extern int numvertexes; 46 | extern dvertex_t dvertexes[MAX_MAP_VERTS]; 47 | 48 | extern int numnodes; 49 | extern dnode_t dnodes[MAX_MAP_NODES]; 50 | 51 | extern int numtexinfo; 52 | extern texinfo_t texinfo[MAX_MAP_TEXINFO]; 53 | 54 | extern int numfaces; 55 | extern dface_t dfaces[MAX_MAP_FACES]; 56 | 57 | extern int numedges; 58 | extern dedge_t dedges[MAX_MAP_EDGES]; 59 | 60 | extern int numleaffaces; 61 | extern unsigned short dleaffaces[MAX_MAP_LEAFFACES]; 62 | 63 | extern int numleafbrushes; 64 | extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; 65 | 66 | extern int numsurfedges; 67 | extern int dsurfedges[MAX_MAP_SURFEDGES]; 68 | 69 | extern int numareas; 70 | extern darea_t dareas[MAX_MAP_AREAS]; 71 | 72 | extern int numareaportals; 73 | extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; 74 | 75 | extern int numbrushes; 76 | extern dbrush_t dbrushes[MAX_MAP_BRUSHES]; 77 | 78 | extern int numbrushsides; 79 | extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; 80 | 81 | extern byte dpop[256]; 82 | 83 | void DecompressVis (byte *in, byte *decompressed); 84 | int CompressVis (byte *vis, byte *dest); 85 | 86 | void LoadBSPFile (char *filename); 87 | void LoadBSPFileTexinfo (char *filename); // just for qdata 88 | void WriteBSPFile (char *filename); 89 | void PrintBSPFileSizes (void); 90 | 91 | //=============== 92 | 93 | 94 | typedef struct epair_s 95 | { 96 | struct epair_s *next; 97 | char *key; 98 | char *value; 99 | } epair_t; 100 | 101 | typedef struct 102 | { 103 | vec3_t origin; 104 | int firstbrush; 105 | int numbrushes; 106 | epair_t *epairs; 107 | 108 | // only valid for func_areaportals 109 | int areaportalnum; 110 | int portalareas[2]; 111 | } entity_t; 112 | 113 | extern int num_entities; 114 | extern entity_t entities[MAX_MAP_ENTITIES]; 115 | 116 | void ParseEntities (void); 117 | void UnparseEntities (void); 118 | 119 | void SetKeyValue (entity_t *ent, char *key, char *value); 120 | char *ValueForKey (entity_t *ent, char *key); 121 | // will return "" if not present 122 | 123 | vec_t FloatForKey (entity_t *ent, char *key); 124 | void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); 125 | 126 | epair_t *ParseEpair (void); 127 | 128 | void PrintEntity (entity_t *ent); 129 | 130 | -------------------------------------------------------------------------------- /src/qvis3/vis.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "cmdlib.h" 24 | #include "mathlib.h" 25 | #include "bspfile.h" 26 | 27 | #define MAX_PORTALS 32768 28 | 29 | #define PORTALFILE "PRT1" 30 | 31 | #define ON_EPSILON 0.1 32 | 33 | typedef struct 34 | { 35 | vec3_t normal; 36 | float dist; 37 | } plane_t; 38 | 39 | #define MAX_POINTS_ON_WINDING 64 40 | #define MAX_POINTS_ON_FIXED_WINDING 12 41 | 42 | typedef struct 43 | { 44 | qboolean original; // don't free, it's part of the portal 45 | int numpoints; 46 | vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized 47 | } winding_t; 48 | 49 | winding_t *NewWinding (int points); 50 | void FreeWinding (winding_t *w); 51 | winding_t *CopyWinding (winding_t *w); 52 | 53 | 54 | typedef enum {stat_none, stat_working, stat_done} vstatus_t; 55 | typedef struct 56 | { 57 | plane_t plane; // normal pointing into neighbor 58 | int leaf; // neighbor 59 | 60 | vec3_t origin; // for fast clip testing 61 | float radius; 62 | 63 | winding_t *winding; 64 | vstatus_t status; 65 | byte *portalfront; // [portals], preliminary 66 | byte *portalflood; // [portals], intermediate 67 | byte *portalvis; // [portals], final 68 | 69 | int nummightsee; // bit count on portalflood for sort 70 | } portal_t; 71 | 72 | typedef struct seperating_plane_s 73 | { 74 | struct seperating_plane_s *next; 75 | plane_t plane; // from portal is on positive side 76 | } sep_t; 77 | 78 | 79 | typedef struct passage_s 80 | { 81 | struct passage_s *next; 82 | int from, to; // leaf numbers 83 | sep_t *planes; 84 | } passage_t; 85 | 86 | #define MAX_PORTALS_ON_LEAF 128 87 | typedef struct leaf_s 88 | { 89 | int numportals; 90 | passage_t *passages; 91 | portal_t *portals[MAX_PORTALS_ON_LEAF]; 92 | } leaf_t; 93 | 94 | 95 | typedef struct pstack_s 96 | { 97 | byte mightsee[MAX_PORTALS/8]; // bit string 98 | struct pstack_s *next; 99 | leaf_t *leaf; 100 | portal_t *portal; // portal exiting 101 | winding_t *source; 102 | winding_t *pass; 103 | 104 | winding_t windings[3]; // source, pass, temp in any order 105 | int freewindings[3]; 106 | 107 | plane_t portalplane; 108 | } pstack_t; 109 | 110 | typedef struct 111 | { 112 | portal_t *base; 113 | int c_chains; 114 | pstack_t pstack_head; 115 | } threaddata_t; 116 | 117 | 118 | 119 | extern int numportals; 120 | extern int portalclusters; 121 | 122 | extern portal_t *portals; 123 | extern leaf_t *leafs; 124 | 125 | extern int c_portaltest, c_portalpass, c_portalcheck; 126 | extern int c_portalskip, c_leafskip; 127 | extern int c_vistest, c_mighttest; 128 | extern int c_chains; 129 | 130 | extern byte *vismap, *vismap_p, *vismap_end; // past visfile 131 | 132 | extern int testlevel; 133 | 134 | extern byte *uncompressed; 135 | 136 | extern int leafbytes, leaflongs; 137 | extern int portalbytes, portallongs; 138 | 139 | 140 | void LeafFlow (int leafnum); 141 | 142 | 143 | void BasePortalVis (int portalnum); 144 | void BetterPortalVis (int portalnum); 145 | void PortalFlow (int portalnum); 146 | 147 | extern portal_t *sorted_portals[MAX_MAP_PORTALS*2]; 148 | 149 | int CountBits (byte *bits, int numbits); 150 | -------------------------------------------------------------------------------- /src/common/mathlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // mathlib.c -- math primitives 24 | 25 | #include "cmdlib.h" 26 | #include "mathlib.h" 27 | 28 | vec3_t vec3_origin = {0,0,0}; 29 | 30 | 31 | double VectorLength(vec3_t v) 32 | { 33 | int i; 34 | double length; 35 | 36 | length = 0; 37 | for (i=0 ; i< 3 ; i++) 38 | length += v[i]*v[i]; 39 | length = sqrt (length); // FIXME 40 | 41 | return length; 42 | } 43 | 44 | qboolean VectorCompare (vec3_t v1, vec3_t v2) 45 | { 46 | int i; 47 | 48 | for (i=0 ; i<3 ; i++) 49 | if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) 50 | return false; 51 | 52 | return true; 53 | } 54 | 55 | vec_t Q_rint (vec_t in) 56 | { 57 | return floor (in + 0.5); 58 | } 59 | 60 | void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc) 61 | { 62 | vc[0] = va[0] + scale*vb[0]; 63 | vc[1] = va[1] + scale*vb[1]; 64 | vc[2] = va[2] + scale*vb[2]; 65 | } 66 | 67 | void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) 68 | { 69 | cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; 70 | cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; 71 | cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; 72 | } 73 | 74 | vec_t _DotProduct (vec3_t v1, vec3_t v2) 75 | { 76 | return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; 77 | } 78 | 79 | void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) 80 | { 81 | out[0] = va[0]-vb[0]; 82 | out[1] = va[1]-vb[1]; 83 | out[2] = va[2]-vb[2]; 84 | } 85 | 86 | void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) 87 | { 88 | out[0] = va[0]+vb[0]; 89 | out[1] = va[1]+vb[1]; 90 | out[2] = va[2]+vb[2]; 91 | } 92 | 93 | void _VectorCopy (vec3_t in, vec3_t out) 94 | { 95 | out[0] = in[0]; 96 | out[1] = in[1]; 97 | out[2] = in[2]; 98 | } 99 | 100 | void _VectorScale (vec3_t v, vec_t scale, vec3_t out) 101 | { 102 | out[0] = v[0] * scale; 103 | out[1] = v[1] * scale; 104 | out[2] = v[2] * scale; 105 | } 106 | 107 | vec_t VectorNormalize (vec3_t in, vec3_t out) 108 | { 109 | vec_t length, ilength; 110 | 111 | length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); 112 | if (length == 0) 113 | { 114 | VectorClear (out); 115 | return 0; 116 | } 117 | 118 | ilength = 1.0/length; 119 | out[0] = in[0]*ilength; 120 | out[1] = in[1]*ilength; 121 | out[2] = in[2]*ilength; 122 | 123 | return length; 124 | } 125 | 126 | vec_t ColorNormalize (vec3_t in, vec3_t out) 127 | { 128 | float max, scale; 129 | 130 | max = in[0]; 131 | if (in[1] > max) 132 | max = in[1]; 133 | if (in[2] > max) 134 | max = in[2]; 135 | 136 | if (max == 0) 137 | return 0; 138 | 139 | scale = 1.0 / max; 140 | 141 | VectorScale (in, scale, out); 142 | 143 | return max; 144 | } 145 | 146 | 147 | 148 | void VectorInverse (vec3_t v) 149 | { 150 | v[0] = -v[0]; 151 | v[1] = -v[1]; 152 | v[2] = -v[2]; 153 | } 154 | 155 | void ClearBounds (vec3_t mins, vec3_t maxs) 156 | { 157 | mins[0] = mins[1] = mins[2] = 99999; 158 | maxs[0] = maxs[1] = maxs[2] = -99999; 159 | } 160 | 161 | void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) 162 | { 163 | int i; 164 | vec_t val; 165 | 166 | for (i=0 ; i<3 ; i++) 167 | { 168 | val = v[i]; 169 | if (val < mins[i]) 170 | mins[i] = val; 171 | if (val > maxs[i]) 172 | maxs[i] = val; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/common/cmdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // cmdlib.h 24 | 25 | #ifndef __CMDLIB__ 26 | #define __CMDLIB__ 27 | 28 | #ifdef _WIN32 29 | #pragma warning(disable : 4244) // MIPS 30 | #pragma warning(disable : 4136) // X86 31 | #pragma warning(disable : 4051) // ALPHA 32 | 33 | #pragma warning(disable : 4018) // signed/unsigned mismatch 34 | #pragma warning(disable : 4305) // truncate from double to float 35 | #endif 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #ifndef __BYTEBOOL__ 46 | #define __BYTEBOOL__ 47 | typedef enum {false, true} qboolean; 48 | typedef unsigned char byte; 49 | #endif 50 | 51 | // the dec offsetof macro doesnt work very well... 52 | #define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) 53 | 54 | 55 | // set these before calling CheckParm 56 | extern int myargc; 57 | extern char **myargv; 58 | 59 | char *strupr (char *in); 60 | char *strlower (char *in); 61 | int Q_strncasecmp (char *s1, char *s2, int n); 62 | int Q_strcasecmp (char *s1, char *s2); 63 | void Q_getwd (char *out); 64 | 65 | int Q_filelength (FILE *f); 66 | int FileTime (char *path); 67 | 68 | void Q_mkdir (char *path); 69 | 70 | extern char qdir[1024]; 71 | extern char gamedir[1024]; 72 | void SetQdirFromPath (char *path); 73 | char *ExpandArg (char *path); // from cmd line 74 | char *ExpandPath (char *path); // from scripts 75 | char *ExpandPathAndArchive (char *path); 76 | 77 | 78 | double I_FloatTime (void); 79 | 80 | void Error (char *error, ...); 81 | int CheckParm (char *check); 82 | 83 | FILE *SafeOpenWrite (char *filename); 84 | FILE *SafeOpenRead (char *filename); 85 | void SafeRead (FILE *f, void *buffer, int count); 86 | void SafeWrite (FILE *f, void *buffer, int count); 87 | 88 | int LoadFile (char *filename, void **bufferptr); 89 | int TryLoadFile (char *filename, void **bufferptr); 90 | void SaveFile (char *filename, void *buffer, int count); 91 | qboolean FileExists (char *filename); 92 | 93 | void DefaultExtension (char *path, char *extension); 94 | void DefaultPath (char *path, char *basepath); 95 | void StripFilename (char *path); 96 | void StripExtension (char *path); 97 | 98 | void ExtractFilePath (char *path, char *dest); 99 | void ExtractFileBase (char *path, char *dest); 100 | void ExtractFileExtension (char *path, char *dest); 101 | 102 | int ParseNum (char *str); 103 | 104 | short BigShort (short l); 105 | short LittleShort (short l); 106 | int BigLong (int l); 107 | int LittleLong (int l); 108 | float BigFloat (float l); 109 | float LittleFloat (float l); 110 | 111 | 112 | char *COM_Parse (char *data); 113 | 114 | extern char com_token[1024]; 115 | extern qboolean com_eof; 116 | 117 | char *copystring(char *s); 118 | 119 | 120 | void CRC_Init(unsigned short *crcvalue); 121 | void CRC_ProcessByte(unsigned short *crcvalue, byte data); 122 | unsigned short CRC_Value(unsigned short crcvalue); 123 | 124 | void CreatePath (char *path); 125 | void QCopyFile (char *from, char *to); 126 | 127 | extern qboolean archive; 128 | extern char archivedir[1024]; 129 | 130 | 131 | extern qboolean verbose; 132 | void qprintf (char *format, ...); 133 | 134 | void ExpandWildcards (int *argc, char ***argv); 135 | 136 | 137 | // for compression routines 138 | typedef struct 139 | { 140 | byte *data; 141 | int count; 142 | } cblock_t; 143 | 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /src/qrad3/qrad.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "cmdlib.h" 24 | #include "mathlib.h" 25 | #include "bspfile.h" 26 | #include "polylib.h" 27 | #include "threads.h" 28 | #include "lbmlib.h" 29 | 30 | #ifdef WIN32 31 | #include 32 | #endif 33 | 34 | typedef enum 35 | { 36 | emit_surface, 37 | emit_point, 38 | emit_spotlight 39 | } emittype_t; 40 | 41 | 42 | 43 | typedef struct directlight_s 44 | { 45 | struct directlight_s *next; 46 | emittype_t type; 47 | 48 | float intensity; 49 | int style; 50 | vec3_t origin; 51 | vec3_t color; 52 | vec3_t normal; // for surfaces and spotlights 53 | float stopdot; // for spotlights 54 | } directlight_t; 55 | 56 | 57 | // the sum of all tranfer->transfer values for a given patch 58 | // should equal exactly 0x10000, showing that all radiance 59 | // reaches other patches 60 | typedef struct 61 | { 62 | unsigned short patch; 63 | unsigned short transfer; 64 | } transfer_t; 65 | 66 | 67 | #define MAX_PATCHES 65000 // larger will cause 32 bit overflows 68 | 69 | typedef struct patch_s 70 | { 71 | winding_t *winding; 72 | struct patch_s *next; // next in face 73 | int numtransfers; 74 | transfer_t *transfers; 75 | 76 | int cluster; // for pvs checking 77 | vec3_t origin; 78 | dplane_t *plane; 79 | 80 | qboolean sky; 81 | 82 | vec3_t totallight; // accumulated by radiosity 83 | // does NOT include light 84 | // accounted for by direct lighting 85 | float area; 86 | 87 | // illuminance * reflectivity = radiosity 88 | vec3_t reflectivity; 89 | vec3_t baselight; // emissivity only 90 | 91 | // each style 0 lightmap sample in the patch will be 92 | // added up to get the average illuminance of the entire patch 93 | vec3_t samplelight; 94 | int samples; // for averaging direct light 95 | } patch_t; 96 | 97 | extern patch_t *face_patches[MAX_MAP_FACES]; 98 | extern entity_t *face_entity[MAX_MAP_FACES]; 99 | extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels 100 | extern patch_t patches[MAX_PATCHES]; 101 | extern unsigned num_patches; 102 | 103 | extern int leafparents[MAX_MAP_LEAFS]; 104 | extern int nodeparents[MAX_MAP_NODES]; 105 | 106 | extern float lightscale; 107 | 108 | 109 | void MakeShadowSplits (void); 110 | 111 | //============================================== 112 | 113 | 114 | void BuildVisMatrix (void); 115 | qboolean CheckVisBit (unsigned p1, unsigned p2); 116 | 117 | //============================================== 118 | 119 | extern float ambient, maxlight; 120 | 121 | void LinkPlaneFaces (void); 122 | 123 | extern qboolean extrasamples; 124 | extern int numbounce; 125 | 126 | extern directlight_t *directlights[MAX_MAP_LEAFS]; 127 | 128 | extern byte nodehit[MAX_MAP_NODES]; 129 | 130 | void BuildLightmaps (void); 131 | 132 | void BuildFacelights (int facenum); 133 | 134 | void FinalLightFace (int facenum); 135 | 136 | qboolean PvsForOrigin (vec3_t org, byte *pvs); 137 | 138 | int TestLine_r (int node, vec3_t start, vec3_t stop); 139 | 140 | void CreateDirectLights (void); 141 | 142 | dleaf_t *PointInLeaf (vec3_t point); 143 | 144 | 145 | extern dplane_t backplanes[MAX_MAP_PLANES]; 146 | extern int fakeplanes; // created planes for origin offset 147 | 148 | extern float subdiv; 149 | 150 | extern float direct_scale; 151 | extern float entity_scale; 152 | 153 | int PointInLeafnum (vec3_t point); 154 | void MakeTnodes (dmodel_t *bm); 155 | void MakePatches (void); 156 | void SubdividePatches (void); 157 | void PairEdges (void); 158 | void CalcTextureReflectivity (void); 159 | -------------------------------------------------------------------------------- /src/qdata/tables.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qdata.h" 24 | 25 | /* 26 | ============================================================================= 27 | 28 | ALPHALIGHT GENERATION 29 | 30 | Find alphamap values that best match modulated lightmap values 31 | 32 | This isn't used anymore, but I'm keeping it around... 33 | ============================================================================= 34 | */ 35 | 36 | unsigned short alphamap[32*32*32]; 37 | unsigned char inverse16to8table[65536]; 38 | 39 | /* 40 | static int FindNearestColor( unsigned int color ) 41 | { 42 | int i; 43 | int closest_so_far = 0; 44 | float closest_distance_so_far = 100000000; 45 | float d; 46 | float r[2], g[2], b[2]; 47 | 48 | // incoming color is assumed to be in 0xRRGGBB format 49 | r[0] = ( color & 31 ) << 3; 50 | g[0] = ( ( color >> 5 ) & 63 ) << 2; 51 | b[0] = ( ( color >> 11 ) & 31 ) << 3; 52 | 53 | for ( i = 0; i < 256; i++ ) 54 | { 55 | r[1] = ( d_8to24table[i] >> 0 ) & 0xFF; 56 | g[1] = ( d_8to24table[i] >> 8 ) & 0xFF; 57 | b[1] = ( d_8to24table[i] >> 16 ) & 0xFF; 58 | 59 | d = ( r[1] - r[0] ) * ( r[1] - r[0] ) + 60 | ( g[1] - g[0] ) * ( g[1] - g[0] ) + 61 | ( b[1] - b[0] ) * ( b[1] - b[0] ); 62 | 63 | if ( d < closest_distance_so_far ) 64 | { 65 | closest_distance_so_far = d; 66 | closest_so_far = i; 67 | } 68 | } 69 | 70 | return closest_so_far; 71 | } 72 | */ 73 | 74 | extern byte BestColor( int, int, int, int, int ); 75 | 76 | void Inverse16_BuildTable( void ) 77 | { 78 | int i; 79 | 80 | /* 81 | ** create the 16-to-8 table 82 | */ 83 | for ( i = 0; i < 65536; i++ ) 84 | { 85 | int r = i & 31; 86 | int g = ( i >> 5 ) & 63; 87 | int b = ( i >> 11 ) & 31; 88 | 89 | r <<= 3; 90 | g <<= 2; 91 | b <<= 3; 92 | 93 | inverse16to8table[i] = BestColor( r, g, b, 0, 255 ); 94 | } 95 | } 96 | 97 | void Alphalight_Thread (int i) 98 | { 99 | int j; 100 | float r, g, b; 101 | float mr, mg, mb, ma; 102 | float distortion, bestdistortion; 103 | float v; 104 | 105 | r = (i>>10) * (1.0/16); 106 | g = ((i>>5)&31) * (1.0/16); 107 | b = (i&31) * (1.0/16); 108 | 109 | bestdistortion = 999999; 110 | for (j=0 ; j<16*16*16*16 ; j++) 111 | { 112 | mr = (j>>12) * (1.0/16); 113 | mg = ((j>>8)&15) * (1.0/16); 114 | mb = ((j>>4)&15) * (1.0/16); 115 | ma = (j&15) * (1.0/16); 116 | 117 | v = r * 0.5 - (mr*ma + 0.5*(1.0-ma)); 118 | distortion = v*v; 119 | v = g * 0.5 - (mg*ma + 0.5*(1.0-ma)); 120 | distortion += v*v; 121 | v = b * 0.5 - (mb*ma + 0.5*(1.0-ma)); 122 | distortion += v*v; 123 | 124 | distortion *= 1.0 + ma*4; 125 | 126 | if (distortion < bestdistortion) 127 | { 128 | bestdistortion = distortion; 129 | alphamap[i] = j; 130 | } 131 | } 132 | } 133 | 134 | void Cmd_Alphalight (void) 135 | { 136 | char savename[1024]; 137 | 138 | GetToken (false); 139 | 140 | if (g_release) 141 | { 142 | ReleaseFile (token); 143 | return; 144 | } 145 | 146 | sprintf (savename, "%s%s", gamedir, token); 147 | printf ("Building alphalight table...\n"); 148 | 149 | RunThreadsOnIndividual (32*32*32, true, Alphalight_Thread); 150 | 151 | SaveFile (savename, (byte *)alphamap, sizeof(alphamap)); 152 | } 153 | 154 | 155 | void Cmd_Inverse16Table( void ) 156 | { 157 | char savename[1024]; 158 | 159 | if ( g_release ) 160 | { 161 | sprintf (savename, "pics/16to8.dat"); 162 | ReleaseFile( savename ); 163 | return; 164 | } 165 | 166 | sprintf (savename, "%spics/16to8.dat", gamedir); 167 | printf ("Building inverse 16-to-8 table...\n"); 168 | 169 | Inverse16_BuildTable(); 170 | 171 | SaveFile( savename, (byte *) inverse16to8table, sizeof( inverse16to8table ) ); 172 | } 173 | -------------------------------------------------------------------------------- /src/common/trilib.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // 24 | // trilib.c: library for loading triangles from an Alias triangle file 25 | // 26 | 27 | #include 28 | #include "cmdlib.h" 29 | #include "mathlib.h" 30 | #include "trilib.h" 31 | 32 | // on disk representation of a face 33 | 34 | 35 | #define FLOAT_START 99999.0 36 | #define FLOAT_END -FLOAT_START 37 | #define MAGIC 123322 38 | 39 | //#define NOISY 1 40 | 41 | typedef struct { 42 | float v[3]; 43 | } vector; 44 | 45 | typedef struct 46 | { 47 | vector n; /* normal */ 48 | vector p; /* point */ 49 | vector c; /* color */ 50 | float u; /* u */ 51 | float v; /* v */ 52 | } aliaspoint_t; 53 | 54 | typedef struct { 55 | aliaspoint_t pt[3]; 56 | } tf_triangle; 57 | 58 | 59 | void ByteSwapTri (tf_triangle *tri) 60 | { 61 | int i; 62 | 63 | for (i=0 ; iverts[j][k] = tri.pt[j].p.v[k]; 173 | } 174 | } 175 | 176 | ptri++; 177 | 178 | if ((ptri - *pptri) >= MAXTRIANGLES) 179 | Error ("Error: too many triangles; increase MAXTRIANGLES\n"); 180 | } 181 | } 182 | 183 | *numtriangles = ptri - *pptri; 184 | 185 | fclose (input); 186 | } 187 | 188 | -------------------------------------------------------------------------------- /src/qbsp3/tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | #include "qbsp.h" 23 | 24 | extern int c_nodes; 25 | 26 | void RemovePortalFromNode (portal_t *portal, node_t *l); 27 | 28 | node_t *NodeForPoint (node_t *node, vec3_t origin) 29 | { 30 | plane_t *plane; 31 | vec_t d; 32 | 33 | while (node->planenum != PLANENUM_LEAF) 34 | { 35 | plane = &mapplanes[node->planenum]; 36 | d = DotProduct (origin, plane->normal) - plane->dist; 37 | if (d >= 0) 38 | node = node->children[0]; 39 | else 40 | node = node->children[1]; 41 | } 42 | 43 | return node; 44 | } 45 | 46 | 47 | 48 | /* 49 | ============= 50 | FreeTreePortals_r 51 | ============= 52 | */ 53 | void FreeTreePortals_r (node_t *node) 54 | { 55 | portal_t *p, *nextp; 56 | int s; 57 | 58 | // free children 59 | if (node->planenum != PLANENUM_LEAF) 60 | { 61 | FreeTreePortals_r (node->children[0]); 62 | FreeTreePortals_r (node->children[1]); 63 | } 64 | 65 | // free portals 66 | for (p=node->portals ; p ; p=nextp) 67 | { 68 | s = (p->nodes[1] == node); 69 | nextp = p->next[s]; 70 | 71 | RemovePortalFromNode (p, p->nodes[!s]); 72 | FreePortal (p); 73 | } 74 | node->portals = NULL; 75 | } 76 | 77 | /* 78 | ============= 79 | FreeTree_r 80 | ============= 81 | */ 82 | void FreeTree_r (node_t *node) 83 | { 84 | face_t *f, *nextf; 85 | 86 | // free children 87 | if (node->planenum != PLANENUM_LEAF) 88 | { 89 | FreeTree_r (node->children[0]); 90 | FreeTree_r (node->children[1]); 91 | } 92 | 93 | // free bspbrushes 94 | FreeBrushList (node->brushlist); 95 | 96 | // free faces 97 | for (f=node->faces ; f ; f=nextf) 98 | { 99 | nextf = f->next; 100 | FreeFace (f); 101 | } 102 | 103 | // free the node 104 | if (node->volume) 105 | FreeBrush (node->volume); 106 | 107 | if (numthreads == 1) 108 | c_nodes--; 109 | free (node); 110 | } 111 | 112 | 113 | /* 114 | ============= 115 | FreeTree 116 | ============= 117 | */ 118 | void FreeTree (tree_t *tree) 119 | { 120 | FreeTreePortals_r (tree->headnode); 121 | FreeTree_r (tree->headnode); 122 | free (tree); 123 | } 124 | 125 | //=============================================================== 126 | 127 | void PrintTree_r (node_t *node, int depth) 128 | { 129 | int i; 130 | plane_t *plane; 131 | bspbrush_t *bb; 132 | 133 | for (i=0 ; iplanenum == PLANENUM_LEAF) 136 | { 137 | if (!node->brushlist) 138 | printf ("NULL\n"); 139 | else 140 | { 141 | for (bb=node->brushlist ; bb ; bb=bb->next) 142 | printf ("%i ", bb->original->brushnum); 143 | printf ("\n"); 144 | } 145 | return; 146 | } 147 | 148 | plane = &mapplanes[node->planenum]; 149 | printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum, 150 | plane->normal[0], plane->normal[1], plane->normal[2], 151 | plane->dist); 152 | PrintTree_r (node->children[0], depth+1); 153 | PrintTree_r (node->children[1], depth+1); 154 | } 155 | 156 | /* 157 | ========================================================= 158 | 159 | NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED 160 | 161 | ========================================================= 162 | */ 163 | 164 | int c_pruned; 165 | 166 | /* 167 | ============ 168 | PruneNodes_r 169 | ============ 170 | */ 171 | void PruneNodes_r (node_t *node) 172 | { 173 | bspbrush_t *b, *next; 174 | 175 | if (node->planenum == PLANENUM_LEAF) 176 | return; 177 | PruneNodes_r (node->children[0]); 178 | PruneNodes_r (node->children[1]); 179 | 180 | if ( (node->children[0]->contents & CONTENTS_SOLID) 181 | && (node->children[1]->contents & CONTENTS_SOLID) ) 182 | { 183 | if (node->faces) 184 | Error ("node->faces seperating CONTENTS_SOLID"); 185 | if (node->children[0]->faces || node->children[1]->faces) 186 | Error ("!node->faces with children"); 187 | 188 | // FIXME: free stuff 189 | node->planenum = PLANENUM_LEAF; 190 | node->contents = CONTENTS_SOLID; 191 | node->detail_seperator = false; 192 | 193 | if (node->brushlist) 194 | Error ("PruneNodes: node->brushlist"); 195 | 196 | // combine brush lists 197 | node->brushlist = node->children[1]->brushlist; 198 | 199 | for (b=node->children[0]->brushlist ; b ; b=next) 200 | { 201 | next = b->next; 202 | b->next = node->brushlist; 203 | node->brushlist = b; 204 | } 205 | 206 | c_pruned++; 207 | } 208 | } 209 | 210 | 211 | void PruneNodes (node_t *node) 212 | { 213 | qprintf ("--- PruneNodes ---\n"); 214 | c_pruned = 0; 215 | PruneNodes_r (node); 216 | qprintf ("%5i pruned nodes\n", c_pruned); 217 | } 218 | 219 | //=========================================================== 220 | -------------------------------------------------------------------------------- /src/qbsp3/textures.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qbsp.h" 24 | 25 | int nummiptex; 26 | textureref_t textureref[MAX_MAP_TEXTURES]; 27 | 28 | //========================================================================== 29 | 30 | 31 | int FindMiptex (char *name) 32 | { 33 | int i; 34 | char path[1024]; 35 | miptex_t *mt; 36 | 37 | for (i=0 ; ivalue); 51 | textureref[i].flags = LittleLong (mt->flags); 52 | textureref[i].contents = LittleLong (mt->contents); 53 | strcpy (textureref[i].animname, mt->animname); 54 | free (mt); 55 | } 56 | nummiptex++; 57 | 58 | if (textureref[i].animname[0]) 59 | FindMiptex (textureref[i].animname); 60 | 61 | return i; 62 | } 63 | 64 | 65 | /* 66 | ================== 67 | textureAxisFromPlane 68 | ================== 69 | */ 70 | vec3_t baseaxis[18] = 71 | { 72 | {0,0,1}, {1,0,0}, {0,-1,0}, // floor 73 | {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling 74 | {1,0,0}, {0,1,0}, {0,0,-1}, // west wall 75 | {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall 76 | {0,1,0}, {1,0,0}, {0,0,-1}, // south wall 77 | {0,-1,0}, {1,0,0}, {0,0,-1} // north wall 78 | }; 79 | 80 | void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) 81 | { 82 | int bestaxis; 83 | vec_t dot,best; 84 | int i; 85 | 86 | best = 0; 87 | bestaxis = 0; 88 | 89 | for (i=0 ; i<6 ; i++) 90 | { 91 | dot = DotProduct (pln->normal, baseaxis[i*3]); 92 | if (dot > best) 93 | { 94 | best = dot; 95 | bestaxis = i; 96 | } 97 | } 98 | 99 | VectorCopy (baseaxis[bestaxis*3+1], xv); 100 | VectorCopy (baseaxis[bestaxis*3+2], yv); 101 | } 102 | 103 | 104 | 105 | 106 | int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin) 107 | { 108 | vec3_t vecs[2]; 109 | int sv, tv; 110 | vec_t ang, sinv, cosv; 111 | vec_t ns, nt; 112 | texinfo_t tx, *tc; 113 | int i, j, k; 114 | float shift[2]; 115 | brush_texture_t anim; 116 | int mt; 117 | 118 | if (!bt->name[0]) 119 | return 0; 120 | 121 | memset (&tx, 0, sizeof(tx)); 122 | strcpy (tx.texture, bt->name); 123 | 124 | TextureAxisFromPlane(plane, vecs[0], vecs[1]); 125 | 126 | shift[0] = DotProduct (origin, vecs[0]); 127 | shift[1] = DotProduct (origin, vecs[1]); 128 | 129 | if (!bt->scale[0]) 130 | bt->scale[0] = 1; 131 | if (!bt->scale[1]) 132 | bt->scale[1] = 1; 133 | 134 | 135 | // rotate axis 136 | if (bt->rotate == 0) 137 | { sinv = 0 ; cosv = 1; } 138 | else if (bt->rotate == 90) 139 | { sinv = 1 ; cosv = 0; } 140 | else if (bt->rotate == 180) 141 | { sinv = 0 ; cosv = -1; } 142 | else if (bt->rotate == 270) 143 | { sinv = -1 ; cosv = 0; } 144 | else 145 | { 146 | ang = bt->rotate / 180 * Q_PI; 147 | sinv = sin(ang); 148 | cosv = cos(ang); 149 | } 150 | 151 | if (vecs[0][0]) 152 | sv = 0; 153 | else if (vecs[0][1]) 154 | sv = 1; 155 | else 156 | sv = 2; 157 | 158 | if (vecs[1][0]) 159 | tv = 0; 160 | else if (vecs[1][1]) 161 | tv = 1; 162 | else 163 | tv = 2; 164 | 165 | for (i=0 ; i<2 ; i++) 166 | { 167 | ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; 168 | nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; 169 | vecs[i][sv] = ns; 170 | vecs[i][tv] = nt; 171 | } 172 | 173 | for (i=0 ; i<2 ; i++) 174 | for (j=0 ; j<3 ; j++) 175 | tx.vecs[i][j] = vecs[i][j] / bt->scale[i]; 176 | 177 | tx.vecs[0][3] = bt->shift[0] + shift[0]; 178 | tx.vecs[1][3] = bt->shift[1] + shift[1]; 179 | tx.flags = bt->flags; 180 | tx.value = bt->value; 181 | 182 | // 183 | // find the texinfo 184 | // 185 | tc = texinfo; 186 | for (i=0 ; iflags != tx.flags) 189 | continue; 190 | if (tc->value != tx.value) 191 | continue; 192 | for (j=0 ; j<2 ; j++) 193 | { 194 | if (strcmp (tc->texture, tx.texture)) 195 | goto skip; 196 | for (k=0 ; k<4 ; k++) 197 | { 198 | if (tc->vecs[j][k] != tx.vecs[j][k]) 199 | goto skip; 200 | } 201 | } 202 | return i; 203 | skip:; 204 | } 205 | *tc = tx; 206 | numtexinfo++; 207 | 208 | // load the next animation 209 | mt = FindMiptex (bt->name); 210 | if (textureref[mt].animname[0]) 211 | { 212 | anim = *bt; 213 | strcpy (anim.name, textureref[mt].animname); 214 | tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); 215 | } 216 | else 217 | tc->nexttexinfo = -1; 218 | 219 | 220 | return i; 221 | } 222 | -------------------------------------------------------------------------------- /src/qdata/sprites.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qdata.h" 24 | 25 | #define MAX_SPRFRAMES MAX_MD2SKINS 26 | 27 | dsprite_t sprite; 28 | dsprframe_t frames[MAX_SPRFRAMES]; 29 | 30 | byte *byteimage, *lbmpalette; 31 | int byteimagewidth, byteimageheight; 32 | 33 | char spritename[1024]; 34 | 35 | 36 | void FinishSprite (void); 37 | void Cmd_Spritename (void); 38 | 39 | 40 | 41 | /* 42 | ============== 43 | FinishSprite 44 | ============== 45 | */ 46 | void FinishSprite (void) 47 | { 48 | FILE *spriteouthandle; 49 | int i, curframe; 50 | dsprite_t spritetemp; 51 | char savename[1024]; 52 | 53 | if (sprite.numframes == 0) 54 | return; 55 | 56 | if (!strlen(spritename)) 57 | Error ("Didn't name sprite file"); 58 | 59 | sprintf (savename, "%s%s.sp2", gamedir, spritename); 60 | 61 | if (g_release) 62 | { 63 | char name[1024]; 64 | 65 | sprintf (name, "%s.sp2", spritename); 66 | ReleaseFile (name); 67 | spritename[0] = 0; // clear for a new sprite 68 | sprite.numframes = 0; 69 | return; 70 | } 71 | 72 | 73 | printf ("saving in %s\n", savename); 74 | CreatePath (savename); 75 | spriteouthandle = SafeOpenWrite (savename); 76 | 77 | 78 | // 79 | // write out the sprite header 80 | // 81 | spritetemp.ident = LittleLong (IDSPRITEHEADER); 82 | spritetemp.version = LittleLong (SPRITE_VERSION); 83 | spritetemp.numframes = LittleLong (sprite.numframes); 84 | 85 | SafeWrite (spriteouthandle, &spritetemp, 12); 86 | 87 | // 88 | // write out the frames 89 | // 90 | curframe = 0; 91 | 92 | for (i=0 ; i 256) || (h > 256)) 173 | Error ("Sprite has a dimension longer than 256"); 174 | 175 | xh = xl+w; 176 | yh = yl+h; 177 | 178 | if (sprite.numframes >= MAX_SPRFRAMES) 179 | Error ("Too many frames; increase MAX_SPRFRAMES\n"); 180 | 181 | pframe = &frames[sprite.numframes]; 182 | pframe->width = w; 183 | pframe->height = h; 184 | pframe->origin_x = ox; 185 | pframe->origin_y = oy; 186 | sprintf (pframe->name, "%s_%i.pcx", spritename, sprite.numframes); 187 | sprintf (savename, "%s%s_%i.pcx", gamedir, spritename, sprite.numframes); 188 | sprite.numframes++; 189 | 190 | if (g_release) 191 | { 192 | ReleaseFile (pframe->name); 193 | return; 194 | } 195 | 196 | // crop it to the proper size 197 | cropped = malloc (w*h); 198 | for (y=0 ; y /* XoXus: needed for memset call */ 31 | #include "mdfour.h" 32 | 33 | /* NOTE: This code makes no attempt to be fast! 34 | 35 | It assumes that a int is at least 32 bits long 36 | */ 37 | 38 | static struct mdfour *m; 39 | 40 | #define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z))) 41 | #define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))) 42 | #define H(X,Y,Z) ((X)^(Y)^(Z)) 43 | #ifdef LARGE_INT32 44 | #define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF)) 45 | #else 46 | #define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s)))) 47 | #endif 48 | 49 | #define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) 50 | #define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s) 51 | #define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s) 52 | 53 | /* this applies md4 to 64 byte chunks */ 54 | static void mdfour64(uint32 *M) 55 | { 56 | int j; 57 | uint32 AA, BB, CC, DD; 58 | uint32 X[16]; 59 | uint32 A,B,C,D; 60 | 61 | for (j=0;j<16;j++) 62 | X[j] = M[j]; 63 | 64 | A = m->A; B = m->B; C = m->C; D = m->D; 65 | AA = A; BB = B; CC = C; DD = D; 66 | 67 | ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7); 68 | ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19); 69 | ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7); 70 | ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19); 71 | ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7); 72 | ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19); 73 | ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7); 74 | ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); 75 | 76 | ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5); 77 | ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13); 78 | ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5); 79 | ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13); 80 | ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5); 81 | ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13); 82 | ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5); 83 | ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); 84 | 85 | ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9); 86 | ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15); 87 | ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9); 88 | ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15); 89 | ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9); 90 | ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15); 91 | ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9); 92 | ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15); 93 | 94 | A += AA; B += BB; C += CC; D += DD; 95 | 96 | #ifdef LARGE_INT32 97 | A &= 0xFFFFFFFF; B &= 0xFFFFFFFF; 98 | C &= 0xFFFFFFFF; D &= 0xFFFFFFFF; 99 | #endif 100 | 101 | for (j=0;j<16;j++) 102 | X[j] = 0; 103 | 104 | m->A = A; m->B = B; m->C = C; m->D = D; 105 | } 106 | 107 | static void copy64(uint32 *M, unsigned char *in) 108 | { 109 | int i; 110 | 111 | for (i=0;i<16;i++) 112 | M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) | 113 | (in[i*4+1]<<8) | (in[i*4+0]<<0); 114 | } 115 | 116 | static void copy4(unsigned char *out,uint32 x) 117 | { 118 | out[0] = x&0xFF; 119 | out[1] = (x>>8)&0xFF; 120 | out[2] = (x>>16)&0xFF; 121 | out[3] = (x>>24)&0xFF; 122 | } 123 | 124 | void mdfour_begin(struct mdfour *md) 125 | { 126 | md->A = 0x67452301; 127 | md->B = 0xefcdab89; 128 | md->C = 0x98badcfe; 129 | md->D = 0x10325476; 130 | md->totalN = 0; 131 | } 132 | 133 | 134 | static void mdfour_tail(unsigned char *in, int n) 135 | { 136 | unsigned char buf[128]; 137 | uint32 M[16]; 138 | uint32 b; 139 | 140 | m->totalN += n; 141 | 142 | b = m->totalN * 8; 143 | 144 | memset(buf, 0, 128); 145 | if (n) memcpy(buf, in, n); 146 | buf[n] = 0x80; 147 | 148 | if (n <= 55) { 149 | copy4(buf+56, b); 150 | copy64(M, buf); 151 | mdfour64(M); 152 | } else { 153 | copy4(buf+120, b); 154 | copy64(M, buf); 155 | mdfour64(M); 156 | copy64(M, buf+64); 157 | mdfour64(M); 158 | } 159 | } 160 | 161 | void mdfour_update(struct mdfour *md, unsigned char *in, int n) 162 | { 163 | uint32 M[16]; 164 | 165 | if (n == 0) mdfour_tail(in, n); 166 | 167 | m = md; 168 | 169 | while (n >= 64) { 170 | copy64(M, in); 171 | mdfour64(M); 172 | in += 64; 173 | n -= 64; 174 | m->totalN += 64; 175 | } 176 | 177 | mdfour_tail(in, n); 178 | } 179 | 180 | 181 | void mdfour_result(struct mdfour *md, unsigned char *out) 182 | { 183 | m = md; 184 | 185 | copy4(out, m->A); 186 | copy4(out+4, m->B); 187 | copy4(out+8, m->C); 188 | copy4(out+12, m->D); 189 | } 190 | 191 | 192 | void mdfour(unsigned char *out, unsigned char *in, int n) 193 | { 194 | struct mdfour md; 195 | mdfour_begin(&md); 196 | mdfour_update(&md, in, n); 197 | mdfour_result(&md, out); 198 | } 199 | 200 | /////////////////////////////////////////////////////////////// 201 | // MD4-based checksum utility functions 202 | // 203 | // Copyright (C) 2000 Jeff Teunissen 204 | // 205 | // Author: Jeff Teunissen 206 | // Date: 01 Jan 2000 207 | 208 | unsigned Com_BlockChecksum (void *buffer, int length) 209 | { 210 | int digest[4]; 211 | unsigned val; 212 | 213 | mdfour ( (unsigned char *) digest, (unsigned char *) buffer, length ); 214 | 215 | val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; 216 | 217 | return val; 218 | } 219 | 220 | void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf) 221 | { 222 | mdfour ( outbuf, (unsigned char *) buffer, len ); 223 | } 224 | 225 | -------------------------------------------------------------------------------- /src/qdata/anorms.h: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | {-0.525731, 0.000000, 0.850651}, 24 | {-0.442863, 0.238856, 0.864188}, 25 | {-0.295242, 0.000000, 0.955423}, 26 | {-0.309017, 0.500000, 0.809017}, 27 | {-0.162460, 0.262866, 0.951056}, 28 | {0.000000, 0.000000, 1.000000}, 29 | {0.000000, 0.850651, 0.525731}, 30 | {-0.147621, 0.716567, 0.681718}, 31 | {0.147621, 0.716567, 0.681718}, 32 | {0.000000, 0.525731, 0.850651}, 33 | {0.309017, 0.500000, 0.809017}, 34 | {0.525731, 0.000000, 0.850651}, 35 | {0.295242, 0.000000, 0.955423}, 36 | {0.442863, 0.238856, 0.864188}, 37 | {0.162460, 0.262866, 0.951056}, 38 | {-0.681718, 0.147621, 0.716567}, 39 | {-0.809017, 0.309017, 0.500000}, 40 | {-0.587785, 0.425325, 0.688191}, 41 | {-0.850651, 0.525731, 0.000000}, 42 | {-0.864188, 0.442863, 0.238856}, 43 | {-0.716567, 0.681718, 0.147621}, 44 | {-0.688191, 0.587785, 0.425325}, 45 | {-0.500000, 0.809017, 0.309017}, 46 | {-0.238856, 0.864188, 0.442863}, 47 | {-0.425325, 0.688191, 0.587785}, 48 | {-0.716567, 0.681718, -0.147621}, 49 | {-0.500000, 0.809017, -0.309017}, 50 | {-0.525731, 0.850651, 0.000000}, 51 | {0.000000, 0.850651, -0.525731}, 52 | {-0.238856, 0.864188, -0.442863}, 53 | {0.000000, 0.955423, -0.295242}, 54 | {-0.262866, 0.951056, -0.162460}, 55 | {0.000000, 1.000000, 0.000000}, 56 | {0.000000, 0.955423, 0.295242}, 57 | {-0.262866, 0.951056, 0.162460}, 58 | {0.238856, 0.864188, 0.442863}, 59 | {0.262866, 0.951056, 0.162460}, 60 | {0.500000, 0.809017, 0.309017}, 61 | {0.238856, 0.864188, -0.442863}, 62 | {0.262866, 0.951056, -0.162460}, 63 | {0.500000, 0.809017, -0.309017}, 64 | {0.850651, 0.525731, 0.000000}, 65 | {0.716567, 0.681718, 0.147621}, 66 | {0.716567, 0.681718, -0.147621}, 67 | {0.525731, 0.850651, 0.000000}, 68 | {0.425325, 0.688191, 0.587785}, 69 | {0.864188, 0.442863, 0.238856}, 70 | {0.688191, 0.587785, 0.425325}, 71 | {0.809017, 0.309017, 0.500000}, 72 | {0.681718, 0.147621, 0.716567}, 73 | {0.587785, 0.425325, 0.688191}, 74 | {0.955423, 0.295242, 0.000000}, 75 | {1.000000, 0.000000, 0.000000}, 76 | {0.951056, 0.162460, 0.262866}, 77 | {0.850651, -0.525731, 0.000000}, 78 | {0.955423, -0.295242, 0.000000}, 79 | {0.864188, -0.442863, 0.238856}, 80 | {0.951056, -0.162460, 0.262866}, 81 | {0.809017, -0.309017, 0.500000}, 82 | {0.681718, -0.147621, 0.716567}, 83 | {0.850651, 0.000000, 0.525731}, 84 | {0.864188, 0.442863, -0.238856}, 85 | {0.809017, 0.309017, -0.500000}, 86 | {0.951056, 0.162460, -0.262866}, 87 | {0.525731, 0.000000, -0.850651}, 88 | {0.681718, 0.147621, -0.716567}, 89 | {0.681718, -0.147621, -0.716567}, 90 | {0.850651, 0.000000, -0.525731}, 91 | {0.809017, -0.309017, -0.500000}, 92 | {0.864188, -0.442863, -0.238856}, 93 | {0.951056, -0.162460, -0.262866}, 94 | {0.147621, 0.716567, -0.681718}, 95 | {0.309017, 0.500000, -0.809017}, 96 | {0.425325, 0.688191, -0.587785}, 97 | {0.442863, 0.238856, -0.864188}, 98 | {0.587785, 0.425325, -0.688191}, 99 | {0.688191, 0.587785, -0.425325}, 100 | {-0.147621, 0.716567, -0.681718}, 101 | {-0.309017, 0.500000, -0.809017}, 102 | {0.000000, 0.525731, -0.850651}, 103 | {-0.525731, 0.000000, -0.850651}, 104 | {-0.442863, 0.238856, -0.864188}, 105 | {-0.295242, 0.000000, -0.955423}, 106 | {-0.162460, 0.262866, -0.951056}, 107 | {0.000000, 0.000000, -1.000000}, 108 | {0.295242, 0.000000, -0.955423}, 109 | {0.162460, 0.262866, -0.951056}, 110 | {-0.442863, -0.238856, -0.864188}, 111 | {-0.309017, -0.500000, -0.809017}, 112 | {-0.162460, -0.262866, -0.951056}, 113 | {0.000000, -0.850651, -0.525731}, 114 | {-0.147621, -0.716567, -0.681718}, 115 | {0.147621, -0.716567, -0.681718}, 116 | {0.000000, -0.525731, -0.850651}, 117 | {0.309017, -0.500000, -0.809017}, 118 | {0.442863, -0.238856, -0.864188}, 119 | {0.162460, -0.262866, -0.951056}, 120 | {0.238856, -0.864188, -0.442863}, 121 | {0.500000, -0.809017, -0.309017}, 122 | {0.425325, -0.688191, -0.587785}, 123 | {0.716567, -0.681718, -0.147621}, 124 | {0.688191, -0.587785, -0.425325}, 125 | {0.587785, -0.425325, -0.688191}, 126 | {0.000000, -0.955423, -0.295242}, 127 | {0.000000, -1.000000, 0.000000}, 128 | {0.262866, -0.951056, -0.162460}, 129 | {0.000000, -0.850651, 0.525731}, 130 | {0.000000, -0.955423, 0.295242}, 131 | {0.238856, -0.864188, 0.442863}, 132 | {0.262866, -0.951056, 0.162460}, 133 | {0.500000, -0.809017, 0.309017}, 134 | {0.716567, -0.681718, 0.147621}, 135 | {0.525731, -0.850651, 0.000000}, 136 | {-0.238856, -0.864188, -0.442863}, 137 | {-0.500000, -0.809017, -0.309017}, 138 | {-0.262866, -0.951056, -0.162460}, 139 | {-0.850651, -0.525731, 0.000000}, 140 | {-0.716567, -0.681718, -0.147621}, 141 | {-0.716567, -0.681718, 0.147621}, 142 | {-0.525731, -0.850651, 0.000000}, 143 | {-0.500000, -0.809017, 0.309017}, 144 | {-0.238856, -0.864188, 0.442863}, 145 | {-0.262866, -0.951056, 0.162460}, 146 | {-0.864188, -0.442863, 0.238856}, 147 | {-0.809017, -0.309017, 0.500000}, 148 | {-0.688191, -0.587785, 0.425325}, 149 | {-0.681718, -0.147621, 0.716567}, 150 | {-0.442863, -0.238856, 0.864188}, 151 | {-0.587785, -0.425325, 0.688191}, 152 | {-0.309017, -0.500000, 0.809017}, 153 | {-0.147621, -0.716567, 0.681718}, 154 | {-0.425325, -0.688191, 0.587785}, 155 | {-0.162460, -0.262866, 0.951056}, 156 | {0.442863, -0.238856, 0.864188}, 157 | {0.162460, -0.262866, 0.951056}, 158 | {0.309017, -0.500000, 0.809017}, 159 | {0.147621, -0.716567, 0.681718}, 160 | {0.000000, -0.525731, 0.850651}, 161 | {0.425325, -0.688191, 0.587785}, 162 | {0.587785, -0.425325, 0.688191}, 163 | {0.688191, -0.587785, 0.425325}, 164 | {-0.955423, 0.295242, 0.000000}, 165 | {-0.951056, 0.162460, 0.262866}, 166 | {-1.000000, 0.000000, 0.000000}, 167 | {-0.850651, 0.000000, 0.525731}, 168 | {-0.955423, -0.295242, 0.000000}, 169 | {-0.951056, -0.162460, 0.262866}, 170 | {-0.864188, 0.442863, -0.238856}, 171 | {-0.951056, 0.162460, -0.262866}, 172 | {-0.809017, 0.309017, -0.500000}, 173 | {-0.864188, -0.442863, -0.238856}, 174 | {-0.951056, -0.162460, -0.262866}, 175 | {-0.809017, -0.309017, -0.500000}, 176 | {-0.681718, 0.147621, -0.716567}, 177 | {-0.681718, -0.147621, -0.716567}, 178 | {-0.850651, 0.000000, -0.525731}, 179 | {-0.688191, 0.587785, -0.425325}, 180 | {-0.587785, 0.425325, -0.688191}, 181 | {-0.425325, 0.688191, -0.587785}, 182 | {-0.425325, -0.688191, -0.587785}, 183 | {-0.587785, -0.425325, -0.688191}, 184 | {-0.688191, -0.587785, -0.425325}, 185 | -------------------------------------------------------------------------------- /src/common/scriplib.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // scriplib.c 24 | 25 | #include "cmdlib.h" 26 | #include "scriplib.h" 27 | 28 | /* 29 | ============================================================================= 30 | 31 | PARSING STUFF 32 | 33 | ============================================================================= 34 | */ 35 | 36 | typedef struct 37 | { 38 | char filename[1024]; 39 | char *buffer,*script_p,*end_p; 40 | int line; 41 | } script_t; 42 | 43 | #define MAX_INCLUDES 8 44 | script_t scriptstack[MAX_INCLUDES]; 45 | script_t *script; 46 | int scriptline; 47 | 48 | char token[MAXTOKEN]; 49 | qboolean endofscript; 50 | qboolean tokenready; // only true if UnGetToken was just called 51 | 52 | /* 53 | ============== 54 | AddScriptToStack 55 | ============== 56 | */ 57 | void AddScriptToStack (char *filename) 58 | { 59 | int size; 60 | 61 | script++; 62 | if (script == &scriptstack[MAX_INCLUDES]) 63 | Error ("script file exceeded MAX_INCLUDES"); 64 | strcpy (script->filename, ExpandPath (filename) ); 65 | 66 | size = LoadFile (script->filename, (void **)&script->buffer); 67 | 68 | printf ("entering %s\n", script->filename); 69 | 70 | script->line = 1; 71 | 72 | script->script_p = script->buffer; 73 | script->end_p = script->buffer + size; 74 | } 75 | 76 | 77 | /* 78 | ============== 79 | LoadScriptFile 80 | ============== 81 | */ 82 | void LoadScriptFile (char *filename) 83 | { 84 | script = scriptstack; 85 | AddScriptToStack (filename); 86 | 87 | endofscript = false; 88 | tokenready = false; 89 | } 90 | 91 | 92 | /* 93 | ============== 94 | ParseFromMemory 95 | ============== 96 | */ 97 | void ParseFromMemory (char *buffer, int size) 98 | { 99 | script = scriptstack; 100 | script++; 101 | if (script == &scriptstack[MAX_INCLUDES]) 102 | Error ("script file exceeded MAX_INCLUDES"); 103 | strcpy (script->filename, "memory buffer" ); 104 | 105 | script->buffer = buffer; 106 | script->line = 1; 107 | script->script_p = script->buffer; 108 | script->end_p = script->buffer + size; 109 | 110 | endofscript = false; 111 | tokenready = false; 112 | } 113 | 114 | 115 | /* 116 | ============== 117 | UnGetToken 118 | 119 | Signals that the current token was not used, and should be reported 120 | for the next GetToken. Note that 121 | 122 | GetToken (true); 123 | UnGetToken (); 124 | GetToken (false); 125 | 126 | could cross a line boundary. 127 | ============== 128 | */ 129 | void UnGetToken (void) 130 | { 131 | tokenready = true; 132 | } 133 | 134 | 135 | qboolean EndOfScript (qboolean crossline) 136 | { 137 | if (!crossline) 138 | Error ("Line %i is incomplete\n",scriptline); 139 | 140 | if (!strcmp (script->filename, "memory buffer")) 141 | { 142 | endofscript = true; 143 | return false; 144 | } 145 | 146 | free (script->buffer); 147 | if (script == scriptstack+1) 148 | { 149 | endofscript = true; 150 | return false; 151 | } 152 | script--; 153 | scriptline = script->line; 154 | printf ("returning to %s\n", script->filename); 155 | return GetToken (crossline); 156 | } 157 | 158 | /* 159 | ============== 160 | GetToken 161 | ============== 162 | */ 163 | qboolean GetToken (qboolean crossline) 164 | { 165 | char *token_p; 166 | 167 | if (tokenready) // is a token allready waiting? 168 | { 169 | tokenready = false; 170 | return true; 171 | } 172 | 173 | if (script->script_p >= script->end_p) 174 | return EndOfScript (crossline); 175 | 176 | // 177 | // skip space 178 | // 179 | skipspace: 180 | while (*script->script_p <= 32) 181 | { 182 | if (script->script_p >= script->end_p) 183 | return EndOfScript (crossline); 184 | if (*script->script_p++ == '\n') 185 | { 186 | if (!crossline) 187 | Error ("Line %i is incomplete\n",scriptline); 188 | scriptline = script->line++; 189 | } 190 | } 191 | 192 | if (script->script_p >= script->end_p) 193 | return EndOfScript (crossline); 194 | 195 | // ; # // comments 196 | if (*script->script_p == ';' || *script->script_p == '#' 197 | || ( script->script_p[0] == '/' && script->script_p[1] == '/') ) 198 | { 199 | if (!crossline) 200 | Error ("Line %i is incomplete\n",scriptline); 201 | while (*script->script_p++ != '\n') 202 | if (script->script_p >= script->end_p) 203 | return EndOfScript (crossline); 204 | goto skipspace; 205 | } 206 | 207 | // /* */ comments 208 | if (script->script_p[0] == '/' && script->script_p[1] == '*') 209 | { 210 | if (!crossline) 211 | Error ("Line %i is incomplete\n",scriptline); 212 | script->script_p+=2; 213 | while (script->script_p[0] != '*' && script->script_p[1] != '/') 214 | { 215 | script->script_p++; 216 | if (script->script_p >= script->end_p) 217 | return EndOfScript (crossline); 218 | } 219 | script->script_p += 2; 220 | goto skipspace; 221 | } 222 | 223 | // 224 | // copy token 225 | // 226 | token_p = token; 227 | 228 | if (*script->script_p == '"') 229 | { 230 | // quoted token 231 | script->script_p++; 232 | while (*script->script_p != '"') 233 | { 234 | *token_p++ = *script->script_p++; 235 | if (script->script_p == script->end_p) 236 | break; 237 | if (token_p == &token[MAXTOKEN]) 238 | Error ("Token too large on line %i\n",scriptline); 239 | } 240 | script->script_p++; 241 | } 242 | else // regular token 243 | while ( *script->script_p > 32 && *script->script_p != ';') 244 | { 245 | *token_p++ = *script->script_p++; 246 | if (script->script_p == script->end_p) 247 | break; 248 | if (token_p == &token[MAXTOKEN]) 249 | Error ("Token too large on line %i\n",scriptline); 250 | } 251 | 252 | *token_p = 0; 253 | 254 | if (!strcmp (token, "$include")) 255 | { 256 | GetToken (false); 257 | AddScriptToStack (token); 258 | return GetToken (crossline); 259 | } 260 | 261 | return true; 262 | } 263 | 264 | 265 | /* 266 | ============== 267 | TokenAvailable 268 | 269 | Returns true if there is another token on the line 270 | ============== 271 | */ 272 | qboolean TokenAvailable (void) 273 | { 274 | char *search_p; 275 | 276 | search_p = script->script_p; 277 | 278 | if (search_p >= script->end_p) 279 | return false; 280 | 281 | while ( *search_p <= 32) 282 | { 283 | if (*search_p == '\n') 284 | return false; 285 | search_p++; 286 | if (search_p == script->end_p) 287 | return false; 288 | 289 | } 290 | 291 | if (*search_p == ';') 292 | return false; 293 | 294 | return true; 295 | } 296 | 297 | 298 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------ # 2 | # Makefile for the "Quake II Map Tools" # 3 | # # 4 | # Just type "make" to compile the # 5 | # - bspinfo # 6 | # - qbsp3 # 7 | # - qdata # 8 | # - qrad3 # 9 | # - qvis3 # 10 | # # 11 | # Platforms: # 12 | # - Linux # 13 | # - FreeBSD # 14 | # ------------------------------------------------------ # 15 | 16 | # Check the OS type 17 | OSTYPE := $(shell uname -s) 18 | 19 | # Some plattforms call it "amd64" and some "x86_64" 20 | ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/amd64/x86_64/) 21 | 22 | # Refuse all other plattforms as a firewall against PEBKAC 23 | # (You'll need some #ifdef for your unsupported plattform!) 24 | ifneq ($(ARCH),i386) 25 | ifneq ($(ARCH),x86_64) 26 | $(error arch $(ARCH) is currently not supported) 27 | endif 28 | endif 29 | 30 | # ---------- 31 | 32 | # Base CFLAGS. 33 | # 34 | # -O2 are enough optimizations. 35 | # 36 | # -fno-strict-aliasing since the source doesn't comply 37 | # with strict aliasing rules and it's next to impossible 38 | # to get it there... 39 | # 40 | # -fomit-frame-pointer since the framepointer is mostly 41 | # useless for debugging Quake II and slows things down. 42 | # 43 | # -g to build allways with debug symbols. Please do not 44 | # change this, since it's our only chance to debug this 45 | # crap when random crashes happen! 46 | # 47 | # -MMD to generate header dependencies. 48 | CFLAGS := -O2 -fno-strict-aliasing -fomit-frame-pointer \ 49 | -Wall -pipe -g -MMD 50 | 51 | # ---------- 52 | 53 | # Base include path. 54 | ifeq ($(OSTYPE),Linux) 55 | INCLUDE := -I./src/common 56 | else ifeq ($(OSTYPE),FreeBSD) 57 | INCLUDE := -I./src/common 58 | endif 59 | 60 | # ---------- 61 | 62 | # Base LDFLAGS. 63 | ifeq ($(OSTYPE),Linux) 64 | LDFLAGS := -L/usr/lib -lm 65 | else ifeq ($(OSTYPE),FreeBSD) 66 | LDFLAGS := -L/usr/local/lib -lm 67 | endif 68 | 69 | # ---------- 70 | 71 | # When make is invoked by "make VERBOSE=1" print 72 | # the compiler and linker commands. 73 | 74 | ifdef VERBOSE 75 | Q := 76 | else 77 | Q := @ 78 | endif 79 | 80 | # ---------- 81 | 82 | # Builds everything 83 | all: bspinfo qbsp3 qdata qrad3 qvis3 84 | 85 | # ---------- 86 | 87 | # Cleanup 88 | clean: 89 | @echo "===> CLEAN" 90 | ${Q}rm -Rf build release 91 | 92 | # ---------- 93 | 94 | # common stuff 95 | build/common/%.o: %.c 96 | @echo '===> CC $<' 97 | ${Q}mkdir -p $(@D) 98 | ${Q}$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< 99 | 100 | # ---------- 101 | 102 | # bspinfo 103 | bspinfo: 104 | @echo '===> Building bspinfo' 105 | ${Q}mkdir -p release 106 | $(MAKE) release/bspinfo 107 | 108 | build/bspinfo/%.o: %.c 109 | @echo '===> CC $<' 110 | ${Q}mkdir -p $(@D) 111 | ${Q}$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< 112 | 113 | # ---------- 114 | 115 | # qbsp3 116 | qbsp3: 117 | @echo '===> Building qbsp3' 118 | ${Q}mkdir -p release 119 | $(MAKE) release/qbsp3 120 | 121 | build/qbsp3/%.o: %.c 122 | @echo '===> CC $<' 123 | ${Q}mkdir -p $(@D) 124 | ${Q}$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< 125 | 126 | # ---------- 127 | 128 | # qdata 129 | qdata: 130 | @echo '===> Building qdata' 131 | ${Q}mkdir -p release 132 | $(MAKE) release/qdata 133 | 134 | build/qdata/%.o: %.c 135 | @echo '===> CC $<' 136 | ${Q}mkdir -p $(@D) 137 | ${Q}$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< 138 | 139 | # ---------- 140 | 141 | # qrad3 142 | qrad3: 143 | @echo '===> Building qrad3' 144 | ${Q}mkdir -p release 145 | $(MAKE) release/qrad3 146 | 147 | build/qrad3/%.o: %.c 148 | @echo '===> CC $<' 149 | ${Q}mkdir -p $(@D) 150 | ${Q}$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< 151 | 152 | # ---------- 153 | 154 | # qvis3 155 | qvis3: 156 | @echo '===> Building qvis3' 157 | ${Q}mkdir -p release 158 | $(MAKE) release/qvis3 159 | 160 | build/qvis3/%.o: %.c 161 | @echo '===> CC $<' 162 | ${Q}mkdir -p $(@D) 163 | ${Q}$(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< 164 | 165 | # ---------- 166 | 167 | # Common objects 168 | COMMON_OBJS_ = \ 169 | src/common/bspfile.o \ 170 | src/common/cmdlib.o \ 171 | src/common/l3dslib.o \ 172 | src/common/lbmlib.o \ 173 | src/common/mathlib.o \ 174 | src/common/mdfour.o \ 175 | src/common/polylib.o \ 176 | src/common/scriplib.o \ 177 | src/common/threads.o \ 178 | src/common/trilib.o 179 | 180 | # Used by bspinfo 181 | BSPINFO_OBJS_ = \ 182 | src/bspinfo/bspinfo.o 183 | 184 | # Used by qbsp3 185 | QBSP_OBJS_ = \ 186 | src/qbsp3/brushbsp.o \ 187 | src/qbsp3/csg.o \ 188 | src/qbsp3/faces.o \ 189 | src/qbsp3/glfile.o \ 190 | src/qbsp3/leakfile.o \ 191 | src/qbsp3/map.o \ 192 | src/qbsp3/nodraw.o \ 193 | src/qbsp3/portals.o \ 194 | src/qbsp3/prtfile.o \ 195 | src/qbsp3/qbsp3.o \ 196 | src/qbsp3/textures.o \ 197 | src/qbsp3/tree.o \ 198 | src/qbsp3/writebsp.o 199 | 200 | # Used by qdata 201 | QDATA_OBJS_ = \ 202 | src/qdata/images.o \ 203 | src/qdata/models.o \ 204 | src/qdata/qdata.o \ 205 | src/qdata/sprites.o \ 206 | src/qdata/tables.o \ 207 | src/qdata/video.o 208 | 209 | # Used by qrad3 210 | QRAD_OBJS_ = \ 211 | src/qrad3/lightmap.o \ 212 | src/qrad3/patches.o \ 213 | src/qrad3/qrad3.o \ 214 | src/qrad3/trace.o 215 | 216 | # Used by qvis3 217 | QVIS_OBJS_ = \ 218 | src/qvis3/flow.o \ 219 | src/qvis3/qvis3.o 220 | 221 | # ---------- 222 | 223 | # Rewrite pathes to our object directory 224 | COMMON_OBJS = $(patsubst %,build/common/%,$(COMMON_OBJS_)) 225 | BSPINFO_OBJS = $(patsubst %,build/bspinfo/%,$(BSPINFO_OBJS_)) 226 | QBSP_OBJS = $(patsubst %,build/qbsp3/%,$(QBSP_OBJS_)) 227 | QDATA_OBJS = $(patsubst %,build/qdata/%,$(QDATA_OBJS_)) 228 | QRAD_OBJS = $(patsubst %,build/qrad3/%,$(QRAD_OBJS_)) 229 | QVIS_OBJS = $(patsubst %,build/qvis3/%,$(QVIS_OBJS_)) 230 | 231 | # ---------- 232 | 233 | # Generate header dependencies 234 | COMMON_DEPS= $(COMMON_OBJS:.o=.d) 235 | BSPINFO_DEPS= $(BSPINFO_OBJS:.o=.d) 236 | QBSP_DEPS= $(QBSP_OBJS:.o=.d) 237 | QDATA_DEPS= $(QDATA_OBJS:.o=.d) 238 | QRAD_DEPS= $(QRAD_OBJS:.o=.d) 239 | QVIS_DEPS= $(QVIS_OBJS:.o=.d) 240 | 241 | # ---------- 242 | 243 | -include $(COMMON_DEPS) 244 | -include $(BSPINFO_DEPS) 245 | -include $(QBSP_DEPS) 246 | -include $(QDATA_DEPS) 247 | -include $(QRAD_DEPS) 248 | -include $(QVIS_DEPS) 249 | 250 | # ---------- 251 | 252 | # release/bspinfo 253 | release/bspinfo : $(COMMON_OBJS) $(BSPINFO_OBJS) 254 | @echo '===> LD $@' 255 | ${Q}$(CC) $(COMMON_OBJS) $(BSPINFO_OBJS) $(LDFLAGS) -o $@ 256 | 257 | # release/qbsp3 258 | release/qbsp3 : $(COMMON_OBJS) $(QBSP_OBJS) 259 | @echo '===> LD $@' 260 | ${Q}$(CC) $(COMMON_OBJS) $(QBSP_OBJS) $(LDFLAGS) -o $@ 261 | 262 | # release/qdata 263 | release/qdata : $(COMMON_OBJS) $(QDATA_OBJS) 264 | @echo '===> LD $@' 265 | ${Q}$(CC) $(COMMON_OBJS) $(QDATA_OBJS) $(LDFLAGS) -o $@ 266 | 267 | # release/qrad3 268 | release/qrad3 : $(COMMON_OBJS) $(QRAD_OBJS) 269 | @echo '===> LD $@' 270 | ${Q}$(CC) $(COMMON_OBJS) $(QRAD_OBJS) $(LDFLAGS) -o $@ 271 | 272 | # release/qvis3 273 | release/qvis3 : $(COMMON_OBJS) $(QVIS_OBJS) 274 | @echo '===> LD $@' 275 | ${Q}$(CC) $(COMMON_OBJS) $(QVIS_OBJS) $(LDFLAGS) -o $@ 276 | 277 | -------------------------------------------------------------------------------- /src/common/l3dslib.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | // 24 | // l3dslib.c: library for loading triangles from an Alias triangle file 25 | // 26 | 27 | #include 28 | #include "cmdlib.h" 29 | #include "mathlib.h" 30 | #include "trilib.h" 31 | #include "l3dslib.h" 32 | 33 | #define MAIN3DS 0x4D4D 34 | #define EDIT3DS 0x3D3D // this is the start of the editor config 35 | #define EDIT_OBJECT 0x4000 36 | #define OBJ_TRIMESH 0x4100 37 | #define TRI_VERTEXL 0x4110 38 | #define TRI_FACEL1 0x4120 39 | 40 | #define MAXVERTS 2000 41 | 42 | typedef struct { 43 | int v[4]; 44 | } tri; 45 | 46 | float fverts[MAXVERTS][3]; 47 | tri tris[MAXTRIANGLES]; 48 | 49 | int bytesread, level, numtris, totaltris; 50 | int vertsfound, trisfound; 51 | 52 | triangle_t *ptri; 53 | 54 | 55 | // Alias stores triangles as 3 explicit vertices in .tri files, so even though we 56 | // start out with a vertex pool and vertex indices for triangles, we have to convert 57 | // to raw, explicit triangles 58 | void StoreAliasTriangles (void) 59 | { 60 | int i, j, k; 61 | 62 | if ((totaltris + numtris) > MAXTRIANGLES) 63 | Error ("Error: Too many triangles"); 64 | 65 | for (i=0; i MAXVERTS) 102 | Error ("Error: Too many vertices"); 103 | 104 | for (i=0 ; i MAXTRIANGLES) 143 | Error ("Error: Too many triangles"); 144 | 145 | for (i=0 ; i 0) 222 | { 223 | w -= ParseChunk (input); 224 | } 225 | 226 | retval = length; 227 | goto Done; 228 | 229 | default: 230 | // skip other chunks 231 | while (w > 0) 232 | { 233 | t = w; 234 | 235 | if (t > BLOCK_SIZE) 236 | t = BLOCK_SIZE; 237 | 238 | if (feof(input)) 239 | Error ("Error: unexpected end of file"); 240 | 241 | fread (&temp, t, 1, input); 242 | bytesread += t; 243 | 244 | w -= t; 245 | } 246 | 247 | retval = length; 248 | goto Done; 249 | } 250 | 251 | Done: 252 | level--; 253 | return retval; 254 | } 255 | 256 | 257 | void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles) 258 | { 259 | FILE *input; 260 | short int tshort; 261 | 262 | bytesread = 0; 263 | level = 0; 264 | numtris = 0; 265 | totaltris = 0; 266 | vertsfound = 0; 267 | trisfound = 0; 268 | 269 | if ((input = fopen(filename, "rb")) == 0) { 270 | fprintf(stderr,"reader: could not open file '%s'\n", filename); 271 | exit(0); 272 | } 273 | 274 | fread(&tshort, sizeof(tshort), 1, input); 275 | 276 | // should only be MAIN3DS, but some files seem to start with EDIT3DS, with 277 | // no MAIN3DS 278 | if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) { 279 | fprintf(stderr,"File is not a 3DS file.\n"); 280 | exit(0); 281 | } 282 | 283 | // back to top of file so we can parse the first chunk descriptor 284 | fseek(input, 0, SEEK_SET); 285 | 286 | ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); 287 | 288 | *pptri = ptri; 289 | 290 | // parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT | 291 | // OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks 292 | ParseChunk (input); 293 | 294 | if (vertsfound || trisfound) 295 | Error ("Incomplete triangle set"); 296 | 297 | *numtriangles = totaltris; 298 | 299 | fclose (input); 300 | } 301 | 302 | -------------------------------------------------------------------------------- /src/qbsp3/prtfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qbsp.h" 24 | 25 | /* 26 | ============================================================================== 27 | 28 | PORTAL FILE GENERATION 29 | 30 | Save out name.prt for qvis to read 31 | ============================================================================== 32 | */ 33 | 34 | 35 | #define PORTALFILE "PRT1" 36 | 37 | FILE *pf; 38 | int num_visclusters; // clusters the player can be in 39 | int num_visportals; 40 | 41 | void WriteFloat (FILE *f, vec_t v) 42 | { 43 | if ( fabs(v - Q_rint(v)) < 0.001 ) 44 | fprintf (f,"%i ",(int)Q_rint(v)); 45 | else 46 | fprintf (f,"%f ",v); 47 | } 48 | 49 | /* 50 | ================= 51 | WritePortalFile_r 52 | ================= 53 | */ 54 | void WritePortalFile_r (node_t *node) 55 | { 56 | int i, s; 57 | portal_t *p; 58 | winding_t *w; 59 | vec3_t normal; 60 | vec_t dist; 61 | 62 | // decision node 63 | if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) 64 | { 65 | WritePortalFile_r (node->children[0]); 66 | WritePortalFile_r (node->children[1]); 67 | return; 68 | } 69 | 70 | if (node->contents & CONTENTS_SOLID) 71 | return; 72 | 73 | for (p = node->portals ; p ; p=p->next[s]) 74 | { 75 | w = p->winding; 76 | s = (p->nodes[1] == node); 77 | if (w && p->nodes[0] == node) 78 | { 79 | if (!Portal_VisFlood (p)) 80 | continue; 81 | // write out to the file 82 | 83 | // sometimes planes get turned around when they are very near 84 | // the changeover point between different axis. interpret the 85 | // plane the same way vis will, and flip the side orders if needed 86 | // FIXME: is this still relevent? 87 | WindingPlane (w, normal, &dist); 88 | if ( DotProduct (p->plane.normal, normal) < 0.99 ) 89 | { // backwards... 90 | fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster); 91 | } 92 | else 93 | fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster); 94 | for (i=0 ; inumpoints ; i++) 95 | { 96 | fprintf (pf,"("); 97 | WriteFloat (pf, w->p[i][0]); 98 | WriteFloat (pf, w->p[i][1]); 99 | WriteFloat (pf, w->p[i][2]); 100 | fprintf (pf,") "); 101 | } 102 | fprintf (pf,"\n"); 103 | } 104 | } 105 | 106 | } 107 | 108 | /* 109 | ================ 110 | FillLeafNumbers_r 111 | 112 | All of the leafs under node will have the same cluster 113 | ================ 114 | */ 115 | void FillLeafNumbers_r (node_t *node, int num) 116 | { 117 | if (node->planenum == PLANENUM_LEAF) 118 | { 119 | if (node->contents & CONTENTS_SOLID) 120 | node->cluster = -1; 121 | else 122 | node->cluster = num; 123 | return; 124 | } 125 | node->cluster = num; 126 | FillLeafNumbers_r (node->children[0], num); 127 | FillLeafNumbers_r (node->children[1], num); 128 | } 129 | 130 | /* 131 | ================ 132 | NumberLeafs_r 133 | ================ 134 | */ 135 | void NumberLeafs_r (node_t *node) 136 | { 137 | portal_t *p; 138 | 139 | if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) 140 | { // decision node 141 | node->cluster = -99; 142 | NumberLeafs_r (node->children[0]); 143 | NumberLeafs_r (node->children[1]); 144 | return; 145 | } 146 | 147 | // either a leaf or a detail cluster 148 | 149 | if ( node->contents & CONTENTS_SOLID ) 150 | { // solid block, viewpoint never inside 151 | node->cluster = -1; 152 | return; 153 | } 154 | 155 | FillLeafNumbers_r (node, num_visclusters); 156 | num_visclusters++; 157 | 158 | // count the portals 159 | for (p = node->portals ; p ; ) 160 | { 161 | if (p->nodes[0] == node) // only write out from first leaf 162 | { 163 | if (Portal_VisFlood (p)) 164 | num_visportals++; 165 | p = p->next[0]; 166 | } 167 | else 168 | p = p->next[1]; 169 | } 170 | 171 | } 172 | 173 | 174 | /* 175 | ================ 176 | CreateVisPortals_r 177 | ================ 178 | */ 179 | void CreateVisPortals_r (node_t *node) 180 | { 181 | // stop as soon as we get to a detail_seperator, which 182 | // means that everything below is in a single cluster 183 | if (node->planenum == PLANENUM_LEAF || node->detail_seperator ) 184 | return; 185 | 186 | MakeNodePortal (node); 187 | SplitNodePortals (node); 188 | 189 | CreateVisPortals_r (node->children[0]); 190 | CreateVisPortals_r (node->children[1]); 191 | } 192 | 193 | /* 194 | ================ 195 | FinishVisPortals_r 196 | ================ 197 | */ 198 | void FinishVisPortals2_r (node_t *node) 199 | { 200 | if (node->planenum == PLANENUM_LEAF) 201 | return; 202 | 203 | MakeNodePortal (node); 204 | SplitNodePortals (node); 205 | 206 | FinishVisPortals2_r (node->children[0]); 207 | FinishVisPortals2_r (node->children[1]); 208 | } 209 | 210 | void FinishVisPortals_r (node_t *node) 211 | { 212 | if (node->planenum == PLANENUM_LEAF) 213 | return; 214 | 215 | if (node->detail_seperator) 216 | { 217 | FinishVisPortals2_r (node); 218 | return; 219 | } 220 | 221 | FinishVisPortals_r (node->children[0]); 222 | FinishVisPortals_r (node->children[1]); 223 | } 224 | 225 | 226 | int clusterleaf; 227 | void SaveClusters_r (node_t *node) 228 | { 229 | if (node->planenum == PLANENUM_LEAF) 230 | { 231 | dleafs[clusterleaf++].cluster = node->cluster; 232 | return; 233 | } 234 | SaveClusters_r (node->children[0]); 235 | SaveClusters_r (node->children[1]); 236 | } 237 | 238 | /* 239 | ================ 240 | WritePortalFile 241 | ================ 242 | */ 243 | void WritePortalFile (tree_t *tree) 244 | { 245 | char filename[1024]; 246 | node_t *headnode; 247 | 248 | qprintf ("--- WritePortalFile ---\n"); 249 | 250 | headnode = tree->headnode; 251 | num_visclusters = 0; 252 | num_visportals = 0; 253 | 254 | FreeTreePortals_r (headnode); 255 | 256 | MakeHeadnodePortals (tree); 257 | 258 | CreateVisPortals_r (headnode); 259 | 260 | // set the cluster field in every leaf and count the total number of portals 261 | 262 | NumberLeafs_r (headnode); 263 | 264 | // write the file 265 | sprintf (filename, "%s.prt", source); 266 | printf ("writing %s\n", filename); 267 | pf = fopen (filename, "w"); 268 | if (!pf) 269 | Error ("Error opening %s", filename); 270 | 271 | fprintf (pf, "%s\n", PORTALFILE); 272 | fprintf (pf, "%i\n", num_visclusters); 273 | fprintf (pf, "%i\n", num_visportals); 274 | 275 | qprintf ("%5i visclusters\n", num_visclusters); 276 | qprintf ("%5i visportals\n", num_visportals); 277 | 278 | WritePortalFile_r (headnode); 279 | 280 | fclose (pf); 281 | 282 | // we need to store the clusters out now because ordering 283 | // issues made us do this after writebsp... 284 | clusterleaf = 1; 285 | SaveClusters_r (headnode); 286 | } 287 | 288 | -------------------------------------------------------------------------------- /src/qrad3/trace.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "cmdlib.h" 24 | #include "mathlib.h" 25 | #include "bspfile.h" 26 | 27 | #define ON_EPSILON 0.1 28 | 29 | typedef struct tnode_s 30 | { 31 | int type; 32 | vec3_t normal; 33 | float dist; 34 | int children[2]; 35 | int pad; 36 | } tnode_t; 37 | 38 | tnode_t *tnodes, *tnode_p; 39 | 40 | /* 41 | ============== 42 | MakeTnode 43 | 44 | Converts the disk node structure into the efficient tracing structure 45 | ============== 46 | */ 47 | void MakeTnode (int nodenum) 48 | { 49 | tnode_t *t; 50 | dplane_t *plane; 51 | int i; 52 | dnode_t *node; 53 | 54 | t = tnode_p++; 55 | 56 | node = dnodes + nodenum; 57 | plane = dplanes + node->planenum; 58 | 59 | t->type = plane->type; 60 | VectorCopy (plane->normal, t->normal); 61 | t->dist = plane->dist; 62 | 63 | for (i=0 ; i<2 ; i++) 64 | { 65 | if (node->children[i] < 0) 66 | t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31); 67 | else 68 | { 69 | t->children[i] = tnode_p - tnodes; 70 | MakeTnode (node->children[i]); 71 | } 72 | } 73 | 74 | } 75 | 76 | 77 | /* 78 | ============= 79 | MakeTnodes 80 | 81 | Loads the node structure out of a .bsp file to be used for light occlusion 82 | ============= 83 | */ 84 | void MakeTnodes (dmodel_t *bm) 85 | { 86 | // 32 byte align the structs 87 | tnodes = malloc( (numnodes+1) * sizeof(tnode_t)); 88 | tnodes = (tnode_t *)(((int)tnodes + 31)&~31); 89 | tnode_p = tnodes; 90 | 91 | MakeTnode (0); 92 | } 93 | 94 | 95 | //========================================================== 96 | 97 | 98 | int TestLine_r (int node, vec3_t start, vec3_t stop) 99 | { 100 | tnode_t *tnode; 101 | float front, back; 102 | vec3_t mid; 103 | float frac; 104 | int side; 105 | int r; 106 | 107 | if (node & (1<<31)) 108 | return node & ~(1<<31); // leaf node 109 | 110 | tnode = &tnodes[node]; 111 | switch (tnode->type) 112 | { 113 | case PLANE_X: 114 | front = start[0] - tnode->dist; 115 | back = stop[0] - tnode->dist; 116 | break; 117 | case PLANE_Y: 118 | front = start[1] - tnode->dist; 119 | back = stop[1] - tnode->dist; 120 | break; 121 | case PLANE_Z: 122 | front = start[2] - tnode->dist; 123 | back = stop[2] - tnode->dist; 124 | break; 125 | default: 126 | front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist; 127 | back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist; 128 | break; 129 | } 130 | 131 | if (front >= -ON_EPSILON && back >= -ON_EPSILON) 132 | return TestLine_r (tnode->children[0], start, stop); 133 | 134 | if (front < ON_EPSILON && back < ON_EPSILON) 135 | return TestLine_r (tnode->children[1], start, stop); 136 | 137 | side = front < 0; 138 | 139 | frac = front / (front-back); 140 | 141 | mid[0] = start[0] + (stop[0] - start[0])*frac; 142 | mid[1] = start[1] + (stop[1] - start[1])*frac; 143 | mid[2] = start[2] + (stop[2] - start[2])*frac; 144 | 145 | r = TestLine_r (tnode->children[side], start, mid); 146 | if (r) 147 | return r; 148 | return TestLine_r (tnode->children[!side], mid, stop); 149 | } 150 | 151 | int TestLine (vec3_t start, vec3_t stop) 152 | { 153 | return TestLine_r (0, start, stop); 154 | } 155 | 156 | /* 157 | ============================================================================== 158 | 159 | LINE TRACING 160 | 161 | The major lighting operation is a point to point visibility test, performed 162 | by recursive subdivision of the line by the BSP tree. 163 | 164 | ============================================================================== 165 | */ 166 | 167 | typedef struct 168 | { 169 | vec3_t backpt; 170 | int side; 171 | int node; 172 | } tracestack_t; 173 | 174 | 175 | /* 176 | ============== 177 | TestLine 178 | ============== 179 | */ 180 | qboolean _TestLine (vec3_t start, vec3_t stop) 181 | { 182 | int node; 183 | float front, back; 184 | tracestack_t *tstack_p; 185 | int side; 186 | float frontx,fronty, frontz, backx, backy, backz; 187 | tracestack_t tracestack[64]; 188 | tnode_t *tnode; 189 | 190 | frontx = start[0]; 191 | fronty = start[1]; 192 | frontz = start[2]; 193 | backx = stop[0]; 194 | backy = stop[1]; 195 | backz = stop[2]; 196 | 197 | tstack_p = tracestack; 198 | node = 0; 199 | 200 | while (1) 201 | { 202 | if (node == CONTENTS_SOLID) 203 | { 204 | #if 0 205 | float d1, d2, d3; 206 | 207 | d1 = backx - frontx; 208 | d2 = backy - fronty; 209 | d3 = backz - frontz; 210 | 211 | if (d1*d1 + d2*d2 + d3*d3 > 1) 212 | #endif 213 | return false; // DONE! 214 | } 215 | 216 | while (node < 0) 217 | { 218 | // pop up the stack for a back side 219 | tstack_p--; 220 | if (tstack_p < tracestack) 221 | return true; 222 | node = tstack_p->node; 223 | 224 | // set the hit point for this plane 225 | 226 | frontx = backx; 227 | fronty = backy; 228 | frontz = backz; 229 | 230 | // go down the back side 231 | 232 | backx = tstack_p->backpt[0]; 233 | backy = tstack_p->backpt[1]; 234 | backz = tstack_p->backpt[2]; 235 | 236 | node = tnodes[tstack_p->node].children[!tstack_p->side]; 237 | } 238 | 239 | tnode = &tnodes[node]; 240 | 241 | switch (tnode->type) 242 | { 243 | case PLANE_X: 244 | front = frontx - tnode->dist; 245 | back = backx - tnode->dist; 246 | break; 247 | case PLANE_Y: 248 | front = fronty - tnode->dist; 249 | back = backy - tnode->dist; 250 | break; 251 | case PLANE_Z: 252 | front = frontz - tnode->dist; 253 | back = backz - tnode->dist; 254 | break; 255 | default: 256 | front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist; 257 | back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist; 258 | break; 259 | } 260 | 261 | if (front > -ON_EPSILON && back > -ON_EPSILON) 262 | // if (front > 0 && back > 0) 263 | { 264 | node = tnode->children[0]; 265 | continue; 266 | } 267 | 268 | if (front < ON_EPSILON && back < ON_EPSILON) 269 | // if (front <= 0 && back <= 0) 270 | { 271 | node = tnode->children[1]; 272 | continue; 273 | } 274 | 275 | side = front < 0; 276 | 277 | front = front / (front-back); 278 | 279 | tstack_p->node = node; 280 | tstack_p->side = side; 281 | tstack_p->backpt[0] = backx; 282 | tstack_p->backpt[1] = backy; 283 | tstack_p->backpt[2] = backz; 284 | 285 | tstack_p++; 286 | 287 | backx = frontx + front*(backx-frontx); 288 | backy = fronty + front*(backy-fronty); 289 | backz = frontz + front*(backz-frontz); 290 | 291 | node = tnode->children[side]; 292 | } 293 | } 294 | 295 | 296 | -------------------------------------------------------------------------------- /src/common/threads.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "cmdlib.h" 24 | #include "threads.h" 25 | 26 | #define MAX_THREADS 64 27 | 28 | int dispatch; 29 | int workcount; 30 | int oldf; 31 | qboolean pacifier; 32 | 33 | qboolean threaded; 34 | 35 | /* 36 | ============= 37 | GetThreadWork 38 | 39 | ============= 40 | */ 41 | int GetThreadWork (void) 42 | { 43 | int r; 44 | int f; 45 | 46 | ThreadLock (); 47 | 48 | if (dispatch == workcount) 49 | { 50 | ThreadUnlock (); 51 | return -1; 52 | } 53 | 54 | f = 10*dispatch / workcount; 55 | if (f != oldf) 56 | { 57 | oldf = f; 58 | if (pacifier) 59 | printf ("%i...", f); 60 | } 61 | 62 | r = dispatch; 63 | dispatch++; 64 | ThreadUnlock (); 65 | 66 | return r; 67 | } 68 | 69 | 70 | void (*workfunction) (int); 71 | 72 | void ThreadWorkerFunction (int threadnum) 73 | { 74 | int work; 75 | 76 | while (1) 77 | { 78 | work = GetThreadWork (); 79 | if (work == -1) 80 | break; 81 | //printf ("thread %i, work %i\n", threadnum, work); 82 | workfunction(work); 83 | } 84 | } 85 | 86 | void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)) 87 | { 88 | if (numthreads == -1) 89 | ThreadSetDefault (); 90 | workfunction = func; 91 | RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); 92 | } 93 | 94 | 95 | /* 96 | =================================================================== 97 | 98 | WIN32 99 | 100 | =================================================================== 101 | */ 102 | #ifdef WIN32 103 | 104 | #define USED 105 | 106 | #include 107 | 108 | int numthreads = -1; 109 | CRITICAL_SECTION crit; 110 | static int enter; 111 | 112 | void ThreadSetDefault (void) 113 | { 114 | SYSTEM_INFO info; 115 | 116 | if (numthreads == -1) // not set manually 117 | { 118 | GetSystemInfo (&info); 119 | numthreads = info.dwNumberOfProcessors; 120 | if (numthreads < 1 || numthreads > 32) 121 | numthreads = 1; 122 | } 123 | 124 | qprintf ("%i threads\n", numthreads); 125 | } 126 | 127 | 128 | void ThreadLock (void) 129 | { 130 | if (!threaded) 131 | return; 132 | EnterCriticalSection (&crit); 133 | if (enter) 134 | Error ("Recursive ThreadLock\n"); 135 | enter = 1; 136 | } 137 | 138 | void ThreadUnlock (void) 139 | { 140 | if (!threaded) 141 | return; 142 | if (!enter) 143 | Error ("ThreadUnlock without lock\n"); 144 | enter = 0; 145 | LeaveCriticalSection (&crit); 146 | } 147 | 148 | /* 149 | ============= 150 | RunThreadsOn 151 | ============= 152 | */ 153 | void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) 154 | { 155 | int threadid[MAX_THREADS]; 156 | HANDLE threadhandle[MAX_THREADS]; 157 | int i; 158 | int start, end; 159 | 160 | start = I_FloatTime (); 161 | dispatch = 0; 162 | workcount = workcnt; 163 | oldf = -1; 164 | pacifier = showpacifier; 165 | threaded = true; 166 | 167 | // 168 | // run threads in parallel 169 | // 170 | InitializeCriticalSection (&crit); 171 | 172 | if (numthreads == 1) 173 | { // use same thread 174 | func (0); 175 | } 176 | else 177 | { 178 | for (i=0 ; i 226 | 227 | pthread_mutex_t *my_mutex; 228 | 229 | void ThreadLock (void) 230 | { 231 | if (my_mutex) 232 | pthread_mutex_lock (my_mutex); 233 | } 234 | 235 | void ThreadUnlock (void) 236 | { 237 | if (my_mutex) 238 | pthread_mutex_unlock (my_mutex); 239 | } 240 | 241 | 242 | /* 243 | ============= 244 | RunThreadsOn 245 | ============= 246 | */ 247 | void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) 248 | { 249 | int i; 250 | pthread_t work_threads[MAX_THREADS]; 251 | pthread_addr_t status; 252 | pthread_attr_t attrib; 253 | pthread_mutexattr_t mattrib; 254 | int start, end; 255 | 256 | start = I_FloatTime (); 257 | dispatch = 0; 258 | workcount = workcnt; 259 | oldf = -1; 260 | pacifier = showpacifier; 261 | threaded = true; 262 | 263 | if (pacifier) 264 | setbuf (stdout, NULL); 265 | 266 | if (!my_mutex) 267 | { 268 | my_mutex = malloc (sizeof(*my_mutex)); 269 | if (pthread_mutexattr_create (&mattrib) == -1) 270 | Error ("pthread_mutex_attr_create failed"); 271 | if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) 272 | Error ("pthread_mutexattr_setkind_np failed"); 273 | if (pthread_mutex_init (my_mutex, mattrib) == -1) 274 | Error ("pthread_mutex_init failed"); 275 | } 276 | 277 | if (pthread_attr_create (&attrib) == -1) 278 | Error ("pthread_attr_create failed"); 279 | if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) 280 | Error ("pthread_attr_setstacksize failed"); 281 | 282 | for (i=0 ; i 317 | #include 318 | #include 319 | #include 320 | 321 | 322 | int numthreads = -1; 323 | abilock_t lck; 324 | 325 | void ThreadSetDefault (void) 326 | { 327 | if (numthreads == -1) 328 | numthreads = prctl(PR_MAXPPROCS); 329 | printf ("%i threads\n", numthreads); 330 | //@@ 331 | usconfig (CONF_INITUSERS, numthreads); 332 | } 333 | 334 | 335 | void ThreadLock (void) 336 | { 337 | spin_lock (&lck); 338 | } 339 | 340 | void ThreadUnlock (void) 341 | { 342 | release_lock (&lck); 343 | } 344 | 345 | 346 | /* 347 | ============= 348 | RunThreadsOn 349 | ============= 350 | */ 351 | void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) 352 | { 353 | int i; 354 | int pid[MAX_THREADS]; 355 | int start, end; 356 | 357 | start = I_FloatTime (); 358 | dispatch = 0; 359 | workcount = workcnt; 360 | oldf = -1; 361 | pacifier = showpacifier; 362 | threaded = true; 363 | 364 | if (pacifier) 365 | setbuf (stdout, NULL); 366 | 367 | init_lock (&lck); 368 | 369 | for (i=0 ; iside hasn't been checked 154 | side_t *side; // NULL = non-visible 155 | face_t *face[2]; // output face in bsp file 156 | } portal_t; 157 | 158 | typedef struct 159 | { 160 | node_t *headnode; 161 | node_t outside_node; 162 | vec3_t mins, maxs; 163 | } tree_t; 164 | 165 | extern int entity_num; 166 | 167 | extern plane_t mapplanes[MAX_MAP_PLANES]; 168 | extern int nummapplanes; 169 | 170 | extern int nummapbrushes; 171 | extern mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; 172 | 173 | extern vec3_t map_mins, map_maxs; 174 | 175 | #define MAX_MAP_SIDES (MAX_MAP_BRUSHES*6) 176 | 177 | extern int nummapbrushsides; 178 | extern side_t brushsides[MAX_MAP_SIDES]; 179 | 180 | extern qboolean noprune; 181 | extern qboolean nodetail; 182 | extern qboolean fulldetail; 183 | extern qboolean nomerge; 184 | extern qboolean nosubdiv; 185 | extern qboolean nowater; 186 | extern qboolean noweld; 187 | extern qboolean noshare; 188 | extern qboolean notjunc; 189 | 190 | extern vec_t microvolume; 191 | 192 | extern char outbase[32]; 193 | 194 | extern char source[1024]; 195 | 196 | void LoadMapFile (char *filename); 197 | int FindFloatPlane (vec3_t normal, vec_t dist); 198 | 199 | //============================================================================= 200 | 201 | // textures.c 202 | 203 | typedef struct 204 | { 205 | char name[64]; 206 | int flags; 207 | int value; 208 | int contents; 209 | char animname[64]; 210 | } textureref_t; 211 | 212 | #define MAX_MAP_TEXTURES 1024 213 | 214 | extern textureref_t textureref[MAX_MAP_TEXTURES]; 215 | 216 | int FindMiptex (char *name); 217 | 218 | int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin); 219 | 220 | //============================================================================= 221 | 222 | void FindGCD (int *v); 223 | 224 | mapbrush_t *Brush_LoadEntity (entity_t *ent); 225 | int PlaneTypeForNormal (vec3_t normal); 226 | qboolean MakeBrushPlanes (mapbrush_t *b); 227 | int FindIntPlane (int *inormal, int *iorigin); 228 | void CreateBrush (int brushnum); 229 | 230 | 231 | //============================================================================= 232 | 233 | // draw.c 234 | 235 | extern vec3_t draw_mins, draw_maxs; 236 | extern qboolean drawflag; 237 | 238 | void Draw_ClearWindow (void); 239 | void DrawWinding (winding_t *w); 240 | 241 | void GLS_BeginScene (void); 242 | void GLS_Winding (winding_t *w, int code); 243 | void GLS_EndScene (void); 244 | 245 | //============================================================================= 246 | 247 | // csg 248 | 249 | bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, 250 | vec3_t clipmins, vec3_t clipmaxs); 251 | bspbrush_t *ChopBrushes (bspbrush_t *head); 252 | bspbrush_t *InitialBrushList (bspbrush_t *list); 253 | bspbrush_t *OptimizedBrushList (bspbrush_t *list); 254 | 255 | void WriteBrushMap (char *name, bspbrush_t *list); 256 | 257 | //============================================================================= 258 | 259 | // brushbsp 260 | 261 | void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis); 262 | 263 | bspbrush_t *CopyBrush (bspbrush_t *brush); 264 | 265 | void SplitBrush (bspbrush_t *brush, int planenum, 266 | bspbrush_t **front, bspbrush_t **back); 267 | 268 | tree_t *AllocTree (void); 269 | node_t *AllocNode (void); 270 | bspbrush_t *AllocBrush (int numsides); 271 | int CountBrushList (bspbrush_t *brushes); 272 | void FreeBrush (bspbrush_t *brushes); 273 | vec_t BrushVolume (bspbrush_t *brush); 274 | 275 | void BoundBrush (bspbrush_t *brush); 276 | void FreeBrushList (bspbrush_t *brushes); 277 | 278 | tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs); 279 | 280 | //============================================================================= 281 | 282 | // portals.c 283 | 284 | int VisibleContents (int contents); 285 | 286 | void MakeHeadnodePortals (tree_t *tree); 287 | void MakeNodePortal (node_t *node); 288 | void SplitNodePortals (node_t *node); 289 | 290 | qboolean Portal_VisFlood (portal_t *p); 291 | 292 | qboolean FloodEntities (tree_t *tree); 293 | void FillOutside (node_t *headnode); 294 | void FloodAreas (tree_t *tree); 295 | void MarkVisibleSides (tree_t *tree, int start, int end); 296 | void FreePortal (portal_t *p); 297 | void EmitAreaPortals (node_t *headnode); 298 | 299 | void MakeTreePortals (tree_t *tree); 300 | 301 | //============================================================================= 302 | 303 | // glfile.c 304 | 305 | void OutputWinding (winding_t *w, FILE *glview); 306 | void WriteGLView (tree_t *tree, char *source); 307 | 308 | //============================================================================= 309 | 310 | // leakfile.c 311 | 312 | void LeakFile (tree_t *tree); 313 | 314 | //============================================================================= 315 | 316 | // prtfile.c 317 | 318 | void WritePortalFile (tree_t *tree); 319 | 320 | //============================================================================= 321 | 322 | // writebsp.c 323 | 324 | void SetModelNumbers (void); 325 | void SetLightStyles (void); 326 | 327 | void BeginBSPFile (void); 328 | void WriteBSP (node_t *headnode); 329 | void EndBSPFile (void); 330 | void BeginModel (void); 331 | void EndModel (void); 332 | 333 | //============================================================================= 334 | 335 | // faces.c 336 | 337 | void MakeFaces (node_t *headnode); 338 | void FixTjuncs (node_t *headnode); 339 | int GetEdge2 (int v1, int v2, face_t *f); 340 | 341 | face_t *AllocFace (void); 342 | void FreeFace (face_t *f); 343 | 344 | void MergeNodeFaces (node_t *node); 345 | 346 | //============================================================================= 347 | 348 | // tree.c 349 | 350 | void FreeTree (tree_t *tree); 351 | void FreeTree_r (node_t *node); 352 | void PrintTree_r (node_t *node, int depth); 353 | void FreeTreePortals_r (node_t *node); 354 | void PruneNodes_r (node_t *node); 355 | void PruneNodes (node_t *node); 356 | -------------------------------------------------------------------------------- /src/qrad3/patches.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "qrad.h" 24 | 25 | vec3_t texture_reflectivity[MAX_MAP_TEXINFO]; 26 | 27 | /* 28 | =================================================================== 29 | 30 | TEXTURE LIGHT VALUES 31 | 32 | =================================================================== 33 | */ 34 | 35 | /* 36 | ====================== 37 | CalcTextureReflectivity 38 | ====================== 39 | */ 40 | void CalcTextureReflectivity (void) 41 | { 42 | int i; 43 | int j, k, texels; 44 | int color[3]; 45 | int texel; 46 | byte *palette; 47 | char path[1024]; 48 | float r, scale; 49 | miptex_t *mt; 50 | 51 | sprintf (path, "%spics/colormap.pcx", gamedir); 52 | 53 | // get the game palette 54 | Load256Image (path, NULL, &palette, NULL, NULL); 55 | 56 | // allways set index 0 even if no textures 57 | texture_reflectivity[0][0] = 0.5; 58 | texture_reflectivity[0][1] = 0.5; 59 | texture_reflectivity[0][2] = 0.5; 60 | 61 | for (i=0 ; iwidth)*LittleLong(mt->height); 86 | color[0] = color[1] = color[2] = 0; 87 | 88 | for (j=0 ; joffsets[0]) + j]; 91 | for (k=0 ; k<3 ; k++) 92 | color[k] += palette[texel*3+k]; 93 | } 94 | 95 | for (j=0 ; j<3 ; j++) 96 | { 97 | r = color[j]/texels/255.0; 98 | texture_reflectivity[i][j] = r; 99 | } 100 | // scale the reflectivity up, because the textures are 101 | // so dim 102 | scale = ColorNormalize (texture_reflectivity[i], 103 | texture_reflectivity[i]); 104 | if (scale < 0.5) 105 | { 106 | scale *= 2; 107 | VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]); 108 | } 109 | #if 0 110 | texture_reflectivity[i][0] = 0.5; 111 | texture_reflectivity[i][1] = 0.5; 112 | texture_reflectivity[i][2] = 0.5; 113 | #endif 114 | } 115 | } 116 | 117 | /* 118 | ======================================================================= 119 | 120 | MAKE FACES 121 | 122 | ======================================================================= 123 | */ 124 | 125 | /* 126 | ============= 127 | WindingFromFace 128 | ============= 129 | */ 130 | winding_t *WindingFromFace (dface_t *f) 131 | { 132 | int i; 133 | int se; 134 | dvertex_t *dv; 135 | int v; 136 | winding_t *w; 137 | 138 | w = AllocWinding (f->numedges); 139 | w->numpoints = f->numedges; 140 | 141 | for (i=0 ; inumedges ; i++) 142 | { 143 | se = dsurfedges[f->firstedge + i]; 144 | if (se < 0) 145 | v = dedges[-se].v[1]; 146 | else 147 | v = dedges[se].v[0]; 148 | 149 | dv = &dvertexes[v]; 150 | VectorCopy (dv->point, w->p[i]); 151 | } 152 | 153 | RemoveColinearPoints (w); 154 | 155 | return w; 156 | } 157 | 158 | /* 159 | ============= 160 | BaseLightForFace 161 | ============= 162 | */ 163 | void BaseLightForFace (dface_t *f, vec3_t color) 164 | { 165 | texinfo_t *tx; 166 | 167 | // 168 | // check for light emited by texture 169 | // 170 | tx = &texinfo[f->texinfo]; 171 | if (!(tx->flags & SURF_LIGHT) || tx->value == 0) 172 | { 173 | VectorClear (color); 174 | return; 175 | } 176 | 177 | VectorScale (texture_reflectivity[f->texinfo], tx->value, color); 178 | } 179 | 180 | qboolean IsSky (dface_t *f) 181 | { 182 | texinfo_t *tx; 183 | 184 | tx = &texinfo[f->texinfo]; 185 | if (tx->flags & SURF_SKY) 186 | return true; 187 | return false; 188 | } 189 | 190 | /* 191 | ============= 192 | MakePatchForFace 193 | ============= 194 | */ 195 | float totalarea; 196 | void MakePatchForFace (int fn, winding_t *w) 197 | { 198 | dface_t *f; 199 | float area; 200 | patch_t *patch; 201 | dplane_t *pl; 202 | int i; 203 | vec3_t color; 204 | dleaf_t *leaf; 205 | 206 | f = &dfaces[fn]; 207 | 208 | area = WindingArea (w); 209 | totalarea += area; 210 | 211 | patch = &patches[num_patches]; 212 | if (num_patches == MAX_PATCHES) 213 | Error ("num_patches == MAX_PATCHES"); 214 | patch->next = face_patches[fn]; 215 | face_patches[fn] = patch; 216 | 217 | patch->winding = w; 218 | 219 | if (f->side) 220 | patch->plane = &backplanes[f->planenum]; 221 | else 222 | patch->plane = &dplanes[f->planenum]; 223 | if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) 224 | { // origin offset faces must create new planes 225 | if (numplanes + fakeplanes >= MAX_MAP_PLANES) 226 | Error ("numplanes + fakeplanes >= MAX_MAP_PLANES"); 227 | pl = &dplanes[numplanes + fakeplanes]; 228 | fakeplanes++; 229 | 230 | *pl = *(patch->plane); 231 | pl->dist += DotProduct (face_offset[fn], pl->normal); 232 | patch->plane = pl; 233 | } 234 | 235 | WindingCenter (w, patch->origin); 236 | VectorAdd (patch->origin, patch->plane->normal, patch->origin); 237 | leaf = PointInLeaf(patch->origin); 238 | patch->cluster = leaf->cluster; 239 | if (patch->cluster == -1) 240 | qprintf ("patch->cluster == -1\n"); 241 | 242 | patch->area = area; 243 | if (patch->area <= 1) 244 | patch->area = 1; 245 | patch->sky = IsSky (f); 246 | 247 | VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity); 248 | 249 | // non-bmodel patches can emit light 250 | if (fn < dmodels[0].numfaces) 251 | { 252 | BaseLightForFace (f, patch->baselight); 253 | 254 | ColorNormalize (patch->reflectivity, color); 255 | 256 | for (i=0 ; i<3 ; i++) 257 | patch->baselight[i] *= color[i]; 258 | 259 | VectorCopy (patch->baselight, patch->totallight); 260 | } 261 | num_patches++; 262 | } 263 | 264 | 265 | entity_t *EntityForModel (int modnum) 266 | { 267 | int i; 268 | char *s; 269 | char name[16]; 270 | 271 | sprintf (name, "*%i", modnum); 272 | // search the entities for one using modnum 273 | for (i=0 ; inumfaces ; j++) 310 | { 311 | fn = mod->firstface + j; 312 | face_entity[fn] = ent; 313 | VectorCopy (origin, face_offset[fn]); 314 | f = &dfaces[fn]; 315 | w = WindingFromFace (f); 316 | for (k=0 ; knumpoints ; k++) 317 | { 318 | VectorAdd (w->p[k], origin, w->p[k]); 319 | } 320 | MakePatchForFace (fn, w); 321 | } 322 | } 323 | 324 | qprintf ("%i sqaure feet\n", (int)(totalarea/64)); 325 | } 326 | 327 | /* 328 | ======================================================================= 329 | 330 | SUBDIVIDE 331 | 332 | ======================================================================= 333 | */ 334 | 335 | void FinishSplit (patch_t *patch, patch_t *newp) 336 | { 337 | dleaf_t *leaf; 338 | 339 | VectorCopy (patch->baselight, newp->baselight); 340 | VectorCopy (patch->totallight, newp->totallight); 341 | VectorCopy (patch->reflectivity, newp->reflectivity); 342 | newp->plane = patch->plane; 343 | newp->sky = patch->sky; 344 | 345 | patch->area = WindingArea (patch->winding); 346 | newp->area = WindingArea (newp->winding); 347 | 348 | if (patch->area <= 1) 349 | patch->area = 1; 350 | if (newp->area <= 1) 351 | newp->area = 1; 352 | 353 | WindingCenter (patch->winding, patch->origin); 354 | VectorAdd (patch->origin, patch->plane->normal, patch->origin); 355 | leaf = PointInLeaf(patch->origin); 356 | patch->cluster = leaf->cluster; 357 | if (patch->cluster == -1) 358 | qprintf ("patch->cluster == -1\n"); 359 | 360 | WindingCenter (newp->winding, newp->origin); 361 | VectorAdd (newp->origin, newp->plane->normal, newp->origin); 362 | leaf = PointInLeaf(newp->origin); 363 | newp->cluster = leaf->cluster; 364 | if (newp->cluster == -1) 365 | qprintf ("patch->cluster == -1\n"); 366 | } 367 | 368 | /* 369 | ============= 370 | SubdividePatch 371 | 372 | Chops the patch only if its local bounds exceed the max size 373 | ============= 374 | */ 375 | void SubdividePatch (patch_t *patch) 376 | { 377 | winding_t *w, *o1, *o2; 378 | vec3_t mins, maxs, total; 379 | vec3_t split; 380 | vec_t dist; 381 | int i, j; 382 | vec_t v; 383 | patch_t *newp; 384 | 385 | w = patch->winding; 386 | mins[0] = mins[1] = mins[2] = 99999; 387 | maxs[0] = maxs[1] = maxs[2] = -99999; 388 | for (i=0 ; inumpoints ; i++) 389 | { 390 | for (j=0 ; j<3 ; j++) 391 | { 392 | v = w->p[i][j]; 393 | if (v < mins[j]) 394 | mins[j] = v; 395 | if (v > maxs[j]) 396 | maxs[j] = v; 397 | } 398 | } 399 | VectorSubtract (maxs, mins, total); 400 | for (i=0 ; i<3 ; i++) 401 | if (total[i] > (subdiv+1) ) 402 | break; 403 | if (i == 3) 404 | { 405 | // no splitting needed 406 | return; 407 | } 408 | 409 | // 410 | // split the winding 411 | // 412 | VectorCopy (vec3_origin, split); 413 | split[i] = 1; 414 | dist = (mins[i] + maxs[i])*0.5; 415 | ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); 416 | 417 | // 418 | // create a new patch 419 | // 420 | if (num_patches == MAX_PATCHES) 421 | Error ("MAX_PATCHES"); 422 | newp = &patches[num_patches]; 423 | num_patches++; 424 | 425 | newp->next = patch->next; 426 | patch->next = newp; 427 | 428 | patch->winding = o1; 429 | newp->winding = o2; 430 | 431 | FinishSplit (patch, newp); 432 | 433 | SubdividePatch (patch); 434 | SubdividePatch (newp); 435 | } 436 | 437 | 438 | /* 439 | ============= 440 | DicePatch 441 | 442 | Chops the patch by a global grid 443 | ============= 444 | */ 445 | void DicePatch (patch_t *patch) 446 | { 447 | winding_t *w, *o1, *o2; 448 | vec3_t mins, maxs; 449 | vec3_t split; 450 | vec_t dist; 451 | int i; 452 | patch_t *newp; 453 | 454 | w = patch->winding; 455 | WindingBounds (w, mins, maxs); 456 | for (i=0 ; i<3 ; i++) 457 | if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv)) 458 | break; 459 | if (i == 3) 460 | { 461 | // no splitting needed 462 | return; 463 | } 464 | 465 | // 466 | // split the winding 467 | // 468 | VectorCopy (vec3_origin, split); 469 | split[i] = 1; 470 | dist = subdiv*(1+floor((mins[i]+1)/subdiv)); 471 | ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); 472 | 473 | // 474 | // create a new patch 475 | // 476 | if (num_patches == MAX_PATCHES) 477 | Error ("MAX_PATCHES"); 478 | newp = &patches[num_patches]; 479 | num_patches++; 480 | 481 | newp->next = patch->next; 482 | patch->next = newp; 483 | 484 | patch->winding = o1; 485 | newp->winding = o2; 486 | 487 | FinishSplit (patch, newp); 488 | 489 | DicePatch (patch); 490 | DicePatch (newp); 491 | } 492 | 493 | 494 | /* 495 | ============= 496 | SubdividePatches 497 | ============= 498 | */ 499 | void SubdividePatches (void) 500 | { 501 | int i, num; 502 | 503 | if (subdiv < 1) 504 | return; 505 | 506 | num = num_patches; // because the list will grow 507 | for (i=0 ; i= sizeof(pf->name)) 119 | Error ("Filename too long for pak: %s", filename); 120 | 121 | len = LoadFile (source, (void **)&buf); 122 | 123 | if (g_compress_pak && len < 4096*1024 ) 124 | { 125 | cblock_t in, out; 126 | cblock_t Huffman (cblock_t in); 127 | 128 | in.count = len; 129 | in.data = buf; 130 | 131 | out = Huffman (in); 132 | 133 | if (out.count < in.count) 134 | { 135 | printf (" compressed from %i to %i\n", in.count, out.count); 136 | free (in.data); 137 | buf = out.data; 138 | len = out.count; 139 | } 140 | else 141 | free (out.data); 142 | } 143 | 144 | strcpy (pf->name, filename); 145 | pf->filepos = LittleLong(ftell(pakfile)); 146 | pf->filelen = LittleLong(len); 147 | pf++; 148 | 149 | SafeWrite (pakfile, buf, len); 150 | 151 | free (buf); 152 | } 153 | 154 | 155 | /* 156 | ============== 157 | FinishPak 158 | ============== 159 | */ 160 | void FinishPak (void) 161 | { 162 | int dirlen; 163 | int d; 164 | int i; 165 | unsigned checksum; 166 | 167 | if (!g_pak) 168 | return; 169 | 170 | pakheader.id[0] = 'P'; 171 | pakheader.id[1] = 'A'; 172 | pakheader.id[2] = 'C'; 173 | pakheader.id[3] = 'K'; 174 | dirlen = (byte *)pf - (byte *)pfiles; 175 | pakheader.dirofs = LittleLong(ftell(pakfile)); 176 | pakheader.dirlen = LittleLong(dirlen); 177 | 178 | checksum = Com_BlockChecksum ( (void *)pfiles, dirlen ); 179 | 180 | SafeWrite (pakfile, pfiles, dirlen); 181 | 182 | i = ftell (pakfile); 183 | 184 | fseek (pakfile, 0, SEEK_SET); 185 | SafeWrite (pakfile, &pakheader, sizeof(pakheader)); 186 | fclose (pakfile); 187 | 188 | d = pf - pfiles; 189 | printf ("%i files packed in %i bytes\n",d, i); 190 | printf ("checksum: 0x%x\n", checksum); 191 | } 192 | 193 | 194 | /* 195 | =============== 196 | Cmd_File 197 | 198 | This is only used to cause a file to be copied during a release 199 | build (default.cfg, maps, etc) 200 | =============== 201 | */ 202 | void Cmd_File (void) 203 | { 204 | GetToken (false); 205 | ReleaseFile (token); 206 | } 207 | 208 | /* 209 | =============== 210 | PackDirectory_r 211 | 212 | =============== 213 | */ 214 | #ifdef _WIN32 215 | #include "io.h" 216 | void PackDirectory_r (char *dir) 217 | { 218 | struct _finddata_t fileinfo; 219 | int handle; 220 | char dirstring[1024]; 221 | char filename[1024]; 222 | 223 | sprintf (dirstring, "%s%s/*.*", gamedir, dir); 224 | 225 | handle = _findfirst (dirstring, &fileinfo); 226 | if (handle == -1) 227 | return; 228 | 229 | do 230 | { 231 | sprintf (filename, "%s/%s", dir, fileinfo.name); 232 | if (fileinfo.attrib & _A_SUBDIR) 233 | { // directory 234 | if (fileinfo.name[0] != '.') // don't pak . and .. 235 | PackDirectory_r (filename); 236 | continue; 237 | } 238 | // copy or pack the file 239 | ReleaseFile (filename); 240 | } while (_findnext( handle, &fileinfo ) != -1); 241 | 242 | _findclose (handle); 243 | } 244 | #else 245 | 246 | #include 247 | #ifdef NeXT 248 | #include 249 | #else 250 | #include 251 | #endif 252 | 253 | void PackDirectory_r (char *dir) 254 | { 255 | #ifdef NeXT 256 | struct direct **namelist, *ent; 257 | #else 258 | struct dirent **namelist, *ent; 259 | #endif 260 | int count; 261 | struct stat st; 262 | int i; 263 | int len; 264 | char fullname[1024]; 265 | char dirstring[1024]; 266 | char *name; 267 | 268 | sprintf (dirstring, "%s%s", gamedir, dir); 269 | count = scandir(dirstring, &namelist, NULL, NULL); 270 | 271 | for (i=0 ; id_name; 275 | 276 | if (name[0] == '.') 277 | continue; 278 | 279 | sprintf (fullname, "%s/%s", dir, name); 280 | sprintf (dirstring, "%s%s/%s", gamedir, dir, name); 281 | 282 | if (stat (dirstring, &st) == -1) 283 | Error ("fstating %s", pf->name); 284 | if (st.st_mode & S_IFDIR) 285 | { // directory 286 | PackDirectory_r (fullname); 287 | continue; 288 | } 289 | 290 | // copy or pack the file 291 | ReleaseFile (fullname); 292 | } 293 | } 294 | #endif 295 | 296 | 297 | /* 298 | =============== 299 | Cmd_Dir 300 | 301 | This is only used to cause a directory to be copied during a 302 | release build (sounds, etc) 303 | =============== 304 | */ 305 | void Cmd_Dir (void) 306 | { 307 | GetToken (false); 308 | PackDirectory_r (token); 309 | } 310 | 311 | //======================================================================== 312 | 313 | #define MAX_RTEX 16384 314 | int numrtex; 315 | char rtex[MAX_RTEX][64]; 316 | 317 | void ReleaseTexture (char *name) 318 | { 319 | int i; 320 | char path[1024]; 321 | 322 | for (i=0 ; i= argc) 520 | Error ("usage: qgrab [-archive ] [-release ] [-only ] [-3ds] file.qgr"); 521 | 522 | if (do3ds) 523 | trifileext = ext_3ds; 524 | else 525 | trifileext = ext_tri; 526 | 527 | for ( ; iplanenum = PLANENUM_LEAF; 77 | node->contents = 0; //CONTENTS_SOLID; 78 | return node; 79 | } 80 | return node; 81 | } 82 | 83 | // create a seperator along the largest axis 84 | node = AllocNode (); 85 | 86 | if (xh - xl > yh - yl) 87 | { // split x axis 88 | mid = xl + (xh-xl)/2 + 1; 89 | normal[0] = 1; 90 | normal[1] = 0; 91 | normal[2] = 0; 92 | dist = mid*1024; 93 | node->planenum = FindFloatPlane (normal, dist); 94 | node->children[0] = BlockTree ( mid, yl, xh, yh); 95 | node->children[1] = BlockTree ( xl, yl, mid-1, yh); 96 | } 97 | else 98 | { 99 | mid = yl + (yh-yl)/2 + 1; 100 | normal[0] = 0; 101 | normal[1] = 1; 102 | normal[2] = 0; 103 | dist = mid*1024; 104 | node->planenum = FindFloatPlane (normal, dist); 105 | node->children[0] = BlockTree ( xl, mid, xh, yh); 106 | node->children[1] = BlockTree ( xl, yl, xh, mid-1); 107 | } 108 | 109 | return node; 110 | } 111 | 112 | /* 113 | ============ 114 | ProcessBlock_Thread 115 | 116 | ============ 117 | */ 118 | int brush_start, brush_end; 119 | void ProcessBlock_Thread (int blocknum) 120 | { 121 | int xblock, yblock; 122 | vec3_t mins, maxs; 123 | bspbrush_t *brushes; 124 | tree_t *tree; 125 | node_t *node; 126 | 127 | yblock = block_yl + blocknum / (block_xh-block_xl+1); 128 | xblock = block_xl + blocknum % (block_xh-block_xl+1); 129 | 130 | qprintf ("############### block %2i,%2i ###############\n", xblock, yblock); 131 | 132 | mins[0] = xblock*1024; 133 | mins[1] = yblock*1024; 134 | mins[2] = -4096; 135 | maxs[0] = (xblock+1)*1024; 136 | maxs[1] = (yblock+1)*1024; 137 | maxs[2] = 4096; 138 | 139 | // the makelist and chopbrushes could be cached between the passes... 140 | brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs); 141 | if (!brushes) 142 | { 143 | node = AllocNode (); 144 | node->planenum = PLANENUM_LEAF; 145 | node->contents = CONTENTS_SOLID; 146 | block_nodes[xblock+5][yblock+5] = node; 147 | return; 148 | } 149 | 150 | if (!nocsg) 151 | brushes = ChopBrushes (brushes); 152 | 153 | tree = BrushBSP (brushes, mins, maxs); 154 | 155 | block_nodes[xblock+5][yblock+5] = tree->headnode; 156 | } 157 | 158 | /* 159 | ============ 160 | ProcessWorldModel 161 | 162 | ============ 163 | */ 164 | void ProcessWorldModel (void) 165 | { 166 | entity_t *e; 167 | tree_t *tree; 168 | qboolean leaked; 169 | qboolean optimize; 170 | 171 | e = &entities[entity_num]; 172 | 173 | brush_start = e->firstbrush; 174 | brush_end = brush_start + e->numbrushes; 175 | leaked = false; 176 | 177 | // 178 | // perform per-block operations 179 | // 180 | if (block_xh * 1024 > map_maxs[0]) 181 | block_xh = floor(map_maxs[0]/1024.0); 182 | if ( (block_xl+1) * 1024 < map_mins[0]) 183 | block_xl = floor(map_mins[0]/1024.0); 184 | if (block_yh * 1024 > map_maxs[1]) 185 | block_yh = floor(map_maxs[1]/1024.0); 186 | if ( (block_yl+1) * 1024 < map_mins[1]) 187 | block_yl = floor(map_mins[1]/1024.0); 188 | 189 | if (block_xl <-4) 190 | block_xl = -4; 191 | if (block_yl <-4) 192 | block_yl = -4; 193 | if (block_xh > 3) 194 | block_xh = 3; 195 | if (block_yh > 3) 196 | block_yh = 3; 197 | 198 | for (optimize = false ; optimize <= true ; optimize++) 199 | { 200 | qprintf ("--------------------------------------------\n"); 201 | 202 | RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1), 203 | !verbose, ProcessBlock_Thread); 204 | 205 | // 206 | // build the division tree 207 | // oversizing the blocks guarantees that all the boundaries 208 | // will also get nodes. 209 | // 210 | 211 | qprintf ("--------------------------------------------\n"); 212 | 213 | tree = AllocTree (); 214 | tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1); 215 | 216 | tree->mins[0] = (block_xl)*1024; 217 | tree->mins[1] = (block_yl)*1024; 218 | tree->mins[2] = map_mins[2] - 8; 219 | 220 | tree->maxs[0] = (block_xh+1)*1024; 221 | tree->maxs[1] = (block_yh+1)*1024; 222 | tree->maxs[2] = map_maxs[2] + 8; 223 | 224 | // 225 | // perform the global operations 226 | // 227 | MakeTreePortals (tree); 228 | 229 | if (FloodEntities (tree)) 230 | FillOutside (tree->headnode); 231 | else 232 | { 233 | printf ("**** leaked ****\n"); 234 | leaked = true; 235 | LeakFile (tree); 236 | if (leaktest) 237 | { 238 | printf ("--- MAP LEAKED ---\n"); 239 | exit (0); 240 | } 241 | } 242 | 243 | MarkVisibleSides (tree, brush_start, brush_end); 244 | if (noopt || leaked) 245 | break; 246 | if (!optimize) 247 | { 248 | FreeTree (tree); 249 | } 250 | } 251 | 252 | FloodAreas (tree); 253 | if (glview) 254 | WriteGLView (tree, source); 255 | MakeFaces (tree->headnode); 256 | FixTjuncs (tree->headnode); 257 | 258 | if (!noprune) 259 | PruneNodes (tree->headnode); 260 | 261 | WriteBSP (tree->headnode); 262 | 263 | if (!leaked) 264 | WritePortalFile (tree); 265 | 266 | FreeTree (tree); 267 | } 268 | 269 | /* 270 | ============ 271 | ProcessSubModel 272 | 273 | ============ 274 | */ 275 | void ProcessSubModel (void) 276 | { 277 | entity_t *e; 278 | int start, end; 279 | tree_t *tree; 280 | bspbrush_t *list; 281 | vec3_t mins, maxs; 282 | 283 | e = &entities[entity_num]; 284 | 285 | start = e->firstbrush; 286 | end = start + e->numbrushes; 287 | 288 | mins[0] = mins[1] = mins[2] = -4096; 289 | maxs[0] = maxs[1] = maxs[2] = 4096; 290 | list = MakeBspBrushList (start, end, mins, maxs); 291 | if (!nocsg) 292 | list = ChopBrushes (list); 293 | tree = BrushBSP (list, mins, maxs); 294 | MakeTreePortals (tree); 295 | MarkVisibleSides (tree, start, end); 296 | MakeFaces (tree->headnode); 297 | FixTjuncs (tree->headnode); 298 | WriteBSP (tree->headnode); 299 | FreeTree (tree); 300 | } 301 | 302 | /* 303 | ============ 304 | ProcessModels 305 | ============ 306 | */ 307 | void ProcessModels (void) 308 | { 309 | BeginBSPFile (); 310 | 311 | for (entity_num=0 ; entity_num< num_entities ; entity_num++) 312 | { 313 | if (!entities[entity_num].numbrushes) 314 | continue; 315 | 316 | qprintf ("############### model %i ###############\n", nummodels); 317 | BeginModel (); 318 | if (entity_num == 0) 319 | ProcessWorldModel (); 320 | else 321 | ProcessSubModel (); 322 | EndModel (); 323 | 324 | if (!verboseentities) 325 | verbose = false; // don't bother printing submodels 326 | } 327 | 328 | EndBSPFile (); 329 | } 330 | 331 | 332 | /* 333 | ============ 334 | main 335 | ============ 336 | */ 337 | int main (int argc, char **argv) 338 | { 339 | int i; 340 | double start, end; 341 | char path[1024]; 342 | 343 | printf ("---- qbsp3 ----\n"); 344 | 345 | for (i=1 ; i 64k edges 420 | short numedges; 421 | short texinfo; 422 | 423 | // lighting info 424 | byte styles[MAXLIGHTMAPS]; 425 | int lightofs; // start of [numstyles*surfsize] samples 426 | } dface_t; 427 | 428 | typedef struct 429 | { 430 | int contents; // OR of all brushes (not needed?) 431 | 432 | short cluster; 433 | short area; 434 | 435 | short mins[3]; // for frustum culling 436 | short maxs[3]; 437 | 438 | unsigned short firstleafface; 439 | unsigned short numleaffaces; 440 | 441 | unsigned short firstleafbrush; 442 | unsigned short numleafbrushes; 443 | } dleaf_t; 444 | 445 | typedef struct 446 | { 447 | unsigned short planenum; // facing out of the leaf 448 | short texinfo; 449 | } dbrushside_t; 450 | 451 | typedef struct 452 | { 453 | int firstside; 454 | int numsides; 455 | int contents; 456 | } dbrush_t; 457 | 458 | #define ANGLE_UP -1 459 | #define ANGLE_DOWN -2 460 | 461 | 462 | // the visibility lump consists of a header with a count, then 463 | // byte offsets for the PVS and PHS of each cluster, then the raw 464 | // compressed bit vectors 465 | #define DVIS_PVS 0 466 | #define DVIS_PHS 1 467 | typedef struct 468 | { 469 | int numclusters; 470 | int bitofs[8][2]; // bitofs[numclusters][2] 471 | } dvis_t; 472 | 473 | // each area has a list of portals that lead into other areas 474 | // when portals are closed, other areas may not be visible or 475 | // hearable even if the vis info says that it should be 476 | typedef struct 477 | { 478 | int portalnum; 479 | int otherarea; 480 | } dareaportal_t; 481 | 482 | typedef struct 483 | { 484 | int numareaportals; 485 | int firstareaportal; 486 | } darea_t; 487 | -------------------------------------------------------------------------------- /src/qbsp3/writebsp.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | #include "qbsp.h" 23 | 24 | int c_nofaces; 25 | int c_facenodes; 26 | 27 | 28 | /* 29 | ========================================================= 30 | 31 | ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES 32 | 33 | ========================================================= 34 | */ 35 | 36 | int planeused[MAX_MAP_PLANES]; 37 | 38 | /* 39 | ============ 40 | EmitPlanes 41 | 42 | There is no oportunity to discard planes, because all of the original 43 | brushes will be saved in the map. 44 | ============ 45 | */ 46 | void EmitPlanes (void) 47 | { 48 | int i; 49 | dplane_t *dp; 50 | plane_t *mp; 51 | int planetranslate[MAX_MAP_PLANES]; 52 | 53 | mp = mapplanes; 54 | for (i=0 ; inormal, dp->normal); 59 | dp->dist = mp->dist; 60 | dp->type = mp->type; 61 | numplanes++; 62 | } 63 | } 64 | 65 | 66 | //======================================================== 67 | 68 | void EmitMarkFace (dleaf_t *leaf_p, face_t *f) 69 | { 70 | int i; 71 | int facenum; 72 | 73 | while (f->merged) 74 | f = f->merged; 75 | 76 | if (f->split[0]) 77 | { 78 | EmitMarkFace (leaf_p, f->split[0]); 79 | EmitMarkFace (leaf_p, f->split[1]); 80 | return; 81 | } 82 | 83 | facenum = f->outputnumber; 84 | if (facenum == -1) 85 | return; // degenerate face 86 | 87 | if (facenum < 0 || facenum >= numfaces) 88 | Error ("Bad leafface"); 89 | for (i=leaf_p->firstleafface ; i= MAX_MAP_LEAFFACES) 95 | Error ("MAX_MAP_LEAFFACES"); 96 | 97 | dleaffaces[numleaffaces] = facenum; 98 | numleaffaces++; 99 | } 100 | 101 | } 102 | 103 | 104 | /* 105 | ================== 106 | EmitLeaf 107 | ================== 108 | */ 109 | void EmitLeaf (node_t *node) 110 | { 111 | dleaf_t *leaf_p; 112 | portal_t *p; 113 | int s; 114 | face_t *f; 115 | bspbrush_t *b; 116 | int i; 117 | int brushnum; 118 | 119 | // emit a leaf 120 | if (numleafs >= MAX_MAP_LEAFS) 121 | Error ("MAX_MAP_LEAFS"); 122 | 123 | leaf_p = &dleafs[numleafs]; 124 | numleafs++; 125 | 126 | leaf_p->contents = node->contents; 127 | leaf_p->cluster = node->cluster; 128 | leaf_p->area = node->area; 129 | 130 | // 131 | // write bounding box info 132 | // 133 | VectorCopy (node->mins, leaf_p->mins); 134 | VectorCopy (node->maxs, leaf_p->maxs); 135 | 136 | // 137 | // write the leafbrushes 138 | // 139 | leaf_p->firstleafbrush = numleafbrushes; 140 | for (b=node->brushlist ; b ; b=b->next) 141 | { 142 | if (numleafbrushes >= MAX_MAP_LEAFBRUSHES) 143 | Error ("MAX_MAP_LEAFBRUSHES"); 144 | 145 | brushnum = b->original - mapbrushes; 146 | for (i=leaf_p->firstleafbrush ; inumleafbrushes = numleafbrushes - leaf_p->firstleafbrush; 156 | 157 | // 158 | // write the leaffaces 159 | // 160 | if (leaf_p->contents & CONTENTS_SOLID) 161 | return; // no leaffaces in solids 162 | 163 | leaf_p->firstleafface = numleaffaces; 164 | 165 | for (p = node->portals ; p ; p = p->next[s]) 166 | { 167 | s = (p->nodes[1] == node); 168 | f = p->face[s]; 169 | if (!f) 170 | continue; // not a visible portal 171 | 172 | EmitMarkFace (leaf_p, f); 173 | } 174 | 175 | leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface; 176 | } 177 | 178 | 179 | /* 180 | ================== 181 | EmitFace 182 | ================== 183 | */ 184 | void EmitFace (face_t *f) 185 | { 186 | dface_t *df; 187 | int i; 188 | int e; 189 | 190 | f->outputnumber = -1; 191 | 192 | if (f->numpoints < 3) 193 | { 194 | return; // degenerated 195 | } 196 | if (f->merged || f->split[0] || f->split[1]) 197 | { 198 | return; // not a final face 199 | } 200 | 201 | // save output number so leaffaces can use 202 | f->outputnumber = numfaces; 203 | 204 | if (numfaces >= MAX_MAP_FACES) 205 | Error ("numfaces == MAX_MAP_FACES"); 206 | df = &dfaces[numfaces]; 207 | numfaces++; 208 | 209 | // planenum is used by qlight, but not quake 210 | df->planenum = f->planenum & (~1); 211 | df->side = f->planenum & 1; 212 | 213 | df->firstedge = numsurfedges; 214 | df->numedges = f->numpoints; 215 | df->texinfo = f->texinfo; 216 | for (i=0 ; inumpoints ; i++) 217 | { 218 | // e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f); 219 | e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f); 220 | if (numsurfedges >= MAX_MAP_SURFEDGES) 221 | Error ("numsurfedges == MAX_MAP_SURFEDGES"); 222 | dsurfedges[numsurfedges] = e; 223 | numsurfedges++; 224 | } 225 | } 226 | 227 | /* 228 | ============ 229 | EmitDrawingNode_r 230 | ============ 231 | */ 232 | int EmitDrawNode_r (node_t *node) 233 | { 234 | dnode_t *n; 235 | face_t *f; 236 | int i; 237 | 238 | if (node->planenum == PLANENUM_LEAF) 239 | { 240 | EmitLeaf (node); 241 | return -numleafs; 242 | } 243 | 244 | // emit a node 245 | if (numnodes == MAX_MAP_NODES) 246 | Error ("MAX_MAP_NODES"); 247 | n = &dnodes[numnodes]; 248 | numnodes++; 249 | 250 | VectorCopy (node->mins, n->mins); 251 | VectorCopy (node->maxs, n->maxs); 252 | 253 | planeused[node->planenum]++; 254 | planeused[node->planenum^1]++; 255 | 256 | if (node->planenum & 1) 257 | Error ("WriteDrawNodes_r: odd planenum"); 258 | n->planenum = node->planenum; 259 | n->firstface = numfaces; 260 | 261 | if (!node->faces) 262 | c_nofaces++; 263 | else 264 | c_facenodes++; 265 | 266 | for (f=node->faces ; f ; f=f->next) 267 | EmitFace (f); 268 | 269 | n->numfaces = numfaces - n->firstface; 270 | 271 | 272 | // 273 | // recursively output the other nodes 274 | // 275 | for (i=0 ; i<2 ; i++) 276 | { 277 | if (node->children[i]->planenum == PLANENUM_LEAF) 278 | { 279 | n->children[i] = -(numleafs + 1); 280 | EmitLeaf (node->children[i]); 281 | } 282 | else 283 | { 284 | n->children[i] = numnodes; 285 | EmitDrawNode_r (node->children[i]); 286 | } 287 | } 288 | 289 | return n - dnodes; 290 | } 291 | 292 | //========================================================= 293 | 294 | 295 | /* 296 | ============ 297 | WriteBSP 298 | ============ 299 | */ 300 | void WriteBSP (node_t *headnode) 301 | { 302 | int oldfaces; 303 | 304 | c_nofaces = 0; 305 | c_facenodes = 0; 306 | 307 | qprintf ("--- WriteBSP ---\n"); 308 | 309 | oldfaces = numfaces; 310 | dmodels[nummodels].headnode = EmitDrawNode_r (headnode); 311 | EmitAreaPortals (headnode); 312 | 313 | qprintf ("%5i nodes with faces\n", c_facenodes); 314 | qprintf ("%5i nodes without faces\n", c_nofaces); 315 | qprintf ("%5i faces\n", numfaces-oldfaces); 316 | } 317 | 318 | //=========================================================== 319 | 320 | /* 321 | ============ 322 | SetModelNumbers 323 | ============ 324 | */ 325 | void SetModelNumbers (void) 326 | { 327 | int i; 328 | int models; 329 | char value[10]; 330 | 331 | models = 1; 332 | for (i=1 ; icontents = b->contents; 418 | db->firstside = numbrushsides; 419 | db->numsides = b->numsides; 420 | for (j=0 ; jnumsides ; j++) 421 | { 422 | if (numbrushsides == MAX_MAP_BRUSHSIDES) 423 | Error ("MAX_MAP_BRUSHSIDES"); 424 | cp = &dbrushsides[numbrushsides]; 425 | numbrushsides++; 426 | cp->planenum = b->original_sides[j].planenum; 427 | cp->texinfo = b->original_sides[j].texinfo; 428 | } 429 | 430 | // add any axis planes not contained in the brush to bevel off corners 431 | for (x=0 ; x<3 ; x++) 432 | for (s=-1 ; s<=1 ; s+=2) 433 | { 434 | // add the plane 435 | VectorCopy (vec3_origin, normal); 436 | normal[x] = s; 437 | if (s == -1) 438 | dist = -b->mins[x]; 439 | else 440 | dist = b->maxs[x]; 441 | planenum = FindFloatPlane (normal, dist); 442 | for (i=0 ; inumsides ; i++) 443 | if (b->original_sides[i].planenum == planenum) 444 | break; 445 | if (i == b->numsides) 446 | { 447 | if (numbrushsides >= MAX_MAP_BRUSHSIDES) 448 | Error ("MAX_MAP_BRUSHSIDES"); 449 | 450 | dbrushsides[numbrushsides].planenum = planenum; 451 | dbrushsides[numbrushsides].texinfo = 452 | dbrushsides[numbrushsides-1].texinfo; 453 | numbrushsides++; 454 | db->numsides++; 455 | } 456 | } 457 | 458 | } 459 | 460 | } 461 | 462 | //=========================================================== 463 | 464 | /* 465 | ================== 466 | BeginBSPFile 467 | ================== 468 | */ 469 | void BeginBSPFile (void) 470 | { 471 | // these values may actually be initialized 472 | // if the file existed when loaded, so clear them explicitly 473 | nummodels = 0; 474 | numfaces = 0; 475 | numnodes = 0; 476 | numbrushsides = 0; 477 | numvertexes = 0; 478 | numleaffaces = 0; 479 | numleafbrushes = 0; 480 | numsurfedges = 0; 481 | 482 | // edge 0 is not used, because 0 can't be negated 483 | numedges = 1; 484 | 485 | // leave vertex 0 as an error 486 | numvertexes = 1; 487 | 488 | // leave leaf 0 as an error 489 | numleafs = 1; 490 | dleafs[0].contents = CONTENTS_SOLID; 491 | } 492 | 493 | 494 | /* 495 | ============ 496 | EndBSPFile 497 | ============ 498 | */ 499 | void EndBSPFile (void) 500 | { 501 | char path[1024]; 502 | int len; 503 | byte *buf; 504 | 505 | 506 | EmitBrushes (); 507 | EmitPlanes (); 508 | UnparseEntities (); 509 | 510 | // load the pop 511 | #if 0 512 | sprintf (path, "%s/pics/pop.lmp", gamedir); 513 | len = LoadFile (path, &buf); 514 | memcpy (dpop, buf, sizeof(dpop)); 515 | free (buf); 516 | #endif 517 | 518 | // write the map 519 | sprintf (path, "%s.bsp", source); 520 | printf ("Writing %s\n", path); 521 | WriteBSPFile (path); 522 | } 523 | 524 | 525 | /* 526 | ================== 527 | BeginModel 528 | ================== 529 | */ 530 | int firstmodleaf; 531 | extern int firstmodeledge; 532 | extern int firstmodelface; 533 | void BeginModel (void) 534 | { 535 | dmodel_t *mod; 536 | int start, end; 537 | mapbrush_t *b; 538 | int j; 539 | entity_t *e; 540 | vec3_t mins, maxs; 541 | 542 | if (nummodels == MAX_MAP_MODELS) 543 | Error ("MAX_MAP_MODELS"); 544 | mod = &dmodels[nummodels]; 545 | 546 | mod->firstface = numfaces; 547 | 548 | firstmodleaf = numleafs; 549 | firstmodeledge = numedges; 550 | firstmodelface = numfaces; 551 | 552 | // 553 | // bound the brushes 554 | // 555 | e = &entities[entity_num]; 556 | 557 | start = e->firstbrush; 558 | end = start + e->numbrushes; 559 | ClearBounds (mins, maxs); 560 | 561 | for (j=start ; jnumsides) 565 | continue; // not a real brush (origin brush) 566 | AddPointToBounds (b->mins, mins, maxs); 567 | AddPointToBounds (b->maxs, mins, maxs); 568 | } 569 | 570 | VectorCopy (mins, mod->mins); 571 | VectorCopy (maxs, mod->maxs); 572 | } 573 | 574 | 575 | /* 576 | ================== 577 | EndModel 578 | ================== 579 | */ 580 | void EndModel (void) 581 | { 582 | dmodel_t *mod; 583 | 584 | mod = &dmodels[nummodels]; 585 | 586 | mod->numfaces = numfaces - mod->firstface; 587 | 588 | nummodels++; 589 | } 590 | 591 | -------------------------------------------------------------------------------- /src/common/polylib.c: -------------------------------------------------------------------------------- 1 | /* 2 | =========================================================================== 3 | Copyright (C) 1997-2006 Id Software, Inc. 4 | 5 | This file is part of Quake 2 Tools source code. 6 | 7 | Quake 2 Tools source code is free software; you can redistribute it 8 | and/or modify it under the terms of the GNU General Public License as 9 | published by the Free Software Foundation; either version 2 of the License, 10 | or (at your option) any later version. 11 | 12 | Quake 2 Tools source code is distributed in the hope that it will be 13 | useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with Quake 2 Tools source code; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | =========================================================================== 21 | */ 22 | 23 | #include "cmdlib.h" 24 | #include "mathlib.h" 25 | #include "polylib.h" 26 | 27 | 28 | extern int numthreads; 29 | 30 | // counters are only bumped when running single threaded, 31 | // because they are an awefull coherence problem 32 | int c_active_windings; 33 | int c_peak_windings; 34 | int c_winding_allocs; 35 | int c_winding_points; 36 | 37 | #define BOGUS_RANGE 8192 38 | 39 | void pw(winding_t *w) 40 | { 41 | int i; 42 | for (i=0 ; inumpoints ; i++) 43 | printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]); 44 | } 45 | 46 | 47 | /* 48 | ============= 49 | AllocWinding 50 | ============= 51 | */ 52 | winding_t *AllocWinding (int points) 53 | { 54 | winding_t *w; 55 | int s; 56 | 57 | if (numthreads == 1) 58 | { 59 | c_winding_allocs++; 60 | c_winding_points += points; 61 | c_active_windings++; 62 | if (c_active_windings > c_peak_windings) 63 | c_peak_windings = c_active_windings; 64 | } 65 | s = sizeof(vec_t)*3*points + sizeof(int); 66 | w = malloc (s); 67 | memset (w, 0, s); 68 | return w; 69 | } 70 | 71 | void FreeWinding (winding_t *w) 72 | { 73 | if (*(unsigned *)w == 0xdeaddead) 74 | Error ("FreeWinding: freed a freed winding"); 75 | *(unsigned *)w = 0xdeaddead; 76 | 77 | if (numthreads == 1) 78 | c_active_windings--; 79 | free (w); 80 | } 81 | 82 | /* 83 | ============ 84 | RemoveColinearPoints 85 | ============ 86 | */ 87 | int c_removed; 88 | 89 | void RemoveColinearPoints (winding_t *w) 90 | { 91 | int i, j, k; 92 | vec3_t v1, v2; 93 | int nump; 94 | vec3_t p[MAX_POINTS_ON_WINDING]; 95 | 96 | nump = 0; 97 | for (i=0 ; inumpoints ; i++) 98 | { 99 | j = (i+1)%w->numpoints; 100 | k = (i+w->numpoints-1)%w->numpoints; 101 | VectorSubtract (w->p[j], w->p[i], v1); 102 | VectorSubtract (w->p[i], w->p[k], v2); 103 | VectorNormalize(v1,v1); 104 | VectorNormalize(v2,v2); 105 | if (DotProduct(v1, v2) < 0.999) 106 | { 107 | VectorCopy (w->p[i], p[nump]); 108 | nump++; 109 | } 110 | } 111 | 112 | if (nump == w->numpoints) 113 | return; 114 | 115 | if (numthreads == 1) 116 | c_removed += w->numpoints - nump; 117 | w->numpoints = nump; 118 | memcpy (w->p, p, nump*sizeof(p[0])); 119 | } 120 | 121 | /* 122 | ============ 123 | WindingPlane 124 | ============ 125 | */ 126 | void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist) 127 | { 128 | vec3_t v1, v2; 129 | 130 | VectorSubtract (w->p[1], w->p[0], v1); 131 | VectorSubtract (w->p[2], w->p[0], v2); 132 | CrossProduct (v2, v1, normal); 133 | VectorNormalize (normal, normal); 134 | *dist = DotProduct (w->p[0], normal); 135 | 136 | } 137 | 138 | /* 139 | ============= 140 | WindingArea 141 | ============= 142 | */ 143 | vec_t WindingArea (winding_t *w) 144 | { 145 | int i; 146 | vec3_t d1, d2, cross; 147 | vec_t total; 148 | 149 | total = 0; 150 | for (i=2 ; inumpoints ; i++) 151 | { 152 | VectorSubtract (w->p[i-1], w->p[0], d1); 153 | VectorSubtract (w->p[i], w->p[0], d2); 154 | CrossProduct (d1, d2, cross); 155 | total += 0.5 * VectorLength ( cross ); 156 | } 157 | return total; 158 | } 159 | 160 | void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs) 161 | { 162 | vec_t v; 163 | int i,j; 164 | 165 | mins[0] = mins[1] = mins[2] = 99999; 166 | maxs[0] = maxs[1] = maxs[2] = -99999; 167 | 168 | for (i=0 ; inumpoints ; i++) 169 | { 170 | for (j=0 ; j<3 ; j++) 171 | { 172 | v = w->p[i][j]; 173 | if (v < mins[j]) 174 | mins[j] = v; 175 | if (v > maxs[j]) 176 | maxs[j] = v; 177 | } 178 | } 179 | } 180 | 181 | /* 182 | ============= 183 | WindingCenter 184 | ============= 185 | */ 186 | void WindingCenter (winding_t *w, vec3_t center) 187 | { 188 | int i; 189 | float scale; 190 | 191 | VectorCopy (vec3_origin, center); 192 | for (i=0 ; inumpoints ; i++) 193 | VectorAdd (w->p[i], center, center); 194 | 195 | scale = 1.0/w->numpoints; 196 | VectorScale (center, scale, center); 197 | } 198 | 199 | /* 200 | ================= 201 | BaseWindingForPlane 202 | ================= 203 | */ 204 | winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist) 205 | { 206 | int i, x; 207 | vec_t max, v; 208 | vec3_t org, vright, vup; 209 | winding_t *w; 210 | 211 | // find the major axis 212 | 213 | max = -BOGUS_RANGE; 214 | x = -1; 215 | for (i=0 ; i<3; i++) 216 | { 217 | v = fabs(normal[i]); 218 | if (v > max) 219 | { 220 | x = i; 221 | max = v; 222 | } 223 | } 224 | if (x==-1) 225 | Error ("BaseWindingForPlane: no axis found"); 226 | 227 | VectorCopy (vec3_origin, vup); 228 | switch (x) 229 | { 230 | case 0: 231 | case 1: 232 | vup[2] = 1; 233 | break; 234 | case 2: 235 | vup[0] = 1; 236 | break; 237 | } 238 | 239 | v = DotProduct (vup, normal); 240 | VectorMA (vup, -v, normal, vup); 241 | VectorNormalize (vup, vup); 242 | 243 | VectorScale (normal, dist, org); 244 | 245 | CrossProduct (vup, normal, vright); 246 | 247 | VectorScale (vup, 8192, vup); 248 | VectorScale (vright, 8192, vright); 249 | 250 | // project a really big axis aligned box onto the plane 251 | w = AllocWinding (4); 252 | 253 | VectorSubtract (org, vright, w->p[0]); 254 | VectorAdd (w->p[0], vup, w->p[0]); 255 | 256 | VectorAdd (org, vright, w->p[1]); 257 | VectorAdd (w->p[1], vup, w->p[1]); 258 | 259 | VectorAdd (org, vright, w->p[2]); 260 | VectorSubtract (w->p[2], vup, w->p[2]); 261 | 262 | VectorSubtract (org, vright, w->p[3]); 263 | VectorSubtract (w->p[3], vup, w->p[3]); 264 | 265 | w->numpoints = 4; 266 | 267 | return w; 268 | } 269 | 270 | /* 271 | ================== 272 | CopyWinding 273 | ================== 274 | */ 275 | winding_t *CopyWinding (winding_t *w) 276 | { 277 | int size; 278 | winding_t *c; 279 | 280 | c = AllocWinding (w->numpoints); 281 | size = (int)((winding_t *)0)->p[w->numpoints]; 282 | memcpy (c, w, size); 283 | return c; 284 | } 285 | 286 | /* 287 | ================== 288 | ReverseWinding 289 | ================== 290 | */ 291 | winding_t *ReverseWinding (winding_t *w) 292 | { 293 | int i; 294 | winding_t *c; 295 | 296 | c = AllocWinding (w->numpoints); 297 | for (i=0 ; inumpoints ; i++) 298 | { 299 | VectorCopy (w->p[w->numpoints-1-i], c->p[i]); 300 | } 301 | c->numpoints = w->numpoints; 302 | return c; 303 | } 304 | 305 | 306 | /* 307 | ============= 308 | ClipWindingEpsilon 309 | ============= 310 | */ 311 | void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, 312 | vec_t epsilon, winding_t **front, winding_t **back) 313 | { 314 | vec_t dists[MAX_POINTS_ON_WINDING+4]; 315 | int sides[MAX_POINTS_ON_WINDING+4]; 316 | int counts[3]; 317 | static vec_t dot; // VC 4.2 optimizer bug if not static 318 | int i, j; 319 | vec_t *p1, *p2; 320 | vec3_t mid; 321 | winding_t *f, *b; 322 | int maxpts; 323 | 324 | counts[0] = counts[1] = counts[2] = 0; 325 | 326 | // determine sides for each point 327 | for (i=0 ; inumpoints ; i++) 328 | { 329 | dot = DotProduct (in->p[i], normal); 330 | dot -= dist; 331 | dists[i] = dot; 332 | if (dot > epsilon) 333 | sides[i] = SIDE_FRONT; 334 | else if (dot < -epsilon) 335 | sides[i] = SIDE_BACK; 336 | else 337 | { 338 | sides[i] = SIDE_ON; 339 | } 340 | counts[sides[i]]++; 341 | } 342 | sides[i] = sides[0]; 343 | dists[i] = dists[0]; 344 | 345 | *front = *back = NULL; 346 | 347 | if (!counts[0]) 348 | { 349 | *back = CopyWinding (in); 350 | return; 351 | } 352 | if (!counts[1]) 353 | { 354 | *front = CopyWinding (in); 355 | return; 356 | } 357 | 358 | maxpts = in->numpoints+4; // cant use counts[0]+2 because 359 | // of fp grouping errors 360 | 361 | *front = f = AllocWinding (maxpts); 362 | *back = b = AllocWinding (maxpts); 363 | 364 | for (i=0 ; inumpoints ; i++) 365 | { 366 | p1 = in->p[i]; 367 | 368 | if (sides[i] == SIDE_ON) 369 | { 370 | VectorCopy (p1, f->p[f->numpoints]); 371 | f->numpoints++; 372 | VectorCopy (p1, b->p[b->numpoints]); 373 | b->numpoints++; 374 | continue; 375 | } 376 | 377 | if (sides[i] == SIDE_FRONT) 378 | { 379 | VectorCopy (p1, f->p[f->numpoints]); 380 | f->numpoints++; 381 | } 382 | if (sides[i] == SIDE_BACK) 383 | { 384 | VectorCopy (p1, b->p[b->numpoints]); 385 | b->numpoints++; 386 | } 387 | 388 | if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 389 | continue; 390 | 391 | // generate a split point 392 | p2 = in->p[(i+1)%in->numpoints]; 393 | 394 | dot = dists[i] / (dists[i]-dists[i+1]); 395 | for (j=0 ; j<3 ; j++) 396 | { // avoid round off error when possible 397 | if (normal[j] == 1) 398 | mid[j] = dist; 399 | else if (normal[j] == -1) 400 | mid[j] = -dist; 401 | else 402 | mid[j] = p1[j] + dot*(p2[j]-p1[j]); 403 | } 404 | 405 | VectorCopy (mid, f->p[f->numpoints]); 406 | f->numpoints++; 407 | VectorCopy (mid, b->p[b->numpoints]); 408 | b->numpoints++; 409 | } 410 | 411 | if (f->numpoints > maxpts || b->numpoints > maxpts) 412 | Error ("ClipWinding: points exceeded estimate"); 413 | if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) 414 | Error ("ClipWinding: MAX_POINTS_ON_WINDING"); 415 | } 416 | 417 | 418 | /* 419 | ============= 420 | ChopWindingInPlace 421 | ============= 422 | */ 423 | void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon) 424 | { 425 | winding_t *in; 426 | vec_t dists[MAX_POINTS_ON_WINDING+4]; 427 | int sides[MAX_POINTS_ON_WINDING+4]; 428 | int counts[3]; 429 | static vec_t dot; // VC 4.2 optimizer bug if not static 430 | int i, j; 431 | vec_t *p1, *p2; 432 | vec3_t mid; 433 | winding_t *f; 434 | int maxpts; 435 | 436 | in = *inout; 437 | counts[0] = counts[1] = counts[2] = 0; 438 | 439 | // determine sides for each point 440 | for (i=0 ; inumpoints ; i++) 441 | { 442 | dot = DotProduct (in->p[i], normal); 443 | dot -= dist; 444 | dists[i] = dot; 445 | if (dot > epsilon) 446 | sides[i] = SIDE_FRONT; 447 | else if (dot < -epsilon) 448 | sides[i] = SIDE_BACK; 449 | else 450 | { 451 | sides[i] = SIDE_ON; 452 | } 453 | counts[sides[i]]++; 454 | } 455 | sides[i] = sides[0]; 456 | dists[i] = dists[0]; 457 | 458 | if (!counts[0]) 459 | { 460 | FreeWinding (in); 461 | *inout = NULL; 462 | return; 463 | } 464 | if (!counts[1]) 465 | return; // inout stays the same 466 | 467 | maxpts = in->numpoints+4; // cant use counts[0]+2 because 468 | // of fp grouping errors 469 | 470 | f = AllocWinding (maxpts); 471 | 472 | for (i=0 ; inumpoints ; i++) 473 | { 474 | p1 = in->p[i]; 475 | 476 | if (sides[i] == SIDE_ON) 477 | { 478 | VectorCopy (p1, f->p[f->numpoints]); 479 | f->numpoints++; 480 | continue; 481 | } 482 | 483 | if (sides[i] == SIDE_FRONT) 484 | { 485 | VectorCopy (p1, f->p[f->numpoints]); 486 | f->numpoints++; 487 | } 488 | 489 | if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 490 | continue; 491 | 492 | // generate a split point 493 | p2 = in->p[(i+1)%in->numpoints]; 494 | 495 | dot = dists[i] / (dists[i]-dists[i+1]); 496 | for (j=0 ; j<3 ; j++) 497 | { // avoid round off error when possible 498 | if (normal[j] == 1) 499 | mid[j] = dist; 500 | else if (normal[j] == -1) 501 | mid[j] = -dist; 502 | else 503 | mid[j] = p1[j] + dot*(p2[j]-p1[j]); 504 | } 505 | 506 | VectorCopy (mid, f->p[f->numpoints]); 507 | f->numpoints++; 508 | } 509 | 510 | if (f->numpoints > maxpts) 511 | Error ("ClipWinding: points exceeded estimate"); 512 | if (f->numpoints > MAX_POINTS_ON_WINDING) 513 | Error ("ClipWinding: MAX_POINTS_ON_WINDING"); 514 | 515 | FreeWinding (in); 516 | *inout = f; 517 | } 518 | 519 | 520 | /* 521 | ================= 522 | ChopWinding 523 | 524 | Returns the fragment of in that is on the front side 525 | of the cliping plane. The original is freed. 526 | ================= 527 | */ 528 | winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) 529 | { 530 | winding_t *f, *b; 531 | 532 | ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b); 533 | FreeWinding (in); 534 | if (b) 535 | FreeWinding (b); 536 | return f; 537 | } 538 | 539 | 540 | /* 541 | ================= 542 | CheckWinding 543 | 544 | ================= 545 | */ 546 | void CheckWinding (winding_t *w) 547 | { 548 | int i, j; 549 | vec_t *p1, *p2; 550 | vec_t d, edgedist; 551 | vec3_t dir, edgenormal, facenormal; 552 | vec_t area; 553 | vec_t facedist; 554 | 555 | if (w->numpoints < 3) 556 | Error ("CheckWinding: %i points",w->numpoints); 557 | 558 | area = WindingArea(w); 559 | if (area < 1) 560 | Error ("CheckWinding: %f area", area); 561 | 562 | WindingPlane (w, facenormal, &facedist); 563 | 564 | for (i=0 ; inumpoints ; i++) 565 | { 566 | p1 = w->p[i]; 567 | 568 | for (j=0 ; j<3 ; j++) 569 | if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) 570 | Error ("CheckFace: BUGUS_RANGE: %f",p1[j]); 571 | 572 | j = i+1 == w->numpoints ? 0 : i+1; 573 | 574 | // check the point is on the face plane 575 | d = DotProduct (p1, facenormal) - facedist; 576 | if (d < -ON_EPSILON || d > ON_EPSILON) 577 | Error ("CheckWinding: point off plane"); 578 | 579 | // check the edge isnt degenerate 580 | p2 = w->p[j]; 581 | VectorSubtract (p2, p1, dir); 582 | 583 | if (VectorLength (dir) < ON_EPSILON) 584 | Error ("CheckWinding: degenerate edge"); 585 | 586 | CrossProduct (facenormal, dir, edgenormal); 587 | VectorNormalize (edgenormal, edgenormal); 588 | edgedist = DotProduct (p1, edgenormal); 589 | edgedist += ON_EPSILON; 590 | 591 | // all other points must be on front side 592 | for (j=0 ; jnumpoints ; j++) 593 | { 594 | if (j == i) 595 | continue; 596 | d = DotProduct (w->p[j], edgenormal); 597 | if (d > edgedist) 598 | Error ("CheckWinding: non-convex"); 599 | } 600 | } 601 | } 602 | 603 | 604 | /* 605 | ============ 606 | WindingOnPlaneSide 607 | ============ 608 | */ 609 | int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist) 610 | { 611 | qboolean front, back; 612 | int i; 613 | vec_t d; 614 | 615 | front = false; 616 | back = false; 617 | for (i=0 ; inumpoints ; i++) 618 | { 619 | d = DotProduct (w->p[i], normal) - dist; 620 | if (d < -ON_EPSILON) 621 | { 622 | if (front) 623 | return SIDE_CROSS; 624 | back = true; 625 | continue; 626 | } 627 | if (d > ON_EPSILON) 628 | { 629 | if (back) 630 | return SIDE_CROSS; 631 | front = true; 632 | continue; 633 | } 634 | } 635 | 636 | if (back) 637 | return SIDE_BACK; 638 | if (front) 639 | return SIDE_FRONT; 640 | return SIDE_ON; 641 | } 642 | 643 | --------------------------------------------------------------------------------