#include "video.h" #include "scene.h" #include "vector.h" #include "quadtree.h" #include "shader.h" #include #include #include #include #define GL_GLEXT_PROTOTYPES #include //#include #include //#include #include #include #include #include #include #include FTFont *font; int main(int argc, char **argv) { video::width = 1280; video::height = 720; video::init(); Scene scene; GLShaderProgram program; GLVertexShader terrain_vertex("terrain_vertex.glsl"); GLFragmentShader terrain_fragment("terrain_fragment.glsl"); program.attach(terrain_vertex); program.attach(terrain_fragment); program.link(); font = new FTTextureFont("font.ttf"); font->FaceSize(10); GLuint grass_texture; { SDL_Surface *surface = IMG_Load("Grass0073_3_S.jpg"); 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, &grass_texture); glBindTexture(GL_TEXTURE_2D, grass_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) { //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, image->w, image->h, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); } else { //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->w, image->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->w, image->h, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); } SDL_FreeSurface(surface); SDL_FreeSurface(image); } //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.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_KP_PLUS: case SDLK_PLUS: scene.qt->create_nodes(scene.qt->levels+1); break; case SDLK_KP_MINUS: case SDLK_MINUS: if(scene.qt->levels > 1) { scene.qt->create_nodes(scene.qt->levels-1); } break; case SDLK_KP_MULTIPLY: node = scene.qt->find(scene.pos.x, scene.pos.z); node->parent->merge(); scene.qt->make_vbo(); break; case SDLK_KP_DIVIDE: node = scene.qt->find(scene.pos.x, scene.pos.z); node->subdivide(); scene.qt->make_vbo(); break; case SDLK_SPACE: scene.yvel = .05; break; case SDLK_h: gravity = !gravity; break; case SDLK_u: scene.update(); break; case SDLK_c: scene.qt->fix_cracks(); 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 %d") % scene.pos.str() % node->x % node->y % node->width % node->height % node->level).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); if(terrain) { program.use(); glBindTexture(GL_TEXTURE_2D, grass_texture); glEnable(GL_TEXTURE_2D); glBindBuffer(GL_ARRAY_BUFFER, scene.qt->vbo_object); glVertexPointer(3, GL_FLOAT, 0, NULL); glNormalPointer(GL_FLOAT, 0, (GLvoid*)(scene.qt->vertices*3*sizeof(float))); glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)(scene.qt->vertices*3*sizeof(float)*2)); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawArrays(GL_TRIANGLES, 0, scene.qt->vertices); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); glUseProgram(0); } if(grid) { if(terrain) glColor3f(0, 0, 0); else glColor3f(1, 1, 1); std::queue q; q.push(scene.qt->root); while(!q.empty()) { Quadtree::QuadNode *node = q.front(); q.pop(); if(node->vertex_array) { grid ? node->draw_grid() : node->draw(); } else for(int i = 0; i < 4; i++) q.push(node->children[i]); } } //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 %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(); usleep(1000); } video::free(); return 0; }