From d9f44af7aee41a111a3d7427d8735bc821f1824f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 15 Dec 2009 19:37:12 +0100 Subject: Moved source files to src; sort triangles by texture. --- BSPTree.cpp | 164 ---------------------- BSPTree.h | 177 ------------------------ CMakeLists.txt | 15 +- Game.cpp | 122 ---------------- Game.h | 51 ------- Level.cpp | 260 ---------------------------------- Level.h | 74 ---------- Renderer.cpp | 77 ----------- Renderer.h | 56 -------- Shader.cpp | 95 ------------- Shader.h | 41 ------ Texture.cpp | 44 ------ Texture.h | 40 ------ Triangle.h | 105 -------------- config.h | 27 ---- gl.h | 32 ----- src/BSPTree.cpp | 164 ++++++++++++++++++++++ src/BSPTree.h | 177 ++++++++++++++++++++++++ src/CMakeLists.txt | 13 ++ src/Game.cpp | 129 +++++++++++++++++ src/Game.h | 53 +++++++ src/Level.cpp | 260 ++++++++++++++++++++++++++++++++++ src/Level.h | 74 ++++++++++ src/Renderer.cpp | 69 ++++++++++ src/Renderer.h | 78 +++++++++++ src/Shader.cpp | 95 +++++++++++++ src/Shader.h | 41 ++++++ src/Texture.cpp | 44 ++++++ src/Texture.h | 40 ++++++ src/Triangle.h | 105 ++++++++++++++ src/config.h | 27 ++++ src/gl.h | 32 +++++ src/zoom.cpp | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++ zoom.cpp | 398 ----------------------------------------------------- 34 files changed, 1800 insertions(+), 1777 deletions(-) delete mode 100644 BSPTree.cpp delete mode 100644 BSPTree.h delete mode 100644 Game.cpp delete mode 100644 Game.h delete mode 100644 Level.cpp delete mode 100644 Level.h delete mode 100644 Renderer.cpp delete mode 100644 Renderer.h delete mode 100644 Shader.cpp delete mode 100644 Shader.h delete mode 100644 Texture.cpp delete mode 100644 Texture.h delete mode 100644 Triangle.h delete mode 100644 config.h delete mode 100644 gl.h create mode 100644 src/BSPTree.cpp create mode 100644 src/BSPTree.h create mode 100644 src/CMakeLists.txt create mode 100644 src/Game.cpp create mode 100644 src/Game.h create mode 100644 src/Level.cpp create mode 100644 src/Level.h create mode 100644 src/Renderer.cpp create mode 100644 src/Renderer.h create mode 100644 src/Shader.cpp create mode 100644 src/Shader.h create mode 100644 src/Texture.cpp create mode 100644 src/Texture.h create mode 100644 src/Triangle.h create mode 100644 src/config.h create mode 100644 src/gl.h create mode 100644 src/zoom.cpp delete mode 100644 zoom.cpp diff --git a/BSPTree.cpp b/BSPTree.cpp deleted file mode 100644 index a94c77a..0000000 --- a/BSPTree.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * BSPTree.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "BSPTree.h" - -namespace Zoom { - -vmml::vec3f BSPTree::Plane::intersection(const vmml::vec3f &p, const vmml::vec3f &dir) const { - float r = (d - p.dot(normal))/dir.dot(normal); - - return p + r*dir; -} - -void BSPTree::Plane::partition(const TriangleRecord &t, std::list *front, std::list *back) const { - for(int i = 0; i < 3; ++i) { - if(contains(t.triangle.getVertex(i))) { - const vmml::vec3f *v[3] = {&t.triangle.getVertex(i), &t.triangle.getVertex((i+1)%3), &t.triangle.getVertex((i+2)%3)}; - - vmml::vec3f is = intersection(*v[1], *v[2]-*v[1]); - - if(isInFront(*v[1])) { - front->push_back(TriangleRecord(Triangle(*v[0], *v[1], is, t.triangle.getColor()), t.data)); - back->push_back(TriangleRecord(Triangle(*v[0], is, *v[2], t.triangle.getColor()), t.data)); - } - else { - back->push_back(TriangleRecord(Triangle(*v[0], *v[1], is, t.triangle.getColor()), t.data)); - front->push_back(TriangleRecord(Triangle(*v[0], is, *v[2], t.triangle.getColor()), t.data)); - } - - return; - } - } - - for(int i = 0; i < 3; ++i) { - const vmml::vec3f *v[3] = {&t.triangle.getVertex(i), &t.triangle.getVertex((i+1)%3), &t.triangle.getVertex((i+2)%3)}; - - if((isInFront(*v[0]) && isBehind(*v[1]) && isBehind(*v[2])) - || (isBehind(*v[0]) && isInFront(*v[1]) && isInFront(*v[2]))) { - vmml::vec3f is1 = intersection(*v[0], *v[1]-*v[0]); - vmml::vec3f is2 = intersection(*v[0], *v[2]-*v[0]); - - if(isInFront(*v[0])) { - front->push_back(TriangleRecord(Triangle(*v[0], is1, is2, t.triangle.getColor()), t.data)); - back->push_back(TriangleRecord(Triangle(is1, *v[1], is2, t.triangle.getColor()), t.data)); - back->push_back(TriangleRecord(Triangle(*v[1], *v[2], is2, t.triangle.getColor()), t.data)); - } - else { - back->push_back(TriangleRecord(Triangle(*v[0], is1, is2, t.triangle.getColor()), t.data)); - front->push_back(TriangleRecord(Triangle(is1, *v[1], is2, t.triangle.getColor()), t.data)); - front->push_back(TriangleRecord(Triangle(*v[1], *v[2], is2, t.triangle.getColor()), t.data)); - } - - return; - } - } -} - - -BSPTree::BSPTree(const std::list &triangles) : frontTree(0), backTree(0) { - const Triangle *planeT = findNearestTriangle(triangles, findCenter(triangles)); - - if(!planeT) - return; - - plane = Plane(*planeT); - - std::list front, back; - - for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { - if(t->triangle.isDegenerate()) - continue; - - if(plane.contains(t->triangle)) { - this->triangles.push_back(*t); - continue; - } - else if(plane.isInFront(t->triangle)) { - front.push_back(*t); - continue; - } - else if(plane.isBehind(t->triangle)) { - back.push_back(*t); - continue; - } - - plane.partition(*t, &front, &back); - } - - if(!front.empty()) - frontTree = new BSPTree(front); - - if(!back.empty()) - backTree = new BSPTree(back); -} - -BSPTree& BSPTree::operator=(const BSPTree &tree) { - if(frontTree) { - delete frontTree; - frontTree = 0; - } - - if(backTree) { - delete backTree; - backTree = 0; - } - - plane = tree.plane; - triangles = tree.triangles; - - if(tree.frontTree) - frontTree = new BSPTree(*tree.frontTree); - - if(tree.backTree) - backTree = new BSPTree(*tree.backTree); - - return *this; -} - -vmml::vec3f BSPTree::findCenter(const std::list &triangles) { - vmml::vec3f v; - - for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { - v += t->triangle.getCenter(); - } - - return v/triangles.size(); -} - -const Triangle* BSPTree::findNearestTriangle(const std::list &triangles, const vmml::vec3f &v) { - const Triangle *current = 0; - float distanceSq; - - for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { - if(t->triangle.isDegenerate()) - continue; - - float d = t->triangle.getCenter().squared_distance(v); - - if(!current || d < distanceSq) { - current = &t->triangle; - distanceSq = d; - } - } - - return current; -} - -} diff --git a/BSPTree.h b/BSPTree.h deleted file mode 100644 index 1944ef1..0000000 --- a/BSPTree.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * BSPTree.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_BSPTREE_H_ -#define ZOOM_BSPTREE_H_ - -#include "Triangle.h" -#include -#include - -#include -#include - -namespace Zoom { - -class BSPTree { - public: - class TriangleData { - protected: - TriangleData() {} - - public: - virtual ~TriangleData() {} - }; - - struct TriangleRecord { - public: - TriangleRecord(Triangle triangle0, boost::shared_ptr data0) - : triangle(triangle0), data(data0) {} - TriangleRecord(Triangle triangle0) : triangle(triangle0) {} - TriangleRecord() {} - - Triangle triangle; - boost::shared_ptr data; - }; - - private: - class Plane { - public: - Plane() : d(0) {} - Plane(const vmml::vec3f &n, float d0) : normal(n), d(d0) {} - Plane(const Triangle &t) : normal(t.computeNormal()), d(t.getVertex(0).dot(normal)) {} - - bool contains(const vmml::vec3f &v) const { - return (fabsf(normal.dot(v) - d) < 1E-6); - } - - bool isBehind(const vmml::vec3f &v) const { - return (normal.dot(v) - d) < 0; - } - - bool isInFront(const vmml::vec3f &v) const { - return (normal.dot(v) - d) > 0; - } - - - bool contains(const Triangle &t) const { - for(int i = 0; i < 3; ++i) { - if(!contains(t.getVertex(i))) - return false; - } - - return true; - } - - bool isBehind(const Triangle &t) const { - for(int i = 0; i < 3; ++i) { - if(!isBehind(t.getVertex(i)) && !contains(t.getVertex(i))) - return false; - } - - return true; - } - - bool isInFront(const Triangle &t) const { - for(int i = 0; i < 3; ++i) { - if(!isInFront(t.getVertex(i)) && !contains(t.getVertex(i))) - return false; - } - - return true; - } - - - const vmml::vec3f& getNormal() const { - return normal; - } - - vmml::vec3f intersection(const vmml::vec3f &p, const vmml::vec3f &dir) const; - void partition(const TriangleRecord &t, std::list *front, std::list *back) const; - - private: - vmml::vec3f normal; - float d; - }; - - public: - BSPTree(const std::list &triangles); - - BSPTree(const BSPTree &tree) : frontTree(0), backTree(0) { - *this = tree; - } - - virtual ~BSPTree() { - if(frontTree) - delete frontTree; - - if(backTree) - delete backTree; - } - - BSPTree& operator=(const BSPTree &tree); - - template - void visit(const T& visitor, const vmml::vec3f &p) const { - doVisit(visitor, p); - } - - template - void visit(T& visitor, const vmml::vec3f &p) const { - doVisit(visitor, p); - } - - private: - Plane plane; - std::list triangles; - BSPTree *frontTree, *backTree; - - template - void doVisit(T& visitor, const vmml::vec3f &p) const { - if(plane.isBehind(p)) { - if(frontTree) - frontTree->visit(visitor, p); - - for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { - visitor(*t); - } - - if(backTree) - backTree->visit(visitor, p); - } - else { - if(backTree) - backTree->visit(visitor, p); - - for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { - visitor(*t); - } - - if(frontTree) - frontTree->visit(visitor, p); - } - } - - static vmml::vec3f findCenter(const std::list &triangles); - static const Triangle* findNearestTriangle(const std::list &triangles, const vmml::vec3f &v); -}; - -} - -#endif /* ZOOM_BSPTREE_H_ */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 305c938..7a57452 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,17 +11,4 @@ find_package(LibXml2 REQUIRED) include_directories(${Boost_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${GLPNG_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) -add_executable(zoom - BSPTree.cpp BSPTree.h - Game.cpp Game.h - config.h - gl.h - Level.cpp Level.h - Renderer.cpp Renderer.h - Shader.cpp Shader.h - Texture.cpp Texture.h - Triangle.h - zoom.cpp -) - -target_link_libraries(zoom ${Boost_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARY} ${GLPNG_LIBRARY} ${LIBXML2_LIBRARIES}) +add_subdirectory(src) diff --git a/Game.cpp b/Game.cpp deleted file mode 100644 index d948b2f..0000000 --- a/Game.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Game.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "Game.h" -#include "BSPTree.h" -#include "Level.h" -#include "Shader.h" -#include "Triangle.h" -#include "gl.h" - -namespace Zoom { - -Game::Game(bool multisample) : angle(0), lightPos(0) { - glClearColor(0.0, 0.0, 0.0, 1.0); - glClearDepth(1.0); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - //glEnable(GL_BLEND); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - -#ifndef _WIN32 - if(multisample) - glEnable(GL_MULTISAMPLE_ARB); -#endif - - glShadeModel(GL_SMOOTH); - - glEnable(GL_LIGHTING); - glLightfv(GL_LIGHT0, GL_AMBIENT, vmml::vec4f::ZERO.array); - glLightfv(GL_LIGHT0, GL_DIFFUSE, vmml::vec4f::ONE.array); - glLightfv(GL_LIGHT0, GL_SPECULAR, vmml::vec4f::ONE.array); - glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0); - glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.3); - glEnable(GL_LIGHT0); - - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vmml::vec4f::ONE.array); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 128); - - glEnable(GL_CULL_FACE); - glFrontFace(GL_CCW); - - Shader::loadProgram("default.vert", "default.frag"); - - loadLevel("level.xml"); -} - -bool Game::loadLevel(const std::string &name) { - level = Level::loadLevel(name); - - return level; -} - -void Game::run(int delta) { - angle += delta*0.01; - - if(angle >= 360) - angle -= 360; - - lightPos += delta; - lightPos %= 24000; -} - -void Game::render() { - int i; - float light[] = {0, 0, 0, 1}; - - if(lightPos < 12000) i = lightPos; - else i = 24000 - lightPos; - - if(i < 4000) { - light[0] = 0.0; - light[2] = -i * 0.001; - } - else if(i < 8000) { - light[0] = (i-4000) * 0.001; - light[2] = -4.0; - } - else if(i < 12000) { - light[0] = 4.0; - light[2] = -4.0 - (i-8000) * 0.001; - } - else { - light[0] = 4.0; - light[2] = -8.0; - } - - glLightfv(GL_LIGHT0, GL_POSITION, light); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glPushMatrix(); - //glRotatef(10, 1, 2, 1); - /*glRotatef(5*angle, 0, -1, 2); - glRotatef(7*angle, 2, -1, 0); - glRotatef(11*angle, 2, -1, 2);*/ - - renderer.render(level->getRooms().front().walls); - - glPopMatrix(); -} - -} diff --git a/Game.h b/Game.h deleted file mode 100644 index f651125..0000000 --- a/Game.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Game.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_GAME_H_ -#define ZOOM_GAME_H_ - -#include "Renderer.h" -#include -#include - -namespace Zoom { - -class Level; -class Triangle; - -class Game { - public: - Game(bool multisample); - - bool loadLevel(const std::string &name); - - void run(int delta); - void render(); - - private: - Renderer renderer; - boost::shared_ptr level; - - float angle; - int lightPos; -}; - -} - -#endif /* ZOOM_GAME_H_ */ diff --git a/Level.cpp b/Level.cpp deleted file mode 100644 index 2867ab9..0000000 --- a/Level.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Level.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "Level.h" -#include "Texture.h" -#include -#include - -#include - -namespace Zoom { - -boost::shared_ptr Level::loadLevel(const std::string &filename) { - boost::shared_ptr level; - - xmlDocPtr doc = xmlParseFile(("levels/"+filename).c_str()); - - if(doc) { - if(validateLevel(doc)) { - xmlNodePtr root = xmlDocGetRootElement(doc); - if(root && !xmlStrcmp(root->name, (xmlChar*)"level")) { - level = boost::shared_ptr(new Level); - - for(xmlNodePtr node = root->children; node != 0; node = node->next) { - if(node->type != XML_ELEMENT_NODE) - continue; - - if(!xmlStrcmp(node->name, (xmlChar*)"info")) { - level->loadLevelInfo(node); - } - else if(!xmlStrcmp(node->name, (xmlChar*)"rooms")) { - level->loadRooms(node); - } - else if(!xmlStrcmp(node->name, (xmlChar*)"textures")) { - level->loadTextures(node); - } - } - - for(std::list::iterator room = level->rooms.begin(); room != level->rooms.end(); ++room) { - for(std::list::iterator wall = room->walls.begin(); wall != room->walls.end(); ++wall) { - boost::shared_ptr wallData = boost::dynamic_pointer_cast(wall->data); - - if(!wallData->texture.empty()) { - std::map::iterator texture = level->textures.find(wallData->texture); - - if(texture != level->textures.end()) - wall->triangle.setTexture(texture->second); - } - } - } - } - } - - xmlFreeDoc(doc); - } - - xmlCleanupParser(); - - return level; -} - -void Level::loadLevelInfo(xmlNodePtr infoNode) { - for(xmlNodePtr node = infoNode->children; node != 0; node = node->next) { - if(node->type != XML_ELEMENT_NODE) - continue; - - if(!xmlStrcmp(node->name, (xmlChar*)"name")) { - xmlChar *data = xmlNodeGetContent(node); - name = (char*)data; - xmlFree(data); - } - else if(!xmlStrcmp(node->name, (xmlChar*)"desc")) { - xmlChar *data = xmlNodeGetContent(node); - description = (char*)data; - xmlFree(data); - } - else if(!xmlStrcmp(node->name, (xmlChar*)"start")) { - startPoint = loadVector(node); - } - } -} - -void Level::loadRooms(xmlNodePtr roomsNode) { - for(xmlNodePtr node = roomsNode->children; node != 0; node = node->next) { - if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"room")) { - loadRoom(node); - } - } -} - -void Level::loadRoom(xmlNodePtr roomNode) { - rooms.push_back(Room()); - - xmlChar *data = xmlGetProp(roomNode, (xmlChar*)"id"); - if(data) { - rooms.back().id = (char*)data; - - xmlFree(data); - } - - for(xmlNodePtr node = roomNode->children; node != 0; node = node->next) { - if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"triangle")) { - rooms.back().walls.push_back(loadWall(node)); - } - } -} - -void Level::loadTextures(xmlNodePtr texturesNode) { - for(xmlNodePtr node = texturesNode->children; node != 0; node = node->next) { - if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"texture")) { - std::string id, name; - - xmlChar *data = xmlGetProp(node, (xmlChar*)"id"); - if(data) { - id = (char*)data; - xmlFree(data); - } - - data = xmlGetProp(node, (xmlChar*)"name"); - if(data) { - name = (char*)data; - xmlFree(data); - } - - if(!id.empty() && !name.empty()) { - unsigned texture = Texture::loadTexture(name); - - if(texture) { - textures.insert(std::make_pair(id, texture)); - } - } - } - } -} - -BSPTree::TriangleRecord Level::loadWall(xmlNodePtr wallNode) { - boost::shared_ptr wallData(new WallData); - - BSPTree::TriangleRecord wall; - wall.data = wallData; - - - xmlChar *data = xmlGetProp(wallNode, (xmlChar*)"texture"); - if(data) { - wallData->texture = (char*)data; - xmlFree(data); - } - - int vertexNum = -1; - - for(xmlNodePtr node = wallNode->children; node != 0; node = node->next) { - if(node->type != XML_ELEMENT_NODE) - continue; - - if(!xmlStrcmp(node->name, (xmlChar*)"vertex")) { - if(++vertexNum > 2) - break; - - wall.triangle.setVertex(vertexNum, loadVector(node)); - } - else if(!xmlStrcmp(node->name, (xmlChar*)"normal")) { - if(vertexNum < 0) - continue; - - wall.triangle.setNormal(vertexNum, loadVector(node)); - } - else if(!xmlStrcmp(node->name, (xmlChar*)"texcoords")) { - if(vertexNum < 0) continue; - - data = xmlGetProp(node, (xmlChar*)"s"); - if(data) { - wall.triangle.getTexCoords(vertexNum)[0] = atof((char*)data); - xmlFree(data); - } - - data = xmlGetProp(node, (xmlChar*)"t"); - if(data) { - wall.triangle.getTexCoords(vertexNum)[1] = atof((char*)data); - xmlFree(data); - } - } - } - - vmml::vec3f normal = wall.triangle.computeNormal(); - - if(normal.squared_length() > 0) { - normal.normalize(); - - for(int i = 0; i < 3; ++i) { - if(wall.triangle.getNormal(i).squared_length() == 0) - wall.triangle.setNormal(i, normal); - } - } - - - return wall; -} - -vmml::vec3f Level::loadVector(xmlNodePtr node) { - vmml::vec3f ret(vmml::vec3f::ZERO); - - xmlChar *data = xmlGetProp(node, (xmlChar*)"x"); - if(data) { - ret.x() = atof((char*)data); - xmlFree(data); - } - - data = xmlGetProp(node, (xmlChar*)"y"); - if(data) { - ret.y() = atof((char*)data); - xmlFree(data); - } - - data = xmlGetProp(node, (xmlChar*)"z"); - if(data) { - ret.z() = atof((char*)data); - xmlFree(data); - } - - return ret; -} - -bool Level::validateLevel(xmlDocPtr doc) { - bool ret = false; - - xmlDtdPtr dtd = xmlParseDTD((xmlChar*)"-//libzoom//DTD level 0.1//EN", (xmlChar*)"levels/level.dtd"); - - if(dtd) { - xmlValidCtxtPtr validCtxt = xmlNewValidCtxt(); - - if(validCtxt) { - if(xmlValidateDtd(validCtxt, doc, dtd)) - ret = true; - - xmlFreeValidCtxt(validCtxt); - } - - xmlFreeDtd(dtd); - } - - return ret; -} - -} diff --git a/Level.h b/Level.h deleted file mode 100644 index 277b6e7..0000000 --- a/Level.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Level.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_LEVEL_H_ -#define ZOOM_LEVEL_H_ - -#include "BSPTree.h" - -#include -#include -#include - -#include -#include -#include - -namespace Zoom { - -class Level { - public: - static boost::shared_ptr loadLevel(const std::string &filename); - - struct WallData : public BSPTree::TriangleData { - std::string texture; - }; - - struct Room { - std::string id; - std::list walls; - }; - - const std::list &getRooms() const { - return rooms; - } - - private: - std::list rooms; - std::map textures; - - std::string name, description; - vmml::vec3f startPoint; - - Level() {} - - void loadLevelInfo(xmlNodePtr infoNode); - void loadRooms(xmlNodePtr roomsNode); - void loadRoom(xmlNodePtr roomNode); - void loadTextures(xmlNodePtr texturesNode); - - static BSPTree::TriangleRecord loadWall(xmlNodePtr wallNode); - static vmml::vec3f loadVector(xmlNodePtr node); - - static bool validateLevel(xmlDocPtr doc); -}; - -} - -#endif /* ZOOM_LEVEL_H_ */ diff --git a/Renderer.cpp b/Renderer.cpp deleted file mode 100644 index 558e415..0000000 --- a/Renderer.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Renderer.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "Renderer.h" -#include "BSPTree.h" -#include "gl.h" - -namespace Zoom { - -void Renderer::render(const BSPTree &tree) { - vmml::mat4f transform, inverseTransform; - glGetFloatv(GL_MODELVIEW_MATRIX, transform.array); - - transform.inverse(inverseTransform); - - vmml::vec3f viewPoint = inverseTransform*vmml::vec3f::ZERO; - - glBegin(GL_TRIANGLES); - tree.visit(renderVisitor, viewPoint); - glEnd(); - -} - -void Renderer::render(const std::list &triangles) { - glBegin(GL_TRIANGLES); - for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { - renderTriangle(t->triangle); - } - glEnd(); -} - -void Renderer::renderTriangle(const Triangle &t) { - glColor4fv(t.getColor().array); - - if(t.getTexture() != lastTexture) { - glEnd(); - - if(t.getTexture()) { - glBindTexture(GL_TEXTURE_2D, t.getTexture()); - - if(!lastTexture) { - glEnable(GL_TEXTURE_2D); - } - } - else { - glDisable(GL_TEXTURE_2D); - } - - lastTexture = t.getTexture(); - - glBegin(GL_TRIANGLES); - } - - for(int i = 0; i < 3; ++i) { - glTexCoord2fv(t.getTexCoords(i).array); - glNormal3fv(t.getNormal(i).array); - glVertex3fv(t.getVertex(i).array); - } -} - -} diff --git a/Renderer.h b/Renderer.h deleted file mode 100644 index d72b5bb..0000000 --- a/Renderer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Renderer.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_RENDERER_H_ -#define ZOOM_RENDERER_H_ - -#include "BSPTree.h" - -namespace Zoom { - -class Renderer { - public: - Renderer() : lastTexture(0), renderVisitor(this) {} - - void render(const BSPTree &tree); - void render(const std::list &triangles); - - private: - void renderTriangle(const Triangle &t); - - class RenderVisitor { - public: - RenderVisitor(Renderer *renderer0) : renderer(renderer0) {} - - void operator() (const BSPTree::TriangleRecord &t) const { - renderer->renderTriangle(t.triangle); - } - - private: - Renderer *renderer; - }; - - unsigned lastTexture; - - const RenderVisitor renderVisitor; -}; - -} - -#endif /* ZOOM_RENDERER_H_ */ diff --git a/Shader.cpp b/Shader.cpp deleted file mode 100644 index 420b6c6..0000000 --- a/Shader.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Shader.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "Shader.h" -#include -#include -#include -#include - -namespace Zoom { - -bool Shader::loadProgram(const std::string &vertexShader, const std::string &fragmentShader) { - GLhandleARB program, vs = 0, fs = 0; - - if(!vertexShader.empty()) - vs = loadShader(vertexShader, GL_VERTEX_SHADER_ARB); - - if(!fragmentShader.empty()) - fs = loadShader(fragmentShader, GL_FRAGMENT_SHADER_ARB); - - program = glCreateProgramObjectARB(); - - if(vs) - glAttachObjectARB(program, vs); - - if(fs) - glAttachObjectARB(program, fs); - - glLinkProgramARB(program); - printInfoLog(program); - - glUseProgramObjectARB(program); - - return true; -} - -GLhandleARB Shader::loadShader(const std::string &name, GLenum type) { - std::vector lines; - std::ifstream file(("shader/" + name).c_str(), std::ios_base::in); - if(!file.good()) - throw std::ios::failure("Can't read file '" + name + "'"); - - while(file.good() && !file.eof()) { - std::string line; - std::getline(file, line); - - if(!line.empty()) - lines.push_back(line); - } - - boost::scoped_array strings(new const char*[lines.size()]); - for(std::size_t i = 0; i < lines.size(); ++i) { - strings[i] = lines[i].c_str(); - } - - GLhandleARB shader = glCreateShaderObjectARB(type); - glShaderSourceARB(shader, lines.size(), strings.get(), 0); - glCompileShaderARB(shader); - printInfoLog(shader); - - return shader; -} - -void Shader::printInfoLog(GLhandleARB obj) { - int length = 0; - - glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - - if(length > 0) { - boost::scoped_array log(new char[length]); - - int foo; - glGetInfoLogARB(obj, length, &foo, log.get()); - std::cerr << log.get() << std::endl; - } -} - - -} diff --git a/Shader.h b/Shader.h deleted file mode 100644 index 8111f0c..0000000 --- a/Shader.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Shader.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_SHADER_H_ -#define ZOOM_SHADER_H_ - -#include "gl.h" -#include - -namespace Zoom { - -class Shader { - public: - static bool loadProgram(const std::string &vertexShader, const std::string &fragmentShader); - - private: - Shader(); - - static GLhandleARB loadShader(const std::string &name, GLenum type); - static void printInfoLog(GLhandleARB obj); -}; - -} - -#endif /* ZOOM_SHADER_H_ */ diff --git a/Texture.cpp b/Texture.cpp deleted file mode 100644 index d5ec1f2..0000000 --- a/Texture.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Texture.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "Texture.h" -#include "gl.h" -#include - -namespace Zoom { - -std::map Texture::textures; - -unsigned Texture::loadTexture(const std::string &name) { - std::map::iterator it = textures.find(name); - - if(it != textures.end()) - return it->second; - - pngInfo info; - unsigned texture = pngBind(("tex/" + name).c_str(), PNG_NOMIPMAP, PNG_ALPHA, &info, GL_REPEAT, GL_LINEAR, GL_LINEAR); - - if(texture) { - textures.insert(std::make_pair(name, texture)); - } - - return texture; -} - -} diff --git a/Texture.h b/Texture.h deleted file mode 100644 index fd078f3..0000000 --- a/Texture.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Texture.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_TEXTURE_H_ -#define ZOOM_TEXTURE_H_ - -#include -#include - -namespace Zoom { - -class Texture { - public: - static unsigned loadTexture(const std::string &name); - - private: - Texture(); - - static std::map textures; -}; - -} - -#endif /* ZOOM_TEXTURE_H_ */ diff --git a/Triangle.h b/Triangle.h deleted file mode 100644 index 2b34c3f..0000000 --- a/Triangle.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Triangle.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_TRIANGLE_H_ -#define ZOOM_TRIANGLE_H_ - -#include -#include - -namespace Zoom { - -class Triangle { - public: - Triangle() : color(vmml::vec4f::ONE), texture(0) { - vertices[0] = vertices[1] = vertices[2] = vmml::vec3f::ZERO; - normals[0] = normals[1] = normals[2] = vmml::vec3f::ZERO; - texcoords[0] = texcoords[1] = texcoords[2] = vmml::vec2f::ZERO; - } - - Triangle(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &v3, const vmml::vec4f &color0) : color(color0), texture(0) { - vertices[0] = v1; - vertices[1] = v2; - vertices[2] = v3; - - normals[0] = normals[1] = normals[2] = vmml::vec3f::ZERO; - texcoords[0] = texcoords[1] = texcoords[2] = vmml::vec2f::ZERO; - } - - const vmml::vec3f& getVertex(int i) const {return vertices[i];} - vmml::vec3f& getVertex(int i) {return vertices[i];} - void setVertex(int i, vmml::vec3f v) { - vertices[i] = v; - } - - const vmml::vec3f& getNormal(int i) const {return normals[i];} - vmml::vec3f& getNormal(int i) {return normals[i];} - void setNormal(int i, vmml::vec3f n) { - normals[i] = n; - } - - const vmml::vec2f& getTexCoords(int i) const {return texcoords[i];} - vmml::vec2f& getTexCoords(int i) {return texcoords[i];} - void setTexCoords(int i, vmml::vec2f t) { - texcoords[i] = t; - } - - unsigned getTexture() const { - return texture; - } - void setTexture(unsigned tex) { - texture = tex; - } - - const vmml::vec4f& getColor() const {return color;} - vmml::vec4f& getColor() {return color;} - void setColor(vmml::vec4f c) { - color = c; - } - - vmml::vec3f computeNormal() const { - return vertices[0].compute_normal(vertices[1], vertices[2]); - } - - bool isDegenerate() const { - return (computeNormal().squared_length() == 0); - } - - void transform(const vmml::mat4f &matrix) { - for(int i = 0; i < 3; ++i) { - vertices[i] = matrix*vertices[i]; - } - } - - vmml::vec3f getCenter() const { - return (vertices[0]+vertices[1]+vertices[2])/3; - } - - private: - vmml::vec3f vertices[3]; - vmml::vec3f normals[3]; - vmml::vec2f texcoords[3]; - vmml::vec4f color; - unsigned texture; -}; - -} - -#endif /*ZOOM_TRIANGLE_H_*/ - diff --git a/config.h b/config.h deleted file mode 100644 index 9af944d..0000000 --- a/config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * config.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_CONFIG_H_ -#define ZOOM_CONFIG_H_ - -#define MIN_FRAME_DELTA 10 -#define DEFAULT_WIDTH 800 -#define DEFAULT_HEIGHT 600 - -#endif /* ZOOM_CONFIG_H_ */ diff --git a/gl.h b/gl.h deleted file mode 100644 index 3272b25..0000000 --- a/gl.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * gl.h - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#ifndef ZOOM_GL_H_ -#define ZOOM_GL_H_ - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include -#include -#include - -#endif /* ZOOM_GL_H_ */ diff --git a/src/BSPTree.cpp b/src/BSPTree.cpp new file mode 100644 index 0000000..a94c77a --- /dev/null +++ b/src/BSPTree.cpp @@ -0,0 +1,164 @@ +/* + * BSPTree.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "BSPTree.h" + +namespace Zoom { + +vmml::vec3f BSPTree::Plane::intersection(const vmml::vec3f &p, const vmml::vec3f &dir) const { + float r = (d - p.dot(normal))/dir.dot(normal); + + return p + r*dir; +} + +void BSPTree::Plane::partition(const TriangleRecord &t, std::list *front, std::list *back) const { + for(int i = 0; i < 3; ++i) { + if(contains(t.triangle.getVertex(i))) { + const vmml::vec3f *v[3] = {&t.triangle.getVertex(i), &t.triangle.getVertex((i+1)%3), &t.triangle.getVertex((i+2)%3)}; + + vmml::vec3f is = intersection(*v[1], *v[2]-*v[1]); + + if(isInFront(*v[1])) { + front->push_back(TriangleRecord(Triangle(*v[0], *v[1], is, t.triangle.getColor()), t.data)); + back->push_back(TriangleRecord(Triangle(*v[0], is, *v[2], t.triangle.getColor()), t.data)); + } + else { + back->push_back(TriangleRecord(Triangle(*v[0], *v[1], is, t.triangle.getColor()), t.data)); + front->push_back(TriangleRecord(Triangle(*v[0], is, *v[2], t.triangle.getColor()), t.data)); + } + + return; + } + } + + for(int i = 0; i < 3; ++i) { + const vmml::vec3f *v[3] = {&t.triangle.getVertex(i), &t.triangle.getVertex((i+1)%3), &t.triangle.getVertex((i+2)%3)}; + + if((isInFront(*v[0]) && isBehind(*v[1]) && isBehind(*v[2])) + || (isBehind(*v[0]) && isInFront(*v[1]) && isInFront(*v[2]))) { + vmml::vec3f is1 = intersection(*v[0], *v[1]-*v[0]); + vmml::vec3f is2 = intersection(*v[0], *v[2]-*v[0]); + + if(isInFront(*v[0])) { + front->push_back(TriangleRecord(Triangle(*v[0], is1, is2, t.triangle.getColor()), t.data)); + back->push_back(TriangleRecord(Triangle(is1, *v[1], is2, t.triangle.getColor()), t.data)); + back->push_back(TriangleRecord(Triangle(*v[1], *v[2], is2, t.triangle.getColor()), t.data)); + } + else { + back->push_back(TriangleRecord(Triangle(*v[0], is1, is2, t.triangle.getColor()), t.data)); + front->push_back(TriangleRecord(Triangle(is1, *v[1], is2, t.triangle.getColor()), t.data)); + front->push_back(TriangleRecord(Triangle(*v[1], *v[2], is2, t.triangle.getColor()), t.data)); + } + + return; + } + } +} + + +BSPTree::BSPTree(const std::list &triangles) : frontTree(0), backTree(0) { + const Triangle *planeT = findNearestTriangle(triangles, findCenter(triangles)); + + if(!planeT) + return; + + plane = Plane(*planeT); + + std::list front, back; + + for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { + if(t->triangle.isDegenerate()) + continue; + + if(plane.contains(t->triangle)) { + this->triangles.push_back(*t); + continue; + } + else if(plane.isInFront(t->triangle)) { + front.push_back(*t); + continue; + } + else if(plane.isBehind(t->triangle)) { + back.push_back(*t); + continue; + } + + plane.partition(*t, &front, &back); + } + + if(!front.empty()) + frontTree = new BSPTree(front); + + if(!back.empty()) + backTree = new BSPTree(back); +} + +BSPTree& BSPTree::operator=(const BSPTree &tree) { + if(frontTree) { + delete frontTree; + frontTree = 0; + } + + if(backTree) { + delete backTree; + backTree = 0; + } + + plane = tree.plane; + triangles = tree.triangles; + + if(tree.frontTree) + frontTree = new BSPTree(*tree.frontTree); + + if(tree.backTree) + backTree = new BSPTree(*tree.backTree); + + return *this; +} + +vmml::vec3f BSPTree::findCenter(const std::list &triangles) { + vmml::vec3f v; + + for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { + v += t->triangle.getCenter(); + } + + return v/triangles.size(); +} + +const Triangle* BSPTree::findNearestTriangle(const std::list &triangles, const vmml::vec3f &v) { + const Triangle *current = 0; + float distanceSq; + + for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { + if(t->triangle.isDegenerate()) + continue; + + float d = t->triangle.getCenter().squared_distance(v); + + if(!current || d < distanceSq) { + current = &t->triangle; + distanceSq = d; + } + } + + return current; +} + +} diff --git a/src/BSPTree.h b/src/BSPTree.h new file mode 100644 index 0000000..1944ef1 --- /dev/null +++ b/src/BSPTree.h @@ -0,0 +1,177 @@ +/* + * BSPTree.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_BSPTREE_H_ +#define ZOOM_BSPTREE_H_ + +#include "Triangle.h" +#include +#include + +#include +#include + +namespace Zoom { + +class BSPTree { + public: + class TriangleData { + protected: + TriangleData() {} + + public: + virtual ~TriangleData() {} + }; + + struct TriangleRecord { + public: + TriangleRecord(Triangle triangle0, boost::shared_ptr data0) + : triangle(triangle0), data(data0) {} + TriangleRecord(Triangle triangle0) : triangle(triangle0) {} + TriangleRecord() {} + + Triangle triangle; + boost::shared_ptr data; + }; + + private: + class Plane { + public: + Plane() : d(0) {} + Plane(const vmml::vec3f &n, float d0) : normal(n), d(d0) {} + Plane(const Triangle &t) : normal(t.computeNormal()), d(t.getVertex(0).dot(normal)) {} + + bool contains(const vmml::vec3f &v) const { + return (fabsf(normal.dot(v) - d) < 1E-6); + } + + bool isBehind(const vmml::vec3f &v) const { + return (normal.dot(v) - d) < 0; + } + + bool isInFront(const vmml::vec3f &v) const { + return (normal.dot(v) - d) > 0; + } + + + bool contains(const Triangle &t) const { + for(int i = 0; i < 3; ++i) { + if(!contains(t.getVertex(i))) + return false; + } + + return true; + } + + bool isBehind(const Triangle &t) const { + for(int i = 0; i < 3; ++i) { + if(!isBehind(t.getVertex(i)) && !contains(t.getVertex(i))) + return false; + } + + return true; + } + + bool isInFront(const Triangle &t) const { + for(int i = 0; i < 3; ++i) { + if(!isInFront(t.getVertex(i)) && !contains(t.getVertex(i))) + return false; + } + + return true; + } + + + const vmml::vec3f& getNormal() const { + return normal; + } + + vmml::vec3f intersection(const vmml::vec3f &p, const vmml::vec3f &dir) const; + void partition(const TriangleRecord &t, std::list *front, std::list *back) const; + + private: + vmml::vec3f normal; + float d; + }; + + public: + BSPTree(const std::list &triangles); + + BSPTree(const BSPTree &tree) : frontTree(0), backTree(0) { + *this = tree; + } + + virtual ~BSPTree() { + if(frontTree) + delete frontTree; + + if(backTree) + delete backTree; + } + + BSPTree& operator=(const BSPTree &tree); + + template + void visit(const T& visitor, const vmml::vec3f &p) const { + doVisit(visitor, p); + } + + template + void visit(T& visitor, const vmml::vec3f &p) const { + doVisit(visitor, p); + } + + private: + Plane plane; + std::list triangles; + BSPTree *frontTree, *backTree; + + template + void doVisit(T& visitor, const vmml::vec3f &p) const { + if(plane.isBehind(p)) { + if(frontTree) + frontTree->visit(visitor, p); + + for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { + visitor(*t); + } + + if(backTree) + backTree->visit(visitor, p); + } + else { + if(backTree) + backTree->visit(visitor, p); + + for(std::list::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { + visitor(*t); + } + + if(frontTree) + frontTree->visit(visitor, p); + } + } + + static vmml::vec3f findCenter(const std::list &triangles); + static const Triangle* findNearestTriangle(const std::list &triangles, const vmml::vec3f &v); +}; + +} + +#endif /* ZOOM_BSPTREE_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..e1c9378 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,13 @@ +add_executable(zoom + BSPTree.cpp BSPTree.h + Game.cpp Game.h + config.h + gl.h + Level.cpp Level.h + Renderer.cpp Renderer.h + Shader.cpp Shader.h + Texture.cpp Texture.h + Triangle.h + zoom.cpp +) +target_link_libraries(zoom ${Boost_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARY} ${GLPNG_LIBRARY} ${LIBXML2_LIBRARIES}) diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 0000000..c738080 --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,129 @@ +/* + * Game.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Game.h" +#include "BSPTree.h" +#include "Level.h" +#include "Shader.h" +#include "Triangle.h" +#include "gl.h" +#include + +namespace Zoom { + +Game::Game(bool multisample) : angle(0), lightPos(0) { + glClearColor(0.0, 0.0, 0.0, 1.0); + glClearDepth(1.0); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +#ifndef _WIN32 + if(multisample) + glEnable(GL_MULTISAMPLE_ARB); +#endif + + glShadeModel(GL_SMOOTH); + + glEnable(GL_LIGHTING); + glLightfv(GL_LIGHT0, GL_AMBIENT, vmml::vec4f::ZERO.array); + glLightfv(GL_LIGHT0, GL_DIFFUSE, vmml::vec4f::ONE.array); + glLightfv(GL_LIGHT0, GL_SPECULAR, vmml::vec4f::ONE.array); + glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0); + glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.3); + glEnable(GL_LIGHT0); + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vmml::vec4f::ONE.array); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 128); + + glEnable(GL_CULL_FACE); + glFrontFace(GL_CCW); + + Shader::loadProgram("default.vert", "default.frag"); + + loadLevel("level.xml"); + triangles.insert(triangles.end(), level->getRooms().front().walls.begin(), level->getRooms().front().walls.end()); + std::sort(triangles.begin(), triangles.end(), Renderer::TextureSorter()); +} + +bool Game::loadLevel(const std::string &name) { + level = Level::loadLevel(name); + + return level; +} + +void Game::run(int delta) { + angle += delta*0.01; + + if(angle >= 360) + angle -= 360; + + lightPos += delta; + lightPos %= 24000; +} + +void Game::render() { + int i; + float light[] = {0, 0, 0, 1}; + + if(lightPos < 12000) i = lightPos; + else i = 24000 - lightPos; + + if(i < 4000) { + light[0] = 0.0; + light[2] = -i * 0.001; + } + else if(i < 8000) { + light[0] = (i-4000) * 0.001; + light[2] = -4.0; + } + else if(i < 12000) { + light[0] = 4.0; + light[2] = -4.0 - (i-8000) * 0.001; + } + else { + light[0] = 4.0; + light[2] = -8.0; + } + + /*std::vector triangles(level->getRooms().front().walls.begin(), + level->getRooms().front().walls.end()); + std::sort(triangles.begin(), triangles.end(), Renderer::TextureSorter());*/ + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(15, 1, 2, 1); + /*glRotatef(5*angle, 0, -1, 2); + glRotatef(7*angle, 2, -1, 0); + glRotatef(11*angle, 2, -1, 2);*/ + + glLightfv(GL_LIGHT0, GL_POSITION, light); + //renderer.render(std::list(triangles.begin(), triangles.end())); + renderer.render(triangles); + + glPopMatrix(); +} + +} diff --git a/src/Game.h b/src/Game.h new file mode 100644 index 0000000..0fe7233 --- /dev/null +++ b/src/Game.h @@ -0,0 +1,53 @@ +/* + * Game.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_GAME_H_ +#define ZOOM_GAME_H_ + +#include "Renderer.h" +#include +#include + +namespace Zoom { + +class Level; +class Triangle; + +class Game { + public: + Game(bool multisample); + + bool loadLevel(const std::string &name); + + void run(int delta); + void render(); + + private: + Renderer renderer; + + boost::shared_ptr level; + std::vector triangles; + + float angle; + int lightPos; +}; + +} + +#endif /* ZOOM_GAME_H_ */ diff --git a/src/Level.cpp b/src/Level.cpp new file mode 100644 index 0000000..2867ab9 --- /dev/null +++ b/src/Level.cpp @@ -0,0 +1,260 @@ +/* + * Level.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Level.h" +#include "Texture.h" +#include +#include + +#include + +namespace Zoom { + +boost::shared_ptr Level::loadLevel(const std::string &filename) { + boost::shared_ptr level; + + xmlDocPtr doc = xmlParseFile(("levels/"+filename).c_str()); + + if(doc) { + if(validateLevel(doc)) { + xmlNodePtr root = xmlDocGetRootElement(doc); + if(root && !xmlStrcmp(root->name, (xmlChar*)"level")) { + level = boost::shared_ptr(new Level); + + for(xmlNodePtr node = root->children; node != 0; node = node->next) { + if(node->type != XML_ELEMENT_NODE) + continue; + + if(!xmlStrcmp(node->name, (xmlChar*)"info")) { + level->loadLevelInfo(node); + } + else if(!xmlStrcmp(node->name, (xmlChar*)"rooms")) { + level->loadRooms(node); + } + else if(!xmlStrcmp(node->name, (xmlChar*)"textures")) { + level->loadTextures(node); + } + } + + for(std::list::iterator room = level->rooms.begin(); room != level->rooms.end(); ++room) { + for(std::list::iterator wall = room->walls.begin(); wall != room->walls.end(); ++wall) { + boost::shared_ptr wallData = boost::dynamic_pointer_cast(wall->data); + + if(!wallData->texture.empty()) { + std::map::iterator texture = level->textures.find(wallData->texture); + + if(texture != level->textures.end()) + wall->triangle.setTexture(texture->second); + } + } + } + } + } + + xmlFreeDoc(doc); + } + + xmlCleanupParser(); + + return level; +} + +void Level::loadLevelInfo(xmlNodePtr infoNode) { + for(xmlNodePtr node = infoNode->children; node != 0; node = node->next) { + if(node->type != XML_ELEMENT_NODE) + continue; + + if(!xmlStrcmp(node->name, (xmlChar*)"name")) { + xmlChar *data = xmlNodeGetContent(node); + name = (char*)data; + xmlFree(data); + } + else if(!xmlStrcmp(node->name, (xmlChar*)"desc")) { + xmlChar *data = xmlNodeGetContent(node); + description = (char*)data; + xmlFree(data); + } + else if(!xmlStrcmp(node->name, (xmlChar*)"start")) { + startPoint = loadVector(node); + } + } +} + +void Level::loadRooms(xmlNodePtr roomsNode) { + for(xmlNodePtr node = roomsNode->children; node != 0; node = node->next) { + if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"room")) { + loadRoom(node); + } + } +} + +void Level::loadRoom(xmlNodePtr roomNode) { + rooms.push_back(Room()); + + xmlChar *data = xmlGetProp(roomNode, (xmlChar*)"id"); + if(data) { + rooms.back().id = (char*)data; + + xmlFree(data); + } + + for(xmlNodePtr node = roomNode->children; node != 0; node = node->next) { + if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"triangle")) { + rooms.back().walls.push_back(loadWall(node)); + } + } +} + +void Level::loadTextures(xmlNodePtr texturesNode) { + for(xmlNodePtr node = texturesNode->children; node != 0; node = node->next) { + if(node->type == XML_ELEMENT_NODE && !xmlStrcmp(node->name, (xmlChar*)"texture")) { + std::string id, name; + + xmlChar *data = xmlGetProp(node, (xmlChar*)"id"); + if(data) { + id = (char*)data; + xmlFree(data); + } + + data = xmlGetProp(node, (xmlChar*)"name"); + if(data) { + name = (char*)data; + xmlFree(data); + } + + if(!id.empty() && !name.empty()) { + unsigned texture = Texture::loadTexture(name); + + if(texture) { + textures.insert(std::make_pair(id, texture)); + } + } + } + } +} + +BSPTree::TriangleRecord Level::loadWall(xmlNodePtr wallNode) { + boost::shared_ptr wallData(new WallData); + + BSPTree::TriangleRecord wall; + wall.data = wallData; + + + xmlChar *data = xmlGetProp(wallNode, (xmlChar*)"texture"); + if(data) { + wallData->texture = (char*)data; + xmlFree(data); + } + + int vertexNum = -1; + + for(xmlNodePtr node = wallNode->children; node != 0; node = node->next) { + if(node->type != XML_ELEMENT_NODE) + continue; + + if(!xmlStrcmp(node->name, (xmlChar*)"vertex")) { + if(++vertexNum > 2) + break; + + wall.triangle.setVertex(vertexNum, loadVector(node)); + } + else if(!xmlStrcmp(node->name, (xmlChar*)"normal")) { + if(vertexNum < 0) + continue; + + wall.triangle.setNormal(vertexNum, loadVector(node)); + } + else if(!xmlStrcmp(node->name, (xmlChar*)"texcoords")) { + if(vertexNum < 0) continue; + + data = xmlGetProp(node, (xmlChar*)"s"); + if(data) { + wall.triangle.getTexCoords(vertexNum)[0] = atof((char*)data); + xmlFree(data); + } + + data = xmlGetProp(node, (xmlChar*)"t"); + if(data) { + wall.triangle.getTexCoords(vertexNum)[1] = atof((char*)data); + xmlFree(data); + } + } + } + + vmml::vec3f normal = wall.triangle.computeNormal(); + + if(normal.squared_length() > 0) { + normal.normalize(); + + for(int i = 0; i < 3; ++i) { + if(wall.triangle.getNormal(i).squared_length() == 0) + wall.triangle.setNormal(i, normal); + } + } + + + return wall; +} + +vmml::vec3f Level::loadVector(xmlNodePtr node) { + vmml::vec3f ret(vmml::vec3f::ZERO); + + xmlChar *data = xmlGetProp(node, (xmlChar*)"x"); + if(data) { + ret.x() = atof((char*)data); + xmlFree(data); + } + + data = xmlGetProp(node, (xmlChar*)"y"); + if(data) { + ret.y() = atof((char*)data); + xmlFree(data); + } + + data = xmlGetProp(node, (xmlChar*)"z"); + if(data) { + ret.z() = atof((char*)data); + xmlFree(data); + } + + return ret; +} + +bool Level::validateLevel(xmlDocPtr doc) { + bool ret = false; + + xmlDtdPtr dtd = xmlParseDTD((xmlChar*)"-//libzoom//DTD level 0.1//EN", (xmlChar*)"levels/level.dtd"); + + if(dtd) { + xmlValidCtxtPtr validCtxt = xmlNewValidCtxt(); + + if(validCtxt) { + if(xmlValidateDtd(validCtxt, doc, dtd)) + ret = true; + + xmlFreeValidCtxt(validCtxt); + } + + xmlFreeDtd(dtd); + } + + return ret; +} + +} diff --git a/src/Level.h b/src/Level.h new file mode 100644 index 0000000..277b6e7 --- /dev/null +++ b/src/Level.h @@ -0,0 +1,74 @@ +/* + * Level.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_LEVEL_H_ +#define ZOOM_LEVEL_H_ + +#include "BSPTree.h" + +#include +#include +#include + +#include +#include +#include + +namespace Zoom { + +class Level { + public: + static boost::shared_ptr loadLevel(const std::string &filename); + + struct WallData : public BSPTree::TriangleData { + std::string texture; + }; + + struct Room { + std::string id; + std::list walls; + }; + + const std::list &getRooms() const { + return rooms; + } + + private: + std::list rooms; + std::map textures; + + std::string name, description; + vmml::vec3f startPoint; + + Level() {} + + void loadLevelInfo(xmlNodePtr infoNode); + void loadRooms(xmlNodePtr roomsNode); + void loadRoom(xmlNodePtr roomNode); + void loadTextures(xmlNodePtr texturesNode); + + static BSPTree::TriangleRecord loadWall(xmlNodePtr wallNode); + static vmml::vec3f loadVector(xmlNodePtr node); + + static bool validateLevel(xmlDocPtr doc); +}; + +} + +#endif /* ZOOM_LEVEL_H_ */ diff --git a/src/Renderer.cpp b/src/Renderer.cpp new file mode 100644 index 0000000..ad4849b --- /dev/null +++ b/src/Renderer.cpp @@ -0,0 +1,69 @@ +/* + * Renderer.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Renderer.h" + +namespace Zoom { + +void Renderer::render(const BSPTree &tree) { + vmml::mat4f transform, inverseTransform; + glGetFloatv(GL_MODELVIEW_MATRIX, transform.array); + + transform.inverse(inverseTransform); + + vmml::vec3f viewPoint = inverseTransform*vmml::vec3f::ZERO; + + glBegin(GL_TRIANGLES); + tree.visit(renderVisitor, viewPoint); + glEnd(); + +} + +void Renderer::renderTriangle(const Triangle &t) { + glColor4fv(t.getColor().array); + + if(t.getTexture() != activeTexture) { + glEnd(); + useTexture(t.getTexture()); + glBegin(GL_TRIANGLES); + } + + for(int i = 0; i < 3; ++i) { + glTexCoord2fv(t.getTexCoords(i).array); + glNormal3fv(t.getNormal(i).array); + glVertex3fv(t.getVertex(i).array); + } +} + +void Renderer::useTexture(unsigned texture) { + if(texture) { + glBindTexture(GL_TEXTURE_2D, texture); + + if(activeTexture) { + glEnable(GL_TEXTURE_2D); + } + } + else { + glDisable(GL_TEXTURE_2D); + } + + activeTexture = texture; +} + +} diff --git a/src/Renderer.h b/src/Renderer.h new file mode 100644 index 0000000..fb98e38 --- /dev/null +++ b/src/Renderer.h @@ -0,0 +1,78 @@ +/* + * Renderer.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_RENDERER_H_ +#define ZOOM_RENDERER_H_ + +#include "BSPTree.h" +#include "gl.h" + +namespace Zoom { + +class Renderer { + public: + Renderer() : activeTexture(0), renderVisitor(this) {} + + void render(const BSPTree &tree); + + template + void render(const T &triangles) { + typename T::const_iterator t = triangles.begin(); + if(t == triangles.end()) + return; + + useTexture(t->triangle.getTexture()); + + glBegin(GL_TRIANGLES); + for(; t != triangles.end(); ++t) { + renderTriangle(t->triangle); + } + glEnd(); + } + + struct TextureSorter { + bool operator() (const BSPTree::TriangleRecord &t1, const BSPTree::TriangleRecord &t2) { + return (t1.triangle.getTexture() < t2.triangle.getTexture()); + } + }; + + private: + void renderTriangle(const Triangle &t); + void useTexture(unsigned texture); + + class RenderVisitor { + public: + RenderVisitor(Renderer *renderer0) : renderer(renderer0) {} + + void operator() (const BSPTree::TriangleRecord &t) const { + renderer->renderTriangle(t.triangle); + } + + private: + Renderer *renderer; + }; + + unsigned activeTexture; + + const RenderVisitor renderVisitor; +}; + +} + +#endif /* ZOOM_RENDERER_H_ */ diff --git a/src/Shader.cpp b/src/Shader.cpp new file mode 100644 index 0000000..420b6c6 --- /dev/null +++ b/src/Shader.cpp @@ -0,0 +1,95 @@ +/* + * Shader.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Shader.h" +#include +#include +#include +#include + +namespace Zoom { + +bool Shader::loadProgram(const std::string &vertexShader, const std::string &fragmentShader) { + GLhandleARB program, vs = 0, fs = 0; + + if(!vertexShader.empty()) + vs = loadShader(vertexShader, GL_VERTEX_SHADER_ARB); + + if(!fragmentShader.empty()) + fs = loadShader(fragmentShader, GL_FRAGMENT_SHADER_ARB); + + program = glCreateProgramObjectARB(); + + if(vs) + glAttachObjectARB(program, vs); + + if(fs) + glAttachObjectARB(program, fs); + + glLinkProgramARB(program); + printInfoLog(program); + + glUseProgramObjectARB(program); + + return true; +} + +GLhandleARB Shader::loadShader(const std::string &name, GLenum type) { + std::vector lines; + std::ifstream file(("shader/" + name).c_str(), std::ios_base::in); + if(!file.good()) + throw std::ios::failure("Can't read file '" + name + "'"); + + while(file.good() && !file.eof()) { + std::string line; + std::getline(file, line); + + if(!line.empty()) + lines.push_back(line); + } + + boost::scoped_array strings(new const char*[lines.size()]); + for(std::size_t i = 0; i < lines.size(); ++i) { + strings[i] = lines[i].c_str(); + } + + GLhandleARB shader = glCreateShaderObjectARB(type); + glShaderSourceARB(shader, lines.size(), strings.get(), 0); + glCompileShaderARB(shader); + printInfoLog(shader); + + return shader; +} + +void Shader::printInfoLog(GLhandleARB obj) { + int length = 0; + + glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + + if(length > 0) { + boost::scoped_array log(new char[length]); + + int foo; + glGetInfoLogARB(obj, length, &foo, log.get()); + std::cerr << log.get() << std::endl; + } +} + + +} diff --git a/src/Shader.h b/src/Shader.h new file mode 100644 index 0000000..8111f0c --- /dev/null +++ b/src/Shader.h @@ -0,0 +1,41 @@ +/* + * Shader.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_SHADER_H_ +#define ZOOM_SHADER_H_ + +#include "gl.h" +#include + +namespace Zoom { + +class Shader { + public: + static bool loadProgram(const std::string &vertexShader, const std::string &fragmentShader); + + private: + Shader(); + + static GLhandleARB loadShader(const std::string &name, GLenum type); + static void printInfoLog(GLhandleARB obj); +}; + +} + +#endif /* ZOOM_SHADER_H_ */ diff --git a/src/Texture.cpp b/src/Texture.cpp new file mode 100644 index 0000000..d5ec1f2 --- /dev/null +++ b/src/Texture.cpp @@ -0,0 +1,44 @@ +/* + * Texture.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Texture.h" +#include "gl.h" +#include + +namespace Zoom { + +std::map Texture::textures; + +unsigned Texture::loadTexture(const std::string &name) { + std::map::iterator it = textures.find(name); + + if(it != textures.end()) + return it->second; + + pngInfo info; + unsigned texture = pngBind(("tex/" + name).c_str(), PNG_NOMIPMAP, PNG_ALPHA, &info, GL_REPEAT, GL_LINEAR, GL_LINEAR); + + if(texture) { + textures.insert(std::make_pair(name, texture)); + } + + return texture; +} + +} diff --git a/src/Texture.h b/src/Texture.h new file mode 100644 index 0000000..fd078f3 --- /dev/null +++ b/src/Texture.h @@ -0,0 +1,40 @@ +/* + * Texture.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_TEXTURE_H_ +#define ZOOM_TEXTURE_H_ + +#include +#include + +namespace Zoom { + +class Texture { + public: + static unsigned loadTexture(const std::string &name); + + private: + Texture(); + + static std::map textures; +}; + +} + +#endif /* ZOOM_TEXTURE_H_ */ diff --git a/src/Triangle.h b/src/Triangle.h new file mode 100644 index 0000000..2b34c3f --- /dev/null +++ b/src/Triangle.h @@ -0,0 +1,105 @@ +/* + * Triangle.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_TRIANGLE_H_ +#define ZOOM_TRIANGLE_H_ + +#include +#include + +namespace Zoom { + +class Triangle { + public: + Triangle() : color(vmml::vec4f::ONE), texture(0) { + vertices[0] = vertices[1] = vertices[2] = vmml::vec3f::ZERO; + normals[0] = normals[1] = normals[2] = vmml::vec3f::ZERO; + texcoords[0] = texcoords[1] = texcoords[2] = vmml::vec2f::ZERO; + } + + Triangle(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &v3, const vmml::vec4f &color0) : color(color0), texture(0) { + vertices[0] = v1; + vertices[1] = v2; + vertices[2] = v3; + + normals[0] = normals[1] = normals[2] = vmml::vec3f::ZERO; + texcoords[0] = texcoords[1] = texcoords[2] = vmml::vec2f::ZERO; + } + + const vmml::vec3f& getVertex(int i) const {return vertices[i];} + vmml::vec3f& getVertex(int i) {return vertices[i];} + void setVertex(int i, vmml::vec3f v) { + vertices[i] = v; + } + + const vmml::vec3f& getNormal(int i) const {return normals[i];} + vmml::vec3f& getNormal(int i) {return normals[i];} + void setNormal(int i, vmml::vec3f n) { + normals[i] = n; + } + + const vmml::vec2f& getTexCoords(int i) const {return texcoords[i];} + vmml::vec2f& getTexCoords(int i) {return texcoords[i];} + void setTexCoords(int i, vmml::vec2f t) { + texcoords[i] = t; + } + + unsigned getTexture() const { + return texture; + } + void setTexture(unsigned tex) { + texture = tex; + } + + const vmml::vec4f& getColor() const {return color;} + vmml::vec4f& getColor() {return color;} + void setColor(vmml::vec4f c) { + color = c; + } + + vmml::vec3f computeNormal() const { + return vertices[0].compute_normal(vertices[1], vertices[2]); + } + + bool isDegenerate() const { + return (computeNormal().squared_length() == 0); + } + + void transform(const vmml::mat4f &matrix) { + for(int i = 0; i < 3; ++i) { + vertices[i] = matrix*vertices[i]; + } + } + + vmml::vec3f getCenter() const { + return (vertices[0]+vertices[1]+vertices[2])/3; + } + + private: + vmml::vec3f vertices[3]; + vmml::vec3f normals[3]; + vmml::vec2f texcoords[3]; + vmml::vec4f color; + unsigned texture; +}; + +} + +#endif /*ZOOM_TRIANGLE_H_*/ + diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..9af944d --- /dev/null +++ b/src/config.h @@ -0,0 +1,27 @@ +/* + * config.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_CONFIG_H_ +#define ZOOM_CONFIG_H_ + +#define MIN_FRAME_DELTA 10 +#define DEFAULT_WIDTH 800 +#define DEFAULT_HEIGHT 600 + +#endif /* ZOOM_CONFIG_H_ */ diff --git a/src/gl.h b/src/gl.h new file mode 100644 index 0000000..3272b25 --- /dev/null +++ b/src/gl.h @@ -0,0 +1,32 @@ +/* + * gl.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef ZOOM_GL_H_ +#define ZOOM_GL_H_ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include +#include +#include + +#endif /* ZOOM_GL_H_ */ diff --git a/src/zoom.cpp b/src/zoom.cpp new file mode 100644 index 0000000..6fab527 --- /dev/null +++ b/src/zoom.cpp @@ -0,0 +1,398 @@ +/* + * zoom.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "Game.h" +#include "config.h" +#include "gl.h" + +#ifdef _WIN32 +#else +#include +#include +#include +#include +#include +#endif + +void resize(int width, int height) +{ + if(height == 0) { + height = 1; + } + + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(50.0f, (GLfloat)width/(GLfloat)height, 0.1, 1000); + + glMatrixMode(GL_MODELVIEW); + + glViewport(0, 0, width, height); +} + + +#ifdef _WIN32 + +bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC); +void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC); +LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC) { + WNDCLASS wc; + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)wndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = 0; + wc.lpszMenuName = 0; + wc.lpszClassName = "3D"; + + if (!RegisterClass(&wc)) { + MessageBox(0, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; // Exit And Return FALSE + } + + DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dwStyle = WS_OVERLAPPEDWINDOW; + + RECT windowRect; + windowRect.left = 0; + windowRect.right = DEFAULT_WIDTH; + windowRect.top = 0; + windowRect.bottom = DEFAULT_HEIGHT; + + AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); + + *hWnd = CreateWindowEx(dwExStyle, "3D" /* Class Name */, "3D" /* Title*/, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, + 0, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, 0, 0, hInstance, 0); + if(!*hWnd) { + MessageBox(0, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; + } + + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 16, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 16, // 16Bit Z-Buffer (Depth Buffer) + 0, // No Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + *hDC=GetDC(*hWnd); + if (!*hDC) { + WGLUninit(*hWnd, 0, 0); + MessageBox(0, "Can't Create A GL Device Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; + } + + GLuint pixelFormat = ChoosePixelFormat(*hDC, &pfd); + if(!pixelFormat) { + WGLUninit(*hWnd, *hDC, 0); + MessageBox(0, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!SetPixelFormat(*hDC, pixelFormat, &pfd)) { + WGLUninit(*hWnd, *hDC, 0); + MessageBox(0, "Can't Set The PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; + } + + *hRC=wglCreateContext(*hDC); + if(!*hRC) { + WGLUninit(*hWnd, *hDC, 0); + MessageBox(0, "Can't Create A GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!wglMakeCurrent(*hDC, *hRC)) { + WGLUninit(*hWnd, *hDC, *hRC); + MessageBox(0, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); + return false; + } + + ShowWindow(*hWnd, SW_SHOW); + SetForegroundWindow(*hWnd); + SetFocus(*hWnd); + + return true; +} + +void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC) { + wglMakeCurrent(0, 0); + + if(hRC) + wglDeleteContext(hRC); + + if(hDC) + ReleaseDC(hWnd, hDC); + + if(hWnd) + DestroyWindow(hWnd); +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + HWND hWnd = 0; + HDC hDC = 0; + HGLRC hRC = 0; + + if(!WGLInit(hInstance, &hWnd, &hDC, &hRC)) { + return 0; + } + + glewInit(); + + resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + + bool running = true; + MSG msg; + + while(running) + { + unsigned long delta = 0; + unsigned long ticks = GetTickCount(); + + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if(msg.message == WM_QUIT) + { + running = false; + break; + } + else // If Not, Deal With Window Messages + { + TranslateMessage(&msg); // Translate The Message + DispatchMessage(&msg); // Dispatch The Message + } + } + + delta = GetTickCount()-ticks; + + if(delta < MIN_FRAME_DELTA) { + Sleep(MIN_FRAME_DELTA - delta); + delta = GetTickCount()-ticks; + } + + ticks += delta; + + static DisplayClass render; + render.renderScene(delta); + SwapBuffers(hDC); + } + + WGLUninit(hWnd, hDC, hRC); + return msg.wParam; +} + +LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_CLOSE: + PostQuitMessage(0); + return 0; + + case WM_SIZE: + resize(LOWORD(lParam), HIWORD(lParam)); + return 0; + + default: + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } +} + +#else + +bool GLXinit(Display *disp, Atom windele, Window *wnd, GLXContext *gc, bool *multisample) { + static const int msAttributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_X_RENDERABLE, True, + GLX_DOUBLEBUFFER, True, + GLX_DEPTH_SIZE, 1, + GLX_SAMPLE_BUFFERS, 1, + GLX_SAMPLES, 4, + None}; + + static const int attributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_X_RENDERABLE, True, + GLX_DOUBLEBUFFER, True, + GLX_DEPTH_SIZE, 1, + None}; + + bool ok = false; + *multisample = true; + + int nElements; + GLXFBConfig *fbConfig = glXChooseFBConfig(disp, DefaultScreen(disp), msAttributeList, &nElements); + if(!fbConfig || !nElements) { + if(fbConfig) { + XFree(fbConfig); + } + + *multisample = false; + fbConfig = glXChooseFBConfig(disp, DefaultScreen(disp), attributeList, &nElements); + } + + if(fbConfig && nElements) { + XVisualInfo *vi = glXGetVisualFromFBConfig(disp, *fbConfig); + + if(vi) { + Colormap cmap = XCreateColormap(disp, RootWindow(disp, vi->screen), vi->visual, AllocNone); + XSetWindowAttributes swa; + swa.colormap = cmap; + swa.border_pixel = 0; + swa.event_mask = StructureNotifyMask/* | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask*/; + + *wnd = XCreateWindow(disp, RootWindow(disp, vi->screen), 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0, vi->depth, InputOutput, + vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); + + XClassHint chint; + chint.res_name = const_cast("3D"); + chint.res_class = const_cast("3d"); + XSetClassHint(disp, *wnd, &chint); + + char *str = const_cast("3D"); + XTextProperty name; + if(XStringListToTextProperty(&str, 1, &name) != 0) + { + XSetWMName(disp, *wnd, &name); + XFree(name.value); + } + + XSetWMProtocols(disp, *wnd, &windele, 1); + + XMapWindow(disp, *wnd); + + *gc = glXCreateContext(disp, vi, NULL, True); + + glXMakeCurrent(disp, *wnd, *gc); + + ok = true; + + XFree(vi); + } + } + + if(fbConfig) + XFree(fbConfig); + + XSync(disp, 0); + + return ok; +} + +int main() { + Display *disp = XOpenDisplay(0); + Atom windele = XInternAtom(disp, "WM_DELETE_WINDOW", False); + Window wnd; + GLXContext gc; + + bool multisample; + if(!GLXinit(disp, windele, &wnd, &gc, &multisample)) + return 1; + + glewInit(); + + resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + + Zoom::Game game(multisample); + + GLint samples; + glGetIntegerv(GL_SAMPLES, &samples); + std::cerr << "Using " << samples << " samples" << std::endl; + + bool running = true; + + unsigned long delta = 0; + unsigned long frames = 0, tocks = 0; + + struct timeval tv; + gettimeofday(&tv, NULL); + unsigned long ticks = tv.tv_usec; + + while(running) { + while(XPending(disp)) { + XEvent event; + XNextEvent(disp, &event); + switch(event.type) { + case ConfigureNotify: + resize(event.xconfigure.width, event.xconfigure.height); + break; + + case ClientMessage: + if(static_cast(event.xclient.data.l[0]) == windele) + running = false; + } + } + + if(!running) break; + + game.run(delta); + + game.render(); + glXSwapBuffers(disp, wnd); + XSync(disp, 0); + + long slept = 0; + gettimeofday(&tv, NULL); + delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000; + + if(delta < MIN_FRAME_DELTA) { + usleep((MIN_FRAME_DELTA-delta)*1000); + slept += (MIN_FRAME_DELTA-delta); + + gettimeofday(&tv, NULL); + delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000; + } + + ticks = (ticks + delta*1000) % 1000000; + + frames++; + tocks += delta*1000; + if(tocks > 1000000) { + std::cerr << frames << " fps; slept a total of " << slept << " ms" << std::endl; + frames = 0; + tocks -= 1000000; + slept = 0; + } + } + + XDestroyWindow(disp, wnd); + glXDestroyContext(disp, gc); + XCloseDisplay(disp); + + return 0; +} + +#endif diff --git a/zoom.cpp b/zoom.cpp deleted file mode 100644 index 6fab527..0000000 --- a/zoom.cpp +++ /dev/null @@ -1,398 +0,0 @@ -/* - * zoom.cpp - * - * Copyright (C) 2009 Matthias Schiffer - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this program. If not, see . - */ - -#include "Game.h" -#include "config.h" -#include "gl.h" - -#ifdef _WIN32 -#else -#include -#include -#include -#include -#include -#endif - -void resize(int width, int height) -{ - if(height == 0) { - height = 1; - } - - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(50.0f, (GLfloat)width/(GLfloat)height, 0.1, 1000); - - glMatrixMode(GL_MODELVIEW); - - glViewport(0, 0, width, height); -} - - -#ifdef _WIN32 - -bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC); -void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC); -LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC) { - WNDCLASS wc; - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)wndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = 0; - wc.lpszMenuName = 0; - wc.lpszClassName = "3D"; - - if (!RegisterClass(&wc)) { - MessageBox(0, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; // Exit And Return FALSE - } - - DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dwStyle = WS_OVERLAPPEDWINDOW; - - RECT windowRect; - windowRect.left = 0; - windowRect.right = DEFAULT_WIDTH; - windowRect.top = 0; - windowRect.bottom = DEFAULT_HEIGHT; - - AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); - - *hWnd = CreateWindowEx(dwExStyle, "3D" /* Class Name */, "3D" /* Title*/, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, - 0, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, 0, 0, hInstance, 0); - if(!*hWnd) { - MessageBox(0, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering - PFD_TYPE_RGBA, // Request An RGBA Format - 16, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 16, // 16Bit Z-Buffer (Depth Buffer) - 0, // No Stencil Buffer - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - *hDC=GetDC(*hWnd); - if (!*hDC) { - WGLUninit(*hWnd, 0, 0); - MessageBox(0, "Can't Create A GL Device Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - GLuint pixelFormat = ChoosePixelFormat(*hDC, &pfd); - if(!pixelFormat) { - WGLUninit(*hWnd, *hDC, 0); - MessageBox(0, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - if(!SetPixelFormat(*hDC, pixelFormat, &pfd)) { - WGLUninit(*hWnd, *hDC, 0); - MessageBox(0, "Can't Set The PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - *hRC=wglCreateContext(*hDC); - if(!*hRC) { - WGLUninit(*hWnd, *hDC, 0); - MessageBox(0, "Can't Create A GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - if(!wglMakeCurrent(*hDC, *hRC)) { - WGLUninit(*hWnd, *hDC, *hRC); - MessageBox(0, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - ShowWindow(*hWnd, SW_SHOW); - SetForegroundWindow(*hWnd); - SetFocus(*hWnd); - - return true; -} - -void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC) { - wglMakeCurrent(0, 0); - - if(hRC) - wglDeleteContext(hRC); - - if(hDC) - ReleaseDC(hWnd, hDC); - - if(hWnd) - DestroyWindow(hWnd); -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - HWND hWnd = 0; - HDC hDC = 0; - HGLRC hRC = 0; - - if(!WGLInit(hInstance, &hWnd, &hDC, &hRC)) { - return 0; - } - - glewInit(); - - resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); - - bool running = true; - MSG msg; - - while(running) - { - unsigned long delta = 0; - unsigned long ticks = GetTickCount(); - - while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if(msg.message == WM_QUIT) - { - running = false; - break; - } - else // If Not, Deal With Window Messages - { - TranslateMessage(&msg); // Translate The Message - DispatchMessage(&msg); // Dispatch The Message - } - } - - delta = GetTickCount()-ticks; - - if(delta < MIN_FRAME_DELTA) { - Sleep(MIN_FRAME_DELTA - delta); - delta = GetTickCount()-ticks; - } - - ticks += delta; - - static DisplayClass render; - render.renderScene(delta); - SwapBuffers(hDC); - } - - WGLUninit(hWnd, hDC, hRC); - return msg.wParam; -} - -LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_CLOSE: - PostQuitMessage(0); - return 0; - - case WM_SIZE: - resize(LOWORD(lParam), HIWORD(lParam)); - return 0; - - default: - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } -} - -#else - -bool GLXinit(Display *disp, Atom windele, Window *wnd, GLXContext *gc, bool *multisample) { - static const int msAttributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_X_RENDERABLE, True, - GLX_DOUBLEBUFFER, True, - GLX_DEPTH_SIZE, 1, - GLX_SAMPLE_BUFFERS, 1, - GLX_SAMPLES, 4, - None}; - - static const int attributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_X_RENDERABLE, True, - GLX_DOUBLEBUFFER, True, - GLX_DEPTH_SIZE, 1, - None}; - - bool ok = false; - *multisample = true; - - int nElements; - GLXFBConfig *fbConfig = glXChooseFBConfig(disp, DefaultScreen(disp), msAttributeList, &nElements); - if(!fbConfig || !nElements) { - if(fbConfig) { - XFree(fbConfig); - } - - *multisample = false; - fbConfig = glXChooseFBConfig(disp, DefaultScreen(disp), attributeList, &nElements); - } - - if(fbConfig && nElements) { - XVisualInfo *vi = glXGetVisualFromFBConfig(disp, *fbConfig); - - if(vi) { - Colormap cmap = XCreateColormap(disp, RootWindow(disp, vi->screen), vi->visual, AllocNone); - XSetWindowAttributes swa; - swa.colormap = cmap; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask/* | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask*/; - - *wnd = XCreateWindow(disp, RootWindow(disp, vi->screen), 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0, vi->depth, InputOutput, - vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); - - XClassHint chint; - chint.res_name = const_cast("3D"); - chint.res_class = const_cast("3d"); - XSetClassHint(disp, *wnd, &chint); - - char *str = const_cast("3D"); - XTextProperty name; - if(XStringListToTextProperty(&str, 1, &name) != 0) - { - XSetWMName(disp, *wnd, &name); - XFree(name.value); - } - - XSetWMProtocols(disp, *wnd, &windele, 1); - - XMapWindow(disp, *wnd); - - *gc = glXCreateContext(disp, vi, NULL, True); - - glXMakeCurrent(disp, *wnd, *gc); - - ok = true; - - XFree(vi); - } - } - - if(fbConfig) - XFree(fbConfig); - - XSync(disp, 0); - - return ok; -} - -int main() { - Display *disp = XOpenDisplay(0); - Atom windele = XInternAtom(disp, "WM_DELETE_WINDOW", False); - Window wnd; - GLXContext gc; - - bool multisample; - if(!GLXinit(disp, windele, &wnd, &gc, &multisample)) - return 1; - - glewInit(); - - resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); - - Zoom::Game game(multisample); - - GLint samples; - glGetIntegerv(GL_SAMPLES, &samples); - std::cerr << "Using " << samples << " samples" << std::endl; - - bool running = true; - - unsigned long delta = 0; - unsigned long frames = 0, tocks = 0; - - struct timeval tv; - gettimeofday(&tv, NULL); - unsigned long ticks = tv.tv_usec; - - while(running) { - while(XPending(disp)) { - XEvent event; - XNextEvent(disp, &event); - switch(event.type) { - case ConfigureNotify: - resize(event.xconfigure.width, event.xconfigure.height); - break; - - case ClientMessage: - if(static_cast(event.xclient.data.l[0]) == windele) - running = false; - } - } - - if(!running) break; - - game.run(delta); - - game.render(); - glXSwapBuffers(disp, wnd); - XSync(disp, 0); - - long slept = 0; - gettimeofday(&tv, NULL); - delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000; - - if(delta < MIN_FRAME_DELTA) { - usleep((MIN_FRAME_DELTA-delta)*1000); - slept += (MIN_FRAME_DELTA-delta); - - gettimeofday(&tv, NULL); - delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000; - } - - ticks = (ticks + delta*1000) % 1000000; - - frames++; - tocks += delta*1000; - if(tocks > 1000000) { - std::cerr << frames << " fps; slept a total of " << slept << " ms" << std::endl; - frames = 0; - tocks -= 1000000; - slept = 0; - } - } - - XDestroyWindow(disp, wnd); - glXDestroyContext(disp, gc); - XCloseDisplay(disp); - - return 0; -} - -#endif -- cgit v1.2.3