3DzzD - Applet Boot - source code

LASTEST VERSION HERE : http://www.java-gaming.org/index.php/topic,22239.0.html

[s]EDIT :

look here for the lastest version :

It will be part of the next 3DzzD release but as this one is not yet ready and also beccause it can be used separatly, here it is.

http://demo.dzzd.net/Test/CAR.html

How to use it :

Put Boot.class, Boot$AppletLoader.class and an Image BLANK.GIF (wich will be the Java splash for recent JVM) on your remote server and replace BOOTCLASS parameter with your own applet class name.

I recommend to not pack it in a jar

The animation will play until the init method of the Applet return, so you may do all your initialisation and loading stuff inside the constructor or the init() method.

Dowload Java 1.1 binary

HTML code :

Java sources :

/*
* This file is part of 3DzzD http://dzzd.net/.
*
* Released under LGPL
*
* 3DzzD is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 3DzzD 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with 3DzzD.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2005 - 2009 Bruno Augier
*/




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

/**
 * Boot
 *
 * An Applet Boot class
 * 
 * @author Bruno Augier
 * @website: http://dzzd.net/
 * @version 1.00 2008/04/15
 */
public final class Boot extends Applet implements Runnable,AppletStub
{		
	private int nbStart=0;
	private Graphics g;		
	private int bgColor;
	Container c;
	
	public boolean loaded;
	public Thread t;
	public Applet a;
		
	private int w()
	{
		return this.getSize().width;
	}
	
	private int h()
	{
		return this.getSize().height;
	}	 	
	
	private int nb=0;
	private long lTime;
	
	public void run()
	{
					
		try
		{
			this.lTime=System.currentTimeMillis();
			while(!this.loaded)
			{
				int cx=this.w()>>1;
				int cy=this.h()>>1;
				for(int n=0;n<180;n++)
				{
					int r=255;
					int v=165+(n>>1);
					int b=75+n;
					this.g.setColor(new Color(b|(v<<8)|(r<<16)));
					double a=(nb-n*1.1)*Math.PI/180.0;
					double ca=Math.cos(a);
					double sa=Math.sin(a);
					int x=cx+(int)(8.0*ca);
					int y=cy+(int)(8.0*sa);
					
					int x2=cx+(int)(12.0*ca);
					int y2=cy+(int)(12.0*sa);
					this.g.drawLine(x,y,x2,y2);
				}
				nb+=6;
				long time=System.currentTimeMillis();
				long delta=time-lTime;
				lTime=time;
				if(delta<20)
					Thread.sleep(20-delta);
				Thread.sleep(1);	
			}
		}
		catch(InterruptedException ie)
		{
		}
		
	}
	
