├── BSP ├── BSP.cbp ├── BSP.depend ├── BSP.layout ├── include │ └── bsp │ │ ├── bsp.hpp │ │ ├── common.hpp │ │ └── lumps.hpp ├── lib │ ├── libBSP.a │ └── libBSP_d.a ├── main.cpp ├── obj │ ├── Debug │ │ └── src │ │ │ ├── bsp.o │ │ │ └── lumps.o │ └── Release │ │ └── src │ │ ├── bsp.o │ │ └── lumps.o └── src │ ├── bsp.cpp │ └── lumps.cpp ├── bin ├── BSP Decompiler.exe ├── export.css ├── lua5.1.dll ├── lua51.dll └── settings.lua ├── license.txt ├── readme.txt └── src ├── BSP Decompiler.cbp ├── BSP Decompiler.depend ├── BSP Decompiler.layout ├── cod.cpp ├── cod.hpp ├── common.cpp ├── common.hpp ├── console.cpp ├── console.hpp ├── lumps.cpp ├── lumps.hpp ├── main.cpp ├── map.cpp ├── map.hpp ├── math.cpp ├── math.hpp ├── settings.cpp ├── settings.hpp ├── statistics.cpp └── statistics.hpp /BSP/BSP.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 51 | 52 | -------------------------------------------------------------------------------- /BSP/BSP.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1248725773 source:e:\projects\bsp\src\bsp.cpp 3 | 4 | 5 | 6 | 1239051954 source:e:\projects\bsp\src\lumps.cpp 7 | 8 | 1262134301 source:d:\projects\bsp\src\lumps.cpp 9 | "bsp/lumps.hpp" 10 | 11 | 1262096026 source:d:\projects\bsp\src\bsp.cpp 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /BSP/BSP.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BSP/include/bsp/bsp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BSP_BSP 2 | #define BSP_BSP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "common.hpp" 9 | #include "lumps.hpp" 10 | 11 | namespace BSP 12 | { 13 | class BSP; 14 | 15 | //////////////////////////////////////////////////////////////// 16 | 17 | class _Lump // base class, to allow heterogeneous arrays (of type Lump *) 18 | { 19 | public: 20 | virtual void *array() = 0; 21 | virtual unsigned int size() const = 0; 22 | 23 | virtual void read(char *i, unsigned int isize) = 0; 24 | virtual void write(FILE *output) const = 0; 25 | }; 26 | 27 | //////////////////////////////////////////////////////////////// 28 | 29 | template // T = parameter type 30 | class Lump: public _Lump // derived class, allows the use of any class (using templates) 31 | { 32 | public: 33 | Lump() : 34 | _array(NULL), 35 | _size(0) 36 | { 37 | } 38 | 39 | virtual ~Lump() 40 | { 41 | } 42 | 43 | void *array() 44 | { 45 | return _array; 46 | } 47 | 48 | unsigned int size() const 49 | { 50 | return _size; 51 | } 52 | 53 | //////////////// 54 | 55 | void read(char *i, unsigned int isize) 56 | { 57 | _size = (isize - (isize % sizeof(T))) / sizeof(T); 58 | _array = (T *) i; 59 | } 60 | 61 | void write(FILE *output) const 62 | { 63 | unsigned int n = 0; 64 | T *it; 65 | for (it = _array; it < _array + _size; it++) 66 | { 67 | fprintf(output, "[%6u] ", n); 68 | it->write(output); 69 | fprintf(output, "\r\n"); 70 | n++; 71 | } 72 | } 73 | 74 | //////////////// 75 | 76 | T *_array; 77 | unsigned int _size; 78 | }; 79 | 80 | //////////////////////////////////////////////////////////////// 81 | 82 | class BSP_Handle 83 | { 84 | public: 85 | BSP_Handle(std::string filename); 86 | ~BSP_Handle(); 87 | 88 | private: 89 | void cod1(); 90 | void cod2(); 91 | void cod4(); 92 | void cod5(); 93 | 94 | void read(); 95 | 96 | public: 97 | template 98 | T *array(LumpReference reference) 99 | { 100 | if (exists(reference) && size(reference)) 101 | { 102 | return (T *) lumps[reference]->array(); 103 | } 104 | else 105 | { 106 | fprintf(stderr, "ERROR: Lump reference `%u' does not exist.\n", reference); 107 | return NULL; 108 | } 109 | } 110 | 111 | unsigned int size(LumpReference reference); 112 | 113 | bool exists(LumpReference reference); 114 | void write(FILE *output, LumpReference reference); 115 | 116 | std::map lumps; // holds Lump instance which will parse the lump according to the struct passed 117 | std::map lump_reference; // each different lump in any game has a reference ID 118 | 119 | std::string map; 120 | int cod_version; 121 | int cod_size; 122 | 123 | Data data; 124 | char *i; 125 | 126 | std::vector index; 127 | 128 | bool success; 129 | }; 130 | 131 | //////////////////////////////////////////////////////////////// 132 | } 133 | 134 | #endif // BSP_BSP 135 | -------------------------------------------------------------------------------- /BSP/include/bsp/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BSP_HEADER 2 | #define BSP_HEADER 3 | 4 | #define COD1_VERSION 59 5 | #define COD2_VERSION 4 6 | #define COD4_VERSION 22 7 | #define COD5_VERSION 31 8 | 9 | namespace BSP 10 | { 11 | //////////////////////////////////////////////////////////////// 12 | 13 | // doesn't correspond as how it's stored in the BSP 14 | struct Index 15 | { 16 | unsigned int id; 17 | unsigned int offset; 18 | unsigned int size; 19 | 20 | Index(unsigned int id = 0, unsigned int offset = 0, unsigned int size = 0) : 21 | id(id), 22 | offset(offset), 23 | size(size) 24 | {} 25 | }; 26 | 27 | //////////////////////////////////////////////////////////////// 28 | 29 | union DoubleWord 30 | { 31 | unsigned char b[4]; 32 | unsigned short s[2]; 33 | int i; 34 | unsigned int u, x; 35 | float f, g; 36 | 37 | DoubleWord() 38 | { 39 | b[0] = 0; 40 | b[1] = 0; 41 | b[2] = 0; 42 | b[3] = 0; 43 | 44 | s[0] = 0; 45 | s[1] = 0; 46 | } 47 | }; 48 | 49 | struct Data 50 | { 51 | char *buffer; 52 | size_t size; 53 | 54 | Data(char *buffer = NULL, size_t size = 0) : buffer(buffer), size(size) {} 55 | }; 56 | 57 | //////////////////////////////////////////////////////////////// 58 | } 59 | 60 | #endif // BSP_HEADER 61 | -------------------------------------------------------------------------------- /BSP/include/bsp/lumps.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BSP_LUMPS 2 | #define BSP_LUMPS 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #undef PLANES 9 | 10 | namespace BSP 11 | { 12 | //////////////////////////////////////////////////////////////// 13 | 14 | extern const char *LumpName[]; 15 | 16 | //////////////////////////////////////////////////////////////// 17 | 18 | enum LumpReference 19 | { 20 | // cod1 21 | UNKNOWN, 22 | MATERIALS, 23 | LIGHTMAPS, 24 | LIGHTGRIDHASH, 25 | LIGHTGRIDVALUES, 26 | PLANES, 27 | BRUSHSIDES, 28 | BRUSHES, 29 | TRIANGLESOUPS, 30 | DRAWVERTICES, 31 | DRAWINDICES, 32 | CULLGROUPS, 33 | CULLGROUPINDICES, 34 | UNKNOWN12, 35 | UNKNOWN13, 36 | UNKNOWN14, 37 | UNKNOWN15, 38 | UNKNOWN16, 39 | PORTALVERTICES, 40 | OCCLUDER, 41 | OCCLUDERPLANES, 42 | OCCLUDEREDGES, 43 | OCCLUDERINDICES, 44 | AABBTREES, 45 | CELLS, 46 | PORTALS, 47 | NODES, 48 | LEAVES, 49 | LEAFBRUSHES, 50 | UNKNOWN28, 51 | COLLISIONVERTICES, 52 | COLLISIONEDGES, 53 | COLLISIONTRIANGLES, 54 | COLLISIONBORDERS, 55 | COLLISIONPARTS, 56 | COLLISIONAABBS, 57 | MODELS, 58 | VISIBILITY, 59 | ENTITIES, 60 | 61 | // cod4 62 | LIGHTGRIDPONTS, 63 | LIGHTGRIDCOLOURS, 64 | LAYEREDTRIANGLESOUPS, 65 | LAYEREDDRAWVERTICES, 66 | LAYEREDDRAWINDICES, 67 | LAYEREDAABBTREES, 68 | PATHS, 69 | REFLECTIONPROBES, 70 | LAYEREDDATA, 71 | PRIMARYLIGHTS, 72 | LIGHTGRIDHEADER, 73 | LIGHTGRIDROWS, 74 | SIMPLETRIANGLESOUPS, 75 | SIMPLEVERTICES, 76 | SIMPLEINDICES, 77 | SIMPLEAABBTREES, 78 | LIGHTREGIONS, 79 | LIGHTREGIONHULLS, 80 | LIGHTREGIONAXES 81 | }; 82 | 83 | //////////////////////////////////////////////////////////////// 84 | 85 | struct Material 86 | { 87 | char name[64]; 88 | unsigned int flags[2]; 89 | 90 | void write(FILE *output) const; 91 | }; 92 | 93 | struct Plane 94 | { 95 | float normal[3]; 96 | float distance; 97 | 98 | void write(FILE *output) const; 99 | }; 100 | 101 | struct Brushside 102 | { 103 | union Column1 104 | { 105 | unsigned int plane; 106 | float distance; 107 | } column1; 108 | 109 | unsigned int material_id; 110 | 111 | void write(FILE *output) const; 112 | }; 113 | 114 | struct Brush 115 | { 116 | unsigned short sides; 117 | unsigned short material_id; 118 | 119 | void write(FILE *output) const; 120 | }; 121 | 122 | struct TriangleSoup 123 | { 124 | unsigned short material_id; 125 | unsigned short draw_order; 126 | 127 | unsigned int vertex_offset; 128 | unsigned short vertex_length; 129 | 130 | unsigned short triangle_length; 131 | unsigned int triangle_offset; 132 | 133 | void write(FILE *output) const; 134 | }; 135 | 136 | /*struct DrawVertex 137 | { 138 | float position[3]; 139 | float normal[3]; 140 | 141 | unsigned int rgba; 142 | 143 | virtual void write(FILE *output) const = 0; 144 | };*/ 145 | 146 | struct DrawVertex1 147 | { 148 | float position[3]; 149 | float normal[3]; 150 | 151 | unsigned int rgba; 152 | 153 | float unknown[4]; 154 | 155 | void write(FILE *output) const; 156 | }; 157 | 158 | struct DrawVertex2 159 | { 160 | float position[3]; 161 | float normal[3]; 162 | 163 | unsigned int rgba; 164 | 165 | float uv[2]; 166 | float st[2]; 167 | 168 | float unknown[6]; 169 | 170 | void write(FILE *output) const; 171 | }; 172 | 173 | struct DrawIndex 174 | { 175 | unsigned short vertex[3]; 176 | 177 | void write(FILE *output) const; 178 | }; 179 | 180 | struct PortalVertex 181 | { 182 | float unknown[3]; 183 | 184 | void write(FILE *output) const; 185 | }; 186 | 187 | struct AABBTree 188 | { 189 | unsigned int unknown[3]; 190 | 191 | void write(FILE *output) const; 192 | }; 193 | 194 | struct Cell 195 | { 196 | float unknown[3]; 197 | 198 | void write(FILE *output) const; 199 | }; 200 | 201 | struct Portal 202 | { 203 | unsigned int unknown[4]; 204 | 205 | void write(FILE *output) const; 206 | }; 207 | 208 | struct Node 209 | { 210 | int unknown[9]; 211 | 212 | void write(FILE *output) const; 213 | }; 214 | 215 | struct Leaf 216 | { 217 | int unknown[9]; 218 | 219 | void write(FILE *output) const; 220 | }; 221 | 222 | struct LeafBrush 223 | { 224 | int unknown; 225 | 226 | void write(FILE *output) const; 227 | }; 228 | 229 | struct CollisionVertex 230 | { 231 | float unknown; 232 | float position[3]; 233 | 234 | void write(FILE *output) const; 235 | }; 236 | 237 | struct CollisionEdge 238 | { 239 | unsigned int unknown; 240 | 241 | float position[3]; 242 | float normal[3][3]; 243 | float distance; 244 | 245 | void write(FILE *output) const; 246 | }; 247 | 248 | struct CollisionTriangle 249 | { 250 | float normal[3]; 251 | float distance; 252 | float unknown[8]; 253 | unsigned int vertex_id[3]; 254 | int edge_id[3]; 255 | 256 | void write(FILE *output) const; 257 | }; 258 | 259 | struct CollisionBorder 260 | { 261 | float unknown[7]; 262 | 263 | void write(FILE *output) const; 264 | }; 265 | 266 | struct CollisionPart 267 | { 268 | short unknown[6]; 269 | 270 | void write(FILE *output) const; 271 | }; 272 | 273 | struct CollisionAABB 274 | { 275 | float unknown[6]; 276 | unsigned short unknown2[4]; 277 | 278 | void write(FILE *output) const; 279 | }; 280 | 281 | struct Model 282 | { 283 | float position[2][3]; 284 | 285 | unsigned int trianglesoups_offset; 286 | unsigned int trianglesoups_size; 287 | unsigned int collisionaabbs_offset; 288 | unsigned int collisionaabbs_size; 289 | unsigned int brushes_offset; 290 | unsigned int brushes_size; 291 | 292 | void write(FILE *output) const; 293 | }; 294 | 295 | struct Entity 296 | { 297 | std::map pairs; 298 | 299 | void write(FILE *output) const; 300 | }; 301 | 302 | //////////////////////////////////////////////////////////////// 303 | } 304 | 305 | #endif // BSP_LUMPS 306 | -------------------------------------------------------------------------------- /BSP/lib/libBSP.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/BSP/lib/libBSP.a -------------------------------------------------------------------------------- /BSP/lib/libBSP_d.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/BSP/lib/libBSP_d.a -------------------------------------------------------------------------------- /BSP/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() 6 | { 7 | cout << "Hello world!" << endl; 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /BSP/obj/Debug/src/bsp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/BSP/obj/Debug/src/bsp.o -------------------------------------------------------------------------------- /BSP/obj/Debug/src/lumps.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/BSP/obj/Debug/src/lumps.o -------------------------------------------------------------------------------- /BSP/obj/Release/src/bsp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/BSP/obj/Release/src/bsp.o -------------------------------------------------------------------------------- /BSP/obj/Release/src/lumps.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/BSP/obj/Release/src/lumps.o -------------------------------------------------------------------------------- /BSP/src/bsp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace BSP 5 | { 6 | BSP_Handle *bsp; 7 | 8 | //////////////////////////////////////////////////////////////// 9 | 10 | BSP_Handle::BSP_Handle(std::string filename) : 11 | cod_version(0), 12 | cod_size(0), 13 | success(false) 14 | { 15 | bsp = this; 16 | map = filename.substr(filename.find_last_of("/\\") + 1); 17 | 18 | // opening input file 19 | FILE *input; 20 | input = fopen(filename.c_str(), "rb+"); 21 | if (!input) 22 | { 23 | printf("ERROR: Could not open input BSP file `%s'.\n", filename.c_str()); 24 | return; 25 | } 26 | 27 | // reading input file 28 | fseek(input, 0, SEEK_END); 29 | data = Data(new char[ftell(input)], ftell(input)); 30 | fseek(input, 0, SEEK_SET); 31 | 32 | if (fread(data.buffer, 1, data.size, input) != data.size) 33 | { 34 | printf("ERROR: Could not read BSP file `%s'.\n", filename.c_str()); 35 | delete[] data.buffer; 36 | data.buffer = NULL; 37 | fclose(input); 38 | return; 39 | } 40 | fclose(input); 41 | 42 | // checking file format 43 | if (data.size < 9 || data.buffer[0] != 'I' || data.buffer[1] != 'B' || data.buffer[2] != 'S' || data.buffer[3] != 'P') 44 | { 45 | printf("ERROR: The BSP's file format is unsupported.\n"); 46 | delete[] data.buffer; 47 | data.buffer = NULL; 48 | return; 49 | } 50 | 51 | // initialising data access variable 52 | i = data.buffer; 53 | i += 4; 54 | 55 | // version check 56 | DoubleWord version; 57 | version.b[0] = *i; i++; 58 | version.b[1] = *i; i++; 59 | version.b[2] = *i; i++; 60 | version.b[3] = *i; i++; 61 | 62 | // check if this is CoD1, CoD2, ... 63 | switch (version.u) 64 | { 65 | case COD1_VERSION: 66 | { 67 | cod1(); 68 | break; 69 | } 70 | case COD2_VERSION: 71 | { 72 | cod2(); 73 | break; 74 | } 75 | case COD4_VERSION: 76 | { 77 | cod4(); 78 | break; 79 | } 80 | case COD5_VERSION: 81 | { 82 | cod5(); 83 | break; 84 | } 85 | default: 86 | { 87 | printf("ERROR: The BSP's file version is unsupported.\n"); 88 | delete[] data.buffer; 89 | data.buffer = NULL; 90 | return; 91 | } 92 | } 93 | 94 | read(); 95 | } 96 | 97 | BSP_Handle::~BSP_Handle() 98 | { 99 | delete[] data.buffer; 100 | 101 | std::map::iterator it; 102 | for (it = lumps.begin(); it != lumps.end(); it++) 103 | { 104 | delete (*it).second; 105 | } 106 | } 107 | 108 | void BSP_Handle::cod1() 109 | { 110 | cod_version = 1; 111 | cod_size = 33; 112 | 113 | lump_reference[ 0] = MATERIALS; 114 | lump_reference[ 2] = PLANES; 115 | lump_reference[ 3] = BRUSHSIDES; 116 | lump_reference[ 4] = BRUSHES; 117 | lump_reference[ 6] = TRIANGLESOUPS; 118 | lump_reference[ 7] = DRAWVERTICES; 119 | lump_reference[ 8] = DRAWINDICES; 120 | /*lump_reference[11] = PORTALVERTICES; 121 | lump_reference[16] = AABBTREES; 122 | lump_reference[17] = CELLS; 123 | lump_reference[18] = PORTALS; 124 | lump_reference[20] = NODES; 125 | lump_reference[21] = LEAVES; 126 | lump_reference[22] = LEAFBRUSHES; 127 | //lump_reference[29] = COLLISIONVERTICES; 128 | //lump_reference[30] = COLLISIONEDGES; 129 | //lump_reference[31] = COLLISIONTRIANGLES; 130 | //lump_reference[32] = COLLISIONBORDERS; 131 | //lump_reference[33] = COLLISIONPARTS; 132 | //lump_reference[34] = COLLISIONAABBS;*/ 133 | lump_reference[27] = MODELS; 134 | lump_reference[29] = ENTITIES; 135 | 136 | lumps[MATERIALS] = new Lump; 137 | lumps[PLANES] = new Lump; 138 | lumps[BRUSHSIDES] = new Lump; 139 | lumps[BRUSHES] = new Lump; 140 | lumps[TRIANGLESOUPS] = new Lump; 141 | lumps[DRAWVERTICES] = new Lump; 142 | lumps[DRAWINDICES] = new Lump; 143 | /*lumps[PORTALVERTICES] = new Lump; 144 | lumps[AABBTREES] = new Lump; 145 | lumps[CELLS] = new Lump; 146 | lumps[PORTALS] = new Lump; 147 | lumps[NODES] = new Lump; 148 | lumps[LEAVES] = new Lump; 149 | lumps[LEAFBRUSHES] = new Lump; 150 | //lumps[COLLISIONVERTICES] = new Lump; 151 | //lumps[COLLISIONEDGES] = new Lump; 152 | //lumps[COLLISIONTRIANGLES] = new Lump; 153 | //lumps[COLLISIONBORDERS] = new Lump; 154 | //lumps[COLLISIONPARTS] = new Lump; 155 | //lumps[COLLISIONAABBS] = new Lump;*/ 156 | lumps[MODELS] = new Lump; 157 | lumps[ENTITIES] = new Lump; 158 | } 159 | 160 | void BSP_Handle::cod2() 161 | { 162 | cod_version = 2; 163 | cod_size = -1; 164 | 165 | lump_reference[ 0] = MATERIALS; 166 | lump_reference[ 4] = PLANES; 167 | lump_reference[ 5] = BRUSHSIDES; 168 | lump_reference[ 6] = BRUSHES; 169 | lump_reference[ 7] = TRIANGLESOUPS; 170 | lump_reference[ 8] = DRAWVERTICES; 171 | lump_reference[ 9] = DRAWINDICES; 172 | lump_reference[17] = PORTALVERTICES; 173 | lump_reference[22] = AABBTREES; 174 | lump_reference[23] = CELLS; 175 | lump_reference[24] = PORTALS; 176 | lump_reference[25] = NODES; 177 | lump_reference[26] = LEAVES; 178 | lump_reference[27] = LEAFBRUSHES; 179 | lump_reference[29] = COLLISIONVERTICES; 180 | lump_reference[30] = COLLISIONEDGES; 181 | lump_reference[31] = COLLISIONTRIANGLES; 182 | lump_reference[32] = COLLISIONBORDERS; 183 | lump_reference[33] = COLLISIONPARTS; 184 | lump_reference[34] = COLLISIONAABBS; 185 | lump_reference[35] = MODELS; 186 | lump_reference[37] = ENTITIES; 187 | 188 | lumps[MATERIALS] = new Lump; 189 | lumps[PLANES] = new Lump; 190 | lumps[BRUSHSIDES] = new Lump; 191 | lumps[BRUSHES] = new Lump; 192 | lumps[TRIANGLESOUPS] = new Lump; 193 | lumps[DRAWVERTICES] = new Lump; 194 | lumps[DRAWINDICES] = new Lump; 195 | lumps[PORTALVERTICES] = new Lump; 196 | lumps[AABBTREES] = new Lump; 197 | lumps[CELLS] = new Lump; 198 | lumps[PORTALS] = new Lump; 199 | lumps[NODES] = new Lump; 200 | lumps[LEAVES] = new Lump; 201 | lumps[LEAFBRUSHES] = new Lump; 202 | lumps[COLLISIONVERTICES] = new Lump; 203 | lumps[COLLISIONEDGES] = new Lump; 204 | lumps[COLLISIONTRIANGLES] = new Lump; 205 | lumps[COLLISIONBORDERS] = new Lump; 206 | lumps[COLLISIONPARTS] = new Lump; 207 | lumps[COLLISIONAABBS] = new Lump; 208 | lumps[MODELS] = new Lump; 209 | lumps[ENTITIES] = new Lump; 210 | } 211 | 212 | void BSP_Handle::cod4() 213 | { 214 | cod_version = 4; 215 | 216 | DoubleWord size; 217 | size.b[0] = *i; i++; 218 | size.b[1] = *i; i++; 219 | size.b[2] = *i; i++; 220 | size.b[3] = *i; i++; 221 | 222 | cod_size = size.i; 223 | 224 | lump_reference[ 0] = MATERIALS; 225 | lump_reference[ 1] = LIGHTMAPS; 226 | lump_reference[ 2] = LIGHTGRIDPONTS; 227 | lump_reference[ 3] = LIGHTGRIDCOLOURS; 228 | lump_reference[ 4] = PLANES; 229 | lump_reference[ 5] = BRUSHSIDES; 230 | lump_reference[ 6] = UNKNOWN; 231 | lump_reference[ 7] = UNKNOWN; 232 | lump_reference[ 8] = BRUSHES; 233 | lump_reference[ 9] = LAYEREDTRIANGLESOUPS; 234 | lump_reference[10] = LAYEREDDRAWVERTICES; 235 | lump_reference[11] = LAYEREDDRAWINDICES; 236 | lump_reference[19] = PORTALVERTICES; 237 | lump_reference[24] = LAYEREDAABBTREES; 238 | lump_reference[25] = CELLS; 239 | lump_reference[26] = PORTALS; 240 | lump_reference[27] = NODES; 241 | lump_reference[28] = LEAVES; 242 | lump_reference[29] = LEAFBRUSHES; 243 | lump_reference[31] = COLLISIONVERTICES; 244 | lump_reference[32] = COLLISIONTRIANGLES; 245 | lump_reference[33] = COLLISIONEDGES; 246 | lump_reference[34] = COLLISIONBORDERS; 247 | lump_reference[35] = COLLISIONPARTS; 248 | lump_reference[36] = COLLISIONAABBS; 249 | lump_reference[37] = MODELS; 250 | lump_reference[39] = ENTITIES; 251 | lump_reference[40] = PATHS; 252 | lump_reference[41] = REFLECTIONPROBES; 253 | lump_reference[42] = LAYEREDDATA; 254 | lump_reference[43] = PRIMARYLIGHTS; 255 | lump_reference[44] = LIGHTGRIDHEADER; 256 | lump_reference[45] = LIGHTGRIDROWS; 257 | lump_reference[47] = SIMPLETRIANGLESOUPS; 258 | lump_reference[48] = SIMPLEVERTICES; 259 | lump_reference[49] = SIMPLEINDICES; 260 | lump_reference[51] = SIMPLEAABBTREES; 261 | lump_reference[52] = LIGHTREGIONS; 262 | lump_reference[53] = LIGHTREGIONHULLS; 263 | lump_reference[54] = LIGHTREGIONAXES; 264 | } 265 | 266 | void BSP_Handle::cod5() 267 | { 268 | cod_version = 5; 269 | 270 | DoubleWord size; 271 | size.b[0] = *i; i++; 272 | size.b[1] = *i; i++; 273 | size.b[2] = *i; i++; 274 | size.b[3] = *i; i++; 275 | 276 | cod_size = size.i; 277 | } 278 | 279 | void BSP_Handle::read() 280 | { 281 | DoubleWord offset, size, id; 282 | offset.u = id.u = 0; 283 | 284 | unsigned int padded = 0, n = 0; 285 | 286 | // read size and offset of each lump 287 | while (((size_t) (i + 7) - (size_t) data.buffer) < data.size) 288 | { 289 | if (cod_version < 3) 290 | { 291 | if (index.size()) 292 | { 293 | id.u++; 294 | } 295 | 296 | size.b[0] = *i; i++; 297 | size.b[1] = *i; i++; 298 | size.b[2] = *i; i++; 299 | size.b[3] = *i; i++; 300 | 301 | offset.b[0] = *i; i++; 302 | offset.b[1] = *i; i++; 303 | offset.b[2] = *i; i++; 304 | offset.b[3] = *i; i++; 305 | } 306 | else if (cod_version > 3) 307 | { 308 | if (!index.size()) 309 | { 310 | offset.i += 12 + ((cod_size * 2) * 4); 311 | } 312 | else 313 | { 314 | unsigned int length = index[index.size() - 1].offset + index[index.size() - 1].size; 315 | unsigned int padding = 0; 316 | 317 | // variance 318 | if (id.u != 7 && id.u != 39) 319 | { 320 | padding = (length % 4); // make it a multiple of 4 bytes 321 | 322 | if (padding) 323 | { 324 | padding = (4 - padding); 325 | } 326 | } 327 | else if (id.u == 39) 328 | { 329 | padding = 1; 330 | } 331 | 332 | offset.i = length + padding; 333 | padded += padding; 334 | } 335 | 336 | id.b[0] = *i; i++; 337 | id.b[1] = *i; i++; 338 | id.b[2] = *i; i++; 339 | id.b[3] = *i; i++; 340 | 341 | size.b[0] = *i; i++; 342 | size.b[1] = *i; i++; 343 | size.b[2] = *i; i++; 344 | size.b[3] = *i; i++; 345 | 346 | if (id.u == 39) 347 | { 348 | size.u--; // we know your length, no need for 0x00 349 | } 350 | } 351 | 352 | // if we reached the number of lumps used by this CoD 353 | if (cod_size == -1 && offset.u == 0 && size.u == 0) 354 | { 355 | break; 356 | } 357 | 358 | // as long as the end of the file is not too close... 359 | if ((offset.u + size.u) <= data.size) 360 | { 361 | if (size.u) 362 | { 363 | index.push_back(Index(id.u, offset.u, size.u)); 364 | } 365 | } 366 | else 367 | { 368 | printf("WARNING: The bsp's file is too short, the lump's directory is pointing outside the file by `%u' bytes, starting at lump `%u'.\n", ((offset.u + size.u) - data.size), id.u); 369 | break; 370 | } 371 | 372 | if (cod_size != -1 && (n + 1) == (unsigned int) cod_size) 373 | { 374 | break; 375 | } 376 | n++; 377 | } 378 | 379 | //////// 380 | 381 | // run a function for each lump 382 | std::vector::iterator it; 383 | for (it = index.begin(); it < index.end(); it++) 384 | { 385 | if (lump_reference.find((*it).id) != lump_reference.end()) 386 | { 387 | LumpReference reference = lump_reference[(*it).id]; 388 | if ((*it).size && exists(reference)) 389 | { 390 | lumps[reference]->read(data.buffer + (*it).offset, (*it).size); 391 | } 392 | } 393 | } 394 | 395 | success = true; 396 | } 397 | 398 | bool BSP_Handle::exists(LumpReference reference) 399 | { 400 | return (lumps.find(reference) != lumps.end()); 401 | } 402 | 403 | unsigned int BSP_Handle::size(LumpReference reference) 404 | { 405 | if (exists(reference)) 406 | { 407 | return lumps[reference]->size(); 408 | } 409 | return 0; 410 | } 411 | 412 | void BSP_Handle::write(FILE *output, LumpReference reference) 413 | { 414 | if (exists(reference) && size(reference)) 415 | { 416 | lumps[reference]->write(output); 417 | } 418 | } 419 | 420 | template<> 421 | void Lump::read(char *i, unsigned int isize) 422 | { 423 | std::vector vector; 424 | char *size = i + isize; 425 | 426 | bool in_entity = false; 427 | while (i < size) 428 | { 429 | bool in_string = false; 430 | bool has_key = false; 431 | Entity entity; 432 | std::string key, value; 433 | while (i < size && in_entity) 434 | { 435 | while (i < size && in_string) 436 | { 437 | if (*i == '"') 438 | { 439 | i++; 440 | in_string = false; 441 | if (!has_key) 442 | { 443 | has_key = true; 444 | } 445 | else 446 | { 447 | entity.pairs[key] = value; 448 | has_key = false; 449 | key = value = ""; 450 | } 451 | break; 452 | } 453 | else if (!has_key) 454 | { 455 | key.push_back(*i); 456 | } 457 | else if (has_key) 458 | { 459 | value.push_back(*i); 460 | } 461 | i++; 462 | } 463 | 464 | if (*i == '"') 465 | { 466 | in_string = true; 467 | } 468 | else if (*i == '}') 469 | { 470 | in_entity = false; 471 | vector.push_back(entity); 472 | break; 473 | } 474 | i++; 475 | } 476 | 477 | if (*i == '{') 478 | { 479 | in_entity = true; 480 | } 481 | i++; 482 | } 483 | 484 | _size = vector.size(); 485 | _array = new Entity[_size]; 486 | 487 | for (unsigned int n = 0; n < _size; n++) 488 | { 489 | _array[n] = vector[n]; 490 | } 491 | } 492 | 493 | template<> 494 | Lump::~Lump() 495 | { 496 | delete[] _array; 497 | } 498 | 499 | template<> 500 | void Lump::write(FILE *output) const 501 | { 502 | unsigned int n = 0, offset = 0, side = 0; 503 | 504 | Brush *brush; 505 | for (brush = bsp->array(BRUSHES); brush < bsp->array(BRUSHES) + bsp->size(BRUSHES); brush++) 506 | { 507 | side = 0; 508 | Brushside *brushside; 509 | for (brushside = _array + offset; brushside < (_array + offset + (*brush).sides); brushside++) 510 | { 511 | if (side < 6) 512 | { 513 | fprintf(output, "[%6u] %12g %6u\r\n", n, (*brushside).column1.distance, (*brushside).material_id); 514 | } 515 | else 516 | { 517 | fprintf(output, "[%6u] %11u# %6u\r\n", n, (*brushside).column1.plane, (*brushside).material_id); 518 | } 519 | side++; 520 | n++; 521 | } 522 | offset += (*brush).sides; 523 | } 524 | } 525 | 526 | template<> 527 | void Lump::write(FILE *output) const 528 | { 529 | unsigned int n = 0; 530 | Entity *entity; 531 | for (entity = _array; entity < (_array + _size); entity++) 532 | { 533 | unsigned int m = 0; 534 | std::map::const_iterator it; 535 | for (it = (*entity).pairs.begin(); it != (*entity).pairs.end(); it++) 536 | { 537 | fprintf(output, "[%6u.%02u] %s %s\r\n", n, m, (*it).first.c_str(), (*it).second.c_str()); 538 | m++; 539 | } 540 | fprintf(output, "\r\n"); 541 | n++; 542 | } 543 | } 544 | 545 | //////////////////////////////////////////////////////////////// 546 | } 547 | -------------------------------------------------------------------------------- /BSP/src/lumps.cpp: -------------------------------------------------------------------------------- 1 | #include "bsp/lumps.hpp" 2 | 3 | namespace BSP 4 | { 5 | //////////////////////////////////////////////////////////////// 6 | 7 | const char *LumpName[] = 8 | { 9 | "Unknown", 10 | "Materials", 11 | "LightMaps", 12 | "LightGridHash", 13 | "LightGridValues", 14 | "Planes", 15 | "Brushsides", 16 | "Brushes", 17 | "TriangleSoups", 18 | "DrawVertices", 19 | "DrawIndices", 20 | "CullGroups", 21 | "CullGroupIndices", 22 | "Unknown12", 23 | "Unknown13", 24 | "Unknown14", 25 | "Unknown15", 26 | "Unknown16", 27 | "PortalVertices", 28 | "Occluder", 29 | "OccluderPlanes", 30 | "OccluderEdges", 31 | "OccluderIndices", 32 | "AABBTrees", 33 | "Cells", 34 | "Portals", 35 | "Nodes", 36 | "Leaves", 37 | "LeafBrushes", 38 | "Unknown28", 39 | "CollisionVertices", 40 | "CollisionEdges", 41 | "CollisionTriangles", 42 | "CollisionBorders", 43 | "CollisionParts", 44 | "CollisionAABBs", 45 | "Models", 46 | "Visibility", 47 | "Entities", 48 | 49 | // cod4 50 | "LightGridPoints", 51 | "LightGridColours", 52 | "LayeredTriangleSoups", 53 | "LayeredDrawVertices", 54 | "LayeredDrawIndices", 55 | "LayeredAABBTrees", 56 | "Paths", 57 | "ReflectionProbes", 58 | "LayeredData", 59 | "PrimaryLights", 60 | "LightGridHeader", 61 | "LightGridRows", 62 | "SimpleTriangleSoups", 63 | "SimpleVertices", 64 | "SimpleIndices", 65 | "SimpleAABBTrees", 66 | "LightRegions", 67 | "LightRegionHulls", 68 | "LightRegionAxes" 69 | }; 70 | 71 | //////////////////////////////////////////////////////////////// 72 | 73 | void Material::write(FILE *output) const 74 | { 75 | for (unsigned int a = 0; a < 64; a++) 76 | { 77 | if (name[a]) 78 | { 79 | fputc(name[a], output); 80 | } 81 | else 82 | { 83 | fputc(' ', output); 84 | } 85 | } 86 | 87 | fprintf(output, "0x%08x 0x%08x", flags[0], flags[1]); 88 | } 89 | 90 | void Plane::write(FILE *output) const 91 | { 92 | fprintf(output, "%12g %12g %12g %6g", normal[0], normal[1], normal[2], distance); 93 | } 94 | 95 | void Brushside::write(FILE *output) const 96 | { 97 | // exception!!! 98 | } 99 | 100 | void Brush::write(FILE *output) const 101 | { 102 | fprintf(output, "%6u %6u", sides, material_id); 103 | } 104 | 105 | void TriangleSoup::write(FILE *output) const 106 | { 107 | fprintf(output, "%6u %6u %6u %6u %6u %6u", material_id, draw_order, vertex_offset, vertex_length, triangle_offset, triangle_length); 108 | } 109 | 110 | void DrawVertex1::write(FILE *output) const 111 | { 112 | fprintf(output, "%6g %6g %6g %12g %12g %12g 0x%08x %12g %12g %12g %12g", position[0], position[1], position[2], normal[0], normal[1], normal[2], rgba, unknown[0], unknown[1], unknown[2], unknown[3]); 113 | } 114 | 115 | void DrawVertex2::write(FILE *output) const 116 | { 117 | fprintf(output, "%6g %6g %6g %12g %12g %12g 0x%08x %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g", position[0], position[1], position[2], normal[0], normal[1], normal[2], rgba, uv[0], uv[1], st[0], st[1], unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5]); 118 | } 119 | 120 | void DrawIndex::write(FILE *output) const 121 | { 122 | fprintf(output, "%6u %6u %6u", vertex[0], vertex[1], vertex[2]); 123 | } 124 | 125 | void PortalVertex::write(FILE *output) const 126 | { 127 | fprintf(output, "%12g %12g %12g", unknown[0], unknown[1], unknown[2]); 128 | } 129 | 130 | void AABBTree::write(FILE *output) const 131 | { 132 | fprintf(output, "%6u %6u %6u", unknown[0], unknown[1], unknown[2]); 133 | } 134 | 135 | void Cell::write(FILE *output) const 136 | { 137 | fprintf(output, "%12g %12g %12g", unknown[0], unknown[1], unknown[2]); 138 | } 139 | void Portal::write(FILE *output) const 140 | { 141 | fprintf(output, "%6u %6u %6u", unknown[0], unknown[1], unknown[2]); 142 | } 143 | 144 | void Node::write(FILE *output) const 145 | { 146 | fprintf(output, "%6i %6i %6i %6i %6i %6i %6i %6i %6i", unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5], unknown[6], unknown[7], unknown[8]); 147 | } 148 | 149 | void Leaf::write(FILE *output) const 150 | { 151 | fprintf(output, "%6i %6i %6i %6i %6i %6i %6i %6i %6i", unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5], unknown[6], unknown[7], unknown[8]); 152 | } 153 | 154 | void LeafBrush::write(FILE *output) const 155 | { 156 | fprintf(output, "%6i", unknown); 157 | } 158 | 159 | void CollisionVertex::write(FILE *output) const 160 | { 161 | fprintf(output, "%12g %12g %12g %12g", unknown, position[0], position[1], position[2]); 162 | } 163 | 164 | void CollisionEdge::write(FILE *output) const 165 | { 166 | fprintf(output, "%4u %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g", unknown, position[0], position[1], position[2], normal[0][0], normal[0][1], normal[0][2], normal[1][0], normal[1][1], normal[1][2], normal[2][0], normal[2][1], normal[2][2], distance); 167 | } 168 | 169 | void CollisionTriangle::write(FILE *output) const 170 | { 171 | fprintf(output, "%12g %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g %12g %6u %6u %6u %6i %6i %6i", normal[0], normal[1], normal[2], distance, unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5], unknown[6], unknown[7], vertex_id[0], vertex_id[1], vertex_id[2], edge_id[0], edge_id[1], edge_id[2]); 172 | } 173 | 174 | void CollisionBorder::write(FILE *output) const 175 | { 176 | fprintf(output, "%12g %12g %12g %12g %12g %12g %12g", unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5], unknown[6]); 177 | } 178 | 179 | void CollisionPart::write(FILE *output) const 180 | { 181 | fprintf(output, "%4i %4i %4i %4i %4i %4i", unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5]); 182 | } 183 | 184 | void CollisionAABB::write(FILE *output) const 185 | { 186 | fprintf(output, "%12g %12g %12g %12g %12g %12g %4u %4u %4u %4u", unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5], unknown2[0], unknown2[1], unknown2[2], unknown2[3]); 187 | } 188 | 189 | void Model::write(FILE *output) const 190 | { 191 | fprintf(output, "%12g %12g %12g %12g %12g %12g %6i %6i %6i %6i %6i %6i", position[0][0], position[0][1], position[0][2], position[1][0], position[1][1], position[1][2], trianglesoups_offset, trianglesoups_size, collisionaabbs_offset, collisionaabbs_size, brushes_offset, brushes_size); 192 | } 193 | 194 | void Entity::write(FILE *output) const 195 | { 196 | // exception 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /bin/BSP Decompiler.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/bin/BSP Decompiler.exe -------------------------------------------------------------------------------- /bin/export.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | pre { 7 | border-right: 2px solid silver; 8 | } 9 | 10 | h1 { 11 | font-size: 16pt; 12 | margin-bottom: 10px; 13 | padding: 5px; 14 | border: 2px solid black; 15 | } 16 | 17 | h2 { 18 | font-weight: bold; 19 | font-size: 12pt; 20 | margin-top: 15px; 21 | padding-bottom: 2px; 22 | border-bottom: 1px solid gray; 23 | } 24 | 25 | .lump { 26 | font-size: 9pt; 27 | border-bottom: 2px solid gray; 28 | /*border-left: 2px solid silver;*/ 29 | padding: 5px; 30 | -moz-column-width: 180px; 31 | -moz-column-gap: 10px; 32 | } 33 | 34 | .lump_wide { 35 | border-bottom: 2px solid gray; 36 | padding: 5px; 37 | font-size: 8pt; 38 | } 39 | 40 | #all { 41 | margin: 5px; 42 | } 43 | 44 | a 45 | { 46 | padding:5px; 47 | text-decoration:none; 48 | } -------------------------------------------------------------------------------- /bin/lua5.1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/bin/lua5.1.dll -------------------------------------------------------------------------------- /bin/lua51.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kungfooman/CoD-BSP-Decompiler/e74a65bbe8909abb2572bb2db28db4c1790b5b57/bin/lua51.dll -------------------------------------------------------------------------------- /bin/settings.lua: -------------------------------------------------------------------------------- 1 | pause = 1 -- wait for a key stroke at the end of the process 2 | 3 | batch_file = 0 -- write batch file for quick redecompilation and copies BSP file 4 | statistics = 0 -- writes statistics text file 5 | 6 | export_raw_lumps = 0 -- exports raw lumps (lump splitter) 7 | export_html = 0 -- exports lumps / bsp in HTML format, else in TXT format 8 | export_bsp = 0 -- exports interpreted data of all lumps 9 | export_lumps = 0 -- exports interpreted data per lump 10 | 11 | map = 1 -- writes MAP file 12 | map_version = 5 -- MAP file format for either (CoD) 1, 2, 4 or 5; 0 defaults to BSP version 13 | map_layers = 1 -- enables layers 14 | map_brushes = 1 -- appends brushes 15 | map_triangles = 1 -- appends all triangles stored as in the draw lumps 16 | map_entities = 1 -- appends entities 17 | map_models = 1 -- appends models 18 | map_spawns = 1 -- appends spawns 19 | 20 | caulk_brushes = 0 -- makes all brushes caulk (except tool textures) 21 | caulk_tool_brushes = 0 -- makes all tool brushes caulk 22 | caulk_triangles = 1 -- makes all triangles caulk (except tool textures) 23 | 24 | layer_split = 1 -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2011 CodeManX and Daevius. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY CODEMANX AND DAEVIUS ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CODEMANX OR DAEVIUS OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | The views and conclusions contained in the software and documentation are those of the 24 | authors and should not be interpreted as representing official policies, either expressed 25 | or implied, of CodeManX and Daevius. 26 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Call of Duty 1 and 2 BSP Decompiler CoDEmanX and Daevius 2 | ----------------------------------------- -------------------- 3 | April 9th, 2011 4 | 5 | Hereby we release our decompiler and the sources. May it prove to be useful for 6 | you or your team. 7 | 8 | By modifying the settings.lua file you can alter the output of the decompiler. 9 | Drop BSP files from CoD1 or CoD2 onto the executable for decompilation. 10 | 11 | 12 | Please emphasize that you used our decompiled sources, either put a link to a 13 | post about the tool / about us, or put our names in your credit list. We have 14 | spend much time on this project and we're pleased to hear whenever other people 15 | appreciate the work! 16 | 17 | This tool is released for educational purposes only. We are not responsible for 18 | any map piraty or other issues caused. 19 | 20 | CoDEmanX and Daevius -------------------------------------------------------------------------------- /src/BSP Decompiler.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 78 | 79 | -------------------------------------------------------------------------------- /src/BSP Decompiler.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1265374732 source:d:\c\bsp decompiler\main.cpp 3 | 4 | 5 | 6 | 7 | 8 | "console.hpp" 9 | "settings.hpp" 10 | "statistics.hpp" 11 | "lumps.hpp" 12 | "map.hpp" 13 | 14 | 1262086429 d:\c\bsp decompiler\console.hpp 15 | 16 | 17 | 1265381352 d:\c\bsp decompiler\settings.hpp 18 | 19 | 20 | 21 | 1265931095 source:d:\c\bsp decompiler\settings.cpp 22 | "settings.hpp" 23 | 24 | 25 | 26 | 27 | 28 | 1262113866 source:d:\c\bsp decompiler\console.cpp 29 | "console.hpp" 30 | 31 | 32 | 1262134666 source:d:\c\bsp decompiler\lumps.cpp 33 | "lumps.hpp" 34 | "console.hpp" 35 | "common.hpp" 36 | 37 | 38 | 1262096292 d:\c\bsp decompiler\lumps.hpp 39 | 40 | 41 | 1263586782 d:\c\bsp decompiler\common.hpp 42 | "settings.hpp" 43 | "math.hpp" 44 | 45 | 46 | 1262100820 d:\c\bsp decompiler\statistics.hpp 47 | 48 | 49 | 1262739084 d:\c\bsp decompiler\map.hpp 50 | 51 | 52 | 53 | "settings.hpp" 54 | 55 | 1262184556 d:\c\bsp decompiler\math.hpp 56 | 57 | 58 | 1267388414 source:d:\c\bsp decompiler\map.cpp 59 | "console.hpp" 60 | "map.hpp" 61 | "math.hpp" 62 | "common.hpp" 63 | "cod.hpp" 64 | 65 | 66 | 67 | 1262181574 source:d:\c\bsp decompiler\math.cpp 68 | "math.hpp" 69 | 70 | 1263589184 source:d:\c\bsp decompiler\statistics.cpp 71 | "console.hpp" 72 | "statistics.hpp" 73 | "math.hpp" 74 | 75 | 76 | 1267387727 source:d:\c\bsp decompiler\common.cpp 77 | "common.hpp" 78 | "cod.hpp" 79 | 80 | 81 | 82 | 1262732232 d:\c\bsp decompiler\tool_textures.hpp 83 | 84 | 1262732562 source:d:\c\bsp decompiler\tool_textures.cpp 85 | "tool_textures.hpp" 86 | 87 | 88 | 1262739723 source:d:\c\bsp decompiler\cod.cpp 89 | "cod.hpp" 90 | 91 | 92 | 1262739758 d:\c\bsp decompiler\cod.hpp 93 | 94 | -------------------------------------------------------------------------------- /src/BSP Decompiler.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/cod.cpp: -------------------------------------------------------------------------------- 1 | #include "cod.hpp" 2 | 3 | #include 4 | 5 | bool tool_texture(const char *texture, int map_version) 6 | { 7 | if (tool_textures[map_version]) 8 | { 9 | unsigned int i = 0; 10 | while (tool_textures[map_version][i]) 11 | { 12 | if (!strcmp(tool_textures[map_version][i], texture)) 13 | { 14 | return true; 15 | } 16 | i++; 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | bool spawn_classname(const char *classname, int map_version) 23 | { 24 | if (spawn_classnames[map_version]) 25 | { 26 | unsigned int i = 0; 27 | while (spawn_classnames[map_version][i]) 28 | { 29 | if (!strcmp(spawn_classnames[map_version][i], classname)) 30 | { 31 | return true; 32 | } 33 | i++; 34 | } 35 | } 36 | return false; 37 | } 38 | 39 | const char *cod1_tool_textures[] = 40 | { 41 | "$additive", 42 | "$glare_blind", 43 | "$line", 44 | "$opaque", 45 | "$point", 46 | "descript", 47 | "aitrig", 48 | "blank", 49 | "case", 50 | "case1024", 51 | "case1024x512", 52 | "case256", 53 | "case256x1024", 54 | "case512", 55 | "case512x1024", 56 | "clipfoliage", 57 | "metal@temp", 58 | "nodraw_notsolid", 59 | "nosight_noclip", 60 | "return_ai_trigger", 61 | "return_spawner_trigger", 62 | "spawner_trigger", 63 | "ai_nopass", 64 | "ai_nopasslarge", 65 | "ai_nosight", 66 | "areaportal", 67 | "blackish", 68 | "case1024x128", 69 | "caulk", 70 | "clip", 71 | "clip_metal", 72 | "clip_nosight", 73 | "clip_nosight_metal", 74 | "clipfull", 75 | "clipmissile", 76 | "clipmonster", 77 | "clipplayer", 78 | "clipshot", 79 | "clipweap", 80 | "clipweap_glass", 81 | "clusterportal", 82 | "gridblock", 83 | "hint", 84 | "hood", 85 | "ladder", 86 | "lightgrid", 87 | "mirror", 88 | "mirror1", 89 | "mirror1a", 90 | "nodraw", 91 | "nodraw_decal", 92 | "occluder", 93 | "origin", 94 | "portal", 95 | "portalcaulk", 96 | "portalnodraw", 97 | "shadow", 98 | "skip", 99 | "terrain", 100 | "terrain2", 101 | "trigger", 102 | "vehicleclip", 103 | "water", 104 | 0 105 | }; 106 | 107 | const char *cod2_tool_textures[] = 108 | { 109 | "$additive", 110 | "$glare_blind", 111 | "$line", 112 | "$opaque", 113 | "$point", 114 | "aa_default", 115 | "aitrig", 116 | "ambient", 117 | "bcs", 118 | "black", 119 | "caulk", 120 | "caulk_shadow", 121 | "clip", 122 | "clip_ai", 123 | "clip_foliage", 124 | "clip_full", 125 | "clip_metal", 126 | "clip_missile", 127 | "clip_nosight", 128 | "clip_nosight_dirt", 129 | "clip_nosight_metal", 130 | "clip_nosight_nothing", 131 | "clip_nosight_novehicle", 132 | "clip_nosight_rock", 133 | "clip_player", 134 | "clip_snow", 135 | "clip_vehicle", 136 | "clip_water", 137 | "clip_water_player", 138 | "clip_weap", 139 | "clip_weap_glass", 140 | "escort", 141 | "goal_volume", 142 | "hint", 143 | "kill", 144 | "ladder", 145 | "lightmap_blue", 146 | "lightmap_cyan", 147 | "lightmap_gray", 148 | "lightmap_green", 149 | "lightmap_purple", 150 | "lightmap_red", 151 | "lightmap_yellow", 152 | "mantle_on", 153 | "mantle_over", 154 | "mine", 155 | "nodraw", 156 | "nodraw_decal", 157 | "nodraw_notsolid", 158 | "nosight_noclip", 159 | "occluder", 160 | "origin", 161 | "portal", 162 | "portal_debug_solid", 163 | "portal_debug_trans", 164 | "portal_nodraw", 165 | "region", 166 | "return_ai_trigger", 167 | "return_spawner_trigger", 168 | "skip", 169 | "smoke", 170 | "spawner_trigger", 171 | "stopspawn", 172 | "tool_transparent", 173 | "traverse", 174 | "trigger", 175 | "volume", 176 | "white", 177 | "white_nocull", 178 | "white_nocull_offset", 179 | 0 180 | }; 181 | 182 | const char *cod4_tool_textures[] = 183 | { 184 | "$additive", 185 | "$line", 186 | "$line_nodepth", 187 | "$opaque", 188 | "$point", 189 | "aa_default", 190 | "aitrig", 191 | "ambient", 192 | "autosave", 193 | "auto_adjust", 194 | "bcs", 195 | "caulk", 196 | "caulk_shadow", 197 | "clip", 198 | "clip_ai", 199 | "clip_foliage", 200 | "clip_full", 201 | "clip_magic_jeepride", 202 | "clip_metal", 203 | "clip_missile", 204 | "clip_nosight", 205 | "clip_nosight_dirt", 206 | "clip_nosight_for_bridge_on_jeepride_fire_clip", 207 | "clip_nosight_metal", 208 | "clip_nosight_nothing", 209 | "clip_nosight_novehicle", 210 | "clip_nosight_rock", 211 | "clip_player", 212 | "clip_shot_block", 213 | "clip_snow", 214 | "clip_vehicle", 215 | "clip_water", 216 | "clip_water_player", 217 | "clip_weap", 218 | "clip_weap_glass", 219 | "compass_fov", 220 | "escort", 221 | "flag", 222 | "fog", 223 | "friendly_respawn", 224 | "goal_volume", 225 | "gray", 226 | "hint", 227 | "indoor_outdoor", 228 | "kill", 229 | "ladder", 230 | "lightgrid_sky", 231 | "lightgrid_volume", 232 | "lightmap_blue", 233 | "lightmap_cyan", 234 | "lightmap_gray", 235 | "lightmap_green", 236 | "lightmap_purple", 237 | "lightmap_red", 238 | "lightmap_yellow", 239 | "light_portal", 240 | "mantle_on", 241 | "mantle_over", 242 | "mine", 243 | "mortar_off", 244 | "mortar_on", 245 | "nodraw", 246 | "nodraw_decal", 247 | "nodraw_glass", 248 | "nodraw_notsolid", 249 | "nosight_noclip", 250 | "origin", 251 | "physics_geometry", 252 | "portal", 253 | "portal_debug_solid", 254 | "portal_debug_trans", 255 | "portal_nodraw", 256 | "region", 257 | "return_ai_trigger", 258 | "return_spawner_trigger", 259 | "skip", 260 | "smoke", 261 | "smoothing_hard", 262 | "smoothing_smooth", 263 | "smoothing_smooth_other", 264 | "spawner_trigger", 265 | "stopspawn", 266 | "tool_transparent", 267 | "traverse", 268 | "trigger", 269 | "trigger_damage", 270 | "trigger_hint", 271 | "trigger_vision", 272 | "unlock", 273 | "vehiclegate", 274 | "vehicle_trigger", 275 | "volume", 276 | "white_additive", 277 | "white_multiply", 278 | "white_nocull", 279 | "white_nocull_offset", 280 | "white_tools", 281 | "zfaux_wall", 282 | 0 283 | }; 284 | 285 | const char *cod5_tool_textures[] = 286 | { 287 | "$additive", 288 | "$additive_nodepth", 289 | "$line", 290 | "$line_nodepth", 291 | "$opaque", 292 | "$point", 293 | "aa_default", 294 | "aitrig", 295 | "ambient", 296 | "autosave", 297 | "auto_adjust", 298 | "bcs", 299 | "caulk", 300 | "caulk_shadow", 301 | "clip", 302 | "clip_ai", 303 | "clip_foliage", 304 | "clip_full", 305 | "clip_metal", 306 | "clip_missile", 307 | "clip_missile_nosight", 308 | "clip_missile_nosight_dirt", 309 | "clip_missile_nosight_metal", 310 | "clip_missile_nosight_novehicle", 311 | "clip_missile_nosight_rock", 312 | "clip_missile_nosight_wood", 313 | "clip_missile_no_player", 314 | "clip_nosight", 315 | "clip_nosight_dirt", 316 | "clip_nosight_metal", 317 | "clip_nosight_nothing", 318 | "clip_nosight_novehicle", 319 | "clip_nosight_rock", 320 | "clip_nosight_wood", 321 | "clip_player", 322 | "clip_snow", 323 | "clip_vehicle", 324 | "clip_water", 325 | "clip_water_player", 326 | "clip_weap", 327 | "clip_weap_glass", 328 | "clip_wood", 329 | "compass_fov", 330 | "escort", 331 | "flag", 332 | "fog", 333 | "friendly_respawn", 334 | "goal_volume", 335 | "gray", 336 | "hint", 337 | "indoor_outdoor", 338 | "kill", 339 | "ladder", 340 | "lightgrid_sky", 341 | "lightgrid_volume", 342 | "lightmap_blue", 343 | "lightmap_cyan", 344 | "lightmap_gray", 345 | "lightmap_green", 346 | "lightmap_purple", 347 | "lightmap_red", 348 | "lightmap_yellow", 349 | "light_portal", 350 | "mantle_on", 351 | "mantle_over", 352 | "mine", 353 | "mortar_off", 354 | "mortar_on", 355 | "mount", 356 | "mount_mantle_on", 357 | "mount_mantle_over", 358 | "music_trigger", 359 | "nodraw", 360 | "nodraw_decal", 361 | "nodraw_notsolid", 362 | "nosight_noclip", 363 | "occlusion", 364 | "origin", 365 | "physics_geometry", 366 | "portal", 367 | "portal_debug_solid", 368 | "portal_debug_trans", 369 | "portal_nodraw", 370 | "procedural_grass", 371 | "region", 372 | "return_ai_trigger", 373 | "return_spawner_trigger", 374 | "skip", 375 | "smoke", 376 | "smoothing_hard", 377 | "smoothing_smooth", 378 | "smoothing_smooth_other", 379 | "sound_trigger", 380 | "spawner_trigger", 381 | "stopspawn", 382 | "tool_transparent", 383 | "traverse", 384 | "trigger", 385 | "trigger_damage", 386 | "trigger_hint", 387 | "trigger_vision", 388 | "undertow", 389 | "unlock", 390 | "vehiclegate", 391 | "vehicle_trigger", 392 | "volume", 393 | "white_additive", 394 | "white_multiply", 395 | "white_nocull", 396 | "white_nocull_offset", 397 | "white_tools", 398 | 399 | "ch_godray01", 400 | "ch_godray_bright", 401 | "ch_godray_fire", 402 | "ch_hotspot01", 403 | "ch_hotspot02", 404 | "event1", 405 | "event2", 406 | "event3", 407 | "event4", 408 | "event5", 409 | "event6", 410 | "event7", 411 | "event8", 412 | "global_invisible", 413 | "godray_ber2", 414 | "hdrportal_darken", 415 | "hdrportal_darken_more", 416 | "hdrportal_lighten", 417 | "lst_glow", 418 | "pel1_glow", 419 | "temp_cover", 420 | 0 421 | }; 422 | 423 | const char **tool_textures[] = 424 | { 425 | 0, 426 | cod1_tool_textures, 427 | cod2_tool_textures, 428 | 0, 429 | cod4_tool_textures, 430 | cod5_tool_textures, 431 | 0 432 | }; 433 | 434 | //////////////////////////////////////////////////////////////// 435 | 436 | const char *cod1_spawn_classnames[] = 437 | { 438 | 0 439 | }; 440 | 441 | const char *cod2_spawn_classnames[] = 442 | { 443 | "mp_tdm_spawn", 444 | "mp_dm_spawn", 445 | "mp_global_intermission", 446 | "mp_ctf_spawn_allied", 447 | "mp_ctf_spawn_axis", 448 | "mp_sd_spawn_defender", 449 | "mp_sd_spawn_attacker", 450 | 0 451 | }; 452 | 453 | const char *cod4_spawn_classnames[] = 454 | { 455 | 0 456 | }; 457 | 458 | const char *cod5_spawn_classnames[] = 459 | { 460 | 0 461 | }; 462 | 463 | const char **spawn_classnames[] = 464 | { 465 | 0, 466 | cod1_spawn_classnames, 467 | cod2_spawn_classnames, 468 | 0, 469 | cod4_spawn_classnames, 470 | cod5_spawn_classnames, 471 | 0 472 | }; 473 | -------------------------------------------------------------------------------- /src/cod.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COD_H 2 | #define COD_H 3 | 4 | bool tool_texture(const char *texture, int map_version); 5 | bool spawn_classname(const char *classname, int map_version); 6 | 7 | extern const char **tool_textures[]; 8 | extern const char *cod1_tool_textures[]; 9 | extern const char *cod2_tool_textures[]; 10 | extern const char *cod4_tool_textures[]; 11 | extern const char *cod5_tool_textures[]; 12 | 13 | extern const char **spawn_classnames[]; 14 | extern const char *cod1_spawn_classnames[]; 15 | extern const char *cod2_spawn_classnames[]; 16 | extern const char *cod4_spawn_classnames[]; 17 | extern const char *cod5_spawn_classnames[]; 18 | 19 | #endif // COD_H 20 | 21 | -------------------------------------------------------------------------------- /src/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | #include "cod.hpp" 3 | 4 | #include 5 | #include 6 | 7 | std::string to_str(unsigned int number) 8 | { 9 | std::string text; 10 | std::stringstream stream; 11 | stream << number; 12 | stream >> text; 13 | return text; 14 | } 15 | 16 | int to_int(const std::string &text) 17 | { 18 | int number; 19 | std::stringstream stream(text); 20 | stream >> number; 21 | return number; 22 | } 23 | 24 | void write_vertex(FILE *output, const BSP::DrawVertex1 &vertex, const Settings &settings) 25 | { 26 | if (settings.map_version == 1) 27 | { 28 | fprintf( 29 | output, 30 | " ( %g %g %g %g %g %u %u %u %u 0 )", 31 | vertex.position[0], 32 | vertex.position[1], 33 | vertex.position[2], 34 | vertex.unknown[0] * 1024, 35 | vertex.unknown[1] * 1024, 36 | (vertex.rgba & 0x0000ff00) >> 8, // B 37 | (vertex.rgba & 0x00ff0000) >> 16, // G 38 | (vertex.rgba & 0xff000000) >> 24, // R 39 | (vertex.rgba & 0x000000ff) >> 0 // A 40 | ); 41 | } 42 | else if (settings.map_version == 2) 43 | { 44 | fprintf( 45 | output, 46 | " v %g %g %g c %u %u %u %u t %g %g %g %g\n", 47 | vertex.position[0], 48 | vertex.position[1], 49 | vertex.position[2], 50 | (vertex.rgba & 0x0000ff00) >> 8, // B 51 | (vertex.rgba & 0x00ff0000) >> 16, // G 52 | (vertex.rgba & 0xff000000) >> 24, // R 53 | (vertex.rgba & 0x000000ff) >> 0, // A 54 | vertex.unknown[1] * 1024, 55 | vertex.unknown[2] * 1024, 56 | vertex.unknown[1] * 1024, 57 | vertex.unknown[2] * 1024 58 | ); 59 | } 60 | else if (settings.map_version > 3) 61 | { 62 | fprintf( 63 | output, 64 | " v %g %g %g t %g %g\n", 65 | vertex.position[0], 66 | vertex.position[1], 67 | vertex.position[2], 68 | vertex.unknown[1] * 1024, 69 | vertex.unknown[2] * 1024 70 | ); 71 | } 72 | } 73 | 74 | void write_vertex(FILE *output, const BSP::DrawVertex2 &vertex, const Settings &settings) 75 | { 76 | if (settings.map_version == 1) 77 | { 78 | fprintf( 79 | output, 80 | " ( %g %g %g %g %g %u %u %u %u 0 )", 81 | vertex.position[0], 82 | vertex.position[1], 83 | vertex.position[2], 84 | vertex.uv[0] * 1024, 85 | vertex.uv[1] * 1024, 86 | (vertex.rgba & 0x0000ff00) >> 8, // B 87 | (vertex.rgba & 0x00ff0000) >> 16, // G 88 | (vertex.rgba & 0xff000000) >> 24, // R 89 | (vertex.rgba & 0x000000ff) >> 0 // A 90 | ); 91 | } 92 | else if (settings.map_version == 2) 93 | { 94 | fprintf( 95 | output, 96 | " v %g %g %g c %u %u %u %u t %g %g %g %g\n", 97 | vertex.position[0], 98 | vertex.position[1], 99 | vertex.position[2], 100 | (vertex.rgba & 0x0000ff00) >> 8, // B 101 | (vertex.rgba & 0x00ff0000) >> 16, // G 102 | (vertex.rgba & 0xff000000) >> 24, // R 103 | (vertex.rgba & 0x000000ff) >> 0, // A 104 | vertex.uv[0] * 1024, 105 | vertex.uv[1] * 1024, 106 | (vertex.st[0] * 1024) + 2, 107 | -((vertex.st[1] * 1024) + 2) 108 | ); 109 | } 110 | else 111 | { 112 | fprintf( 113 | output, 114 | " v %g %g %g t %g %g %g %g\n", 115 | vertex.position[0], 116 | vertex.position[1], 117 | vertex.position[2], 118 | vertex.uv[0] * 1024, 119 | vertex.uv[1] * 1024, 120 | (vertex.st[0] * 1024) + 2, 121 | -((vertex.st[1] * 1024) + 2) 122 | ); 123 | } 124 | } 125 | 126 | void write_vertex(FILE *output, double x, double y, double z) 127 | { 128 | fprintf( 129 | output, 130 | " v %g %g %g t 0 0 0 0\n", 131 | x, 132 | y, 133 | z 134 | ); 135 | } 136 | 137 | void write_brush(FILE *output, Position position1, Position position2, Position position3, const char *texture, const Settings &settings) 138 | { 139 | bool is_tool = false; 140 | if (tool_texture(texture, settings.map_version)) 141 | { 142 | is_tool = true; 143 | } 144 | else if (str_prefix("textures/common/", texture)) 145 | { 146 | texture += strlen("textures/common/"); 147 | if (tool_texture(texture, settings.map_version)) 148 | { 149 | is_tool = true; 150 | } 151 | } 152 | 153 | if (settings.map_version == 1 && str_prefix("textures/", texture)) 154 | { 155 | texture += strlen("textures/"); 156 | } 157 | 158 | if ((settings.caulk_brushes && settings.caulk_tool_brushes) || (settings.caulk_brushes && !is_tool)) 159 | { 160 | texture = "caulk"; 161 | } 162 | 163 | if (settings.map_version > 1) 164 | { 165 | fprintf(output, " ( %g %g %g ) ( %g %g %g ) ( %g %g %g ) %s 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0\n", 166 | position1.x, position1.y, position1.z, 167 | position2.x, position2.y, position2.z, 168 | position3.x, position3.y, position3.z, 169 | texture 170 | ); 171 | } 172 | else 173 | { 174 | fprintf(output, " ( %g %g %g ) ( %g %g %g ) ( %g %g %g ) %s 0 0 0 1 1 0 0 0 0\n", 175 | position1.x, position1.y, position1.z, 176 | position2.x, position2.y, position2.z, 177 | position3.x, position3.y, position3.z, 178 | texture 179 | ); 180 | } 181 | } 182 | 183 | void push_if_unique(std::vector &positions, const Position &position) 184 | { 185 | bool found = false; 186 | std::vector::iterator it; 187 | for (it = positions.begin(); it < positions.end(); it++) 188 | { 189 | if (*it == position) 190 | { 191 | found = true; 192 | break; 193 | } 194 | } 195 | 196 | if (!found) 197 | { 198 | positions.push_back(position); 199 | } 200 | } 201 | 202 | bool str_prefix(const char *prefix, const char *string) 203 | { 204 | while (*prefix) 205 | { 206 | if (*prefix != *string) 207 | { 208 | return false; 209 | } 210 | prefix++; 211 | string++; 212 | } 213 | return true; 214 | } 215 | -------------------------------------------------------------------------------- /src/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include "settings.hpp" 5 | #include "math.hpp" 6 | 7 | #include 8 | 9 | struct Brushplane 10 | { 11 | Normal normal; 12 | double distance; 13 | unsigned int material_id; 14 | 15 | Brushplane() 16 | { 17 | } 18 | }; 19 | 20 | std::string to_str(unsigned int number); 21 | int to_int(const std::string &text); 22 | 23 | void write_vertex(FILE *output, const BSP::DrawVertex1 &vertex, const Settings &settings); 24 | void write_vertex(FILE *output, const BSP::DrawVertex2 &vertex, const Settings &settings); 25 | void write_vertex(FILE *output, double x, double y, double z); 26 | 27 | void write_brush(FILE *output, Position position1, Position position2, Position position3, const char *texture, const Settings &settings); 28 | 29 | void push_if_unique(std::vector &positions, const Position &position); 30 | 31 | bool str_prefix(const char *prefix, const char *string); 32 | 33 | #endif // COMMON_H 34 | -------------------------------------------------------------------------------- /src/console.cpp: -------------------------------------------------------------------------------- 1 | #include "console.hpp" 2 | 3 | #include 4 | 5 | Console console; 6 | 7 | void initialise_console(const char *title) 8 | { 9 | console.handle = GetStdHandle(STD_OUTPUT_HANDLE); 10 | 11 | system("cls"); 12 | SetConsoleTitle(title); 13 | 14 | printf("%s\n", title); 15 | for (unsigned int i = 0; i < strlen(title); i++) 16 | { 17 | printf("-"); 18 | } 19 | printf("\n\n"); 20 | } 21 | 22 | void retrieve_cursor_position() 23 | { 24 | CONSOLE_SCREEN_BUFFER_INFO info; 25 | GetConsoleScreenBufferInfo(console.handle, &info); 26 | 27 | console.position = info.dwCursorPosition; 28 | } 29 | 30 | void restore_cursor_position() 31 | { 32 | SetConsoleCursorPosition(console.handle, console.position); 33 | } 34 | -------------------------------------------------------------------------------- /src/console.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONSOLE_H 2 | #define CONSOLE_H 3 | 4 | #include 5 | 6 | struct Console 7 | { 8 | HANDLE handle; 9 | COORD position; 10 | }; 11 | 12 | void initialise_console(const char *title); 13 | 14 | void retrieve_cursor_position(); 15 | void restore_cursor_position(); 16 | 17 | #endif // CONSOLE_H 18 | -------------------------------------------------------------------------------- /src/lumps.cpp: -------------------------------------------------------------------------------- 1 | #include "lumps.hpp" 2 | #include "console.hpp" 3 | #include "common.hpp" 4 | 5 | #include 6 | 7 | using namespace BSP; 8 | 9 | void write_raw_lumps(BSP_Handle *bsp, const std::string &path) 10 | { 11 | printf("Exporting raw lumps..."); 12 | retrieve_cursor_position(); 13 | 14 | unsigned int n = 0; 15 | std::vector::iterator it; 16 | for (it = bsp->index.begin(); it < bsp->index.end(); it++) 17 | { 18 | restore_cursor_position(); 19 | printf("%3.0f%%", ceil(((float) n / bsp->index.size()) * 100.0f)); 20 | 21 | if ((*it).size) 22 | { 23 | LumpReference reference = UNKNOWN; 24 | if (bsp->lump_reference.find((*it).id) != bsp->lump_reference.end()) 25 | { 26 | reference = bsp->lump_reference[(*it).id]; 27 | } 28 | 29 | std::string filename(path); 30 | if ((*it).id < 10) 31 | { 32 | filename += '0'; 33 | } 34 | filename += to_str((*it).id) + "_" + LumpName[reference] + ".lump"; 35 | 36 | FILE *output = fopen(filename.c_str(), "wb+"); 37 | if (!output) 38 | { 39 | fprintf(stderr, "ERROR: Could not write to `%s'.\n\n", filename.c_str()); 40 | } 41 | else 42 | { 43 | fwrite(bsp->data.buffer + (*it).offset, 1, (*it).size, output); 44 | fclose(output); 45 | } 46 | } 47 | n++; 48 | } 49 | 50 | restore_cursor_position(); 51 | printf("100%%\n"); 52 | } 53 | 54 | void write_bsp(BSP_Handle *bsp, const std::string &path, std::string filename, bool export_html) 55 | { 56 | printf("Exporting BSP..."); 57 | retrieve_cursor_position(); 58 | 59 | if (export_html) 60 | { 61 | filename = path + filename + ".html"; 62 | } 63 | else 64 | { 65 | filename = path + filename + ".txt"; 66 | } 67 | 68 | FILE *output = fopen(filename.c_str(), "wb+"); 69 | if (!output) 70 | { 71 | fprintf(stderr, "ERROR: Could not write to `%s'.\n", filename.c_str()); 72 | } 73 | else 74 | { 75 | std::vector::iterator it; 76 | if (export_html) 77 | { 78 | fprintf(output, "\n\n\nBSP export - %s\n\n\n\n
\n

