3d680d5d188ee0420fae2d803c2cec1cbc317a55
[tpg/acess2.git] / Usermode / Applications / axwin2_src / WM / video_text.c
1 /*
2  * Acess GUI (AxWin) Version 2
3  * By John Hodge (thePowersGang)
4  */
5 #include <acess/sys.h>
6 #include "common.h"
7
8 typedef struct sGlyph {
9         struct sGlyph   *Next;
10         struct sGlyph   *Prev;
11         
12         uint32_t        Codepoint;
13         
14         // Effective dimensions (distance to move 'cursor')
15         short   Width;
16         short   Height;
17         
18         // Distance from the current cursor position to render at
19         short   OffsetX;
20         short   OffsetY;
21         
22         // True dimensions (size of the bitmap
23         short   TrueWidth;
24         short   TrueHeight;
25         
26         // Bitmap Data
27         uint8_t Bitmap[];       // 8-bit alpha
28         
29 }       tGlyph;
30
31 struct sFont {
32         struct sFont    *Next;
33          int    ReferenceCount;
34         
35         tGlyph  *AsciiGlyphs[128];      // Glyphs 0-127
36         
37         tGlyph  *FirstGlyph;
38         tGlyph  *LastGlyph;
39         
40         tGlyph  *(*CacheGlyph)(struct sFont *this, uint32_t Codepoint);
41         
42 };
43
44
45 // === PROTOTYPES ===
46  int    Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text);
47 void    Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
48 tGlyph  *_GetGlyph(tFont *Font, uint32_t Codepoint);
49 void    _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color);
50 tGlyph  *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint);
51  int    ReadUTF8(const char *Input, uint32_t *Output);
52
53 // === GLOBALS ===
54 tFont   gSystemFont = {
55         .CacheGlyph = _SystemFont_CacheGlyph
56 };
57
58 // === CODE ===
59 /**
60  * \brief Draw text to the screen
61  */
62 int Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text)
63 {
64          int    xOfs = 0;
65         tGlyph  *glyph;
66         uint32_t        ch = 0;
67
68         _SysDebug("Video_DrawText: (X=%i,Y=%i,W=%i,H=%i,Font=%p,", X, Y, W, H, Font);
69         _SysDebug("  Color=%08x,Text='%s')", Color, Text);
70         
71         // Check the bounds
72         if(W < 0 || X < 0 || X >= giScreenWidth)        return 0;
73         if(X + W > giScreenWidth)       W = giScreenWidth - X;
74         
75         if(H < 0 || Y < 0 || Y >= giScreenHeight)       return 0;
76         if(Y + H > giScreenHeight)      H = giScreenHeight - Y;
77         
78         // Handle NULL font (system default monospace)
79         if( !Font )     Font = &gSystemFont;
80         
81         while( *Text )
82         {
83                 // Read character
84                 Text += ReadUTF8(Text, &ch);
85                 
86                 // Find (or load) the glyph
87                 glyph = _GetGlyph(Font, ch);
88                 if( !glyph )    continue ;      // If not found, just don't render it
89                 
90                 // End render if it will overflow the perscribed range
91                 if( xOfs + glyph->TrueWidth > W )
92                         break;
93                 
94                 xOfs += glyph->Width;
95                 _RenderGlyph(X + xOfs, Y, glyph, Color);
96         }
97         
98         return xOfs;
99 }
100
101 void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H)
102 {
103          int    w=0, h=0;
104         uint32_t        ch;
105         tGlyph  *glyph;
106         if( !Font )     Font = &gSystemFont;
107         
108         while( *Text )
109         {
110                 Text += ReadUTF8(Text, &ch);
111                 glyph = _GetGlyph(Font, ch);
112                 if( !glyph )    continue;
113                 
114                 w += glyph->Width;
115                 if( h < glyph->Height ) h = glyph->Height;
116         }
117         
118         if(W)   *W = w;
119         if(H)   *H = h;
120 }
121
122 tGlyph  *_GetGlyph(tFont *Font, uint32_t Codepoint)
123 {
124         tGlyph  *next = NULL, *prev = NULL;
125         tGlyph  *new;
126         
127         // Check for ASCII
128         if( Codepoint < 128 )
129         {
130                 if( Font->AsciiGlyphs[Codepoint] == NULL ) {
131                         Font->AsciiGlyphs[Codepoint] = Font->CacheGlyph(Font, Codepoint);
132                 }
133                 
134                 return Font->AsciiGlyphs[Codepoint];
135         }
136         
137         // If within the range
138         if( Font->FirstGlyph && Font->FirstGlyph->Codepoint < Codepoint && Codepoint < Font->LastGlyph->Codepoint )
139         {
140                 // Find what end is "closest"
141                 if( Codepoint - Font->FirstGlyph->Codepoint < Font->LastGlyph->Codepoint - Codepoint )
142                 {
143                         // Start from the bottom
144                         for( next = Font->FirstGlyph;
145                                  next && next->Codepoint < Codepoint;
146                                  prev = next, next = next->Next
147                                  );
148                         
149                         if( next->Codepoint == Codepoint )
150                                 return next;
151                         
152                 }
153                 else
154                 {
155                         // Start at the top
156                         // NOTE: The roles of next and prev are reversed here to allow 
157                         //       the insert to be able to assume that `prev` is the
158                         //       previous entry, and `next` is the next.
159                         for( prev = Font->LastGlyph;
160                                  prev && prev->Codepoint > Codepoint;
161                                  next = prev, prev = prev->Prev
162                                  );
163                         if( prev->Codepoint == Codepoint )
164                                 return prev;
165                 }
166         }
167         else
168         {
169                 // If below first
170                 if( !Font->FirstGlyph ||  Font->FirstGlyph->Codepoint > Codepoint ) {
171                         prev = NULL;
172                         next = Font->FirstGlyph;
173                 }
174                 // Above last
175                 else {
176                         prev = Font->LastGlyph;
177                         next = NULL;
178                 }
179         }
180         
181         // Load new
182         new = Font->CacheGlyph(Font, Codepoint);
183         if( !new )      return NULL;
184         
185         // Add to list
186         // - Forward link
187         if( prev ) {
188                 new->Next = prev->Next;
189                 prev->Next = new;
190         }
191         else {
192                 new->Next = Font->FirstGlyph;
193                 Font->FirstGlyph = new;
194         }
195         
196         // - Backlink
197         if( next ) {
198                 new->Prev = next->Prev;
199                 next->Prev = new;
200         }
201         else {
202                 new->Prev = Font->LastGlyph;
203                 Font->LastGlyph = new;
204         }
205         
206         // Return
207         return new;
208 }
209
210 /**
211  */
212 void _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color)
213 {
214          int    xStart = 0, yStart = 0;
215          int    x, y;
216         uint32_t        *outBuf;
217         uint8_t *inBuf;
218         // TODO: Implement
219
220         X += Glyph->OffsetX;
221         if( X < 0 ) {   // If -ve, skip the first -X collums
222                 xStart = -X;
223                 X = 0;
224         }
225
226         Y += Glyph->OffsetY;
227         if( Y < 0 ) {   // If -ve, skip the first -Y lines
228                 yStart = -Y;
229                 Y = 0;
230         }
231
232         outBuf = gpScreenBuffer + Y*giScreenWidth + X;
233         inBuf = Glyph->Bitmap + yStart*Glyph->TrueWidth;
234
235         for( y = yStart; y < Glyph->TrueHeight; y ++ )
236         {
237                 for( x = xStart; x < Glyph->TrueWidth; x ++ )
238                 {
239                         outBuf[x] = Video_AlphaBlend( outBuf[x], Color, inBuf[x] );
240                 }
241                 outBuf += giScreenWidth;
242                 inBuf += Glyph->TrueWidth;
243
244         }
245 }
246
247 // Load system font (8x16 monospace)
248 #include "font_8x16.h"
249
250 /*
251  */
252 tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint)
253 {
254          int    i;
255         uint8_t index = 0;
256         tGlyph  *ret;
257         uint8_t *data;
258
259         _SysDebug("_SystemFont_CacheGlyph: (Font=%p, Codepoint=0x%06x)", Font, Codepoint);
260         
261         if( Codepoint < 128 ) {
262                 index = Codepoint;
263         }
264         else {
265                 index = '?';    // Unknowns come out as a question mark
266         }
267
268         _SysDebug(" index = %i", index);
269
270         ret = malloc( sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT );
271         if( !ret ) {
272                 _SysDebug("ERROR: malloc(%i) failed", sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT);
273                 return NULL;
274         }
275
276         ret->Codepoint = Codepoint;
277
278         ret->Width = FONT_WIDTH;
279         ret->Height = FONT_HEIGHT;
280         
281         ret->TrueWidth = FONT_WIDTH;
282         ret->TrueHeight = FONT_HEIGHT;
283
284         ret->OffsetX = 0;
285         ret->OffsetY = 0;
286         
287         data = &VTermFont[index * FONT_HEIGHT];
288
289         for( i = 0; i < FONT_HEIGHT; i ++ )
290         {
291                 ret->Bitmap[ i * 8 + 0 ] = data[i] & (1 << 7) ? 255 : 0;
292                 ret->Bitmap[ i * 8 + 1 ] = data[i] & (1 << 6) ? 255 : 0;
293                 ret->Bitmap[ i * 8 + 2 ] = data[i] & (1 << 5) ? 255 : 0;
294                 ret->Bitmap[ i * 8 + 3 ] = data[i] & (1 << 4) ? 255 : 0;
295                 ret->Bitmap[ i * 8 + 4 ] = data[i] & (1 << 3) ? 255 : 0;
296                 ret->Bitmap[ i * 8 + 5 ] = data[i] & (1 << 2) ? 255 : 0;
297                 ret->Bitmap[ i * 8 + 6 ] = data[i] & (1 << 1) ? 255 : 0;
298                 ret->Bitmap[ i * 8 + 7 ] = data[i] & (1 << 0) ? 255 : 0;
299         }
300
301         return ret;
302 }
303
304
305 /**
306  * \fn int ReadUTF8(char *Input, uint32_t *Val)
307  * \brief Read a UTF-8 character from a string
308  */
309 int ReadUTF8(const char *Input, uint32_t *Val)
310 {
311         const uint8_t   *str = (const uint8_t *)Input;
312         *Val = 0xFFFD;  // Assume invalid character
313         
314         // ASCII
315         if( !(*str & 0x80) ) {
316                 *Val = *str;
317                 return 1;
318         }
319         
320         // Middle of a sequence
321         if( (*str & 0xC0) == 0x80 ) {
322                 return 1;
323         }
324         
325         // Two Byte
326         if( (*str & 0xE0) == 0xC0 ) {
327                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
328                 str ++;
329                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
330                 *Val |= (*str & 0x3F);  // Lower 6 Bits
331                 return 2;
332         }
333         
334         // Three Byte
335         if( (*str & 0xF0) == 0xE0 ) {
336                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
337                 str ++;
338                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
339                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
340                 str ++;
341                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
342                 *Val |= (*str & 0x3F);  // Lower 6 Bits
343                 return 3;
344         }
345         
346         // Four Byte
347         if( (*str & 0xF1) == 0xF0 ) {
348                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
349                 str ++;
350                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
351                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
352                 str ++;
353                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
354                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
355                 str ++;
356                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
357                 *Val |= (*str & 0x3F);  // Lower 6 Bits
358                 return 4;
359         }
360         
361         // UTF-8 Doesn't support more than four bytes
362         return 4;
363 }
364
365
366
367

UCC git Repository :: git.ucc.asn.au