	public void paint(Graphics g)
	{
		
		if(this.nbStart++==0)
		{	
			String sBgColor=this.getParameter("BOOTBGCOLOR");
			if(sBgColor!=null)
			{
				try
				{
					this.bgColor=Integer.parseInt(sBgColor,16);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				
			}	
			this.c=this.getParent();
			this.g=this.c.getGraphics();
			this.c.remove(this);	
							
			this.loaded=false;
			this.t=new Thread(this);
			this.t.start();
			
			
			String bootClass=this.getParameter("BOOTCLASS");
			new AppletLoader(bootClass);
		}
		Color color=new Color(this.bgColor);
		this.c.setBackground(color);	
		this.g.setColor(color);
		this.g.fillRect(0,0,w(),h());
		
		super.paint(g);
		
	}
	
	private class AppletLoader implements Runnable
	{
		String name;
		
		AppletLoader(String name)
		{		
			this.name=name;
			Thread t=new Thread(this);
			t.start();	
		}
		
		public void run()
		{
			
			try
			{
				Thread.sleep(2000);
				a=(Applet)Class.forName(this.name).newInstance();
				
				{	
					a.setStub(Boot.this);
					a.setSize(w(),h());
					a.init();
					c.add(a);
					a.start();
				}	
								
				loaded=true;
				t.join();
							
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
				
		}
		
	}
	
	public void start()
	{
		if(this.a!=null)
			this.a.start();
	}
	
	public void stop()
	{
		if(this.a!=null)
			this.a.stop();
	}
	
	public void destroy()
	{
		if(this.a!=null)
			this.a.destroy();
		this.a=null;
	}
	/*
	public void update(Graphics g)
	{
		
	}*/
		
	public void appletResize(int width, int height) 
	{
		if(this.a!=null)
			this.a.setSize(width,height);
	}
}

[/s]

http://demo.dzzd.net/test/IPHONE.html
error 404 http couldnt be found

oups sorry wrong URL :slight_smile:

seemed to run smooth enough.

I did notice few artifacts, when spinning the car around (attached image) .

would strictfp help this? or is it calculated with double precision?

anyway if someone really didnt want artifacts im sure they could just render an extremely low poly version first, then render the high quality one.

thanks for testing,

it use double precision but that’s a bug, I am currently modifyng the soft renderer for the next release and it make more artefact than before as I dont finished modifications yet

In FF java6 with a clear cache I get;

approx 5 seconds white box
approx 2 seconds white box with black border
approx 15 seconds loading animation
car appears & applet runs smoothly (looks very nice!)

After the app is cached the white box no longer appears.

thks for the detailled answer

[quote]approx 5 seconds white box
[/quote]
that’s the BLANK.GIF image wich can be replaced by any 2*2 color image (I let white for debug purpose)

NB: this thread is a pool, dont hesitate to vote plzzz :slight_smile:

it is loading forever, It hasnt started :confused:

could you, plz, provide the console content ?

works fine now ???

so update your vote :slight_smile:

On a phone modem, you just see a blank window for quite a while before the little rotating circle thing comes up. It could be confusing if there happens to be one other person in the world besides me that doesn’t have a high speed connection.

Worked smoothly in Vista, Java 6u13. :slight_smile: I’ll try it in Linux later.


can’t I dont think you allowed it?

Worked nicely in Ubuntu 9.04 as well. Good work!

[quote]can’t I dont think you allowed it?
[/quote]
oups, I dont know how to do this…

[quote]Worked smoothly in Vista, Java 6u13. I’ll try it in Linux later.
Worked nicely in Ubuntu 9.04 as well. Good work!
[/quote]
double cool ! 8)

Online Test :

http://demo.dzzd.net/View3D/IPHONE.html

Dowload Java 1.1 binary

special thanks to jojoh for pointing out some bugs

HTML code :

<APPLET      code   = "Boot.class"
       width   = "600"
       height   = "400"
       MAYSCRIPT>
<PARAM NAME="IMAGE" VALUE="BLANK.GIF">
<PARAM NAME="BOOTBGCOLOR" VALUE="eeeeee">
<PARAM NAME="BOOTCLASS" VALUE="Viewer3D">      
<PARAM NAME="BOOTTOSTART" VALUE="FALSE">

<!-- START OF CUSTOM JAVA ERROR MESSAGE -->

<TABLE STYLE="WIDTH: 500px;
               HEIGHT: 450px;
               BACKGROUND-COLOR: #000000">
  <TBODY>
   <TR>
    <TD STYLE="TEXT-ALIGN: center">
     <A href="http://java.com/">
      <IMG STYLE="BORDER: 0px;"
           src="JAVA.JPG">
     </A>
    </TD>
   </TR>
 </TABLE>

<!-- END OF CUSTOM JAVA ERROR MESSAGE -->

</APPLET>

Java code :

/*
* This file is part of 3DzzD http://dzzd.net/.
*
* Released under LGPL
*
* 3DzzD is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 3DzzD 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with 3DzzD.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2005 - 2009 Bruno Augier
*/


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

/**
 * Boot
 *
 * An Applet Boot class
 * 
 * @author Bruno Augier
 * @website: http://dzzd.net/
 * @version 1.00 2008/04/15
 */
public final class Boot extends Applet implements Runnable,AppletStub
{		
	private volatile int nbStart=0;
	private volatile Graphics g;		
	private volatile int bgColor;
	private volatile Container c;
	private volatile boolean loaded;
	private volatile Thread t;
	private volatile Applet a;
	private volatile boolean bootToStart=false;
	
		
	private int w()
	{
		return this.getSize().width;
	}
	
	private int h()
	{
		return this.getSize().height;
	}	 	
	
