~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/Util/PPGeDraw.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
#include <algorithm>
 
19
 
 
20
#include "image/zim_load.h"
 
21
#include "image/png_load.h"
 
22
#include "util/text/utf8.h"
 
23
 
 
24
#include "Common/ChunkFile.h"
 
25
#include "Core/HDRemaster.h"
 
26
#include "Core/Host.h"
 
27
#include "GPU/ge_constants.h"
 
28
#include "GPU/GPUState.h"
 
29
#include "GPU/GPUInterface.h"
 
30
#include "Core/FileSystems/MetaFileSystem.h"
 
31
#include "Core/Util/PPGeDraw.h"
 
32
#include "Core/HLE/sceKernel.h"
 
33
#include "Core/HLE/sceKernelMemory.h"
 
34
#include "Core/HLE/sceGe.h"
 
35
#include "Core/MemMapHelpers.h"
 
36
#include "Core/System.h"
 
37
 
 
38
static u32 atlasPtr;
 
39
static int atlasWidth;
 
40
static int atlasHeight;
 
41
 
 
42
struct PPGeVertex {
 
43
        u16_le u, v;
 
44
        u32_le color;
 
45
        float_le x, y, z;
 
46
};
 
47
 
 
48
struct PPGeRemasterVertex {
 
49
        float_le u, v;
 
50
        u32_le color;
 
51
        float_le x, y, z;
 
52
};
 
53
 
 
54
static PSPPointer<PspGeListArgs> listArgs;
 
55
static u32 listArgsSize = sizeof(PspGeListArgs);
 
56
static u32 savedContextPtr;
 
57
static u32 savedContextSize = 512 * 4;
 
58
 
 
59
// Display list writer
 
60
static u32 dlPtr;
 
61
static u32 dlWritePtr;
 
62
static u32 dlSize = 0x10000; // should be enough for a frame of gui...
 
63
 
 
64
static u32 dataPtr;
 
65
static u32 dataWritePtr;
 
66
static u32 dataSize = 0x10000; // should be enough for a frame of gui...
 
67
 
 
68
static PSPPointer<u16_le> palette;
 
69
static u32 paletteSize = sizeof(u16) * 16;
 
70
 
 
71
// Vertex collector
 
72
static u32 vertexStart;
 
73
static u32 vertexCount;
 
74
 
 
75
// Used for formating text
 
76
struct AtlasCharVertex
 
77
{
 
78
        float x;
 
79
        float y;
 
80
        const AtlasChar *c;
 
81
};
 
82
 
 
83
struct AtlasTextMetrics
 
84
{
 
85
        float x;
 
86
        float y;
 
87
        float maxWidth;
 
88
        float lineHeight;
 
89
        float scale;
 
90
        int numLines;
 
91
 
 
92
};
 
93
 
 
94
typedef std::vector<AtlasCharVertex> AtlasCharLine;
 
95
typedef std::vector<AtlasCharLine> AtlasLineArray;
 
96
 
 
97
static AtlasCharLine char_one_line;
 
98
static AtlasLineArray char_lines;
 
99
static AtlasTextMetrics char_lines_metrics;
 
100
 
 
101
//only 0xFFFFFF of data is used
 
102
static void WriteCmd(u8 cmd, u32 data) {
 
103
        Memory::Write_U32((cmd << 24) | (data & 0xFFFFFF), dlWritePtr);
 
104
        dlWritePtr += 4;
 
105
}
 
106
 
 
107
static void WriteCmdAddrWithBase(u8 cmd, u32 addr) {
 
108
        WriteCmd(GE_CMD_BASE, (addr >> 8) & 0xFF0000);
 
109
        WriteCmd(cmd, addr & 0xFFFFFF);
 
110
}
 
111
 
 
112
/*
 
113
static void WriteCmdFloat(u8 cmd, float f) {
 
114
        union {
 
115
                float fl;
 
116
                u32 u;
 
117
        } conv;
 
118
        conv.fl = f;
 
119
        WriteCmd(cmd, conv.u >> 8);
 
120
}*/
 
121
 
 
122
static void BeginVertexData() {
 
123
        vertexCount = 0;
 
124
        vertexStart = dataWritePtr;
 
125
}
 
126
 
 
127
static void Vertex(float x, float y, float u, float v, int tw, int th, u32 color = 0xFFFFFFFF) {
 
128
        if (g_RemasterMode) {
 
129
                PPGeRemasterVertex vtx;
 
130
                vtx.x = x - 0.5f; vtx.y = y - 0.5f; vtx.z = 0;
 
131
                vtx.u = u * tw - 0.5f; vtx.v = v * th - 0.5f;
 
132
                vtx.color = color;
 
133
                Memory::WriteStruct(dataWritePtr, &vtx);
 
134
                dataWritePtr += sizeof(vtx);
 
135
        } else {
 
136
                PPGeVertex vtx;
 
137
                vtx.x = x - 0.5f; vtx.y = y - 0.5f; vtx.z = 0;
 
138
                vtx.u = u * tw - 0.5f; vtx.v = v * th - 0.5f;
 
139
                vtx.color = color;
 
140
                Memory::WriteStruct(dataWritePtr, &vtx);
 
141
                dataWritePtr += sizeof(vtx);
 
142
        }
 
143
        vertexCount++;
 
144
}
 
145
 
 
146
static void EndVertexDataAndDraw(int prim) {
 
147
        WriteCmdAddrWithBase(GE_CMD_VADDR, vertexStart);
 
148
        WriteCmd(GE_CMD_PRIM, (prim << 16) | vertexCount);
 
149
}
 
