~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/Font/PGF.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2012- PPSSPP Project.
 
2
 
 
3
// This program is free software: you can redistribute it and/or modify
 
4
// it under the terms of the GNU General Public License as published by
 
5
// the Free Software Foundation, version 2.0 or later versions.
 
6
 
 
7
// This program is distributed in the hope that it will be useful,
 
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
// GNU General Public License 2.0 for more details.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official git repository and contact information can be found at
 
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 
17
 
 
18
// ============== NOTE!!!!
 
19
 
 
20
// Thanks to the JPCSP project! This sceFont implementation is basically a C++ take on JPCSP's font code.
 
21
// Some parts, especially in this file, were simply copied, so I guess this really makes this file GPL3.
 
22
 
 
23
#include <algorithm>
 
24
#include "Common/ChunkFile.h"
 
25
#include "Core/MemMap.h"
 
26
#include "Core/Reporting.h"
 
27
#include "Core/Font/PGF.h"
 
28
#include "Core/HLE/HLE.h"
 
29
 
 
30
#include "GPU/GPUInterface.h"
 
31
#include "GPU/GPUState.h"
 
32
 
 
33
// These fonts, created by ttf2pgf, don't have complete glyph info and need to be identified.
 
34
static bool isJPCSPFont(const char *fontName) {
 
35
        return !strcmp(fontName, "Liberation Sans") || !strcmp(fontName, "Liberation Serif") || !strcmp(fontName, "Sazanami") || !strcmp(fontName, "UnDotum") || !strcmp(fontName, "Microsoft YaHei");
 
36
}
 
37
 
 
38
// Gets a number of bits from an offset.
 
39
static int getBits(int numBits, const u8 *buf, size_t pos) {
 
40
        _dbg_assert_msg_(SCEFONT, numBits <= 32, "Unable to return more than 32 bits, %d requested", numBits);
 
41
 
 
42
        const size_t wordpos = pos >> 5;
 
43
        const u32 *wordbuf = (const u32 *)buf;
 
44
        const u8 bitoff = pos & 31;
 
45
 
 
46
        // Might just be in one, has to be within two.
 
47
        if (bitoff + numBits < 32) {
 
48
                const u32 mask = (1 << numBits) - 1;
 
49
                return (wordbuf[wordpos] >> bitoff) & mask;
 
50
        } else {
 
51
                int v = wordbuf[wordpos] >> bitoff;
 
52
 
 
53
                const u8 done = 32 - bitoff;
 
54
                const u8 remaining = numBits - done;
 
55
                const u32 mask = (1 << remaining) - 1;
 
56
                v |= (wordbuf[wordpos + 1] & mask) << done;
 
57
                return v;
 
58
        }
 
59
}
 
60
 
 
61
static inline int consumeBits(int numBits, const u8 *buf, size_t &pos) {
 
62
        int v = getBits(numBits, buf, pos);
 
63
        pos += numBits;
 
64
        return v;
 
65
}
 
66
 
 
67
static std::vector<int> getTable(const u8 *buf, int bpe, size_t length) {
 
68
        std::vector<int> vec;
 
69
        vec.resize(length);
 
70
        for (size_t i = 0; i < length; i++) {
 
71
                vec[i] = getBits(bpe, buf, bpe * i);
 
72
        }
 
73
        return vec;
 
74
}
 
75
 
 
76
PGF::PGF()
 
77
        : fontData(0) {
 
78
 
 
79
}
 
80
 
 
81
PGF::~PGF() {
 
82
        if (fontData) {
 
83
                delete [] fontData;
 
84
        }
 
85
}
 
86
 
 
87
struct GlyphFromPGF1State {
 
88
        int x;
 
89
        int y;
 
90
        int w;
 
91
        int h;
 
92
        int left;
 
93
        int top;
 
94
        int flags;
 
95
        int shadowID;
 
96
        int advanceH;
 
97
        int advanceV;
 
98
        int dimensionWidth, dimensionHeight;
 
99
        int xAdjustH, xAdjustV;
 
100
        int yAdjustH, yAdjustV;
 
101
        u32 ptr;
 
102
 
 
103
        operator Glyph() {
 
104
                Glyph ret;
 
105
                ret.w = w;
 
106
                ret.h = h;
 
107
                ret.left = left;
 
108
                ret.top = top;
 
109
                ret.flags = flags;
 
110
                // Wasn't read before.
 
111
                ret.shadowFlags = 0;
 
112
                ret.shadowID = shadowID;
 
113
                ret.advanceH = advanceH;
 
114
                ret.advanceV = advanceV;
 
115
                ret.dimensionWidth = dimensionWidth;
 
116
                ret.dimensionHeight = dimensionHeight;
 
117
                ret.xAdjustH = xAdjustH;
 
118
                ret.xAdjustV = xAdjustV;
 
119
                ret.yAdjustH = yAdjustH;
 
120
                ret.yAdjustV = yAdjustV;
 
121
                ret.ptr = ptr;
 
122
                return ret;
 
123
        }
 
124
};
 
