Added support for data files internationalization by a simple 3 lines code in lisprea...
[supertux.git] / src / screen / font.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 // 
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include <cstdlib>
22 #include <cstring>
23
24 #include "globals.h"
25 #include "defines.h"
26 #include "screen.h"
27 #include "font.h"
28 #include "drawing_context.h"
29 #include "../lispreader.h"
30
31 Font::Font(const std::string& file, FontType ntype, int nw, int nh,
32         int nshadowsize)
33     : chars(0), shadow_chars(0), type(ntype), w(nw), h(nh),
34       shadowsize(nshadowsize)
35 {
36   chars = new Surface(file, USE_ALPHA);
37  
38   switch(type) {
39     case TEXT:
40       first_char = 32;
41       break;
42     case NUM:
43       first_char = 48;
44       break;
45   }
46   last_char = first_char + (chars->h / h) * 16;
47   if(last_char > 127) // we have left out some control chars at 128-159
48     last_char += 32;
49    
50   // Load shadow font.
51   if(shadowsize > 0) {
52     SDL_Surface* conv = SDL_DisplayFormatAlpha(chars->impl->get_sdl_surface());
53     int pixels = conv->w * conv->h;
54     SDL_LockSurface(conv);
55     for(int i = 0; i < pixels; ++i) {
56       Uint32 *p = (Uint32 *)conv->pixels + i;
57       *p = *p & conv->format->Amask;
58     }
59     SDL_UnlockSurface(conv);
60     SDL_SetAlpha(conv, SDL_SRCALPHA, 128);
61     shadow_chars = new Surface(conv, USE_ALPHA);
62     SDL_FreeSurface(conv);
63   }
64 }
65
66 Font::~Font()
67 {
68   delete chars;
69   delete shadow_chars;
70 }
71
72 float
73 Font::get_height() const
74 {
75   return h;
76 }
77
78 float
79 Font::get_text_width(const std::string& text) const
80 {
81   return text.size() * w;
82 }
83
84 void
85 Font::draw(const std::string& text, const Vector& pos, Uint32 drawing_effect)
86 {
87   if(shadowsize > 0)
88     draw_chars(shadow_chars, text, pos + Vector(shadowsize, shadowsize),
89                drawing_effect);
90
91   draw_chars(chars, text, pos, drawing_effect);
92 }
93
94 void
95 Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
96                  Uint32 drawing_effect)
97 {
98   SurfaceImpl* impl = pchars->impl;
99
100   Vector p = pos;
101   for(size_t i = 0; i < text.size(); ++i)
102   {
103     int c = (unsigned char) text[i];
104     if(c > 127) // correct for the 32 controlchars at 128-159
105       c -= 32;
106     // a non-printable character?
107     if(c == '\n') {
108       p.x = pos.x;
109       p.y += h + 2;
110       continue;
111     }
112     if(c == ' ' || c < first_char || c > last_char) {
113       p.x += w;
114       continue;
115     }
116     
117     int index = c - first_char;
118     int source_x = (index % 16) * w;
119     int source_y = (index / 16) * h;
120
121     impl->draw_part(source_x, source_y, p.x, p.y, w, h, 255, drawing_effect);
122     p.x += w;
123   }
124 }
125
126 /* --- SCROLL TEXT FUNCTION --- */
127
128 #define MAX_VEL     10
129 #define SPEED_INC   0.01
130 #define SCROLL      60
131 #define ITEMS_SPACE 4
132
133 void display_text_file(const std::string& file, const std::string& surface, float scroll_speed)
134 {
135   Surface* sur = new Surface(datadir + surface, IGNORE_ALPHA);
136   display_text_file(file, sur, scroll_speed);
137   delete sur;
138 }
139
140 void display_text_file(const std::string& file, Surface* surface, float scroll_speed)
141 {
142   std::string text;
143   std::vector<std::string> names;
144   
145   lisp_object_t* root_obj = lisp_read_from_file(datadir + file);
146   lisp_object_t* cur = lisp_car(root_obj);
147
148   if (lisp_symbol_p(cur) && strcmp(lisp_symbol(cur), "text") == 0)
149     {
150       LispReader reader(lisp_cdr(root_obj));
151       reader.read_string("text", text);
152     }
153   else
154     {
155       std::cerr << "Error: Could not open text. Ignoring...\n";
156       return;
157     }
158
159   unsigned int l, i;
160   l = 0;
161   while(true)
162     {
163     i = l;
164     l = text.find("\n", i);
165     if(l != std::string::npos)
166       break;
167
168     char* temp = 0;
169     text.copy(temp, l, i);
170     names.push_back(temp);
171     }
172
173   int done = 0;
174   float scroll = 0;
175   float speed = scroll_speed / 50;
176
177   DrawingContext context;
178   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
179
180   Uint32 lastticks = SDL_GetTicks();
181   while(!done)
182     {
183       /* in case of input, exit */
184       SDL_Event event;
185       while(SDL_PollEvent(&event))
186         switch(event.type)
187           {
188           case SDL_KEYDOWN:
189             switch(event.key.keysym.sym)
190               {
191               case SDLK_UP:
192                 speed -= SPEED_INC;
193                 break;
194               case SDLK_DOWN:
195                 speed += SPEED_INC;
196                 break;
197               case SDLK_SPACE:
198               case SDLK_RETURN:
199                 if(speed >= 0)
200                   scroll += SCROLL;
201                 break;
202               case SDLK_ESCAPE:
203                 done = 1;
204                 break;
205               default:
206                 break;
207               }
208             break;
209           case SDL_QUIT:
210             done = 1;
211             break;
212           default:
213             break;
214           }
215
216       if(speed > MAX_VEL)
217         speed = MAX_VEL;
218       else if(speed < -MAX_VEL)
219         speed = -MAX_VEL;
220
221       /* draw the credits */
222       context.draw_surface(surface, Vector(0,0), 0);
223
224       float y = 0;
225       for(size_t i = 0; i < names.size(); i++) {
226         if(names[i].size() == 0) {
227           y += white_text->get_height() + ITEMS_SPACE;
228           continue;
229         }
230
231         Font* font = 0;
232         switch(names[i][0])
233         {
234           case ' ': font = white_small_text; break;
235           case '\t': font = white_text; break;
236           case '-': font = white_big_text; break;
237           case '*': font = blue_text; break;
238           default: font = blue_text; break;
239         }
240
241         context.draw_text_center(font,
242             names[i].substr(1, names[i].size()-1),
243             Vector(0, screen->h + y - scroll), LAYER_FOREGROUND1);
244         y += font->get_height() + ITEMS_SPACE;
245       }
246
247       context.do_drawing();
248
249       if(screen->h+y-scroll < 0 && 20+screen->h+y-scroll < 0)
250         done = 1;
251
252       Uint32 ticks = SDL_GetTicks();
253       scroll += speed * (ticks - lastticks);
254       lastticks = ticks;
255       if(scroll < 0)
256         scroll = 0;
257
258       SDL_Delay(10);
259     }
260
261   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
262   Menu::set_current(main_menu);
263 }
264