added some changes to AppletLoader

Started by bobjob, June 26, 2010, 21:01:44

Previous topic - Next topic

bobjob

maybe some more effecient code for handling resize would be :

the first version of the resize code creates a new Image 1 per second.

this code should probably work better:
private boolean resize = true;
	public void setSize(Dimension size) { resize = true; super.setSize(size);}
	public void setSize(int width, int height) { resize = true; super.resize(width, height);}
	public void resize(Dimension size) { resize = true; super.resize(size);}
	public void resize(int width, int height) { resize = true; super.resize(width, height);}
	public void reshape(int x, int y, int width, int height) { resize = true; super.reshape(x, y, width, height); }
	
	
	/*
	 * @see java.awt.Container#paint(java.awt.Graphics)
	 */

	public void paint(Graphics g) {
		
		// don't paint loader if applet loaded
		if(state == STATE_DONE) {
			return;
		}
		
		
		
		// create offscreen if missing
		if (offscreen == null) {
			if (errorImage != null) {
				offscreen = createImage(errorImage.getWidth(null)+20, errorImage.getHeight(null)+32);
			} else if (buttonError != null) {
				offscreen = createImage(600, 400);
			} else {
				if (logo == null) {
					return;
				}
				offscreen = createImage(logo.getWidth(this)*2, logo.getHeight(this)*2);
			}
		} 
		int width = offscreen.getWidth(this);
		int height = offscreen.getHeight(this);
		
		// draw everything onto an image before drawing to avoid flicker
		Graphics og = offscreen.getGraphics();
		//og.setClip(0,0,getWidth(), getHeight());
		
		FontMetrics fm = og.getFontMetrics();

		// set background color
		og.setColor(bgColor);
		og.fillRect(0, 0, width, height);

		if (buttonError != null) {
			

			if (errorImage != null) {
        		og.drawImage(errorImage, 10, 32, null);
        		
        	}
    		
    		og.setColor(Color.BLACK);
    		Graphics2D g2D = (Graphics2D) og;
    		
    		g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f));
			
 
    		g2D.fillRect(0, 0, width, 90);
			g2D.setComposite(AlphaComposite.SrcOver);
    		for (int i = 0; i < 2; i++) {
    			if (i == 1) og.setColor(Color.white);
    			else  og.setColor(Color.black);
    			og.drawString("Error accessing \"OpenGL 3D Hardware\".", 4-i, 20-i);
    			og.drawString("Resolve problem by:", 4-i, 40-i);
    			og.drawString("1. Restart Internet Browser.", 4-i, 60-i);
    			og.drawString("2. Click " + buttonError + " when prompted to access \"OpenGL 3D Hardware\".", 4-i, 80-i);
    		}
   		
    		og.dispose();
    		if (resize) {
    			g.setColor(bgColor);
    			g.fillRect(0, 0, getWidth(), getHeight());
    		}
    		
    		int x = (getWidth()/2) - (offscreen.getWidth(null) / 2);
    		if (x < 0) x = 0;
			g.drawImage(offscreen, x, 0, null);
			return;
		}
		
		// get logo position so its in the middle of applet
		int x = 0, y = 0;
		
		if(logo != null && !fatalError) {
			x = (width - logo.getWidth(this)) / 2;
			y = (height - logo.getHeight(this)) / 2;
		}

		og.setColor(fgColor);
		String message = getDescriptionForState();

		// if we had a failure of some sort, notify the user
		if (fatalError) {
			String[] errorMessage = (certificateRefused) ? certificateRefusedMessage : genericErrorMessage;
			
			if (!certificateRefused) {
				errorMessage[errorMessage.length-1] = fatalErrorDescription;
			}			
			
			for(int i=0; i<errorMessage.length; i++) {
				if(errorMessage[i] != null) {
					int messageX = (width - fm.stringWidth(errorMessage[i])) / 2;
					int messageY = (height - (fm.getHeight() * errorMessage.length)) / 2;
					
					og.setColor(errorColor);
					og.drawString(errorMessage[i], messageX, messageY + i*fm.getHeight());
				}
			}
		} else {
			og.setColor(fgColor);

			// draw logo
			og.drawImage(logo, x, y, null);
			
			// draw message
			int messageX = (width - fm.stringWidth(message)) / 2;
			int messageY = y + logo.getHeight(null) + 20;
			og.drawString(message, messageX, messageY);
			
			// draw subtaskmessage, if any
			if(subtaskMessage.length() > 0) {
				messageX = (width - fm.stringWidth(subtaskMessage)) / 2;
				og.drawString(subtaskMessage, messageX, messageY+20);
			}

			// draw loading bar, clipping it depending on percentage done
			int barSize = (progressbar.getWidth(this) * percentage) / 100;
			og.clipRect(x, y, barSize, progressbar.getHeight(this));
			og.drawImage(progressbar, x, y, null);
		}
		
		og.dispose();

		// finally draw it all
		
		g.setClip(0,0,getWidth(), getHeight());
		if (resize) {
			g.setColor(bgColor);
			g.fillRect(0, 0, getWidth(), getHeight());
		}
		x = (getWidth()/2) - (offscreen.getWidth(null) / 2);
		y = (getHeight()/2) - (offscreen.getHeight(null) / 2);
		if (x < logo.getWidth(null)/-2) x = logo.getWidth(null)/-2;
		if (y < logo.getHeight(null)/-2) y = logo.getHeight(null)/-2;
		g.drawImage(offscreen, x, y, null);
	}