125
 
 
126
void PGF::DoState(PointerWrap &p) {
 
127
        auto s = p.Section("PGF", 1, 2);
 
128
        if (!s)
 
129
                return;
 
130
 
 
131
        p.Do(header);
 
132
        p.Do(rev3extra);
 
133
 
 
134
        // Don't savestate size_t directly, 32-bit and 64-bit are different.
 
135
        u32 fontDataSizeTemp = (u32)fontDataSize;
 
136
        p.Do(fontDataSizeTemp);
 
137
        fontDataSize = (size_t)fontDataSizeTemp;
 
138
        if (p.mode == p.MODE_READ) {
 
139
                if (fontData) {
 
140
                        delete [] fontData;
 
141
                }
 
142
                if (fontDataSize) {
 
143
                        fontData = new u8[fontDataSize];
 
144
                        p.DoArray(fontData, (int)fontDataSize);
 
145
                }
 
146
        } else if (fontDataSize) {
 
147
                p.DoArray(fontData, (int)fontDataSize);
 
148
        }
 
149
        p.Do(fileName);
 
150
 
 
151
        p.DoArray(dimensionTable, ARRAY_SIZE(dimensionTable));
 
152
        p.DoArray(xAdjustTable, ARRAY_SIZE(xAdjustTable));
 
153
        p.DoArray(yAdjustTable, ARRAY_SIZE(yAdjustTable));
 
154
        p.DoArray(advanceTable, ARRAY_SIZE(advanceTable));
 
155
        p.DoArray(charmapCompressionTable1, ARRAY_SIZE(charmapCompressionTable1));
 
156
        p.DoArray(charmapCompressionTable2, ARRAY_SIZE(charmapCompressionTable2));
 
157
 
 
158
        p.Do(charmap_compr);
 
159
        p.Do(charmap);
 
160
        if (s == 1) {
 
161
                std::vector<GlyphFromPGF1State> oldGlyphs;
 
162
                p.Do(oldGlyphs);
 
163
                glyphs.resize(oldGlyphs.size());
 
164
                for (size_t i = 0; i < oldGlyphs.size(); ++i) {
 
165
                        glyphs[i] = oldGlyphs[i];
 
166
                }
 
167
                p.Do(oldGlyphs);
 
168
                shadowGlyphs.resize(oldGlyphs.size());
 
169
                for (size_t i = 0; i < oldGlyphs.size(); ++i) {
 
170
                        shadowGlyphs[i] = oldGlyphs[i];
 
171
                }
 
172
        } else {
 
173
                p.Do(glyphs);
 
174
                p.Do(shadowGlyphs);
 
175
        }
 
176
        p.Do(firstGlyph);
 
177
}
 
