summaryrefslogtreecommitdiffstats
path: root/src/demos/vertexProgRefract/VertexProgRefract.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/demos/vertexProgRefract/VertexProgRefract.java')
-rw-r--r--src/demos/vertexProgRefract/VertexProgRefract.java722
1 files changed, 722 insertions, 0 deletions
diff --git a/src/demos/vertexProgRefract/VertexProgRefract.java b/src/demos/vertexProgRefract/VertexProgRefract.java
new file mode 100644
index 0000000..edbef87
--- /dev/null
+++ b/src/demos/vertexProgRefract/VertexProgRefract.java
@@ -0,0 +1,722 @@
+/*
+ * 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.vertexProgRefract;
+
+import com.sun.opengl.util.gl2.GLUT;
+import com.sun.opengl.util.texture.Texture;
+import demos.common.Demo;
+import demos.common.DemoListener;
+import demos.util.Bunny;
+import demos.util.Cubemap;
+import demos.util.SystemTime;
+import demos.util.Time;
+import gleem.BSphere;
+import gleem.BSphereProvider;
+import gleem.ExaminerViewer;
+import gleem.ManipManager;
+import gleem.MouseButtonHelper;
+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 javax.media.opengl.*;
+import javax.media.opengl.awt.*;
+import javax.media.opengl.glu.GLU;
+import com.sun.opengl.util.Animator;
+import com.sun.opengl.util.BufferUtil;
+import javax.swing.JOptionPane;
+
+
+
+/**
+ Wavelength-dependent refraction demo<br>
+ It's a chromatic aberration!<br>
+ [email protected] 4/2001<br><p>
+
+ Currently 3 passes - could do it in 1 with 4 texture units<p>
+
+ Cubemap courtesy of Paul Debevec<p>
+
+ Ported to Java and ARB_fragment_program by Kenneth Russell
+*/
+
+public class VertexProgRefract extends Demo {
+ public static void main(String[] args) {
+
+ GLCanvas canvas = new GLCanvas();
+ final VertexProgRefract demo = new VertexProgRefract();
+
+ canvas.addGLEventListener(demo);
+ canvas.addKeyListener(new KeyAdapter() {
+ public void keyTyped(KeyEvent e) {
+ demo.dispatchKey(e.getKeyChar());
+ }
+ });
+
+ final Animator animator = new Animator(canvas);
+ demo.setDemoListener(new DemoListener() {
+ public void shutdownDemo() {
+ runExit(animator);
+ }
+ public void repaint() {}
+ });
+
+ Frame frame = new Frame("Refraction Using Vertex Programs");
+ 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(animator);
+ }
+ });
+
+ animator.start();
+ }
+
+// private boolean useRegisterCombiners;
+ private boolean initComplete;
+ private boolean firstRender = true;
+ private int vtxProg;
+ private int fragProg;
+ private Texture cubemap;
+ private int bunnydl;
+ private int obj;
+
+ private GLU glu = new GLU();
+ private GLUT glut = new GLUT();
+
+ private GLAutoDrawable drawable;
+ private ExaminerViewer viewer;
+ private boolean doViewAll = true;
+
+ private Time time = new SystemTime();
+ private float animRate = (float) Math.toRadians(-6.0f); // Radians / sec
+
+ private float refract = 1.1f; // ratio of indicies of refraction
+ private float wavelengthDelta = 0.05f; // difference in refraction for each "wavelength" (R,G,B)
+ private float fresnel = 2.0f; // Fresnel multiplier
+
+ private boolean wire = false;
+ private boolean toggleWire = false;
+
+ private static final String transformRefract =
+"!!ARBvp1.0\n" +
+"# Refraction\n" +
+"\n" +
+"# Parameters\n" +
+"PARAM mvp [4] = { state.matrix.mvp }; # modelview projection matrix\n" +
+"PARAM mvit[4] = { state.matrix.modelview.invtrans }; # modelview matrix inverse transpose\n" +
+"PARAM mv [4] = { state.matrix.modelview }; # modelview matrix\n" +
+"PARAM tex [4] = { state.matrix.texture }; # texture matrix\n" +
+"PARAM eyePosition = program.env[0]; # eye position\n" +
+"PARAM fresnel = program.env[1]; # fresnel multiplier\n" +
+"PARAM texScale = program.env[2]; # texture scale\n" +
+"PARAM misc = program.env[3]; # misc. constants\n" +
+"PARAM refraction = program.env[4]; # refractive index\n" +
+"\n" +
+"# Per vertex inputs\n" +
+"ATTRIB iPos = vertex.position; #position\n" +
+"ATTRIB iCol0 = vertex.color; #color\n" +
+"ATTRIB iNorm = vertex.normal; #normal\n" +
+"\n" +
+"# Temporaries\n" +
+"TEMP r0;\n" +
+"TEMP r1;\n" +
+"TEMP r2;\n" +
+"TEMP r3;\n" +
+"TEMP r8;\n" +
+"TEMP r9;\n" +
+"TEMP r11;\n" +
+"\n" +
+"# Outputs\n" +
+"OUTPUT oPos = result.position; #position\n" +
+"OUTPUT oCol0 = result.color; #primary color\n" +
+"OUTPUT oTex0 = result.texcoord[0]; #texture coordinate set 0\n" +
+"OUTPUT oTex1 = result.texcoord[1]; #texture coordinate set 1\n" +
+"\n" +
+"\n" +
+"# transform vertex position to eye space\n" +
+"DP4 r9.x, mv[0], iPos ;\n" +
+"DP4 r9.y, mv[1], iPos ;\n" +
+"DP4 r9.z, mv[2], iPos ;\n" +
+"DP4 r9.w, mv[3], iPos ;\n" +
+"\n" +
+"# transform normal to eye space\n" +
+"DP3 r11.x, mvit[0], iNorm ;\n" +
+"DP3 r11.y, mvit[1], iNorm ;\n" +
+"DP3 r11.z, mvit[2], iNorm ;\n" +
+"\n" +
+"# vertex->eye vector\n" +
+"ADD r0, -r9, eyePosition;\n" +
+"\n" +
+"# normalize\n" +
+"DP3 r8.w, r0, r0;\n" +
+"RSQ r8.w, r8.w;\n" +
+"MUL r8, r0, r8.w; # r8 = eye/incident vector\n" +
+"\n" +
+"# refraction, Renderman style\n" +
+"\n" +
+"# float IdotN = I.N;\n" +
+"# float k = 1 - eta*eta*(1 - IdotN*IdotN);\n" +
+"# return k < 0 ? (0,0,0) : eta*I - (eta*IdotN + sqrt(k))*N;\n" +
+"\n" +
+"DP3 r0.x, r11, -r8; # r0 = N.I\n" +
+"\n" +
+"MAD r1.x, -r0.x, r0.x, misc.y; # r1 = -IdotN*IdotN + 1\n" +
+"MUL r1.x, r1.x, refraction.y; # r1 = -(r1*eta*eta)+1\n" +
+"ADD r1.x, misc.y, -r1.x;\n" +
+"\n" +
+"RSQ r2.x, r1.x;\n" +
+"RCP r2.x, r2.x;\n" +
+"MAD r2.x, refraction.x, r0.x, r2.x;\n" +
+"MUL r2, r11, r2.x;\n" +
+"MAD r2, refraction.x, -r8, r2;\n" +
+"\n" +
+"# transform refracted ray by cubemap transform\n" +
+"DP3 oTex0.x, tex[0], r2;\n" +
+"DP3 oTex0.y, tex[1], r2;\n" +
+"DP3 oTex0.z, tex[2], r2;\n" +
+"\n" +
+"# calculate reflection\n" +
+"MUL r0, r11, misc.z;\n" +
+"DP3 r3.w, r11, r8;\n" +
+"MAD r3, r3.w, r0, -r8;\n" +
+"\n" +
+"# transform reflected ray by cubemap transform\n" +
+"DP3 oTex1.x, tex[0], r3;\n" +
+"DP3 oTex1.y, tex[1], r3;\n" +
+"DP3 oTex1.z, tex[2], r3;\n" +
+"\n" +
+"# cheesy Fresnel approximation = (1-(I.N))^p\n" +
+"DP3 r0.x, r8, r11;\n" +
+"ADD r0.x, misc.y, -r0.x;\n" +
+"MUL r0.x, r0.x, r0.x;\n" +
+"MUL oCol0, r0.x, fresnel;\n" +
+"\n" +
+"# transform vertex to clip space\n" +
+"DP4 oPos.x, mvp[0], iPos ;\n" +
+"DP4 oPos.y, mvp[1], iPos ;\n" +
+"DP4 oPos.z, mvp[2], iPos ;\n" +
+"DP4 oPos.w, mvp[3], iPos ;\n" +
+"\n" +
+"END\n";
+
+ public void init(GLAutoDrawable drawable) {
+
+ drawable.setGL(new DebugGL2(drawable.getGL().getGL2()));
+
+ initComplete = false;
+
+ GL2 gl = drawable.getGL().getGL2();
+
+ float cc = 1.0f;
+ gl.glClearColor(cc, cc, cc, 1);
+ gl.glColor3f(1,1,1);
+ gl.glEnable(GL.GL_DEPTH_TEST);
+
+ try {
+ initExtension(gl, "GL_ARB_vertex_program");
+ initExtension(gl, "GL_VERSION_1_3"); // For multitexturing support
+ if (!gl.isExtensionAvailable("GL_ARB_fragment_program")) {
+// if (gl.isExtensionAvailable("GL_NV_register_combiners")) {
+// useRegisterCombiners = true;
+// } else {
+ final String message = "This demo requires the GL_ARB_fragment_program extension";
+// + "or GL_NV_register_combiners extension";
+ new Thread(new Runnable() {
+ public void run() {
+ JOptionPane.showMessageDialog(null, message, "Unavailable extension", JOptionPane.ERROR_MESSAGE);
+ shutdownDemo();
+ }
+ }).start();
+ throw new RuntimeException(message);
+// }
+ }
+ } catch (RuntimeException e) {
+ shutdownDemo();
+ throw(e);
+ }
+
+ b[' '] = true; // animate by default
+
+ int[] vtxProgTmp = new int[1];
+ gl.glGenProgramsARB(1, vtxProgTmp, 0);
+ vtxProg = vtxProgTmp[0];
+ gl.glBindProgramARB(GL2.GL_VERTEX_PROGRAM_ARB, vtxProg);
+ gl.glProgramStringARB(GL2.GL_VERTEX_PROGRAM_ARB, GL2.GL_PROGRAM_FORMAT_ASCII_ARB, transformRefract.length(),
+ transformRefract);
+
+ gl.glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, 0, 0.0f, 0.0f, 0.0f, 1.0f); // eye position
+
+ gl.glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, 1, fresnel, fresnel, fresnel, 1.0f); // fresnel multiplier
+
+ gl.glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, 2, 1.0f, -1.0f, 1.0f, 0.0f); // texture scale
+ gl.glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, 3, 0.0f, 1.0f, 2.0f, 3.0f); // misc constants
+
+ try {
+ cubemap = Cubemap.loadFromStreams(getClass().getClassLoader(),
+ "demos/data/cubemaps/uffizi_",
+ "png",
+ true);
+ } catch (IOException e) {
+ shutdownDemo();
+ throw new RuntimeException(e);
+ }
+
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
+
+ gl.glDisable(GL.GL_CULL_FACE);
+
+// if (useRegisterCombiners) {
+// initCombiners(gl);
+// } else {
+ initFragmentProgram(gl);
+// }
+
+ try {
+ bunnydl = Bunny.gen3DObjectList(gl);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ doViewAll = true;
+
+ // Do this only once per drawable, not once each time the OpenGL
+ // context is created
+ if (firstRender) {
+ firstRender = false;
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) drawable);
+ this.drawable = drawable;
+
+ viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons());
+ viewer.setNoAltKeyMode(true);
+ viewer.setAutoRedrawMode(false);
+ viewer.attach((AWTGLAutoDrawable) drawable, new BSphereProvider() {
+ public BSphere getBoundingSphere() {
+ return new BSphere(new Vec3f(0, 0, 0), 1.0f);
+ }
+ });
+ viewer.setVertFOV((float) (15.0f * Math.PI / 32.0f));
+ viewer.setZNear(0.1f);
+ viewer.setZFar(10.0f);
+ }
+
+ initComplete = true;
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ if (!initComplete) {
+ return;
+ }
+
+ time.update();
+
+ GL2 gl = drawable.getGL().getGL2();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT);
+
+ if (doViewAll) {
+ viewer.viewAll(gl);
+ doViewAll = false;
+ }
+
+ if (getFlag(' ')) {
+ viewer.rotateAboutFocalPoint(new Rotf(Vec3f.Y_AXIS, (float) (time.deltaT() * animRate)));
+ }
+
+ if (toggleWire) {
+ toggleWire = false;
+ wire = !wire;
+ if (wire) {
+ gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE);
+ } else {
+ gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL);
+ }
+ }
+
+ // draw background
+ gl.glDisable(GL.GL_DEPTH_TEST);
+ drawSkyBox(gl);
+ gl.glEnable(GL.GL_DEPTH_TEST);
+
+ gl.glPushMatrix();
+
+ viewer.update(gl);
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, viewer.getCameraParameters());
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+
+ gl.glBindProgramARB(GL2.GL_VERTEX_PROGRAM_ARB, vtxProg);
+
+ gl.glEnable(GL2.GL_VERTEX_PROGRAM_ARB);
+ gl.glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, 62, fresnel, fresnel, fresnel, 1.0f);
+
+ // set texture transforms
+ gl.glActiveTexture(GL.GL_TEXTURE0);
+ cubemap.bind();
+ cubemap.enable();
+ gl.glMatrixMode(GL.GL_TEXTURE);
+ gl.glLoadIdentity();
+ viewer.updateInverseRotation(gl);
+
+ gl.glActiveTexture(GL.GL_TEXTURE1);
+ cubemap.bind();
+ cubemap.enable();
+ gl.glMatrixMode(GL.GL_TEXTURE);
+ gl.glLoadIdentity();
+ viewer.updateInverseRotation(gl);
+
+// if (useRegisterCombiners) {
+// gl.glEnable(GL2.GL_REGISTER_COMBINERS_NV);
+// } else {
+ gl.glBindProgramARB(GL2.GL_FRAGMENT_PROGRAM_ARB, fragProg);
+ gl.glEnable(GL2.GL_FRAGMENT_PROGRAM_ARB);
+// }
+
+ gl.glColor3f(1.0f, 1.0f, 1.0f);
+
+ if (getFlag('s')) {
+ // single pass
+ setRefraction(gl, refract);
+ drawObj(gl, obj);
+
+ } else {
+ // red pass
+ gl.glColorMask(true, false, false, false);
+ setRefraction(gl, refract);
+ drawObj(gl, obj);
+
+ gl.glDepthMask(false);
+ gl.glDepthFunc(GL.GL_EQUAL);
+
+ // green pass
+ gl.glColorMask(false, true, false, false);
+ setRefraction(gl, refract + wavelengthDelta);
+ drawObj(gl, obj);
+
+ // blue pass
+ gl.glColorMask(false, false, true, false);
+ setRefraction(gl, refract + (wavelengthDelta * 2));
+ drawObj(gl, obj);
+
+ gl.glDepthMask(true);
+ gl.glDepthFunc(GL.GL_LESS);
+ gl.glColorMask(true, true, true, false);
+ }
+
+// if (useRegisterCombiners) {
+// gl.glDisable(GL2.GL_REGISTER_COMBINERS_NV);
+// } else {
+ gl.glDisable(GL2.GL_FRAGMENT_PROGRAM_ARB);
+// }
+ gl.glDisable(GL2.GL_VERTEX_PROGRAM_ARB);
+
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glPopMatrix();
+ }
+
+ // Unused routines
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
+ public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+ public void shutdownDemo() {
+ if (drawable != null) {
+ viewer.detach();
+ ManipManager.getManipManager().unregisterWindow((AWTGLAutoDrawable) drawable);
+ drawable.removeGLEventListener(this);
+ }
+ super.shutdownDemo();
+ }
+
+ private boolean[] b = new boolean[256];
+ private void dispatchKey(char k) {
+ setFlag(k, !getFlag(k));
+
+ // Quit on escape or 'q'
+ if ((k == (char) 27) || (k == 'q')) {
+ shutdownDemo();
+ return;
+ }
+
+ switch (k) {
+ case '1':
+ obj = 0;
+ break;
+
+ case '2':
+ obj = 1;
+ break;
+
+ case '3':
+ obj = 2;
+ break;
+
+ case '4':
+ obj = 3;
+ break;
+
+ case 'v':
+ doViewAll = true;
+ break;
+
+ case 'w':
+ toggleWire = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ private void setFlag(char key, boolean val) {
+ b[((int) key) & 0xFF] = val;
+ }
+
+ private boolean getFlag(char key) {
+ return b[((int) key) & 0xFF];
+ }
+
+ private void initExtension(GL gl, String glExtensionName) {
+ if (!gl.isExtensionAvailable(glExtensionName)) {
+ final String message = "OpenGL extension \"" + glExtensionName + "\" not available";
+ new Thread(new Runnable() {
+ public void run() {
+ JOptionPane.showMessageDialog(null, message, "Unavailable extension", JOptionPane.ERROR_MESSAGE);
+ shutdownDemo();
+ }
+ }).start();
+ throw new RuntimeException(message);
+ }
+ }
+
+ // initalize texture combiners to compute:
+ // refraction*(1-fresnel) + reflection*fresnel
+// private void initCombiners(GL gl) {
+// gl.glCombinerParameteriNV(GL.GL_NUM_GENERAL_COMBINERS_NV, 1);
+//
+// // combiner 0
+// // a*b+c*d
+// gl.glCombinerInputNV(GL.GL_COMBINER0_NV, GL.GL_RGB, GL.GL_VARIABLE_A_NV, GL.GL_TEXTURE0, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB);
+// gl.glCombinerInputNV(GL.GL_COMBINER0_NV, GL.GL_RGB, GL.GL_VARIABLE_B_NV, GL.GL_PRIMARY_COLOR_NV, GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB);
+// gl.glCombinerInputNV(GL.GL_COMBINER0_NV, GL.GL_RGB, GL.GL_VARIABLE_C_NV, GL.GL_TEXTURE1, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB);
+// gl.glCombinerInputNV(GL.GL_COMBINER0_NV, GL.GL_RGB, GL.GL_VARIABLE_D_NV, GL.GL_PRIMARY_COLOR_NV, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB);
+//
+// // output:
+// // (stage, portion, abOutput, cdOutput, sumOutput, scale, bias, abDotProduct, cdDotProduct, muxSum)
+// gl.glCombinerOutputNV(GL.GL_COMBINER0_NV, GL.GL_RGB, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, GL.GL_SPARE0_NV, GL.GL_NONE, GL.GL_NONE, false, false, false);
+//
+// // final combiner
+// // output: Frgb = A*B + (1-A)*C + D
+// // (variable, input, mapping, componentUsage);
+// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_A_NV, GL.GL_SPARE0_NV, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB);
+// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_B_NV, GL.GL_ZERO, GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB);
+// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_C_NV, GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB);
+// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_D_NV, GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB);
+// }
+
+ private void initFragmentProgram(GL2 gl) {
+ int[] fragProgTmp = new int[1];
+ gl.glGenProgramsARB(1, fragProgTmp, 0);
+ fragProg = fragProgTmp[0];
+ String combineFragProg =
+"!!ARBfp1.0\n" +
+"# compute refraction*(1-fresnel) + reflection*fresnel\n" +
+"TEMP texSamp0, texSamp1;\n" +
+"TEMP invFresnel;\n" +
+"PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n" +
+"TEX texSamp0, fragment.texcoord[0], texture[0], CUBE;\n" +
+"TEX texSamp1, fragment.texcoord[1], texture[1], CUBE;\n" +
+"SUB invFresnel, one, fragment.color;\n" +
+"MUL texSamp0, texSamp0, invFresnel;\n" +
+"MUL texSamp1, texSamp1, fragment.color;\n" +
+"ADD texSamp0, texSamp0, texSamp1;\n" +
+"MOV result.color, texSamp0;\n" +
+"END";
+
+ gl.glBindProgramARB(GL2.GL_FRAGMENT_PROGRAM_ARB, fragProg);
+ gl.glProgramStringARB(GL2.GL_FRAGMENT_PROGRAM_ARB, GL2.GL_PROGRAM_FORMAT_ASCII_ARB,
+ combineFragProg.length(), combineFragProg);
+ int[] errPos = new int[1];
+ gl.glGetIntegerv(GL2.GL_PROGRAM_ERROR_POSITION_ARB, errPos, 0);
+ if (errPos[0] >= 0) {
+ System.out.println("Fragment program failed to load:");
+ String errMsg = gl.glGetString(GL2.GL_PROGRAM_ERROR_STRING_ARB);
+ if (errMsg == null) {
+ System.out.println("[No error message available]");
+ } else {
+ System.out.println("Error message: \"" + errMsg + "\"");
+ }
+ System.out.println("Error occurred at position " + errPos[0] + " in program:");
+ int endPos = errPos[0];
+ while (endPos < combineFragProg.length() && combineFragProg.charAt(endPos) != '\n') {
+ ++endPos;
+ }
+ System.out.println(combineFragProg.substring(errPos[0], endPos));
+ }
+ }
+
+ private void drawSkyBox(GL2 gl) {
+ // Compensates for ExaminerViewer's modification of modelview matrix
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+
+ gl.glActiveTexture(GL.GL_TEXTURE1);
+ gl.glDisable(GL.GL_TEXTURE_CUBE_MAP);
+
+ gl.glActiveTexture(GL.GL_TEXTURE0);
+ cubemap.bind();
+ cubemap.enable();
+
+ // This is a workaround for a driver bug on Mac OS X where the
+ // normals are not being sent down to the hardware in
+ // GL_NORMAL_MAP texgen mode. Temporarily enabling lighting
+ // causes the normals to be sent down. Thanks to Ken Dyke.
+ gl.glEnable(GL2ES1.GL_LIGHTING);
+
+ gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP);
+ gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP);
+ gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP);
+
+ gl.glEnable(GL2.GL_TEXTURE_GEN_S);
+ gl.glEnable(GL2.GL_TEXTURE_GEN_T);
+ gl.glEnable(GL2.GL_TEXTURE_GEN_R);
+
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
+
+ gl.glMatrixMode(GL.GL_TEXTURE);
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ viewer.updateInverseRotation(gl);
+
+ glut.glutSolidSphere(5.0, 40, 20);
+
+ gl.glDisable(GL2ES1.GL_LIGHTING);
+
+ gl.glPopMatrix();
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+
+ gl.glDisable(GL2.GL_TEXTURE_GEN_S);
+ gl.glDisable(GL2.GL_TEXTURE_GEN_T);
+ gl.glDisable(GL2.GL_TEXTURE_GEN_R);
+ }
+
+ private void drawObj(GL2 gl, int obj) {
+ switch(obj) {
+ case 0:
+ gl.glCallList(bunnydl);
+ break;
+
+ case 1:
+ glut.glutSolidSphere(0.5, 64, 64);
+ break;
+
+ case 2:
+ glut.glutSolidTorus(0.25, 0.5, 64, 64);
+ break;
+
+ case 3:
+ drawPlane(gl, 1.0f, 1.0f, 50, 50);
+ break;
+ }
+ }
+
+ private void setRefraction(GL2 gl, float index) {
+ gl.glProgramEnvParameter4fARB(GL2.GL_VERTEX_PROGRAM_ARB, 4, index, index*index, 0.0f, 0.0f);
+ }
+
+ // draw square subdivided into quad strips
+ private void drawPlane(GL2 gl, float w, float h, int rows, int cols) {
+ int x, y;
+ float vx, vy, s, t;
+ float ts, tt, tw, th;
+
+ ts = 1.0f / cols;
+ tt = 1.0f / rows;
+
+ tw = w / cols;
+ th = h / rows;
+
+ gl.glNormal3f(0.0f, 0.0f, 1.0f);
+
+ for(y=0; y<rows; y++) {
+ gl.glBegin(GL2.GL_QUAD_STRIP);
+ for(x=0; x<=cols; x++) {
+ vx = tw * x -(w/2.0f);
+ vy = th * y -(h/2.0f);
+ s = ts * x;
+ t = tt * y;
+
+ gl.glTexCoord2f(s, t);
+ gl.glColor3f(s, t, 0.0f);
+ gl.glVertex3f(vx, vy, 0.0f);
+
+ gl.glColor3f(s, t + tt, 0.0f);
+ gl.glTexCoord2f(s, t + tt);
+ gl.glVertex3f(vx, vy + th, 0.0f);
+ }
+ gl.glEnd();
+ }
+ }
+
+ private static void runExit(final Animator animator) {
+ // 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. Instead run
+ // the exit routine in another thread.
+ new Thread(new Runnable() {
+ public void run() {
+ animator.stop();
+ System.exit(0);
+ }
+ }).start();
+ }
+}