2 more evil mainloops are gone
[supertux.git] / src / video / surface.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.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  02111-1307, USA.
19
20 #include <config.h>
21
22 #include <cassert>
23 #include <iostream>
24 #include <algorithm>
25 #include <stdexcept>
26 #include <sstream>
27 #include <math.h>
28
29 #include <SDL.h>
30 #include <SDL_image.h>
31
32 #include "gameconfig.hpp"
33 #include "physfs/physfs_sdl.hpp"
34 #include "video/surface.hpp"
35 #include "image_texture.hpp"
36 #include "texture_manager.hpp"
37
38 Surface::Surface(const std::string& file)
39 {
40   texture = texture_manager->get(file);
41   texture->ref();
42   uv_left = 0;
43   uv_top = 0;
44   uv_right = texture->get_uv_right();
45   uv_bottom = texture->get_uv_bottom();
46
47   width = texture->get_image_width();
48   height = texture->get_image_height();
49 }
50
51 Surface::Surface(const std::string& file, int x, int y, int w, int h)
52 {
53   texture = texture_manager->get(file);
54   texture->ref();
55
56   float tex_w = static_cast<float> (texture->get_width());
57   float tex_h = static_cast<float> (texture->get_height());
58   uv_left = static_cast<float>(x) / tex_w;
59   uv_top = static_cast<float>(y) / tex_h;
60   uv_right = static_cast<float>(x+w) / tex_w;
61   uv_bottom = static_cast<float>(y+h) / tex_h;
62
63   width = w;
64   height = h;
65 }
66
67 Surface::Surface(const Surface& other)
68 {
69   texture = other.texture;
70   texture->ref();
71
72   uv_left = other.uv_left;
73   uv_top = other.uv_top;
74   uv_right = other.uv_right;
75   uv_bottom = other.uv_bottom;
76   width = other.width;
77   height = other.height;
78 }
79
80 const Surface&
81 Surface::operator= (const Surface& other)
82 {
83   other.texture->ref();
84   texture->unref();
85   texture = other.texture;
86
87   uv_left = other.uv_left;
88   uv_top = other.uv_top;
89   uv_right = other.uv_right;
90   uv_bottom = other.uv_bottom;
91   width = other.width;
92   height = other.height;
93
94   return *this;
95 }
96
97 Surface::~Surface()
98 {
99   texture->unref();
100 }
101
102 void
103 Surface::hflip()
104 {
105   std::swap(uv_left, uv_right);
106 }
107
108 static inline void intern_draw(float left, float top, float right, float bottom,                               float uv_left, float uv_top,
109                                float uv_right, float uv_bottom,
110                                DrawingEffect effect)
111 {
112   if(effect & HORIZONTAL_FLIP)
113     std::swap(uv_left, uv_right);
114   if(effect & VERTICAL_FLIP) {
115     std::swap(uv_top, uv_bottom);
116   }
117   
118   glBegin(GL_QUADS);
119   glTexCoord2f(uv_left, uv_top);
120   glVertex2f(left, top);
121   
122   glTexCoord2f(uv_right, uv_top);
123   glVertex2f(right, top);
124
125   glTexCoord2f(uv_right, uv_bottom);
126   glVertex2f(right, bottom);
127
128   glTexCoord2f(uv_left, uv_bottom);
129   glVertex2f(left, bottom);
130   glEnd();
131 }
132
133 void
134 Surface::draw(float x, float y, float alpha, DrawingEffect effect) const
135 {
136   glColor4f(1.0f, 1.0f, 1.0f, alpha);
137   glBindTexture(GL_TEXTURE_2D, texture->get_handle());
138
139   intern_draw(x, y,
140               x + width, y + height,
141               uv_left, uv_top, uv_right, uv_bottom, effect);
142 }
143
144 void
145 Surface::draw_part(float src_x, float src_y, float dst_x, float dst_y,
146                    float width, float height, float alpha,
147                    DrawingEffect effect) const
148 {
149   float uv_width = uv_right - uv_left;
150   float uv_height = uv_bottom - uv_top;
151   
152   float uv_left = this->uv_left + (uv_width * src_x) / this->width;
153   float uv_top = this->uv_top + (uv_height * src_y) / this->height;
154   float uv_right = this->uv_left + (uv_width * (src_x + width)) / this->width;
155   float uv_bottom = this->uv_top + (uv_height * (src_y + height)) / this->height;
156   
157   glColor4f(1.0f, 1.0f, 1.0f, alpha);
158   glBindTexture(GL_TEXTURE_2D, texture->get_handle());  
159   
160   intern_draw(dst_x, dst_y,
161               dst_x + width, dst_y + height,
162               uv_left, uv_top, uv_right, uv_bottom, effect);
163 }
164