summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct1
m---------common0
-rw-r--r--game.cpp22
-rw-r--r--game.h1
-rw-r--r--model.cpp104
-rw-r--r--model.h50
-rw-r--r--models/README3
-rw-r--r--models/trees.blendbin0 -> 3827560 bytes
-rw-r--r--scene.cpp89
-rw-r--r--scene.h13
-rw-r--r--shaders/fog_fragment.glsl9
-rw-r--r--shaders/terrain_fragment.glsl7
-rw-r--r--shaders/tree_fragment.glsl22
-rw-r--r--shaders/tree_vertex.glsl14
-rw-r--r--terrain.h5
15 files changed, 337 insertions, 3 deletions
diff --git a/SConstruct b/SConstruct
index 05a7038..eabcf02 100644
--- a/SConstruct
+++ b/SConstruct
@@ -26,6 +26,7 @@ else:
env.ParseConfig('pkg-config --cflags --libs ftgl')
env.ParseConfig('pkg-config --cflags --libs CEGUI')
env.ParseConfig('pkg-config --cflags --libs CEGUI-OPENGL')
+ env.ParseConfig('pkg-config --cflags --libs assimp')
if not GetOption('release'):
env.Append(CPPFLAGS = ['-Wall', '-g'])
diff --git a/common b/common
-Subproject ff7f9de199213ea6d4832c0b91f2a96f5edc6bb
+Subproject 6e746716d6a5c72fbd42539c6d5d92da8830cb9
diff --git a/game.cpp b/game.cpp
index e24bacf..1288b0c 100644
--- a/game.cpp
+++ b/game.cpp
@@ -88,6 +88,9 @@ void Game::handle_type(const boost::system::error_code& error, std::size_t bytes
case message::MSG_TYPE_PLAYER:
handle_player();
break;
+ case message::MSG_TYPE_OBJECT:
+ handle_object();
+ break;
default:
std::cout << "unknown type: " << (int)*type << std::endl;
}
@@ -154,6 +157,25 @@ void Game::handle_player() {
scene->players.push_back(Player::p(new Player(id, pos, name)));
}
+void Game::handle_object() {
+ message::Object m;
+
+ m.recv(socket);
+
+ // type is ignored for now
+ uint32_t type = m.get_type();
+ Vector3 pos(m.get_pos());
+
+ Terrain::Chunk *chunk = scene->terrain->find_chunk(pos.x, pos.z);
+ if(!chunk) {
+ std::cerr << "got object for non-existing chunk, discarding" << std::endl;
+ return;
+ }
+
+ pos.y = chunk->find(pos.x, pos.z)->get_height(pos.x, pos.z);
+ chunk->objects.push_back(Terrain::Chunk::ObjectPair(scene->tree, pos));
+}
+
Game& Game::get_instance() {
if(!game)
game = new Game();
diff --git a/game.h b/game.h
index 6c58565..76c9413 100644
--- a/game.h
+++ b/game.h
@@ -30,6 +30,7 @@ class Game {
void handle_chunk();
void handle_message();
void handle_player();
+ void handle_object();
static Game& get_instance();
};
diff --git a/model.cpp b/model.cpp
new file mode 100644
index 0000000..67e4561
--- /dev/null
+++ b/model.cpp
@@ -0,0 +1,104 @@
+#include "model.h"
+
+#include <iostream>
+#include <stdexcept>
+
+namespace models {
+
+Mesh::Mesh(const aiScene *scene, const aiMesh *mesh, std::map<std::string, GLuint>& scene_textures) {
+ aiMaterial *mat = scene->mMaterials[mesh->mMaterialIndex];
+ unsigned int texture_count = mat->GetTextureCount(aiTextureType_DIFFUSE);
+ for(unsigned int j = 0; j < texture_count; j++) {
+ aiString ai_path;
+ if(mat->GetTexture(aiTextureType_DIFFUSE, j, &ai_path) == AI_SUCCESS) {
+ std::string path(ai_path.data, ai_path.length);
+ GLuint tex = scene_textures[path];
+ textures.push_back(tex);
+ }
+ }
+
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+ vertices = 0;
+
+ for(unsigned int i = 0; i < mesh->mNumFaces; i++)
+ vertices += mesh->mFaces[i].mNumIndices;
+
+ glBufferData(GL_ARRAY_BUFFER, vertices*3*2*3 * sizeof(float), NULL, GL_STATIC_DRAW);
+
+ float *buffer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+ unsigned int index = 0;
+
+ for(unsigned int i = 0; i < mesh->mNumFaces; i++) {
+ aiFace *face = &mesh->mFaces[i];
+
+ for(unsigned int j = 0; j < face->mNumIndices; j++) {
+ aiVector3D *texcoord = &mesh->mTextureCoords[0][face->mIndices[j]];
+ aiVector3D *vertex = &mesh->mVertices[face->mIndices[j]];
+ aiVector3D *normal = &mesh->mNormals[face->mIndices[j]];
+
+ buffer[index++] = vertex->x;
+ buffer[index++] = vertex->y;
+ buffer[index++] = vertex->z;
+
+ buffer[index++] = texcoord->x;
+ buffer[index++] = 2 - texcoord->y;
+
+ buffer[index++] = normal->x;
+ buffer[index++] = normal->y;
+ buffer[index++] = normal->z;
+ }
+ }
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+}
+
+Mesh::~Mesh() {
+ glDeleteBuffers(1, &vbo);
+}
+
+void Mesh::render() {
+ GLenum tex_i = GL_TEXTURE0;
+ for(std::vector<GLuint>::iterator it = textures.begin(); it != textures.end(); it++) {
+ glActiveTexture(tex_i++);
+ glBindTexture(GL_TEXTURE_2D, *it);
+ }
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ glVertexPointer(3, GL_FLOAT, 8*sizeof(float), NULL);
+ glTexCoordPointer(2, GL_FLOAT, 8*sizeof(float), (const GLvoid*)(sizeof(float)*3));
+ glNormalPointer(GL_FLOAT, 8*sizeof(float), (const GLvoid*)(sizeof(float)*5));
+ glDrawArrays(GL_TRIANGLES, 0, vertices);
+
+ glPopClientAttrib();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+Tree::Tree(const aiScene *scene, std::map<std::string, GLuint>& scene_textures) {
+ trunk = new Mesh(scene, scene->mMeshes[22], scene_textures);
+ leaves = new Mesh(scene, scene->mMeshes[3], scene_textures);
+}
+
+Tree::~Tree() {
+ delete trunk;
+ delete leaves;
+}
+
+void Tree::render() {
+ trunk->render();
+ glTranslatef(0.786, 2.845, 5.1);
+ leaves->render();
+}
+
+} // namespace models
diff --git a/model.h b/model.h
new file mode 100644
index 0000000..7659d9c
--- /dev/null
+++ b/model.h
@@ -0,0 +1,50 @@
+#ifndef MODEL_H
+#define MODEL_H
+
+#include "gl.h"
+
+#include <assimp/assimp.hpp>
+#include <assimp/aiScene.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace models {
+
+class Mesh {
+ private:
+ GLuint vbo;
+ GLuint vertices;
+
+ public:
+ Mesh(const aiScene *scene, const aiMesh *mesh, std::map<std::string, GLuint>& scene_textures);
+ virtual ~Mesh();
+
+ void render();
+
+ std::vector<GLuint> textures;
+};
+
+class Model {
+ public:
+ virtual ~Model() {};
+
+ virtual void render() = 0;
+};
+
+class Tree : public Model {
+ private:
+ Mesh *trunk;
+ Mesh *leaves;
+
+ public:
+ Tree(const aiScene *scene, std::map<std::string, GLuint>& scene_textures);
+ virtual ~Tree();
+
+ virtual void render();
+};
+
+}
+
+#endif
diff --git a/models/README b/models/README
new file mode 100644
index 0000000..5d31225
--- /dev/null
+++ b/models/README
@@ -0,0 +1,3 @@
+File: trees.blend
+License: CC-BY 3.0
+Source: http://opengameart.org/content/low-poly-trees-stumps-branches
diff --git a/models/trees.blend b/models/trees.blend
new file mode 100644
index 0000000..108feb6
--- /dev/null
+++ b/models/trees.blend
Binary files differ
diff --git a/scene.cpp b/scene.cpp
index 1fda39e..4e884a6 100644
--- a/scene.cpp
+++ b/scene.cpp
@@ -5,6 +5,7 @@
#include <SDL_image.h>
#include <boost/format.hpp>
#include <boost/bind.hpp>
+#include <assimp/aiPostProcess.h>
#include "gl.h"
@@ -27,10 +28,13 @@ Scene::Scene() {
tool = NULL;
/* setup shader programs */
+ GLFragmentShader fog_fragment("shaders/fog_fragment.glsl");
+
GLVertexShader terrain_vertex("shaders/terrain_vertex.glsl");
GLFragmentShader terrain_fragment("shaders/terrain_fragment.glsl");
terrain_program.attach(terrain_vertex);
terrain_program.attach(terrain_fragment);
+ terrain_program.attach(fog_fragment);
terrain_program.link();
GLFragmentShader water_fragment("shaders/water_fragment.glsl");
@@ -38,12 +42,24 @@ Scene::Scene() {
water_program.attach(water_fragment);
water_program.link();
+ GLVertexShader tree_vertex("shaders/tree_vertex.glsl");
+ GLFragmentShader tree_fragment("shaders/tree_fragment.glsl");
+ tree_program.attach(tree_vertex);
+ tree_program.attach(tree_fragment);
+ tree_program.attach(fog_fragment);
+ tree_program.link();
+
terrain_program.use();
GLint tex = glGetUniformLocation(terrain_program.get_program(), "tex");
GLint texv[] = {0, 1, 2};
glUniform1iv(tex, 3, texv);
GLint markloc = glGetUniformLocation(terrain_program.get_program(), "marktex");
glUniform1i(markloc, 3);
+
+ tree_program.use();
+ tex = glGetUniformLocation(tree_program.get_program(), "tex");
+ glUniform1iv(tex, 1, texv);
+
glUseProgram(0);
/* load textures */
@@ -54,6 +70,17 @@ Scene::Scene() {
marker_texture = load_texture("textures/cross.png");
placeholder_texture = load_texture("textures/placeholder.png");
+ tree_scene = ai_importer.ReadFile("models/trees.blend", aiProcess_Triangulate);
+
+ for(unsigned int i = 0; i < tree_scene->mNumTextures; i++) {
+ aiTexture *texture = tree_scene->mTextures[i];
+ GLuint tx = load_texture(texture);
+ std::string name = (boost::format("*%d") % i).str();
+ scene_textures.insert(std::pair<std::string, GLuint>(name, tx));
+ }
+
+ tree = new models::Tree(tree_scene, scene_textures);
+
/* init terrain */
terrain = new Terrain();
@@ -78,6 +105,7 @@ Scene::~Scene() {
delete lua;
if(tool)
delete tool;
+ delete tree;
if(terrain)
delete terrain;
delete font;
@@ -380,6 +408,8 @@ void Scene::render() {
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
+ Terrain::Chunk::ObjectList trees;
+
// render terrain
if(render_terrain) {
const float fog_color[4] = {1, 1, 1, 0};
@@ -417,6 +447,9 @@ void Scene::render() {
// draw chunk VBOs
for(std::list<Terrain::Chunk*>::iterator it = terrain->chunks.begin(); it != terrain->chunks.end(); it++) {
Terrain::Chunk *chunk = *it;
+
+ trees.insert(trees.end(), chunk->objects.begin(), chunk->objects.end());
+
glPushMatrix();
glTranslatef(-pos.x + chunk->x, -pos.y, -pos.z + chunk->y);
glUniform2f(chunk_pos, chunk->x, chunk->y);
@@ -548,7 +581,39 @@ void Scene::render() {
(*it)->render(font, steps, placeholder_texture);
}
+ // don't pop matrix; use translated player position
+
+ // rotate to point upwards along the y-aksis
+ glRotatef(-90, 1, 0, 0);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ tree_program.use();
+
+ GLint player_pos = glGetUniformLocation(tree_program.get_program(), "player_pos");
+ glUniform3f(player_pos, pos.x, pos.y, pos.z);
+
+ GLint tree_pos = glGetUniformLocation(tree_program.get_program(), "tree_pos");
+
+ //tree->render();
+ for(Terrain::Chunk::ObjectList::iterator it = trees.begin(); it != trees.end(); it++) {
+ glPushMatrix();
+ Vector3 pos(it->second);
+ glUniform3f(tree_pos, pos.x, pos.y, pos.z);
+ // rotated around x-axis; swap y and z, do magic to fix positions
+ glTranslatef(pos.x, -pos.z, pos.y+.5);
+ it->first->render();
+ glPopMatrix();
+ }
+
glPopMatrix();
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ glUseProgram(0);
+
+ // active texture # must be reset before rendering UI stuff
+ glActiveTexture(GL_TEXTURE0);
// HUD
video::ortho();
@@ -608,6 +673,30 @@ GLuint Scene::load_texture(const char *filename) {
return texture;
}
+GLuint Scene::load_texture(aiTexture *texture) {
+ GLuint tex;
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ if(texture->mHeight == 0) {
+ SDL_RWops *rw = SDL_RWFromConstMem(texture->pcData, texture->mWidth);
+ SDL_Surface *image = IMG_Load_RW(rw, 1);
+ if(image->format->Amask) {
+ gluBuild2DMipmaps(GL_TEXTURE_2D, 4, image->w, image->h, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
+ } else {
+ gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->w, image->h, GL_RGB, GL_UNSIGNED_BYTE, image->pixels);
+ }
+
+ SDL_FreeSurface(image);
+ } else {
+ gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texture->mWidth, texture->mHeight, GL_BGRA, GL_UNSIGNED_BYTE, texture->pcData);
+ }
+
+ return tex;
+}
+
static bool playerlist_sort(Vector3 pos, Player::p a, Player::p b) {
return (a->get_pos() - pos).length() > (b->get_pos() - pos).length();
}
diff --git a/scene.h b/scene.h
index 247b52c..6c75c91 100644
--- a/scene.h
+++ b/scene.h
@@ -9,8 +9,13 @@
#include "tool.h"
#include "scripting.h"
#include "player.h"
+#include "model.h"
#include <FTGL/ftgl.h>
+#include <assimp/assimp.hpp>
+#include <assimp/aiScene.h>
+
+using models::Model;
class Scene {
public:
@@ -46,8 +51,15 @@ class Scene {
GLShaderProgram terrain_program;
GLShaderProgram water_program;
+ GLShaderProgram tree_program;
GLuint grass_texture, rock_texture, soil_texture, water_texture, marker_texture, placeholder_texture;
+ std::map<std::string, GLuint> scene_textures;
+
+ Assimp::Importer ai_importer;
+ const aiScene *tree_scene;
+
+ Model *tree;
Scene();
~Scene();
@@ -59,6 +71,7 @@ class Scene {
void events();
void render();
GLuint load_texture(const char *filename);
+ GLuint load_texture(aiTexture *texture);
void sort_players();
};
diff --git a/shaders/fog_fragment.glsl b/shaders/fog_fragment.glsl
new file mode 100644
index 0000000..90b4591
--- /dev/null
+++ b/shaders/fog_fragment.glsl
@@ -0,0 +1,9 @@
+#version 120
+
+void foggify(vec3 player_pos, vec3 pos) {
+ gl_FragColor = mix(gl_FragColor, gl_Fog.color, pow(length(player_pos - pos)/100, 5));
+ if(player_pos.y < 30 - 1.7)
+ gl_FragColor = mix(gl_FragColor, vec4(0, .3, .8, 0), .7);
+}
+
+/* vim: set syn=glsl: */
diff --git a/shaders/terrain_fragment.glsl b/shaders/terrain_fragment.glsl
index 8b966fd..d1f5892 100644
--- a/shaders/terrain_fragment.glsl
+++ b/shaders/terrain_fragment.glsl
@@ -7,6 +7,8 @@ uniform sampler2D marktex;
uniform vec3 selpos, player_pos;
uniform bool show_sel;
+void foggify(vec3 player_pos, vec3 pos);
+
void main() {
vec3 n = normalize(normal);
float diffuse = max(dot(n, light_pos), 0.5);
@@ -27,9 +29,8 @@ void main() {
vec2 st = vec2((pos.x + 1 - selpos.x) / 2, (pos.z + 1 - selpos.z) / 2);
gl_FragColor += texture2D(marktex, st);
}
- gl_FragColor = mix(gl_FragColor, gl_Fog.color, pow(length(player_pos - pos)/100, 5));
- if(player_pos.y < 30 - 1.7)
- gl_FragColor = mix(gl_FragColor, vec4(0, .3, .8, 0), .7);
+
+ foggify(player_pos, pos);
}
/* vim: set syn=glsl: */
diff --git a/shaders/tree_fragment.glsl b/shaders/tree_fragment.glsl
new file mode 100644
index 0000000..382ab4e
--- /dev/null
+++ b/shaders/tree_fragment.glsl
@@ -0,0 +1,22 @@
+#version 120
+
+uniform sampler2D tex;
+uniform vec3 player_pos;
+varying vec3 normal, pos;
+
+void foggify(vec3 player_pos, vec3 pos);
+
+void main() {
+ vec4 color = texture2D(tex, gl_TexCoord[0].st);
+
+ if(color.a < 0.7)
+ discard;
+
+ gl_FragColor = color;
+ float n = clamp(dot(normal, vec3(0, 0, 1)) + .5, .3, 1);
+ gl_FragColor.rgb *= n;
+
+ foggify(player_pos, pos);
+}
+
+/* vim: set syn=glsl: */
diff --git a/shaders/tree_vertex.glsl b/shaders/tree_vertex.glsl
new file mode 100644
index 0000000..4c06bee
--- /dev/null
+++ b/shaders/tree_vertex.glsl
@@ -0,0 +1,14 @@
+#version 120
+
+uniform vec3 tree_pos;
+varying vec3 normal, pos;
+
+void main() {
+ normal = gl_Normal;
+ pos = gl_Vertex.xyz + tree_pos;
+
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+}
+
+/* vim: set syn=glsl: */
diff --git a/terrain.h b/terrain.h
index 386f6e3..aff95a4 100644
--- a/terrain.h
+++ b/terrain.h
@@ -3,6 +3,7 @@
#include "vector.h"
#include "terrain_cache.h"
+#include "model.h"
#include <list>
#include <queue>
@@ -29,6 +30,9 @@ class Terrain {
};
struct Chunk {
+ typedef std::pair<models::Model*, Vector3> ObjectPair;
+ typedef std::list<ObjectPair> ObjectList;
+
Terrain *terrain;
Node **nodes;
float x, y;
@@ -42,6 +46,7 @@ class Terrain {
unsigned int vbo_object;
unsigned int node_count;
unsigned int vertices;
+ ObjectList objects;
Chunk(Terrain *tree, float x, float y);
~Chunk();