added comments
[supertux.git] / lib / video / 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 "app/globals.h"
25 #include "video/screen.h"
26 #include "video/font.h"
27 #include "video/drawing_context.h"
28 #include "utils/lispreader.h"
29
30 Font::Font(const std::string& file, FontType ntype, int nw, int nh,
31         int nshadowsize)
32     : chars(0), shadow_chars(0), type(ntype), w(nw), h(nh),
33       shadowsize(nshadowsize)
34 {
35   chars = new Surface(file, true);
36  
37   switch(type) {
38     case TEXT:
39       first_char = 32;
40       break;
41     case NUM:
42       first_char = 48;
43       break;
44   }
45   last_char = first_char + (chars->h / h) * 16;
46   if(last_char > 127) // we have left out some control chars at 128-159
47     last_char += 32;
48    
49   // Load shadow font.
50   if(shadowsize > 0) {
51     SDL_Surface* conv = SDL_DisplayFormatAlpha(chars->impl->get_sdl_surface());
52     int pixels = conv->w * conv->h;
53     SDL_LockSurface(conv);
54     for(int i = 0; i < pixels; ++i) {
55       Uint32 *p = (Uint32 *)conv->pixels + i;
56       *p = *p & conv->format->Amask;
57     }
58     SDL_UnlockSurface(conv);
59     SDL_SetAlpha(conv, SDL_SRCALPHA, 128);
60     shadow_chars = new Surface(conv, true);
61     SDL_FreeSurface(conv);
62   }
63 }
64
65 Font::~Font()
66 {
67   delete chars;
68   delete shadow_chars;
69 }
70
71 float
72 Font::get_height() const
73 {
74   return h;
75 }
76
77 float
78 Font::get_text_width(const std::string& text) const
79 {
80   return text.size() * w;
81 }
82
83 void
84 Font::draw(const std::string& text, const Vector& pos, Uint32 drawing_effect)
85 {
86   if(shadowsize > 0)
87     draw_chars(shadow_chars, text, pos + Vector(shadowsize, shadowsize),
88                drawing_effect);
89
90   draw_chars(chars, text, pos, drawing_effect);
91 }
92
93 void
94 Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
95                  Uint32 drawing_effect)
96 {
97   SurfaceImpl* impl = pchars->impl;
98
99   Vector p = pos;
100   for(size_t i = 0; i < text.size(); ++i)
101   {
102     int c = (unsigned char) text[i];
103     if(c > 127) // correct for the 32 controlchars at 128-159
104       c -= 32;
105     // a non-printable character?
106     if(c == '\n') {
107       p.x = pos.x;
108       p.y += h + 2;
109       continue;
110     }
111     if(c == ' ' || c < first_char || c > last_char) {
112       p.x += w;
113       continue;
114     }
115     
116     int index = c - first_char;
117     int source_x = (index % 16) * w;
118     int source_y = (index / 16) * h;
119
120     impl->draw_part(source_x, source_y, p.x, p.y, w, h, 255, drawing_effect);
121     p.x += w;
122   }
123 }
124
125 /* --- SCROLL TEXT FUNCTION --- */
126
127 #define MAX_VEL     10
128 #define SPEED_INC   0.01
129 #define SCROLL      60
130 #define ITEMS_SPACE 4
131
132 void display_text_file(const std::string& file, float scroll_speed)
133 {
134   std::string text;
135   std::vector<std::string> names;
136
137   LispReader* reader = LispReader::load(datadir + "/" + file, "supertux-text");
138
139   if(!reader)
140     {
141     std::cerr << "Error: Could not open text. Ignoring...\n";
142     return;
143     }
144
145   reader->read_string("text", text, true);
146   std::string background_file;
147   reader->read_string("background", background_file, true);
148   delete reader;
149
150   // Split text string lines into a vector
151   names.clear();
152   unsigned int i, l;
153   i = 0;
154   while(true)
155     {
156     l = text.find("\n", i);
157
158     if(l == std::string::npos)
159       {
160       char temp[1024];
161       temp[text.copy(temp, text.size() - i, i)] = '\0';
162       names.push_back(temp);
163       break;
164       }
165
166     char temp[1024];
167     temp[text.copy(temp, l-i, i)] = '\0';
168     names.push_back(temp);
169
170     i = l+1;
171     }
172
173   // load background image
174   Surface* background = new Surface(datadir + "/images/background/" + background_file, false);
175
176   int done = 0;
177   float scroll = 0;
178   float speed = scroll_speed / 50;
179
180   DrawingContext context;
181   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
182
183   Uint32 lastticks = SDL_GetTicks();
184   while(!done)
185     {
186       /* in case of input, exit */
187       SDL_Event event;
188       while(SDL_PollEvent(&event))
189         switch(event.type)
190           {
191           case SDL_KEYDOWN:
192             switch(event.key.keysym.sym)
193               {
194               case SDLK_UP:
195                 speed -= SPEED_INC;
196                 break;
197               case SDLK_DOWN:
198                 speed += SPEED_INC;
199                 break;
200               case SDLK_SPACE:
201               case SDLK_RETURN:
202                 if(speed >= 0)
203                   scroll += SCROLL;
204                 break;
205               case SDLK_ESCAPE:
206                 done = 1;
207                 break;
208               default:
209                 break;
210               }
211             break;
212           case SDL_QUIT:
213             done = 1;
214             break;
215           default:
216             break;
217           }
218
219       if(speed > MAX_VEL)
220         speed = MAX_VEL;
221       else if(speed < -MAX_VEL)
222         speed = -MAX_VEL;
223
224       /* draw the credits */
225       context.draw_surface(background, Vector(0,0), 0);
226
227       float y = 0;
228       for(size_t i = 0; i < names.size(); i++) {
229         if(names[i].size() == 0) {
230           y += white_text->get_height() + ITEMS_SPACE;
231           continue;
232         }
233
234         Font* font = 0;
235         switch(names[i][0])
236         {
237           case ' ': font = white_small_text; break;
238           case '\t': font = white_text; break;
239           case '-': font = white_big_text; break;
240           case '*': font = blue_text; break;
241           default: font = blue_text; break;
242         }
243
244         context.draw_text_center(font,
245             names[i].substr(1, names[i].size()-1),
246             Vector(0, screen->h + y - scroll), LAYER_FOREGROUND1);
247         y += font->get_height() + ITEMS_SPACE;
248       }
249
250       context.do_drawing();
251
252       if(screen->h+y-scroll < 0 && 20+screen->h+y-scroll < 0)
253         done = 1;
254
255       Uint32 ticks = SDL_GetTicks();
256       scroll += speed * (ticks - lastticks);
257       lastticks = ticks;
258       if(scroll < 0)
259         scroll = 0;
260
261       SDL_Delay(10);
262     }
263
264   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
265   delete background;
266 }
267