5dc462f27608a9ee07755bb0463180042e693b4b
[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(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 tGlyph  *_GetGlyph(tFont *Font, uint32_t Codepoint)
100 {
101         tGlyph  *next = NULL, *prev = NULL;
102         tGlyph  *new;
103         
104         // Check for ASCII
105         if( Codepoint < 128 )
106         {
107                 if( Font->AsciiGlyphs[Codepoint] == NULL ) {
108                         Font->AsciiGlyphs[Codepoint] = Font->CacheGlyph(Font, Codepoint);
109                 }
110                 
111                 return Font->AsciiGlyphs[Codepoint];
112         }
113         
114         // If within the range
115         if( Font->FirstGlyph && Font->FirstGlyph->Codepoint < Codepoint && Codepoint < Font->LastGlyph->Codepoint )
116         {
117                 // Find what end is "closest"
118                 if( Codepoint - Font->FirstGlyph->Codepoint < Font->LastGlyph->Codepoint - Codepoint )
119                 {
120                         // Start from the bottom
121                         for( next = Font->FirstGlyph;
122                                  next && next->Codepoint < Codepoint;
123                                  prev = next, next = next->Next
124                                  );
125                         
126                         if( next->Codepoint == Codepoint )
127                                 return next;
128                         
129                 }
130                 else
131                 {
132                         // Start at the top
133                         // NOTE: The roles of next and prev are reversed here to allow 
134                         //       the insert to be able to assume that `prev` is the
135                         //       previous entry, and `next` is the next.
136                         for( prev = Font->LastGlyph;
137                                  prev && prev->Codepoint > Codepoint;
138                                  next = prev, prev = prev->Prev
139                                  );
140                         if( prev->Codepoint == Codepoint )
141                                 return prev;
142                 }
143         }
144         else
145         {
146                 // If below first
147                 if( !Font->FirstGlyph ||  Font->FirstGlyph->Codepoint > Codepoint ) {
148                         prev = NULL;
149                         next = Font->FirstGlyph;
150                 }
151                 // Above last
152                 else {
153                         prev = Font->LastGlyph;
154                         next = NULL;
155                 }
156         }
157         
158         // Load new
159         new = Font->CacheGlyph(Font, Codepoint);
160         if( !new )      return NULL;
161         
162         // Add to list
163         // - Forward link
164         if( prev ) {
165                 new->Next = prev->Next;
166                 prev->Next = new;
167         }
168         else {
169                 new->Next = Font->FirstGlyph;
170                 Font->FirstGlyph = new;
171         }
172         
173         // - Backlink
174         if( next ) {
175                 new->Prev = next->Prev;
176                 next->Prev = new;
177         }
178         else {
179                 new->Prev = Font->LastGlyph;
180                 Font->LastGlyph = new;
181         }
182         
183         // Return
184         return new;
185 }
186
187 /**
188  */
189 void _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color)
190 {
191          int    xStart = 0, yStart = 0;
192          int    x, y;
193         uint32_t        *outBuf;
194         uint8_t *inBuf;
195         // TODO: Implement
196
197         X += Glyph->OffsetX;
198         if( X < 0 ) {   // If -ve, skip the first -X collums
199                 xStart = -X;
200                 X = 0;
201         }
202
203         Y += Glyph->OffsetY;
204         if( Y < 0 ) {   // If -ve, skip the first -Y lines
205                 yStart = -Y;
206                 Y = 0;
207         }
208
209         outBuf = gpScreenBuffer + Y*giScreenWidth + X;
210         inBuf = Glyph->Bitmap + yStart*Glyph->TrueWidth;
211
212         for( y = yStart; y < Glyph->TrueHeight; y ++ )
213         {
214                 for( x = xStart; x < Glyph->TrueWidth; x ++ )
215                 {
216                         outBuf[x] = Video_AlphaBlend( outBuf[x], Color, inBuf[x] );
217                 }
218                 outBuf += giScreenWidth;
219                 inBuf += Glyph->TrueWidth;
220
221         }
222 }
223
224 // Load system font (8x16 monospace)
225 #include "font_8x16.h"
226
227 /*
228  */
229 tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint)
230 {
231          int    i;
232         uint8_t index = 0;
233         tGlyph  *ret;
234         uint8_t *data;
235
236         _SysDebug("_SystemFont_CacheGlyph: (Font=%p, Codepoint=0x%06x)", Font, Codepoint);
237         
238         if( Codepoint < 128 ) {
239                 index = Codepoint;
240         }
241         else {
242                 index = '?';    // Unknowns come out as a question mark
243         }
244
245         _SysDebug(" index = %i", index);
246
247         ret = malloc( sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT );
248
249         ret->Codepoint = Codepoint;
250
251         ret->Width = FONT_WIDTH;
252         ret->Height = FONT_HEIGHT;
253         
254         ret->TrueWidth = FONT_WIDTH;
255         ret->TrueHeight = FONT_HEIGHT;
256
257         ret->OffsetX = 0;
258         ret->OffsetY = 0;
259         
260         data = &VTermFont[index * FONT_HEIGHT];
261
262         for( i = 0; i < FONT_HEIGHT; i ++ )
263         {
264                 ret->Bitmap[ i * 8 + 0 ] = data[i] & (1 << 7) ? 255 : 0;
265                 ret->Bitmap[ i * 8 + 1 ] = data[i] & (1 << 6) ? 255 : 0;
266                 ret->Bitmap[ i * 8 + 2 ] = data[i] & (1 << 5) ? 255 : 0;
267                 ret->Bitmap[ i * 8 + 3 ] = data[i] & (1 << 4) ? 255 : 0;
268                 ret->Bitmap[ i * 8 + 4 ] = data[i] & (1 << 3) ? 255 : 0;
269                 ret->Bitmap[ i * 8 + 5 ] = data[i] & (1 << 2) ? 255 : 0;
270                 ret->Bitmap[ i * 8 + 6 ] = data[i] & (1 << 1) ? 255 : 0;
271                 ret->Bitmap[ i * 8 + 7 ] = data[i] & (1 << 0) ? 255 : 0;
272         }
273
274         return ret;
275 }
276
277
278 /**
279  * \fn int ReadUTF8(char *Input, uint32_t *Val)
280  * \brief Read a UTF-8 character from a string
281  */
282 int ReadUTF8(char *Input, uint32_t *Val)
283 {
284         uint8_t *str = (uint8_t *)Input;
285         *Val = 0xFFFD;  // Assume invalid character
286         
287         // ASCII
288         if( !(*str & 0x80) ) {
289                 *Val = *str;
290                 return 1;
291         }
292         
293         // Middle of a sequence
294         if( (*str & 0xC0) == 0x80 ) {
295                 return 1;
296         }
297         
298         // Two Byte
299         if( (*str & 0xE0) == 0xC0 ) {
300                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
301                 str ++;
302                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
303                 *Val |= (*str & 0x3F);  // Lower 6 Bits
304                 return 2;
305         }
306         
307         // Three Byte
308         if( (*str & 0xF0) == 0xE0 ) {
309                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
310                 str ++;
311                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
312                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
313                 str ++;
314                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
315                 *Val |= (*str & 0x3F);  // Lower 6 Bits
316                 return 3;
317         }
318         
319         // Four Byte
320         if( (*str & 0xF1) == 0xF0 ) {
321                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
322                 str ++;
323                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
324                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
325                 str ++;
326                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
327                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
328                 str ++;
329                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
330                 *Val |= (*str & 0x3F);  // Lower 6 Bits
331                 return 4;
332         }
333         
334         // UTF-8 Doesn't support more than four bytes
335         return 4;
336 }
337
338
339
340

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