2015-05-06 01:27:59 -04:00
|
|
|
#include "GsContextView.h"
|
|
|
|
#include "GsStateUtils.h"
|
2019-06-04 22:56:44 -04:00
|
|
|
#include "gs/GsPixelFormats.h"
|
2020-01-02 20:33:11 +00:00
|
|
|
#include "gs/GSH_OpenGLWin32/GSH_OpenGLWin32.h"
|
2015-05-06 01:27:59 -04:00
|
|
|
#include "win32/VerticalSplitter.h"
|
|
|
|
|
|
|
|
#define WNDSTYLE (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
|
|
|
|
|
2016-08-27 12:47:37 +09:00
|
|
|
enum TAB_IDS
|
|
|
|
{
|
|
|
|
TAB_ID_FRAMEBUFFER,
|
|
|
|
TAB_ID_TEXTURE_BASE,
|
|
|
|
TAB_ID_TEXTURE_MIP1,
|
|
|
|
TAB_ID_TEXTURE_MIP2,
|
|
|
|
TAB_ID_TEXTURE_MIP3,
|
|
|
|
TAB_ID_TEXTURE_MIP4,
|
|
|
|
TAB_ID_TEXTURE_MIP5,
|
|
|
|
TAB_ID_TEXTURE_MIP6
|
|
|
|
};
|
|
|
|
|
2015-05-06 01:27:59 -04:00
|
|
|
CGsContextView::CGsContextView(HWND parent, const RECT& rect, CGSHandler* gs, unsigned int contextId)
|
2018-04-30 21:01:23 +01:00
|
|
|
: m_contextId(contextId)
|
|
|
|
, m_gs(gs)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
Create(0, Framework::Win32::CDefaultWndClass::GetName(), NULL, WNDSTYLE, rect, parent, NULL);
|
|
|
|
SetClassPtr();
|
|
|
|
|
|
|
|
m_mainSplitter = std::make_unique<Framework::Win32::CVerticalSplitter>(m_hWnd, GetClientRect());
|
|
|
|
|
|
|
|
m_bufferSelectionTab = std::make_unique<Framework::Win32::CTab>(*m_mainSplitter, Framework::Win32::CRect(0, 0, 1, 1), TCS_BOTTOM);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Framebuffer")), TAB_ID_FRAMEBUFFER);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Base)")), TAB_ID_TEXTURE_BASE);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Mip 1)")), TAB_ID_TEXTURE_MIP1);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Mip 2)")), TAB_ID_TEXTURE_MIP2);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Mip 3)")), TAB_ID_TEXTURE_MIP3);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Mip 4)")), TAB_ID_TEXTURE_MIP4);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Mip 5)")), TAB_ID_TEXTURE_MIP5);
|
2016-08-27 12:47:37 +09:00
|
|
|
m_bufferSelectionTab->SetTabData(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_bufferSelectionTab->InsertTab(_T("Texture (Mip 6)")), TAB_ID_TEXTURE_MIP6);
|
2015-05-06 01:27:59 -04:00
|
|
|
|
|
|
|
m_bufferView = std::make_unique<CPixelBufferView>(*m_bufferSelectionTab, Framework::Win32::CRect(0, 0, 1, 1));
|
2020-01-02 20:33:11 +00:00
|
|
|
m_bufferView->Show(SW_SHOW);
|
2015-05-06 01:27:59 -04:00
|
|
|
m_stateView = std::make_unique<CGsContextStateView>(*m_mainSplitter, GetClientRect(), m_contextId);
|
|
|
|
m_stateView->Show(SW_SHOW);
|
|
|
|
|
|
|
|
m_mainSplitter->SetChild(0, *m_bufferSelectionTab);
|
|
|
|
m_mainSplitter->SetChild(1, *m_stateView);
|
|
|
|
m_mainSplitter->SetMasterChild(1);
|
|
|
|
m_mainSplitter->SetEdgePosition(0.5f);
|
|
|
|
}
|
|
|
|
|
|
|
|
CGsContextView::~CGsContextView()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGsContextView::SetFbDisplayMode(FB_DISPLAY_MODE fbDisplayMode)
|
|
|
|
{
|
|
|
|
m_fbDisplayMode = fbDisplayMode;
|
|
|
|
UpdateBufferView();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGsContextView::UpdateState(CGSHandler* gs, CGsPacketMetadata*, DRAWINGKICK_INFO* drawingKick)
|
|
|
|
{
|
|
|
|
assert(gs == m_gs);
|
|
|
|
m_drawingKick = (*drawingKick);
|
|
|
|
UpdateBufferView();
|
|
|
|
m_stateView->UpdateState(m_gs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGsContextView::UpdateBufferView()
|
|
|
|
{
|
2016-08-27 12:47:37 +09:00
|
|
|
int selectionIndex = m_bufferSelectionTab->GetSelection();
|
|
|
|
uint32 selectedId = m_bufferSelectionTab->GetTabData(selectionIndex);
|
|
|
|
switch(selectedId)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
2016-08-27 12:47:37 +09:00
|
|
|
case TAB_ID_FRAMEBUFFER:
|
2017-04-08 17:38:27 -04:00
|
|
|
UpdateFramebufferView();
|
2016-08-27 12:47:37 +09:00
|
|
|
break;
|
|
|
|
case TAB_ID_TEXTURE_BASE:
|
|
|
|
case TAB_ID_TEXTURE_MIP1:
|
|
|
|
case TAB_ID_TEXTURE_MIP2:
|
|
|
|
case TAB_ID_TEXTURE_MIP3:
|
|
|
|
case TAB_ID_TEXTURE_MIP4:
|
|
|
|
case TAB_ID_TEXTURE_MIP5:
|
|
|
|
case TAB_ID_TEXTURE_MIP6:
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
uint64 tex0Reg = m_gs->GetRegisters()[GS_REG_TEX0_1 + m_contextId];
|
|
|
|
uint64 tex1Reg = m_gs->GetRegisters()[GS_REG_TEX1_1 + m_contextId];
|
|
|
|
uint64 miptbp1Reg = m_gs->GetRegisters()[GS_REG_MIPTBP1_1 + m_contextId];
|
|
|
|
uint64 miptbp2Reg = m_gs->GetRegisters()[GS_REG_MIPTBP2_1 + m_contextId];
|
|
|
|
auto tex0 = make_convertible<CGSHandler::TEX0>(tex0Reg);
|
|
|
|
auto tex1 = make_convertible<CGSHandler::TEX1>(tex1Reg);
|
|
|
|
|
|
|
|
uint32 mipLevel = selectedId - TAB_ID_TEXTURE_BASE;
|
|
|
|
Framework::CBitmap texture, clutTexture;
|
|
|
|
|
|
|
|
if(mipLevel <= tex1.nMaxMip)
|
2016-08-27 12:47:37 +09:00
|
|
|
{
|
2020-01-26 14:38:18 +00:00
|
|
|
texture = static_cast<CGSH_OpenGLWin32*>(m_gs)->GetTexture(tex0Reg, tex1.nMaxMip, miptbp1Reg, miptbp2Reg, mipLevel);
|
2016-08-27 12:47:37 +09:00
|
|
|
}
|
2018-04-30 21:01:23 +01:00
|
|
|
|
|
|
|
if(!texture.IsEmpty() && CGsPixelFormats::IsPsmIDTEX(tex0.nPsm))
|
|
|
|
{
|
|
|
|
ColorArray convertedClut;
|
|
|
|
m_gs->MakeLinearCLUT(tex0, convertedClut);
|
|
|
|
clutTexture = LookupBitmap(texture, convertedClut);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!texture.IsEmpty() && CGsPixelFormats::IsPsmIDTEX4(tex0.nPsm))
|
|
|
|
{
|
|
|
|
//Too hard to see if pixel brightness is not boosted
|
|
|
|
BrightenBitmap(texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
CPixelBufferView::PixelBufferArray pixelBuffers;
|
|
|
|
pixelBuffers.emplace_back("Raw", std::move(texture));
|
|
|
|
if(!clutTexture.IsEmpty())
|
|
|
|
{
|
|
|
|
pixelBuffers.emplace_back("+ CLUT", std::move(clutTexture));
|
|
|
|
}
|
|
|
|
m_bufferView->SetPixelBuffers(std::move(pixelBuffers));
|
|
|
|
}
|
|
|
|
break;
|
2015-05-06 01:27:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-08 17:38:27 -04:00
|
|
|
void CGsContextView::UpdateFramebufferView()
|
|
|
|
{
|
|
|
|
uint64 frameReg = m_gs->GetRegisters()[GS_REG_FRAME_1 + m_contextId];
|
|
|
|
auto frame = make_convertible<CGSHandler::FRAME>(frameReg);
|
|
|
|
|
2020-01-26 14:38:18 +00:00
|
|
|
auto framebuffer = static_cast<CGSH_OpenGLWin32*>(m_gs)->GetFramebuffer(frame);
|
2017-04-08 17:38:27 -04:00
|
|
|
if(framebuffer.IsEmpty())
|
|
|
|
{
|
|
|
|
m_bufferView->SetPixelBuffers(CPixelBufferView::PixelBufferArray());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Clip framebuffer
|
|
|
|
if(m_fbDisplayMode == FB_DISPLAY_MODE_448P)
|
|
|
|
{
|
|
|
|
framebuffer = framebuffer.ResizeCanvas(640, 448);
|
|
|
|
}
|
|
|
|
else if(m_fbDisplayMode == FB_DISPLAY_MODE_448I)
|
|
|
|
{
|
|
|
|
framebuffer = framebuffer.ResizeCanvas(640, 224);
|
|
|
|
}
|
|
|
|
|
|
|
|
Framework::CBitmap alphaFramebuffer;
|
|
|
|
if(frame.nPsm == CGSHandler::PSMCT32)
|
|
|
|
{
|
|
|
|
assert(framebuffer.GetBitsPerPixel() == 32);
|
|
|
|
alphaFramebuffer = ExtractAlpha32(framebuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto postProcessFramebuffer =
|
2018-04-30 21:01:23 +01:00
|
|
|
[this](Framework::CBitmap src) {
|
|
|
|
if(!src.IsEmpty())
|
|
|
|
{
|
|
|
|
RenderDrawKick(src);
|
|
|
|
if(m_fbDisplayMode == FB_DISPLAY_MODE_448I)
|
|
|
|
{
|
|
|
|
src = src.Resize(640, 448);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return src;
|
|
|
|
};
|
2017-04-08 17:38:27 -04:00
|
|
|
|
|
|
|
framebuffer = postProcessFramebuffer(std::move(framebuffer));
|
|
|
|
alphaFramebuffer = postProcessFramebuffer(std::move(alphaFramebuffer));
|
|
|
|
|
|
|
|
CPixelBufferView::PixelBufferArray pixelBuffers;
|
|
|
|
pixelBuffers.emplace_back("Raw", std::move(framebuffer));
|
|
|
|
if(!alphaFramebuffer.IsEmpty())
|
|
|
|
{
|
|
|
|
pixelBuffers.emplace_back("Alpha", std::move(alphaFramebuffer));
|
|
|
|
}
|
|
|
|
m_bufferView->SetPixelBuffers(std::move(pixelBuffers));
|
|
|
|
}
|
|
|
|
|
2015-05-06 01:27:59 -04:00
|
|
|
void CGsContextView::RenderDrawKick(Framework::CBitmap& bitmap)
|
|
|
|
{
|
|
|
|
if(m_drawingKick.primType == CGSHandler::PRIM_INVALID) return;
|
|
|
|
if(m_drawingKick.context != m_contextId) return;
|
|
|
|
|
|
|
|
auto primHighlightColor = Framework::CColor(0, 0xFF, 0, 0xFF);
|
|
|
|
|
|
|
|
switch(m_drawingKick.primType)
|
|
|
|
{
|
|
|
|
case CGSHandler::PRIM_TRIANGLE:
|
|
|
|
case CGSHandler::PRIM_TRIANGLESTRIP:
|
|
|
|
case CGSHandler::PRIM_TRIANGLEFAN:
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
int x1 = static_cast<int16>(m_drawingKick.vertex[0].x) / 16;
|
|
|
|
int y1 = static_cast<int16>(m_drawingKick.vertex[0].y) / 16;
|
|
|
|
int x2 = static_cast<int16>(m_drawingKick.vertex[1].x) / 16;
|
|
|
|
int y2 = static_cast<int16>(m_drawingKick.vertex[1].y) / 16;
|
|
|
|
int x3 = static_cast<int16>(m_drawingKick.vertex[2].x) / 16;
|
|
|
|
int y3 = static_cast<int16>(m_drawingKick.vertex[2].y) / 16;
|
|
|
|
bitmap.DrawLine(x1, y1, x2, y2, primHighlightColor);
|
|
|
|
bitmap.DrawLine(x1, y1, x3, y3, primHighlightColor);
|
|
|
|
bitmap.DrawLine(x2, y2, x3, y3, primHighlightColor);
|
|
|
|
}
|
|
|
|
break;
|
2015-05-06 01:27:59 -04:00
|
|
|
case CGSHandler::PRIM_SPRITE:
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
int x1 = static_cast<int16>(m_drawingKick.vertex[0].x) / 16;
|
|
|
|
int y1 = static_cast<int16>(m_drawingKick.vertex[0].y) / 16;
|
|
|
|
int x2 = static_cast<int16>(m_drawingKick.vertex[1].x) / 16;
|
|
|
|
int y2 = static_cast<int16>(m_drawingKick.vertex[1].y) / 16;
|
|
|
|
bitmap.DrawLine(x1, y1, x1, y2, primHighlightColor);
|
|
|
|
bitmap.DrawLine(x1, y2, x2, y2, primHighlightColor);
|
|
|
|
bitmap.DrawLine(x2, y2, x2, y1, primHighlightColor);
|
|
|
|
bitmap.DrawLine(x2, y1, x1, y1, primHighlightColor);
|
|
|
|
}
|
|
|
|
break;
|
2015-05-06 01:27:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-17 20:01:03 -04:00
|
|
|
void CGsContextView::BrightenBitmap(Framework::CBitmap& bitmap)
|
|
|
|
{
|
|
|
|
assert(!bitmap.IsEmpty());
|
|
|
|
assert(bitmap.GetBitsPerPixel() == 8);
|
|
|
|
auto pixels = reinterpret_cast<uint8*>(bitmap.GetPixels());
|
|
|
|
for(uint32 y = 0; y < bitmap.GetHeight(); y++)
|
|
|
|
{
|
|
|
|
for(uint32 x = 0; x < bitmap.GetWidth(); x++)
|
|
|
|
{
|
|
|
|
pixels[x] <<= 4;
|
|
|
|
}
|
|
|
|
pixels += bitmap.GetPitch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-26 12:12:50 +00:00
|
|
|
uint32 CGsContextView::Color_Ps2ToRGBA(uint32 color)
|
|
|
|
{
|
|
|
|
uint8 r = (color & 0xFF);
|
|
|
|
uint8 b = (color & 0xFF00) >> 8;
|
|
|
|
uint8 g = (color & 0xFF0000) >> 16;
|
|
|
|
uint8 a = (color & 0xFF000000) >> 24;
|
|
|
|
return g << 0 | b << 8 | r << 16 | a << 24;
|
|
|
|
}
|
|
|
|
|
2016-10-31 10:42:31 -04:00
|
|
|
Framework::CBitmap CGsContextView::LookupBitmap(const Framework::CBitmap& srcBitmap, const ColorArray& clut)
|
|
|
|
{
|
|
|
|
assert(!srcBitmap.IsEmpty());
|
|
|
|
assert(srcBitmap.GetBitsPerPixel() == 8);
|
|
|
|
auto dstBitmap = Framework::CBitmap(srcBitmap.GetWidth(), srcBitmap.GetHeight(), 32);
|
|
|
|
auto srcPixels = reinterpret_cast<uint8*>(srcBitmap.GetPixels());
|
|
|
|
auto dstPixels = reinterpret_cast<uint32*>(dstBitmap.GetPixels());
|
|
|
|
for(uint32 y = 0; y < srcBitmap.GetHeight(); y++)
|
|
|
|
{
|
|
|
|
for(uint32 x = 0; x < srcBitmap.GetWidth(); x++)
|
|
|
|
{
|
|
|
|
uint8 index = srcPixels[x];
|
|
|
|
uint32 color = clut[index];
|
2020-01-26 12:12:50 +00:00
|
|
|
uint32 newColor = Color_Ps2ToRGBA(color);
|
2016-10-31 10:42:31 -04:00
|
|
|
dstPixels[x] = newColor;
|
|
|
|
}
|
|
|
|
srcPixels += srcBitmap.GetPitch();
|
|
|
|
dstPixels += dstBitmap.GetPitch() / 4;
|
|
|
|
}
|
|
|
|
return std::move(dstBitmap);
|
|
|
|
}
|
|
|
|
|
2017-04-08 17:38:27 -04:00
|
|
|
Framework::CBitmap CGsContextView::ExtractAlpha32(const Framework::CBitmap& srcBitmap)
|
|
|
|
{
|
|
|
|
assert(!srcBitmap.IsEmpty());
|
|
|
|
assert(srcBitmap.GetBitsPerPixel() == 32);
|
|
|
|
auto dstBitmap = Framework::CBitmap(srcBitmap.GetWidth(), srcBitmap.GetHeight(), 32);
|
|
|
|
auto srcPixels = reinterpret_cast<uint32*>(srcBitmap.GetPixels());
|
|
|
|
auto dstPixels = reinterpret_cast<uint32*>(dstBitmap.GetPixels());
|
|
|
|
for(uint32 y = 0; y < srcBitmap.GetHeight(); y++)
|
|
|
|
{
|
|
|
|
for(uint32 x = 0; x < srcBitmap.GetWidth(); x++)
|
|
|
|
{
|
|
|
|
uint32 color = srcPixels[x];
|
|
|
|
uint32 alpha = color >> 24;
|
|
|
|
dstPixels[x] = (alpha) | (alpha << 8) | (alpha << 16) | 0xFF000000;
|
|
|
|
}
|
|
|
|
srcPixels += srcBitmap.GetPitch() / 4;
|
|
|
|
dstPixels += dstBitmap.GetPitch() / 4;
|
|
|
|
}
|
|
|
|
return std::move(dstBitmap);
|
|
|
|
}
|
|
|
|
|
2015-05-06 01:27:59 -04:00
|
|
|
long CGsContextView::OnSize(unsigned int, unsigned int, unsigned int)
|
|
|
|
{
|
|
|
|
m_mainSplitter->SetSizePosition(GetClientRect());
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
long CGsContextView::OnCommand(unsigned short, unsigned short, HWND hwndFrom)
|
|
|
|
{
|
|
|
|
if(CWindow::IsCommandSource(m_mainSplitter.get(), hwndFrom))
|
|
|
|
{
|
|
|
|
m_bufferView->SetSizePosition(m_bufferSelectionTab->GetDisplayAreaRect());
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-01-09 22:01:09 -05:00
|
|
|
LRESULT CGsContextView::OnNotify(WPARAM wParam, NMHDR* hdr)
|
2015-05-06 01:27:59 -04:00
|
|
|
{
|
|
|
|
if(CWindow::IsNotifySource(m_bufferSelectionTab.get(), hdr))
|
|
|
|
{
|
|
|
|
if(hdr->code == TCN_SELCHANGE)
|
|
|
|
{
|
|
|
|
UpdateBufferView();
|
|
|
|
m_bufferView->FitBitmap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|