/*
* Copyright (C) 2014 James Lawrence.
*
* This file is part of GrimEdi.
*
* GrimEdi is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Created by JFormDesigner on Fri Mar 22 14:35:59 GMT 2013
*/
package com.sqrt4.grimedi.ui.component;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.math.FloatUtil;
import com.sqrt.liblab.entry.model.*;
import com.sqrt.liblab.threed.Angle;
import com.sqrt.liblab.threed.Bounds3;
import com.sqrt.liblab.threed.Vector2f;
import com.sqrt.liblab.threed.Vector3f;
import com.sqrt4.grimedi.ui.MainWindow;
import com.sqrt4.grimedi.ui.layout.WrapLayout;
import javax.media.opengl.*;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.PrintStream;
import java.nio.Buffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author James Lawrence
*/
public class ModelRenderer extends JPanel implements GLEventListener {
private OurAnimator animator;
private GrimModel model;
private java.util.List<Texture> textures = new LinkedList<Texture>();
private boolean _regenerateTextures;
public boolean drawTextures = true;
public boolean drawWireframe;
public boolean drawNormals;
public boolean smoothShading = true;
public boolean drawPlane = true;
public boolean useCallList = true;
public float planeWidth = 0.5f;
public float planeExtent = 10f;
private Vector3f target;
private float camDistance = 1f, theta, phi;
private boolean mouseUpdate, rebuildList = true, builtList;
private int listId;
private Lock mouseLock = new ReentrantLock();
private int oldX, oldY, rX, rY;
private GLU glu = new GLU();
private ModelNode selected;
private FrameCallback callback;
private GLCanvas canvas;
private int viewWidth, viewHeight;
public ModelRenderer() {
initComponents();
toggleTextures.setSelected(drawTextures);
toggleWireframe.setSelected(drawWireframe);
toggleNormals.setSelected(drawNormals);
toggleSmooth.setSelected(smoothShading);
toggleGrid.setSelected(drawPlane);
}
public int getViewportWidth() {
return viewWidth;
}
public int getViewportHeight() {
return viewHeight;
}
public void setSelectedNode(ModelNode node) {
selected = node;
rebuildList = true;
}
public ModelNode getSelectedNode() {
return selected;
}
public void setModel(final GrimModel model) {
this.model = model;
loadGL();
selected = null;
_regenerateTextures = true;
rebuildList = true;
phi = 0;
theta = -4.71f;
camDistance = 1;
colorMapSelector.setLabFile(model.container);
Bounds3 bounds = model.getBounds();
target = bounds == null ? Vector3f.zero : bounds.center;
}
public void setCallback(FrameCallback fc) {
this.callback = fc;
}
public FrameCallback getCallback() {
return callback;
}
private IntBuffer viewport = Buffers.newDirectIntBuffer(4);
private FloatBuffer modelview = Buffers.newDirectFloatBuffer(16);
private FloatBuffer projview = Buffers.newDirectFloatBuffer(16);
private FloatBuffer zBuf = Buffers.newDirectFloatBuffer(1);
private FloatBuffer result = Buffers.newDirectFloatBuffer(4);
public void init(GLAutoDrawable glAutoDrawable) {
//glAutoDrawable.setGL(new DebugGL2(glAutoDrawable.getGL().getGL2()));
GL2 gl = glAutoDrawable.getGL().getGL2();
gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glEnable(GL2.GL_LIGHT0);
gl.glAlphaFunc(GL.GL_GREATER, 0.5f);
gl.glEnable(GL2.GL_ALPHA_TEST);
gl.glColorMaterial(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE);
gl.glEnable(GL2.GL_COLOR_MATERIAL);
for (int i = 0; i < textures.size(); i++)
gl.glDeleteTextures(1, IntBuffer.wrap(new int[]{i + 1}));
textures.clear();
_regenerateTextures = true;
}
public GL getGL() {
return canvas.getGL();
}
public void dispose(GLAutoDrawable glAutoDrawable) {
}
public void display(GLAutoDrawable glAutoDrawable) {
GL2 gl2 = glAutoDrawable.getGL().getGL2();
gl2.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
if (model == null || target == null)
return;
if (callback != null)
callback.preDisplay(gl2);
Vector3f rot = new Vector3f(camDistance * FloatUtil.cos(theta),
camDistance * FloatUtil.cos(phi) * FloatUtil.sin(theta),
camDistance * FloatUtil.sin(phi) * FloatUtil.sin(theta));
Vector3f cam = target.add(rot);
gl2.glLoadIdentity();
if (mouseUpdate && mouseLock.tryLock()) {
Vector3f orig = toWorld(gl2, oldX, oldY);
Vector3f n = toWorld(gl2, oldX + rX, oldY + rY);
Vector3f delta = n.sub(orig);
theta += delta.x;
phi += delta.y;
// Todo: clamp..
rX = rY = 0;
mouseUpdate = false;
mouseLock.unlock();
}
glu.gluLookAt(cam.x, cam.y, cam.z, target.x, target.y, target.z, 0, 0, 1);
if (useCallList && rebuildList) {
if (builtList)
gl2.glDeleteLists(listId, 1);
listId = gl2.glGenLists(1);
gl2.glNewList(listId, GL2.GL_COMPILE);
doRender(gl2);
gl2.glEndList();
builtList = true;
rebuildList = false;
}
if (!useCallList && builtList) {
rebuildList = true;
builtList = false;
gl2.glDeleteLists(listId, 1);
}
gl2.glCallList(listId);
if (drawTextures)
_regenerateTextures = false;
if (callback != null)
callback.postDisplay(gl2);
}
private void doRender(GL2 gl2) {
// Draw floor plane...
if (drawPlane) {
gl2.glColor3f(0.7f, 0.7f, 0.7f);
gl2.glBegin(GL2.GL_LINES);
for (float x = -planeExtent; x <= planeExtent; x += planeWidth) {
gl2.glVertex3f(x, -planeExtent, 0);
gl2.glVertex3f(x, planeExtent, 0); // left-to-right
gl2.glVertex3f(-planeExtent, x, 0);
gl2.glVertex3f(planeExtent, x, 0); // top-to-bottom
}
gl2.glEnd();
}
renderNode(gl2, model.hierarchy.get(0));
}
private void renderNode(GL2 gl2, ModelNode node) {
boolean isSelected = selected == node;
// -- translateViewport
Vector3f animPos = node.pos.add(node.animPos);
Angle animPitch = node.pitch.add(node.animPitch);
Angle animYaw = node.yaw.add(node.animYaw);
Angle animRoll = node.roll.add(node.animRoll);
// -- translateViewportStart
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glPushMatrix();
// --
gl2.glTranslatef(animPos.x, animPos.y, animPos.z);
gl2.glRotatef(animYaw.degrees, 0, 0, 1);
gl2.glRotatef(animPitch.degrees, 1, 0, 0);
gl2.glRotatef(animRoll.degrees, 0, 1, 0);
// --
if (node.hierarchyVisible) {
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glPushMatrix();
gl2.glTranslatef(node.pivot.x, node.pivot.y, node.pivot.z);
// Draw mesh...
if (node.mesh != null && node.meshVisible) {
for (MeshFace face : node.mesh.faces) {
Texture tex = null;
int texId;
gl2.glEnable(GL2.GL_LIGHTING);
// Load the texture if needed...
if (drawTextures && face.texture != null) {
tex = face.texture;
texId = _regenerateTextures ? genTexture(gl2, tex) : getTexture(tex);
gl2.glEnable(GL2.GL_TEXTURE_2D);
gl2.glBindTexture(GL.GL_TEXTURE_2D, texId);
}
// Draw the shape (if we're not wireframing, draw solid, if we're texturing then draw under the wireframe...)
if (!drawWireframe || drawTextures) {
gl2.glColor3f(1, 1, 1);
switch (face.vertices.size()) {
case 3:
gl2.glBegin(GL.GL_TRIANGLES);
break;
case 4:
gl2.glBegin(GL2.GL_QUADS);
break;
default:
gl2.glBegin(GL2.GL_POLYGON);
break;
}
for (int i = 0; i < face.vertices.size(); i++) {
Vector3f vertex = face.vertices.get(i);
Vector3f normal = smoothShading ? face.normals.get(i) : face.normal;
if (tex != null) {
Vector2f uv = face.uv.get(i);
// Model stores the tex coords backwards...
gl2.glTexCoord2f(uv.x / tex.width, 1f + uv.y / tex.height);
}
gl2.glNormal3f(normal.x, normal.y, normal.z);
gl2.glVertex3f(vertex.x, vertex.y, vertex.z);
}
gl2.glEnd();
gl2.glDisable(GL2.GL_TEXTURE_2D);
}
// Draw wireframe if need be
if (drawWireframe || isSelected) {
if (isSelected)
gl2.glColor3f(1, 0, 0);
else
gl2.glColor3f(1, 1, 1);
gl2.glBegin(GL2.GL_LINE_STRIP);
List<Vector3f> vertices = face.vertices;
for (int i = 0; i < vertices.size(); i++) {
Vector3f v = vertices.get(i);
Vector3f normal = smoothShading ? face.normals.get(i) : face.normal;
gl2.glNormal3f(normal.x, normal.y, normal.z);
gl2.glVertex3f(v.x, v.y, v.z);
}
Vector3f v = face.vertices.get(0);
Vector3f normal = smoothShading ? face.normals.get(0) : face.normal;
gl2.glNormal3f(normal.x, normal.y, normal.z);
gl2.glVertex3f(v.x, v.y, v.z);
gl2.glEnd();
}
if (drawNormals) {
final float normalLength = 0.01f * camDistance;
if (isSelected)
gl2.glColor3f(0, 1, 0);
else
gl2.glColor3f(0, 0, 1);
gl2.glDisable(GL2.GL_LIGHTING);
gl2.glBegin(GL2.GL_LINES);
Vector3f normal = face.normal;
Vector3f center = face.getBounds(new Vector3f(0, 0, 0)).center;
gl2.glVertex3f(center.x, center.y, center.z);
gl2.glVertex3f(center.x + normal.x * normalLength, center.y + normal.y * normalLength, center.z + normal.z * normalLength);
List<Vector3f> vertices = face.vertices;
for (int i = 0; i < vertices.size(); i++) {
Vector3f v = vertices.get(i);
normal = face.normals.get(i);
gl2.glVertex3f(v.x, v.y, v.z);
gl2.glVertex3f(v.x + normal.x * normalLength, v.y + normal.y * normalLength, v.z + normal.z * normalLength);
}
gl2.glEnd();
}
}
}
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glPopMatrix();
if (node.child != null)
renderNode(gl2, node.child);
}
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glPopMatrix();
if (node.sibling != null)
renderNode(gl2, node.sibling);
gl2.glDisable(GL2.GL_LIGHTING);
}
public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) {
GL2 gl2 = glAutoDrawable.getGL().getGL2();
gl2.glMatrixMode(GL2.GL_PROJECTION);
gl2.glLoadIdentity();
GLU glu = new GLU();
float aspect = (float) width / (float) height;
glu.gluPerspective(45, aspect, 0.0001f, 20f);
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glLoadIdentity();
viewWidth = width;
viewHeight = height;
}
private Vector3f toWorld(GL2 gl2, int x, int y) {
viewport.clear();
modelview.clear();
projview.clear();
zBuf.clear();
result.clear();
gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport);
gl2.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, modelview);
gl2.glGetFloatv(GL2.GL_PROJECTION_MATRIX, projview);
float winX = viewport.get(3) - x;
gl2.glReadPixels((int) winX, y, 1, 1, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, zBuf);
float winZ = zBuf.get(0);
glu.gluUnProject(winX, y, winZ, modelview, projview, viewport, result);
float px = result.get(0);
float py = result.get(1);
float pz = result.get(2);
return new Vector3f(px, py, pz);
}
public void refreshModelCache() {
rebuildList = true;
}
private void loadGL() {
try {
if (animator != null)
return;
animator = new OurAnimator();
GLCapabilities caps = new GLCapabilities(GLProfile.getDefault());
caps.setDepthBits(32);
canvas = new GLCanvas(caps);
canvas.addGLEventListener(this);
panel2.add(canvas, BorderLayout.CENTER);
animator.add(canvas);
animator.start();
MouseAdapter mad = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
mouseLock.lock();
oldX = e.getX();
oldY = e.getY();
mouseLock.unlock();
}
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
mouseLock.lock();
rX = x - oldX;
rY = y - oldY;
oldX = x;
oldY = y;
mouseUpdate = true;
mouseLock.unlock();
}
public void mouseWheelMoved(MouseWheelEvent e) {
camDistance += e.getPreciseWheelRotation() * 0.1f;
}
};
canvas.addMouseListener(mad);
canvas.addMouseMotionListener(mad);
canvas.addMouseWheelListener(mad);
} catch (Throwable t) {
MainWindow.getInstance().handleException(t);
}
}
private int getTexture(Texture tex) {
if (textures.contains(tex))
return textures.indexOf(tex) + 1;
return -1;
}
private int genTexture(GL2 gl, Texture tex) {
int id = getTexture(tex);
if (id != -1) {
gl.glDeleteTextures(1, IntBuffer.wrap(new int[]{id}));
} else {
id = textures.size() + 1;
textures.add(tex);
}
gl.glGenTextures(1, IntBuffer.wrap(new int[]{id}));
gl.glBindTexture(GL.GL_TEXTURE_2D, id);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA8, tex.width, tex.height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, toRgba(tex));
return id;
}
private Buffer toRgba(Texture tex) {
final int size = tex.width * tex.height;
ColorMap map = colorMapSelector.getSelected();
IntBuffer pix = IntBuffer.allocate(size);
for (int i = 0; i < size; i++) {
int idx = tex.indices[i] & 0xff;
pix.put(tex.hasAlpha && idx == 0 ? 0 : map.colors[idx] | (0xff << 24));
}
pix.flip();
return pix;
}
private void colorMapSelected(ItemEvent ignore) {
_regenerateTextures = true;
rebuildList = true;
}
public GrimModel getModel() {
return model;
}
public ColorMap getColorMap() {
return colorMapSelector.getSelected();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
panel2 = new JPanel();
panel4 = new JPanel();
panel1 = new JPanel();
label1 = new JLabel();
colorMapSelector = new ColorMapSelector();
toggleTextures = new JCheckBox();
toggleWireframe = new JCheckBox();
toggleNormals = new JCheckBox();
toggleSmooth = new JCheckBox();
toggleGrid = new JCheckBox();
normalToggleAction = new NormalToggleAction();
toggleSmoothAction = new ToggleSmoothAction();
toggleTextureAction = new ToggleTextures();
toggleWireframeAction = new ToggleWireframe();
toggleGridAction = new ToggleGridAction();
//======== this ========
setLayout(new BorderLayout());
//======== panel2 ========
{
panel2.setLayout(new BorderLayout());
}
add(panel2, BorderLayout.CENTER);
//======== panel4 ========
{
panel4.setLayout(null);
panel4.setLayout(new WrapLayout());
//======== panel1 ========
{
panel1.setLayout(new FlowLayout());
//---- label1 ----
label1.setText("Color Map:");
panel1.add(label1);
//---- colorMapSelector ----
colorMapSelector.setMinimumSize(new Dimension(100, 20));
colorMapSelector.setPreferredSize(new Dimension(100, 20));
colorMapSelector.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
colorMapSelected(e);
}
});
panel1.add(colorMapSelector);
}
panel4.add(panel1);
panel1.setBounds(new Rectangle(new Point(45, 5), panel1.getPreferredSize()));
//---- toggleTextures ----
toggleTextures.setAction(toggleTextureAction);
toggleTextures.setSelected(true);
panel4.add(toggleTextures);
toggleTextures.setBounds(new Rectangle(new Point(217, 8), toggleTextures.getPreferredSize()));
//---- toggleWireframe ----
toggleWireframe.setAction(toggleWireframeAction);
panel4.add(toggleWireframe);
toggleWireframe.setBounds(new Rectangle(new Point(291, 8), toggleWireframe.getPreferredSize()));
//---- toggleNormals ----
toggleNormals.setAction(normalToggleAction);
panel4.add(toggleNormals);
toggleNormals.setBounds(new Rectangle(new Point(371, 8), toggleNormals.getPreferredSize()));
//---- toggleSmooth ----
toggleSmooth.setAction(toggleSmoothAction);
panel4.add(toggleSmooth);
toggleSmooth.setBounds(new Rectangle(new Point(164, 40), toggleSmooth.getPreferredSize()));
//---- toggleGrid ----
toggleGrid.setAction(toggleGridAction);
panel4.add(toggleGrid);
toggleGrid.setBounds(new Rectangle(new Point(270, 40), toggleGrid.getPreferredSize()));
}
add(panel4, BorderLayout.NORTH);
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// Generated using JFormDesigner non-commercial license
private JPanel panel2;
private JPanel panel4;
private JPanel panel1;
private JLabel label1;
private ColorMapSelector colorMapSelector;
private JCheckBox toggleTextures;
private JCheckBox toggleWireframe;
private JCheckBox toggleNormals;
private JCheckBox toggleSmooth;
private JCheckBox toggleGrid;
private NormalToggleAction normalToggleAction;
private ToggleSmoothAction toggleSmoothAction;
private ToggleTextures toggleTextureAction;
private ToggleWireframe toggleWireframeAction;
private ToggleGridAction toggleGridAction;
// JFormDesigner - End of variables declaration //GEN-END:variables
private class ToggleSmoothAction extends AbstractAction {
private ToggleSmoothAction() {
// JFormDesigner - Action initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
putValue(NAME, "Smooth shading");
putValue(SHORT_DESCRIPTION, "toggle smooth shading");
// JFormDesigner - End of action initialization //GEN-END:initComponents
}
public void actionPerformed(ActionEvent e) {
smoothShading = toggleSmooth.isSelected();
rebuildList = true;
}
}
private class NormalToggleAction extends AbstractAction {
private NormalToggleAction() {
// JFormDesigner - Action initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
putValue(NAME, "Normals");
putValue(SHORT_DESCRIPTION, "draw normals");
// JFormDesigner - End of action initialization //GEN-END:initComponents
}
public void actionPerformed(ActionEvent e) {
drawNormals = toggleNormals.isSelected();
rebuildList = true;
}
}
private class ToggleTextures extends AbstractAction {
private ToggleTextures() {
// JFormDesigner - Action initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
putValue(NAME, "Textured");
putValue(SHORT_DESCRIPTION, "map face textures");
// JFormDesigner - End of action initialization //GEN-END:initComponents
}
public void actionPerformed(ActionEvent e) {
drawTextures = toggleTextures.isSelected();
colorMapSelector.setEnabled(drawTextures);
rebuildList = true;
}
}
private class ToggleWireframe extends AbstractAction {
private ToggleWireframe() {
// JFormDesigner - Action initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
putValue(NAME, "Wireframe");
putValue(SHORT_DESCRIPTION, "draw wireframes");
// JFormDesigner - End of action initialization //GEN-END:initComponents
}
public void actionPerformed(ActionEvent e) {
drawWireframe = toggleWireframe.isSelected();
rebuildList = true;
}
}
private class ToggleGridAction extends AbstractAction {
private ToggleGridAction() {
// JFormDesigner - Action initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
putValue(NAME, "Grid");
putValue(SHORT_DESCRIPTION, "draw a grid");
// JFormDesigner - End of action initialization //GEN-END:initComponents
}
public void actionPerformed(ActionEvent e) {
drawPlane = toggleGrid.isSelected();
rebuildList = true;
}
}
}
class OurAnimator implements GLAnimatorControl {
private List<GLAutoDrawable> drawables = Collections.synchronizedList(new LinkedList<GLAutoDrawable>());
private boolean started, paused;
private int frameDelta;
private Runnable _runner = new Runnable() {
public void run() {
try {
while (started) {
try {
long start = System.currentTimeMillis();
if (isAnimating()) {
for (int i = 0; isAnimating() && i < drawables.size(); i++) {
GLAutoDrawable drawable = drawables.get(i);
drawable.display();
}
}
long delta = System.currentTimeMillis() - start;
Thread.sleep(Math.max(frameDelta - delta, 5));
} catch (Throwable ignore) {
MainWindow.getInstance().handleException(ignore);
}
}
} finally {
started = false;
paused = false;
}
}
};
private Thread thread;
public boolean isStarted() {
return started;
}
public boolean isAnimating() {
return started && !paused && !drawables.isEmpty();
}
public boolean isPaused() {
return paused;
}
public Thread getThread() {
return thread;
}
public boolean start() {
if (thread != null)
return false;
started = true;
paused = false;
thread = new Thread(_runner);
thread.setPriority(1);
thread.setDaemon(true);
thread.start();
return true;
}
public boolean stop() {
if (thread == null)
return false;
started = false;
try {
thread.join();
thread = null;
return true;
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
public boolean pause() {
if (thread == null)
return false;
paused = true;
return true;
}
public boolean resume() {
if (!paused)
return false;
paused = false;
return true;
}
public void add(GLAutoDrawable glAutoDrawable) {
if (drawables.contains(glAutoDrawable))
return;
drawables.add(glAutoDrawable);
glAutoDrawable.setAnimator(this);
}
public void remove(GLAutoDrawable glAutoDrawable) {
drawables.remove(glAutoDrawable);
}
@Override
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return null;
}
@Override
public void setUncaughtExceptionHandler(UncaughtExceptionHandler uncaughtExceptionHandler) {
}
public void setUpdateFPSFrames(int i, PrintStream printStream) {
frameDelta = 1000 / i;
}
public void resetFPSCounter() {
}
public int getUpdateFPSFrames() {
return 0;
}
public long getFPSStartTime() {
return 0;
}
public long getLastFPSUpdateTime() {
return 0;
}
public long getLastFPSPeriod() {
return 0;
}
public float getLastFPS() {
return 0;
}
public int getTotalFPSFrames() {
return 0;
}
public long getTotalFPSDuration() {
return 0;
}
public float getTotalFPS() {
return 0;
}
}