class Scene::SceneImpl : public Mippleton<SceneImpl>
{
- class Scenery : public Entity
+ class Quad : public Entity
{
public:
- Scenery(const Matrix4& transform, const std::string& textureName) :
- transformation(transform),
- image(textureName) {}
-
- protected:
- Matrix4 transformation;
- Tilemap image;
- bool blending;
- long detail;
- bool fog;
- };
-
- class TilePanel : public Scenery
- {
- public:
- TilePanel(const Matrix4& transform, const std::string& textureName,
- SerializablePtr root) :
- Scenery(transform, textureName),
- width(1),
- height(1)
+ Quad(const Vector3 vertices[4], const std::string& texture,
+ Tilemap::Index tileIndex) :
+ tilemap_(texture),
+ detail_(0),
+ blending_(false),
+ fog_(false)
{
- std::map<std::string,SerializablePtr> rootObj;
-
- if (root->get(rootObj))
+ for (int i = 0, num = 0; i < 4; ++i)
{
- std::map<std::string,SerializablePtr>::iterator it;
-
- if ((it = rootObj.find("width")) != rootObj.end())
+ for (int j = 0; j < 3; ++j, ++num)
{
- (*it).second->get(width);
- }
- if ((it = rootObj.find("tiles")) != rootObj.end())
- {
- std::vector<SerializablePtr> theTiles;
-
- if ((*it).second->get(theTiles))
- {
- std::vector<SerializablePtr>::iterator jt;
-
- height = theTiles.size() / width;
- int w, h;
-
- indices.resize(height);
-
- for (h = height - 1, jt = theTiles.begin();
- jt != theTiles.end(); h--)
- {
- std::vector<Tilemap::Index> row;
-
- for (w = 0; w < width && jt != theTiles.end();
- w++, jt++)
- {
- long index;
-
- if ((*jt)->get(index))
- {
- row.push_back(Tilemap::Index(index));
- }
- }
-
- indices[h] = row;
- }
- }
+ vertices_[num] = vertices[i][j];
}
}
- }
-
- void draw(Scalar alpha) const
- {
- glPushMatrix();
- //std::cout << "transforming..." << std::endl;
- //std::cout << transformation << std::endl;
- glMultMatrix(transformation.data());
-
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- image.bind();
-
- long x, y;
- Scalar xf, yf;
- for (y = 0, yf = 0.0; y < height; y++, yf += 1.0)
+ if (!tilemap_.getTileCoords(tileIndex, texCoords_))
{
- for (x = 0, xf = 0.0; x < width; x++, xf += 1.0)
- {
- Scalar texCoords[8];
-
- Tilemap::Index index = indices[y][x];
-
- if (image.getTileCoords(index, texCoords))
- {
- glBegin(GL_TRIANGLE_FAN);
- glTexCoord2f(texCoords[0], texCoords[1]);
- glVertex2f(xf, yf);
- glTexCoord2f(texCoords[2], texCoords[3]);
- glVertex2f(xf+1.0, yf);
- glTexCoord2f(texCoords[4], texCoords[5]);
- glVertex2f(xf+1.0, yf+1.0);
- glTexCoord2f(texCoords[6], texCoords[7]);
- glVertex2f(xf, yf+1.0);
- glEnd();
- }
- }
+ std::cerr << "no coords for tile's texture" << std::endl;
}
-
- glPopMatrix();
}
- bool isVisible(const Camera& cam)
+ void setDetail(long detail)
{
- return true;
+ detail_ = detail;
}
- private:
- long width, height;
- std::vector<std::vector<Tilemap::Index> > indices;
- };
-
- class Billboard : public Scenery
- {
- public:
- Billboard(const Matrix4& transform, const std::string& textureName,
- SerializablePtr root) :
- Scenery(transform, textureName),
- index(0),
- uScale(1)
+ void setBlending(bool blending)
{
- std::map<std::string,SerializablePtr> rootObj;
-
- if (root->get(rootObj))
- {
- std::map<std::string,SerializablePtr>::iterator it;
-
- if ((it = rootObj.find("tile")) != rootObj.end())
- {
- long value;
- if ((*it).second->get(value))
- {
- index = Tilemap::Index(value);
- }
- }
- if ((it = rootObj.find("u_scale")) != rootObj.end())
- {
- (*it).second->get(uScale);
- }
- if ((it = rootObj.find("fog")) != rootObj.end())
- {
- (*it).second->get(fog);
- }
- if ((it = rootObj.find("blend")) != rootObj.end())
- {
- (*it).second->get(blending);
- }
- }
-
- image.getTileCoords(index, texCoords);
+ blending_ = blending;
}
- void draw(Scalar alpha) const
+ void setFog(bool fog)
{
- glPushMatrix();
- glMultMatrix(transformation.data());
+ fog_ = fog;
+ }
- if (blending)
+ void draw(Scalar alpha = 0.0) const
+ {
+ if (blending_)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- /*if (fog) glEnable(GL_FOG);*/
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- image.bind();
+ tilemap_.bind();
- float increment = 1.0f / float(uScale);
- int x;
- float xf;
+ //glEnableClientState(GL_VERTEX_ARRAY);
+ //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ //glVertexPointer(3, GL_SCALAR, 0, vertices_);
+ //glTexCoordPointer(2, GL_SCALAR, 0, texCoords_);
+
+ //glDrawArrays(GL_TRIANGLE_FAN, 0, sizeof(vertices_));
+
+ //glDisableClientState(GL_VERTEX_ARRAY);
+ //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- for (x = 0, xf = 0.0f; x < uScale; x++, xf += increment)
- {
glBegin(GL_TRIANGLE_FAN);
- glTexCoord2f(texCoords[0], texCoords[1]);
- glVertex2f(xf, 0.0f);
- glTexCoord2f(texCoords[2], texCoords[3]);
- glVertex2f(xf+increment, 0.0f);
- glTexCoord2f(texCoords[4], texCoords[5]);
- glVertex2f(xf+increment, 1.0f);
- glTexCoord2f(texCoords[6], texCoords[7]);
- glVertex2f(xf, 1.0f);
+ glTexCoord2f(texCoords_[0], texCoords_[1]);
+ glVertex3v(vertices_);
+ glTexCoord2f(texCoords_[2], texCoords_[3]);
+ glVertex3v(vertices_+3);
+ glTexCoord2f(texCoords_[4], texCoords_[5]);
+ glVertex3v(vertices_+6);
+ glTexCoord2f(texCoords_[6], texCoords_[7]);
+ glVertex3v(vertices_+9);
glEnd();
- }
glDisable(GL_BLEND);
- glDisable(GL_FOG);
-
- glPopMatrix();
}
- bool isVisible(const Camera& cam)
+ bool isVisible(const Camera& cam) const
{
- return false;
+ return aabb_.isVisible(cam);
}
private:
- Tilemap::Index index;
- Scalar texCoords[8];
- long uScale;
+ Scalar vertices_[12];
+ Scalar texCoords_[8];
+
+ Tilemap tilemap_;
+
+ long detail_;
+ bool blending_;
+ bool fog_;
};
- static bool loadBox(Aabb& theBox, SerializablePtr obj)
+ static void loadBox(Aabb& theBox, SerializablePtr obj)
{
std::vector<SerializablePtr> numbers;
- if (obj->get(numbers))
+ if (obj->get(numbers) && numbers.size() == 6)
{
- if (numbers.size() == 6)
- {
- double num;
-
- if (numbers[0]->getNumber(num))
- {
- theBox.min[0] = Scalar(num);
- }
- if (numbers[1]->getNumber(num))
- {
- theBox.min[1] = Scalar(num);
- }
- if (numbers[2]->getNumber(num))
- {
- theBox.min[2] = Scalar(num);
- }
- if (numbers[3]->getNumber(num))
- {
- theBox.max[0] = Scalar(num);
- }
- if (numbers[4]->getNumber(num))
- {
- theBox.max[1] = Scalar(num);
- }
- if (numbers[5]->getNumber(num))
- {
- theBox.max[2] = Scalar(num);
- }
- }
+ double num;
+
+ if (numbers[0]->getNumber(num)) theBox.min[0] = Scalar(num);
+ if (numbers[1]->getNumber(num)) theBox.min[1] = Scalar(num);
+ if (numbers[2]->getNumber(num)) theBox.min[2] = Scalar(num);
+ if (numbers[3]->getNumber(num)) theBox.max[0] = Scalar(num);
+ if (numbers[4]->getNumber(num)) theBox.max[1] = Scalar(num);
+ if (numbers[5]->getNumber(num)) theBox.max[2] = Scalar(num);
}
-
- return false;
}
public:
loadFromFile();
}
- ~SceneImpl()
- {
- }
-
void loadInstructions(SerializablePtr root)
{
std::vector<SerializablePtr> rootObj;
+ std::vector<SerializablePtr>::iterator it;
- if (root->get(rootObj))
+ if (!root->get(rootObj))
{
- std::vector<SerializablePtr>::iterator it;
+ std::cerr << "error loading scene instructions" << std::endl;
+ return;
+ }
- Matrix4 transform;
- std::string texture;
+ Matrix4 transform;
+ std::string texture;
- for (it = rootObj.begin(); it != rootObj.end(); it++)
- {
- std::string instruction;
+ for (it = rootObj.begin(); it != rootObj.end(); ++it)
+ {
+ std::string instruction;
- if ((*it)->get(instruction))
+ if ((*it)->get(instruction))
+ {
+ if (instruction == "reset_transform")
+ {
+ transform.identity();
+ }
+ else if (instruction == "translate")
{
- if (instruction == "reset_transform")
+ std::vector<SerializablePtr> values;
+
+ ++it;
+ if ((*it)->get(values))
{
- transform.identity();
+ Vector3 vec;
+
+ for (size_t i = 0; i < values.size(); ++i)
+ {
+ double value;
+
+ if (values[i]->getNumber(value))
+ {
+ vec[i] = value;
+ }
+ }
+
+ Matrix4 translation;
+ cml::matrix_translation(translation, vec);
+ transform = translation * transform;
}
- else if (instruction == "translate")
+ }
+ else if (instruction == "scale")
+ {
+ std::vector<SerializablePtr> values;
+
+ ++it;
+ if ((*it)->get(values))
{
- std::vector<SerializablePtr> values;
+ if (values.size() == 1)
+ {
+ double value = 1.0;
+
+ values[0]->getNumber(value);
- it++;
- if ((*it)->get(values))
+ Matrix4 scaling;
+ cml::matrix_uniform_scale(scaling,
+ Scalar(value));
+ transform = scaling * transform;
+ }
+ else if (values.size() == 3)
{
Vector3 vec;
- for (size_t i = 0; i < values.size(); i++)
+ for (size_t i = 0; i < values.size(); ++i)
{
double value;
}
}
- Matrix4 translation;
- cml::matrix_translation(translation, vec);
- transform = translation * transform;
+ Matrix4 scaling;
+ cml::matrix_scale(scaling, vec);
+ transform = scaling * transform;
}
}
- else if (instruction == "scale")
- {
- std::vector<SerializablePtr> values;
+ }
+ else if (instruction == "rotate")
+ {
+ std::vector<SerializablePtr> values;
- it++;
- if ((*it)->get(values))
+ ++it;
+ if ((*it)->get(values))
+ {
+ if (values.size() == 2)
{
- if (values.size() == 1)
- {
- double value = 1.0;
-
- values[0]->getNumber(value);
+ std::string axis;
+ size_t index = 0;
+ double value = 0.0;
- Matrix4 scaling;
- cml::matrix_uniform_scale(scaling, Scalar(value));
- transform = scaling * transform;
- }
- else if (values.size() == 3)
+ if (values[0]->get(axis))
{
- Vector3 vec;
-
- for (size_t i = 0; i < values.size(); i++)
- {
- double value;
-
- if (values[i]->getNumber(value))
- {
- vec[i] = value;
- }
- }
+ if (axis == "x") index = 0;
+ else if (axis == "y") index = 1;
+ else if (axis == "z") index = 2;
- Matrix4 scaling;
- cml::matrix_scale(scaling, vec);
- transform = scaling * transform;
+ values[1]->getNumber(value);
}
- }
- }
- else if (instruction == "rotate")
- {
- std::vector<SerializablePtr> values;
-
- it++;
- if ((*it)->get(values))
- {
- if (values.size() == 2)
- {
- std::string axis;
- size_t axisIndex = 0;
- double value = 0.0;
- Vector3 vec(0.0, 0.0, 0.0);
- if (values[0]->get(axis))
- {
- if (axis == "x")
- {
- axisIndex = 0;
- vec[0] = 1.0;
- }
- else if (axis == "y")
- {
- axisIndex = 1;
- vec[1] = 1.0;
- }
- else if (axis == "z")
- {
- axisIndex = 2;
- vec[2] = 1.0;
- }
- values[1]->getNumber(value);
- }
-
- cml::matrix_rotate_about_world_axis(transform,
- axisIndex, Scalar(value * cml::constantsd::rad_per_deg()));
- }
+ cml::matrix_rotate_about_world_axis(transform,
+ index, cml::rad(Scalar(value)));
}
}
- else if (instruction == "texture")
- {
- it++;
- (*it)->get(texture);
- }
- else if (instruction == "tilemap")
- {
- it++;
- TilePanel* tilePanel = new TilePanel(transform, texture,
- *it);
- boost::shared_ptr<Scenery> sceneItem(tilePanel);
- objects.push_back(sceneItem);
- }
- else if (instruction == "billboard")
- {
- it++;
- Billboard* billboard = new Billboard(transform, texture,
- *it);
- boost::shared_ptr<Scenery> sceneItem(billboard);
- objects.push_back(sceneItem);
- }
+ }
+ else if (instruction == "texture")
+ {
+ ++it;
+ (*it)->get(texture);
+ }
+ else if (instruction == "tilemap")
+ {
+ ++it;
+ loadTilemap(*it, transform, texture);
+ }
+ else if (instruction == "billboard")
+ {
+ ++it;
+ loadBillboard(*it, transform, texture);
}
}
}
}
- void loadFromFile()
+ void loadTilemap(SerializablePtr root, const Matrix4& transform,
+ const std::string& texture)
{
- std::string filePath = Scene::getPathToResource(getName());
+ std::map<std::string,SerializablePtr> rootObj;
+ std::map<std::string,SerializablePtr>::iterator it;
- Deserializer deserializer(filePath, true);
+ if (!root->get(rootObj))
+ {
+ std::cerr << "error loading scene tilemap object" << std::endl;
+ return;
+ }
- SerializablePtr root = deserializer.deserialize();
+ long width = 1;
+ long height = 1;
+ std::vector< std::vector<Tilemap::Index> > indices;
- if (root)
+ if ((it = rootObj.find("width")) != rootObj.end())
{
- std::map<std::string,SerializablePtr> rootObj;
+ (*it).second->get(width);
+ }
+ else
+ {
+ std::cerr << "width is a required field of a tilemap" << std::endl;
+ return;
+ }
- if (root->get(rootObj))
+ std::vector<SerializablePtr> tiles;
+
+ if ((it = rootObj.find("tiles")) != rootObj.end() &&
+ (*it).second->get(tiles) &&
+ tiles.size() % width == 0)
+ {
+ std::vector<SerializablePtr>::iterator jt;
+ int w, h;
+
+ height = tiles.size() / width;
+ indices.resize(height);
+
+ // the indices are stored upside-down in the scene file so that they
+ // are easier to edit as text, so we'll need to load them last row
+ // first
+
+ for (h = height - 1, jt = tiles.begin(); jt != tiles.end(); --h)
{
- std::map<std::string,SerializablePtr>::iterator it;
+ std::vector<Tilemap::Index> row;
- if ((it = rootObj.find("playfield_bounds")) != rootObj.end())
- {
- loadBox(playfieldBounds, (*it).second);
- }
- if ((it = rootObj.find("maximum_bounds")) != rootObj.end())
+ for (w = 0; w < width && jt != tiles.end(); ++w, ++jt)
{
- loadBox(maximumBounds, (*it).second);
- }
- if ((it = rootObj.find("instructions")) != rootObj.end())
- {
- loadInstructions((*it).second);
+ long index;
+
+ if ((*jt)->get(index))
+ {
+ row.push_back(Tilemap::Index(index));
+ }
}
+
+ indices[h] = row;
+ }
+ }
+ else
+ {
+ std::cerr << "error loading tiles from tilemap object" << std::endl;
+ return;
+ }
+
+ Vector4 vertices[height+1][width+1];
+
+ Matrix4 transposedTransform = transform;
+ transposedTransform.transpose();
+
+ for (int h = 0; h <= height; ++h)
+ {
+ for (int w = 0; w <= width; ++w)
+ {
+ vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) *
+ transposedTransform;
+ }
+ }
+
+ for (int h = 0; h < height; ++h)
+ {
+ for (int w = 0; w < width; ++w)
+ {
+ if (indices[h][w] == Tilemap::NO_TILE) continue;
+
+ Vector3 quadVertices[4];
+
+ demoteVector(quadVertices[0], vertices[h][w]);
+ demoteVector(quadVertices[1], vertices[h][w+1]);
+ demoteVector(quadVertices[2], vertices[h+1][w+1]);
+ demoteVector(quadVertices[3], vertices[h+1][w]);
+
+ Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
+ boost::shared_ptr<Quad> quadPtr(quad);
+
+ objects.push_back(quadPtr);
+ }
+ }
+ }
+
+ void loadBillboard(SerializablePtr root, const Matrix4& transform,
+ const std::string& texture)
+ {
+ std::map<std::string,SerializablePtr> rootObj;
+ std::map<std::string,SerializablePtr>::iterator it;
+
+ if (!root->get(rootObj))
+ {
+ std::cerr << "error loading scene billboard object" << std::endl;
+ return;
+ }
+
+ Tilemap::Index index = 0;
+ long width = 1;
+ bool blending = false;
+ bool fog = false;
+
+ if ((it = rootObj.find("tile")) != rootObj.end())
+ {
+ long value;
+ if ((*it).second->get(value))
+ {
+ index = Tilemap::Index(value);
}
}
- std::cout << "playfield: " << playfieldBounds.min << " ... " <<
- playfieldBounds.max << std::endl;
+ if ((it = rootObj.find("u_scale")) != rootObj.end())
+ {
+ (*it).second->get(width);
+ }
+
+ if ((it = rootObj.find("blend")) != rootObj.end())
+ {
+ (*it).second->get(blending);
+ }
+
+ if ((it = rootObj.find("fog")) != rootObj.end())
+ {
+ (*it).second->get(fog);
+ }
+
+
+ Vector4 vertices[2][width+1];
+
+ Matrix4 transposedTransform = transform;
+ transposedTransform.transpose();
+
+ Scalar xf;
+ Scalar increment = 1.0 / Scalar(width);
+
+ for (int h = 0; h <= 1; ++h)
+ {
+ xf = 0.0;
+ for (int w = 0; w <= width; ++w, xf += increment)
+ {
+ vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) *
+ transposedTransform;
+ }
+ }
+
+ for (int w = 0; w < width; ++w)
+ {
+ Vector3 quadVertices[4];
+
+ demoteVector(quadVertices[0], vertices[0][w]);
+ demoteVector(quadVertices[1], vertices[0][w+1]);
+ demoteVector(quadVertices[2], vertices[1][w+1]);
+ demoteVector(quadVertices[3], vertices[1][w]);
+
+ Quad* quad = new Quad(quadVertices, texture, index);
+ quad->setBlending(blending);
+ quad->setFog(fog);
+
+ boost::shared_ptr<Quad> quadPtr(quad);
+
+ objects.push_back(quadPtr);
+ }
+ }
+
+
+ void loadFromFile()
+ {
+ std::string filePath = Scene::getPathToResource(getName());
+
+ Deserializer deserializer(filePath, true);
+ SerializablePtr root = deserializer.deserialize();
+
+ std::map<std::string,SerializablePtr> rootObj;
+ std::map<std::string,SerializablePtr>::iterator it;
+
+ if (!root || !root->get(rootObj))
+ {
+ std::cerr << "error loading scene file" << std::endl;
+ return;
+ }
+
+ if ((it = rootObj.find("playfield_bounds")) != rootObj.end())
+ {
+ loadBox(playfieldBounds, (*it).second);
+ }
+ if ((it = rootObj.find("maximum_bounds")) != rootObj.end())
+ {
+ loadBox(maximumBounds, (*it).second);
+ }
+ if ((it = rootObj.find("instructions")) != rootObj.end())
+ {
+ loadInstructions((*it).second);
+ }
}
void draw(Scalar alpha)
{
- SceneryVector::iterator it;
+ QuadVector::iterator it;
- for (it = objects.begin(); it != objects.end(); it++)
+ for (it = objects.begin(); it != objects.end(); ++it)
{
//std::cout << "draw object";
(*it)->draw(alpha);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBindTexture(GL_TEXTURE_2D, 0);
- glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
- playfieldBounds.draw(0.0);
+ glColor3f(0.0f, 1.0f, 0.0f);
+ playfieldBounds.draw();
+ glColor3f(0.0f, 0.0f, 1.0f);
+ maximumBounds.draw();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
Aabb playfieldBounds;
Aabb maximumBounds;
- typedef std::vector<boost::shared_ptr<Scenery> > SceneryVector;
- SceneryVector objects;
+ typedef std::vector< boost::shared_ptr<Quad> > QuadVector;
+ QuadVector objects;
};