Added string cache.
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
#include "lc_global.h"
|
||||
#include "lc_stringcache.h"
|
||||
#include "lc_texture.h"
|
||||
#include "lc_context.h"
|
||||
|
||||
lcStringCache gStringCache;
|
||||
|
||||
lcStringCache::lcStringCache()
|
||||
{
|
||||
mTexture = nullptr;
|
||||
mBuffer = nullptr;
|
||||
mRefCount = 0;
|
||||
}
|
||||
|
||||
lcStringCache::~lcStringCache()
|
||||
{
|
||||
delete mBuffer;
|
||||
delete mTexture;
|
||||
}
|
||||
|
||||
void lcStringCache::AddRef(lcContext* Context)
|
||||
{
|
||||
mRefCount++;
|
||||
|
||||
if (mRefCount == 1)
|
||||
{
|
||||
mTexture = new lcTexture();
|
||||
mTexture->mWidth = 256;
|
||||
mTexture->mHeight = 256;
|
||||
|
||||
glGenTextures(1, &mTexture->mTexture);
|
||||
Context->BindTexture2D(mTexture->mTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
mBuffer = new unsigned char[mTexture->mWidth * mTexture->mHeight * 2];
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, mTexture->mWidth, mTexture->mHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, mBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void lcStringCache::Release(lcContext* Context)
|
||||
{
|
||||
mRefCount--;
|
||||
|
||||
if (mRefCount == 0)
|
||||
{
|
||||
Context->UnbindTexture2D(mTexture->mTexture); // todo: unbind from all contexts
|
||||
|
||||
delete mTexture;
|
||||
mTexture = nullptr;
|
||||
delete mBuffer;
|
||||
mBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void lcStringCache::CacheStrings(lcContext* Context, const QStringList& Strings)
|
||||
{
|
||||
bool Update = false;
|
||||
|
||||
for (const QString& String : Strings)
|
||||
{
|
||||
if (mStrings.find(String) == mStrings.end())
|
||||
{
|
||||
mStrings[String] = lcStringCacheEntry();
|
||||
Update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Update)
|
||||
return;
|
||||
|
||||
QImage Image(128, 128, QImage::Format_RGBA8888);
|
||||
QPainter Painter;
|
||||
QFont Font("Helvetica", 20);
|
||||
int DestX = 0, DestY = 0, DestHeight = 0;
|
||||
memset(mBuffer, 0, mTexture->mWidth * mTexture->mHeight * 2);
|
||||
|
||||
for (auto& Entry : mStrings)
|
||||
{
|
||||
QRect SourceRect;
|
||||
|
||||
Painter.begin(&Image);
|
||||
Painter.fillRect(0, 0, Image.width(), Image.height(), QColor(0, 0, 0));
|
||||
Painter.setBrush(QColor(255, 255, 255));
|
||||
Painter.setPen(QColor(255, 255, 255));
|
||||
Painter.setFont(Font);
|
||||
Painter.drawText(0, 0, Image.width(), Image.height(), 0, Entry.first, &SourceRect);
|
||||
Painter.end();
|
||||
|
||||
if (DestX + SourceRect.width() > mTexture->mWidth)
|
||||
{
|
||||
DestX = 0;
|
||||
DestY += DestHeight;
|
||||
DestHeight = 0;
|
||||
}
|
||||
|
||||
lcStringCacheEntry& String = Entry.second;
|
||||
|
||||
if (SourceRect.width() > mTexture->mWidth || DestY + SourceRect.height() > mTexture->mHeight)
|
||||
{
|
||||
memset(&String, 0, sizeof(String));
|
||||
break;
|
||||
}
|
||||
|
||||
String.Top = mTexture->mHeight - DestY - 1;
|
||||
String.Bottom = String.Top - SourceRect.height();
|
||||
String.Left = DestX;
|
||||
String.Right = DestX + SourceRect.width();
|
||||
|
||||
for (int y = SourceRect.top(); y < SourceRect.bottom(); y++)
|
||||
{
|
||||
const unsigned char* Source = Image.constBits() + y * Image.width() * 4;
|
||||
unsigned char* Dest = mBuffer + ((String.Top - y) * mTexture->mWidth + String.Left) * 2;
|
||||
|
||||
for (int x = SourceRect.left(); x < SourceRect.right(); x++)
|
||||
{
|
||||
*Dest = *(Dest + 1) = *Source;
|
||||
Source += 4;
|
||||
Dest += 2;
|
||||
}
|
||||
}
|
||||
|
||||
DestX += SourceRect.width();
|
||||
DestHeight = qMax(DestHeight, SourceRect.height());
|
||||
}
|
||||
|
||||
Context->BindTexture2D(mTexture->mTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, mTexture->mWidth, mTexture->mHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, mBuffer);
|
||||
}
|
||||
|
||||
void lcStringCache::GetStringDimensions(int* cx, int* cy, const QString& String) const
|
||||
{
|
||||
const auto& Entry = mStrings.find(String);
|
||||
|
||||
if (Entry != mStrings.end())
|
||||
{
|
||||
const lcStringCacheEntry& FontString = Entry->second;
|
||||
*cx = FontString.Right - FontString.Left;
|
||||
*cy = FontString.Top - FontString.Bottom;
|
||||
}
|
||||
else
|
||||
*cx = *cy = 0;
|
||||
}
|
||||
|
||||
void lcStringCache::DrawStrings(lcContext* Context, const lcMatrix44* Transforms, const QStringList& Strings) const
|
||||
{
|
||||
float* Verts = (float*)alloca(Strings.size() * 6 * 5 * sizeof(float));
|
||||
float* Buffer = Verts;
|
||||
|
||||
for (int StringIdx = 0; StringIdx < Strings.size(); StringIdx++)
|
||||
{
|
||||
const auto& Entry = mStrings.find(Strings[StringIdx]);
|
||||
|
||||
if (Entry == mStrings.end())
|
||||
continue;
|
||||
|
||||
const lcStringCacheEntry& FontString = Entry->second;
|
||||
|
||||
float u0 = (float)FontString.Left / (float)(mTexture->mWidth - 1);
|
||||
float u1 = (float)FontString.Right / (float)(mTexture->mWidth - 1);
|
||||
float v0 = (float)FontString.Bottom / (float)(mTexture->mHeight - 1);
|
||||
float v1 = (float)FontString.Top / (float)(mTexture->mHeight - 1);
|
||||
|
||||
float Width = FontString.Right - FontString.Left;
|
||||
float Height = FontString.Top - FontString.Bottom;
|
||||
float Left = -Width / 2.0f;
|
||||
float Top = Height / 2.0f;
|
||||
float Z = 0.0f;
|
||||
|
||||
lcVector3 Points[4] =
|
||||
{
|
||||
lcVector3(Left, Top, Z),
|
||||
lcVector3(Left, Top - Height, Z),
|
||||
lcVector3(Left + Width, Top - Height, Z),
|
||||
lcVector3(Left + Width, Top, Z),
|
||||
};
|
||||
|
||||
for (int PointIdx = 0; PointIdx < 4; PointIdx++)
|
||||
Points[PointIdx] = lcMul31(Points[PointIdx], Transforms[StringIdx]);
|
||||
|
||||
*Buffer++ = Points[0].x;
|
||||
*Buffer++ = Points[0].y;
|
||||
*Buffer++ = Points[0].z;
|
||||
*Buffer++ = u0;
|
||||
*Buffer++ = v1;
|
||||
|
||||
*Buffer++ = Points[1].x;
|
||||
*Buffer++ = Points[1].y;
|
||||
*Buffer++ = Points[1].z;
|
||||
*Buffer++ = u0;
|
||||
*Buffer++ = v0;
|
||||
|
||||
*Buffer++ = Points[2].x;
|
||||
*Buffer++ = Points[2].y;
|
||||
*Buffer++ = Points[2].z;
|
||||
*Buffer++ = u1;
|
||||
*Buffer++ = v0;
|
||||
|
||||
*Buffer++ = Points[2].x;
|
||||
*Buffer++ = Points[2].y;
|
||||
*Buffer++ = Points[2].z;
|
||||
*Buffer++ = u1;
|
||||
*Buffer++ = v0;
|
||||
|
||||
*Buffer++ = Points[3].x;
|
||||
*Buffer++ = Points[3].y;
|
||||
*Buffer++ = Points[3].z;
|
||||
*Buffer++ = u1;
|
||||
*Buffer++ = v1;
|
||||
|
||||
*Buffer++ = Points[0].x;
|
||||
*Buffer++ = Points[0].y;
|
||||
*Buffer++ = Points[0].z;
|
||||
*Buffer++ = u0;
|
||||
*Buffer++ = v1;
|
||||
}
|
||||
|
||||
Context->SetVertexBufferPointer(Verts);
|
||||
Context->SetVertexFormat(0, 3, 0, 2, 0, false);
|
||||
|
||||
Context->BindTexture2D(mTexture->mTexture);
|
||||
Context->SetColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
Context->DrawPrimitives(GL_TRIANGLES, 0, Strings.size() * 6);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user