summaryrefslogtreecommitdiffstats
path: root/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java')
-rw-r--r--src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java844
1 files changed, 844 insertions, 0 deletions
diff --git a/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java b/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java
new file mode 100644
index 0000000..5eb5614
--- /dev/null
+++ b/src/demos/hwShadowmapsSimple/HWShadowmapsSimple.java
@@ -0,0 +1,844 @@
+/*
+ * Portions Copyright (C) 2003 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 java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+import javax.imageio.*;
+
+import net.java.games.jogl.*;
+import net.java.games.jogl.util.*;
+import demos.util.*;
+import gleem.*;
+import gleem.linalg.*;
+
+/** 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 {
+ private volatile boolean quit;
+
+ private GLCanvas canvas;
+ private GLPbuffer pbuffer;
+
+ 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 int decal;
+ private int 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 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();
+
+ // Profiling
+ private DurationTimer timer = new DurationTimer();
+ private boolean firstRender = true;
+ private int frameCount;
+
+ public static void main(String[] args) {
+ new HWShadowmapsSimple().run(args);
+ }
+
+ public void run(String[] args) {
+ canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
+ canvas.addGLEventListener(new Listener());
+ canvas.setNoAutoRedrawMode(true);
+
+ Frame frame = new Frame("ARB_shadow Shadows");
+ frame.setLayout(new BorderLayout());
+ canvas.setSize(512, 512);
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.show();
+ canvas.requestFocus();
+
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ quit = true;
+ }
+ });
+
+ while (!quit) {
+ if (viewer != null) {
+ 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();
+ }
+ }
+ canvas.display();
+ }
+
+ System.exit(0);
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ class Listener implements GLEventListener {
+
+ public void init(GLDrawable drawable) {
+ // drawable.setGL(new DebugGL(drawable.getGL()));
+
+ GL gl = drawable.getGL();
+ GLU glu = drawable.getGLU();
+ glut = new GLUT();
+
+ try {
+ checkExtension(gl, "GL_ARB_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();
+ quit = true;
+ throw(e);
+ }
+
+ gl.glClearColor(.5f, .5f, .5f, .5f);
+
+ decal = genTexture(gl);
+ gl.glBindTexture(GL.GL_TEXTURE_2D, decal);
+ BufferedImage img = readPNGImage("demos/data/images/decal_image.png");
+ makeRGBTexture(gl, glu, img, GL.GL_TEXTURE_2D, true);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
+
+ light_image = genTexture(gl);
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_image);
+ img = readPNGImage("demos/data/images/nvlogo_spot.png");
+ makeRGBTexture(gl, glu, img, GL.GL_TEXTURE_2D, true);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
+
+ quad = gl.glGenLists(1);
+ gl.glNewList(quad, GL.GL_COMPILE);
+ gl.glPushMatrix();
+ gl.glRotatef(-90, 1, 0, 0);
+ gl.glScalef(4,4,4);
+ gl.glBegin(GL.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, GL.GL_COMPILE);
+ glut.glutWireCube(gl, 2);
+ gl.glEndList();
+
+ geometry = gl.glGenLists(1);
+ gl.glNewList(geometry, GL.GL_COMPILE);
+ gl.glPushMatrix();
+ // gl.glTranslatef(0, .4f, 0);
+ // FIXME
+ // glutSolidTeapot(.5f);
+ glut.glutSolidTorus(gl, 0.25f, 0.5f, 40, 20);
+ gl.glPopMatrix();
+ gl.glEndList();
+
+ gl.glEnable(GL.GL_LIGHT0);
+ gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, light_ambient);
+ gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, light_intensity);
+ gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, light_intensity);
+
+ gl.glEnable(GL.GL_DEPTH_TEST);
+
+ // init pbuffer
+ GLCapabilities caps = new GLCapabilities();
+ caps.setDoubleBuffered(false);
+ pbuffer = drawable.createOffscreenDrawable(caps, TEX_SIZE, TEX_SIZE);
+ pbuffer.addGLEventListener(new PbufferListener());
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow(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, 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, drawable);
+
+ viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons());
+ viewer.attach(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));
+
+ drawable.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ dispatchKey(e.getKeyChar());
+ }
+ });
+ }
+
+ public void display(GLDrawable drawable) {
+ if (quit) {
+ return;
+ }
+
+ if (!fullyInitialized) {
+ return;
+ }
+
+ if (!firstRender) {
+ if (++frameCount == 30) {
+ timer.stop();
+ System.err.println("Frames per second: " + (30.0f / timer.getDurationAsSeconds()));
+ timer.reset();
+ timer.start();
+ frameCount = 0;
+ }
+ } else {
+ firstRender = false;
+ timer.start();
+ }
+
+ GL gl = drawable.getGL();
+ GLU glu = drawable.getGLU();
+
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ if (doViewAll) {
+ viewer.viewAll(gl);
+ doViewAll = false;
+ // Immediately zap effects
+ gl.glMatrixMode(GL.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glMatrixMode(GL.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ }
+
+ CameraParameters params = viewer.getCameraParameters();
+
+ switch (displayMode) {
+ case RENDER_SCENE_FROM_CAMERA_VIEW: render_scene_from_camera_view(gl, glu, drawable, params); break;
+ case RENDER_SCENE_FROM_CAMERA_VIEW_SHADOWED: render_scene_from_camera_view_shadowed(gl, glu, drawable, params); break;
+ case RENDER_SCENE_FROM_LIGHT_VIEW: render_scene_from_light_view(gl, glu); break;
+ default: throw new RuntimeException("Illegal display mode " + displayMode);
+ }
+ }
+
+ // Unused routines
+ public void reshape(GLDrawable drawable, int x, int y, int width, int height) {}
+ public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private void checkExtension(GL gl, String extensionName) {
+ if (!gl.isExtensionAvailable(extensionName)) {
+ throw new GLException("Unable to initialize " + extensionName + " OpenGL extension");
+ }
+ }
+
+ private void dispatchKey(char k) {
+ if ((k == (char) 27) || (k == 'q')) {
+ quit = true;
+ return;
+ }
+
+ switch (k) {
+ case 27:
+ case 'q':
+ quit = true;
+ 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(GLDrawable drawable) {
+ // drawable.setGL(new DebugGL(drawable.getGL()));
+
+ GL gl = drawable.getGL();
+ GLU glu = drawable.getGLU();
+
+ gl.glEnable(GL.GL_DEPTH_TEST);
+
+ int[] depth_bits = new int[1];
+ gl.glGetIntegerv(GL.GL_DEPTH_BITS, depth_bits);
+
+ if (depth_bits[0] == 16) depth_format = GL.GL_DEPTH_COMPONENT16_ARB;
+ else depth_format = GL.GL_DEPTH_COMPONENT24_ARB;
+
+ light_view_depth = genTexture(gl);
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_view_depth);
+ gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, depth_format, TEX_SIZE, TEX_SIZE, 0,
+ GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_INT, (byte[]) null);
+ set_light_view_texture_parameters(gl);
+
+ fullyInitialized = true;
+ }
+
+ public void display(GLDrawable drawable) {
+ GL gl = drawable.getGL();
+ GLU glu = drawable.getGLU();
+
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ gl.glPolygonOffset(((Tweak) tweaks.get(POLYGON_OFFSET_SCALE)).val,
+ ((Tweak) tweaks.get(POLYGON_OFFSET_BIAS)).val);
+ gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
+
+ render_scene_from_light_view(gl, glu);
+
+ gl.glDisable(GL.GL_POLYGON_OFFSET_FILL);
+
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_view_depth);
+
+ // trying different ways of getting the depth info over
+ gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEX_SIZE, TEX_SIZE);
+ }
+
+ // Unused routines
+ public void reshape(GLDrawable drawable, int x, int y, int width, int height) {}
+ public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
+ }
+
+ private void set_light_view_texture_parameters(GL gl) {
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_view_depth);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_COMPARE_MODE_ARB, GL.GL_COMPARE_R_TO_TEXTURE_ARB);
+ gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_COMPARE_FUNC_ARB, GL.GL_LEQUAL);
+ }
+
+ private int genTexture(GL gl) {
+ int[] tmp = new int[1];
+ gl.glGenTextures(1, tmp);
+ return tmp[0];
+ }
+
+ private BufferedImage readPNGImage(String resourceName) {
+ try {
+ BufferedImage img = ImageIO.read(getClass().getClassLoader().getResourceAsStream(resourceName));
+ if (img == null) {
+ throw new RuntimeException("Error reading resource " + resourceName);
+ }
+ return img;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void makeRGBTexture(GL gl, GLU glu, BufferedImage img, int target, boolean mipmapped) {
+ ByteBuffer dest = null;
+ switch (img.getType()) {
+ case BufferedImage.TYPE_3BYTE_BGR:
+ case BufferedImage.TYPE_CUSTOM: {
+ byte[] data = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
+ dest = ByteBuffer.allocateDirect(data.length);
+ dest.order(ByteOrder.nativeOrder());
+ dest.put(data, 0, data.length);
+ break;
+ }
+
+ case BufferedImage.TYPE_INT_RGB: {
+ int[] data = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
+ dest = ByteBuffer.allocateDirect(data.length * BufferUtils.SIZEOF_INT);
+ dest.order(ByteOrder.nativeOrder());
+ dest.asIntBuffer().put(data, 0, data.length);
+ break;
+ }
+
+ default:
+ throw new RuntimeException("Unsupported image type " + img.getType());
+ }
+
+ if (mipmapped) {
+ glu.gluBuild2DMipmaps(target, GL.GL_RGB8, img.getWidth(), img.getHeight(), GL.GL_RGB,
+ GL.GL_UNSIGNED_BYTE, dest);
+ } else {
+ gl.glTexImage2D(target, 0, GL.GL_RGB, img.getWidth(), img.getHeight(), 0,
+ GL.GL_RGB, GL.GL_UNSIGNED_BYTE, dest);
+ }
+ }
+
+ private void eye_linear_texgen(GL gl) {
+ Mat4f m = new Mat4f();
+ m.makeIdent();
+
+ set_texgen_planes(gl, GL.GL_EYE_PLANE, m);
+ gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR);
+ gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR);
+ gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR);
+ gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR);
+ }
+
+ private void obj_linear_texgen(GL gl) {
+ Mat4f m = new Mat4f();
+ m.makeIdent();
+
+ set_texgen_planes(gl, GL.GL_OBJECT_PLANE, m);
+ gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR);
+ gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR);
+ gl.glTexGeni(GL.GL_R, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR);
+ gl.glTexGeni(GL.GL_Q, GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_LINEAR);
+ }
+
+ private void set_texgen_planes(GL gl, int plane_type, Mat4f m) {
+ int[] coord = {GL.GL_S, GL.GL_T, GL.GL_R, GL.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);
+ }
+ }
+
+ private void texgen(GL gl, boolean enable) {
+ if(enable) {
+ gl.glEnable(GL.GL_TEXTURE_GEN_S);
+ gl.glEnable(GL.GL_TEXTURE_GEN_T);
+ gl.glEnable(GL.GL_TEXTURE_GEN_R);
+ gl.glEnable(GL.GL_TEXTURE_GEN_Q);
+ } else {
+ gl.glDisable(GL.GL_TEXTURE_GEN_S);
+ gl.glDisable(GL.GL_TEXTURE_GEN_T);
+ gl.glDisable(GL.GL_TEXTURE_GEN_R);
+ gl.glDisable(GL.GL_TEXTURE_GEN_Q);
+ }
+ }
+
+ private void render_light_frustum(GL gl) {
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ applyTransform(gl, spotlightTransform);
+ applyTransform(gl, perspectiveInverse(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar));
+ gl.glDisable(GL.GL_LIGHTING);
+ gl.glColor3f(1,1,0);
+ gl.glCallList(wirecube);
+ gl.glColor3f(1,1,1);
+ gl.glEnable(GL.GL_LIGHTING);
+ gl.glPopMatrix();
+ }
+
+ private void render_quad(GL gl) {
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+ obj_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glMatrixMode(GL.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glScalef(4,4,1);
+ gl.glMatrixMode(GL.GL_MODELVIEW);
+
+ gl.glDisable(GL.GL_LIGHTING);
+ gl.glBindTexture(GL.GL_TEXTURE_2D, decal);
+ gl.glEnable(GL.GL_TEXTURE_2D);
+ gl.glCallList(quad);
+ gl.glDisable(GL.GL_TEXTURE_2D);
+ gl.glEnable(GL.GL_LIGHTING);
+
+ texgen(gl, false);
+ gl.glMatrixMode(GL.GL_TEXTURE);
+ gl.glLoadIdentity();
+ gl.glMatrixMode(GL.GL_MODELVIEW);
+ }
+
+ private void render_scene(GL gl, Mat4f view, GLDrawable 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(GL.GL_LIGHTING);
+ gl.glCallList(geometry);
+ gl.glDisable(GL.GL_LIGHTING);
+
+ gl.glPopMatrix();
+
+ gl.glPopMatrix();
+ }
+
+ private void render_manipulators(GL gl, Mat4f view, GLDrawable 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(drawable, params);
+ ManipManager.getManipManager().render(drawable, gl);
+ }
+
+ gl.glPopMatrix();
+ }
+
+ private void render_scene_from_camera_view(GL gl, GLU glu, GLDrawable drawable, CameraParameters params) {
+ // place light
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ applyTransform(gl, cameraInverseTransform);
+ applyTransform(gl, spotlightTransform);
+ gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_pos);
+ gl.glPopMatrix();
+
+ // spot image
+ gl.glActiveTextureARB(GL.GL_TEXTURE1_ARB);
+
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL.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(GL.GL_MODELVIEW);
+
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_image);
+ gl.glEnable(GL.GL_TEXTURE_2D);
+ gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
+
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+ gl.glMatrixMode(GL.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());
+ applyTransform(gl, cameraPerspective);
+ gl.glMatrixMode(GL.GL_MODELVIEW);
+ render_scene(gl, cameraTransform, drawable, params);
+
+ gl.glActiveTextureARB(GL.GL_TEXTURE1_ARB);
+ gl.glDisable(GL.GL_TEXTURE_2D);
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+
+ render_manipulators(gl, cameraTransform, drawable, params);
+
+ render_light_frustum(gl);
+ }
+
+ private void render_scene_from_camera_view_shadowed(GL gl, GLU glu, GLDrawable drawable, CameraParameters params) {
+ // place light
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ applyTransform(gl, cameraInverseTransform);
+ applyTransform(gl, spotlightTransform);
+ gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_pos);
+ gl.glPopMatrix();
+
+ // spot image
+ gl.glActiveTextureARB(GL.GL_TEXTURE1_ARB);
+
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL.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(GL.GL_MODELVIEW);
+
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_image);
+ gl.glEnable(GL.GL_TEXTURE_2D);
+ gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
+
+ // depth compare
+ gl.glActiveTextureARB(GL.GL_TEXTURE2_ARB);
+
+ gl.glPushMatrix();
+ applyTransform(gl, cameraInverseTransform);
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL.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(GL.GL_MODELVIEW);
+
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_view_depth);
+ gl.glEnable(GL.GL_TEXTURE_2D);
+ gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
+
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+
+ gl.glMatrixMode(GL.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());
+ applyTransform(gl, cameraPerspective);
+ gl.glMatrixMode(GL.GL_MODELVIEW);
+ render_scene(gl, cameraTransform, drawable, params);
+
+ gl.glActiveTextureARB(GL.GL_TEXTURE1_ARB);
+ gl.glDisable(GL.GL_TEXTURE_2D);
+ gl.glActiveTextureARB(GL.GL_TEXTURE2_ARB);
+ gl.glDisable(GL.GL_TEXTURE_2D);
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+
+ render_manipulators(gl, cameraTransform, drawable, params);
+
+ render_light_frustum(gl);
+ }
+
+ private void largest_square_power_of_two_viewport(GL gl) {
+ Dimension dim = canvas.getSize();
+ float min = Math.min(dim.width, dim.height);
+ float log2min = (float) Math.log(min) / (float) Math.log(2.0);
+ float pow2 = (float) Math.floor(log2min);
+ int size = 1 << (int) pow2;
+ gl.glViewport(0, 0, size, size);
+ }
+
+ private void render_scene_from_light_view(GL gl, GLU glu) {
+ // place light
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_pos);
+ gl.glPopMatrix();
+
+ // spot image
+ gl.glActiveTextureARB(GL.GL_TEXTURE1_ARB);
+
+ gl.glPushMatrix();
+ eye_linear_texgen(gl);
+ texgen(gl, true);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL.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(GL.GL_MODELVIEW);
+
+ gl.glBindTexture(GL.GL_TEXTURE_2D, light_image);
+ gl.glEnable(GL.GL_TEXTURE_2D);
+ gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
+
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+
+ gl.glViewport(0, 0, TEX_SIZE, TEX_SIZE);
+ gl.glMatrixMode(GL.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(lightshaper_fovy, 1, lightshaper_zNear, lightshaper_zFar);
+ gl.glMatrixMode(GL.GL_MODELVIEW);
+ if (displayMode == RENDER_SCENE_FROM_LIGHT_VIEW)
+ largest_square_power_of_two_viewport(gl);
+ render_scene(gl, spotlightTransform, null, null);
+
+ gl.glActiveTextureARB(GL.GL_TEXTURE1_ARB);
+ gl.glDisable(GL.GL_TEXTURE_2D);
+ gl.glActiveTextureARB(GL.GL_TEXTURE0_ARB);
+ }
+
+ 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(GL gl, Mat4f xform) {
+ float[] data = new float[16];
+ xform.getColumnMajorData(data);
+ gl.glMultMatrixf(data);
+ }
+
+ 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;
+ }
+}