150
 
 
151
static u32 __PPGeDoAlloc(u32 &size, bool fromTop, const char *name) {
 
152
        u32 ptr = kernelMemory.Alloc(size, fromTop, name);
 
153
        // Didn't get it.
 
154
        if (ptr == (u32)-1)
 
155
                return 0;
 
156
        return ptr;
 
157
}
 
158
 
 
159
void __PPGeSetupListArgs()
 
160
{
 
161
        if (listArgs.IsValid())
 
162
                return;
 
163
 
 
164
        listArgs = __PPGeDoAlloc(listArgsSize, false, "PPGe List Args");
 
165
        if (listArgs.IsValid()) {
 
166
                listArgs->size = 8;
 
167
                if (savedContextPtr == 0)
 
168
                        savedContextPtr = __PPGeDoAlloc(savedContextSize, false, "PPGe Saved Context");
 
169
                listArgs->context = savedContextPtr;
 
170
        }
 
171
}
 
172
 
 
173
void __PPGeInit()
 
174
{
 
175
        // PPGe isn't really important for headless, and LoadZIM takes a long time.
 
176
        if (PSP_CoreParameter().gpuCore == GPUCORE_NULL || host->ShouldSkipUI()) {
 
177
                // Let's just not bother.
 
178
                dlPtr = 0;
 
179
                NOTICE_LOG(SCEGE, "Not initializing PPGe - GPU is NullGpu");
 
180
                return;
 
181
        }
 
182
        u8 *imageData[12];
 
183
        int width[12];
 
184
        int height[12];
 
185
        int flags;
 
186
        if (!LoadZIM("ppge_atlas.zim", width, height, &flags, imageData)) {
 
187
                PanicAlert("Failed to load ppge_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.");
 
188
                ERROR_LOG(SCEGE, "PPGe init failed - no atlas texture. PPGe stuff will not be drawn.");
 
189
                return;
 
190
        }
 
191
 
 
192
        u32 atlasSize = height[0] * width[0] / 2;  // it's a 4-bit paletted texture in ram
 
193
        atlasWidth = width[0];
 
194
        atlasHeight = height[0];
 
195
        dlPtr = __PPGeDoAlloc(dlSize, false, "PPGe Display List");
 
196
        dataPtr = __PPGeDoAlloc(dataSize, false, "PPGe Vertex Data");
 
197
        __PPGeSetupListArgs();
 
198
        atlasPtr = __PPGeDoAlloc(atlasSize, false, "PPGe Atlas Texture");
 
199
        palette = __PPGeDoAlloc(paletteSize, false, "PPGe Texture Palette");
 
200
 
 
201
        // Generate 16-greyscale palette. All PPGe graphics are greyscale so we can use a tiny paletted texture.
 
202
        for (int i = 0; i < 16; i++) {
 
203
                int val = i;
 
204
                palette[i] = (val << 12) | 0xFFF;
 
205
        }
 
206
 
 
207
        const u32_le *imagePtr = (u32_le *)imageData[0];
 
208
        u8 *ramPtr = (u8 *)Memory::GetPointer(atlasPtr);
 
209
 
 
210
        // Palettize to 4-bit, the easy way.
 
211
        for (int i = 0; i < width[0] * height[0] / 2; i++) {
 
212
                // Each pixel is 16 bits, so this loads two pixels.
 
213
                u32 c = imagePtr[i];
 
214
                // It's white anyway, so we only look at one channel of each pixel.
 
215
                int a1 = (c & 0x0000000F) >> 0;
 
216
                int a2 = (c & 0x000F0000) >> 16;
 
217
                u8 cval = (a2 << 4) | a1;
 
218
                ramPtr[i] = cval;
 
219
        }
 
220
        
 
221
        free(imageData[0]);
 
222
 
 
223
        DEBUG_LOG(SCEGE, "PPGe drawing library initialized. DL: %08x Data: %08x Atlas: %08x (%i) Args: %08x",
 
224
                dlPtr, dataPtr, atlasPtr, atlasSize, listArgs.ptr);
 
225
}
 
226
 
 
227
void __PPGeDoState(PointerWrap &p)
 
228
{
 
229
        auto s = p.Section("PPGeDraw", 1, 2);
 
230
        if (!s)
 
231
                return;
 
232
 
 
233
        p.Do(atlasPtr);
 
234
        p.Do(atlasWidth);
 
235
        p.Do(atlasHeight);
 
236
        p.Do(palette);
 
237
 
 
238
        p.Do(savedContextPtr);
 
239
        p.Do(savedContextSize);
 
240
 
 
241
        if (s == 1) {
 
242
                listArgs = 0;
 
243
        } else {
 
244
                p.Do(listArgs);
 
245
        }
 
246
 
 
247
        p.Do(dlPtr);
 
248
        p.Do(dlWritePtr);
 
249
        p.Do(dlSize);
 
250
 
 
251
        p.Do(dataPtr);
 
252
        p.Do(dataWritePtr);
 
253
        p.Do(dataSize);
 
254
 
 
255
        p.Do(vertexStart);
 
256
        p.Do(vertexCount);
 
257
 
 
258
        p.Do(char_lines);
 
259
        p.Do(char_lines_metrics);
 
260
}
 
261
 
 
262
void __PPGeShutdown()
 
