#include "TerrainSample.h" #include "SamplesGame.h" #if defined(ADD_SAMPLE) ADD_SAMPLE("Graphics", "Terrain", TerrainSample, 12); #endif struct TerrainHitFilter : public PhysicsController::HitFilter { TerrainHitFilter(Terrain* terrain) { terrainObject = terrain->getNode()->getCollisionObject(); } bool filter(PhysicsCollisionObject* object) { // Filter out all objects but the terrain return (object != terrainObject); } PhysicsCollisionObject* terrainObject; }; TerrainSample::TerrainSample() : _font(NULL), _scene(NULL), _terrain(NULL), _sky(NULL), _form(NULL), _formVisible(true), _wireframe(false), _debugPhysics(false), _snapToGround(true), _vsync(true), _mode(MODE_LOOK), _sphere(NULL), _box(NULL), _directionalLight(NULL) { } TerrainSample::~TerrainSample() { SAFE_RELEASE(_box); SAFE_RELEASE(_sphere); SAFE_RELEASE(_form); SAFE_RELEASE(_font); SAFE_RELEASE(_scene); } void TerrainSample::initialize() { // Load scene _scene = Scene::load("res/common/terrain/sample.scene"); _terrain = _scene->findNode("terrain")->getTerrain(); _sky = _scene->findNode("sky"); _sky->setTag("lighting", "none"); // Load shapes Bundle* bundle; bundle = Bundle::create("res/common/sphere.gpb"); _sphere = bundle->loadNode("sphere"); _sphere->getModel()->setMaterial("res/common/terrain/shapes.material#sphere", 0); SAFE_RELEASE(bundle); bundle = Bundle::create("res/common/box.gpb"); _box = bundle->loadNode("box"); _box->getModel()->setMaterial("res/common/terrain/shapes.material#box", 0); SAFE_RELEASE(bundle); // Load font _font = Font::create("res/ui/arial.gpb"); // Setup form _form = Form::create("res/common/terrain/terrain.form"); _form->getControl("plusButton")->addListener(this, Control::Listener::CLICK); _form->getControl("minusButton")->addListener(this, Control::Listener::CLICK); _form->getControl("wireframe")->addListener(this, Control::Listener::VALUE_CHANGED); _form->getControl("patches")->addListener(this, Control::Listener::VALUE_CHANGED); _form->getControl("physics")->addListener(this, Control::Listener::VALUE_CHANGED); _form->getControl("lod")->addListener(this, Control::Listener::VALUE_CHANGED); _form->getControl("culling")->addListener(this, Control::Listener::VALUE_CHANGED); _form->getControl("snapToGround")->addListener(this, Control::Listener::VALUE_CHANGED); _form->getControl("dropSphere")->addListener(this, Control::Listener::CLICK); _form->getControl("dropBox")->addListener(this, Control::Listener::CLICK); _form->getControl("clearAll")->addListener(this, Control::Listener::CLICK); Control* main = _form->getControl("main"); _formSize.set(main->getWidth(), main->getHeight()); // Use script camera for navigation enableScriptCamera(true); setScriptCameraSpeed(20, 80); _directionalLight = _scene->findNode("directionalLight")->getLight(); } void TerrainSample::finalize() { SAFE_RELEASE(_font); SAFE_RELEASE(_scene); SAFE_RELEASE(_form); SAFE_RELEASE(_sphere); SAFE_RELEASE(_box); } void TerrainSample::update(float elapsedTime) { Node* camera = _scene->getActiveCamera()->getNode(); if (_snapToGround) { // Get current camera location in world coords Vector3 pos = camera->getTranslationWorld(); // Query the height of our terrain at this location float height = _terrain->getHeight(pos.x, pos.z); // Snap our camera to the ground camera->setTranslationY(height + 10); } // Keep the sky centered around the viewer _sky->setTranslationX(camera->getTranslationX()); _sky->setTranslationZ(camera->getTranslationZ()); // Prune dropped physics shapes that fall off the terrain for (std::list::iterator itr = _shapes.begin(); itr != _shapes.end(); ) { Node* shape = *itr; if (shape->getTranslation().y < 0) { _scene->removeNode(shape); std::list::iterator oldItr = itr; ++itr; _shapes.erase(oldItr); } else { ++itr; } } } void TerrainSample::render(float elapsedTime) { clear(Game::CLEAR_COLOR_DEPTH, 0, 0, 0, 1, 1, 0); // Draw scene _scene->visit(this, &TerrainSample::drawScene); // Debug draw if (_debugPhysics) Game::getInstance()->getPhysicsController()->drawDebug(_scene->getActiveCamera()->getViewProjectionMatrix()); // Draw form _form->draw(); // Draw text char buffer[1024]; sprintf(buffer, "FPS: %d", getFrameRate()); _font->start(); _font->drawText(buffer, 65, 18, Vector4::one(), 30); _font->finish(); } bool TerrainSample::drawScene(Node* node) { Camera* camera = _scene->getActiveCamera(); if (node->getModel()) { if (node->getBoundingSphere().intersects(camera->getFrustum())) { node->getModel()->draw(); } } else if (node->getTerrain()) { Terrain* terrain = node->getTerrain(); terrain->draw(_wireframe); } return true; } void TerrainSample::keyEvent(Keyboard::KeyEvent evt, int key) { // Process keyboard shortcuts for options if (evt == Keyboard::KEY_PRESS) { switch (key) { case Keyboard::KEY_ONE: { CheckBox* cb = static_cast(_form->getControl("wireframe")); cb->setChecked(!cb->isChecked()); } break; case Keyboard::KEY_TWO: { CheckBox* cb = static_cast(_form->getControl("patches")); cb->setChecked(!cb->isChecked()); } break; case Keyboard::KEY_THREE: { CheckBox* cb = static_cast(_form->getControl("physics")); cb->setChecked(!cb->isChecked()); } break; case Keyboard::KEY_FOUR: { CheckBox* cb = static_cast(_form->getControl("lod")); cb->setChecked(!cb->isChecked()); } break; case Keyboard::KEY_FIVE: { CheckBox* cb = static_cast(_form->getControl("culling")); cb->setChecked(!cb->isChecked()); } break; case Keyboard::KEY_SIX: { CheckBox* cb = static_cast(_form->getControl("snapToGround")); cb->setChecked(!cb->isChecked()); } break; } } } void TerrainSample::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex) { if (evt == Touch::TOUCH_PRESS) { // If the FPS region is touched, toggle vsync (if platform supports it) if (x >= 65 && x < 300 && y >= 18 && y <= 48) { _vsync = !_vsync; setVsync(_vsync); } else if (_mode != MODE_LOOK) { // Ray sample Ray pickRay; _scene->getActiveCamera()->pickRay(Rectangle (0, 0, getWidth(), getHeight()), x, y, &pickRay); PhysicsController::HitResult hitResult; TerrainHitFilter hitFilter(_terrain); if (Game::getInstance()->getPhysicsController()->rayTest(pickRay, 1000000, &hitResult, &hitFilter) && hitResult.object == _terrain->getNode()->getCollisionObject()) { Node* clone = NULL; PhysicsCollisionShape::Definition rbShape; switch (_mode) { case MODE_DROP_SPHERE: { clone = _sphere->clone(); rbShape = PhysicsCollisionShape::sphere(); } break; case MODE_DROP_BOX: { clone = _box->clone(); rbShape = PhysicsCollisionShape::box(); } break; } if (clone) { clone->setScale(10,10,10); clone->setTranslation(hitResult.point.x, hitResult.point.y + 50, hitResult.point.z); PhysicsRigidBody::Parameters rbParams(1); clone->setCollisionObject(PhysicsCollisionObject::RIGID_BODY, rbShape, &rbParams); _scene->addNode(clone); clone->release(); _shapes.push_back(clone); _mode = MODE_LOOK; setMessage(NULL); } } } } } bool TerrainSample::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta) { return false; } void TerrainSample::controlEvent(Control* control, EventType evt) { if (strcmp(control->getId(), "plusButton") == 0) { control->setVisible(false); _form->getControl("minusButton")->setVisible(true); _form->getControl("settings")->setVisible(true); _form->getControl("physicsSettings")->setVisible(true); _form->getControl("main")->setSize(_formSize.x, _formSize.y); _formVisible = true; } else if (strcmp(control->getId(), "minusButton") == 0) { control->setVisible(false); _form->getControl("plusButton")->setVisible(true); _form->getControl("settings")->setVisible(false); _form->getControl("physicsSettings")->setVisible(false); _form->getControl("main")->setSize(50, 50); _formVisible = false; } else if (strcmp(control->getId(), "wireframe") == 0) { _wireframe = static_cast(control)->isChecked(); } else if (strcmp(control->getId(), "patches") == 0) { _terrain->setFlag(Terrain::DEBUG_PATCHES, static_cast(control)->isChecked()); } else if (strcmp(control->getId(), "physics") == 0) { _debugPhysics = static_cast(control)->isChecked(); } else if (strcmp(control->getId(), "lod") == 0) { _terrain->setFlag(Terrain::LEVEL_OF_DETAIL, static_cast(control)->isChecked()); } else if (strcmp(control->getId(), "snapToGround") == 0) { _snapToGround = static_cast(control)->isChecked(); if (_snapToGround) setScriptCameraSpeed(20, 80); else setScriptCameraSpeed(200, 800); } else if (strcmp(control->getId(), "dropSphere") == 0) { if (_mode == MODE_DROP_SPHERE) { _mode = MODE_LOOK; setMessage(NULL); } else { _mode = MODE_DROP_SPHERE; setMessage("Click on the terrain to drop a sphere."); } } else if (strcmp(control->getId(), "dropBox") == 0) { if (_mode == MODE_DROP_BOX) { _mode = MODE_LOOK; setMessage(NULL); } else { _mode = MODE_DROP_BOX; setMessage("Click on the terrain to drop a box."); } } else if (strcmp(control->getId(), "clearAll") == 0) { for (std::list::iterator itr = _shapes.begin(); itr != _shapes.end(); ++itr) _scene->removeNode(*itr); _shapes.clear(); } } void TerrainSample::setMessage(const char* message) { Label* label = static_cast(_form->getControl("message")); label->setText(message ? message : ""); _form->getControl("messageBox")->setVisible(message ? true : false); } Vector3 TerrainSample::getLightDirection0() const { return _directionalLight->getNode()->getForwardVectorView(); } Vector3 TerrainSample::getLightColor0() const { return _directionalLight->getColor(); } bool TerrainSample::resolveAutoBinding(const char* autoBinding, Node* node, MaterialParameter* parameter) { if (strcmp(autoBinding, "LIGHT_DIRECTION_0") == 0) { parameter->bindValue(this, &TerrainSample::getLightDirection0); return true; } else if (strcmp(autoBinding, "LIGHT_COLOR_0") == 0) { parameter->bindValue(this, &TerrainSample::getLightColor0); return true; } return false; }