diff --git a/gfx_es2/draw_text.cpp b/gfx_es2/draw_text.cpp index dff9a6a080..53baf045c9 100644 --- a/gfx_es2/draw_text.cpp +++ b/gfx_es2/draw_text.cpp @@ -1,9 +1,9 @@ #include "base/logging.h" #include "base/stringutil.h" -#include "gfx/gl_common.h" -#include "gfx_es2/draw_text.h" +#include "thin3d/thin3d.h" #include "util/hash/hash.h" #include "util/text/utf8.h" +#include "gfx_es2/draw_text.h" #ifdef USING_QT_UI #include @@ -32,9 +32,10 @@ struct TextDrawerContext { int *pBitmapBits; }; -TextDrawer::TextDrawer() { +TextDrawer::TextDrawer(Thin3DContext *thin3d) : thin3d_(thin3d), ctx_(NULL) { fontScaleX_ = 1.0f; fontScaleY_ = 1.0f; + ctx_ = new TextDrawerContext(); ctx_->hDC = CreateCompatibleDC(NULL); @@ -55,7 +56,7 @@ TextDrawer::TextDrawer() { TextDrawer::~TextDrawer() { for (auto iter = cache_.begin(); iter != cache_.end(); ++iter) { - glDeleteTextures(1, &iter->second->textureHandle); + iter->second->texture->Release(); delete iter->second; } cache_.clear(); @@ -123,6 +124,9 @@ void TextDrawer::MeasureString(const char *str, float *w, float *h) { } void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { + if (!strlen(str)) + return; + uint32_t stringHash = hash::Fletcher((const uint8_t *)str, strlen(str)); uint32_t entryHash = stringHash ^ fontHash_; @@ -134,7 +138,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float if (iter != cache_.end()) { entry = iter->second; entry->lastUsedFrame = frameCount_; - glBindTexture(GL_TEXTURE_2D, entry->textureHandle); + thin3d_->SetTexture(0, entry->texture); } else { // Render the string to our bitmap and save to a GL texture. std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); @@ -163,30 +167,23 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_HIDEPREFIX|DT_TOP|DT_LEFT, 0); entry = new TextStringEntry(); - glGenTextures(1, &entry->textureHandle); - glBindTexture(GL_TEXTURE_2D, entry->textureHandle); entry->width = size.cx; entry->height = size.cy; entry->bmWidth = (size.cx + 3) & ~3; entry->bmHeight = (size.cy + 3) & ~3; entry->lastUsedFrame = frameCount_; + entry->texture = thin3d_->CreateTexture(LINEAR2D, RGBA4444, entry->bmWidth, entry->bmHeight, 1, 0); // Convert the bitmap to a gl-compatible array of pixels. uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { BYTE bAlpha = (BYTE)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); bitmapData[entry->bmWidth * y + x] = (bAlpha) | 0xfff0; // ^ rand(); } } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry->bmWidth, entry->bmHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, bitmapData); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + entry->texture->SetImageData(0, 0, 0, entry->bmWidth, entry->bmHeight, 1, 0, entry->bmWidth * 2, (const uint8_t *)bitmapData); + entry->texture->Finalize(0); delete [] bitmapData; cache_[entryHash] = entry; diff --git a/gfx_es2/draw_text.h b/gfx_es2/draw_text.h index 4280180ec8..3d94a0528e 100644 --- a/gfx_es2/draw_text.h +++ b/gfx_es2/draw_text.h @@ -12,13 +12,23 @@ #include "base/basictypes.h" #include "gfx_es2/draw_buffer.h" +#if !(defined(_WIN32) && !defined(USING_QT_UI)) +#include "gfx_es2/gl_state.h" +#endif + +class Thin3DContext; +class Thin3DTexture; #ifdef USING_QT_UI #include #endif struct TextStringEntry { - uint32_t textureHandle; +#if defined(_WIN32) && !defined(USING_QT_UI) + Thin3DTexture *texture; +#else + GLuint textureHandle; +#endif int width; int height; int bmWidth; @@ -38,7 +48,7 @@ struct TextDrawerFontContext; class TextDrawer { public: - TextDrawer(); + TextDrawer(Thin3DContext *thin3d); ~TextDrawer(); uint32_t SetFont(const char *fontName, int size, int flags); @@ -52,6 +62,8 @@ public: void OncePerFrame(); private: + Thin3DContext *thin3d_; + int frameCount_; float fontScaleX_; float fontScaleY_; diff --git a/thin3d/thin3d.cpp b/thin3d/thin3d.cpp index 4ce2a275b3..7c74d6b933 100644 --- a/thin3d/thin3d.cpp +++ b/thin3d/thin3d.cpp @@ -13,7 +13,7 @@ static const char * const hlslFsTexCol = "struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n" "sampler2D tex0 : register(s0);\n" "float4 main(PS_INPUT input) : COLOR0 {\n" -" return input.color * tex2D(tex0, input.uv).bgra;\n" +" return input.color * tex2D(tex0, input.uv);\n" "}\n"; static const char * const glsl_fsCol = diff --git a/thin3d/thin3d.h b/thin3d/thin3d.h index e6f9dfa87b..45fbf8ac35 100644 --- a/thin3d/thin3d.h +++ b/thin3d/thin3d.h @@ -147,7 +147,7 @@ public: class Thin3DTexture : public Thin3DObject { public: - virtual void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, uint8_t *data) = 0; + virtual void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) = 0; virtual void AutoGenMipmaps() = 0; virtual void Finalize(int zim_flags) = 0; // TODO: Tidy up @@ -210,6 +210,7 @@ enum T3DTextureType : uint8_t { enum T3DImageFormat : uint8_t { LUMINANCE, RGBA8888, + RGBA4444, DXT1, ETC1, // Needs simulation on many platforms D16, @@ -234,6 +235,14 @@ enum T3DFileType { DETECT, }; +enum T3DInfo { + APINAME, + APIVERSION, + VENDOR, + SHADELANGVERSION, + RENDERER, +}; + class Thin3DContext : public Thin3DObject { public: virtual ~Thin3DContext(); @@ -287,7 +296,7 @@ public: targetHeight_ = h; } - virtual const char *GetAPIName() const = 0; + virtual const char *GetInfoString(T3DInfo info) const = 0; protected: void CreatePresets(); diff --git a/thin3d/thin3d_d3d9.cpp b/thin3d/thin3d_d3d9.cpp index 037a184c66..e55b690289 100644 --- a/thin3d/thin3d_d3d9.cpp +++ b/thin3d/thin3d_d3d9.cpp @@ -214,7 +214,7 @@ private: class Thin3DDX9Texture : public Thin3DTexture { public: Thin3DDX9Texture(LPDIRECT3DDEVICE9 device, T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels); - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, uint8_t *data) override; + void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; void AutoGenMipmaps() override {} void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler); void Finalize(int zim_flags) override {} @@ -230,6 +230,7 @@ private: D3DFORMAT FormatToD3D(T3DImageFormat fmt) { switch (fmt) { case RGBA8888: return D3DFMT_A8R8G8B8; + case RGBA4444: return D3DFMT_A4R4G4B4; case D24S8: return D3DFMT_D24S8; case D16: return D3DFMT_D16; default: return D3DFMT_UNKNOWN; @@ -256,9 +257,22 @@ Thin3DDX9Texture::Thin3DDX9Texture(LPDIRECT3DDEVICE9 device, T3DTextureType type hr = device->CreateCubeTexture(width, mipLevels, 0, fmt_, D3DPOOL_MANAGED, &cubeTex_, NULL); break; } + if (FAILED(hr)) { + ELOG("Texture creation failed"); + } } -void Thin3DDX9Texture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, uint8_t *data) { +inline uint16_t Shuffle4444(uint16_t x) { + return (x << 12) | (x >> 4); +} + +// A rather different transform, for curious reasons.. +inline uint32_t Shuffle8888(uint32_t x) { + return (x & 0xFF00FF00) | ((x >> 16) & 0xFF) | ((x << 16) & 0xFF0000); +} + + +void Thin3DDX9Texture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) { if (!tex_) { return; } @@ -274,8 +288,25 @@ void Thin3DDX9Texture::SetImageData(int x, int y, int z, int width, int height, D3DLOCKED_RECT rect; if (x == 0 && y == 0) { tex_->LockRect(level, &rect, NULL, D3DLOCK_DISCARD); + for (int i = 0; i < height; i++) { - memcpy((uint8_t *)rect.pBits + rect.Pitch * i, data + stride * i, width * 4); + uint8_t *dest = (uint8_t *)rect.pBits + rect.Pitch * i; + const uint8_t *source = data + stride * i; + int j; + switch (fmt_) { + case D3DFMT_A4R4G4B4: + // This is backwards from OpenGL so we need to shuffle around a bit. + for (j = 0; j < width; j++) { + ((uint16_t *)dest)[j] = Shuffle4444(((uint16_t *)source)[j]); + } + break; + + case D3DFMT_A8R8G8B8: + for (j = 0; j < width; j++) { + ((uint32_t *)dest)[j] = Shuffle8888(((uint32_t *)source)[j]); + } + break; + } } tex_->UnlockRect(level); } @@ -344,7 +375,17 @@ public: void DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *pipeline, Thin3DVertexFormat *format, Thin3DBuffer *vdata, Thin3DBuffer *idata, int vertexCount, int offset) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal); - const char *GetAPIName() const override { return "Direct3D9"; } + const char *GetInfoString(T3DInfo info) const override { + // TODO: Make these actually query the right information + switch (info) { + case APIVERSION: return "DirectX 9.0"; + case VENDOR: return "?"; + case RENDERER: return "?"; + case SHADELANGVERSION: return "3.0"; + case APINAME: return "Direct3D 9"; + default: return "?"; + } + } private: // void CompileShader(const char *hlsl_source); diff --git a/thin3d/thin3d_gl.cpp b/thin3d/thin3d_gl.cpp index 257b7a5621..f179b6135f 100644 --- a/thin3d/thin3d_gl.cpp +++ b/thin3d/thin3d_gl.cpp @@ -279,12 +279,21 @@ public: void DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, Thin3DBuffer *vdata, Thin3DBuffer *idata, int vertexCount, int offset) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override; - const char *GetAPIName() const override { -#ifdef USING_GLES2 - return "OpenGL ES"; -#else - return "OpenGL"; -#endif + const char *GetInfoString(T3DInfo info) const override { + // TODO: Make these actually query the right information + switch (info) { + case APINAME: + #ifdef USING_GLES2 + return "OpenGL ES"; + #else + return "OpenGL"; + #endif + case VENDOR: return (const char *)glGetString(GL_VENDOR); + case RENDERER: return (const char *)glGetString(GL_RENDERER); + case SHADELANGVERSION: return (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION); + case APIVERSION: return (const char *)glGetString(GL_VERSION); + default: return "?"; + } } }; @@ -318,13 +327,16 @@ GLuint TypeToTarget(T3DTextureType type) { class Thin3DGLTexture : public Thin3DTexture { public: - Thin3DGLTexture(T3DTextureType type, T3DImageFormat format, int mipLevels) : format_(format), tex_(0), target_(TypeToTarget(type)), mipLevels_(mipLevels) { + Thin3DGLTexture(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) : format_(format), tex_(0), target_(TypeToTarget(type)), mipLevels_(mipLevels) { + width_ = width; + height_ = height; + depth_ = depth; glGenTextures(1, &tex_); } ~Thin3DGLTexture() { glDeleteTextures(1, &tex_); } - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, uint8_t *data) override; + void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; void AutoGenMipmaps() override; void Bind() { @@ -341,8 +353,7 @@ private: }; Thin3DTexture *Thin3DGLContext::CreateTexture(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) { - Thin3DGLTexture *tex = new Thin3DGLTexture(type, format, mipLevels); - return tex; + return new Thin3DGLTexture(type, format, width, height, depth, mipLevels); } void Thin3DGLTexture::AutoGenMipmaps() { @@ -350,13 +361,7 @@ void Thin3DGLTexture::AutoGenMipmaps() { glGenerateMipmap(target_); } -void Thin3DGLTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, uint8_t *data) { - if (level == 0) { - width_ = width; - height_ = height; - depth_ = depth; - } - +void Thin3DGLTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) { int internalFormat; int format; int type; @@ -366,6 +371,11 @@ void Thin3DGLTexture::SetImageData(int x, int y, int z, int width, int height, i format = GL_RGBA; type = GL_UNSIGNED_BYTE; break; + case RGBA4444: + internalFormat = GL_RGBA; + format = GL_RGBA; + type = GL_UNSIGNED_SHORT_4_4_4_4; + break; default: return; } @@ -373,7 +383,7 @@ void Thin3DGLTexture::SetImageData(int x, int y, int z, int width, int height, i glBindTexture(target_, tex_); switch (target_) { case GL_TEXTURE_2D: - glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type, data); + glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width_, height_, 0, format, type, data); break; } } diff --git a/ui/ui_context.cpp b/ui/ui_context.cpp index 51c5f7a82e..2b23035fc4 100644 --- a/ui/ui_context.cpp +++ b/ui/ui_context.cpp @@ -30,7 +30,7 @@ void UIContext::Init(Thin3DContext *thin3d, Thin3DShaderSet *uishader, Thin3DSha uidrawbuffer_ = uidrawbuffer; uidrawbufferTop_ = uidrawbufferTop; #if defined(_WIN32) || defined(USING_QT_UI) - textDrawer_ = new TextDrawer(); + textDrawer_ = new TextDrawer(thin3d); #else textDrawer_ = 0; #endif