dungeon_crawler

annotate prototype/src/tile.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 1ea56011c1ff
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@46 2 #include <ctype.h>
nuclear@7 3 #include <map>
nuclear@1 4 #include "opengl.h"
nuclear@7 5 #include <assimp/cimport.h>
nuclear@7 6 #include <assimp/scene.h>
nuclear@7 7 #include <assimp/postprocess.h>
nuclear@1 8 #include "tile.h"
nuclear@11 9 #include "tileset.h"
nuclear@35 10 #include "renderer.h"
nuclear@46 11 #include "datapath.h"
nuclear@49 12 #include "cfg.h"
nuclear@1 13
nuclear@7 14 using std::map;
nuclear@7 15
nuclear@7 16 static void build_nodemap(map<aiMesh*, aiNode*> *nmap, const aiScene *scn, aiNode *node);
nuclear@21 17 static PointLight *mesh_to_light(Mesh *m);
nuclear@7 18
nuclear@31 19 bool ass_obj_hack;
nuclear@31 20
nuclear@11 21 Tile::Tile(TileSet *tileset)
nuclear@11 22 {
nuclear@11 23 tset = tileset;
nuclear@46 24 last_upd = LONG_MIN;
nuclear@48 25
nuclear@48 26 memset(samples, 0, sizeof samples);
nuclear@11 27 }
nuclear@7 28
nuclear@38 29 Tile::~Tile()
nuclear@38 30 {
nuclear@38 31 for(auto m : meshes) {
nuclear@38 32 delete m;
nuclear@38 33 }
nuclear@38 34 for(auto lt : lights) {
nuclear@38 35 delete lt;
nuclear@38 36 }
nuclear@46 37 for(auto psa : psattr) {
nuclear@46 38 psys_free_attr(psa);
nuclear@46 39 }
nuclear@46 40 for(auto ps : psys_global) {
nuclear@46 41 psys_free(ps);
nuclear@38 42 }
nuclear@38 43 }
nuclear@38 44
nuclear@48 45 AudioSample *Tile::get_sample(int sidx) const
nuclear@48 46 {
nuclear@48 47 if(sidx >= 0 && sidx < MAX_TILE_SAMPLES) {
nuclear@48 48 return samples[sidx];
nuclear@48 49 }
nuclear@48 50 return 0;
nuclear@48 51 }
nuclear@48 52
nuclear@49 53 int Tile::get_audio_source_count() const
nuclear@45 54 {
nuclear@49 55 return (int)ausrc.size();
nuclear@49 56 }
nuclear@49 57
nuclear@49 58 const Tile::AudioSourceDesc &Tile::get_audio_source(int idx) const
nuclear@49 59 {
nuclear@49 60 if(idx < 0 || idx >= (int)ausrc.size()) {
nuclear@50 61 static AudioSourceDesc d = { 0, Vector3(), 0 };
nuclear@49 62 return d;
nuclear@49 63 }
nuclear@49 64 return ausrc[idx];
nuclear@45 65 }
nuclear@45 66
nuclear@46 67 int Tile::get_unique_psys_count() const
nuclear@45 68 {
nuclear@45 69 return (int)psattr.size();
nuclear@45 70 }
nuclear@45 71
nuclear@49 72 struct psys_attributes *Tile::get_unique_psys(int idx)
nuclear@49 73 {
nuclear@49 74 if(idx < 0 || idx >= (int)psattr.size()) {
nuclear@49 75 return 0;
nuclear@49 76 }
nuclear@49 77 return psattr[idx];
nuclear@49 78 }
nuclear@49 79
nuclear@49 80 const struct psys_attributes *Tile::get_unique_psys(int idx) const
nuclear@49 81 {
nuclear@49 82 if(idx < 0 || idx >= (int)psattr.size()) {
nuclear@49 83 return 0;
nuclear@49 84 }
nuclear@49 85 return psattr[idx];
nuclear@49 86 }
nuclear@49 87
nuclear@1 88 bool Tile::load(const char *fname)
nuclear@1 89 {
nuclear@5 90 if(!fname) {
nuclear@5 91 return false;
nuclear@5 92 }
nuclear@5 93
nuclear@14 94 char *saved_fname = (char*)alloca(strlen(fname) + 1);
nuclear@14 95 strcpy(saved_fname, fname);
nuclear@14 96
nuclear@3 97 unsigned int proc_flags = aiProcess_JoinIdenticalVertices |
nuclear@35 98 aiProcess_CalcTangentSpace |
nuclear@7 99 aiProcess_Triangulate |
nuclear@7 100 aiProcess_SortByPType |
nuclear@7 101 aiProcess_FlipUVs;
nuclear@4 102
nuclear@3 103 const aiScene *scn = aiImportFile(fname, proc_flags);
nuclear@3 104 if(!scn) {
nuclear@3 105 fprintf(stderr, "failed to load tile: %s\n", fname);
nuclear@3 106 return -1;
nuclear@3 107 }
nuclear@3 108
nuclear@7 109 map<aiMesh*, aiNode*> nodemap;
nuclear@7 110 build_nodemap(&nodemap, scn, scn->mRootNode);
nuclear@7 111
nuclear@31 112 if(strstr(fname, ".obj") == fname + strlen(fname) - 4) {
nuclear@31 113 ass_obj_hack = true;
nuclear@31 114 } else {
nuclear@31 115 ass_obj_hack = false;
nuclear@31 116 }
nuclear@31 117
nuclear@21 118 //load_lights(scn);
nuclear@7 119 load_meshes(scn, nodemap);
nuclear@3 120
nuclear@22 121 printf("loaded tile %s: %d meshes, %d lights\n", saved_fname, (int)meshes.size(), (int)lights.size());
nuclear@38 122
nuclear@38 123 aiReleaseImport(scn);
nuclear@48 124
nuclear@48 125 // XXX get the default audio samples for now
nuclear@49 126 if(cfg.sound) {
nuclear@49 127 SampleSet *sampleset = tset->get_samples();
nuclear@49 128 samples[TILE_SAMPLE_WALK] = sampleset->get("walk_stone.ogg");
nuclear@49 129 samples[TILE_SAMPLE_RUN] = sampleset->get("run_stone.ogg");
nuclear@49 130 }
nuclear@1 131 return true;
nuclear@1 132 }
nuclear@1 133
nuclear@38 134 void Tile::update(unsigned long msec, float dt)
nuclear@38 135 {
nuclear@46 136 // update particle systems
nuclear@46 137 for(auto ps : psys_global) {
nuclear@46 138 psys_update(ps, (float)msec / 1000.0f);
nuclear@46 139 }
nuclear@38 140 }
nuclear@38 141
nuclear@5 142 void Tile::draw(unsigned int draw_mask) const
nuclear@1 143 {
nuclear@4 144 for(size_t i=0; i<meshes.size(); i++) {
nuclear@4 145 if(mesh_side[i] & draw_mask) {
nuclear@5 146 meshes[i]->draw();
nuclear@4 147 }
nuclear@4 148 }
nuclear@4 149 }
nuclear@1 150
nuclear@23 151 void Tile::draw_lights(unsigned int draw_mask) const
nuclear@23 152 {
nuclear@23 153 for(size_t i=0; i<lights.size(); i++) {
nuclear@23 154 if(light_side[i] & draw_mask) {
nuclear@23 155 lights[i]->draw();
nuclear@23 156 }
nuclear@23 157 }
nuclear@23 158 }
nuclear@23 159
nuclear@46 160 void Tile::draw_post(unsigned int draw_mask) const
nuclear@46 161 {
nuclear@46 162 // draw global particle systems (simulated once)
nuclear@46 163 for(size_t i=0; i<psys_global.size(); i++) {
nuclear@46 164 if(psys_side[i] & draw_mask) {
nuclear@46 165 psys_draw(psys_global[i]);
nuclear@46 166 }
nuclear@46 167 }
nuclear@46 168 }
nuclear@46 169
nuclear@21 170 /*
nuclear@4 171 int Tile::load_lights(const aiScene *scn)
nuclear@4 172 {
nuclear@4 173 int count = 0;
nuclear@4 174
nuclear@4 175 for(int i=0; i<(int)scn->mNumLights; i++) {
nuclear@4 176 Light *lt;
nuclear@4 177 aiLight *ailt = scn->mLights[i];
nuclear@4 178
nuclear@4 179 switch(ailt->mType) {
nuclear@4 180 case aiLightSource_POINT:
nuclear@4 181 lt = new PointLight(Vector3(ailt->mPosition.x, ailt->mPosition.y, ailt->mPosition.z));
nuclear@4 182 ((PointLight*)lt)->set_attenuation(ailt->mAttenuationConstant, ailt->mAttenuationLinear,
nuclear@4 183 ailt->mAttenuationQuadratic);
nuclear@4 184 break;
nuclear@4 185
nuclear@4 186 case aiLightSource_DIRECTIONAL:
nuclear@4 187 lt = new PointLight(Vector3(ailt->mDirection.x, ailt->mDirection.y, ailt->mDirection.z));
nuclear@4 188 break;
nuclear@4 189
nuclear@4 190 default:
nuclear@4 191 continue;
nuclear@4 192 }
nuclear@4 193
nuclear@4 194 lt->set_color(Color(ailt->mColorDiffuse.r, ailt->mColorDiffuse.g, ailt->mColorDiffuse.b, 1.0));
nuclear@4 195
nuclear@4 196 lights.push_back(lt);
nuclear@4 197 count++;
nuclear@4 198 }
nuclear@4 199
nuclear@4 200 return count;
nuclear@1 201 }
nuclear@21 202 */
nuclear@4 203
nuclear@7 204 int Tile::load_meshes(const aiScene *scn, const std::map<aiMesh*, aiNode*> &nmap)
nuclear@4 205 {
nuclear@4 206 int count = 0;
nuclear@4 207
nuclear@41 208 int attr_loc = rend->get_tangent_location();
nuclear@35 209 if(attr_loc == -1) {
nuclear@35 210 fprintf(stderr, "warning: failed to retrieve tangent attribute location while loading tile\n");
nuclear@35 211 }
nuclear@35 212
nuclear@4 213 for(int i=0; i<(int)scn->mNumMeshes; i++) {
nuclear@37 214 // ignore any lines or other crap
nuclear@37 215 if(scn->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) {
nuclear@37 216 continue;
nuclear@37 217 }
nuclear@37 218
nuclear@4 219 Mesh *mesh = new Mesh;
nuclear@4 220 if(!mesh->create(scn, scn->mMeshes[i])) {
nuclear@4 221 delete mesh;
nuclear@4 222 continue;
nuclear@4 223 }
nuclear@35 224 if(attr_loc != -1) {
nuclear@35 225 mesh->set_attrib_location(MESH_ATTR_TANGENT, attr_loc);
nuclear@35 226 }
nuclear@4 227
nuclear@11 228 Material mat;
nuclear@11 229 mat.load(scn->mMaterials[scn->mMeshes[i]->mMaterialIndex], tset->get_textures());
nuclear@11 230 mesh->set_material(mat);
nuclear@11 231
nuclear@7 232 // retrieve the node pointer
nuclear@7 233 const char *name = "<unknown>";
nuclear@7 234
nuclear@7 235 auto iter = nmap.find(scn->mMeshes[i]);
nuclear@7 236 if(iter != nmap.end()) {
nuclear@7 237 aiNode *node = iter->second;
nuclear@7 238
nuclear@7 239 Matrix4x4 xform;
nuclear@7 240 //xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
nuclear@7 241 xform = *(Matrix4x4*)&node->mTransformation;
nuclear@7 242 mesh->set_xform(xform);
nuclear@7 243
nuclear@7 244 name = node->mName.data;
nuclear@7 245 mesh->set_name(name);
nuclear@7 246 }
nuclear@7 247
nuclear@4 248 // find which side is this mesh on
nuclear@7 249 unsigned int side = 0;
nuclear@7 250 if(strstr(name, "NORTH")) {
nuclear@7 251 side |= TILE_NORTH;
nuclear@7 252 }
nuclear@7 253 if(strstr(name, "SOUTH")) {
nuclear@7 254 side |= TILE_SOUTH;
nuclear@7 255 }
nuclear@7 256 if(strstr(name, "EAST")) {
nuclear@7 257 side |= TILE_EAST;
nuclear@7 258 }
nuclear@7 259 if(strstr(name, "WEST")) {
nuclear@7 260 side |= TILE_WEST;
nuclear@7 261 }
nuclear@7 262 if(!side) {
nuclear@4 263 side = TILE_ALL;
nuclear@4 264 }
nuclear@4 265
nuclear@21 266 // what a sordid hack... if the name contains "LIGHT", then make a light out of this
nuclear@21 267 // and destroy the mesh...
nuclear@21 268 if(strstr(name, "LIGHT")) {
nuclear@21 269 PointLight *lt = mesh_to_light(mesh);
nuclear@21 270 if(!lt) {
nuclear@21 271 fprintf(stderr, "failed to convert mesh %s to light\n", name);
nuclear@21 272 } else {
nuclear@21 273 lights.push_back(lt);
nuclear@21 274 light_side.push_back(side);
nuclear@21 275 }
nuclear@21 276 delete mesh;
nuclear@21 277
nuclear@46 278 // ... ALSO add a fire particle system :) save me jebus
nuclear@46 279 struct psys_emitter *ps = psys_create();
nuclear@46 280 if(ps && psys_load_attr(&ps->attr, datafile_path("fire.psys")) == 0) {
nuclear@46 281 Vector3 lpos = lt->get_position();
nuclear@46 282 psys_set_pos(ps, v3_cons(lpos.x, lpos.y, lpos.z), 0);
nuclear@46 283 psys_global.push_back(ps);
nuclear@46 284 psys_side.push_back(side);
nuclear@46 285 } else {
nuclear@46 286 fprintf(stderr, "failed to create global particle system\n");
nuclear@46 287 }
nuclear@46 288
nuclear@49 289 // ... AND make an audio source out of each light source
nuclear@49 290 if(cfg.sound) {
nuclear@49 291 SampleSet *sampleset = tset->get_samples();
nuclear@49 292 AudioSample *sample = sampleset->get("fire.ogg");
nuclear@49 293 if(sample) {
nuclear@51 294 AudioSourceDesc adesc = {side, lt->get_position(), sample, 1.0, 0.1};
nuclear@49 295 ausrc.push_back(adesc);
nuclear@49 296 }
nuclear@49 297 }
nuclear@49 298
nuclear@21 299 } else {
nuclear@21 300 meshes.push_back(mesh);
nuclear@21 301 mesh_side.push_back(side);
nuclear@21 302 count++;
nuclear@21 303 }
nuclear@4 304 }
nuclear@4 305 return count;
nuclear@4 306 }
nuclear@7 307
nuclear@7 308 static void build_nodemap(map<aiMesh*, aiNode*> *nmap, const aiScene *scn, aiNode *node)
nuclear@7 309 {
nuclear@7 310 unsigned int i;
nuclear@7 311
nuclear@7 312 for(i=0; i<node->mNumMeshes; i++) {
nuclear@7 313 aiMesh *m = scn->mMeshes[node->mMeshes[i]];
nuclear@7 314
nuclear@7 315 (*nmap)[m] = node;
nuclear@7 316 }
nuclear@7 317
nuclear@7 318 for(i=0; i<node->mNumChildren; i++) {
nuclear@7 319 build_nodemap(nmap, scn, node->mChildren[i]);
nuclear@7 320 }
nuclear@7 321 }
nuclear@21 322
nuclear@21 323 static PointLight *mesh_to_light(Mesh *m)
nuclear@21 324 {
nuclear@21 325 Vector3 center = m->get_bsph_center();
nuclear@21 326 float rad = m->get_bsph_radius();
nuclear@21 327
nuclear@21 328 PointLight *lt = new PointLight(center);
nuclear@21 329 lt->set_radius(rad);
nuclear@21 330
nuclear@21 331 lt->set_color(m->get_material().kd);
nuclear@21 332
nuclear@21 333 return lt;
nuclear@21 334 }