public enum VerticalAlignment {
	Top,Middle,Bottom
} public abstract class ClickHandler extends EventHandler {
	
	/** 
	 * called when the element with this handler added is clicked on.
	 * Specifically the release of the click 
	 ***/
	public abstract void onClick();
	
	Event.EventType getType(){
		return Event.EventType.ClickEvent;
	}
	
	protected void fireHandler(){
		onClick();
	}
} public class Gwtish extends ApplicationAdapter {

	

	final static String logstag = "GdxScoreTester";
	public static Logger Log = Logger.getLogger(logstag); 
	public static PerspectiveCamera cam;
	
	Environment environment;
	
	
	@Override
	public void create () {
		float w = Gdx.graphics.getWidth();		
		float h = Gdx.graphics.getHeight();
	
		cam = new PerspectiveCamera(67,w,h);
		
		DemoScene.setupForDemoScene(Gwtish.cam);

		sceneTest();

		
		Log.info("setup ended");
	}


	public  AssetManager assetsmanager;	
	boolean loading = false;
	  
	private void sceneTest() {
		
		assetsmanager = new AssetManager();
        loading = true;
        
		// a test scene to show/test gwtish functionality (this will add stuff to load)
		DemoScene.setup();
		
		
		
	}
	
	
	static public AssetManager getAssetManager(){
		
		return ((Gwtish)Gdx.app.getApplicationListener()).assetsmanager;
		
	}

	@Override
	public void render () {
		  if (loading && assetsmanager.update())
		  {
			  DemoScene.doneLoading();
			  loading = false;
		  }
		  
		
		Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

		float delta = Gdx.graphics.getDeltaTime(); //in seconds!
		GWTishModelManagement.updateTouchState();		

		
		DemoScene.fpscontrols.update(delta);
		
		//----------- Handle interactions:
		float xc = Gdx.input.getX();
		float yc = Gdx.input.getY();
		Vector2 screenCursorPosition = new Vector2(xc,yc);	
		GWTishModelManagement.getHitables(screenCursorPosition.x,screenCursorPosition.y,cam);
		//----
		//Handle animations:
		GWTishModelManagement.updateObjectMovementAndFrames(delta);
		//

		GWTishModelManagement.modelBatch.begin(cam);
		GWTishModelManagement.modelBatch.render(GWTishModelManagement.allStandardInstances,environment); //basic environment
		GWTishModelManagement.modelBatch.end();
		
	}
	
	@Override
	public void resume() {
		super.resume();
	}

	@Override
	public void dispose () {

		assetsmanager.dispose();
		GWTishModelManagement.dispose();
	}
} public class HorizontalPanel extends CellPanel {
	final static String logstag = "GWTish.HorizontalPanel";
	public static Logger Log = Logger.getLogger(logstag); //not we are using this rather then gdxs to allow level control per tag

	//current stats
	float currentTotalWidgetWidth   = 0f;

	VerticalAlignment DefaultAlignmentinCell = VerticalAlignment.Middle;



	/**
	 * Creates a background and lets you position widgets vertical within it
	 * 
	 */
	public HorizontalPanel() {
		super(10,10); //default size and background


	}

	Vector3 getNextPosition(float incomingWidth,float incomingHeight,Widget widget){ //,boolean updateWidth

		int index = contents.indexOf(widget);

		Alignment align = contentAlignments.get(widget);
		if (align == null) {
			align = new Alignment(HorizontalAlignment.Left,
					defaultVerticalAlignment);
			contentAlignments.put(widget, align);
		}

		float newLocationX = currentTotalWidgetWidth;		

		float newLocationY = 0;

		float maxH = (largestHeightOfStoredWidgets);
		//ensure its at least min height
		if (maxH<MinSizY){
			maxH=MinSizY;
		}

		switch (align.vert) {
		case Bottom:
			newLocationY = -(maxH - incomingHeight);
			break;
		case Middle:
			newLocationY =  -(maxH - incomingHeight)/2; //center in panel
			break;
		case Top:
			newLocationY = 0;
			break;
		default:
			newLocationY =  -(maxH - incomingHeight)/2; //center in panel
			break;

		}



		/*

		if (DefaultAlignmentinCell == VerticalAlignment.Middle){


			newLocationY =  (maxH - incomingHeight)/2; //center in panel



		}*/

		//the following option shouldnt be needed I think
	//	if (updateWidth){
			currentTotalWidgetWidth=currentTotalWidgetWidth+incomingWidth+spaceing;
	//	}

		float zdisplace = 0f; //3f
		return new Vector3(getLeftPadding()+newLocationX,-getTopPadding()+newLocationY,zdisplace); //messureing from topleft downwards hence inverting the padding


	}

	/**
	 * Refreshes the position of all widgets 
	 * 
		recalculateLargestWidgets(); should be run first
	 */
	void repositionWidgets() {
		Log.info("repositionWidgets in hp");
		//simply clear and re-add them all

		//reset  stats

		currentTotalWidgetWidth = 0f;
		//largestWidthOfStoredWidgets = 0f;
		//largestHeightOfStoredWidgets = 0f;


		for (Widget widget : contents) {	

			//	super.removeAttachment(widget); //remove			
			internalAdd(widget); //re add

		}
		Log.info("new size:"+currentTotalWidgetWidth+","+largestHeightOfStoredWidgets);
		//update back size
		//sizeToFitContents(); 

	}

	private VerticalAlignment defaultVerticalAlignment = VerticalAlignment.Middle;

	/**
	 * Sets the default horizontal alignment to be used for widgets added to this
	 * panel. It only applies to widgets added after this property is set.
	 * 
	 */
	public void setHorizontalAlignment(VerticalAlignment align) {
		defaultVerticalAlignment = align;
	}


	//
	@Override
	void sizeToFitContents() {
		
		Log.info("size to fit contents new size:"+currentTotalWidgetWidth+","+largestHeightOfStoredWidgets);
		
		
		this.setSizeAs(getLeftPadding()+currentTotalWidgetWidth+getRightPadding(),
				getBottomPadding()+largestHeightOfStoredWidgets+getTopPadding());
	}

} public class Image extends Widget {
	Texture image;
	protected Material ImageMaterial;
	private boolean setup = false; 
	
	//static String IMAGEBACKGROUND="IMAGEBACKGROUND";

	/**
	 * creates a empty image widget sized 0,0. It wont be visible till setImage is called
	 */
	public Image() {	
		super(0,0);
		
	}

	public Image(String internalFileLocation) {	
		this(Gdx.files.internal(internalFileLocation));		
	}

	public Image(FileHandle imageFileHandle) {	
		this(new Texture(imageFileHandle));		
	}
	
	public Image(Texture image) {		
		super(image.getWidth(), image.getHeight());		
		this.image = image;
		ImageMaterial = setupMaterial(image);
		setImage(image,false);//no need to size as we are already correct

	}


	protected Material setupMaterial(Texture image){
		
		Material mat = getBackgroundMaterial();		
		mat.set(ColorAttribute.createDiffuse(Color.WHITE),
				new BlendingAttribute(true,GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA,1.0f),				 
				TextureAttribute.createDiffuse(image)
				 );

		ImageMaterial = mat;
		setup  = true;
		return mat;
	}


	
	/**
	 * Replaces the Material, in case you want this image to clone another's look.
	 * 
	 * @param texture
	 */
	public void replaceMaterialAttribute(Material replacementMaterial){
		
		Log.info("replaceing material with new one:"+replacementMaterial.id);
		
		super.nodes.first().parts.first().material = replacementMaterial; //This only works because image are basic quads with 1 node and 1 part. More complex objects will not work. 
 		
		/**
		for (Node part : 	super.nodes) {
		
			Log.info("node id:"+part.id);
			
			for (NodePart nodepart : part.parts) {
				
				Log.info("replaceing mat on nodepart"+nodepart.meshPart.id);
				nodepart.material = replacementMaterial; //This only works because image objects have a single material stored in slot zero. More complex objects will not work. 
		 		
			}
		}**/
		
		
		return;
	}



	public void setImage(Texture image){
		setImage(image,true);
	}
	
	//changes the image to the specified one, resizing if needed
	public void setImage(Texture image,boolean size){
		
		if (!setup){ //if the empty constructor was used we might not be setup yet
		   setupMaterial(image); 
		}
		this.image=image;
		Material mat = getBackgroundMaterial();
		mat.set(TextureAttribute.createDiffuse(image));
		
		if (size){			
			setSizeAs(image.getWidth(), image.getHeight());			
		}

	}
	
	
	
	public Texture getImage() {
		return image;
	}

	/**
	 * 
	 * lets you add a specific attribute to the material used to render this image
	 * This attribute could contain a ID that your material manager uses to select a custom shader for it
	 * (for example, if you want to do bump mapping on it, or a distance field)
	 * 
	 * @param shadersAttribute
	 */
	public void setShaderAttribute(Attribute shadersAttribute,boolean clearExisting){
		//set the material to use that attribute
		if (clearExisting){
			ImageMaterial.clear();
		}
		
		ImageMaterial.set(shadersAttribute);
		
	}



	/**
	 * Do not use for anything but ZINDEX. Images dont support style changes right now.
	 * Might not ever, depending how styles end up being handled.
	 * This is because Images will use their own shader, or one supplied, not the standard text shader giving CSS like functions
	 */
	@Override
	public Style getStyle() {
		return super.getStyle();
	}
	


	//setVisibleRect

} public class Label extends LabelBase {

	final static String logstag = "GWTish.Label";
	public static Logger Log = Logger.getLogger(logstag); //not we are using this rather then gdxs to allow level control per tag

	/**
	 * The name of the label material
	 */
	public static final String LABEL_MATERIAL = "LabelMaterial";

	/**
	 * contents of this text label;
	 */
	String contents = "TextNotSetError";


	//static int LabelNativeWidth =512;
	//static int LabelNativeHeight=512;



	/**
	 * flags if we need to do any initial setup work or not.
	 * (might be unnecessary)
	 */
	static Boolean labelSetupDone = false;

	/**
	 * we can optionally interpret html like br tags as newlines
	 */
	private boolean interpretBRasNewLine=false;

	public boolean isInterpretBRasNewLine() {
		return interpretBRasNewLine;
	}
	/**
	 * we can optionally interpret html like br tags as newlines
	 * defaults to false. Does not refresh text
	 */
	public void setInterpretBRasNewLine(boolean interpretBRasNewLine) {
		this.interpretBRasNewLine = interpretBRasNewLine;
	}

	private boolean interpretBackslashNasNewLine=true;

	public boolean isInterpretBackslashNasNewLine() {
		return interpretBackslashNasNewLine;
	}
	/**
	 * interpret \n as newlines
	 * Note;  \r\n or \n\r will be converted to just \n
	 * 
	 * defaults to true	
	 * @param interpretBackslashNasNewLine
	 */
	public void setInterpretBackslashNasNewLine(boolean interpretBackslashNasNewLine) {
		this.interpretBackslashNasNewLine = interpretBackslashNasNewLine;
	}

	//defaults
	BitmapFont defaultFont;

	/** default scale factor of the text **/
	float ModelScale = 1.0f;

	enum SizeMode {
		/** label is a fixed, specified size and everything is scaled to fit.
		 *  Padding does not increase size. **/
		Fixed,
		/** label expands till it contains the text **/
		ExpandXYToFit,
		/**
		 * Expands variably with new lines, but wraps to the width.
		 * This is somewhat like a HTML DIV with a style width specified
		 */
		ExpandHeightMaxWidth,

	}

	SizeMode labelsSizeMode = SizeMode.ExpandXYToFit;


	/**
	 * under fixed width mode this marks the maximum width of the widget. Any expansion of the text beyond it will result
	 * in word wrapping.
	 * Under fixed mode this will be the size regardless of its its all needed or not.
	 */
	float maxWidth = -1; //default for no max
	/**
	 * Not used unless we are on fixed mode, then its the height.
	 */
	float maxHeight = -1; //default for no max

	/**
	 * The text alignment used to last generate the text texture
	 */
	private TextAlign lastUsedTextAlignment;



	/**
	 * 
	 * @param contents
	 */
	public Label (String contents){ 
		this(contents, false,true, -1,-1, SizeMode.ExpandXYToFit, MODELALIGNMENT.TOPLEFT,TextAlign.LEFT); //defaults to top left alignment of pivot with no max width
	}
	/**
	 * 
	 * @param contents
	 * @param MaxWidth
	 */
	public Label (String contents,float MaxWidth){ 
		this( contents, false, true,MaxWidth,-1, SizeMode.ExpandHeightMaxWidth, MODELALIGNMENT.TOPLEFT,TextAlign.LEFT); //defaults to top left alignment of pivot
	}

	/**
	 * fixed size label - texture scales into it (non-gwt like)
	 * @param contents
	 * @param Width
	 * @param Height
	 * @param modelalignment
	 * @param textalign
	 */
	public Label(String contents, float Width, float Height, MODELALIGNMENT modelalignment, TextAlign textalign) {
		this( contents, false, true,Width, Height, SizeMode.Fixed, modelalignment,textalign); //defaults to top left alignment of pivot
	}
	/**
	 * * fixed size label - texture scales into it (non-gwt like)
	 * @param contents
	 * @param MaxWidth
	 * @param MaxHeight
	 */
	public Label (String contents,float MaxWidth,float MaxHeight){ 
		this( contents, false,true, MaxWidth,MaxHeight, SizeMode.Fixed, MODELALIGNMENT.TOPLEFT,TextAlign.LEFT); //defaults to top left alignment of pivot
	}

	/**
	 * 
	 * @param contents
	 * @param MaxWidth
	 *  @param MaxHeight
	 */
	public Label (String contents,float Width,float Height, MODELALIGNMENT alignment){ 
		this( contents, false,true, Width,Height, SizeMode.Fixed, alignment,TextAlign.LEFT); 
	}

	/**
	 * 
	 * @param contents
	 * @param MaxWidth
	 */
	public Label (String contents,float MaxWidth,MODELALIGNMENT alignment){ 
		this( contents, false,true, MaxWidth,-1, SizeMode.ExpandHeightMaxWidth, alignment,TextAlign.LEFT); 
	}
	/**
	 * 
	 * @param contents
	 * @param MaxWidth
	 * @param modelAlignement
	 */
	public Label (String contents,boolean interpretBRasNewLine,boolean interpretNLasNewLine,float MaxWidth,float MaxHeight, SizeMode sizeMode, MODELALIGNMENT modelAlignement, TextAlign textAlignment){ 

		super(generateObjectData(true, true, contents, interpretBRasNewLine,interpretNLasNewLine,sizeMode, MaxWidth, MaxHeight, modelAlignement,textAlignment,null));
		super.setStyle(this.getTextMaterial()); //no style settings will work before this is set
		contents = standardiseNewlines(contents);
		
		this.lastUsedTextAlignment = textAlignment;
		this.userData="label_"+contents;


		if (!labelSetupDone){
			firstTimeSetUp();
			labelSetupDone=true;
		}


		labelsSizeMode = sizeMode;
		this.maxWidth = MaxWidth;
		this.maxHeight = MaxHeight;
		this.contents=contents;

		Material materialAccordingToStyle = this.getStyle().getMaterial();
		Material materialAccordingToGetMaterial = this.getTextMaterial();

		//debug checks
		if (materialAccordingToStyle!=materialAccordingToGetMaterial){
			Log.info( "materials dont match!"); 
		}
		if (materialAccordingToStyle==null){
			Log.info( "materialAccordingToStyle is null"); 
		}
		if (materialAccordingToGetMaterial==null){
			Log.info( "materialAccordingToGetMaterial is null"); 
		}
		//--------------------------------------------------------


		GwtishWidgetShaderAttribute matttest = (GwtishWidgetShaderAttribute) materialAccordingToGetMaterial.get(GwtishWidgetShaderAttribute.ID);

		Log.info( "<---------------------------------------------text :   "+contents); 
		Log.info( "matt test for label has Text:"+matttest.hasText()); 
		Log.info( "text col:   "+matttest.textColour); 

		if (sizeMode==SizeMode.Fixed){
			//calc needed shader scaleing. Fixed size mode enlarges and shrinks texture to fit model - but does so in the shader, not by changing the underlying texture resolution
			//(which is pointless - as you could only ever lose information and make it look worse.)

			calculateCorrectShaderTextScale(1.0f); //default to a 1.0f, which means we use the native bitmap font size 

			//old;
			//if fixed mode we might need to pad the texture to ensure it keeps its ratio			
			//setPaddingToPreserveTextRatio(TextAlign.LEFT,  maxWidth , maxHeight, this.textureSize.x, this.textureSize.y);

		}

	}


	/*
	 * Generates a label with the specified contents, auto expanding its size to fit
	 * Newlines in the content are respected 
	 * 
	 * @param contents
	 *
	public Label (String contents){
		super(generateObjectData(true, true, contents, SizeMode.ExpandXYToFit,-1));//No max width

		super.setStyle(this.getMaterial(LABEL_MATERIAL));

		labelsSizeMode = SizeMode.ExpandXYToFit;
		this.maxWidth = -1;
		this.contents=contents;

		if (!labelSetupDone){
			firstTimeSetUp();
			labelSetupDone=true;
		}


	}
	 */




	/**
	 * The object data needed on creation is just the background mesh instance and the cursor position.
	 * This shouldn't need to be run outside the objects first creation, allthough a resize might be required.
	 * 
	 * After its created everything should eventually be alterable separately without full recreation
	 * 
	 * @param regenTexture - probably can be removed
	 * @param regenMaterial
	 * @param contents
	 * @param labelsSizeMode
	 * @param maxWidth
	 * @param alignment - the meshs pivot alignment
	 * @param textAlignment 
	 * @return
	 */
	private static backgroundAndCursorObject generateObjectData(
			boolean regenTexture,
			boolean regenMaterial,
			String contents,
			boolean interpretBRasNewLine,
			boolean interpretNLasNewLine,
			SizeMode labelsSizeMode,
			float maxWidth ,
			float maxHeight,
			MODELALIGNMENT alignment, 
			TextAlign textAlignment,
			Style style) {


		TextureAndCursorObject textureData = null;


		BitmapFont font;     //     = getEffectiveFont(style);
		float NativeToSceneRatio;// = getNativeToSceneResizeRatio(style, font);

		if (contents.isEmpty()){
			//if no contents we dont bother getting the font
			//(this allows the creation of empty labels before the font is ready)
			font=null;
			NativeToSceneRatio=1.0f; //randomvalue, no real effect with empty texture
		} else {
			
			font          = getEffectiveFont(style);
			NativeToSceneRatio = getNativeToSceneResizeRatio(style, font);

		}
		if (interpretNLasNewLine){
		contents = standardiseNewlinesStatic(contents);
		}
		int startFromX =0;
		int startFromY =0;
		Pixmap addToThis = null;


		if (regenTexture){			

			textureData = generateTexture(labelsSizeMode, contents,interpretBRasNewLine,interpretNLasNewLine,
					NativeToSceneRatio,maxWidth,textAlignment,style,font,
					startFromX,startFromY,addToThis); //left default	

		}

		Texture newTexture = textureData.textureItself;

		newTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);//MipMapLinearNearest does not work with DistanceField shaders

		//DistanceFieldAttribute textStyle = null;
		//GwtishWidgetDistanceFieldAttribute textStyle = null;

		//if (textStyle==null){
		//	textStyle = new DistanceFieldShader.DistanceFieldAttribute(DistanceFieldAttribute.presetTextStyle.whiteWithShadow);
		GwtishWidgetShaderAttribute textStyle = new GwtishWidgetShaderAttribute(GwtishWidgetShaderAttribute.presetTextStyle.whiteWithShadow);

		//assign texture to special shader
		textStyle.distanceFieldTextureMap = newTexture;
		//}


		//we normally get the model size from the generated material unless its specified as fixed
		float textureSizeX = newTexture.getWidth();
		float textureSizeY = newTexture.getHeight();

		float SizeX = textureSizeX * (1.0f/NativeToSceneRatio);
		float SizeY = textureSizeY * (1.0f/NativeToSceneRatio);

		if (labelsSizeMode==SizeMode.Fixed){

			SizeX = maxWidth;			
			SizeY = maxHeight;

			textStyle.setTextScaleing(TextScalingMode.fitPreserveRatio); 

			Log.info( "fitarea detected texture size mode set as:"+textStyle.textScaleingMode); 
			//setPaddingToPreserveTextRatio(TextAlign.LEFT,  maxWidth , maxHeight, sizeX, sizeY);

		}

		//TODO:also ensure its bigger then the minimum size?
		//


		Material mat = 	
				new Material(LABEL_MATERIAL,
						new BlendingAttribute(true,GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA,1.0f),
						//TextureAttribute.createDiffuse(newTexture),
						//	ColorAttribute.createDiffuse(defaultBackColour), //needs to be passed into this function
						textStyle);



		Model newModel = Widget.generateBackground(SizeX, SizeY, mat, alignment);

		//GwtishWidgetShaderAttribute matttest2 = (GwtishWidgetShaderAttribute) newModel.getMaterial(LABEL_MATERIAL).get(GwtishWidgetShaderAttribute.ID);

		//Log.info( "1fitarea set as:"+matttest2.textScaleingMode); 
		//Log.info( "paddingLeft:   "+matttest2.paddingLeft); 



		backgroundAndCursorObject setupData = new backgroundAndCursorObject(newModel,
				textureData.Cursor.x,
				textureData.Cursor.y,
				new Vector2(textureSizeX,textureSizeY),
				textureData.rawPixelData,
				textureData.newline_indexs
				);


		GwtishWidgetShaderAttribute testAttribute = (GwtishWidgetShaderAttribute)setupData.object.getMaterial(LABEL_MATERIAL).get(GwtishWidgetShaderAttribute.ID);

		Log.info( "<---------------------------------------------setupData :   "+testAttribute.hasText()); 



		return setupData;


	}

	private static BitmapFont getEffectiveFont(Style style) {

		BitmapFont rawFont = Style.getDefaultFont(); // FontHandling.standdardFont;
		BitmapFont adjustedFont = rawFont;

		if (style!=null){


			rawFont = style.getFont(); // FontHandling.standdardFont;

			//make a copy of the font so we can customize the line height data
			//probably not very efficient?
			adjustedFont = new BitmapFont(
					rawFont.getData(),
					rawFont.getRegion(), 
					rawFont.usesIntegerPositions());

			float LineHeight = (float) style.getLineHeightValue();
			Style.Unit LineHeightUnit = style.getLineHeightUnit();

			//we only support PX or Unitless at the moment		
			if (LineHeightUnit == Style.Unit.PX){
				adjustedFont.getData().setLineHeight(LineHeight);
			}
			if (LineHeightUnit == Style.Unit.UNITLESS){				
				//only supported if font size is pixels
				if (style.getFontSizeUnit() == Unit.PX){


					//double fontsize = style.getFontSize(); //wait, we  dont want real size as the texture map is generated at native resolution regardless of what the display size will be.
					double fontsize = FontHandling.getNativeFontSize(rawFont) ;//rawFont.getLineHeight();
					double effectiveSize = fontsize*LineHeight;

					Log.info( "native fontsize:   "+fontsize+"   LineHeight:"+LineHeight); 

					Log.info( "effective lineheight:   "+effectiveSize); 
					adjustedFont.getData().setLineHeight((float) effectiveSize);

				}
			}

		}
		return adjustedFont;
	}

	/**
	 * 
	 * @param text
	 * @param NativeSceneRatio
	 * @param effectiveMaxWidth
	 * @param align
	 * @param stylesettings
	 * @param font
	 * @return
	 */
	static public TextureAndCursorObject generatePixmapForShader(
			String text, 
			boolean interpretBRasNewLine,
			boolean interpretNLasNewLine,
			float NativeSceneRatio, 
			float effectiveMaxWidth,
			TextAlign align, 
			Style stylesettings,
			BitmapFont font,
			int startFromX,
			int startFromY,
			Pixmap addToThis
			) {

		//  BitmapFontData data = DefaultStyles.standdardFont.getData();

		GlyphLayout layout = getNewLayout(text, interpretBRasNewLine, interpretNLasNewLine,NativeSceneRatio, effectiveMaxWidth, align, font);
		TextureAndCursorObject textureDAta = generateTexture_fromLayout(layout, font,startFromX,startFromY,addToThis); 

		//Font size  trying to figure out

		//Note; in order to scale text to fit in other modes we still render at the native size, but dont effect the mesh size
		//the texture will then auto-scale into the space. 
		//
		//However...this "solution" doesn't deal with maxwidth because the width of the characters determines how many per line can fit.
		//So this might take some thinking about.
		//a) there should be a minimum texture pixel size per character, regardless of final visual size
		//b) for the wrapping to work, however, at least the correct ratio needs to end up in the layout?
		//ii) or maybe we change the width proportionally the other way? (then when its sized up to the widget size it will be correct? err...seems weird but should work? )
		//
		//font size is stored in style right now, so whatever we do we use that 




		//old;


		//   float currentWidth  = layout.width;
		//   float currentHeight = layout.height;
		/*
	    for (GlyphRun grun : layout.runs) {

	    	Log.info("______________run width:"+grun.width+" at "+grun.y);	
	    	String runstring = "";

	    	for (Glyph g : grun.glyphs) {

	    	//	Log.info("___g:"+g.toString());
	    		runstring=runstring+g.toString();

			}
	    	Log.info("___runstring:"+runstring);



		}
		 */

		//	Log.info("______________predicted size = "+currentWidth+","+currentHeight);

		//	TextureAndCursorObject textureDAta = generateTexture( text, 0, 0,  sizeratio, true,maxWidth); //note zeros as size isn't used




		return textureDAta;

	}
	private static GlyphLayout getNewLayout(String text, 
			boolean interpretBRasNewLine, boolean interpretNLasNewLine,
			float NativeSceneRatio,
			float effectiveMaxWidth, TextAlign align, BitmapFont font) {
		GlyphLayout layout = new GlyphLayout();	    
		//layout.setText(DefaultStyles.standdardFont, text);



		//if maxWidth is zero or -1 then we dynamically work it out instead
		//this means the texture will just be as horizontally long as it needs too, without forced wrapping
		if (effectiveMaxWidth<1){
			layout.setText(font, text); 
			effectiveMaxWidth = layout.width; //gets width at native font size
		}	else {

			//if the effectiveMaxWidth is set however,we might have to shrink it by the NativeSceneRatio
			//This is because font size effects when wraps have to happen.
			//Bigger font = bigger letters = must wrap sooner
			//
			//so this "fake shrunk" newwidth is used to determine the wrapping of the font, which is then scaled up again at the end.
			//Note; the actual per-character pixel size of the map never changes, we are just using this to cropit different

			effectiveMaxWidth = effectiveMaxWidth * NativeSceneRatio;


		}



		Log.info(text+"___layout width:"+effectiveMaxWidth);
		Log.info(text+"___layout line height:"+font.getLineHeight());

		//convert from text align to layout align
		int layoutAlignment = Align.center;

		switch (align) {
		case CENTER:
			layoutAlignment = Align.center;
			break;
		case JUSTIFY:		    
			Log.info("___JUSTIFY NOT SUPPORTED. DEFAULTING TO CENTER");
			layoutAlignment = Align.center;
			break;
		case LEFT:
			layoutAlignment = Align.left;
			break;
		case RIGHT:
			layoutAlignment = Align.right;
			break;
		default:
			layoutAlignment = Align.center;
			break;
		}

		if (!interpretNLasNewLine){
			text=text.replace("\n", "");	
		}
		//if we are set to interpret <br> as newline, then we replace them with \n
		if (interpretBRasNewLine){	
			text=text.replace("<br>", "\n");					
		}


		layout.setText(font, text, Color.BLACK, effectiveMaxWidth, layoutAlignment, true); //can't centralize without width
		return layout;
	}


	//note implemented yet
	//private static Vector2 caclculateModelSizeFromTexture(float getNativeToSceneResizeRatio, Style stylesettings) {

	//textureSize.x, textureSize.y

	//	Vector2 test = new Vector2(0,0);

	//	return test;

	//}

	/**
	 * The ratio between the internal pixmap font size and the one requested in the style as the output size.
	 * The actual widget size should thus be;
	 * 
	 * (texturemap size * ratio) + padding
	 * 
	 * @param stylesettings
	 * @param font
	 * @return
	 */
	private static float getNativeToSceneResizeRatio(Style stylesettings, BitmapFont font) {
		float ShrinkWidthRatio = 1.0f;

		//if font size is set we work out the changes here
		if (stylesettings!=null && stylesettings.fontSizeUnit!=Unit.NOTSET){

			///font.getData().setScale(3.5f); //scaling only effects spacing, not font size
			//how to do font size ?
			//maybe work out the difference between native and result width/height as ratio?
			//scale down the width so it wraps at the correct letters, then..umm...set the shader font scale up? to....err.something?		

			//lets try getting te ratio of the native map height to the result height;
			float baseToAssent = font.getCapHeight()+font.getAscent();
			Log.info("__native cap+ascent:"+baseToAssent);	
			float baseToDecent = -font.getDescent();
			Log.info("__native baseToDecent:"+baseToDecent);	

			float fontHeight = baseToAssent+baseToDecent; //seems too small?
			fontHeight=32; //actual size		
			Log.info("__native fontHeight:"+fontHeight);

			double fontSizeRequested = stylesettings.getFontSize();
			Log.info("__requested fontHeight:"+fontSizeRequested+" ("+stylesettings.getFontSizeUnit()+")");
			double ratio = fontHeight/fontSizeRequested;
			ShrinkWidthRatio = (float) ratio;

			Log.info("__ratio:"+ShrinkWidthRatio); //shrink width by this amount (if fixed width)

			//now sale up again using the ratio in the shader? or just geometry

			//-------------------------
		} else {
			ShrinkWidthRatio = 1f; //default no change
		}
		return ShrinkWidthRatio;
	}



	/**
	 * new method using the layout function to give us the data needed to...well..layout the glyphs
	 * @param layout
	 * @param standdardFont - should match the one used to generate the layout
	 * @return
	 **/
	static public TextureAndCursorObject generateTexture_fromLayout(GlyphLayout layout, BitmapFont standdardFont,
			int startFromX,int startFromY,Pixmap addToThis){

		//create according to predicted size 
		int currentWidth  = (int) layout.width;
		int currentHeight = (int) (layout.height+standdardFont.getCapHeight()); //not sure if cap  height is correct
		//.info("_________standdardFont.getCapHeight()="+standdardFont.getCapHeight()+" ");

		Pixmap textPixmap;

		//new pixmap with old data
		if (addToThis!=null){

			int newRequiredWidth  = startFromX+currentWidth;			 
			int newRequiredHeight = startFromY+currentHeight;

			//if new width or height is bigger we need to make a new map
			if (newRequiredWidth>addToThis.getWidth() || newRequiredHeight>addToThis.getHeight()){

				//should pick the biggest values for both dimensions
				if (newRequiredWidth<addToThis.getWidth()){
					newRequiredWidth=addToThis.getWidth();
				}
				if (newRequiredHeight<addToThis.getHeight()){
					newRequiredHeight=addToThis.getHeight();
				}

				Log.info("_________creating new pixmap of size:"+newRequiredWidth+","+newRequiredHeight+" ");

				textPixmap = new Pixmap(newRequiredWidth, newRequiredHeight, Format.RGBA8888);
				textPixmap.drawPixmap(addToThis, 0, 0);

				//dispose old
				addToThis.dispose();

			} else {
				Log.info("_________reuse old map!:"+newRequiredWidth+","+newRequiredHeight+" ");

				//reuse old map!
				textPixmap=addToThis;
			}


		} else {
			Log.info("________New pixmap with no data:"+currentWidth+","+currentHeight+" ");

			//new pixmap with no data
			textPixmap = new Pixmap(currentWidth, currentHeight, Format.RGBA8888);

		}

		Log.info("_______ ");


		Pixmap fontPixmap = getFontPixmap(standdardFont);

		int currentTargetX = 0;
		int currentTargetY = 0;

		float advance = 0;
		
		int current_index = 0; //used only to keep track of newlines
		ArrayList<Integer> newline_indexs = new ArrayList<Integer>();

		Log.info("_______ "+startFromX+" "+startFromY);//0,0
		Log.info("_______runs "+layout.runs.size);// Firefox crashs after this point
		//now loop over each run of letters. 
		for (GlyphRun grun : layout.runs) {

			String runstring = "";
			float currentRunX= 0; 
			advance = 0;

			//store as newline location
			if (current_index>0){
				newline_indexs.add(current_index);
			}
			
			//now draw each letter
			//	Log.info("_________grun="+grun.x+","+grun.y+" ");
			int i =0;
			for (Glyph glyph : grun.glyphs) {
				current_index++;
				
				advance = grun.xAdvances.get(i);
				i++;
				currentRunX=currentRunX   +   advance    ; //1 should not be needed

				currentTargetX = startFromX+ (int)grun.x  + (int)currentRunX;		//used to use startfrom to add to the pixmap, now we add to the texture instead		
				currentTargetY = startFromY+ (int)grun.y;

			 	int destX = currentTargetX + glyph.xoffset;
				int destY = currentTargetY + glyph.yoffset;
//				
//				if (destX<0){
//					destX=0;
//				}
//
//				if (destY<0){
//					destY=0;
//				}
				Log.info("___g:"+glyph.toString());//$ in chrome, space in FF

				Log.info("___textPixmap:"+textPixmap.getWidth()+","+textPixmap.getHeight()+", "+
				"___fontPixmap:"+fontPixmap.getWidth()+","+fontPixmap.getHeight()+", "+
				        +glyph.srcX+", "+glyph.srcY+", "+glyph.width+", "+glyph.height+", "+
						destX+", "+
						destY+", "+						
						glyph.width+", "+glyph.height);	//is minus 7 offsetx ok?
				textPixmap.drawPixmap(
						fontPixmap,
						glyph.srcX,
						glyph.srcY, 
						glyph.width, 
						glyph.height,
						destX,
						destY,						
						glyph.width, 
						glyph.height);

				//	Log.info("___g:"+g.toString());

				Log.info("___g:"+glyph.toString());
				runstring=runstring+glyph.toString();

			}
			if (grun.glyphs.size>0){
				advance = grun.xAdvances.get(i);
				i++;
				currentRunX=currentRunX+advance;
				Log.info("______________last run width:"+grun.width+" drawn was till "+currentRunX);	
			}
			//Log.info("___runstring drawen:"+runstring);



		}

		//work out final cursor position, which is currentTargetX + last advance
		int cx = (int) (currentTargetX+advance);
		int cy = (int) (currentTargetY); 

		//PixmapAndCursorObject pixmapAndCursor = new PixmapAndCursorObject(textPixmap, cx, cy);

		Texture textureData; 
		//	if (startFromX==0 && startFromY==0 || addToThis==null){
		textureData = new Texture(textPixmap);
		/*
		} else {
			//add pixmap to existing texture
			//textureData = new Texture(pixmapAndCursor.textureItself);

			//enlarge?
			//
			Log.info("______________textPixmap size: "+textPixmap.getWidth()+","+textPixmap.getHeight());	
			Log.info("______________adding at: "+startFromX+","+startFromY);	
			Log.info("______________texture size: "+addToThis.getWidth()+","+addToThis.getHeight());	

		//	textPixmap.fill();			

			//addToThis.getTextureData().prepare();
		//	Pixmap existingTexture = addToThis.getTextureData().consumePixmap();


			addToThis.draw(textPixmap, startFromX, startFromY); //todo: startFromY is wrong?? seems to draw offscreen if set

			//note; drawing doesnt work if ANY of it is outside the bounds

			//add the startfroms to the cursor pos
			cx=startFromX+cx;
			cy=startFromY+cy;

			textureData=addToThis;
		}*/
		
		newline_indexs.add(current_index);

		TextureAndCursorObject textureAndCursorObject = new TextureAndCursorObject(
				textureData,
				cx,
				cy,
				textPixmap,
				newline_indexs);

		//textPixmap.dispose();


		Log.info("_______generateTexture_fromLayout done");
		return textureAndCursorObject;


	}


	static HashMap<BitmapFont,Pixmap> fontCache = new HashMap<BitmapFont,Pixmap>();

	/**
	 * Gets a pixmap of the specified font, using a cache if its already been created before
	 * @param standdardFont
	 * @return
	 */
	private static Pixmap getFontPixmap(BitmapFont standdardFont) {

		Pixmap	fontPixmap = fontCache.get(standdardFont);

		if (fontPixmap==null){		
			BitmapFontData data = standdardFont.getData(); 
			fontPixmap = new Pixmap(Gdx.files.internal(data.imagePaths[0])); 
			fontCache.put(standdardFont, fontPixmap);
		}

		return fontPixmap;
	}





	static public TextureAndCursorObject generateTextureNormal(String text,int TITLE_WIDTH,int TITLE_HEIGHT, float sizeratio) {

		TextureAndCursorObject textureDAta = generateTexture( text, TITLE_WIDTH, TITLE_HEIGHT,  sizeratio,false,-1);

		return textureDAta;
	}

	static public TextureAndCursorObject generateTexture(String text,int DefaultWidth,int DefaultHeight, float sizeratio, boolean expandSizeToFit, float maxWidth) {

		PixmapAndCursorObject data = generatePixmap(text, DefaultWidth, DefaultHeight, sizeratio, expandSizeToFit,maxWidth);
		TextureAndCursorObject textureAndCursorObject = new TextureAndCursorObject(
				new Texture(data.textureItself),
				data.Cursor.x,data.Cursor.y,
				data.textureItself,
				null
				);
		//	data.textureItself.dispose();


		return textureAndCursorObject;
	}

	static public PixmapAndCursorObject generatePixmap(String text,int DefaultWidth,int DefaultHeight, float sizeratio, boolean expandSizeToFit, float maxWidth) {

		//if maxWidth = -1 then theres no max width

		String Letters    = text;
		Pixmap textPixmap = new Pixmap(DefaultWidth, DefaultHeight, Format.RGBA8888);

		if (!expandSizeToFit){

			textPixmap = new Pixmap(DefaultWidth, DefaultHeight, Format.RGBA8888);

		} else {
			//start arbitrarily big (this will be fixed later
			textPixmap = new Pixmap(500, 500, Format.RGBA8888);

		}

		//	textPixmap.setColor(1, 0, 0, 1);					
		//	textPixmap.drawRectangle(3, 3, TITLE_WIDTH-3, TITLE_HEIGHT-3);

		BitmapFontData data = FontHandling.standdardFont.getData(); //new BitmapFontData(Gdx.files.internal(data.imagePaths[0]), true);

		Pixmap fontPixmap = new Pixmap(Gdx.files.internal(data.imagePaths[0]));

		// draw the character onto our base pixmap

		int totalwidth=0;
		int current_testedwidth=0;

		int currentX=0;

		float scaledown = sizeratio;

		//Glyph defaultglyph = data.getGlyph(Letters.charAt(0));


		//int totalheight=defaultglyph.height+9;

		Log.info("scaledown="+scaledown);
		double lastremainder =0;
		int yp=0;

		int destX = 0;
		int destY = 0;
		int cheight = 0;

		//the bottom right corner of the texture map thats used
		int biggestX = 0;
		int biggestY = 0;

		for (int i = 0; i < Letters.length(); i++) {

			Glyph glyph = data.getGlyph(Letters.charAt(i));

			if (glyph==null){
				Log.info("_______(current glyph not valid not in character set, setting glyph to space)");
				glyph=data.getGlyph(' '); //temp


			}


			int cwidth =  (int)(glyph.width  * scaledown);
			cheight = (int)(glyph.height * scaledown);

			int yglyphoffset = (int) (glyph.yoffset * scaledown);

			destX = 0+currentX+glyph.xoffset;


			//Log.info("Letters.charAt(i)="+Letters.charAt(i));

			if (Letters.charAt(i) == '\n' || (destX>maxWidth && maxWidth!=-1) ){

				//new line  NB; defaultglyph.height seems to be zero for some reason
				yp=(int) (yp+(data.lineHeight* scaledown)+5);
				currentX=0;
				destX=glyph.xoffset;
				lastremainder=0;
				//Log.info("______________adding line. (yp now="+yp+") next char is:"+Letters.charAt(i));

				//we skip \n as we don't want to really write that
				if (Letters.charAt(i) == '\n'){
					continue;
				}
				//---
			}

			destY = 0+(yp+(yglyphoffset ));



			//note if we are going to go of the edge, and we are on expand mode, we have to quickly get a bigger map to work in
			boolean hadToEnlarge = false;
			int cbiggestX = destX+cwidth;
			int cbiggestY = destY+cheight;

			//ensure its bigger then anything we have already (remember cbiggest is just the current lines largest x value, not the overall for all lines)
			if (cbiggestX>biggestX){
				biggestX = cbiggestX;
			}
			if (cbiggestY>biggestY){
				biggestY = cbiggestY;
			}
			if (expandSizeToFit && (biggestX>textPixmap.getWidth())){
				Log.info("______________x ("+biggestX+") out of range, having to make canvas bigger");
				//we just double the X size, as we are cropping later anyway
				cbiggestX=biggestX*2;
				hadToEnlarge =  true;					
			} else {
				cbiggestX = textPixmap.getWidth();
			}

			if (expandSizeToFit && (biggestY>textPixmap.getHeight())){
				Log.info("______________y ("+cbiggestY+") out of range, having to make canvas bigger");
				//we just double the Y size, as we are cropping later anyway
				cbiggestY=biggestY*2;
				hadToEnlarge =  true;					
			} else {
				cbiggestY = textPixmap.getHeight();
			}

			if (hadToEnlarge){
				textPixmap = sizePixmapTo(textPixmap, cbiggestX, cbiggestY);
			}
			//--------------------


			textPixmap.drawPixmap(
					fontPixmap,
					glyph.srcX,
					glyph.srcY, 
					glyph.width, 
					glyph.height+1,
					destX,
					destY,//+(TILE_HEIGHT - (cheight)) / 2,						
					cwidth, 
					cheight);



			double newprecisepos =  ((glyph.xadvance+2)  * scaledown)+lastremainder;//glyph.width+3
			lastremainder = newprecisepos - Math.floor(newprecisepos);
			int newpos = (int) (Math.floor(newprecisepos));
			//	Log.info("newpos="+newpos);
			//	Log.info("lastremainder="+lastremainder);
			currentX=currentX + newpos;
		}

		if (expandSizeToFit){
			//crop down to final size
			// biggestX = currentX;
			// biggestY = destY+cheight;

			Log.info("______________final cropped size="+biggestX+","+biggestY);

			textPixmap = sizePixmapTo(textPixmap, biggestX, biggestY);

			//	LabelNativeWidth  = biggestX;
			//LabelNativeHeight = biggestY;

		}

		//0,0 should be current cursor position after this update
		return new PixmapAndCursorObject(textPixmap,0,0);

	}


	private static Pixmap sizePixmapTo(Pixmap textPixmap, int biggestX, int biggestY) {
		Pixmap croppedPixMap = new Pixmap(biggestX, biggestY, Format.RGBA8888);
		croppedPixMap.drawPixmap(textPixmap, 0, 0);

		textPixmap.dispose();
		textPixmap = croppedPixMap;
		return textPixmap;
	}

	/**
	 * Sets the text and regenerates the texture 
	 **/
	public void setText(String text){
		text = standardiseNewlines(text);
		
		this.contents=text;

		//todo; check if we can add instead?

		regenerateTexture(text,null);

	}
	
	public String standardiseNewlines(String text) {
		if (interpretBackslashNasNewLine){
			text = standardiseNewlinesStatic(text);			
		}
		return text;
	}
	static String standardiseNewlinesStatic(String text) {
		text=text.replaceAll("\\r\\n|\\r|\\n", "\n");
		return text;
	}

	/**
	 * if possible, adds text to existing text rather then redrawing the lot.
	 * sometimes a redraw is needed, however
	 * @param text
	 */
	public void addText(String text) {
		//if empty string ignore
		if (text.isEmpty()){
			return; // no op
		}
		text = standardiseNewlines(text);
		this.contents=contents+text;

		Log.info("adding: "+text+" to existing text");

		boolean textWraps=false;

		//	if (labelsSizeMode==SizeMode.Fixed || labelsSizeMode==SizeMode.ExpandXYToFit){ //these things never wrap

		//	Log.info("(label doesnt wrap) ");
		//		textWraps=false;
		//	} else {
		//we might still wrap, but we need to work it out based on if we have a new height

		//get new predicted size based on existing settings
		float effectiveMaxWidth = maxWidth;
		if (maxWidth!=-1){
			effectiveMaxWidth = maxWidth - (this.getStyle().getPaddingLeft() + this.getStyle().getPaddingRight());
		}
		BitmapFont font          = getEffectiveFont(this.getStyle());
		float NativeToSceneRatio = getNativeToSceneResizeRatio(this.getStyle(), font);

		GlyphLayout layout = getNewLayout(contents, interpretBRasNewLine,interpretBackslashNasNewLine, NativeToSceneRatio, effectiveMaxWidth, this.lastUsedTextAlignment, font);

		int newheight = (int) (layout.height +font.getCapHeight());
		int newwidth = (int) layout.width;

		Log.info(" new height = "+newheight);
		Log.info(" current text height = "+textureSize.y);

		//notes;
		//cursor y seems to slowly get displaced (ie, a few pixels too big each time)
		//also x might be too small
		if (newheight>textureSize.y){
			Log.info(" size changed, so we need to regenerate ");
			textWraps=true;
		} else {
			textWraps=false;
		}

		//	}

		if (textWraps){

			//get rid of old texture
			//((TextureAttribute)infoBoxsMaterial.get(TextureAttribute.Diffuse)).textureDescription.texture.dispose();


			Log.info(" regenerating texture ");
			regenerateTexture(contents,null);

		} else {
			Log.info(" adding to texture ");

			//	Texture addToExisting = new Texture(newwidth, newheight, Format.RGBA8888);
			//	addToExisting.draw(super.currentPixmap, 0, 0);


			regenerateTexture(text,super.currentPixmap);
		}



	}



	/**
	 * 
	 */
	private void regenerateTexture(String text,Pixmap addToExisting) {

		TextAlign align = this.getStyle().getTextAlignment();
		lastUsedTextAlignment = align;

		//note; we subtract the left/right padding from maxwidth to get the required width of the texture itself
		float effectiveMaxWidth = maxWidth;
		if (maxWidth!=-1){
			effectiveMaxWidth = maxWidth - (this.getStyle().getPaddingLeft() + this.getStyle().getPaddingRight());
		}


		BitmapFont font = getEffectiveFont(this.getStyle());
		float NativeToSceneRatio = getNativeToSceneResizeRatio(this.getStyle(), font);

		Log.info("_________regenerating texture; labelsSizeMode:"+labelsSizeMode+" (width="+effectiveMaxWidth+")");

		int startFromX =0;
		int startFromY =0;

		if (addToExisting!=null){
			startFromX =(int) super.Cursor.x;
			startFromY =(int) super.Cursor.y;
			Log.info("Cursor is currently at: "+startFromX+","+startFromY);
		}


		TextureAndCursorObject textureAndData = generateTexture(
				labelsSizeMode, 
				text, //contents
				interpretBRasNewLine,
				interpretBackslashNasNewLine,
				NativeToSceneRatio,
				effectiveMaxWidth,//-1 is the default max width which means "any size"
				align,
				this.getStyle(),
				font,
				startFromX,
				startFromY,
				addToExisting); 

		Material ourMaterial = getTextMaterial();// this.getMaterial(LABEL_MATERIAL);	

		Texture newTexture = textureAndData.textureItself;

		//dispose of previous texture 
		//((TextureAttribute)infoBoxsMaterial.get(TextureAttribute.Diffuse)).textureDescription.texture.dispose();
		//

		//infoBoxsMaterial.set(TextureAttribute.createDiffuse(newTexture));


		GwtishWidgetShaderAttribute textStyleData = (GwtishWidgetShaderAttribute)ourMaterial.get(GwtishWidgetShaderAttribute.ID);

		//dispose of previous texture if there was one
		if (textStyleData!=null && textStyleData.distanceFieldTextureMap!=null){
			textStyleData.distanceFieldTextureMap.dispose();
		}

		textStyleData.distanceFieldTextureMap = newTexture;
		//


		//if (textStyle==null){
		//textStyle = new DistanceFieldShader.DistanceFieldAttribute(DistanceFieldAttribute.presetTextStyle.whiteWithShadow);

		//ColorAttribute ColorAttributestyle = ((ColorAttribute)infoBoxsMaterial.get(ColorAttribute.Diffuse));	
		//  TextureAttribute.createDiffuse(NewTexture.textureItself)	,	
		// ColorAttribute.createDiffuse(defaultBackColour)


		float textureSizeX = textureAndData.textureItself.getWidth();
		float textureSizeY = textureAndData.textureItself.getHeight();

		if (textureSizeX>10000){
			Log.severe("Texture SizeX Over 10,000! Consider spliting label");
		}
		if (textureSizeY>10000){
			Log.severe("Texture SizeY Over 10,000! Consider spliting label");
		}

		//update stats on our texture size
		super.updateData(new Vector2(textureSizeX,textureSizeY), textureAndData.Cursor,textureAndData.rawPixelData,textureAndData.newline_indexs); //TODO: cursor position should always be set to the next position to type. Not sure textureAndData returns this yet
		//---------------------


		//new widget size (without padding, as the  setSizeAs adds it itself)
		float x = textureSizeX * (1.0f/NativeToSceneRatio);
		float y = textureSizeY * (1.0f/NativeToSceneRatio);


		Log.info("_________setting text to;"+text+" texturesize:"+textureSizeX+","+textureSizeY);
		Log.info("_________NativeToSceneRatio;"+(1.0f/NativeToSceneRatio));

		//boolean autoPadToPreserveRatio = true;
		Log.info("_________setting text to;"+text+" size:"+x+","+y);

		switch (labelsSizeMode) {
		case ExpandHeightMaxWidth:
			this.setSizeAs(x, y); //width should be locked thanks to generateTexture wrapping, but we could insert a test here to be sure? Or only set Y?
			break;
		case ExpandXYToFit:
			this.setSizeAs(x, y); 
			break;
		case Fixed:		
			Log.info("_________(fixed mode, so size doesnt change)");
			//real size should only set if not on fixed size mode. However, we do want to effect the padding as the real widget ratio might not match the text texture, so we need to pad the widget to compensate
			//setPaddingToPreserveTextRatio(align, maxWidth, maxHeight, x, y);

			break;
		}


		//ensure the text scale in the shader is correct
		//this effectively "fills" the mesh with the text and a surrounding border of padding
		calculateCorrectShaderTextScale(NativeToSceneRatio); 

	}

	/*
	//now handled in shader
	private void setPaddingToPreserveTextRatio(TextAlign align, float maxWidth , float maxHeight, float textureSizeX, float textureSizeY) {

		boolean autoPadToPreserveRatio = true;

		if (autoPadToPreserveRatio){

			Log.info("____(using padding to correct aspect ratio of text. Raw texture size is:"+textureSizeX+","+textureSizeY+")__");
			Log.info("____(using padding to correct aspect ratio of text. fixed size is:"+maxWidth+","+maxHeight+")__");

			//we need to work out which dimension needs to be scaled down more to fit 
			float diffX = maxWidth  - textureSizeX;
			float diffY = maxHeight - textureSizeY;

			//ie
			//200 - 50
			//50 - 40gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggcdddddddddddddddddddddddddddddddddddxggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg < - THIS line contributed by a visiting cat
			//+150,+10
			float newX =0;
			float newY =0;
			boolean textureSmallerInX = false;
			boolean textureSmallerInY = false;

			if (diffX>0){
				//texture size is smaller then width in X
				textureSmallerInX = true;
			}
			if (diffY>0){
				//texture size is smaller then width in X
				textureSmallerInY = true;
			}

			//if they are both smaller
			if (textureSmallerInX && textureSmallerInY){
				Log.info("____(both dimensions are smaller)__");
				//find the smaller difference and set that equal to the limit
				if (diffX<diffY){
					float textureSizeRatio = textureSizeY/textureSizeX;
					Log.info("______y needs more padding, ratio to x is"+textureSizeRatio);
					 newX = maxWidth;
					 newY = textureSizeY*textureSizeRatio;
				} else {
					float textureSizeRatio = textureSizeX/textureSizeY;
					Log.info("______x needs more padding, ratio to y is"+textureSizeRatio);
					 newX = textureSizeX*textureSizeRatio;
					 newY = maxHeight;
				}
			}


			//which is the bigger difference?
			/**
			if (diffX>diffY){
				//x needs more shrinking
				float textureSizeRatio = textureSizeY/textureSizeX;
				Log.info("______x needs more shrinking, ratio to y is"+textureSizeRatio);
				 newX = maxWidth;
				 newY = textureSizeY*textureSizeRatio;

			} else {
				//y needs more				
				float textureSizeRatio = textureSizeX/textureSizeY;
				Log.info("______y needs more shrinking, ratio to x is"+textureSizeRatio);
				 newX = textureSizeX*textureSizeRatio;
				 newY = maxHeight;
			}/

			float paddingX = maxWidth  - newX;
			float paddingY = maxHeight - newY;


			Log.info("______"+this.contents+"____paddingX="+paddingX+" paddingY="+paddingY);

			//this becomes the padding, and its applied based on alignment
			if (align == TextAlign.CENTER){

				Log.info("__________setting padding both sides="+(paddingX/2));
				this.getStyle().setPaddingLeft(paddingX/2);
				this.getStyle().setPaddingRight(paddingX/2);
			}
			if (align == TextAlign.LEFT){

				Log.info("__________padding on right="+paddingX);
				this.getStyle().setPaddingRight(paddingX);
			}
			if (align == TextAlign.RIGHT){                             
				this.getStyle().setPaddingLeft(paddingX);
			}                                                                                  



		}
	}
	 */



	/**
	 * 
	 * @param labelsSizeMode
	 * @param contents
	 * @param NativeToSceneRatio
	 * @param effectiveMaxWidth - max width of the texts texture (will wrap to this)
	 * @param align
	 * @param style
	 * @param font
	 * @return
	 */
	static private TextureAndCursorObject generateTexture(
			SizeMode labelsSizeMode,			
			String contents, 
			boolean interpretBRasNewLine,
			boolean interpretNLasNewLine,
			float NativeToSceneRatio,
			float effectiveMaxWidth,
			TextAlign align, 
			Style style,
			BitmapFont font,
			int startFromX,
			int startFromY,
			Pixmap addToThis
			) {


		TextureAndCursorObject NewTexture = null;

		//if empty we use a quick function
		if (contents.isEmpty()){
			NewTexture  = generateEmptyTexture();
			return NewTexture;

		}

		switch (labelsSizeMode) {
		case ExpandHeightMaxWidth:
			NewTexture = generatePixmapForShader(contents,interpretBRasNewLine,interpretNLasNewLine,NativeToSceneRatio,effectiveMaxWidth,align,style,font,startFromX,startFromY,addToThis); //-1 = no max width
			break;
		case Fixed:			
			//Note; the textures internal size is not related to the widgets size directly, but it needs to know
			//the final width/height ratio in order to pad the Pixmap enough to preserve its ratio.
			NewTexture = generatePixmapForShader(contents,interpretBRasNewLine,interpretNLasNewLine,NativeToSceneRatio,-1,align,style,font,startFromX,startFromY,addToThis); //-1 = no max width
			break;
			//expand to fit is also the default
		case ExpandXYToFit:
		default:
			Log.info("______________generating expand to fit text ");
			NewTexture = generatePixmapForShader(contents,interpretBRasNewLine,interpretNLasNewLine,NativeToSceneRatio,-1,align,style,font,startFromX,startFromY,addToThis); //-1 = no max width
			break;

		}

		NewTexture.textureItself.setFilter(TextureFilter.Linear, TextureFilter.Linear);//ensure mipmaping is disabled, else distance field shaders wont work
		//NewTexture.textureItself.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);//ensure mipmaping is disabled, else distance field shaders wont work
		return NewTexture;
	}

	/**
	 * should be a more optimized way to do this with zero  length strings
	 * @return
	 */
	private static TextureAndCursorObject generateEmptyTexture() {

		Pixmap textPixmap = new Pixmap(1, 1, Format.RGBA8888);
		Texture textureData = new Texture(textPixmap);


		TextureAndCursorObject textureAndCursorObject = new TextureAndCursorObject(
				textureData,
				0,
				0,
				textPixmap,null);

		return textureAndCursorObject;
	}



	static public void firstTimeSetUp(){
		//setup font size cache		
		FontHandling.cacheFontSizes();


	}







	//
	//
	//--------------
	// Styling functions below.
	// These are all subject to a lot of change
	// Especially as we
	// Try to make it as GWT-like as possible in its api

	/**
	 * sets the back color
	 * @param labelBackColor
	 */
	public void setLabelBackColor(Color labelBackColor) {
		//	labelBackColor = Color.PINK; //TEMP during testing. Currently another shader bug - the background colour isn't being used correctly for the transparancy, its only effecting the shadows blending
		//Material infoBoxsMaterial = this.getMaterial(LABEL_MATERIAL);		
		//ColorAttribute ColorAttributestyle = ((ColorAttribute)infoBoxsMaterial.get(ColorAttribute.Diffuse));

		//infoBoxsMaterial.set( ColorAttribute.createDiffuse(labelBackColor));


		super.getStyle().setBackgroundColor(labelBackColor);

	}

	/**
	 *   Gets this object's text.
	 * @return
	 */
	public String getText() {		
		return this.contents;
	}


	public Material getTextMaterial(){
		return this.getMaterial(LABEL_MATERIAL);
	}

	public Material getMaterial(){
		return this.getMaterial(LABEL_MATERIAL);
	}

	@Override
	public void setOpacity(float opacity){


		super.setOpacity(opacity);


	}

	public void setMaxWidth(float maxWidth) {
		this.maxWidth = maxWidth;
		labelsSizeMode = SizeMode.ExpandHeightMaxWidth;
		layoutStyleChanged();
	}

	//regenerates the texture if the style layout is changed (ie, text alignment or padding)
	@Override
	public void layoutStyleChanged() {
		super.layoutStyleChanged();

		//If the padding has changed and we are on fixed width mode, we need to regenerate
		//the texture to ensure its still contained within the widget

		///if (this.getStyle().getTextAlignment() != lastUsedTextAlignment){
		regenerateTexture(contents,null);

		//}

		//work out a appropriate text scale for the shader so it fits
		//calculateCorrectShaderTextScale();


		//the shader takes care of text positioning, but not sizing, so we need to recalculate sizes based on mode.
		/*
		float newTotalWidth  = -1;
		float newTotalHeight = -1;	
		float newTextWidth  = -1;
		float newTextHeight = -1;	


		//different behavior based on sizemode
		switch (this.labelsSizeMode){
		case ExpandHeightMaxWidth:


			break;
		case ExpandXYToFit:


			break;
		case Fixed:
			//same totals as before
			newTotalWidth  = maxWidth;
			newTotalHeight = maxHeight;

			//new text size is the total size, minus all the padding		
			newTextWidth  = newTotalWidth  - (getStyle().getPaddingLeft()+getStyle().getPaddingRight());
			newTextHeight =	newTotalHeight - (getStyle().getPaddingTop()+getStyle().getPaddingBottom());

			//regenerate texture
			regenerateTexture(contents);

			break;
		default:
			break;

		}
		/**
		 * For fixed size labels;

Size is still w/h
Label size is (w-(left+right), h-(top+bottom)

For dynamic sized labels

Label size is  w+(leftpadding+rightpadding), h+(top+bottom)
Text size remains just h/w, however


		 */

		//		Log.info(" size now::"+this.getWidth()+","+this.getHeight());


	}
	/**
	 * work out a appropriate text scale for the shader so it fits
	 * This is most important for fixedSize mode, where the text scales to the widget
	 * 		
	 * @param nativeToSceneRatio - scales the text on the shader down or up to match requested font size (ie, 0.5 = half size)
	 */
	private void calculateCorrectShaderTextScale(float nativeToSceneRatio) {
		float textScale =1;
		if (labelsSizeMode==SizeMode.Fixed){			
			//fixed works differently, as its based on widget size, not font size			
			//the smaller ratio  - either the width or height
			float effectiveMaxWidth = this.maxWidth - (this.getStyle().getPaddingLeft()+this.getStyle().getPaddingRight());			 
			float effectiveMaxHeight = this.maxHeight- (this.getStyle().getPaddingBottom()+this.getStyle().getPaddingTop());

			textScale = Math.min(
					effectiveMaxWidth / (textureSize.x),
					effectiveMaxHeight / (textureSize.y)
					); 		

		} else {			
			textScale =  (1.0f/nativeToSceneRatio);			
		}

		this.getStyle().setTextScale(textScale);
		/*

		float widgetWidth  = this.getWidth(); //returns size with padding
		float widgetHeight = this.getHeight();

		Log.info("_________setting shader to textScale based on real size ;"+widgetWidth+","+widgetHeight);
		Log.info("_________setting shader to textScale based on texture size ;"+textureSize.x+","+textureSize.y);

		float totalPaddingWidth =  (getStyle().getPaddingLeft()+getStyle().getPaddingRight());
		if (totalPaddingWidth>widgetWidth){
			totalPaddingWidth=widgetWidth;
		}
		float totalPaddingHeight =  (getStyle().getPaddingTop()+getStyle().getPaddingBottom());
		if (totalPaddingHeight>widgetHeight){
			totalPaddingHeight=widgetHeight;
		}

		//now get the widget size without padding
		float widgetWidthWithoutPadding  = widgetWidth-totalPaddingWidth;		
		float widgetHeightWithoutPadding = widgetHeight-totalPaddingHeight;
		//---

		//the smaller ratio  - either the width or height
		float textScale = Math.min(
									widgetWidthWithoutPadding / (textureSize.x),
				                    widgetHeightWithoutPadding/ (textureSize.y)
				                   ); 

		Log.info("_________setting shader to textScale;"+textScale);

		this.getStyle().setTextScale(textScale);*/

	}



	/**
	 * disposes of textures and pixmaps used to make this label
	 */
	public void dispose(){
		super.dispose();
		super.currentPixmap.dispose();

		Material material = this.getMaterial(LABEL_MATERIAL);	
		GwtishWidgetShaderAttribute textStyleData = (GwtishWidgetShaderAttribute)material.get(GwtishWidgetShaderAttribute.ID);
		//dispose of previous texture 
		textStyleData.distanceFieldTextureMap.dispose();

		//	((TextureAttribute)material.get(TextureAttribute.Diffuse)).textureDescription.texture.dispose();

	}


	/**
	 *  br or nl
	 */
	boolean containsNewlines() {

		String labtext = this.getText();
		boolean countbr = this.isInterpretBRasNewLine();

		return containsNewlines(labtext,countbr);

	}

	static boolean containsNewlines(String labtext,boolean countbr) {

		boolean hasNewlines = true;

		if (countbr){
			//if it contains no nlss && no brs
			if (!labtext.contains("\n") && !labtext.contains("<br>"))
			{
				Log.info("no nextnl or br ");
				hasNewlines = false;
			}			
		} else {
			//if it contains no nlss 
			if (!labtext.contains("\n") )
			{
				Log.info("no nextnl ");
				hasNewlines = false;
			}
		}
		return hasNewlines;
	}

	/**
	 * Returns the index of the last newline.<br>
	 * Or , to be exact, the last bundles <br>
	 * <br>
	 * <br>
	 * A newline can be originally caused  by a \n , a {@literal<br>} , or auto-wrapping<br>
	 * <br>
	 * @return
	 */
	public int getLastNewLineLocation(){
		
		if (newline_indexs.size()<2){
			return -1; //There was no newlines
		}
		
		//last element of array is the length
		int internalLength = newline_indexs.get(newline_indexs.size()-1); //internal text length (not same as this.contents see below for reasons)
	
		
		Integer lastBundleIndex = newline_indexs.get(newline_indexs.size()-2); //Location of last bundle, HOWEVER:
		//The index is currently likely not correct, and we have to do a trick to fix it.
		int lastBundleIndex_fromEnd = internalLength-lastBundleIndex ;
//		Why the end? glade you asked..
//		This is because the character count internally is bassed of a string where {@literal <br>'}s have been replaced by \n
//		Therefor the indexs dont match the ones from the original string you set, or those from "getText()"
//		As a work-around we thus count from the end of the string. As we are looking for the very last newline, no others could have come
//		in-between, and thus no other <br>s swapped for \ns. There for the distance from the strings end is the same in each.
//		
		//We can now convert back using the original string length. (contents is what the user specified, and getText() returns)
		lastBundleIndex = this.contents.length() -  lastBundleIndex_fromEnd;
				
		return lastBundleIndex;		
	}
	
	
	
	
	public int getFirstNewLineLocation(){
		if (newline_indexs.size()<2){
			return -1; //There was no newlines (the last element iin array is always there even if there is no newlines)
		}
		
		Integer nextBundleIndex = newline_indexs.get(0); //works only as its the first newline. See getLastNewLineLocation() for why others are more complex
		return nextBundleIndex;		
	}

	/**
	 * actually, currently bundle locations
	 * @return
	 */
	public ArrayList<Integer> getNewlineLocations(){
		return super.newline_indexs;
	}
	
	
} public class VerticalPanel extends CellPanel {

	final static String logstag = "GWTish.VerticalPanel";
	public static Logger Log = Logger.getLogger(logstag); //not we are using this rather then gdxs to allow level control per tag
	
	// current stats
	float currentTotalWidgetHeight = 0f;

	HorizontalAlignment DefaultAlignmentinCell = HorizontalAlignment.Center;

	/**
	 * Creates a background and lets you position widgets vertical within it
	 * 
	 */
	public VerticalPanel() {

		super(10, 10); // default size and background
		super.setZIndex(15, Widget.generateUniqueGroupID("VerticalPanel"));
		

	}

	Vector3 getNextPosition(float incomingWidth, float incomingHeight,
			 Widget widget) { //boolean updateHeight,

		int index = contents.indexOf(widget);

		Alignment align = contentAlignments.get(widget);
		if (align == null) {
			align = new Alignment(defaultHorizontalAlignment,
					VerticalAlignment.Middle);
			contentAlignments.put(widget, align);
		}

		float newLocationX = 0;

		// note; maxW could be worked out after the largestWidthOfStoredWidgets is.
		// its wasteful to work it out each time here
		float maxW = (largestWidthOfStoredWidgets);
		// or minimum size if smaller
		if (maxW < this.MinSizX) {
			maxW = this.MinSizX;
		}
		// -----------------------

		switch (align.horizontal) {
		case Left:
			newLocationX = getLeftPadding();//0;
			break;
		case Right:
			newLocationX = (maxW - incomingWidth) - getRightPadding();
			break;
			// default and center are the same
		case Center:
		default:
			float total = maxW + getLeftPadding() + getRightPadding();
			
		//	newLocationX = (maxW - incomingWidth) / 2;
			newLocationX = getLeftPadding() +((total - incomingWidth) / 2);

		}

		float newLocationY = currentTotalWidgetHeight; // under the last widget

	//	if (updateHeight) {
			currentTotalWidgetHeight = currentTotalWidgetHeight
					+ incomingHeight + spaceing; // should spacing be scaled?
	//	}

		Log.info( index + " adding incomingHeight: "
				+ incomingHeight + " total=" + currentTotalWidgetHeight);

		float zdisplace = 0f; //3f
		
		return new Vector3(newLocationX, 
				-(getTopPadding()	+ newLocationY), //messureing from top left, hence the negative
				zdisplace);

		
		//return new Vector3(getLeftPadding() + newLocationX, 
		//		getTopPadding()	+ newLocationY, 3f);

	}

	
	/**
	 * Refreshes the position of all widgets recalculateLargestWidgets(); should
	 * be run first
	 */
	public void repositionWidgets() { //todo:should be protected, only public for testing
		Log.info( "Reposition " + contents.size() + " widgets in vp ");
		// simply clear and re-add them all

		// reset stats
		currentTotalWidgetHeight = 0f;
		// largestWidthOfStoredWidgets = 0f;
		// largestHeightOfStoredWidgets = 0f;

		for (Widget widget : contents) {
			// super.removeAttachment(widget); //remove
			internalAdd(widget); // re add only when needed

		}

		Log.info( "new size:" + largestWidthOfStoredWidgets + ","
				+ currentTotalWidgetHeight);

	}

	private HorizontalAlignment defaultHorizontalAlignment = HorizontalAlignment.Center;

	/**
	 * Sets the default horizontal alignment to be used for widgets added to this
	 * panel. It only applies to widgets added after this property is set.
	 * 
	 **/
	public void setHorizontalAlignment(HorizontalAlignment align) {
		defaultHorizontalAlignment = align;
	}


	@Override
	public void sizeToFitContents() { //todo: remove public
		
		setSizeAs(getLeftPadding() + largestWidthOfStoredWidgets + getRightPadding(),getBottomPadding() + currentTotalWidgetHeight + getTopPadding());
		
	}

} public class AnimatableModelInstance extends ModelInstance implements IsAnimatableModelInstance, hitable {
	final static String logstag = "ME.AnimatableModelInstance";

	//Use this instead of the models matrix
	public final PosRotScale transState = new PosRotScale();

	//This is only here to mask the superclasss one. (or at least help prevent it from accidently being used, as it still can with a cast)
	//If this is used in any way there is a problem with the code!
	//check for the yellow squiggle under it in eclipse, if its missing theres likely a problem!
	private Matrix4 transform = new Matrix4();

	/** a temp variable used to remember if this should be drawn on the background or foreground. 
	 * This is used to help hide/show objects remembering their place **/
	RenderOrder currentRenderPlacement; //default

	/** list of things attached to this object. These things will all move and rotate with it **/
	HashMap<IsAnimatableModelInstance,PosRotScale> attachlist = new HashMap<IsAnimatableModelInstance,PosRotScale>();

	/** What THIS object is attached too, if anything **/
	private IsAnimatableModelInstance parentObject = null;




	//how the parent object (if any) effects this one;
	/** Determines if the position is inherited **/
	//in future we can have x/y/z separate for more advanced behaviors
	boolean inheritedPosition = true;
	/** Determines if the rotation is inherited **/
	//in future we can have x/y/z separate for more advanced behaviors
	boolean inheritedRotation = true;
	/** Determines if the scale is inherited **/
	boolean inheritedScale = true;

	/**
	 * The local bounding box is the boundary of this object, not counting anything attached to it.
	 * If its bull, it needs to be created again which any call like getWidth() will do automatically.
	 */
	private BoundingBox localBoundingBox;

	/**
	 * The collision box is the bounding box multiplied by its current transform.
	 * So, effectively, its the real boundary's the object currently has in the co-ordinate system of
	 * where its positioned.
	 * The collisionBox is updated every time its moved assuming its ever been requested.
	 * collisionBox.mul(super.getMatrixTransform());
	 **/
	private BoundingBox collisionBox;

	/**
	 * Determines if we inherit visibility from parent.
	 * NOTE: If inheriting both the parents visibility AND the local visibility have to be set to true for this object to render
	 * @param model
	 */
	public boolean inheritVisibility = true;

	/**
	 * Determines if we should render this icon or not.
	 * 
	 * NOTE: If inheriting, both the parents visibility AND the local visibility have to be set to true for this object to render
	 * Please use "isVisible()" to check for effective visibility
	 * @param model
	 */	
	public boolean localVisibility = true;


	/**
	 * If this object should be added to the hitable list
	 */
	private boolean Hitable = false;

	/** Necessary as part of hit detection **/
	private float lastHitDistance; 

	// this is just an example constructor, make sure to implement the constructor you need
	public AnimatableModelInstance (Model model) {
		super(model);
	}

	//Method used to update the transform
	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setTransform(com.lostagain.nl.me.newmovements.PosRotScale)
	 */
	@Override
	public void setTransform ( PosRotScale newState) {

		transState.position.set(newState.position);
		transState.rotation.set(newState.rotation);
		transState.scale.set(newState.scale);

		sycnTransform();
	}

	//Method used to update the transform from a parent
	//Works exactly like setTransform, but firsts tests if a particular type of transform should be inherited
	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#inheritTransform(com.lostagain.nl.me.newmovements.PosRotScale)
	 */
	@Override
	public void inheritTransform ( PosRotScale newState) {

		if (inheritedPosition){
			transState.position.set(newState.position);
		}
		if (inheritedRotation){
			transState.rotation.set(newState.rotation);
		}
		if (inheritedScale){

			//transState.scale.set(newState.scale);
			setToScale(newState.scale,false);


		}

		sycnTransform();
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#sycnTransform()
	 */
	@Override
	public void sycnTransform() {
		super.transform.set(transState.position, transState.rotation, transState.scale);

		//now we check if there's a collision box to update
		if (collisionBox!=null){
			recalculateCollisionBox();
		}

		//now update all attached objects too;
		updateAllAttachedObjects();
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setToPosition(com.badlogic.gdx.math.Vector3)
	 */
	@Override
	public void setToPosition(Vector3 vector3) {		
		transState.position.set(vector3);
		sycnTransform();
	}
	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setToRotation(com.badlogic.gdx.math.Quaternion)
	 */
	@Override
	public void setToRotation(Quaternion angle) {		
		transState.rotation.set(angle);
		sycnTransform();
	}

	/**
	 * Sets the transform of this meshobject to a certain scale
	 * It will also scale all things attached to this, if they have been set to inherit the scale, 
	 * as well as scaling their relative displacement so they remain attached to the same place
	 *  
	 **/
	@Override
	public void setToScale(Vector3 scale) {	
		setToScale(scale,true);
	}

	//we have a separate method with the option to not sycn
	//this is so internal methods like inheritTransform can call setToScale without wastefully sycning
	//when they are about to do that anyway.
	private void setToScale(Vector3 scale,boolean sycn) {		

		transState.scale.set(scale);

		//if we have had our scale change we need to also scale our attachment points position
		//this is so they stayed pinned to the same place
		//for (AnimatableModelInstance object : attachlist.keySet()) {

		//	PosRotScale displacement = attachlist.get(object);
		//	displacement.position.scl(scale);
		//	updateAtachment(object, displacement);

		//}
		if (sycn){
			sycnTransform();
		}
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getMatrixTransform()
	 */
	@Override
	public Matrix4 getMatrixTransform() {		
		return super.transform;
	}

	public void hide(){	
		hide(true);
	}	


	public void hide(boolean setlocalVisibility){		
		currentRenderPlacement = GWTishModelManagement.removeModel(this);	

		if (setlocalVisibility){
			localVisibility = false;
		}

		//ensure its not on the hitable list
		GWTishModelManagement.removeHitable(this);

		//we also hide things positioned relatively to this. Nothing overrides this
		for (IsAnimatableModelInstance object : attachlist.keySet()) {
			if (object.isInheriteingVisibility()){
				object.hide(false);
			}
		}
	}

	public void show(){	
		show(true);
	}


	public void show(boolean setlocalVisibility){		

		//if we are not inheritVisibility, or our parent is visible
		if (!inheritVisibility
				|| (getParentObject()!=null && this.getParentObject().isVisible())){

			GWTishModelManagement.addmodel(this,currentRenderPlacement);

			if (Hitable){
				GWTishModelManagement.addHitable(this);
			}


		}


		if (setlocalVisibility){
			localVisibility = true;
		}

		//we also show things positioned relatively to this unless they have visible false set
		for (IsAnimatableModelInstance object : attachlist.keySet()) {
			if (object.isInheriteingVisibility()  && object.isVisible() ){
				object.show(false);
			}
		}
	}


	/**
	 * returns scaled width
	 */
	@Override
	public float getScaledWidth(){		
		return this.getWidth()*this.transState.scale.x;
	}

	/**
	 * returns scaled height
	 */
	@Override
	public float getScaledHeight(){		
		return this.getHeight()*this.transState.scale.y;
	}
	/**
	 * returns unscaled total width, based on a bounding box
	 */
	@Override
	public float getWidth(){
		if (localBoundingBox==null){
			createBoundBox();
		}
		return localBoundingBox.getWidth();
	}
	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getHeight()
	 */
	/**
	 * returns unscaled total height, based on a bounding box
	 */
	@Override
	public float getHeight(){
		if (localBoundingBox==null){
			createBoundBox();
		}
		return localBoundingBox.getHeight();
	}

	/**
	 * the position of the pivot relative to the bounding box center
	 * @return
	 */
	public Vector3 getPivotsDisplacementFromCenterOfBoundingBox(){

		Vector3 centerOnStage =  getCenterOnStage();
		Vector3 currentPos = this.getTransform().position;

		return centerOnStage.sub(currentPos);

	}


	/**
	 * = getCenterOfBoundingBox() * position matrix
	 * @return
	 */
	public Vector3 getCenterOnStage(){
		return getCenterOfBoundingBox().mul(getMatrixTransform());
	}

	/**
	 * Note; Gets the center position of the bounding box if it was scaled but not positioned, you need to multiply by the position to get the center on the stage
	 */
	public Vector3 getCenterOfBoundingBoxScaled(){
		return getCenterOfBoundingBox().scl(getTransform().scale);
	}

	/**
	 * Note; Gets the center position of the bounding box if it was unscaled, you need to multiply by the position to get the center on the stage
	 */
	@Override
	public Vector3 getCenterOfBoundingBox(){
		if (localBoundingBox==null){
			createBoundBox();
		}
		Vector3 center = new Vector3();
		return localBoundingBox.getCenter(center);
	}

	/**
	 * The bounding box of this object if it was not scaled
	 */
	private void createBoundBox() {

		localBoundingBox = new BoundingBox();

		super.calculateBoundingBox(localBoundingBox);

	}


	private void recalculateCollisionBox() {

		//the bounding box is a prerequisite
		if (localBoundingBox==null){
			createBoundBox();

		}
		//so is an existing collisionBox
		if (collisionBox==null){
			collisionBox = new BoundingBox();

		}
		//ok, now we know we have both we set one to the other
		collisionBox.set(localBoundingBox);

		//Then the collision box gets multiplied by our current position so its boundary's match the real space co-ordinates
		collisionBox.mul(getMatrixTransform());

		//Gdx.app.log(logstag,"collision box matrix="+getMatrixTransform());
		//Gdx.app.log(logstag,"collision box="       +collisionBox);
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getLocalCollisionBox()
	 */

	/**
	 * 
	 * @param onceOnly - indicate that you dont want the collision box to auto-update when this object is moved
	 * @return
	 */
	@Override
	public BoundingBox getLocalCollisionBox(boolean onceOnly) {

		if (collisionBox==null){
			recalculateCollisionBox();
		}
		BoundingBox collisionBoxTemp = collisionBox;

		if (onceOnly){
			collisionBox=null; //clear so we dont update again
		}

		return collisionBoxTemp;
	}

	@Override
	public BoundingBox getLocalCollisionBox() {
		return getLocalCollisionBox(false); 
		/*
		if (collisionBox==null){
			recalculateCollisionBox();
		}
		return collisionBox;*/
	}


	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getLocalBoundingBox()
	 */
	@Override
	public BoundingBox getLocalBoundingBox() {
		if (localBoundingBox==null){
			createBoundBox();
		}
		return localBoundingBox;
	}

	/**
	 * should not really need to be public only temp while testing things to ensure it isn't the bounding box being inaccurate
	 */
	public void wasResized(){
		if (localBoundingBox!=null){
			createBoundBox();
		}
		if (collisionBox!=null){
			recalculateCollisionBox();
		}

	}
	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#attachThis(com.lostagain.nl.me.newmovements.AnimatableModelInstance, com.lostagain.nl.me.newmovements.PosRotScale)
	 */
	@Override
	public void attachThis(IsAnimatableModelInstance objectToAttach, PosRotScale displacement){

		//	Gdx.app.log(logstag,"_____________________________________adding object "); 

		//add if not already there
		if (!attachlist.containsKey(objectToAttach))
		{
			attachlist.put(objectToAttach, displacement);

			//associate this as the parent object
			//objectToAttach.parentObject=this;
			objectToAttach.setParentObject(this);

			//give it a initial update
			updateAttachedObject(objectToAttach);

			//PosRotScale newposition = transState.copy().displaceBy(displacement); //attachlist.get(objectToAttach)
			//objectToAttach.inheritTransform(newposition);


		} else {
			Gdx.app.log(logstag,"_____________________________________already attached so repositioning to new displacement"); 
			this.updateAtachment(objectToAttach, displacement);

			//give it a initial update
			updateAttachedObject(objectToAttach);

			//PosRotScale newposition = transState.copy().displaceBy(displacement);
			//objectToAttach.inheritTransform(newposition);

		}

		//	Gdx.app.log(logstag,"_____________________________________total objects now: "+attachlist.size()); 

	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#removeAttachment(com.lostagain.nl.me.newmovements.AnimatableModelInstance)
	 */
	@Override
	public void removeAttachment(IsAnimatableModelInstance objectToRemove){

		if (attachlist.containsKey(objectToRemove))
		{
			attachlist.remove(objectToRemove);
			//remove this as the parent object
			//objectToRemove.parentObject=null;
			objectToRemove.setParentObject(null);

		}


	}

	private void updateAttachedObject(IsAnimatableModelInstance objectToUpdate){

		PosRotScale displacement = attachlist.get(objectToUpdate).copy();			
		displacement.position = displacement.position.scl(transState.scale); //displacement needs to be scaled			
		PosRotScale newposition = transState.copy().displaceBy(displacement);


		objectToUpdate.inheritTransform(newposition);
	}

	protected void updateAllAttachedObjects(){

		//Gdx.app.log(logstag,"_____________________________________updateAllAttachedObjects ="+attachlist.size()); 

		for (IsAnimatableModelInstance object : attachlist.keySet()) {


			updateAttachedObject(object);


		}

	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#updateAtachment(com.lostagain.nl.me.newmovements.AnimatableModelInstance, com.lostagain.nl.me.newmovements.PosRotScale)
	 */
	@Override
	public void updateAtachment(IsAnimatableModelInstance object,
			PosRotScale displacement) {

		attachlist.put(object, displacement);
		updateAttachedObject(object);


	}

	public PosRotScale getAttachmentsPoint(AnimatableModelInstance object){
		return attachlist.get(object);
	}






	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#lookAt(com.lostagain.nl.me.newmovements.AnimatableModelInstance)
	 */
	@Override
	public void lookAt(IsAnimatableModelInstance target){			
		Quaternion angle = getAngleTo(target);			
		setToRotation(angle);			
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#lookAt(com.lostagain.nl.me.newmovements.AnimatableModelInstance, com.badlogic.gdx.math.Vector3)
	 */
	@Override
	public void lookAt(IsAnimatableModelInstance target, Vector3 Axis){			
		Quaternion angle = getAngleTo(target,Axis);			
		setToRotation(angle);			
	}

	@Override
	public void lookAt(Vector3 target, Vector3 Axis){			
		Quaternion angle = getAngleTo(target,Axis);			
		setToRotation(angle);			
	}
	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getAngleTo(com.lostagain.nl.me.newmovements.AnimatableModelInstance)
	 */
	@Override
	public Quaternion getAngleTo(IsAnimatableModelInstance target) {
		return  getAngleTo(target, new Vector3(1,0,0));
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getAngleTo(com.lostagain.nl.me.newmovements.AnimatableModelInstance, com.badlogic.gdx.math.Vector3)
	 */
	@Override
	public Quaternion getAngleTo(IsAnimatableModelInstance target, Vector3 Axis) {
		return getAngleTo(target.getTransform().position, Axis);
		//	return getAngleTo(target.transState.position, Axis);
	}

	@Override
	public Quaternion getAngleTo(Vector3 target, Vector3 Axis) {

		Vector3 thisPoint   = this.transState.position.cpy();
		//Vector3 targetPoint = target.transState.position.cpy();
		Vector3 targetPoint = target.cpy();

		//get difference (which is the same as target relative to 0,0,0 if this point was 0,0,0)
		targetPoint.sub(thisPoint);			
		targetPoint.nor();

		//test if they are in the same the same place, if so just return default angle
		if (targetPoint.len() < 0.01f) 
		{
			return new Quaternion();
		}

		//else we use this difference and find its angle relative to the Axis
		//Vector3 xAxis = new Vector3(1,0,0);

		Quaternion result = new Quaternion();		

		result.setFromCross(Axis,targetPoint);


		return result;

	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#getAttachments()
	 */
	@Override
	public Set<IsAnimatableModelInstance> getAttachments() {

		return attachlist.keySet();
	}


	/**
	 * gets all attachments and child attachments
	 */
	@Override
	public Set<IsAnimatableModelInstance> getAllAttachments() {

		Set<IsAnimatableModelInstance> attachments = new HashSet();
		Set<IsAnimatableModelInstance> direct_children = new HashSet<IsAnimatableModelInstance>(attachlist.keySet());

		attachments.addAll(direct_children);

		for (IsAnimatableModelInstance childAttach : direct_children) {

			attachments.addAll(childAttach.getAllAttachments());

		}				


		return attachments;
	}



	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setInheritedPosition(boolean)
	 */
	@Override
	public void setInheritedPosition(boolean inheritedPosition) {
		this.inheritedPosition = inheritedPosition;
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setInheritedRotation(boolean)
	 */
	@Override
	public void setInheritedRotation(boolean inheritedRotation) {
		this.inheritedRotation = inheritedRotation;
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setInheritedScale(boolean)
	 */
	@Override
	public void setInheritedScale(boolean inheritedScale) {
		this.inheritedScale = inheritedScale;
	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#setInheritedVisibility(boolean)
	 */
	/**
	 * sets the visibility to be inherited from any parent object.
	 */
	@Override
	public void setInheritedVisibility(boolean inheritVisibility) {
		this.inheritVisibility = inheritVisibility;

		//update our visibility
		//if our local visibility is false we just ensure we are hidden, nothing else to change
		if (localVisibility==false){
			this.hide(false);


			return;
		} else {
			//if our local visibility is true then we base it on the parent setting
			if (getParentObject()!=null && this.getParentObject().isVisible()){
				this.show(false); //NOTE the false, this is used so we dont disturb the local visibility setting
			} else {
				this.hide(false);
			}


		}

	}

	/* (non-Javadoc)
	 * @see com.lostagain.nl.me.newmovements.IsAnimatableModelInstance#isInheriteingVisibility()
	 */
	@Override
	public boolean isInheriteingVisibility() {
		return inheritVisibility;
	}

	@Override
	public boolean isVisible() {

		//if local visibility is false, or we are not inheriting the visibility, then our localvisibility should match are visibility
		if (getParentObject()==null || localVisibility==false || !inheritVisibility ){
			return localVisibility;
		}

		///if we are inheriting and we are not hidden then our visibility should match our parents
		return getParentObject().isVisible();

	}

	/**
	 * If this is set to render in the overlay list
	 * @return
	 */
	public boolean isOverlay() {

		if (currentRenderPlacement == RenderOrder.OVERLAY){
			return true;
		} else {
			return false;
		}

	}

	/**
	 * Adds it to the hitable list. This is a list of things designed to be clicked on or shot at.
	 * ie. Fires events when a ray hits.
	 * You will need to override the public boolean rayHits(Ray ray) for your own logic to determine
	 * if a ray hits.
	 * Note; When a object is hidden it will automatically be removed from the hitables list.
	 *  
	 * @param hitable
	 */
	public void setAsHitable(boolean hitable){
		this.Hitable = hitable;

		if (Hitable){
			if (isVisible()){
				GWTishModelManagement.addHitable(this);
			}
		} else {
			GWTishModelManagement.removeHitable(this);
		}


	}

	@Override
	public PosRotScale getTransform() {
		return this.transState;
	}

	@Override
	public void fireTouchDown() {

	}

	@Override
	public void fireTouchUp() {

	}
	@Override
	public void fireClick() {

	}
	@Override
	public void fireDragStart() {

	}

	//The following two just keep track of where this hit was in the stack of hits for a given ray
	@Override
	public void setLastHitsRange(float range) {
		lastHitDistance = range;

	}

	@Override
	public float getLastHitsRange() {
		return lastHitDistance;
	}


	/**
	 * does this object block whats behind it?
	 * @return
	 */
	@Override
	public objectInteractionType getInteractionType() {
		return objectInteractionType.Normal;
	}

	/**
	 * Defaults to intersectRayBounds against bounding box, but you can override for more precision if needed.
	 * Note; You can also override to make this FASTER!
	 * If you dont need precise distances to work out which object is "in front" of other ones, you can override
	 * to use intersectRayBoundsFast instead, and just return a null for no hit, and your own values for the Vector3
	 * to set which is in front.
	 * For example, a 2d game could be optimised just to return the Z distance as its hit point.
	 * As the higher z values will always be "in front" on a 2d game.
	 */
	@Override
	public Vector3 rayHits(Ray ray) {
		//boolean hit = Intersector.intersectRayBoundsFast(ray, this.getLocalCollisionBox());
		//Gdx.app.log(logstag,"testing for hit on object:"+hit);


		//new more precise distance test
		Vector3 intersection = new Vector3();
		boolean hit = Intersector.intersectRayBounds(ray, this.getLocalCollisionBox(), intersection);
		//Gdx.app.log(logstag,"testing for hit on object:"+hit);
		if (hit){
			return intersection;
		}
		return null;
	}

	protected boolean isHitable() {

		return GWTishModelManagement.hitables.contains(this);

	}


	public boolean hasAttachment(AnimatableModelInstance object) {
		return attachlist.containsKey(object);
	}


	public void setAsOverlay(boolean status){

		if (status){
			currentRenderPlacement = RenderOrder.OVERLAY;
			GWTishModelManagement.setAsOverlay(this);			
		} else {
			currentRenderPlacement = RenderOrder.STANDARD;
			GWTishModelManagement.setAsStandard(this);			
		}

	}

	/**
	 * @return the parentObject
	 */
	public IsAnimatableModelInstance getParentObject() {
		return parentObject;
	}

	/**
	 * @param parentObject the parentObject to set, detaching from any existing ones first
	 */
	public void setParentObject(IsAnimatableModelInstance parentObject) {
		if (this.parentObject!=null){
			this.parentObject.removeAttachment(this);	
		}
		this.parentObject = parentObject;
	}


	/**
	 * Note; returns the displacement specification of the specified object from this one. NOT a copy of it.
	 * Changing the returned value will change the displacement
	 */
	public PosRotScale getAttachmentsPoint(IsAnimatableModelInstance object){
		return attachlist.get(object);
	}

	/**
	 * To help debugging you can optionally give objects a name
	 */
	@Override
	public String getName() {
		return "AnimatedModalInstance";
	}



} public class GWTishModelManagement {

	private static String logstag="ME.GWTishModelManagement";
	public static Logger Log = Logger.getLogger(logstag); //not we are using this rather then gdxs to allow level control per tag



	/** All the 3d models we want to render in the standard draw order should go into this list **/
	public static ObjectSet<ModelInstance> allStandardInstances = new ObjectSet<ModelInstance>();

	/** All the 3d models that appear INFRONT of the Standard ones.
	 * You can use this for special overlay objects - effects, interfaces, etc.
	 * Remember fine-grain controll within grouped objects should be dealt with the Zindex attribute, not this **/
	public static ObjectSet<ModelInstance> allOverlayInstances = new ObjectSet<ModelInstance>();


	public static ShaderProvider myshaderprovider = new GwtishDefaultShaderProvider();



	public static ModelBatch modelBatch;

	public static RenderableSorter mysorter;


	/**all hitable models **/
	public static ObjectSet<hitable> hitables = new ObjectSet<hitable>(); //should be changed to a set to stop duplicates

	/** everything the mouse is currently down over **/
	public static ObjectSet<hitable> mousedownOn = new ObjectSet<hitable>();

	/** Has a drag started? (that is, has the cursor moved after its been down, but not released?)**/
	static boolean dragStarted = false;


	/** All model with texture animations **/
	public static ObjectSet<Animating> animatingobjects = new ObjectSet<Animating>();

	/** All models currently moving **/
	public static ObjectSet<Moving> movingObjects = new ObjectSet<Moving>();


	static public enum RenderOrder {
		STANDARD,OVERLAY;//,zdecides; //zdecides not used
	}

	//test objects
	static AnimatableModelInstance lookAtTester;


	public static void addmodel(AnimatableModelInstance model) {	
		addmodel(model,RenderOrder.STANDARD);
	}

	/** 
	 * Adds the model to the render list.
	 * RenderOrder determines if its rendered in front or behind the spritestage.
	 * 
	 * You can also  it chooses if its a background or foreground object based on its Z position
	 * If Z is less then the stage Z 5 its behind
	 * If its more then 5its in front
	  If adding a AnimatableModelInstance we also check all its attachments are added too. **/
	public static void addmodel(AnimatableModelInstance model, GWTishModelManagement.RenderOrder order) {	

		addmodel((ModelInstance)model,order); //note we cast so as to call the non-AnimatableModelInstance specific method below

		for (IsAnimatableModelInstance attachedModel : model.getAttachments()) {	
			if (attachedModel.isInheriteingVisibility() && attachedModel.isVisible()){
				addmodel((AnimatableModelInstance)attachedModel,order); //we call this function so as to get objects attached to objects attached to this, etc
			}
		}

	}

	public static void addmodel(ModelInstance model) {	
		addmodel(model,RenderOrder.STANDARD);
	}
	/** Adds the model to the render list.
	 * RenderOrder determines if its rendered in front or behind the spritestage.
	 * 
	 * You can also  it chooses if its a background or foreground object based on its Z position
	 * If Z is less then the stage Z 5 its behind
	 * If its more then 5its in front**/
	public static void addmodel(ModelInstance model, RenderOrder order) {	

		//temp test putting it all in front of the stage while we test material based ordering
		//order = GWTishModelManagement.RenderOrder.OVERLAY;		


		//ignore if present already
		if (allStandardInstances.contains(model) || allOverlayInstances.contains(model)){
			Log.info("________model already on a render list");
			return;
		}
		Vector3 position = new Vector3();
		model.transform.getTranslation(position);
		float Z = position.z; //is this always correct?
		//float Z = model.transform.getValues()[Matrix4.M23];

		//	Gdx.app.log(logstag,"z = "+Z);

		if (order == RenderOrder.STANDARD ){
			allStandardInstances.add(model);
			return;
		}

		if (order == RenderOrder.OVERLAY){
			allOverlayInstances.add(model);
			return;
		}

		allStandardInstances.add(model); //temp till we remove zdecides

		//depending on if we are above/below the stage position we add it accordingly		
		//if (Z<5){
		//	allBackgroundInstances.add(model);
		//} else {
		//	allForgroundInstances.add(model);
		//}

	}

	/**
	 * removes the model from the render lists, and returns where it was in the render order (either forground or background)
	 * @param model
	 * @return 
	 */
	public static GWTishModelManagement.RenderOrder removeModel(ModelInstance model) {		
		Boolean wasInForground = allStandardInstances.remove(model);

		if (wasInForground){
			return GWTishModelManagement.RenderOrder.STANDARD;			
		}

		Boolean wasInBackground= allOverlayInstances.remove(model);

		if (wasInBackground){
			return GWTishModelManagement.RenderOrder.OVERLAY;			
		}

		return null;
	}


	/** the current state of mouse or touch **/
	public static GWTishModelManagement.TouchState currentTouchState = GWTishModelManagement.TouchState.NONE;

	public static Vector2 touchStartedAt = null;


	/**
	 * @return the lastHits
	 */
	public static ArrayList<hitable> getLastUnderCursor() {
		return underCursorList;
	}

	//--

	//	public static  GWTishModelManagement the3dscene = new GWTishModelManagement();

	private static ArrayList<hitable> lastHits = new ArrayList<hitable>();


	/**
	 * @return the lastHits
	 */
	public static ArrayList<hitable> getLastHits() {
		return lastHits;
	}



	/**
	 * tests the sort order of foreground objects
	 * @param deltatime
	 */
	//public void testSortOrder(float deltatime){

	//	modelBatch.getRenderableSorter().sort(MainExplorationView.camera,);


	//}


	public void updateAnimatedBacks(float deltatime){


		//replaced with noise shader !
		/*
		TextureRegion currentimage = testNoise.getKeyFrame(deltatime);

		for (ModelInstance instance : animatedbacks) {

			TextureAttribute attribute = instance.materials.get(0).get(TextureAttribute.class, TextureAttribute.Diffuse);

			if (attribute!=null){			
				attribute.set(currentimage );		
			} else {
				Gdx.app.log(logstag,"________************________________attribute is null:");
			}

		}*/


	}


	/**
	 * run setup() before using gwtish widgets
	 * by default the smartsort is turned on, and a internal shader provider is used
	 */
	static public void setup(){
		setup(true,null);
	}
	
	/**
	 * @param shaderprovider - use your own shaderprovider
	 * @param useSmartSorter - to support zindex set to true
	 */
	static public void setup(boolean useSmartSorter, ShaderProvider shaderprovider){

		// String vert = Gdx.files.internal("shaders/test.vertex.glsl").readString();//"shaders/distancefield.vert"
		// String frag = Gdx.files.internal("shaders/test.fragment.glsl").readString();

		//modelBatch = new ModelBatch(vert,frag);
		//	 MyShaderProvider myshaderprovider = new MyShaderProvider();

		if (useSmartSorter){
			mysorter = new MySorter();
		} else {
			mysorter = new DefaultRenderableSorter();
		}
		if (shaderprovider==null){
			shaderprovider=myshaderprovider;
		}
		modelBatch = new ModelBatch(shaderprovider,mysorter);

		//First we add one object at the center with a defaultshader used
		// Its VERY important to use a defaultshader object as the first thing created, else
		//the default shader will get confused and think it can render things with other shaders too.
		//This is because to figure out if it can render something it always compared to the first object it gets.

		//We also have to have transparency on the first shader we make else transparency wont be supported at all
		Material testmaterial = new Material(
				ColorAttribute.createDiffuse(Color.RED), 
				ColorAttribute.createSpecular(Color.WHITE),
				new BlendingAttribute(1f), 
				FloatAttribute.createShininess(16f));

		ModelBuilder modelBuilder = new ModelBuilder();
		//note; maybe these things could be pre-created and stored rather then a new one each time?
		Model model =  modelBuilder.createXYZCoordinates(25f, testmaterial, Usage.Position | Usage.Normal | Usage.TextureCoordinates);
		
		
		
		ModelInstance centermaker =  new ModelInstance(model); //ModelMaker.createCenterPoint(testmaterial);


		Renderable renderableWithoutAttribute = new Renderable();
		centermaker.getRenderable(renderableWithoutAttribute);

		//DefaultShader test = new DefaultShader(renderableWithoutAttribute);
/*
		Material beamShader = new Material(
				ColorAttribute.createDiffuse(Color.BLUE), 
				ColorAttribute.createSpecular(Color.WHITE),
				new BlendingAttribute(1f), 
				FloatAttribute.createShininess(16f),
				new ConceptBeamShader.ConceptBeamAttribute(0.4f,Color.BLUE,5.0f,Color.WHITE)
				);






		ModelInstance beamtest = ModelMaker.createRectangleAt(500, 1000, 30, 200, 200, Color.BLACK, beamShader); // new ModelInstance(model1); 
*/
		//	Renderable renderableWithAttribute = new Renderable();
		//	beamtest.getRenderable(renderableWithAttribute);

		//	Boolean defaultCanRender = test.canRender(renderableWithAttribute);


		//	Gdx.app.log(logstag,"default created with attribute = "+defaultCanRender);



		//--------------	

		//The following was a test of how the domains colour range should look. Re-enable during testing.

		/*
		Pixmap colourMapAsPixMap = MEDomain.getHomeDomain().getDomainsColourMap().getPixMap(200, 200);
		//Pixmap colourMapAsPixMap = MessyModelMaker.createNoiseImage(200, 200);


		Texture colmap = new Texture(colourMapAsPixMap);

		Material testmaterial3 = new Material
				(
						ColorAttribute.createSpecular(Color.WHITE),
						new BlendingAttribute(1f), 
						FloatAttribute.createShininess(16f),
						TextureAttribute.createDiffuse(colmap)
						);



		ModelInstance colortest = ModelMaker.createRectangleAt(0, 900, 130, 200, 200, Color.BLACK, testmaterial3); 
		 */


		//ModelManagment.addmodel(centermaker,RenderOrder.infrontStage);

/*

		if (GameMode.currentGameMode!=GameMode.Production){
			GWTishModelManagement.addmodel(beamtest,GWTishModelManagement.RenderOrder.OVERLAY);
			//	ModelManagment.addmodel(colortest,RenderOrder.infrontStage);

			addTestModels();
		}

*/







		//A lot of earlier code used for creating and debugging objects and shaders is below
		//While its not critical, please leave for now as its a good reference for cutting and pasting tests

		//NoiseAnimation testNoise = new NoiseAnimation();
		//Gdx.app.log(logstag,"creating testbounc");
		//testNoise.create();

		//FileHandle imageFileHandle3 = Gdx.files.internal("data/badlogic.jpg"); 

		//Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE0);
		// Texture blobtexture = new Texture(imageFileHandle3);
		//  blobtexture.bind(0);

		/*
	        Material testmaterial = new Material(
	        		ColorAttribute.createDiffuse(Color.BLUE), 
					ColorAttribute.createSpecular(Color.WHITE),
					new BlendingAttribute(1f), 
					FloatAttribute.createShininess(16f),new ConceptBeamShader.ConceptBeamAttribute(0.4f,Color.BLUE,Color.WHITE));

	       // testmaterial.set(TextureAttribute.createDiffuse(blobtexture));

	    	ModelInstance instance = ModelMaker.createRectangleAt(0, 0, 30, 200, 200, Color.BLACK, testmaterial); // new ModelInstance(model1); 
			Renderable renderableWithAttribute = new Renderable();
			instance.getRenderable(renderableWithAttribute);

	    	DefaultShader test = new DefaultShader(renderableWithAttribute);
	    	Boolean defaultCanRender = test.canRender(renderableWithAttribute);
	    	//If true this means a default shader created with a renderable with the custom attribute will by rendered by DefaultShader
	    	Gdx.app.log(logstag,"default created with attribute = "+defaultCanRender);


	    	ModelInstance instance2 = ModelMaker.createRectangleAt(0, 0, 30, 200, 200, Color.BLACK,null);
	    	Renderable renderableWithoutAttribute = new Renderable();
	    	instance2.getRenderable(renderableWithoutAttribute);

	    	DefaultShader test2 = new DefaultShader(renderableWithoutAttribute);
	    	Boolean defaultCanRender2 = test2.canRender(renderableWithAttribute); //now we test if the shader created without the attribute will render with one.
	    	//If true this means a default shader will think it can render 
	    	Gdx.app.log(logstag,"default created without attribute = "+defaultCanRender2);




			//Model  model1 = modelBuilder.createSphere(150, 150, 150, 20, 20,
			//		blob,Usage.Position | Usage.Normal | Usage.TextureCoordinates );

			//String alias = model1.meshes.get(0).getVertexAttribute(Usage.TextureCoordinates).alias;

		//	Model model1 = ModelMaker.createRectangleAt(0, 0, 30, 200, 200, Color.BLACK, blob);


			//Gdx.app.log(logstag,"aliasaliasaliasalias = "+alias);
	//

			//model2.meshes.get(0).getVertexAttribute(Usage.TextureCoordinates).alias = "a_texCoord";

			//  Model model3 = createRectangle(-10f,500f,10f,-500f,0f);


			//  ModelInstance model4 = createRectangleAt(50f,50f,10f,200f,0f);



			instance.userData = MyShaderProvider.shadertypes.conceptbeam;

			ModelManagment.addmodel(instance);

			//CameraOverlay = MessyModelMaker.addNoiseRectangle(0,0,300,300,true);
			//CameraOverlay.materials.get(0).set( new BlendingAttribute(true,GL20.GL_SRC_ALPHA, GL20.GL_ONE,0.0f));

			//CameraOverlay.userData =MyShaderProvider.shadertypes.noise; 
			//instance2.userData = MyShaderProvider.shadertypes.distancefield;
			//ModelManagment.addmodel(CameraOverlay);



		 */

		//for some reason transparency's dont work till we add something with a transparent texture for the first time

		/*
	    	Texture texture = new Texture(Gdx.files.internal("data/dfield.png"), false);
			texture.setFilter(TextureFilter.MipMapLinearNearest, TextureFilter.Linear);

			Model model2 = modelBuilder.createBox(220f, 220f, 15f, 
					new Material(TextureAttribute.createDiffuse(texture),new BlendingAttribute(0.6f)),
					Usage.Position | Usage.Normal | Usage.TextureCoordinates);
	        ModelInstance instance3 = new ModelInstance(model2);      

			ModelManagment.addmodel(instance3);
		 */

		//instance.transform.setToTranslation(200,500,10);

		//  environment = new Environment();
		//  environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
		// environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
	}

	public static void addTestModels() {

		Material blue = new Material
				(
						ColorAttribute.createSpecular(Color.WHITE),
						new BlendingAttribute(1f), 
						FloatAttribute.createShininess(16f),
						ColorAttribute.createDiffuse(Color.BLUE)
						);

		ModelBuilder modelBuilder = new ModelBuilder();

		Model lookAtTesterm =  modelBuilder.createXYZCoordinates(95f, blue, Usage.Position | Usage.Normal | Usage.TextureCoordinates);
		lookAtTester = new AnimatableModelInstance(lookAtTesterm);
		lookAtTester.setToPosition(new Vector3 (500,500,0));


		GWTishModelManagement.addmodel(lookAtTester,GWTishModelManagement.RenderOrder.OVERLAY);

	}


	/**
	 * This class stores hits between rays and objects.
	 * NOTE: The equals has been overriden so this can be directly compared with a object list.
	 * this means  a.equals(b) will be true even if a is a rayHit and b is a animatedObject.
	 * This is quite different to how equals normally behaves.
	 * 
	 * @author darkflame	 *
	 */
	static public class rayHit {

		hitable hitthis;
		Vector3 atThis;

		public rayHit(hitable hitthis, Vector3 atThis) {
			super();
			this.hitthis = hitthis;
			this.atThis = atThis;
		}
		/**
		 * NOTE: The equals has been overriden so this can be directly compared with a object list.
		 * this means  a.equals(b) will be true even if a is a rayHit and b is a animatedObject.
		 * This is quite different to how equals normally behaves.
		 */
		//@Override
		//public boolean equals(Object obj) {
		////	if (hitthis.equals(obj)){
		//		return true;
		//	}			
		//	return super.equals(obj);
		//}

	}
	/**
	 * what was in the line of the ray the last time getHitables was run
	 */
	static ArrayList<rayHit> underCursorHits = new ArrayList<rayHit>();

	/**
	 * what was in the line of the ray the last time getHitables was run
	 */
	static ArrayList<hitable> underCursorList = new ArrayList<hitable>();
	/** 
	 * Comparator to sort by distance
	 */
	static public class OrderByDistance implements Comparator<rayHit> {
		@Override
		public int compare(rayHit o1, rayHit o2) {

			//if either is overlay but not the other, put that on top
			if (o1.hitthis.isOverlay() && !o2.hitthis.isOverlay() ){
				return -1;
			}
			//if either is overlay but not the other, put that on top
			if (!o1.hitthis.isOverlay() && o2.hitthis.isOverlay() ){
				return 1;
			}	

			//if both are widgets then we compare zindexs if they are in the same group
			if (o1.hitthis instanceof Widget
					&& o2.hitthis instanceof Widget){

				Widget o1w = (Widget) o1.hitthis;
				Widget o2w = (Widget) o2.hitthis;
				// same group?
				if (o1w.getStyle().getZIndexGroup() == o2w.getStyle().getZIndexGroup()){
					int zin1 = o1w.getStyle().getZIndexValue();
					int zin2 = o2w.getStyle().getZIndexValue();
					return -(zin1-zin2);
				}

			}


			//---
			float hit1 = o1.hitthis.getLastHitsRange();
			float hit2 = o2.hitthis.getLastHitsRange();		

			return (int) (hit1 - hit2);
		}
	};

	/**  mouse state (still being implemented. Will replace newtouch and newup)
	 **/
	public static enum TouchState {
		/** screen is not touched or mouse is not down **/
		NONE,
		/**
		 * the mouse has just gone down or the screen has just been touced
		 */
		NewTouchDown,
		/**
		 * screen is being touched or mouse is down
		 */
		TouchDown,
		/**
		 * mouse or touch just went up
		 */
		NewTouchUp,

		/**
		 * The mouse has just moved a bit since being down  **/
		NewDrag,

		/**
		 * The mouse has moved a bit since being down and is still being held **/
		Dragging;

	}

	static OrderByDistance distanceSorter = new OrderByDistance();


	private static double ScenePixelScaleX=1;
	private static double ScenePixelScaleY=1;






	public static void setSceneScale(double currentSceneRatio, double currentSceneRatio2) 
	{
		ScenePixelScaleX = currentSceneRatio;
		ScenePixelScaleY = currentSceneRatio2;

	}

	/**
	 * note; the coordinates must be given unscaled (ie, real pixels of 1:1 viewport)
	 * If you wish Event.getCurrentEvent().getClientX/Y to return values scaled  to your current display
	 * Set your scene scaleing with setSceneScale(x,y). Values will then be multiplied by this  
	 *  
	 * @param x - unscaled screen x
	 * @param y - unscaled screen y
	 * @param camera
	 * @return
	 */
	public static ArrayList<hitable> getHitables(float x, float y, Camera camera) 
	{


		//generate current event object
		boolean altKeyWasPressed   = Gdx.input.isKeyPressed(Input.Keys.ALT_LEFT);
		boolean cntrKeyWasPressed  = Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT);
		boolean shiftKeyWasPressed = Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT);
		int currentEventX        = (int) x;
		int currentEventY        = (int) y;
		int currentEventKeyCode    = 0; //TODO: fill this in if possible?

		//The mouse button currently down
		NativeEvent.EventButtonType buttonTypeDown = NativeEvent.EventButtonType.None;	

		if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
			buttonTypeDown = NativeEvent.EventButtonType.Left;
		} else if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)){
			buttonTypeDown = NativeEvent.EventButtonType.Right;
		}  else if (Gdx.input.isButtonPressed(Input.Buttons.MIDDLE)){
			buttonTypeDown = NativeEvent.EventButtonType.Middle;
		}



		Event currentEvent = new Event(
				buttonTypeDown,
				altKeyWasPressed,  
				cntrKeyWasPressed,  
				shiftKeyWasPressed,
				(int)(currentEventX*ScenePixelScaleX),
				(int)(currentEventY*ScenePixelScaleY),  
				currentEventKeyCode);	


		//set it as the current event (this also stores the current last event as the previous event)
		Event.setCurrentEvent(currentEvent);


		Ray pickray = camera.getPickRay(x, y);

		TouchState currentTouchState = GWTishModelManagement.currentTouchState;
		ArrayList<hitable> hits = getHitables(pickray,false,currentTouchState); //penitates was previously on true. This seemed wrong so changed to false 

		//clear event
		Event.setCurrentEvent(null);
		lastHits=hits;

		return hits;
	}


	//TODO: make lower statement private in favor of above
	/**
	 * Gets all the hitables the current ray hits.
	 * If penetrate isn't turned on, nothing under the first blocker will be returned.
	 * We always stop at the first interface no mater what.
	 * 
	 * While not returned in order, the first of the array will be the one ontop.
	 * 
	 * @param ray
	 * @param hitsPenetrate
	 * @param processHits
	 * @return
	 */
	public static ArrayList<hitable> getHitables(Ray ray,boolean hitsPenetrate, GWTishModelManagement.TouchState applyTouchAction) {

		underCursorList.clear();
		underCursorHits.clear();

		//We ensure no touch events are canceled. This is only ever set to true during a touch/click event of some sort, when we want to cancel further actions
		cancelCurrentTouchEvent=false;
		//


		//Vector3 position = new Vector3();
		for (hitable newInstance : hitables) {

			//	position = newInstance.getCenterOnStage();

			//first check if it hits at all. We base this on the hitables internal tester
			//this lets different hitables use different intersect types (ie, radius, boundingbox, polygon etc)
			Vector3 hitPoint = newInstance.rayHits(ray);
			if (hitPoint==null){
				continue;
			}
			float dist2 = ray.origin.dst2(hitPoint);
			newInstance.setLastHitsRange(dist2);

			underCursorHits.add(new rayHit(newInstance,hitPoint));				
			underCursorList.add(newInstance);

		}


		//Gdx.app.log(logstag,"_underCursorList_ :"+underCursorList.toString());		

		//If anything is set to auto-hide and not currently under the cursor, then we hide it, provided this was some sort of click event
		if (applyTouchAction!=null && applyTouchAction!=TouchState.NONE){
			Iterator<IsAnimatableModelInstance> autoHideIt = autoHideList.iterator();
			while (autoHideIt.hasNext()) {
				IsAnimatableModelInstance isAnimatableModelInstance = (IsAnimatableModelInstance) autoHideIt.next();

				//	Gdx.app.log(logstag,"_autoHideTesting_ :"+isAnimatableModelInstance.getClass().getName());	

				if (!underCursorList.contains(isAnimatableModelInstance)) {
					Set<IsAnimatableModelInstance> attachments = isAnimatableModelInstance.getAllAttachments();

					//	Gdx.app.log(logstag,"attachments::::"+attachments .toString());	

					//unfortunately we also need to check for children of the autoHidingObject, as we might be clicking
					//something on the object (like a button) but not the object itself)					
					boolean containsNoneOf = Collections.disjoint(underCursorList, attachments);
					if (containsNoneOf){	
						isAnimatableModelInstance.hide();		
						autoHideIt.remove();
					}

				}
			}
		}

		//	Gdx.app.log(logstag,"underCursor:"+underCursor.size());

		//sort by distance
		Collections.sort(underCursorHits,distanceSorter);//todo: might need to take zindex into account 
		//	listUnderCursorToLog(underCursorHits);//helps debug


		ArrayList<hitable> onesHit = new ArrayList<hitable>();

		//crop to the ones on top, hitting as we go
		for (rayHit hit : underCursorHits) {

			//allow a chance to cancel
			if (cancelCurrentTouchEvent){	

				Log.info("canceling current touch event:"+applyTouchAction.name());				
				cancelCurrentTouchEvent = false;
				return onesHit;
			}

			//


			hitable object = hit.hitthis;

			objectInteractionType type = object.getInteractionType();
			onesHit.add(object);

			if (type == objectInteractionType.None){
				//no interactions at all on this object so we just continue to next under mouse
				//(will still be on the onesHit list)
				continue;
			}

			//update the Event data for this specific hit (if hits penetrate each hit might have a different position)
			Event.getCurrentEvent().setCurrentEventLocation(hit.atThis);
			//(no need to make a new event as the rest of the properties will be the same)


			//fire the correct event depending on type
			if (applyTouchAction!=null){
				switch (applyTouchAction) {
				case NONE:
					break;
				case NewTouchDown:
					Log.info("_firing touchdown on :"+object.getClass());
					object.fireTouchDown();
					mousedownOn.add(object);
					break;
				case NewTouchUp:

					Log.info("_firing touchup on :"+object.getClass());
					object.fireTouchUp();					
					boolean wasPreviouslyDownOn = mousedownOn.remove(object);
					if (wasPreviouslyDownOn){
						Log.info("_firing click on :"+object.getClass());
						object.fireClick();
					}
					break;
				case TouchDown:

					break;
				case NewDrag:
					object.fireDragStart();					
					mousedownOn.remove(object);


					break;
				}
			}



			if (type == objectInteractionType.Interface){
				return onesHit;
			}
			if (type == objectInteractionType.Blocker && !hitsPenetrate){

				//	Gdx.app.log(logstag,"_hit blocker :"+object.getClass()+" totalunder cursor:"+underCursorHits.size());


				return onesHit;
			}


		}

		//ensure not canceled for next time
		cancelCurrentTouchEvent=false;

		return onesHit;

	}

	static  boolean cancelCurrentTouchEvent=false;

	/**
	 * cancels the current touch event
	 */
	static	public void cancelCurrentTouchEvents(){
		cancelCurrentTouchEvent = true;
	}

	private static void listUnderCursorToLog(ArrayList<rayHit> underCursorHits2) {
		for (rayHit rayhit : underCursorHits2) {
			Log.info("undercursor last click/touch action    :"+rayhit.hitthis.getName()+"        ("+rayhit.hitthis.getInteractionType()+")");


		}
	}

	/**
	 * 
	 * 
	 * version;
	 * 
	 * 1. Get everything under cursor
	 *    - remember highest hitblocker
	 *    - remember highest hit
	 * 
	 *  2. If not penetrating test highest hit against highest clickblocker
	 *     If higher, then hit and exit.
	 *     
	 *    
	 * 3. If penetrating Loop over potential hits
	 *  - count as hit if higher then highest clickblocker
	 * 
	 * @param ray
	 * @param hitsPenetrate  - if the hits penetrate it means everything under the cursor will count as hit, not just the top.
	 * @param processHits - if the hits should be processed, or if we are just looking for the nearest collision (this can be optimised a lot)
	 * 
	 * @return the nearest hitable
	 * 
	 */
	public static hitable testForHits(Ray ray, boolean hitsPenetrate, boolean processHits) {

		Log.info("_-testing hit in :"+hitables.size+" models");
		Log.info("_-testing ray at :"+ray.origin.x+","+ray.origin.y);


		Vector3 position = new Vector3();

		ArrayList<hitable> everyThingUnderCursor = new ArrayList<hitable>();
		hitable closestNonBlockerTouched = null;	    
		hitable closestBlockerTouched = null;

		for (hitable newInstance : hitables) {




			//for (int i = 0; i < hitables.size; ++i) {

			//final hitable instance = hitables.get(i);

			//instance.getTransform().getTranslation(position);
			//position.add(instance.getCenter());
			position = newInstance.getCenterOnStage();


			//first check if it hits at all. We base this on the hitables internal tester
			//this lets different hitables use different intersect types (ie, radius, boundingbox, polygon etc)

			//	if (Intersector.intersectRaySphere(ray, instance.getCenter(), instance.getRadius(), null)) {
			Vector3 hitPoint = newInstance.rayHits(ray);
			if (hitPoint==null){
				//if it didn't hit we can just skip to the next thing to test
				continue;
			}


			//float dist2 = ray.origin.dst2(position);

			float dist2 = ray.origin.dst2(hitPoint);


			Log.info("_hit "+newInstance.getClass()+" object at distance "+dist2+" position was("+position+")");

			if (newInstance.getInteractionType() == objectInteractionType.Blocker){
				Log.info("(it was blocker)");

			}

			//set last hit range
			newInstance.setLastHitsRange(dist2);


			//if its a blocker we see if its higher then the last blocker
			if (newInstance.getInteractionType() == objectInteractionType.Blocker){

				//if none set just continue
				if (closestBlockerTouched==null){
					closestBlockerTouched=newInstance;
					continue;
				}
				//else we test if its closer
				//Note the > I think this is because the ray goes from furthest to nearest. So higher values are nearer
				if (newInstance.getLastHitsRange()<closestBlockerTouched.getLastHitsRange()){
					Log.info("(new blocker is closer)");
					closestBlockerTouched = newInstance;
					continue;
				}


			} else {

				//add to every not hitable under cursor list
				everyThingUnderCursor.add(newInstance);

				//if its not a blocker we do the same tests for normal objects

				//if none set just continue
				if (closestNonBlockerTouched==null){
					closestNonBlockerTouched=newInstance;
					continue;
				}
				//else we test if its closer
				if (newInstance.getLastHitsRange() < closestNonBlockerTouched.getLastHitsRange()){
					Log.info("(new non-blocker is closer)");
					closestNonBlockerTouched=newInstance;
					continue;
				}


			}







		}

		//now we have all the things potential hit, we check for actual hits 

		//If we arnt penetrating we just see if the highest hitable is higher then the highest blocker
		//if so we hit it and exit
		if (!hitsPenetrate && closestNonBlockerTouched!=null){

			Log.info("ClosestNonBlockerTouched as at:"+closestNonBlockerTouched.getLastHitsRange()+" ("+closestNonBlockerTouched.getClass()+")");

			if (closestBlockerTouched==null){
				if (processHits){
					closestNonBlockerTouched.fireTouchDown();
					mousedownOn.add(closestNonBlockerTouched);
				}
				//	mousedownOn.add(closestBlockerTouched); //hmm....not sure if we should use this anymore
				return closestNonBlockerTouched;
			}

			//if blocker is further then non-blocker
			if (closestBlockerTouched.getLastHitsRange() < closestNonBlockerTouched.getLastHitsRange()){
				Log.info("closestBlockerTouched as at:"+closestBlockerTouched.getLastHitsRange()+" ("+closestBlockerTouched.getClass()+")");

				if (processHits){
					closestNonBlockerTouched.fireTouchDown();
					mousedownOn.add(closestNonBlockerTouched);
				}
				//	mousedownOn.add(closestBlockerTouched); //hmm....not sure if we should use this anymore
				return closestNonBlockerTouched;
			}
		} else{
			Log.info("hits penatrating, mousing down on;"+everyThingUnderCursor.size()+" objects");
		}



		//if not we loop and hit anything above the highest blocker
		for (hitable instance : everyThingUnderCursor) {

			if (closestBlockerTouched==null || instance.getLastHitsRange()<closestBlockerTouched.getLastHitsRange()){

				if (processHits){
					instance.fireTouchDown();
					mousedownOn.add(instance);

				}
			}

		}

		//and if it exists we should hit the highest blocker too
		if (closestBlockerTouched!=null){
			closestBlockerTouched.fireTouchDown();
			mousedownOn.add(closestBlockerTouched);

		}

		// if (highest!=null){
		//  	closestNonBlockerTouched.fireTouchDown();
		//mousedownOn.add(closestBlockerTouched); //hmm....not sure if we should use this anymore
		//	return true;
		//}

		//    if (result!=-1 && !hitsPenetrate){
		//    	Gdx.app.log(logstag,"_closest hit was_"+result);
		//       closestBlockerTouched.fireTouchDown();
		//       mousedownOn.add(closestBlockerTouched);

		//   	return true;
		//   }
		if (closestBlockerTouched!=null){
			return closestBlockerTouched;
		}
		return null;
	}

	public static void addHitable(hitable model) {
		hitables.add(model);

	}

	public static boolean removeHitable(hitable model) {

		return hitables.remove(model);



	}
	public static void addMoving(Moving model) {
		movingObjects.add(model);

	}

	public static void removeMoving(Moving model) 
	{

		movingObjects.remove(model);

	}
	public static void addAnimating(Animating model) {
		animatingobjects.add(model);

	}

	public static void removeAnimating(Animating model) 
	{
		//animatingobjects.removeValue(model,true);
		animatingobjects.remove(model);
	}

	/** fires the drag event on everything the mouse was down on.
	 * This event should be fired once after a mousedown then mouse movement 
	 * @return **/
	public static void fireDragStartOnAll()	 {

		if (!dragStarted) {

			Log.info("_-drag start on all :"+mousedownOn.size);
			for (hitable model : mousedownOn) {
				model.fireDragStart();	

			}
			dragStarted=true;
		}
	}

	public static void fireDragStartEnd() {
		dragStarted=false;
	}

	public static void untouchAll() { //should be renamed we no longer fire touchup

		//Gdx.app.log(logstag,"_-mousedownOn size to untouch:"+mousedownOn.size);

		//for (hitable model : mousedownOn) {
		//	model.fireTouchUp();		

		//}
		mousedownOn.clear();
		//Gdx.app.log(logstag,"_----------removing md:"+mousedownOn.size);
		//Boolean removedtest = mousedownOn.removeValue(model,true);

		//Gdx.app.log(logstag,"_-mousedownOn:"+mousedownOn.size);
	}

	
	public static void dispose() {

		animatingobjects.clear();
		movingObjects.clear();
		modelBatch.dispose();

	}


	public static void updateObjectMovementAndFrames(float deltatime){

		for (Animating instance : animatingobjects) {

			instance.updateAnimationFrame(deltatime);

		}

		for (Moving instance : movingObjects) {

			instance.updatePosition(deltatime);			

		}

		//temp (testing lookat by linking to camera
		//should point from camera updated each frame		
		//	MECamera.angleTest.lookAt(lookAtTester);


	}

	static HashSet<IsAnimatableModelInstance> autoHideList = new HashSet<IsAnimatableModelInstance>();
	//
	//TODO: do we also need to check for it being over any of their subwidgets as well?
	//
	/**
	 * Models set to auto-hide will have .hide() triggered on the next MouseDown event, if that event is not 
	 * over them
	 *
	 * @param modelinstance
	 * @param b
	 */
	public static void setModelToAutoHide(IsAnimatableModelInstance model, boolean b) {
		if (b){
			autoHideList.add(model);
		} else {
			autoHideList.remove(model);
		}
	}

	static HashSet<IsAnimatableModelInstance> modalObjectList = new HashSet<IsAnimatableModelInstance>();

	/**
	 * Models set to modal are the only ones that can have events run on them IF any models have been set as modal at all.
	 * Keep the modal list empty for normal behavior.
	 *
	 * @param modelinstance
	 * @param b
	 */
	public static void setModelasModalObject(IsAnimatableModelInstance model, boolean b) {
		if (b){
			modalObjectList.add(model);
		} else {
			modalObjectList.remove(model);
		}
	}

	/**
	 * changes the render order of a item to "overlay"
	 * (that is, puts it in the overlay list after taking it out of the normal list
	 * If using a animatablemodelinstance, use its own SetASOverlay function so it stays in sycn
	 * @param model
	 */
	public static void setAsOverlay(ModelInstance model){

		//only add to overlay if it was in standard anyway
		if (allStandardInstances.remove(model)) {
			allOverlayInstances.add(model);
		}


	}
	/**
	 * changes the render order of a item to "standard"
	 * (that is, puts it in the standard list after taking it out of the ovelay list
	 * 
	 * If using a animatablemodelinstance, use its own SetASStandard function so it stays in sycn
	 * @param model
	 * 
	 */
	public static void setAsStandard(ModelInstance model){

		//we only add it to standard if it was in overlay
		if (allOverlayInstances.remove(model)){
			allStandardInstances.add(model);
		}

	}

	public static void updateTouchState() {

		//new touch system
		//first we update the state if needed based on what it was before
		//and what it is now
		if (Gdx.input.isTouched()) {
			//if we are touched we look at state we were before
			switch (GWTishModelManagement.currentTouchState) {
			case NONE:			
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewTouchDown; //if we wernt touching before then its a new touch!


				break;
			case NewTouchDown:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.TouchDown; //if we previously were a new touchdown, then now we are a non-new touchdown

				//currently duplicated elsewhere in MainExplorationView				
			//	Log.info(" new touch down");
				GWTishModelManagement.touchStartedAt = new Vector2(Gdx.input.getX(),Gdx.input.getY());



				break;
			case NewTouchUp:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewTouchDown; //if we just touched up and then the very next frame touched down....then the user is suspiciously fast
				break;
			case TouchDown:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.TouchDown; //still a touchdown unless the mouse moved;


				Vector2 currentLoc = new Vector2(Gdx.input.getX(),Gdx.input.getY());
				if (GWTishModelManagement.touchStartedAt.dst2(currentLoc)>5){							
					GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewDrag;
				}				

				break;
			case NewDrag:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.Dragging; //newdrags become Dragging 
				break;				
			case Dragging:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.Dragging; //do nothing
				break;
			}

		} else {

			switch (GWTishModelManagement.currentTouchState) {
			case NONE:	
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NONE; //still none
				break;
			case NewTouchDown:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewTouchUp; //we were touching now are not, so its a new touchup.
				break;
			case NewTouchUp:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NONE; //now none
				break;
			case TouchDown:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewTouchUp; //we were touching now are not, so its a new touchup.
				break;
			case NewDrag:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewTouchUp; //we were touching now are not, so its a new touchup.
				break;
			case Dragging:
				GWTishModelManagement.currentTouchState = GWTishModelManagement.TouchState.NewTouchUp; //we were touching now are not, so its a new touchup.
				break;
			}

		}

	}





} 	public enum StyleParam {
		//pixel effects:
		/** text color **/
		color,
		/** back color **/
		backcolor,
		/***
		 * glowSize
		 */
		glowSize,
		/**
		 * glowColour
		 */
		glowColour,
		/**
		 * shadowColour
		 */
		shadowColour,
		/**
		 * shadowXDisplacement
		 */
		shadowXDisplacement,
		/**
		 * shadowYDisplacement
		 */
		shadowYDisplacement,
		/**
		 * borderColor
		 */
		borderColor,
		/**
		 * borderWidth
		 */
		borderWidth,
		/**
		 * borderWidth
		 */
		borderRadius,
		/**
		 * brightnessFilter (0.0 = black, 1.0=normal)
		 */
		brightnessFilter,
		/**
		 * contrastFilter  (0.0 = grey, 1.0=normal)
		 */
		contrastFilter,
		/**
		 * hueFilter 
		 */
		hueFilter,
		/**
		 * saturationFilter  (0.0 = desaturated, 1.0=normal)
		 */
		saturationFilter,
		/**
		 * valueFilter  (0.0 = black, 1.0=normal)
		 */	
		valueFilter,
		//--
		//css-like transform effects (not yet supported)
		/*
		 * should support equilivants of;

@-webkit-keyframes bigbombshake {
	0% { -webkit-transform: translate(4px, 2px) rotate(0deg) scale(1.1,1.1); } 
	20% { -webkit-transform: translate(-6px, 0px) rotate(2deg) scale(1.0,1.0); }
	40% { -webkit-transform: translate(2px, -2px) rotate(2deg) scale(1.0,1.0); }
	60% { -webkit-transform: translate(-6px, 2px) rotate(0deg) scale(1.1,1.1); }
	80% { -webkit-transform: translate(-2px, -2px) rotate(2deg) scale(0.9,0.9); }
	100% { -webkit-transform: translate(2px, -4px) rotate(-2deg) scale(1.1,1.1); }
}


		 */
		
		//--
		/**
		 * not supported yet
		 */		
		translate,
		/**
		 * not supported yet
		 */
		rotate,
		/**
		 * not supported yet
		 */		
		scale;
	} public enum Unit {
 /** special unit used to indicate a not-set value **/
 NOTSET,
 /** Unitless, this means if used for lineheight the number gets multiplied by the fontsize**/
 UNITLESS,
 PX,
 /**percentage, should be % in strings **/
 PCT, 
 MM,
 CM,
 IN,
 PC,
 PT,
 EX		 
}
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.BlendingAttribute;
import com.badlogic.gdx.graphics.g3d.utils.FirstPersonCameraController;
import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Vector3;
import com.lostagain.nl.GWTish.ComplexPanel.VerticalAlignment;
import com.lostagain.nl.GWTish.ClickHandler;
import com.lostagain.nl.GWTish.Gwtish;
import com.lostagain.nl.GWTish.HorizontalPanel;
import com.lostagain.nl.GWTish.Image;
import com.lostagain.nl.GWTish.Label;
import com.lostagain.nl.GWTish.VerticalPanel;
import com.lostagain.nl.GWTish.Management.AnimatableModelInstance;
import com.lostagain.nl.GWTish.Management.GWTishModelManagement;
import com.lostagain.nl.GWTish.shader.GwtishWidgetShaderAttribute.StyleParam;
import com.lostagain.nl.GWTish.Style.Unit;
package com.lostagain.nl.GWTish.tests;


/**
 * makes a demo scene to show how  Labels, widgets for layour, and interaction works. 
 * 
 * @author darkflame
 * @author atresica
 *
 */
public class DemoScene {

	public static FirstPersonCameraController fpscontrols;
	

	/**
	 * fires Gwtish.assets.load(..) for all 3d models used in this scene.
	 * doneLoading() should be fired after that loading is done and the assets ready to use.
	 */
	public static  void setup()
	{
	
		setup(Gwtish.getAssetManager()); //default to Gwtish.java 's asset manager
	}
	
	static  AssetManager assetsmanager;
	
	/**
	 * fires Gwtish.assets.load(..) for all 3d models used in this scene.
	 * doneLoading() should be fired after that loading is done and the assets ready to use.
	 *
	 * @param assetsmanager - supply your own asset manager
	 */
	public static  void setup( AssetManager assetsmanager){

		DemoScene.assetsmanager=assetsmanager;
		//set all "background" models loading

		//Walls etc:
		assetsmanager.load("walls.g3db", Model.class);
		assetsmanager.load("floor.g3db", Model.class);
		assetsmanager.load("roof_reflect.g3db", Model.class);
		assetsmanager.load("roof.g3db", Model.class);

		//Edge:
		assetsmanager.load("flooredge.g3db", Model.class);
		//Desk	
		assetsmanager.load("table_centered.g3db", Model.class);
		//Computer:	
		assetsmanager.load("computer.g3db", Model.class);
		//paper:	
		assetsmanager.load("paper.g3db", Model.class);


		assetsmanager.load("cal.g3db", Model.class);
	}
	
	/**
	 * sets up the demo scenes visuals and interactions.
	 * 
	 */
	public static void doneLoading() {

		//Non gwtish models/scanary setup:
		setupBackgroundModels();	
		//(displays 3d model files loaded by asset manager)

		//________________create newspaper text
		VerticalPanel newspaperFrame = getNewsPaper();

		//position it
		newspaperFrame.setToPosition(new Vector3(12, 90, -65));
		newspaperFrame.setToRotation(new Quaternion(Vector3.X, -90).mul(new Quaternion(Vector3.Z, -104)));

		GWTishModelManagement.addmodel(newspaperFrame);	// necessary if you want to render the actual verticalpanel on screen.

		//________________create calander date
		VerticalPanel calframe = getCal();
		//position it
		calframe.setToPosition(new Vector3(5f, 97, -95));
		calframe.setToRotation(new Quaternion(Vector3.Y, -90).mul(new Quaternion(Vector3.X, -30)));

		GWTishModelManagement.addmodel(calframe);	


		
		//whiteboard
		VerticalPanel whiteboardframe = getWhiteBoard();
		// position whiteboardframe
		whiteboardframe.setToPosition(new Vector3(170, 200, -80));
		whiteboardframe.setToRotation(new Quaternion(Vector3.Y, -90).mul(new Quaternion(Vector3.X, 0)).mul(new Quaternion(Vector3.Z, -2)));
		
		GWTishModelManagement.addmodel(whiteboardframe);	
		
		
		//computer screen
		VerticalPanel computerscreenframe = getComputerScreen();
		// position computer
		computerscreenframe.setToPosition(new Vector3(-21, 132, -154));
		computerscreenframe.setToRotation(new Quaternion(Vector3.Y, -47.5f).mul(new Quaternion(Vector3.X, -13)).mul(new Quaternion(Vector3.Z, -2.8f)));


		
		GWTishModelManagement.addmodel(computerscreenframe);	
		
		
		
		
		
		
		//now we add simple interactions:
		//
		//Newspaper click
		newspaperFrame.addClickHandler(new ClickHandler() {
			@Override
			public void onClick() {
				// move cam
				activecam.position.set(-40f, 140f, -75f); 
				activecam.lookAt(12, 30, -65);//focus on newspaper
			}
		});

		//calframe click
		calframe.addClickHandler(new ClickHandler() {
			@Override
			public void onClick() {
				// move cam
				activecam.position.set(-25f, 120f, -95f); 
				activecam.lookAt(5f, 97, -95);//focus on calender
			}
		});
		//whiteboardtext click
		whiteboardframe.addClickHandler(new ClickHandler() {
			@Override
			public void onClick() {
				// move cam
				activecam.position.set(30f,125, -45f); 
				activecam.lookAt(170, 200, -10);//focus on whiteboardtext
			}
		});
		
		//computerscreenframe click
		computerscreenframe.addClickHandler(new ClickHandler() {
			@Override
			public void onClick() {
				// move cam
				activecam.position.set(-35f, 110, -95f); 
				activecam.lookAt(-15, 105, -154);//focus on computerscreenframe
			}
		});
		
	}



	private static void setupBackgroundModels() {
		//Note:Beware of models and draw order, large models will often need to be broken up or their pivots adjusted if the sorting algorithm is justing using pivot distances
		//

		Model floor = assetsmanager.get("floor.g3db", Model.class);
		ModelInstance floorInstance = new ModelInstance(floor); 
		BlendingAttribute blendingAttribute = new BlendingAttribute(GL20.GL_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
		blendingAttribute.opacity=0.8f;
		floorInstance.materials.get(0).set(blendingAttribute);
		GWTishModelManagement.addmodel(floorInstance);		

		Model wall = assetsmanager.get("walls.g3db", Model.class);
		ModelInstance wallInstance = new ModelInstance(wall); 
		GWTishModelManagement.addmodel(wallInstance);	

		Model flooredge = assetsmanager.get("flooredge.g3db", Model.class);
		ModelInstance flooredgeInstance = new ModelInstance(flooredge); 
		GWTishModelManagement.addmodel(flooredgeInstance);		
		//		
		Model roof = assetsmanager.get("roof.g3db", Model.class);
		ModelInstance roofInstance = new ModelInstance(roof); 
		GWTishModelManagement.addmodel(roofInstance);	
		Model roof_reflect = assetsmanager.get("roof_reflect.g3db", Model.class);
		ModelInstance roof_reflectInstance = new ModelInstance(roof_reflect); 
		GWTishModelManagement.addmodel(roof_reflectInstance);	
		//
		Model table = assetsmanager.get("table_centered.g3db", Model.class);
		AnimatableModelInstance tableInstance = new AnimatableModelInstance(table); 
		tableInstance.setToPosition(new Vector3(-23.609f, 85.806f, -74.658f));
		GWTishModelManagement.addmodel(tableInstance);	
		

		Model cal = assetsmanager.get("cal.g3db", Model.class);
		ModelInstance calInstance = new ModelInstance(cal); 
		GWTishModelManagement.addmodel(calInstance);	

		Model paper = assetsmanager.get("paper.g3db", Model.class);
		ModelInstance paperInstance = new ModelInstance(paper); 
		GWTishModelManagement.addmodel(paperInstance);	

		Model computer = assetsmanager.get("computer.g3db", Model.class);
		ModelInstance computerInstance = new ModelInstance(computer); 
		GWTishModelManagement.addmodel(computerInstance);
	}

	/**
	 * creates the text for a desk calendar 
	 * @return
	 */
	private static VerticalPanel getCal() {

		Label DayLab = new Label("17th");