dungeon_crawler

view prototype/src/tile.cc @ 48:aa9e28670ae2

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