178
 
 
179
bool PGF::ReadPtr(const u8 *ptr, size_t dataSize) {
 
180
        const u8 *const startPtr = ptr;
 
181
 
 
182
        if (dataSize < sizeof(header)) {
 
183
                return false;
 
184
        }
 
185
 
 
186
        DEBUG_LOG(SCEFONT, "Reading %d bytes of PGF header", (int)sizeof(header));
 
187
        memcpy(&header, ptr, sizeof(header));
 
188
        ptr += sizeof(header);
 
189
 
 
190
        fileName = header.fontName;
 
191
 
 
192
        if (header.revision == 3) {
 
193
                memcpy(&rev3extra, ptr, sizeof(rev3extra));
 
194
                rev3extra.compCharMapLength1 &= 0xFFFF;
 
195
                rev3extra.compCharMapLength2 &= 0xFFFF;
 
196
                ptr += sizeof(rev3extra);
 
197
        }
 
198
 
 
199
        const u32_le *wptr = (const u32_le *)ptr;
 
200
        dimensionTable[0].resize(header.dimTableLength);
 
201
        dimensionTable[1].resize(header.dimTableLength);
 
202
        for (int i = 0; i < header.dimTableLength; i++) {
 
203
                dimensionTable[0][i] = *wptr++;
 
204
                dimensionTable[1][i] = *wptr++;
 
205
        }
 
206
 
 
207
        xAdjustTable[0].resize(header.xAdjustTableLength);
 
208
        xAdjustTable[1].resize(header.xAdjustTableLength);
 
209
        for (int i = 0; i < header.xAdjustTableLength; i++) {
 
210
                xAdjustTable[0][i] = *wptr++;
 
211
                xAdjustTable[1][i] = *wptr++;
 
212
        }
 
213
 
 
214
        yAdjustTable[0].resize(header.yAdjustTableLength);
 
215
        yAdjustTable[1].resize(header.yAdjustTableLength);
 
216
        for (int i = 0; i < header.yAdjustTableLength; i++) {
 
217
                yAdjustTable[0][i] = *wptr++;
 
218
                yAdjustTable[1][i] = *wptr++;
 
219
        }
 
220
 
 
221
        advanceTable[0].resize(header.advanceTableLength);
 
222
        advanceTable[1].resize(header.advanceTableLength);
 
223
        for (int i = 0; i < header.advanceTableLength; i++) {
 
224
                advanceTable[0][i] = *wptr++;
 
225
                advanceTable[1][i] = *wptr++;
 
226
        }
 
227
 
 
228
        const u8 *uptr = (const u8 *)wptr;
 
229
 
 
230
        if (uptr >= startPtr + dataSize) {
 
231
                return false;
 
232
        }
 
233
 
 
234
        int shadowCharMapSize = ((header.shadowMapLength * header.shadowMapBpe + 31) & ~31) / 8;
 
235
        const u8 *shadowCharMap = uptr;
 
236
        uptr += shadowCharMapSize;
 
237
 
 
238
        const u16_le *sptr = (const u16_le *)uptr;
 
239
        if (header.revision == 3) {
 
240
                charmapCompressionTable1[0].resize(rev3extra.compCharMapLength1);
 
241
                charmapCompressionTable1[1].resize(rev3extra.compCharMapLength1);
 
242
                for (int i = 0; i < rev3extra.compCharMapLength1; i++) {
 
243
                        charmapCompressionTable1[0][i] = *sptr++;
 
244
                        charmapCompressionTable1[1][i] = *sptr++;
 
245
                }
 
246
 
 
247
                charmapCompressionTable2[0].resize(rev3extra.compCharMapLength2);
 
248
                charmapCompressionTable2[1].resize(rev3extra.compCharMapLength2);
 
249
                for (int i = 0; i < rev3extra.compCharMapLength2; i++) {
 
250
                        charmapCompressionTable2[0][i] = *sptr++;
 
251
                        charmapCompressionTable2[1][i] = *sptr++;
 
252
                }
 
253
        }
 
254
 
 
255
        uptr = (const u8 *)sptr;
 
256
 
 
257
        if (uptr >= startPtr + dataSize) {
 
258
                return false;
 
259
        }
 
260
 
 
261
        int charMapSize = ((header.charMapLength * header.charMapBpe + 31) & ~31) / 8;
 
262
        const u8 *charMap = uptr;
 
263
        uptr += charMapSize;
 
264
 
 
265
        int charPointerSize = (((header.charPointerLength * header.charPointerBpe + 31) & ~31) / 8);
 
266
        const u8 *charPointerTable = uptr;
 
267
        uptr += charPointerSize;
 
268
 
 
269
        // PGF Fontdata.
 
270
        u32 fontDataOffset = (u32)(uptr - startPtr);
 
271
 
 
272
        fontDataSize = dataSize - fontDataOffset;
 
273
        fontData = new u8[fontDataSize];
 
274
        memcpy(fontData, uptr, fontDataSize);
 
275
 
 
276
        // charmap.resize();
 
277
        charmap.resize(header.charMapLength);
 
278
        int charmap_compr_len = header.revision == 3 ? 7 : 1;
 
279
        charmap_compr.resize(charmap_compr_len * 4);
 
280
        glyphs.resize(header.charPointerLength);
 
281
        shadowGlyphs.resize(header.charPointerLength);
 
282
        firstGlyph = header.firstGlyph;
 
283
 
 
284
        // Parse out the char map (array where each entry is an irregular number of bits)
 
285
        // BPE = bits per entry, I think.
 
286
        for (int i = 0; i < header.charMapLength; i++) {
 
287
                charmap[i] = getBits(header.charMapBpe, charMap, i * header.charMapBpe);
 
288
                // This check seems a little odd.
 
289
                if ((size_t)charmap[i] >= glyphs.size())
 
290
                        charmap[i] = 65535;
 
291
        }
 
292
 
 
293
        std::vector<int> charPointers = getTable(charPointerTable, header.charPointerBpe, glyphs.size());
 
294
        std::vector<int> shadowMap = getTable(shadowCharMap, header.shadowMapBpe, (s32)header.shadowMapLength);
 
295
 
 
296
        // Pregenerate glyphs.
 
297
        for (size_t i = 0; i < glyphs.size(); i++) {
 
298
                ReadCharGlyph(fontData, charPointers[i] * 4 * 8  /* ??? */, glyphs[i]);
 
299
        }
 
300
 
 
301
        // And shadow glyphs.
 
302
        for (size_t i = 0; i < glyphs.size(); i++) {
 
303
                size_t shadowId = glyphs[i].shadowID;
 
304
                if (shadowId < shadowMap.size()) {
 
305
                        size_t charId = shadowMap[shadowId];
 
306
                        if (charId < shadowGlyphs.size()) {
 
307
                                // TODO: check for pre existing shadow glyph
 
308
                                ReadShadowGlyph(fontData, charPointers[charId] * 4 * 8  /* ??? */, shadowGlyphs[charId]);
 
309
                        }
 
310
                }
 
311
        }
 
312
 
 
313
        return true;
 
314
}
 
