Browse Source

Canvases now have OpenGL ES support, updated Texture:setWrap to return false for repeat wrap modes in non-power-of-two textures if OpenGL ES 2 is used and the implementation doesn't have support for repeat on NPOT textures.

--HG--
branch : minor
Alex Szpakowski 10 years ago
parent
commit
8067d42df2

+ 1 - 1
src/modules/graphics/Texture.h

@@ -95,7 +95,7 @@ public:
 	virtual void setFilter(const Filter &f) = 0;
 	virtual const Filter &getFilter() const;
 
-	virtual void setWrap(const Wrap &w) = 0;
+	virtual bool setWrap(const Wrap &w) = 0;
 	virtual const Wrap &getWrap() const;
 
 	virtual const Vertex *getVertices() const;

+ 77 - 21
src/modules/graphics/opengl/Canvas.cpp

@@ -571,12 +571,17 @@ bool Canvas::loadVolatile()
 
 	convertFormat(format, internalformat, externalformat, textype);
 
+	// in GLES2, the internalformat and format params of TexImage have to match.
+	GLint iformat = (GLint) internalformat;
+	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
+		iformat = (GLint) externalformat;
+
 	while (glGetError() != GL_NO_ERROR)
 		/* Clear the error buffer. */;
 
 	glTexImage2D(GL_TEXTURE_2D,
 	             0,
-	             (GLint) internalformat,
+	             iformat,
 	             width, height,
 	             0,
 	             externalformat,
@@ -691,11 +696,24 @@ void Canvas::setFilter(const Texture::Filter &f)
 	gl.setTextureFilter(filter);
 }
 
-void Canvas::setWrap(const Texture::Wrap &w)
+bool Canvas::setWrap(const Texture::Wrap &w)
 {
+	bool success = true;
 	wrap = w;
+
+	if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
+	{
+		if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
+			success = false;
+
+		// If we only have limited NPOT support then the wrap mode must be CLAMP.
+		wrap.s = wrap.t = WRAP_CLAMP;
+	}
+
 	gl.bindTexture(texture);
 	gl.setTextureWrap(wrap);
+
+	return success;
 }
 
 GLuint Canvas::getGLTexture() const
@@ -738,10 +756,13 @@ void Canvas::setupGrab()
 	gl.matrices.projection.push_back(Matrix::ortho(0.0, width, 0.0, height));
 
 	// Make sure the correct sRGB setting is used when drawing to the canvas.
-	if (format == FORMAT_SRGB)
-		glEnable(GL_FRAMEBUFFER_SRGB);
-	else if (screenHasSRGB)
-		glDisable(GL_FRAMEBUFFER_SRGB);
+	if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
+	{
+		if (format == FORMAT_SRGB)
+			glEnable(GL_FRAMEBUFFER_SRGB);
+		else if (screenHasSRGB)
+			glDisable(GL_FRAMEBUFFER_SRGB);
+	}
 
 	if (msaa_buffer != 0)
 		msaa_dirty = true;
@@ -829,8 +850,11 @@ void Canvas::stopGrab(bool switchingToOtherCanvas)
 
 	if (switchingToOtherCanvas)
 	{
-		if (format == FORMAT_SRGB)
-			glDisable(GL_FRAMEBUFFER_SRGB);
+		if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
+		{
+			if (format == FORMAT_SRGB)
+				glDisable(GL_FRAMEBUFFER_SRGB);
+		}
 	}
 	else
 	{
@@ -839,10 +863,13 @@ void Canvas::stopGrab(bool switchingToOtherCanvas)
 		current = nullptr;
 		gl.setViewport(systemViewport);
 
-		if (format == FORMAT_SRGB && !screenHasSRGB)
-			glDisable(GL_FRAMEBUFFER_SRGB);
-		else if (format != FORMAT_SRGB && screenHasSRGB)
-			glEnable(GL_FRAMEBUFFER_SRGB);
+		if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
+		{
+			if (format == FORMAT_SRGB && !screenHasSRGB)
+				glDisable(GL_FRAMEBUFFER_SRGB);
+			else if (format != FORMAT_SRGB && screenHasSRGB)
+				glEnable(GL_FRAMEBUFFER_SRGB);
+		}
 	}
 }
 
@@ -865,7 +892,7 @@ void Canvas::clear(Color c)
 
 	// We don't need to worry about multiple FBO attachments or global clear
 	// color state when OpenGL 3.0+ is supported.
-	if (GLAD_VERSION_3_0)
+	if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
 	{
 		glClearBufferfv(GL_COLOR, 0, glcolor);
 
@@ -1020,7 +1047,11 @@ Canvas::Format Canvas::getSizedFormat(Canvas::Format format)
 	switch (format)
 	{
 	case FORMAT_NORMAL:
-		return FORMAT_RGBA8;
+		// 32-bit render targets don't have guaranteed support on OpenGL ES 2.
+		if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8))
+			return FORMAT_RGBA4;
+		else
+			return FORMAT_RGBA8;
 	case FORMAT_HDR:
 		return FORMAT_RGBA16F;
 	default:
