CRasterFont::CRasterFont(urde::CInputStream& in, urde::IObjectStore& store) { u32 magic; in.readBytesToBuf(&magic, 4); if (magic != SBIG('FONT')) return; u32 version = in.readUint32Big(); x4_monoWidth = in.readUint32Big(); x8_monoHeight = in.readUint32Big(); if (version >= 1) x8c_baseline = in.readUint32Big(); else x8c_baseline = x8_monoHeight; if (version >= 2) x90_lineMargin = in.readUint32Big(); bool tmp1 = in.readBool(); bool tmp2 = in.readBool(); u32 tmp3 = in.readUint32Big(); u32 tmp4 = in.readUint32Big(); std::string name= in.readString(); u32 txtrId = in.readUint32Big(); x30_fontInfo = CFontInfo(tmp1, tmp2, tmp3, tmp4, name.c_str()); x80_texture = store.GetObj({'TXTR', txtrId}); EColorType mode = EColorType(in.readUint32Big()); /* TODO: Make an enum */ if (mode == EColorType::One) x2c_mode = EColorType::One; else if (mode == EColorType::Zero) x2c_mode = EColorType::Zero; u32 glyphCount = in.readUint32Big(); xc_glyphs.reserve(glyphCount); for (u32 i = 0 ; i < glyphCount ; ++i) { wchar_t chr = in.readUint16Big(); float startU = in.readFloatBig(); float startV = in.readFloatBig(); float endU = in.readFloatBig(); float endV = in.readFloatBig(); s32 a = in.readInt32Big(); s32 b = in.readInt32Big(); s32 c = in.readInt32Big(); s32 cellWidth = in.readInt32Big(); s32 cellHeight = in.readInt32Big(); s32 baseline = in.readInt32Big(); s32 kernStart = in.readInt32Big(); xc_glyphs[i] = std::make_pair(chr, CGlyph(a, b, c, startU, startV, endU, endV, cellWidth, cellHeight, baseline, kernStart)); } std::sort(xc_glyphs.begin(), xc_glyphs.end(), [=](auto& a, auto& b) -> bool{ return a.first < b.first; }); u32 kernCount = in.readUint32Big(); x1c_kerning.reserve(kernCount); for (u32 i = 0 ; i < kernCount ; ++i) { wchar_t first = in.readUint16Big(); wchar_t second = in.readUint16Big(); s32 howMuch = in.readUint32Big(); x1c_kerning[i] = CKernPair(first, second, howMuch); } }
CTextRenderer::CGlyph* CTextRenderer::CGlyphCache::NewGlyph(CGlyphId GlyphId, int Width, int Height) { ivec2 Granularity; Granularity.x = (Width%m_PPG == 0 ? (Width / m_PPG) : (Width / m_PPG) + 1); Granularity.y = (Height%m_PPG == 0 ? (Height / m_PPG) : (Height / m_PPG) + 1); if(Granularity.x < 1) Granularity.x = 1; if(Granularity.y < 1) Granularity.y = 1; //First pass: find a free slot in blocks //We use backward iteration because non-full blockes are at the end for(int i=m_Blocks.size()-1; i>=0; i--) { if(m_Blocks[i].m_Granularity == Granularity) { if(!m_Blocks[i].IsFull()) { CGlyph* pGlyph = &m_Glyphs[m_Glyphs.add(CGlyph(GlyphId))]; pGlyph->m_Width = Width; pGlyph->m_Height = Height; pGlyph->m_Granularity = Granularity; pGlyph->m_Block = i; pGlyph->m_BlockPos = m_Blocks[i].m_Size; UpdateGlyph(pGlyph); m_Blocks[pGlyph->m_Block].m_Size++; return pGlyph; } else break; //Only the last block of this granularity can be non-full } } //Second pass: find the oldest glyph with the same granularity int OldestTick = m_RenderTick; int OldestGlyph = -1; for(int i=0; i<m_Glyphs.size(); i++) { if(m_Glyphs[i].m_Granularity == Granularity && m_Glyphs[i].m_RenderTick < OldestTick) { OldestTick = m_Glyphs[i].m_RenderTick; OldestGlyph = i; } } if(OldestGlyph >= 0) //Replace the glyph { CGlyph Glyph = CGlyph(GlyphId); Glyph.m_Block = m_Glyphs[OldestGlyph].m_Block; Glyph.m_BlockPos = m_Glyphs[OldestGlyph].m_BlockPos; m_Glyphs.remove_index(OldestGlyph); int GlyphId = m_Glyphs.add(Glyph); CGlyph* pGlyph = &m_Glyphs[GlyphId]; pGlyph->m_Width = Width; pGlyph->m_Height = Height; pGlyph->m_Granularity = Granularity; UpdateGlyph(pGlyph); UpdateVersion(); return pGlyph; } else //Add a new block { int BlockId = NewBlock(Granularity); CGlyph* pGlyph = &m_Glyphs[m_Glyphs.add(CGlyph(GlyphId))]; pGlyph->m_Width = Width; pGlyph->m_Height = Height; pGlyph->m_Granularity = Granularity; pGlyph->m_Block = BlockId; pGlyph->m_BlockPos = 0; UpdateGlyph(pGlyph); m_Blocks[pGlyph->m_Block].m_Size++; return pGlyph; } }