Main Menu

FCP Code als applet

Started by mogli, March 16, 2006, 04:47:31 PM

Previous topic - Next topic

mogli

Hi!

Ich versuche momentan den FPS Code in ein applet umzuwandeln.

Leider allerdings ohne Erfolg. Kann mir vielleicht jemand dabei helfen? Bzw mir ein paar Tips geben?

gruss mogli

EgonOlsen

Was genau willst du machen? Wenn du die Funktionalität 1-zu-1 übernehmen willst, d.h. aus der Hauptschleife an sonstigem AWT- und Swingkram vorbei zeichnen willst, dann geht das z.B. so, wie in diesem Beispiel:

import java.applet.*;
import java.awt.*;

import com.threed.jpct.*;

public class ExampleApplet extends Applet implements Runnable {
 private Thread loopThread;
 
 private World world=null;
 private Object3D obj=null;

  private FrameBuffer buffer=null;
  private boolean exit=false;

  public ExampleApplet() {}

  public void init() {
     getAppletContext().showStatus("Initializing...");
     buffer=new FrameBuffer(480, 300, FrameBuffer.SAMPLINGMODE_NORMAL);
     buffer.enableRenderer(IRenderer.RENDERER_SOFTWARE, IRenderer.MODE_OPENGL);

     world=new World();
     world.setAmbientLight(200,200,200);

     obj=Primitives.getCube(3);
     world.addObject(obj);

     world.buildAllObjects();
     world.getCamera().setPosition(new SimpleVector(0,0,-30));

     getAppletContext().showStatus("Done !");
  }

  public void destroy() {
     TextureManager.getInstance().flush();
     Object3D.resetNextID();
     exit=true;
     super.destroy();
  }

  public void paint(Graphics g) {
  }

  public void update(Graphics g) {
  }

  public String getAppletInfo() {
    return ("Example Applet ");
  }

  public void run() {
    if (Thread.currentThread() == loopThread) {
      mainLoop();
    }
  }
 
  public void start() {
    if (loopThread==null) {
      loopThread = new Thread(this);
      loopThread.start();
    }
  }

  private void mainLoop() {
     Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
     while (!exit) {
       buffer.clear();
       obj.rotateX(0.01f);
       obj.rotateY(-0.01f);
       world.renderScene(buffer);
       world.draw(buffer);
       buffer.update();
       buffer.display(this.getGraphics());
       Thread.yield();
     }
     loopThread=null;
  }
}

mogli

danke, ja werd das mal als basis nehmen und dann mal weiter sehen.

vielen dank schonmal!

mogli

Mein Applet läuft bereits sehr gut. Vielen Dank noch mal für die Hilfe.

Ich habe nun eine Frage bezüglich eines Ladebalkens.
Ich würde während ich das 3ds-worldfile lade, gerne einen Ladebalken einblenden, der den aktuellen Lade-Status ausgibt.
Habe gelesen, dass man die init-Methode bzw das Laden des worldfiles in eine andere Methode auslagern könnte und diese dann in der funktion paint() aufruft.
Das habe ich auch versucht allerdings, allerdings ohne Erfolg, das Fenster bleibt grau. Das die initialisierungs-Methode in paint() nur einmal aufgerufen wird, habe ich mit einem bool-Wert abgefangen.

Wäre nett, wenn mir jemand ne Hilfe geben könnte.

EgonOlsen

Pack das Laden in einen eigenen Thread und lass den Hauptthread entweder direkt den Ladebalken zeichnen oder dies über die normalen AWT-Mechanismen in update/paint erledigen, so wie in diesem Beispiel:

import java.applet.*;
import java.awt.*;

import com.threed.jpct.*;

public class ExampleApplet extends Applet implements Runnable {
 private Thread loopThread;

 private World world=null;
 private Object3D obj=null;

  private FrameBuffer buffer=null;
  private boolean exit=false;
  private boolean loading=true;

  public ExampleApplet() {}

  public void init() {
     getAppletContext().showStatus("Initializing...");
     buffer=new FrameBuffer(480, 300, FrameBuffer.SAMPLINGMODE_NORMAL);
     buffer.enableRenderer(IRenderer.RENDERER_SOFTWARE, IRenderer.MODE_OPENGL);

     world=new World();
     world.setAmbientLight(200,200,200);

     obj=Primitives.getCube(3);
     world.addObject(obj);

     world.buildAllObjects();
     world.getCamera().setPosition(new SimpleVector(0,0,-30));

     getAppletContext().showStatus("Done !");
  }

  public void destroy() {
     TextureManager.getInstance().flush();
     Object3D.resetNextID();
     world.removeAll();
     exit=true;
     super.destroy();
  }

  public void paint(Graphics g) {
  }

  public void update(Graphics g) {
    if (loading) {
      paintLoadingStuff(g);
    }
  }

  public String getAppletInfo() {
    return ("Example Applet ");
  }

  public void run() {
    if (Thread.currentThread() == loopThread) {
      mainLoop();
    }
  }

  public void start() {
    if (loopThread==null) {
      loopThread = new Thread(this);
      loopThread.start();
    }
  }