@@ -1055,7 +1086,7 @@ void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum
 		break;
 	case FORMAT_RGB10A2:
 		internalformat = GL_RGB10_A2;
-		type = GL_UNSIGNED_INT_10_10_10_2;
+		type = GL_UNSIGNED_INT_2_10_10_10_REV;
 		break;
 	case FORMAT_RG11B10F:
 		internalformat = GL_R11F_G11F_B10F;
@@ -1064,7 +1095,12 @@ void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum
 		break;
 	case FORMAT_RGBA16F:
 		internalformat = GL_RGBA16F;
-		type = GL_FLOAT;
+		if (GLAD_OES_texture_float)
+			type = GL_HALF_FLOAT_OES;
+		else if (GLAD_VERSION_1_0)
+			type = GL_FLOAT;
+		else
+			type = GL_HALF_FLOAT;
 		break;
 	case FORMAT_RGBA32F:
 		internalformat = GL_RGBA32F;
@@ -1073,6 +1109,8 @@ void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum
 	case FORMAT_SRGB:
 		internalformat = GL_SRGB8_ALPHA8;
 		type = GL_UNSIGNED_BYTE;
+		if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
+			externalformat = GL_SRGB_ALPHA;
 		break;
 	}
 }
@@ -1106,7 +1144,7 @@ bool Canvas::isSupported()
 
 bool Canvas::isMultiCanvasSupported()
 {
-	// system must support at least 4 simultanious active canvases.
+	// system must support at least 4 simultaneous active canvases.
 	return gl.getMaxRenderTargets() >= 4;
 }
 
@@ -1124,24 +1162,38 @@ bool Canvas::isFormatSupported(Canvas::Format format)
 	switch (format)
 	{
 	case FORMAT_RGBA8:
+		supported = GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8;
+		break;
 	case FORMAT_RGBA4:
 	case FORMAT_RGB5A1:
-	case FORMAT_RGB10A2:
 		supported = true;
 		break;
 	case FORMAT_RGB565:
 		supported = GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility;
 		break;
+	case FORMAT_RGB10A2:
+		supported = GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0;
+		break;
 	case FORMAT_RG11B10F:
-		supported = GLAD_VERSION_3_0 || GLAD_EXT_packed_float;
+		supported = GLAD_VERSION_3_0 || GLAD_EXT_packed_float /*|| GLAD_APPLE_color_buffer_packed_float*/;
 		break;
 	case FORMAT_RGBA16F:
+		if (GLAD_VERSION_1_0)
+			supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
+		else if (GLAD_ES_VERSION_2_0)
+			supported = GLAD_EXT_color_buffer_half_float && (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float);
+		break;
 	case FORMAT_RGBA32F:
 		supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
 		break;
 	case FORMAT_SRGB:
-		supported = GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
-			&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
+		if (GLAD_VERSION_1_0)
+		{
+			supported = GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
+				&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
+		}
+		else
+			supported = GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB;
 		break;
 	default:
 		supported = false;
@@ -1164,6 +1216,10 @@ bool Canvas::isFormatSupported(Canvas::Format format)
 	GLenum textype = GL_UNSIGNED_BYTE;
 	convertFormat(format, internalformat, externalformat, textype);
 
+	// in GLES2, the internalformat and format params of TexImage have to match.
+	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
+		internalformat = externalformat;
+
 	GLuint texture = 0;
 	glGenTextures(1, &texture);
 	gl.bindTexture(texture);

+ 1 - 1
src/modules/graphics/opengl/Canvas.h

@@ -71,7 +71,7 @@ public:
 	// Implements Texture.
 	virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
 	virtual void setFilter(const Texture::Filter &f);
-	virtual void setWrap(const Texture::Wrap &w);
+	virtual bool setWrap(const Texture::Wrap &w);
 	virtual GLuint getGLTexture() const;
 	virtual void predraw();
 

+ 9 - 5
src/modules/graphics/opengl/Graphics.cpp

@@ -254,12 +254,16 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
 	// Set whether drawing converts input from linear -> sRGB colorspace.
-	if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
+	if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
+		|| GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB)
 	{
-		if (sRGB)
-			glEnable(GL_FRAMEBUFFER_SRGB);
-		else
-			glDisable(GL_FRAMEBUFFER_SRGB);
+		if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
+		{
+			if (sRGB)
+				glEnable(GL_FRAMEBUFFER_SRGB);
+			else
+				glDisable(GL_FRAMEBUFFER_SRGB);
+		}
 	}
 	else
 		sRGB = false;

+ 32 - 5
src/modules/graphics/opengl/Image.cpp

