summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-07-21 13:56:12 -0700
committerEric Anholt <eric@anholt.net>2009-07-28 13:53:48 -0700
commitbc6d901d45839c5ab1a689c5e3efc44500ce3fb5 (patch)
tree2d49574fd73b170464438dbb5606a24bc8c1fdca
parenta9c85b079846cb92929c1acbc8577551953aa1e4 (diff)
Add a bright red ground plane.
-rw-r--r--Makefile.am1
-rw-r--r--glass.c69
-rw-r--r--glass.h21
-rw-r--r--ground.c154
-rw-r--r--ground.frag125
-rw-r--r--ground.vert28
6 files changed, 377 insertions, 21 deletions
diff --git a/Makefile.am b/Makefile.am
index 67483dd..e297c3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,5 +9,6 @@ bin_PROGRAMS = glass
glass_SOURCES = \
glass.c \
glass.h \
+ ground.c \
matrix.c \
load_texture.c
diff --git a/glass.c b/glass.c
index 3e9cdd2..9eae85f 100644
--- a/glass.c
+++ b/glass.c
@@ -39,8 +39,6 @@
#include "glass.h"
-#include <glu3.h>
-
#include <SDL.h>
#define DEFAULT_WIDTH 600
@@ -67,10 +65,7 @@ enum uniform_list {
UNIFORM_F0,
};
-struct uniform_desc {
- const char *name;
- GLint location;
-} uniforms[] = {
+struct uniform_desc uniforms[] = {
[UNIFORM_MV] = { "mv" },
[UNIFORM_MVP] = { "mvp" },
[UNIFORM_LIGHT_EYE] = { "light_eye" },
@@ -80,7 +75,14 @@ struct uniform_desc {
[UNIFORM_F0] = { "F0" },
};
+struct uniform_desc ground_uniforms[GROUND_UNIFORM_MAX] = {
+ [GROUND_UNIFORM_MV] = { "mv" },
+ [GROUND_UNIFORM_MVP] = { "mvp" },
+};
+
+
static GLuint glass_prog = 0;
+GLuint ground_prog = 0;
struct revolved_object ring;
GLuint normalmap_tex, heightmap_tex;
@@ -89,15 +91,15 @@ static const GLUvec4 x_axis = {{1.0, 0.0, 0.0, 1.0}};
static const GLUvec4 y_axis = {{0.0, 1.0, 0.0, 1.0}};
static const GLUvec4 z_axis = {{0.0, 0.0, 1.0, 1.0}};
-static GLUvec4 eye_world = {{0.0, 0.0, 2.0, 1.0}};
+GLUvec4 eye_world = {{0.0, 0.0, 2.0, 1.0}};
static GLUvec4 eye_center_world = {{0.0, 1.0, 2.0, 1.0}};
static GLUvec4 light_eye;
-static GLUmat4 projection;
-static GLUmat4 world_to_eye;
+GLUmat4 projection;
+GLUmat4 world_to_eye;
static time_t start_tv_sec = 0;
static float start_time, cur_time, last_fps_time = 0;
-static int no_multi_draw_arrays;
+int no_multi_draw_arrays;
static int frames = 0, last_fps_frames = 0;
static SDL_Surface *sdl_surf = NULL;
static GLboolean done = GL_FALSE;
@@ -152,8 +154,6 @@ update_light_position(void)
light_eye.values[1] /= light_eye.values[3];
light_eye.values[2] /= light_eye.values[3];
light_eye.values[3] = 1.0;
-
- glUniform3fv(uniforms[UNIFORM_LIGHT_EYE].location, 1, light_eye.values);
}
static void
@@ -239,7 +239,11 @@ draw_rings(void)
if (glass_prog != 0) {
glUseProgram(glass_prog);
+ glUniform3fv(uniforms[UNIFORM_LIGHT_EYE].location, 1,
+ light_eye.values);
+
glBindVertexArray(ring.array_obj);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ring.vbo);
for (instance = 0; instance < 27; instance++) {
install_transform(instance);
do_ring_drawelements();
@@ -261,6 +265,7 @@ draw(void)
glViewport(0, 0, win_width, win_height);
draw_rings();
+ draw_ground();
SDL_GL_SwapBuffers();
frames++;
@@ -422,9 +427,6 @@ revolve(const float *verts, unsigned int num_verts,
}
}
- glGenVertexArrays(1, &ring.array_obj);
- glBindVertexArray(ring.array_obj);
-
glBindBuffer(GL_ARRAY_BUFFER_ARB, ring.vbo);
glVertexPointer(3, GL_FLOAT, 0, (void *)(uintptr_t)ring.pos_offset);
glEnable(GL_VERTEX_ARRAY);
@@ -439,11 +441,8 @@ revolve(const float *verts, unsigned int num_verts,
glTexCoordPointer(3, GL_FLOAT, 0, (void *)(uintptr_t)ring.tangent_offset);
glEnable(GL_TEXTURE_COORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER_ARB, ring.vbo);
glNormalPointer(GL_FLOAT, 0, (void *)(uintptr_t)ring.norm_offset);
glEnable(GL_NORMAL_ARRAY);
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ring.vbo);
}
static void
@@ -674,13 +673,12 @@ load_program(char *base_filename)
}
static void
-load_programs(void)
+load_glass_program(void)
{
int i;
- if (glass_prog != 0) {
+ if (glass_prog != 0)
glDeleteProgram(glass_prog);
- }
glass_prog = load_program("glass");
@@ -696,6 +694,30 @@ load_programs(void)
}
static void
+load_ground_program(void)
+{
+ int i;
+
+ if (ground_prog != 0)
+ glDeleteProgram(ground_prog);
+
+ ground_prog = load_program("ground");
+
+ for (i = 0; i < ARRAY_SIZE(ground_uniforms); i++) {
+ ground_uniforms[i].location =
+ glGetUniformLocation(ground_prog,
+ ground_uniforms[i].name);
+ }
+}
+
+static void
+load_programs(void)
+{
+ load_glass_program();
+ load_ground_program();
+}
+
+static void
init(void)
{
int size;
@@ -722,6 +744,8 @@ init(void)
*/
world_to_eye = gluLookAt4v(&eye_world, &eye_center_world, &z_axis);
+ setup_ground();
+
generate_rounded_rect_verts(0.2, 1.0, .02, 0.9, corner_steps,
&verts, &num_verts);
@@ -745,6 +769,9 @@ init(void)
size = ring.elements_offset + ring.elements_vert_stride *
ring.num_verts;
+ glGenVertexArrays(1, &ring.array_obj);
+ glBindVertexArray(ring.array_obj);
+
glGenBuffers(1, &vbo);
ring.vbo = vbo;
glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo);
diff --git a/glass.h b/glass.h
index ae113f4..39d0355 100644
--- a/glass.h
+++ b/glass.h
@@ -27,6 +27,23 @@
#define GL_GLEXT_PROTOTYPES
#include <GL/glew.h>
+#include <glu3.h>
+
+enum ground_uniform_list {
+ GROUND_UNIFORM_MV,
+ GROUND_UNIFORM_MVP,
+ GROUND_UNIFORM_MAX
+};
+
+struct uniform_desc {
+ const char *name;
+ GLint location;
+};
+
+extern struct uniform_desc ground_uniforms[GROUND_UNIFORM_MAX];
+extern GLuint ground_prog;
+extern GLUmat4 projection;
+extern GLUmat4 world_to_eye;
/* matrix.c */
void mult_m4_p4(float *result, const float *mat4, const float *point4);
@@ -41,3 +58,7 @@ void print_m4(const float *mat4, const char *name);
/* load_texture.c */
GLuint load_texture_rgb(const char *filename);
+
+/* ground.c */
+void draw_ground(void);
+void setup_ground(void);
diff --git a/ground.c b/ground.c
new file mode 100644
index 0000000..feff32f
--- /dev/null
+++ b/ground.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2009 Eric Anholt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <err.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <getopt.h>
+
+#include "glass.h"
+
+static const int ground_size = 256;
+static GLuint ground_obj;
+static int elements_offset;
+extern int no_multi_draw_arrays;
+extern GLUvec4 eye_world;
+
+static GLuint ground_vbo;
+
+/* The ground plane is located in world coordinates, so no need to do any
+ * object_to_world transformation.
+ */
+static void
+install_ground_transform(void)
+{
+ GLUmat4 mvp;
+
+ mvp = gluMult4m_4m(&projection, &world_to_eye);
+
+ glUniformMatrix4fv(ground_uniforms[GROUND_UNIFORM_MV].location, 1, 0,
+ (float *)&world_to_eye);
+ glUniformMatrix4fv(ground_uniforms[GROUND_UNIFORM_MVP].location, 1, 0,
+ (float *)&mvp);
+}
+
+void
+draw_ground(void)
+{
+ GLvoid *indices[ground_size];
+ GLsizei count[ground_size];
+ int v;
+
+ if (ground_prog == 0)
+ return;
+
+ glUseProgram(ground_prog);
+ install_ground_transform();
+
+ glBindVertexArray(ground_obj);
+
+ for (v = 0; v < ground_size - 1; v++) {
+ indices[v] = (void *)(uintptr_t)(elements_offset +
+ v * sizeof(uint32_t) * 2 *
+ ground_size);
+ count[v] = 2 * ground_size;
+ }
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ground_vbo);
+ if (GLEW_EXT_multi_draw_arrays && !no_multi_draw_arrays) {
+ glMultiDrawElements(GL_TRIANGLE_STRIP,
+ count,
+ GL_UNSIGNED_INT,
+ (const GLvoid **)indices,
+ ground_size - 1);
+ } else {
+ for (v = 0; v < ground_size - 1; v++) {
+ glDrawElements(GL_TRIANGLE_STRIP,
+ ground_size * 2,
+ GL_UNSIGNED_INT,
+ indices[v]);
+ }
+ }
+}
+
+void
+setup_ground(void)
+{
+ int ground_size = 256;
+ int vbo_size, x, y;
+ int pos_offset;
+ char *base;
+ float *pos;
+ uint32_t *elements;
+
+ glGenVertexArrays(1, &ground_obj);
+ glBindVertexArray(ground_obj);
+
+ pos_offset = 0;
+ elements_offset = pos_offset +
+ sizeof(float) * ground_size * ground_size * 3;
+
+ vbo_size = elements_offset +
+ 2 * sizeof(uint32_t) * (ground_size - 1) * ground_size;
+
+ glGenBuffers(1, &ground_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER_ARB, ground_vbo);
+ glBufferData(GL_ARRAY_BUFFER_ARB, vbo_size, NULL, GL_STATIC_DRAW_ARB);
+ base = glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ pos = (float *)(base + pos_offset);
+ elements = (uint32_t *)(base + elements_offset);
+
+ /* position generation */
+ for (y = 0; y < ground_size; y++) {
+ for (x = 0; x < ground_size; x++) {
+ float *element = &pos[(y * ground_size + x) * 3];
+
+ element[0] = x - ground_size / 2;
+ element[1] = y - ground_size / 2;
+ element[2] = 0.0;
+ }
+ }
+
+ uint32_t *next_element = elements;
+ for (y = 0; y < ground_size - 1; y++) {
+ for (x = 0; x < ground_size; x++) {
+ *next_element++ = (y + 1) * ground_size + x;
+ *next_element++ = y * ground_size + x;
+ }
+ }
+
+ glUnmapBuffer(GL_ARRAY_BUFFER_ARB);
+
+ glVertexPointer(3, GL_FLOAT, 0, (void *)(uintptr_t)pos_offset);
+ glEnable(GL_VERTEX_ARRAY);
+}
diff --git a/ground.frag b/ground.frag
new file mode 100644
index 0000000..1938364
--- /dev/null
+++ b/ground.frag
@@ -0,0 +1,125 @@
+void main()
+{
+ gl_FragColor = vec4(1,0,0,0);
+}
+
+#if 0
+varying vec3 light_surf;
+varying vec3 eye_surf;
+varying vec3 tangent_surf;
+varying vec2 texcoord;
+uniform sampler2D normal_sampler;
+uniform sampler2D heightmap_sampler;
+uniform float F0, ni;
+
+float schlick_fresnel(float n_dot_l)
+{
+ return F0 + (1 - F0) * pow(1 - n_dot_l, 5);
+}
+
+/* This returns garbage compared to Schlick. */
+float fresnel(float v_dot_h)
+{
+ float c = v_dot_h; /* cos theta, v . h or l . h */
+ float g = sqrt(ni * ni + c * c - 1);
+ float gmc = g - c;
+ float gpc = g + c;
+ float c_gpc_m_1_squared = (c * gpc - 1) * (c * gpc - 1);
+ float c_gmc_p_1_squared = (c * gmc + 1) * (c * gmc + 1);
+
+ return gmc*gmc / (2 * gpc*gpc) * (1 + c_gmc_p_1_squared /
+ c_gpc_m_1_squared);
+}
+
+void main()
+{
+ const vec4 material_color = vec4(0.7, 0.5, 0.3, 0.0);
+ vec3 l = normalize(light_surf);
+ vec3 v = normalize(eye_surf);
+ vec3 h = normalize(l + v);
+ vec3 t = normalize(tangent_surf);
+ vec3 n = texture2D(normal_sampler, texcoord).xyz * 2 - 1;
+ /* Hack: Reduce the significance of our normal map, which otherwise
+ * looks incongruous with the straight edges.
+ */
+ n = normalize(n + vec3(0,0,1));
+ float n_dot_l = dot(n, l);
+ float n_dot_v = dot(n, v);
+ float n_dot_h = dot(n, h);
+ float v_dot_h = dot(v, h);
+ float s = .7;
+ float d = 1 - s;
+ float Ii = 0.9; /*intensity of incoming light */
+ float Iia = .1 * Ii; /*intensity of ambient light */
+
+ float cos2_alpha = n_dot_h * n_dot_h;
+ float tan2_alpha = (1 - cos2_alpha) / cos2_alpha;
+ float Rs;
+ float D;
+
+ /* Aniso BRDF from Ward's "Measuring and Modeling
+ * Anisotropic Reflection".
+ */
+
+ /* brushed metal */
+ float ward_n = .037;
+ float ward_m = .063;
+
+ /* Make phi be the angle between the projections of
+ * the tangent and half-angle vectors onto the
+ * surface plane (z=0). Doing it right would involve
+ * projecting onto the plane defined by n.
+ */
+ float cos_phi = dot(normalize(t.xy), normalize(h.xy));
+
+ float cos2_phi_over_m2 = ((cos_phi * cos_phi) / (ward_m * ward_m));
+ float sin2_phi_over_n2 = ((1 - cos_phi * cos_phi) / (ward_n * ward_n));
+#if 1
+ D = exp(-tan2_alpha * (cos2_phi_over_m2 + sin2_phi_over_n2));
+#else
+ /* Ward's "computationally convenient" equation.
+ * Doesn't work.
+ */
+ D = exp(-2 * (cos2_phi_over_m2 +
+ sin2_phi_over_n2) /
+ (1 + n_dot_h));
+#endif
+ Rs = 2 * schlick_fresnel(n_dot_l) * D /
+ sqrt(n_dot_l * n_dot_v) / (ward_m * ward_n);
+
+ Rs *= step(0, n_dot_l);
+ Rs *= step(0, n_dot_v);
+
+ float Rd = (1 - F0) * 2;
+ /* Ambient occlusion factor -- sample the height map we
+ * used to generate the normal map, and reduce intensity in
+ * the valleys.
+ */
+ float heightmap = texture2D(heightmap_sampler, texcoord).x;
+ float Ra = Rd * (.8 + .2 * heightmap);
+
+ gl_FragColor = n_dot_l * step(0, n_dot_l) *
+ vec4(material_color.xyz *
+ (Rd * d + Rs * s),
+ material_color.w) +
+ Iia * Ra * material_color.xyzw;
+
+ /* Debugging scalars -- Map [0,1] to [0.5,1] to catch negative
+ * values. Multiply by the step function to catch when
+ * the scalar won't come into play because Rs == 0.
+ */
+#if 0
+ gl_FragColor = vec4(vec3(F0 / 2 + .5), 1);
+#endif
+/* Normal visualization */
+/*
+vec3 temp = vec3((normal.x + 1) / 2,
+ (normal.y + 1) / 2,
+ (normal.z + 1) / 2);
+gl_FragColor = vec4(temp.xyz, 0);
+*/
+/*
+ gl_FragColor = texture2D(normal_sampler, texcoord);
+*/
+}
+#endif \ No newline at end of file
diff --git a/ground.vert b/ground.vert
new file mode 100644
index 0000000..a1e3dd9
--- /dev/null
+++ b/ground.vert
@@ -0,0 +1,28 @@
+/*uniform vec3 light_eye;
+varying vec2 texcoord;
+varying vec3 light_surf;
+varying vec3 eye_surf;
+varying vec3 tangent_surf;
+*/
+uniform mat4 mvp, mv;
+
+void main()
+{
+/* vec3 t = (mv * vec4(1.0,, 0.0)).xyz;
+ vec3 n = (mv * vec4(gl_Normal, 0.0)).xyz;
+*/
+ gl_Position = mvp * gl_Vertex;
+/*
+ mat3 tbn = mat3(t,
+ cross(n, t),
+ n
+ );
+
+ vec3 vertex_eye = vec3(mv * gl_Vertex);
+
+ texcoord = vec2(gl_MultiTexCoord0.x * 4, gl_MultiTexCoord0.y);
+ light_surf = normalize((light_eye - vertex_eye) * tbn);
+ eye_surf = normalize((-vertex_eye) * tbn);
+ tangent_surf = gl_MultiTexCoord1.xyz * tbn;
+*/
+}