Advertisement

DirectX 11: Drawing text using sprites

Started by March 05, 2014 06:22 AM
1 comment, last by InfinityMachine 10 years, 11 months ago

After grueling hours for troubleshooting, I've finally realized that my eyes alone aren't enough. I've read up on the basic form: getting text from an external picture file and mapping to squares. I've debugged all of the blasted hlsl errors, and currently, no compile errors show up... But neither does a texture. ...And neither does my text. I can't seem to place my finger on it...

No errors leaves me to believe that it's something set syntactically correct, but I can't place it. I've check culling (none), texture, shader, ...Just nothing shows up. The back buffer does get cleared, and my object class displays what is handed to it. So here goes:

SetTextShaderConfiguration() gets placed in front of DrawText(), in the Render() function. It sets the view to screen-space and sets the shaders.


void InfiniteText::SetTextShaderConfiguration(){
	UINT stride=sizeof(VertexText);
	UINT offset=0;
	
	iD3D.DeviceContext->VSSetShader(Fontvs,0,0);
	iD3D.DeviceContext->PSSetShader(Fontps,0,0);

	Projection=iD3D.mProjection;
	iD3D.WorldCB.mWorldVP=XMMatrixTranspose(Projection);

	iD3D.DeviceContext->UpdateSubresource(iD3D.MatrixBuffer, 0, NULL, &iD3D.WorldCB, 0, 0);
	iD3D.DeviceContext->VSSetConstantBuffers(0,1,&iD3D.MatrixBuffer);

	iD3D.DeviceContext->IASetInputLayout(InLayout);
	iD3D.DeviceContext->IASetVertexBuffers(0,1, &FontVertexBuffer, &stride, &offset);
	iD3D.DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	
	iD3D.DeviceContext->PSSetShaderResources(0,1, &FontSRV);
	iD3D.DeviceContext->PSSetSamplers(0,1,&FontSRVSampler);
} 

The texture and vertex buffers are initialized:


