/// <summary>Called when the renderer for this batch has changed.</summary>
		public void ChangeRenderer(Renderman renderer){
			
			Renderer=renderer;
			
			RenderWithCamera(renderer.RenderLayer);
			
			// Let the mesh know that the parent changed:
			Mesh.ChangeParent();
			
			InputMode mode;
			
			if(Renderer.RenderingInWorld){
				mode=PowerUI.Input.WorldInputMode;
			}else{
				mode=PowerUI.Input.Mode;
			}
			
			bool isPhysics=(mode==InputMode.Physics);
			
			if(isPhysics==PhysicsMode){
				return;
			}
			
			Mesh.SetPhysicsMode(isPhysics);
		}
		/// <summary>Creates a new UI Batch which will be rendered with the given renderer.</summary>
		/// <param name="renderer">The renderer that will render this batch.</param>
		public UIBatch(Renderman renderer){
			
			Mesh=new DynamicMesh(this);
			
			ChangeRenderer(renderer);
			
		}
		/// <summary>Creates a new UI Camera which will be rendered with the given renderer.</summary>
		/// <param name="renderer">The renderer that will render this camera.</param>
		public UICamera(Renderman renderer){
			Renderer=renderer;
			
			// Create the root gameobject:
			Gameobject=new GameObject();
			
			// Create camera gameobject:
			CameraObject=new GameObject();
			
			// Parent the camera to the root:
			CameraObject.transform.parent=Gameobject.transform;
			
			// Add a camera:
			SourceCamera=CameraObject.AddComponent<Camera>();
			
			// Set the clear flags:
			SourceCamera.clearFlags=CameraClearFlags.Depth;
			
			// Set the culling mask:
			SourceCamera.cullingMask=(1<<UI.Layer);
			
			// Make it forward rendered:
			SourceCamera.renderingPath=RenderingPath.Forward;
			
			// Setup the cameras distance:
			SetCameraDistance(UI.GetCameraDistance());
			
			// Setup the field of view:
			SetFieldOfView(UI.GetFieldOfView());
			
			// Parent it to the root:
			Gameobject.transform.parent=UI.GUINode.transform;
			
			// Call the camera creation method:
			UI.CameraGotCreated(SourceCamera);
			
		}
		/// <summary>This locates the vertices of this block in world space to the position defined by the given box.</summary>
		/// <param name="block">The position of the vertices in screen coordinates.</param>
		/// <param name="renderer">The renderer used when rendering this block.</param>
		/// <param name="zIndex">The depth of the vertices.</param>
		private void ApplyVertices(BoxRegion block,Renderman renderer,float zIndex){
		
			// Compute the min/max pixels:
			Vector3 min=renderer.PixelToWorldUnit(block.X,block.Y,zIndex);
			Vector3 max=renderer.PixelToWorldUnit(block.MaxX,block.MaxY,zIndex);
			
			// Get the 4 corners:
			VertexTopLeft=min;
			VertexBottomRight=max;
			VertexTopRight=new Vector3(max.x,min.y,min.z); 
			VertexBottomLeft=new Vector3(min.x,max.y,min.z);
			
		}
		/// <summary>Sets the vertices of this box to that specified by the given block
		/// but clipped to fit within a boundary. At the same time, an image is applied
		/// to the block and its UV coordinates are also clipped.</summary>
		/// <param name="boundary">The clipping boundary. The vertices will be clipped to within this.</param>
		/// <param name="block">The position of the vertices.</param>
		/// <param name="renderer">The renderer that will render this block.</param>
		/// <param name="zIndex">The depth of the vertices.</param>
		/// <param name="imgLocation">The location of the image on the meshes atlas.</param>
		public UVBlock SetClipped(BoxRegion boundary,BoxRegion block,Renderman renderer,float zIndex,AtlasLocation imgLocation,UVBlock uvBlock){
			
			// Image defines how big we want the image to be in pixels on the screen.
			// So firstly we need to find the ratio of how scaled our image actually is:
			float originalHeight=block.Height;
			float scaleX=imgLocation.Width/block.Width;
			float scaleY=imgLocation.Height/originalHeight;
			
			// We'll need to clip block and make sure the image block is clipped too:
			float blockX=block.X;
			float blockY=block.Y;
			
			if(block.ClipByChecked(boundary)){
				
				// It actually got clipped - time to do some UV clipping too.
				
				// Apply the verts:
				ApplyVertices(block,renderer,zIndex);
				
				block.X-=blockX;
				block.Y-=blockY;
				block.MaxX-=blockX;
				block.MaxY-=blockY;
				
				// Flip the gaps (the clipped and now 'missing' sections) - UV's are inverted relative to the vertices.
				
				// Bottom gap is just block.Y:
				float bottomGap=block.Y;
				
				// Top gap is the original height - the new maximum; write it to the bottom gap:
				block.Y=originalHeight-block.MaxY;
				
				// Update the top gap:
				block.MaxY=originalHeight-bottomGap;
				
				// Image was in terms of real screen pixels, so now we need to scale it to being in 'actual image' pixels.
				// From there, the region 
				block.X*=scaleX;
				block.MaxX*=scaleX;
				
				block.Y*=scaleY;
				block.MaxY*=scaleY;
				
				if(uvBlock==null || uvBlock.Shared){
					
					// Create the UV block:
					uvBlock=new UVBlock();
					
				}
				
				// Get the new max/min values:
				uvBlock.MinX=imgLocation.GetU(block.X+0.2f);
				uvBlock.MaxX=imgLocation.GetU(block.MaxX-0.2f);
				uvBlock.MaxY=imgLocation.GetV(block.MaxY-0.2f);
				uvBlock.MinY=imgLocation.GetV(block.Y+0.2f);
				
			}else{
				
				// Apply the verts:
				ApplyVertices(block,renderer,zIndex);
				
				// Globally share the UV!
				uvBlock=imgLocation;
				
			}
			
			return uvBlock;
			
		}
		/// <summary>Sets the vertices of this box to that specified by the given block
		/// but clipped to fit within a boundary.</summary>
		/// <param name="boundary">The clipping boundary. The vertices will be clipped to within this.</param>
		/// <param name="block">The position of the vertices.</param>
		/// <param name="zIndex">The depth of the vertices.</param>
		public void SetClipped(BoxRegion boundary,BoxRegion block,Renderman renderer,float zIndex){
			// Clipping with no image/ affect on UVs:
			block.ClipBy(boundary);
			// And just apply the result:
			ApplyVertices(block,renderer,zIndex);
		}
