dungeon_crawler

annotate prototype/src/level.cc @ 80:a373b36ffc17

better
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Oct 2012 01:59:39 +0300
parents d57df51f6b50
children
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@58 72
nuclear@58 73 if(buf[i] != '#') {
nuclear@38 74 GridCell *cell = new GridCell(deftile);
nuclear@38 75 *grid_row = cell;
nuclear@38 76 cell_list.push_back(*grid_row);
nuclear@58 77
nuclear@58 78 Tile *tile;
nuclear@58 79
nuclear@58 80 switch(buf[i]) {
nuclear@58 81 case '*':
nuclear@58 82 if(!(tile = tileset->get_tile("light"))) {
nuclear@58 83 fprintf(stderr, "failed to add light tile\n");
nuclear@58 84 }
nuclear@58 85 break;
nuclear@58 86
nuclear@58 87 default:
nuclear@58 88 tile = 0;
nuclear@58 89 break;
nuclear@58 90 }
nuclear@58 91
nuclear@58 92 if(tile) {
nuclear@58 93 cell->add_tile(tile);
nuclear@58 94 }
nuclear@5 95 }
nuclear@5 96 grid_row++;
nuclear@5 97 }
nuclear@5 98
nuclear@5 99 if(++y >= ysz) {
nuclear@5 100 break;
nuclear@5 101 }
nuclear@5 102 }
nuclear@5 103 fclose(fp);
nuclear@1 104
nuclear@50 105 for(int i=0; i<ysz; i++) {
nuclear@50 106 for(int j=0; j<xsz; j++) {
nuclear@50 107 GridCell *cell = get_cell(j, i);
nuclear@50 108 if(!cell) {
nuclear@50 109 continue;
nuclear@50 110 }
nuclear@50 111
nuclear@50 112 // find the adjacency mask of this cell and store it
nuclear@50 113 unsigned int adjmask = get_cell_dirmask(j, i);
nuclear@50 114 cell->set_adj_mask(adjmask);
nuclear@50 115
nuclear@50 116 // add any audio sources in this grid-cell to the level static audio manager
nuclear@50 117 std::list<Tile::AudioSourceDesc> asrc = cell->get_audio_sources();
nuclear@50 118 for(auto sdesc : asrc) {
nuclear@50 119 if(sdesc.dirmask & adjmask) {
nuclear@51 120 Vector3 pos = sdesc.pos + get_cell_pos(j, i);
nuclear@51 121
nuclear@50 122 AudioSource *s = new AudioSource;
nuclear@50 123 s->set_sample(sdesc.sample);
nuclear@51 124 s->set_position(pos);
nuclear@51 125 s->set_volume(sdesc.volume);
nuclear@51 126 s->set_reference_dist(sdesc.ref_dist);
nuclear@51 127 //s->set_rolloff(1.0);
nuclear@50 128 austatic.add_source(s);
nuclear@50 129 }
nuclear@50 130 }
nuclear@50 131 }
nuclear@50 132 }
nuclear@50 133
nuclear@1 134 return true;
nuclear@1 135 }
nuclear@1 136
nuclear@1 137 bool Level::save(const char *fname) const
nuclear@1 138 {
nuclear@1 139 return false;
nuclear@1 140 }
nuclear@1 141
nuclear@50 142 GridCell *Level::get_cell(int x, int y)
nuclear@50 143 {
nuclear@50 144 if(x < 0 || x >= xsz || y < 0 || y >= ysz) {
nuclear@50 145 return 0;
nuclear@50 146 }
nuclear@50 147 return cells[y * xsz + x];
nuclear@50 148 }
nuclear@50 149
nuclear@1 150 const GridCell *Level::get_cell(int x, int y) const
nuclear@1 151 {
nuclear@1 152 if(x < 0 || x >= xsz || y < 0 || y >= ysz) {
nuclear@1 153 return 0;
nuclear@1 154 }
nuclear@1 155 return cells[y * xsz + x];
nuclear@1 156 }
nuclear@1 157
nuclear@1 158 Vector3 Level::get_cell_pos(int x, int y) const
nuclear@1 159 {
nuclear@46 160 float posx = (float)x * cell_size;
nuclear@46 161 float posy = (float)y * cell_size;
nuclear@46 162 posx -= cell_size * (float)xsz / 2.0f;
nuclear@46 163 posy -= cell_size * (float)ysz / 2.0f;
nuclear@1 164 return Vector3(posx, 0, posy);
nuclear@1 165 }
nuclear@1 166
nuclear@48 167 void Level::get_cell_coords_at(const Vector3 &pos, int *xptr, int *yptr) const
nuclear@48 168 {
nuclear@48 169 float posx = pos.x + cell_size * (float)xsz / 2.0f;
nuclear@48 170 float posy = pos.z + cell_size * (float)ysz / 2.0f;
nuclear@48 171 *xptr = (int)round(posx / cell_size);
nuclear@48 172 *yptr = (int)round(posy / cell_size);
nuclear@48 173 }
nuclear@48 174
nuclear@23 175 unsigned int Level::get_cell_dirmask(int x, int y) const
nuclear@23 176 {
nuclear@23 177 unsigned int dmask = TILE_ALL;
nuclear@23 178 if(y > 0 && get_cell(x, y - 1)) {
nuclear@23 179 dmask &= ~TILE_NORTH;
nuclear@23 180 }
nuclear@23 181 if(y < ysz - 1 && get_cell(x, y + 1)) {
nuclear@23 182 dmask &= ~TILE_SOUTH;
nuclear@23 183 }
nuclear@23 184 if(x > 0 && get_cell(x - 1, y)) {
nuclear@23 185 dmask &= ~TILE_WEST;
nuclear@23 186 }
nuclear@23 187 if(x < xsz - 1 && get_cell(x + 1, y)) {
nuclear@23 188 dmask &= ~TILE_EAST;
nuclear@23 189 }
nuclear@23 190 return dmask;
nuclear@23 191 }
nuclear@23 192
nuclear@49 193 void Level::set_player_position(const Vector3 &ppos)
nuclear@49 194 {
nuclear@49 195 player_pos = ppos;
nuclear@49 196 }
nuclear@49 197
nuclear@38 198 void Level::update(unsigned long msec, float dt)
nuclear@38 199 {
nuclear@38 200 for(auto cell : cell_list) {
nuclear@38 201 cell->update(msec, dt);
nuclear@38 202 }
nuclear@49 203
nuclear@49 204 // activate the closest audio sources
nuclear@49 205 if(cfg.sound) {
nuclear@49 206 austatic.active_range(player_pos, 2.0);
nuclear@49 207 }
nuclear@38 208 }
nuclear@38 209
nuclear@1 210 void Level::draw() const
nuclear@1 211 {
nuclear@1 212 glMatrixMode(GL_MODELVIEW);
nuclear@1 213
nuclear@1 214 for(int i=0; i<ysz; i++) {
nuclear@1 215 for(int j=0; j<xsz; j++) {
nuclear@1 216 const GridCell *cell = get_cell(j, i);
nuclear@1 217 if(cell) {
nuclear@1 218 Vector3 pos = get_cell_pos(j, i);
nuclear@1 219 glPushMatrix();
nuclear@1 220 glTranslatef(pos.x, pos.y, pos.z);
nuclear@1 221 glScalef(cell_size, cell_size, cell_size);
nuclear@5 222
nuclear@23 223 unsigned int dmask = get_cell_dirmask(j, i);
nuclear@5 224
nuclear@5 225 cell->draw(dmask);
nuclear@1 226 glPopMatrix();
nuclear@1 227 }
nuclear@1 228 }
nuclear@1 229 }
nuclear@1 230 }
nuclear@1 231
nuclear@23 232 void Level::draw_lights() const
nuclear@23 233 {
nuclear@23 234 glMatrixMode(GL_MODELVIEW);
nuclear@23 235
nuclear@23 236 for(int i=0; i<ysz; i++) {
nuclear@23 237 for(int j=0; j<xsz; j++) {
nuclear@23 238 const GridCell *cell = get_cell(j, i);
nuclear@23 239 if(cell) {
nuclear@23 240 Vector3 pos = get_cell_pos(j, i);
nuclear@23 241
nuclear@23 242 glPushMatrix();
nuclear@23 243 glTranslatef(pos.x, pos.y, pos.z);
nuclear@23 244 glScalef(cell_size, cell_size, cell_size);
nuclear@23 245
nuclear@23 246 unsigned int dmask = get_cell_dirmask(j, i);
nuclear@23 247 cell->draw_lights(dmask);
nuclear@23 248
nuclear@23 249 glPopMatrix();
nuclear@23 250 }
nuclear@23 251 }
nuclear@23 252 }
nuclear@23 253 }
nuclear@23 254
nuclear@46 255 void Level::draw_post() const
nuclear@46 256 {
nuclear@46 257 glMatrixMode(GL_MODELVIEW);
nuclear@46 258
nuclear@46 259 for(int i=0; i<ysz; i++) {
nuclear@46 260 for(int j=0; j<xsz; j++) {
nuclear@46 261 const GridCell *cell = get_cell(j, i);
nuclear@46 262 if(cell) {
nuclear@46 263 Vector3 pos = get_cell_pos(j, i);
nuclear@46 264 glPushMatrix();
nuclear@46 265 glTranslatef(pos.x, pos.y, pos.z);
nuclear@46 266 glScalef(cell_size, cell_size, cell_size);
nuclear@46 267
nuclear@46 268 unsigned int dmask = get_cell_dirmask(j, i);
nuclear@46 269
nuclear@46 270 cell->draw_post(dmask);
nuclear@46 271 glPopMatrix();
nuclear@46 272 }
nuclear@46 273 }
nuclear@46 274 }
nuclear@46 275 }
nuclear@46 276
nuclear@1 277 void Level::draw_grid() const
nuclear@1 278 {
nuclear@1 279 float xlen = xsz * cell_size;
nuclear@1 280 float ylen = ysz * cell_size;
nuclear@1 281
nuclear@1 282 glPushAttrib(GL_ENABLE_BIT);
nuclear@1 283 glDisable(GL_LIGHTING);
nuclear@1 284
nuclear@1 285 glBegin(GL_LINES);
nuclear@1 286 glColor3f(0.4, 0.4, 0.4);
nuclear@1 287
nuclear@1 288 float y = -ylen / 2.0 - cell_size / 2.0;
nuclear@1 289 for(int i=0; i<ysz; i++) {
nuclear@1 290 glVertex3f(-xlen / 2.0, 0, y);
nuclear@1 291 glVertex3f(xlen / 2.0, 0, y);
nuclear@1 292 y += cell_size;
nuclear@1 293 }
nuclear@1 294
nuclear@1 295 float x = -xlen / 2.0 - cell_size / 2.0;
nuclear@1 296 for(int i=0; i<xsz; i++) {
nuclear@1 297 glVertex3f(x, 0, -ylen / 2.0);
nuclear@1 298 glVertex3f(x, 0, ylen / 2.0);
nuclear@1 299 x += cell_size;
nuclear@1 300 }
nuclear@1 301 glEnd();
nuclear@1 302
nuclear@1 303 glPopAttrib();
nuclear@1 304 }
nuclear@1 305
nuclear@5 306
nuclear@48 307 AudioSample *Level::get_sample(int x, int y, int which) const
nuclear@48 308 {
nuclear@48 309 const GridCell *cell = get_cell(x, y);
nuclear@48 310 if(!cell) {
nuclear@48 311 return 0;
nuclear@48 312 }
nuclear@48 313 return cell->get_sample(which);
nuclear@48 314 }
nuclear@48 315
nuclear@48 316
nuclear@38 317 GridCell::GridCell(Tile *tile)
nuclear@5 318 {
nuclear@5 319 if(tile) {
nuclear@45 320 add_tile(tile);
nuclear@5 321 }
nuclear@50 322
nuclear@50 323 adjmask = TILE_ALL;
nuclear@50 324 }
nuclear@50 325
nuclear@50 326 void GridCell::set_adj_mask(unsigned int mask)
nuclear@50 327 {
nuclear@50 328 adjmask = mask;
nuclear@50 329 }
nuclear@50 330
nuclear@50 331 unsigned int GridCell::get_adj_mask() const
nuclear@50 332 {
nuclear@50 333 return adjmask;
nuclear@5 334 }
nuclear@5 335
nuclear@38 336 void GridCell::add_tile(Tile *tile)
nuclear@1 337 {
nuclear@45 338 if(!tile) {
nuclear@45 339 return;
nuclear@45 340 }
nuclear@45 341
nuclear@1 342 tiles.push_back(tile);
nuclear@45 343
nuclear@45 344 /* instanciate any particle systems */
nuclear@45 345 int num_psattr = tile->get_unique_psys_count();
nuclear@45 346
nuclear@45 347 for(int i=0; i<num_psattr; i++) {
nuclear@49 348 const struct psys_attributes *psattr = tile->get_unique_psys(i);
nuclear@45 349 struct psys_emitter *emitter = psys_create();
nuclear@49 350 emitter->attr = *psattr;
nuclear@45 351 psys.push_back(emitter);
nuclear@45 352 }
nuclear@1 353 }
nuclear@1 354
nuclear@38 355 void GridCell::update(unsigned long msec, float dt)
nuclear@38 356 {
nuclear@45 357 for(auto ps : psys) {
nuclear@45 358 psys_update(ps, (float)msec / 1000.0f);
nuclear@45 359 }
nuclear@38 360 }
nuclear@38 361
nuclear@5 362 void GridCell::draw(unsigned int draw_mask) const
nuclear@1 363 {
nuclear@23 364 for(auto tile : tiles) {
nuclear@23 365 tile->draw(draw_mask);
nuclear@1 366 }
nuclear@1 367 }
nuclear@23 368
nuclear@23 369 void GridCell::draw_lights(unsigned int draw_mask) const
nuclear@23 370 {
nuclear@23 371 for(auto tile : tiles) {
nuclear@23 372 tile->draw_lights(draw_mask);
nuclear@23 373 }
nuclear@23 374 }
nuclear@45 375
nuclear@45 376 void GridCell::draw_post(unsigned int draw_mask) const
nuclear@45 377 {
nuclear@45 378 for(auto tile : tiles) {
nuclear@45 379 tile->draw_post(draw_mask);
nuclear@45 380 }
nuclear@45 381 for(auto ps : psys) {
nuclear@45 382 psys_draw(ps);
nuclear@45 383 }
nuclear@45 384 }
nuclear@48 385
nuclear@48 386 AudioSample *GridCell::get_sample(int which) const
nuclear@48 387 {
nuclear@48 388 for(auto tile : tiles) {
nuclear@48 389 AudioSample *s = tile->get_sample(which);
nuclear@48 390 if(s) {
nuclear@48 391 return s;
nuclear@48 392 }
nuclear@48 393 }
nuclear@48 394 return 0;
nuclear@48 395 }
nuclear@49 396
nuclear@49 397 std::list<Tile::AudioSourceDesc> GridCell::get_audio_sources() const
nuclear@49 398 {
nuclear@49 399 std::list<Tile::AudioSourceDesc> srclist;
nuclear@49 400
nuclear@49 401 for(auto tile : tiles) {
nuclear@49 402 int num_src = tile->get_audio_source_count();
nuclear@49 403 for(int i=0; i<num_src; i++) {
nuclear@49 404 srclist.push_back(tile->get_audio_source(i));
nuclear@49 405 }
nuclear@49 406 }
nuclear@49 407 return srclist;
nuclear@49 408 }