263
{
 
264
        if (atlasPtr)
 
265
                kernelMemory.Free(atlasPtr);
 
266
        if (dataPtr)
 
267
                kernelMemory.Free(dataPtr);
 
268
        if (dlPtr)
 
269
                kernelMemory.Free(dlPtr);
 
270
        if (listArgs.IsValid())
 
271
                kernelMemory.Free(listArgs.ptr);
 
272
        if (savedContextPtr)
 
273
                kernelMemory.Free(savedContextPtr);
 
274
        if (palette)
 
275
                kernelMemory.Free(palette.ptr);
 
276
 
 
277
        atlasPtr = 0;
 
278
        dataPtr = 0;
 
279
        dlPtr = 0;
 
280
        savedContextPtr = 0;
 
281
        listArgs = 0;
 
282
}
 
283
 
 
284
void PPGeBegin()
 
285
{
 
286
        if (!dlPtr)
 
287
                return;
 
288
 
 
289
        // Reset write pointers to start of command and data buffers.
 
290
        dlWritePtr = dlPtr;
 
291
        dataWritePtr = dataPtr;
 
292
 
 
293
        // Set up the correct states for UI drawing
 
294
        WriteCmd(GE_CMD_OFFSETADDR, 0);
 
295
        WriteCmd(GE_CMD_ALPHABLENDENABLE, 1);
 
296
        WriteCmd(GE_CMD_BLENDMODE, 2 | (3 << 4));
 
297
        WriteCmd(GE_CMD_ALPHATESTENABLE, 0);
 
298
        WriteCmd(GE_CMD_COLORTESTENABLE, 0); 
 
299
        WriteCmd(GE_CMD_ZTESTENABLE, 0);
 
300
        WriteCmd(GE_CMD_LIGHTINGENABLE, 0);
 
301
        WriteCmd(GE_CMD_FOGENABLE, 0);
 
302
        WriteCmd(GE_CMD_STENCILTESTENABLE, 0);
 
303
        WriteCmd(GE_CMD_CULLFACEENABLE, 0);
 
304
        WriteCmd(GE_CMD_CLEARMODE, 0);  // Normal mode
 
305
        WriteCmd(GE_CMD_MASKRGB, 0);
 
306
        WriteCmd(GE_CMD_MASKALPHA, 0);
 
307
 
 
308
        PPGeSetDefaultTexture();
 
309
 
 
310
        WriteCmd(GE_CMD_SCISSOR1, (0 << 10) | 0);
 
311
        WriteCmd(GE_CMD_SCISSOR2, (271 << 10) | 479);
 
312
        WriteCmd(GE_CMD_MINZ, 0);
 
313
        WriteCmd(GE_CMD_MAXZ, 0xFFFF);
 
314
 
 
315
        // Through mode, so we don't have to bother with matrices
 
316
        if (g_RemasterMode) {
 
317
                WriteCmd(GE_CMD_VERTEXTYPE, GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_POS_FLOAT | GE_VTYPE_THROUGH);
 
318
        } else {
 
319
                WriteCmd(GE_CMD_VERTEXTYPE, GE_VTYPE_TC_16BIT | GE_VTYPE_COL_8888 | GE_VTYPE_POS_FLOAT | GE_VTYPE_THROUGH);
 
320
        }
 
321
}
 
322
 
 
323
void PPGeEnd()
 
324
{
 
325
        if (!dlPtr)
 
326
                return;
 
327
 
 
328
        WriteCmd(GE_CMD_FINISH, 0);
 
329
        WriteCmd(GE_CMD_END, 0);
 
330
 
 
331
        // Might've come from an old savestate.
 
332
        __PPGeSetupListArgs();
 
333
 
 
334
        if (dataWritePtr > dataPtr) {
 
335
                // We actually drew something
 
336
                gpu->EnableInterrupts(false);
 
337
                u32 list = sceGeListEnQueue(dlPtr, dlWritePtr, -1, listArgs.ptr);
 
338
                DEBUG_LOG(SCEGE, "PPGe enqueued display list %i", list);
 
339
                gpu->EnableInterrupts(true);
 
340
        }
 
341
}
 
342
 
 
343
static const AtlasChar *PPGeGetChar(const AtlasFont &atlasfont, unsigned int cval)
 
344
{
 
345
        const AtlasChar *c = atlasfont.getChar(cval);
 
346
        if (c == NULL) {
 
347
                // Try to use a replacement character, these come from the below table.
 
348
                // http://unicode.org/cldr/charts/supplemental/character_fallback_substitutions.html
 
349
                switch (cval) {
 
350
                case 0x00A0: // NO-BREAK SPACE
 
351
                case 0x2000: // EN QUAD
 
352
                case 0x2001: // EM QUAD
 
353
                case 0x2002: // EN SPACE
 
354
                case 0x2003: // EM SPACE
 
355
                case 0x2004: // THREE-PER-EM SPACE
 
356
                case 0x2005: // FOUR-PER-EM SPACE
 
357
                case 0x2006: // SIX-PER-EM SPACE
 
358
                case 0x2007: // FIGURE SPACE
 
359
                case 0x2008: // PUNCTUATION SPACE
 
360
                case 0x2009: // THIN SPACE
 
361
                case 0x200A: // HAIR SPACE
 
362
                case 0x202F: // NARROW NO-BREAK SPACE
 
363
                case 0x205F: // MEDIUM MATHEMATICAL
 
364
                case 0x3000: // IDEOGRAPHIC SPACE
 
365
                        c = atlasfont.getChar(0x0020);
 
366
                        break;
 
367
 
 
368
                default:
 
369
                        c = atlasfont.getChar(0xFFFD);
 
370
                        break;
 
371
                }
 
372
                if (c == NULL)
 
373
                        c = atlasfont.getChar('?');
 
374
        }
 
375
        return c;
 
376
}
 
377
 
 
378
// Break a single text string into mutiple lines.
 