315
 
 
316
int PGF::GetCharIndex(int charCode, const std::vector<int> &charmapCompressed) {
 
317
        int charIndex = 0;
 
318
        for (size_t i = 0; i < charmapCompressed.size(); i += 2) {
 
319
                if (charCode >= charmapCompressed[i] && charCode < charmapCompressed[i] + charmapCompressed[i + 1]) {
 
320
                        charIndex += charCode - charmapCompressed[i];
 
321
                        return charIndex;
 
322
                }
 
323
                charIndex += charmapCompressed[i + 1];
 
324
        }
 
325
        return -1;
 
326
}
 
327
 
 
328
bool PGF::GetCharInfo(int charCode, PGFCharInfo *charInfo, int altCharCode, int glyphType) const {
 
329
        Glyph glyph;
 
330
        memset(charInfo, 0, sizeof(*charInfo));
 
331
 
 
332
        if (!GetCharGlyph(charCode, glyphType, glyph)) {
 
333
                if (charCode < firstGlyph) {
 
334
                        // Character not in font, return zeroed charInfo as on real PSP.
 
335
                        return false;
 
336
                }
 
337
                if (!GetCharGlyph(altCharCode, glyphType, glyph)) {
 
338
                        return false;
 
339
                }
 
340
        }
 
341
 
 
342
        charInfo->bitmapWidth = glyph.w;
 
343
        charInfo->bitmapHeight = glyph.h;
 
344
        charInfo->bitmapLeft = glyph.left;
 
345
        charInfo->bitmapTop = glyph.top;
 
346
        charInfo->sfp26Width = glyph.dimensionWidth;
 
347
        charInfo->sfp26Height = glyph.dimensionHeight;
 
348
        charInfo->sfp26Ascender = glyph.yAdjustH;
 
349
        // Font y goes upwards.  If top is 10 and height is 11, the descender is approx. -1 (below 0.)
 
350
        charInfo->sfp26Descender = charInfo->sfp26Ascender - (s32_le)charInfo->sfp26Height;
 
351
        charInfo->sfp26BearingHX = glyph.xAdjustH;
 
352
        charInfo->sfp26BearingHY = glyph.yAdjustH;
 
353
        charInfo->sfp26BearingVX = glyph.xAdjustV;
 
354
        charInfo->sfp26BearingVY = glyph.yAdjustV;
 
355
        charInfo->sfp26AdvanceH = glyph.advanceH;
 
356
        charInfo->sfp26AdvanceV = glyph.advanceV;
 
357
        charInfo->shadowFlags = glyph.shadowFlags;
 
358
        charInfo->shadowId = glyph.shadowID;
 
359
        return true;
 
360
}
 
