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; +}  | 