edit: attached the full source file

kappa

Quote from: bobjob on July 06, 2010, 02:40:49
A few more things, I understand if you guys are busy, or dont want to implement these changes as they are probably more for people who want to tweek the AppletLoader experience.
:-\ Sorry for constantly bugging you guys on the topic of the AppletLoader, its just that I want to port my game over, and would like to make sure its as smooth as possible, so im finding a few concerns as I go.

hey, thats no problem at all, we are always trying to improve the library. Especially as theres been lots of effort and testing put into LWJGL applets to try and get them to just work nicely. We are now starting to see them come into their own, with major success stories like Minecraft, big companies like Sega using them and some pretty cool games in the pipeline. So your feedback and time is much appreciated.

Quote from: bobjob on July 06, 2010, 02:40:49
4. More of a question. Why is the applet loader "Applet" and not "JApplet". One reason JApplet is better, on Windows Java 1.6 there is less flicker on resizing and drawing. What are the reasons for Applet?

The idea with the AppletLoader was to be as small and start as fast as possible (initial release of lwjgl_util_applet.jar was only 10kb large, although has grown since :) ). When its done its stuff it then just passes over control to the LWJGL applet while leaving as small a footprint as possible (if any). The thing with JApplet is it bring Swings along with it, not sure how much time this adds to startup or how much more memory it takes but could be worth testing. However as for flicker, enabling double buffering will probably get rid of it and its probably why JApplet doesn't suffer from it. Some of the java4k games had some pretty small pieces of code to enable double buffering so might be worth adding. Personally not seen much flicker, are you seeing flicker when resizing the applet?

Quote from: bobjob on July 06, 2010, 02:40:49
2. I understand the red error writing for most cases, but in regards to the security certificate being declined i was thinking maybe use a nicer error popup.
tends to give the user a "I Killed the virus before it killed my computer" feeling.

3. Adding a "al_redirect" url
if the security popup is declined, offer a "redirect url" option. If the seperate_jvm tag is used on the platforms that support it, applets can just be reloaded without a browser restart, simple solution is to redirect to getDocumentBase().
fine for most cases, except IE Java 1.6(another IE applet lingering bug requires a querystring cache fix)
any comments on how the look can be improved? maybe use the fgcolor font instead? I did see your applet and it has a very nice certificate decline screen, however not sure its a good idea to add another image to the default LWJGL AppletLoader, could maybe be an optional parameter? what do you think?

Also one new pit fall to watch out for is when using mixed jars (signed/unsigned) with java 1.6.0.18+ the AppletLoader is no longer able to show its own error screen since java will throw an exception before jars are even initialised. Can be seen with http://www.lwjgl.org/applet
Kind of sucks since the idea was to get everyone to use the LWJGL certificate so it becomes common enough that users don't suffer the dialog anymore. thx Oracle.

Quote from: bobjob on July 06, 2010, 02:40:49
5. There is a problem on Internet Explorer with lingering applets. you can prevent this by calling super.destroy(): at the end of destroy method (also i include super.destroy at the start of init());
not sure how this will effect other platforms, if users decline the security dialog, helps to make sure that they will get a popup next time they load the browser (at least using IE).

can't this be done inside the users LWJGL Applet code?

Will have a look at the resize stuff tonight.

bobjob

