From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/Camera/RenderLayers/GUITexture.cpp | 524 +++++++++++++++++++++++++++++ 1 file changed, 524 insertions(+) create mode 100644 Runtime/Camera/RenderLayers/GUITexture.cpp (limited to 'Runtime/Camera/RenderLayers/GUITexture.cpp') 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 ("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<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 +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<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 + } +} -- cgit v1.1-26-g67d0