379
static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, float x, float y, 
 
380
                                                                        int align, float scale, int wrapType, float wrapWidth, bool dryRun)
 
381
{
 
382
        y += atlasfont.ascend * scale;
 
383
        float sx = x, sy = y;
 
384
 
 
385
        // TODO: Can we wrap it smartly on the screen edge?
 
386
        if (wrapWidth <= 0) {
 
387
                wrapWidth = 480.f;
 
388
        }
 
389
 
 
390
        // used for replacing with ellipses
 
391
        float wrapCutoff = 8.0f;
 
392
        const AtlasChar *dot = PPGeGetChar(atlasfont, '.');
 
393
        if (dot) {
 
394
                wrapCutoff = dot->wx * scale * 3.0f;
 
395
        }
 
396
        float threshold = sx + wrapWidth - wrapCutoff;
 
397
 
 
398
        //const float wrapGreyZone = 2.0f; // Grey zone for punctuations at line ends
 
399
 
 
400
        int numLines = 1;
 
401
        float maxw = 0;
 
402
        float lineHeight = atlasfont.height * scale;
 
403
        for (UTF8 utf(text); !utf.end(); )
 
404
        {
 
405
                float lineWidth = 0;
 
406
                bool skipRest = false;
 
407
                while (!utf.end())
 
408
                {
 
409
                        UTF8 utfWord(utf);
 
410
                        float nextWidth = 0;
 
411
                        float spaceWidth = 0;
 
412
                        int numChars = 0;
 
413
                        bool finished = false;
 
414
                        while (!utfWord.end() && !finished)
 
415
                        {
 
416
                                UTF8 utfPrev = utfWord;
 
417
                                u32 cval = utfWord.next();
 
418
                                const AtlasChar *ch = PPGeGetChar(atlasfont, cval);
 
419
                                if (!ch) {
 
420
                                        continue;
 
421
                                }
 
422
 
 
423
                                switch (cval) {
 
424
                                // TODO: This list of punctuation is very incomplete.
 
425
                                case ',':
 
426
                                case '.':
 
427
                                case ':':
 
428
                                case '!':
 
429
                                case ')':
 
430
                                case '?':
 
431
                                case 0x3001: // IDEOGRAPHIC COMMA
 
432
                                case 0x3002: // IDEOGRAPHIC FULL STOP
 
433
                                case 0x06D4: // ARABIC FULL STOP
 
434
                                case 0xFF01: // FULLWIDTH EXCLAMATION MARK
 
435
                                case 0xFF09: // FULLWIDTH RIGHT PARENTHESIS
 
436
                                case 0xFF1F: // FULLWIDTH QUESTION MARK
 
437
                                        // Count this character (punctuation is so clingy), but then we're done.
 
438
                                        ++numChars;
 
439
                                        nextWidth += ch->wx * scale;
 
440
                                        finished = true;
 
441
                                        break;
 
442
 
 
443
                                case ' ':
 
444
                                case 0x3000: // IDEOGRAPHIC SPACE
 
445
                                        spaceWidth += ch->wx * scale;
 
446
                                        finished = true;
 
447
                                        break;
 
448
 
 
449
                                case '\t':
 
450
                                case '\r':
 
451
                                case '\n':
 
452
                                        // Ignore this character and we're done.
 
453
                                        finished = true;
 
454
                                        break;
 
455
 
 
456
                                default:
 
457
                                        {
 
458
                                                // CJK characters can be wrapped more freely.
 
459
                                                bool isCJK = (cval >= 0x1100 && cval <= 0x11FF); // Hangul Jamo.
 
460
                                                isCJK = isCJK || (cval >= 0x2E80 && cval <= 0x2FFF); // Kangxi Radicals etc.
 
461
#if 0
 
462
                                                isCJK = isCJK || (cval >= 0x3040 && cval <= 0x31FF); // Hiragana, Katakana, Hangul Compatibility Jamo etc.
 
463
                                                isCJK = isCJK || (cval >= 0x3200 && cval <= 0x32FF); // CJK Enclosed
 
464
                                                isCJK = isCJK || (cval >= 0x3300 && cval <= 0x33FF); // CJK Compatibility
 
465
                                                isCJK = isCJK || (cval >= 0x3400 && cval <= 0x4DB5); // CJK Unified Ideographs Extension A
 
466
#else
 
467
                                                isCJK = isCJK || (cval >= 0x3040 && cval <= 0x4DB5); // Above collapsed
 
468
#endif
 
469
                                                isCJK = isCJK || (cval >= 0x4E00 && cval <= 0x9FBB); // CJK Unified Ideographs
 
470
                                                isCJK = isCJK || (cval >= 0xAC00 && cval <= 0xD7AF); // Hangul Syllables
 
471
                                                isCJK = isCJK || (cval >= 0xF900 && cval <= 0xFAD9); // CJK Compatibility Ideographs
 
472
                                                isCJK = isCJK || (cval >= 0x20000 && cval <= 0x2A6D6); // CJK Unified Ideographs Extension B
 
473
                                                isCJK = isCJK || (cval >= 0x2F800 && cval <= 0x2FA1D); // CJK Compatibility Supplement
 
474
                                                if (isCJK) {
 
475
                                                        if (numChars > 0) {
 
476
                                                                utfWord = utfPrev;
 
477
                                                                finished = true;
 
478
                                                                break;
 
479
                                                        }                                               
 
480
                                                }
 
481
                                        }
 
482
                                        ++numChars;
 
483
                                        nextWidth += ch->wx * scale;
 
484
                                        break;
 
485
                                }
 
486
                        }
 
487
 
 
488
                        bool useEllipsis = false;
 
489
                        if (wrapType > 0)
 
490
                        {
 
491
                                if (lineWidth + nextWidth > wrapWidth || skipRest)
 
492
                                {
 
493
                                        if (wrapType & PPGE_LINE_WRAP_WORD) {
 
494
                                                // TODO: Should check if we have had at least one other word instead.
 
495
                                                if (lineWidth > 0) {
 
496
                                                        ++numLines;
 
497
                                                        break;
 
498
                                                }
 
499
                                        }
 
500
                                        if (wrapType & PPGE_LINE_USE_ELLIPSIS) {
 
501
                                                useEllipsis = true;
 
502
                                                if (skipRest) {
 
503
                                                        numChars = 0;
 
504
                                                } else if (nextWidth < wrapCutoff) {
 
505
                                                        // The word is too short, so just backspace!
 
506
                                                        x = threshold;
 
507
                                                }
 
508
                                                nextWidth = 0;
 
509
                                                spaceWidth = 0;
 
510
                                                lineWidth = wrapWidth;
 
511
                                        }
 
512
                                }
 
513
                        }
 
514
                        for (int i = 0; i < numChars; ++i)
 
515
                        {
 
516
                                u32 cval = utf.next();
 
517
                                const AtlasChar *c = PPGeGetChar(atlasfont, cval);
 
518
                                if (c)
 
519
                                {
 
520
                                        if (useEllipsis && x >= threshold && dot)
 
521
                                        {
 
522
                                                if (!dryRun)
 
523
                                                {
 
524
                                                        AtlasCharVertex cv;
 
525
                                                        // Replace the following part with an ellipsis.
 
526
                                                        cv.x = x + dot->ox * scale;
 
527
                                                        cv.y = y + dot->oy * scale;
 
528
                                                        cv.c = dot;
 
529
                                                        char_one_line.push_back(cv);
 
530
                                                        cv.x += dot->wx * scale;
 
531
                                                        char_one_line.push_back(cv);
 
532
                                                        cv.x += dot->wx * scale;
 
533
                                                        char_one_line.push_back(cv);
 
534
                                                }
 
535
                                                skipRest = true;
 
536
                                                break;
 
537
                                        }
 
538
                                        if (!dryRun)
 
539
                                        {
 
540
                                                AtlasCharVertex cv;
 
541
                                                cv.x = x + c->ox * scale;
 
542
                                                cv.y = y + c->oy * scale;
 
543
                                                cv.c = c;
 
544
                                                char_one_line.push_back(cv);
 
545
                                        }
 
546
                                        x += c->wx * scale;
 
547
                                }
 
548
                        }
 
549
                        lineWidth += nextWidth;
 
550
 
 
551
                        u32 cval = utf.next();
 
552
                        if (spaceWidth > 0)
 
553
                        {
 
554
                                if (!dryRun)
 
555
                                {
 
556
                                        // No need to check c.
 
557
                                        const AtlasChar *c = PPGeGetChar(atlasfont, cval);
 
558
                                        AtlasCharVertex cv;
 
559
                                        cv.x = x + c->ox * scale;
 
560
                                        cv.y = y + c->oy * scale;
 
561
                                        cv.c = c;
 
562
                                        char_one_line.push_back(cv);
 
563
                                }
 
564
                                x += spaceWidth;
 
565
                                lineWidth += spaceWidth;
 
566
                                if (wrapType > 0 && lineWidth > wrapWidth) {
 
567
                                        lineWidth = wrapWidth;
 
568
                                }
 
569
                        }
 
570
                        else if (cval == '\n') {
 
571
                                ++numLines;
 
572
                                break;
 
573
                        }
 
574
                        utf = utfWord;
 
575
                }
 
576
                y += lineHeight;
 
577
                x = sx;
 
578
                if (lineWidth > maxw) {
 
579
                        maxw = lineWidth;
 
580
                }
 
581
                if (!dryRun)
 
582
                {
 
583
                        char_lines.push_back(char_one_line);
 
584
                        char_one_line.clear();
 
585
                }
 
586
        }
 
587
 
 
588
        const float w = maxw;
 
589
        const float h = (float)numLines * lineHeight;
 
590
        if (align)
 
591
        {
 
592
                if (!dryRun)
 
593
                {
 
594
                        for (auto i = char_lines.begin(); i != char_lines.end(); ++i)
 
595
                        {
 
596
                                for (auto j = i->begin(); j != i->end(); ++j)
 
597
                                {
 
598
                                        if (align & PPGE_ALIGN_HCENTER) j->x -= w / 2.0f;
 
599
                                        else if (align & PPGE_ALIGN_RIGHT) j->x -= w;
 
600
 
 
601
                                        if (align & PPGE_ALIGN_VCENTER) j->y -= h / 2.0f;
 
602
                                        else if (align & PPGE_ALIGN_BOTTOM) j->y -= h;
 
603
                                }
 
604
                        }
 
605
                }
 
606
                if (align & PPGE_ALIGN_HCENTER) sx -= w / 2.0f;
 
607
                else if (align & PPGE_ALIGN_RIGHT) sx -= w;
 
608
                if (align & PPGE_ALIGN_VCENTER) sy -= h / 2.0f;
 
609
                else if (align & PPGE_ALIGN_BOTTOM) sy -= h;
 
610
        }
 
611
 
 
612
        AtlasTextMetrics metrics = { sx, sy, w, lineHeight, scale, numLines };
 
613
        return metrics;
 
614
}
 
