bool TerrainObject::place(object_state init_state) { if (this->state == object_state::removed) { throw Error(MSG(err) << "Building cannot change state with no position"); } // remove any other floating objects // which intersect with the new placement // if non-floating objects are on the foundation // then this placement will fail for (coord::tile temp_pos : tile_list(this->pos)) { std::vector<TerrainObject *> to_remove; TerrainChunk *chunk = this->get_terrain()->get_chunk(temp_pos); if (chunk == nullptr) { continue; } for (auto obj : chunk->get_data(temp_pos)->obj) { // ignore self and annexes of self if (obj != this && obj->get_parent() != this) { if (obj->is_floating()) { // floating objects get removed to_remove.push_back(obj); } else if (obj->check_collisions()) { // solid objects obstruct placement return false; } } } // all obstructing objects get deleted for (auto remove_obj : to_remove) { remove_obj->unit.location = nullptr; } } // set new state this->state = init_state; return true; }
float Terrain::get_height_recursive(TerrainChunk* tc, float x, float y) { TerrainChunk* child; if(!tc->getBoundingBox()->contains(glm::vec2(x,y))) return 0.0f; if(tc->areChildrenLoaded()) { for(int i=0;i<4;i++) { child = dynamic_cast<TerrainChunk*>(tc->getChild(i)); if(child->getBoundingBox()->contains(glm::vec2(x,y))) return get_height_recursive(child,x,y); } // This code should not be reached... return 0 anyways return 0.0f; } return tc->getHeightAt(x,y); }
void Terrain::generateTerrainChunks(int chunksize){ //determine dimensions of octree mChunks.init(Vec3f(), Vec3f((float)mWidth, 0, (float)mDepth)*mScale, Vec3f((float)chunksize,0,(float)chunksize)*mScale); mNumChunksX = mWidth/chunksize; mNumChunksY = mDepth/chunksize; //mChunks = new TerrainChunk*[mNumChunksY]; float y = -mDepth*mScale.z/2; for (int j = 0; j < mNumChunksY; ++j){ //mChunks[j] = new TerrainChunk[mNumChunksX]; float x = -mWidth*mScale.x/2; for (int i = 0; i < mNumChunksX; ++i){ TerrainChunk* chunk = new TerrainChunk(); chunk->generate(chunksize+1,mScale.x,x,y); mChunks.insert(chunk->getBox(), chunk); x += chunksize*mScale.x; } y += chunksize*mScale.z; } init(mWidth,mDepth,mScale.x,mScale.z,mHeightfield,mScale.y); }
TerrainChunk* ChunkGenerator::createChunk(int id) { TerrainChunk* tc = m_Reader->readId(id); int size = tc->getHeightmap()->getSize() + 3; float skirt_depth = tc->getHeightmap()->getMinHeight() - tc->getError(); std::vector<float>* heights = new std::vector<float>(); float height; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { if (x == 0 || x == size - 1 || y == 0 || y == size - 1) { height = skirt_depth; } else { height = tc->getHeightmap()->getHeightAt(x-1, y-1); } heights->push_back(height); } } m_Vbo->uploadData(&(*heights)[0],heights->size(),m_GroundMesh.size()+heights->size()*id); Mesh* nm = m_Mesh->clone(); nm->addVBAttribute(new VertexBufferAttribute(m_Vbo, Shader::VERTEX_UV1, 1,0,false,sizeof(float)*(m_GroundMesh.size()+heights->size()*id))); tc->setMesh(nm); delete heights; return tc; }
void ShadowMapRenderer::DrawTerrainShadowTexPass(Terrain* terrain, Camera* camera) { _Assert(NULL != terrain); mShadowTexEffect->SetTechnique("Shadow"); mShadowTexEffect->SetMatrix("matWVP", &(camera->ViewMatrix() * camera->ProjMatrix())); mShadowTexEffect->SetMatrix("matWorld", &IDENTITY_MATRIX); _Assert(CASCADE_COUNTS >= 3); mShadowTexEffect->SetMatrix("matLightVP0", &mVirtualCamera[0].matVP); mShadowTexEffect->SetMatrix("matLightVP1", &mVirtualCamera[1].matVP); mShadowTexEffect->SetMatrix("matLightVP2", &mVirtualCamera[2].matVP); mShadowTexEffect->SetRawValue("lightPos0", &(mVirtualCamera[0].pos), 0, sizeof(Vector3)); mShadowTexEffect->SetRawValue("lightPos1", &(mVirtualCamera[1].pos), 0, sizeof(Vector3)); mShadowTexEffect->SetRawValue("lightPos2", &(mVirtualCamera[2].pos), 0, sizeof(Vector3)); mShadowTexEffect->SetTexture("shadowMapTex0", mShadowMapBluredTex[0]->GetD3DTexture()); mShadowTexEffect->SetTexture("shadowMapTex1", mShadowMapBluredTex[1]->GetD3DTexture()); mShadowTexEffect->SetTexture("shadowMapTex2", mShadowMapBluredTex[2]->GetD3DTexture()); float farZ = 0; camera->GetCameraParams(NULL, &farZ, NULL, NULL); mShadowTexEffect->SetFloat("farZ", farZ); mShadowTexEffect->CommitChanges(); std::vector<TerrainChunk*> chunks = terrain->GetChunks(); for(std::vector<TerrainChunk*>::iterator iter = chunks.begin(); iter != chunks.end(); ++iter) { // TODO: bound判断 TerrainChunk* chunk = *iter; chunk->SetVertexStream(); chunk->Draw(); } }
void Terrain::validateLODLevels() { for (ChunkIterator i = _chunks.begin(), e = _chunks.end(); i != e; ++i) { TerrainChunk* chunk = *i; if (chunk->selectedLod == 0) { chunk->selectedVariation = 0; } else { int chunkRow = chunk->index() / _chunkSizes.x; int chunkCol = chunk->index() % _chunkSizes.x; int leftCol = etMax(0, chunkCol - 1); int rightCol = etMin(_chunkSizes.x - 1, chunkCol + 1); int topRow = etMax(0, chunkRow - 1); int bottomRow = etMin(_chunkSizes.y - 1, chunkRow + 1); int leftChunk = leftCol + chunkRow * _chunkSizes.x; int rightChunk = rightCol + chunkRow * _chunkSizes.x; int topChunk = chunkCol + topRow * _chunkSizes.x; int bottomChunk = chunkCol + bottomRow * _chunkSizes.x; int ownLOD = chunk->selectedLod; TerrainLODLevels::LODVariation variation; variation.conjugateLeft = ownLOD > _chunks.at(leftChunk)->selectedLod; variation.conjugateRight = ownLOD > _chunks.at(rightChunk)->selectedLod; variation.conjugateTop = ownLOD > _chunks.at(topChunk)->selectedLod; variation.conjugateBottom = ownLOD > _chunks.at(bottomChunk)->selectedLod; chunk->selectedVariation = variation.definition(); } } }
void TerrainObject::set_ground(int id, int additional) { if (not this->is_placed()) { throw Error(MSG(err) << "Setting ground for object that is not placed yet."); } coord::tile temp_pos = this->pos.start; temp_pos.ne -= additional; temp_pos.se -= additional; while (temp_pos.ne < this->pos.end.ne + additional) { while (temp_pos.se < this->pos.end.se + additional) { TerrainChunk *chunk = this->get_terrain()->get_chunk(temp_pos); if (chunk == nullptr) { continue; } size_t tile_pos = chunk->tile_position_neigh(temp_pos); chunk->get_data(tile_pos)->terrain_id = id; temp_pos.se++; } temp_pos.se = this->pos.start.se - additional; temp_pos.ne++; } }
int main(int argc, char** argv) { if (argc == 3 && strncmp(argv[1], "--convert", 9) == 0) { Configuration* config = new IniConfig(argv[2]); Heightmap* map = new Heightmap(config->getFloatValue("terrain","spacing")); if (map->loadFromImage(config->getValue("terrain","heightmap").c_str())) { std::cout << "Generating Terrain.." << std::endl; TerrainGenerator(map, config->getIntValue("terrain","chunksize"), config->getValue("out","filename").c_str()); std::cout << "..done" << std::endl; std::cout.flush(); } else std::cout << "Generation failed." << std::endl; return 0; } if (argc == 4 && strncmp(argv[1], "--load", 6) == 0) { int id = atoi(argv[3]); TerrainFileReader* reader = new TerrainFileReader(); reader->openFile(argv[2]); TerrainChunk* tc = reader->readId(id); if (tc == NULL || tc->getInfo()->getQuadId() != id) { std::cout << "Got ID" << tc->getInfo()->getQuadId() << " instead of " << id << std::endl; return 1; } else { std::cout << "Successfully got Terrainchunk " << id << std::endl; std::cout << "Spacing of Heightmap is " << tc->getHeightmap()->getSpacing() << " where origin is " << tc->getOrigin().x << "," << tc->getOrigin().y << " and center at " << tc->getCenter().x << "," << tc->getCenter().y << std::endl; } reader->closeFile(); delete tc; delete reader; } if (argc != 2 || strncmp(argv[1], "--run", 5) != 0) { std::cout << "Usage of '" << argv[0] << "'" <<std::endl; std::cout << "\nAvailable Parameter:" << "\n\t--convert terrain.desc" << "\n\t--load terrain.terr chunkid(=0)" << "\n\t--run" << std::endl; return 1; } int width, height; Configuration * win_config = new IniConfig("config.ini"); WindowHints* hints = new WindowHints(); hints->Fullscreen = win_config->getBooleanValue("Window","fullscreen"); hints->Width = win_config->getIntValue("Window","width"); hints->Height = win_config->getIntValue("Window","height"); GraphicsSystem* GSystem = new GraphicsSystem(GraphicsSystem::PROFILE_GL3, hints); if (GSystem->isError()) return -1; GraphicsContext* grctx = GSystem->getGraphicsContext(); Window* win = GSystem->getWindow(); TextureManager* tmgr = new TextureManager(grctx); ModelLoader* mmgr = new ModelLoader(grctx, tmgr); TerrainManager* terrmgr = new TerrainManager(grctx); Model* mdl, *mdl2; Camera* cam = new Camera(); win->getSize(&width, &height); cam->setScreen(width,height); cam->setupLens(65.0f, 1.0f, 1000.0f); if ((mdl = mmgr->loadAsset("Resources/Models/ant01.ms3d")) == NULL) std::cerr << "Could not load Model" << std::endl; if ((mdl2 = mmgr->loadAsset("Resources/Models/dwarf1.ms3d")) == NULL) std::cerr << "Could not load Model" << std::endl; ModelAnimationController mdlanictrl(mdl), mdlanictrl2(mdl2); mdlanictrl.addAnimation("idle", 52, 67, 0.25f, true); mdlanictrl.addAnimation("die", 30, 49, 0.25f, false); mdlanictrl2.addAnimation("begin_walk", 1, 2, 0.25f, false, "walk"); mdlanictrl2.addAnimation("walk", 2, 14, 0.25f, true); mdlanictrl2.addAnimation("jump", 28, 40, 0.5f, false, "begin_walk"); mdlanictrl2.addAnimation("idle", 292, 325, 0.25f, false, "idle2"); mdlanictrl2.addAnimation("idle2", 327, 360, 0.25f, true); mdlanictrl2.addAnimation("die", 230, 251, 0.25f, false); std::cout << "Using DesktopMode: " << width << "x" << height << std::endl; win->setTitle("Xng?! -> Yeah!"); Shader* sh = grctx->createShader(); if (!sh->loadFromFile("Shader/Animation.vs", "Shader/Animation.fs")) return 1; Shader* tsh = grctx->createShader(); if (!tsh->loadFromFile("Shader/Terrain.vs", "Shader/Terrain.fs")) return 1; Timer* t = new Timer(); double frames = 0; grctx->setClearColor(glm::vec4(1.0f, 0.5f, 0.25f, 1.0f)); t->start(); Terrain* terr = terrmgr->loadAsset("Resources/terrain/terrain.terr"); terr->setDetail(0.05f,cam); glm::mat4 mdlm = glm::scale( glm::translate(glm::mat4(1.0f), glm::vec3(5.0f, -5.0f, -20.0f)), glm::vec3(0.5f)); glm::mat4 mdlm2 = glm::scale( glm::translate(glm::mat4(1.0f), glm::vec3(-5.0f, -5.0f, -20.0f)), glm::vec3(0.18f)); mdlm = glm::rotate(mdlm, 180.0f, glm::vec3(0.0f, 1.0f, 0.0f)); mdlm2 = glm::rotate(mdlm2, 180.0f, glm::vec3(0.0f, 1.0f, 0.0f)); glm::vec3 cam_pos = glm::vec3(0.0f,0.0f,0.0f); glm::quat cam_orient = glm::quat(); float speed = 0.0f; float deltaTime = 0; float second = t->getMilli(); float lastTime = second; while (win->isOpen()) { second = t->getMilli(); deltaTime = second - lastTime; lastTime = second; if (glfwGetKey(GLFW_KEY_ESC)) break; if (glfwGetKey(GLFW_KEY_SPACE)) mdlanictrl2.setActiveAnimation("jump"); if (glfwGetKey('W')) mdlanictrl2.setActiveAnimation("begin_walk"); if (glfwGetKey('S')) mdlanictrl2.setActiveAnimation("idle"); if (glfwGetKey('F')) mdlanictrl.setActiveAnimation("die"); if (glfwGetKey('G')) mdlanictrl2.setActiveAnimation("die"); if (glfwGetKey('A')) mdlm2 = glm::rotate(mdlm2, -0.3f, glm::vec3(0.0f, 1.0f, 0.0f)); if (glfwGetKey('D')) mdlm2 = glm::rotate(mdlm2, 0.3f, glm::vec3(0.0f, 1.0f, 0.0f)); if( glfwGetKey(GLFW_KEY_LSHIFT) || glfwGetKey(GLFW_KEY_RSHIFT)) speed = 1.0f; else speed = 0.1f; if (glfwGetKey('I')) cam_pos += glm::cross(cam->getUpVector(),cam->getRightVector()) * speed * deltaTime; if (glfwGetKey('K')) cam_pos -= glm::cross(cam->getUpVector(),cam->getRightVector()) * speed * deltaTime; if (glfwGetKey('J')) cam_pos -= cam->getRightVector() * speed * deltaTime; if (glfwGetKey('L')) cam_pos += cam->getRightVector() * speed * deltaTime; if (glfwGetKey('O')) cam_pos += cam->getUpVector() * speed * deltaTime; if (glfwGetKey('P')) cam_pos -= cam->getUpVector() * speed * deltaTime; if(glfwGetKey(GLFW_KEY_LEFT)) cam_orient = glm::rotate(cam_orient,speed * deltaTime,glm::vec3(0.0f,1.0f,0.0f)); if(glfwGetKey(GLFW_KEY_RIGHT)) cam_orient =glm::rotate(cam_orient,-speed * deltaTime,glm::vec3(0.0f,1.0f,0.0f)); if(glfwGetKey(GLFW_KEY_UP)) cam_orient = glm::rotate(cam_orient,speed * deltaTime,glm::vec3(1.0f,0.0f,0.0f)); if(glfwGetKey(GLFW_KEY_DOWN)) cam_orient = glm::rotate(cam_orient,-speed * deltaTime,glm::vec3(1.0f,0.0f,0.0f)); cam_pos.y = terr->getHeightAt(cam_pos.x,cam_pos.z) + 5; cam->setPosition(cam_pos); cam->setOrientation(cam_orient); mdlanictrl.update(deltaTime); mdlanictrl2.update(deltaTime); grctx->clearDisplay(); grctx->setShader(sh); grctx->setProjectionMatrix(cam->getLens()); grctx->setViewMatrix(cam->getView()); grctx->setModelMatrix(&mdlm); for (int i = 0; i < mdl->getNumMeshes(); i++) { grctx->setMesh(mdl->getMesh(i)); grctx->setMaterial(mdl->getMaterial(mdl->getMesh(i)->getMaterialId())); grctx->setBoneTransformation(mdlanictrl.getBoneTransformation(), mdlanictrl.getNumBones()); grctx->draw(); } grctx->setModelMatrix(&mdlm2); for (int i = 0; i < mdl2->getNumMeshes(); i++) { grctx->setMesh(mdl2->getMesh(i)); grctx->setMaterial(mdl2->getMaterial(mdl2->getMesh(i)->getMaterialId())); grctx->setBoneTransformation(mdlanictrl2.getBoneTransformation(), mdlanictrl2.getNumBones()); grctx->draw(); } grctx->setShader(tsh); grctx->setProjectionMatrix(cam->getLens()); grctx->setViewMatrix(cam->getView()); terr->selectNodes(cam); grctx->swapBuffers(); frames++; } t->end(); delete sh; mmgr->removeAsset("Resources/Models/dwarf1.ms3d"); mmgr->removeAsset("Resources/Models/ant01.ms3d"); std::cout << "TpF: " << t->getLastMilli() / frames << " mspf was " << frames << " Frames in " << t->getLastMilli() << "ms or " << frames / t->getLastSecond() << "fps" << std::endl; delete mmgr; delete tmgr; delete t; delete GSystem; return 0; }
bool GameMain::on_input(SDL_Event *e) { Engine &engine = Engine::get(); switch (e->type) { case SDL_QUIT: engine.stop(); break; case SDL_MOUSEBUTTONDOWN: { //thanks C++! we need a separate scope because of new variables... // a mouse button was pressed... // subtract value from window height to get position relative to lower right (0,0). coord::window mousepos_window {(coord::pixel_t) e->button.x, (coord::pixel_t) e->button.y}; coord::camgame mousepos_camgame = mousepos_window.to_camgame(); // TODO once the terrain elevation milestone is implemented, use a method // more suitable for converting camgame to phys3 coord::phys3 mousepos_phys3 = mousepos_camgame.to_phys3(); coord::tile mousepos_tile = mousepos_phys3.to_tile3().to_tile(); if (clicking_active and e->button.button == SDL_BUTTON_LEFT) { log::dbg("LMB [window]: x %9hd y %9hd", mousepos_window.x, mousepos_window.y); log::dbg("LMB [camgame]: x %9hd y %9hd", mousepos_camgame.x, mousepos_camgame.y); auto phys_per_tile = openage::coord::settings::phys_per_tile; log::dbg("LMB [phys3]: NE %8.3f SE %8.3f UP %8.3f", ((float) mousepos_phys3.ne) / phys_per_tile, ((float) mousepos_phys3.se) / phys_per_tile, ((float) mousepos_phys3.up) / phys_per_tile); log::dbg("LMB [tile]: NE %8ld SE %8ld", mousepos_tile.ne, mousepos_tile.se); TerrainChunk *chunk = terrain->get_create_chunk(mousepos_tile); chunk->get_data(mousepos_tile)->terrain_id = editor_current_terrain; } else if (clicking_active and e->button.button == SDL_BUTTON_RIGHT) { // get chunk clicked on, don't create it if it's not there already // -> placing buildings in void is forbidden that way TerrainChunk *chunk = terrain->get_chunk(mousepos_tile); if (chunk == nullptr) { break; } // get object currently standing at the clicked position TerrainObject *obj = chunk->get_data(mousepos_tile)->obj; if (obj != nullptr) { obj->remove(); this->placed_buildings.erase(obj); this->available_sounds[obj->sound_id_destruction].play(); delete obj; } else { TestBuilding *newbuilding = this->available_buildings[this->editor_current_building]; int coloring = util::random_range(1, 8 + 1); TerrainObject *newobj = new TerrainObject( newbuilding->texture, newbuilding->foundation_size, coloring, newbuilding->sound_id_destruction ); // try to place the obj, it knows best whether it will fit. bool obj_placed = newobj->place(terrain, mousepos_tile); if (obj_placed) { this->available_sounds[newbuilding->sound_id_creation].play(); this->placed_buildings.insert(newobj); if (newbuilding->foundation_terrain > 0) { // TODO: use the gamedata terrain lookup! newobj->set_ground(newbuilding->foundation_terrain, 0); } } else { delete newobj; } } break; } else if (not scrolling_active and e->button.button == SDL_BUTTON_MIDDLE) { // activate scrolling SDL_SetRelativeMouseMode(SDL_TRUE); scrolling_active = true; // deactivate clicking as long as mousescrolling is active clicking_active = false; } break; } case SDL_MOUSEBUTTONUP: if (scrolling_active and e->button.button == SDL_BUTTON_MIDDLE) { // stop scrolling SDL_SetRelativeMouseMode(SDL_FALSE); scrolling_active = false; // reactivate mouse clicks as scrolling is over clicking_active = true; } break; case SDL_MOUSEMOTION: // scroll, if middle mouse is being pressed // SDL_GetRelativeMouseMode() queries sdl for that. if (scrolling_active) { // move the cam coord::vec2f cam_movement {0.0, 0.0}; cam_movement.x = e->motion.xrel; cam_movement.y = e->motion.yrel; // this factor controls the scroll speed // cam_movement *= 1; // calculate camera position delta from velocity and frame duration coord::camgame_delta cam_delta; cam_delta.x = cam_movement.x; cam_delta.y = - cam_movement.y; //update camera phys position engine.camgame_phys += cam_delta.to_phys3(); } break; case SDL_MOUSEWHEEL: if (this->ctrl_active) { editor_current_building = util::mod<ssize_t>(editor_current_building + e->wheel.y, this->available_buildings.size()); } else { editor_current_terrain = util::mod<ssize_t>(editor_current_terrain + e->wheel.y, this->terrain->terrain_id_count); } break; case SDL_KEYUP: switch (((SDL_KeyboardEvent *) e)->keysym.sym) { case SDLK_ESCAPE: //stop the game engine.stop(); break; case SDLK_F1: engine.drawing_huds = !engine.drawing_huds; break; case SDLK_F3: engine.drawing_debug_overlay = !engine.drawing_debug_overlay; break; case SDLK_LCTRL: this->ctrl_active = false; break; } break; case SDL_KEYDOWN: switch (((SDL_KeyboardEvent *) e)->keysym.sym) { case SDLK_SPACE: this->terrain->blending_enabled = !terrain->blending_enabled; break; case SDLK_F2: engine.get_screenshot_manager().save_screenshot(); break; case SDLK_LCTRL: this->ctrl_active = true; break; } break; } return true; }
/** set a terrain tile id by a given position. if the tiles chunk does not exist yet, this chunk is created. */ void Terrain::set_tile(coord::tile position, int tile) { TerrainChunk *c = this->get_create_chunk(position.to_chunk()); return c->set_tile(position.get_pos_on_chunk().to_tile(), tile); }
/** get a terrain tile id by a given position. the chunk, which this tile lies on, will be created, if it does not exist yet. */ int Terrain::get_tile(coord::tile position) { TerrainChunk *c = this->get_create_chunk(position.to_chunk()); return c->get_tile(position.get_pos_on_chunk().to_tile()); }