diff options
-rw-r--r-- | main.cpp | 307 | ||||
-rw-r--r-- | scene.cpp | 303 | ||||
-rw-r--r-- | scene.h | 25 |
3 files changed, 332 insertions, 303 deletions
@@ -1,52 +1,8 @@ #include "video.h" #include "scene.h" -#include "vector.h" -#include "quadtree.h" -#include "shader.h" - -#include <SDL_image.h> -#include <FTGL/ftgl.h> -#include <boost/format.hpp> -#include <boost/shared_ptr.hpp> #include "gl.h" -#include <iostream> -#include <cmath> -#include <list> -#include <vector> -#include <map> -#include <queue> - -FTFont *font; - -GLuint load_texture(const std::string filename) { - GLuint texture; - SDL_Surface *surface = IMG_Load(filename.c_str()); - SDL_Surface *image = SDL_CreateRGBSurface(SDL_SWSURFACE, surface->w, surface->h, 32, - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); - SDL_Rect area; - area.x = area.y = 0; - area.w = surface->w; - area.h = surface->h; - SDL_BlitSurface(surface, &area, image, &area); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - 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(surface); - SDL_FreeSurface(image); - - return texture; -} - - int main(int argc, char **argv) { video::width = 1280; video::height = 720; @@ -54,269 +10,14 @@ int main(int argc, char **argv) { Scene scene; - GLShaderProgram program; - GLVertexShader terrain_vertex("shaders/terrain_vertex.glsl"); - GLFragmentShader terrain_fragment("shaders/terrain_fragment.glsl"); - program.attach(terrain_vertex); - program.attach(terrain_fragment); - program.link(); - - { - program.use(); - GLint tex1loc = glGetUniformLocation(program.get_program(), "tex[1]"); - glUniform1i(tex1loc, 1); - GLint tex2loc = glGetUniformLocation(program.get_program(), "tex[2]"); - glUniform1i(tex2loc, 2); - glUseProgram(0); - } - - font = new FTTextureFont("font.ttf"); - font->FaceSize(10); - - GLuint grass_texture = load_texture("textures/Grass0073_3_S.jpg"); - GLuint rock_texture = load_texture("textures/RockJagged0010_2_S.jpg"); - GLuint soil_texture = load_texture("textures/SoilSand0168_9_S.jpg"); - //SDL_WM_GrabInput(SDL_GRAB_ON); - SDL_Event event; - bool running = true; - bool grid = false; - bool terrain = true; - bool gravity = true; SDL_WarpMouse(video::width/2, video::height/2); - unsigned int last_time = SDL_GetTicks(); - Vector3 selected; - Quadtree::QuadNode *node; - Quadtree::QuadNode *last_node = NULL; + scene.last_time = SDL_GetTicks(); scene.update(); - while(running) { - unsigned int time = SDL_GetTicks(); - unsigned int steps = time - last_time + 1; - last_time = time; - bool do_select = 0; - int sx, sy; - while(SDL_PollEvent(&event)) { - switch(event.type) { - case SDL_QUIT: - running = false; - break; - case SDL_KEYDOWN: - switch(event.key.keysym.sym) { - case SDLK_ESCAPE: - running = false; - break; - case SDLK_g: - grid = !grid; - break; - case SDLK_t: - terrain = !terrain; - break; - case SDLK_SPACE: - scene.yvel = .05; - break; - case SDLK_h: - gravity = !gravity; - break; - case SDLK_u: - scene.update(); - break; - default: - break; - } - break; - case SDL_MOUSEBUTTONUP: - switch(event.button.button) { - case SDL_BUTTON_LEFT: - sx = event.button.x; - sy = event.button.y; - do_select = true; - // TODO: reimplement selection - break; - case SDL_BUTTON_WHEELUP: - case SDL_BUTTON_WHEELDOWN: - // TODO: reimplement? - break; - } - case SDL_MOUSEMOTION: - if(event.motion.x == video::width/2 && event.motion.y == video::height/2) - break; - scene.yaw += (float)event.motion.xrel / 500; - scene.pitch += (float)event.motion.yrel / 500; - if(scene.yaw > 2*M_PI) - scene.yaw -= 2*M_PI; - else if(scene.yaw < 0) - scene.yaw += 2*M_PI; - if(scene.pitch > M_PI) - scene.pitch = M_PI; - else if(scene.pitch < 0) - scene.pitch = 0; - SDL_WarpMouse(video::width/2, video::height/2); - break; - } - } - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glLoadIdentity(); - video::persp(); - - unsigned char *keystate = SDL_GetKeyState(NULL); - float forward = 0; - float right = 0; - bool moved = false; - if(keystate[SDLK_w]) { - moved = true; - forward++; - } - if(keystate[SDLK_s]) { - moved = true; - forward--; - } - if(keystate[SDLK_a]) { - moved = true; - right--; - } - if(keystate[SDLK_d]) { - moved = true; - right++; - } - if(keystate[SDLK_q]) - scene.pos.y -= 0.002*steps*(keystate[SDLK_LSHIFT]?10:1); - if(keystate[SDLK_e]) - scene.pos.y += 0.002*steps*(keystate[SDLK_LSHIFT]?10:1); - if(moved && (forward || right)) { - scene.move(forward, right, steps*(keystate[SDLK_LSHIFT]?10:1)); - } - - std::string move_str; - Quadtree::QuadNode *node = scene.qt->find(scene.pos.x, scene.pos.z); - if(node) { - if(gravity) { - float y = node->get_height(scene.pos.x, scene.pos.z); - if(scene.pos.y > y && !keystate[SDLK_e]) - scene.yvel -= 9.81 * steps / 85000; - if(scene.yvel < -.5) - scene.yvel = -.5; - scene.pos.y += scene.yvel * steps; - if(scene.pos.y < y) { - scene.pos.y = y; - scene.yvel = 0; - } - } - move_str = (boost::format("%s %.2f,%.2f %.2fx%.2f") % scene.pos.str() % node->x % node->y % node->width % node->height).str(); - - if(last_node != node) { - last_node = node; - scene.update(); - } - } - - scene.lookat(); - - //glEnable(GL_LIGHTING); - const float light_pos[4] = {50, 100, 50, 1}; - //const float light_pos[4] = {0, 1, 0, 0}; - //glLightfv(GL_LIGHT0, GL_POSITION, light_pos); - - unsigned int chunks_rendered = 0; - if(terrain) { - program.use(); - glEnable(GL_TEXTURE_2D); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, grass_texture); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, rock_texture); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, soil_texture); - - std::queue<Quadtree::QuadChunk*> q; - q.push(scene.qt->root); - while(!q.empty()) { - Quadtree::QuadChunk *chunk = q.front(); - q.pop(); - if(!chunk->nodes) { - for(int i = 0; i < 4; i++) - q.push(chunk->children[i]); - continue; - } else if(!chunk->vbo_object) - continue; - chunks_rendered++; - glBindBuffer(GL_ARRAY_BUFFER, chunk->vbo_object); - glVertexPointer(3, GL_FLOAT, 0, NULL); - glNormalPointer(GL_FLOAT, 0, (GLvoid*)(chunk->vertices*3*sizeof(float))); - glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)(chunk->vertices*3*sizeof(float)*2)); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDrawArrays(GL_TRIANGLES, 0, chunk->vertices); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - glDisable(GL_TEXTURE_2D); - // set active to texture0 to avoid breaking the texture font - glActiveTexture(GL_TEXTURE0); - glUseProgram(0); - } - if(grid) { - if(terrain) - glColor3f(0, 0, 0); - else - glColor3f(1, 1, 1); - std::queue<Quadtree::QuadChunk*> q; - q.push(scene.qt->root); - while(!q.empty()) { - Quadtree::QuadChunk *chunk = q.front(); - q.pop(); - if(!chunk->nodes) { - for(int i = 0; i < 4; i++) - q.push(chunk->children[i]); - continue; - } else if(chunk->vbo_object) { - for(unsigned int i = 0; i < chunk->node_count; i++) - chunk->nodes[i]->draw_grid(); - } - } - } - - //glDisable(GL_LIGHTING); - - float px, py, pz; - if(do_select && scene.select(sx, sy, px, py, pz)) { - selected = Vector3(px, py, pz); - } - glColor3f(1, 0, 0); - glBegin(GL_TRIANGLE_FAN); - glVertex3f(selected.x, selected.y, selected.z); - glVertex3f(selected.x+.5, selected.y+1, selected.z-.5); - glVertex3f(selected.x+.5, selected.y+1, selected.z+.5); - glVertex3f(selected.x-.5, selected.y+1, selected.z+.5); - glVertex3f(selected.x-.5, selected.y+1, selected.z-.5); - glVertex3f(selected.x+.5, selected.y+1, selected.z-.5); - glEnd(); - - video::ortho(); - float height = font->LineHeight(); - glColor3f(1, 1, 1); - glTranslatef(0, video::height-height, 0); - font->Render((boost::format("%dx%d chunks: %d steps: %d") - % scene.qt->width % scene.qt->height % chunks_rendered % steps).str().c_str()); - //font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d update: %d") - // % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps % scene.qt->thread_running).str().c_str()); - //glTranslatef(0, height, 0); - //font->Render((boost::format("selected: %x") % selected).str().c_str()); - glTranslatef(0, -height, 0); - font->Render(move_str.c_str()); - /*if(selected) { - glTranslatef(0, height, 0); - //font->Render((boost::format("(%s %s %s %s)") % selected->a->str() % selected->b->str() % selected->c->str() % selected->d->str()).str().c_str()); - font->Render(selected->str().c_str()); - }*/ - - SDL_GL_SwapBuffers(); + while(scene.running) { + scene.events(); + scene.render(); SDL_Delay(1); } @@ -1,13 +1,47 @@ #include "scene.h" +#include "video.h" #include <SDL_image.h> +#include <boost/format.hpp> + #include "gl.h" #include <cmath> +#include <queue> #define inrange(a, b, c) ((a) >= (b) && (a) <= (c)) Scene::Scene() { + running = true; + grid = false; + terrain = true; + gravity = true; + + last_node = NULL; + + do_select = false; + show_selection = false; + + /* setup shader programs */ + 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.link(); + + terrain_program.use(); + GLint tex1loc = glGetUniformLocation(terrain_program.get_program(), "tex[1]"); + glUniform1i(tex1loc, 1); + GLint tex2loc = glGetUniformLocation(terrain_program.get_program(), "tex[2]"); + glUniform1i(tex2loc, 2); + glUseProgram(0); + + /* load textures */ + grass_texture = load_texture("textures/Grass0073_3_S.jpg"); + rock_texture = load_texture("textures/RockJagged0010_2_S.jpg"); + soil_texture = load_texture("textures/SoilSand0168_9_S.jpg"); + + /* load heightmap */ SDL_Surface *hm = IMG_Load("heightmap.png"); float *heightmap = new float[hm->w * hm->h]; for(int x = 0; x < hm->w; x++) { @@ -20,11 +54,16 @@ Scene::Scene() { int h = hm->h; SDL_FreeSurface(hm); qt = new Quadtree(w, h, heightmap); + + /* load font */ + font = new FTTextureFont("font.ttf"); + font->FaceSize(10); } Scene::~Scene() { if(qt) delete qt; + delete font; } void Scene::lookat() { @@ -94,3 +133,267 @@ bool Scene::select(int x, int y, float& px, float& py, float& pz) { void Scene::update() { qt->update(pos.x, pos.z); } + +void Scene::events() { + SDL_Event event; + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_QUIT: + running = false; + break; + case SDL_KEYDOWN: + switch(event.key.keysym.sym) { + case SDLK_ESCAPE: + running = false; + break; + case SDLK_g: + grid = !grid; + break; + case SDLK_t: + terrain = !terrain; + break; + case SDLK_SPACE: + yvel = .05; + break; + case SDLK_h: + gravity = !gravity; + break; + case SDLK_u: + update(); + break; + default: + break; + } + break; + case SDL_MOUSEBUTTONUP: + switch(event.button.button) { + case SDL_BUTTON_LEFT: + sx = event.button.x; + sy = event.button.y; + do_select = true; + // TODO: reimplement selection + break; + case SDL_BUTTON_RIGHT: + show_selection = false; + break; + case SDL_BUTTON_WHEELUP: + case SDL_BUTTON_WHEELDOWN: + // TODO: reimplement? + break; + } + case SDL_MOUSEMOTION: + if(event.motion.x == video::width/2 && event.motion.y == video::height/2) + break; + yaw += (float)event.motion.xrel / 500; + pitch += (float)event.motion.yrel / 500; + if(yaw > 2*M_PI) + yaw -= 2*M_PI; + else if(yaw < 0) + yaw += 2*M_PI; + if(pitch > M_PI) + pitch = M_PI; + else if(pitch < 0) + pitch = 0; + SDL_WarpMouse(video::width/2, video::height/2); + break; + } + } +} + +void Scene::render() { + unsigned int time = SDL_GetTicks(); + unsigned int steps = time - last_time + 1; + last_time = time; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + video::persp(); + + unsigned char *keystate = SDL_GetKeyState(NULL); + float forward = 0; + float right = 0; + bool moved = false; + if(keystate[SDLK_w]) { + moved = true; + forward++; + } + if(keystate[SDLK_s]) { + moved = true; + forward--; + } + if(keystate[SDLK_a]) { + moved = true; + right--; + } + if(keystate[SDLK_d]) { + moved = true; + right++; + } + if(keystate[SDLK_q]) + pos.y -= 0.002*steps*(keystate[SDLK_LSHIFT]?10:1); + if(keystate[SDLK_e]) + pos.y += 0.002*steps*(keystate[SDLK_LSHIFT]?10:1); + if(moved && (forward || right)) { + move(forward, right, steps*(keystate[SDLK_LSHIFT]?10:1)); + } + + std::string move_str; + Quadtree::QuadNode *node = qt->find(pos.x, pos.z); + if(node) { + if(gravity) { + float y = node->get_height(pos.x, pos.z); + if(pos.y > y && !keystate[SDLK_e]) + yvel -= 9.81 * steps / 85000; + if(yvel < -.5) + yvel = -.5; + pos.y += yvel * steps; + if(pos.y < y) { + pos.y = y; + yvel = 0; + } + } + move_str = (boost::format("%s %.2f,%.2f %.2fx%.2f") % pos.str() % node->x % node->y % node->width % node->height).str(); + + if(last_node != node) { + last_node = node; + update(); + } + } + + lookat(); + + //glEnable(GL_LIGHTING); + const float light_pos[4] = {50, 100, 50, 1}; + //const float light_pos[4] = {0, 1, 0, 0}; + //glLightfv(GL_LIGHT0, GL_POSITION, light_pos); + + unsigned int chunks_rendered = 0; + if(terrain) { + terrain_program.use(); + glEnable(GL_TEXTURE_2D); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, grass_texture); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, rock_texture); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, soil_texture); + + std::queue<Quadtree::QuadChunk*> q; + q.push(qt->root); + while(!q.empty()) { + Quadtree::QuadChunk *chunk = q.front(); + q.pop(); + if(!chunk->nodes) { + for(int i = 0; i < 4; i++) + q.push(chunk->children[i]); + continue; + } else if(!chunk->vbo_object) + continue; + chunks_rendered++; + glBindBuffer(GL_ARRAY_BUFFER, chunk->vbo_object); + glVertexPointer(3, GL_FLOAT, 0, NULL); + glNormalPointer(GL_FLOAT, 0, (GLvoid*)(chunk->vertices*3*sizeof(float))); + glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)(chunk->vertices*3*sizeof(float)*2)); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glDrawArrays(GL_TRIANGLES, 0, chunk->vertices); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + glDisable(GL_TEXTURE_2D); + // set active to texture0 to avoid breaking the texture font + glActiveTexture(GL_TEXTURE0); + glUseProgram(0); + } + if(grid) { + if(terrain) + glColor3f(0, 0, 0); + else + glColor3f(1, 1, 1); + std::queue<Quadtree::QuadChunk*> q; + q.push(qt->root); + while(!q.empty()) { + Quadtree::QuadChunk *chunk = q.front(); + q.pop(); + if(!chunk->nodes) { + for(int i = 0; i < 4; i++) + q.push(chunk->children[i]); + continue; + } else if(chunk->vbo_object) { + for(unsigned int i = 0; i < chunk->node_count; i++) + chunk->nodes[i]->draw_grid(); + } + } + } + + //glDisable(GL_LIGHTING); + + float px, py, pz; + if(do_select && select(sx, sy, px, py, pz)) { + do_select = false; + selected = Vector3(px, py, pz); + show_selection = true; + } + if(show_selection) { + glColor3f(1, 0, 0); + glBegin(GL_TRIANGLE_FAN); + glVertex3f(selected.x, selected.y, selected.z); + glVertex3f(selected.x+.5, selected.y+1, selected.z-.5); + glVertex3f(selected.x+.5, selected.y+1, selected.z+.5); + glVertex3f(selected.x-.5, selected.y+1, selected.z+.5); + glVertex3f(selected.x-.5, selected.y+1, selected.z-.5); + glVertex3f(selected.x+.5, selected.y+1, selected.z-.5); + glEnd(); + } + + video::ortho(); + float height = font->LineHeight(); + glColor3f(1, 1, 1); + glTranslatef(0, video::height-height, 0); + font->Render((boost::format("%dx%d chunks: %d steps: %d") + % qt->width % qt->height % chunks_rendered % steps).str().c_str()); + //font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d update: %d") + // % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps % scene.qt->thread_running).str().c_str()); + //glTranslatef(0, height, 0); + //font->Render((boost::format("selected: %x") % selected).str().c_str()); + glTranslatef(0, -height, 0); + font->Render(move_str.c_str()); + /*if(selected) { + glTranslatef(0, height, 0); + //font->Render((boost::format("(%s %s %s %s)") % selected->a->str() % selected->b->str() % selected->c->str() % selected->d->str()).str().c_str()); + font->Render(selected->str().c_str()); + }*/ + + SDL_GL_SwapBuffers(); +} + +GLuint Scene::load_texture(const char *filename) { + GLuint texture; + SDL_Surface *surface = IMG_Load(filename); + SDL_Surface *image = SDL_CreateRGBSurface(SDL_SWSURFACE, surface->w, surface->h, 32, + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + SDL_Rect area; + area.x = area.y = 0; + area.w = surface->w; + area.h = surface->h; + SDL_BlitSurface(surface, &area, image, &area); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + 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(surface); + SDL_FreeSurface(image); + + return texture; +} @@ -3,6 +3,10 @@ #include "vector.h" #include "quadtree.h" +#include "gl.h" +#include "shader.h" + +#include <FTGL/ftgl.h> class Scene { public: @@ -10,6 +14,24 @@ class Scene { Vector3 pos; float yvel; Quadtree *qt; + FTFont *font; + + bool running; + bool grid; + bool terrain; + bool gravity; + + Quadtree::QuadNode *last_node; + + unsigned int last_time; + Vector3 selected; + + bool do_select, show_selection; + int sx, sy; + + GLShaderProgram terrain_program; + + GLuint grass_texture, rock_texture, soil_texture; Scene(); ~Scene(); @@ -18,6 +40,9 @@ class Scene { void move(float forward, float right, int steps); bool select(int x, int y, float& px, float& py, float& pz); void update(); + void events(); + void render(); + GLuint load_texture(const char *filename); }; #endif |