@@ -155,12 +155,24 @@ void Image::setFilter(const Texture::Filter &f)
 	gl.setTextureFilter(filter);
 }
 
-void Image::setWrap(const Texture::Wrap &w)
+bool Image::setWrap(const Texture::Wrap &w)
 {
+	bool success = true;
 	wrap = w;
 
+	if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
+	{
+		if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
+			success = false;
+
+		// If we only have limited NPOT support then the wrap mode must be CLAMP.
+		wrap.s = wrap.t = WRAP_CLAMP;
+	}
+
 	bind();
 	gl.setTextureWrap(w);
+
+	return success;
 }
 
 void Image::setMipmapSharpness(float sharpness)
@@ -263,10 +275,18 @@ void Image::loadTextureFromCompressedData()
 void Image::loadTextureFromImageData()
 {
 	GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
+	GLenum format  = GL_RGBA;
+
+	// in GLES2, the internalformat and format params of TexImage have to match.
+	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
+	{
+		format  = flags.sRGB ? GL_SRGB_ALPHA : GL_RGBA;
+		iformat = format;
+	}
 
 	{
 		love::thread::Lock lock(data->getMutex());
-		glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, GL_RGBA,
+		glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, format,
 		             GL_UNSIGNED_BYTE, data->getData());
 	}
 
@@ -292,14 +312,21 @@ bool Image::loadVolatile()
 			throw love::Exception("sRGB images are not supported on this system.");
 	}
 
+	// NPOT textures don't support mipmapping without full NPOT support.
+	if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
+	{
+		flags.mipmaps = false;
+		filter.mipmap = FILTER_NONE;
+	}
+
 	if (maxMipmapSharpness == 0.0f && GLAD_VERSION_1_4)
 		glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
 
 	glGenTextures(1, &texture);
 	gl.bindTexture(texture);
 
-	gl.setTextureFilter(filter);
-	gl.setTextureWrap(wrap);
+	setFilter(filter);
+	setWrap(wrap);
 	setMipmapSharpness(mipmapSharpness);
 
 	// Use a default texture if the size is too big for the system.
@@ -616,7 +643,7 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::Format format, bo
 
 bool Image::hasSRGBSupport()
 {
-	return GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
+	return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
 }
 
 bool Image::getConstant(const char *in, FlagType &out)

+ 1 - 1
src/modules/graphics/opengl/Image.h

@@ -108,7 +108,7 @@ public:
 	virtual GLuint getGLTexture() const;
 
 	virtual void setFilter(const Texture::Filter &f);
-	virtual void setWrap(const Texture::Wrap &w);
+	virtual bool setWrap(const Texture::Wrap &w);
 
 	void setMipmapSharpness(float sharpness);
 	float getMipmapSharpness() const;

+ 8 - 0
src/modules/graphics/opengl/Texture.h

@@ -55,6 +55,14 @@ public:
 	 **/
 	virtual void postdraw() {}
 
+	/**
+	 * Unextended OpenGL ES 2 doesn't support non-clamp wrap modes or mipmapping
+	 * with non-power-of-two textures.
+	 **/
+	static bool hasLimitedNpot()
+	{
+		return GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot);
+	}
 
 }; // Texture
 

+ 5 - 11
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -713,26 +713,20 @@ int w_getBlendMode(lua_State *L)
 
 int w_setDefaultFilter(lua_State *L)
 {
-	Texture::FilterMode min;
-	Texture::FilterMode mag;
+	Texture::Filter f;
 
 	const char *minstr = luaL_checkstring(L, 1);
 	const char *magstr = luaL_optstring(L, 2, minstr);
 
-	if (!Texture::getConstant(minstr, min))
+	if (!Texture::getConstant(minstr, f.min))
 		return luaL_error(L, "Invalid filter mode: %s", minstr);
-	if (!Texture::getConstant(magstr, mag))
+	if (!Texture::getConstant(magstr, f.mag))
 		return luaL_error(L, "Invalid filter mode: %s", magstr);
 
-	float anisotropy = (float) luaL_optnumber(L, 3, 1.0);
-
-	Texture::Filter f;
-	f.min = min;
-	f.mag = mag;
-	f.anisotropy = anisotropy;
+	f.anisotropy = (float) luaL_optnumber(L, 3, 1.0);
 
 	instance()->setDefaultFilter(f);
-	
+
 	return 0;
 }
 

+ 2 - 2
src/modules/graphics/opengl/wrap_Texture.cpp

@@ -105,8 +105,8 @@ int w_Texture_setWrap(lua_State *L)
 	if (!Texture::getConstant(tstr, w.t))
 		return luaL_error(L, "Invalid wrap mode, %s", tstr);
 
-	t->setWrap(w);
-	return 0;
+	luax_pushboolean(L, t->setWrap(w));
+	return 1;
 }
 
 int w_Texture_getWrap(lua_State *L)