diff options
Diffstat (limited to 'shadow_map.c')
-rw-r--r-- | shadow_map.c | 142 |
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); +} |