UFO: Alien Invasion
bspslicer.cpp
Go to the documentation of this file.
1/*
2 * @file
3 * @brief Based on the BSP_tool from botman's Half-Life BSP utilities
4 */
5#ifndef ANDROID
6#include "bspslicer.h"
7#include "../ports/system.h"
8#include "../common/common.h"
9#include "../shared/images.h"
10
11#define DEPTH 3
12
13static bool SL_CreatePNGFile (const char* filename, unsigned char* buffer, int width, int height)
14{
16
17 /* create the .bmp file... */
18 if (FS_OpenFile(filename, &f, FILE_WRITE) == -1)
19 return false;
20
21 R_WritePNG(&f, buffer, width, height);
22
23 return true;
24}
25
26#define IMAGE_BUFFER_SET_BLACK(buffer, offset) do {int i; for (i = 0; i < DEPTH; i++) {buffer[offset + i] = 0xFF; } } while(0);
27
28static void SL_Bresenham (int x0, int y0, int x1, int y1, int width, int height, bool rotated, unsigned char* outputBuffer)
29{
30 int dy = y1 - y0;
31 int dx = x1 - x0;
32 int stepx, stepy;
33 int offset;
34 const int maxOffset = width * height * DEPTH;
35
36 if (dy < 0) {
37 dy = -dy;
38 stepy = -1;
39 } else {
40 stepy = 1;
41 }
42 if (dx < 0) {
43 dx = -dx;
44 stepx = -1;
45 } else {
46 stepx = 1;
47 }
48 dy *= 2;
49 dx *= 2;
50
51 if (rotated)
52 offset = x0 * DEPTH * height + y0;
53 else
54 offset = y0 * width * DEPTH + x0 * DEPTH;
55
56 if (offset >= 0 && offset < maxOffset) {
57 IMAGE_BUFFER_SET_BLACK(outputBuffer, offset);
58 } else
59 return;
60
61 if (dx > dy) {
62 int fraction = 2 * dy - (dx >> 1); /* same as 2*dy - dx */
63 while (x0 != x1) {
64 if (fraction >= 0) {
65 y0 += stepy;
66 fraction -= dx; /* same as fraction -= 2*dx */
67 }
68 x0 += stepx;
69 fraction += dy; /* same as fraction -= 2*dy */
70
71 if (rotated)
72 offset = x0 * DEPTH * height + y0;
73 else
74 offset = y0 * width * DEPTH + x0 * DEPTH;
75
76 if (offset >= 0 && offset < maxOffset) {
77 IMAGE_BUFFER_SET_BLACK(outputBuffer, offset);
78 } else
79 return;
80 }
81 } else {
82 int fraction = dx - (dy >> 1);
83 while (y0 != y1) {
84 if (fraction >= 0) {
85 x0 += stepx;
86 fraction -= dy;
87 }
88 y0 += stepy;
89 fraction += dx;
90
91 if (rotated)
92 offset = x0 * DEPTH * height + y0;
93 else
94 offset = y0 * width * DEPTH + x0 * DEPTH;
95
96 if (offset >= 0 && offset < maxOffset) {
97 IMAGE_BUFFER_SET_BLACK(outputBuffer, offset);
98 } else
99 return;
100 }
101 }
102}
103
107static float SL_DistanceToIntersection (const vec3_t origin, const vec3_t vector, const vec3_t planeOrigin, const vec3_t planeNormal)
108{
109 const float d = -(DotProduct(planeNormal, planeOrigin));
110 const float numerator = DotProduct(planeNormal, origin) + d;
111 const float denominator = DotProduct(planeNormal, vector);
112
113 if (fabs(denominator) < 0.00001)
114 /* normal is orthogonal to vector, no intersection */
115 return -1.0f;
116
117 return -(numerator / denominator);
118}
119
123static bool SL_VectorIntersectPlane (const vec3_t origin, const vec3_t vector, const vec3_t planeOrigin, const vec3_t planeNormal, vec3_t intersectPoint)
124{
125 vec3_t v_temp;
126 const float dist = SL_DistanceToIntersection(origin, vector, planeOrigin, planeNormal);
127 if (dist < 0)
128 return false;
129
130 VectorScale(vector, dist, v_temp);
131 VectorAdd(origin, v_temp, intersectPoint);
132
133 return true;
134}
135
139static void SL_SliceTheWorld (const TR_TILE_TYPE* tile, const vec3_t mins, const vec3_t maxs, float stepsize, int scale, bool singleFile, bool multipleContour)
140{
141 vec3_t zDistance = { 0.0f, 0.0f, 0.0f };
142 const vec3_t zNormal = { 0.0f, 0.0f, 1.0f };
143 vec3_t v[2];
144 vec3_t vTemp, intersectPoint;
145 float lineX1, lineY1, lineX2, lineY2;
146 bool first, both;
147 char filename[MAX_QPATH];
148 const float minX = mins[0];
149 const float maxX = maxs[0];
150 const float minY = mins[1];
151 const float maxY = maxs[1];
152 const float minZ = mins[2];
153 const float maxZ = maxs[2];
154
155 const int numberOfSlices = (int) ((maxZ - minZ) / stepsize);
156 int width;
157 int height;
158 bool rotated = false;
159 unsigned char* pictureBuffer;
160
161 lineX1 = lineY1 = lineX2 = lineY2 = 0.0f;
162
163 width = (int) (maxX - minX);
164 height = (int) (maxY - minY);
165
166 /* is the map higher than it is wide? */
167 if (height > width) {
168 rotated = true; /* rotate the map 90 degrees */
169 width = (int) (maxY - minY); /* swap the width and height */
170 height = (int) (maxX - minX);
171 }
172
173 height /= scale;
174 width /= scale;
175
176 pictureBuffer = Mem_AllocTypeN(unsigned char, width * height * DEPTH);
177
178 for (int sliceIndex = 0; sliceIndex < numberOfSlices; sliceIndex++) {
179 const float zHeight = minZ + (sliceIndex * stepsize);
180 zDistance[2] = zHeight;
181
182 /* if not doing a contour map then clear the buffer each pass... */
183 if (!singleFile && !multipleContour)
184 memset(pictureBuffer, 0, width * height * DEPTH);
185
186 /* loop through all the faces of the BSP file... */
187 for (int j = 0; j < tile->nummodels; j++) {
188 const dBspModel_t* model = &tile->models[j];
189 for (int faceIndex = 0; faceIndex < model->numfaces; faceIndex++) {
190 const dBspSurface_t* face = &tile->faces[model->firstface + faceIndex];
191 const dBspTexinfo_t* texinfo = &tile->texinfo[face->texinfo];
193 continue;
196 first = true;
197 both = false;
198
199 /* for each face, loop though all of the edges, getting the vertexes... */
200 for (int edgeIndex = 0; edgeIndex < face->numedges; edgeIndex++) {
201 /* get the coordinates of the vertex of this edge... */
202 int edge = tile->surfedges[face->firstedge + edgeIndex];
203
204 if (edge < 0) {
205 edge = -edge;
206 const dBspEdge_t* e = &tile->edges[edge];
207 v[0][0] = tile->vertexes[e->v[1]].point[0];
208 v[0][1] = tile->vertexes[e->v[1]].point[1];
209 v[0][2] = tile->vertexes[e->v[1]].point[2];
210 } else {
211 const dBspEdge_t* e = &tile->edges[edge];
212 v[0][0] = tile->vertexes[e->v[0]].point[0];
213 v[0][1] = tile->vertexes[e->v[0]].point[1];
214 v[0][2] = tile->vertexes[e->v[0]].point[2];
215 }
216
217 /* get the coordinates of the vertex of the next edge... */
218 edge = tile->surfedges[face->firstedge
219 + ((edgeIndex + 1) % face->numedges)];
220
221 if (edge < 0) {
222 edge = -edge;
223 const dBspEdge_t* e = &tile->edges[edge];
224 v[1][0] = tile->vertexes[e->v[1]].point[0];
225 v[1][1] = tile->vertexes[e->v[1]].point[1];
226 v[1][2] = tile->vertexes[e->v[1]].point[2];
227 } else {
228 const dBspEdge_t* e = &tile->edges[edge];
229 v[1][0] = tile->vertexes[e->v[0]].point[0];
230 v[1][1] = tile->vertexes[e->v[0]].point[1];
231 v[1][2] = tile->vertexes[e->v[0]].point[2];
232 }
233
234 /* vector from v[0] to v[1] intersect the Z plane? */
235 if (((v[0][2] < zHeight) && (v[1][2] > zHeight))
236 || ((v[1][2] < zHeight) && (v[0][2] > zHeight))) {
237 /* create a normalized vector between the 2 vertexes... */
238 VectorSubtract(v[1], v[0], vTemp);
239 VectorNormalize(vTemp);
240
241 /* find the point where the vector intersects the Z plane... */
242 SL_VectorIntersectPlane(v[0], vTemp, zDistance,
243 zNormal, intersectPoint);
244
245 /* is this the first or second Z plane intersection point? */
246 if (first) {
247 first = false;
248 lineX1 = intersectPoint[0];
249 lineY1 = intersectPoint[1];
250 } else {
251 both = true;
252 lineX2 = intersectPoint[0];
253 lineY2 = intersectPoint[1];
254 }
255 }
256
257 /* move v[1] to v[0] */
258 VectorCopy(v[1], v[0]);
259 }
260
261 /* did we find 2 points that intersected the Z plane? */
262 if (both) {
263 /* offset by min_x to start at 0 */
264 lineX1 -= minX;
265 lineX2 -= minX;
266 /* offset by min_y to start at 0 */
267 lineY1 -= minY;
268 lineY2 -= minY;
269
270 lineX1 = lineX1 / scale;
271 lineY1 = lineY1 / scale;
272 lineX2 = lineX2 / scale;
273 lineY2 = lineY2 / scale;
274
275 /* are these points within the bounding box of the world? */
276 if (lineX1 >= 0 && lineX1 < width && lineY1 >= 0 && lineY1 < height
277 && lineX2 >= 0 && lineX2 < width && lineY2 >= 0 && lineY2 < height) {
278 const int x1 = (int) lineX1;
279 const int y1 = (int) lineY1;
280 const int x2 = (int) lineX2;
281 const int y2 = (int) lineY2;
282
283 if (rotated)
284 SL_Bresenham(x1, height - y1, x2, height - y2, width, height, rotated, pictureBuffer);
285 else
286 SL_Bresenham(x1, y1, x2, y2, width, height, rotated, pictureBuffer);
287 }
288 }
289 }
290 }
291
292 if (!singleFile) {
293 Com_sprintf(filename, sizeof(filename), "out%d.png", sliceIndex + 1);
294 Com_Printf("creating %s...\n", filename);
295 SL_CreatePNGFile(filename, pictureBuffer, width, height);
296 }
297 }
298
299 if (singleFile) {
300 Q_strncpyz(filename, "out.png", sizeof(filename));
301 Com_Printf("creating %s...\n", filename);
302 SL_CreatePNGFile(filename, pictureBuffer, width, height);
303 }
304
305 Mem_Free(pictureBuffer);
306}
307
315void SL_BSPSlice (const TR_TILE_TYPE* model, float thickness, int scale, bool singleFile, bool multipleContour)
316{
320
321 if (model == nullptr)
322 return;
323
324 for (int i = 0; i < model->nummodels; i++) {
325 const dBspModel_t* d = &model->models[i];
326 AddPointToBounds(d->dbmBox.mins, mins, maxs);
327 AddPointToBounds(d->dbmBox.maxs, mins, maxs);
328 }
329
330 /* don't start or end on exact multiples of the Z slice thickness
331 * (if you do, it causes "weirdness" in the plane intersect function) */
332
333 /* offset a tiny bit */
334 mins[2] = (float) floor(mins[2]) + 0.01f;
335 maxs[2] = (float) floor(maxs[2]) + 0.01f;
336
337 SL_SliceTheWorld(model, mins, maxs, thickness, scale, singleFile, multipleContour);
338}
339
340#endif
void SL_BSPSlice(const TR_TILE_TYPE *model, float thickness, int scale, bool singleFile, bool multipleContour)
Definition: bspslicer.cpp:315
static bool SL_CreatePNGFile(const char *filename, unsigned char *buffer, int width, int height)
Definition: bspslicer.cpp:13
static void SL_SliceTheWorld(const TR_TILE_TYPE *tile, const vec3_t mins, const vec3_t maxs, float stepsize, int scale, bool singleFile, bool multipleContour)
slice the world in Z planes going from min_z to max_z by stepsize...
Definition: bspslicer.cpp:139
#define DEPTH
Definition: bspslicer.cpp:11
#define IMAGE_BUFFER_SET_BLACK(buffer, offset)
Definition: bspslicer.cpp:26
static bool SL_VectorIntersectPlane(const vec3_t origin, const vec3_t vector, const vec3_t planeOrigin, const vec3_t planeNormal, vec3_t intersectPoint)
Definition: bspslicer.cpp:123
static void SL_Bresenham(int x0, int y0, int x1, int y1, int width, int height, bool rotated, unsigned char *outputBuffer)
Definition: bspslicer.cpp:28
static float SL_DistanceToIntersection(const vec3_t origin, const vec3_t vector, const vec3_t planeOrigin, const vec3_t planeNormal)
Definition: bspslicer.cpp:107
vec3_t maxs
Definition: aabb.h:258
vec3_t mins
Definition: aabb.h:257
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
#define SURF_BLEND66
Definition: defines.h:258
#define UNIT_HEIGHT
Definition: defines.h:122
#define SURF_NODRAW
Definition: defines.h:260
#define SURF_SKIP
Definition: defines.h:262
#define SURF_BLEND33
Definition: defines.h:257
#define SURF_HINT
Definition: defines.h:261
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
Definition: defines.h:294
#define MAX_WORLD_WIDTH
-MAX_WORLD_WIDTH up tp +MAX_WORLD_WIDTH
Definition: defines.h:288
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
#define MAX_QPATH
Definition: filesys.h:40
@ FILE_WRITE
Definition: filesys.h:111
void R_WritePNG(qFILE *f, byte *buffer, int width, int height)
Definition: images.cpp:56
voidpf uLong int origin
Definition: ioapi.h:45
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const char * filename
Definition: ioapi.h:41
voidpf uLong offset
Definition: ioapi.h:45
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition: mathlib.cpp:745
void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs)
If the point is outside the box defined by mins and maxs, expand the box to accommodate it....
Definition: mathlib.cpp:1042
#define Mem_Free(ptr)
Definition: mem.h:35
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
QGL_EXTERN GLint i
Definition: r_gl.h:113
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
unsigned short v[2]
Definition: typedefs.h:400
int numfaces
Definition: typedefs.h:358
int firstface
Definition: typedefs.h:358
AABB dbmBox
Definition: typedefs.h:355
short texinfo
Definition: typedefs.h:409
short numedges
Definition: typedefs.h:408
uint32_t surfaceFlags
Definition: typedefs.h:390
vec_t vec3_t[3]
Definition: ufotypes.h:39
static const vec3_t scale
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
#define VectorCopy(src, dest)
Definition: vector.h:51
#define VectorAdd(a, b, dest)
Definition: vector.h:47
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
#define VectorScale(in, scale, out)
Definition: vector.h:79