diff options
Diffstat (limited to 'scene.cpp')
-rw-r--r-- | scene.cpp | 303 |
1 files changed, 303 insertions, 0 deletions
@@ -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; +} |