UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
13 static bool SL_CreatePNGFile (const char* filename, unsigned char* buffer, int width, int height)
14 {
15  ScopedFile f;
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 
28 static 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 
107 static 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 
123 static 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 
139 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)
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 
315 void SL_BSPSlice (const TR_TILE_TYPE* model, float thickness, int scale, bool singleFile, bool multipleContour)
316 {
318  vec3_t mins = {-MAX_WORLD_WIDTH, -MAX_WORLD_WIDTH, 0};
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
#define SURF_NODRAW
Definition: defines.h:260
#define VectorCopy(src, dest)
Definition: vector.h:51
#define Mem_AllocTypeN(type, n)
Definition: mem.h:38
unsigned short v[2]
Definition: typedefs.h:400
static bool SL_CreatePNGFile(const char *filename, unsigned char *buffer, int width, int height)
Definition: bspslicer.cpp:13
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition: files.cpp:162
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
static const vec3_t scale
voidpf uLong int origin
Definition: ioapi.h:45
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
const char * filename
Definition: ioapi.h:41
#define UNIT_HEIGHT
Definition: defines.h:122
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
vec3_t maxs
Definition: aabb.h:258
#define VectorScale(in, scale, out)
Definition: vector.h:79
uint32_t surfaceFlags
Definition: typedefs.h:390
void SL_BSPSlice(const TR_TILE_TYPE *model, float thickness, int scale, bool singleFile, bool multipleContour)
Definition: bspslicer.cpp:315
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define SURF_BLEND33
Definition: defines.h:257
AABB dbmBox
Definition: typedefs.h:355
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
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 IMAGE_BUFFER_SET_BLACK(buffer, offset)
Definition: bspslicer.cpp:26
short numedges
Definition: typedefs.h:408
int numfaces
Definition: typedefs.h:358
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define SURF_SKIP
Definition: defines.h:262
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
Definition: defines.h:294
#define VectorAdd(a, b, dest)
Definition: vector.h:47
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition: mathlib.cpp:745
#define DEPTH
Definition: bspslicer.cpp:11
#define Mem_Free(ptr)
Definition: mem.h:35
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
vec_t vec3_t[3]
Definition: ufotypes.h:39
short texinfo
Definition: typedefs.h:409
void R_WritePNG(qFILE *f, byte *buffer, int width, int height)
Definition: images.cpp:56
#define MAX_WORLD_WIDTH
-MAX_WORLD_WIDTH up tp +MAX_WORLD_WIDTH
Definition: defines.h:288
vec3_t mins
Definition: aabb.h:257
#define SURF_HINT
Definition: defines.h:261
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
#define SURF_BLEND66
Definition: defines.h:258
voidpf uLong offset
Definition: ioapi.h:45
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
static float SL_DistanceToIntersection(const vec3_t origin, const vec3_t vector, const vec3_t planeOrigin, const vec3_t planeNormal)
Definition: bspslicer.cpp:107
int firstface
Definition: typedefs.h:358
#define VectorSubtract(a, b, dest)
Definition: vector.h:45