/* * (c) Copyright 1993, Silicon Graphics, Inc. * Copyright © 2012 Linaro Limited * * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. * * glmark2 is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * glmark2. If not, see . * * Authors: * Jesse Barker */ #include "scene.h" #include "stack.h" #include "splines.h" #include "table.h" #include "logo.h" #include "lamp.h" #include "util.h" #include "log.h" #include using LibMatrix::Stack4; using LibMatrix::mat4; using LibMatrix::vec3; using LibMatrix::vec4; using LibMatrix::uvec3; using std::string; using std::map; class SceneIdeasPrivate { public: SceneIdeasPrivate() : valid_(false), currentSpeed_(1.0), // Real time. currentTime_(START_TIME_), timeOffset_(START_TIME_) { startTime_.tv_sec = 0; startTime_.tv_usec = 0; } ~SceneIdeasPrivate() { } void initialize(map& options); void reset_time(); void update_time(); void update_projection(const mat4& proj); void draw(); bool valid() { return valid_; } private: void postIdle(); void initLights(); bool valid_; Stack4 projection_; Stack4 modelview_; float currentSpeed_; float currentTime_; float timeOffset_; struct timeval startTime_; static const float CYCLE_TIME_; static const float TIME_; static const float START_TIME_; // Table Table table_; // Logo SGILogo logo_; // Lamp Lamp lamp_; // Light constants static const vec4 light0_position_; static const vec4 light1_position_; static const vec4 light2_position_; // Object constants ViewFromSpline viewFromSpline_; ViewToSpline viewToSpline_; LightPositionSpline lightPosSpline_; LogoPositionSpline logoPosSpline_; LogoRotationSpline logoRotSpline_; vec3 viewFrom_; vec3 viewTo_; vec3 lightPos_; vec3 logoPos_; vec3 logoRot_; vec4 lightPositions_[3]; }; const float SceneIdeasPrivate::TIME_(15.0); const float SceneIdeasPrivate::CYCLE_TIME_(TIME_ * 1.0 - 3.0); const float SceneIdeasPrivate::START_TIME_(0.6); const vec4 SceneIdeasPrivate::light0_position_(0.0, 1.0, 0.0, 0.0); const vec4 SceneIdeasPrivate::light1_position_(-1.0, 0.0, 0.0, 0.0); const vec4 SceneIdeasPrivate::light2_position_(0.0, -1.0, 0.0, 0.0); void SceneIdeasPrivate::initLights() { const mat4& curMV(modelview_.getCurrent()); lightPositions_[0] = curMV * light0_position_; lightPositions_[1] = curMV * light1_position_; lightPositions_[2] = curMV * light2_position_; } void SceneIdeasPrivate::initialize(map& options) { // Initialize the positions for the lights we'll use. initLights(); // Tell the objects in the scene to initialize themselves. table_.init(); if (!table_.valid()) { Log::debug("SceneIdeas: table object not properly initialized!\n"); return; } logo_.init(); if (!logo_.valid()) { Log::debug("SceneIdeas: logo object not properly initialized!\n"); return; } lamp_.init(); if (!lamp_.valid()) { Log::debug("SceneIdeas: lamp object not properly initialized!\n"); return; } reset_time(); // If the option string tells us the user wants the speed to be a function // of the scene duration, do it. Otherwise, take the value explicitly. static const string durationLabel("duration"); static const string speedLabel("speed"); if (options[speedLabel].value == durationLabel) { float duration = Util::fromString(options[durationLabel].value); currentSpeed_ = (CYCLE_TIME_ - START_TIME_) / duration; } else { currentSpeed_ = Util::fromString(options[speedLabel].value); } // If we're here, we're okay to run. valid_ = true; } void SceneIdeasPrivate::reset_time() { timeOffset_ = START_TIME_; gettimeofday(&startTime_, NULL); } void SceneIdeasPrivate::update_time() { // Compute new time struct timeval current = {0, 0}; gettimeofday(¤t, NULL); float timediff = (current.tv_sec - startTime_.tv_sec) + static_cast(current.tv_usec - startTime_.tv_usec) / 1000000.0; float sceneTime = timediff * currentSpeed_ + timeOffset_; // Keep the current time in [START_TIME_..CYCLE_TIME_) // Every other cycle starting with 0 start at the beginning and goes // forward in time. Other cycles start at the end and go backwards. currentTime_ = std::fmod(sceneTime, CYCLE_TIME_); unsigned int cycle = sceneTime/CYCLE_TIME_; if (cycle % 2) { currentTime_ = CYCLE_TIME_ - currentTime_; } } void SceneIdeasPrivate::update_projection(const mat4& proj) { // Projection hasn't changed since last frame. if (projection_.getCurrent() == proj) { return; } projection_.loadIdentity(); projection_ *= proj; } SceneIdeas::SceneIdeas(Canvas& canvas) : Scene(canvas, "ideas"), priv_(0) { options_["speed"] = Scene::Option("speed", "duration", "Time coefficient (1.0 is \"wall clock\" speed, <1.0 is slower, >1.0 is faster). A special value of \"duration\" computes this as a function of the \"duration\" option"); } SceneIdeas::~SceneIdeas() { delete priv_; } bool SceneIdeas::load() { running_ = false; return true; } void SceneIdeas::unload() { } bool SceneIdeas::setup() { if (!Scene::setup()) return false; priv_ = new SceneIdeasPrivate(); priv_->initialize(options_); if (!priv_->valid()) return false; priv_->update_projection(canvas_.projection()); // Core Scene state currentFrame_ = 0; running_ = true; startTime_ = Util::get_timestamp_us() / 1000000.0; lastUpdateTime_ = startTime_; return true; } void SceneIdeas::update() { Scene::update(); priv_->update_time(); priv_->update_projection(canvas_.projection()); } void SceneIdeasPrivate::draw() { viewFromSpline_.getCurrentVec(currentTime_, viewFrom_); viewToSpline_.getCurrentVec(currentTime_, viewTo_); lightPosSpline_.getCurrentVec(currentTime_, lightPos_); logoPosSpline_.getCurrentVec(currentTime_, logoPos_); logoRotSpline_.getCurrentVec(currentTime_, logoRot_); // Tell the logo its new position logo_.setPosition(logoPos_); vec4 lp4(lightPos_.x(), lightPos_.y(), lightPos_.z(), 0.0); // // SHADOW // modelview_.loadIdentity(); modelview_.lookAt(viewFrom_.x(), viewFrom_.y(), viewFrom_.z(), viewTo_.x(), viewTo_.y(), viewTo_.z(), 0.0, 1.0, 0.0); float pca(0.0); if (viewFrom_.y() > 0.0) { table_.draw(modelview_, projection_, lightPos_, logoPos_, currentTime_, pca); } glEnable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); if (logoPos_.y() < 0.0) { // Set the color assuming we're still under the table. uvec3 flatColor(128 / 2, 102 / 2, 179 / 2); if (logoPos_.y() > -0.33) { // We're emerging from the table float c(1.0 - logoPos_.y() / -0.33); pca /= 4.0; flatColor.x(static_cast(128.0 * (1.0 - c) * 0.5 + 255.0 * pca * c)); flatColor.y(static_cast(102.0 * (1.0 - c) * 0.5 + 255.0 * pca * c)); flatColor.z(static_cast(179.0 * (1.0 - c) * 0.5 + 200.0 * pca * c)); } modelview_.push(); modelview_.scale(0.04, 0.0, 0.04); modelview_.rotate(-90.0, 1.0, 0.0, 0.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.z()), 0.0, 0.0, 1.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.y()), 0.0, 1.0, 0.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.x()), 1.0, 0.0, 0.0); modelview_.rotate(0.1 * 353, 1.0, 0.0, 0.0); modelview_.rotate(0.1 * 450, 0.0, 1.0, 0.0); logo_.draw(modelview_, projection_, lightPositions_[0], SGILogo::LOGO_FLAT, flatColor); modelview_.pop(); } if (logoPos_.y() > 0.0) { modelview_.push(); modelview_.translate(lightPos_.x(), lightPos_.y(), lightPos_.z()); mat4 tv; tv[3][1] = -1.0; tv[3][3] = 0.0; tv[0][0] = tv[1][1] = tv[2][2] = lightPos_.y(); modelview_ *= tv; modelview_.translate(-lightPos_.x() + logoPos_.x(), -lightPos_.y() + logoPos_.y(), -lightPos_.z() + logoPos_.z()); modelview_.scale(0.04, 0.04, 0.04); modelview_.rotate(-90.0, 1.0, 0.0, 0.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.z()), 0.0, 0.0, 1.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.y()), 0.0, 1.0, 0.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.x()), 1.0, 0.0, 0.0); modelview_.rotate(35.3, 1.0, 0.0, 0.0); modelview_.rotate(45.0, 0.0, 1.0, 0.0); logo_.draw(modelview_, projection_, lightPositions_[0], SGILogo::LOGO_SHADOW); modelview_.pop(); } // // DONE SHADOW // glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); modelview_.loadIdentity(); modelview_.lookAt(viewFrom_.x(), viewFrom_.y(), viewFrom_.z(), viewTo_.x(), viewTo_.y(), viewTo_.z(), 0.0, 1.0, 0.0); modelview_.push(); modelview_.translate(lightPos_.x(), lightPos_.y(), lightPos_.z()); modelview_.scale(0.1, 0.1, 0.1); float x(lightPos_.x() - logoPos_.x()); float y(lightPos_.y() - logoPos_.y()); float z(lightPos_.z() - logoPos_.z()); double a3(0.0); if (x != 0.0) { a3 = -atan2(z, x) * 10.0 * 180.0 / M_PI; } double a4(-atan2(sqrt(x * x + z * z), y) * 10.0 * 180.0 / M_PI); modelview_.rotate(0.1 * static_cast(a3), 0.0, 1.0, 0.0); modelview_.rotate(0.1 * static_cast(a4), 0.0, 0.0, 1.0); modelview_.rotate(-90.0, 1.0, 0.0, 0.0); lamp_.draw(modelview_, projection_, lightPositions_); modelview_.pop(); lightPositions_[0] = modelview_.getCurrent() * lp4; if (logoPos_.y() > -0.33) { modelview_.push(); modelview_.translate(logoPos_.x(), logoPos_.y(), logoPos_.z()); modelview_.scale(0.04, 0.04, 0.04); modelview_.rotate(-90.0, 1.0, 0.0, 0.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.z()), 0.0, 0.0, 1.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.y()), 0.0, 1.0, 0.0); modelview_.rotate(0.1 * static_cast(10.0 * logoRot_.x()), 1.0, 0.0, 0.0); modelview_.rotate(35.3, 1.0, 0.0, 0.0); modelview_.rotate(45.0, 0.0, 1.0, 0.0); logo_.draw(modelview_, projection_, lightPositions_[0], SGILogo::LOGO_NORMAL); modelview_.pop(); } if (viewFrom_.y() < 0.0) { table_.drawUnder(modelview_, projection_); } } void SceneIdeas::draw() { priv_->draw(); } Scene::ValidationResult SceneIdeas::validate() { return Scene::ValidationUnknown; } void SceneIdeas::teardown() { delete priv_; priv_ = 0; Scene::teardown(); }