mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Write rough framework for GPU discard test screen
This commit is contained in:
parent
8686960180
commit
df98721e73
@ -127,8 +127,6 @@ UI::EventReturn DevMenu::OnShaderView(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UI::EventReturn DevMenu::OnFreezeFrame(UI::EventParams &e) {
|
||||
if (PSP_CoreParameter().frozen) {
|
||||
PSP_CoreParameter().frozen = false;
|
||||
|
178
UI/GPUDriverTestScreen.cpp
Normal file
178
UI/GPUDriverTestScreen.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "GPUDriverTestScreen.h"
|
||||
#include "i18n/i18n.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
static const std::vector<Draw::ShaderSource> fsDiscard = {
|
||||
{Draw::ShaderLanguage::GLSL_ES_200,
|
||||
R"(varying vec4 oColor0;
|
||||
varying vec2 oTexCoord0;
|
||||
uniform sampler2D Sampler0;
|
||||
void main() {
|
||||
vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0;
|
||||
if (color.a <= 0.0)
|
||||
discard;
|
||||
gl_FragColor = color;
|
||||
})"
|
||||
},
|
||||
{Draw::ShaderLanguage::GLSL_VULKAN,
|
||||
R"(layout(location = 0) in vec4 oColor0;
|
||||
layout(location = 1) in vec2 oTexCoord0;
|
||||
layout(location = 0) out vec4 fragColor0;
|
||||
layout(set = 0, binding = 1) uniform sampler2D Sampler0;
|
||||
void main() {
|
||||
vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
|
||||
if (color.a <= 0.0)
|
||||
discard;
|
||||
fragColor0 = color;
|
||||
})"
|
||||
},
|
||||
};
|
||||
|
||||
GPUDriverTestScreen::GPUDriverTestScreen() {
|
||||
using namespace Draw;
|
||||
}
|
||||
|
||||
GPUDriverTestScreen::~GPUDriverTestScreen() {
|
||||
if (discardWriteStencil_)
|
||||
discardWriteStencil_->Release();
|
||||
if (drawTestStencil_)
|
||||
drawTestStencil_->Release();
|
||||
if (drawTestDepth_)
|
||||
drawTestDepth_->Release();
|
||||
if (discard_)
|
||||
discard_->Release();
|
||||
if (samplerNearest_)
|
||||
samplerNearest_->Release();
|
||||
}
|
||||
|
||||
void GPUDriverTestScreen::CreateViews() {
|
||||
// Don't bother with views for now.
|
||||
using namespace UI;
|
||||
I18NCategory *di = GetI18NCategory("Dialog");
|
||||
I18NCategory *cr = GetI18NCategory("PSPCredits");
|
||||
|
||||
auto tabs = new TabHolder(UI::ORIENT_HORIZONTAL, 30.0f);
|
||||
root_ = tabs;
|
||||
tabs->AddTab("Discard", new LinearLayout(UI::ORIENT_VERTICAL));
|
||||
}
|
||||
|
||||
void GPUDriverTestScreen::render() {
|
||||
using namespace Draw;
|
||||
UIScreen::render();
|
||||
|
||||
if (!discardWriteStencil_) {
|
||||
DrawContext *draw = screenManager()->getDrawContext();
|
||||
|
||||
// Create the special shader module.
|
||||
|
||||
discard_ = CreateShader(draw, Draw::ShaderStage::FRAGMENT, fsDiscard);
|
||||
|
||||
InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw);
|
||||
BlendState *blendOff = draw->CreateBlendState({false, 0xF});
|
||||
|
||||
// Write depth, write stencil.
|
||||
DepthStencilStateDesc dsDesc{};
|
||||
dsDesc.depthTestEnabled = true;
|
||||
dsDesc.depthWriteEnabled = true;
|
||||
dsDesc.depthCompare = Comparison::ALWAYS;
|
||||
dsDesc.stencilEnabled = true;
|
||||
dsDesc.front.compareMask = 0xFF;
|
||||
dsDesc.front.compareOp = Comparison::ALWAYS;
|
||||
dsDesc.front.passOp = StencilOp::REPLACE;
|
||||
dsDesc.front.failOp = StencilOp::ZERO;
|
||||
dsDesc.front.depthFailOp = StencilOp::ZERO;
|
||||
dsDesc.front.reference = 0xFF;
|
||||
dsDesc.front.writeMask = 0xFF;
|
||||
dsDesc.back = dsDesc.front;
|
||||
DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc);
|
||||
|
||||
dsDesc.depthCompare = Comparison::ALWAYS;
|
||||
dsDesc.front.compareOp = Comparison::EQUAL;
|
||||
DepthStencilState *stencilTestEqual = draw->CreateDepthStencilState(dsDesc);
|
||||
|
||||
dsDesc.depthCompare = Comparison::LESS_EQUAL;
|
||||
dsDesc.front.compareOp = Comparison::ALWAYS;
|
||||
DepthStencilState *depthTestEqual = draw->CreateDepthStencilState(dsDesc);
|
||||
|
||||
RasterState *rasterNoCull = draw->CreateRasterState({});
|
||||
|
||||
PipelineDesc discardDesc{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discard_ },
|
||||
inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc,
|
||||
};
|
||||
discardWriteStencil_ = draw->CreateGraphicsPipeline(discardDesc);
|
||||
|
||||
PipelineDesc testStencilDesc{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
|
||||
inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc,
|
||||
};
|
||||
drawTestStencil_ = draw->CreateGraphicsPipeline(testStencilDesc);
|
||||
|
||||
PipelineDesc testDepthDesc{
|
||||
Primitive::TRIANGLE_LIST,
|
||||
{draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D)},
|
||||
inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc,
|
||||
};
|
||||
drawTestDepth_ = draw->CreateGraphicsPipeline(testDepthDesc);
|
||||
|
||||
inputLayout->Release();
|
||||
blendOff->Release();
|
||||
depthStencilWrite->Release();
|
||||
stencilTestEqual->Release();
|
||||
depthTestEqual->Release();
|
||||
rasterNoCull->Release();
|
||||
|
||||
SamplerStateDesc nearestDesc{};
|
||||
samplerNearest_ = draw->CreateSamplerState(nearestDesc);
|
||||
}
|
||||
|
||||
UIContext &dc = *screenManager()->getUIContext();
|
||||
const Bounds &bounds = dc.GetBounds();
|
||||
|
||||
const char *testNames[] = {"Normal", "Z test", "Stencil test"};
|
||||
|
||||
const int numTests = ARRAY_SIZE(testNames);
|
||||
|
||||
uint32_t textColorOK = 0xFF30FF30;
|
||||
uint32_t textColorBAD = 0xFF3030FF;
|
||||
uint32_t bgColorOK = 0xFF106010;
|
||||
uint32_t bgColorBAD = 0xFF101060;
|
||||
|
||||
// Don't want any fancy font texture stuff going on here, so use FLAG_DYNAMIC_ASCII everywhere!
|
||||
|
||||
float testW = 200.f;
|
||||
float padding = 20.0f;
|
||||
UI::Style style = dc.theme->itemStyle;
|
||||
|
||||
float y = 100;
|
||||
float x = dc.GetBounds().centerX() - ((float)numTests * testW + (float)(numTests - 1) * padding) / 2.0f;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
dc.Begin();
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
Bounds bounds = {x - testW / 2, y + 40, testW, 70};
|
||||
dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII);
|
||||
|
||||
dc.FillRect(UI::Drawable(bgColorOK), bounds);
|
||||
// test bounds
|
||||
dc.Flush();
|
||||
|
||||
dc.BeginPipeline(discardWriteStencil_, samplerNearest_);
|
||||
|
||||
dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER);
|
||||
dc.Flush();
|
||||
|
||||
dc.BeginPipeline(drawTestStencil_, samplerNearest_);
|
||||
dc.FillRect(UI::Drawable(textColorOK), bounds);
|
||||
dc.Flush();
|
||||
|
||||
// Methodology:
|
||||
// 1. Draw text in red, writing to stencil.
|
||||
// 2. Use stencil test equality to make it green.
|
||||
|
||||
x += testW + padding;
|
||||
}
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
dc.Flush();
|
||||
}
|
29
UI/GPUDriverTestScreen.h
Normal file
29
UI/GPUDriverTestScreen.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/display.h"
|
||||
#include "ui/ui_context.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/viewgroup.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "Common/LogManager.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
|
||||
class GPUDriverTestScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
GPUDriverTestScreen();
|
||||
~GPUDriverTestScreen();
|
||||
|
||||
void CreateViews() override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
Draw::ShaderModule *discard_ = nullptr;
|
||||
Draw::Pipeline *discardWriteStencil_ = nullptr;
|
||||
Draw::Pipeline *drawTestStencil_ = nullptr;
|
||||
Draw::Pipeline *drawTestDepth_ = nullptr;
|
||||
Draw::SamplerState *samplerNearest_ = nullptr;
|
||||
};
|
@ -44,6 +44,7 @@
|
||||
#include "UI/TiltAnalogSettingsScreen.h"
|
||||
#include "UI/TiltEventProcessor.h"
|
||||
#include "UI/ComboKeyMappingScreen.h"
|
||||
#include "UI/GPUDriverTestScreen.h"
|
||||
|
||||
#include "Common/KeyMap.h"
|
||||
#include "Common/FileUtil.h"
|
||||
@ -1211,8 +1212,8 @@ UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) {
|
||||
screenManager()->push(new DeveloperToolsScreen());
|
||||
return UI::EVENT_DONE;
|
||||
screenManager()->push(new DeveloperToolsScreen());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) {
|
||||
@ -1232,12 +1233,12 @@ UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) {
|
||||
|
||||
//when the tilt event type is modified, we need to reset all tilt settings.
|
||||
//refer to the ResetTiltEvents() function for a detailed explanation.
|
||||
UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e){
|
||||
UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e) {
|
||||
TiltEventProcessor::ResetTiltEvents();
|
||||
return UI::EVENT_DONE;
|
||||
};
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e){
|
||||
UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e) {
|
||||
screenManager()->push(new TiltAnalogSettingsScreen());
|
||||
return UI::EVENT_DONE;
|
||||
};
|
||||
@ -1276,7 +1277,7 @@ void DeveloperToolsScreen::CreateViews() {
|
||||
// iOS can now use JIT on all modes, apparently.
|
||||
// The bool may come in handy for future non-jit platforms though (UWP XB1?)
|
||||
|
||||
static const char *cpuCores[] = { "Interpreter", "Dynarec (JIT)", "IR Interpreter" };
|
||||
static const char *cpuCores[] = {"Interpreter", "Dynarec (JIT)", "IR Interpreter"};
|
||||
PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, gr->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), sy->GetName(), screenManager()));
|
||||
core->OnChoice.Handle(this, &DeveloperToolsScreen::OnJitAffectingSetting);
|
||||
if (!canUseJit) {
|
||||
@ -1308,6 +1309,14 @@ void DeveloperToolsScreen::CreateViews() {
|
||||
list->Add(new ItemHeader(dev->T("Texture Replacement")));
|
||||
list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures")));
|
||||
list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures")));
|
||||
|
||||
// For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply
|
||||
// because the D3D drivers are generally solid enough to not need this type of investigation.
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
|
||||
list->Add(new ItemHeader(dev->T("Hardware Tests")));
|
||||
list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest);
|
||||
}
|
||||
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game")));
|
||||
createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile);
|
||||
@ -1382,6 +1391,11 @@ UI::EventReturn DeveloperToolsScreen::OnLogConfig(UI::EventParams &e) {
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn DeveloperToolsScreen::OnGPUDriverTest(UI::EventParams &e) {
|
||||
screenManager()->push(new GPUDriverTestScreen());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn DeveloperToolsScreen::OnJitAffectingSetting(UI::EventParams &e) {
|
||||
NativeMessageReceived("clear jit", "");
|
||||
return UI::EVENT_DONE;
|
||||
|
@ -158,6 +158,7 @@ private:
|
||||
UI::EventReturn OnLogConfig(UI::EventParams &e);
|
||||
UI::EventReturn OnJitAffectingSetting(UI::EventParams &e);
|
||||
UI::EventReturn OnRemoteDebugger(UI::EventParams &e);
|
||||
UI::EventReturn OnGPUDriverTest(UI::EventParams &e);
|
||||
|
||||
bool allowDebugger_ = false;
|
||||
bool canAllowDebugger_ = true;
|
||||
|
@ -96,6 +96,7 @@
|
||||
#include "UI/BackgroundAudio.h"
|
||||
#include "UI/TextureUtil.h"
|
||||
#include "UI/DiscordIntegration.h"
|
||||
#include "UI/GPUDriverTestScreen.h"
|
||||
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
#include "Common/KeyMap.h"
|
||||
|
@ -32,6 +32,7 @@
|
||||
<ClCompile Include="GamepadEmu.cpp" />
|
||||
<ClCompile Include="GameScreen.cpp" />
|
||||
<ClCompile Include="GameSettingsScreen.cpp" />
|
||||
<ClCompile Include="GPUDriverTestScreen.cpp" />
|
||||
<ClCompile Include="MainScreen.cpp" />
|
||||
<ClCompile Include="MiscScreens.cpp" />
|
||||
<ClCompile Include="NativeApp.cpp" />
|
||||
@ -64,6 +65,7 @@
|
||||
<ClInclude Include="GameScreen.h" />
|
||||
<ClInclude Include="GameSettingsScreen.h" />
|
||||
<ClInclude Include="CwCheatScreen.h" />
|
||||
<ClInclude Include="GPUDriverTestScreen.h" />
|
||||
<ClInclude Include="HostTypes.h" />
|
||||
<ClInclude Include="MainScreen.h" />
|
||||
<ClInclude Include="MiscScreens.h" />
|
||||
|
@ -71,6 +71,9 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextureUtil.cpp" />
|
||||
<ClCompile Include="DiscordIntegration.cpp" />
|
||||
<ClCompile Include="GPUDriverTestScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="GameInfoCache.h" />
|
||||
@ -143,6 +146,9 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureUtil.h" />
|
||||
<ClInclude Include="DiscordIntegration.h" />
|
||||
<ClInclude Include="GPUDriverTestScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Screens">
|
||||
|
@ -78,6 +78,7 @@ void DrawBuffer::Shutdown() {
|
||||
void DrawBuffer::Begin(Draw::Pipeline *program) {
|
||||
pipeline_ = program;
|
||||
count_ = 0;
|
||||
curZ_ = 0.0f;
|
||||
}
|
||||
|
||||
void DrawBuffer::Flush(bool set_blend_state) {
|
||||
|
@ -97,7 +97,7 @@ public:
|
||||
|
||||
void V(float x, float y, float z, uint32_t color, float u, float v);
|
||||
void V(float x, float y, uint32_t color, float u, float v) {
|
||||
V(x, y, 0.0f, color, u, v);
|
||||
V(x, y, curZ_, color, u, v);
|
||||
}
|
||||
|
||||
void Circle(float x, float y, float radius, float thickness, int segments, float startAngle, uint32_t color, float u_mul);
|
||||
@ -166,6 +166,10 @@ public:
|
||||
alphaStack_.pop_back();
|
||||
}
|
||||
|
||||
void SetCurZ(float curZ) {
|
||||
curZ_ = curZ;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Vertex {
|
||||
float x, y, z;
|
||||
@ -191,5 +195,7 @@ private:
|
||||
bool inited_;
|
||||
float fontscalex;
|
||||
float fontscaley;
|
||||
|
||||
float curZ_ = 0.0f;
|
||||
};
|
||||
|
||||
|
@ -101,11 +101,6 @@ bool RefCountedObject::ReleaseAssertLast() {
|
||||
|
||||
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
|
||||
|
||||
struct ShaderSource {
|
||||
ShaderLanguage lang;
|
||||
const char *src;
|
||||
};
|
||||
|
||||
static const std::vector<ShaderSource> fsTexCol = {
|
||||
{ShaderLanguage::GLSL_ES_200,
|
||||
"#ifdef GL_ES\n"
|
||||
@ -196,6 +191,7 @@ static const std::vector<ShaderSource> vsCol = {
|
||||
"attribute vec3 Position;\n"
|
||||
"attribute vec4 Color0;\n"
|
||||
"varying vec4 oColor0;\n"
|
||||
|
||||
"uniform mat4 WorldViewProj;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
|
||||
@ -317,7 +313,7 @@ const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{
|
||||
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 }
|
||||
} };
|
||||
|
||||
static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
|
||||
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
|
||||
uint32_t supported = draw->GetSupportedShaderLanguages();
|
||||
for (auto iter : sources) {
|
||||
if ((uint32_t)iter.lang & supported) {
|
||||
|
@ -662,4 +662,13 @@ struct VsColUB {
|
||||
};
|
||||
extern const UniformBufferDesc vsColBufDesc;
|
||||
|
||||
// Useful utility for specifying a shader in multiple languages.
|
||||
|
||||
struct ShaderSource {
|
||||
ShaderLanguage lang;
|
||||
const char *src;
|
||||
};
|
||||
|
||||
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources);
|
||||
|
||||
} // namespace Draw
|
||||
|
@ -15,9 +15,9 @@
|
||||
DrawBuffer ui_draw2d;
|
||||
DrawBuffer ui_draw2d_front;
|
||||
|
||||
void UIBegin(Draw::Pipeline *shaderSet) {
|
||||
ui_draw2d.Begin(shaderSet);
|
||||
ui_draw2d_front.Begin(shaderSet);
|
||||
void UIBegin(Draw::Pipeline *pipeline) {
|
||||
ui_draw2d.Begin(pipeline);
|
||||
ui_draw2d_front.Begin(pipeline);
|
||||
}
|
||||
|
||||
void UIFlush() {
|
||||
|
@ -52,6 +52,12 @@ void UIContext::BeginNoTex() {
|
||||
UIBegin(ui_pipeline_notex_);
|
||||
}
|
||||
|
||||
void UIContext::BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState) {
|
||||
draw_->BindSamplerStates(0, 1, &sampler_);
|
||||
draw_->BindTexture(0, uitexture_->GetTexture());
|
||||
UIBegin(pipeline);
|
||||
}
|
||||
|
||||
void UIContext::RebindTexture() const {
|
||||
draw_->BindTexture(0, uitexture_->GetTexture());
|
||||
}
|
||||
@ -65,6 +71,11 @@ void UIContext::Flush() {
|
||||
}
|
||||
}
|
||||
|
||||
void UIContext::SetCurZ(float curZ) {
|
||||
ui_draw2d.SetCurZ(curZ);
|
||||
ui_draw2d_front.SetCurZ(curZ);
|
||||
}
|
||||
|
||||
// TODO: Support transformed bounds using stencil instead.
|
||||
void UIContext::PushScissor(const Bounds &bounds) {
|
||||
Flush();
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
|
||||
void Begin();
|
||||
void BeginNoTex();
|
||||
void BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState);
|
||||
void Flush();
|
||||
|
||||
void RebindTexture() const;
|
||||
@ -85,6 +86,7 @@ public:
|
||||
void SetBounds(const Bounds &b) { bounds_ = b; }
|
||||
const Bounds &GetBounds() const { return bounds_; }
|
||||
Draw::DrawContext *GetDrawContext() { return draw_; }
|
||||
void SetCurZ(float curZ);
|
||||
|
||||
void PushTransform(const UITransform &transform);
|
||||
void PopTransform();
|
||||
|
Loading…
Reference in New Issue
Block a user