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

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