361
 
 
362
void PGF::GetFontInfo(PGFFontInfo *fi) const {
 
363
        fi->maxGlyphWidthI = header.maxSize[0];
 
364
        fi->maxGlyphHeightI = header.maxSize[1];
 
365
        fi->maxGlyphAscenderI = header.maxAscender;
 
366
        fi->maxGlyphDescenderI = header.maxDescender;
 
367
        fi->maxGlyphLeftXI = header.maxLeftXAdjust;
 
368
        fi->maxGlyphBaseYI = header.maxBaseYAdjust;
 
369
        fi->minGlyphCenterXI = header.minCenterXAdjust;
 
370
        fi->maxGlyphTopYI = header.maxTopYAdjust;
 
371
        fi->maxGlyphAdvanceXI = header.maxAdvance[0];
 
372
        fi->maxGlyphAdvanceYI = header.maxAdvance[1];
 
373
        fi->maxGlyphWidthF = (float)header.maxSize[0] / 64.0f;
 
374
        fi->maxGlyphHeightF = (float)header.maxSize[1] / 64.0f;
 
375
        fi->maxGlyphAscenderF = (float)header.maxAscender / 64.0f;
 
376
        fi->maxGlyphDescenderF = (float)header.maxDescender / 64.0f;
 
377
        fi->maxGlyphLeftXF = (float)header.maxLeftXAdjust / 64.0f;
 
378
        fi->maxGlyphBaseYF = (float)header.maxBaseYAdjust / 64.0f;
 
379
        fi->minGlyphCenterXF = (float)header.minCenterXAdjust / 64.0f;
 
380
        fi->maxGlyphTopYF = (float)header.maxTopYAdjust / 64.0f;
 
381
        fi->maxGlyphAdvanceXF = (float)header.maxAdvance[0] / 64.0f;
 
382
        fi->maxGlyphAdvanceYF = (float)header.maxAdvance[1] / 64.0f;
 
383
 
 
384
        fi->maxGlyphWidth = header.maxGlyphWidth;
 
385
        fi->maxGlyphHeight = header.maxGlyphHeight;
 
386
        fi->numGlyphs = header.charPointerLength;
 
387
        fi->shadowMapLength = 0;  // header.shadowMapLength; TODO
 
388
 
 
389
        fi->BPP = header.bpp;
 
390
}
 
391
 
 
392
bool PGF::ReadShadowGlyph(const u8 *fontdata, size_t charPtr, Glyph &glyph) {
 
393
        // Most of the glyph info is from the char data.
 
394
        if (!ReadCharGlyph(fontdata, charPtr, glyph))
 
395
                return false;
 
396
 
 
397
        // Skip over the char data.
 
398
        if (charPtr + 96 > fontDataSize * 8)
 
399
                return false;
 
400
        charPtr += getBits(14, fontdata, charPtr) * 8;
 
401
        if (charPtr + 96 > fontDataSize * 8)
 
402
                return false;
 
403
 
 
404
        // Skip size.
 
405
        charPtr += 14;
 
406
 
 
407
        glyph.w = consumeBits(7, fontdata, charPtr);
 
408
        glyph.h = consumeBits(7, fontdata, charPtr);
 
409
 
 
410
        glyph.left = consumeBits(7, fontdata, charPtr);
 
411
        if (glyph.left >= 64) {
 
412
                glyph.left -= 128;
 
413
        }
 
414
 
 
415
        glyph.top = consumeBits(7, fontdata, charPtr);
 
416
        if (glyph.top >= 64) {
 
417
                glyph.top -= 128;
 
418
        }
 
419
 
 
420
        glyph.ptr = (u32)(charPtr / 8);
 
421
        return true;
 
422
}
 
