mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #15897 from hrydgard/many-gl-fixes
Many GL/GLES fixes
This commit is contained in:
commit
fd8419e28a
18 changed files with 91 additions and 52 deletions
|
@ -263,6 +263,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
|
|||
caps_.framebufferStencilBlitSupported = false;
|
||||
caps_.framebufferDepthCopySupported = true;
|
||||
caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw.
|
||||
caps_.textureDepthSupported = true;
|
||||
caps_.texture3DSupported = true;
|
||||
caps_.fragmentShaderInt32Supported = true;
|
||||
caps_.anisoSupported = true;
|
||||
|
|
|
@ -682,6 +682,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID
|
|||
HRESULT fboINTZ = d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_INTZ);
|
||||
supportsINTZ = SUCCEEDED(displayINTZ) && SUCCEEDED(fboINTZ);
|
||||
}
|
||||
caps_.textureDepthSupported = supportsINTZ;
|
||||
|
||||
shaderLanguageDesc_.Init(HLSL_D3D9);
|
||||
|
||||
|
|
|
@ -758,9 +758,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
|||
}
|
||||
|
||||
GLRProgram *curProgram = nullptr;
|
||||
int activeSlot = 0;
|
||||
if (first)
|
||||
glActiveTexture(GL_TEXTURE0 + activeSlot);
|
||||
int activeSlot = -1;
|
||||
|
||||
// State filtering tracking.
|
||||
int attrMask = 0;
|
||||
|
@ -1037,15 +1035,17 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
|||
activeSlot = slot;
|
||||
}
|
||||
if (c.bind_fb_texture.aspect == GL_COLOR_BUFFER_BIT) {
|
||||
if (curTex[slot] != &c.bind_fb_texture.framebuffer->color_texture)
|
||||
if (curTex[slot] != &c.bind_fb_texture.framebuffer->color_texture) {
|
||||
glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->color_texture.texture);
|
||||
curTex[slot] = &c.bind_fb_texture.framebuffer->color_texture;
|
||||
curTex[slot] = &c.bind_fb_texture.framebuffer->color_texture;
|
||||
}
|
||||
} else if (c.bind_fb_texture.aspect == GL_DEPTH_BUFFER_BIT) {
|
||||
if (curTex[slot] != &c.bind_fb_texture.framebuffer->z_stencil_texture)
|
||||
if (curTex[slot] != &c.bind_fb_texture.framebuffer->z_stencil_texture) {
|
||||
glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->z_stencil_texture.texture);
|
||||
curTex[slot] = &c.bind_fb_texture.framebuffer->z_stencil_texture;
|
||||
curTex[slot] = &c.bind_fb_texture.framebuffer->z_stencil_texture;
|
||||
}
|
||||
} else {
|
||||
// TODO: Stencil texturing?
|
||||
// Can't texture from stencil buffers.
|
||||
curTex[slot] = nullptr;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
@ -1202,8 +1202,13 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
|||
}
|
||||
case GLRRenderCommand::TEXTURE_SUBIMAGE:
|
||||
{
|
||||
GLRTexture *tex = c.texture_subimage.texture;
|
||||
GLint slot = c.texture_subimage.slot;
|
||||
if (slot != activeSlot) {
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
activeSlot = slot;
|
||||
}
|
||||
// TODO: Need bind?
|
||||
GLRTexture *tex = c.texture_subimage.texture;
|
||||
if (!c.texture_subimage.data)
|
||||
Crash();
|
||||
_assert_(tex->target == GL_TEXTURE_2D);
|
||||
|
|
|
@ -148,11 +148,12 @@ struct GLRRenderData {
|
|||
struct {
|
||||
GLRTexture *texture;
|
||||
Draw::DataFormat format;
|
||||
int level;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
uint8_t slot;
|
||||
uint8_t level;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
GLRAllocType allocType;
|
||||
uint8_t *data; // owned, delete[]-d
|
||||
} texture_subimage;
|
||||
|
|
|
@ -555,7 +555,7 @@ public:
|
|||
initSteps_.push_back(step);
|
||||
}
|
||||
|
||||
void TextureSubImage(GLRTexture *texture, int level, int x, int y, int width, int height, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) {
|
||||
void TextureSubImage(int slot, GLRTexture *texture, int level, int x, int y, int width, int height, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
GLRRenderData _data{ GLRRenderCommand::TEXTURE_SUBIMAGE };
|
||||
_data.texture_subimage.texture = texture;
|
||||
|
@ -567,6 +567,7 @@ public:
|
|||
_data.texture_subimage.width = width;
|
||||
_data.texture_subimage.height = height;
|
||||
_data.texture_subimage.allocType = allocType;
|
||||
_data.texture_subimage.slot = slot;
|
||||
curRenderStep_->commands.push_back(_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -533,12 +533,14 @@ OpenGLContext::OpenGLContext() {
|
|||
}
|
||||
}
|
||||
caps_.texture3DSupported = gl_extensions.OES_texture_3D;
|
||||
caps_.textureDepthSupported = gl_extensions.GLES3 || gl_extensions.OES_depth_texture;
|
||||
} else {
|
||||
if (gl_extensions.VersionGEThan(3, 3, 0)) {
|
||||
caps_.fragmentShaderInt32Supported = true;
|
||||
}
|
||||
caps_.preferredDepthBufferFormat = DataFormat::D24_S8;
|
||||
caps_.texture3DSupported = true;
|
||||
caps_.textureDepthSupported = true;
|
||||
}
|
||||
|
||||
caps_.dualSourceBlend = gl_extensions.ARB_blend_func_extended || gl_extensions.EXT_blend_func_extended;
|
||||
|
@ -821,11 +823,14 @@ OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) :
|
|||
return;
|
||||
|
||||
int level = 0;
|
||||
int width = width_;
|
||||
int height = height_;
|
||||
int depth = depth_;
|
||||
for (auto data : desc.initData) {
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, level, 0, data, desc.initDataCallback);
|
||||
width_ = (width_ + 1) / 2;
|
||||
height_ = (height_ + 1) / 2;
|
||||
depth_ = (depth_ + 1) / 2;
|
||||
SetImageData(0, 0, 0, width, height, depth, level, 0, data, desc.initDataCallback);
|
||||
width = (width + 1) / 2;
|
||||
height = (height + 1) / 2;
|
||||
depth = (depth + 1) / 2;
|
||||
level++;
|
||||
}
|
||||
mipLevels_ = desc.generateMips ? desc.mipLevels : level;
|
||||
|
@ -1211,7 +1216,7 @@ bool OpenGLPipeline::LinkShaders() {
|
|||
}
|
||||
std::vector<GLRProgram::Initializer> initialize;
|
||||
for (int i = 0; i < MAX_TEXTURE_SLOTS; ++i) {
|
||||
if (i < queries.size()) {
|
||||
if (i < samplers_.size()) {
|
||||
initialize.push_back({ &samplerLocs_[i], 0, i });
|
||||
} else {
|
||||
samplerLocs_[i] = -1;
|
||||
|
|
|
@ -789,6 +789,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
|
|||
caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case.
|
||||
caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan.
|
||||
caps_.texture3DSupported = true;
|
||||
caps_.textureDepthSupported = true;
|
||||
caps_.fragmentShaderInt32Supported = true;
|
||||
caps_.textureNPOTFullySupported = true;
|
||||
caps_.fragmentShaderDepthWriteSupported = true;
|
||||
|
|
|
@ -543,6 +543,7 @@ struct DeviceCaps {
|
|||
bool fragmentShaderInt32Supported;
|
||||
bool textureNPOTFullySupported;
|
||||
bool fragmentShaderDepthWriteSupported;
|
||||
bool textureDepthSupported;
|
||||
|
||||
std::string deviceName; // The device name to use when creating the thin3d context, to get the same one.
|
||||
};
|
||||
|
|
|
@ -230,7 +230,10 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (Shade
|
|||
{ draw2DVs_, fs },
|
||||
inputLayout,
|
||||
depthStencil,
|
||||
blend, rasterNoCull, &draw2DUBDesc,
|
||||
blend,
|
||||
rasterNoCull,
|
||||
&draw2DUBDesc,
|
||||
info.samplers.is_empty() ? samplers : info.samplers,
|
||||
};
|
||||
|
||||
Draw::Pipeline *pipeline = draw_->CreateGraphicsPipeline(pipelineDesc);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "GPU/GPU.h"
|
||||
#include "Common/GPU/Shader.h"
|
||||
|
||||
// For framebuffer copies and similar things that just require passthrough.
|
||||
struct Draw2DVertex {
|
||||
|
@ -32,7 +33,7 @@ inline RasterChannel Draw2DSourceChannel(Draw2DShader shader) {
|
|||
struct Draw2DPipelineInfo {
|
||||
RasterChannel readChannel;
|
||||
RasterChannel writeChannel;
|
||||
bool secondTexture;
|
||||
Slice<SamplerDef> samplers;
|
||||
};
|
||||
|
||||
struct Draw2DPipeline {
|
||||
|
|
|
@ -609,15 +609,15 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFFU;\n");
|
||||
WRITE(p, " uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3U;\n");
|
||||
WRITE(p, " float index0 = t.r;\n");
|
||||
WRITE(p, " float mul = 32.0 / 256.0;\n");
|
||||
WRITE(p, " if (depalFmt == 0) {\n"); // yes, different versions of Test Drive use different formats. Could do compile time by adding more compat flags but meh.
|
||||
WRITE(p, " if (depalShift == 5) { index0 = t.g; mul = 64.0 / 256.0; }\n");
|
||||
WRITE(p, " else if (depalShift == 11) { index0 = t.b; }\n");
|
||||
WRITE(p, " float factor = 32.0 / 256.0;\n");
|
||||
WRITE(p, " if (depalFmt == 0u) {\n"); // yes, different versions of Test Drive use different formats. Could do compile time by adding more compat flags but meh.
|
||||
WRITE(p, " if (depalShift == 5u) { index0 = t.g; factor = 64.0 / 256.0; }\n");
|
||||
WRITE(p, " else if (depalShift == 11u) { index0 = t.b; }\n");
|
||||
WRITE(p, " } else {\n");
|
||||
WRITE(p, " if (depalShift == 5) { index0 = t.g; }\n");
|
||||
WRITE(p, " else if (depalShift == 10) { index0 = t.b; }\n");
|
||||
WRITE(p, " if (depalShift == 5u) { index0 = t.g; }\n");
|
||||
WRITE(p, " else if (depalShift == 10u) { index0 = t.b; }\n");
|
||||
WRITE(p, " }\n");
|
||||
WRITE(p, " t = %s(pal, vec2(index0 * mul, 0.0));\n", compat.texture);
|
||||
WRITE(p, " t = %s(pal, vec2(index0 * factor, 0.0));\n", compat.texture);
|
||||
} else {
|
||||
if (doTextureProjection) {
|
||||
// We don't use textureProj because we need better control and it's probably not much of a savings anyway.
|
||||
|
|
|
@ -1044,6 +1044,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
|
|||
}
|
||||
|
||||
if (candidate.channel == RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) {
|
||||
WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding");
|
||||
// Flag to bind a null texture if we can't support depth textures.
|
||||
// Should only happen on old OpenGL.
|
||||
nextFramebufferTexture_ = nullptr;
|
||||
|
@ -1890,13 +1891,14 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
|||
|
||||
bool depth = channel == RASTER_DEPTH;
|
||||
bool need_depalettize = CanDepalettize(texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->drawnFormat);
|
||||
bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && !depth && !gstate_c.curTextureIs3D;
|
||||
|
||||
// Shader depal is not supported during 3D texturing or depth texturing, and requires 32-bit integer instructions in the shader.
|
||||
bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer &&
|
||||
!depth &&
|
||||
!gstate_c.curTextureIs3D &&
|
||||
draw_->GetDeviceCaps().fragmentShaderInt32Supported;
|
||||
|
||||
// TODO: Implement shader depal in the fragment shader generator for D3D11 at least.
|
||||
if (!draw_->GetDeviceCaps().fragmentShaderInt32Supported) {
|
||||
useShaderDepal = false;
|
||||
}
|
||||
|
||||
switch (draw_->GetShaderLanguageDesc().shaderLanguage) {
|
||||
case ShaderLanguage::HLSL_D3D11:
|
||||
case ShaderLanguage::HLSL_D3D9:
|
||||
|
@ -1915,7 +1917,6 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
|||
smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->drawnFormat, clutTexture.rampLength);
|
||||
|
||||
if (useShaderDepal) {
|
||||
|
||||
// Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture.
|
||||
BindAsClutTexture(clutTexture.texture);
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETe
|
|||
return Draw2DPipelineInfo{
|
||||
config.bufferFormat == GE_FORMAT_DEPTH16 ? RASTER_DEPTH : RASTER_COLOR,
|
||||
RASTER_COLOR,
|
||||
samplers
|
||||
};
|
||||
});
|
||||
delete[] buffer;
|
||||
|
|
|
@ -504,13 +504,13 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p
|
|||
}
|
||||
renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]);
|
||||
// Position
|
||||
renderManager_->TextureSubImage(data_tex[0], 0, 0, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)pos, GLRAllocType::NEW);
|
||||
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, 0, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)pos, GLRAllocType::NEW);
|
||||
// Texcoord
|
||||
if (hasTexCoord)
|
||||
renderManager_->TextureSubImage(data_tex[0], 0, size_u, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)tex, GLRAllocType::NEW);
|
||||
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)tex, GLRAllocType::NEW);
|
||||
// Color
|
||||
if (hasColor)
|
||||
renderManager_->TextureSubImage(data_tex[0], 0, size_u * 2, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)col, GLRAllocType::NEW);
|
||||
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u * 2, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)col, GLRAllocType::NEW);
|
||||
|
||||
// Weight U
|
||||
if (prevSizeWU < weights.size_u) {
|
||||
|
@ -521,7 +521,7 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p
|
|||
renderManager_->FinalizeTexture(data_tex[1], 0, false);
|
||||
}
|
||||
renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1]);
|
||||
renderManager_->TextureSubImage(data_tex[1], 0, 0, 0, weights.size_u * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.u, GLRAllocType::NONE);
|
||||
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1], 0, 0, 0, weights.size_u * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.u, GLRAllocType::NONE);
|
||||
|
||||
// Weight V
|
||||
if (prevSizeWV < weights.size_v) {
|
||||
|
@ -532,7 +532,7 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p
|
|||
renderManager_->FinalizeTexture(data_tex[2], 0, false);
|
||||
}
|
||||
renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]);
|
||||
renderManager_->TextureSubImage(data_tex[2], 0, 0, 0, weights.size_v * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.v, GLRAllocType::NONE);
|
||||
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2], 0, 0, 0, weights.size_v * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.v, GLRAllocType::NONE);
|
||||
}
|
||||
|
||||
void TessellationDataTransferGLES::EndFrame() {
|
||||
|
|
|
@ -201,9 +201,9 @@ void GPU_GLES::CheckGPUFeatures() {
|
|||
features |= GPU_SUPPORTS_DEPTH_CLAMP | GPU_SUPPORTS_ACCURATE_DEPTH;
|
||||
// Our implementation of depth texturing needs simple Z range, so can't
|
||||
// use the extension hacks (yet).
|
||||
if (gl_extensions.GLES3)
|
||||
features |= GPU_SUPPORTS_DEPTH_TEXTURE;
|
||||
}
|
||||
if (draw_->GetDeviceCaps().textureDepthSupported)
|
||||
features |= GPU_SUPPORTS_DEPTH_TEXTURE;
|
||||
if (draw_->GetDeviceCaps().clipDistanceSupported)
|
||||
features |= GPU_SUPPORTS_CLIP_DISTANCE;
|
||||
if (draw_->GetDeviceCaps().cullDistanceSupported)
|
||||
|
|
|
@ -96,8 +96,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
|
|||
|
||||
std::vector<GLRProgram::UniformLocQuery> queries;
|
||||
queries.push_back({ &u_tex, "tex" });
|
||||
queries.push_back({ &u_proj, "u_proj" });
|
||||
queries.push_back({ &u_proj_through, "u_proj_through" });
|
||||
queries.push_back({ &u_pal, "pal" });
|
||||
queries.push_back({ &u_testtex, "testtex" });
|
||||
queries.push_back({ &u_fbotex, "fbotex" });
|
||||
|
||||
queries.push_back({ &u_proj, "u_proj" });
|
||||
queries.push_back({ &u_proj_through, "u_proj_through" });
|
||||
|
@ -108,13 +109,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
|
|||
queries.push_back({ &u_alphacolormask, "u_alphacolormask" });
|
||||
queries.push_back({ &u_colorWriteMask, "u_colorWriteMask" });
|
||||
queries.push_back({ &u_stencilReplaceValue, "u_stencilReplaceValue" });
|
||||
queries.push_back({ &u_testtex, "testtex" });
|
||||
|
||||
queries.push_back({ &u_fbotex, "fbotex" });
|
||||
queries.push_back({ &u_blendFixA, "u_blendFixA" });
|
||||
queries.push_back({ &u_blendFixB, "u_blendFixB" });
|
||||
queries.push_back({ &u_fbotexSize, "u_fbotexSize" });
|
||||
queries.push_back({ &u_pal, "pal" });
|
||||
|
||||
// Transform
|
||||
queries.push_back({ &u_view, "u_view" });
|
||||
|
|
|
@ -218,6 +218,11 @@ void TextureCacheGLES::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBas
|
|||
}
|
||||
|
||||
void TextureCacheGLES::BindTexture(TexCacheEntry *entry) {
|
||||
if (!entry) {
|
||||
render_->BindTexture(0, nullptr);
|
||||
lastBoundTexture = nullptr;
|
||||
return;
|
||||
}
|
||||
if (entry->textureName != lastBoundTexture) {
|
||||
render_->BindTexture(0, entry->textureName);
|
||||
lastBoundTexture = entry->textureName;
|
||||
|
|
|
@ -28,18 +28,33 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
|
|||
float alpha = (iter->endTime - now) * 4.0f;
|
||||
if (alpha > 1.0) alpha = 1.0f;
|
||||
if (alpha < 0.0) alpha = 0.0f;
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
// Messages that are wider than the screen are left-aligned instead of centered.
|
||||
|
||||
int align = 0;
|
||||
// Simple heuristic: Draw messages that contain line breaks with ASCII_FONT (likely debug output)
|
||||
if (iter->text.find('\n') != 0) {
|
||||
align |= FLAG_DYNAMIC_ASCII;
|
||||
}
|
||||
|
||||
float tw, th;
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, iter->text.c_str(), &tw, &th);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, iter->text.c_str(), &tw, &th, align);
|
||||
float x = bounds_.centerX();
|
||||
int align = ALIGN_TOP | ALIGN_HCENTER;
|
||||
if (tw > bounds_.w) {
|
||||
align = ALIGN_TOP | ALIGN_LEFT;
|
||||
align |= ALIGN_TOP | ALIGN_LEFT;
|
||||
x = 2;
|
||||
} else {
|
||||
align |= ALIGN_TOP | ALIGN_HCENTER;
|
||||
}
|
||||
float scale = 1.0f;
|
||||
if (th > bounds_.h - y) {
|
||||
// Scale down!
|
||||
scale = std::max(0.15f, (bounds_.h - y) / th);
|
||||
dc.SetFontScale(scale, scale);
|
||||
}
|
||||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
dc.DrawTextShadow(iter->text.c_str(), x, y, colorAlpha(iter->color, alpha), align);
|
||||
y += h;
|
||||
y += th * scale;
|
||||
}
|
||||
|
||||
osm.Unlock();
|
||||
|
|
Loading…
Add table
Reference in a new issue