package demos.dualDepthPeeling; import java.awt.Frame; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.nio.FloatBuffer; import com.jogamp.opengl.*; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.glu.GLU; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.util.*; import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; import com.jogamp.opengl.util.glsl.ShaderState; import demos.data.DemosDataAnchor; // Translated from C++ Version see below: //-------------------------------------------------------------------------------------- // Order Independent Transparency with Dual Depth Peeling // // Author: Louis Bavoil // Email: sdkfeedback@nvidia.com // // Depth peeling is traditionally used to perform order independent transparency (OIT) // with N geometry passes for N transparency layers. Dual depth peeling enables peeling // N transparency layers in N/2+1 passes, by peeling from the front and the back // simultaneously using a min-max depth buffer. This sample performs either normal or // dual depth peeling and blends on the fly. // // Copyright (c) NVIDIA Corporation. All rights reserved. //-------------------------------------------------------------------------------------- public class DualDepthPeeling implements GLEventListener, KeyListener, MouseListener, MouseMotionListener { public final static int DUAL_PEELING_MODE = 0; public final static int F2B_PEELING_MODE = 1; public final static int WEIGHTED_AVERAGE_MODE = 2; public final static int WEIGHTED_SUM_MODE = 3; public final static float FOVY = 30.0f; public final static float ZNEAR = 0.0001f; public final static float ZFAR = 10.0f; public final static float FPS_TIME_WINDOW = 1; public final static float MAX_DEPTH = 1.0f; public int g_numPasses = 4; public int g_imageWidth = 1024; public int g_imageHeight = 768; public Model g_model; public int g_quadDisplayList; public int[] g_vboId = new int[1]; public int[] g_eboId = new int[1]; public boolean g_useOQ = true; public int[] g_queryId = new int[1]; public String MODEL_FILENAME = "models/dragon.obj"; public static final String s_FrontBlenderTex = "FrontBlenderTex"; public static final String s_BackBlenderTex = "BackBlenderTex"; public static final String s_DepthBlenderTex = "DepthBlenderTex"; public static final String s_ColorTex = "ColorTex"; public static final String s_ColorTex0 = "ColorTex0"; public static final String s_ColorTex1 = "ColorTex1"; public static final String s_TempTex = "TempTex"; public static final String s_BackgroundColor = "BackgroundColor"; public GLUniformData g_FrontBlenderTexUnit; public GLUniformData g_BackBlenderTexUnit; public GLUniformData g_DepthBlenderTexUnit; public GLUniformData g_ColorTexUnit; public GLUniformData g_ColorTex0Unit; public GLUniformData g_ColorTex1Unit; public GLUniformData g_TempTexUnit; public GLUniformData g_AlphaUni; public GLUniformData g_backgroundColorUni; public ShaderState g_shaderState; public ShaderProgram g_shaderDualInit; public ShaderProgram g_shaderDualPeel; public ShaderProgram g_shaderDualBlend; public ShaderProgram g_shaderDualFinal; public ShaderProgram g_shaderFrontInit; public ShaderProgram g_shaderFrontPeel; public ShaderProgram g_shaderFrontBlend; public ShaderProgram g_shaderFrontFinal; public ShaderProgram g_shaderAverageInit; public ShaderProgram g_shaderAverageFinal; public ShaderProgram g_shaderWeightedSumInit; public ShaderProgram g_shaderWeightedSumFinal; public float g_opacity = 0.6f; public char g_mode = DUAL_PEELING_MODE; public boolean g_showOsd = true; public boolean g_bShowUI = true; public int g_numGeoPasses = 0; public boolean g_rotating = false; public boolean g_panning = false; public boolean g_scaling = false; public int g_oldX, g_oldY; public int g_newX, g_newY; public float g_bbScale = 1.0f; public float[] g_bbTrans = new float[]{0.0f, 0.0f, 0.0f}; public float[] g_rot = new float[]{0.0f, 45.0f}; public float[] g_pos = new float[]{0.0f, 0.0f, 2.0f}; static final FloatBuffer g_white = Buffers.newDirectFloatBuffer(new float[]{1.0f,1.0f,1.0f}); static final FloatBuffer g_black = Buffers.newDirectFloatBuffer(new float[]{0.0f,0.0f,0.0f}); FloatBuffer g_backgroundColor = g_white; public int[] g_dualBackBlenderFboId = new int[1]; public int[] g_dualPeelingSingleFboId = new int[1]; public int[] g_dualDepthTexId = new int[2]; public int[] g_dualFrontBlenderTexId = new int[2]; public int[] g_dualBackTempTexId = new int[2]; public int[] g_dualBackBlenderTexId = new int[1]; public int[] g_frontFboId = new int[2]; public int[] g_frontDepthTexId = new int[2]; public int[] g_frontColorTexId = new int[2]; public int[] g_frontColorBlenderTexId = new int[1]; public int[] g_frontColorBlenderFboId = new int[1]; public int[] g_accumulationTexId = new int[2]; public int[] g_accumulationFboId = new int[1]; int g_drawBuffers[] = {GL2.GL_COLOR_ATTACHMENT0, GL2.GL_COLOR_ATTACHMENT1, GL2.GL_COLOR_ATTACHMENT2, GL2.GL_COLOR_ATTACHMENT3, GL2.GL_COLOR_ATTACHMENT4, GL2.GL_COLOR_ATTACHMENT5, GL2.GL_COLOR_ATTACHMENT6 }; boolean reloadShaders = false; public DualDepthPeeling() { InitGL(); } public void InitDualPeelingRenderTargets(GL2 gl) { gl.glGenTextures(2, g_dualDepthTexId, 0); gl.glGenTextures(2, g_dualFrontBlenderTexId, 0); gl.glGenTextures(2, g_dualBackTempTexId, 0); gl.glGenFramebuffers(1, g_dualPeelingSingleFboId, 0); for (int i = 0; i < 2; i++) { gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualDepthTexId[i]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); //gl.glEnable( GL2.GL_PIXEL_UNPACK_BUFFER ); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_FLOAT_RG32_NV, g_imageWidth, g_imageHeight, 0, GL2.GL_RGB, GL2.GL_FLOAT, null); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualFrontBlenderTexId[i]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_RGBA, g_imageWidth, g_imageHeight, 0, GL2.GL_RGBA, GL2.GL_FLOAT, null); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualBackTempTexId[i]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_RGBA, g_imageWidth, g_imageHeight, 0, GL2.GL_RGBA, GL2.GL_FLOAT, null); } gl.glGenTextures(1, g_dualBackBlenderTexId, 0); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualBackBlenderTexId[0]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_RGB, g_imageWidth, g_imageHeight, 0, GL2.GL_RGB, GL2.GL_FLOAT, null); gl.glGenFramebuffers(1, g_dualBackBlenderFboId, 0); gl.glBindFramebuffer( GL2.GL_FRAMEBUFFER, g_dualBackBlenderFboId[0]); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualBackBlenderTexId[0], 0); gl.glBindFramebuffer( GL2.GL_FRAMEBUFFER, g_dualPeelingSingleFboId[0]); int j = 0; gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualDepthTexId[j], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT1, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualFrontBlenderTexId[j], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT2, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualBackTempTexId[j], 0); j = 1; gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT3, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualDepthTexId[j], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT4, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualFrontBlenderTexId[j], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT5, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualBackTempTexId[j], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT6, GL2.GL_TEXTURE_RECTANGLE_ARB, g_dualBackBlenderTexId[0], 0); } //-------------------------------------------------------------------------- void DeleteDualPeelingRenderTargets(GL2 gl) { gl.glDeleteFramebuffers(1, g_dualBackBlenderFboId, 0); gl.glDeleteFramebuffers(1, g_dualPeelingSingleFboId, 0); gl.glDeleteTextures(2, g_dualDepthTexId, 0); gl.glDeleteTextures(2, g_dualFrontBlenderTexId, 0); gl.glDeleteTextures(2, g_dualBackTempTexId, 0); gl.glDeleteTextures(1, g_dualBackBlenderTexId, 0); } //-------------------------------------------------------------------------- void InitFrontPeelingRenderTargets(GL2 gl) { gl.glGenTextures(2, g_frontDepthTexId, 0); gl.glGenTextures(2, g_frontColorTexId, 0); gl.glGenFramebuffers(2, g_frontFboId, 0); for (int i = 0; i < 2; i++) { gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontDepthTexId[i]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_DEPTH_COMPONENT32F, g_imageWidth, g_imageHeight, 0, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, null); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontColorTexId[i]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_RGBA, g_imageWidth, g_imageHeight, 0, GL2.GL_RGBA, GL2.GL_FLOAT, null); gl.glBindFramebuffer( GL2.GL_FRAMEBUFFER, g_frontFboId[i]); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_DEPTH_ATTACHMENT, GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontDepthTexId[i], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontColorTexId[i], 0); } gl.glGenTextures(1, g_frontColorBlenderTexId, 0); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontColorBlenderTexId[0]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2. GL_RGBA, g_imageWidth, g_imageHeight, 0, GL2.GL_RGBA, GL2.GL_FLOAT, null); gl.glGenFramebuffers(1, g_frontColorBlenderFboId, 0); gl.glBindFramebuffer( GL2.GL_FRAMEBUFFER, g_frontColorBlenderFboId[0]); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_DEPTH_ATTACHMENT, GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontDepthTexId[0], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, GL2.GL_TEXTURE_RECTANGLE_ARB, g_frontColorBlenderTexId[0], 0); } //-------------------------------------------------------------------------- void DeleteFrontPeelingRenderTargets(GL2 gl) { gl.glDeleteFramebuffers(2, g_frontFboId, 0); gl.glDeleteFramebuffers(1, g_frontColorBlenderFboId, 0); gl.glDeleteTextures(2, g_frontDepthTexId, 0); gl.glDeleteTextures(2, g_frontColorTexId, 0); gl.glDeleteTextures(1, g_frontColorBlenderTexId, 0); } //-------------------------------------------------------------------------- void InitAccumulationRenderTargets(GL2 gl) { gl.glGenTextures(2, g_accumulationTexId, 0); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_accumulationTexId[0]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_RGBA16F, g_imageWidth, g_imageHeight, 0, GL2.GL_RGBA, GL2.GL_FLOAT, null); gl.glBindTexture( GL2.GL_TEXTURE_RECTANGLE_ARB, g_accumulationTexId[1]); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); gl.glTexParameteri( GL2.GL_TEXTURE_RECTANGLE_ARB, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); gl.glTexImage2D( GL2.GL_TEXTURE_RECTANGLE_ARB, 0, GL2.GL_FLOAT_R32_NV, g_imageWidth, g_imageHeight, 0, GL2.GL_RGBA, GL2.GL_FLOAT, null); gl.glGenFramebuffers(1, g_accumulationFboId, 0); gl.glBindFramebuffer( GL2.GL_FRAMEBUFFER, g_accumulationFboId[0]); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0, GL2.GL_TEXTURE_RECTANGLE_ARB, g_accumulationTexId[0], 0); gl.glFramebufferTexture2D( GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT1, GL2.GL_TEXTURE_RECTANGLE_ARB, g_accumulationTexId[1], 0); } //-------------------------------------------------------------------------- void DeleteAccumulationRenderTargets(GL2 gl) { gl.glDeleteFramebuffers(1, g_accumulationFboId, 0); gl.glDeleteTextures(2, g_accumulationTexId, 0); } //-------------------------------------------------------------------------- void MakeFullScreenQuad(GL2 gl) { GLU glu = GLU.createGLU(gl); g_quadDisplayList = gl.glGenLists(1); gl.glNewList(g_quadDisplayList, GL2.GL_COMPILE); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glPushMatrix(); gl.glLoadIdentity(); glu.gluOrtho2D(0.0f, 1.0f, 0.0f, 1.0f); gl.glBegin(GL2.GL_QUADS); { gl.glVertex2f(0.0f, 0.0f); gl.glVertex2f(1.0f, 0.0f); gl.glVertex2f(1.0f, 1.0f); gl.glVertex2f(0.0f, 1.0f); } gl.glEnd(); gl.glPopMatrix(); gl.glEndList(); } //-------------------------------------------------------------------------- void LoadModel( GL2 gl, String model_filename) { g_model = new Model(); System.err.println("loading OBJ...\n"); g_model.loadModelFromFile(DemosDataAnchor.class, model_filename ); System.err.println("compiling mesh...\n"); g_model.compileModel(); System.err.println(g_model.getPositionCount() + " vertices"); System.err.println((g_model.getIndexCount()/3) + " triangles"); int totalVertexSize = g_model.getCompiledVertexCount() * Buffers.SIZEOF_FLOAT; int totalIndexSize = g_model.getCompiledIndexCount() * Buffers.SIZEOF_INT; gl.glGenBuffers(1, g_vboId, 0); gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, g_vboId[0]); gl.glBufferData(GL2.GL_ARRAY_BUFFER, totalVertexSize, g_model.getCompiledVertices(), GL2.GL_STATIC_DRAW); gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); gl.glGenBuffers(1, g_eboId, 0); gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, g_eboId[0]); gl.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, totalIndexSize, g_model.getCompiledIndices(), GL2.GL_STATIC_DRAW); gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); float[] modelMin = new float[3]; float[] modelMax = new float[3]; g_model.computeBoundingBox(modelMin, modelMax); float[] diag = new float[]{ modelMax[0] - modelMin[0], modelMax[1] - modelMin[1], modelMax[2] - modelMin[2] }; g_bbScale = (float)(1.0 / Math.sqrt(diag[0]*diag[0] + diag[1]*diag[1] + diag[2]*diag[2]) * 1.5); g_bbTrans = new float[]{ (float)( -g_bbScale * (modelMin[0] + 0.5 * diag[0])), (float)( -g_bbScale * (modelMin[1] + 0.5 * diag[1]) ), (float)( -g_bbScale * (modelMin[2] + 0.5 * diag[2]) ) }; } //-------------------------------------------------------------------------- void DrawModel(GL2 gl) { gl.glBindBuffer( GL2.GL_ARRAY_BUFFER, g_vboId[0]); gl.glBindBuffer( GL2.GL_ELEMENT_ARRAY_BUFFER, g_eboId[0]); int stride = g_model.getCompiledVertexSize() * Buffers.SIZEOF_FLOAT; int normalOffset = g_model.getCompiledNormalOffset() * Buffers.SIZEOF_FLOAT; gl.glVertexPointer(g_model.getPositionSize(), GL2.GL_FLOAT, stride, 0); gl.glNormalPointer(GL2.GL_FLOAT, stride, normalOffset); gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); gl.glEnableClientState(GL2.GL_NORMAL_ARRAY); gl.glDrawElements( GL2.GL_TRIANGLES, g_model.getCompiledIndexCount(), GL2.GL_UNSIGNED_INT, 0); gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); gl.glDisableClientState(GL2.GL_NORMAL_ARRAY); g_numGeoPasses++; } public GLCanvas GetCanvas() { return m_kCanvas; } ShaderProgram build(GL2ES2 gl, String basename, boolean link) { ShaderProgram sp = new ShaderProgram(); ShaderCode vp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, DualDepthPeeling.class, "shader", null, basename, false); ShaderCode fp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, DualDepthPeeling.class, "shader", null, basename, false); sp.add(vp); sp.add(fp); if(link && !sp.link(gl, System.err)) { throw new GLException("Couldn't link program: "+sp); } return sp; } ShaderProgram build(GL2ES2 gl, String[] basenames, boolean link) { ShaderProgram sp = new ShaderProgram(); ShaderCode vp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, basenames.length, DualDepthPeeling.class, "shader", basenames, null, null, false); sp.add(vp); ShaderCode fp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, basenames.length, DualDepthPeeling.class, "shader", basenames, null, null, false); sp.add(fp); if(link && !sp.link(gl, System.err)) { throw new GLException("Couldn't link program: "+sp); } return sp; } //-------------------------------------------------------------------------- void BuildShaders(GL2 gl) { System.err.println("\nloading shaders...\n"); g_shaderState = new ShaderState(); // g_shaderState.setVerbose(true); g_shaderDualInit = build(gl, "dual_peeling_init", true); g_shaderDualPeel = build(gl, new String[] { "shade", "dual_peeling_peel" }, true); g_shaderDualBlend = build(gl, "dual_peeling_blend", true); g_shaderDualFinal = build(gl, "dual_peeling_final", true); g_shaderFrontInit = build(gl, new String[] { "shade", "front_peeling_init" }, true); g_shaderFrontPeel = build(gl, new String[] { "shade", "front_peeling_peel" }, true); g_shaderFrontBlend = build(gl, "front_peeling_blend", true); g_shaderFrontFinal = build(gl, "front_peeling_final", true); g_shaderAverageInit = build(gl, new String[] { "shade", "wavg_init" }, true); g_shaderAverageFinal = build(gl, "wavg_final", true); g_shaderWeightedSumInit = build(gl, new String[] { "shade", "wsum_init" }, true); g_shaderWeightedSumFinal = build(gl, "wsum_final", true); g_DepthBlenderTexUnit = new GLUniformData(s_DepthBlenderTex, 0); g_shaderState.ownUniform(g_DepthBlenderTexUnit); g_FrontBlenderTexUnit = new GLUniformData(s_FrontBlenderTex, 1); g_shaderState.ownUniform(g_FrontBlenderTexUnit); g_BackBlenderTexUnit = new GLUniformData(s_BackBlenderTex, 2); g_shaderState.ownUniform(g_BackBlenderTexUnit); g_TempTexUnit = new GLUniformData(s_TempTex, 0); g_shaderState.ownUniform(g_TempTexUnit); g_AlphaUni = new GLUniformData("Alpha", g_opacity); g_shaderState.ownUniform(g_AlphaUni); g_backgroundColorUni = new GLUniformData(s_BackgroundColor, 3, g_backgroundColor); g_shaderState.ownUniform(g_backgroundColorUni); g_ColorTexUnit = new GLUniformData(s_ColorTex, 0); g_shaderState.ownUniform(g_ColorTexUnit); g_ColorTex0Unit = new GLUniformData(s_ColorTex0, 0); g_shaderState.ownUniform(g_ColorTex0Unit); g_ColorTex1Unit = new GLUniformData(s_ColorTex1, 1); g_shaderState.ownUniform(g_ColorTex1Unit); } //-------------------------------------------------------------------------- void DestroyShaders(GL2 gl) { g_shaderState.release(gl, false, false, false); g_shaderDualInit.destroy(gl); g_shaderDualPeel.destroy(gl); g_shaderDualBlend.destroy(gl); g_shaderDualFinal.destroy(gl); g_shaderFrontInit.destroy(gl); g_shaderFrontPeel.destroy(gl); g_shaderFrontBlend.destroy(gl); g_shaderFrontFinal.destroy(gl); g_shaderAverageInit.destroy(gl); g_shaderAverageFinal.destroy(gl); g_shaderWeightedSumInit.destroy(gl); g_shaderWeightedSumFinal.destroy(gl); } //-------------------------------------------------------------------------- void ReloadShaders(GL2 gl) { DestroyShaders(gl); BuildShaders(gl); } /** GLCanvas for Java/JOGL */ private GLCanvas m_kCanvas; void InitGL() { GLProfile kProfile = GLProfile.getMaxProgrammable(true); GLCapabilities kGlCapabilities = new GLCapabilities(kProfile); kGlCapabilities.setHardwareAccelerated(true); m_kCanvas = new GLCanvas(kGlCapabilities); m_kCanvas.setSize(g_imageWidth, g_imageHeight); m_kCanvas.addGLEventListener( this ); m_kCanvas.addKeyListener( this ); m_kCanvas.addMouseListener( this ); m_kCanvas.addMouseMotionListener( this ); } //-------------------------------------------------------------------------- void RenderDualPeeling(GL2 gl) { gl.glDisable(GL2.GL_DEPTH_TEST); gl.glEnable(GL2.GL_BLEND); // --------------------------------------------------------------------- // 1. Initialize Min-Max Depth Buffer // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, g_dualPeelingSingleFboId[0]); // Render targets 1 and 2 store the front and back colors // Clear to 0.0 and use MAX blending to filter written color // At most one front color and one back color can be written every pass gl.glDrawBuffers(2, g_drawBuffers, 1); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); // Render target 0 stores (-minDepth, maxDepth, alphaMultiplier) gl.glDrawBuffer(g_drawBuffers[0]); gl.glClearColor(-MAX_DEPTH, -MAX_DEPTH, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); gl.glBlendEquation(GL2.GL_MAX); g_shaderState.attachShaderProgram(gl, g_shaderDualInit, true); DrawModel(gl); g_shaderState.useProgram(gl, false); // --------------------------------------------------------------------- // 2. Dual Depth Peeling + Blending // --------------------------------------------------------------------- // Since we cannot blend the back colors in the geometry passes, // we use another render target to do the alpha blending //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_dualBackBlenderFboId); gl.glDrawBuffer(g_drawBuffers[6]); gl.glClearColor(g_backgroundColor.get(0), g_backgroundColor.get(1), g_backgroundColor.get(2), 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); int currId = 0; for (int pass = 1; g_useOQ || pass < g_numPasses; pass++) { currId = pass % 2; int prevId = 1 - currId; int bufId = currId * 3; //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_dualPeelingFboId[currId]); gl.glDrawBuffers(2, g_drawBuffers, bufId+1); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); gl.glDrawBuffer(g_drawBuffers[bufId+0]); gl.glClearColor(-MAX_DEPTH, -MAX_DEPTH, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); // Render target 0: RG32F MAX blending // Render target 1: RGBA MAX blending // Render target 2: RGBA MAX blending gl.glDrawBuffers(3, g_drawBuffers, bufId+0); gl.glBlendEquation(GL2.GL_MAX); // uses g_DepthBlenderTexUnit // uses g_FrontBlenderTexUnit // uses g_AlphaUni g_shaderState.attachShaderProgram(gl, g_shaderDualPeel, true); GLHelper.bindTextureRECT(gl, g_dualDepthTexId[prevId], g_DepthBlenderTexUnit.intValue()); GLHelper.bindTextureRECT(gl, g_dualFrontBlenderTexId[prevId], g_FrontBlenderTexUnit.intValue()); DrawModel(gl); g_shaderState.useProgram(gl, false); // Full screen pass to alpha-blend the back color gl.glDrawBuffer(g_drawBuffers[6]); gl.glBlendEquation(GL2.GL_FUNC_ADD); gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA); if (g_useOQ) { gl.glBeginQuery(GL2.GL_SAMPLES_PASSED, g_queryId[0]); } g_TempTexUnit.setData(0); g_shaderState.attachShaderProgram(gl, g_shaderDualBlend, true); GLHelper.bindTextureRECT(gl, g_dualBackTempTexId[currId], g_TempTexUnit.intValue()); gl.glCallList(g_quadDisplayList); g_shaderState.useProgram(gl, false); if (g_useOQ) { gl.glEndQuery(GL2.GL_SAMPLES_PASSED); int[] sample_count = new int[]{0}; gl.glGetQueryObjectuiv(g_queryId[0], GL2.GL_QUERY_RESULT, sample_count, 0); if (sample_count[0] == 0) { break; } } } gl.glDisable(GL2.GL_BLEND); // --------------------------------------------------------------------- // 3. Final Pass // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); gl.glDrawBuffer(GL2.GL_BACK); // use g_FrontBlenderTexUnit // use g_BackBlenderTexUnit g_shaderState.attachShaderProgram(gl, g_shaderDualFinal, true); GLHelper.bindTextureRECT(gl, g_dualFrontBlenderTexId[currId], g_FrontBlenderTexUnit.intValue()); GLHelper.bindTextureRECT(gl, g_dualBackBlenderTexId[0], g_BackBlenderTexUnit.intValue()); gl.glCallList(g_quadDisplayList); g_shaderState.useProgram(gl, false); } //-------------------------------------------------------------------------- void RenderFrontToBackPeeling(GL2 gl) { // --------------------------------------------------------------------- // 1. Initialize Min Depth Buffer // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, g_frontColorBlenderFboId[0]); gl.glDrawBuffer(g_drawBuffers[0]); gl.glClearColor(0, 0, 0, 1); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glEnable(GL2.GL_DEPTH_TEST); // uses g_AlphaUni g_shaderState.attachShaderProgram(gl, g_shaderFrontInit, true); DrawModel(gl); g_shaderState.useProgram(gl, false); // --------------------------------------------------------------------- // 2. Depth Peeling + Blending // --------------------------------------------------------------------- int numLayers = (g_numPasses - 1) * 2; for (int layer = 1; g_useOQ || layer < numLayers; layer++) { int currId = layer % 2; int prevId = 1 - currId; gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, g_frontFboId[currId]); gl.glDrawBuffer(g_drawBuffers[0]); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glDisable(GL2.GL_BLEND); gl.glEnable(GL2.GL_DEPTH_TEST); if (g_useOQ) { gl.glBeginQuery(GL2.GL_SAMPLES_PASSED, g_queryId[0]); } // uses g_DepthBlenderTexUnit // uses g_FrontBlenderTexUnit // uses g_AlphaUni g_shaderState.attachShaderProgram(gl, g_shaderDualPeel, true); GLHelper.bindTextureRECT(gl, g_frontDepthTexId[prevId], g_DepthBlenderTexUnit.intValue()); DrawModel(gl); g_shaderState.useProgram(gl, false); if (g_useOQ) { gl.glEndQuery(GL2.GL_SAMPLES_PASSED); } gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, g_frontColorBlenderFboId[0]); gl.glDrawBuffer(g_drawBuffers[0]); gl.glDisable(GL2.GL_DEPTH_TEST); gl.glEnable(GL2.GL_BLEND); gl.glBlendEquation(GL2.GL_FUNC_ADD); gl.glBlendFuncSeparate(GL2.GL_DST_ALPHA, GL2.GL_ONE, GL2.GL_ZERO, GL2.GL_ONE_MINUS_SRC_ALPHA); // uses g_TempTexUnit g_shaderState.attachShaderProgram(gl, g_shaderDualBlend, true); GLHelper.bindTextureRECT(gl, g_frontColorTexId[currId], g_TempTexUnit.intValue()); gl.glCallList(g_quadDisplayList); g_shaderState.useProgram(gl, false); gl.glDisable(GL2.GL_BLEND); if (g_useOQ) { int[] sample_count = new int[]{0}; gl.glGetQueryObjectuiv(g_queryId[0], GL2.GL_QUERY_RESULT, sample_count, 0); if (sample_count[0] == 0) { break; } } } // --------------------------------------------------------------------- // 3. Final Pass // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); gl.glDrawBuffer(GL2.GL_BACK); gl.glDisable(GL2.GL_DEPTH_TEST); // uses g_backgroundColorUni g_shaderState.attachShaderProgram(gl, g_shaderFrontFinal, true); GLHelper.bindTextureRECT(gl, g_frontColorBlenderTexId[0], g_ColorTexUnit.intValue()); gl.glCallList(g_quadDisplayList); g_shaderState.useProgram(gl, false); } //-------------------------------------------------------------------------- void RenderAverageColors(GL2 gl) { gl.glDisable(GL2.GL_DEPTH_TEST); // --------------------------------------------------------------------- // 1. Accumulate Colors and Depth Complexity // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, g_accumulationFboId[0]); gl.glDrawBuffers(2, g_drawBuffers, 0); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); gl.glBlendEquation(GL2.GL_FUNC_ADD); gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE); gl.glEnable(GL2.GL_BLEND); // uses g_AlphaUni g_shaderState.attachShaderProgram(gl, g_shaderAverageInit, true); DrawModel(gl); g_shaderState.useProgram(gl, false); gl.glDisable(GL2.GL_BLEND); // --------------------------------------------------------------------- // 2. Approximate Blending // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); gl.glDrawBuffer(GL2.GL_BACK); // uses g_backgroundColorUni g_shaderState.attachShaderProgram(gl, g_shaderAverageFinal, true); GLHelper.bindTextureRECT(gl, g_accumulationTexId[0], g_ColorTex0Unit.intValue()); GLHelper.bindTextureRECT(gl, g_accumulationTexId[1], g_ColorTex1Unit.intValue()); gl.glCallList(g_quadDisplayList); g_shaderState.useProgram(gl, false); } //-------------------------------------------------------------------------- void RenderWeightedSum(GL2 gl) { gl.glDisable(GL2.GL_DEPTH_TEST); // --------------------------------------------------------------------- // 1. Accumulate (alpha * color) and (alpha) // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, g_accumulationFboId[0]); gl.glDrawBuffer(g_drawBuffers[0]); gl.glClearColor(0, 0, 0, 0); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); gl.glBlendEquation(GL2.GL_FUNC_ADD); gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE); gl.glEnable(GL2.GL_BLEND); g_shaderState.attachShaderProgram(gl, g_shaderWeightedSumInit, true); DrawModel(gl); g_shaderState.useProgram(gl, false); gl.glDisable(GL2.GL_BLEND); // --------------------------------------------------------------------- // 2. Weighted Sum // --------------------------------------------------------------------- gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); gl.glDrawBuffer(GL2.GL_BACK); g_shaderState.attachShaderProgram(gl, g_shaderWeightedSumFinal, true); GLHelper.bindTextureRECT(gl, g_accumulationTexId[0], this.g_ColorTexUnit.intValue()); gl.glCallList(g_quadDisplayList); g_shaderState.useProgram(gl, false); } public static void main(String[] args) { System.out.println("dual_depth_peeling - sample comparing multiple order independent transparency techniques\n"); System.out.println(" Commands:\n"); System.out.println(" A/D - Change uniform opacity\n"); System.out.println(" 1 - Dual peeling mode\n"); System.out.println(" 2 - Front to back peeling mode\n"); System.out.println(" 3 - Weighted average mode\n"); System.out.println(" 4 - Weighted sum mode\n"); System.out.println(" R - Reload all shaders\n"); System.out.println(" B - Change background color\n"); System.out.println(" Q - Toggle occlusion queries\n"); System.out.println(" +/- - Change number of geometry passes\n\n"); DualDepthPeeling kWorld = new DualDepthPeeling(); Frame frame = new Frame("Dual Depth Peeling"); frame.add( kWorld.GetCanvas() ); frame.setSize(kWorld.GetCanvas().getWidth(), kWorld.GetCanvas().getHeight()); /* Animator serves the purpose of the idle function, calls display: */ final Animator animator = new Animator( kWorld.GetCanvas() ); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { // Run this on another thread than the AWT event queue to // avoid deadlocks on shutdown on some platforms new Thread(new Runnable() { public void run() { animator.stop(); System.exit(0); } }).start(); } }); frame.setVisible(true); animator.start(); } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyReleased(KeyEvent e) { switch(e.getKeyChar()) { case 8: g_bShowUI = !g_bShowUI; break; case 'q': g_useOQ = !g_useOQ; break; case '+': g_numPasses++; break; case '-': g_numPasses--; break; case 'b': g_backgroundColor = (g_backgroundColor == g_white) ? g_black : g_white; g_backgroundColorUni.setData(g_backgroundColor); break; case 'o': g_showOsd = !g_showOsd; break; case 'r': reloadShaders = true; break; case '1': g_mode = DUAL_PEELING_MODE; break; case '2': g_mode = F2B_PEELING_MODE; break; case '3': g_mode = WEIGHTED_AVERAGE_MODE; break; case '4': g_mode = WEIGHTED_SUM_MODE; break; case 'a': g_opacity -= 0.05; g_opacity = (float)Math.max(g_opacity, 0.0); g_AlphaUni.setData(g_opacity); break; case 'd': g_opacity += 0.05; g_opacity = (float)Math.min(g_opacity, 1.0); g_AlphaUni.setData(g_opacity); break; } } @Override public void display(GLAutoDrawable arg0) { GL2 gl = arg0.getGL().getGL2(); if(reloadShaders) { reloadShaders = false; ReloadShaders(gl); } GLU glu = GLU.createGLU(gl); g_numGeoPasses = 0; gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); glu.gluLookAt(g_pos[0], g_pos[1], g_pos[2], g_pos[0], g_pos[1], 0, 0, 1, 0); gl.glRotatef(g_rot[0], 1, 0, 0); gl.glRotatef(g_rot[1], 0, 1, 0); gl.glTranslatef(g_bbTrans[0], g_bbTrans[1], g_bbTrans[2]); gl.glScalef(g_bbScale, g_bbScale, g_bbScale); switch (g_mode) { case DUAL_PEELING_MODE: RenderDualPeeling(gl); break; case F2B_PEELING_MODE: RenderFrontToBackPeeling(gl); break; case WEIGHTED_AVERAGE_MODE: RenderAverageColors(gl); break; case WEIGHTED_SUM_MODE: RenderWeightedSum(gl); break; } /* Call swapBuffers to render on-screen: */ arg0.swapBuffers(); } @Override public void dispose(GLAutoDrawable arg0) { // TODO Auto-generated method stub } @Override public void init(GLAutoDrawable drawable) { System.err.println( "init" ); GL2 gl = drawable.getGL().getGL2(); m_kCanvas.setAutoSwapBufferMode( false ); // Allocate render targets first try { InitDualPeelingRenderTargets(gl); } catch ( GLException e ) { try { InitDualPeelingRenderTargets(gl); } catch ( GLException e1 ) { System.err.println( e1.getStackTrace() ); } } InitFrontPeelingRenderTargets(gl); InitAccumulationRenderTargets(gl); gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0); BuildShaders(gl); LoadModel(gl, MODEL_FILENAME); MakeFullScreenQuad(gl); gl.glDisable(GL2.GL_CULL_FACE); gl.glDisable(GL2.GL_LIGHTING); gl.glDisable(GL2.GL_NORMALIZE); gl.glGenQueries(1, g_queryId, 0); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL2 gl = drawable.getGL().getGL2(); if (g_imageWidth != width || g_imageHeight != height) { g_imageWidth = width; g_imageHeight = height; DeleteDualPeelingRenderTargets(gl); InitDualPeelingRenderTargets(gl); DeleteFrontPeelingRenderTargets(gl); InitFrontPeelingRenderTargets(gl); DeleteAccumulationRenderTargets(gl); InitAccumulationRenderTargets(gl); } gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); GLU glu = GLU.createGLU(gl); glu.gluPerspective(FOVY, (float)g_imageWidth/(float)g_imageHeight, ZNEAR, ZFAR); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glViewport(0, 0, g_imageWidth, g_imageHeight); } @Override public void mouseDragged(MouseEvent e) { g_oldX = g_newX; g_oldY = g_newY; g_newX = e.getX(); g_newY = e.getY(); float rel_x = (g_newX - g_oldX) / (float)g_imageWidth; float rel_y = (g_newY - g_oldY) / (float)g_imageHeight; if (g_rotating) { g_rot[1] += (rel_x * 180); g_rot[0] += (rel_y * 180); } else if (g_panning) { g_pos[0] -= rel_x; g_pos[1] += rel_y; } else if (g_scaling) { g_pos[2] -= rel_y * g_pos[2]; } } @Override public void mouseMoved(MouseEvent e) {} @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) { g_newX = e.getX(); g_newY = e.getY(); g_scaling = false; g_panning = false; g_rotating = false; if (e.getButton() == MouseEvent.BUTTON1) { if (e.isShiftDown()) { g_scaling = true; } else if (e.isControlDown()) { g_panning = true; } else { g_rotating = true; } } } @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} }