dungeon_crawler

annotate prototype/src/tile.cc @ 78:12a1dcfe91fa

gamma correct rendering
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 26 Oct 2012 21:22:14 +0300
parents 7f52d6310317
children
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@60 144 int tang_loc = rend->get_tangent_location();
nuclear@60 145
nuclear@4 146 for(size_t i=0; i<meshes.size(); i++) {
nuclear@4 147 if(mesh_side[i] & draw_mask) {
nuclear@60 148 meshes[i]->set_attrib_location(MESH_ATTR_TANGENT, tang_loc);
nuclear@5 149 meshes[i]->draw();
nuclear@4 150 }
nuclear@4 151 }
nuclear@4 152 }
nuclear@1 153
nuclear@23 154 void Tile::draw_lights(unsigned int draw_mask) const
nuclear@23 155 {
nuclear@23 156 for(size_t i=0; i<lights.size(); i++) {
nuclear@23 157 if(light_side[i] & draw_mask) {
nuclear@63 158 //printf("rendering light ...\n");
nuclear@23 159 lights[i]->draw();
nuclear@23 160 }
nuclear@23 161 }
nuclear@23 162 }
nuclear@23 163
nuclear@46 164 void Tile::draw_post(unsigned int draw_mask) const
nuclear@46 165 {
nuclear@46 166 // draw global particle systems (simulated once)
nuclear@46 167 for(size_t i=0; i<psys_global.size(); i++) {
nuclear@46 168 if(psys_side[i] & draw_mask) {
nuclear@46 169 psys_draw(psys_global[i]);
nuclear@46 170 }
nuclear@46 171 }
nuclear@46 172 }
nuclear@46 173
nuclear@21 174 /*
nuclear@4 175 int Tile::load_lights(const aiScene *scn)
nuclear@4 176 {
nuclear@4 177 int count = 0;
nuclear@4 178
nuclear@4 179 for(int i=0; i<(int)scn->mNumLights; i++) {
nuclear@4 180 Light *lt;
nuclear@4 181 aiLight *ailt = scn->mLights[i];
nuclear@4 182
nuclear@4 183 switch(ailt->mType) {
nuclear@4 184 case aiLightSource_POINT:
nuclear@4 185 lt = new PointLight(Vector3(ailt->mPosition.x, ailt->mPosition.y, ailt->mPosition.z));
nuclear@4 186 ((PointLight*)lt)->set_attenuation(ailt->mAttenuationConstant, ailt->mAttenuationLinear,
nuclear@4 187 ailt->mAttenuationQuadratic);
nuclear@4 188 break;
nuclear@4 189
nuclear@4 190 case aiLightSource_DIRECTIONAL:
nuclear@4 191 lt = new PointLight(Vector3(ailt->mDirection.x, ailt->mDirection.y, ailt->mDirection.z));
nuclear@4 192 break;
nuclear@4 193
nuclear@4 194 default:
nuclear@4 195 continue;
nuclear@4 196 }
nuclear@4 197
nuclear@4 198 lt->set_color(Color(ailt->mColorDiffuse.r, ailt->mColorDiffuse.g, ailt->mColorDiffuse.b, 1.0));
nuclear@4 199
nuclear@4 200 lights.push_back(lt);
nuclear@4 201 count++;
nuclear@4 202 }
nuclear@4 203
nuclear@4 204 return count;
nuclear@1 205 }
nuclear@21 206 */
nuclear@4 207
nuclear@7 208 int Tile::load_meshes(const aiScene *scn, const std::map<aiMesh*, aiNode*> &nmap)
nuclear@4 209 {
nuclear@4 210 int count = 0;
nuclear@4 211
nuclear@4 212 for(int i=0; i<(int)scn->mNumMeshes; i++) {
nuclear@37 213 // ignore any lines or other crap
nuclear@37 214 if(scn->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) {
nuclear@37 215 continue;
nuclear@37 216 }
nuclear@37 217
nuclear@4 218 Mesh *mesh = new Mesh;
nuclear@4 219 if(!mesh->create(scn, scn->mMeshes[i])) {
nuclear@4 220 delete mesh;
nuclear@4 221 continue;
nuclear@4 222 }
nuclear@4 223
nuclear@11 224 Material mat;
nuclear@11 225 mat.load(scn->mMaterials[scn->mMeshes[i]->mMaterialIndex], tset->get_textures());
nuclear@11 226 mesh->set_material(mat);
nuclear@11 227
nuclear@7 228 // retrieve the node pointer
nuclear@7 229 const char *name = "<unknown>";
nuclear@7 230
nuclear@7 231 auto iter = nmap.find(scn->mMeshes[i]);
nuclear@7 232 if(iter != nmap.end()) {
nuclear@7 233 aiNode *node = iter->second;
nuclear@7 234
nuclear@7 235 Matrix4x4 xform;
nuclear@7 236 //xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
nuclear@7 237 xform = *(Matrix4x4*)&node->mTransformation;
nuclear@7 238 mesh->set_xform(xform);
nuclear@7 239
nuclear@7 240 name = node->mName.data;
nuclear@7 241 mesh->set_name(name);
nuclear@7 242 }
nuclear@7 243
nuclear@4 244 // find which side is this mesh on
nuclear@7 245 unsigned int side = 0;
nuclear@7 246 if(strstr(name, "NORTH")) {
nuclear@7 247 side |= TILE_NORTH;
nuclear@7 248 }
nuclear@7 249 if(strstr(name, "SOUTH")) {
nuclear@7 250 side |= TILE_SOUTH;
nuclear@7 251 }
nuclear@7 252 if(strstr(name, "EAST")) {
nuclear@7 253 side |= TILE_EAST;
nuclear@7 254 }
nuclear@7 255 if(strstr(name, "WEST")) {
nuclear@7 256 side |= TILE_WEST;
nuclear@7 257 }
nuclear@7 258 if(!side) {
nuclear@4 259 side = TILE_ALL;
nuclear@4 260 }
nuclear@4 261
nuclear@21 262 // what a sordid hack... if the name contains "LIGHT", then make a light out of this
nuclear@21 263 // and destroy the mesh...
nuclear@21 264 if(strstr(name, "LIGHT")) {
nuclear@21 265 PointLight *lt = mesh_to_light(mesh);
nuclear@21 266 if(!lt) {
nuclear@21 267 fprintf(stderr, "failed to convert mesh %s to light\n", name);
nuclear@21 268 } else {
nuclear@21 269 lights.push_back(lt);
nuclear@21 270 light_side.push_back(side);
nuclear@21 271 }
nuclear@21 272 delete mesh;
nuclear@21 273
nuclear@46 274 // ... ALSO add a fire particle system :) save me jebus
nuclear@46 275 struct psys_emitter *ps = psys_create();
nuclear@63 276 if(ps && psys_load_attr(&ps->attr, datafile_path("fire.psys").c_str()) == 0) {
nuclear@46 277 Vector3 lpos = lt->get_position();
nuclear@53 278 psys_set_pos(ps, v3_cons(lpos.x, lpos.y + 0.01, lpos.z), 0);
nuclear@46 279 psys_global.push_back(ps);
nuclear@46 280 psys_side.push_back(side);
nuclear@46 281 } else {
nuclear@46 282 fprintf(stderr, "failed to create global particle system\n");
nuclear@46 283 }
nuclear@46 284
nuclear@49 285 // ... AND make an audio source out of each light source
nuclear@49 286 if(cfg.sound) {
nuclear@49 287 SampleSet *sampleset = tset->get_samples();
nuclear@49 288 AudioSample *sample = sampleset->get("fire.ogg");
nuclear@49 289 if(sample) {
nuclear@51 290 AudioSourceDesc adesc = {side, lt->get_position(), sample, 1.0, 0.1};
nuclear@49 291 ausrc.push_back(adesc);
nuclear@49 292 }
nuclear@49 293 }
nuclear@49 294
nuclear@21 295 } else {
nuclear@21 296 meshes.push_back(mesh);
nuclear@21 297 mesh_side.push_back(side);
nuclear@21 298 count++;
nuclear@21 299 }
nuclear@4 300 }
nuclear@4 301 return count;
nuclear@4 302 }
nuclear@7 303
nuclear@7 304 static void build_nodemap(map<aiMesh*, aiNode*> *nmap, const aiScene *scn, aiNode *node)
nuclear@7 305 {
nuclear@7 306 unsigned int i;
nuclear@7 307
nuclear@7 308 for(i=0; i<node->mNumMeshes; i++) {
nuclear@7 309 aiMesh *m = scn->mMeshes[node->mMeshes[i]];
nuclear@7 310
nuclear@7 311 (*nmap)[m] = node;
nuclear@7 312 }
nuclear@7 313
nuclear@7 314 for(i=0; i<node->mNumChildren; i++) {
nuclear@7 315 build_nodemap(nmap, scn, node->mChildren[i]);
nuclear@7 316 }
nuclear@7 317 }
nuclear@21 318
nuclear@21 319 static PointLight *mesh_to_light(Mesh *m)
nuclear@21 320 {
nuclear@21 321 Vector3 center = m->get_bsph_center();
nuclear@21 322 float rad = m->get_bsph_radius();
nuclear@21 323
nuclear@21 324 PointLight *lt = new PointLight(center);
nuclear@21 325 lt->set_radius(rad);
nuclear@21 326
nuclear@21 327 lt->set_color(m->get_material().kd);
nuclear@78 328 lt->set_intensity(0.8);
nuclear@21 329
nuclear@21 330 return lt;
nuclear@21 331 }