void InfiniteText::InitializeText(){
	float textureWidth=551.0f;
	UINT numLetters=32;
	HRESULT hr;

	D3DX11CompileFromFile(L"Shaders.hlsl", NULL, NULL, "VShader", "vs_5_0",0,0,0,&FontvsBuffer,0,0);
	D3DX11CompileFromFile(L"Shaders.hlsl", NULL, NULL, "PShader", "ps_5_0",0,0,0,&FontpsBuffer,&ppErrorMsgs,0);
	hr = iD3D.Device->CreateVertexShader(FontvsBuffer->GetBufferPointer(),FontvsBuffer->GetBufferSize(), NULL, &Fontvs);
	if(FAILED(hr)){
		MessageBox(iEngine.hWnd, L"CreateVertexShader Failed", L"Failed", MB_OK);
	}

	hr = iD3D.Device->CreatePixelShader(FontpsBuffer->GetBufferPointer(),FontpsBuffer->GetBufferSize(), NULL, &Fontps);
	if(FAILED(hr)){
		MessageBox(iEngine.hWnd, L"CreatePixelShader Failed", L"Failed", MB_OK);
	}

	D3D11_INPUT_ELEMENT_DESC IEDesc[]={
                {"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
				{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
            };

    UINT NumElements = ARRAYSIZE(IEDesc);
    hr=iD3D.Device->CreateInputLayout(IEDesc,NumElements,FontvsBuffer->GetBufferPointer(),FontvsBuffer->GetBufferSize(),&InLayout);
	if(FAILED(hr)){
		MessageBox(iEngine.hWnd, L"CreateInputLayout Failed", L"Failed", MB_OK);
	}

	D3D11_SAMPLER_DESC FontSamplerDesc;
	FontSamplerDesc.AddressU=D3D11_TEXTURE_ADDRESS_WRAP;
	FontSamplerDesc.AddressV=D3D11_TEXTURE_ADDRESS_WRAP;
	FontSamplerDesc.AddressW=D3D11_TEXTURE_ADDRESS_WRAP;
	FontSamplerDesc.Filter=D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	FontSamplerDesc.MipLODBias=0.0f;
	FontSamplerDesc.MaxAnisotropy=0;
	FontSamplerDesc.MaxLOD= D3D11_FLOAT32_MAX;
	FontSamplerDesc.MinLOD=0;
	FontSamplerDesc.ComparisonFunc=D3D11_COMPARISON_NEVER;

	D3DX11CreateShaderResourceViewFromFile(iD3D.Device, L"Font.dds", NULL, NULL, &FontSRV, NULL);
	
	hr=iD3D.Device->CreateSamplerState(&FontSamplerDesc, &FontSRVSampler);
	if(FAILED(hr)){
		MessageBox(iEngine.hWnd, L"CreateSamplerState Failed", L"Failed", MB_OK);
	}

	D3D11_BUFFER_DESC Vbufferdescription;
	ZeroMemory(&Vbufferdescription, sizeof(Vbufferdescription));

	Vbufferdescription.BindFlags=D3D11_BIND_VERTEX_BUFFER;
	Vbufferdescription.Usage=D3D11_USAGE_DYNAMIC;
	Vbufferdescription.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
	Vbufferdescription.ByteWidth=sizeof(VertexText)*6*numLetters;

	hr = iD3D.Device->CreateBuffer(&Vbufferdescription, NULL, &FontVertexBuffer);
	if(FAILED(hr)){
		MessageBox(iEngine.hWnd, L"CreateBuffer Failed", L"Failed", MB_OK);
	}
}

and finally the DrawText() function:


bool InfiniteText::DrawString(char* Text, float xPos, float yPos){
	int letterSize = sizeof(VertexText)*6;
	int textSize = strlen(Text);

	if(textSize > numLetters)
		textSize=numLetters;

	float cScreenWidth = 32.0f/iD3D.cWidth;
	float cScreenHeight= 32.0f/iD3D.cHeight;

	float TexelWidth= 32.0f/textureWidth;

	D3D11_MAPPED_SUBRESOURCE MappedSub;
	HRESULT hr = iD3D.DeviceContext->Map(FontVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedSub); //MAP START
	
	if(FAILED(hr)){
		MessageBox(iEngine.hWnd, L"Map failed", L"Failed", MB_OK);
		return false;
	}
	
	VertexText* Sprite = (VertexText*)MappedSub.pData;

	const int indexA = static_cast<int>('A');
	const int indexZ = static_cast<int>('Z');

	for(int i=0; i<textSize;i++){
		float thisStartX = xPos +(cScreenWidth * static_cast<char>(i));
        float thisEndX =thisStartX + cScreenWidth;
        float thisStartY = yPos;
        float thisEndY = thisStartY + cScreenHeight;

		Sprite[0].Translation=XMFLOAT3(thisEndX,thisEndY,1.0f);
		Sprite[1].Translation=XMFLOAT3(thisEndX,yPos,1.0f);
		Sprite[2].Translation=XMFLOAT3(thisStartX,yPos,1.0f);
		Sprite[3].Translation=XMFLOAT3(thisStartX,yPos,1.0f);
		Sprite[4].Translation=XMFLOAT3(thisStartX,thisEndY,1.0f);
		Sprite[5].Translation=XMFLOAT3(thisEndX,thisEndY,1.0f);

		int TexLookup=0;
		int Letter= static_cast<char>(Text[i]);

		if (Letter < indexA || Letter > indexZ){
			TexLookup=(indexZ - indexA) +1;
		}
		else{
			TexLookup=(Letter-indexA);
		}

		float texStart = 0.0f + (TexelWidth*static_cast<float>(TexLookup));
		float TexEnd = texStart + TexelWidth;

		Sprite[0].TextureCoord = XMFLOAT2(TexEnd,0.0f);
		Sprite[1].TextureCoord = XMFLOAT2(TexEnd,1.0f);
		Sprite[2].TextureCoord = XMFLOAT2(texStart,1.0f);
		Sprite[3].TextureCoord = XMFLOAT2(texStart,1.0f);
		Sprite[4].TextureCoord = XMFLOAT2(texStart,0.0f);
		Sprite[5].TextureCoord = XMFLOAT2(TexEnd,0.0f);

		Sprite= Sprite + 6;
	}
		iD3D.DeviceContext->Unmap(FontVertexBuffer,0); //MAP END
		iD3D.DeviceContext->Draw(6*textSize,0);

		return true;
}

The resources are created just fine... I think. Just that the text doesn't appear. Additionally, I've set the TOPOLOGY to line list. (To check to see if the geometry appeared at least) and also with ...FILL_WIREFRAME to which I've found that no geometry is there either. My controls class is up, and I've looked around a bit- making sure that it doesn't acquire another matrix somehow. [attachment=20230:Debug.png]

Also, the HLSL file:


Texture2D txDiffuse : register( t0 );
SamplerState samLinear : register( s0 );

cbuffer ConstantBuffer:register( b0 )
{
    float4x4	WVP;
}

struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD0;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD0;
};

PS_INPUT VShader(float4 inPos :POSITION, float2 inTexCoord: TEXCOORD0)
{
    PS_INPUT output;
    output.Pos = mul(inPos, WVP);
    output.Tex = inTexCoord;
    
    return output;
}

float4 PShader( PS_INPUT input) : SV_Target
{
	float4 Color=txDiffuse.Sample( samLinear, input.Tex );
	clip(Color.a-0.25);
	return Color;
}

Another pair of eyes is appreciated!

Find yourself. If you can't, keep looking.

I haven't started messing with DirectX 11 yet, so this is just some general debugging advice.

I hate to ask, but I've seen countless people "debug" their code without using the debugger... Set a breakpoint in your DrawText function and trace the code through checking all your variables along the way. Make sure you're really passing it text instead of an empty string. Check all your local variables to ensure you're getting the values you expect. etc. If you don't hit your breakpoint, it's because you're not calling your function. ;)