Quote from: javalwjgl on July 06, 2010, 17:41:16
The idea with the AppletLoader was to be as small and start as fast as possible (initial release of lwjgl_util_applet.jar was only 10kb large, although has grown since :) ). When its done its stuff it then just passes over control to the LWJGL applet while leaving as small a footprint as possible (if any). The thing with JApplet is it bring Swings along with it, not sure how much time this adds to startup or how much more memory it takes but could be worth testing. However as for flicker, enabling double buffering will probably get rid of it and its probably why JApplet doesn't suffer from it. Some of the java4k games had some pretty small pieces of code to enable double buffering so might be worth adding. Personally not seen much flicker, are you seeing flicker when resizing the applet?
Yeah I get that now, a few of those things could probably handled in a round about way via the loaded applet.

Quotecould maybe be an optional parameter? what do you think?
thats what I was thinking, as the intial download would be to big (and you'd be hoping they wouldnt cancel the popup), also the error image will depend on the OS, and best work out at runtime (loaded outside of jar file).
Java default and the Mac version (on my mac)


Quote
Also one new pit fall to watch out for is when using mixed jars (signed/unsigned) with java 1.6.0.18+ the AppletLoader is no longer able to show its own error screen since java will throw an exception before jars are even initialised. Can be seen with http://www.lwjgl.org/applet
Kind of sucks since the idea was to get everyone to use the LWJGL certificate so it becomes common enough that users don't suffer the dialog anymore. thx Oracle.
Yeah that sux, but cant you just split the appletLoader into 2 jar files, One file to hold the Unsigned Applet, and the other to hold the signed methods that are needed.
But Im guessing that will still will give that ugly yellow mixed code dialog for the unsigned jar.

Quote
Quote from: bobjob on July 06, 2010, 02:40:49
5. There is a problem on Internet Explorer with lingering applets. you can prevent this by calling super.destroy(): at the end of destroy method (also i include super.destroy at the start of init());
not sure how this will effect other platforms, if users decline the security dialog, helps to make sure that they will get a popup next time they load the browser (at least using IE).
can't this be done inside the users LWJGL Applet code?
I didnt actually test that  :-[ (I just assumed it wouldnt) Ill make sure to try.

Quote
Will have a look at the resize stuff tonight.
cool.

also something worth noting was when you click on the declined error image it will attempt to reload the applet (but requires a bit of extra code for the cache fix on Interenet Explorer)
This is useful when the JVM supports seperate_jvm

bobjob

nvm the mixed code idea.
I tried it, the applet ran until it got to the code that required permissions, even though it had them it still wouldnt run.

kappa

hmm, had a look at the resize stuff, there seems to be some sort of getParent() and while loop stuff in start() what does that do?

Also instead of creating a new image on each resize, maybe it would be nicer (faster?) to just move the image (x,y) after a resize to centre the logo?

bobjob

Quote from: javalwjgl on July 06, 2010, 20:16:38
hmm, had a look at the resize stuff, there seems to be some sort of getParent() and while loop stuff in start() what does that do?
the getPerant() code was to allow an applet run as a webstart to be resizable; instead of a fixed frame.

Quote
Also instead of creating a new image on each resize, wouldn't it be easier to just move the image to centre it instead?
you must have downloaded the older version. I probably should have removed that one.
The decent version in the post:
Quote from: bobjob on July 06, 2010, 08:30:02
the first version of the resize code creates a new Image 1 per second.
this code should probably work better:
I dont mind how its implemented, just figured Id offer code, as I thought it was a good idea.

kappa

Quote from: bobjob on July 06, 2010, 19:31:34
nvm the mixed code idea.
I tried it, the applet ran until it got to the code that required permissions, even though it had them it still wouldnt run.

oh, looks like there is a solution to this problem, if lwjgl_util_applet.jar and lzma.jar is signed and theres no Trusted-Library stuff in the META-INF then it works fine (that is the certifcate refused screen is shown), even with unsigned jars (those that don't go outside the sandbox) in the al_jars parameter.

so guess a solution would be to sign lzma.jar with lwjgl's certificate in future.

bobjob

you beet me to a solution

I was about to post
package signed;

import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
public class SignedClass {
	public SignedClass() throws Exception {
		String path = (String) AccessController.doPrivileged(new PrivilegedExceptionAction() {
			public Object run() throws Exception {
				return System.getProperty("user.dir");
			}
		});
		System.out.println(path);
	}
}


package unsigned;

import java.applet.Applet;

public class UnsignedApplet extends Applet {
	public void init() {
		System.out.println("ASD1");
		super.destroy();
		try {
			new SignedClass();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("ASD2");
	}
}


as long as the signed jar has the "Trusted-Library: true" set in the manifest file. I kept playing with that mixing unsigned applet, with signed methods idea.
And different package names.

bobjob

do you think its possible to do a mixed code version. so that people could extend from the applet loader and make there own applet to display, (do there own paint method and such as long as it was unsigned).

so while loading: play a mini game of something that doesnt require any certificate, and implement any other changes (Like a resizable webstart frames).
I assume the appletLoader itself would be tiny. and then any personal requirements could just be extended/satisfied without any resigning.

Then only the LWJGL certificate would be required, and peoples code would stay up to date with any changes in LWJGL.

Anyway, Iv exausted all my question and concerns ;), feel like I have a decent understanding of the AppletLoader now. Confident enough to use it, and build My projects on a custom version for the moment.

kappa

Quote from: bobjob on July 07, 2010, 07:07:09
do you think its possible to do a mixed code version. so that people could extend from the applet loader and make there own applet to display, (do there own paint method and such as long as it was unsigned).

so while loading: play a mini game of something that doesnt require any certificate, and implement any other changes (Like a resizable webstart frames).
I assume the appletLoader itself would be tiny. and then any personal requirements could just be extended/satisfied without any resigning.

Then only the LWJGL certificate would be required, and peoples code would stay up to date with any changes in LWJGL.

Anyway, Iv exausted all my question and concerns ;), feel like I have a decent understanding of the AppletLoader now. Confident enough to use it, and build My projects on a custom version for the moment.

ha, funny you'd mention that, that was what the original AppletLoader did. I had a version of space invaders (java2d) running with commodore 64 style loading bars around it while the lwjgl applet downloaded in the background, hence why you'll notice alot of the methods and variables are 'protected' so a class that extends the appletloader can use use them. So yeh just extending the AppletLoader and overriding the paint method should still work.

As for mixed code, this is goning to be a pretty difficult now after Oracle messed up the security stuff in java 6u18+ (will break certificate refused screen) and its become pretty hard to mix signed and unsigned code as they no longer share the same classloader. Not sure how mixed code can work now for such a problem without actually building lots more code into the AppletLoader to support this. You should be fine if you can live with signing all your own code though or using a custom AppletLoader.

anyway looking into adding double buffering now for drawing to avoid flicker. Flicker is currently pretty bad when using an animated gif for the logo.

bobjob

Iv have been fiddling around with mix code idea and i think i may have come up with a solution to allow people to extends from the AppletLoader.

The main problem, is with getting resources.

Would it be a security risk, to give the unsigned applet access to a Classloader method from the AppletLoader

namely:
classLoader.getResourceAsStream();

I was hoping that the unsigned applet wouldnt be able to access any other resources outside of the class loader.


edit:
Works fine in windows, but I seem to get some problems in Mac.

edit 2:
Ok got it working. aparantly windows and mac handle the URL "file:" protocol different, you learn something new everyday

edit 3:
A basic loader applet would look something like this

package org.lwjgl.util.applet;

public class LWJGLAppletLoader extends AppletLoader {

	public void loaderInit(boolean error) {}
	
	public void loaderStart() {}

	public void loaderStop() {}
	
	public void loaderDestroy() {}
	
	public void loaderPaint(Graphics g) {}
}


A few other handy methods like
setStartWhenReady(false)

for people who want to program games on the load screen, and want to give the user the option to keep playing.

stripped the appletloader to only the core LWJGL style applet loader, without resize or extra bits
here is a debug version: http://have2chat.net/mixedcode

last edit (i hope):
everything should work like the original appletloader except:
The need to include two files in the applet archive path: signed loader, and unsigned applet.

also if this code is usable, there is 1 little catch. a small static method will need to be included with the LWJGL jars for grabbig resources.
its very small (and should be unisgned). the code is included in:
mixedcode.zip!/mixedcode/game/src/resourceAccess/ResourceGrabber.java


but all of this is pointless, if it is a security risk.  :-\

code is attached.

kappa

quick update, I've added code to handle resizing and the applet logo and text should now remain centred when applet is resized.

As for the flicker, double buffering is already being used and the tearing seems to be due to a deeper problem with gif animation and the java Toolkit. Hopefully can find a solution to this, related jgo thread.

spasi

Java 6 u21 has support for customized applet/JWS loading, info here.

kappa

Quote from: spasi on July 11, 2010, 09:44:56
Java 6 u21 has support for customized applet/JWS loading, info here.

hey that's pretty cool stuff, took them long enough to 'get it' though.