summaryrefslogtreecommitdiffstats
path: root/src/demos/hwShadowmapsSimple
diff options
context:
space:
mode:
Diffstat (limited to 'src/demos/hwShadowmapsSimple')
-rw-r--r--src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java830
1 files changed, 830 insertions, 0 deletions
diff --git a/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java b/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java
new file mode 100644
index 0000000..1c7effe
--- /dev/null
+++ b/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java
@@ -0,0 +1,830 @@
+/*
+ * Portions Copyright (C) 2003-2005 Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*
+ *
+ * COPYRIGHT NVIDIA CORPORATION 2003. ALL RIGHTS RESERVED.
+ * BY ACCESSING OR USING THIS SOFTWARE, YOU AGREE TO:
+ *
+ * 1) ACKNOWLEDGE NVIDIA'S EXCLUSIVE OWNERSHIP OF ALL RIGHTS
+ * IN AND TO THE SOFTWARE;
+ *
+ * 2) NOT MAKE OR DISTRIBUTE COPIES OF THE SOFTWARE WITHOUT
+ * INCLUDING THIS NOTICE AND AGREEMENT;
+ *
+ * 3) ACKNOWLEDGE THAT TO THE MAXIMUM EXTENT PERMITTED BY
+ * APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* AND
+ * THAT NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED
+ * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY
+ * SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES
+ * WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
+ * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
+ * INFORMATION, OR ANY OTHER PECUNIARY LOSS), INCLUDING ATTORNEYS'
+ * FEES, RELATING TO THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+package demos.hwShadowmapsSimple;
+
+import com.sun.opengl.util.gl2.GLUT;
+import com.sun.opengl.util.texture.Texture;
+import com.sun.opengl.util.texture.TextureIO;
+import demos.common.Demo;
+import demos.common.DemoListener;
+import gleem.BSphere;
+import gleem.BSphereProvider;
+import gleem.CameraParameters;
+import gleem.ExaminerViewer;
+import gleem.HandleBoxManip;
+import gleem.ManipManager;
+import gleem.MouseButtonHelper;
+import gleem.linalg.Mat4f;
+import gleem.linalg.Rotf;
+import gleem.linalg.Vec3f;
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.util.ArrayList;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLPbuffer;
+import javax.media.opengl.awt.AWTGLAutoDrawable;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.glu.GLU;
+import javax.swing.JOptionPane;
+
+
+/** This demo is a simple illustration of ARB_shadow and ARB_depth_texture. <P>
+ Cass Everitt <BR>
+ 12-11-00 <P>
+
+ hw_shadowmaps_simple (c) 2001 NVIDIA Corporation <P>
+
+ Ported to Java by Kenneth Russell
+*/
+
+public class HWShadowmapsSimple extends Demo {
+ public static void main(String[] args) {
+ final GLCanvas canvas = new GLCanvas();
+ final HWShadowmapsSimple demo = new HWShadowmapsSimple();
+ canvas.addGLEventListener(demo);
+
+ canvas.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ demo.dispatchKey(e.getKeyChar());
+ demo.demoListener.repaint();
+ }
+ });
+
+ demo.setDemoListener(new DemoListener() {
+ public void shutdownDemo() {
+ runExit();
+ }
+ public void repaint() {
+ canvas.repaint();
+ }
+ });
+
+ Frame frame = new Frame("ARB_shadow Shadows");
+ frame.setLayout(new BorderLayout());
+ canvas.setSize(512, 512);
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.setVisible(true);
+ canvas.requestFocus();
+
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ runExit();
+ }
+ });
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ public void shutdownDemo() {
+ ManipManager.getManipManager().unregisterWindow((AWTGLAutoDrawable) drawable);
+ drawable.removeGLEventListener(this);
+ super.shutdownDemo();
+ }
+
+ private GLPbuffer pbuffer;
+
+ private GLU glu;
+ private GLUT glut;
+
+ private float[] light_ambient = { 0, 0, 0, 0 };
+ private float[] light_intensity = { 1, 1, 1, 1 };
+ private float[] light_pos = { 0, 0, 0, 1 };
+
+ static class Tweak {
+ String name;
+ float val;
+ float incr;
+
+ Tweak(String name, float val, float incr) {
+ this.name = name;
+ this.val = val;
+ this.incr = incr;
+ }
+ };
+ private java.util.List/*<Tweak>*/ tweaks = new ArrayList();
+ private static final int R_COORDINATE_SCALE = 0;
+ private static final int R_COORDINATE_BIAS = 1;
+ private static final int POLYGON_OFFSET_SCALE = 2;
+ private static final int POLYGON_OFFSET_BIAS = 3;
+ private int curr_tweak;
+
+ // Texture objects
+ private static final int TEX_SIZE = 1024;
+ private Texture decal;
+ private Texture light_image;
+ private int light_view_depth;
+
+ // Depth buffer format
+ private int depth_format;
+
+ private boolean fullyInitialized;
+
+ // Display mode
+ private static final int RENDER_SCENE_FROM_CAMERA_VIEW = 0;
+ private static final int RENDER_SCENE_FROM_CAMERA_VIEW_SHADOWED = 1;
+ private static final int RENDER_SCENE_FROM_LIGHT_VIEW = 2;
+ private static final int NUM_DISPLAY_MODES = 3;
+ private int displayMode = 1;
+
+ // Display lists
+ private int quad;
+ private int wirecube;
+ private int geometry;
+
+ // Shadowing light
+ private float lightshaper_fovy = 60.0f;
+ private float lightshaper_zNear = 0.5f;
+ private float lightshaper_zFar = 5.0f;
+
+ // Manipulators
+ private GLAutoDrawable drawable;
+ private ExaminerViewer viewer;
+ private boolean doViewAll = true;
+ // private float zNear = 0.5f;
+ // private float zFar = 5.0f;
+ private float zNear = 0.5f;
+ private float zFar = 50.0f;
+ private HandleBoxManip object;
+ private HandleBoxManip spotlight;
+ private Mat4f cameraPerspective = new Mat4f();
+ private Mat4f cameraTransform = new Mat4f();
+ private Mat4f cameraInverseTransform = new Mat4f();
+ private Mat4f spotlightTransform = new Mat4f();
+ private Mat4f spotlightInverseTransform = new Mat4f();
+ private Mat4f objectTransform = new Mat4f();
+ private int viewportX;
+ private int viewportY;
+
+ public void init(GLAutoDrawable drawable) {
+ // Use debug pipeline
+ // drawable.setGL(new DebugGL(drawable.getGL().getGL2()));
+
+ GL2 gl = drawable.getGL().getGL2();
+ glu = new GLU();
+ glut = new GLUT();
+
+ try {
+ checkExtension(gl, "GL_VERSION_1_3"); // For multitexture
+ checkExtension(gl, "GL_ARB_depth_texture");
+ checkExtension(gl, "GL_ARB_shadow");
+ checkExtension(gl, "GL_ARB_pbuffer");
+ checkExtension(gl, "GL_ARB_pixel_format");
+ } catch (GLException e) {
+ e.printStackTrace();
+ throw(e);
+ }
+
+ gl.glClearColor(.5f, .5f, .5f, .5f);
+
+ try {
+ decal = TextureIO.newTexture(getClass().getClassLoader().getResourceAsStream("demos/data/images/decal_image.png"),
+ true,
+ TextureIO.PNG);
+ decal.setTexParameteri(GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
+ decal.setTexParameteri(GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
+ light_image = TextureIO.newTexture(getClass().getClassLoader().getResourceAsStream("demos/data/images/nvlogo_spot.png"),
+ true,
+ TextureIO.PNG);
+ } catch (IOException e) {
+ throw new GLException(e);
+ }
+
+ quad = gl.glGenLists(1);
+ gl.glNewList(quad, GL2.GL_COMPILE);
+ gl.glPushMatrix();
+ gl.glRotatef(-90, 1, 0, 0);
+ gl.glScalef(4,4,4);
+ gl.glBegin(GL2.GL_QUADS);
+ gl.glNormal3f(0, 0, 1);
+ gl.glVertex2f(-1, -1);
+ gl.glVertex2f(-1, 1);
+ gl.glVertex2f( 1, 1);
+ gl.glVertex2f( 1, -1);
+ gl.glEnd();
+ gl.glPopMatrix();
+ gl.glEndList();
+
+ wirecube = gl.glGenLists(1);
+ gl.glNewList(wirecube, GL2.GL_COMPILE);
+ glut.glutWireCube(2);
+ gl.glEndList();
+
+ geometry = gl.glGenLists(1);
+ gl.glNewList(geometry, GL2.GL_COMPILE);
+ gl.glPushMatrix();
+ glut.glutSolidTeapot(0.8f);
+ gl.glPopMatrix();
+ gl.glEndList();
+
+ gl.glEnable(GL2.GL_LIGHT0);
+ gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, light_ambient, 0);
+ gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, light_intensity, 0);
+ gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, light_intensity, 0);
+
+ gl.glEnable(GL2.GL_DEPTH_TEST);
+
+ // init pbuffer
+ GLCapabilities caps = new GLCapabilities(gl.getGLProfile());
+ caps.setDoubleBuffered(false);
+
+ if (!GLDrawableFactory.getFactory(gl.getGLProfile()).canCreateGLPbuffer()) {
+ unavailableExtension("Can not create pbuffer");
+ }
+ if (pbuffer != null) {
+ pbuffer.destroy();
+ pbuffer = null;
+ }
+ pbuffer = GLDrawableFactory.getFactory(gl.getGLProfile()).createGLPbuffer(caps, null, TEX_SIZE, TEX_SIZE, drawable.getContext());
+ pbuffer.addGLEventListener(new PbufferListener());
+
+ doViewAll = true;
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) drawable);
+ this.drawable = drawable;
+
+ object = new HandleBoxManip();
+ object.setTranslation(new Vec3f(0, 0.7f, 1.8f));
+ object.setGeometryScale(new Vec3f(0.7f, 0.7f, 0.7f));
+ manager.showManipInWindow(object, (AWTGLAutoDrawable) drawable);
+
+ spotlight = new HandleBoxManip();
+ spotlight.setScale(new Vec3f(0.5f, 0.5f, 0.5f));
+ spotlight.setTranslation(new Vec3f(-0.25f, 2.35f, 5.0f));
+ spotlight.setRotation(new Rotf(Vec3f.X_AXIS, (float) Math.toRadians(-30.0f)));
+ manager.showManipInWindow(spotlight, (AWTGLAutoDrawable) drawable);
+
+ viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons());
+ viewer.attach((AWTGLAutoDrawable) drawable, new BSphereProvider() {
+ public BSphere getBoundingSphere() {
+ return new BSphere(object.getTranslation(), 2.0f);
+ }
+ });
+ viewer.setOrientation(new Rotf(Vec3f.Y_AXIS, (float) Math.toRadians(45.0f)).times
+ (new Rotf(Vec3f.X_AXIS, (float) Math.toRadians(-15.0f))));
+ viewer.setVertFOV((float) Math.toRadians(lightshaper_fovy / 2.0f));
+ viewer.setZNear(zNear);
+ viewer.setZFar(zFar);
+
+ float bias = 1/((float) Math.pow(2.0,16.0)-1);
+
+ tweaks.add(new Tweak("r coordinate scale", 0.5f, bias));
+ tweaks.add(new Tweak("r coordinate bias", 0.5f, bias));
+ tweaks.add(new Tweak("polygon offset scale", 2.5f, 0.5f));
+ tweaks.add(new Tweak("polygon offset bias", 10.0f, 1.0f));
+
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ glu = null;
+ glut = null;
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ viewer.update();
+
+ // Grab these values once per render to avoid multithreading
+ // issues with their values being changed by manipulation from
+ // the AWT thread during the render
+ CameraParameters params = viewer.getCameraParameters();
+
+ cameraPerspective.set(params.getProjectionMatrix());
+ cameraInverseTransform.set(params.getModelviewMatrix());
+ cameraTransform.set(cameraInverseTransform);
+ cameraTransform.invertRigid();
+ spotlightTransform.set(spotlight.getTransform());
+ spotlightInverseTransform.set(spotlightTransform);
+ spotlightInverseTransform.invertRigid();
+ objectTransform.set(object.getTransform());
+
+ if (displayMode == RENDER_SCENE_FROM_CAMERA_VIEW_SHADOWED || !fullyInitialized) {
+ if (pbuffer != null) {
+ pbuffer.display();
+ }
+ }
+
+ if (!fullyInitialized) {
+ // Repaint again later once everything is set up
+ demoListener.repaint();
+ return;
+ }
+
+ GL2 gl = drawable.getGL().getGL2();
+
+ gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
+
+ if (doViewAll) {
+ viewer.viewAll(gl);
+ doViewAll = false;
+ // Immediately zap effects
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ // Schedule repaint to clean up first bogus frame
+ demoListener.repaint();
+ }
+
+ switch (displayMode) {
+ case RENDER_SCENE_FROM_CAMERA_VIEW: render_scene_from_camera_view(gl, drawable, params); break;
+ case RENDER_SCENE_FROM_CAMERA_VIEW_SHADOWED: render_scene_from_camera_view_shadowed(gl, drawable, params); break;
+ case RENDER_SCENE_FROM_LIGHT_VIEW: render_scene_from_light_view(gl, drawable, viewportX, viewportY); break;
+ default: throw new RuntimeException("Illegal display mode " + displayMode);
+ }
+ }
+
+ // Unused routines
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ viewportX = x;
+ viewportY = y;
+ }
+ public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
+
+ private void checkExtension(GL2 gl, String extensionName) {
+ if (!gl.isExtensionAvailable(extensionName)) {
+ String message = "Unable to initialize " + extensionName + " OpenGL extension";
+ unavailableExtension(message);
+ }
+ }
+
+ private void unavailableExtension(String message) {
+ JOptionPane.showMessageDialog(null, message, "Unavailable extension", JOptionPane.ERROR_MESSAGE);
+ throw new GLException(message);
+ }
+
+ private void dispatchKey(char k) {
+ switch (k) {
+ case 27:
+ case 'q':
+ shutdownDemo();
+ break;
+
+ case 'v':
+ doViewAll = true;
+ System.err.println("Forcing viewAll()");
+ break;
+
+ case ' ':
+ displayMode = (displayMode + 1) % NUM_DISPLAY_MODES;
+ System.err.println("Switching to display mode " + displayMode);
+ break;
+
+ // FIXME: add more key behaviors from original demo
+
+ default:
+ break;
+ }
+ }
+
+ class PbufferListener implements GLEventListener {
+ public void init(GLAutoDrawable drawable) {
+ // Use debug pipeline
+ // drawable.setGL(new DebugGL(drawable.getGL()));
+
+ GL2 gl = drawable.getGL().getGL2();
+
+ gl.glEnable(GL2.GL_DEPTH_TEST);
+
+ int[] depth_bits = new int[1];
+ gl.glGetIntegerv(GL2.GL_DEPTH_BITS, depth_bits, 0);
+
+ if (depth_bits[0] == 16) depth_format = GL2.GL_DEPTH_COMPONENT16;
+ else depth_format = GL2.GL_DEPTH_COMPONENT24;
+
+ light_view_depth = genTexture(gl);
+ gl.glBindTexture(GL2.GL_TEXTURE_2D, light_view_depth);
+ gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, depth_format, TEX_SIZE, TEX_SIZE, 0,
+ GL2.GL_DEPTH_COMPONENT, GL2.GL_UNSIGNED_INT, null);
+ set_light_view_texture_parameters(gl);
+
+ fullyInitialized = true;
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+
+ gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
+
+ gl.glPolygonOffset(((Tweak) tweaks.get(POLYGON_OFFSET_SCALE)).val,
+ ((Tweak) tweaks.get(POLYGON_OFFSET_BIAS)).val);
+ gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL);
+
+ render_scene_from_light_view(gl, drawable, 0, 0);
+
+ gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL);
+
+ gl.glBindTexture(GL2.GL_TEXTURE_2D, light_view_depth);
+
+ // trying different ways of getting the depth info over
+ gl.glCopyTexSubImage2D(GL2.GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEX_SIZE, TEX_SIZE);
+ }
+
+ // Unused routines
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
+ public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
+ }
+
+ private void set_light_view_texture_parameters(GL2 gl) {
+ gl.glBindTexture(GL2.GL_TEXTURE_2D, light_view_depth);
+ gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
+ gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
+ gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE);
+ gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_COMPARE_FUNC, GL2.GL_LEQUAL);
+ }
+
+ private int genTexture(GL2 gl) {
+ int[] tmp = new int[1];
+ gl.glGenTextures(1, tmp, 0);
+ return tmp[0];
+ }
+
+ private void eye_linear_texgen(GL2 gl) {
+ Mat4f m = new Mat4f();
+ m.makeIdent();
+
+ set_texgen_planes(gl, GL2.GL_EYE_PLANE, m);
+ gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
+ gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
+ gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
+ gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR);
+ }
+
+ private void obj_linear_texgen(GL2 gl) {
+ Mat4f m = new Mat4f();
+ m.makeIdent();
+
+ set_texgen_planes(gl, GL2.GL_OBJECT_PLANE, m);
+ gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR);
+ gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR);
+ gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR);
+ gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR);
+ }
+
+ private void set_texgen_planes(GL2 gl, int plane_type, Mat4f m) {
+ int[] coord = {GL2.GL_S, GL2.GL_T, GL2.GL_R, GL2.GL_Q};
+ float[] row = new float[4];
+ for(int i = 0; i < 4; i++) {
+ getRow(m, i, row);
+ gl.glTexGenfv(coord[i], plane_type, row, 0);
+ }
+ }
+
+ private void texgen(GL2 gl, boolean enable) {
+ if(enable) {
+ gl.glEnable(GL2.GL_TEXTURE_GEN_S);
+ gl.glEnable(GL2.GL_TEXTURE_GEN_T);
+ gl.glEnable(GL2.GL_TEXTURE_GEN_R);
+ gl.glEnable(GL2.GL_TEXTURE_GEN_Q);
+ } else {
+ gl.glDisable(GL2.GL_TEXTURE_GEN_S);
+ gl.glDisable(GL2.GL_TEXTURE_GEN_T);
+ gl.glDisable(GL2.GL_TEXTURE_GEN_R);
+ gl.glDisable(GL2.GL_TEXTURE_GEN_Q);
+ }
+ }
+
+ private void render_light_frustum(GL2 gl) {
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ applyTransform(gl, spotlightTransform);
+ applyTransform(gl, perspectiveInverse(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar));
+ gl.glDisable(GL2.GL_LIGHTING);
+ gl.glColor3f(1,1,0);
+ gl.glCallList(wirecube);
+ gl.glColor3f(1,1,1);
+ gl.glEnable(GL2.GL_LIGHTING);
+ gl.glPopMatrix();
+ }
+
+ private void render_quad(GL2 gl) {
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+ obj_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glScalef(4,4,1);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+
+ gl.glDisable(GL2.GL_LIGHTING);
+ decal.bind();
+ decal.enable();
+ gl.glCallList(quad);
+ decal.disable();
+ gl.glEnable(GL2.GL_LIGHTING);
+
+ texgen(gl, false);
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ }
+
+ private void render_scene(GL2 gl, Mat4f view, GLAutoDrawable drawable, CameraParameters params) {
+ gl.glColor3f(1,1,1);
+ gl.glPushMatrix();
+ Mat4f inverseView = new Mat4f(view);
+ inverseView.invertRigid();
+ applyTransform(gl, inverseView);
+
+ gl.glPushMatrix();
+ render_quad(gl);
+
+ applyTransform(gl, objectTransform);
+
+ gl.glEnable(GL2.GL_LIGHTING);
+ gl.glCallList(geometry);
+ gl.glDisable(GL2.GL_LIGHTING);
+
+ gl.glPopMatrix();
+
+ gl.glPopMatrix();
+ }
+
+ private void render_manipulators(GL2 gl, Mat4f view, GLAutoDrawable drawable, CameraParameters params) {
+ gl.glColor3f(1,1,1);
+ gl.glPushMatrix();
+ Mat4f inverseView = new Mat4f(view);
+ inverseView.invertRigid();
+ applyTransform(gl, inverseView);
+
+ if (params != null) {
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, params);
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+ }
+
+ gl.glPopMatrix();
+ }
+
+ private void render_scene_from_camera_view(GL2 gl, GLAutoDrawable drawable, CameraParameters params) {
+ // place light
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ applyTransform(gl, cameraInverseTransform);
+ applyTransform(gl, spotlightTransform);
+ gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, light_pos, 0);
+ gl.glPopMatrix();
+
+ // spot image
+ gl.glActiveTexture(GL2.GL_TEXTURE1);
+
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glTranslatef(.5f, .5f, .5f);
+ gl.glScalef(.5f, -.5f, .5f);
+ glu.gluPerspective(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar);
+ applyTransform(gl, spotlightInverseTransform);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+
+ light_image.bind();
+ light_image.enable();
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
+
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glViewport(viewportX, viewportY, drawable.getWidth(), drawable.getHeight());
+ applyTransform(gl, cameraPerspective);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ render_scene(gl, cameraTransform, drawable, params);
+
+ gl.glActiveTexture(GL2.GL_TEXTURE1);
+ light_image.disable();
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+
+ render_manipulators(gl, cameraTransform, drawable, params);
+
+ render_light_frustum(gl);
+ }
+
+ private void render_scene_from_camera_view_shadowed(GL2 gl, GLAutoDrawable drawable, CameraParameters params) {
+ // place light
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ applyTransform(gl, cameraInverseTransform);
+ applyTransform(gl, spotlightTransform);
+ gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, light_pos, 0);
+ gl.glPopMatrix();
+
+ // spot image
+ gl.glActiveTexture(GL2.GL_TEXTURE1);
+
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glTranslatef(.5f, .5f, .5f);
+ gl.glScalef(.5f, -.5f, .5f);
+ glu.gluPerspective(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar);
+ applyTransform(gl, spotlightInverseTransform);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+
+ light_image.bind();
+ light_image.enable();
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
+
+ // depth compare
+ gl.glActiveTexture(GL2.GL_TEXTURE2);
+
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glTranslatef(.5f, .5f, ((Tweak) tweaks.get(R_COORDINATE_SCALE)).val);
+ gl.glScalef(.5f, .5f, ((Tweak) tweaks.get(R_COORDINATE_BIAS)).val);
+ glu.gluPerspective(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar);
+ applyTransform(gl, spotlightInverseTransform);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+
+ gl.glBindTexture(GL2.GL_TEXTURE_2D, light_view_depth);
+ gl.glEnable(GL2.GL_TEXTURE_2D);
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
+
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glViewport(viewportX, viewportY, drawable.getWidth(), drawable.getHeight());
+ applyTransform(gl, cameraPerspective);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ render_scene(gl, cameraTransform, drawable, params);
+
+ gl.glActiveTexture(GL2.GL_TEXTURE1);
+ light_image.disable();
+ gl.glActiveTexture(GL2.GL_TEXTURE2);
+ gl.glDisable(GL2.GL_TEXTURE_2D);
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+
+ render_manipulators(gl, cameraTransform, drawable, params);
+
+ render_light_frustum(gl);
+ }
+
+ private void largest_square_power_of_two_viewport(GL2 gl, GLAutoDrawable drawable, int viewportX, int viewportY) {
+ float min = Math.min(drawable.getWidth(), drawable.getHeight());
+ float log2min = (float) Math.log(min) / (float) Math.log(2.0);
+ float pow2 = (float) Math.floor(log2min);
+ int size = 1 << (int) pow2;
+ gl.glViewport(viewportX, viewportY, size, size);
+ }
+
+ private void render_scene_from_light_view(GL2 gl, GLAutoDrawable drawable, int viewportX, int viewportY) {
+ // place light
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, light_pos, 0);
+ gl.glPopMatrix();
+
+ // spot image
+ gl.glActiveTexture(GL2.GL_TEXTURE1);
+
+ gl.glPushMatrix();
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glTranslatef(.5f, .5f, .5f);
+ gl.glScalef(.5f, .5f, .5f);
+ glu.gluPerspective(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+
+ light_image.bind();
+ light_image.enable();
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
+
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+
+ gl.glViewport(0, 0, TEX_SIZE, TEX_SIZE);
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar);
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ if (displayMode == RENDER_SCENE_FROM_LIGHT_VIEW)
+ largest_square_power_of_two_viewport(gl, drawable, viewportX, viewportY);
+ render_scene(gl, spotlightTransform, null, null);
+
+ gl.glActiveTexture(GL2.GL_TEXTURE1);
+ light_image.disable();
+ gl.glActiveTexture(GL2.GL_TEXTURE0);
+ }
+
+ private static void getRow(Mat4f m, int row, float[] out) {
+ out[0] = m.get(row, 0);
+ out[1] = m.get(row, 1);
+ out[2] = m.get(row, 2);
+ out[3] = m.get(row, 3);
+ }
+
+ private static void applyTransform(GL2 gl, Mat4f xform) {
+ float[] data = new float[16];
+ xform.getColumnMajorData(data);
+ gl.glMultMatrixf(data, 0);
+ }
+
+ private static Mat4f perspectiveInverse(float fovy, float aspect, float zNear, float zFar) {
+ float tangent = (float) Math.tan(Math.toRadians(fovy / 2.0));
+ float y = tangent * zNear;
+ float x = aspect * y;
+ return frustumInverse(-x, x, -y, y, zNear, zFar);
+ }
+
+ private static Mat4f frustumInverse(float left, float right,
+ float bottom, float top,
+ float zNear, float zFar) {
+ Mat4f m = new Mat4f();
+ m.makeIdent();
+
+ m.set(0, 0, (right - left) / (2 * zNear));
+ m.set(0, 3, (right + left) / (2 * zNear));
+
+ m.set(1, 1, (top - bottom) / (2 * zNear));
+ m.set(1, 3, (top + bottom) / (2 * zNear));
+
+ m.set(2, 2, 0);
+ m.set(2, 3, -1);
+
+ m.set(3, 2, -(zFar - zNear) / (2 * zFar * zNear));
+ m.set(3, 3, (zFar + zNear) / (2 * zFar * zNear));
+
+ return m;
+ }
+
+ private static void runExit() {
+ // Note: calling System.exit() synchronously inside the draw,
+ // reshape or init callbacks can lead to deadlocks on certain
+ // platforms (in particular, X11) because the JAWT's locking
+ // routines cause a global AWT lock to be grabbed. Run the
+ // exit routine in another thread.
+ new Thread(new Runnable() {
+ public void run() {
+ System.exit(0);
+ }
+ }).start();
+ }
+}