63a1389e35097f0a7b02eec8d20e5a36e70fd235
[rocksndiamonds.git] / src / libgame / text.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * text.c                                                   *
12 ***********************************************************/
13
14 #include <stdio.h>
15 #include <stdarg.h>
16
17 #include "text.h"
18 #include "misc.h"
19
20
21 /* ========================================================================= */
22 /* font functions                                                            */
23 /* ========================================================================= */
24
25 void InitFontInfo(struct FontBitmapInfo *font_bitmap_info, int num_fonts,
26                   int (*select_font_function)(int),
27                   int (*get_font_from_token_function)(char *))
28 {
29   gfx.num_fonts = num_fonts;
30   gfx.font_bitmap_info = font_bitmap_info;
31   gfx.select_font_function = select_font_function;
32   gfx.get_font_from_token_function = get_font_from_token_function;
33 }
34
35 void FreeFontInfo(struct FontBitmapInfo *font_bitmap_info)
36 {
37   if (font_bitmap_info == NULL)
38     return;
39
40   free(font_bitmap_info);
41 }
42
43 struct FontBitmapInfo *getFontBitmapInfo(int font_nr)
44 {
45   int font_bitmap_id = gfx.select_font_function(font_nr);
46
47   return &gfx.font_bitmap_info[font_bitmap_id];
48 }
49
50 int getFontWidth(int font_nr)
51 {
52   int font_bitmap_id = gfx.select_font_function(font_nr);
53
54   return gfx.font_bitmap_info[font_bitmap_id].width;
55 }
56
57 int getFontHeight(int font_nr)
58 {
59   int font_bitmap_id = gfx.select_font_function(font_nr);
60
61   return gfx.font_bitmap_info[font_bitmap_id].height;
62 }
63
64 int getTextWidth(char *text, int font_nr)
65 {
66   return (text != NULL ? strlen(text) * getFontWidth(font_nr) : 0);
67 }
68
69 static int getFontCharPosition(int font_nr, char c)
70 {
71   int font_bitmap_id = gfx.select_font_function(font_nr);
72   struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
73   boolean default_font = (font->num_chars == DEFAULT_NUM_CHARS_PER_FONT);
74   int font_pos = (unsigned char)c - 32;
75
76   /* map some special characters to their ascii values in default font */
77   if (default_font)
78     font_pos = MAP_FONT_ASCII(c) - 32;
79
80   /* this allows dynamic special characters together with special font */
81   if (font_pos < 0 || font_pos >= font->num_chars)
82     font_pos = 0;
83
84   return font_pos;
85 }
86
87 void getFontCharSource(int font_nr, char c, Bitmap **bitmap, int *x, int *y)
88 {
89   int font_bitmap_id = gfx.select_font_function(font_nr);
90   struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
91   int font_pos = getFontCharPosition(font_nr, c);
92
93   *bitmap = font->bitmap;
94   *x = font->src_x + (font_pos % font->num_chars_per_line) * font->width;
95   *y = font->src_y + (font_pos / font->num_chars_per_line) * font->height;
96 }
97
98
99 /* ========================================================================= */
100 /* text string helper functions                                              */
101 /* ========================================================================= */
102
103 int maxWordLengthInString(char *text)
104 {
105   char *text_ptr;
106   int word_len = 0, max_word_len = 0;
107
108   for (text_ptr = text; *text_ptr; text_ptr++)
109   {
110     word_len = (*text_ptr != ' ' ? word_len + 1 : 0);
111
112     max_word_len = MAX(word_len, max_word_len);
113   }
114
115   return max_word_len;
116 }
117
118
119 /* ========================================================================= */
120 /* simple text drawing functions                                             */
121 /* ========================================================================= */
122
123 void DrawInitTextExt(char *text, int ypos, int font_nr, boolean force)
124 {
125 #if 1
126 #if 0
127   static unsigned int progress_delay = 0;
128   unsigned int progress_delay_value = 100;      /* (in milliseconds) */
129 #endif
130
131   // LimitScreenUpdates(TRUE);  // (ignore "force" for now)
132   // LimitScreenUpdates(!force);
133   LimitScreenUpdates(TRUE);
134
135   UPDATE_BUSY_STATE();
136
137 #if 0
138   if (!force && !DelayReached(&progress_delay, progress_delay_value))
139     return;
140 #endif
141
142   if (window != NULL &&
143       gfx.draw_init_text &&
144       gfx.num_fonts > 0 &&
145       gfx.font_bitmap_info[font_nr].bitmap != NULL)
146   {
147     int x = (video.width - getTextWidth(text, font_nr)) / 2;
148     int y = ypos;
149     int width = video.width;
150     int height = getFontHeight(font_nr);
151
152     ClearRectangle(drawto, 0, y, width, height);
153     DrawTextExt(drawto, x, y, text, font_nr, BLIT_OPAQUE);
154
155     BlitBitmap(drawto, window, 0, 0, video.width, video.height, 0, 0);
156   }
157 #else
158   static unsigned int progress_delay = 0;
159   unsigned int progress_delay_value = 100;      /* (in milliseconds) */
160
161   // LimitScreenUpdates(TRUE);  // (ignore "force" for now)
162   LimitScreenUpdates(!force);
163
164   UPDATE_BUSY_STATE();
165
166   if (!force && !DelayReached(&progress_delay, progress_delay_value))
167     return;
168
169   if (window != NULL &&
170       gfx.draw_init_text &&
171       gfx.num_fonts > 0 &&
172       gfx.font_bitmap_info[font_nr].bitmap != NULL)
173   {
174     int x = (video.width - getTextWidth(text, font_nr)) / 2;
175     int y = ypos;
176     int width = video.width;
177     int height = getFontHeight(font_nr);
178
179     ClearRectangle(drawto, 0, y, width, height);
180     DrawTextExt(drawto, x, y, text, font_nr, BLIT_OPAQUE);
181
182     /* this makes things significantly faster than directly drawing to window */
183     BlitBitmap(drawto, window, 0, y, width, height, 0, y);
184   }
185 #endif
186 }
187
188 void DrawInitText(char *text, int ypos, int font_nr)
189 {
190   // DrawInitTextExt(text, ypos, font_nr, TRUE);
191   DrawInitTextExt(text, ypos, font_nr, FALSE);
192 }
193
194 void DrawInitTextAlways(char *text, int ypos, int font_nr)
195 {
196   DrawInitTextExt(text, ypos, font_nr, TRUE);
197 }
198
199 void DrawInitTextIfNeeded(char *text, int ypos, int font_nr)
200 {
201   DrawInitTextExt(text, ypos, font_nr, FALSE);
202 }
203
204 void DrawTextF(int x, int y, int font_nr, char *format, ...)
205 {
206   char buffer[MAX_OUTPUT_LINESIZE + 1];
207   va_list ap;
208
209   va_start(ap, format);
210   vsprintf(buffer, format, ap);
211   va_end(ap);
212
213   if (strlen(buffer) > MAX_OUTPUT_LINESIZE)
214     Error(ERR_EXIT, "string too long in DrawTextF() -- aborting");
215
216   DrawText(gfx.sx + x, gfx.sy + y, buffer, font_nr);
217 }
218
219 void DrawTextFCentered(int y, int font_nr, char *format, ...)
220 {
221   char buffer[MAX_OUTPUT_LINESIZE + 1];
222   va_list ap;
223
224   va_start(ap, format);
225   vsprintf(buffer, format, ap);
226   va_end(ap);
227
228   if (strlen(buffer) > MAX_OUTPUT_LINESIZE)
229     Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting");
230
231   DrawText(gfx.sx + (gfx.sxsize - getTextWidth(buffer, font_nr)) / 2,
232            gfx.sy + y, buffer, font_nr);
233 }
234
235 void DrawTextS(int x, int y, int font_nr, char *text)
236 {
237   DrawText(gfx.sx + x, gfx.sy + y, text, font_nr);
238 }
239
240 void DrawTextSCentered(int y, int font_nr, char *text)
241 {
242   DrawText(gfx.sx + (gfx.sxsize - getTextWidth(text, font_nr)) / 2,
243            gfx.sy + y, text, font_nr);
244 }
245
246 void DrawTextCentered(int y, int font_nr, char *text)
247 {
248   DrawText((gfx.sxsize - getTextWidth(text, font_nr)) / 2, y, text, font_nr);
249 }
250
251 void DrawTextSAligned(int x, int y, char *text, int font_nr, int align)
252 {
253   DrawText(gfx.sx + ALIGNED_XPOS(x, getTextWidth(text, font_nr), align),
254            gfx.sx + y, text, font_nr);
255 }
256
257 void DrawTextAligned(int x, int y, char *text, int font_nr, int align)
258 {
259   DrawText(ALIGNED_XPOS(x, getTextWidth(text, font_nr), align),
260            y, text, font_nr);
261 }
262
263 void DrawText(int x, int y, char *text, int font_nr)
264 {
265   int mask_mode = BLIT_OPAQUE;
266
267   if (DrawingOnBackground(x, y))
268     mask_mode = BLIT_ON_BACKGROUND;
269
270   DrawTextExt(drawto, x, y, text, font_nr, mask_mode);
271
272 #if 1
273   if (IN_GFX_FIELD_FULL(x, y))
274     redraw_mask |= REDRAW_FIELD;
275   else if (IN_GFX_DOOR_1(x, y))
276     redraw_mask |= REDRAW_DOOR_1;
277   else if (IN_GFX_DOOR_2(x, y))
278     redraw_mask |= REDRAW_DOOR_2;
279   else if (IN_GFX_DOOR_3(x, y))
280     redraw_mask |= REDRAW_DOOR_3;
281   else
282     redraw_mask |= REDRAW_ALL;
283 #else
284   if (x < gfx.dx)
285     redraw_mask |= REDRAW_FIELD;
286   else if (y < gfx.vy || gfx.vy == 0)
287     redraw_mask |= REDRAW_DOOR_1;
288 #endif
289 }
290
291 void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
292                  int font_nr, int mask_mode)
293 {
294 #if 1
295   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
296 #else
297   int font_bitmap_id = gfx.select_font_function(font_nr);
298   struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
299 #endif
300   int font_width = getFontWidth(font_nr);
301   int font_height = getFontHeight(font_nr);
302 #if 0
303   int border_1 = gfx.sx + gfx.sxsize;
304   int border_2 = gfx.dx + gfx.dxsize;
305   int dst_x_start = dst_x;
306 #endif
307   Bitmap *src_bitmap;
308   int src_x, src_y;
309   char *text_ptr = text;
310
311   if (font->bitmap == NULL)
312     return;
313
314   /* skip text to be printed outside the window (left/right will be clipped) */
315   if (dst_y < 0 || dst_y + font_height > video.height)
316     return;
317
318   /* add offset for drawing font characters */
319   dst_x += font->draw_xoffset;
320   dst_y += font->draw_yoffset;
321
322   while (*text_ptr)
323   {
324     char c = *text_ptr++;
325
326     if (c == '\n')
327       c = ' ';          /* print space instead of newline */
328
329     getFontCharSource(font_nr, c, &src_bitmap, &src_x, &src_y);
330
331     /* clip text at the left side of the window */
332     if (dst_x < 0)
333     {
334       dst_x += font_width;
335
336       continue;
337     }
338
339     /* clip text at the right side of the window */
340 #if 1
341     if (dst_x + font_width > video.width)
342       break;
343 #else
344     /* (this does not work well when trying to print text to whole screen) */
345     if ((dst_x_start < border_1 && dst_x + font_width > border_1) ||
346         (dst_x_start < border_2 && dst_x + font_width > border_2))
347       break;
348 #endif
349
350     if (mask_mode == BLIT_INVERSE)      /* special mode for text gadgets */
351     {
352       /* first step: draw solid colored rectangle (use "cursor" character) */
353       if (strlen(text) == 1)    /* only one char inverted => draw cursor */
354       {
355         Bitmap *cursor_bitmap;
356         int cursor_x, cursor_y;
357
358         getFontCharSource(font_nr, FONT_ASCII_CURSOR, &cursor_bitmap,
359                           &cursor_x, &cursor_y);
360
361         BlitBitmap(cursor_bitmap, dst_bitmap, cursor_x, cursor_y,
362                    font_width, font_height, dst_x, dst_y);
363       }
364
365 #if defined(TARGET_SDL)
366       /* second step: draw masked inverted character */
367       SDLCopyInverseMasked(src_bitmap, dst_bitmap, src_x, src_y,
368                            font_width, font_height, dst_x, dst_y);
369 #else
370       /* second step: draw masked black rectangle (use "space" character) */
371       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
372                     dst_x - src_x, dst_y - src_y);
373       BlitBitmapMasked(src_bitmap, dst_bitmap, 0, 0,
374                        font_width, font_height, dst_x, dst_y);
375 #endif
376     }
377     else if (mask_mode == BLIT_MASKED || mask_mode == BLIT_ON_BACKGROUND)
378     {
379       if (mask_mode == BLIT_ON_BACKGROUND)
380       {
381         /* clear font character background */
382         ClearRectangleOnBackground(dst_bitmap, dst_x, dst_y,
383                                    font_width, font_height);
384       }
385
386       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
387                     dst_x - src_x, dst_y - src_y);
388
389       BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y,
390                        font_width, font_height, dst_x, dst_y);
391     }
392     else        /* normal, non-masked font blitting */
393     {
394       BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y,
395                  font_width, font_height, dst_x, dst_y);
396     }
397
398     dst_x += font_width;
399   }
400 }
401
402
403 /* ========================================================================= */
404 /* text buffer drawing functions                                             */
405 /* ========================================================================= */
406
407 #define MAX_LINES_FROM_FILE             1024
408
409 #if 1
410
411 char *GetTextBufferFromFile(char *filename, int max_lines)
412 {
413   File *file;
414   char *buffer;
415   int num_lines = 0;
416
417   if (filename == NULL)
418     return NULL;
419
420   if (!(file = openFile(filename, MODE_READ)))
421     return NULL;
422
423   buffer = checked_calloc(1);   /* start with valid, but empty text buffer */
424
425   while (!checkEndOfFile(file) && num_lines < max_lines)
426   {
427     char line[MAX_LINE_LEN];
428
429     /* read next line of input file */
430     if (!getStringFromFile(file, line, MAX_LINE_LEN))
431       break;
432
433     buffer = checked_realloc(buffer, strlen(buffer) + strlen(line) + 1);
434
435     strcat(buffer, line);
436
437     num_lines++;
438   }
439
440   closeFile(file);
441
442   return buffer;
443 }
444
445 #else
446
447 char *GetTextBufferFromFile(char *filename, int max_lines)
448 {
449   FILE *file;
450   char *buffer;
451   int num_lines = 0;
452
453   if (filename == NULL)
454     return NULL;
455
456   if (!(file = fopen(filename, MODE_READ)))
457     return NULL;
458
459   buffer = checked_calloc(1);   /* start with valid, but empty text buffer */
460
461   while (!feof(file) && num_lines < max_lines)
462   {
463     char line[MAX_LINE_LEN];
464
465     /* read next line of input file */
466     if (!fgets(line, MAX_LINE_LEN, file))
467       break;
468
469     buffer = checked_realloc(buffer, strlen(buffer) + strlen(line) + 1);
470
471     strcat(buffer, line);
472
473     num_lines++;
474   }
475
476   fclose(file);
477
478   return buffer;
479 }
480
481 #endif
482
483 void DrawTextToTextArea_OLD(int x, int y, char *text, int font_nr, int line_length,
484                             int area_xsize, int area_ysize, int mask_mode)
485 {
486   int area_line = 0;
487   int font_height = getFontHeight(font_nr);
488
489   if (text == NULL)
490     return;
491
492   while (*text && area_line < area_ysize)
493   {
494     char buffer[MAX_OUTPUT_LINESIZE + 1];
495     int i;
496
497     for (i = 0; i < line_length && *text; i++)
498       if ((buffer[i] = *text++) == '\n')
499         break;
500     buffer[MIN(i, area_xsize)] = '\0';
501
502     DrawTextExt(drawto, x, y + area_line * font_height, buffer, font_nr,
503                 mask_mode);
504
505     area_line++;
506   }
507
508   redraw_mask |= REDRAW_FIELD;
509 }
510
511 static boolean RenderLineToBuffer(char **src_buffer_ptr, char *dst_buffer,
512                                   int *dst_buffer_len, int line_length,
513                                   boolean last_line_was_empty)
514 {
515   char *text_ptr = *src_buffer_ptr;
516   char *buffer = dst_buffer;
517   int buffer_len = *dst_buffer_len;
518   boolean buffer_filled = FALSE;
519
520   while (*text_ptr)
521   {
522     char *word_ptr;
523     int word_len;
524
525     /* skip leading whitespaces */
526     while (*text_ptr == ' ' || *text_ptr == '\t')
527       text_ptr++;
528
529     word_ptr = text_ptr;
530     word_len = 0;
531
532     /* look for end of next word */
533     while (*word_ptr != ' ' && *word_ptr != '\t' && *word_ptr != '\0')
534     {
535       word_ptr++;
536       word_len++;
537     }
538
539     if (word_len == 0)
540     {
541       continue;
542     }
543     else if (*text_ptr == '\n')         /* special case: force empty line */
544     {
545       if (buffer_len == 0)
546         text_ptr++;
547
548       /* prevent printing of multiple empty lines */
549       if (buffer_len > 0 || !last_line_was_empty)
550         buffer_filled = TRUE;
551     }
552     else if (word_len < line_length - buffer_len)
553     {
554       /* word fits into text buffer -- add word */
555
556       if (buffer_len > 0)
557         buffer[buffer_len++] = ' ';
558
559       strncpy(&buffer[buffer_len], text_ptr, word_len);
560       buffer_len += word_len;
561       buffer[buffer_len] = '\0';
562       text_ptr += word_len;
563     }
564     else if (buffer_len > 0)
565     {
566       /* not enough space left for word in text buffer -- print buffer */
567
568       buffer_filled = TRUE;
569     }
570     else
571     {
572       /* word does not fit at all into empty text buffer -- cut word */
573
574       strncpy(buffer, text_ptr, line_length);
575       buffer[line_length] = '\0';
576       text_ptr += line_length;
577       buffer_filled = TRUE;
578     }
579
580     if (buffer_filled)
581       break;
582   }
583
584   *src_buffer_ptr = text_ptr;
585   *dst_buffer_len = buffer_len;
586
587   return buffer_filled;
588 }
589
590 #if 0
591 void DrawTextWrapped_OLD(int x, int y, char *text, int font_nr, int line_length,
592                          int max_lines)
593 {
594   char *text_ptr = text;
595   int current_line = 0;
596   int font_height = getFontHeight(font_nr);
597
598   while (*text_ptr && current_line < max_lines)
599   {
600     char buffer[line_length + 1];
601     int buffer_len = 0;
602
603     buffer[0] = '\0';
604
605     RenderLineToBuffer(&text_ptr, buffer, &buffer_len, line_length, TRUE);
606
607     DrawText(x, y + current_line * font_height, buffer, font_nr);
608     current_line++;
609   }
610 }
611 #endif
612
613 #if 0
614 int DrawTextFromFile_OLD(int x, int y, char *filename, int font_nr,
615                          int line_length, int max_lines, boolean wrap_text)
616 {
617   int font_height = getFontHeight(font_nr);
618   char line[MAX_LINE_LEN];
619   char buffer[line_length + 1];
620   int buffer_len;
621   int current_line = 0;
622   FILE *file;
623
624   if (current_line >= max_lines)
625     return 0;
626
627   if (filename == NULL)
628     return 0;
629
630   if (!(file = fopen(filename, MODE_READ)))
631     return 0;
632
633   buffer[0] = '\0';
634   buffer_len = 0;
635
636   while (!feof(file) && current_line < max_lines)
637   {
638     char *line_ptr;
639     boolean last_line_was_empty = TRUE;
640
641     /* read next line of input file */
642     if (!fgets(line, MAX_LINE_LEN, file))
643       break;
644
645     /* skip comments (lines directly beginning with '#') */
646     if (line[0] == '#')
647       continue;
648
649     /* cut trailing newline from input line */
650     for (line_ptr = line; *line_ptr; line_ptr++)
651     {
652       if (*line_ptr == '\n' || *line_ptr == '\r')
653       {
654         *line_ptr = '\0';
655         break;
656       }
657     }
658
659     if (strlen(line) == 0)              /* special case: force empty line */
660       strcpy(line, "\n");
661
662     line_ptr = line;
663
664     while (*line_ptr && current_line < max_lines)
665     {
666 #if 1
667       boolean buffer_filled;
668
669       if (wrap_text)
670       {
671         buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len,
672                                            line_length, last_line_was_empty);
673       }
674       else
675       {
676         if (strlen(line_ptr) <= line_length)
677         {
678           buffer_len = strlen(line_ptr);
679           strcpy(buffer, line_ptr);
680         }
681         else
682         {
683           buffer_len = line_length;
684           strncpy(buffer, line_ptr, line_length);
685         }
686
687         buffer[buffer_len] = '\0';
688         line_ptr += buffer_len;
689
690         buffer_filled = TRUE;
691       }
692 #else
693       boolean buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len,
694                                                  line_length, last_line_was_empty);
695 #endif
696
697       if (buffer_filled)
698       {
699         DrawText(x, y + current_line * font_height, buffer, font_nr);
700         current_line++;
701
702         last_line_was_empty = (buffer_len == 0);
703
704         buffer[0] = '\0';
705         buffer_len = 0;
706       }
707     }
708   }
709
710   fclose(file);
711
712   if (buffer_len > 0 && current_line < max_lines)
713   {
714     DrawText(x, y + current_line * font_height, buffer, font_nr);
715     current_line++;
716   }
717
718   return current_line;
719 }
720 #endif
721
722 static boolean getCheckedTokenValueFromString(char *string, char **token,
723                                               char **value)
724 {
725   char *ptr;
726
727   if (!getTokenValueFromString(string, token, value))
728     return FALSE;
729
730   if (**token != '.')                   /* token should begin with dot */
731     return FALSE;
732
733   for (ptr = *token; *ptr; ptr++)       /* token should contain no whitespace */
734     if (*ptr == ' ' || *ptr == '\t')
735       return FALSE;
736
737   for (ptr = *value; *ptr; ptr++)       /* value should contain no whitespace */
738     if (*ptr == ' ' || *ptr == '\t')
739       return FALSE;
740
741   return TRUE;
742 }
743
744 static void DrawTextBuffer_Flush(int x, int y, char *buffer, int font_nr,
745                                  int line_length, int cut_length,
746                                  int line_spacing, int mask_mode,
747                                  boolean centered, int current_line)
748 {
749   int buffer_len = strlen(buffer);
750   int font_width = getFontWidth(font_nr);
751   int font_height = getFontHeight(font_nr);
752   int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0);
753   int offset_xsize =
754     (centered ? font_width * (line_length - buffer_len) / 2 : 0);
755   int final_cut_length = MAX(0, cut_length - offset_chars);
756   int xx = x + offset_xsize;
757   int yy = y + current_line * (font_height + line_spacing);
758
759   buffer[final_cut_length] = '\0';
760
761   if (mask_mode != -1)
762     DrawTextExt(drawto, xx, yy, buffer, font_nr, mask_mode);
763   else
764     DrawText(xx, yy, buffer, font_nr);
765 }
766
767 int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
768                    int line_length, int cut_length, int max_lines,
769                    int line_spacing, int mask_mode, boolean autowrap,
770                    boolean centered, boolean parse_comments)
771 {
772 #if 0
773   int font_width = getFontWidth(font_nr);
774   int font_height = getFontHeight(font_nr);
775 #endif
776   char buffer[line_length + 1];
777   int buffer_len;
778   int current_line = 0;
779
780   if (text_buffer == NULL || *text_buffer == '\0')
781     return 0;
782
783   if (current_line >= max_lines)
784     return 0;
785
786   if (cut_length == -1)
787     cut_length = line_length;
788
789   buffer[0] = '\0';
790   buffer_len = 0;
791
792   while (*text_buffer && current_line < max_lines)
793   {
794     char line[MAX_LINE_LEN + 1];
795     char *line_ptr;
796     boolean last_line_was_empty = TRUE;
797 #if 1
798     int num_line_chars = MAX_LINE_LEN;
799 #else
800     int num_line_chars = (autowrap ? MAX_LINE_LEN : line_length);
801 #endif
802     int i;
803
804     /* copy next line from text buffer to line buffer (nearly fgets() style) */
805     for (i = 0; i < num_line_chars && *text_buffer; i++)
806       if ((line[i] = *text_buffer++) == '\n')
807         break;
808     line[i] = '\0';
809
810     /* prevent 'num_line_chars' sized lines to cause additional empty line */
811     if (i == num_line_chars && *text_buffer == '\n')
812       text_buffer++;
813
814     /* skip comments (lines directly beginning with '#') */
815     if (line[0] == '#' && parse_comments)
816     {
817       char *token, *value;
818
819       /* try to read generic token/value pair definition after comment sign */
820       if (getCheckedTokenValueFromString(line + 1, &token, &value))
821       {
822         /* if found, flush the current buffer, if non-empty */
823         if (buffer_len > 0 && current_line < max_lines)
824         {
825           DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length,
826                                line_spacing, mask_mode, centered, current_line);
827
828           current_line++;
829
830           buffer[0] = '\0';
831           buffer_len = 0;
832         }
833
834         if (strEqual(token, ".font"))
835           font_nr = gfx.get_font_from_token_function(value);
836         else if (strEqual(token, ".autowrap"))
837           autowrap = get_boolean_from_string(value);
838         else if (strEqual(token, ".centered"))
839           centered = get_boolean_from_string(value);
840         else if (strEqual(token, ".parse_comments"))
841           parse_comments = get_boolean_from_string(value);
842       }
843
844       continue;
845     }
846
847     /* cut trailing newline and carriage return from input line */
848     for (line_ptr = line; *line_ptr; line_ptr++)
849     {
850       if (*line_ptr == '\n' || *line_ptr == '\r')
851       {
852         *line_ptr = '\0';
853         break;
854       }
855     }
856
857     if (strlen(line) == 0)              /* special case: force empty line */
858       strcpy(line, "\n");
859
860     line_ptr = line;
861
862     while (*line_ptr && current_line < max_lines)
863     {
864       boolean buffer_filled;
865
866       if (autowrap)
867       {
868         buffer_filled = RenderLineToBuffer(&line_ptr, buffer, &buffer_len,
869                                            line_length, last_line_was_empty);
870       }
871       else
872       {
873         if (strlen(line_ptr) <= line_length)
874         {
875           buffer_len = strlen(line_ptr);
876           strcpy(buffer, line_ptr);
877         }
878         else
879         {
880           buffer_len = line_length;
881           strncpy(buffer, line_ptr, line_length);
882         }
883
884         buffer[buffer_len] = '\0';
885         line_ptr += buffer_len;
886
887         buffer_filled = TRUE;
888       }
889
890       if (buffer_filled)
891       {
892 #if 1
893         DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length,
894                              line_spacing, mask_mode, centered, current_line);
895 #else
896         int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0);
897         int offset_xsize =
898           (centered ?  font_width * (line_length - buffer_len) / 2 : 0);
899         int final_cut_length = MAX(0, cut_length - offset_chars);
900         int xx = x + offset_xsize;
901
902         buffer[final_cut_length] = '\0';
903
904         if (mask_mode != -1)
905           DrawTextExt(drawto, xx, y + current_line * font_height, buffer,
906                       font_nr, mask_mode);
907         else
908           DrawText(xx, y + current_line * font_height, buffer, font_nr);
909 #endif
910
911         current_line++;
912
913         last_line_was_empty = (buffer_len == 0);
914
915         buffer[0] = '\0';
916         buffer_len = 0;
917       }
918     }
919   }
920
921   if (buffer_len > 0 && current_line < max_lines)
922   {
923 #if 1
924     DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length,
925                          line_spacing, mask_mode, centered, current_line);
926 #else
927     int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0);
928         int offset_xsize =
929           (centered ?  font_width * (line_length - buffer_len) / 2 : 0);
930     int final_cut_length = MAX(0, cut_length - offset_chars);
931     int xx = x + offset_xsize;
932
933     buffer[final_cut_length] = '\0';
934
935     if (mask_mode != -1)
936       DrawTextExt(drawto, xx, y + current_line * font_height, buffer,
937                   font_nr, mask_mode);
938     else
939       DrawText(xx, y + current_line * font_height, buffer, font_nr);
940 #endif
941
942     current_line++;
943   }
944
945   return current_line;
946 }
947
948 int DrawTextBufferVA(int x, int y, char *format, va_list ap, int font_nr,
949                      int line_length, int cut_length, int max_lines,
950                      int line_spacing, int mask_mode, boolean autowrap,
951                      boolean centered, boolean parse_comments)
952 {
953   char text_buffer[MAX_OUTPUT_LINESIZE];
954   int text_length = vsnprintf(text_buffer, MAX_OUTPUT_LINESIZE, format, ap);
955
956   if (text_length >= MAX_OUTPUT_LINESIZE)
957     Error(ERR_WARN, "string too long in DrawTextBufferVA() -- truncated");
958
959   int num_lines_printed = DrawTextBuffer(x, y, text_buffer, font_nr,
960                                          line_length, cut_length, max_lines,
961                                          line_spacing, mask_mode, autowrap,
962                                          centered, parse_comments);
963   return num_lines_printed;
964 }
965
966 int DrawTextFile(int x, int y, char *filename, int font_nr,
967                  int line_length, int cut_length, int max_lines,
968                  int line_spacing, int mask_mode, boolean autowrap,
969                  boolean centered, boolean parse_comments)
970 {
971   char *text_buffer = GetTextBufferFromFile(filename, MAX_LINES_FROM_FILE);
972   int num_lines_printed = DrawTextBuffer(x, y, text_buffer, font_nr,
973                                          line_length, cut_length, max_lines,
974                                          line_spacing, mask_mode, autowrap,
975                                          centered, parse_comments);
976   checked_free(text_buffer);
977
978   return num_lines_printed;
979 }
980
981 #if 0
982 void DrawTextWrapped(int x, int y, char *text, int font_nr, int line_length,
983                      int max_lines)
984 {
985   DrawTextBuffer(x, y, text, font_nr, line_length, -1, max_lines, -1, TRUE,
986                  FALSE, FALSE);
987 }
988
989 void DrawTextToTextArea(int x, int y, char *text, int font_nr, int line_length,
990                         int cut_length, int max_lines, int mask_mode)
991 {
992   DrawTextBuffer(x, y, text, font_nr, line_length, cut_length, max_lines,
993                  mask_mode, FALSE, FALSE, FALSE);
994 }
995 #endif