423
 
 
424
bool PGF::ReadCharGlyph(const u8 *fontdata, size_t charPtr, Glyph &glyph) {
 
425
        // Skip size.
 
426
        charPtr += 14;
 
427
 
 
428
        glyph.w = consumeBits(7, fontdata, charPtr);
 
429
        glyph.h = consumeBits(7, fontdata, charPtr);
 
430
 
 
431
        glyph.left = consumeBits(7, fontdata, charPtr);
 
432
        if (glyph.left >= 64) {
 
433
                glyph.left -= 128;
 
434
        }
 
435
 
 
436
        glyph.top = consumeBits(7, fontdata, charPtr);
 
437
        if (glyph.top >= 64) {
 
438
                glyph.top -= 128;
 
439
        }
 
440
 
 
441
        glyph.flags = consumeBits(6, fontdata, charPtr);
 
442
 
 
443
        glyph.shadowFlags = consumeBits(2, fontdata, charPtr) << (2 + 3);
 
444
        glyph.shadowFlags |= consumeBits(2, fontdata, charPtr) << 3;
 
445
        glyph.shadowFlags |= consumeBits(3, fontdata, charPtr);
 
446
 
 
447
        glyph.shadowID = consumeBits(9, fontdata, charPtr);
 
448
 
 
449
        if ((glyph.flags & FONT_PGF_METRIC_DIMENSION_INDEX) == FONT_PGF_METRIC_DIMENSION_INDEX)
 
450
        {
 
451
                int dimensionIndex = consumeBits(8, fontdata, charPtr);
 
452
 
 
453
                if (dimensionIndex < header.dimTableLength) {
 
454
                        glyph.dimensionWidth = dimensionTable[0][dimensionIndex];
 
455
                        glyph.dimensionHeight = dimensionTable[1][dimensionIndex];
 
456
                }
 
457
 
 
458
                if (dimensionIndex == 0 && isJPCSPFont(fileName.c_str())) {
 
459
                        // Fonts created by ttf2pgf do not contain complete Glyph information.
 
460
                        // Provide default values.
 
461
                        glyph.dimensionWidth = glyph.w << 6;
 
462
                        glyph.dimensionHeight = glyph.h << 6;
 
463
                }
 
464
        }
 
465
        else
 
466
        {
 
467
                glyph.dimensionWidth = consumeBits(32, fontdata, charPtr);
 
468
                glyph.dimensionHeight = consumeBits(32, fontdata, charPtr);
 
469
        }
 
470
 
 
471
        if ((glyph.flags & FONT_PGF_METRIC_BEARING_X_INDEX) == FONT_PGF_METRIC_BEARING_X_INDEX)
 
472
        {
 
473
                int xAdjustIndex = consumeBits(8, fontdata, charPtr);
 
474
 
 
475
                if (xAdjustIndex < header.xAdjustTableLength) {
 
476
                        glyph.xAdjustH = xAdjustTable[0][xAdjustIndex];
 
477
                        glyph.xAdjustV = xAdjustTable[1][xAdjustIndex];
 
478
                }
 
479
 
 
480
                if (xAdjustIndex == 0 && isJPCSPFont(fileName.c_str()))
 
481
                {
 
482
                        // Fonts created by ttf2pgf do not contain complete Glyph information.
 
483
                        // Provide default values.
 
484
                        glyph.xAdjustH = glyph.left << 6;
 
485
                        glyph.xAdjustV = glyph.left << 6;
 
486
                }
 
487
        }
 
488
        else
 
489
        {
 
490
                glyph.xAdjustH = consumeBits(32, fontdata, charPtr);
 
491
                glyph.xAdjustV = consumeBits(32, fontdata, charPtr);
 
492
        }
 
493
 
 
494
        if ((glyph.flags & FONT_PGF_METRIC_BEARING_Y_INDEX) == FONT_PGF_METRIC_BEARING_Y_INDEX)
 
495
        {
 
496
                int yAdjustIndex = consumeBits(8, fontdata, charPtr);
 
497
 
 
498
                if (yAdjustIndex < header.yAdjustTableLength) {
 
499
                        glyph.yAdjustH = yAdjustTable[0][yAdjustIndex];
 
500
                        glyph.yAdjustV = yAdjustTable[1][yAdjustIndex];
 
501
                }
 
502
 
 
503
                if (yAdjustIndex == 0 && isJPCSPFont(fileName.c_str()))
 
504
                {
 
505
                        // Fonts created by ttf2pgf do not contain complete Glyph information.
 
506
                        // Provide default values.
 
507
                        glyph.yAdjustH = glyph.top << 6;
 
508
                        glyph.yAdjustV = glyph.top << 6;
 
509
                }
 
510
        }
 
511
        else
 
512
        {
 
513
                glyph.yAdjustH = consumeBits(32, fontdata, charPtr);
 
514
                glyph.yAdjustV = consumeBits(32, fontdata, charPtr);
 
515
        }
 
516
 
 
517
        if ((glyph.flags & FONT_PGF_METRIC_ADVANCE_INDEX) == FONT_PGF_METRIC_ADVANCE_INDEX)
 
518
        {
 
519
                int advanceIndex = consumeBits(8, fontdata, charPtr);
 
520
 
 
521
                if (advanceIndex < header.advanceTableLength) {
 
522
                        glyph.advanceH = advanceTable[0][advanceIndex];
 
523
                        glyph.advanceV = advanceTable[1][advanceIndex];
 
524
                }
 
525
        }
 
526
        else
 
527
        {
 
528
                glyph.advanceH = consumeBits(32, fontdata, charPtr);
 
529
                glyph.advanceV = consumeBits(32, fontdata, charPtr);
 
530
        }
 
531
 
 
532
        glyph.ptr = (u32)(charPtr / 8);
 
533
        return true;
 
534
}
 
535
 
 
536
bool PGF::GetCharGlyph(int charCode, int glyphType, Glyph &glyph) const {
 
537
        if (charCode < firstGlyph)
 
538
                return false;
 
539
        charCode -= firstGlyph;
 
540
        if (charCode < (int)charmap.size()) {
 
541
                charCode = charmap[charCode];
 
542
        }
 
543
        if (glyphType == FONT_PGF_CHARGLYPH) {
 
544
                if (charCode >= (int)glyphs.size())
 
545
                        return false;
 
546
                glyph = glyphs[charCode];
 
547
        } else {
 
548
                if (charCode >= (int)shadowGlyphs.size())
 
549
                        return false;
 
550
                glyph = shadowGlyphs[charCode];
 
551
        }
 
552
        return true;
 
553
}
 
