diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index dce347c82..1a1472e21 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -45,6 +45,7 @@ Image::Image(love::image::ImageData *data) , mipmapSharpness(defaultMipmapSharpness) , mipmapsCreated(false) , compressed(false) + , usingDefaultTexture(false) { data->retain(); preload(); @@ -59,6 +60,7 @@ Image::Image(love::image::CompressedData *cdata) , mipmapSharpness(defaultMipmapSharpness) , mipmapsCreated(false) , compressed(true) + , usingDefaultTexture(false) { cdata->retain(); preload(); @@ -246,7 +248,7 @@ void Image::createMipmaps() void Image::checkMipmapsCreated() { - if (mipmapsCreated || filter.mipmap == FILTER_NONE) + if (mipmapsCreated || filter.mipmap == FILTER_NONE || usingDefaultTexture) return; if (isCompressed() && cdata && hasCompressedTextureSupport(cdata->getType())) @@ -263,8 +265,15 @@ void Image::setFilter(const Image::Filter &f) { filter = f; + // We don't want filtering or (attempted) mipmaps on the default texture. + if (usingDefaultTexture) + { + filter.mipmap = FILTER_NONE; + filter.min = filter.mag = FILTER_NEAREST; + } + bind(); - filter.anisotropy = gl.setTextureFilter(f); + filter.anisotropy = gl.setTextureFilter(filter); checkMipmapsCreated(); } @@ -353,18 +362,6 @@ void Image::unload() bool Image::loadVolatile() { - // glTexImage2D is guaranteed to throw an error in this case. - if (width > gl.getMaxTextureSize()) - { - throw love::Exception("Cannot create image: " - "width of %d pixels is too large for this system.", (int) width); - } - else if (height > gl.getMaxTextureSize()) - { - throw love::Exception("Cannot create image:" - "height of %d pixels is too large for this system.", (int) height); - } - if (isCompressed() && cdata && !hasCompressedTextureSupport(cdata->getType())) { const char *str; @@ -400,6 +397,13 @@ bool Image::loadVolatilePOT() float s = width/p2width; float t = height/p2height; + // Use a default texture if the size is too big for the system. + if (p2width > gl.getMaxTextureSize() || p2height > gl.getMaxTextureSize()) + { + uploadDefaultTexture(); + return true; + } + vertices[1].t = t; vertices[2].t = t; vertices[2].s = s; @@ -450,9 +454,11 @@ bool Image::loadVolatilePOT() data->getData()); } - if (glGetError() != GL_NO_ERROR) - throw love::Exception("Cannot create image: size may be too large for this system."); + GLenum glerr = glGetError(); + if (glerr != GL_NO_ERROR) + throw love::Exception("Cannot create image (error code 0x%x)", glerr); + usingDefaultTexture = false; mipmapsCreated = false; checkMipmapsCreated(); @@ -468,6 +474,13 @@ bool Image::loadVolatileNPOT() gl.setTextureWrap(wrap); setMipmapSharpness(mipmapSharpness); + // Use a default texture if the size is too big for the system. + if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize()) + { + uploadDefaultTexture(); + return true; + } + // We want this lock to potentially cover mipmap creation as well. love::thread::EmptyLock lock; @@ -499,9 +512,11 @@ bool Image::loadVolatileNPOT() data->getData()); } - if (glGetError() != GL_NO_ERROR) - throw love::Exception("Cannot create image: size may be too large for this system."); + GLenum glerr = glGetError(); + if (glerr != GL_NO_ERROR) + throw love::Exception("Cannot create image (error code 0x%x)", glerr); + usingDefaultTexture = false; mipmapsCreated = false; checkMipmapsCreated(); @@ -524,6 +539,10 @@ bool Image::refresh() if (texture == 0) return false; + if (gl.getMaxTextureSize()) + + while (glGetError() != GL_NO_ERROR); // clear errors + // We want this lock to potentially cover mipmap creation as well. love::thread::EmptyLock lock; @@ -554,12 +573,31 @@ bool Image::refresh() data->getData()); } + if (glGetError() != GL_NO_ERROR) + uploadDefaultTexture(); + else + usingDefaultTexture = false; + mipmapsCreated = false; checkMipmapsCreated(); return true; } +void Image::uploadDefaultTexture() +{ + usingDefaultTexture = true; + + bind(); + setFilter(filter); + + // A nice friendly checkerboard to signify invalid textures... + GLubyte px[] = {0xFF,0xFF,0xFF,0xFF, 0x20,0x20,0x20,0xFF, + 0x20,0x20,0x20,0xFF, 0xFF,0xFF,0xFF,0xFF}; + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px); +} + love::Vector Image::getTexCoordScale() const { // FIXME: this should be changed if Image::loadVolatilePOT changes. diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 843c9f986..86fd94c66 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -146,6 +146,8 @@ public: private: vertex *scaleNPOT(const vertex *v, size_t count) const; + void uploadDefaultTexture(); + void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS, const uint16 *e = 0, GLsizei ecount = 0) const; friend class Shader; @@ -180,6 +182,10 @@ private: // Whether this Image is using a compressed texture. bool compressed; + // True if the image wasn't able to be properly created and it had to fall + // back to a default texture. + bool usingDefaultTexture; + // The image's filter mode Image::Filter filter;