615
 
 
616
void PPGeMeasureText(float *w, float *h, int *n, 
 
617
                                        const char *text, float scale, int WrapType, int wrapWidth)
 
618
{
 
619
        const AtlasFont &atlasfont = *ppge_atlas.fonts[0];
 
620
        AtlasTextMetrics metrics = BreakLines(text, atlasfont, 0, 0, 0, scale, WrapType, wrapWidth, true);
 
621
        if (w) *w = metrics.maxWidth;
 
622
        if (h) *h = metrics.lineHeight;
 
623
        if (n) *n = metrics.numLines;
 
624
}
 
625
 
 
626
void PPGePrepareText(const char *text, float x, float y, int align, float scale, int WrapType, int wrapWidth)
 
627
{
 
628
        const AtlasFont &atlasfont = *ppge_atlas.fonts[0];
 
629
        char_lines_metrics = BreakLines(text, atlasfont, x, y, align, scale, WrapType, wrapWidth, false);
 
630
}
 
631
 
 
632
void PPGeMeasureCurrentText(float *x, float *y, float *w, float *h, int *n)
 
633
{
 
634
        if (x) *x = char_lines_metrics.x;
 
635
        if (y) *y = char_lines_metrics.y;
 
636
        if (w) *w = char_lines_metrics.maxWidth;
 
637
        if (h) *h = char_lines_metrics.lineHeight;
 
638
        if (n) *n = char_lines_metrics.numLines;
 
639
}
 
