summaryrefslogtreecommitdiff
path: root/Runtime/Camera/RenderLayers
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Camera/RenderLayers')
-rw-r--r--Runtime/Camera/RenderLayers/GUIElement.cpp31
-rw-r--r--Runtime/Camera/RenderLayers/GUIElement.h30
-rw-r--r--Runtime/Camera/RenderLayers/GUILayer.cpp104
-rw-r--r--Runtime/Camera/RenderLayers/GUILayer.h33
-rw-r--r--Runtime/Camera/RenderLayers/GUIText.cpp303
-rw-r--r--Runtime/Camera/RenderLayers/GUIText.h93
-rw-r--r--Runtime/Camera/RenderLayers/GUITexture.cpp524
-rw-r--r--Runtime/Camera/RenderLayers/GUITexture.h73
8 files changed, 1191 insertions, 0 deletions
diff --git a/Runtime/Camera/RenderLayers/GUIElement.cpp b/Runtime/Camera/RenderLayers/GUIElement.cpp
new file mode 100644
index 0000000..73ff0e0
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUIElement.cpp
@@ -0,0 +1,31 @@
+#include "UnityPrefix.h"
+#include "GUIElement.h"
+#include "GUILayer.h"
+#include "Runtime/Math/Vector2.h"
+
+GUIElement::GUIElement (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+}
+
+GUIElement::~GUIElement ()
+{
+}
+
+void GUIElement::AddToManager ()
+{
+ GUILayer::ms_GUIElements->add_delayed (this);
+}
+
+void GUIElement::RemoveFromManager ()
+{
+ GUILayer::ms_GUIElements->remove_delayed (this);
+}
+
+bool GUIElement::HitTest (const Vector2f& screenSpacePosition, const Rectf& cameraRect)
+{
+ Rectf rect = GetScreenRect (cameraRect);
+ return rect.Contains (screenSpacePosition.x, screenSpacePosition.y);
+}
+
+IMPLEMENT_CLASS (GUIElement)
diff --git a/Runtime/Camera/RenderLayers/GUIElement.h b/Runtime/Camera/RenderLayers/GUIElement.h
new file mode 100644
index 0000000..0092da9
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUIElement.h
@@ -0,0 +1,30 @@
+#ifndef GUIELEMENT_H
+#define GUIELEMENT_H
+
+#include "Runtime/GameCode/Behaviour.h"
+#include "Runtime/Math/Rect.h"
+class Vector2f;
+
+
+// Base class for all GUI elements.
+// Registers itself with the GUILayer when enabled.
+class GUIElement : public Behaviour
+{
+public:
+
+ REGISTER_DERIVED_ABSTRACT_CLASS (GUIElement, Behaviour)
+
+ GUIElement (MemLabelId label, ObjectCreationMode mode);
+
+ virtual void RenderGUIElement (const Rectf& cameraRect) = 0;
+ virtual Rectf GetScreenRect (const Rectf& cameraRect) = 0;
+
+ bool HitTest (const Vector2f& screenSpaceCoordinates, const Rectf& cameraRect);
+
+private:
+
+ virtual void AddToManager ();
+ virtual void RemoveFromManager ();
+};
+
+#endif
diff --git a/Runtime/Camera/RenderLayers/GUILayer.cpp b/Runtime/Camera/RenderLayers/GUILayer.cpp
new file mode 100644
index 0000000..69deeb8
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUILayer.cpp
@@ -0,0 +1,104 @@
+#include "UnityPrefix.h"
+#include "GUILayer.h"
+#include "Runtime/Camera/Camera.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Camera/RenderManager.h"
+#include "Runtime/Math/Vector2.h"
+#include "Runtime/BaseClasses/Tags.h"
+#include "Runtime/Allocator/MemoryMacros.h"
+#include "Runtime/Profiler/ExternalGraphicsProfiler.h"
+
+PROFILER_INFORMATION(gGUILayerProfile, "Camera.GUILayer", kProfilerRender);
+
+GUILayer::GUIElements* GUILayer::ms_GUIElements = NULL;
+
+GUILayer::GUILayer(MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+}
+
+GUILayer::~GUILayer ()
+{
+}
+
+inline bool SortGUIByDepth (GUIElement* lhs, GUIElement* rhs)
+{
+ return lhs->GetComponent (Transform).GetLocalPosition ().z < rhs->GetComponent (Transform).GetLocalPosition ().z;
+}
+
+void GUILayer::InitializeClass ()
+{
+ ms_GUIElements = new GUIElements;
+}
+
+void GUILayer::CleanupClass()
+{
+ delete ms_GUIElements;
+}
+
+
+void GUILayer::RenderGUILayer ()
+{
+ PROFILER_AUTO_GFX(gGUILayerProfile, this);
+
+ ms_GUIElements->apply_delayed ();
+ if (ms_GUIElements->empty())
+ return;
+
+ typedef UNITY_TEMP_VECTOR(GUIElement*) TempElements;
+ TempElements elements (ms_GUIElements->begin (), ms_GUIElements->end ());
+
+ std::sort (elements.begin (), elements.end (), SortGUIByDepth);
+
+ Camera& camera = GetComponent(Camera);
+ UInt32 cullingMask = camera.GetCullingMask ();
+ Rectf cameraRect = camera.GetScreenViewportRect();
+
+ for (TempElements::iterator it=elements.begin(), itEnd = elements.end(); it != itEnd; ++it)
+ {
+ GUIElement& element = **it;
+ if (element.GetGameObject ().GetLayerMask () & cullingMask)
+ element.RenderGUIElement (cameraRect);
+ }
+}
+
+GUIElement* GUILayer::HitTest (const Vector2f& screenPosition)
+{
+ Camera& camera = GetComponent (Camera);
+ Vector3f viewportPos3D = camera.ScreenToViewportPoint (Vector3f (screenPosition.x, screenPosition.y, camera.GetNear()));
+ Vector2f viewportPos (viewportPos3D.x, viewportPos3D.y);
+ Rectf normalized (0.0F,0.0F,1.0F,1.0F);
+
+ if (!normalized.Contains (viewportPos.x, viewportPos.y))
+ return NULL;
+
+ Rectf cameraRect = camera.GetScreenViewportRect();
+
+ Rectf windowRect = GetRenderManager ().GetWindowRect ();
+ viewportPos.x *= windowRect.Width ();
+ viewportPos.y *= windowRect.Height ();
+
+ GUIElement* topmost = NULL;
+ float topmostZ = -std::numeric_limits<float>::infinity ();
+
+ // GUI hit testing always ignores IgnoreRaycast layer
+ UInt32 cullingMask = camera.GetCullingMask() & ~(kIgnoreRaycastMask);
+
+ for (GUIElements::iterator it=ms_GUIElements->begin (), itEnd = ms_GUIElements->end (); it != itEnd; ++it)
+ {
+ GUIElement* element = *it;
+ if (element && (element->GetGameObject ().GetLayerMask () & cullingMask) && element->HitTest (viewportPos, cameraRect))
+ {
+ float z = element->GetComponent (Transform).GetLocalPosition ().z;
+ if (z > topmostZ)
+ {
+ topmost = element;
+ topmostZ = z;
+ }
+ }
+ }
+
+ return topmost;
+}
+
+IMPLEMENT_CLASS_HAS_INIT(GUILayer)
diff --git a/Runtime/Camera/RenderLayers/GUILayer.h b/Runtime/Camera/RenderLayers/GUILayer.h
new file mode 100644
index 0000000..925b070
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUILayer.h
@@ -0,0 +1,33 @@
+#ifndef GUILAYER_H
+#define GUILAYER_H
+
+#include "GUIElement.h"
+#include "Runtime/GameCode/Behaviour.h"
+#include "Runtime/Utilities/delayed_set.h"
+
+/// A GUI Layer is attached to the camera.
+/// It tracks all enabled GUIElements (eg. Text, GUITexture) and renders them
+class GUILayer : public Behaviour
+{
+public:
+ REGISTER_DERIVED_CLASS (GUILayer, Behaviour)
+
+ GUILayer (MemLabelId label, ObjectCreationMode mode);
+
+ void RenderGUILayer();
+ GUIElement* HitTest (const Vector2f& screenPosition);
+
+ static void InitializeClass ();
+ static void CleanupClass ();
+
+ // Behaviour
+ virtual void AddToManager() { };
+ virtual void RemoveFromManager() { };
+
+private:
+ typedef delayed_set <PPtr<GUIElement> > GUIElements;
+ static GUIElements* ms_GUIElements;
+ friend class GUIElement;
+};
+
+#endif
diff --git a/Runtime/Camera/RenderLayers/GUIText.cpp b/Runtime/Camera/RenderLayers/GUIText.cpp
new file mode 100644
index 0000000..9602bdd
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUIText.cpp
@@ -0,0 +1,303 @@
+#include "UnityPrefix.h"
+#include "GUIText.h"
+#include "Runtime/Filters/Misc/Font.h"
+#include "Runtime/Misc/ResourceManager.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/IMGUI/TextMeshGenerator2.h"
+#include "Runtime/Shaders/Material.h"
+#include "Runtime/Filters/Mesh/Mesh.h"
+#include "Runtime/Camera/RenderManager.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Shaders/Shader.h"
+#include "Runtime/GfxDevice/GfxDevice.h"
+#include "Runtime/Shaders/VBO.h"
+#include "Runtime/Camera/CameraUtil.h"
+#include "External/shaderlab/Library/intshader.h"
+#include "Runtime/Profiler/Profiler.h"
+
+static Font* gDefaultFont = NULL;
+
+GUIText::GUIText (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+ m_FontSize = 0;
+ m_FontStyle = 0;
+ m_RichText = true;
+ m_Color = 0xffffffff;
+}
+
+GUIText::~GUIText ()
+{
+}
+
+Font * GUIText::GetFont () const {
+ Font *f = m_Font;
+ if (!f) {
+ if (!gDefaultFont)
+ gDefaultFont = GetBuiltinResource<Font> (kDefaultFontName);
+ return gDefaultFont;
+ }
+ else {
+ return f;
+ }
+
+}
+
+PROFILER_INFORMATION(gRenderGUIText, "GUIText.Render", kProfilerGUI)
+PROFILER_INFORMATION(gSubmitVBOProfileGUIText, "Mesh.SubmitVBO", kProfilerRender)
+
+void GUIText::RenderGUIElement (const Rectf& cameraRect)
+{
+ if (m_Text.empty ())
+ return;
+
+ PROFILER_AUTO(gRenderGUIText, this)
+
+ pair<Font*, Material*> temp = GetFontAndMaterial ();
+ Font* font = temp.first;
+ Material* material = temp.second;
+ if (font == NULL || material == NULL)
+ return;
+
+ TextMeshGenerator2 &tmgen = TextMeshGenerator2::Get (UTF16String(m_Text.c_str()), font, (TextAnchor)m_Anchor, (TextAlignment)m_Alignment, 0, m_TabSize, m_LineSpacing, m_RichText, m_PixelCorrect, m_Color, m_FontSize, m_FontStyle);
+
+ GfxDevice& device = GetGfxDevice();
+ DeviceMVPMatricesState preserveMVP; // save MVP matrices, restore when returning from this function!
+
+ Vector2f size = tmgen.GetSize ();
+ Vector2f offset = tmgen.GetTextOffset (Rectf (0, 0, -size.x, size.y * 2));
+ switch (m_Alignment)
+ {
+ case kRight: offset.x += size.x; break;
+ case kCenter:
+ if (m_PixelCorrect)
+ offset.x += Roundf(size.x * 0.5f);
+ else
+ offset.x += size.x * 0.5f;
+ break;
+ }
+ Matrix4x4f textMatrix;
+ if (!m_PixelCorrect)
+ {
+ Matrix4x4f ortho;
+ ortho.SetOrtho( 0, 1, 0, 1, -1, 100 );
+ device.SetProjectionMatrix (ortho);
+
+ Transform& transform = GetComponent (Transform);
+ Vector3f position = transform.GetPosition ();
+ position.z = 0.0F;
+ Vector3f scale = transform.GetWorldScaleLossy ();
+ scale.x *= 0.05F * font->GetDeprecatedPixelScale ();
+ scale.y *= -0.05F * font->GetDeprecatedPixelScale ();
+ scale.z = 1.0F;
+
+ position.x += offset.x * scale.x;
+ position.y -= offset.y * scale.y;
+
+ textMatrix.SetTranslate( position );
+ textMatrix.Scale( scale );
+ }
+ else {
+ // Find out how large a rect the font should be rendered into, so that it is pixel correct. call the generator with this size.
+ Rectf rectNoOffset = cameraRect;
+ rectNoOffset.Move( -rectNoOffset.x, -rectNoOffset.y );
+ LoadPixelMatrix( rectNoOffset, device, true, false );
+
+ Transform& transform = GetComponent (Transform);
+ Vector3f position = transform.GetPosition ();
+ position.z = 0.0F;
+
+ textMatrix.SetTranslate( Vector3f( Roundf (position.x * cameraRect.Width() + m_PixelOffset.x), Roundf(position.y * cameraRect.Height() + m_PixelOffset.y), 0.0f ) );
+ textMatrix.Scale( Vector3f( 1.0F, -1.0F, 1.0f ) );
+
+ textMatrix.Translate( Vector3f( offset.x, -offset.y, 0.0f ) );
+ }
+ device.SetViewMatrix( textMatrix.GetPtr() );
+
+ int passCount = material->GetPassCount ();
+ for (int i=0;i < passCount ;i++)
+ {
+ const ChannelAssigns* channels = material->SetPass (i);
+ tmgen.RenderRaw (*channels);
+ }
+}
+
+
+void DrawGUIText (const std::string& text, Font* font, Material* material)
+{
+ if (text.empty())
+ return;
+ if (font == NULL || material == NULL)
+ return;
+
+ PROFILER_AUTO(gRenderGUIText, NULL)
+
+ TextMeshGenerator2 &tmgen = TextMeshGenerator2::Get (UTF16String(text.c_str()), font, kUpperLeft, kAuto, 0, 0, 1.0f, false, true, 0xffffffff, 0, 0);
+
+ static SHADERPROP (MainTex);
+ Texture* fontTexture = font->GetTexture();
+ // In the case when font is a custum font, GetTexture() will return NULL, so in this case take the main texture from font's material
+ if (fontTexture == NULL && font->GetMaterial())
+ {
+ fontTexture = font->GetMaterial()->GetTexture(kSLPropMainTex);
+ }
+ material->SetTexture(kSLPropMainTex, fontTexture);
+
+ int passCount = material->GetPassCount ();
+ for (int i=0;i < passCount ;i++)
+ {
+ const ChannelAssigns* channels = material->SetPass (i);
+ tmgen.RenderRaw (*channels);
+ }
+}
+
+Rectf GUIText::GetScreenRect (const Rectf& cameraRect)
+{
+ if (m_Text.empty ())
+ return Rectf();
+
+ Font* font = GetFontAndMaterial ().first;
+ if (font == NULL)
+ return Rectf();
+
+ TextMeshGenerator2 &tmgen = TextMeshGenerator2::Get (UTF16String(m_Text.c_str()), font, (TextAnchor)m_Anchor, (TextAlignment)m_Alignment, 0, m_TabSize, m_LineSpacing, m_RichText, m_PixelCorrect, m_Color, m_FontSize, m_FontStyle);
+ Vector2f size = tmgen.GetSize ();
+ Vector2f offset = tmgen.GetTextOffset (Rectf (0, 0, -size.x, size.y * 2));
+ Rectf rect (offset.x, -offset.y, size.x, size.y);
+
+ Transform& transform = GetComponent (Transform);
+ if (!m_PixelCorrect)
+ {
+ Vector3f position = transform.GetPosition ();
+ position.z = 0.0F;
+ Vector3f scale = transform.GetWorldScaleLossy ();
+ scale.x *= 0.05F * font->GetDeprecatedPixelScale ();
+ scale.y *= -0.05F * font->GetDeprecatedPixelScale ();
+ scale.z = 1.0F;
+
+ rect.Scale (scale.x, scale.y);
+ rect.Move (position.x, position.y);
+ Rectf windowRect = GetRenderManager ().GetWindowRect ();
+ rect.Scale (windowRect.Width (), windowRect.Height ());
+ }
+ else
+ {
+ Rectf windowRect = GetRenderManager ().GetWindowRect ();
+
+ Vector3f position = transform.GetPosition ();
+ position.x = Roundf (position.x * windowRect.Width() + m_PixelOffset.x);
+ position.y = Roundf (position.y * windowRect.Height() + m_PixelOffset.y);
+
+ Vector3f scale = Vector3f (1.0F ,-1.0F,1);
+
+ rect.Scale (scale.x, scale.y);
+ rect.Move (position.x, position.y);
+ }
+ if (rect.height < 0)
+ {
+ rect.height = -rect.height;
+ rect.y -= rect.height;
+ }
+ return rect;
+}
+
+pair<Font*, Material*> GUIText::GetFontAndMaterial ()
+{
+ Font* font = m_Font;
+ Material* material = m_Material;
+ if (font != NULL && material == NULL)
+ material = font->GetMaterial ();
+
+ // Use default resource instead!
+ if (font == NULL || material == NULL)
+ {
+ if (gDefaultFont == NULL)
+ {
+ gDefaultFont = GetBuiltinResource<Font> (kDefaultFontName);
+ if (!gDefaultFont)
+ {
+ LogString ("Couldn't load default font!");
+ return std::make_pair<Font*, Material*> (NULL, NULL);
+ }
+ if (!gDefaultFont->GetMaterial())
+ {
+ LogString ("Couldn't load default font material!");
+ return std::make_pair<Font*, Material*> (NULL, NULL);
+ }
+ }
+
+ if (font == NULL)
+ font = gDefaultFont;
+ if (material == NULL)
+ material = gDefaultFont->GetMaterial();
+ }
+
+ return std::make_pair (font, material);
+}
+
+void GUIText::Reset ()
+{
+ Super::Reset ();
+ m_PixelCorrect = true;
+ m_Anchor = kUpperLeft;
+ m_Alignment = kLeft;
+ m_LineSpacing = 1.0F;
+ m_TabSize = 4.0F;
+ m_PixelOffset = Vector2f(0,0);
+}
+
+Material* GUIText::GetMaterial ()
+{
+ return GetFontAndMaterial ().second;
+}
+
+void GUIText::SetMaterial (Material* material)
+{
+ m_Material = material;
+ SetDirty ();
+}
+
+void GUIText::SetFont (PPtr<Font> font)
+{
+ m_Font = font;
+ SetDirty();
+}
+
+
+template<class TransferFunction> inline
+void GUIText::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ transfer.SetVersion (3);
+ TRANSFER_SIMPLE(m_Text);
+ TRANSFER_SIMPLE(m_Anchor);
+ TRANSFER_SIMPLE(m_Alignment);
+ TRANSFER(m_PixelOffset);
+ TRANSFER(m_LineSpacing);
+ TRANSFER(m_TabSize);
+ TRANSFER(m_Font);
+ TRANSFER(m_Material);
+ TRANSFER(m_FontSize);
+ TRANSFER(m_FontStyle);
+ TRANSFER(m_Color);
+
+ TRANSFER(m_PixelCorrect);
+ TRANSFER(m_RichText);
+
+ #if UNITY_EDITOR
+ // Explanation: in verson 1.2.2 we added pixel correct drawing. By default it is on.
+ // for backwards compatbility we disable it
+ if(transfer.IsOldVersion(1))
+ m_PixelCorrect = false;
+
+ // In version 1.5.0 line spacing is multiplicative instead of additive
+ if(transfer.IsOldVersion(1) || transfer.IsOldVersion(2))
+ {
+ Font* font = GetFont();
+ m_LineSpacing = (font->GetLineSpacing() + m_LineSpacing) / font->GetLineSpacing();
+ }
+ #endif
+}
+
+IMPLEMENT_CLASS (GUIText)
+IMPLEMENT_OBJECT_SERIALIZE (GUIText)
diff --git a/Runtime/Camera/RenderLayers/GUIText.h b/Runtime/Camera/RenderLayers/GUIText.h
new file mode 100644
index 0000000..fdfeeb9
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUIText.h
@@ -0,0 +1,93 @@
+#ifndef GUITEXT_H
+#define GUITEXT_H
+
+#include <string>
+#include "GUIElement.h"
+#include "Runtime/Math/Color.h"
+#include "Runtime/Math/Vector2.h"
+
+class Font;
+namespace Unity { class Material; }
+
+/// Can be Attached to any game object in the scene.
+/// Registers with GUILayer, GUILayer renders it.
+/// Position comes from transform.position.x,y
+/// size comes from transform.scale.x,y
+class GUIText : public GUIElement
+{
+ public:
+
+ REGISTER_DERIVED_CLASS (GUIText, GUIElement)
+ DECLARE_OBJECT_SERIALIZE (GUIText)
+
+ GUIText (MemLabelId label, ObjectCreationMode mode);
+ virtual void Reset ();
+
+ const UnityStr& GetText () const { return m_Text; }
+ void SetText (const std::string& text) { m_Text = text; }
+
+ // GUIElement
+ virtual void RenderGUIElement (const Rectf& cameraRect);
+ virtual Rectf GetScreenRect (const Rectf& cameraRect);
+
+ void SetFont (PPtr<Font> font);
+ Font * GetFont () const;
+
+ Material* GetMaterial ();
+ void SetMaterial (Material* material);
+
+ void SetPixelOffset (const Vector2f& offset) { m_PixelOffset = offset; SetDirty(); }
+ Vector2f GetPixelOffset () { return m_PixelOffset; }
+
+ void SetLineSpacing (float space) { m_LineSpacing = space; SetDirty(); }
+ float GetLineSpacing() const { return m_LineSpacing; }
+
+ void SetTabSize (float size) { m_TabSize = size; SetDirty(); }
+ float GetTabSize() const { return m_TabSize; }
+
+ void SetAlignment (int align) { m_Alignment = align; SetDirty(); }
+ int GetAlignment() const { return m_Alignment; }
+
+ void SetAnchor (int size) { m_Anchor = size; SetDirty(); }
+ int GetAnchor() const { return m_Anchor; }
+
+ void SetFontSize (int size) { m_FontSize = size; SetDirty(); }
+ int GetFontSize() const { return m_FontSize; }
+
+ void SetFontStyle (int style) { m_FontStyle = style; SetDirty(); }
+ int GetFontStyle() const { return m_FontStyle; }
+
+ void SetRichText (bool richText) { m_RichText = richText; SetDirty(); }
+ bool GetRichText() const { return m_RichText; }
+
+ void SetColor (ColorRGBA32 color) { m_Color = color; SetDirty(); }
+ ColorRGBA32 GetColor() const { return m_Color; }
+
+ private:
+
+ std::pair<Font*, Material*> GetFontAndMaterial ();
+
+ UnityStr m_Text;
+
+ short m_Alignment; ///< enum { left, center, right }
+ short m_Anchor; ///< Where the text-mesh is anchored related to local origo. enum { upper left, upper center, upper right, middle left, middle center, middle right, lower left, lower center, lower right }
+
+ float m_LineSpacing; ///< Spacing between lines as multiplum of height of a character.
+ float m_TabSize; ///< Length of one tab
+ bool m_PixelCorrect; ///< Place & scale the text to a pixel-correct position.
+ bool m_RichText;///< Enable HTML-style tags for text formatting.
+ Vector2f m_PixelOffset;
+
+ int m_FontSize; ///<The font size to use. Set to 0 to use default font size. Only applicable for dynamic fonts.
+ int m_FontStyle; ///<The font style to use. Only applicable for dynamic fonts. enum { Normal, Bold, Italic, Bold and Italic }
+
+ ColorRGBA32 m_Color;
+
+ PPtr<Font> m_Font;
+ PPtr<Material> m_Material;
+};
+
+
+void DrawGUIText (const std::string& text, Font* font, Material* material);
+
+#endif
diff --git a/Runtime/Camera/RenderLayers/GUITexture.cpp b/Runtime/Camera/RenderLayers/GUITexture.cpp
new file mode 100644
index 0000000..b30d7e4
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUITexture.cpp
@@ -0,0 +1,524 @@
+#include "UnityPrefix.h"
+#include "GUITexture.h"
+#include "External/shaderlab/Library/texenv.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Shaders/Shader.h"
+#include "Runtime/Shaders/Material.h"
+#include "External/shaderlab/Library/properties.h"
+#include "Runtime/Utilities/BitUtility.h"
+#include "Runtime/GfxDevice/GfxDevice.h"
+#include "Runtime/Shaders/VBO.h"
+#include "Runtime/Camera/CameraUtil.h"
+#include "Runtime/Shaders/GraphicsCaps.h"
+#include "External/shaderlab/Library/intshader.h"
+#include "Runtime/Profiler/Profiler.h"
+#include "Runtime/Misc/ResourceManager.h"
+
+extern bool IsNPOTTextureAllowed(bool hasMipMap);
+
+static SHADERPROP (MainTex);
+static Shader* gGUI2DShader = NULL;
+static Material* gGUI2DMaterial = NULL;
+
+
+// can't do in InitializeClass because graphics might not be created yet
+static void InitializeGUIShaders()
+{
+ if( !gGUI2DMaterial )
+ {
+ Shader* shader = GetBuiltinResource<Shader> ("Internal-GUITexture.shader");
+ gGUI2DMaterial = Material::CreateMaterial (*shader, Object::kHideAndDontSave);
+ gGUI2DShader = gGUI2DMaterial->GetShader ();
+ }
+}
+
+void GUITexture::InitializeClass ()
+{
+}
+
+void GUITexture::CleanupClass ()
+{
+ gGUI2DShader = NULL;
+ gGUI2DMaterial = NULL;
+}
+
+GUITexture::GUITexture (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+ m_Sheet = NULL;
+ m_PrevTextureWidth = 0;
+ m_PrevTextureHeight = 0;
+ m_PrevTextureBaseLevel = Texture::GetMasterTextureLimit();
+}
+
+GUITexture::~GUITexture ()
+{
+ SAFE_RELEASE_LABEL(m_Sheet, kMemShader);
+}
+
+void GUITexture::BuildSheet()
+{
+ InitializeGUIShaders();
+
+ Texture* texture = m_Texture;
+ if( !texture )
+ return;
+
+ SAFE_RELEASE_LABEL(m_Sheet, kMemShader);
+ bool is2D = (texture->GetDimension () == kTexDim2D);
+ m_Sheet = gGUI2DShader->MakeProperties();
+ m_Sheet->SetTexture (kSLPropMainTex, texture);
+
+ ShaderLab::PropertySheet::TextureProperty* prop = m_Sheet->GetTextureProperty (kSLPropMainTex);
+ if (prop && prop->scaleOffsetValue)
+ {
+ // for NPOT textures (in case it is not supported) override the GL texture name and texture scale
+ // so that we use unscaled texture and ignore the padded dummy portion
+ bool isNPOT = !IsPowerOfTwo(m_PrevTextureWidth) || !IsPowerOfTwo(m_PrevTextureHeight);
+ if( is2D && isNPOT && !IsNPOTTextureAllowed(texture->HasMipMap()) )
+ {
+ // Need to take master texture limit into account because that
+ // changes scaling...
+ int baseMipLevel = Texture::GetMasterTextureLimit();
+ if( !texture->HasMipMap() )
+ baseMipLevel = 0;
+ int texWidth = texture->GetDataWidth() >> baseMipLevel;
+ int texHeight = texture->GetDataHeight() >> baseMipLevel;
+ int actualWidth = texture->GetGLWidth() >> baseMipLevel;
+ int actualHeight = texture->GetGLHeight() >> baseMipLevel;
+ // ...and shifting above might produce zeros
+ float scaleX = (actualWidth > 0) ? float(texWidth) / float(actualWidth) : 1.0f;
+ float scaleY = (actualHeight > 0) ? float(texHeight) / float(actualHeight) : 1.0f;
+ scaleX *= texture->GetUVScaleX();
+ scaleY *= texture->GetUVScaleY();
+ prop->texEnv->OverrideTextureInfo( texture->GetUnscaledTextureID(), scaleX, scaleY );
+ prop->scaleOffsetValue->Set (scaleX, scaleY, 0,0);
+ }
+ else
+ {
+ prop->scaleOffsetValue->Set (1,1,0,0);
+ }
+ }
+}
+
+void GUITexture::AwakeFromLoad (AwakeFromLoadMode awakeMode) {
+ Super::AwakeFromLoad (awakeMode);
+ BuildSheet ();
+}
+
+void GUITexture::SetTexture (Texture* tex)
+{
+ m_Texture = tex;
+ if( tex )
+ {
+ m_PrevTextureWidth = tex->GetDataWidth();
+ m_PrevTextureHeight = tex->GetDataHeight();
+ }
+ m_PrevTextureBaseLevel = Texture::GetMasterTextureLimit();
+ if( tex && !tex->HasMipMap() )
+ m_PrevTextureBaseLevel = 0;
+ BuildSheet ();
+}
+
+Texture* GUITexture::GetTexture ()
+{
+ return m_Texture;
+}
+
+void GUITexture::Reset ()
+{
+ Super::Reset ();
+ m_Color = ColorRGBAf (.5, .5, .5, .5);
+ m_LeftBorder = m_RightBorder = m_TopBorder = m_BottomBorder = 0;
+ m_PixelInset = Rectf (0,0,0,0);
+}
+
+void GUITexture::SetColor (const ColorRGBAf& color) {
+ m_Color = color;
+ BuildSheet ();
+ SetDirty ();
+}
+
+struct GUITextureVertex {
+ Vector3f vert;
+ ColorRGBA32 color;
+ Vector2f uv;
+};
+
+static bool FillGUITextureVBOChunk( const Rectf &screenRect, Texture* tex, const Rectf &sourceRect, int leftBorder, int rightBorder, int topBorder, int bottomBorder, ColorRGBA32 color )
+{
+ DebugAssertIf( !tex );
+ Vector2f texScale (1.0f / (float)tex->GetDataWidth(), 1.0f / (float)tex->GetDataHeight());
+
+ float x0 = RoundfToInt(screenRect.x);
+ float x3 = RoundfToInt(screenRect.GetRight());
+
+ int y0 = RoundfToInt(screenRect.y);
+ int y3 = RoundfToInt(screenRect.GetBottom());
+
+ float x1 = x0 + (float)leftBorder;
+ float x2 = x3 - (float)rightBorder;
+ int y1 = int(y0 + (float)bottomBorder);
+ int y2 = int(y3 - (float)topBorder);
+
+ float tx0 = sourceRect.x;
+ float tx1 = tx0 + texScale.x * (float)leftBorder;
+ float tx3 = sourceRect.GetRight();
+ float tx2 = tx3 - texScale.x * (float)rightBorder;
+
+ float ty0 = sourceRect.y;
+ float ty1 = ty0 + texScale.y * (float)bottomBorder;
+ float ty3 = sourceRect.GetBottom();
+ float ty2 = ty3 - texScale.y * (float)topBorder;
+
+ GUITextureVertex* vbPtr;
+ unsigned short* ibPtr;
+ DynamicVBO& vbo = GetGfxDevice().GetDynamicVBO();
+ if( !vbo.GetChunk(
+ (1<<kShaderChannelVertex) | (1<<kShaderChannelColor) | (1<<kShaderChannelTexCoord0),
+ 16, // 16 vertices
+ 9*6, // 9 quads
+ DynamicVBO::kDrawIndexedTriangles,
+ (void**)&vbPtr, (void**)&ibPtr ) )
+ {
+ return false;
+ }
+
+ vbPtr[ 0].vert.Set( x0, y0, 0.0f ); vbPtr[ 0].color = color; vbPtr[ 0].uv.Set( tx0, ty0 );
+ vbPtr[ 1].vert.Set( x1, y0, 0.0f ); vbPtr[ 1].color = color; vbPtr[ 1].uv.Set( tx1, ty0 );
+ vbPtr[ 2].vert.Set( x2, y0, 0.0f ); vbPtr[ 2].color = color; vbPtr[ 2].uv.Set( tx2, ty0 );
+ vbPtr[ 3].vert.Set( x3, y0, 0.0f ); vbPtr[ 3].color = color; vbPtr[ 3].uv.Set( tx3, ty0 );
+ vbPtr[ 4].vert.Set( x0, y1, 0.0f ); vbPtr[ 4].color = color; vbPtr[ 4].uv.Set( tx0, ty1 );
+ vbPtr[ 5].vert.Set( x1, y1, 0.0f ); vbPtr[ 5].color = color; vbPtr[ 5].uv.Set( tx1, ty1 );
+ vbPtr[ 6].vert.Set( x2, y1, 0.0f ); vbPtr[ 6].color = color; vbPtr[ 6].uv.Set( tx2, ty1 );
+ vbPtr[ 7].vert.Set( x3, y1, 0.0f ); vbPtr[ 7].color = color; vbPtr[ 7].uv.Set( tx3, ty1 );
+ vbPtr[ 8].vert.Set( x0, y2, 0.0f ); vbPtr[ 8].color = color; vbPtr[ 8].uv.Set( tx0, ty2 );
+ vbPtr[ 9].vert.Set( x1, y2, 0.0f ); vbPtr[ 9].color = color; vbPtr[ 9].uv.Set( tx1, ty2 );
+ vbPtr[10].vert.Set( x2, y2, 0.0f ); vbPtr[10].color = color; vbPtr[10].uv.Set( tx2, ty2 );
+ vbPtr[11].vert.Set( x3, y2, 0.0f ); vbPtr[11].color = color; vbPtr[11].uv.Set( tx3, ty2 );
+ vbPtr[12].vert.Set( x0, y3, 0.0f ); vbPtr[12].color = color; vbPtr[12].uv.Set( tx0, ty3 );
+ vbPtr[13].vert.Set( x1, y3, 0.0f ); vbPtr[13].color = color; vbPtr[13].uv.Set( tx1, ty3 );
+ vbPtr[14].vert.Set( x2, y3, 0.0f ); vbPtr[14].color = color; vbPtr[14].uv.Set( tx2, ty3 );
+ vbPtr[15].vert.Set( x3, y3, 0.0f ); vbPtr[15].color = color; vbPtr[15].uv.Set( tx3, ty3 );
+
+ static UInt16 ib[9*6] = {
+ 0, 4, 1, 1, 4, 5,
+ 1, 5, 2, 2, 5, 6,
+ 2, 6, 3, 3, 6, 7,
+ 4, 8, 5, 5, 8, 9,
+ 5, 9, 6, 6, 9, 10,
+ 6, 10, 7, 7, 10, 11,
+ 8, 12, 9, 9, 12, 13,
+ 9, 13, 10, 10, 13, 14,
+ 10, 14, 11, 11, 14, 15,
+ };
+ memcpy( ibPtr, ib, sizeof(ib) );
+ vbo.ReleaseChunk( 16, 9*6 );
+
+ return true;
+}
+
+PROFILER_INFORMATION(gRenderGUITexture, "GUITexture.Render", kProfilerGUI)
+PROFILER_INFORMATION(gSubmitVBOProfileGUITexture, "Mesh.SubmitVBO", kProfilerRender)
+
+void GUITexture::DrawGUITexture (const Rectf &bounds)
+{
+ PROFILER_AUTO(gRenderGUITexture, NULL)
+
+ InitializeGUIShaders();
+
+ Shader* shader = gGUI2DShader;
+
+ GfxDevice& device = GetGfxDevice();
+ DynamicVBO& vbo = device.GetDynamicVBO();
+
+ ColorRGBA32 color = m_Color;
+ color = device.ConvertToDeviceVertexColor(color);
+
+ if( !FillGUITextureVBOChunk( bounds, m_Texture, Rectf(0,0,1,1), m_LeftBorder, m_RightBorder, m_TopBorder, m_BottomBorder, color ) )
+ return;
+ const ShaderLab::SubShader& ss = shader->GetShaderLabShader()->GetActiveSubShader();
+ const int passCount = ss.GetValidPassCount();
+ for( int i = 0; i != passCount; ++i )
+ {
+ const ChannelAssigns* channels = shader->SetPass (0, i, 0, m_Sheet);
+
+ PROFILER_BEGIN(gSubmitVBOProfileGUITexture, this)
+ vbo.DrawChunk (*channels);
+ GPU_TIMESTAMP();
+ PROFILER_END
+ }
+}
+
+void GUITexture::RenderGUIElement (const Rectf& cameraRect)
+{
+ Texture* tex = m_Texture;
+ if( !tex )
+ return;
+
+ // Before rendering check whether something serious has changed:
+ // * texture could have changed from POT to NPOT, or the size may have changed (at least in the editor)
+ // * global texture limit might have changed
+ int texWidth = tex->GetDataWidth();
+ int texHeight = tex->GetDataHeight();
+ int masterTexLimit = Texture::GetMasterTextureLimit();
+ if( !tex->HasMipMap() )
+ masterTexLimit = 0;
+ if( texWidth != m_PrevTextureWidth || texHeight != m_PrevTextureHeight || m_PrevTextureBaseLevel != masterTexLimit )
+ {
+ m_PrevTextureWidth = texWidth;
+ m_PrevTextureHeight = texHeight;
+ m_PrevTextureBaseLevel = masterTexLimit;
+ BuildSheet();
+ }
+
+ GfxDevice& device = GetGfxDevice();
+ DeviceMVPMatricesState preserveMVP;
+
+ Rectf rectNoOffset = cameraRect;
+ rectNoOffset.Move( -rectNoOffset.x, -rectNoOffset.y );
+ LoadPixelMatrix( rectNoOffset, device, true, false );
+
+ Rectf drawBox = CalculateDrawBox (cameraRect);
+ DrawGUITexture (drawBox);
+}
+
+Rectf GUITexture::CalculateDrawBox (const Rectf& screenViewportRect)
+{
+ Transform& transform = GetComponent (Transform);
+ Rectf drawBox;
+
+ Vector3f position = transform.GetPosition ();
+ Vector3f scale = transform.GetWorldScaleLossy ();
+
+ float xmin = position.x - scale.x * 0.5F;
+ float xmax = position.x + scale.x * 0.5F;
+
+ float ymin = position.y - scale.y * 0.5F;
+ float ymax = position.y + scale.y * 0.5F;
+
+ drawBox.x = screenViewportRect.Width() * xmin + m_PixelInset.x;
+ drawBox.SetRight( screenViewportRect.Width() * xmax + m_PixelInset.GetRight() );
+ drawBox.y = screenViewportRect.Height() * ymin + m_PixelInset.y;
+ drawBox.SetBottom( screenViewportRect.Height() * ymax + m_PixelInset.GetBottom() );
+
+ return drawBox;
+}
+
+Rectf GUITexture::GetScreenRect (const Rectf& cameraRect)
+{
+ return CalculateDrawBox (cameraRect);
+}
+
+template<class TransferFunction>
+void GUITexture::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ TRANSFER_SIMPLE (m_Texture);
+ TRANSFER_SIMPLE (m_Color);
+
+ TRANSFER (m_PixelInset);
+
+ TRANSFER (m_LeftBorder);
+ TRANSFER (m_RightBorder);
+ TRANSFER (m_TopBorder);
+ TRANSFER (m_BottomBorder);
+}
+
+IMPLEMENT_CLASS_HAS_INIT (GUITexture)
+IMPLEMENT_OBJECT_SERIALIZE (GUITexture)
+
+void DrawGUITexture (const Rectf &screenRect, Texture* texture, ColorRGBA32 color, Material* material) {
+ DrawGUITexture (screenRect, texture, 0,0,0,0, color, material);
+}
+void DrawGUITexture (const Rectf &screenRect, Texture* texture, int leftBorder, int rightBorder, int topBorder, int bottomBorder, ColorRGBA32 color, Material* material) {
+ DrawGUITexture (screenRect, texture, Rectf (0,0,1,1), leftBorder, rightBorder, topBorder, bottomBorder, color, material);
+}
+
+void HandleGUITextureProps( ShaderLab::PropertySheet *sheet, Texture *texture )
+{
+ sheet->SetTexture (kSLPropMainTex, texture);
+
+ int texWidth = texture->GetDataWidth();
+ int texHeight = texture->GetDataHeight();
+
+ ShaderLab::PropertySheet::TextureProperty* prop = sheet->GetTextureProperty (kSLPropMainTex);
+ if (prop && prop->scaleOffsetValue)
+ {
+ float uvScaleX = texture->GetUVScaleX();
+ float uvScaleY = texture->GetUVScaleY();
+
+ // for NPOT textures (in case it is not supported) override the GL texture name and texture scale
+ // so that we use unscaled texture and ignore the padded dummy portion
+ bool isNPOT = !IsPowerOfTwo(texWidth) || !IsPowerOfTwo(texHeight);
+ if( texture->GetDimension() == kTexDim2D && isNPOT && !IsNPOTTextureAllowed(texture->HasMipMap()) )
+ {
+ // Need to take master texture limit into account because that
+ // changes scaling...
+ int baseMipLevel = Texture::GetMasterTextureLimit();
+ if (!texture->HasMipMap())
+ baseMipLevel = 0;
+ texWidth = texWidth >> baseMipLevel;
+ texHeight = texHeight >> baseMipLevel;
+ int actualWidth = texture->GetGLWidth() >> baseMipLevel;
+ int actualHeight = texture->GetGLHeight() >> baseMipLevel;
+ // ...and shifting above might produce zeros
+ float scaleX = (actualWidth > 0) ? float(texWidth) / float(actualWidth) : 1.0f;
+ float scaleY = (actualHeight > 0) ? float(texHeight) / float(actualHeight) : 1.0f;
+ scaleX *= uvScaleX;
+ scaleY *= uvScaleY;
+ prop->texEnv->OverrideTextureInfo( texture->GetUnscaledTextureID(), scaleX, scaleY );
+ prop->scaleOffsetValue->Set (scaleX, scaleY, 0, 0);
+ }
+ else
+ {
+ prop->scaleOffsetValue->Set (uvScaleX,uvScaleY,0,0);
+ }
+ }
+}
+
+// Fills out the VBO with the new inverted-coordinate GUI rectangle
+
+static bool FillGUITextureVBOChunkInverted( const Rectf &screenRect, Texture* tex, const Rectf &sourceRect, int leftBorder, int rightBorder, int topBorder, int bottomBorder, ColorRGBA32 color, UInt32* outTriangles )
+{
+ DebugAssertIf( !tex );
+ Vector2f texScale (1.0f / (float)tex->GetDataWidth(), 1.0f / (float)tex->GetDataHeight());
+
+ float x0 = RoundfToInt(screenRect.x);
+ float x3 = RoundfToInt(screenRect.GetRight());
+ float y0 = RoundfToInt(screenRect.GetBottom());
+ float y3 = RoundfToInt(screenRect.y);
+
+ float tx0 = sourceRect.x;
+ float tx3 = sourceRect.GetRight();
+ float ty0 = sourceRect.y;
+ float ty3 = sourceRect.GetBottom();
+
+ GUITextureVertex* vbPtr;
+ unsigned short* ibPtr;
+ DynamicVBO& vbo = GetGfxDevice().GetDynamicVBO();
+
+ if ((leftBorder|rightBorder|topBorder|bottomBorder) == 0)
+ {
+ // no borders, texture is just a quad
+ if( !vbo.GetChunk(
+ (1<<kShaderChannelVertex) | (1<<kShaderChannelColor) | (1<<kShaderChannelTexCoord0),
+ 4, // 4 vertices
+ 6, // 1 quad
+ DynamicVBO::kDrawIndexedTriangles,
+ (void**)&vbPtr, (void**)&ibPtr ) )
+ {
+ return false;
+ }
+
+ vbPtr[ 0].vert.Set( x0, y0, 0.0f ); vbPtr[ 0].color = color; vbPtr[ 0].uv.Set( tx0, ty0 );
+ vbPtr[ 1].vert.Set( x3, y0, 0.0f ); vbPtr[ 1].color = color; vbPtr[ 1].uv.Set( tx3, ty0 );
+ vbPtr[ 2].vert.Set( x0, y3, 0.0f ); vbPtr[ 2].color = color; vbPtr[ 2].uv.Set( tx0, ty3 );
+ vbPtr[ 3].vert.Set( x3, y3, 0.0f ); vbPtr[ 3].color = color; vbPtr[ 3].uv.Set( tx3, ty3 );
+ static UInt16 ib[1*6] = {
+ 0, 2, 1, 1, 2, 3,
+ };
+ memcpy( ibPtr, ib, sizeof(ib) );
+ vbo.ReleaseChunk( 4, 6 );
+ *outTriangles = 2;
+ }
+ else
+ {
+ // with borders, texture is a 3x3 quad grid
+ float x1 = x0 + (float)leftBorder;
+ float x2 = x3 - (float)rightBorder;
+ float y1 = y0 - (float)topBorder;
+ float y2 = y3 + (float)bottomBorder;
+
+ float tx1 = tx0 + texScale.x * (float)leftBorder;
+ float tx2 = tx3 - texScale.x * (float)rightBorder;
+ float ty1 = ty0 + texScale.y * (float)topBorder;
+ float ty2 = ty3 - texScale.y * (float)bottomBorder;
+
+ if( !vbo.GetChunk(
+ (1<<kShaderChannelVertex) | (1<<kShaderChannelColor) | (1<<kShaderChannelTexCoord0),
+ 16, // 16 vertices
+ 9*6, // 9 quads
+ DynamicVBO::kDrawIndexedTriangles,
+ (void**)&vbPtr, (void**)&ibPtr ) )
+ {
+ return false;
+ }
+
+ vbPtr[ 0].vert.Set( x0, y0, 0.0f ); vbPtr[ 0].color = color; vbPtr[ 0].uv.Set( tx0, ty0 );
+ vbPtr[ 1].vert.Set( x1, y0, 0.0f ); vbPtr[ 1].color = color; vbPtr[ 1].uv.Set( tx1, ty0 );
+ vbPtr[ 2].vert.Set( x2, y0, 0.0f ); vbPtr[ 2].color = color; vbPtr[ 2].uv.Set( tx2, ty0 );
+ vbPtr[ 3].vert.Set( x3, y0, 0.0f ); vbPtr[ 3].color = color; vbPtr[ 3].uv.Set( tx3, ty0 );
+ vbPtr[ 4].vert.Set( x0, y1, 0.0f ); vbPtr[ 4].color = color; vbPtr[ 4].uv.Set( tx0, ty1 );
+ vbPtr[ 5].vert.Set( x1, y1, 0.0f ); vbPtr[ 5].color = color; vbPtr[ 5].uv.Set( tx1, ty1 );
+ vbPtr[ 6].vert.Set( x2, y1, 0.0f ); vbPtr[ 6].color = color; vbPtr[ 6].uv.Set( tx2, ty1 );
+ vbPtr[ 7].vert.Set( x3, y1, 0.0f ); vbPtr[ 7].color = color; vbPtr[ 7].uv.Set( tx3, ty1 );
+ vbPtr[ 8].vert.Set( x0, y2, 0.0f ); vbPtr[ 8].color = color; vbPtr[ 8].uv.Set( tx0, ty2 );
+ vbPtr[ 9].vert.Set( x1, y2, 0.0f ); vbPtr[ 9].color = color; vbPtr[ 9].uv.Set( tx1, ty2 );
+ vbPtr[10].vert.Set( x2, y2, 0.0f ); vbPtr[10].color = color; vbPtr[10].uv.Set( tx2, ty2 );
+ vbPtr[11].vert.Set( x3, y2, 0.0f ); vbPtr[11].color = color; vbPtr[11].uv.Set( tx3, ty2 );
+ vbPtr[12].vert.Set( x0, y3, 0.0f ); vbPtr[12].color = color; vbPtr[12].uv.Set( tx0, ty3 );
+ vbPtr[13].vert.Set( x1, y3, 0.0f ); vbPtr[13].color = color; vbPtr[13].uv.Set( tx1, ty3 );
+ vbPtr[14].vert.Set( x2, y3, 0.0f ); vbPtr[14].color = color; vbPtr[14].uv.Set( tx2, ty3 );
+ vbPtr[15].vert.Set( x3, y3, 0.0f ); vbPtr[15].color = color; vbPtr[15].uv.Set( tx3, ty3 );
+ static UInt16 ib[9*6] = {
+ 0, 4, 1, 1, 4, 5, // Top-left
+ 1, 5, 2, 2, 5, 6, // Top-mid
+ 2, 6, 3, 3, 6, 7, // Top-right
+ 4, 8, 5, 5, 8, 9, // mid-left
+ 5, 9, 6, 6, 9, 10, // mid-center
+ 6, 10, 7, 7, 10, 11, // mid-right
+ 8, 12, 9, 9, 12, 13, // bottom-left
+ 9, 13, 10, 10, 13, 14, // bottom-mid
+ 10, 14, 11, 11, 14, 15, // bottom-right
+ };
+ memcpy( ibPtr, ib, sizeof(ib) );
+ vbo.ReleaseChunk( 16, 9*6 );
+ *outTriangles = 9 * 2;
+ }
+
+ return true;
+}
+
+void DrawGUITexture (const Rectf &screenRect, Texture* tex, const Rectf &sourceRect, int leftBorder, int rightBorder, int topBorder, int bottomBorder, ColorRGBA32 color, Material* material)
+{
+ InitializeGUIShaders();
+
+ if( !tex )
+ {
+ ErrorString ("DrawGUITexture: texture is null");
+ return;
+ }
+
+ GfxDevice& device = GetGfxDevice();
+ color = device.ConvertToDeviceVertexColor( color );
+ UInt32 triCount;
+
+ // temp workaround to flip Y-axis. should probably be done in FillGUITextureVBOChunk - but for now we do it here
+ if( !FillGUITextureVBOChunkInverted( screenRect, tex, sourceRect, leftBorder, rightBorder, bottomBorder, topBorder, color, &triCount ) )
+ return;
+
+ if (material)
+ {
+ HandleGUITextureProps( &material->GetWritableProperties(), tex );
+ }
+ else
+ {
+ HandleGUITextureProps( &gGUI2DMaterial->GetWritableProperties(), tex );
+ material = gGUI2DMaterial;
+ }
+
+ int passCount = material->GetPassCount();
+
+ DynamicVBO& vbo = device.GetDynamicVBO();
+
+ for( int i = 0; i < passCount; ++i)
+ {
+ const ChannelAssigns* channels = material->SetPass (i, 0, false);
+
+ PROFILER_BEGIN(gSubmitVBOProfileGUITexture, NULL);
+ vbo.DrawChunk (*channels);
+ GPU_TIMESTAMP();
+ PROFILER_END
+ }
+}
diff --git a/Runtime/Camera/RenderLayers/GUITexture.h b/Runtime/Camera/RenderLayers/GUITexture.h
new file mode 100644
index 0000000..55988ae
--- /dev/null
+++ b/Runtime/Camera/RenderLayers/GUITexture.h
@@ -0,0 +1,73 @@
+#ifndef GUITEXTURE_H
+#define GUITEXTURE_H
+
+#include "GUIElement.h"
+#include "Runtime/Graphics/Texture.h"
+#include "Runtime/Math/Color.h"
+#include "Runtime/Math/Rect.h"
+
+
+namespace Unity { class Material; }
+namespace ShaderLab { class PropertySheet; }
+
+// Attached to any game object in the scene.
+// Registers with GUILayer, GUILayer renders it.
+// Position comes from transform.position.x,y
+// size comes from transform.scale.x,y
+class GUITexture : public GUIElement
+{
+public:
+
+ REGISTER_DERIVED_CLASS (GUITexture, GUIElement)
+ DECLARE_OBJECT_SERIALIZE (GUITexture)
+
+ GUITexture (MemLabelId label, ObjectCreationMode mode);
+
+ virtual void Reset ();
+
+ // GUIElement
+ virtual void RenderGUIElement (const Rectf& cameraRect);
+ virtual Rectf GetScreenRect (const Rectf& cameraRect);
+
+ virtual void AwakeFromLoad(AwakeFromLoadMode mode);
+
+ void SetColor (const ColorRGBAf& color);
+ inline ColorRGBAf GetColor () { return m_Color; }
+
+ void SetTexture (Texture* tex);
+ Texture* GetTexture ();
+
+ int m_LeftBorder; ///< The border pixels - this part of texture is never scaled.
+ int m_RightBorder; ///< The border pixels - this part of texture is never scaled.
+ int m_TopBorder; ///< The border pixels - this part of texture is never scaled.
+ int m_BottomBorder; ///< The border pixels - this part of texture is never scaled.
+
+ PPtr<Texture> m_Texture; ///< The texture to use.
+ ColorRGBAf m_Color; ///< Tint color.
+
+ static void InitializeClass();
+ static void CleanupClass();
+
+ const Rectf &GetPixelInset() const { return m_PixelInset; }
+ void SetPixelInset(const Rectf &r) { m_PixelInset = r; SetDirty(); }
+
+private:
+ void DrawGUITexture (const Rectf& bounds);
+ void BuildSheet ();
+ Rectf CalculateDrawBox (const Rectf& screenViewportRect);
+
+ Rectf m_PixelInset;
+
+ ShaderLab::PropertySheet *m_Sheet;
+ int m_PrevTextureWidth;
+ int m_PrevTextureHeight;
+ int m_PrevTextureBaseLevel;
+};
+
+// Immediate mode DrawGUITexture API
+void DrawGUITexture (const Rectf &screenRect, Texture* texture, const Rectf &sourceRect, int leftBorder, int rightBorder, int topBorder, int bottomBorder, ColorRGBA32 color, Material* material = NULL);
+void DrawGUITexture (const Rectf &screenRect, Texture* texture, int leftBorder, int rightBorder, int topBorder, int bottomBorder, ColorRGBA32 color, Material* material = NULL);
+void DrawGUITexture (const Rectf &screenRect, Texture* texture, ColorRGBA32 color, Material* material = NULL);
+void HandleGUITextureProps (ShaderLab::PropertySheet *sheet, Texture *texture);
+
+#endif