1 /** 2 * Copyright (c) 2006-2012 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 #include <iostream> 27 using namespace std; 28 29 namespace love 30 { 31 namespace graphics 32 { 33 namespace opengl 34 { Image(love::image::ImageData * data)35 Image::Image(love::image::ImageData * data) 36 : width((float)(data->getWidth())), height((float)(data->getHeight())), texture(0) 37 { 38 data->retain(); 39 this->data = data; 40 41 memset(vertices, 255, sizeof(vertex)*4); 42 43 vertices[0].x = 0; vertices[0].y = 0; 44 vertices[1].x = 0; vertices[1].y = height; 45 vertices[2].x = width; vertices[2].y = height; 46 vertices[3].x = width; vertices[3].y = 0; 47 48 vertices[0].s = 0; vertices[0].t = 0; 49 vertices[1].s = 0; vertices[1].t = 1; 50 vertices[2].s = 1; vertices[2].t = 1; 51 vertices[3].s = 1; vertices[3].t = 0; 52 } 53 ~Image()54 Image::~Image() 55 { 56 if (data != 0) 57 data->release(); 58 unload(); 59 } 60 getWidth() const61 float Image::getWidth() const 62 { 63 return width; 64 } 65 getHeight() const66 float Image::getHeight() const 67 { 68 return height; 69 } 70 getVertices() const71 const vertex * Image::getVertices() const 72 { 73 return vertices; 74 } 75 getData() const76 love::image::ImageData * Image::getData() const 77 { 78 return data; 79 } 80 getRectangleVertices(int x,int y,int w,int h,vertex * vertices) const81 void Image::getRectangleVertices(int x, int y, int w, int h, vertex * vertices) const 82 { 83 // Check upper. 84 x = (x+w > (int)width) ? (int)width-w : x; 85 y = (y+h > (int)height) ? (int)height-h : y; 86 87 // Check lower. 88 x = (x < 0) ? 0 : x; 89 y = (y < 0) ? 0 : y; 90 91 vertices[0].x = 0; vertices[0].y = 0; 92 vertices[1].x = 0; vertices[1].y = (float)h; 93 vertices[2].x = (float)w; vertices[2].y = (float)h; 94 vertices[3].x = (float)w; vertices[3].y = 0; 95 96 float tx = (float)x/width; 97 float ty = (float)y/height; 98 float tw = (float)w/width; 99 float th = (float)h/height; 100 101 vertices[0].s = tx; vertices[0].t = ty; 102 vertices[1].s = tx; vertices[1].t = ty+th; 103 vertices[2].s = tx+tw; vertices[2].t = ty+th; 104 vertices[3].s = tx+tw; vertices[3].t = ty; 105 } 106 draw(float x,float y,float angle,float sx,float sy,float ox,float oy,float kx,float ky) const107 void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const 108 { 109 static Matrix t; 110 111 t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); 112 drawv(t, vertices); 113 } 114 drawq(love::graphics::Quad * quad,float x,float y,float angle,float sx,float sy,float ox,float oy,float kx,float ky) const115 void Image::drawq(love::graphics::Quad * quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const 116 { 117 static Matrix t; 118 const vertex * v = quad->getVertices(); 119 120 t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); 121 drawv(t, v); 122 } 123 setFilter(const Image::Filter & f)124 void Image::setFilter(const Image::Filter& f) 125 { 126 GLint gmin, gmag; 127 gmin = gmag = 0; // so that they're not used uninitialized 128 129 switch(f.min) 130 { 131 case FILTER_LINEAR: 132 gmin = GL_LINEAR; 133 break; 134 case FILTER_NEAREST: 135 gmin = GL_NEAREST; 136 break; 137 default: 138 break; 139 } 140 141 switch(f.mag) 142 { 143 case FILTER_LINEAR: 144 gmag = GL_LINEAR; 145 break; 146 case FILTER_NEAREST: 147 gmag = GL_NEAREST; 148 break; 149 default: 150 break; 151 } 152 153 bind(); 154 155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); 156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); 157 } 158 getFilter() const159 Image::Filter Image::getFilter() const 160 { 161 bind(); 162 163 GLint gmin, gmag; 164 165 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin); 166 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag); 167 168 Image::Filter f; 169 170 switch(gmin) 171 { 172 case GL_NEAREST: 173 f.min = FILTER_NEAREST; 174 break; 175 case GL_LINEAR: 176 default: 177 f.min = FILTER_LINEAR; 178 break; 179 } 180 181 switch(gmin) 182 { 183 case GL_NEAREST: 184 f.mag = FILTER_NEAREST; 185 break; 186 case GL_LINEAR: 187 default: 188 f.mag = FILTER_LINEAR; 189 break; 190 } 191 192 return f; 193 } 194 setWrap(Image::Wrap w)195 void Image::setWrap(Image::Wrap w) 196 { 197 GLint gs, gt; 198 199 switch(w.s) 200 { 201 case WRAP_CLAMP: 202 gs = GL_CLAMP_TO_EDGE; 203 break; 204 case WRAP_REPEAT: 205 default: 206 gs = GL_REPEAT; 207 break; 208 } 209 210 switch(w.t) 211 { 212 case WRAP_CLAMP: 213 gt = GL_CLAMP_TO_EDGE; 214 break; 215 case WRAP_REPEAT: 216 default: 217 gt = GL_REPEAT; 218 break; 219 } 220 221 bind(); 222 223 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs); 224 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt); 225 } 226 getWrap() const227 Image::Wrap Image::getWrap() const 228 { 229 bind(); 230 231 GLint gs, gt; 232 233 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs); 234 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, >); 235 236 Wrap w; 237 238 switch(gs) 239 { 240 case GL_CLAMP_TO_EDGE: 241 w.s = WRAP_CLAMP; 242 break; 243 case GL_REPEAT: 244 default: 245 w.s = WRAP_REPEAT; 246 break; 247 } 248 249 switch(gt) 250 { 251 case GL_CLAMP_TO_EDGE: 252 w.t = WRAP_CLAMP; 253 break; 254 case GL_REPEAT: 255 default: 256 w.t = WRAP_REPEAT; 257 break; 258 } 259 260 return w; 261 } 262 bind() const263 void Image::bind() const 264 { 265 if (texture == 0) 266 return; 267 268 bindTexture(texture); 269 } 270 load()271 bool Image::load() 272 { 273 return loadVolatile(); 274 } 275 unload()276 void Image::unload() 277 { 278 return unloadVolatile(); 279 } 280 loadVolatile()281 bool Image::loadVolatile() 282 { 283 if (hasNpot()) 284 return loadVolatileNPOT(); 285 else 286 return loadVolatilePOT(); 287 } 288 loadVolatilePOT()289 bool Image::loadVolatilePOT() 290 { 291 glGenTextures(1,(GLuint*)&texture); 292 bindTexture(texture); 293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 295 296 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 297 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 298 299 float p2width = next_p2(width); 300 float p2height = next_p2(height); 301 float s = width/p2width; 302 float t = height/p2height; 303 304 vertices[1].t = t; 305 vertices[2].t = t; 306 vertices[2].s = s; 307 vertices[3].s = s; 308 309 glTexImage2D(GL_TEXTURE_2D, 310 0, 311 GL_RGBA8, 312 (GLsizei)p2width, 313 (GLsizei)p2height, 314 0, 315 GL_RGBA, 316 GL_UNSIGNED_BYTE, 317 0); 318 319 glTexSubImage2D(GL_TEXTURE_2D, 320 0, 321 0, 322 0, 323 (GLsizei)width, 324 (GLsizei)height, 325 GL_RGBA, 326 GL_UNSIGNED_BYTE, 327 data->getData()); 328 329 setFilter(settings.filter); 330 setWrap(settings.wrap); 331 332 return true; 333 } 334 loadVolatileNPOT()335 bool Image::loadVolatileNPOT() 336 { 337 glGenTextures(1,(GLuint*)&texture); 338 bindTexture(texture); 339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 341 342 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 343 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 344 345 glTexImage2D(GL_TEXTURE_2D, 346 0, 347 GL_RGBA8, 348 (GLsizei)width, 349 (GLsizei)height, 350 0, 351 GL_RGBA, 352 GL_UNSIGNED_BYTE, 353 data->getData()); 354 355 setFilter(settings.filter); 356 setWrap(settings.wrap); 357 358 return true; 359 } 360 unloadVolatile()361 void Image::unloadVolatile() 362 { 363 settings.filter = getFilter(); 364 settings.wrap = getWrap(); 365 // Delete the hardware texture. 366 if (texture != 0) 367 { 368 deleteTexture(texture); 369 texture = 0; 370 } 371 } 372 drawv(const Matrix & t,const vertex * v) const373 void Image::drawv(const Matrix & t, const vertex * v) const 374 { 375 bind(); 376 377 glPushMatrix(); 378 379 glMultMatrixf((const GLfloat*)t.getElements()); 380 381 glEnableClientState(GL_VERTEX_ARRAY); 382 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 383 glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&v[0].x); 384 glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid*)&v[0].s); 385 glDrawArrays(GL_QUADS, 0, 4); 386 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 387 glDisableClientState(GL_VERTEX_ARRAY); 388 389 glPopMatrix(); 390 } 391 hasNpot()392 bool Image::hasNpot() 393 { 394 return GLEE_ARB_texture_non_power_of_two != 0; 395 } 396 397 } // opengl 398 } // graphics 399 } // love 400