%s

\n", bsp->map.c_str(), bsp->map.c_str()); 79 | 80 | fprintf(output, "
"); 81 | for (it = bsp->index.begin(); it < bsp->index.end(); it++) 82 | { 83 | if (bsp->lump_reference.find((*it).id) != bsp->lump_reference.end() && (*it).size) 84 | { 85 | fprintf(output, "%s ", (*it).id, LumpName[bsp->lump_reference[(*it).id]]); 86 | } 87 | } 88 | fprintf(output, "
\n"); 89 | } 90 | 91 | unsigned int n = 0; 92 | for (it = bsp->index.begin(); it < bsp->index.end(); it++) 93 | { 94 | restore_cursor_position(); 95 | printf("%3.0f%%", ceil(((float) n / bsp->index.size()) * 100.0f)); 96 | 97 | if (bsp->lump_reference.find((*it).id) != bsp->lump_reference.end()) 98 | { 99 | LumpReference reference = bsp->lump_reference[(*it).id]; 100 | if ((*it).size && bsp->size(reference)) 101 | { 102 | if (export_html) 103 | { 104 | fprintf(output, "

Lump %u - %s (%u)

", (*it).id, (*it).id, LumpName[reference], bsp->size(reference));
105 |                         bsp->write(output, reference);
106 |                         fprintf(output, "
"); 107 | } 108 | else 109 | { 110 | fprintf(output, "Lump %u - %s (%u)\r\n", (*it).id, LumpName[reference], bsp->size(reference)); 111 | bsp->write(output, reference); 112 | fprintf(output, "\r\n\r\n"); 113 | } 114 | } 115 | } 116 | n++; 117 | } 118 | 119 | if (export_html) 120 | { 121 | fprintf(output, "
"); 122 | } 123 | fclose(output); 124 | } 125 | 126 | restore_cursor_position(); 127 | printf("100%%\n"); 128 | } 129 | 130 | void write_lumps(BSP_Handle *bsp, const std::string &path, bool export_html) 131 | { 132 | printf("Exporting lumps..."); 133 | retrieve_cursor_position(); 134 | 135 | unsigned int n = 0; 136 | std::vector::iterator it; 137 | for (it = bsp->index.begin(); it < bsp->index.end(); it++) 138 | { 139 | restore_cursor_position(); 140 | printf("%3.0f%%", ceil(((float) n / bsp->index.size()) * 100.0f)); 141 | 142 | if (bsp->lump_reference.find((*it).id) != bsp->lump_reference.end()) 143 | { 144 | LumpReference reference = bsp->lump_reference[(*it).id]; 145 | if ((*it).size && bsp->size(reference)) 146 | { 147 | std::string tmp_filename(path); 148 | if ((*it).id < 10) 149 | { 150 | tmp_filename += '0'; 151 | } 152 | 153 | if (export_html) 154 | { 155 | tmp_filename += to_str((*it).id) + "_" + LumpName[reference] + ".html"; 156 | } 157 | else 158 | { 159 | tmp_filename += to_str((*it).id) + "_" + LumpName[reference] + ".txt"; 160 | } 161 | 162 | FILE *output = fopen(tmp_filename.c_str(), "wb+"); 163 | if (!output) 164 | { 165 | fprintf(stderr, "ERROR: Could not write to `%s'.\n", tmp_filename.c_str()); 166 | } 167 | else 168 | { 169 | if (export_html) 170 | { 171 | fprintf(output, "\n\n\nLump %u export - %s\n\n\n\n
\n

%s

\n", (*it).id, bsp->map.c_str(), bsp->map.c_str()); 172 | fprintf(output, "

Lump %u - %s (%u)

", (*it).id, (*it).id, LumpName[reference], bsp->size(reference));
173 | 
174 |                         bsp->write(output, reference);
175 | 
176 |                         fprintf(output, "
"); 177 | fprintf(output, "
"); 178 | } 179 | else 180 | { 181 | fprintf(output, "Lump %u - %s (%u)\r\n", (*it).id, LumpName[reference], bsp->size(reference)); 182 | 183 | bsp->write(output, reference); 184 | } 185 | 186 | fclose(output); 187 | } 188 | } 189 | } 190 | n++; 191 | } 192 | 193 | restore_cursor_position(); 194 | printf("100%%\n"); 195 | } 196 | -------------------------------------------------------------------------------- /src/lumps.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LUMPS_H 2 | #define LUMPS_H 3 | 4 | #include 5 | 6 | void write_raw_lumps(BSP::BSP_Handle *bsp, const std::string &path); 7 | void write_bsp(BSP::BSP_Handle *bsp, const std::string &path, std::string filename, bool export_html); 8 | void write_lumps(BSP::BSP_Handle *bsp, const std::string &path, bool export_html); 9 | 10 | #endif // LUMPS_H 11 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "console.hpp" 9 | #include "settings.hpp" 10 | #include "statistics.hpp" 11 | #include "lumps.hpp" 12 | #include "map.hpp" 13 | 14 | using namespace BSP; 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | initialise_console("BSP Decompiler - by Daevius & CoDEmanX"); 19 | 20 | if (argc < 2) 21 | { 22 | fprintf(stderr, "ERROR: Nothing to decompile, drop one or multiple BSP files onto the executable to decompile\n\n"); 23 | system("pause"); 24 | return 1; 25 | } 26 | 27 | //////////////// 28 | 29 | Settings settings; 30 | settings.executable = argv[0]; 31 | 32 | std::string root_path(settings.executable); 33 | root_path = root_path.substr(0, root_path.find_last_of("/\\") + 1); 34 | 35 | std::string data_path = root_path + "data\\"; 36 | boost::filesystem::path bfs_data_path(data_path); 37 | if (!boost::filesystem::exists(bfs_data_path) || !boost::filesystem::is_directory(bfs_data_path)) 38 | { 39 | boost::filesystem::create_directory(bfs_data_path); 40 | } 41 | 42 | //////////////// 43 | 44 | freopen((root_path + "error.log").c_str(), "w", stderr); 45 | 46 | //////////////// 47 | 48 | if (initialise_settings(settings, (root_path + "settings.lua").c_str())) 49 | { 50 | printf("\n"); 51 | system("pause"); 52 | return 1; 53 | } 54 | 55 | //////////////// 56 | 57 | for (int i = 1; i < argc; i++) 58 | { 59 | clock_t clock = std::clock(); 60 | 61 | printf("File %i out of %i:\n\n", i, argc - 1); 62 | 63 | std::string bsp_filename(argv[i]); 64 | bsp_filename = bsp_filename.substr(bsp_filename.find_last_of("/\\") + 1); 65 | 66 | std::string bsp_name = bsp_filename.substr(0, bsp_filename.find_first_of(".")); 67 | std::string bsp_path = data_path;/* + bsp_name + '\\'; 68 | 69 | boost::filesystem::path bfs_bsp_path(bsp_path); 70 | if (!boost::filesystem::exists(bfs_bsp_path) || !boost::filesystem::is_directory(bfs_bsp_path)) 71 | { 72 | boost::filesystem::create_directory(bfs_bsp_path); 73 | }*/ 74 | 75 | //////////////// 76 | 77 | if (settings.batch_file) 78 | { 79 | printf("Generating batch file..."); 80 | if (!boost::filesystem::exists(boost::filesystem::path(bsp_path + bsp_filename))) 81 | { 82 | boost::filesystem::copy_file(argv[i], bsp_path + bsp_filename); 83 | } 84 | printf("done\n"); 85 | 86 | printf("Copying BSP file `%s'...", bsp_filename.c_str()); 87 | std::string batch_filename = bsp_path + "decompile.bat"; 88 | if (!boost::filesystem::exists(boost::filesystem::path(batch_filename))) 89 | { 90 | FILE *batch_file = fopen(batch_filename.c_str(), "wb+"); 91 | if (!batch_file) 92 | { 93 | fprintf(stderr, "ERROR: Could not write to `%s'.\n\n", batch_filename.c_str()); 94 | } 95 | else 96 | { 97 | fprintf(batch_file, "@echo off\r\n\"%s\" \"%s\"", settings.executable.c_str(), (bsp_path + bsp_filename).c_str()); 98 | fclose(batch_file); 99 | } 100 | } 101 | printf("done\n"); 102 | } 103 | 104 | //////////////// 105 | 106 | printf("Parsing BSP file `%s'...\n", bsp_filename.c_str()); 107 | BSP_Handle *bsp = new BSP_Handle(argv[i]); 108 | if (!bsp->success) 109 | { 110 | printf("\n\n"); 111 | 112 | printf("\nFinished in %g seconds\n\n", (float) (std::clock() - clock) / CLOCKS_PER_SEC); 113 | printf("---------------------------------------------\n\n"); 114 | continue; 115 | } 116 | printf("done\n\n"); 117 | 118 | if (!settings.map_version) 119 | { 120 | settings.map_version = bsp->cod_version; 121 | } 122 | 123 | //////////////// 124 | 125 | if (settings.statistics) 126 | { 127 | write_statistics(bsp, bsp_path); 128 | } 129 | 130 | if (settings.export_raw_lumps) 131 | { 132 | boost::filesystem::path bfs_bsp_path_raw_lumps(bsp_path + "raw_lumps\\"); 133 | if (!boost::filesystem::exists(bfs_bsp_path_raw_lumps) || !boost::filesystem::is_directory(bfs_bsp_path_raw_lumps)) 134 | { 135 | boost::filesystem::create_directory(bfs_bsp_path_raw_lumps); 136 | } 137 | 138 | write_raw_lumps(bsp, bsp_path + "raw_lumps\\"); 139 | } 140 | 141 | if (settings.export_bsp) 142 | { 143 | write_bsp(bsp, bsp_path, bsp_name, settings.export_html); 144 | } 145 | 146 | if (settings.export_lumps) 147 | { 148 | boost::filesystem::path bfs_bsp_path_lumps(bsp_path + "lumps\\"); 149 | if (!boost::filesystem::exists(bfs_bsp_path_lumps) || !boost::filesystem::is_directory(bfs_bsp_path_lumps)) 150 | { 151 | boost::filesystem::create_directory(bfs_bsp_path_lumps); 152 | } 153 | 154 | write_lumps(bsp, bsp_path + "lumps\\", settings.export_html); 155 | } 156 | 157 | if (settings.map) 158 | { 159 | write_map(bsp, bsp_path, bsp_name, settings); 160 | } 161 | 162 | //////////////// 163 | 164 | printf("\nFinished in %g seconds\n\n", (float) (std::clock() - clock) / CLOCKS_PER_SEC); 165 | printf("---------------------------------------------\n\n"); 166 | } 167 | 168 | if (settings.pause) 169 | { 170 | system("pause"); 171 | } 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /src/map.cpp: -------------------------------------------------------------------------------- 1 | #include "console.hpp" 2 | #include "map.hpp" 3 | #include "math.hpp" 4 | #include "common.hpp" 5 | #include "cod.hpp" 6 | 7 | #include 8 | #include 9 | 10 | using namespace BSP; 11 | 12 | void write_map(BSP_Handle *bsp, const std::string &bsp_path, const std::string &bsp_name, const Settings &settings) 13 | { 14 | printf("Writing map file...\n"); 15 | 16 | std::string output_filename = bsp_path + bsp_name + ".map"; 17 | FILE *output = fopen(output_filename.c_str(), "wb+"); 18 | if (!output) 19 | { 20 | fprintf(stderr, "ERROR: Could not write to `%s'.\n", output_filename.c_str()); 21 | } 22 | else 23 | { 24 | if (settings.map_version > 1) 25 | { 26 | fprintf(output, "iwmap 4\n"); 27 | 28 | if (settings.map_version > 2) 29 | { 30 | fprintf(output, "\"000_Global\" flags active\n\"The Map\" flags expanded\n"); 31 | 32 | if (settings.map_layers) 33 | { 34 | fprintf(output, "\"Brushes\" flags expanded\n\"Brushes/Tools\" flags\n\"Triangles\" flags expanded\n\"Entities\" flags expanded\n\"Entities/Models\" flags\n\"Entities/Spawns\" flags\n"); 35 | } 36 | } 37 | } 38 | 39 | unsigned int entity_i = 0; 40 | std::list entities; 41 | std::map brushmodels; 42 | 43 | if (bsp->size(ENTITIES)) 44 | { 45 | map_prepare(bsp, output, entities, brushmodels); 46 | } 47 | 48 | if (bsp->size(MODELS)) 49 | { 50 | if (settings.map_version > 1) 51 | { 52 | fprintf(output, "// entity %u\n", entity_i); 53 | } 54 | fprintf(output, "{\n"); 55 | entity_i++; 56 | 57 | if (brushmodels.find(0) != brushmodels.end()) 58 | { 59 | std::map::iterator entity = brushmodels.find(0); 60 | std::map::iterator pair; 61 | for (pair = (*entity).second.pairs.begin(); pair != (*entity).second.pairs.end(); pair++) 62 | { 63 | fprintf(output, "\"%s\" \"%s\"\n", (*pair).first.c_str(), (*pair).second.c_str()); 64 | } 65 | } 66 | 67 | if (settings.map_triangles && bsp->size(TRIANGLESOUPS) && bsp->size(DRAWINDICES) && bsp->size(DRAWVERTICES)) 68 | { 69 | map_triangles(bsp, output, settings, entity_i); 70 | } 71 | 72 | if (settings.map_brushes && bsp->size(BRUSHES) && bsp->size(BRUSHSIDES) && bsp->size(PLANES) && bsp->size(TRIANGLESOUPS) && bsp->size(DRAWINDICES) && bsp->size(DRAWVERTICES)) 73 | { 74 | map_brushes(bsp, output, settings, entity_i, brushmodels); 75 | } 76 | fprintf(output, "}\n"); 77 | } 78 | 79 | /*#ifndef RELEASE 80 | if (settings.map_patches && bsp->size(COLLISIONTRIANGLES) && bsp->size(COLLISIONVERTICES) && bsp->size(MATERIALS)) 81 | { 82 | map_patches(bsp, output, settings, entity_i); 83 | } 84 | #endif*/ 85 | 86 | if ((settings.map_entities || settings.map_models) && bsp->size(ENTITIES) > 1) 87 | { 88 | map_entities(bsp, output, settings, entity_i, entities); 89 | } 90 | 91 | fclose(output); 92 | } 93 | } 94 | 95 | void map_prepare(BSP_Handle *bsp, FILE *output, std::list &entities, std::map &brushmodels) 96 | { 97 | printf(" Preparing..."); 98 | retrieve_cursor_position(); 99 | 100 | entities.assign(bsp->array(ENTITIES) + 1, bsp->array(ENTITIES) + bsp->size(ENTITIES)); 101 | brushmodels[0] = bsp->array(ENTITIES)[0]; 102 | 103 | unsigned int n = 0; 104 | bool remove_entity = false; 105 | std::list::iterator entity; 106 | for (entity = entities.begin(); entity != entities.end(); entity++) 107 | { 108 | restore_cursor_position(); 109 | printf("%3.1f%%", ceil(((float) n / entities.size()) * 1000.0f) / 10.0f); 110 | 111 | bool remove_pair = false; 112 | std::map::iterator terminal; 113 | 114 | std::map::iterator pair; 115 | for (pair = (*entity).pairs.begin(); pair != (*entity).pairs.end(); pair++) 116 | { 117 | if (remove_pair) 118 | { 119 | (*entity).pairs.erase(terminal); 120 | remove_pair = false; 121 | } 122 | 123 | if ((*pair).first == "model" && (*pair).second[0] == '*') 124 | { 125 | std::string id = (*pair).second.substr(1); 126 | (*entity).pairs.erase(pair); 127 | brushmodels[to_int(id)] = (*entity); 128 | remove_entity = true; 129 | break; 130 | } 131 | else if ((*pair).first == "gndLt") 132 | { 133 | terminal = pair; 134 | remove_pair = true; 135 | } 136 | } 137 | 138 | if (remove_entity) 139 | { 140 | entity = entities.erase(entity); 141 | entity--; 142 | remove_entity = false; 143 | } 144 | n++; 145 | } 146 | 147 | restore_cursor_position(); 148 | printf("100.0%%\n"); 149 | } 150 | 151 | void map_brushes(BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i, std::map &brushmodels) 152 | { 153 | printf(" Brushes..."); 154 | retrieve_cursor_position(); 155 | 156 | std::list brushsides; 157 | brushsides.assign(bsp->array(BRUSHSIDES), bsp->array(BRUSHSIDES) + bsp->size(BRUSHSIDES)); 158 | 159 | Brushside *brushside = bsp->array(BRUSHSIDES); 160 | 161 | unsigned int brushmodel = 0; 162 | for (Model *model = bsp->array(MODELS); model < bsp->array(MODELS) + bsp->size(MODELS); model++) 163 | { 164 | if (entity_i && model != bsp->array(MODELS)) 165 | { 166 | fprintf(output, "// entity %u\n", entity_i); 167 | fprintf(output, "{\n"); 168 | entity_i++; 169 | 170 | if (brushmodels.find(brushmodel) != brushmodels.end()) 171 | { 172 | std::map::iterator entity = brushmodels.find(brushmodel); 173 | std::map::iterator pair; 174 | for (pair = (*entity).second.pairs.begin(); pair != (*entity).second.pairs.end(); pair++) 175 | { 176 | fprintf(output, "\"%s\" \"%s\"\n", (*pair).first.c_str(), (*pair).second.c_str()); 177 | } 178 | } 179 | } 180 | 181 | for (Brush *brush = bsp->array(BRUSHES) + model->brushes_offset; brush < bsp->array(BRUSHES) + model->brushes_offset + model->brushes_size; brush++) 182 | { 183 | restore_cursor_position(); 184 | printf("%3.1f%%", ceil(((float) (brush - bsp->array(BRUSHES)) / bsp->size(BRUSHES)) * 1000.0f) / 10.0f); 185 | 186 | std::vector brushplanes; 187 | for (unsigned int i = 0; i < (*brush).sides; i++) 188 | { 189 | Brushplane brushplane; 190 | if (i < 6) 191 | { 192 | switch (i) 193 | { 194 | case 0: 195 | { 196 | brushplane.normal.x = -1.0; 197 | brushplane.normal.y = 0.0; 198 | brushplane.normal.z = 0.0; 199 | break; 200 | } 201 | case 1: 202 | { 203 | brushplane.normal.x = 1.0; 204 | brushplane.normal.y = 0.0; 205 | brushplane.normal.z = 0.0; 206 | break; 207 | } 208 | case 2: 209 | { 210 | brushplane.normal.x = 0.0; 211 | brushplane.normal.y = -1.0; 212 | brushplane.normal.z = 0.0; 213 | break; 214 | } 215 | case 3: 216 | { 217 | brushplane.normal.x = 0.0; 218 | brushplane.normal.y = 1.0; 219 | brushplane.normal.z = 0.0; 220 | break; 221 | } 222 | case 4: 223 | { 224 | brushplane.normal.x = 0.0; 225 | brushplane.normal.y = 0.0; 226 | brushplane.normal.z = -1.0; 227 | break; 228 | } 229 | case 5: 230 | { 231 | brushplane.normal.x = 0.0; 232 | brushplane.normal.y = 0.0; 233 | brushplane.normal.z = 1.0; 234 | break; 235 | } 236 | } 237 | 238 | brushplane.distance = (*brushside).column1.distance; 239 | brushplane.material_id = (*brushside).material_id; 240 | brushplanes.push_back(brushplane); 241 | } 242 | else 243 | { 244 | //if (unique_brushsides.find((*brushside).material_id) == unique_brushsides.end() || unique_brushsides[(*brushside).material_id].find((*brushside).column1.plane) == unique_brushsides[(*brushside).material_id].end()) 245 | //{ 246 | //unique_brushsides[(*brushside).material_id].insert((*brushside).column1.plane); 247 | 248 | Plane *plane = bsp->array(PLANES) + (*brushside).column1.plane; 249 | brushplane.normal.x = (*plane).normal[0]; 250 | brushplane.normal.y = (*plane).normal[1]; 251 | brushplane.normal.z = (*plane).normal[2]; 252 | brushplane.distance = (*plane).distance; 253 | brushplane.material_id = (*brushside).material_id; 254 | 255 | bool unique = true; 256 | std::vector::iterator other_brushplane; 257 | for (other_brushplane = brushplanes.begin(); other_brushplane < brushplanes.end(); other_brushplane++) 258 | { 259 | if (brushplane.material_id == (*other_brushplane).material_id) 260 | { 261 | fprintf(stderr, " id"); 262 | } 263 | fprintf(stderr, " %g %g", brushplane.distance, (*other_brushplane).distance); 264 | if ((brushplane.distance - (*other_brushplane).distance) > 0.0f) 265 | { 266 | fprintf(stderr, " distance"); 267 | } 268 | if (brushplane.normal == (*other_brushplane).normal) 269 | { 270 | fprintf(stderr, " normal"); 271 | } 272 | 273 | if (brushplane.material_id == (*other_brushplane).material_id && ((brushplane.distance - (*other_brushplane).distance) > 0.0f) && brushplane.normal == (*other_brushplane).normal) 274 | { 275 | unique = false; 276 | break; 277 | } 278 | else if (brushplane.material_id == (*other_brushplane).material_id && ((brushplane.distance - (*other_brushplane).distance) < 0.0f) && brushplane.normal == (*other_brushplane).normal) 279 | { 280 | unique = false; 281 | (*other_brushplane) = brushplane; 282 | break; 283 | } 284 | fprintf(stderr, "\n"); 285 | } 286 | 287 | if (unique) 288 | { 289 | brushplanes.push_back(brushplane); 290 | fprintf(stderr, "Brushside: %4u %8.4g %8.4g %8.4g %8.4g %3u\n", (*brushside).column1.plane, brushplane.normal.x, brushplane.normal.y, brushplane.normal.z, brushplane.distance, brushplane.material_id); 291 | } 292 | else 293 | { 294 | fprintf(stderr, "Discarting brushside %u;\r\n", (brushside - bsp->array(BRUSHSIDES))); 295 | } 296 | } 297 | brushside++; 298 | } 299 | fprintf(stderr, "\n"); 300 | 301 | std::map > brushplane_intersections; 302 | 303 | unsigned int n = 0; 304 | std::vector::iterator brushplane; 305 | // print out the results for the other dynamic sides 306 | for (brushplane = (brushplanes.begin() + 6); brushplane < brushplanes.end(); brushplane++) 307 | { 308 | Position position; 309 | double xn = (*brushplane).normal.x, 310 | yn = (*brushplane).normal.y, 311 | zn = (*brushplane).normal.z, 312 | x0 = xn * (*brushplane).distance, 313 | y0 = yn * (*brushplane).distance, 314 | z0 = zn * (*brushplane).distance; 315 | 316 | // find intersections to the static sides 317 | std::vector intersections; 318 | if (xn) 319 | { 320 | //fprintf(error, "On X: %6g %6g %6g %6g:", brushplanes[2].distance, brushplanes[3].distance, brushplanes[4].distance, brushplanes[5].distance); 321 | 322 | position(0.0, brushplanes[2].distance, brushplanes[4].distance); 323 | position.x = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.y * yn) - (position.z * zn)) / xn; 324 | if (within(brushplanes[0].distance, position.x, brushplanes[1].distance)) 325 | { 326 | //fprintf(error, " %6g", position.x); 327 | push_if_unique(intersections, position); 328 | } 329 | 330 | position(0.0, brushplanes[2].distance, brushplanes[5].distance); 331 | position.x = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.y * yn) - (position.z * zn)) / xn; 332 | if (within(brushplanes[0].distance, position.x, brushplanes[1].distance)) 333 | { 334 | //fprintf(error, " %6g", position.x); 335 | push_if_unique(intersections, position); 336 | } 337 | 338 | position(0.0, brushplanes[3].distance, brushplanes[4].distance); 339 | position.x = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.y * yn) - (position.z * zn)) / xn; 340 | if (within(brushplanes[0].distance, position.x, brushplanes[1].distance)) 341 | { 342 | //fprintf(error, " %6g", position.x); 343 | push_if_unique(intersections, position); 344 | } 345 | 346 | position(0.0, brushplanes[3].distance, brushplanes[5].distance); 347 | position.x = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.y * yn) - (position.z * zn)) / xn; 348 | if (within(brushplanes[0].distance, position.x, brushplanes[1].distance)) 349 | { 350 | //fprintf(error, " %6g", position.x); 351 | push_if_unique(intersections, position); 352 | } 353 | 354 | //fprintf(error, "\r\n"); 355 | } 356 | 357 | if (yn) 358 | { 359 | //fprintf(error, "On Y: %6g %6g %6g %6g:", brushplanes[0].distance, brushplanes[1].distance, brushplanes[4].distance, brushplanes[5].distance); 360 | 361 | position(brushplanes[0].distance, 0.0, brushplanes[4].distance); 362 | position.y = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.z * zn)) / yn; 363 | if (within(brushplanes[2].distance, position.y, brushplanes[3].distance)) 364 | { 365 | //fprintf(error, " %6g", position.y); 366 | push_if_unique(intersections, position); 367 | } 368 | 369 | position(brushplanes[0].distance, 0.0, brushplanes[5].distance); 370 | position.y = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.z * zn)) / yn; 371 | if (within(brushplanes[2].distance, position.y, brushplanes[3].distance)) 372 | { 373 | //fprintf(error, " %6g", position.y); 374 | push_if_unique(intersections, position); 375 | } 376 | 377 | position(brushplanes[1].distance, 0.0, brushplanes[4].distance); 378 | position.y = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.z * zn)) / yn; 379 | if (within(brushplanes[2].distance, position.y, brushplanes[3].distance)) 380 | { 381 | //fprintf(error, " %6g", position.y); 382 | push_if_unique(intersections, position); 383 | } 384 | 385 | position(brushplanes[1].distance, 0.0, brushplanes[5].distance); 386 | position.y = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.z * zn)) / yn; 387 | if (within(brushplanes[2].distance, position.y, brushplanes[3].distance)) 388 | { 389 | //fprintf(error, " %6g", position.y); 390 | push_if_unique(intersections, position); 391 | } 392 | 393 | //fprintf(error, "\r\n"); 394 | } 395 | 396 | if (zn) 397 | { 398 | //fprintf(error, "On Z: %6g %6g %6g %6g:", brushplanes[0].distance, brushplanes[1].distance, brushplanes[2].distance, brushplanes[3].distance); 399 | 400 | position(brushplanes[0].distance, brushplanes[2].distance, 0.0); 401 | position.z = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.y * yn)) / zn; 402 | if (within(brushplanes[4].distance, position.z, brushplanes[5].distance)) 403 | { 404 | //fprintf(error, " %6g", position.z); 405 | push_if_unique(intersections, position); 406 | } 407 | 408 | position(brushplanes[0].distance, brushplanes[3].distance, 0.0); 409 | position.z = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.y * yn)) / zn; 410 | if (within(brushplanes[4].distance, position.z, brushplanes[5].distance)) 411 | { 412 | //fprintf(error, " %6g", position.z); 413 | push_if_unique(intersections, position); 414 | } 415 | 416 | position(brushplanes[1].distance, brushplanes[2].distance, 0.0); 417 | position.z = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.y * yn)) / zn; 418 | if (within(brushplanes[4].distance, position.z, brushplanes[5].distance)) 419 | { 420 | //fprintf(error, " %6g", position.z); 421 | push_if_unique(intersections, position); 422 | } 423 | 424 | position(brushplanes[1].distance, brushplanes[3].distance, 0.0); 425 | position.z = ((x0 * xn) + (y0 * yn) + (z0 * zn) - (position.x * xn) - (position.y * yn)) / zn; 426 | if (within(brushplanes[4].distance, position.z, brushplanes[5].distance)) 427 | { 428 | //fprintf(error, " %6g", position.z); 429 | push_if_unique(intersections, position); 430 | } 431 | 432 | //fprintf(error, "\r\n"); 433 | } 434 | 435 | /*fprintf(error, "Max: %u\r\n", intersections.size()); 436 | 437 | std::vector::iterator intersection; 438 | for (intersection = intersections.begin(); intersection < intersections.end(); intersection++) 439 | { 440 | fprintf(error, "- %6g %6g %6g\r\n", (*intersection).x, (*intersection).y, (*intersection).z); 441 | }*/ 442 | 443 | unsigned int max = intersections.size(); 444 | if (max < 3) 445 | { 446 | #ifndef RELEASE 447 | fprintf(stderr, "Ignoring brushside %6u of brush %6u: less then 3 intersections found with the bounding box\n", std::distance(brushplanes.begin(), brushplane), (brush - bsp->array(BRUSHES))); 448 | #endif 449 | n++; 450 | continue; 451 | } 452 | else 453 | { 454 | //fprintf(error, "\r\n\r\n"); 455 | double least_difference = -1.0; 456 | unsigned int least_i = 0, least_j = 0, least_k = 0; 457 | 458 | double tmp_difference = 0.0f; 459 | unsigned int i = 0, j = 0, k = 0; 460 | //bool stop = false; 461 | for (i = 0; i < max; i++) 462 | { 463 | for (j = 0; j < max; j++) 464 | { 465 | if (i != j) 466 | { 467 | for (k = 0; k < max; k++) 468 | { 469 | if (i != k && j != k) 470 | { 471 | Normal normal(triangle_normal(intersections[i], intersections[j], intersections[k])); 472 | tmp_difference = difference(normal.x, (*brushplane).normal.x) + difference(normal.y, (*brushplane).normal.y) + difference(normal.z, (*brushplane).normal.z); 473 | if (tmp_difference < LEAST_VALUE_EPSILON && (tmp_difference < least_difference || least_difference == -1.0)) 474 | { 475 | least_difference = tmp_difference; 476 | least_i = i; 477 | least_j = j; 478 | least_k = k; 479 | } 480 | 481 | //fprintf(error, "Epsilon indication: %g %g %g with normals: %g %g %g %g %g %g", abs(normal.x - (*brushplane).normal[0]), abs(normal.y - (*brushplane).normal[1]), abs(normal.z - (*brushplane).normal[2]), normal.x, normal.y, normal.z, (*brushplane).normal[0], (*brushplane).normal[1], (*brushplane).normal[2]); 482 | /*if (equal(normal.x, (*brushplane).normal[0]) && equal(normal.y, (*brushplane).normal[1]) && equal(normal.z, (*brushplane).normal[2])) 483 | { 484 | //fprintf(error, "...succes\r\n"); 485 | stop = true; 486 | break; 487 | }*/ 488 | //fprintf(error, "\r\n"); 489 | } 490 | } 491 | } 492 | } 493 | } 494 | 495 | if (least_difference == -1.0) 496 | { 497 | #ifndef RELEASE 498 | fprintf(stderr, "\nIgnoring brushside %u of brush %u: no sequence found of 3 intersections giving a correct normal of (%g %g %g) out of these intersections:\n", std::distance(brushplanes.begin(), brushplane), (brush - bsp->array(BRUSHES)), (*brushplane).normal.x, (*brushplane).normal.y, (*brushplane).normal.z); 499 | std::vector::iterator intersection; 500 | for (intersection = intersections.begin(); intersection < intersections.end(); intersection++) 501 | { 502 | fprintf(stderr, "(%g %g %g)\n", (*intersection).x, (*intersection).y, (*intersection).z); 503 | } 504 | 505 | fprintf(stderr, "Those interactions give these combinations and their normal:\n"); 506 | 507 | for (i = 0; i < max; i++) 508 | { 509 | for (j = 0; j < max; j++) 510 | { 511 | if (i != j) 512 | { 513 | for (k = 0; k < max; k++) 514 | { 515 | if (i != k && j != k) 516 | { 517 | Normal normal(triangle_normal(intersections[i], intersections[j], intersections[k])); 518 | fprintf(stderr, "(%g %g %g) (%g %g %g) (%g %g %g) normal: (%g %g %g)\n", intersections[i].x, intersections[i].y, intersections[i].z, intersections[j].x, intersections[j].y, intersections[j].z, intersections[k].x, intersections[k].y, intersections[k].z, normal.x, normal.y, normal.z); 519 | } 520 | } 521 | } 522 | } 523 | } 524 | 525 | fprintf(stderr, "\n"); 526 | #endif 527 | n++; 528 | continue; 529 | } 530 | 531 | brushplane_intersections[n].push_back(intersections[least_i]); 532 | brushplane_intersections[n].push_back(intersections[least_j]); 533 | brushplane_intersections[n].push_back(intersections[least_k]); 534 | } 535 | n++; 536 | } 537 | 538 | #ifndef RELEASE 539 | fprintf(output, "// ###: %2u %2u\n", (brush - bsp->array(BRUSHES)), std::distance(brushplanes.begin(), brushplane)); 540 | #endif 541 | 542 | /*for (brushplane = brushplanes.begin(); brushplane < brushplanes.end(); brushplane++) 543 | { 544 | if (((*brushplane).normal.x + (*brushplane).normal.y + (*brushplane).normal.z) < 0.0) 545 | { 546 | (*brushplane).distance = -(*brushplane).distance; 547 | } 548 | } 549 | 550 | n = 0; 551 | for (brushplane = brushplanes.begin(); brushplane < brushplanes.end(); brushplane++) 552 | { 553 | fprintf(output, "\r\n///////////////////////////////////////////////////////////////////\r\n"); 554 | std::list lines; 555 | for (std::vector::iterator brushplane2 = brushplanes.begin(); brushplane2 < brushplanes.end(); brushplane2++) 556 | { 557 | if (brushplane != brushplane2) 558 | { 559 | if (plane_plane_intersection((*brushplane), (*brushplane2), lines)) 560 | { 561 | fprintf(output, "// slope (%4g, %4g, %4g) %4g || (%4g, %4g, %4g) %4g\r\n", (*brushplane).normal.x, (*brushplane).normal.y, (*brushplane).normal.z, (*brushplane).distance, (*brushplane2).normal.x, (*brushplane2).normal.y, (*brushplane2).normal.z, (*brushplane2).distance); 562 | } 563 | } 564 | } 565 | 566 | unsigned int size = lines.size(); 567 | 568 | for (std::list::iterator line = lines.begin(); line != lines.end(); line++) 569 | { 570 | fprintf(output, "// line (%4g, %4g, %4g) + t(%4g, %4g, %4g)\r\n", (*line).point.x, (*line).point.y, (*line).point.z, (*line).slope.x, (*line).slope.y, (*line).slope.z); 571 | } 572 | 573 | unsigned int v = 0; 574 | Vertex *convex = new Vertex[size], closest_vertex, tmp_vertex; 575 | 576 | bool first_t; 577 | double t, tmp_t; 578 | Line first_line = *(lines.begin()); 579 | std::list::iterator line = lines.begin(), closest_line; 580 | 581 | for (unsigned int i = 0; i < (size - 1); i++) 582 | { 583 | first_t = true; 584 | closest_line = line; 585 | for (std::list::iterator iterator = lines.begin(); iterator != lines.end(); iterator++) 586 | { 587 | if (line != iterator && dot((*brushplane).normal, cross((*line).slope, (*iterator).slope)) > 0.0 && line_line_intersection(*line, *iterator, tmp_vertex, tmp_t)) 588 | { 589 | if (first_t || tmp_t > t) 590 | { 591 | t = tmp_t; 592 | first_t = false; 593 | 594 | closest_line = iterator; 595 | closest_vertex = tmp_vertex; 596 | } 597 | } 598 | } 599 | 600 | if (closest_line != line) 601 | { 602 | fprintf(output, "// xline (%4g, %4g, %4g) (%4g, %4g, %4g)\r\n", (*line).point.x, (*line).point.y, (*line).point.z, (*line).slope.x, (*line).slope.y, (*line).slope.z); 603 | 604 | lines.erase(line); 605 | line = closest_line; 606 | 607 | convex[v] = closest_vertex; 608 | v++; 609 | } 610 | else 611 | { 612 | fprintf(error, "No intersection found between the boundary lines of a flat, convex brushside. %u\r\n", i); 613 | break; 614 | } 615 | } 616 | 617 | if (line_line_intersection(first_line, *(lines.begin()), tmp_vertex, t)) 618 | { 619 | fprintf(output, "// xline (%4g, %4g, %4g) (%4g, %4g, %4g)\r\n", (*lines.begin()).point.x, (*lines.begin()).point.y, (*lines.begin()).point.z, (*lines.begin()).slope.x, (*lines.begin()).slope.y, (*lines.begin()).slope.z); 620 | convex[v] = tmp_vertex; 621 | v++; 622 | } 623 | 624 | fprintf(output, "// convex"); 625 | for (unsigned int i = 0; i < v; i++) 626 | { 627 | ( -1061.09 -2848.28 113 ) ( -1111.3199 -2834.8201 49 ) ( -1111.3199 -2834.8201 113 ) caulk 128 128 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0 628 | fprintf(output, " (%4g, %4g, %4g)", convex[i].x, convex[i].y, convex[i].z); 629 | } 630 | fprintf(output, "\r\n"); 631 | 632 | // see which triangles share the same position as the brush sides 633 | TriangleSoup *triangle_soup; 634 | for (triangle_soup = bsp->array(TRIANGLESOUPS); triangle_soup < bsp->array(TRIANGLESOUPS) + bsp->size(TRIANGLESOUPS); triangle_soup++) 635 | { 636 | if ((*triangle_soup).material_id == (*brushplane).material_id && !((*triangle_soup).triangle_length % 3) && !((*triangle_soup).triangle_offset % 3)) 637 | { 638 | for (unsigned int i = 0; i < ((*triangle_soup).triangle_length / 3); i++) 639 | { 640 | unsigned int offset = ((*triangle_soup).triangle_offset / 3); 641 | 642 | DrawVertex *drawvertex[3] = { 643 | &bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[0]], 644 | &bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[1]], 645 | &bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]] 646 | }; 647 | 648 | if (drawvertex[0]->rgba == 0xffffffff && drawvertex[1]->rgba == 0xffffffff && drawvertex[2]->rgba == 0xffffffff) 649 | { 650 | Vertex triangle[3] = { 651 | Vertex(drawvertex[0]->position[0], drawvertex[0]->position[1], drawvertex[0]->position[2]), 652 | Vertex(drawvertex[1]->position[0], drawvertex[1]->position[1], drawvertex[1]->position[2]), 653 | Vertex(drawvertex[2]->position[0], drawvertex[2]->position[1], drawvertex[2]->position[2]) 654 | }; 655 | 656 | Normal normal(drawvertex[0]->normal[0], drawvertex[0]->normal[1], drawvertex[0]->normal[2]); 657 | normal /= normal.length(); 658 | 659 | Normal convex_normal = cross(convex[1] - convex[0], convex[2] - convex[0]); 660 | convex_normal /= convex_normal.length(); 661 | 662 | //fprintf(output, "// normal2 (%4g, %4g, %4g)\r\n", normal2.x, normal2.y, normal2.z); 663 | fprintf(output, "// normal (%4g, %4g, %4g) %4g == (%4g, %4g, %4g) %4g\r\n", normal.x, normal.y, normal.z, dot(normal, triangle[0]), (*brushplane).normal.x, (*brushplane).normal.y, (*brushplane).normal.z, (*brushplane).distance); 664 | if (coplanar(triangle, normal, *brushplane))//in_brushplane(triangle[0], normal[0], *brushplane) && in_brushplane(triangle[1], normal[1], *brushplane) && in_brushplane(triangle[2], normal[2], *brushplane)) 665 | { 666 | //fprintf(output, "// #%2u: %2u %2u %2u %2u", n, (triangle_soup - bsp->array(TRIANGLESOUPS)), i, (brush - bsp->array(BRUSHES)), std::distance(brushplanes.begin(), brushplane)); 667 | fprintf(output, "// coplanar (%4g, %4g, %4g) (%4g, %4g, %4g) (%4g, %4g, %4g)\r\n", triangle[0].x, triangle[0].y, triangle[0].z, triangle[1].x, triangle[1].y, triangle[1].z, triangle[2].x, triangle[2].y, triangle[2].z); 668 | if (triangle_overlaps_convex(triangle, normal, convex, v, convex_normal)) 669 | { 670 | fprintf(output, "YES!\r\n"); 671 | } 672 | n++; 673 | } 674 | } 675 | } 676 | } 677 | } 678 | 679 | delete[] convex; 680 | fprintf(output, "\r\n"); 681 | }*/ 682 | 683 | // print out the results of the 6 static sides 684 | fprintf(output, "// brush %u\n{\n", (brush - bsp->array(BRUSHES))); 685 | 686 | if (settings.map_layers && settings.map_version > 2) 687 | { 688 | bool tool = true; 689 | for (brushplane = brushplanes.begin(); brushplane < brushplanes.end(); brushplane++) 690 | { 691 | if (!tool_texture(bsp->array(MATERIALS)[(*brushplane).material_id].name, settings.map_version)) 692 | { 693 | tool = false; 694 | break; 695 | } 696 | } 697 | 698 | if (tool) 699 | { 700 | fprintf(output, "layer \"Brushes/Tools\"\n"); 701 | } 702 | else 703 | { 704 | fprintf(output, "layer \"Brushes\"\n"); 705 | } 706 | } 707 | 708 | write_brush(output, 709 | Position(brushplanes[1].distance, brushplanes[3].distance, brushplanes[4].distance), 710 | Position(brushplanes[0].distance, brushplanes[3].distance, brushplanes[4].distance), 711 | Position(brushplanes[0].distance, brushplanes[2].distance, brushplanes[4].distance), 712 | bsp->array(MATERIALS)[brushplanes[4].material_id].name, 713 | settings 714 | ); 715 | 716 | write_brush(output, 717 | Position(brushplanes[0].distance, brushplanes[2].distance, brushplanes[5].distance), 718 | Position(brushplanes[0].distance, brushplanes[3].distance, brushplanes[5].distance), 719 | Position(brushplanes[1].distance, brushplanes[3].distance, brushplanes[5].distance), 720 | bsp->array(MATERIALS)[brushplanes[5].material_id].name, 721 | settings 722 | ); 723 | 724 | write_brush(output, 725 | Position(brushplanes[0].distance, brushplanes[2].distance, brushplanes[5].distance), 726 | Position(brushplanes[1].distance, brushplanes[2].distance, brushplanes[5].distance), 727 | Position(brushplanes[1].distance, brushplanes[2].distance, brushplanes[4].distance), 728 | bsp->array(MATERIALS)[brushplanes[3].material_id].name, 729 | settings 730 | ); 731 | 732 | write_brush(output, 733 | Position(brushplanes[1].distance, brushplanes[2].distance, brushplanes[5].distance), 734 | Position(brushplanes[1].distance, brushplanes[3].distance, brushplanes[5].distance), 735 | Position(brushplanes[1].distance, brushplanes[3].distance, brushplanes[4].distance), 736 | bsp->array(MATERIALS)[brushplanes[1].material_id].name, 737 | settings 738 | ); 739 | 740 | write_brush(output, 741 | Position(brushplanes[1].distance, brushplanes[3].distance, brushplanes[5].distance), 742 | Position(brushplanes[0].distance, brushplanes[3].distance, brushplanes[5].distance), 743 | Position(brushplanes[0].distance, brushplanes[3].distance, brushplanes[4].distance), 744 | bsp->array(MATERIALS)[brushplanes[2].material_id].name, 745 | settings 746 | ); 747 | 748 | write_brush(output, 749 | Position(brushplanes[0].distance, brushplanes[3].distance, brushplanes[5].distance), 750 | Position(brushplanes[0].distance, brushplanes[2].distance, brushplanes[5].distance), 751 | Position(brushplanes[0].distance, brushplanes[2].distance, brushplanes[4].distance), 752 | bsp->array(MATERIALS)[brushplanes[0].material_id].name, 753 | settings 754 | ); 755 | 756 | n = 0; 757 | for (brushplane = (brushplanes.begin() + 6); brushplane < brushplanes.end(); brushplane++) 758 | { 759 | if (brushplane_intersections.find(n) != brushplane_intersections.end()) 760 | { 761 | write_brush(output, 762 | Position(brushplane_intersections[n][0].x, brushplane_intersections[n][0].y, brushplane_intersections[n][0].z), 763 | Position(brushplane_intersections[n][1].x, brushplane_intersections[n][1].y, brushplane_intersections[n][1].z), 764 | Position(brushplane_intersections[n][2].x, brushplane_intersections[n][2].y, brushplane_intersections[n][2].z), 765 | bsp->array(MATERIALS)[(*brushplane).material_id].name, 766 | settings 767 | ); 768 | } 769 | n++; 770 | } 771 | 772 | fprintf(output, "}\n"); 773 | } 774 | 775 | if ((model + 1) < bsp->array(MODELS) + bsp->size(MODELS)) 776 | { 777 | fprintf(output, "}\n"); 778 | } 779 | brushmodel++; 780 | } 781 | 782 | restore_cursor_position(); 783 | printf("100.0%%\n"); 784 | } 785 | 786 | void map_triangles(BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i) 787 | { 788 | printf(" Triangles..."); 789 | retrieve_cursor_position(); 790 | 791 | /*if (entity_i || (!entity_i && (settings.map_version == 4 || settings.map_version == 5))) 792 | { 793 | fprintf(output, "// entity %u\n", entity_i); 794 | } 795 | fprintf(output, "{\n"); 796 | entity_i++;*/ 797 | 798 | TriangleSoup *triangle_soup; 799 | for (triangle_soup = bsp->array(TRIANGLESOUPS); triangle_soup < bsp->array(TRIANGLESOUPS) + bsp->size(TRIANGLESOUPS); triangle_soup++) 800 | { 801 | restore_cursor_position(); 802 | printf("%3.1f%%", ceil(((float) (triangle_soup - bsp->array(TRIANGLESOUPS)) / bsp->size(TRIANGLESOUPS)) * 1000.0f) / 10.0f); 803 | 804 | if (!((*triangle_soup).triangle_length % 3) && !((*triangle_soup).triangle_offset % 3)) 805 | { 806 | for (unsigned int i = 0; i < ((*triangle_soup).triangle_length / 3); i++) 807 | { 808 | unsigned int offset = ((*triangle_soup).triangle_offset / 3); 809 | 810 | if (settings.map_version > 1) 811 | { 812 | fprintf(output, " {\n mesh\n {\n"); 813 | 814 | if (settings.map_layers && settings.map_version > 2) 815 | { 816 | fprintf(output, "layer \"Triangles\"\n"); 817 | } 818 | 819 | if (settings.map_version > 2) 820 | { 821 | fprintf(output, " toolFlags splitGeo;\n"); 822 | } 823 | 824 | if (settings.caulk_triangles) 825 | { 826 | fprintf(output, " caulk\n"); 827 | } 828 | else 829 | { 830 | fprintf(output, " %s\r\n", bsp->array(MATERIALS)[(*triangle_soup).material_id].name); 831 | } 832 | fprintf(output, " lightmap_gray\n 2 2 16 8\n (\n"); 833 | 834 | if (bsp->cod_version == 1) 835 | { 836 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 837 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 838 | 839 | fprintf(output, " )\n (\n"); 840 | 841 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[1]], settings); 842 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[0]], settings); 843 | } 844 | else if (bsp->cod_version == 2) 845 | { 846 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 847 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 848 | 849 | fprintf(output, " )\n (\n"); 850 | 851 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[1]], settings); 852 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[0]], settings); 853 | } 854 | 855 | fprintf(output, " )\n }\n }\n"); 856 | } 857 | else 858 | { 859 | fprintf(output, " {\n patchTerrainDef3\n {\n"); 860 | 861 | if (settings.caulk_triangles) 862 | { 863 | fprintf(output, " caulk\n"); 864 | } 865 | else 866 | { 867 | char *texture = bsp->array(MATERIALS)[(*triangle_soup).material_id].name; 868 | if (str_prefix("textures/", texture)) 869 | { 870 | texture += strlen("textures/"); 871 | } 872 | fprintf(output, " %s\r\n", texture); 873 | } 874 | fprintf(output, " ( 2 2 0 0 0 15 4 )\n(\n("); 875 | 876 | if (bsp->cod_version == 1) 877 | { 878 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 879 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 880 | 881 | fprintf(output, " )\n("); 882 | 883 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[1]], settings); 884 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[0]], settings); 885 | } 886 | else if (bsp->cod_version == 2) 887 | { 888 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 889 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[2]], settings); 890 | 891 | fprintf(output, " )\n("); 892 | 893 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[1]], settings); 894 | write_vertex(output, bsp->array(DRAWVERTICES)[(*triangle_soup).vertex_offset + bsp->array(DRAWINDICES)[offset + i].vertex[0]], settings); 895 | } 896 | 897 | fprintf(output, " )\n)\n }\n }\n"); 898 | } 899 | } 900 | } 901 | } 902 | 903 | //fprintf(output, "}\n"); 904 | 905 | restore_cursor_position(); 906 | printf("100.0%%\n"); 907 | } 908 | 909 | /*void map_patches(BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i) 910 | { 911 | printf(" Patches..."); 912 | retrieve_cursor_position(); 913 | 914 | fprintf(output, "// entity %u\n{\n", entity_i); 915 | entity_i++; 916 | 917 | std::list triangles; 918 | 919 | CollisionTriangle *collision_triangle; 920 | for (collision_triangle = bsp->array(COLLISIONTRIANGLES); collision_triangle < bsp->array(COLLISIONTRIANGLES) + bsp->size(COLLISIONTRIANGLES); collision_triangle++) 921 | { 922 | restore_cursor_position(); 923 | printf("%3.1f%%", ceil(((float) (collision_triangle - bsp->array(COLLISIONTRIANGLES)) / bsp->size(COLLISIONTRIANGLES)) * 1000.0f) / 10.0f); 924 | 925 | Triangle new_triangle((*collision_triangle).vertex_id[0], (*collision_triangle).vertex_id[1], (*collision_triangle).vertex_id[2]); 926 | 927 | bool found_shared_diagonal = false; 928 | std::list::iterator triangle; 929 | for (triangle = triangles.begin(); triangle != triangles.end(); triangle++) 930 | { 931 | unsigned int vertices[4] = {0, 0, 0, 0}; 932 | if ((*triangle).share_diagonal(new_triangle, vertices)) 933 | { 934 | fprintf(output, " {\n mesh\n {\n"); 935 | if (settings.map_version == 4 || settings.map_version == 5) 936 | { 937 | fprintf(output, " toolFlags splitGeo;\n"); 938 | } 939 | fprintf(output, " caulk\n lightmap_gray\n 2 2 16 8\n (\n"); 940 | 941 | write_vertex(output, bsp->array(COLLISIONVERTICES)[vertices[0]].position[0], bsp->array(COLLISIONVERTICES)[vertices[0]].position[1], bsp->array(COLLISIONVERTICES)[vertices[0]].position[2]); 942 | write_vertex(output, bsp->array(COLLISIONVERTICES)[vertices[1]].position[0], bsp->array(COLLISIONVERTICES)[vertices[1]].position[1], bsp->array(COLLISIONVERTICES)[vertices[1]].position[2]); 943 | 944 | fprintf(output, " )\n (\n"); 945 | write_vertex(output, bsp->array(COLLISIONVERTICES)[vertices[2]].position[0], bsp->array(COLLISIONVERTICES)[vertices[2]].position[1], bsp->array(COLLISIONVERTICES)[vertices[2]].position[2]); 946 | write_vertex(output, bsp->array(COLLISIONVERTICES)[vertices[3]].position[0], bsp->array(COLLISIONVERTICES)[vertices[3]].position[1], bsp->array(COLLISIONVERTICES)[vertices[3]].position[2]); 947 | 948 | fprintf(output, " )\n }\n }\n"); 949 | 950 | found_shared_diagonal = true; 951 | triangles.erase(triangle); 952 | break; 953 | } 954 | } 955 | 956 | if (!found_shared_diagonal) 957 | { 958 | triangles.push_back(new_triangle); 959 | } 960 | } 961 | 962 | fprintf(output, "}\n"); 963 | 964 | restore_cursor_position(); 965 | printf("100.0%%\n"); 966 | }*/ 967 | 968 | void map_entities(BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i, std::list &entities) 969 | { 970 | printf(" Entities..."); 971 | retrieve_cursor_position(); 972 | 973 | unsigned int n = 1; 974 | std::list::iterator entity; 975 | for (entity = entities.begin(); entity != entities.end(); entity++) 976 | { 977 | restore_cursor_position(); 978 | printf("%3.1f%%", ceil(((float) (n - 1) / (bsp->size(ENTITIES) - 1)) * 1000.0f) / 10.0f); 979 | 980 | if (entity_i || (!entity_i && settings.map_version > 1)) 981 | { 982 | fprintf(output, "// entity %u\n", entity_i); 983 | } 984 | fprintf(output, "{\n"); 985 | entity_i++; 986 | 987 | if (settings.map_layers && settings.map_version > 2) 988 | { 989 | if ((*entity).pairs.find("classname")->second == "misc_model" || (*entity).pairs.find("classname")->second == "script_model") 990 | { 991 | if (settings.map_models) 992 | { 993 | fprintf(output, "layer \"Entities/Models\"\n"); 994 | } 995 | } 996 | else if (spawn_classname((*entity).pairs.find("classname")->second.c_str(), settings.map_version)) 997 | { 998 | if (settings.map_spawns) 999 | { 1000 | fprintf(output, "layer \"Entities/Spawns\"\n"); 1001 | } 1002 | } 1003 | else if (settings.map_entities) 1004 | { 1005 | fprintf(output, "layer \"Entities\"\n"); 1006 | } 1007 | } 1008 | 1009 | std::map::iterator pair; 1010 | for (pair = (*entity).pairs.begin(); pair != (*entity).pairs.end(); pair++) 1011 | { 1012 | fprintf(output, " \"%s\" \"%s\"\n", (*pair).first.c_str(), (*pair).second.c_str()); 1013 | } 1014 | 1015 | fprintf(output, "}\n"); 1016 | n++; 1017 | } 1018 | 1019 | restore_cursor_position(); 1020 | printf("100.0%%\n"); 1021 | } 1022 | -------------------------------------------------------------------------------- /src/map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAP_H 2 | #define MAP_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "settings.hpp" 10 | 11 | void write_map(BSP::BSP_Handle *bsp, const std::string &bsp_path, const std::string &bsp_name, const Settings &settings); 12 | void map_prepare(BSP::BSP_Handle *bsp, FILE *output, std::list &entities, std::map &brushmodels); 13 | void map_brushes(BSP::BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i, std::map &brushmodels); 14 | void map_triangles(BSP::BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i); 15 | //void map_patches(BSP::BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i); 16 | void map_entities(BSP::BSP_Handle *bsp, FILE *output, const Settings &settings, unsigned int &entity_i, std::list &entities); 17 | 18 | #endif // MAP_H 19 | -------------------------------------------------------------------------------- /src/math.cpp: -------------------------------------------------------------------------------- 1 | #include "math.hpp" 2 | 3 | bool within(double min, double value, double max) 4 | { 5 | if (equal(value, min) || equal(value, max) || (value > min && value < max)) 6 | { 7 | return true; 8 | } 9 | return false; 10 | } 11 | 12 | Normal triangle_normal(const Position &position1, const Position &position2, const Position &position3) 13 | { 14 | Vector vector1(position2.x - position1.x, position2.y - position1.y, position2.z - position1.z); 15 | Vector vector2(position3.x - position1.x, position3.y - position1.y, position3.z - position1.z); 16 | Vector vector3; 17 | 18 | vector3.x = (vector1.y * vector2.z) - (vector1.z * vector2.y); 19 | vector3.y = (vector1.z * vector2.x) - (vector1.x * vector2.z); 20 | vector3.z = (vector1.x * vector2.y) - (vector1.y * vector2.x); 21 | 22 | Normal normal; 23 | double distance = sqrt((vector3.x * vector3.x) + (vector3.y * vector3.y) + (vector3.z * vector3.z)); 24 | if (equal(distance, 0.0)) 25 | { 26 | return Normal(0, 0, 0); 27 | } 28 | 29 | normal.x = -vector3.x / distance; 30 | normal.y = -vector3.y / distance; 31 | normal.z = -vector3.z / distance; 32 | return normal; 33 | } 34 | -------------------------------------------------------------------------------- /src/math.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H 2 | #define MATH_H 3 | 4 | #define EPSILON 0.000025 5 | #define LEAST_VALUE_EPSILON 0.000100 6 | 7 | #include 8 | 9 | inline 10 | bool equal(double value1, double value2) 11 | { 12 | return ((value1 == value2) || EPSILON > fabs(value1 - value2)); 13 | } 14 | 15 | inline 16 | double difference(double value1, double value2) 17 | { 18 | return fabs(value1 - value2); 19 | } 20 | 21 | bool within(double min, double value, double max); 22 | 23 | struct Vector 24 | { 25 | double x, y, z; 26 | 27 | Vector() 28 | { 29 | } 30 | 31 | Vector(double x, double y, double z) : 32 | x(x), 33 | y(y), 34 | z(z) 35 | { 36 | } 37 | 38 | void operator() (double ix = 0.0, double iy = 0.0, double iz = 0.0) 39 | { 40 | x = ix; 41 | y = iy; 42 | z = iz; 43 | } 44 | 45 | double length() const 46 | { 47 | return sqrt((x * x) + (y * y) + (z * z)); 48 | } 49 | 50 | operator bool () const 51 | { 52 | if (equal(x, 0.0) && equal(y, 0.0) && equal(z, 0.0)) 53 | { 54 | return false; 55 | } 56 | return true; 57 | } 58 | 59 | bool operator! () const 60 | { 61 | if (equal(x, 0.0) && equal(y, 0.0) && equal(z, 0.0)) 62 | { 63 | return true; 64 | } 65 | return false; 66 | } 67 | 68 | bool operator== (const Vector &vector) const 69 | { 70 | if (equal(x, vector.x) && equal(y, vector.y) && equal(z, vector.z)) 71 | { 72 | return true; 73 | } 74 | return false; 75 | } 76 | 77 | bool operator!= (const Vector &vector) const 78 | { 79 | if (equal(x, vector.x) && equal(y, vector.y) && equal(z, vector.z)) 80 | { 81 | return false; 82 | } 83 | return true; 84 | } 85 | 86 | Vector operator+ () const 87 | { 88 | return Vector(x, y, z); 89 | } 90 | 91 | Vector operator+ (const Vector &vector) const 92 | { 93 | return Vector(x + vector.x, y + vector.y, z + vector.z); 94 | } 95 | 96 | void operator+= (const Vector &vector) 97 | { 98 | x += vector.x; 99 | y += vector.y; 100 | z += vector.z; 101 | } 102 | 103 | Vector operator- () const 104 | { 105 | return Vector(-x, -y, -z); 106 | } 107 | 108 | Vector operator- (const Vector &vector) const 109 | { 110 | return Vector(x - vector.x, y - vector.y, z - vector.z); 111 | } 112 | 113 | void operator-= (const Vector &vector) 114 | { 115 | x -= vector.x; 116 | y -= vector.y; 117 | z -= vector.z; 118 | } 119 | 120 | Vector operator* (double scalar) const 121 | { 122 | return Vector(x * scalar, y * scalar, z * scalar); 123 | } 124 | 125 | Vector operator* (const Vector &vector) const 126 | { 127 | return Vector(x * vector.x, y * vector.y, z * vector.z); 128 | } 129 | 130 | void operator*= (double scalar) 131 | { 132 | x *= scalar; 133 | y *= scalar; 134 | z *= scalar; 135 | } 136 | 137 | void operator*= (const Vector &vector) 138 | { 139 | x *= vector.x; 140 | y *= vector.y; 141 | z *= vector.z; 142 | } 143 | 144 | Vector operator/ (double scalar) const 145 | { 146 | return Vector(x / scalar, y / scalar, z / scalar); 147 | } 148 | 149 | Vector operator/ (const Vector &vector) const 150 | { 151 | return Vector(x / vector.x, y / vector.y, z / vector.z); 152 | } 153 | 154 | void operator/= (double scalar) 155 | { 156 | x /= scalar; 157 | y /= scalar; 158 | z /= scalar; 159 | } 160 | 161 | void operator/= (const Vector &vector) 162 | { 163 | x /= vector.x; 164 | y /= vector.y; 165 | z /= vector.z; 166 | } 167 | }; 168 | 169 | typedef Vector Normal; 170 | typedef Vector Position; 171 | typedef Vector Vertex; 172 | 173 | Normal triangle_normal(const Position &position1, const Position &position2, const Position &position3); 174 | 175 | struct Triangle 176 | { 177 | unsigned int id[3]; 178 | 179 | Triangle(unsigned int id1, unsigned int id2, unsigned int id3) 180 | { 181 | id[0] = id1; 182 | id[1] = id2; 183 | id[2] = id3; 184 | } 185 | 186 | bool share_diagonal(Triangle &triangle, unsigned int *vertices) 187 | { 188 | unsigned int shared_vertices = 0; 189 | bool had_first_shared = false; 190 | 191 | unsigned int i = 0, j = 0; 192 | for (i = 0; i < 3; i++) 193 | { 194 | bool shared = false; 195 | for (j = 0; j < 3; j++) 196 | { 197 | if (id[i] == triangle.id[j]) 198 | { 199 | shared_vertices++; 200 | 201 | if (!had_first_shared) 202 | { 203 | vertices[1] = id[i]; 204 | had_first_shared = true; 205 | } 206 | else 207 | { 208 | vertices[2] = id[i]; 209 | } 210 | shared = true; 211 | break; 212 | } 213 | } 214 | 215 | if (!shared) 216 | { 217 | vertices[0] = id[i]; 218 | } 219 | } 220 | 221 | for (i = 0; i < 3; i++) 222 | { 223 | bool shared = false; 224 | for (j = 0; j < 3; j++) 225 | { 226 | if (triangle.id[i] == id[j]) 227 | { 228 | shared = true; 229 | break; 230 | } 231 | } 232 | 233 | if (!shared) 234 | { 235 | vertices[3] = triangle.id[i]; 236 | break; 237 | } 238 | } 239 | 240 | if (shared_vertices == 2) 241 | { 242 | return true; 243 | } 244 | return false; 245 | } 246 | }; 247 | 248 | #endif // MATH_H 249 | -------------------------------------------------------------------------------- /src/settings.cpp: -------------------------------------------------------------------------------- 1 | #include "settings.hpp" 2 | 3 | #include 4 | 5 | extern "C" 6 | { 7 | #include 8 | #include 9 | #include 10 | } 11 | 12 | int initialise_settings(Settings &settings, const char *filename) 13 | { 14 | lua_State *lua_state = lua_open(); 15 | if (luaL_loadfile(lua_state, filename) || lua_pcall(lua_state, 0, 0, 0)) 16 | { 17 | fprintf(stderr, "ERROR: Lua says `%s'\n", lua_tostring(lua_state, -1)); 18 | lua_close(lua_state); 19 | return 1; 20 | } 21 | else 22 | { 23 | //////////////// 24 | 25 | lua_getglobal(lua_state, "pause"); 26 | if (lua_isnumber(lua_state, -1)) 27 | { 28 | settings.pause = lua_tonumber(lua_state, -1); 29 | } 30 | else 31 | { 32 | fprintf(stderr, "WARNING: No setting for `pause' given, defaulting to 0\n"); 33 | } 34 | lua_pop(lua_state, 1); 35 | 36 | //////////////// 37 | 38 | lua_getglobal(lua_state, "batch_file"); 39 | if (lua_isnumber(lua_state, -1)) 40 | { 41 | settings.batch_file = lua_tonumber(lua_state, -1); 42 | } 43 | else 44 | { 45 | fprintf(stderr, "WARNING: No setting for `batch_file' given, defaulting to 0\n"); 46 | } 47 | lua_pop(lua_state, 1); 48 | 49 | lua_getglobal(lua_state, "statistics"); 50 | if (lua_isnumber(lua_state, -1)) 51 | { 52 | settings.statistics = lua_tonumber(lua_state, -1); 53 | } 54 | else 55 | { 56 | fprintf(stderr, "WARNING: No setting for `statistics' given, defaulting to 0\n"); 57 | } 58 | lua_pop(lua_state, 1); 59 | 60 | //////////////// 61 | 62 | lua_getglobal(lua_state, "export_raw_lumps"); 63 | if (lua_isnumber(lua_state, -1)) 64 | { 65 | settings.export_raw_lumps = lua_tonumber(lua_state, -1); 66 | } 67 | else 68 | { 69 | fprintf(stderr, "WARNING: No setting for `export_raw_lumps' given, defaulting to 0\n"); 70 | } 71 | lua_pop(lua_state, 1); 72 | 73 | lua_getglobal(lua_state, "export_html"); 74 | if (lua_isnumber(lua_state, -1)) 75 | { 76 | settings.export_html = lua_tonumber(lua_state, -1); 77 | } 78 | else 79 | { 80 | fprintf(stderr, "WARNING: No setting for `export_html' given, defaulting to 0\n"); 81 | } 82 | lua_pop(lua_state, 1); 83 | 84 | lua_getglobal(lua_state, "export_bsp"); 85 | if (lua_isnumber(lua_state, -1)) 86 | { 87 | settings.export_bsp = lua_tonumber(lua_state, -1); 88 | } 89 | else 90 | { 91 | fprintf(stderr, "WARNING: No setting for `export_bsp' given, defaulting to 0\n"); 92 | } 93 | lua_pop(lua_state, 1); 94 | 95 | lua_getglobal(lua_state, "export_lumps"); 96 | if (lua_isnumber(lua_state, -1)) 97 | { 98 | settings.export_lumps = lua_tonumber(lua_state, -1); 99 | } 100 | else 101 | { 102 | fprintf(stderr, "WARNING: No setting for `export_lumps' given, defaulting to 0\n"); 103 | } 104 | lua_pop(lua_state, 1); 105 | 106 | //////////////// 107 | 108 | lua_getglobal(lua_state, "map"); 109 | if (lua_isnumber(lua_state, -1)) 110 | { 111 | settings.map = lua_tonumber(lua_state, -1); 112 | } 113 | else 114 | { 115 | fprintf(stderr, "WARNING: No setting for `map' given, defaulting to 0\n"); 116 | } 117 | lua_pop(lua_state, 1); 118 | 119 | lua_getglobal(lua_state, "map_version"); 120 | if (lua_isnumber(lua_state, -1)) 121 | { 122 | settings.map_version = lua_tonumber(lua_state, -1); 123 | } 124 | 125 | if (settings.map_version != 0 && settings.map_version != 1 && settings.map_version != 2 && settings.map_version != 4 && settings.map_version != 5) 126 | { 127 | fprintf(stderr, "WARNING: No setting for `map_version' given, defaulting to 0\n"); 128 | settings.map_version = 0; 129 | } 130 | lua_pop(lua_state, 1); 131 | 132 | lua_getglobal(lua_state, "map_layers"); 133 | if (lua_isnumber(lua_state, -1)) 134 | { 135 | settings.map_layers = lua_tonumber(lua_state, -1); 136 | } 137 | else 138 | { 139 | fprintf(stderr, "WARNING: No setting for `map_layers' given, defaulting to 0\n"); 140 | } 141 | lua_pop(lua_state, 1); 142 | 143 | lua_getglobal(lua_state, "map_brushes"); 144 | if (lua_isnumber(lua_state, -1)) 145 | { 146 | settings.map_brushes = lua_tonumber(lua_state, -1); 147 | } 148 | else 149 | { 150 | fprintf(stderr, "WARNING: No setting for `map_brushes' given, defaulting to 0\n"); 151 | } 152 | lua_pop(lua_state, 1); 153 | 154 | lua_getglobal(lua_state, "map_triangles"); 155 | if (lua_isnumber(lua_state, -1)) 156 | { 157 | settings.map_triangles = lua_tonumber(lua_state, -1); 158 | } 159 | else 160 | { 161 | fprintf(stderr, "WARNING: No setting for `map_triangles' given, defaulting to 0\n"); 162 | } 163 | lua_pop(lua_state, 1); 164 | 165 | /*lua_getglobal(lua_state, "map_patches"); 166 | if (lua_isnumber(lua_state, -1)) 167 | { 168 | settings.map_patches = lua_tonumber(lua_state, -1); 169 | } 170 | else 171 | { 172 | fprintf(stderr, "WARNING: No setting for `map_patches' given, defaulting to 0\n"); 173 | } 174 | lua_pop(lua_state, 1);*/ 175 | 176 | lua_getglobal(lua_state, "map_entities"); 177 | if (lua_isnumber(lua_state, -1)) 178 | { 179 | settings.map_entities = lua_tonumber(lua_state, -1); 180 | } 181 | else 182 | { 183 | fprintf(stderr, "WARNING: No setting for `map_entities' given, defaulting to 0\n"); 184 | } 185 | lua_pop(lua_state, 1); 186 | 187 | lua_getglobal(lua_state, "map_models"); 188 | if (lua_isnumber(lua_state, -1)) 189 | { 190 | settings.map_models = lua_tonumber(lua_state, -1); 191 | } 192 | else 193 | { 194 | fprintf(stderr, "WARNING: No setting for `map_models' given, defaulting to 0\n"); 195 | } 196 | lua_pop(lua_state, 1); 197 | 198 | lua_getglobal(lua_state, "map_spawns"); 199 | if (lua_isnumber(lua_state, -1)) 200 | { 201 | settings.map_spawns = lua_tonumber(lua_state, -1); 202 | } 203 | else 204 | { 205 | fprintf(stderr, "WARNING: No setting for `map_spawns' given, defaulting to 0\n"); 206 | } 207 | lua_pop(lua_state, 1); 208 | 209 | //////////////// 210 | 211 | lua_getglobal(lua_state, "caulk_brushes"); 212 | if (lua_isnumber(lua_state, -1)) 213 | { 214 | settings.caulk_brushes = lua_tonumber(lua_state, -1); 215 | } 216 | else 217 | { 218 | fprintf(stderr, "WARNING: No setting for `caulk_brushes' given, defaulting to 0\n"); 219 | } 220 | lua_pop(lua_state, 1); 221 | 222 | lua_getglobal(lua_state, "caulk_tool_brushes"); 223 | if (lua_isnumber(lua_state, -1)) 224 | { 225 | settings.caulk_tool_brushes = lua_tonumber(lua_state, -1); 226 | } 227 | else 228 | { 229 | fprintf(stderr, "WARNING: No setting for `caulk_tool_brushes' given, defaulting to 0\n"); 230 | } 231 | lua_pop(lua_state, 1); 232 | 233 | lua_getglobal(lua_state, "caulk_triangles"); 234 | if (lua_isnumber(lua_state, -1)) 235 | { 236 | settings.caulk_triangles = lua_tonumber(lua_state, -1); 237 | } 238 | else 239 | { 240 | fprintf(stderr, "WARNING: No setting for `caulk_triangles' given, defaulting to 0\n"); 241 | } 242 | lua_pop(lua_state, 1); 243 | 244 | //////////////// 245 | 246 | lua_getglobal(lua_state, "layer_split"); 247 | if (lua_isnumber(lua_state, -1)) 248 | { 249 | settings.layer_split = lua_tonumber(lua_state, -1); 250 | } 251 | else 252 | { 253 | fprintf(stderr, "WARNING: No setting for `layer_split' given, defaulting to 0\n"); 254 | } 255 | lua_pop(lua_state, 1); 256 | 257 | //////////////// 258 | 259 | } 260 | lua_close(lua_state); 261 | return 0; 262 | } 263 | -------------------------------------------------------------------------------- /src/settings.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_H 2 | #define SETTINGS_H 3 | 4 | #include 5 | #include 6 | 7 | struct Settings 8 | { 9 | std::string executable; 10 | 11 | bool pause; 12 | 13 | bool batch_file; 14 | bool statistics; 15 | 16 | bool export_raw_lumps; 17 | bool export_html; 18 | bool export_bsp; 19 | bool export_lumps; 20 | 21 | bool map; 22 | int map_version; 23 | bool map_layers; 24 | bool map_brushes; 25 | bool map_triangles; 26 | //bool map_patches; 27 | bool map_entities; 28 | bool map_models; 29 | bool map_spawns; 30 | 31 | bool caulk_brushes; 32 | bool caulk_tool_brushes; 33 | bool caulk_triangles; 34 | 35 | bool layer_split; 36 | 37 | Settings() : 38 | pause(false), 39 | 40 | batch_file(false), 41 | statistics(false), 42 | 43 | export_raw_lumps(false), 44 | export_html(false), 45 | export_bsp(false), 46 | export_lumps(false), 47 | 48 | map(false), 49 | map_version(0), 50 | map_layers(false), 51 | map_brushes(false), 52 | map_triangles(false), 53 | //map_patches(false), 54 | map_entities(false), 55 | map_models(false), 56 | map_spawns(false), 57 | 58 | caulk_brushes(false), 59 | caulk_tool_brushes(false), 60 | caulk_triangles(false), 61 | 62 | layer_split(false) 63 | { 64 | } 65 | }; 66 | 67 | int initialise_settings(Settings &settings, const char *filename); 68 | 69 | #endif // SETTINGS_H 70 | -------------------------------------------------------------------------------- /src/statistics.cpp: -------------------------------------------------------------------------------- 1 | #include "console.hpp" 2 | #include "statistics.hpp" 3 | #include "math.hpp" 4 | 5 | #include 6 | 7 | using namespace BSP; 8 | 9 | void write_statistics(BSP_Handle *bsp, const std::string &path) 10 | { 11 | printf("Writing statistics..."); 12 | 13 | const char *filename = (path + "statistics.txt").c_str(); 14 | FILE *output = fopen(filename, "wb+"); 15 | if (!output) 16 | { 17 | fprintf(stderr, "ERROR: Could not write to `%s'.\n\n", filename); 18 | } 19 | else 20 | { 21 | retrieve_cursor_position(); 22 | printf("0%%"); 23 | 24 | time_t rawtime; 25 | time(&rawtime); 26 | char *time_string = ctime(&rawtime); 27 | time_string[strlen(time_string) - 1] = 0x00; 28 | 29 | fprintf(output, "Filename: %s\r\n", bsp->map.c_str()); 30 | fprintf(output, "Decompile data: %s\r\n", time_string); 31 | fprintf(output, "CoD Version: %i\r\n\r\n", bsp->cod_version); 32 | 33 | if (bsp->cod_version < 3) 34 | { 35 | fprintf(output, "## Offset Size Entries Name\r\n----------------------------------------------------------------------\r\n"); 36 | 37 | std::vector::iterator it; 38 | for (it = bsp->index.begin(); it < bsp->index.end(); it++) 39 | { 40 | fprintf(output, "%02u 0x%08x 0x%08x %6u %s\r\n", (*it).id, (*it).offset, (*it).size, bsp->size(bsp->lump_reference[(*it).id]), LumpName[bsp->lump_reference[(*it).id]]); 41 | } 42 | } 43 | else if (bsp->cod_version > 3) 44 | { 45 | fprintf(output, "## Offset Size Entries Name\r\n----------------------------------------------------------------------\r\n"); 46 | 47 | std::vector::iterator it; 48 | for (it = bsp->index.begin(); it < bsp->index.end(); it++) 49 | { 50 | fprintf(output, "%02u 0x%08x 0x%08x %6u %s\r\n", (*it).id, (*it).offset, (*it).size, bsp->size(bsp->lump_reference[(*it).id]), LumpName[bsp->lump_reference[(*it).id]]); 51 | } 52 | } 53 | 54 | fprintf(output, "\r\nTotal size: 0x%08x; Last lump offset + size: 0x%08x;\r\n", bsp->data.size, bsp->index.back().offset + bsp->index.back().size); 55 | 56 | unsigned int nills = 0; 57 | unsigned int non_ones = 0; 58 | 59 | Plane *plane; 60 | for (plane = bsp->array(PLANES); plane < bsp->array(PLANES) + bsp->size(PLANES); plane++) 61 | { 62 | double length = sqrt((plane->normal[0] * plane->normal[0]) + (plane->normal[1] * plane->normal[1]) + (plane->normal[2] * plane->normal[2])); 63 | 64 | if (equal(length, 0.0)) 65 | { 66 | nills++; 67 | } 68 | else if (!equal(length, 1.0)) 69 | { 70 | non_ones++; 71 | } 72 | } 73 | 74 | fprintf(output, "\r\nPlane normals: non-length(%u); non-normalized(%u);\r\n", nills, non_ones); 75 | 76 | restore_cursor_position(); 77 | printf("100%%"); 78 | 79 | fclose(output); 80 | } 81 | 82 | printf("\n"); 83 | } 84 | -------------------------------------------------------------------------------- /src/statistics.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STATISTICS_H 2 | #define STATISTICS_H 3 | 4 | #include 5 | 6 | void write_statistics(BSP::BSP_Handle *bsp, const std::string &path); 7 | 8 | #endif // STATISTICS_H 9 | 10 | --------------------------------------------------------------------------------