summaryrefslogtreecommitdiff
path: root/scene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene.cpp')
-rw-r--r--scene.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/scene.cpp b/scene.cpp
index 199471f..dd27044 100644
--- a/scene.cpp
+++ b/scene.cpp
@@ -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;
+}