SceneJellyfish: Clean up the arrangement of the files to more closely match the
naming scheme for the other scenes (rename the header "scene-jellyfish.h", and
move the private implementation into the public scene source).
diff --git a/src/jellyfish-private.cpp b/src/jellyfish-private.cpp
deleted file mode 100644
index 3d8e999..0000000
--- a/src/jellyfish-private.cpp
+++ /dev/null
@@ -1,517 +0,0 @@
-//
-// 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 <http://www.gnu.org/licenses/>.
-//
-// Authors:
-// Aleksandar Rodic - Creator and WebGL implementation
-// Jesse Barker - glmark2 port
-//
-#include <string>
-#include <fstream>
-#include <iomanip>
-#include "log.h"
-#include "util.h"
-#include "scene.h"
-#include "texture.h"
-#include "shader-source.h"
-#include "jellyfish-private.h"
-
-using LibMatrix::mat4;
-using LibMatrix::vec3;
-using LibMatrix::vec2;
-using std::string;
-using std::vector;
-
-void
-GradientRenderer::init()
-{
- // Program set up
- static const string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/gradient.vert");
- static const string frg_shader_filename(GLMARK_DATA_PATH"/shaders/gradient.frag");
- ShaderSource vtx_source(vtx_shader_filename);
- ShaderSource frg_source(frg_shader_filename);
- if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
- frg_source.str()))
- {
- return;
- }
- positionLocation_ = program_["position"].location();
- uvLocation_ = program_["uvIn"].location();
-
- // Set up the position data for our "quad".
- vertices_.push_back(vec2(-1.0, -1.0));
- vertices_.push_back(vec2(1.0, -1.0));
- vertices_.push_back(vec2(-1.0, 1.0));
- vertices_.push_back(vec2(1.0, 1.0));
- uvs_.push_back(vec2(1.0, 1.0));
- uvs_.push_back(vec2(1.0, 1.0));
- uvs_.push_back(vec2(0.0, 0.0));
- uvs_.push_back(vec2(0.0, 0.0));
- uvOffset_ = vertices_.size() * sizeof(vec2);
-
- // Set up the VBO and stash our position data in it.
- glGenBuffers(1, &bufferObject_);
- glBindBuffer(GL_ARRAY_BUFFER, bufferObject_);
- glBufferData(GL_ARRAY_BUFFER, (vertices_.size() + uvs_.size()) * sizeof(vec2),
- 0, GL_STATIC_DRAW);
- glBufferSubData(GL_ARRAY_BUFFER, 0, vertices_.size() * sizeof(vec2),
- &vertices_.front());
- glBufferSubData(GL_ARRAY_BUFFER, uvOffset_, uvs_.size() * sizeof(vec2),
- &uvs_.front());
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-}
-
-void
-GradientRenderer::cleanup()
-{
- program_.stop();
- program_.release();
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDeleteBuffers(1, &bufferObject_);
-}
-
-void
-GradientRenderer::draw()
-{
- static const vec3 lightBlue(0.360784314, 0.584313725, 1.0);
- static const vec3 darkBlue(0.074509804, 0.156862745, 0.619607843);
- glBindBuffer(GL_ARRAY_BUFFER, bufferObject_);
- program_.start();
- program_["color1"] = lightBlue;
- program_["color2"] = darkBlue;
- glEnableVertexAttribArray(positionLocation_);
- glEnableVertexAttribArray(uvLocation_);
- glVertexAttribPointer(positionLocation_, 2, GL_FLOAT, GL_FALSE, 0, 0);
- glVertexAttribPointer(uvLocation_, 2, GL_FLOAT, GL_FALSE, 0,
- reinterpret_cast<GLvoid*>(uvOffset_));
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- glDisableVertexAttribArray(positionLocation_);
- glDisableVertexAttribArray(uvLocation_);
- program_.stop();
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-}
-
-//!
-// Parse index values from an OBJ file.
-//
-// @param source the source line to parse
-// @param idx the unsigned short to populate
-//
-static void
-obj_get_index(const string& source, unsigned short& idx)
-{
- // Skip the definition type...
- string::size_type endPos = source.find(" ");
- string::size_type startPos(0);
- if (endPos == string::npos)
- {
- Log::error("Bad element '%s'\n", source.c_str());
- return;
- }
- // Find the first value...
- startPos = endPos + 1;
- string is(source, startPos);
- idx = Util::fromString<unsigned short>(is);
-}
-
-//!
-// Parse vec3 values from an OBJ file.
-//
-// @param source the source line to parse
-// @param v the vec3 to populate
-//
-static void
-obj_get_values(const string& source, vec3& v)
-{
- // Skip the definition type...
- string::size_type endPos = source.find(" ");
- string::size_type startPos(0);
- if (endPos == string::npos)
- {
- Log::error("Bad element '%s'\n", source.c_str());
- return;
- }
- // Find the first value...
- startPos = endPos + 1;
- endPos = source.find(" ", startPos);
- if (endPos == string::npos)
- {
- Log::error("Bad element '%s'\n", source.c_str());
- return;
- }
- string::size_type numChars(endPos - startPos);
- string xs(source, startPos, numChars);
- float x = Util::fromString<float>(xs);
- // Then the second value...
- startPos = endPos + 1;
- endPos = source.find(" ", startPos);
- if (endPos == string::npos)
- {
- Log::error("Bad element '%s'\n", source.c_str());
- return;
- }
- numChars = endPos - startPos;
- string ys(source, startPos, numChars);
- float y = Util::fromString<float>(ys);
- // And the third value (there might be a fourth, but we don't care)...
- startPos = endPos + 1;
- endPos = source.find(" ", startPos);
- if (endPos == string::npos)
- {
- numChars = endPos;
- }
- else
- {
- numChars = endPos - startPos;
- }
- string zs(source, startPos, endPos - startPos);
- float z = Util::fromString<float>(zs);
- v.x(x);
- v.y(y);
- v.z(z);
-}
-
-// Custom OBJ loader.
-//
-// To support the jellyfish model, some amendments to the OBJ format are
-// necessary. In particular, a vertex color attribute is required, and
-// it contains an index list rather than a face list.
-bool
-JellyfishPrivate::load_obj(const std::string &filename)
-{
- std::ifstream inputFile(filename.c_str());
- if (!inputFile)
- {
- Log::error("Failed to open '%s'\n", filename.c_str());
- return false;
- }
-
- vector<string> sourceVec;
- string curLine;
- while (getline(inputFile, curLine))
- {
- sourceVec.push_back(curLine);
- }
-
- static const string vertex_definition("v");
- static const string normal_definition("vn");
- static const string texcoord_definition("vt");
- static const string color_definition("vc");
- static const string index_definition("i");
- for (vector<string>::const_iterator lineIt = sourceVec.begin();
- lineIt != sourceVec.end();
- lineIt++)
- {
- const string& curSrc = *lineIt;
- // Is it a vertex attribute, a face description, comment or other?
- // We only care about the first two, we ignore comments, object names,
- // group names, smoothing groups, etc.
- string::size_type startPos(0);
- string::size_type spacePos = curSrc.find(" ", startPos);
- string definitionType(curSrc, startPos, spacePos - startPos);
- if (definitionType == vertex_definition)
- {
- vec3 v;
- obj_get_values(curSrc, v);
- positions_.push_back(v);
- }
- else if (definitionType == normal_definition)
- {
- vec3 v;
- obj_get_values(curSrc, v);
- normals_.push_back(v);
- }
- else if (definitionType == color_definition)
- {
- vec3 v;
- obj_get_values(curSrc, v);
- colors_.push_back(v);
- }
- else if (definitionType == texcoord_definition)
- {
- vec3 v;
- obj_get_values(curSrc, v);
- texcoords_.push_back(v);
- }
- else if (definitionType == index_definition)
- {
- unsigned short idx(0);
- obj_get_index(curSrc, idx);
- indices_.push_back(idx);
- }
- }
-
- Log::debug("Object populated with %u vertices %u normals %u colors %u texcoords and %u indices.\n",
- positions_.size(), normals_.size(), colors_.size(), texcoords_.size(), indices_.size());
- return true;
-}
-
-JellyfishPrivate::JellyfishPrivate() :
- positionLocation_(0),
- normalLocation_(0),
- colorLocation_(0),
- texcoordLocation_(0),
- viewport_(512.0, 512.0),
- lightPosition_(10.0, 40.0, -60.0),
- lightColor_(0.8, 1.3, 1.1, 1.0),
- lightRadius_(200.0),
- ambientColor_(0.3, 0.2, 1.0, 1.0),
- fresnelColor_(0.8, 0.7, 0.6, 1.1),
- fresnelPower_(1.0),
- rotation_(0.0),
- currentTime_(0.0),
- lastUpdateTime_(0.0)
-{
- static const string modelFilename(GLMARK_DATA_PATH"/models/jellyfish.jobj");
- if (!load_obj(modelFilename))
- {
- return;
- }
-
- // Now that we've setup the vertex data, we can setup the map of how
- // that data will be laid out in the buffer object.
- static const unsigned int sv3(sizeof(vec3));
- dataMap_.positionOffset = 0;
- dataMap_.positionSize = positions_.size() * sv3;
- dataMap_.totalSize = dataMap_.positionSize;
- dataMap_.normalOffset = dataMap_.positionOffset + dataMap_.positionSize;
- dataMap_.normalSize = normals_.size() * sv3;
- dataMap_.totalSize += dataMap_.normalSize;
- dataMap_.colorOffset = dataMap_.normalOffset + dataMap_.normalSize;
- dataMap_.colorSize = colors_.size() * sv3;
- dataMap_.totalSize += dataMap_.colorSize;
- dataMap_.texcoordOffset = dataMap_.colorOffset + dataMap_.colorSize;
- dataMap_.texcoordSize = texcoords_.size() * sv3;
- dataMap_.totalSize += dataMap_.texcoordSize;
-}
-
-JellyfishPrivate::~JellyfishPrivate()
-{
- positions_.clear();
- normals_.clear();
- colors_.clear();
- texcoords_.clear();
- indices_.clear();
-}
-
-void
-JellyfishPrivate::initialize(double time)
-{
- lastUpdateTime_ = time;
- currentTime_ = static_cast<uint64_t>(lastUpdateTime_) % 100000000 / 1000.0;
- whichCaustic_ = static_cast<uint64_t>(currentTime_ * 30) % 32 + 1;
- rotation_ = 0.0;
-
- gradient_.init();
-
- // Set up program first so we can store attribute and uniform locations
- // away for the
- using std::string;
- static const string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/jellyfish.vert");
- static const string frg_shader_filename(GLMARK_DATA_PATH"/shaders/jellyfish.frag");
-
- ShaderSource vtx_source(vtx_shader_filename);
- ShaderSource frg_source(frg_shader_filename);
-
- if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
- frg_source.str()))
- {
- return;
- }
-
- // Stash away attribute and uniform locations for handy use.
- positionLocation_ = program_["aVertexPosition"].location();
- normalLocation_ = program_["aVertexNormal"].location();
- colorLocation_ = program_["aVertexColor"].location();
- texcoordLocation_ = program_["aTextureCoord"].location();
-
- // We need 2 buffers for our work here. One for the vertex data.
- // and one for the index data.
- glGenBuffers(2, &bufferObjects_[0]);
-
- // First, setup the vertex data by binding the first buffer object,
- // allocating its data store, and filling it in with our vertex data.
- glBindBuffer(GL_ARRAY_BUFFER, bufferObjects_[0]);
- glBufferData(GL_ARRAY_BUFFER, dataMap_.totalSize, 0, GL_STATIC_DRAW);
- glBufferSubData(GL_ARRAY_BUFFER, dataMap_.positionOffset,
- dataMap_.positionSize, &positions_.front());
- glBufferSubData(GL_ARRAY_BUFFER, dataMap_.normalOffset,
- dataMap_.normalSize, &normals_.front());
- glBufferSubData(GL_ARRAY_BUFFER, dataMap_.colorOffset,
- dataMap_.colorSize, &colors_.front());
- glBufferSubData(GL_ARRAY_BUFFER, dataMap_.texcoordOffset,
- dataMap_.texcoordSize, &texcoords_.front());
-
- // Now repeat for our index data.
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects_[1]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(unsigned short),
- &indices_.front(), GL_STATIC_DRAW);
-
- // "Unbind" our buffer objects to make sure the state is consistent.
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
- // Finally, set up our textures.
- //
- // First, the main jellyfish texture
- bool gotTex = Texture::load("jellyfish256", &textureObjects_[0], GL_LINEAR,
- GL_LINEAR, 0);
- if (!gotTex || textureObjects_[0] == 0)
- {
- Log::error("Jellyfish texture set up failed!!!\n");
- }
- glBindTexture(GL_TEXTURE_2D, 0);
- // Then, the caustics textures
- static const string baseName("jellyfish-caustics-");
- for (unsigned int i = 1; i < 33; i++)
- {
- std::stringstream ss;
- ss << std::setw(2) << std::setfill('0') << i;
- string curName(baseName);
- curName += ss.str();
- gotTex = Texture::load(curName, &textureObjects_[i], GL_LINEAR,
- GL_LINEAR, 0);
- if (!gotTex || textureObjects_[i] == 0)
- {
- Log::error("Caustics texture[%u] set up failed!!!\n", i);
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glBindTexture(GL_TEXTURE_2D, 0);
- }
-}
-
-void
-JellyfishPrivate::update_viewport(const vec2& vp)
-{
- if (viewport_.x() == vp.x() && viewport_.y() == vp.y())
- {
- return;
- }
- viewport_ = vp;
- projection_.loadIdentity();
- projection_.perspective(30.0, viewport_.x()/viewport_.y(), 20.0, 120.0);
-}
-
-void
-JellyfishPrivate::update_time()
-{
- double now = Util::get_timestamp_us() / 1000.0;
- double elapsedTime = now - lastUpdateTime_;
- rotation_ += (2.0 * elapsedTime) / 1000.0;
- currentTime_ = static_cast<uint64_t>(now) % 100000000 / 1000.0;
- whichCaustic_ = static_cast<uint64_t>(currentTime_ * 30) % 32 + 1;
- lastUpdateTime_ = now;
-}
-
-void
-JellyfishPrivate::cleanup()
-{
- program_.stop();
- program_.release();
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
- glDeleteTextures(33, &textureObjects_[0]);
- glDeleteBuffers(2, &bufferObjects_[0]);
-
- gradient_.cleanup();
-}
-
-void
-JellyfishPrivate::draw()
-{
- // "Clear" the background to the desired gradient.
- gradient_.draw();
-
- // We need "world", "world view projection", and "world inverse transpose"
- // matrix uniforms for the current shader.
- //
- // NOTE: Some of this seems a bit of a no-op (e.g., multipying by and
- // inverting identity matrices), but leave it like the original
- // WebGL files for the time being. Worth revisiting not doing all
- // of that math every draw call (might even be good to be doing
- // some of it in the shader as well).
- world_.push();
- world_.translate(0.0, 5.0, -75.0);
- world_.rotate(sin(rotation_ / 10.0) * 30.0, 0.0, 1.0, 0.0);
- world_.rotate(sin(rotation_ / 20.0) * 30.0, 1.0, 0.0, 0.0);
- world_.scale(5.0, 5.0, 5.0);
- world_.translate(0.0, sin(rotation_ / 10.0) * 2.5, 0.0);
- mat4 worldViewProjection(projection_.getCurrent());
- worldViewProjection *= world_.getCurrent();;
- mat4 worldInverseTranspose(world_.getCurrent());
- worldInverseTranspose.inverse().transpose();
-
- // Load up the uniforms
- program_.start();
- program_["uWorld"] = world_.getCurrent();
- program_["uWorldViewProj"] = worldViewProjection;
- program_["uWorldInvTranspose"] = worldInverseTranspose;
- program_["uCurrentTime"] = currentTime_;
- // Revisit making these constants rather than uniforms as they appear never
- // to change
- program_["uLightPos"] = lightPosition_;
- program_["uLightRadius"] = lightRadius_;
- program_["uLightCol"] = lightColor_;
- program_["uAmbientCol"] = ambientColor_;
- program_["uFresnelCol"] = fresnelColor_;
- program_["uFresnelPower"] = fresnelPower_;
- // Set up textures for this frame.
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, textureObjects_[0]);
- program_["uSampler"] = 0;
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, textureObjects_[whichCaustic_]);
- program_["uSampler1"] = 1;
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glDisable(GL_CULL_FACE);
- glDisable(GL_DEPTH_TEST);
-
- glBindBuffer(GL_ARRAY_BUFFER, bufferObjects_[0]);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects_[1]);
-
- glEnableVertexAttribArray(positionLocation_);
- glEnableVertexAttribArray(normalLocation_);
- glEnableVertexAttribArray(colorLocation_);
- glEnableVertexAttribArray(texcoordLocation_);
- glVertexAttribPointer(positionLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
- reinterpret_cast<const GLvoid*>(dataMap_.positionOffset));
- glVertexAttribPointer(normalLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
- reinterpret_cast<const GLvoid*>(dataMap_.normalOffset));
- glVertexAttribPointer(colorLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
- reinterpret_cast<const GLvoid*>(dataMap_.colorOffset));
- glVertexAttribPointer(texcoordLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
- reinterpret_cast<const GLvoid*>(dataMap_.texcoordOffset));
-
- glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_SHORT, 0);
-
- glDisableVertexAttribArray(positionLocation_);
- glDisableVertexAttribArray(normalLocation_);
- glDisableVertexAttribArray(colorLocation_);
- glDisableVertexAttribArray(texcoordLocation_);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
- program_.stop();
- world_.pop();
-}
diff --git a/src/scene-jellyfish.cpp b/src/scene-jellyfish.cpp
index f07ddbd..36e29a9 100644
--- a/src/scene-jellyfish.cpp
+++ b/src/scene-jellyfish.cpp
@@ -20,9 +20,15 @@
// Aleksandar Rodic - Creator and WebGL implementation
// Jesse Barker - glmark2 port
//
+#include <string>
+#include <fstream>
+#include <iomanip>
#include "scene.h"
-#include "jellyfish-private.h"
+#include "scene-jellyfish.h"
+#include "log.h"
#include "util.h"
+#include "texture.h"
+#include "shader-source.h"
SceneJellyfish::SceneJellyfish(Canvas& canvas) :
Scene(canvas, "jellyfish")
@@ -88,3 +94,493 @@
{
return Scene::ValidationUnknown;
}
+
+
+//
+// JellyfishPrivate implementation
+//
+using LibMatrix::mat4;
+using LibMatrix::vec3;
+using LibMatrix::vec2;
+using std::string;
+using std::vector;
+
+void
+GradientRenderer::init()
+{
+ // Program set up
+ static const string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/gradient.vert");
+ static const string frg_shader_filename(GLMARK_DATA_PATH"/shaders/gradient.frag");
+ ShaderSource vtx_source(vtx_shader_filename);
+ ShaderSource frg_source(frg_shader_filename);
+ if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
+ frg_source.str()))
+ {
+ return;
+ }
+ positionLocation_ = program_["position"].location();
+ uvLocation_ = program_["uvIn"].location();
+
+ // Set up the position data for our "quad".
+ vertices_.push_back(vec2(-1.0, -1.0));
+ vertices_.push_back(vec2(1.0, -1.0));
+ vertices_.push_back(vec2(-1.0, 1.0));
+ vertices_.push_back(vec2(1.0, 1.0));
+ uvs_.push_back(vec2(1.0, 1.0));
+ uvs_.push_back(vec2(1.0, 1.0));
+ uvs_.push_back(vec2(0.0, 0.0));
+ uvs_.push_back(vec2(0.0, 0.0));
+ uvOffset_ = vertices_.size() * sizeof(vec2);
+
+ // Set up the VBO and stash our position data in it.
+ glGenBuffers(1, &bufferObject_);
+ glBindBuffer(GL_ARRAY_BUFFER, bufferObject_);
+ glBufferData(GL_ARRAY_BUFFER, (vertices_.size() + uvs_.size()) * sizeof(vec2),
+ 0, GL_STATIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, vertices_.size() * sizeof(vec2),
+ &vertices_.front());
+ glBufferSubData(GL_ARRAY_BUFFER, uvOffset_, uvs_.size() * sizeof(vec2),
+ &uvs_.front());
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+void
+GradientRenderer::cleanup()
+{
+ program_.stop();
+ program_.release();
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &bufferObject_);
+}
+
+void
+GradientRenderer::draw()
+{
+ static const vec3 lightBlue(0.360784314, 0.584313725, 1.0);
+ static const vec3 darkBlue(0.074509804, 0.156862745, 0.619607843);
+ glBindBuffer(GL_ARRAY_BUFFER, bufferObject_);
+ program_.start();
+ program_["color1"] = lightBlue;
+ program_["color2"] = darkBlue;
+ glEnableVertexAttribArray(positionLocation_);
+ glEnableVertexAttribArray(uvLocation_);
+ glVertexAttribPointer(positionLocation_, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ glVertexAttribPointer(uvLocation_, 2, GL_FLOAT, GL_FALSE, 0,
+ reinterpret_cast<GLvoid*>(uvOffset_));
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDisableVertexAttribArray(positionLocation_);
+ glDisableVertexAttribArray(uvLocation_);
+ program_.stop();
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+//!
+// Parse index values from an OBJ file.
+//
+// @param source the source line to parse
+// @param idx the unsigned short to populate
+//
+static void
+obj_get_index(const string& source, unsigned short& idx)
+{
+ // Skip the definition type...
+ string::size_type endPos = source.find(" ");
+ string::size_type startPos(0);
+ if (endPos == string::npos)
+ {
+ Log::error("Bad element '%s'\n", source.c_str());
+ return;
+ }
+ // Find the first value...
+ startPos = endPos + 1;
+ string is(source, startPos);
+ idx = Util::fromString<unsigned short>(is);
+}
+
+//!
+// Parse vec3 values from an OBJ file.
+//
+// @param source the source line to parse
+// @param v the vec3 to populate
+//
+static void
+obj_get_values(const string& source, vec3& v)
+{
+ // Skip the definition type...
+ string::size_type endPos = source.find(" ");
+ string::size_type startPos(0);
+ if (endPos == string::npos)
+ {
+ Log::error("Bad element '%s'\n", source.c_str());
+ return;
+ }
+ // Find the first value...
+ startPos = endPos + 1;
+ endPos = source.find(" ", startPos);
+ if (endPos == string::npos)
+ {
+ Log::error("Bad element '%s'\n", source.c_str());
+ return;
+ }
+ string::size_type numChars(endPos - startPos);
+ string xs(source, startPos, numChars);
+ float x = Util::fromString<float>(xs);
+ // Then the second value...
+ startPos = endPos + 1;
+ endPos = source.find(" ", startPos);
+ if (endPos == string::npos)
+ {
+ Log::error("Bad element '%s'\n", source.c_str());
+ return;
+ }
+ numChars = endPos - startPos;
+ string ys(source, startPos, numChars);
+ float y = Util::fromString<float>(ys);
+ // And the third value (there might be a fourth, but we don't care)...
+ startPos = endPos + 1;
+ endPos = source.find(" ", startPos);
+ if (endPos == string::npos)
+ {
+ numChars = endPos;
+ }
+ else
+ {
+ numChars = endPos - startPos;
+ }
+ string zs(source, startPos, endPos - startPos);
+ float z = Util::fromString<float>(zs);
+ v.x(x);
+ v.y(y);
+ v.z(z);
+}
+
+// Custom OBJ loader.
+//
+// To support the jellyfish model, some amendments to the OBJ format are
+// necessary. In particular, a vertex color attribute is required, and
+// it contains an index list rather than a face list.
+bool
+JellyfishPrivate::load_obj(const std::string &filename)
+{
+ std::ifstream inputFile(filename.c_str());
+ if (!inputFile)
+ {
+ Log::error("Failed to open '%s'\n", filename.c_str());
+ return false;
+ }
+
+ vector<string> sourceVec;
+ string curLine;
+ while (getline(inputFile, curLine))
+ {
+ sourceVec.push_back(curLine);
+ }
+
+ static const string vertex_definition("v");
+ static const string normal_definition("vn");
+ static const string texcoord_definition("vt");
+ static const string color_definition("vc");
+ static const string index_definition("i");
+ for (vector<string>::const_iterator lineIt = sourceVec.begin();
+ lineIt != sourceVec.end();
+ lineIt++)
+ {
+ const string& curSrc = *lineIt;
+ // Is it a vertex attribute, a face description, comment or other?
+ // We only care about the first two, we ignore comments, object names,
+ // group names, smoothing groups, etc.
+ string::size_type startPos(0);
+ string::size_type spacePos = curSrc.find(" ", startPos);
+ string definitionType(curSrc, startPos, spacePos - startPos);
+ if (definitionType == vertex_definition)
+ {
+ vec3 v;
+ obj_get_values(curSrc, v);
+ positions_.push_back(v);
+ }
+ else if (definitionType == normal_definition)
+ {
+ vec3 v;
+ obj_get_values(curSrc, v);
+ normals_.push_back(v);
+ }
+ else if (definitionType == color_definition)
+ {
+ vec3 v;
+ obj_get_values(curSrc, v);
+ colors_.push_back(v);
+ }
+ else if (definitionType == texcoord_definition)
+ {
+ vec3 v;
+ obj_get_values(curSrc, v);
+ texcoords_.push_back(v);
+ }
+ else if (definitionType == index_definition)
+ {
+ unsigned short idx(0);
+ obj_get_index(curSrc, idx);
+ indices_.push_back(idx);
+ }
+ }
+
+ Log::debug("Object populated with %u vertices %u normals %u colors %u texcoords and %u indices.\n",
+ positions_.size(), normals_.size(), colors_.size(), texcoords_.size(), indices_.size());
+ return true;
+}
+
+JellyfishPrivate::JellyfishPrivate() :
+ positionLocation_(0),
+ normalLocation_(0),
+ colorLocation_(0),
+ texcoordLocation_(0),
+ viewport_(512.0, 512.0),
+ lightPosition_(10.0, 40.0, -60.0),
+ lightColor_(0.8, 1.3, 1.1, 1.0),
+ lightRadius_(200.0),
+ ambientColor_(0.3, 0.2, 1.0, 1.0),
+ fresnelColor_(0.8, 0.7, 0.6, 1.1),
+ fresnelPower_(1.0),
+ rotation_(0.0),
+ currentTime_(0.0),
+ lastUpdateTime_(0.0)
+{
+ static const string modelFilename(GLMARK_DATA_PATH"/models/jellyfish.jobj");
+ if (!load_obj(modelFilename))
+ {
+ return;
+ }
+
+ // Now that we've setup the vertex data, we can setup the map of how
+ // that data will be laid out in the buffer object.
+ static const unsigned int sv3(sizeof(vec3));
+ dataMap_.positionOffset = 0;
+ dataMap_.positionSize = positions_.size() * sv3;
+ dataMap_.totalSize = dataMap_.positionSize;
+ dataMap_.normalOffset = dataMap_.positionOffset + dataMap_.positionSize;
+ dataMap_.normalSize = normals_.size() * sv3;
+ dataMap_.totalSize += dataMap_.normalSize;
+ dataMap_.colorOffset = dataMap_.normalOffset + dataMap_.normalSize;
+ dataMap_.colorSize = colors_.size() * sv3;
+ dataMap_.totalSize += dataMap_.colorSize;
+ dataMap_.texcoordOffset = dataMap_.colorOffset + dataMap_.colorSize;
+ dataMap_.texcoordSize = texcoords_.size() * sv3;
+ dataMap_.totalSize += dataMap_.texcoordSize;
+}
+
+JellyfishPrivate::~JellyfishPrivate()
+{
+ positions_.clear();
+ normals_.clear();
+ colors_.clear();
+ texcoords_.clear();
+ indices_.clear();
+}
+
+void
+JellyfishPrivate::initialize(double time)
+{
+ lastUpdateTime_ = time;
+ currentTime_ = static_cast<uint64_t>(lastUpdateTime_) % 100000000 / 1000.0;
+ whichCaustic_ = static_cast<uint64_t>(currentTime_ * 30) % 32 + 1;
+ rotation_ = 0.0;
+
+ gradient_.init();
+
+ // Set up program first so we can store attribute and uniform locations
+ // away for the
+ using std::string;
+ static const string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/jellyfish.vert");
+ static const string frg_shader_filename(GLMARK_DATA_PATH"/shaders/jellyfish.frag");
+
+ ShaderSource vtx_source(vtx_shader_filename);
+ ShaderSource frg_source(frg_shader_filename);
+
+ if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
+ frg_source.str()))
+ {
+ return;
+ }
+
+ // Stash away attribute and uniform locations for handy use.
+ positionLocation_ = program_["aVertexPosition"].location();
+ normalLocation_ = program_["aVertexNormal"].location();
+ colorLocation_ = program_["aVertexColor"].location();
+ texcoordLocation_ = program_["aTextureCoord"].location();
+
+ // We need 2 buffers for our work here. One for the vertex data.
+ // and one for the index data.
+ glGenBuffers(2, &bufferObjects_[0]);
+
+ // First, setup the vertex data by binding the first buffer object,
+ // allocating its data store, and filling it in with our vertex data.
+ glBindBuffer(GL_ARRAY_BUFFER, bufferObjects_[0]);
+ glBufferData(GL_ARRAY_BUFFER, dataMap_.totalSize, 0, GL_STATIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, dataMap_.positionOffset,
+ dataMap_.positionSize, &positions_.front());
+ glBufferSubData(GL_ARRAY_BUFFER, dataMap_.normalOffset,
+ dataMap_.normalSize, &normals_.front());
+ glBufferSubData(GL_ARRAY_BUFFER, dataMap_.colorOffset,
+ dataMap_.colorSize, &colors_.front());
+ glBufferSubData(GL_ARRAY_BUFFER, dataMap_.texcoordOffset,
+ dataMap_.texcoordSize, &texcoords_.front());
+
+ // Now repeat for our index data.
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects_[1]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(unsigned short),
+ &indices_.front(), GL_STATIC_DRAW);
+
+ // "Unbind" our buffer objects to make sure the state is consistent.
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ // Finally, set up our textures.
+ //
+ // First, the main jellyfish texture
+ bool gotTex = Texture::load("jellyfish256", &textureObjects_[0], GL_LINEAR,
+ GL_LINEAR, 0);
+ if (!gotTex || textureObjects_[0] == 0)
+ {
+ Log::error("Jellyfish texture set up failed!!!\n");
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ // Then, the caustics textures
+ static const string baseName("jellyfish-caustics-");
+ for (unsigned int i = 1; i < 33; i++)
+ {
+ std::stringstream ss;
+ ss << std::setw(2) << std::setfill('0') << i;
+ string curName(baseName);
+ curName += ss.str();
+ gotTex = Texture::load(curName, &textureObjects_[i], GL_LINEAR,
+ GL_LINEAR, 0);
+ if (!gotTex || textureObjects_[i] == 0)
+ {
+ Log::error("Caustics texture[%u] set up failed!!!\n", i);
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+}
+
+void
+JellyfishPrivate::update_viewport(const vec2& vp)
+{
+ if (viewport_.x() == vp.x() && viewport_.y() == vp.y())
+ {
+ return;
+ }
+ viewport_ = vp;
+ projection_.loadIdentity();
+ projection_.perspective(30.0, viewport_.x()/viewport_.y(), 20.0, 120.0);
+}
+
+void
+JellyfishPrivate::update_time()
+{
+ double now = Util::get_timestamp_us() / 1000.0;
+ double elapsedTime = now - lastUpdateTime_;
+ rotation_ += (2.0 * elapsedTime) / 1000.0;
+ currentTime_ = static_cast<uint64_t>(now) % 100000000 / 1000.0;
+ whichCaustic_ = static_cast<uint64_t>(currentTime_ * 30) % 32 + 1;
+ lastUpdateTime_ = now;
+}
+
+void
+JellyfishPrivate::cleanup()
+{
+ program_.stop();
+ program_.release();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glDeleteTextures(33, &textureObjects_[0]);
+ glDeleteBuffers(2, &bufferObjects_[0]);
+
+ gradient_.cleanup();
+}
+
+void
+JellyfishPrivate::draw()
+{
+ // "Clear" the background to the desired gradient.
+ gradient_.draw();
+
+ // We need "world", "world view projection", and "world inverse transpose"
+ // matrix uniforms for the current shader.
+ //
+ // NOTE: Some of this seems a bit of a no-op (e.g., multipying by and
+ // inverting identity matrices), but leave it like the original
+ // WebGL files for the time being. Worth revisiting not doing all
+ // of that math every draw call (might even be good to be doing
+ // some of it in the shader as well).
+ world_.push();
+ world_.translate(0.0, 5.0, -75.0);
+ world_.rotate(sin(rotation_ / 10.0) * 30.0, 0.0, 1.0, 0.0);
+ world_.rotate(sin(rotation_ / 20.0) * 30.0, 1.0, 0.0, 0.0);
+ world_.scale(5.0, 5.0, 5.0);
+ world_.translate(0.0, sin(rotation_ / 10.0) * 2.5, 0.0);
+ mat4 worldViewProjection(projection_.getCurrent());
+ worldViewProjection *= world_.getCurrent();;
+ mat4 worldInverseTranspose(world_.getCurrent());
+ worldInverseTranspose.inverse().transpose();
+
+ // Load up the uniforms
+ program_.start();
+ program_["uWorld"] = world_.getCurrent();
+ program_["uWorldViewProj"] = worldViewProjection;
+ program_["uWorldInvTranspose"] = worldInverseTranspose;
+ program_["uCurrentTime"] = currentTime_;
+ // Revisit making these constants rather than uniforms as they appear never
+ // to change
+ program_["uLightPos"] = lightPosition_;
+ program_["uLightRadius"] = lightRadius_;
+ program_["uLightCol"] = lightColor_;
+ program_["uAmbientCol"] = ambientColor_;
+ program_["uFresnelCol"] = fresnelColor_;
+ program_["uFresnelPower"] = fresnelPower_;
+ // Set up textures for this frame.
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, textureObjects_[0]);
+ program_["uSampler"] = 0;
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, textureObjects_[whichCaustic_]);
+ program_["uSampler1"] = 1;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+
+ glBindBuffer(GL_ARRAY_BUFFER, bufferObjects_[0]);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects_[1]);
+
+ glEnableVertexAttribArray(positionLocation_);
+ glEnableVertexAttribArray(normalLocation_);
+ glEnableVertexAttribArray(colorLocation_);
+ glEnableVertexAttribArray(texcoordLocation_);
+ glVertexAttribPointer(positionLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
+ reinterpret_cast<const GLvoid*>(dataMap_.positionOffset));
+ glVertexAttribPointer(normalLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
+ reinterpret_cast<const GLvoid*>(dataMap_.normalOffset));
+ glVertexAttribPointer(colorLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
+ reinterpret_cast<const GLvoid*>(dataMap_.colorOffset));
+ glVertexAttribPointer(texcoordLocation_ , 3, GL_FLOAT, GL_FALSE, 0,
+ reinterpret_cast<const GLvoid*>(dataMap_.texcoordOffset));
+
+ glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_SHORT, 0);
+
+ glDisableVertexAttribArray(positionLocation_);
+ glDisableVertexAttribArray(normalLocation_);
+ glDisableVertexAttribArray(colorLocation_);
+ glDisableVertexAttribArray(texcoordLocation_);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ program_.stop();
+ world_.pop();
+}
diff --git a/src/jellyfish-private.h b/src/scene-jellyfish.h
similarity index 97%
rename from src/jellyfish-private.h
rename to src/scene-jellyfish.h
index 211aa89..a0177df 100644
--- a/src/jellyfish-private.h
+++ b/src/scene-jellyfish.h
@@ -20,8 +20,8 @@
// Aleksandar Rodic - Creator and WebGL implementation
// Jesse Barker - glmark2 port
//
-#ifndef JELLYFISH_PRIVATE_
-#define JELLYFISH_PRIVATE_
+#ifndef SCENE_JELLYFISH_
+#define SCENE_JELLYFISH_
#include <vector>
#include "vec.h"
#include "stack.h"
@@ -115,4 +115,4 @@
void draw();
};
-#endif // JELLYFISH_PRIVATE_
+#endif // SCENE_JELLYFISH_