summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2011-04-01 23:07:56 +0200
committerJon Bergli Heier <snakebite@jvnv.net>2011-04-01 23:07:56 +0200
commite172cde8c082fa3e338b3eb11079b36952874936 (patch)
tree90f65a54ce7b6a663ead31496549e0b9338c81d8
parent3b360c21777aad02394a643b32be2ab25362bba1 (diff)
Terrain shader lighting - work in progress.
-rw-r--r--main.cpp48
-rw-r--r--quadtree.cpp4
-rw-r--r--shader.cpp94
-rw-r--r--shader.h47
-rw-r--r--terrain_fragment.glsl43
-rw-r--r--terrain_vertex.glsl19
6 files changed, 238 insertions, 17 deletions
diff --git a/main.cpp b/main.cpp
index 9f3bf15..cf7c3b9 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,6 +2,7 @@
#include "scene.h"
#include "vector.h"
#include "quadtree.h"
+#include "shader.h"
#include <SDL_image.h>
#include <FTGL/ftgl.h>
@@ -123,6 +124,12 @@ int main(int argc, char **argv) {
video::width = 1280;
video::height = 720;
video::init();
+ 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);
@@ -139,6 +146,7 @@ int main(int argc, char **argv) {
Quadtree *qt = new Quadtree(hm->w, hm->h, heightmap, level);
//Quadtree qt(qt_size, qt_size, (int)ceil(sqrt(qt_size)));
+
GLuint grass_texture;
{
SDL_Surface *surface = IMG_Load("Grass0073_3_S.jpg");
@@ -153,7 +161,7 @@ int main(int argc, char **argv) {
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_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);
@@ -170,6 +178,7 @@ int main(int argc, char **argv) {
SDL_Event event;
bool running = true;
bool grid = false;
+ bool gravity = true;
SDL_WarpMouse(video::width/2, video::height/2);
unsigned int last_time = SDL_GetTicks();
/*boost::timer t;
@@ -211,6 +220,9 @@ int main(int argc, char **argv) {
case SDLK_SPACE:
scene.yvel = .05;
break;
+ case SDLK_h:
+ gravity = !gravity;
+ break;
default:
break;
}
@@ -271,7 +283,7 @@ int main(int argc, char **argv) {
right++;
}
if(keystate[SDLK_q])
- scene.pos.y -= 0.002*steps;
+ 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))
@@ -280,27 +292,30 @@ int main(int argc, char **argv) {
std::string move_str;
Quadtree::QuadNode *node = qt->find(scene.pos.x, scene.pos.z);
if(node) {
- 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;
+ 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 %dx%d %d") % scene.pos.str() % node->x % node->y % node->width % node->height % node->level).str();
+ move_str = (boost::format("%s %.2f,%.2f %.2fx%.2f %d") % scene.pos.str() % node->x % node->y % node->width % node->height % node->level).str();
}
scene.lookat();
glEnable(GL_LIGHTING);
- //const float light_pos[4] = {50, 20, 50, 1};
- const float light_pos[4] = {0, 1, 0, 0};
+ 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(!grid) {
+ program.use();
glBindTexture(GL_TEXTURE_2D, grass_texture);
glEnable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, qt->vbo_object);
@@ -314,11 +329,11 @@ int main(int argc, char **argv) {
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ glUseProgram(0);
} else {
std::queue<Quadtree::QuadNode*> q;
q.push(qt->root);
- glBindTexture(GL_TEXTURE_2D, grass_texture);
- glEnable(GL_TEXTURE_2D);
while(!q.empty()) {
Quadtree::QuadNode *node = q.front();
q.pop();
@@ -330,7 +345,6 @@ int main(int argc, char **argv) {
}
}
- glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
float px, py, pz;
diff --git a/quadtree.cpp b/quadtree.cpp
index 4b7eb52..581f92e 100644
--- a/quadtree.cpp
+++ b/quadtree.cpp
@@ -255,6 +255,10 @@ void Quadtree::make_vbo() {
const size_t tex_coord_chunk_size = sizeof(float)*2*12;
const size_t tex_coords_size = tex_coord_chunk_size*nodes;
+ if(vertices_size + normals_size + tex_coords_size > 100*1024*1024) {
+ std::cerr << ">100 MB" << std::endl;
+ }
+
glBufferData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coords_size, NULL, GL_DYNAMIC_DRAW);
std::queue<Quadtree::QuadNode*> q;
diff --git a/shader.cpp b/shader.cpp
new file mode 100644
index 0000000..8d3493e
--- /dev/null
+++ b/shader.cpp
@@ -0,0 +1,94 @@
+#include <fstream>
+#include <stdexcept>
+
+#include <boost/format.hpp>
+
+#include "shader.h"
+
+inline void gl_check_error(const char *msg) {
+ GLenum error = glGetError();
+ if(error != GL_NO_ERROR) {
+ throw(std::runtime_error((boost::format("%s:\n%s") % msg % gluErrorString(error)).str()));
+ }
+}
+
+void GLBaseShader::shader_source(const char *filename) {
+ std::ifstream inf(filename, std::ios_base::in);
+ if(!inf.is_open()) {
+ throw(std::runtime_error((boost::format("Failed to load shader from file %s") % filename).str()));
+ }
+ inf.seekg(0, std::ios_base::end);
+ int length = inf.tellg();
+ inf.seekg(0, std::ios_base::beg);
+ char *buffer = new char[length];
+ inf.read(buffer, length);
+ inf.close();
+
+ glShaderSource(shader, 1, (const GLchar**)&buffer, &length);
+ gl_check_error("Failed to set shader source");
+ delete[] buffer;
+ glCompileShader(shader);
+ int p;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &p);
+ if(p == 0) {
+ char log[0xffff];
+ int size;
+ glGetShaderInfoLog(shader, 0xffff, &size, (GLchar*)&log);
+ throw(std::runtime_error((boost::format("Failed to compile shader:\n%s") % log).str()));
+ }
+}
+
+void GLBaseShader::shader_source(std::string& filename) {
+ shader_source(filename.c_str());
+}
+
+GLBaseShader::GLBaseShader(GLenum type) {
+ shader = glCreateShader(type);
+}
+
+GLBaseShader::~GLBaseShader() {
+ glDeleteShader(shader);
+}
+
+/**
+ * GLShaderProgram
+ */
+GLShaderProgram::GLShaderProgram() {
+ program = glCreateProgram();
+}
+
+GLShaderProgram::~GLShaderProgram() {
+ glDeleteProgram(program);
+}
+
+void GLShaderProgram::attach(GLBaseShader& shader) {
+ glAttachShader(program, shader.shader);
+
+ gl_check_error("Failed to attach shader to program");
+}
+
+void GLShaderProgram::detach(GLBaseShader& shader) {
+ glDetachShader(program, shader.shader);
+
+ gl_check_error("Failed to detach shader from program");
+}
+
+void GLShaderProgram::link() {
+ glLinkProgram(program);
+ gl_check_error("linkage");
+
+ int p;
+ glGetProgramiv(program, GL_LINK_STATUS, &p);
+ if(p == 0) {
+ char log[0xffff];
+ int size;
+ glGetProgramInfoLog(program, 0xffff, &size, (GLchar*)&log);
+ throw(std::runtime_error((boost::format("Failed to link program:\n%s") % log).str()));
+ }
+}
+
+void GLShaderProgram::use() {
+ glUseProgram(program);
+
+ gl_check_error("Failed to use program");
+}
diff --git a/shader.h b/shader.h
new file mode 100644
index 0000000..70f2361
--- /dev/null
+++ b/shader.h
@@ -0,0 +1,47 @@
+#ifndef SHADER_H
+#define SHADER_H
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+class GLBaseShader {
+ friend class GLShaderProgram;
+
+ protected:
+ void shader_source(const char *filename);
+ void shader_source(std::string& filename);
+ unsigned int shader;
+ public:
+ GLBaseShader(GLenum);
+ ~GLBaseShader();
+};
+
+class GLVertexShader : public GLBaseShader {
+ public:
+ GLVertexShader() : GLBaseShader(GL_VERTEX_SHADER) {};
+ GLVertexShader(const char *s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); };
+ GLVertexShader(std::string& s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); };
+};
+
+class GLFragmentShader : public GLBaseShader {
+ public:
+ GLFragmentShader() : GLBaseShader(GL_FRAGMENT_SHADER) {};
+ GLFragmentShader(const char *s) : GLBaseShader(GL_FRAGMENT_SHADER) { shader_source(s); };
+ GLFragmentShader(std::string& s) : GLBaseShader(GL_FRAGMENT_SHADER) { shader_source(s); };
+};
+
+class GLShaderProgram {
+ protected:
+ unsigned int program;
+ public:
+ GLShaderProgram();
+ ~GLShaderProgram();
+
+ void attach(GLBaseShader&);
+ void detach(GLBaseShader&);
+ void link();
+ void use();
+};
+
+#endif
diff --git a/terrain_fragment.glsl b/terrain_fragment.glsl
new file mode 100644
index 0000000..9c354c5
--- /dev/null
+++ b/terrain_fragment.glsl
@@ -0,0 +1,43 @@
+varying vec3 normal, light_pos, V, N;
+varying vec4 diffuse, ambient;
+
+uniform sampler2D tex;
+
+void main() {
+ //gl_FragColor = gl_Color * diffuse_value;
+ //vec4 color = ambient;
+ //vec3 n = normalize(normal);
+ /*vec3 n = normal;
+ vec3 hv;
+ float dotL = max(dot(n, vec3(0, 1, 0)), 0.0);
+ color += diffuse * dotL;
+ hv = normalize(halfvector);
+ float dotHV = max(dot(n, hv), 0.0);*/
+ //color += gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(dotHV, gl_FrontMaterial.shininess);
+
+ vec3 n = normalize(normal);
+
+ float NdotL = max(dot(light_pos, n), 0.0);
+ float diffuse = max(dot(n, light_pos), 0.0);
+
+ gl_FragColor = vec4(n, 0.0);
+
+ //gl_FragColor = texture2D(tex, gl_TexCoord[0].st) /* diffuse_value*/ * diffuse;
+ //gl_FragColor = gl_Color * diffuse;
+
+ //gl_FragColor = NdotL * diffuse + ambient;
+
+ return;
+
+ vec3 L = normalize(light_pos - V);
+ vec3 E = normalize(-V);
+ vec3 R = normalize(-reflect(L, N));
+
+ vec4 Iamb = gl_FrontLightProduct[0].ambient;
+ vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N, L), 0.0);
+ vec4 Ispec = gl_FrontLightProduct[0].specular * pow(max(dot(R, E), 0.0), 0.3 * gl_FrontMaterial.shininess);
+
+ gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;
+}
+
+/* vim: set syn=glsl: */
diff --git a/terrain_vertex.glsl b/terrain_vertex.glsl
new file mode 100644
index 0000000..25b0c25
--- /dev/null
+++ b/terrain_vertex.glsl
@@ -0,0 +1,19 @@
+varying vec3 normal, light_pos, V, N;
+varying vec4 diffuse, ambient;
+
+void main() {
+ V = vec3(gl_ModelViewMatrix * gl_Vertex);
+ N = normalize(gl_NormalMatrix * gl_Normal);
+
+ normal = gl_Normal;
+ light_pos = vec3(0, 1, 0);
+
+ diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
+ ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
+
+ gl_FrontColor = gl_Color;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+}
+
+/* vim: set syn=glsl: */