Put in some additional draw code to draw something like lines to the destination coordinates that you're using. If that doesn't show up, you might be drawing "behind" your camera, drawing off screen, or on the wrong plane. If that shows up, proceed with the following.

Draw a hard coded sprite to the screen in those coordinates (not using a shader)

Draw your calculated letter sprite to the screen in those coordinates (not using a shader)

Draw your calculated letter sprite to the screen (using a basic shader from a tutorial)

Draw your calculated letter sprite to the screen (using your shader)

Hopefully one of these line items will show you where your problem is. If not, http://www.rastertek.com/tutdx11.html looks pretty comprehensive for tutorials.

- Eck

EckTech Games - Games and Unity Assets I'm working on
Still Flying - My GameDev journal
The Shilwulf Dynasty - Campaign notes for my Rogue Trader RPG

Advertisement


I hate to ask, but I've seen countless people "debug" their code without using the debugger...

I'm using the DirectX debugger and typical stack call list, as well as general forensics.


Make sure you're really passing it text instead of an empty string.

Strings going through, and the function is explicitly called.


Put in some additional draw code to draw something like lines to the destination coordinates that you're using. If that doesn't show up, you might be drawing "behind" your camera

I hope not! Sneaky geometry!


Draw a hard coded sprite to the screen in those coordinates (not using a shader)
Draw your calculated letter sprite to the screen in those coordinates (not using a shader)
Draw your calculated letter sprite to the screen (using a basic shader from a tutorial)
Draw your calculated letter sprite to the screen (using your shader)

I'm going to test these right away! Thanks!

Find yourself. If you can't, keep looking.

This topic is closed to new replies.

Advertisement