/**
* Copyright 2011 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package com.jogamp.opengl.test.junit.jogl.demos.es2;
import static com.jogamp.opengl.GL.*;
import java.nio.FloatBuffer;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLCapabilitiesImmutable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.GLUniformData;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.common.nio.Buffers;
import com.jogamp.newt.event.KeyAdapter;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.glsl.ShaderState;
/**
* <pre>
* __ __|_ ___________________________________________________________________________ ___|__ __
* // /\ _ /\ \\
* //____/ \__ __ _____ _____ _____ _____ _____ | | __ _____ _____ __ __/ \____\\
* \ \ / / __| | | __| _ | | _ | | | __| | | __| | /\ \ / /
* \____\/_/ | | | | | | | | | | | __| | | | | | | | | | |__ " \_\/____/
* /\ \ |_____|_____|_____|__|__|_|_|_|__| | | |_____|_____|_____|_____| _ / /\
* / \____\ http://jogamp.org |_| /____/ \
* \ / "' _________________________________________________________________________ `" \ /
* \/____. .____\/
* </pre>
*
* <p>
* JOGL2 port of my PC 4k intro competition entry for Revision 2011. Sure it got a little bigger
* while porting but the shader and control code remained more or less untouched. The intro renders
* a fullscreen billboard using a single fragment shader. The shader encapsulates basically two
* different routines: A sphere-tracing based raymarcher for a single fractal formula and a bitmap
* orbit trap julia+mandelbrot fractal renderer. Additionally an inline-processing analog-distortion
* filter is applied to all rendered fragments to make the overall look more interesting.
* </p>
*
* <p>
* The different intro parts are all parameter variations of the two routines in the fragment shader
* synched to the music: Parts 3+5 are obviously the mandelbrot and julia bitmap orbit traps, and parts
* 1,2,4 and 6 are pure fractal sphere tracing.
* </p>
*
* <p>
* During the development of the intro it turned out that perfectly raymarching every pixel of the orbit
* trapped julia+mandelbrot fractal was way to slow even on highend hardware. So I inserted a lowres
* intermediate FBO to be used by the bitmap based orbit trap routine wich was ofcourse way faster, but
* had the obvious upscaling artefacts. Maybe I'll produce a perfect quality version for very patient
* people with insane hardware :)
* </p>
*
* <p>
* Papers and articles you should be familiar with before trying to understand the code:
* </p>
*
* <p>
* <ul>
* <li>Distance rendering for fractals: http://www.iquilezles.org/www/articles/distancefractals/distancefractals.htm</li>
* <li>Geometric orbit traps: http://www.iquilezles.org/www/articles/ftrapsgeometric/ftrapsgeometric.htm</li>
* <li>Bitmap orbit traps: http://www.iquilezles.org/www/articles/ftrapsbitmap/ftrapsbitmap.htm</li>
* <li>Ambient occlusion techniques: http://www.iquilezles.org/www/articles/ao/ao.htm</li>
* <li>Sphere tracing: A geometric method for the antialiased ray tracing of implicit surfaces: http://graphics.cs.uiuc.edu/~jch/papers/zeno.pdf</li>
* <li>Rendering fractals with distance estimation function: http://www.iquilezles.org/www/articles/mandelbulb/mandelbulb.htm</li>
* </ul>
* </p>
*
* <p>
* <ul>
* <li>For an impression how this routine looks like see here: http://www.youtube.com/watch?v=lvC8maVHh8Q</li>
* <li>Original release from the Revision can be found here: http://www.pouet.net/prod.php?which=56860</li>
* </ul>
* </p>
*
* <p>
* http://www.youtube.com/user/DemoscenePassivist
* </p>
*
* @author Dominik Ströhlein (DemoscenePassivist)
*/
public class ElektronenMultiplizierer implements GLEventListener {
//BEGIN --- BaseGlobalEnvironment replacement ---
private final GLCapabilities mCaps;
// private final GLU mGlu;
private final String mCommandLineParameter_BaseRoutineClassName;
private final boolean mCommandLineParameter_MultiSampling;
private final int mCommandLineParameter_NumberOfSampleBuffers;
private final boolean mCommandLineParameter_AnisotropicFiltering;
private final float mCommandLineParameter_AnisotropyLevel;
private final boolean mCommandLineParameter_FrameCapture;
private final boolean mCommandLineParameter_FrameSkip;
private boolean mUsesFullScreenMode;
private int mFrameCounter;
private final int mCommandLineParameter_FrameRate;
private long mFrameSkipAverageFramerateTimeStart;
private long mFrameSkipAverageFramerateTimeEnd;
private boolean mFrameSkipManual;
// private int mSkippedFramesCounter;
// private BaseMusic mBaseMusic;
boolean mMusicSyncStartTimeInitialized = false;
private ShaderState st;
private PMVMatrix pmvMatrix;
private GLUniformData pmvMatrixUniform;
private GLUniformData mScreenDimensionUniform;
private GLArrayDataServer vertices0;
// private GLArrayDataServer texCoords0;
public String getBaseRoutineClassName() { return mCommandLineParameter_BaseRoutineClassName; }
public boolean preferMultiSampling() { return mCommandLineParameter_MultiSampling; }
public int getNumberOfSamplingBuffers() { return mCommandLineParameter_NumberOfSampleBuffers; }
public boolean preferAnisotropicFiltering() { return mCommandLineParameter_AnisotropicFiltering; }
public float getAnisotropyLevel() { return mCommandLineParameter_AnisotropyLevel; }
public boolean wantsFrameCapture() { return mCommandLineParameter_FrameCapture; }
public int getDesiredFramerate() { return mCommandLineParameter_FrameRate; }
public boolean wantsFrameSkip() { return mCommandLineParameter_FrameSkip; }
public boolean usesFullScreenMode() { return mUsesFullScreenMode; }
class TimeShiftKeys extends KeyAdapter {
public void keyPressed(final KeyEvent e) {
if(KeyEvent.VK_RIGHT == e.getKeyCode()) {
skipFrames(120);
} else if(KeyEvent.VK_LEFT == e.getKeyCode()) {
skipFrames(-120);
}
}
}
TimeShiftKeys timeShiftKeys;
public ElektronenMultiplizierer (
final String inBaseRoutineClassName,
final boolean inMultiSampling,
final int inNumberOfSampleBuffers,
final boolean inAnisotropicFiltering,
final float inAnisotropyLevel,
final boolean inFrameCapture,
final boolean inFrameSkip, final int desiredFrameRate, final int startFrame
) {
// mGlu = new GLU();
mCommandLineParameter_BaseRoutineClassName = inBaseRoutineClassName;
mCommandLineParameter_MultiSampling = inMultiSampling;
mCommandLineParameter_NumberOfSampleBuffers = (inNumberOfSampleBuffers==-1) ? 2 : inNumberOfSampleBuffers;
mCommandLineParameter_AnisotropicFiltering = inAnisotropicFiltering;
mCommandLineParameter_AnisotropyLevel = (inAnisotropyLevel==-1.0f) ? 2.0f : inAnisotropyLevel;
mCommandLineParameter_FrameCapture = inFrameCapture;
mCommandLineParameter_FrameSkip = inFrameSkip;
mCommandLineParameter_FrameRate = desiredFrameRate;
mCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2));
if (preferMultiSampling()) {
// enable/configure multisampling support ...
mCaps.setSampleBuffers(true);
mCaps.setNumSamples(getNumberOfSamplingBuffers());
mCaps.setAccumAlphaBits(1);
mCaps.setAccumBlueBits(1);
mCaps.setAccumGreenBits(1);
mCaps.setAccumRedBits(1);
// turns out we need to have alpha, otherwise no AA will be visible
mCaps.setAlphaBits(1);
}
mFrameSkipAverageFramerateTimeStart = 0;
mFrameCounter = 0;
skipFrames(startFrame);
timeShiftKeys = new TimeShiftKeys();
}
public ElektronenMultiplizierer() {
this(null, false, -1, false, -1.0f, false, true, 30, 0);
}
/**
* skip frames by turning back start time
* @param frames positive or negative values
*/
public void skipFrames(final int frames) {
final long dft = 1000000000/mCommandLineParameter_FrameRate;
mFrameSkipAverageFramerateTimeStart -= frames * dft ;
mFrameSkipManual = true;
}
public GLCapabilitiesImmutable getGLCapabilities() {
return mCaps;
}
public void init(final GLAutoDrawable drawable) {
if(drawable instanceof GLWindow) {
final GLWindow glw = (GLWindow) drawable;
glw.addKeyListener(0, timeShiftKeys);
}
final GL2ES2 gl = drawable.getGL().getGL2ES2();
gl.setSwapInterval(1);
st = new ShaderState();
final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), "shader",
"shader/bin", "default", true);
final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), "shader",
"shader/bin", "elektronenmultiplizierer_development", true);
// "shader", "shader/bin", "elektronenmultiplizierer_port", true);
vp0.defaultShaderCustomization(gl, true, true);
fp0.defaultShaderCustomization(gl, true, true);
final ShaderProgram sp0 = new ShaderProgram();
sp0.add(gl, vp0, System.err);
sp0.add(gl, fp0, System.err);
st.attachShaderProgram(gl, sp0, true);
final float XRESf = drawable.getSurfaceWidth();
final float YRESf = drawable.getSurfaceHeight();
mScreenDimensionUniform = new GLUniformData("resolution", 2, Buffers.newDirectFloatBuffer(2));
final FloatBuffer mScreenDimensionV = (FloatBuffer) mScreenDimensionUniform.getBuffer();
mScreenDimensionV.put(0, XRESf);
mScreenDimensionV.put(1, YRESf);
st.ownUniform(mScreenDimensionUniform);
st.uniform(gl, mScreenDimensionUniform);
pmvMatrix = new PMVMatrix();
pmvMatrixUniform = new GLUniformData("gcu_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
st.ownUniform(pmvMatrixUniform);
st.uniform(gl, pmvMatrixUniform);
vertices0 = GLArrayDataServer.createGLSL("gca_Vertices", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
vertices0.putf(0); vertices0.putf(YRESf);
vertices0.putf(XRESf); vertices0.putf(YRESf);
vertices0.putf(0); vertices0.putf(0);
vertices0.putf(XRESf); vertices0.putf(0);
vertices0.seal(gl, true);
st.ownAttribute(vertices0, true);
vertices0.enableBuffer(gl, false);
/**
texCoords0 = GLArrayDataServer.createGLSL("gca_TexCoords", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW);
texCoords0.putf(0f); texCoords0.putf(1f);
texCoords0.putf(1f); texCoords0.putf(1f);
texCoords0.putf(0f); texCoords0.putf(0f);
texCoords0.putf(1f); texCoords0.putf(0f);
texCoords0.seal(gl, true);
st.ownAttribute(texCoords0, true);
texCoords0.enableBuffer(gl, false); */
//generate framebufferobject
final int[] result = new int[1];
gl.glGenTextures(1, result, 0);
mFrameBufferTextureID = result[0];
gl.glBindTexture(GL_TEXTURE_2D, mFrameBufferTextureID);
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 384, 384, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
//allocate the framebuffer object ...
gl.glGenFramebuffers(1, result, 0);
mFrameBufferObjectID = result[0];
gl.glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectID);
gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFrameBufferTextureID, 0);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
st.uniform(gl, new GLUniformData("fb", 0));
// will be changed in display(..)
st.uniform(gl, new GLUniformData("en", 0));
st.uniform(gl, new GLUniformData("tm", 0.0f));
st.uniform(gl, new GLUniformData("br", 0.0f));
st.uniform(gl, new GLUniformData("et", 0.0f));
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// if NO music is used sync to mainloop start ...
// (add up current time due to possible turned back start time by skip frames)
mFrameSkipAverageFramerateTimeStart += System.nanoTime();
// mBaseMusic = new BaseMusic(BaseGlobalEnvironment.getInstance().getMusicFileName());
// mBaseMusic.init();
// mBaseMusic.play();
}
public void display(final GLAutoDrawable drawable) {
if (wantsFrameSkip()) {
mFrameSkipAverageFramerateTimeEnd = System.nanoTime();
final double tDesiredFrameRate = getDesiredFramerate();
final double tSingleFrameTime = 1000000000.0f/tDesiredFrameRate;
final double tElapsedTime = mFrameSkipAverageFramerateTimeEnd - mFrameSkipAverageFramerateTimeStart;
final double mFrameCounterTargetValue = tElapsedTime/tSingleFrameTime;
final double mFrameCounterDifference = mFrameCounterTargetValue-mFrameCounter;
if (mFrameSkipManual || mFrameCounterDifference>2) {
mFrameCounter+=mFrameCounterDifference;
// mSkippedFramesCounter+=mFrameCounterDifference;
} else if (mFrameCounterDifference<-2) {
//hold framecounter advance ...
mFrameCounter--;
}
mFrameSkipManual = false;
}
final GL2ES2 gl = drawable.getGL().getGL2ES2();
final int XRES = drawable.getSurfaceWidth();
final int YRES = drawable.getSurfaceHeight();
// if (!getBaseMusic().isOffline()) {
// //if music IS used sync to first second of music ...
// if (BaseRoutineRuntime.getInstance().getBaseMusic().getPositionInMilliseconds()>0 && !mMusicSyncStartTimeInitialized) {
// BaseLogging.getInstance().info("Synching to BaseMusic ...");
// mFrameSkipAverageFramerateTimeStart = (long)(System.nanoTime()-((double)BaseRoutineRuntime.getInstance().getBaseMusic().getPositionInMilliseconds()*1000000.0d));
// mMusicSyncStartTimeInitialized = true;
// }
// }
//allow music DSP's to synchronize with framerate ...
// mBaseMusic.synchonizeMusic();
//use this for offline rendering/capture ...
int MMTime_u_ms = (int)(((mFrameCounter)*44100.0f)/60.0f);
//use this for music synched rendering ...
//int MMTime_u_ms = (int)(BaseRoutineRuntime.getInstance().getBaseMusic().getPositionInMilliseconds()*(44100.0f/1000.0f));
//dedicated sync variable for each event ... kinda lame but who cares X-)
if (MMTime_u_ms>=522240 && !mSyncEvent_01) { mSyncEvent_01 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=1305480 && !mSyncEvent_02) { mSyncEvent_02 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=1827720 && !mSyncEvent_03) { mSyncEvent_03 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=2349960 && !mSyncEvent_04) { mSyncEvent_04 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=3394440 && !mSyncEvent_05) { mSyncEvent_05 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=3916680 && !mSyncEvent_06) { mSyncEvent_06 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=4438408 && !mSyncEvent_07) { mSyncEvent_07 = true; handleSyncEvent(MMTime_u_ms); }
if (MMTime_u_ms>=5482831 && !mSyncEvent_08) { mSyncEvent_08 = true; handleSyncEvent(MMTime_u_ms); }
//calculate current time based on 60fps reference framerate ...
MMTime_u_ms = (int)(((mFrameCounter)*44100.0f)/60.0f);
gl.glDisable(GL_CULL_FACE);
gl.glDisable(GL_DEPTH_TEST);
st.useProgram(gl, true);
vertices0.enableBuffer(gl, true);
// texCoords0.enableBuffer(gl, true);
pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
pmvMatrix.glLoadIdentity();
pmvMatrix.glOrthof(0f, XRES, YRES, 0f, -1f, 1f);
pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
pmvMatrix.glLoadIdentity();
st.uniform(gl, pmvMatrixUniform);
gl.glActiveTexture(GL_TEXTURE0);
//gogogo! O-)
float tBrightnessSync = 40.0f-((MMTime_u_ms-mSyncTime)/1000.0f);
if (tBrightnessSync<1) {
tBrightnessSync=1;
}
mEffectTime = (MMTime_u_ms-mEffectSyncTime)/100000.0f;
if (mSyncEventNumber==0 && mEffectTime<4.0f) {
//fadein and fullscreen rotate
tBrightnessSync = mEffectTime/4.0f;
} else if (mSyncEventNumber==8 && mEffectTime>12.0f) {
//fullscrenn mushroom transform
tBrightnessSync = 1.0f-((mEffectTime-12.0f)/3.5f);
}
if (mSyncEventNumber==0 || mSyncEventNumber==1) {
//zoomin from fog
mEffectNumber = 3;
mEffectTime *= 1.75;
final float tEffectTimeMax = 9.3f;
if (mEffectTime>=tEffectTimeMax) {
mEffectTime=tEffectTimeMax;
}
} else if(mSyncEventNumber==2 || mSyncEventNumber==3) {
//transform big after zoomin
mEffectNumber = 4;
mEffectTime *= 0.25f;
} else if(mSyncEventNumber==4) {
//mandelbrot orbit-trap zoomout
mEffectNumber = 1;
mEffectTime *= 0.0002f;
} else if(mSyncEventNumber==5 || mSyncEventNumber==6) {
//inside fractal
mEffectNumber = 5;
mEffectTime *= 0.02f;
} else if(mSyncEventNumber==7) {
//spiral orbit-trap
mEffectNumber = 0;
mEffectTime *= 0.02f;
} else if(mSyncEventNumber==8) {
//fadeout fractal
mEffectNumber = 6;
mEffectTime *= 0.364f;
}
gl.glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectID);
// gl.glViewport(0, 0, drawable.getWidth(), drawable.getHeight());
final GLUniformData en = st.getUniform("en");
if(mSyncEventNumber==7) {
en.setData(2);
}
if(mSyncEventNumber==4) {
en.setData(7);
} else {
en.setData(0);
}
st.uniform(gl, en);
final GLUniformData et = st.getUniform("et");
st.uniform(gl, et.setData(9.1f));
st.uniform(gl, st.getUniform("tm").setData(MMTime_u_ms/40000.0f));
st.uniform(gl, st.getUniform("br").setData(tBrightnessSync));
if(mSyncEventNumber==4 || mSyncEventNumber==7) {
//render to fbo only when using julia/mandel orbittrap ...
// gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);
}
gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
st.uniform(gl, en.setData(mEffectNumber));
st.uniform(gl, et.setData(mEffectTime));
if( !gl.isGLcore() ) {
gl.glEnable(GL_TEXTURE_2D);
}
gl.glBindTexture(GL_TEXTURE_2D, mFrameBufferTextureID);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);
vertices0.enableBuffer(gl, false);
// texCoords0.enableBuffer(gl, false);
st.useProgram(gl, false);
//---
mFrameCounter++;
}
public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
final GL2ES2 gl = drawable.getGL().getGL2ES2();
st.useProgram(gl, true);
vertices0.seal(false);
vertices0.rewind();
vertices0.putf(0); vertices0.putf(height);
vertices0.putf(width); vertices0.putf(height);
vertices0.putf(0); vertices0.putf(0);
vertices0.putf(width); vertices0.putf(0);
vertices0.seal(gl, true);
st.ownAttribute(vertices0, true);
vertices0.enableBuffer(gl, false);
final FloatBuffer mScreenDimensionV = (FloatBuffer) mScreenDimensionUniform.getBuffer();
mScreenDimensionV.put(0, width);
mScreenDimensionV.put(1, height);
st.uniform(gl, mScreenDimensionUniform);
st.useProgram(gl, false);
gl.glViewport(0, 0, width, height);
}
public void dispose(final GLAutoDrawable drawable) {
final GL2ES2 gl = drawable.getGL().getGL2ES2();
gl.glDeleteFramebuffers(1, new int[] { mFrameBufferObjectID }, 0);
gl.glDeleteTextures(1, new int[] { mFrameBufferTextureID }, 0);
st.destroy(gl);
if(drawable instanceof GLWindow) {
final GLWindow glw = (GLWindow) drawable;
glw.removeKeyListener(timeShiftKeys);
}
}
// public BaseMusic getBaseMusic() {
// return mBaseMusic;
// }
public void resetFrameCounter() {
mFrameCounter = 0;
}
//END --- BaseRoutineRuntime ---
protected int mFrameBufferTextureID;
protected int mFrameBufferObjectID;
protected int mSyncTime;
protected int mSyncEventNumber;
protected float mEffectTime;
protected int mEffectNumber;
protected int mEffectSyncTime;
protected boolean mSyncEvent_01;
protected boolean mSyncEvent_02;
protected boolean mSyncEvent_03;
protected boolean mSyncEvent_04;
protected boolean mSyncEvent_05;
protected boolean mSyncEvent_06;
protected boolean mSyncEvent_07;
protected boolean mSyncEvent_08;
public void handleSyncEvent(final int inMMTime_u_ms) {
mSyncTime = inMMTime_u_ms;
mSyncEventNumber++;
System.out.println("NEW SYNC EVENT! tSyncEventNumber="+mSyncEventNumber+" tSyncTime="+mSyncTime);
if (mSyncEventNumber==0 || mSyncEventNumber==2 || mSyncEventNumber==5 || mSyncEventNumber==8) {
mEffectSyncTime = inMMTime_u_ms;
}
}
}