1 /** \file map.cc
2 Handles all information about the current map, including the individual cells.
3 */
4 /*
5 Copyright (C) 2000 Mathias Broxvall
6 Yannick Perret
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include "map.h"
24 #include "editMode.h"
25 #include "game.h"
26
27 #include <SDL2/SDL_endian.h>
28 #include <SDL2/SDL_image.h>
29 #include <zlib.h>
30 #include <cstdlib>
31
32 /* VISRADIUS is half-width of square of drawable cells */
33 #define VISRADIUS 50
34 #define CHUNKSIZE 32
35
36 #define WRITE_PORTABLE 1
37 #define READ_PORTABLE 1
38
39 const int Map::flagNone = 0, Map::flagFlashCenter = 1, Map::flagTranslucent = 2,
40 Map::flagShowCross = 4;
41 const int Map::mapFormatVersion = 7;
42
saveInt(int32_t v)43 inline int32_t saveInt(int32_t v) { return (int32_t)SDL_SwapBE32((uint32_t)v); }
loadInt(int32_t v)44 inline int32_t loadInt(int32_t v) { return (int32_t)SDL_SwapBE32((uint32_t)v); }
45
46 /* initialization of some fields to be sure... */
Cell()47 Cell::Cell() {
48 texture = -1;
49 flags = 0;
50 for (int i = 0; i < 5; i++) colors[i] = Color(1., 1., 1., 1.);
51 for (int i = 0; i < 4; i++) wallColors[i] = Color(1., 1., 1., 1.);
52 for (int i = 0; i < 5; i++) heights[i] = -8.0;
53 for (int i = 0; i < 5; i++) waterHeights[i] = -20.0;
54 velocity[0] = 0.;
55 velocity[1] = 1.;
56 sunken = 0.;
57 displayListDirty = false;
58 }
59
calcNormals(const float heights[5],Coord3d normals[5])60 static void calcNormals(const float heights[5], Coord3d normals[5]) {
61 Coord3d spines[4] = {
62 Coord3d(-0.5, -0.5, heights[Cell::SW] - heights[Cell::CENTER]),
63 Coord3d(0.5, -0.5, heights[Cell::SE] - heights[Cell::CENTER]),
64 Coord3d(0.5, 0.5, heights[Cell::NE] - heights[Cell::CENTER]),
65 Coord3d(-0.5, 0.5, heights[Cell::NW] - heights[Cell::CENTER]),
66 };
67
68 Coord3d faceNormals[4];
69 for (int i = 0; i < 4; i++) {
70 faceNormals[i] = crossProduct(spines[i], spines[(i + 1) % 4]);
71 faceNormals[i] = faceNormals[i] / length(faceNormals[i]);
72 }
73 for (int i = 0; i < 5; i++) { normals[i] = Coord3d(); }
74 for (int i = 0; i < 4; i++) {
75 normals[i] = normals[i] + faceNormals[i];
76 normals[i] = normals[i] + faceNormals[(i + 3) % 4];
77 normals[4] = normals[4] + faceNormals[i];
78 }
79 for (int i = 0; i < 5; i++) { normals[i] = normals[i] / length(normals[i]); }
80 }
81
82 /* Returns the average normal at a vertex of the cell */
getNormals(Coord3d normals[5]) const83 void Cell::getNormals(Coord3d normals[5]) const { calcNormals(heights, normals); }
84 /* Works on water heights */
getWaterNormals(Coord3d normals[5]) const85 void Cell::getWaterNormals(Coord3d normals[5]) const { calcNormals(waterHeights, normals); }
86
calcHeight(const float heights[5],Real x,Real y)87 static Real calcHeight(const float heights[5], Real x, Real y) {
88 x = x - 0.5f;
89 y = y - 0.5f;
90
91 Real rp = std::abs(x + y);
92 Real rm = std::abs(x - y);
93 Real ph = y > -x ? heights[Cell::NE] : heights[Cell::SW];
94 Real mh = y > x ? heights[Cell::NW] : heights[Cell::SE];
95 Real ch = heights[Cell::CENTER];
96
97 return ch * (1 - rp - rm) + ph * rp + mh * rm;
98 }
99
100 /* Gives the height of the cell in a specified (floatingpoint) position */
getHeight(Real x,Real y) const101 Real Cell::getHeight(Real x, Real y) const { return calcHeight(heights, x, y); }
102
103 /* Works for water */
getWaterHeight(Real x,Real y) const104 Real Cell::getWaterHeight(Real x, Real y) const { return calcHeight(waterHeights, x, y); }
105
Chunk()106 Chunk::Chunk() {
107 is_active = false;
108 is_visible = false;
109 is_updated = true;
110 last_shown = -1;
111 // Init with extreme range to ensure visibility after which
112 // exact range would be calculated
113 maxHeight = 1e3;
114 minHeight = 1e-3;
115 xm = 0;
116 ym = 0;
117 }
118
~Chunk()119 Chunk::~Chunk() {
120 if (is_active) {
121 glDeleteBuffers(2, &tile_vbo[0]);
122 glDeleteBuffers(2, &flag_vbo[0]);
123 glDeleteBuffers(2, &flui_vbo[0]);
124 glDeleteBuffers(2, &wall_vbo[0]);
125 glDeleteBuffers(2, &line_vbo[0]);
126 glDeleteVertexArrays(1, &tile_vao);
127 glDeleteVertexArrays(1, &flag_vao);
128 glDeleteVertexArrays(1, &flui_vao);
129 glDeleteVertexArrays(1, &wall_vao);
130 glDeleteVertexArrays(1, &line_vao);
131 }
132 }
133
createTextureArray(const char ** texs,int ntex,int size)134 static GLuint createTextureArray(const char** texs, int ntex, int size) {
135 GLuint texture_Array = 0;
136 glGenTextures(1, &texture_Array);
137 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_Array);
138 char* data = new char[ntex * size * size * 4];
139 for (int i = 0; i < ntex; i++) {
140 /* loadImage aborts with error if any of the above textures DNE */
141 SDL_Surface* orig = loadImage(texs[i]);
142 Uint32 mask[4];
143 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
144 mask[0] = 0x000000FF;
145 mask[1] = 0x0000FF00;
146 mask[2] = 0x00FF0000;
147 mask[3] = 0xFF000000;
148 #else
149 mask[0] = 0xFF000000;
150 mask[1] = 0x00FF0000;
151 mask[2] = 0x0000FF00;
152 mask[3] = 0x000000FF;
153 #endif
154 SDL_Surface* proj = SDL_CreateRGBSurface(SDL_SWSURFACE, size, size, 32, mask[0], mask[1],
155 mask[2], mask[3]);
156 SDL_Rect orect = {0, 0, orig->w, orig->h};
157 SDL_Rect drect = {0, 0, size, size};
158 SDL_SetSurfaceBlendMode(orig, SDL_BLENDMODE_NONE);
159 SDL_BlitScaled(orig, &orect, proj, &drect);
160 SDL_FreeSurface(orig);
161 SDL_LockSurface(proj);
162 memcpy(&data[i * size * size * 4], proj->pixels, size * size * 4);
163 SDL_UnlockSurface(proj);
164 SDL_FreeSurface(proj);
165 }
166 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, size, size, ntex, 0, GL_RGBA,
167 GL_UNSIGNED_BYTE, data);
168 delete[] data;
169
170 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
171 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
172 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
173 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
174
175 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_Array);
176 return texture_Array;
177 }
178
Map(char * filename)179 Map::Map(char* filename) {
180 gzFile gp;
181 int x, y, i;
182
183 isBonus = 0;
184
185 memset(mapname, 0, sizeof(mapname));
186 memset(author, 0, sizeof(author));
187 gp = gzopen(filename, "rb");
188 if (gp) {
189 int version;
190 int32_t data[6];
191 gzread(gp, data, sizeof(int32_t) * 6);
192 for (i = 0; i < 3; i++) startPosition[i] = 0.5 + loadInt(data[i]);
193 width = loadInt(data[3]);
194 height = loadInt(data[4]);
195 version = loadInt(data[5]);
196
197 if (version < mapFormatVersion)
198 warning("Warning. Map %s is of an old format (v%d, latest is v%d)", filename, version,
199 mapFormatVersion);
200 else if (version > mapFormatVersion) {
201 error(
202 "Error. Map %s is from the future (v%d, I know only format v%d)\n"
203 "This error usually occurs because or broken maps or big/small endian issues",
204 filename, version, mapFormatVersion);
205 }
206
207 if (version >= 7) { /* Read texture indices */
208 gzread(gp, data, sizeof(int32_t) * 1);
209 int nt = loadInt(data[0]); // num textures used in map
210 char textureName[64];
211 for (i = 0; i < nt; i++) {
212 gzread(gp, textureName, 64);
213 indexTranslation[i] = loadTexture(textureName);
214 }
215 } else // for old maps we just assume that all loaded textures are in the same order as
216 // from creator
217 for (i = 0; i < 256; i++) indexTranslation[i] = i;
218
219 cells = new Cell[width * height];
220
221 for (y = 0; y < height; y++)
222 for (x = 0; x < width; x++) {
223 // We have to do this here since Cell::load does not know it's own coordinates
224 Cell& c = cell(x, y);
225 c.load(this, gp, version);
226 }
227 gzclose(gp);
228 } else {
229 warning("could not open %s", filename);
230 width = height = 256;
231 cells = new Cell[width * height];
232 startPosition[0] = startPosition[1] = 252;
233 startPosition[2] = 0.0;
234 for (x = 0; x < width; x++)
235 for (y = 0; y < height; y++) {
236 Cell& c = cells[x + y * width];
237
238 c.flags = 0;
239 for (i = 0; i < 5; i++) {
240 c.heights[i] = -8.0;
241 c.waterHeights[i] = -8.5; // this is the groundwater =)
242 c.colors[i] = Color(0.9, 0.9, 0.9, 1.0);
243 }
244 for (i = 0; i < 4; i++) { c.wallColors[i] = Color(0.7, 0.2, 0.2, 1.0); }
245 c.velocity[0] = 0.0;
246 c.velocity[1] = 0.0;
247 }
248 }
249
250 /* Fix display lists used by each cell */
251 for (y = 0; y < height; y++)
252 for (x = 0; x < width; x++) {
253 Cell& c = cells[x + y * width];
254 c.displayListDirty = true;
255 }
256
257 flags = flagNone;
258 startPosition[2] = getHeight(startPosition[0], startPosition[1]);
259
260 tx_Ice = loadTexture("ice.png");
261 tx_Acid = loadTexture("acid.png");
262 tx_Sand = loadTexture("sand.png");
263 tx_Track = loadTexture("track.png");
264 tx_1 = loadTexture("texture.png");
265 tx_2 = loadTexture("texture2.png");
266 tx_3 = loadTexture("texture3.png");
267 tx_4 = loadTexture("texture4.png");
268 tx_Water = loadTexture("water.png");
269
270 chunks.clear();
271
272 // Construct texture array
273 const int nsubtextures = 9;
274 const int size = 1 << 8;
275 const char* texs[nsubtextures] = {"blank.png", "ice.png", "sand.png",
276 "acid.png", "track.png", "texture.png",
277 "texture2.png", "texture3.png", "texture4.png"};
278 texture_Array = createTextureArray(texs, nsubtextures, size);
279
280 const int nflags = 8;
281 const char* flags[nflags] = {"transparent.png", "cell_multi.png", "cell_ice.png",
282 "cell_sand.png", "cell_track.png", "cell_acid.png",
283 "cell_trampoline.png", "cell_kill.png"};
284 flag_Array = createTextureArray(flags, nflags, size);
285 }
~Map()286 Map::~Map() {
287 delete[] cells;
288 chunks.clear();
289
290 glDeleteTextures(1, &texture_Array);
291 glDeleteTextures(1, &flag_Array);
292 }
293
configureCellAttributes(bool water)294 static void configureCellAttributes(bool water) {
295 // Position
296 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)0);
297 // Color
298 glVertexAttribPointer(1, 4, GL_UNSIGNED_SHORT, GL_TRUE, 8 * sizeof(GLfloat),
299 (void*)(3 * sizeof(GLfloat)));
300 // Texture
301 if (water) {
302 glVertexAttribPointer(2, 2, GL_UNSIGNED_SHORT, GL_TRUE, 8 * sizeof(GLfloat),
303 (void*)(5 * sizeof(GLfloat)));
304 } else {
305 glVertexAttribPointer(2, 4, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 8 * sizeof(GLfloat),
306 (void*)(5 * sizeof(GLfloat)));
307 }
308 // Normal
309 glVertexAttribPointer(3, 4, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 8 * sizeof(GLfloat),
310 (void*)(6 * sizeof(GLfloat)));
311 // Velocity
312 glVertexAttribPointer(4, 2, GL_SHORT, GL_TRUE, 8 * sizeof(GLfloat),
313 (void*)(7 * sizeof(GLfloat)));
314 glEnableVertexAttribArray(0);
315 glEnableVertexAttribArray(1);
316 glEnableVertexAttribArray(2);
317 glEnableVertexAttribArray(3);
318 glEnableVertexAttribArray(4);
319 }
320
321 /* Draws the map on the screen from current viewpoint */
draw(int stage,const Coord3d & focus,GLfloat gameTime)322 void Map::draw(int stage, const Coord3d& focus, GLfloat gameTime) {
323 if (stage == 0) {
324 glDisable(GL_BLEND);
325 } else {
326 glEnable(GL_BLEND);
327 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
328 }
329
330 int cx = (int)focus[0], cy = (int)focus[1];
331 int origx = cx - cx % CHUNKSIZE, origy = cy - cy % CHUNKSIZE;
332 int prad = (VISRADIUS / CHUNKSIZE) + 1;
333
334 Matrix4d mvp;
335 matrixMult(activeView.modelview, activeView.projection, mvp);
336
337 int nchunks = 0;
338 Chunk* drawlist[1024];
339 for (int i = -prad; i <= prad; i++) {
340 for (int j = -prad; j < +prad; j++) {
341 int hx = origx + i * CHUNKSIZE, hy = origy + j * CHUNKSIZE;
342 Chunk* cur = chunk(hx, hy);
343 int update = 0;
344 if (stage == 0) {
345 // Detect if update needed.
346 update = cur->is_updated;
347
348 int visible = testBboxClip(cur->xm, cur->xm + CHUNKSIZE, cur->ym, cur->ym + CHUNKSIZE,
349 cur->minHeight, cur->maxHeight, mvp);
350
351 // Current cell is in viewport
352 int ox = hx + CHUNKSIZE / 2;
353 int oy = hy + CHUNKSIZE / 2;
354 int inrad = (ox - cx) * (ox - cx) + (oy - cy) * (oy - cy) < 2 * VISRADIUS * VISRADIUS;
355 visible = visible && inrad;
356
357 cur->is_visible = visible;
358 }
359 if (cur->is_visible) {
360 cur->last_shown = displayFrameNumber;
361 drawlist[nchunks] = cur;
362 if (update || !cur->is_active) { fillChunkVBO(drawlist[nchunks]); }
363 nchunks++;
364 } else {
365 // Cleanup buffers for zones that have long since dropped out of view
366 if (cur->is_active && cur->last_shown < displayFrameNumber - 10) {
367 glDeleteBuffers(2, &cur->tile_vbo[0]);
368 glDeleteBuffers(2, &cur->flag_vbo[0]);
369 glDeleteBuffers(2, &cur->flui_vbo[0]);
370 glDeleteBuffers(2, &cur->wall_vbo[0]);
371 glDeleteBuffers(2, &cur->line_vbo[0]);
372 glDeleteVertexArrays(1, &cur->tile_vao);
373 glDeleteVertexArrays(1, &cur->flag_vao);
374 glDeleteVertexArrays(1, &cur->flui_vao);
375 glDeleteVertexArrays(1, &cur->wall_vao);
376 glDeleteVertexArrays(1, &cur->line_vao);
377 cur->is_active = false;
378 }
379 }
380 }
381 }
382
383 // Put into shader
384 setActiveProgramAndUniforms(Shader_Tile);
385 glUniform1i(uniformLocations.render_stage, stage);
386 glUniform1f(uniformLocations.gameTime, gameTime);
387
388 // Link in texture atlas :-)
389 glUniform1i(uniformLocations.arrtex, 0);
390 glActiveTexture(GL_TEXTURE0 + 0);
391 glBindTexture(GL_TEXTURE_2D_ARRAY, texture_Array);
392
393 // Run through ye olde draw loop
394 // WALLS
395 for (int i = 0; i < nchunks; i++) {
396 glBindVertexArray(drawlist[i]->wall_vao);
397 glDrawElements(GL_TRIANGLES, CHUNKSIZE * CHUNKSIZE * 12, GL_UNSIGNED_SHORT, (void*)0);
398 }
399
400 // TOPS
401 for (int i = 0; i < nchunks; i++) {
402 glBindVertexArray(drawlist[i]->tile_vao);
403 glDrawElements(GL_TRIANGLES, CHUNKSIZE * CHUNKSIZE * 12, GL_UNSIGNED_SHORT, (void*)0);
404 }
405
406 if (stage == 1 && activeView.show_flag_state) {
407 glActiveTexture(GL_TEXTURE0 + 0);
408 glBindTexture(GL_TEXTURE_2D_ARRAY, flag_Array);
409
410 for (int i = 0; i < nchunks; i++) {
411 glBindVertexArray(drawlist[i]->flag_vao);
412 glDrawElements(GL_TRIANGLES, CHUNKSIZE * CHUNKSIZE * 12, GL_UNSIGNED_SHORT, (void*)0);
413 }
414 }
415
416 if (stage == 1 && !activeView.calculating_shadows) {
417 setActiveProgramAndUniforms(Shader_Water);
418 glUniform1f(uniformLocations.gameTime, gameTime);
419 glUniform1i(uniformLocations.wtex, 0);
420 glActiveTexture(GL_TEXTURE0 + 0);
421 glBindTexture(GL_TEXTURE_2D, textures[tx_Water]);
422
423 // Water
424 for (int i = 0; i < nchunks; i++) {
425 glBindVertexArray(drawlist[i]->flui_vao);
426 glDrawElements(GL_TRIANGLES, CHUNKSIZE * CHUNKSIZE * 12, GL_UNSIGNED_SHORT, (void*)0);
427 }
428 }
429
430 if (!activeView.calculating_shadows) {
431 setActiveProgramAndUniforms(Shader_Line);
432 glUniformC(uniformLocations.line_color, Color(0., 0., 0., 1.));
433
434 glEnable(GL_LINE_SMOOTH);
435 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
436 glLineWidth(2.0f);
437 for (int i = 0; i < nchunks; i++) {
438 glBindVertexArray(drawlist[i]->line_vao);
439 glDrawElements(GL_LINES, CHUNKSIZE * CHUNKSIZE * 8, GL_UNSIGNED_SHORT, (void*)0);
440 }
441 glDisable(GL_LINE_SMOOTH);
442 }
443
444 // Don't keep any VAOs bound/overwritable
445 glBindVertexArray(0);
446 warnForGLerrors(stage ? "Map drawing 1" : "Map drawing 0");
447 }
448
packCell(GLfloat * fout,GLfloat px,GLfloat py,GLfloat pz,Color color,GLfloat tx,GLfloat ty,int txno,float velx,float vely,const GLfloat normal[3])449 static inline void packCell(GLfloat* fout, GLfloat px, GLfloat py, GLfloat pz, Color color,
450 GLfloat tx, GLfloat ty, int txno, float velx, float vely,
451 const GLfloat normal[3]) {
452 uint32_t* aout = (uint32_t*)fout;
453 fout[0] = px;
454 fout[1] = py;
455 fout[2] = pz;
456 aout[3] = ((uint32_t)(color.v[1]) << 16) + (uint32_t)(color.v[0]);
457 aout[4] = ((uint32_t)(color.v[3]) << 16) + (uint32_t)(color.v[2]);
458
459 uint32_t txco = ((uint32_t)(1023.f * ty) << 10) | ((uint32_t)(1023.f * tx) << 0) |
460 ((uint32_t)(1023.f * (txno / 16.f)) << 20);
461 aout[5] = txco;
462 aout[6] = packNormal(normal);
463
464 int vx = std::max(std::min((int)(32677.f * (velx)), 32677), -32677);
465 int vy = std::max(std::min((int)(32677.f * (vely)), 32677), -32677);
466 aout[7] = ((uint32_t)vy << 16) + (uint32_t)vx;
467 }
packWaterCell(GLfloat * fout,GLfloat px,GLfloat py,GLfloat pz,const float vel[2],GLfloat tx,GLfloat ty,const GLfloat normal[3])468 static inline void packWaterCell(GLfloat* fout, GLfloat px, GLfloat py, GLfloat pz,
469 const float vel[2], GLfloat tx, GLfloat ty,
470 const GLfloat normal[3]) {
471 uint32_t* aout = (uint32_t*)fout;
472 fout[0] = px;
473 fout[1] = py;
474 fout[2] = pz;
475 aout[3] = -1;
476 aout[4] = -1;
477 aout[5] = (((uint32_t)(65535.f * ty)) << 16) + (uint32_t)(65535.f * tx);
478 aout[6] = packNormal(normal);
479 int vx = std::max(std::min((int)(32677.f * (0.25f * vel[0])), 32677), -32677);
480 int vy = std::max(std::min((int)(32677.f * (0.25f * vel[1])), 32677), -32677);
481 aout[7] = ((uint32_t)vy << 16) + (uint32_t)vx;
482 }
483
cmp(float l,float r)484 static inline int cmp(float l, float r) {
485 if (l > r) return 1;
486 if (r > l) return -1;
487 return 0;
488 }
489
fillChunkVBO(Chunk * chunk) const490 void Map::fillChunkVBO(Chunk* chunk) const {
491 GLfloat* tdat = new GLfloat[CHUNKSIZE * CHUNKSIZE * 5 * 8];
492 ushort* tidx = new ushort[CHUNKSIZE * CHUNKSIZE * 12];
493
494 GLfloat* sdat = NULL;
495 ushort* sidx = NULL;
496 if (activeView.show_flag_state) {
497 sdat = new GLfloat[CHUNKSIZE * CHUNKSIZE * 5 * 8];
498 sidx = new ushort[CHUNKSIZE * CHUNKSIZE * 12];
499 }
500 GLfloat* wdat = new GLfloat[CHUNKSIZE * CHUNKSIZE * 8 * 8];
501 ushort* widx = new ushort[CHUNKSIZE * CHUNKSIZE * 12];
502 GLfloat* ldat = new GLfloat[CHUNKSIZE * CHUNKSIZE * 4 * 3];
503 ushort* lidx = new ushort[CHUNKSIZE * CHUNKSIZE * 8];
504 GLfloat* fdat = new GLfloat[CHUNKSIZE * CHUNKSIZE * 8 * 5];
505 ushort* fidx = new ushort[CHUNKSIZE * CHUNKSIZE * 12];
506
507 // Create data if not already there
508 bool first_time = false;
509 if (!chunk->is_active) {
510 glGenBuffers(2, &chunk->tile_vbo[0]);
511 glGenBuffers(2, &chunk->flag_vbo[0]);
512 glGenBuffers(2, &chunk->wall_vbo[0]);
513 glGenBuffers(2, &chunk->line_vbo[0]);
514 glGenBuffers(2, &chunk->flui_vbo[0]);
515 glGenVertexArrays(1, &chunk->tile_vao);
516 glGenVertexArrays(1, &chunk->flag_vao);
517 glGenVertexArrays(1, &chunk->wall_vao);
518 glGenVertexArrays(1, &chunk->line_vao);
519 glGenVertexArrays(1, &chunk->flui_vao);
520 first_time = true;
521 }
522 chunk->is_active = true;
523
524 // Update exact chunk bounds as well, and mark all first-timers as
525 // updated
526 GLfloat minz = 1e99, maxz = -1e99;
527 for (int x = chunk->xm; x < chunk->xm + CHUNKSIZE; x++) {
528 for (int y = chunk->ym; y < chunk->ym + CHUNKSIZE; y++) {
529 Cell& c = cell(x, y);
530 c.displayListDirty |= first_time;
531 for (int k = 0; k < 5; k++) {
532 minz = std::min(minz, c.heights[k]);
533 minz = std::min(minz, c.waterHeights[k]);
534 maxz = std::max(maxz, c.heights[k]);
535 maxz = std::max(maxz, c.waterHeights[k]);
536 }
537 }
538 }
539 int jstart = -1;
540 for (int j = 0; j < CHUNKSIZE * CHUNKSIZE; j++) {
541 int x = chunk->xm + j % CHUNKSIZE;
542 int y = chunk->ym + j / CHUNKSIZE;
543 Cell& c = cell(x, y);
544 if (c.displayListDirty) {
545 if (jstart < 0) { jstart = j; }
546
547 int txno = 0;
548 int typed = c.flags & (CELL_ICE | CELL_ACID | CELL_TRACK | CELL_SAND);
549 if (typed || c.texture >= 0) {
550 if ((c.flags & CELL_ICE) || (!typed && c.texture == tx_Ice)) {
551 txno = 1;
552 } else if ((c.flags & CELL_SAND) || (!typed && c.texture == tx_Sand)) {
553 txno = 2;
554 } else if ((c.flags & CELL_TRACK) || (!typed && c.texture == tx_Track)) {
555 txno = 4;
556 } else if ((c.flags & CELL_ACID) || (!typed && c.texture == tx_Acid)) {
557 txno = 3;
558 } else if (c.texture == tx_1) {
559 txno = 5;
560 } else if (c.texture == tx_2) {
561 txno = 6;
562 } else if (c.texture == tx_3) {
563 txno = 7;
564 } else if (c.texture == tx_4) {
565 txno = 8;
566 }
567 } else {
568 // Nothing much...
569 }
570
571 GLfloat nnormal[3] = {0.f, 1.f, 0.f};
572 GLfloat snormal[3] = {0.f, -1.f, 0.f};
573 GLfloat enormal[3] = {-1.f, 0.f, 0.f};
574 GLfloat wnormal[3] = {1.f, 0.f, 0.f};
575
576 float fcnormal[5][3];
577 if (c.flags & CELL_SHADE_FLAT) {
578 for (size_t i = 0; i < 15; i++) { fcnormal[i / 3][i % 3] = 0.f; }
579 } else {
580 Coord3d cnormal[5];
581 c.getNormals(cnormal);
582 for (size_t i = 0; i < 15; i++) {
583 fcnormal[i / 3][i % 3] = (float)cnormal[i / 3][i % 3];
584 }
585 }
586
587 int k = j * 5 * 8;
588 const int texscale = 3.;
589 const float irs = 1.f / texscale;
590 // ((. % t)+t)%t handles negative numbers
591 GLfloat tx = (((x % texscale) + texscale) % texscale) * irs;
592 GLfloat ty = (((y % texscale) + texscale) % texscale) * irs;
593 if (tx >= 1.) tx = 0.;
594 if (ty >= 1.) ty = 0.;
595 packCell(&tdat[k], x, y, c.heights[Cell::SW], c.colors[Cell::SW], tx, ty, txno,
596 c.velocity[0] * irs, c.velocity[1] * irs, fcnormal[Cell::SW]);
597 packCell(&tdat[k + 8], x + 1, y, c.heights[Cell::SE], c.colors[Cell::SE], tx + irs, ty,
598 txno, c.velocity[0] * irs, c.velocity[1] * irs, fcnormal[Cell::SE]);
599 packCell(&tdat[k + 16], x + 1, y + 1, c.heights[Cell::NE], c.colors[Cell::NE], tx + irs,
600 ty + irs, txno, c.velocity[0] * irs, c.velocity[1] * irs, fcnormal[Cell::NE]);
601 packCell(&tdat[k + 24], x, y + 1, c.heights[Cell::NW], c.colors[Cell::NW], tx, ty + irs,
602 txno, c.velocity[0] * irs, c.velocity[1] * irs, fcnormal[Cell::NW]);
603 packCell(&tdat[k + 32], x + 0.5f, y + 0.5f, c.heights[Cell::CENTER],
604 c.colors[Cell::CENTER], tx + irs / 2, ty + irs / 2, txno, c.velocity[0] * irs,
605 c.velocity[1] * irs, fcnormal[Cell::CENTER]);
606
607 const ushort topindices[12] = {0, 1, 4, 1, 2, 4, 2, 3, 4, 3, 0, 4};
608 for (uint i = 0; i < 12; i++) { tidx[j * 12 + i] = 5 * j + topindices[i]; }
609
610 if (activeView.show_flag_state) {
611 Color white(1.f, 1.f, 1.f, 1.f);
612 float height_boost = 0.001f;
613
614 int flag_list[6] = {CELL_ICE, CELL_SAND, CELL_TRACK,
615 CELL_ACID, CELL_TRAMPOLINE, CELL_KILL};
616
617 int flagno = 0;
618 int nflags = 0;
619 for (int k = 0; k < 6; k++) {
620 if (c.flags & flag_list[k]) {
621 nflags++;
622 flagno = k + 2;
623 }
624 }
625 if (nflags > 1) { flagno = 1; }
626
627 packCell(&sdat[k], x, y, c.heights[Cell::SW] + height_boost, white, 0.f, 0.f, flagno,
628 0.f, 0.f, fcnormal[Cell::SW]);
629 packCell(&sdat[k + 8], x + 1, y, c.heights[Cell::SE] + height_boost, white, 1.f, 0.f,
630 flagno, 0.f, 0.f, fcnormal[Cell::SE]);
631 packCell(&sdat[k + 16], x + 1, y + 1, c.heights[Cell::NE] + height_boost, white, 1.f,
632 1.f, flagno, 0.f, 0.f, fcnormal[Cell::NE]);
633 packCell(&sdat[k + 24], x, y + 1, c.heights[Cell::NW] + height_boost, white, 0.f, 1.f,
634 flagno, 0.f, 0.f, fcnormal[Cell::NW]);
635 packCell(&sdat[k + 32], x + 0.5f, y + 0.5f, c.heights[Cell::CENTER] + height_boost,
636 white, 0.5f, 0.5f, flagno, 0.f, 0.f, fcnormal[Cell::CENTER]);
637
638 for (uint i = 0; i < 12; i++) { sidx[j * 12 + i] = 5 * j + topindices[i]; }
639 }
640
641 // We assume that a quad suffices to render each wall
642 // (otherwise, in the worst case, we'd need 6 vertices/side!
643 int p = j * 8 * 8;
644 const Cell& ns = cell(x, y - 1);
645 const float nv[2] = {0.f, 0.f};
646 int nsover = cmp(c.heights[Cell::SW], ns.heights[Cell::NW]) +
647 cmp(c.heights[Cell::SE], ns.heights[Cell::NE]) >
648 0;
649 packCell(&wdat[p], x, y, c.heights[Cell::SW], c.wallColors[Cell::SW], 0.5f, 0.5f, 0,
650 nv[0], nv[1], nsover ? snormal : nnormal);
651 packCell(&wdat[p + 8], x, y, ns.heights[Cell::NW], ns.wallColors[Cell::NW], 0.5f, 0.5f,
652 0, nv[0], nv[1], nsover ? snormal : nnormal);
653 packCell(&wdat[p + 16], x + 1, y, c.heights[Cell::SE], c.wallColors[Cell::SE], 0.5f,
654 0.5f, 0, nv[0], nv[1], nsover ? snormal : nnormal);
655 packCell(&wdat[p + 24], x + 1, y, ns.heights[Cell::NE], ns.wallColors[Cell::NE], 0.5f,
656 0.5f, 0, nv[0], nv[1], nsover ? snormal : nnormal);
657
658 const Cell& ne = cell(x - 1, y);
659 int ewover = cmp(c.heights[Cell::SW], ne.heights[Cell::SE]) +
660 cmp(c.heights[Cell::NW], ne.heights[Cell::NE]) >
661 0;
662 packCell(&wdat[p + 32], x, y, c.heights[Cell::SW], c.wallColors[Cell::SW], 0.5f, 0.5f, 0,
663 nv[0], nv[1], ewover ? enormal : wnormal);
664 packCell(&wdat[p + 40], x, y, ne.heights[Cell::SE], ne.wallColors[Cell::SE], 0.5f, 0.5f,
665 0, nv[0], nv[1], ewover ? enormal : wnormal);
666 packCell(&wdat[p + 48], x, y + 1, c.heights[Cell::NW], c.wallColors[Cell::NW], 0.5f,
667 0.5f, 0, nv[0], nv[1], ewover ? enormal : wnormal);
668 packCell(&wdat[p + 56], x, y + 1, ne.heights[Cell::NE], ne.wallColors[Cell::NE], 0.5f,
669 0.5f, 0, nv[0], nv[1], ewover ? enormal : wnormal);
670
671 // Render the quads, overlapping triangles if twisted
672 const ushort quadmap[6] = {0, 1, 2, 1, 3, 2};
673 const ushort utriang[6] = {0, 1, 3, 0, 3, 2};
674 const ushort dtriang[6] = {0, 1, 2, 1, 2, 3};
675 const ushort* sel;
676 if (cmp(c.heights[Cell::SW], ns.heights[Cell::NW]) *
677 cmp(c.heights[Cell::SE], ns.heights[Cell::NE]) >=
678 0) {
679 sel = quadmap;
680 } else if (c.heights[Cell::SW] < ns.heights[Cell::NW]) {
681 sel = utriang;
682 } else {
683 sel = dtriang;
684 }
685 for (uint i = 0; i < 6; i++) widx[j * 12 + i] = j * 8 + sel[i];
686
687 const ushort aquadmap[6] = {0, 2, 1, 2, 3, 1};
688 const ushort autriang[6] = {0, 2, 1, 2, 3, 1};
689 const ushort adtriang[6] = {0, 3, 1, 2, 3, 0};
690 if (cmp(c.heights[Cell::SW], ne.heights[Cell::SE]) +
691 cmp(c.heights[Cell::NW], ne.heights[Cell::NE])) {
692 sel = aquadmap;
693 } else if (c.heights[Cell::SW] > ne.heights[Cell::SE]) {
694 sel = autriang;
695 } else {
696 sel = adtriang;
697 }
698 for (uint i = 0; i < 6; i++) widx[j * 12 + 6 + i] = j * 8 + 4 + sel[i];
699
700 // Line data ! (thankfully they're all black)
701 int s = j * 12;
702 ldat[s++] = float(x);
703 ldat[s++] = float(y);
704 ldat[s++] = c.heights[Cell::SW];
705 ldat[s++] = float(x + 1);
706 ldat[s++] = float(y);
707 ldat[s++] = c.heights[Cell::SE];
708 ldat[s++] = float(x + 1);
709 ldat[s++] = float(y + 1);
710 ldat[s++] = c.heights[Cell::NE];
711 ldat[s++] = float(x);
712 ldat[s++] = float(y + 1);
713 ldat[s++] = c.heights[Cell::NW];
714
715 int t = j * 8;
716 // We disable lines by doubling indices
717 lidx[t++] = 4 * j + 0;
718 lidx[t++] = 4 * j + (c.flags & (CELL_NOLINESOUTH | CELL_NOGRID) ? 0 : 1);
719 lidx[t++] = 4 * j + 1;
720 lidx[t++] = 4 * j + (c.flags & (CELL_NOLINEEAST | CELL_NOGRID) ? 1 : 2);
721 lidx[t++] = 4 * j + 2;
722 lidx[t++] = 4 * j + (c.flags & (CELL_NOLINENORTH | CELL_NOGRID) ? 2 : 3);
723 lidx[t++] = 4 * j + 3;
724 lidx[t++] = 4 * j + (c.flags & (CELL_NOLINEWEST | CELL_NOGRID) ? 3 : 0);
725
726 // Water
727 int wvis = c.isWaterVisible();
728 if (wvis) {
729 Coord3d onormal[5];
730 c.getWaterNormals(onormal);
731 float fonormal[5][3];
732 for (size_t i = 0; i < 15; i++) {
733 fonormal[i / 3][i % 3] = (float)onormal[i / 3][i % 3];
734 }
735
736 int u = j * 8 * 5;
737 packWaterCell(&fdat[u], x, y, c.waterHeights[Cell::SW], c.velocity, 0.0f, 0.0f,
738 fonormal[Cell::SW]);
739 packWaterCell(&fdat[u + 8], x + 1, y, c.waterHeights[Cell::SE], c.velocity, 1.0f, 0.0f,
740 fonormal[Cell::SE]);
741 packWaterCell(&fdat[u + 16], x + 1, y + 1, c.waterHeights[Cell::NE], c.velocity, 1.0f,
742 1.0f, fonormal[Cell::NE]);
743 packWaterCell(&fdat[u + 24], x, y + 1, c.waterHeights[Cell::NW], c.velocity, 0.0f,
744 1.0f, fonormal[Cell::NW]);
745 packWaterCell(&fdat[u + 32], x + 0.5f, y + 0.5f, c.waterHeights[Cell::CENTER],
746 c.velocity, 0.5f, 0.5f, fonormal[Cell::CENTER]);
747
748 for (uint i = 0; i < 12; i++) { fidx[j * 12 + i] = 5 * j + topindices[i]; }
749 } else {
750 // Zero tile (safer than uninitialized)
751 memset(&fdat[j * 5 * 8], 0, 5 * 8 * sizeof(GLfloat));
752 for (int i = 0; i < 12; i++) { fidx[j * 12 + i] = 0; }
753 }
754 }
755 if ((!c.displayListDirty || j == CHUNKSIZE * CHUNKSIZE - 1) && jstart >= 0) {
756 int jend = c.displayListDirty ? CHUNKSIZE * CHUNKSIZE : j;
757 size_t tile_data_size = 5 * 8 * sizeof(GLfloat);
758 size_t tile_index_size = 12 * sizeof(ushort);
759 size_t wall_data_size = 8 * 8 * sizeof(GLfloat);
760 size_t wall_index_size = 12 * sizeof(ushort);
761 size_t line_data_size = 4 * 3 * sizeof(GLfloat);
762 size_t line_index_size = 8 * sizeof(ushort);
763 size_t flui_data_size = 5 * 8 * sizeof(GLfloat);
764 size_t flui_index_size = 12 * sizeof(ushort);
765
766 if (first_time) {
767 // Tiles
768 glBindVertexArray(chunk->tile_vao);
769 glBindBuffer(GL_ARRAY_BUFFER, chunk->tile_vbo[0]);
770 glBufferData(GL_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * tile_data_size, tdat,
771 GL_DYNAMIC_DRAW);
772 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->tile_vbo[1]);
773 glBufferData(GL_ELEMENT_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * tile_index_size, tidx,
774 GL_DYNAMIC_DRAW);
775 configureCellAttributes(false);
776
777 if (activeView.show_flag_state) {
778 glBindVertexArray(chunk->flag_vao);
779 glBindBuffer(GL_ARRAY_BUFFER, chunk->flag_vbo[0]);
780 glBufferData(GL_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * tile_data_size, sdat,
781 GL_DYNAMIC_DRAW);
782 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->flag_vbo[1]);
783 glBufferData(GL_ELEMENT_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * tile_index_size, sidx,
784 GL_DYNAMIC_DRAW);
785 configureCellAttributes(false);
786 }
787
788 // Walls
789 glBindVertexArray(chunk->wall_vao);
790 glBindBuffer(GL_ARRAY_BUFFER, chunk->wall_vbo[0]);
791 glBufferData(GL_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * wall_data_size, wdat,
792 GL_DYNAMIC_DRAW);
793 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->wall_vbo[1]);
794 glBufferData(GL_ELEMENT_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * wall_index_size, widx,
795 GL_DYNAMIC_DRAW);
796 configureCellAttributes(false);
797 // Lines
798 glBindVertexArray(chunk->line_vao);
799 glBindBuffer(GL_ARRAY_BUFFER, chunk->line_vbo[0]);
800 glBufferData(GL_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * line_data_size, ldat,
801 GL_DYNAMIC_DRAW);
802 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->line_vbo[1]);
803 glBufferData(GL_ELEMENT_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * line_index_size, lidx,
804 GL_DYNAMIC_DRAW);
805 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
806 glEnableVertexAttribArray(0);
807 // Water
808 glBindVertexArray(chunk->flui_vao);
809 glBindBuffer(GL_ARRAY_BUFFER, chunk->flui_vbo[0]);
810 glBufferData(GL_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * flui_data_size, fdat,
811 GL_DYNAMIC_DRAW);
812 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->flui_vbo[1]);
813 glBufferData(GL_ELEMENT_ARRAY_BUFFER, CHUNKSIZE * CHUNKSIZE * flui_index_size, fidx,
814 GL_DYNAMIC_DRAW);
815 configureCellAttributes(true);
816 } else {
817 // chunk VAOs will automatically use their previously bound VBOs
818 glBindVertexArray(0);
819
820 // Tiles
821 glBindBuffer(GL_ARRAY_BUFFER, chunk->tile_vbo[0]);
822 glBufferSubData(GL_ARRAY_BUFFER, jstart * tile_data_size,
823 (jend - jstart) * tile_data_size,
824 &tdat[jstart * tile_data_size / sizeof(GLfloat)]);
825 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->tile_vbo[1]);
826 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, jstart * tile_index_size,
827 (jend - jstart) * tile_index_size,
828 &tidx[jstart * tile_index_size / sizeof(ushort)]);
829
830 if (activeView.show_flag_state) {
831 glBindBuffer(GL_ARRAY_BUFFER, chunk->flag_vbo[0]);
832 glBufferSubData(GL_ARRAY_BUFFER, jstart * tile_data_size,
833 (jend - jstart) * tile_data_size,
834 &sdat[jstart * tile_data_size / sizeof(GLfloat)]);
835 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->tile_vbo[1]);
836 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, jstart * tile_index_size,
837 (jend - jstart) * tile_index_size,
838 &sidx[jstart * tile_index_size / sizeof(ushort)]);
839 }
840
841 // Walls
842 glBindBuffer(GL_ARRAY_BUFFER, chunk->wall_vbo[0]);
843 glBufferSubData(GL_ARRAY_BUFFER, jstart * wall_data_size,
844 (jend - jstart) * wall_data_size,
845 &wdat[jstart * wall_data_size / sizeof(GLfloat)]);
846 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->wall_vbo[1]);
847 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, jstart * wall_index_size,
848 (jend - jstart) * wall_index_size,
849 &widx[jstart * wall_index_size / sizeof(ushort)]);
850 // Lines
851 glBindBuffer(GL_ARRAY_BUFFER, chunk->line_vbo[0]);
852 glBufferSubData(GL_ARRAY_BUFFER, jstart * line_data_size,
853 (jend - jstart) * line_data_size,
854 &ldat[jstart * line_data_size / sizeof(GLfloat)]);
855 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->line_vbo[1]);
856 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, jstart * line_index_size,
857 (jend - jstart) * line_index_size,
858 &lidx[jstart * line_index_size / sizeof(ushort)]);
859 // Water
860 glBindBuffer(GL_ARRAY_BUFFER, chunk->flui_vbo[0]);
861 glBufferSubData(GL_ARRAY_BUFFER, jstart * flui_data_size,
862 (jend - jstart) * flui_data_size,
863 &fdat[jstart * flui_data_size / sizeof(GLfloat)]);
864 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->flui_vbo[1]);
865 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, jstart * flui_index_size,
866 (jend - jstart) * flui_index_size,
867 &tidx[jstart * flui_index_size / sizeof(ushort)]);
868 }
869 jstart = -1;
870 }
871 }
872
873 // Wipe dirty list. This _MUST_ be a separate phase
874 // since cell(x,y) is not guaranteed to be unique!
875 for (int x = chunk->xm; x < chunk->xm + CHUNKSIZE; x++) {
876 for (int y = chunk->ym; y < chunk->ym + CHUNKSIZE; y++) {
877 cell(x, y).displayListDirty = false;
878 }
879 }
880
881 // Tiles
882
883 delete[] tdat;
884 delete[] tidx;
885 delete[] wdat;
886 delete[] widx;
887 delete[] ldat;
888 delete[] lidx;
889 delete[] fdat;
890 delete[] fidx;
891
892 // Update view parameters
893 chunk->minHeight = minz;
894 chunk->maxHeight = maxz;
895 chunk->is_updated = false;
896 }
897
markCellsUpdated(int x1,int y1,int x2,int y2,bool changed_walls)898 void Map::markCellsUpdated(int x1, int y1, int x2, int y2, bool changed_walls) {
899 /* If the walls of a cell have changed, update its neighbors */
900 int dd = changed_walls ? 1 : 0;
901
902 /* Apply the same clamping to bounds as for cell lookups */
903 int xmin = std::max(std::min(std::min(x1, x2) - dd, width - 1), 0);
904 int xmax = std::max(std::min(std::max(x1, x2) + dd, width - 1), 0);
905 int ymin = std::max(std::min(std::min(y1, y2) - dd, height - 1), 0);
906 int ymax = std::max(std::min(std::max(y1, y2) + dd, height - 1), 0);
907
908 for (int xp = xmin - xmin % CHUNKSIZE; xp <= xmax - xmax % CHUNKSIZE; xp += CHUNKSIZE) {
909 for (int yp = ymin - ymin % CHUNKSIZE; yp <= ymax - ymax % CHUNKSIZE; yp += CHUNKSIZE) {
910 Chunk* z = chunk(xp, yp);
911 z->is_updated = true;
912 for (int x = std::max(xmin, xp); x <= std::min(xmax, xp + CHUNKSIZE - 1); x++) {
913 for (int y = std::max(ymin, yp); y <= std::min(ymax, yp + CHUNKSIZE - 1); y++) {
914 Cell& c = cells[x + width * y];
915 c.displayListDirty = true;
916 for (int k = 0; k < 5; k++) {
917 z->minHeight = std::min(z->minHeight, std::min(c.heights[k], c.waterHeights[k]));
918 z->maxHeight = std::max(z->maxHeight, std::max(c.heights[k], c.waterHeights[k]));
919 }
920 }
921 }
922 }
923 }
924 }
925
drawFootprint(int x1,int y1,int x2,int y2,int kind)926 void Map::drawFootprint(int x1, int y1, int x2, int y2, int kind) {
927 Color color(kind ? 0.5 : 0.2, 0.2, kind ? 0.2 : 0.5, 1.0);
928
929 int ncells = (std::abs(x1 - x2) + 1) * (std::abs(y1 - y2) + 1);
930 if (ncells > 2 * 256 * 256) {
931 warning("Footprint requested for too large an area. Drawing nothing.");
932 glEnable(GL_DEPTH_TEST);
933 return;
934 }
935
936 GLfloat* data = new GLfloat[8 * 8 * ncells];
937 uint* idxs = new uint[8 * 3 * ncells];
938
939 GLfloat edge = 0.05f;
940 const GLfloat flat[3] = {0.f, 0.f, 0.f};
941
942 int j = 0;
943 for (int x = std::min(x1, x2); x <= std::max(x1, x2); ++x) {
944 for (int y = std::min(y1, y2); y <= std::max(y1, y2); ++y) {
945 Cell& center = cell(x, y);
946 packObjectVertex(&data[j * 8 * 8], x + edge, y + edge, center.heights[Cell::SW], 0., 0.,
947 color, flat);
948 packObjectVertex(&data[j * 8 * 8 + 8], x + 1 - edge, y + edge, center.heights[Cell::SE],
949 0., 0., color, flat);
950 packObjectVertex(&data[j * 8 * 8 + 16], x + 1 - edge, y + 1 - edge,
951 center.heights[Cell::NE], 0., 0., color, flat);
952 packObjectVertex(&data[j * 8 * 8 + 24], x + edge, y + 1 - edge, center.heights[Cell::NW],
953 0., 0., color, flat);
954 packObjectVertex(&data[j * 8 * 8 + 32], x - edge, y - edge, center.heights[Cell::SW], 0.,
955 0., color, flat);
956 packObjectVertex(&data[j * 8 * 8 + 40], x + 1 + edge, y - edge, center.heights[Cell::SE],
957 0., 0., color, flat);
958 packObjectVertex(&data[j * 8 * 8 + 48], x + 1 + edge, y + 1 + edge,
959 center.heights[Cell::NE], 0., 0., color, flat);
960 packObjectVertex(&data[j * 8 * 8 + 56], x - edge, y + 1 + edge, center.heights[Cell::NW],
961 0., 0., color, flat);
962
963 uint local_triangles[8][3] = {{4, 5, 0}, {0, 5, 1}, {6, 1, 5}, {1, 6, 2},
964 {7, 2, 6}, {2, 7, 3}, {4, 3, 7}, {3, 4, 0}};
965 for (int i = 0; i < 24; i++) {
966 idxs[j * 24 + i] = local_triangles[i / 3][i % 3] + 8 * j;
967 }
968 j++;
969 }
970 }
971
972 GLuint databuf, idxbuf, vao;
973 glGenBuffers(1, &databuf);
974 glGenBuffers(1, &idxbuf);
975 glGenVertexArrays(1, &vao);
976
977 glBindVertexArray(vao);
978 glBindBuffer(GL_ARRAY_BUFFER, databuf);
979 glBufferData(GL_ARRAY_BUFFER, 8 * 8 * ncells * sizeof(GLfloat), data, GL_STATIC_DRAW);
980
981 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxbuf);
982 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 8 * 3 * ncells * sizeof(uint), idxs, GL_STATIC_DRAW);
983 delete[] data;
984 delete[] idxs;
985
986 glDisable(GL_DEPTH_TEST);
987 glEnable(GL_BLEND);
988 glDisable(GL_CULL_FACE);
989
990 setActiveProgramAndUniforms(Shader_Object);
991 setObjectUniforms(Color(0., 0., 0., 1.), 0., Lighting_None);
992
993 glBindTexture(GL_TEXTURE_2D, textureBlank);
994
995 configureObjectAttributes();
996 glDrawElements(GL_TRIANGLES, 8 * 3 * ncells, GL_UNSIGNED_INT, (void*)0);
997
998 glBindVertexArray(0);
999 glDeleteBuffers(1, &databuf);
1000 glDeleteBuffers(1, &idxbuf);
1001 glDeleteVertexArrays(1, &vao);
1002
1003 glEnable(GL_DEPTH_TEST);
1004 }
1005
drawLoop(int x1,int y1,int x2,int y2,int kind)1006 void Map::drawLoop(int x1, int y1, int x2, int y2, int kind) {
1007 Color color(0.2, kind ? 0.2 : 0.8, 0.2, 1.0);
1008
1009 int npts = 4 * std::abs(x1 - x2) + 4 * std::abs(y1 - y2) + 8;
1010 Coord3d* ringPoints = new Coord3d[npts + 2];
1011 Coord3d* rp = ringPoints;
1012 int k = 1;
1013 /* Traverse loop in order. SW is x,y; N is y+1, E is x+1. */
1014 int xl = std::min(x1, x2), xh = std::max(x1, x2), yl = std::min(y1, y2),
1015 yh = std::max(y1, y2);
1016 for (int x = xl; x <= xh; x++) {
1017 Cell& c = cell(x, yl);
1018 Coord3d lx((double)x, (double)yl, c.heights[Cell::SW]);
1019 Coord3d ly((double)x + 1, (double)yl, c.heights[Cell::SE]);
1020 rp[k] = lx;
1021 k++;
1022 rp[k] = ly;
1023 k++;
1024 }
1025 for (int y = yl; y <= yh; y++) {
1026 Cell& c = cell(xh, y);
1027 Coord3d lx((double)xh + 1, (double)y, c.heights[Cell::SE]);
1028 Coord3d ly((double)xh + 1, (double)y + 1, c.heights[Cell::NE]);
1029 rp[k] = lx;
1030 k++;
1031 rp[k] = ly;
1032 k++;
1033 }
1034 for (int x = xh; x >= xl; x--) {
1035 Cell& c = cell(x, yh);
1036 Coord3d lx((double)x + 1, (double)yh + 1, c.heights[Cell::NE]);
1037 Coord3d ly((double)x, (double)yh + 1, c.heights[Cell::NW]);
1038 rp[k] = lx;
1039 k++;
1040 rp[k] = ly;
1041 k++;
1042 }
1043 for (int y = yh; y >= yl; y--) {
1044 Cell& c = cell(xl, y);
1045 Coord3d lx((double)xl, (double)y + 1, c.heights[Cell::NW]);
1046 Coord3d ly((double)xl, (double)y, c.heights[Cell::NE]);
1047 rp[k] = lx;
1048 k++;
1049 rp[k] = ly;
1050 k++;
1051 }
1052 /* Close the loop */
1053 ringPoints[0] = ringPoints[k - 1];
1054 ringPoints[k] = ringPoints[1];
1055
1056 GLfloat* data = new GLfloat[8 * 2 * npts];
1057 GLfloat width = 0.05f;
1058 GLfloat flat[3] = {0., 0., 0.};
1059 char* pos = (char*)data;
1060 int nontrivial = 0;
1061 for (int i = 1; i < npts + 1; i++) {
1062 Coord3d prev = ringPoints[i - 1], cur = ringPoints[i], nxt = ringPoints[i + 1];
1063 Coord3d dir1 = nxt - cur, dir2 = cur - prev;
1064 if (length(dir1) < 1e-2 && length(dir1) < 1e-2) { continue; }
1065 if (length(dir1) < 1e-2) { dir1 = dir2; }
1066 if (length(dir2) < 1e-2) { dir2 = dir1; }
1067 dir1 = dir1 / length(dir1);
1068 dir2 = dir2 / length(dir2);
1069 Coord3d dir = dir1 + dir2;
1070 if (length(dir) < 1e-2) { continue; }
1071 nontrivial++;
1072 dir = dir / length(dir);
1073 dir[2] = 0;
1074 Coord3d up(0., 0., 1.);
1075 Coord3d res = crossProduct(up, dir);
1076 res[2] = 0.;
1077 if (length(res) > 0) res = res / length(res);
1078 Coord3d anti = crossProduct(dir, res);
1079 GLfloat off = 1e-2;
1080 pos += packObjectVertex(pos, cur[0] + width * res[0] + off * anti[0],
1081 cur[1] + width * res[1] + off * anti[1], cur[2] + off * anti[2],
1082 0., 0., color, flat);
1083 pos += packObjectVertex(pos, cur[0] - width * res[0] + off * anti[0],
1084 cur[1] - width * res[1] + off * anti[1], cur[2] + off * anti[2],
1085 0., 0., color, flat);
1086 }
1087 ushort* idxs = new ushort[2 * nontrivial * 3];
1088 for (int i = 0; i < nontrivial; i++) {
1089 int j = (i + 1) % nontrivial;
1090 idxs[6 * i + 0] = 2 * j;
1091 idxs[6 * i + 1] = 2 * i;
1092 idxs[6 * i + 2] = 2 * j + 1;
1093 idxs[6 * i + 3] = 2 * i;
1094 idxs[6 * i + 4] = 2 * i + 1;
1095 idxs[6 * i + 5] = 2 * j + 1;
1096 }
1097 delete[] ringPoints;
1098
1099 // Transfer data
1100 GLuint databuf, idxbuf, vao;
1101 glGenBuffers(1, &databuf);
1102 glGenBuffers(1, &idxbuf);
1103 glGenVertexArrays(1, &vao);
1104
1105 glBindVertexArray(vao);
1106 glBindBuffer(GL_ARRAY_BUFFER, databuf);
1107 glBufferData(GL_ARRAY_BUFFER, 8 * 2 * nontrivial * sizeof(GLfloat), data, GL_STATIC_DRAW);
1108
1109 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxbuf);
1110 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * 3 * nontrivial * sizeof(ushort), idxs,
1111 GL_STATIC_DRAW);
1112 delete[] data;
1113 delete[] idxs;
1114
1115 glEnable(GL_BLEND);
1116 glEnable(GL_CULL_FACE);
1117
1118 setActiveProgramAndUniforms(Shader_Object);
1119 setObjectUniforms(Color(0., 0., 0., 1.), 0., Lighting_None);
1120
1121 glBindTexture(GL_TEXTURE_2D, textureBlank);
1122
1123 configureObjectAttributes();
1124 glDrawElements(GL_TRIANGLES, 2 * 3 * npts, GL_UNSIGNED_SHORT, (void*)0);
1125
1126 glBindVertexArray(0);
1127 glDeleteBuffers(1, &databuf);
1128 glDeleteBuffers(1, &idxbuf);
1129 glDeleteVertexArrays(1, &vao);
1130 }
1131
drawSpotRing(Real x1,Real y1,Real r,int kind)1132 void Map::drawSpotRing(Real x1, Real y1, Real r, int kind) {
1133 int nfacets = std::max(12, (int)(10. * r));
1134 GLfloat width = std::min(0.5 * r, 0.05);
1135 Color color(kind == 0 ? 1. : 0.5, kind == 1 ? 1. : 0.5, kind == 2 ? 1. : 0.5, 1.);
1136 GLfloat flat[3] = {0., 0., 0.};
1137 Real height = Map::getHeight(x1, y1);
1138
1139 GLfloat* data = new GLfloat[8 * 2 * nfacets];
1140 ushort* idxs = new ushort[3 * 2 * nfacets];
1141 char* pos = (char*)data;
1142
1143 for (int i = 0; i < nfacets; i++) {
1144 GLfloat angle = 2 * i * M_PI / nfacets;
1145 pos += packObjectVertex(pos, x1 + (r - width) * std::cos(angle),
1146 y1 + (r - width) * std::sin(angle), height + 1e-2, 0., 0., color,
1147 flat);
1148 pos += packObjectVertex(pos, x1 + (r + width) * std::cos(angle),
1149 y1 + (r + width) * std::sin(angle), height + 1e-2, 0., 0., color,
1150 flat);
1151 }
1152
1153 for (int i = 0; i < nfacets; i++) {
1154 int j = (i + 1) % nfacets;
1155 idxs[6 * i + 0] = 2 * j;
1156 idxs[6 * i + 1] = 2 * i;
1157 idxs[6 * i + 2] = 2 * j + 1;
1158 idxs[6 * i + 3] = 2 * i;
1159 idxs[6 * i + 4] = 2 * i + 1;
1160 idxs[6 * i + 5] = 2 * j + 1;
1161 }
1162
1163 // Transfer data
1164 GLuint databuf, idxbuf, vao;
1165 glGenBuffers(1, &databuf);
1166 glGenBuffers(1, &idxbuf);
1167 glGenVertexArrays(1, &vao);
1168
1169 glBindVertexArray(vao);
1170 glBindBuffer(GL_ARRAY_BUFFER, databuf);
1171 glBufferData(GL_ARRAY_BUFFER, 8 * 2 * nfacets * sizeof(GLfloat), data, GL_STATIC_DRAW);
1172
1173 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxbuf);
1174 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * 3 * nfacets * sizeof(ushort), idxs,
1175 GL_STATIC_DRAW);
1176 delete[] data;
1177 delete[] idxs;
1178
1179 glEnable(GL_BLEND);
1180 glEnable(GL_CULL_FACE);
1181
1182 setActiveProgramAndUniforms(Shader_Object);
1183 setObjectUniforms(Color(0., 0., 0., 1.), 0., Lighting_None);
1184
1185 glBindTexture(GL_TEXTURE_2D, textureBlank);
1186 configureObjectAttributes();
1187 glDrawElements(GL_TRIANGLES, 2 * 3 * nfacets, GL_UNSIGNED_SHORT, (void*)0);
1188
1189 glBindVertexArray(0);
1190 glDeleteBuffers(1, &databuf);
1191 glDeleteBuffers(1, &idxbuf);
1192 glDeleteVertexArrays(1, &vao);
1193 }
1194
chunk(int cx,int cy) const1195 Chunk* Map::chunk(int cx, int cy) const {
1196 if (cx % CHUNKSIZE != 0 || cy % CHUNKSIZE != 0) {
1197 warning("Bad chunk access %d %d", cx, cy);
1198 return NULL;
1199 }
1200 std::pair<int, int> cpos(cx, cy);
1201 if (chunks.count(cpos) == 0) {
1202 // If local region not present, create associated chunk
1203 // & establish height boundaries
1204 Chunk c = Chunk();
1205 c.is_active = false;
1206 c.is_updated = true;
1207 c.is_visible = false;
1208 c.xm = cx;
1209 c.ym = cy;
1210 c.minHeight = 1e99;
1211 c.maxHeight = 1e-99;
1212 for (int dx = c.xm; dx < c.xm + CHUNKSIZE; dx++) {
1213 for (int dy = c.xm; dy < c.xm + CHUNKSIZE; dy++) {
1214 const Cell& w = cell(dx, dy);
1215 for (int k = 0; k < 5; k++) {
1216 c.maxHeight = std::max(c.maxHeight, std::max(w.heights[k], w.waterHeights[k]));
1217 c.minHeight = std::min(c.minHeight, std::min(w.heights[k], w.waterHeights[k]));
1218 }
1219 }
1220 }
1221 chunks[cpos] = c;
1222 }
1223 return &chunks[cpos];
1224 }
1225
1226 /** Saves the map to file in compressed binary or compressed ascii format */
save(char * pathname,int x,int y)1227 int Map::save(char* pathname, int x, int y) {
1228 int version = mapFormatVersion;
1229
1230 if (pathIsLink(pathname)) {
1231 warning("%s is a link, cannot save map", pathname);
1232 return 0;
1233 }
1234
1235 gzFile gp = gzopen(pathname, "wb9");
1236 if (!gp) return 0;
1237 Coord3d tmp = startPosition;
1238 startPosition = Coord3d(x, y, cell(x, y).heights[Cell::CENTER]);
1239 int32_t data[6];
1240 for (int i = 0; i < 3; i++)
1241 data[i] = saveInt((int32_t)startPosition[i]); // no decimal part needed
1242 tmp = startPosition;
1243 data[3] = saveInt((int32_t)width);
1244 data[4] = saveInt((int32_t)height);
1245 data[5] = saveInt((int32_t)version);
1246 gzwrite(gp, data, sizeof(int32_t) * 6);
1247
1248 /* new from version 7, save texture names */
1249 data[0] = saveInt(numTextures);
1250 gzwrite(gp, data, sizeof(int32_t) * 1);
1251 for (int i = 0; i < numTextures; i++) {
1252 char textureName[64];
1253 memset(textureName, 0, sizeof(textureName));
1254 strncpy(textureName, textureNames[i], 63);
1255 gzwrite(gp, textureName, 64);
1256 }
1257
1258 for (int i = 0; i < width * height; i++) cells[i].dump(gp);
1259 gzclose(gp);
1260 return 1;
1261 }
1262
dump(gzFile gp) const1263 void Cell::dump(gzFile gp) const {
1264 int32_t data[8];
1265 for (int i = 0; i < 5; i++) data[i] = saveInt((int32_t)(heights[i] / 0.0025));
1266 gzwrite(gp, data, sizeof(int32_t) * 5);
1267 for (int i = 0; i < 5; i++) {
1268 data[0] = saveInt((int32_t)(colors[i].f0() / 0.01));
1269 data[1] = saveInt((int32_t)(colors[i].f1() / 0.01));
1270 data[2] = saveInt((int32_t)(colors[i].f2() / 0.01));
1271 data[3] = saveInt((int32_t)(colors[i].f3() / 0.01));
1272 gzwrite(gp, data, sizeof(int32_t) * 4);
1273 }
1274 data[0] = saveInt((int32_t)flags);
1275 data[1] = saveInt((int32_t)texture);
1276 gzwrite(gp, data, sizeof(int32_t) * 2);
1277
1278 for (int i = 0; i < 4; i++) {
1279 data[0] = saveInt((int32_t)(wallColors[i].f0() / 0.01));
1280 data[1] = saveInt((int32_t)(wallColors[i].f1() / 0.01));
1281 data[2] = saveInt((int32_t)(wallColors[i].f2() / 0.01));
1282 data[3] = saveInt((int32_t)(wallColors[i].f3() / 0.01));
1283 gzwrite(gp, data, sizeof(int32_t) * 4);
1284 }
1285
1286 data[0] = saveInt((int32_t)(velocity[0] / 0.01));
1287 data[1] = saveInt((int32_t)(velocity[1] / 0.01));
1288 gzwrite(gp, data, sizeof(int32_t) * 2);
1289
1290 for (int i = 0; i < 5; i++) data[i] = saveInt((int32_t)(waterHeights[i] / 0.0025));
1291 gzwrite(gp, data, sizeof(int32_t) * 5);
1292
1293 for (int i = 0; i < 4; i++) {
1294 /* used to refer to texture coordinates */
1295 data[i * 2] = 0;
1296 data[i * 2 + 1] = 0;
1297 }
1298 gzwrite(gp, data, sizeof(int32_t) * 8);
1299 }
1300
load(Map * map,gzFile gp,int version)1301 void Cell::load(Map* map, gzFile gp, int version) {
1302 int32_t data[8];
1303
1304 gzread(gp, data, sizeof(int32_t) * 5);
1305 for (int i = 0; i < 5; i++) heights[i] = 0.0025 * loadInt(data[i]);
1306 for (int i = 0; i < 5; i++) {
1307 if (version < 4) {
1308 // old maps do not have an alpha channel defined
1309 gzread(gp, data, sizeof(int32_t) * 3);
1310 for (int j = 0; j < 3; j++) colors[i].v[j] = 65535 * 0.01 * loadInt(data[j]);
1311 colors[i].v[3] = 65535;
1312 } else {
1313 gzread(gp, data, sizeof(int32_t) * 4);
1314 for (int j = 0; j < 4; j++) colors[i].v[j] = 65535 * 0.01 * loadInt(data[j]);
1315 }
1316 }
1317
1318 gzread(gp, data, sizeof(int32_t) * 2);
1319 flags = loadInt(data[0]);
1320 if (version <= 1) flags = flags & (CELL_ICE | CELL_ACID);
1321 int k = loadInt(data[1]);
1322 texture = (k >= 0 && k < numTextures ? map->indexTranslation[k] : -1);
1323 // in older maps, this field was not initialized
1324 if (version < 5) texture = -1;
1325 if (version < 3) { /* Old maps do not have wallColors defined */
1326 for (int i = 0; i < 4; i++) { wallColors[i] = Color(0.7, 0.2, 0.2, 1.0); }
1327 } else {
1328 for (int i = 0; i < 4; i++) {
1329 if (version < 4) {
1330 // old maps do not have an alpha channel defined
1331 gzread(gp, data, sizeof(int32_t) * 3);
1332 for (int j = 0; j < 3; j++) wallColors[i].v[j] = 65535 * 0.01 * loadInt(data[j]);
1333 wallColors[i].v[3] = 65535;
1334 } else {
1335 gzread(gp, data, sizeof(int32_t) * 4);
1336 for (int j = 0; j < 4; j++) wallColors[i].v[j] = 65535 * 0.01 * loadInt(data[j]);
1337 }
1338 }
1339 }
1340
1341 if (version >= 5) {
1342 gzread(gp, data, sizeof(int32_t) * 2);
1343 velocity[0] = 0.01 * loadInt(data[0]);
1344 velocity[1] = 0.01 * loadInt(data[1]);
1345 } else {
1346 velocity[0] = 0.0;
1347 velocity[1] = 0.0;
1348 }
1349
1350 // currently we just reset the ground water
1351 if (version >= 6) {
1352 gzread(gp, data, sizeof(int32_t) * 5);
1353 for (int i = 0; i < 5; i++) waterHeights[i] = 0.0025 * loadInt(data[i]);
1354 } else {
1355 for (int i = 0; i < 5; i++) waterHeights[i] = heights[i] - 0.5;
1356 }
1357 sunken = 0.0;
1358
1359 if (version >= 7) {
1360 gzread(gp, data, sizeof(int32_t) * 8);
1361 /* used to be texture coordinates; now is free space */
1362 }
1363 }
1364