554
 
 
555
void PGF::DrawCharacter(const GlyphImage *image, int clipX, int clipY, int clipWidth, int clipHeight, int charCode, int altCharCode, int glyphType) const {
 
556
        Glyph glyph;
 
557
        if (!GetCharGlyph(charCode, glyphType, glyph)) {
 
558
                if (charCode < firstGlyph) {
 
559
                        // Don't draw anything if the character is before the first available glyph.
 
560
                        return;
 
561
                }
 
562
                // No Glyph available for this charCode, try to use the alternate char.
 
563
                charCode = altCharCode;
 
564
                if (!GetCharGlyph(charCode, glyphType, glyph)) {
 
565
                        return;
 
566
                }
 
567
        }
 
568
 
 
569
        if (glyph.w <= 0 || glyph.h <= 0) {
 
570
                DEBUG_LOG(SCEFONT, "Glyph with negative size, not rendering");
 
571
                return;
 
572
        }
 
573
 
 
574
        if (((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_H_ROWS) &&
 
575
                ((glyph.flags & FONT_PGF_BMP_OVERLAY) != FONT_PGF_BMP_V_ROWS)) {
 
576
                ERROR_LOG_REPORT(SCEFONT, "Nonsense glyph bitmap direction flag");
 
577
                return;
 
578
        }
 
579
 
 
580
        size_t bitPtr = glyph.ptr * 8;
 
581
        int numberPixels = glyph.w * glyph.h;
 
582
        int pixelIndex = 0;
 
583
 
 
584
        int x = image->xPos64 >> 6;
 
585
        int y = image->yPos64 >> 6;
 
586
        u8 xFrac = image->xPos64 & 0x3F;
 
587
        u8 yFrac = image->yPos64 & 0x3F;
 
588
 
 
589
        // Negative means don't clip on that side.
 
590
        if (clipX < 0)
 
591
                clipX = 0;
 
592
        if (clipY < 0)
 
593
                clipY = 0;
 
594
        if (clipWidth < 0)
 
595
                clipWidth = 8192;
 
596
        if (clipHeight < 0)
 
597
                clipHeight = 8192;
 
598
 
 
599
        // Use a buffer so we can apply subpixel rendering.
 
600
        // TODO: Cache this buffer per glyph?  Maybe even transpose it first?
 
601
        std::vector<u8> decodedPixels;
 
602
        decodedPixels.resize(numberPixels);
 
603
 
 
604
        while (pixelIndex < numberPixels && bitPtr + 8 < fontDataSize * 8) {
 
605
                // This is some kind of nibble based RLE compression.
 
606
                int nibble = consumeBits(4, fontData, bitPtr);
 
607
 
 
608
                int count;
 
609
                int value = 0;
 
610
                if (nibble < 8) {
 
611
                        value = consumeBits(4, fontData, bitPtr);
 
612
                        count = nibble + 1;
 
613
                } else {
 
614
                        count = 16 - nibble;
 
615
                }
 
616
 
 
617
                for (int i = 0; i < count && pixelIndex < numberPixels; i++) {
 
618
                        if (nibble >= 8) {
 
619
                                value = consumeBits(4, fontData, bitPtr);
 
620
                        }
 
621
 
 
622
                        decodedPixels[pixelIndex++] = value | (value << 4);
 
623
                }
 
624
        }
 
625
 
 
626
        auto samplePixel = [&](int xx, int yy) -> u8 {
 
627
                if (xx < 0 || yy < 0 || xx >= glyph.w || yy >= glyph.h) {
 
628
                        return 0;
 
629
                }
 
630
 
 
631
                int index;
 
632
                if ((glyph.flags & FONT_PGF_BMP_OVERLAY) == FONT_PGF_BMP_H_ROWS) {
 
633
                        index = yy * glyph.w + xx;
 
634
                } else {
 
635
                        index = xx * glyph.h + yy;
 
636
                }
 
637
 
 
638
                return decodedPixels[index];
 
639
        };
 
640
 
 
641
        int renderX1 = std::max(clipX, x) - x;
 
642
        int renderY1 = std::max(clipY, y) - y;
 
643
        // We can render up to frac beyond the glyph w/h, so add 1px if necessary.
 
644
        int renderX2 = std::min(clipX + clipWidth - x, glyph.w + (xFrac > 0 ? 1 : 0));
 
645
        int renderY2 = std::min(clipY + clipHeight - y, glyph.h + (yFrac > 0 ? 1 : 0));
 
646
 
 
647
        if (xFrac == 0 && yFrac == 0) {
 
648
                for (int yy = renderY1; yy < renderY2; ++yy) {
 
649
                        for (int xx = renderX1; xx < renderX2; ++xx) {
 
650
                                u8 pixelColor = samplePixel(xx, yy);
 
651
                                SetFontPixel(image->bufferPtr, image->bytesPerLine, image->bufWidth, image->bufHeight, x + xx, y + yy, pixelColor, (FontPixelFormat)(u32)image->pixelFormat);
 
652
                        }
 
653
                }
 
654
        } else {
 
655
                for (int yy = renderY1; yy < renderY2; ++yy) {
 
656
                        for (int xx = renderX1; xx < renderX2; ++xx) {
 
657
                                // First, blend horizontally.  Tests show we blend swizzled to 8 bit.
 
658
                                u32 horiz1 = samplePixel(xx - 1, yy - 1) * xFrac + samplePixel(xx, yy - 1) * (64 - xFrac);
 
659
                                u32 horiz2 = samplePixel(xx - 1, yy + 0) * xFrac + samplePixel(xx, yy + 0) * (64 - xFrac);
 
660
                                // Now blend those together vertically.
 
661
                                u32 blended = horiz1 * yFrac + horiz2 * (64 - yFrac);
 
662
 
 
663
                                // We multiplied an 8 bit value by 64 twice, so now we have a 20 bit value.
 
664
                                u8 pixelColor = blended >> 12;
 
665
                                SetFontPixel(image->bufferPtr, image->bytesPerLine, image->bufWidth, image->bufHeight, x + xx, y + yy, pixelColor, (FontPixelFormat)(u32)image->pixelFormat);
 
666
                        }
 
667
                }
 
668
        }
 
669
 
 
670
        gpu->InvalidateCache(image->bufferPtr, image->bytesPerLine * image->bufHeight, GPU_INVALIDATE_SAFE);
 
671
}
 
672
 
 
673
void PGF::SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, u8 pixelColor, FontPixelFormat pixelformat) const {
 
674
        if (x < 0 || x >= bufWidth || y < 0 || y >= bufHeight) {
 
675
                return;
 
676
        }
 
677
 
 
678
        static const u8 fontPixelSizeInBytes[] = { 0, 0, 1, 3, 4 }; // 0 means 2 pixels per byte
 
679
        int pixelBytes = fontPixelSizeInBytes[pixelformat];
 
680
        int bufMaxWidth = (pixelBytes == 0 ? bpl * 2 : bpl / pixelBytes);
 
681
        if (x >= bufMaxWidth) {
 
682
                return;
 
683
        }
 
684
 
 
685
        int framebufferAddr = base + (y * bpl) + (pixelBytes == 0 ? x / 2 : x * pixelBytes);
 
686
 
 
687
        switch (pixelformat) {
 
688
        case PSP_FONT_PIXELFORMAT_4:
 
689
        case PSP_FONT_PIXELFORMAT_4_REV:
 
690
                {
 
691
                        // We always get a 8-bit value, so take only the top 4 bits.
 
692
                        const u8 pix4 = pixelColor >> 4;
 
693
 
 
694
                        int oldColor = Memory::Read_U8(framebufferAddr);
 
695
                        int newColor;
 
696
                        if ((x & 1) != pixelformat) {
 
697
                                newColor = (pix4 << 4) | (oldColor & 0xF);
 
698
                        } else {
 
699
                                newColor = (oldColor & 0xF0) | pix4;
 
700
                        }
 
701
                        Memory::Write_U8(newColor, framebufferAddr);
 
702
                        break;
 
703
                }
 
704
        case PSP_FONT_PIXELFORMAT_8:
 
705
                {
 
706
                        Memory::Write_U8(pixelColor, framebufferAddr);
 
707
                        break;
 
708
                }
 
709
        case PSP_FONT_PIXELFORMAT_24:
 
710
                {
 
711
                        // Each channel has the same value.
 
712
                        Memory::Write_U8(pixelColor, framebufferAddr + 0);
 
713
                        Memory::Write_U8(pixelColor, framebufferAddr + 1);
 
714
                        Memory::Write_U8(pixelColor, framebufferAddr + 2);
 
715
                        break;
 
716
                }
 
717
        case PSP_FONT_PIXELFORMAT_32:
 
718
                {
 
719
                        // Spread the 8 bits out into one write of 32 bits.
 
720
                        u32 pix32 = pixelColor;
 
721
                        pix32 |= pix32 << 8;
 
722
                        pix32 |= pix32 << 16;
 
723
                        Memory::Write_U32(pix32, framebufferAddr);
 
724
                        break;
 
725
                }
 
726
        }
 
727
}