nuclear@1: #include nuclear@46: #include nuclear@7: #include nuclear@1: #include "opengl.h" nuclear@7: #include nuclear@7: #include nuclear@7: #include nuclear@1: #include "tile.h" nuclear@11: #include "tileset.h" nuclear@35: #include "renderer.h" nuclear@46: #include "datapath.h" nuclear@49: #include "cfg.h" nuclear@1: nuclear@7: using std::map; nuclear@7: nuclear@7: static void build_nodemap(map *nmap, const aiScene *scn, aiNode *node); nuclear@21: static PointLight *mesh_to_light(Mesh *m); nuclear@7: nuclear@31: bool ass_obj_hack; nuclear@31: nuclear@11: Tile::Tile(TileSet *tileset) nuclear@11: { nuclear@11: tset = tileset; nuclear@46: last_upd = LONG_MIN; nuclear@48: nuclear@48: memset(samples, 0, sizeof samples); nuclear@11: } nuclear@7: nuclear@38: Tile::~Tile() nuclear@38: { nuclear@38: for(auto m : meshes) { nuclear@38: delete m; nuclear@38: } nuclear@38: for(auto lt : lights) { nuclear@38: delete lt; nuclear@38: } nuclear@46: for(auto psa : psattr) { nuclear@46: psys_free_attr(psa); nuclear@46: } nuclear@46: for(auto ps : psys_global) { nuclear@46: psys_free(ps); nuclear@38: } nuclear@38: } nuclear@38: nuclear@48: AudioSample *Tile::get_sample(int sidx) const nuclear@48: { nuclear@48: if(sidx >= 0 && sidx < MAX_TILE_SAMPLES) { nuclear@48: return samples[sidx]; nuclear@48: } nuclear@48: return 0; nuclear@48: } nuclear@48: nuclear@49: int Tile::get_audio_source_count() const nuclear@45: { nuclear@49: return (int)ausrc.size(); nuclear@49: } nuclear@49: nuclear@49: const Tile::AudioSourceDesc &Tile::get_audio_source(int idx) const nuclear@49: { nuclear@49: if(idx < 0 || idx >= (int)ausrc.size()) { nuclear@50: static AudioSourceDesc d = { 0, Vector3(), 0 }; nuclear@49: return d; nuclear@49: } nuclear@49: return ausrc[idx]; nuclear@45: } nuclear@45: nuclear@46: int Tile::get_unique_psys_count() const nuclear@45: { nuclear@45: return (int)psattr.size(); nuclear@45: } nuclear@45: nuclear@49: struct psys_attributes *Tile::get_unique_psys(int idx) nuclear@49: { nuclear@49: if(idx < 0 || idx >= (int)psattr.size()) { nuclear@49: return 0; nuclear@49: } nuclear@49: return psattr[idx]; nuclear@49: } nuclear@49: nuclear@49: const struct psys_attributes *Tile::get_unique_psys(int idx) const nuclear@49: { nuclear@49: if(idx < 0 || idx >= (int)psattr.size()) { nuclear@49: return 0; nuclear@49: } nuclear@49: return psattr[idx]; nuclear@49: } nuclear@49: nuclear@1: bool Tile::load(const char *fname) nuclear@1: { nuclear@5: if(!fname) { nuclear@5: return false; nuclear@5: } nuclear@5: nuclear@14: char *saved_fname = (char*)alloca(strlen(fname) + 1); nuclear@14: strcpy(saved_fname, fname); nuclear@14: nuclear@3: unsigned int proc_flags = aiProcess_JoinIdenticalVertices | nuclear@35: aiProcess_CalcTangentSpace | nuclear@7: aiProcess_Triangulate | nuclear@7: aiProcess_SortByPType | nuclear@7: aiProcess_FlipUVs; nuclear@4: nuclear@3: const aiScene *scn = aiImportFile(fname, proc_flags); nuclear@3: if(!scn) { nuclear@3: fprintf(stderr, "failed to load tile: %s\n", fname); nuclear@3: return -1; nuclear@3: } nuclear@3: nuclear@7: map nodemap; nuclear@7: build_nodemap(&nodemap, scn, scn->mRootNode); nuclear@7: nuclear@31: if(strstr(fname, ".obj") == fname + strlen(fname) - 4) { nuclear@31: ass_obj_hack = true; nuclear@31: } else { nuclear@31: ass_obj_hack = false; nuclear@31: } nuclear@31: nuclear@21: //load_lights(scn); nuclear@7: load_meshes(scn, nodemap); nuclear@3: nuclear@22: printf("loaded tile %s: %d meshes, %d lights\n", saved_fname, (int)meshes.size(), (int)lights.size()); nuclear@38: nuclear@38: aiReleaseImport(scn); nuclear@48: nuclear@48: // XXX get the default audio samples for now nuclear@49: if(cfg.sound) { nuclear@49: SampleSet *sampleset = tset->get_samples(); nuclear@49: samples[TILE_SAMPLE_WALK] = sampleset->get("walk_stone.ogg"); nuclear@49: samples[TILE_SAMPLE_RUN] = sampleset->get("run_stone.ogg"); nuclear@49: } nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@38: void Tile::update(unsigned long msec, float dt) nuclear@38: { nuclear@46: // update particle systems nuclear@46: for(auto ps : psys_global) { nuclear@46: psys_update(ps, (float)msec / 1000.0f); nuclear@46: } nuclear@38: } nuclear@38: nuclear@5: void Tile::draw(unsigned int draw_mask) const nuclear@1: { nuclear@4: for(size_t i=0; idraw(); nuclear@4: } nuclear@4: } nuclear@4: } nuclear@1: nuclear@23: void Tile::draw_lights(unsigned int draw_mask) const nuclear@23: { nuclear@23: for(size_t i=0; idraw(); nuclear@23: } nuclear@23: } nuclear@23: } nuclear@23: nuclear@46: void Tile::draw_post(unsigned int draw_mask) const nuclear@46: { nuclear@46: // draw global particle systems (simulated once) nuclear@46: for(size_t i=0; imNumLights; i++) { nuclear@4: Light *lt; nuclear@4: aiLight *ailt = scn->mLights[i]; nuclear@4: nuclear@4: switch(ailt->mType) { nuclear@4: case aiLightSource_POINT: nuclear@4: lt = new PointLight(Vector3(ailt->mPosition.x, ailt->mPosition.y, ailt->mPosition.z)); nuclear@4: ((PointLight*)lt)->set_attenuation(ailt->mAttenuationConstant, ailt->mAttenuationLinear, nuclear@4: ailt->mAttenuationQuadratic); nuclear@4: break; nuclear@4: nuclear@4: case aiLightSource_DIRECTIONAL: nuclear@4: lt = new PointLight(Vector3(ailt->mDirection.x, ailt->mDirection.y, ailt->mDirection.z)); nuclear@4: break; nuclear@4: nuclear@4: default: nuclear@4: continue; nuclear@4: } nuclear@4: nuclear@4: lt->set_color(Color(ailt->mColorDiffuse.r, ailt->mColorDiffuse.g, ailt->mColorDiffuse.b, 1.0)); nuclear@4: nuclear@4: lights.push_back(lt); nuclear@4: count++; nuclear@4: } nuclear@4: nuclear@4: return count; nuclear@1: } nuclear@21: */ nuclear@4: nuclear@7: int Tile::load_meshes(const aiScene *scn, const std::map &nmap) nuclear@4: { nuclear@4: int count = 0; nuclear@4: nuclear@41: int attr_loc = rend->get_tangent_location(); nuclear@35: if(attr_loc == -1) { nuclear@35: fprintf(stderr, "warning: failed to retrieve tangent attribute location while loading tile\n"); nuclear@35: } nuclear@35: nuclear@4: for(int i=0; i<(int)scn->mNumMeshes; i++) { nuclear@37: // ignore any lines or other crap nuclear@37: if(scn->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { nuclear@37: continue; nuclear@37: } nuclear@37: nuclear@4: Mesh *mesh = new Mesh; nuclear@4: if(!mesh->create(scn, scn->mMeshes[i])) { nuclear@4: delete mesh; nuclear@4: continue; nuclear@4: } nuclear@35: if(attr_loc != -1) { nuclear@35: mesh->set_attrib_location(MESH_ATTR_TANGENT, attr_loc); nuclear@35: } nuclear@4: nuclear@11: Material mat; nuclear@11: mat.load(scn->mMaterials[scn->mMeshes[i]->mMaterialIndex], tset->get_textures()); nuclear@11: mesh->set_material(mat); nuclear@11: nuclear@7: // retrieve the node pointer nuclear@7: const char *name = ""; nuclear@7: nuclear@7: auto iter = nmap.find(scn->mMeshes[i]); nuclear@7: if(iter != nmap.end()) { nuclear@7: aiNode *node = iter->second; nuclear@7: nuclear@7: Matrix4x4 xform; nuclear@7: //xform.rotate(Vector3(-M_PI / 2.0, 0, 0)); nuclear@7: xform = *(Matrix4x4*)&node->mTransformation; nuclear@7: mesh->set_xform(xform); nuclear@7: nuclear@7: name = node->mName.data; nuclear@7: mesh->set_name(name); nuclear@7: } nuclear@7: nuclear@4: // find which side is this mesh on nuclear@7: unsigned int side = 0; nuclear@7: if(strstr(name, "NORTH")) { nuclear@7: side |= TILE_NORTH; nuclear@7: } nuclear@7: if(strstr(name, "SOUTH")) { nuclear@7: side |= TILE_SOUTH; nuclear@7: } nuclear@7: if(strstr(name, "EAST")) { nuclear@7: side |= TILE_EAST; nuclear@7: } nuclear@7: if(strstr(name, "WEST")) { nuclear@7: side |= TILE_WEST; nuclear@7: } nuclear@7: if(!side) { nuclear@4: side = TILE_ALL; nuclear@4: } nuclear@4: nuclear@21: // what a sordid hack... if the name contains "LIGHT", then make a light out of this nuclear@21: // and destroy the mesh... nuclear@21: if(strstr(name, "LIGHT")) { nuclear@21: PointLight *lt = mesh_to_light(mesh); nuclear@21: if(!lt) { nuclear@21: fprintf(stderr, "failed to convert mesh %s to light\n", name); nuclear@21: } else { nuclear@21: lights.push_back(lt); nuclear@21: light_side.push_back(side); nuclear@21: } nuclear@21: delete mesh; nuclear@21: nuclear@46: // ... ALSO add a fire particle system :) save me jebus nuclear@46: struct psys_emitter *ps = psys_create(); nuclear@46: if(ps && psys_load_attr(&ps->attr, datafile_path("fire.psys")) == 0) { nuclear@46: Vector3 lpos = lt->get_position(); nuclear@46: psys_set_pos(ps, v3_cons(lpos.x, lpos.y, lpos.z), 0); nuclear@46: psys_global.push_back(ps); nuclear@46: psys_side.push_back(side); nuclear@46: } else { nuclear@46: fprintf(stderr, "failed to create global particle system\n"); nuclear@46: } nuclear@46: nuclear@49: // ... AND make an audio source out of each light source nuclear@49: if(cfg.sound) { nuclear@49: SampleSet *sampleset = tset->get_samples(); nuclear@49: AudioSample *sample = sampleset->get("fire.ogg"); nuclear@49: if(sample) { nuclear@50: AudioSourceDesc adesc = {side, lt->get_position(), sample}; nuclear@49: ausrc.push_back(adesc); nuclear@49: } nuclear@49: } nuclear@49: nuclear@21: } else { nuclear@21: meshes.push_back(mesh); nuclear@21: mesh_side.push_back(side); nuclear@21: count++; nuclear@21: } nuclear@4: } nuclear@4: return count; nuclear@4: } nuclear@7: nuclear@7: static void build_nodemap(map *nmap, const aiScene *scn, aiNode *node) nuclear@7: { nuclear@7: unsigned int i; nuclear@7: nuclear@7: for(i=0; imNumMeshes; i++) { nuclear@7: aiMesh *m = scn->mMeshes[node->mMeshes[i]]; nuclear@7: nuclear@7: (*nmap)[m] = node; nuclear@7: } nuclear@7: nuclear@7: for(i=0; imNumChildren; i++) { nuclear@7: build_nodemap(nmap, scn, node->mChildren[i]); nuclear@7: } nuclear@7: } nuclear@21: nuclear@21: static PointLight *mesh_to_light(Mesh *m) nuclear@21: { nuclear@21: Vector3 center = m->get_bsph_center(); nuclear@21: float rad = m->get_bsph_radius(); nuclear@21: nuclear@21: PointLight *lt = new PointLight(center); nuclear@21: lt->set_radius(rad); nuclear@21: nuclear@21: lt->set_color(m->get_material().kd); nuclear@21: nuclear@21: return lt; nuclear@21: }