  private void paintLoadingStuff(Graphics g) {
    // Do some loading bar or whatever here
    g.clearRect(0, 0, getWidth(), getHeight());
    g.drawString( (int) (Math.random() * 100) + "% finished", 10, 30);
  }
 
  private void loadStuff() {
    try {
      // Simulate loading by waiting 5 secs...
      Thread.sleep(5000);
    } catch(Exception e) {
      e.printStackTrace();
    }
    loading=false;
  }
 
  private void mainLoop() {
     Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
     
     new Thread() {
       public void run() {
         loadStuff();
       }
     }.start();
     
     try {
       while (loading) {
          repaint();
          Thread.sleep(50);
       }
     } catch(Exception e) {e.printStackTrace();}
     
     while (!exit) {
       buffer.clear();
       obj.rotateX(0.01f);
       obj.rotateY(-0.01f);
       world.renderScene(buffer);
       world.draw(buffer);
       buffer.update();
       buffer.display(this.getGraphics());
       Thread.yield();
     }
     loopThread=null;
  }
}

mogli

hmm, nun stehe ich vor einem weiteren Problem.

Ich hatte zuvor zwei Threads, die ich wiefolgt augerufen habe:


public void run(){
  if ( Thread.currentThread() == streamThread ) {
     stream();
  }
  else{
     mainLoop();
  }
}


Zur Info:
Die Methode stream() streamt schon mal die Nebenobjekte.

Wenn ich dies weiterhin so aufrufe, wird die Methode stream() schon während der Initialisierungsmethode aufgerufen. Dies war vorher nicht der Fall da die Initialisierung ja in der init-funktion stattfand.

ich möchte aber das der thread aber erst nach der initialisierung aufgerufen startet.
Im letzten Beispiel also erst nachdem loadStuff() durchgelaufen ist.
stream() soll aber parallel zu mainLoop() verlaufen bzw. parallel zur Ausgabe der Welt/Rumlaufen in der Welt.

EgonOlsen

Dann starte ihn halt von loadStuff() aus an, d.h. wenn dieser fast durchgelaufen ist. Oder habe ich dich jetzt nicht richtig verstanden?

mogli

das habe ich probiert!

Allerdings streamt er dann die Objeke auch erst bevor er die Welt zeichnet/sichtbar für den User ist.

Die stream()-Methode soll aber parallel zur while()-Schleife der mainLoop() verlaufen.

EgonOlsen

Dann hast du das irgendwie an die falsche Stelle gepackt. Ich meinte das etwa so:

private void loadStuff() {
    try {
      // Simulate loading by waiting 5 secs...
      Thread.sleep(5000);
    } catch(Exception e) {
      e.printStackTrace();
    }
    loading=false;

    new Thread() {
       public void run() {
         stream();
       }
     }.start();
  }


P.S.: Wenn du jPCT-Objekte in einem Thread lädst, musst du aufpassen, das du nichts damit anstellst, während der "Zeichenthread" rechnet, zeichnet...also Dinge innerhalb von jPCT erledigt. Ansonsten wirst du lustige Effekte bekommen... :wink:

mogli

hehe, genau diese lustigen effekte hab ich nämlich hinbekommen, aber dann werde ich es da nochmal weiterschauen.

EgonOlsen

Du könntest die "gestreamten" Objekte/Daten in eine Queue einfügen, die dann im Renderthread nach dem Zeichnen abgearbeitet wird, sofern sich etwas darin angesammelt hat. Ansonsten kommen die tollsten Sachen dabei raus...aber das hast du ja schon selber bemerkt... :wink:

mogli

Fein, das funktioniert also auch gut.

Ich hab mal ne Frage zu Threads im Allgemeinen: Muss ich einen Thread eigentlich irgendwie vernichten nachdem er durchgelaufen ist? Ich frag da jetzt aus Performancegründen. Die Methode stop() sollte ja wohl nicht mehr genutzt werden soweit ich das verstanden habe. Oder beendet sich der Thread automatisch nach Ablauf? Also hier im Beispiel wenn stream() fertig ist, beendet sich auch der Thread dazu?

EgonOlsen

Wenn der Thread seinen letzten Befehl ausgeführt hat, ist er weg. Darum musst du dich nicht kümmern.

mogli

welche Teile dürfen denn erst nach dem Rendern ausgeführt werden? Bzw. welche können schon parallel dazu ausgeführt werden?

Also ich streame die Objekte und "bastel" sie dann zusammen. Am Ende "adde" ich sie dann der entsprechenden Welt. Eigentlich muss doch nur der Part mit dem world.addObject(Object) und world.buildAllObjects() nach dem Rendern kommen oder?

EgonOlsen

Quote from: "mogli"Eigentlich muss doch nur der Part mit dem world.addObject(Object) und world.buildAllObjects() nach dem Rendern kommen oder?
Wenn es nur um das Streamen an sich geht, dann ja. Bevor die Welt die Objekte nicht kennt, sind sie ziemlich egal...sofern sie nicht zufällig der Parent eines Objektes sind, welches bereits zur Welt gehört.