jPCT - a 3d engine for Java => Support => Topic started by: Melssj5 on March 28, 2009, 03:57:55 pm

Title: Performance problems
Post by: Melssj5 on March 28, 2009, 03:57:55 pm
Hi, ai am having problems with performance, from time to time (almost each 10 seconds) the CPU usage goes to 100% on the applet and then it stops responfing for 5 or 6 seconds, and then continues on the same way. Any ideas????

I am using a Centrino 1.6, 1Gb RAM, ATIX600, and I am running a GL Canvas inside an applet.

The code is quite simple, The class that does all the Rendering is:

Code: [Select]

 * RenderThread.java
 * Created on 1 de noviembre de 2005, 22:32

package visor;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.DataInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.swing.ImageIcon;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.KeyMapper;
import com.threed.jpct.util.KeyState;
 * @author  Gold Oozaru
 * @version
public class RenderThread extends Thread implements MouseListener{
    static boolean OGL;

    World mundo;
    FrameBuffer buffer;
    KeyMapper mapaTeclas;
    KeyState estadoTeclas;
    TextureManager manejadorTexturas;
    Texture texturaActual;
    boolean izquierda;
    boolean derecha;
    boolean adelante;
    boolean atras;
    boolean luces;
    boolean salir;
    ArrayList paredes;
    ArrayList techos;
    ArrayList pisos;
    Object3D vidrios;
    Object3D otros;
    Object3D inicio;
    Canvas canvas;
    URL docBase;
    public Graphics g;
    String url="";
    String mapa="";
    Object3D seleccionado=null;
    /** Creates new RenderThread */
    public RenderThread(World am, FrameBuffer ab, KeyMapper ak, Canvas ac, String nombreMapa, String aurl) {
    //---------------------Hacer el renderThread
        texturas ();
        //texturasList ();
        pisos=new ArrayList ();
        techos=new ArrayList ();
        paredes=new ArrayList ();
        vidrios=new Object3D (0);
        otros=new Object3D (0);
        inicio=new Object3D (0);
        cargar ("mapa.3DS", 0.3f);
        mundo.addObject (otros);
        mundo.addObject (vidrios);
        addObjects (pisos, mundo);
        addObjects (techos, mundo);
        addObjects (paredes, mundo);
        mundo.buildAllObjects ();
        //System.out.println ("getposition ()"+mundo.getCamera().getPosition ());
    public void addObjects (ArrayList objetos, World mundo) {
    for (int i=0;i<objetos.size();i++) {
    Object3D temp=(Object3D) objetos.get(i);
    mundo.addObject (temp);
    public void cargar (String fileName, float escala) {
try {
URL link=new URL (url+"/mapas/");
System.out.println ("url: "+link.getFile());
        Object3D partes []=Loader.load3DS (link, mapa, escala);
        for (int i=0;i<partes.length;i++) {
            Object3D part=partes [i];
            part.setRotationMatrix(new Matrix());
            if ((i&1)==1) part.setTransparency(0);
            String p1="";
            String p2="";
            String p3="";
            StringTokenizer separador=new StringTokenizer (part.getName(), "_");
            try {
            } catch (Exception E) {
            if (part.getName ().startsWith ("vidrio") || part.getName ().startsWith ("vidrio") || part.getName ().startsWith ("parabrisa")) {
                vidrios=Object3D.mergeObjects (vidrios, part);
            } else if (p2.startsWith ("P")) {
            Object3D temp=new Object3D (0);
            part=Object3D.mergeObjects (part, temp);
            } else if (p2.startsWith ("T")) {
            } else if (p2.startsWith ("W")) {
            Object3D temp=new Object3D (0);
            part=Object3D.mergeObjects (part, temp);
            System.out.println ("pared agregada: "+part.getName());
            } else if (part.getName ().startsWith ("inicio")) {
            inicio=Object3D.mergeObjects (inicio, part);
            } else {
                otros=Object3D.mergeObjects (otros, part);
} catch (Exception E) {
    public void run () {
        while (!salir) {

            if (OGL){

            buffer.clear ();
            buffer.update ();
            mundo.renderScene (buffer);
            mundo.draw (buffer);
            buffer.displayGLOnly ();

            canvas.repaint ();
            try {
            } catch (Exception E) {
                this.stop ();
            do {
                if (estadoTeclas!=KeyState.NONE) {
                    obtenerEventos (estadoTeclas);
            } while (estadoTeclas!=KeyState.NONE);
            hacerMovimientos ();
        this.stop ();
    public void hacerMovimientos () {
        if (izquierda) {
            moverIzquierda ();
        if (derecha) {
            moverDerecha ();
        if (atras) {
            Camera c=mundo.getCamera ();
            c.moveCamera (Camera.CAMERA_MOVEOUT, 6f);
        if (adelante) {
            Camera c=mundo.getCamera ();
            c.moveCamera (Camera.CAMERA_MOVEIN, 6f);
    public void obtenerEventos (KeyState evento) {
        boolean estado=evento.getState ();
        if (estadoTeclas.getKeyCode ()==KeyEvent.VK_UP)
        if (estadoTeclas.getKeyCode ()==KeyEvent.VK_DOWN)
        if (estadoTeclas.getKeyCode ()==KeyEvent.VK_LEFT)
        if (estadoTeclas.getKeyCode ()==KeyEvent.VK_RIGHT)
        if (estadoTeclas.getKeyCode ()==KeyEvent.VK_ESCAPE)
        if (estadoTeclas.getKeyCode ()==KeyEvent.VK_SPACE)

    public String getPath () {
        System.out.println (this.getClass ().getResource (""));
        return (this.getClass ().getResource ("./").getFile().replace ("%20", " "));
    public String getURLPath (String filename) {
        return (this.getClass ().getResource (filename).getFile());   
    public void texturas () {
    manejadorTexturas=TextureManager.getInstance ();
    ArrayList materiales=texturasList ();
    URL link=null;
try {
link = new URL (url+"/images/Texturas/");
} catch (Exception e) {
    for (int i=0;i<materiales.size();i++) {
    manejadorTexturas.addTexture (((String)materiales.get(i))+".JPG", new Texture (link, ((String)materiales.get(i))+".JPG"));
    public ArrayList texturasList () {
    try {
URL link=new URL (url+"/images/Texturas/props.txt");
URLConnection uc=link.openConnection();
DataInputStream dis=new DataInputStream (uc.getInputStream());

    System.out.println ("TEXTURAS: ");
    String texturas=dis.readLine();
StringTokenizer separadorMaterial=new StringTokenizer (texturas, "|");

ArrayList materiales=new ArrayList ();

while (separadorMaterial.hasMoreTokens()) {
String material=separadorMaterial.nextToken();
StringTokenizer separadorTextura=new StringTokenizer (material, ":");
return materiales;

} catch (Exception e) {
return null;
    public void cambiarTextura (String parte) {
    public void moverIzquierda () {
        Camera temp=mundo.getCamera ();
        temp.rotateY (0.02f);
    public void moverDerecha () {
    Camera temp=mundo.getCamera ();
         temp.rotateY (-0.02f);
    public void renderAWT (Graphics g) {

        buffer.clear ();
        buffer.update ();
        mundo.renderScene (buffer);
        mundo.draw (buffer);
        try {
        } catch (Exception E) {
            this.stop ();

    public void enviarComentario (String mensaje, ImageIcon imagen) {

public void mouseClicked(MouseEvent e) {

public void mouseEntered(MouseEvent e) {

public void mouseExited(MouseEvent e) {

public void mousePressed(MouseEvent e) {

public void mouseReleased(MouseEvent evt) {

if (seleccionado!=null)seleccionado.setAdditionalColor(Color.black);

int x=evt.getX();
    int y=evt.getY();
    SimpleVector ray=Interact2D.reproject2D3D(mundo.getCamera(), buffer, x, y);
    int poli[]=Interact2D.pickPolygon(mundo.getVisibilityList(), ray);
    Object3D temp=mundo.getObject(Interact2D.getObjectID(poli));

Title: Re: Performance problems
Post by: EgonOlsen on March 28, 2009, 08:36:49 pm
Maybe the applet thinks that calling repaint() like there's no tomorrow is a smart idea? You could easily check this by adding an IPaintListener to the FrameBuffer and adding a debug output in the startPainting()-method to see, if it's actually being called during that 5-6 sec. lasting pause period.
Title: Re: Performance problems
Post by: Melssj5 on March 28, 2009, 08:59:44 pm
The outputs are also being stopped for that period of time.
Title: Re: Performance problems
Post by: paulscode on March 28, 2009, 09:38:16 pm
This is probably a multi-thread synchronization problem.  In your code, the line "implements MouseListener" is the first thing that caught my attention.  One potential problem spot is your mouseReleased() method, which is altering your "picked polygons" on a different thread than the one handling the "run" method.  That's just the first potential problem I noticed, and not necessarily what is causing your delay problems - there may be other thread-related problems here in the RenderThread class or elsewhere in your project, so I would take a really close look to ensure that everything is running on a single thread.  One easy way to do this is to synchronize everything that does anything to any component of jPCT on a static final Object, (this solved a similar "random performance crash" problem I was having on a target-shooter applet I'm working on).

One more thing I thought I'd point out (you probably already know this, but I'll mention it anyway).  Just because a class extends the Thread class, that doesn't mean all its methods are automatically going to run on a single thread.
Title: Re: Performance problems
Post by: Melssj5 on March 28, 2009, 09:58:28 pm
Paul, the problem is not abouth that beucasse I was happening before adding that piece of code of the listener. Egon or Paul....Do you have a machine with Tomcat and mysql to send a test case??
Title: Re: Performance problems
Post by: paulscode on March 28, 2009, 10:34:32 pm
Unfortunately, I do not.  If it is not a thread problem, then you could always use the "trial and error" method to track down the cause.  I assume this "performance crashing" only happens with this one applet, so I would start a new bare-bones applet project and slowly add components of your current project to it a little at a time.  Then you can at least figure out where in your code to focus more of your attention.  That is often the method I have to end up using to track down particularly tricky problems.  Sorry I couldn't be any more help than that.
Title: Re: Performance problems
Post by: Melssj5 on March 28, 2009, 11:55:54 pm
I changed it to render in software instead of inside a GLCanvas (minor change) and the delay does not appear. COuld this be some issue the the new lwjgl with glCanvas????
Title: Re: Performance problems
Post by: Melssj5 on March 29, 2009, 12:13:19 am
Hi, some news on the topic....

I made a copy of my applet and changed the exteds JApplet for JFrame and it runs great.... and it also ran well when chenged to sw rendering. I have not changed the Rendering Thread/EventManagmentThread just changed the JApplet for JFrame.

Should this be reported as a bug???? Only happens on Applets with GLCanvas.
Title: Re: Performance problems
Post by: EgonOlsen on March 29, 2009, 10:59:48 am
If it is a bug, it's a LWJGL bug, not a jPCT one. Or maybe it's a kind of browser problem. Applets are really pissy sometimes (not to say most of th time...). Which browser is that and have you tried another one?
Title: Re: Performance problems
Post by: paulscode on March 29, 2009, 01:50:58 pm
Is it possible to produce a simplified test case that I could run to see if the problem occurs on other systems besides the one you mentioned?
Title: Re: Performance problems
Post by: fireside on March 29, 2009, 03:04:36 pm
Could this be a memory issue?  I remember Egon saying that there is something like a 64 meg memory limit on an applet.  That wouldn't occur if it was switched to jframe.  I've found it helps to use the keyword static as much as I possibly can, but I haven't done any tests or anything.  The program just seems to run more smoothly.
Title: Re: Performance problems
Post by: EgonOlsen on March 29, 2009, 08:33:07 pm
If it's a memory issue, it could only be the garbage collector taking that long but that's very very unlikely.
Title: Re: Performance problems
Post by: Melssj5 on March 30, 2009, 04:11:59 pm
Hi, I tested it on my laptop using firefox and IE and jre1.6.0_12. I runned it from another 2 machines and the GLCanvas doesnt appeared. Thats strange..... I put an IPaintListener on the FrameBuffer and put some outputs, on the machines that the glcanvas is visible the outputis being printed but ont eh other machines where the GLCanvas is not visible the output is not being printed. Something have to be buggy with it. Now I am using the software renderer which is more stable but is not as fast as I wish it were.
Title: Re: Performance problems
Post by: EgonOlsen on March 30, 2009, 04:22:26 pm
Newer LWJGL versions support to render the native output into a canvas without using AWTGLCanvas. Maybe that's an option. Have a look here: http://www.lwjgl.org/javadoc/org/lwjgl/opengl/Display.html#setParent(java.awt.Canvas) (http://www.lwjgl.org/javadoc/org/lwjgl/opengl/Display.html#setParent(java.awt.Canvas))
Title: Re: Performance problems
Post by: FireBorn on April 01, 2009, 03:20:53 am
This sounds like an issue I was having that I posted about in another thread. Unfortunately, the project has been on hold for a while so I haven't been able to find a solution yet. I'll let you know if I find one, though. :)