640
 
 
641
// Draws some text using the one font we have.
 
642
// Mostly rewritten.
 
643
void PPGeDrawCurrentText(u32 color)
 
644
{
 
645
        if (dlPtr)
 
646
        {
 
647
                float scale = char_lines_metrics.scale;
 
648
                BeginVertexData();
 
649
                for (auto i = char_lines.begin(); i != char_lines.end(); ++i)
 
650
                {
 
651
                        for (auto j = i->begin(); j != i->end(); ++j)
 
652
                        {
 
653
                                float cx1 = j->x;
 
654
                                float cy1 = j->y;
 
655
                                const AtlasChar &c = *j->c;
 
656
                                float cx2 = cx1 + c.pw * scale;
 
657
                                float cy2 = cy1 + c.ph * scale;
 
658
                                Vertex(cx1, cy1, c.sx, c.sy, atlasWidth, atlasHeight, color);
 
659
                                Vertex(cx2, cy2, c.ex, c.ey, atlasWidth, atlasHeight, color);
 
660
                        }
 
661
                }
 
662
                EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
 
663
        }
 
664
        char_one_line.clear();
 
665
        char_lines.clear();
 
666
        AtlasTextMetrics zeroBox = { 0 };
 
667
        char_lines_metrics = zeroBox;
 
668
}
 
669
 
 
670
void PPGeDrawText(const char *text, float x, float y, int align, float scale, u32 color)
 
671
{
 
672
        PPGePrepareText(text, x, y, align, scale, PPGE_LINE_USE_ELLIPSIS);
 
673
        PPGeDrawCurrentText(color);
 
674
}
 
675
 
 
676
void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, int align, float scale, u32 color)
 
677
{
 
678
        PPGePrepareText(text, x, y, align, scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth);
 
679
        PPGeDrawCurrentText(color);
 
680
}
 
681
 
 
682
// Draws a "4-patch" for button-like things that can be resized
 
683
void PPGeDraw4Patch(int atlasImage, float x, float y, float w, float h, u32 color)
 