Beispiel #7
0
	/// <summary>Clears all content from the UI and all WorldUI's. 
	/// Please note that it is safer to set innerHTML to a blank string for a particular UI than calling this.</summary>
	public static void ClearAll(){
		content=null;
		
		if(Renderer!=null){
			Renderer.Destroy();
			Renderer=null;
			document=null;
		}
		
		Fonts.Clear();
		AtlasStacks.Clear();
		Http.Clear();
		SPA.Clear();
		UIAnimation.Clear();
		DynamicTexture.RemoveAll();
		PowerUI.Input.Clear();
		ScreenInfo.Clear();
		WorldUI currentWorldUI=FirstWorldUI;
		
		while(currentWorldUI!=null){
			currentWorldUI.Destroy();
			currentWorldUI=currentWorldUI.UIAfter;
		}
		
		LastWorldUI=null;
		FirstWorldUI=null;
	}
Beispiel #8
0
	/// <summary>Used internally - don't call this one. Startup the UI for use in the Editor with AOT Nitro.</summary>
	/// <param name="nitroAot">True if no gameobject should be generated.</param>
	public static void Start(bool nitroAot){
		
		if(!Started){
			Started=true;
			
			// Setup atlas stacks:
			AtlasStacks.Start();
			
			// Hookup the wrench logging method:
			Wrench.Log.OnLog+=OnLogMessage;
			
			// Hookup the InfiniText logging method:
			InfiniText.Fonts.OnLog+=OnLogMessage;
			
			// Startup the tag handlers:
			Wrench.TagHandlers.Setup();
			
			// Startup the file protocols (internally also starts up the CSS engine):
			FileProtocols.Setup();
			
			// Setup the text/language service:
			if(Variables==null){
				Variables=new FullVariableSet();
				
				if(!nitroAot){
					// Sign up to the variable on change event - whenever a custom var is changed, we need to refresh the screen.
					Variables.OnChange+=OnVariableChange;
					// Ensure that variables is set to whatever the default/current language is.
					OnLanguageChange(Wrench.Text.Language);
					// Sign on to the event that occurs when the language changes.
					Wrench.Text.OnLanguageChanged+=OnLanguageChange;
					// Sign on to the event that occurs when the gender changes.
					Wrench.Text.OnGenderChanged+=ResolveAllVariables;
				}
			}
			
			// Setup the callback queue:
			Callbacks.Start();
			
			// Setup the character providers (for e.g. Emoji):
			CharacterProviders.Setup();
			
			Layer=LayerMask.NameToLayer("PowerUI");
			
			if(Layer<0){
				// Invalid layer.
				#if UNITY_EDITOR
				
				// Create the new layer now (this will actually be a permanent change):
				Layer=PowerUI.LayerManager.Add();
				
				#else
				throw new Exception("Error: PowerUI layer not found. Go to Edit->Project Settings->Tags and add a layer called PowerUI to fix this."+
									" Don't forget to make sure it doesn't render with your main camera too!"
									);
				#endif
			}
			
			// Default FPS:
			SetRate(DefaultRate);
			
			#if !NoNitroRuntime
			// Setup the compiler:
			NitroCode.Setup();
			#endif
		}
		
		if(nitroAot){
			return;
		}
		
		GUINode=GameObject.Find("#PowerUI");
		
		if(GUINode==null){
			// Not started yet.
			
			// Create the UI game object:
			GUINode=new GameObject();
			GUINode.name="#PowerUI";
			
			// Create the camera:
			CameraNode=new GameObject();
			CameraNode.name="Camera";
			
			// Create the updater:
			GlobalUpdater=GUINode.AddComponent<StandardUpdater>();
			
			// Setup the camera:
			GUICamera=CameraNode.AddComponent<Camera>();
		}else{
			// Already started, but we might have updated.
			
			if(CameraNode==null){
				// This can happen if the PowerUI assembly is actively reloaded (e.g. runtime updates).
				CameraNode=GameObject.Find("#PowerUI/Camera");
				CameraTransform=CameraNode.transform;
				GUICamera=CameraNode.GetComponent<Camera>();
			}else{
				// Already started!
				return;
			}
			
		}
		
		// Hide the PowerUI layer from all cameras other than GUICamera: 
		Camera[] cameras=Camera.allCameras;
		
		int layerMask=~(1<<UI.Layer);
		
		for(int i=0;i<cameras.Length;i++){
			// Grab the camera:
			Camera camera=cameras[i];
			
			// Is it the GUICamera?
			if(camera==GUICamera){
				continue;
			}
			
			// Hide the UI layer from it:
			camera.cullingMask&=layerMask;
		}
		
		// Setup the transform:
		CameraTransform=CameraNode.transform;
		CameraTransform.parent=GUINode.transform;
		
		GUICamera.nearClipPlane=0.2f;
		GUICamera.depth=CameraDepth;
		GUICamera.clearFlags=CameraClearFlags.Depth;
		GUICamera.cullingMask=(1<<UI.Layer);
		GUICamera.renderingPath=RenderingPath.Forward;
		
		SetCameraDistance(60f);
		SetFieldOfView(60f);
		
		Renderer=new Renderman();
		
		// Render Mesh.OutputGameObject with the GUI camera:
		Renderer.RenderWithCamera(UI.Layer);
		document=Renderer.RootDocument;
		document.window.top=document.window;
		
		// Some overriding default UI settings:
		document.html.Style.Computed.ChangeTagProperty("color",new PowerUI.Css.Value("#ffffff",PowerUI.Css.ValueType.Color));
		document.html.Style.Computed.ChangeTagProperty("font-size",new PowerUI.Css.Value("14px",PowerUI.Css.ValueType.Pixels));
		document.body.Style.Computed.ChangeTagProperty("overflow",new PowerUI.Css.Value("hidden hidden",PowerUI.Css.ValueType.Point));
		
		UpdateTextDirection();
		
		// Fire the camera event:
		CameraGotCreated(GUICamera);
		
	}
		/// <summary>Creates a new document which will be rendered with the given renderer.</summary>
		/// <param name="renderer">The renderer to use when rendering this document.</param>
		/// <param name="parentWindow">The window that will become the parent window. Used in e.g. iframes.</param>
		/// <param name="aot">True if this is a Nitro AOT document (used in the Editor only).</param>
		public Document(Renderman renderer,Window parentWindow,bool aot):base(){
			AotDocument=aot;
			
			if(!aot && DefaultStyleSheet==null){
				// No default styles loaded yet. Load them now.
				string styleText=((TextAsset)Resources.Load("style")).text;
				// Have they applied any overrides?
				TextAsset extraStyle=Resources.Load("customStyle") as TextAsset;
				if(extraStyle!=null && extraStyle.text!=null){
					styleText+="\n\n"+extraStyle.text;
				}
				DefaultStyleSheet=new Css.StyleSheet(this);
				DefaultStyleSheet.ParseCss(styleText);
			}
			
			#if !NoNitroRuntime
			// Get the default security domain:
			SecurityDomain=UI.DefaultSecurityDomain;
			#endif
			
			Renderer=renderer;
			
			window=new Window();
			window.document=this;
			window.parent=parentWindow;
			if(parentWindow!=null){
				window.top=parentWindow.top;
			}else{
				window.top=window;
			}
			
			ActiveFonts=new Dictionary<string,DynamicFont>();
			Style=new Css.StyleSheet(this);
			html=new Element(this,null);
			html.SetTag("html");
			string ddbox="";
			
			if(parentWindow==null){
				// Dropdown box belongs to the top window only:
				ddbox="<ddbox></ddbox>";
			}
			
			html.innerHTML="<body></body>"+ddbox;
		}
		/// <summary>Creates a new document which will be rendered with the given renderer.</summary>
		/// <param name="renderer">The renderer to use when rendering this document.</param>
		/// <param name="parentWindow">The window that will become the parent window. Used in e.g. iframes.</param>
		public Document(Renderman renderer,Window parentWindow):this(renderer,parentWindow,false){}
		/// <summary>Creates a new document which will be rendered with the given renderer.</summary>
		/// <param name="renderer">The renderer to use when rendering this document.</param>
		public Document(Renderman renderer):this(renderer,null){}
		/// <summary>Destroys this UI. Note that this also occurs if the gameobject is destroyed;
		/// Just destroying the gameobject or a parent gameObject is all that is required.</summary>
		public void Destroy(){
			
			if(Renderer==null){
				return;
			}
		
			Renderer.Destroy();
			Renderer=null;
			
			if(gameObject!=null){
				GameObject.Destroy(gameObject);
				gameObject=null;
				transform=null;
			}
			
			// Remove it from the UI update linked list:
			if(UIBefore==null){
				UI.FirstWorldUI=UIAfter;
			}else{
				UIBefore.UIAfter=UIAfter;
			}
			
			if(UIAfter==null){
				UI.LastWorldUI=UIBefore;
			}else{
				UIAfter.UIBefore=UIBefore;
			}
		}
		/// <summary>Creates a new World UI with the given pixels of space and a given name.
		/// The gameobjects origin sits at the middle of the UI by default. See <see cref="PowerUI.WorldUI.SetOrigin"/>. 
		/// By default, 100 pixels are 1 world unit. See <see cref="PowerUI.WorldUI.SetResolution"/>.</summary>
		/// <param name="name">The name for the UI's gameobject.</param>
		/// <param name="widthPX">The width in pixels of this UI.</param>
		/// <param name="heightPX">The height in pixels of this UI.</param>
		public WorldUI(string name,int widthPX,int heightPX){
			// Start the UI:
			UI.Start();
			
			// Create the gameobject:
			gameObject=new GameObject();
			gameObject.name=name;
			
			// Grab the name:
			Name=name;
			
			transform=gameObject.transform;
			Renderer=new Renderman(this);
			SetDepthResolution(0.01f);
			
			// Apply the default scale:
			transform.localScale=new Vector3(1/100f,1/100f,1f);
			
			document=Renderer.RootDocument;
			
			// Add it to the UI update linked list:
			if(UI.FirstWorldUI==null){
				UI.FirstWorldUI=UI.LastWorldUI=this;
			}else{
				UIBefore=UI.LastWorldUI;
				UI.LastWorldUI=UI.LastWorldUI.UIAfter=this;
			}
			
			SetDimensions(widthPX,heightPX);
			
			SetInputMode(PowerUI.Input.WorldInputMode);
		}
		/// <summary>Permanently destroys this UI batch.</summary>
		public void Destroy(){
			if(Renderer==null){
				return;
			}
			
			if(IsolatedProperty!=null){
				IsolatedProperty.Isolated=false;
				IsolatedProperty.OnBatchDestroy();
				IsolatedProperty=null;
			}
			
			if(Mesh!=null){
				Mesh.Destroy();
				Mesh=null;
			}
			
			Renderer=null;
		}
		/// <summary>Gets a batch from the pool. Null if the pool is empty.</summary>
		public static UIBatch Get(Renderman renderer){
			if(First==null){
				return null;
			}
			
			UIBatch result=First;
			First=result.BatchAfter;
			result.BatchAfter=null;
			result.Setup=false;
			
			// Show it:
			#if PRE_UNITY4
			result.Mesh.OutputGameObject.active=true;
			#else
			result.Mesh.OutputGameObject.SetActive(true);
			#endif
			
			if(result.Renderer!=renderer){
				result.ChangeRenderer(renderer);
			}
			
			return result;
		}