GUI

    I need to create simple GUI. I need to draw rectangle, text. Need to add some GUI elements like buttons and text editor. Need 2 methods for drawing, for drawing rectangle and for drawing text. All GUI elements will use this 2 methods.

    First, I need to create basic classes and draw rectangle.

    I want to draw GUI into RTT, and then combine it with main target RTT.

    All methods for GUI will be in slFramework.

    GS must draw text and rectangle. For this, GS must have special projection matrix and shader.

    
    class slD3D11ShaderGUIRectangle : public slGSD3D11ShaderBase
    {
    public:
    	slD3D11ShaderGUIRectangle(slGSD3D11* gs);
    	virtual ~slD3D11ShaderGUIRectangle();
    
    	slGSD3D11* m_gs = 0;
    
    	ID3D11Buffer* m_cbFrame = 0;
    	ID3D11Buffer* m_cbElement = 0;
    
    	struct cbFrame
    	{
    		slMatrix4_t<float> ProjMtx;
    	}m_cbDataFrame;
    	
    	struct cbElement
    	{
    		slVec4f Corners;
    		slColor Color1;
    		slColor Color2;
    		slVec4f UVs;
    	}m_cbDataElement;
    
    	virtual void SetConstants(slMaterial* material);
    
    	void SetData();
    	bool init();
    
    	void SetOnFrame();
    	void SetOnElement(slGSD3D11Texture*);
    };
    

    Implementation

    
    bool slD3D11ShaderGUIRectangle::init(){
    	const char* text =
    		"Texture2D tex2d_1;\n"
    		"SamplerState tex2D_sampler_1;\n"
    		"struct VSIn{\n"
    		"   float3 position : POSITION;\n"
    		"   float2 uv : TEXCOORD;\n"
    		"};\n"
    		"cbuffer cbFrame{\n"
    		"	float4x4 ProjMtx;\n"
    		"};\n"
    		"cbuffer cbElement{\n"
    		"	float4 Corners;\n"
    		"	float4 Color1;\n"
    		"	float4 Color2;\n"
    		"	float4 UVs;\n"
    		"};\n"
    		"struct VSOut{\n"
    		"   float4 pos : SV_POSITION;\n"
    		"   float2 uv : TEXCOORD0;\n"
    		"	float4 color : COLOR0;\n"
    		"};\n"
    		"struct PSOut{\n"
    		"    float4 color : SV_Target;\n"
    		"};\n"
    		"VSOut VSMain(VSIn input){\n"
    		"   VSOut output;\n"
    		"	output.pos.xyz   = input.position.xyz;\n"
    		"	output.pos.w   = 1.f;\n"
    		"	output.uv   = input.uv;\n"
    		"	return output;\n"
    		"}\n"
    		"PSOut PSMain(VSOut input){\n"
    		"   PSOut output;\n"
    		"   output.color = tex2d_1.Sample(tex2D_sampler_1, input.uv) * input.color;\n"
    		"   output.color.w = 1.f;\n"
    		"   return output;\n"
    		"}\n"
    		"[maxvertexcount(4)]\n"
    		"void GSMain(point VSOut input[1], inout TriangleStream<VSOut> TriStream ){\n"
    		"	VSOut Out;\n"
    
    		"   float4 v1 = mul(ProjMtx, float4(Corners.x, Corners.y, 0.f, 1.f));\n"
    		"   float4 v2 = mul(ProjMtx, float4(Corners.z, Corners.w, 0.f, 1.f));\n"
    
    		"	Out.pos   = float4(v2.x, v1.y, 0.f, 1.f);\n"
    		"	Out.uv = float2(UVs.z,UVs.y);\n"
    		"	Out.color = Color1;\n"
    		"	TriStream.Append(Out);\n"
    
    		"	Out.pos   = float4(v2.x, v2.y, 0.f, 1.f);\n"
    		"	Out.uv = float2(UVs.z,UVs.w);\n"
    		"	Out.color = Color2;\n"
    		"	TriStream.Append(Out);\n"
    
    		"	Out.pos   = float4(v1.x, v1.y, 0.f, 1.f);\n"
    		"	Out.uv = float2(UVs.x,UVs.y);\n"
    		"	Out.color = Color1;\n"
    		"	TriStream.Append(Out);\n"
    
    		"	Out.pos   = float4(v1.x, v2.y, 0.f, 1.f);\n"
    		"	Out.uv = float2(UVs.x,UVs.w);\n"
    		"	Out.color = Color2;\n"
    		"	TriStream.Append(Out);\n"
    		
    		"	TriStream.RestartStrip();\n"
    		"}\n";
    	if (!m_gs->createShaders(
    		"vs_5_0",
    		"ps_5_0",
    		text,
    		text,
    		"VSMain",
    		"PSMain",
    		slMeshVertexType::Null,
    		&this->m_vShader,
    		&this->m_pShader,
    		&this->m_vLayout))
    		return false;
    	if (!m_gs->createGeometryShaders("gs_5_0", text, "GSMain", &m_gShader))
    		return false;
    
    	if (!m_gs->createConstantBuffer(sizeof(cbFrame), &m_cbFrame))
    		return false;
    	if (!m_gs->createConstantBuffer(sizeof(cbElement), &m_cbElement))
    		return false;
    
    	return true;
    }
    void slD3D11ShaderGUIRectangle::SetOnFrame()
    {
    	D3D11_MAPPED_SUBRESOURCE mappedResource;
    	D3D11_BUFFER_DESC d;
    	m_gs->m_d3d11DevCon->Map(m_cbFrame, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    	m_cbFrame->GetDesc(&d);
    	memcpy(mappedResource.pData, &m_cbDataFrame, d.ByteWidth);
    	m_gs->m_d3d11DevCon->Unmap(m_cbFrame, 0);
    	m_gs->m_d3d11DevCon->GSSetConstantBuffers(0, 1, &m_cbFrame);
    }
    
    void slD3D11ShaderGUIRectangle::SetOnElement(slGSD3D11Texture* texture)
    {
    	m_gs->m_d3d11DevCon->PSSetShaderResources(0, 1, &texture->m_textureResView);
    	m_gs->m_d3d11DevCon->PSSetSamplers(0, 1, &texture->m_samplerState);
    
    	D3D11_MAPPED_SUBRESOURCE mappedResource;
    	D3D11_BUFFER_DESC d;
    	m_gs->m_d3d11DevCon->Map(m_cbElement, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    	m_cbElement->GetDesc(&d);
    	memcpy(mappedResource.pData, &m_cbDataElement, d.ByteWidth);
    	m_gs->m_d3d11DevCon->Unmap(m_cbElement, 0);
    	m_gs->m_d3d11DevCon->GSSetConstantBuffers(1, 1, &m_cbElement);
    }
    

    Add in slGSD3D11

    
    void updateGUIMatrix();
    

    This matrix must be recalculated when window changed its size. Call it in updateMainTarget()

    Implementation

    
    void slGSD3D11::updateGUIMatrix()
    {
    	m_shaderGUIRectangle->m_cbDataFrame.ProjMtx.m_data[0].set(2.0f / m_activeWindowSize->x, 0.0f, 0.0f, 0.0f);
    	m_shaderGUIRectangle->m_cbDataFrame.ProjMtx.m_data[1].set(0.0f, 2.0f / -m_activeWindowSize->y, 0.0f, 0.0f);
    	m_shaderGUIRectangle->m_cbDataFrame.ProjMtx.m_data[2].set(0.0f, 0.0f, 0.5f, 0.0f);
    	m_shaderGUIRectangle->m_cbDataFrame.ProjMtx.m_data[3].set(-1.f, 1.f, 0.5f, 1.0f);
    }
    

    Create GUI RTT and white texture

    
    //in bool slGSD3D11::updateMainTarget()
    m_GUIRTT = (slGSD3D11Texture*)SummonRenderTargetTexture(
    		slPoint((uint32_t)m_activeWindowSize->x, (uint32_t)m_activeWindowSize->y),
    		tinf);
    
    //in bool slGSD3D11::Init()
    {
    	slImage img;
    	img.Create(2, 2);
    	img.Fill(ColorWhite);
    	slTextureInfo tinf;
    	m_whiteTexture = (slGSD3D11Texture*)SummonTexture(&img, tinf);
    }
    

    GUI elements without user texture will use white texture.

    Add in GS new methods

    
    // GUI drawing must be outside BeginDraw EndDraw
    virtual void BeginGUI() = 0;
    virtual void DrawGUI() = 0;
    // t and UVs is optional
    virtual void DrawGUIRectangle(const slRect& rect, const slColor& color1, const slColor& color2,
    	slTexture* t, slVec4f* UVs) = 0;
    virtual void EndGUI() = 0;
    

    Implementation

    
    void slGSD3D11::BeginGUI()
    {
    	const float cc[4] = { 0.f,0.f,0.f,0.f };
    	SetRenderTarget(m_GUIRTT);
    	UseDepth(false);
    	m_d3d11DevCon->ClearRenderTargetView(m_currentTargetView, cc);
    	SetActiveShader(m_shaderGUIRectangle);
    	m_shaderGUIRectangle->SetOnFrame();
    }
    
    void slGSD3D11::DrawGUI()
    {
    	// draw elements/widgets here
    }
    
    void slGSD3D11::DrawGUIRectangle(const slRect& rct, const slColor& color1, const slColor& color2,
    	slTexture* t, slVec4f* UVs)
    {
    	slGSD3D11Texture* d3dt = m_whiteTexture;
    	
    	if (t)
    		d3dt = (slGSD3D11Texture*)t;
    
    	m_shaderGUIRectangle->m_cbDataElement.Color1 = color1;
    	m_shaderGUIRectangle->m_cbDataElement.Color2 = color2;
    
    	m_shaderGUIRectangle->m_cbDataElement.Corners.x = (float)(rct.left);
    	m_shaderGUIRectangle->m_cbDataElement.Corners.y = (float)(rct.top);
    	m_shaderGUIRectangle->m_cbDataElement.Corners.z = (float)(rct.right);
    	m_shaderGUIRectangle->m_cbDataElement.Corners.w = (float)(rct.bottom);
    
    	m_shaderGUIRectangle->m_cbDataElement.UVs.x = 0.f;
    	m_shaderGUIRectangle->m_cbDataElement.UVs.y = 0.f;
    	m_shaderGUIRectangle->m_cbDataElement.UVs.z = 1.f;
    	m_shaderGUIRectangle->m_cbDataElement.UVs.w = 1.f;
    
    	if (UVs)
    		m_shaderGUIRectangle->m_cbDataElement.UVs = *UVs;
    
    	m_shaderGUIRectangle->SetOnElement(d3dt);
    
    	m_d3d11DevCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
    	m_d3d11DevCon->Draw(1, 0);
    }
    
    void slGSD3D11::EndGUI()
    {
    	SetRenderTarget(m_mainTargetRTT);
    	UseDepth(true);
    }
    
    

    I need to combine Main RTT and GUI RTT. In main target shader:

    
    // new
    "Texture2D tex2d_2;\n" // GUI
    "SamplerState tex2D_sampler_2;\n" // GUI
    ...
    "   float4 GUIColor = tex2d_2.Sample(tex2D_sampler_2, input.uv);\n"
    "   if(GUIColor.w){output.color = GUIColor;}else\n"
    

    Now draw rectangle in app

    
    app.m_gs->BeginGUI();
    app.m_gs->DrawGUIRectangle(slRect(0, 0, 100, 30), ColorRed, ColorBlue, 0, 0);
    app.m_gs->EndGUI();
    

    Download