684
{
 
685
        if (!dlPtr)
 
686
                return;
 
687
        const AtlasImage &img = ppge_images[atlasImage];
 
688
        float borderx = img.w / 20;
 
689
        float bordery = img.h / 20;
 
690
        float u1 = img.u1, uhalf = (img.u1 + img.u2) / 2, u2 = img.u2;
 
691
        float v1 = img.v1, vhalf = (img.v1 + img.v2) / 2, v2 = img.v2;
 
692
        float xmid1 = x + borderx;
 
693
        float xmid2 = x + w - borderx;
 
694
        float ymid1 = y + bordery;
 
695
        float ymid2 = y + h - bordery;
 
696
        float x2 = x + w;
 
697
        float y2 = y + h;
 
698
        BeginVertexData();
 
699
        // Top row
 
700
        Vertex(x, y, u1, v1, atlasWidth, atlasHeight, color);
 
701
        Vertex(xmid1, ymid1, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
702
        Vertex(xmid1, y, uhalf, v1, atlasWidth, atlasHeight, color);
 
703
        Vertex(xmid2, ymid1, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
704
        Vertex(xmid2, y, uhalf, v1, atlasWidth, atlasHeight, color);
 
705
        Vertex(x2, ymid1, u2, vhalf, atlasWidth, atlasHeight, color);
 
706
        // Middle row
 
707
        Vertex(x, ymid1, u1, vhalf, atlasWidth, atlasHeight, color);
 
708
        Vertex(xmid1, ymid2, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
709
        Vertex(xmid1, ymid1, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
710
        Vertex(xmid2, ymid2, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
711
        Vertex(xmid2, ymid1, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
712
        Vertex(x2, ymid2, u2, v2, atlasWidth, atlasHeight, color);
 
713
        // Bottom row
 
714
        Vertex(x, ymid2, u1, vhalf, atlasWidth, atlasHeight, color);
 
715
        Vertex(xmid1, y2, uhalf, v2, atlasWidth, atlasHeight, color);
 
716
        Vertex(xmid1, ymid2, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
717
        Vertex(xmid2, y2, uhalf, v2, atlasWidth, atlasHeight, color);
 
718
        Vertex(xmid2, ymid2, uhalf, vhalf, atlasWidth, atlasHeight, color);
 
719
        Vertex(x2, y2, u2, v2, atlasWidth, atlasHeight, color);
 
720
        EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
 
721
}
 
722
 
 
723
void PPGeDrawRect(float x1, float y1, float x2, float y2, u32 color)
 
724
{
 
725
        if (!dlPtr)
 
726
                return;
 
727
 
 
728
        WriteCmd(GE_CMD_TEXTUREMAPENABLE, 0);
 
729
 
 
730
        BeginVertexData();
 
731
        Vertex(x1, y1, 0, 0, 0, 0, color);
 
732
        Vertex(x2, y2, 0, 0, 0, 0, color);
 
733
        EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
 
734
 
 
735
        WriteCmd(GE_CMD_TEXTUREMAPENABLE, 1);
 
736
}
 
737
 
 
738
// Just blits an image to the screen, multiplied with the color.
 
739
void PPGeDrawImage(int atlasImage, float x, float y, int align, u32 color)
 
740
{
 
741
        if (!dlPtr)
 
742
                return;
 
743
 
 
744
        const AtlasImage &img = ppge_atlas.images[atlasImage];
 
745
        float w = img.w;
 
746
        float h = img.h;
 
747
        BeginVertexData();
 
748
        Vertex(x, y, img.u1, img.v1, atlasWidth, atlasHeight, color);
 
749
        Vertex(x + w, y + h, img.u2, img.v2, atlasWidth, atlasHeight, color);
 
750
        EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
 
751
}
 
752
 
 
753
void PPGeDrawImage(int atlasImage, float x, float y, float w, float h, int align, u32 color)
 
754
{
 
755
        if (!dlPtr)
 
756
                return;
 
757
 
 
758
        const AtlasImage &img = ppge_atlas.images[atlasImage];
 
759
        BeginVertexData();
 
760
        Vertex(x, y, img.u1, img.v1, atlasWidth, atlasHeight, color);
 
761
        Vertex(x + w, y + h, img.u2, img.v2, atlasWidth, atlasHeight, color);
 
762
        EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
 
763
}
 
764
 
 
765
void PPGeDrawImage(float x, float y, float w, float h, float u1, float v1, float u2, float v2, int tw, int th, u32 color)
 
766
{
 
767
        if (!dlPtr)
 
768
                return;
 
769
        BeginVertexData();
 
770
        Vertex(x, y, u1, v1, tw, th, color);
 
771
        Vertex(x + w, y + h, u2, v2, tw, th, color);
 
772
        EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
 
773
}
 
774
 
 
775
// Return a value such that (1 << value) >= x
 
776
int GetPow2(int x)
 
777
{
 
778
#ifdef __GNUC__
 
779
        int ret = 31 - __builtin_clz(x|1);
 
780
        if ((1 << ret) < x)
 
781
#else
 
782
        int ret = 0;
 
783
        while ((1 << ret) < x)
 
784
#endif
 
785
                ret++;
 
786
        return ret;
 
787
}
 
788
 
 
789
void PPGeSetDefaultTexture()
 
790
{
 
791
        WriteCmd(GE_CMD_TEXTUREMAPENABLE, 1);
 
792
        int wp2 = GetPow2(atlasWidth);
 
793
        int hp2 = GetPow2(atlasHeight);
 
794
        WriteCmd(GE_CMD_CLUTADDR, palette.ptr & 0xFFFFF0);
 
795
        WriteCmd(GE_CMD_CLUTADDRUPPER, (palette.ptr & 0xFF000000) >> 8);
 
796
        WriteCmd(GE_CMD_CLUTFORMAT, 0x00FF02);
 
797
        WriteCmd(GE_CMD_LOADCLUT, 2);
 
798
        WriteCmd(GE_CMD_TEXSIZE0, wp2 | (hp2 << 8));
 
799
        WriteCmd(GE_CMD_TEXMAPMODE, 0 | (1 << 8));
 
800
        WriteCmd(GE_CMD_TEXMODE, 0);
 
801
        WriteCmd(GE_CMD_TEXFORMAT, GE_TFMT_CLUT4);  // 4-bit CLUT
 
802
        WriteCmd(GE_CMD_TEXFILTER, (1 << 8) | 1);   // mag = LINEAR min = LINEAR
 
803
        WriteCmd(GE_CMD_TEXWRAP, (1 << 8) | 1);  // clamp texture wrapping
 
804
        WriteCmd(GE_CMD_TEXFUNC, (0 << 16) | (1 << 8) | 0);  // RGBA texture reads, modulate, no color doubling
 
805
        WriteCmd(GE_CMD_TEXADDR0, atlasPtr & 0xFFFFF0);
 
806
        WriteCmd(GE_CMD_TEXBUFWIDTH0, atlasWidth | ((atlasPtr & 0xFF000000) >> 8));
 
807
        WriteCmd(GE_CMD_TEXFLUSH, 0);
 
808
}
 
809
 
 
810
void PPGeSetTexture(u32 dataAddr, int width, int height)
 
811
{
 
812
        WriteCmd(GE_CMD_TEXTUREMAPENABLE, 1);
 
813
        int wp2 = GetPow2(width);
 
814
        int hp2 = GetPow2(height);
 
815
        WriteCmd(GE_CMD_TEXSIZE0, wp2 | (hp2 << 8));
 
816
        WriteCmd(GE_CMD_TEXMAPMODE, 0 | (1 << 8));
 
817
        WriteCmd(GE_CMD_TEXMODE, 0);
 
818
        WriteCmd(GE_CMD_TEXFORMAT, GE_TFMT_8888);  // 4444
 
819
        WriteCmd(GE_CMD_TEXFILTER, (1 << 8) | 1);   // mag = LINEAR min = LINEAR
 
820
        WriteCmd(GE_CMD_TEXWRAP, (1 << 8) | 1);  // clamp texture wrapping
 
821
        WriteCmd(GE_CMD_TEXFUNC, (0 << 16) | (1 << 8) | 0);  // RGBA texture reads, modulate, no color doubling
 
822
        WriteCmd(GE_CMD_TEXADDR0, dataAddr & 0xFFFFF0);
 
823
        WriteCmd(GE_CMD_TEXBUFWIDTH0, width | ((dataAddr & 0xFF000000) >> 8));
 
824
        WriteCmd(GE_CMD_TEXFLUSH, 0);
 
825
}
 
826
 
 
827
void PPGeDisableTexture()
 
828
{
 
829
        WriteCmd(GE_CMD_TEXTUREMAPENABLE, 0);
 
830
}
 
831
 
 
832
std::vector<PPGeImage *> PPGeImage::loadedTextures_;
 
833
 
 
834
PPGeImage::PPGeImage(const std::string &pspFilename)
 
835
        : filename_(pspFilename), texture_(0) {
 
836
}
 
837
 
 
838
PPGeImage::PPGeImage(u32 pngPointer, size_t pngSize)
 
839
        : filename_(""), png_(pngPointer), size_(pngSize), texture_(0) {
 
840
}
 
841
 
 
842
PPGeImage::~PPGeImage() {
 
843
        Free();
 
844
}
 
845
 
 
846
bool PPGeImage::Load() {
 
847
        Free();
 
848
 
 
849
        // In case it fails to load.
 
850
        width_ = 0;
 
851
        height_ = 0;
 
852
 
 
853
        unsigned char *textureData;
 
854
        int success;
 
855
        if (filename_.empty()) {
 
856
                success = pngLoadPtr(Memory::GetPointer(png_), size_, &width_, &height_, &textureData, false);
 
857
        } else {
 
858
                std::vector<u8> pngData;
 
859
                if (pspFileSystem.ReadEntireFile(filename_, pngData) < 0) {
 
860
                        WARN_LOG(SCEGE, "Bad PPGeImage - cannot load file");
 
861
                        return false;
 
862
                }
 
863
 
 
864
                success = pngLoadPtr((const unsigned char *)&pngData[0], pngData.size(), &width_, &height_, &textureData, false);
 
865
        }
 
866
        if (!success) {
 
867
                WARN_LOG(SCEGE, "Bad PPGeImage - not a valid png");
 
868
                return false;
 
869
        }
 
870
 
 
871
        u32 texSize = width_ * height_ * 4;
 
872
        texture_ = __PPGeDoAlloc(texSize, true, "Savedata Icon");
 
873
        if (texture_ == 0) {
 
874
                free(textureData);
 
875
                WARN_LOG(SCEGE, "Bad PPGeImage - unable to allocate space for texture");
 
876
                return false;
 
877
        }
 
878
 
 
879
        Memory::Memcpy(texture_, textureData, texSize);
 
880
        free(textureData);
 
881
 
 
882
        lastFrame_ = gpuStats.numFlips;
 
883
        loadedTextures_.push_back(this);
 
884
        return true;
 
885
}
 
886
 
 
887
void PPGeImage::Free() {
 
888
        if (texture_ != 0) {
 
889
                kernelMemory.Free(texture_);
 
890
                texture_ = 0;
 
891
                loadedTextures_.erase(std::remove(loadedTextures_.begin(), loadedTextures_.end(), this), loadedTextures_.end());
 
892
        }
 
893
}
 
894
 
 
895
void PPGeImage::DoState(PointerWrap &p) {
 
896
        auto s = p.Section("PPGeImage", 1);
 
897
        if (!s)
 
898
                return;
 
899
 
 
900
        p.Do(filename_);
 
901
        p.Do(png_);
 
902
        p.Do(size_);
 
903
        p.Do(texture_);
 
904
        p.Do(width_);
 
905
        p.Do(height_);
 
906
        p.Do(lastFrame_);
 
907
}
 
908
 
 
909
void PPGeImage::CompatLoad(u32 texture, int width, int height) {
 
910
        // Won't be reloadable, so don't add to loadedTextures_.
 
911
        texture_ = texture;
 
912
        width_ = width;
 
913
        height_ = height;
 
914
}
 
915
 
 
916
void PPGeImage::Decimate() {
 
917
        static const int TOO_OLD_AGE = 30;
 
918
        int tooOldFrame = gpuStats.numFlips - TOO_OLD_AGE;
 
919
        for (size_t i = 0; i < loadedTextures_.size(); ++i) {
 
920
                if (loadedTextures_[i]->lastFrame_ < tooOldFrame) {
 
921
                        loadedTextures_[i]->Free();
 
922
                        // That altered loadedTextures_.
 
923
                        --i;
 
924
                }
 
925
        }
 
926
}
 
927
 
 
928
void PPGeImage::SetTexture() {
 
929
        if (texture_ == 0) {
 
930
                Decimate();
 
931
                Load();
 
932
        }
 
933
 
 
934
        if (texture_ != 0) {
 
935
                lastFrame_ = gpuStats.numFlips;
 
936
                PPGeSetTexture(texture_, width_, height_);
 
937
        } else {
 
938
                PPGeDisableTexture();
 
939
        }
 
940
}
 
941