diff options
-rw-r--r-- | SConstruct | 1 | ||||
m--------- | common | 0 | ||||
-rw-r--r-- | game.cpp | 22 | ||||
-rw-r--r-- | game.h | 1 | ||||
-rw-r--r-- | model.cpp | 104 | ||||
-rw-r--r-- | model.h | 50 | ||||
-rw-r--r-- | models/README | 3 | ||||
-rw-r--r-- | models/trees.blend | bin | 0 -> 3827560 bytes | |||
-rw-r--r-- | scene.cpp | 89 | ||||
-rw-r--r-- | scene.h | 13 | ||||
-rw-r--r-- | shaders/fog_fragment.glsl | 9 | ||||
-rw-r--r-- | shaders/terrain_fragment.glsl | 7 | ||||
-rw-r--r-- | shaders/tree_fragment.glsl | 22 | ||||
-rw-r--r-- | shaders/tree_vertex.glsl | 14 | ||||
-rw-r--r-- | terrain.h | 5 |
15 files changed, 337 insertions, 3 deletions
@@ -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 @@ -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(); @@ -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 @@ -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 Binary files differnew file mode 100644 index 0000000..108feb6 --- /dev/null +++ b/models/trees.blend @@ -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(); } @@ -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: */ @@ -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(); |