Basic infrastructure
This commit is contained in:
commit
da66d49b8a
12 changed files with 1040 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/build
|
||||||
|
|
||||||
|
/.project
|
||||||
|
/.cproject
|
||||||
|
/.settings
|
149
BSPTree.cpp
Normal file
149
BSPTree.cpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#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 Triangle &t, std::list<Triangle> *front, std::list<Triangle> *back) const {
|
||||||
|
for(int i = 0; i < 3; ++i) {
|
||||||
|
if(contains(t.getVertex(i))) {
|
||||||
|
const vmml::vec3f *v[3] = {&t.getVertex(i), &t.getVertex((i+1)%3), &t.getVertex((i+2)%3)};
|
||||||
|
|
||||||
|
vmml::vec3f is = intersection(*v[1], *v[2]-*v[1]);
|
||||||
|
|
||||||
|
if(isInFront(*v[1])) {
|
||||||
|
front->push_back(Triangle(*v[0], *v[1], is, t.getColor()));
|
||||||
|
back->push_back(Triangle(*v[0], is, *v[2], t.getColor()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
back->push_back(Triangle(*v[0], *v[1], is, t.getColor()));
|
||||||
|
front->push_back(Triangle(*v[0], is, *v[2], t.getColor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; ++i) {
|
||||||
|
const vmml::vec3f *v[3] = {&t.getVertex(i), &t.getVertex((i+1)%3), &t.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(Triangle(*v[0], is1, is2, t.getColor()));
|
||||||
|
back->push_back(Triangle(is1, *v[1], is2, t.getColor()));
|
||||||
|
back->push_back(Triangle(*v[1], *v[2], is2, t.getColor()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
back->push_back(Triangle(*v[0], is1, is2, t.getColor()));
|
||||||
|
front->push_back(Triangle(is1, *v[1], is2, t.getColor()));
|
||||||
|
front->push_back(Triangle(*v[1], *v[2], is2, t.getColor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSPTree::BSPTree(const std::list<Triangle> &triangles) : frontTree(0), backTree(0) {
|
||||||
|
const Triangle *planeT = findNearestTriangle(triangles, findCenter(triangles));
|
||||||
|
|
||||||
|
if(!planeT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plane = Plane(*planeT);
|
||||||
|
|
||||||
|
std::list<Triangle> front, back;
|
||||||
|
|
||||||
|
for(std::list<Triangle>::const_iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
||||||
|
if(t->getNormal().squared_length() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(plane.contains(*t)) {
|
||||||
|
this->triangles.push_back(*t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(plane.isInFront(*t)) {
|
||||||
|
front.push_back(*t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(plane.isBehind(*t)) {
|
||||||
|
back.push_back(*t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Triangle> frontPart, backPart;
|
||||||
|
plane.partition(*t, &frontPart, &backPart);
|
||||||
|
front.splice(front.end(), frontPart);
|
||||||
|
back.splice(back.end(), backPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Triangle> &triangles) {
|
||||||
|
vmml::vec3f v;
|
||||||
|
|
||||||
|
for(std::list<Triangle>::const_iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
||||||
|
v += t->getCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return v/triangles.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Triangle* BSPTree::findNearestTriangle(const std::list<Triangle> &triangles, const vmml::vec3f &v) {
|
||||||
|
const Triangle *current = 0;
|
||||||
|
float distanceSq;
|
||||||
|
|
||||||
|
for(std::list<Triangle>::const_iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
||||||
|
if(t->getNormal().squared_length() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float d = t->getCenter().squared_distance(v);
|
||||||
|
|
||||||
|
if(!current || d < distanceSq) {
|
||||||
|
current = &*t;
|
||||||
|
distanceSq = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
172
BSPTree.h
Normal file
172
BSPTree.h
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#ifndef ZOOM_BSPTREE_H_
|
||||||
|
#define ZOOM_BSPTREE_H_
|
||||||
|
|
||||||
|
#include "Triangle.h"
|
||||||
|
#include <list>
|
||||||
|
#include <cmath>
|
||||||
|
#include <vmmlib/vector.hpp>
|
||||||
|
|
||||||
|
namespace Zoom {
|
||||||
|
|
||||||
|
class BSPTree {
|
||||||
|
private:
|
||||||
|
class Plane {
|
||||||
|
public:
|
||||||
|
Plane() : d(0) {}
|
||||||
|
Plane(const vmml::vec3f &n, float d0) : normal(n), d(d0) {}
|
||||||
|
Plane(const Triangle &t) : normal(t.getNormal()), 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 Triangle &t, std::list<Triangle> *front, std::list<Triangle> *back) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vmml::vec3f normal;
|
||||||
|
float d;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
BSPTree(const std::list<Triangle> &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<typename T>
|
||||||
|
void visit(const T& visitor, const vmml::vec3f &p) {
|
||||||
|
doVisit<const T>(visitor, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void visit(T& visitor, const vmml::vec3f &p) {
|
||||||
|
doVisit(visitor, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void visit(const T& visitor, const vmml::vec3f &p) const {
|
||||||
|
doVisit<const T>(visitor, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void visit(T& visitor, const vmml::vec3f &p) const {
|
||||||
|
doVisit(visitor, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Plane plane;
|
||||||
|
std::list<Triangle> triangles;
|
||||||
|
BSPTree *frontTree, *backTree;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void doVisit(T& visitor, const vmml::vec3f &p) {
|
||||||
|
if(plane.isBehind(p)) {
|
||||||
|
if(frontTree)
|
||||||
|
frontTree->visit(visitor, p);
|
||||||
|
|
||||||
|
for(std::list<Triangle>::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<Triangle>::iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
||||||
|
visitor(*t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frontTree)
|
||||||
|
frontTree->visit(visitor, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void doVisit(T& visitor, const vmml::vec3f &p) const {
|
||||||
|
if(plane.isBehind(p)) {
|
||||||
|
if(frontTree)
|
||||||
|
frontTree->visit(visitor, p);
|
||||||
|
|
||||||
|
for(std::list<Triangle>::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<Triangle>::const_iterator t = triangles.begin(); t != triangles.end(); ++t) {
|
||||||
|
visitor(*t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frontTree)
|
||||||
|
frontTree->visit(visitor, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static vmml::vec3f findCenter(const std::list<Triangle> &triangles);
|
||||||
|
static const Triangle* findNearestTriangle(const std::list<Triangle> &triangles, const vmml::vec3f &v);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZOOM_BSPTREE_H_ */
|
18
CMakeLists.txt
Normal file
18
CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
project(ZOOM)
|
||||||
|
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
include_directories(${OPENGL_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_executable(zoom
|
||||||
|
BSPTree.cpp BSPTree.h
|
||||||
|
Game.cpp Game.h
|
||||||
|
config.h
|
||||||
|
gl.h
|
||||||
|
Renderer.cpp Renderer.h
|
||||||
|
Triangle.h
|
||||||
|
zoom.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(zoom ${OPENGL_LIBRARIES})
|
81
Game.cpp
Normal file
81
Game.cpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Game.cpp
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "BSPTree.h"
|
||||||
|
#include "Triangle.h"
|
||||||
|
#include "gl.h"
|
||||||
|
|
||||||
|
namespace Zoom {
|
||||||
|
|
||||||
|
Game::Game(bool multisample) : angle(0) {
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 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
|
||||||
|
|
||||||
|
/*glEnable(GL_LIGHTING);
|
||||||
|
static const float light[] = {1, 1, 1, 0};
|
||||||
|
static const float lightColor[] = {1, 1, 1, 1};
|
||||||
|
glLightfv(GL_LIGHT0, GL_POSITION, light);
|
||||||
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
|
||||||
|
glEnable(GL_LIGHT0);*/
|
||||||
|
|
||||||
|
//glEnable(GL_CULL_FACE);
|
||||||
|
//glFrontFace(GL_CCW);
|
||||||
|
|
||||||
|
glLoadIdentity();
|
||||||
|
glTranslatef(0, 0, -5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::run(int delta) {
|
||||||
|
angle += delta*0.2;
|
||||||
|
|
||||||
|
if(angle >= 360)
|
||||||
|
angle -= 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::render() {
|
||||||
|
std::list<Triangle> triangles;
|
||||||
|
|
||||||
|
triangles.push_back(Triangle(vmml::vec3f(-1, -1, 0), vmml::vec3f(1, -1, 0), vmml::vec3f(1, 1, 0), vmml::vec3f(0, 1, 0)));
|
||||||
|
triangles.push_back(Triangle(vmml::vec3f(-1, -1, 0), vmml::vec3f(-1, 1, 0), vmml::vec3f(1, 1, 0), vmml::vec3f(0, 1, 0)));
|
||||||
|
triangles.push_back(Triangle(vmml::vec3f(-1, -1, -1), vmml::vec3f(1, -1, -1), vmml::vec3f(1, 1, -1), vmml::vec3f(0, 0, 1)));
|
||||||
|
triangles.push_back(Triangle(vmml::vec3f(-1, -1, -1), vmml::vec3f(-1, 1, -1), vmml::vec3f(1, 1, -1), vmml::vec3f(0, 0, 1)));
|
||||||
|
|
||||||
|
BSPTree tree(triangles);
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glRotatef(angle, 1, 2, 1);
|
||||||
|
|
||||||
|
renderer.render(tree);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
Game.h
Normal file
44
Game.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Game.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZOOM_GAME_H_
|
||||||
|
#define ZOOM_GAME_H_
|
||||||
|
|
||||||
|
#include "Renderer.h"
|
||||||
|
|
||||||
|
namespace Zoom {
|
||||||
|
|
||||||
|
class Triangle;
|
||||||
|
|
||||||
|
class Game {
|
||||||
|
public:
|
||||||
|
Game(bool multisample);
|
||||||
|
|
||||||
|
void run(int delta);
|
||||||
|
void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Renderer renderer;
|
||||||
|
|
||||||
|
float angle;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZOOM_GAME_H_ */
|
53
Renderer.cpp
Normal file
53
Renderer.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Renderer.cpp
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "BSPTree.h"
|
||||||
|
|
||||||
|
namespace Zoom {
|
||||||
|
|
||||||
|
const Renderer::RenderVisitor Renderer::renderVisitor = Renderer::RenderVisitor();
|
||||||
|
|
||||||
|
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);
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, t.getColor().array);
|
||||||
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (t.getColor()/2).array);
|
||||||
|
|
||||||
|
glNormal3fv(t.getNormal().array);
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; ++i) {
|
||||||
|
glVertex3fv(t.getVertex(i).array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
46
Renderer.h
Normal file
46
Renderer.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Renderer.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZOOM_RENDERER_H_
|
||||||
|
#define ZOOM_RENDERER_H_
|
||||||
|
|
||||||
|
namespace Zoom {
|
||||||
|
|
||||||
|
class Triangle;
|
||||||
|
class BSPTree;
|
||||||
|
|
||||||
|
class Renderer {
|
||||||
|
public:
|
||||||
|
void render(const BSPTree &tree);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void renderTriangle(const Triangle &t);
|
||||||
|
|
||||||
|
struct RenderVisitor {
|
||||||
|
void operator() (const Triangle &t) const {
|
||||||
|
renderTriangle(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const RenderVisitor renderVisitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZOOM_RENDERER_H_ */
|
47
Triangle.h
Normal file
47
Triangle.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef ZOOM_TRIANGLE_H_
|
||||||
|
#define ZOOM_TRIANGLE_H_
|
||||||
|
|
||||||
|
#include "gl.h"
|
||||||
|
#include <vmmlib/vector.hpp>
|
||||||
|
#include <vmmlib/matrix.hpp>
|
||||||
|
|
||||||
|
namespace Zoom {
|
||||||
|
|
||||||
|
class Triangle {
|
||||||
|
public:
|
||||||
|
Triangle() : c(vmml::vec4f::ONE) {
|
||||||
|
v[0] = v[1] = v[2] = vmml::vec3f::ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
Triangle(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &v3, const vmml::vec4f &c0) : c(c0) {
|
||||||
|
v[0] = v1;
|
||||||
|
v[1] = v2;
|
||||||
|
v[2] = v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vmml::vec3f& getVertex(int i) const {return v[i];}
|
||||||
|
const vmml::vec4f& getColor() const {return c;}
|
||||||
|
|
||||||
|
vmml::vec3f getNormal() const {
|
||||||
|
return v[0].compute_normal(v[1], v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void transform(const vmml::mat4f &m) {
|
||||||
|
for(int i = 0; i < 3; ++i) {
|
||||||
|
v[i] = m*v[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vmml::vec3f getCenter() const {
|
||||||
|
return (v[0]+v[1]+v[2])/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
vmml::vec3f v[3];
|
||||||
|
vmml::vec4f c;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*ZOOM_TRIANGLE_H_*/
|
||||||
|
|
27
config.h
Normal file
27
config.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* config.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZOOM_CONFIG_H_
|
||||||
|
#define ZOOM_CONFIG_H_
|
||||||
|
|
||||||
|
#define MIN_FRAME_DELTA 16
|
||||||
|
#define DEFAULT_WIDTH 800
|
||||||
|
#define DEFAULT_HEIGHT 600
|
||||||
|
|
||||||
|
#endif /* ZOOM_CONFIG_H_ */
|
12
gl.h
Normal file
12
gl.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef _GL_H_
|
||||||
|
#define _GL_H_
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
|
|
||||||
|
#endif /* _GL_H_ */
|
386
zoom.cpp
Normal file
386
zoom.cpp
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
#include "Game.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "gl.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#else
|
||||||
|
#include <iostream>
|
||||||
|
#include <X11/X.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<char*>("3D");
|
||||||
|
chint.res_class = const_cast<char*>("3d");
|
||||||
|
XSetClassHint(disp, *wnd, &chint);
|
||||||
|
|
||||||
|
char *str = const_cast<char*>("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;
|
||||||
|
|
||||||
|
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<Atom>(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
|
Reference in a new issue