1 /**
2 * Copyright (c) 2006-2011 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty.  In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 *    claim that you wrote the original software. If you use this software
14 *    in a product, an acknowledgment in the product documentation would be
15 *    appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 *    misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20 
21 #include "Image.h"
22 
23 // STD
24 #include <cstring> // For memcpy
25 
26 namespace love
27 {
28 namespace graphics
29 {
30 namespace opengl
31 {
32 
Image(love::image::ImageData * data)33 	Image::Image(love::image::ImageData * data)
34 		: width((float)(data->getWidth())), height((float)(data->getHeight())), texture(0)
35 	{
36 		data->retain();
37 		this->data = data;
38 
39 		memset(vertices, 255, sizeof(vertex)*4);
40 
41 		vertices[0].x = 0; vertices[0].y = 0;
42 		vertices[1].x = 0; vertices[1].y = height;
43 		vertices[2].x = width; vertices[2].y = height;
44 		vertices[3].x = width; vertices[3].y = 0;
45 
46 		vertices[0].s = 0; vertices[0].t = 0;
47 		vertices[1].s = 0; vertices[1].t = 1;
48 		vertices[2].s = 1; vertices[2].t = 1;
49 		vertices[3].s = 1; vertices[3].t = 0;
50 
51 	}
52 
~Image()53 	Image::~Image()
54 	{
55 		if(data != 0)
56 			data->release();
57 		unload();
58 	}
59 
getWidth() const60 	float Image::getWidth() const
61 	{
62 		return width;
63 	}
64 
getHeight() const65 	float Image::getHeight() const
66 	{
67 		return height;
68 	}
69 
getVertices() const70 	const vertex * Image::getVertices() const
71 	{
72 		return vertices;
73 	}
74 
getData() const75 	love::image::ImageData * Image::getData() const
76 	{
77 		return data;
78 	}
79 
getRectangleVertices(int x,int y,int w,int h,vertex * vertices) const80 	void Image::getRectangleVertices(int x, int y, int w, int h, vertex * vertices) const
81 	{
82 		// Check upper.
83 		x = (x+w > (int)width) ? (int)width-w : x;
84 		y = (y+h > (int)height) ? (int)height-h : y;
85 
86 		// Check lower.
87 		x = (x < 0) ? 0 : x;
88 		y = (y < 0) ? 0 : y;
89 
90 		vertices[0].x = 0; vertices[0].y = 0;
91 		vertices[1].x = 0; vertices[1].y = (float)h;
92 		vertices[2].x = (float)w; vertices[2].y = (float)h;
93 		vertices[3].x = (float)w; vertices[3].y = 0;
94 
95 		float tx = (float)x/width;
96 		float ty = (float)y/height;
97 		float tw = (float)w/width;
98 		float th = (float)h/height;
99 
100 		vertices[0].s = tx; vertices[0].t = ty;
101 		vertices[1].s = tx; vertices[1].t = ty+th;
102 		vertices[2].s = tx+tw; vertices[2].t = ty+th;
103 		vertices[3].s = tx+tw; vertices[3].t = ty;
104 	}
105 
draw(float x,float y,float angle,float sx,float sy,float ox,float oy) const106 	void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy) const
107 	{
108 		static Matrix t;
109 
110 		t.setTransformation(x, y, angle, sx, sy, ox, oy);
111 		drawv(t, vertices);
112 	}
113 
drawq(Quad * quad,float x,float y,float angle,float sx,float sy,float ox,float oy) const114 	void Image::drawq(Quad * quad, float x, float y, float angle, float sx, float sy, float ox, float oy) const
115 	{
116 		static Matrix t;
117 		const vertex * v = quad->getVertices();
118 
119 		t.setTransformation(x, y, angle, sx, sy, ox, oy);
120 		drawv(t, v);
121 	}
122 
setFilter(Image::Filter f)123 	void Image::setFilter(Image::Filter f)
124 	{
125 		GLint gmin, gmag;
126 		gmin = gmag = 0; // so that they're not used uninitialized
127 
128 		switch(f.min)
129 		{
130 		case FILTER_LINEAR:
131 			gmin = GL_LINEAR;
132 			break;
133 		case FILTER_NEAREST:
134 			gmin = GL_NEAREST;
135 			break;
136 		default:
137 			break;
138 		}
139 
140 		switch(f.mag)
141 		{
142 		case FILTER_LINEAR:
143 			gmag = GL_LINEAR;
144 			break;
145 		case FILTER_NEAREST:
146 			gmag = GL_NEAREST;
147 			break;
148 		default:
149 			break;
150 		}
151 
152 		bind();
153 
154 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
155 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
156 	}
157 
getFilter() const158 	Image::Filter Image::getFilter() const
159 	{
160 		bind();
161 
162 		GLint gmin, gmag;
163 
164 		glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin);
165 		glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag);
166 
167 		Image::Filter f;
168 
169 		switch(gmin)
170 		{
171 		case GL_NEAREST:
172 			f.min = FILTER_NEAREST;
173 			break;
174 		case GL_LINEAR:
175 		default:
176 			f.min = FILTER_LINEAR;
177 			break;
178 		}
179 
180 		switch(gmin)
181 		{
182 		case GL_NEAREST:
183 			f.mag = FILTER_NEAREST;
184 			break;
185 		case GL_LINEAR:
186 		default:
187 			f.mag = FILTER_LINEAR;
188 			break;
189 		}
190 
191 		return f;
192 	}
193 
setWrap(Image::Wrap w)194 	void Image::setWrap(Image::Wrap w)
195 	{
196 		GLint gs, gt;
197 
198 		switch(w.s)
199 		{
200 		case WRAP_CLAMP:
201 			gs = GL_CLAMP_TO_EDGE;
202 			break;
203 		case WRAP_REPEAT:
204 		default:
205 			gs = GL_REPEAT;
206 			break;
207 		}
208 
209 		switch(w.t)
210 		{
211 		case WRAP_CLAMP:
212 			gt = GL_CLAMP_TO_EDGE;
213 			break;
214 		case WRAP_REPEAT:
215 		default:
216 			gt = GL_REPEAT;
217 			break;
218 		}
219 
220 		bind();
221 
222 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs);
223 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt);
224 	}
225 
getWrap() const226 	Image::Wrap Image::getWrap() const
227 	{
228 		bind();
229 
230 		GLint gs, gt;
231 
232 		glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs);
233 		glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &gt);
234 
235 		Wrap w;
236 
237 		switch(gs)
238 		{
239 		case GL_CLAMP_TO_EDGE:
240 			w.s = WRAP_CLAMP;
241 			break;
242 		case GL_REPEAT:
243 		default:
244 			w.s = WRAP_REPEAT;
245 			break;
246 		}
247 
248 		switch(gt)
249 		{
250 		case GL_CLAMP_TO_EDGE:
251 			w.t = WRAP_CLAMP;
252 			break;
253 		case GL_REPEAT:
254 		default:
255 			w.t = WRAP_REPEAT;
256 			break;
257 		}
258 
259 		return w;
260 	}
261 
bind() const262 	void Image::bind() const
263 	{
264 		if(texture != 0)
265 			glBindTexture(GL_TEXTURE_2D,texture);
266 	}
267 
load()268 	bool Image::load()
269 	{
270 		return loadVolatile();
271 	}
272 
unload()273 	void Image::unload()
274 	{
275 		return unloadVolatile();
276 	}
277 
loadVolatile()278 	bool Image::loadVolatile()
279 	{
280 		glGenTextures(1,(GLuint*)&texture);
281 		glBindTexture(GL_TEXTURE_2D, texture);
282 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
283 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
284 
285 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
286 		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
287 
288 		glTexImage2D(GL_TEXTURE_2D,
289 			0,
290 			GL_RGBA8,
291 			(GLsizei)width,
292 			(GLsizei)height,
293 			0,
294 			GL_RGBA,
295 			GL_UNSIGNED_BYTE,
296 			data->getData());
297 
298 		setFilter(settings.filter);
299 		setWrap(settings.wrap);
300 
301 		return true;
302 	}
303 
unloadVolatile()304 	void Image::unloadVolatile()
305 	{
306 		settings.filter = getFilter();
307 		settings.wrap = getWrap();
308 		// Delete the hardware texture.
309 		if(texture != 0)
310 		{
311 			glDeleteTextures(1, (GLuint*)&texture);
312 			texture = 0;
313 		}
314 	}
315 
drawv(const Matrix & t,const vertex * v) const316 	void Image::drawv(const Matrix & t, const vertex * v) const
317 	{
318 		bind();
319 
320 		glPushMatrix();
321 
322 		glMultMatrixf((const GLfloat*)t.getElements());
323 
324 		glEnableClientState(GL_VERTEX_ARRAY);
325 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
326 		glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&v[0].x);
327 		glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&v[0].s);
328 		glDrawArrays(GL_QUADS, 0, 4);
329 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
330 		glDisableClientState(GL_VERTEX_ARRAY);
331 
332 		glPopMatrix();
333 	}
334 
335 } // opengl
336 } // graphics
337 } // love
338