summaryrefslogtreecommitdiff
path: root/shadow_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'shadow_map.c')
-rw-r--r--shadow_map.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/shadow_map.c b/shadow_map.c
new file mode 100644
index 0000000..290343a
--- /dev/null
+++ b/shadow_map.c
@@ -0,0 +1,142 @@
+/*
+ * 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"
+
+extern int no_multi_draw_arrays;
+extern GLUvec4 eye_world;
+static GLUmat4 world_to_light_eye, world_to_light_ndc;
+GLuint shadow_tex = 0, shadow_fbo;
+
+static void
+calculate_light_projection(void)
+{
+ GLUvec4 light_up;
+ GLUmat4 temp;
+
+ /* Wrong. So wrong. */
+ light_up.values[0] = 1.0;
+ light_up.values[1] = 0.0;
+ light_up.values[2] = 0.0;
+ light_up.values[3] = 1.0;
+
+ /* Transform for looking from they eye's point of view at the pile of
+ * rings.
+ */
+ gluLookAt4v(&world_to_light_eye,
+ &light_world,
+ &ring_bounding_sphere_center_world,
+ &light_up);
+ gluPerspective4(&temp, 90, /*XXX: calculate me */
+ 1.0, /* we're using a bounding sphere, w == h */
+ 0.2, 40);
+ gluMult4m_4m(&world_to_light_ndc, &temp, &world_to_light_eye);
+}
+
+/* The ground plane is located in world coordinates, so no need to do any
+ * object_to_world transformation.
+ */
+static void
+install_shadow_transform(int instance)
+{
+ GLUmat4 mvp;
+
+ gluMult4m_4m(&mvp, &world_to_light_ndc, &ring_obj_to_world[instance]);
+
+ glUniformMatrix4fv(shadow_uniforms[SHADOW_UNIFORM_MVP].location, 1, 0,
+ (float *)&mvp);
+}
+
+void
+generate_rings_shadowmap(void)
+{
+ int instance;
+ int shadow_width = 256, shadow_height = 256;
+
+ if (shadow_prog == 0)
+ return;
+
+ glUseProgram(shadow_prog);
+
+ calculate_light_projection();
+
+ if (shadow_tex == 0) {
+ GLenum status;
+
+ glGenTextures(1, &shadow_tex);
+ glBindTexture(GL_TEXTURE_2D, shadow_tex);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
+ shadow_width, shadow_height, 0,
+ GL_RGBA, GL_FLOAT, NULL);
+
+ glGenFramebuffersEXT(1, &shadow_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, shadow_fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D,
+ shadow_tex,
+ 0);
+ status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ fprintf(stderr, "shadow map FBO complete: 0x%08x\n",
+ status);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, shadow_fbo);
+ glViewport(0, 0, shadow_width, shadow_height);
+
+ /* Clear to the material color. */
+ glClearColor(1.0, 0.7, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* Draw the rings in black. */
+ glBindVertexArray(ring.shadow_array_obj);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ring.vbo);
+ for (instance = 0; instance < NUM_RINGS; instance++) {
+ install_shadow_transform(instance);
+ do_ring_drawelements();
+ }
+
+ glEnable(GL_DEPTH_TEST);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+}