Skip to content

Commit 1684cad

Browse files
committed
Added third attempt at rewrite.
1 parent 25411f4 commit 1684cad

File tree

2 files changed

+678
-0
lines changed

2 files changed

+678
-0
lines changed

YSI_Players/y_text2/render.inc

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
/*----------------------------------------------------------------------------*\
2+
| |
3+
| How strings are stored in memory: |
4+
| |
5+
| 0) There is a single cell prefix of the total length. |
6+
| 1) Normal characters are just normal characters. |
7+
| 2) Specifiers and colours have the top two bits as "0b10" (since this is |
8+
| not valid in unicode of any sort). The third bit is then "0b0" for |
9+
| specifiers with their data encoded, and "0b1" for colours with three |
10+
| bytes of "RGB" data following (and some flags for fades etc). |
11+
| 3) The end of the string is a special specifier that does nothing (may |
12+
| look like a colour to avoid additional encodings, since colours at the |
13+
| end are ignored anyway). |
14+
| 4) Each specifier is followed by a pointer to the PREVIOUS one (so the |
15+
| final specifier starts two cells from the end of the string). |
16+
| 5) The pointer is combined with a parameter offset, so each specifier |
17+
| knows which parameter it should be reading (the first if it needs |
18+
| multiple). |
19+
| |
20+
| How to render a string: |
21+
| |
22+
| 1) Jump to the final specifier to start rendering, following the list. |
23+
| 2) When a specifier, do it. |
24+
| 3) When a colour, wait, and convert the colour list to a forward list. |
25+
| 4) Keep track of how many characters are inserted. |
26+
| 5) When on colours, use that tracking to adjust where the next colour is, |
27+
| and reset the count. |
28+
| |
29+
\*----------------------------------------------------------------------------*/
30+
31+
32+
33+
/**--------------------------------------------------------------------------**\
34+
<summary>Text_RenderLoop</summary>
35+
<param name="string:output[]">Where to write the result to.</param>
36+
<param name="outputLength">Output string length.</param>
37+
<param name="const string:input[]">Input string (without length prefix).</param>
38+
<param name="const inputLength">Input string length.</param>
39+
<param name="const Language:language">Output language.</param>
40+
<returns>
41+
-
42+
</returns>
43+
<remarks>
44+
-
45+
</remarks>
46+
\**--------------------------------------------------------------------------**/
47+
48+
static stock Text_RenderLoop(string:output[], outputLength, const string:input[], const inputLength, const Language:language)
49+
{
50+
//
51+
// ███████╗████████╗███████╗██████╗ ██╗
52+
// ██╔════╝╚══██╔══╝██╔════╝██╔══██╗ ███║
53+
// ███████╗ ██║ █████╗ ██████╔╝ ╚██║
54+
// ╚════██║ ██║ ██╔══╝ ██╔═══╝ ██║
55+
// ███████║ ██║ ███████╗██║ ██║
56+
// ╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
57+
//
58+
// Regular specifiers.
59+
new
60+
outputIdx = 0,
61+
curSpecIndex = 0,
62+
prevSpecIndex,
63+
firstColourIndex = -1,
64+
prevColourIndex = -1,
65+
addedLength;
66+
while (outputLength > 0 && curSpecIndex != inputLength)
67+
{
68+
// There is always a specifier at the start of the string, it just might
69+
// not do anything.
70+
if (Specifier_IsColour(input, curSpecIndex))
71+
{
72+
if (outputLength < 2)
73+
break;
74+
addedLength = outputIdx + 1;
75+
// The colour linked list jumps are relative.
76+
if (firstColourIndex == -1)
77+
firstColourIndex = outputIdx;
78+
else
79+
output[prevColourIndex] = addedLength - prevColourIndex;
80+
output[outputIdx] = input[curSpecIndex];
81+
prevColourIndex = addedLength;
82+
output[addedLength] = -1;
83+
outputLength -= 2;
84+
outputIdx += 2;
85+
}
86+
else
87+
{
88+
addedLength = Text_DoSpecifier(Specifier_Read(input, curSpecIndex), language, output[outputIdx], outputLength);
89+
outputIdx += addedLength;
90+
outputLength -= addedLength;
91+
}
92+
// Move on.
93+
prevSpecIndex = curSpecIndex + 2;
94+
curSpecIndex = Specifier_Next(input, curSpecIndex);
95+
// A specifier is always followed by a length of normal text; however,
96+
// that length may be zero...
97+
addedLength = min(outputLength, curSpecIndex - prevSpecIndex);
98+
strcat(output[outputIdx], input[prevSpecIndex], addedLength + 1);
99+
outputIdx += addedLength;
100+
outputLength -= addedLength;
101+
}
102+
// "outputLength" is always one short to make this work.
103+
output[outputIdx] = '\0';
104+
//
105+
// ███████╗████████╗███████╗██████╗ ██████╗
106+
// ██╔════╝╚══██╔══╝██╔════╝██╔══██╗ ╚════██╗
107+
// ███████╗ ██║ █████╗ ██████╔╝ █████╔╝
108+
// ╚════██║ ██║ ██╔══╝ ██╔═══╝ ██╔═══╝
109+
// ███████║ ██║ ███████╗██║ ███████╗
110+
// ╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚══════╝
111+
//
112+
// Colours.
113+
}
114+
115+
/*
116+
117+
88 88 88
118+
88 88 88
119+
88 88 88
120+
88aaaaaaaa88 ,adPPYba, 88 8b,dPPYba, ,adPPYba, 8b,dPPYba, ,adPPYba,
121+
88""""""""88 a8P_____88 88 88P' "8a a8P_____88 88P' "Y8 I8[ ""
122+
88 88 8PP""""""" 88 88 d8 8PP""""""" 88 `"Y8ba,
123+
88 88 "8b, ,aa 88 88b, ,a8" "8b, ,aa 88 aa ]8I
124+
88 88 `"Ybbd8"' 88 88`YbbdP"' `"Ybbd8"' 88 `"YbbdP"'
125+
88
126+
88
127+
128+
*/
129+
130+
static stock
131+
YSI_g_sSpecifier[8];
132+
133+
static stock
134+
YSI_g_sSpecTempl[][8] =
135+
{
136+
"%*.*d", // 6 (6)
137+
"%-*.*d", // 7 (13)
138+
"%0*.*d", // 7 (20)
139+
"%0-*.*d" // 8 (28)
140+
};
141+
142+
#define Text_MakeSpecifier(%1,%0); switch((%1)&(e_SPECIFIER_IS_LEFT|e_SPECIFIER_IS_ZERO)){\
143+
case e_SPECIFIER_IS_LEFT|e_SPECIFIER_IS_ZERO:YSI_g_sSpecifier=YSI_g_sSpecTempl[3],YSI_g_sSpecifier[6]=%0;\
144+
case e_SPECIFIER_IS_ZERO:YSI_g_sSpecifier=YSI_g_sSpecTempl[2],YSI_g_sSpecifier[5]=%0;\
145+
case e_SPECIFIER_IS_LEFT:YSI_g_sSpecifier=YSI_g_sSpecTempl[1],YSI_g_sSpecifier[5]=%0;\
146+
default:YSI_g_sSpecifier=YSI_g_sSpecTempl[0],YSI_g_sSpecifier[4]=%0;}
147+
148+
/**--------------------------------------------------------------------------**\
149+
<summary>Text_SimpleSpecifier</summary>
150+
<param name="width">How wide to make the output string.</param>
151+
<param name="prec">Settings for certain specifiers (dp etc).</param>
152+
<param name="e_SPECIFIER_FLAGS:flags">Padding options.</param>
153+
<param name="specifier">Which letter to use after "%".</param>
154+
<param name="string:output[]">Where to write the result to.</param>
155+
<param name="const outputLength">Output string length.</param>
156+
<returns>
157+
The length of text added.
158+
</returns>
159+
<remarks>
160+
There is always one cell reserved in the output for NULL, so we can always
161+
write that out even when out of space.
162+
</remarks>
163+
\**--------------------------------------------------------------------------**/
164+
165+
static stock Text_SimpleSpecifier(width, prec, e_SPECIFIER_FLAGS:flags, specifier, string:output[], const outputLength)
166+
{
167+
switch(flags & (e_SPECIFIER_IS_LEFT | e_SPECIFIER_IS_ZERO))
168+
{
169+
case e_SPECIFIER_IS_LEFT | e_SPECIFIER_IS_ZERO:
170+
YSI_g_sSpecTempl[3][6] = specifier,
171+
format(output, outputLength, YSI_g_sSpecTempl[3], width, prec, Text_ReadIntParam());
172+
case e_SPECIFIER_IS_ZERO:
173+
YSI_g_sSpecTempl[2][5] = specifier,
174+
format(output, outputLength, YSI_g_sSpecTempl[2], width, prec, Text_ReadIntParam());
175+
case e_SPECIFIER_IS_LEFT:
176+
YSI_g_sSpecTempl[1][5] = specifier,
177+
format(output, outputLength, YSI_g_sSpecTempl[1], width, prec, Text_ReadIntParam());
178+
default:
179+
YSI_g_sSpecTempl[0][4] = specifier,
180+
format(output, outputLength, YSI_g_sSpecTempl[0], width, prec, Text_ReadIntParam());
181+
}
182+
return strlen(output);
183+
}
184+
185+
/**--------------------------------------------------------------------------**\
186+
<summary>Text_DoSpecifier</summary>
187+
<param name="Specifier:specifier">Information about what to insert.</param>
188+
<param name="const Language:language">Output language.</param>
189+
<param name="string:output[]">Where to write the result to.</param>
190+
<param name="const outputLength">Output string length.</param>
191+
<returns>
192+
The length of text added.
193+
</returns>
194+
<remarks>
195+
There is always one cell reserved in the output for NULL, so we can always
196+
write that out even when out of space.
197+
</remarks>
198+
\**--------------------------------------------------------------------------**/
199+
200+
static stock Text_DoSpecifier(Specifier:specifier, const Language:language, string:output[], const outputLength)
201+
{
202+
new
203+
width = Specifier_GetWidth(specifier),
204+
prec = Specifier_GetPrecision(specifier),
205+
e_SPECIFIER_FLAGS:flags = Text_GetPrecision(Specifier:specifier);
206+
switch (width)
207+
{
208+
// Must come first (for parameter reading ordering).
209+
case SPECIFIER_DEFAULT_WIDTH: width = 0;
210+
case SPECIFIER_STAR_WIDTH: width = Text_ReadIntParam();
211+
}
212+
switch (prec)
213+
{
214+
// Must come second (for parameter reading ordering).
215+
case SPECIFIER_DEFAULT_PREC: prec = -1;
216+
case SPECIFIER_STAR_PREC: prec = Text_ReadIntParam();
217+
}
218+
switch (Specifier_GetType(specifier))
219+
{
220+
case E_SPECIFIER_STRING : return Text_DoSpecifierString (width, prec, flags, language, output, outputLength);
221+
case E_SPECIFIER_FLOAT : return Text_DoSpecifierFloat (width, prec, flags, language, output, outputLength);
222+
case E_SPECIFIER_ARRAY : return Text_DoSpecifierArray (width, prec, flags, language, output, outputLength);
223+
case E_SPECIFIER_HEX : return Text_DoSpecifierHexadecimal(width, prec, flags, language, output, outputLength);
224+
case E_SPECIFIER_DEC : return Text_DoSpecifierDecimal (width, prec, flags, language, output, outputLength);
225+
case E_SPECIFIER_BIN : return Text_DoSpecifierBinary (width, prec, flags, language, output, outputLength);
226+
case E_SPECIFIER_CHAR : return Text_DoSpecifierChar (width, prec, flags, language, output, outputLength);
227+
case E_SPECIFIER_IEEE : return Text_DoSpecifierIEEE (width, prec, flags, language, output, outputLength);
228+
case E_SPECIFIER_COMM : return Text_DoSpecifierCommand (width, prec, flags, language, output, outputLength);
229+
case E_SPECIFIER_SUFFIX : return Text_DoSpecifierSuffix (width, prec, flags, language, output, outputLength);
230+
case E_SPECIFIER_UNSIGNED: return Text_DoSpecifierUnsigned (width, prec, flags, language, output, outputLength);
231+
case E_SPECIFIER_SIGNED : return Text_DoSpecifierSigned (width, prec, flags, language, output, outputLength);
232+
case E_SPECIFIER_PLAYER : return Text_DoSpecifierPlayer (width, prec, flags, language, output, outputLength);
233+
case E_SPECIFIER_LOGICAL : return Text_DoSpecifierLogical (width, prec, flags, language, output, outputLength);
234+
case E_SPECIFIER_CUSTOM : return Text_DoSpecifierCustom (width, prec, flags, language, output, outputLength);
235+
case E_SPECIFIER_DATE : return Text_DoSpecifierDate (width, prec, flags, language, output, outputLength);
236+
case E_SPECIFIER_OCT : return Text_DoSpecifierOctal (width, prec, flags, language, output, outputLength);
237+
}
238+
return 0;
239+
}
240+
241+
//#define Text_MakeSpecifier(%0,%1) YSI_g_sSpecifier = ((SpecFlag_IsZeroPadded(%1)) \
242+
// ? ((SpecFlag_IsLeftPadded(%1)) \
243+
// ? (YSI_g_sSpecTempl[3][6] = (%0), YSI_g_sSpecTempl[3]) \
244+
// : (YSI_g_sSpecTempl[2][5] = (%0), YSI_g_sSpecTempl[2])) \
245+
// : ((SpecFlag_IsLeftPadded(%1)) \
246+
// ? (YSI_g_sSpecTempl[1][5] = (%0), YSI_g_sSpecTempl[1]) \
247+
// : (YSI_g_sSpecTempl[0][4] = (%0), YSI_g_sSpecTempl[0])))
248+
249+
/*
250+
251+
ad88888ba 88 ad88 88
252+
d8" "8b "" d8" ""
253+
Y8, 88
254+
`Y8aaaaa, 8b,dPPYba, ,adPPYba, ,adPPYba, 88 MM88MMM 88 ,adPPYba, 8b,dPPYba, ,adPPYba,
255+
`"""""8b, 88P' "8a a8P_____88 a8" "" 88 88 88 a8P_____88 88P' "Y8 I8[ ""
256+
`8b 88 d8 8PP""""""" 8b 88 88 88 8PP""""""" 88 `"Y8ba,
257+
Y8a a8P 88b, ,a8" "8b, ,aa "8a, ,aa 88 88 88 "8b, ,aa 88 aa ]8I
258+
"Y88888P" 88`YbbdP"' `"Ybbd8"' `"Ybbd8"' 88 88 88 `"Ybbd8"' 88 `"YbbdP"'
259+
88
260+
88
261+
262+
*/
263+
264+
static stock Text_DoSpecifierString (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
265+
{
266+
Text_MakeSpecifier(flags, 's');
267+
}
268+
269+
static stock Text_DoSpecifierFloat (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
270+
{
271+
Text_MakeSpecifier(flags, 'f');
272+
}
273+
274+
static stock Text_DoSpecifierArray (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
275+
{
276+
//Text_MakeSpecifier(flags, 's');
277+
}
278+
279+
static stock Text_DoSpecifierHexadecimal(width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
280+
{
281+
new
282+
arg = Text_ReadIntParam();
283+
if (arg & cellmin)
284+
{
285+
if (width>8)
286+
SpecFlag_IsLeftPadded(flags)
287+
? (SpecFlag_IsZeroPadded(flags)
288+
? format(ts, 130, "%x%0-*x", arg >>> 4, width - 7, arg & 15)
289+
: format(ts, 130, "%x%-*x", arg >>> 4, width - 7, arg & 15))
290+
: (SpecFlag_IsZeroPadded(flags)
291+
? format(ts, 130, "%0*x%x", width - 1, arg >>> 4, arg & 15)
292+
: format(ts, 130, "%*x%x", width - 1, arg >>> 4, arg & 15));
293+
else
294+
format(ts,130,"%x%x",arg>>>4,arg&15)
295+
}
296+
else
297+
{
298+
Text_SimpleSpecifier(width, prec, flags, 'x');
299+
}
300+
}
301+
302+
static stock Text_DoSpecifierDecimal (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
303+
{
304+
Text_MakeSpecifier(flags, 'd');
305+
}
306+
307+
static stock Text_DoSpecifierBinary (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
308+
{
309+
Text_MakeSpecifier(flags, 'b');
310+
}
311+
312+
static stock Text_DoSpecifierChar (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
313+
{
314+
Text_MakeSpecifier(flags, 'c');
315+
}
316+
317+
static stock Text_DoSpecifierIEEE (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
318+
{
319+
Text_MakeSpecifier(flags, 's');
320+
Text_MakeSpecifier(flags, 'f');
321+
}
322+
323+
static stock Text_DoSpecifierCommand (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
324+
{
325+
Text_MakeSpecifier(flags, 's');
326+
}
327+
328+
static stock Text_DoSpecifierSuffix (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
329+
{
330+
Text_MakeSpecifier(flags, 's');
331+
}
332+
333+
static stock Text_DoSpecifierUnsigned (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
334+
{
335+
//Text_MakeSpecifier(flags, 's');
336+
}
337+
338+
static stock Text_DoSpecifierSigned (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
339+
{
340+
Text_MakeSpecifier(flags, 's');
341+
}
342+
343+
static stock Text_DoSpecifierPlayer (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
344+
{
345+
Text_MakeSpecifier(flags, 's');
346+
}
347+
348+
static stock Text_DoSpecifierLogical (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
349+
{
350+
Text_MakeSpecifier(flags, 's');
351+
}
352+
353+
static stock Text_DoSpecifierCustom (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
354+
{
355+
Text_MakeSpecifier(flags, 's');
356+
}
357+
358+
static stock Text_DoSpecifierDate (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
359+
{
360+
Text_MakeSpecifier(flags, 's');
361+
}
362+
363+
static stock Text_DoSpecifierOctal (width, prec, e_SPECIFIER_FLAGS:flags, Language:language, string:output[], const outputLength)
364+
{
365+
Text_MakeSpecifier(flags, 's');
366+
}
367+

0 commit comments

Comments
 (0)