	private int nb=0;
	private long lTime;
	public void run()
	{
					
		try
		{
			this.lTime=System.currentTimeMillis();
			while(!this.loaded)
			{
				int cx=this.w()>>1;
				int cy=this.h()>>1;
				for(int n=0;n<180;n++)
				{
					int r=255;
					int v=165+(n>>1);
					int b=75+n;
					this.g.setColor(new Color(b|(v<<8)|(r<<16)));
					double a=(nb-n*1.1)*Math.PI/180.0;
					double ca=Math.cos(a);
					double sa=Math.sin(a);
					int x=cx+(int)(8.0*ca);
					int y=cy+(int)(8.0*sa);
					
					int x2=cx+(int)(12.0*ca);
					int y2=cy+(int)(12.0*sa);
					this.g.drawLine(x,y,x2,y2);
				}
				nb+=6;
				long time=System.currentTimeMillis();
				long delta=time-lTime;
				lTime=time;
				if(delta<20)
					Thread.sleep(20-delta);
				Thread.sleep(1);	
			}
		}
		catch(InterruptedException ie)
		{
			ie.printStackTrace();
		}
		
	}
	
	public void paint(Graphics g)
	{
		
		if(this.nbStart++==0)
		{	
			String sBgColor=this.getParameter("BOOTBGCOLOR");
			if(sBgColor!=null)
			{
				try
				{
					this.bgColor=Integer.parseInt(sBgColor,16);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				
			}	
			this.c=this.getParent();
			this.g=this.c.getGraphics();
			this.c.remove(this);	
							
			this.loaded=false;
			this.t=new Thread(this);
			this.t.start();
			
			String bootToStart=this.getParameter("BOOTTOSTART");
			if(bootToStart!=null && bootToStart.equals("TRUE"))
				this.bootToStart=true;
			String bootClass=this.getParameter("BOOTCLASS");	
			
			new AppletLoader(bootClass);
		}
		Color color=new Color(this.bgColor);
		this.c.setBackground(color);	
		this.g.setColor(color);
		this.g.fillRect(0,0,w(),h());
		
		super.paint(g);
		
	}
	
	private class AppletLoader implements Runnable
	{
		String name;
		
		AppletLoader(String name)
		{		
			this.name=name;
			Thread t=new Thread(this);
			t.start();	
		}
		
		public void run()
		{
			
			try
			{
				Thread.sleep(1000);
				Boot.this.a=(Applet)Class.forName(this.name).newInstance();
				Boot.this.a.setVisible(false);
				
				{	
					Boot.this.a.setStub(Boot.this);
					Boot.this.c.add(Boot.this.a);
					Boot.this.a.resize(new Dimension(Boot.this.w(),Boot.this.h()));
					
					Boot.this.a.init();	
					if(!Boot.this.bootToStart)
						Boot.this.a.setVisible(true);				
					Boot.this.a.start();
					if(Boot.this.bootToStart)
						Boot.this.a.setVisible(true);
				}	
								
				Boot.this.loaded=true;
				Boot.this.t.join();
							
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
				
		}
		
	}
	
	public void start()
	{
		if(this.a!=null)
			this.a.start();
	}
	
	public void stop()
	{
		if(this.a!=null)
			this.a.stop();
	}
	
	public void destroy()
	{
		if(this.a!=null)
			this.a.destroy();
		this.a=null;
	}
	/*
	public void update(Graphics g)
	{
		
	}*/
		
	public void appletResize(int width, int height) 
	{
		if(this.a!=null)
			this.a.setSize(width,height);
	}
}

Hi again!

I was planning to use this great tool more on games4j.com, but was worried about some stability issues, that I couldn’t really test, since it only appeared on OS X (as far as I know). I wasn’t sure if it was this tool or ogg loader combined with multithreading. Seems like it might have been a bit of both. I finally managed to fool someone to let me test crashing his OS X browser a bit, and it seems like running a java 6 applet using this Applet Boot on OS X with java 1.5 on it will freeze the browser (safari and ff tested), and you will have to kill the browser. Only a gray or white space is displayed for the applet as well, and not the error message.

Not sure if there is anything to do about it, but probably good to know about, and would be good to know if someone can confirm that this is the case, and if there is a workaround.

I think that you can easily see what is going wrong by modifying the following part of code :


					Boot.this.a.setStub(Boot.this);
					Boot.this.c.add(Boot.this.a);
					Boot.this.a.resize(new Dimension(Boot.this.w(),Boot.this.h()));
					
					Boot.this.a.init();	
					if(!Boot.this.bootToStart)
						Boot.this.a.setVisible(true);				
					Boot.this.a.start();
					if(Boot.this.bootToStart)
						Boot.this.a.setVisible(true);

a first thing to do would be to put the whole inside a try catch throwable

		
try
{
Boot.this.c.add(Boot.this.a);
					Boot.this.a.resize(new Dimension(Boot.this.w(),Boot.this.h()));
					
					Boot.this.a.init();	
					if(!Boot.this.bootToStart)
						Boot.this.a.setVisible(true);				
					Boot.this.a.start();
					if(Boot.this.bootToStart)
						Boot.this.a.setVisible(true);
}
catch (Throwable t)
{
=> draw a message on screen to the user to tell him that the applet have a problem
}

this can help in some case like for example if the user have an older JVM than the one requiered for the Applet because the booter will just start fine on any JVM (because it is 1.1 compatible) and an exception will be throw, this will avoid an hugly grey or white panel without any information to appear.

another thing you can add in this code bock is logging informations at each step, this way it will be easy to found what is going wrong, optionaly you can also add a timeout that make a message appear after a given amount of time saying that the applet could not start.


try
{
Boot.this.c.add(Boot.this.a);
					Boot.this.a.resize(new Dimension(Boot.this.w(),Boot.this.h()));
					
//Log before init

					Boot.this.a.init();	
					if(!Boot.this.bootToStart)
						Boot.this.a.setVisible(true);	

//Log before start
			
					Boot.this.a.start();
					if(Boot.this.bootToStart)
						Boot.this.a.setVisible(true);
//Log after start

}
catch (Throwable t)
{
=> draw a message on screen to the user to tell him that the applet have a problem
}

last but not least I woul recommend to add a nice flash GUI explaining how to install java inside the Applet tag, this way if a user come without any JVM the flash will be displayed and will provide a user friendly way to alert user to install java

something like

<APPLET .....

<PARAM ....
<PARAM ....


<FLASH TAG src=noJavaGUI.swf .....>

</FLASH TAG>

</APPLET>

Thanks for the suggestions.

I just had a brief look and though that it should all have been taken care of by the try{}catch in the original code, but that is catching Exception and not Throwable, so that was the problem. You were almost right about the changes needed, but the problem is already at the line:


	Boot.this.a = (Applet) Class.forName(this.name).newInstance();

I also made a small change so that it will display a message to the user if it has java 1.1 or better, but not what requested by the applet. That is, if for example a user has java 1.4, and tries to view a 1.5 Applet, a message will be displayed (by applet boot), telling him to install latest version of java, in order to view the applet and then opens java.com in another tab in the browser.

I have not been able to thoroughly test, this, so any reports on how it works would be great (especially for OS X and linux). It is currently in use at:
Dirami Conquest (currently java 1.5)
It seems like there is a pause when it reads libs or the certificates for playing ogg, but that is probably out of hands of the Applet Boot.
Any feedback on the game here

This is the change I did to the code:


/*
 * This file is part of 3DzzD http://dzzd.net/.
 *
 * Released under LGPL
 *
 * 3DzzD is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 3DzzD 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with 3DzzD.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2005 - 2009 Bruno Augier
 */

import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.net.URL;

/**
 * Boot
 * 
 * An Applet Boot class
 * 
 * This file has been changed by Joakim Johnson. Added the not sufficient java stuff and a try{}catch(Throwable)
 * @author Bruno Augier
 * @website: http://dzzd.net/
 * @version 1.00 2008/04/15
 */
public final class Boot extends Applet implements Runnable, AppletStub {
	private volatile int nbStart = 0;
	private volatile Graphics g;
	private volatile int bgColor;
	private volatile Container c;
	private volatile boolean loaded;
	private volatile boolean notSufficientJava = false;
	private volatile Thread t;
	private volatile Applet a;
	private volatile boolean bootToStart = false;

	private int w() {
		return this.getSize().width;
	}

	private int h() {
		return this.getSize().height;
	}

	private int nb = 0;
	private long lTime;

	public void run() {

		try {
			this.lTime = System.currentTimeMillis();
			while (!this.loaded) {
				if(notSufficientJava) {
					this.g.setColor(new Color(255,165,75));
					g.drawString("Please make sure that you have the", w()/2-100, h()/2-30);
					g.drawString("latest version of java installed and activated", w()/2-120, h()/2-10);
				}else {
					int cx = this.w() >> 1;
					int cy = this.h() >> 1;
					for (int n = 0; n < 180; n++) {
						int r = 255;
						int v = 165 + (n >> 1);
						int b = 75 + n;
						this.g.setColor(new Color(b | (v << 8) | (r << 16)));
						double a = (nb - n * 1.1) * Math.PI / 180.0;
						double ca = Math.cos(a);
						double sa = Math.sin(a);
						int x = cx + (int) (8.0 * ca);
						int y = cy + (int) (8.0 * sa);
	
						int x2 = cx + (int) (12.0 * ca);
						int y2 = cy + (int) (12.0 * sa);
						this.g.drawLine(x, y, x2, y2);
					}
					nb += 6;
				}
				long time = System.currentTimeMillis();
				long delta = time - lTime;
				lTime = time;
				if (delta < 20)
					Thread.sleep(20 - delta);
				Thread.sleep(1);
			}
		} catch (InterruptedException ie) {
			ie.printStackTrace();
		}

	}

	public void paint(Graphics g) {

		if (this.nbStart++ == 0) {
			String sBgColor = this.getParameter("BOOTBGCOLOR");
			if (sBgColor != null) {
				try {
					this.bgColor = Integer.parseInt(sBgColor, 16);
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
			this.c = this.getParent();
			this.g = this.c.getGraphics();
			this.c.remove(this);

			this.loaded = false;
			this.t = new Thread(this);
			this.t.start();

			String bootToStart = this.getParameter("BOOTTOSTART");
			if (bootToStart != null && bootToStart.equals("TRUE"))
				this.bootToStart = true;
			String bootClass = this.getParameter("BOOTCLASS");

			new AppletLoader(bootClass);
		}
		Color color = new Color(this.bgColor);
		this.c.setBackground(color);
		this.g.setColor(color);
		this.g.fillRect(0, 0, w(), h());

		super.paint(g);

	}

	private class AppletLoader implements Runnable {
		String name;

		AppletLoader(String name) {
			this.name = name;
			Thread t = new Thread(this);
			t.start();
		}

		public void run() {

			try {
				Thread.sleep(1000);
				try {
					Boot.this.a = (Applet) Class.forName(this.name).newInstance();
					Boot.this.a.setVisible(false);
					Boot.this.a.setStub(Boot.this);
					Boot.this.c.add(Boot.this.a);
					Boot.this.a.resize(new Dimension(Boot.this.w(), Boot.this.h()));

					Boot.this.a.init();
					if (!Boot.this.bootToStart)
						Boot.this.a.setVisible(true);
					Boot.this.a.start();
					if (Boot.this.bootToStart)
						Boot.this.a.setVisible(true);
					Boot.this.loaded = true;
					Boot.this.t.join();
				} catch (Throwable throwable) {
					notSufficientJava=true;
					throwable.printStackTrace();
					Thread.sleep(6000);
					AppletContext a = getAppletContext();
					URL url = new URL("http://java.sun.com/");
					a.showDocument(url, "_blank");
				}

			} catch (Exception e) {
				e.printStackTrace();
			}

		}

	}

	public void start() {
		if (this.a != null)
			this.a.start();
	}

	public void stop() {
		if (this.a != null)
			this.a.stop();
	}

	public void destroy() {
		if (this.a != null)
			this.a.destroy();
		this.a = null;
	}

	/*
	 * public void update(Graphics g) {
	 * 
	 * }
	 */

	public void appletResize(int width, int height) {
		if (this.a != null)
			this.a.setSize(width, height);
	}
}