dungeon_crawler

annotate prototype/src/level.cc @ 51:d57df51f6b50

- fixed audio panning (listener direction) - particles had no fog - sound sources were not destroyed properly
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 18 Sep 2012 09:40:56 +0300
parents c40efa9cf844
children 0d4061b1e6a1
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@1 2 #include <string.h>
nuclear@5 3 #include <errno.h>
nuclear@1 4 #include "opengl.h"
nuclear@1 5 #include "level.h"
nuclear@1 6 #include "tile.h"
nuclear@5 7 #include "tileset.h"
nuclear@49 8 #include "cfg.h"
nuclear@1 9
nuclear@1 10 Level::Level()
nuclear@1 11 {
nuclear@1 12 cell_size = 1.0;
nuclear@1 13
nuclear@1 14 cells = 0;
nuclear@1 15 xsz = ysz = 0;
nuclear@1 16 }
nuclear@1 17
nuclear@1 18 Level::~Level()
nuclear@1 19 {
nuclear@1 20 delete [] cells;
nuclear@38 21
nuclear@38 22 for(auto cell : cell_list) {
nuclear@38 23 delete cell;
nuclear@38 24 }
nuclear@1 25 }
nuclear@1 26
nuclear@1 27 bool Level::load(const char *fname)
nuclear@1 28 {
nuclear@5 29 if(!fname) {
nuclear@5 30 return false;
nuclear@5 31 }
nuclear@5 32
nuclear@5 33 TileSet *tileset = get_active_tileset();
nuclear@5 34 if(!tileset) {
nuclear@5 35 fprintf(stderr, "level loading failed: no active tileset\n");
nuclear@5 36 return false;
nuclear@5 37 }
nuclear@5 38 Tile *deftile = tileset->get_tile("default");
nuclear@5 39 if(!deftile) {
nuclear@5 40 fprintf(stderr, "level loading failed: active tileset has no default tile\n");
nuclear@5 41 return false;
nuclear@5 42 }
nuclear@5 43
nuclear@5 44 FILE *fp = fopen(fname, "r");
nuclear@5 45 if(!fp) {
nuclear@5 46 fprintf(stderr, "failed to open level: %s: %s\n", fname, strerror(errno));
nuclear@5 47 return false;
nuclear@5 48 }
nuclear@5 49
nuclear@5 50 char buf[512];
nuclear@5 51 fgets(buf, sizeof buf, fp);
nuclear@5 52 if(sscanf(buf, "SIZE %dx%d", &xsz, &ysz) != 2) {
nuclear@5 53 fprintf(stderr, "invalid or corrupt level file: %s\n", fname);
nuclear@5 54 fclose(fp);
nuclear@5 55 return false;
nuclear@5 56 }
nuclear@5 57 printf("level size: %dx%d\n", xsz, ysz);
nuclear@1 58
nuclear@1 59 cells = new GridCell*[xsz * ysz];
nuclear@1 60 memset(cells, 0, xsz * ysz * sizeof *cells);
nuclear@1 61
nuclear@5 62 int y = 0;
nuclear@5 63 GridCell **grid_row = cells;
nuclear@5 64
nuclear@5 65 while(fgets(buf, sizeof buf, fp)) {
nuclear@5 66 for(int i=0; i<xsz; i++) {
nuclear@5 67 if(!buf[i] || buf[i] == '\r' || buf[i] == '\n') {
nuclear@5 68 grid_row += xsz - i;
nuclear@5 69 break;
nuclear@5 70 }
nuclear@5 71
nuclear@5 72 if(isalpha(buf[i]) || buf[i] == ' ') {
nuclear@38 73 GridCell *cell = new GridCell(deftile);
nuclear@38 74 *grid_row = cell;
nuclear@38 75 cell_list.push_back(*grid_row);
nuclear@5 76 }
nuclear@5 77 grid_row++;
nuclear@5 78 }
nuclear@5 79
nuclear@5 80 if(++y >= ysz) {
nuclear@5 81 break;
nuclear@5 82 }
nuclear@5 83 }
nuclear@5 84 fclose(fp);
nuclear@1 85
nuclear@50 86 for(int i=0; i<ysz; i++) {
nuclear@50 87 for(int j=0; j<xsz; j++) {
nuclear@50 88 GridCell *cell = get_cell(j, i);
nuclear@50 89 if(!cell) {
nuclear@50 90 continue;
nuclear@50 91 }
nuclear@50 92
nuclear@50 93 // find the adjacency mask of this cell and store it
nuclear@50 94 unsigned int adjmask = get_cell_dirmask(j, i);
nuclear@50 95 cell->set_adj_mask(adjmask);
nuclear@50 96
nuclear@50 97 // add any audio sources in this grid-cell to the level static audio manager
nuclear@50 98 std::list<Tile::AudioSourceDesc> asrc = cell->get_audio_sources();
nuclear@50 99 for(auto sdesc : asrc) {
nuclear@50 100 if(sdesc.dirmask & adjmask) {
nuclear@51 101 Vector3 pos = sdesc.pos + get_cell_pos(j, i);
nuclear@51 102
nuclear@50 103 AudioSource *s = new AudioSource;
nuclear@50 104 s->set_sample(sdesc.sample);
nuclear@51 105 s->set_position(pos);
nuclear@51 106 s->set_volume(sdesc.volume);
nuclear@51 107 s->set_reference_dist(sdesc.ref_dist);
nuclear@51 108 //s->set_rolloff(1.0);
nuclear@50 109 austatic.add_source(s);
nuclear@50 110 }
nuclear@50 111 }
nuclear@50 112 }
nuclear@50 113 }
nuclear@50 114
nuclear@1 115 return true;
nuclear@1 116 }
nuclear@1 117
nuclear@1 118 bool Level::save(const char *fname) const
nuclear@1 119 {
nuclear@1 120 return false;
nuclear@1 121 }
nuclear@1 122
nuclear@50 123 GridCell *Level::get_cell(int x, int y)
nuclear@50 124 {
nuclear@50 125 if(x < 0 || x >= xsz || y < 0 || y >= ysz) {
nuclear@50 126 return 0;
nuclear@50 127 }
nuclear@50 128 return cells[y * xsz + x];
nuclear@50 129 }
nuclear@50 130
nuclear@1 131 const GridCell *Level::get_cell(int x, int y) const
nuclear@1 132 {
nuclear@1 133 if(x < 0 || x >= xsz || y < 0 || y >= ysz) {
nuclear@1 134 return 0;
nuclear@1 135 }
nuclear@1 136 return cells[y * xsz + x];
nuclear@1 137 }
nuclear@1 138
nuclear@1 139 Vector3 Level::get_cell_pos(int x, int y) const
nuclear@1 140 {
nuclear@46 141 float posx = (float)x * cell_size;
nuclear@46 142 float posy = (float)y * cell_size;
nuclear@46 143 posx -= cell_size * (float)xsz / 2.0f;
nuclear@46 144 posy -= cell_size * (float)ysz / 2.0f;
nuclear@1 145 return Vector3(posx, 0, posy);
nuclear@1 146 }
nuclear@1 147
nuclear@48 148 void Level::get_cell_coords_at(const Vector3 &pos, int *xptr, int *yptr) const
nuclear@48 149 {
nuclear@48 150 float posx = pos.x + cell_size * (float)xsz / 2.0f;
nuclear@48 151 float posy = pos.z + cell_size * (float)ysz / 2.0f;
nuclear@48 152 *xptr = (int)round(posx / cell_size);
nuclear@48 153 *yptr = (int)round(posy / cell_size);
nuclear@48 154 }
nuclear@48 155
nuclear@23 156 unsigned int Level::get_cell_dirmask(int x, int y) const
nuclear@23 157 {
nuclear@23 158 unsigned int dmask = TILE_ALL;
nuclear@23 159 if(y > 0 && get_cell(x, y - 1)) {
nuclear@23 160 dmask &= ~TILE_NORTH;
nuclear@23 161 }
nuclear@23 162 if(y < ysz - 1 && get_cell(x, y + 1)) {
nuclear@23 163 dmask &= ~TILE_SOUTH;
nuclear@23 164 }
nuclear@23 165 if(x > 0 && get_cell(x - 1, y)) {
nuclear@23 166 dmask &= ~TILE_WEST;
nuclear@23 167 }
nuclear@23 168 if(x < xsz - 1 && get_cell(x + 1, y)) {
nuclear@23 169 dmask &= ~TILE_EAST;
nuclear@23 170 }
nuclear@23 171 return dmask;
nuclear@23 172 }
nuclear@23 173
nuclear@49 174 void Level::set_player_position(const Vector3 &ppos)
nuclear@49 175 {
nuclear@49 176 player_pos = ppos;
nuclear@49 177 }
nuclear@49 178
nuclear@38 179 void Level::update(unsigned long msec, float dt)
nuclear@38 180 {
nuclear@38 181 for(auto cell : cell_list) {
nuclear@38 182 cell->update(msec, dt);
nuclear@38 183 }
nuclear@49 184
nuclear@49 185 // activate the closest audio sources
nuclear@49 186 if(cfg.sound) {
nuclear@49 187 austatic.active_range(player_pos, 2.0);
nuclear@49 188 }
nuclear@38 189 }
nuclear@38 190
nuclear@1 191 void Level::draw() const
nuclear@1 192 {
nuclear@1 193 glMatrixMode(GL_MODELVIEW);
nuclear@1 194
nuclear@1 195 for(int i=0; i<ysz; i++) {
nuclear@1 196 for(int j=0; j<xsz; j++) {
nuclear@1 197 const GridCell *cell = get_cell(j, i);
nuclear@1 198 if(cell) {
nuclear@1 199 Vector3 pos = get_cell_pos(j, i);
nuclear@1 200 glPushMatrix();
nuclear@1 201 glTranslatef(pos.x, pos.y, pos.z);
nuclear@1 202 glScalef(cell_size, cell_size, cell_size);
nuclear@5 203
nuclear@23 204 unsigned int dmask = get_cell_dirmask(j, i);
nuclear@5 205
nuclear@5 206 cell->draw(dmask);
nuclear@1 207 glPopMatrix();
nuclear@1 208 }
nuclear@1 209 }
nuclear@1 210 }
nuclear@1 211 }
nuclear@1 212
nuclear@23 213 void Level::draw_lights() const
nuclear@23 214 {
nuclear@23 215 glMatrixMode(GL_MODELVIEW);
nuclear@23 216
nuclear@23 217 for(int i=0; i<ysz; i++) {
nuclear@23 218 for(int j=0; j<xsz; j++) {
nuclear@23 219 const GridCell *cell = get_cell(j, i);
nuclear@23 220 if(cell) {
nuclear@23 221 Vector3 pos = get_cell_pos(j, i);
nuclear@23 222
nuclear@23 223 glPushMatrix();
nuclear@23 224 glTranslatef(pos.x, pos.y, pos.z);
nuclear@23 225 glScalef(cell_size, cell_size, cell_size);
nuclear@23 226
nuclear@23 227 unsigned int dmask = get_cell_dirmask(j, i);
nuclear@23 228 cell->draw_lights(dmask);
nuclear@23 229
nuclear@23 230 glPopMatrix();
nuclear@23 231 }
nuclear@23 232 }
nuclear@23 233 }
nuclear@23 234 }
nuclear@23 235
nuclear@46 236 void Level::draw_post() const
nuclear@46 237 {
nuclear@46 238 glMatrixMode(GL_MODELVIEW);
nuclear@46 239
nuclear@46 240 for(int i=0; i<ysz; i++) {
nuclear@46 241 for(int j=0; j<xsz; j++) {
nuclear@46 242 const GridCell *cell = get_cell(j, i);
nuclear@46 243 if(cell) {
nuclear@46 244 Vector3 pos = get_cell_pos(j, i);
nuclear@46 245 glPushMatrix();
nuclear@46 246 glTranslatef(pos.x, pos.y, pos.z);
nuclear@46 247 glScalef(cell_size, cell_size, cell_size);
nuclear@46 248
nuclear@46 249 unsigned int dmask = get_cell_dirmask(j, i);
nuclear@46 250
nuclear@46 251 cell->draw_post(dmask);
nuclear@46 252 glPopMatrix();
nuclear@46 253 }
nuclear@46 254 }
nuclear@46 255 }
nuclear@46 256 }
nuclear@46 257
nuclear@1 258 void Level::draw_grid() const
nuclear@1 259 {
nuclear@1 260 float xlen = xsz * cell_size;
nuclear@1 261 float ylen = ysz * cell_size;
nuclear@1 262
nuclear@1 263 glPushAttrib(GL_ENABLE_BIT);
nuclear@1 264 glDisable(GL_LIGHTING);
nuclear@1 265
nuclear@1 266 glBegin(GL_LINES);
nuclear@1 267 glColor3f(0.4, 0.4, 0.4);
nuclear@1 268
nuclear@1 269 float y = -ylen / 2.0 - cell_size / 2.0;
nuclear@1 270 for(int i=0; i<ysz; i++) {
nuclear@1 271 glVertex3f(-xlen / 2.0, 0, y);
nuclear@1 272 glVertex3f(xlen / 2.0, 0, y);
nuclear@1 273 y += cell_size;
nuclear@1 274 }
nuclear@1 275
nuclear@1 276 float x = -xlen / 2.0 - cell_size / 2.0;
nuclear@1 277 for(int i=0; i<xsz; i++) {
nuclear@1 278 glVertex3f(x, 0, -ylen / 2.0);
nuclear@1 279 glVertex3f(x, 0, ylen / 2.0);
nuclear@1 280 x += cell_size;
nuclear@1 281 }
nuclear@1 282 glEnd();
nuclear@1 283
nuclear@1 284 glPopAttrib();
nuclear@1 285 }
nuclear@1 286
nuclear@5 287
nuclear@48 288 AudioSample *Level::get_sample(int x, int y, int which) const
nuclear@48 289 {
nuclear@48 290 const GridCell *cell = get_cell(x, y);
nuclear@48 291 if(!cell) {
nuclear@48 292 return 0;
nuclear@48 293 }
nuclear@48 294 return cell->get_sample(which);
nuclear@48 295 }
nuclear@48 296
nuclear@48 297
nuclear@38 298 GridCell::GridCell(Tile *tile)
nuclear@5 299 {
nuclear@5 300 if(tile) {
nuclear@45 301 add_tile(tile);
nuclear@5 302 }
nuclear@50 303
nuclear@50 304 adjmask = TILE_ALL;
nuclear@50 305 }
nuclear@50 306
nuclear@50 307 void GridCell::set_adj_mask(unsigned int mask)
nuclear@50 308 {
nuclear@50 309 adjmask = mask;
nuclear@50 310 }
nuclear@50 311
nuclear@50 312 unsigned int GridCell::get_adj_mask() const
nuclear@50 313 {
nuclear@50 314 return adjmask;
nuclear@5 315 }
nuclear@5 316
nuclear@38 317 void GridCell::add_tile(Tile *tile)
nuclear@1 318 {
nuclear@45 319 if(!tile) {
nuclear@45 320 return;
nuclear@45 321 }
nuclear@45 322
nuclear@1 323 tiles.push_back(tile);
nuclear@45 324
nuclear@45 325 /* instanciate any particle systems */
nuclear@45 326 int num_psattr = tile->get_unique_psys_count();
nuclear@45 327
nuclear@45 328 for(int i=0; i<num_psattr; i++) {
nuclear@49 329 const struct psys_attributes *psattr = tile->get_unique_psys(i);
nuclear@45 330 struct psys_emitter *emitter = psys_create();
nuclear@49 331 emitter->attr = *psattr;
nuclear@45 332 psys.push_back(emitter);
nuclear@45 333 }
nuclear@1 334 }
nuclear@1 335
nuclear@38 336 void GridCell::update(unsigned long msec, float dt)
nuclear@38 337 {
nuclear@45 338 for(auto ps : psys) {
nuclear@45 339 psys_update(ps, (float)msec / 1000.0f);
nuclear@45 340 }
nuclear@38 341 }
nuclear@38 342
nuclear@5 343 void GridCell::draw(unsigned int draw_mask) const
nuclear@1 344 {
nuclear@23 345 for(auto tile : tiles) {
nuclear@23 346 tile->draw(draw_mask);
nuclear@1 347 }
nuclear@1 348 }
nuclear@23 349
nuclear@23 350 void GridCell::draw_lights(unsigned int draw_mask) const
nuclear@23 351 {
nuclear@23 352 for(auto tile : tiles) {
nuclear@23 353 tile->draw_lights(draw_mask);
nuclear@23 354 }
nuclear@23 355 }
nuclear@45 356
nuclear@45 357 void GridCell::draw_post(unsigned int draw_mask) const
nuclear@45 358 {
nuclear@45 359 for(auto tile : tiles) {
nuclear@45 360 tile->draw_post(draw_mask);
nuclear@45 361 }
nuclear@45 362 for(auto ps : psys) {
nuclear@45 363 psys_draw(ps);
nuclear@45 364 }
nuclear@45 365 }
nuclear@48 366
nuclear@48 367 AudioSample *GridCell::get_sample(int which) const
nuclear@48 368 {
nuclear@48 369 for(auto tile : tiles) {
nuclear@48 370 AudioSample *s = tile->get_sample(which);
nuclear@48 371 if(s) {
nuclear@48 372 return s;
nuclear@48 373 }
nuclear@48 374 }
nuclear@48 375 return 0;
nuclear@48 376 }
nuclear@49 377
nuclear@49 378 std::list<Tile::AudioSourceDesc> GridCell::get_audio_sources() const
nuclear@49 379 {
nuclear@49 380 std::list<Tile::AudioSourceDesc> srclist;
nuclear@49 381
nuclear@49 382 for(auto tile : tiles) {
nuclear@49 383 int num_src = tile->get_audio_source_count();
nuclear@49 384 for(int i=0; i<num_src; i++) {
nuclear@49 385 srclist.push_back(tile->get_audio_source(i));
nuclear@49 386 }
nuclear@49 387 }
nuclear@49 388 return srclist;
nuclear@49 389 }