mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-19 22:17:10 +00:00
322e3c667d
* I don't think any of these were bugs, but they're certainly better off being fixed.
309 lines
10 KiB
C++
309 lines
10 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019-2020 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "d3d8_debug.h"
|
|
#include "os/os_specific.h"
|
|
#include "stb/stb_truetype.h"
|
|
#include "strings/string_utils.h"
|
|
|
|
D3D8DebugManager::D3D8DebugManager(WrappedD3DDevice8 *wrapper)
|
|
: m_WrappedDevice(wrapper), m_fvf(D3DFVF_XYZ | D3DFVF_TEX1)
|
|
{
|
|
InitFontRendering();
|
|
}
|
|
|
|
D3D8DebugManager::~D3D8DebugManager()
|
|
{
|
|
ShutdownFontRendering();
|
|
}
|
|
|
|
bool D3D8DebugManager::InitFontRendering()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
int width = FONT_TEX_WIDTH;
|
|
int height = FONT_TEX_HEIGHT;
|
|
|
|
rdcstr font = GetEmbeddedResource(sourcecodepro_ttf);
|
|
byte *ttfdata = (byte *)font.c_str();
|
|
|
|
const int firstChar = int(' ') + 1;
|
|
const int lastChar = 127;
|
|
const int numChars = lastChar - firstChar;
|
|
|
|
byte *buf = new byte[width * height];
|
|
|
|
const float pixelHeight = 20.0f;
|
|
|
|
stbtt_BakeFontBitmap(ttfdata, 0, pixelHeight, buf, width, height, firstChar, numChars,
|
|
m_Font.charData);
|
|
|
|
stbtt_fontinfo f = {0};
|
|
stbtt_InitFont(&f, ttfdata, 0);
|
|
|
|
int ascent = 0;
|
|
stbtt_GetFontVMetrics(&f, &ascent, NULL, NULL);
|
|
|
|
m_Font.maxHeight = float(ascent) * stbtt_ScaleForPixelHeight(&f, pixelHeight);
|
|
|
|
IDirect3DTexture8 *fontTex = NULL;
|
|
|
|
hr = m_WrappedDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
|
|
D3DPOOL_DEFAULT, &fontTex);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Failed to create font texture HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
|
|
D3DLOCKED_RECT lockedRegion;
|
|
hr = fontTex->LockRect(0, &lockedRegion, NULL, D3DLOCK_DISCARD);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Failed to lock font texture HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
else
|
|
{
|
|
BYTE *texBase = (BYTE *)lockedRegion.pBits;
|
|
|
|
for(int y = 0; y < height; y++)
|
|
{
|
|
byte *curRow = (texBase + (y * lockedRegion.Pitch));
|
|
|
|
for(int x = 0; x < width; x++)
|
|
{
|
|
curRow[x * 4 + 0] = buf[(y * width) + x];
|
|
curRow[x * 4 + 1] = buf[(y * width) + x];
|
|
curRow[x * 4 + 2] = buf[(y * width) + x];
|
|
curRow[x * 4 + 3] = buf[(y * width) + x];
|
|
}
|
|
}
|
|
|
|
hr = fontTex->UnlockRect(0);
|
|
if(hr != S_OK)
|
|
{
|
|
RDCERR("Failed to unlock font texture HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
}
|
|
|
|
m_Font.Tex = fontTex;
|
|
|
|
delete[] buf;
|
|
|
|
return true;
|
|
}
|
|
|
|
void D3D8DebugManager::ShutdownFontRendering()
|
|
{
|
|
SAFE_RELEASE(m_Font.Tex);
|
|
}
|
|
|
|
void D3D8DebugManager::SetOutputWindow(HWND w)
|
|
{
|
|
// RECT rect;
|
|
// GetClientRect(w, &rect);
|
|
// m_supersamplingX = float(m_width) / float(rect.right - rect.left);
|
|
// m_supersamplingY = float(m_height) / float(rect.bottom - rect.top);
|
|
}
|
|
|
|
void D3D8DebugManager::RenderText(float x, float y, const rdcstr &text)
|
|
{
|
|
rdcarray<rdcstr> lines;
|
|
split(text, lines, '\n');
|
|
|
|
for(const rdcstr &line : lines)
|
|
{
|
|
RenderTextInternal(x, y, line);
|
|
y += 1.0f;
|
|
}
|
|
}
|
|
|
|
void D3D8DebugManager::RenderTextInternal(float x, float y, const rdcstr &text)
|
|
{
|
|
if(text.empty())
|
|
return;
|
|
|
|
RDCASSERT(text.size() < FONT_MAX_CHARS);
|
|
|
|
// transforms
|
|
float width = (float)m_width;
|
|
float height = (float)m_height;
|
|
float nearPlane = 0.001f;
|
|
float farPlane = 1.f;
|
|
D3DMATRIX identity = {1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f,
|
|
0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f};
|
|
D3DMATRIX ortho = {2.f / width,
|
|
0.f,
|
|
0.f,
|
|
0.f,
|
|
0.f,
|
|
-(2.f / height),
|
|
0.f,
|
|
0.f,
|
|
0.f,
|
|
0.f,
|
|
1.f / (farPlane - nearPlane),
|
|
0.f,
|
|
0.f,
|
|
0.f,
|
|
nearPlane / (nearPlane - farPlane),
|
|
1.f};
|
|
|
|
HRESULT res = S_OK;
|
|
res |= m_WrappedDevice->SetTransform(D3DTS_PROJECTION, &ortho);
|
|
res |= m_WrappedDevice->SetTransform(D3DTS_WORLD, &identity);
|
|
res |= m_WrappedDevice->SetTransform(D3DTS_VIEW, &identity);
|
|
|
|
// enable fixed function pipeline
|
|
res |= m_WrappedDevice->SetVertexShader(NULL);
|
|
res |= m_WrappedDevice->SetPixelShader(NULL);
|
|
|
|
// default render states
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_CLIPPING, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0x0000000F);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
|
|
|
|
// texture stage states
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR /*D3DTEXF_POINT*/);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR /*D3DTEXF_POINT*/);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR /*D3DTEXF_POINT*/);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_COLORARG0, D3DTA_CURRENT);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_ALPHAARG0, D3DTA_CURRENT);
|
|
res |= m_WrappedDevice->SetTextureStageState(0, D3DTSS_RESULTARG, D3DTA_CURRENT);
|
|
|
|
res |= m_WrappedDevice->SetVertexShader(m_fvf);
|
|
res |= m_WrappedDevice->SetTexture(0, m_Font.Tex);
|
|
for(uint32_t stage = 1; stage < 8; stage++)
|
|
{
|
|
res |= m_WrappedDevice->SetTexture(stage, NULL);
|
|
}
|
|
|
|
struct Vertex
|
|
{
|
|
float pos[3];
|
|
float uv[2];
|
|
|
|
Vertex() {}
|
|
Vertex(float posx, float posy, float posz, float texu, float texv)
|
|
{
|
|
pos[0] = posx;
|
|
pos[1] = posy;
|
|
pos[2] = posz;
|
|
uv[0] = texu;
|
|
uv[1] = texv;
|
|
}
|
|
};
|
|
|
|
struct Quad
|
|
{
|
|
Vertex vertices[6];
|
|
|
|
Quad() {}
|
|
Quad(float x0, float y0, float z, float s0, float t0, float x1, float y1, float s1, float t1)
|
|
{
|
|
vertices[0] = Vertex(x0, y0, z, s0, t0);
|
|
vertices[1] = Vertex(x1, y0, z, s1, t0);
|
|
vertices[2] = Vertex(x0, y1, z, s0, t1);
|
|
vertices[3] = Vertex(x1, y0, z, s1, t0);
|
|
vertices[4] = Vertex(x1, y1, z, s1, t1);
|
|
vertices[5] = Vertex(x0, y1, z, s0, t1);
|
|
}
|
|
};
|
|
|
|
Quad *quads = NULL;
|
|
Quad background;
|
|
UINT triangleCount = 0;
|
|
{
|
|
UINT quadCount = (UINT)text.size(); // calculate string length
|
|
|
|
triangleCount = quadCount * 2;
|
|
// create text VB
|
|
quads = new Quad[quadCount];
|
|
|
|
float textStartingPositionX = (-width / 2.f) + (x * m_Font.charData[0].xadvance);
|
|
float textStartingPositionY = (-height / 2.f) + ((y + 1.f) * m_Font.maxHeight);
|
|
|
|
float textPositionX = textStartingPositionX;
|
|
float textPositionY = textStartingPositionY;
|
|
|
|
for(UINT i = 0; i < quadCount; ++i)
|
|
{
|
|
char glyphIndex = text[i] - (' ' + 1);
|
|
if(glyphIndex < 0)
|
|
{
|
|
float currentX = textPositionX;
|
|
textPositionX += m_Font.charData[0].xadvance;
|
|
quads[i] = Quad(currentX, textPositionY - m_Font.maxHeight, 0.5f, 0.f, 0.f, textPositionX,
|
|
textPositionY, 0.f, 0.f);
|
|
}
|
|
else
|
|
{
|
|
stbtt_aligned_quad quad;
|
|
stbtt_GetBakedQuad(m_Font.charData, 256, 128, glyphIndex, &textPositionX, &textPositionY,
|
|
&quad, 0);
|
|
quads[i] = Quad(quad.x0, quad.y0, 0.5f, quad.s0, quad.t0, quad.x1, quad.y1, quad.s1, quad.t1);
|
|
}
|
|
}
|
|
|
|
background = Quad(textStartingPositionX, textStartingPositionY - m_Font.maxHeight, 0.6f, 0.f,
|
|
0.f, textPositionX, textPositionY + 3.f, 0.f, 0.f);
|
|
}
|
|
|
|
{
|
|
// overlay render states
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
|
res |= m_WrappedDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, &background, sizeof(Vertex));
|
|
|
|
//// overlay render states
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
|
res |= m_WrappedDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
|
|
|
res |= m_WrappedDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, triangleCount, &quads[0],
|
|
sizeof(Vertex));
|
|
delete[] quads;
|
|
}
|
|
}
|