forgot more stuff
[supertux.git] / src / video / font.cpp
1 //  $Id: font.cpp 2298 2005-03-30 12:01:02Z matzebraun $
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 #include <config.h>
21
22 #include <cstdlib>
23 #include <cstring>
24 #include <stdexcept>
25
26 #include "app/globals.h"
27 #include "lisp/parser.h"
28 #include "lisp/lisp.h"
29 #include "screen.h"
30 #include "font.h"
31 #include "drawing_context.h"
32
33 using namespace SuperTux;
34
35 Font::Font(const std::string& file, FontType ntype, int nw, int nh,
36         int nshadowsize)
37     : chars(0), shadow_chars(0), type(ntype), w(nw), h(nh),
38       shadowsize(nshadowsize)
39 {
40   chars = new Surface(file, true);
41  
42   switch(type) {
43     case TEXT:
44       first_char = 32;
45       break;
46     case NUM:
47       first_char = 48;
48       break;
49   }
50   last_char = first_char + (chars->h / h) * 16;
51   if(last_char > 127) // we have left out some control chars at 128-159
52     last_char += 32;
53    
54   // Load shadow font.
55   if(shadowsize > 0) {
56     SDL_Surface* conv = SDL_DisplayFormatAlpha(chars->impl->get_sdl_surface());
57     int pixels = conv->w * conv->h;
58     SDL_LockSurface(conv);
59     for(int i = 0; i < pixels; ++i) {
60       Uint32 *p = (Uint32 *)conv->pixels + i;
61       *p = *p & conv->format->Amask;
62     }
63     SDL_UnlockSurface(conv);
64     SDL_SetAlpha(conv, SDL_SRCALPHA, 128);
65     shadow_chars = new Surface(conv, true);
66     SDL_FreeSurface(conv);
67   }
68 }
69
70 Font::~Font()
71 {
72   delete chars;
73   delete shadow_chars;
74 }
75
76 float
77 Font::get_text_width(const std::string& text) const
78 {
79   /** Let's calculate the size of the biggest paragraph */
80   std::string::size_type l, hl, ol;
81   hl = 0; l = 0;
82   while(true)
83     {
84     ol = l;
85     l = text.find("\n", l+1);
86     if(l == std::string::npos)
87       break;
88     if(hl < l-ol)
89       hl = l-ol;
90     }
91   if(hl == 0)
92     hl = text.size();
93
94   return hl * w;
95 }
96
97 float
98 Font::get_text_height(const std::string& text) const
99 {
100   /** Let's calculate height of the text */
101   std::string::size_type l, hh;
102   hh = h; l = 0;
103   while(true)
104     {
105     l = text.find("\n", l+1);
106     if(l == std::string::npos)
107       break;
108     hh += h + 2;
109     }
110
111   return hh;
112 }
113
114 float
115 Font::get_height() const
116 {
117   return h;
118 }
119
120 void
121 Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment,
122     uint32_t drawing_effect, uint8_t alpha) const
123 {
124   /* Cut lines changes into seperate strings, needed to support center/right text
125      alignments with break lines.
126      Feel free to replace this hack with a more elegant solution
127   */
128   char temp[1024];
129   std::string::size_type l, i, y;
130   bool done = false;
131   i = y = 0;
132
133   while(!done) {
134     l = text.find("\n", i);
135     if(l == std::string::npos) {
136       l = text.size();
137       done = true;
138     }
139     
140     temp[text.copy(temp, l - i, i)] = '\0';
141     
142     // calculate X positions based on the alignment type
143     Vector pos = Vector(pos_);
144     if(alignment == CENTER_ALLIGN)
145       pos.x -= get_text_width(temp) / 2;
146     else if(alignment == RIGHT_ALLIGN)
147       pos.x -= get_text_width(temp);
148
149     draw_text(temp, pos + Vector(0,y), drawing_effect, alpha);
150
151     i = l+1;
152     y += h + 2;
153   }
154 }
155
156 void
157 Font::draw_text(const std::string& text, const Vector& pos, 
158     uint32_t drawing_effect, uint8_t alpha) const
159 {
160   if(shadowsize > 0)
161     draw_chars(shadow_chars, text, pos + Vector(shadowsize, shadowsize),
162                drawing_effect, alpha);
163
164   draw_chars(chars, text, pos, drawing_effect, alpha);
165 }
166
167 void
168 Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
169                  uint32_t drawing_effect, uint8_t alpha) const
170 {
171   SurfaceImpl* impl = pchars->impl;
172
173   Vector p = pos;
174   for(size_t i = 0; i < text.size(); ++i) {
175     int c = (unsigned char) text[i];
176     if(c > 127) // correct for the 32 controlchars at 128-159
177       c -= 32;
178     // a non-printable character?
179     if(c == '\n') {
180       p.x = pos.x;
181       p.y += h + 2;
182       continue;
183     }
184     if(c == ' ' || c < first_char || c > last_char) {
185       p.x += w;
186       continue;
187     }
188     
189     int index = c - first_char;
190     int source_x = (index % 16) * w;
191     int source_y = (index / 16) * h;
192
193     impl->draw_part(source_x, source_y, p.x, p.y, w, h, alpha, drawing_effect);
194     p.x += w;
195   }
196 }