From b73461721c98c288a85f9fb47858b6e9dd73dddb Mon Sep 17 00:00:00 2001
From: Jonas Kulla <Nyocurio@gmail.com>
Date: Fri, 11 Jul 2014 08:31:12 +0200
Subject: [PATCH] Add meta path with fallback for EXT_unpack_subimage
 parameters

---
 mkxp.pro        |  3 ++-
 src/bitmap.cpp  | 28 +++++++++++++++------
 src/gl-fun.cpp  |  3 +++
 src/gl-fun.h    |  2 ++
 src/gl-meta.h   | 65 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/tilemap.cpp |  8 +++---
 6 files changed, 97 insertions(+), 12 deletions(-)
 create mode 100644 src/gl-meta.h

diff --git a/mkxp.pro b/mkxp.pro
index c93abd5..35079c7 100644
--- a/mkxp.pro
+++ b/mkxp.pro
@@ -124,7 +124,8 @@ HEADERS += \
 	src/al-util.h \
 	src/boost-hash.h \
 	src/debugwriter.h \
-	src/gl-fun.h
+	src/gl-fun.h \
+	src/gl-meta.h
 
 SOURCES += \
 	src/main.cpp \
diff --git a/src/bitmap.cpp b/src/bitmap.cpp
index 21a6585..a040d7d 100644
--- a/src/bitmap.cpp
+++ b/src/bitmap.cpp
@@ -30,6 +30,7 @@
 #include <pixman.h>
 
 #include "gl-util.h"
+#include "gl-meta.h"
 #include "quad.h"
 #include "quadarray.h"
 #include "transform.h"
@@ -875,25 +876,38 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
 			 * there's nothing to upload to begin with */
 			if (SDL_IntersectRect(&btmRect, &txtRect, &inters))
 			{
+				bool subImage = false;
+				int subSrcX = 0, subSrcY = 0;
+
 				if (inters.w != txtRect.w || inters.h != txtRect.h)
 				{
 					/* Clip the text surface */
-					SDL_Rect clipSrc = inters;
-					clipSrc.x -= txtRect.x;
-					clipSrc.y -= txtRect.y;
+					subSrcX = inters.x - txtRect.x;
+					subSrcY = inters.y - txtRect.y;
+					subImage = true;
 
 					posRect.x = inters.x;
 					posRect.y = inters.y;
 					posRect.w = inters.w;
 					posRect.h = inters.h;
-
-					PixelStore::setupSubImage(txtSurf->w, clipSrc.x, clipSrc.y);
 				}
 
 				TEX::bind(p->gl.tex);
-				TEX::uploadSubImage(posRect.x, posRect.y, posRect.w, posRect.h, txtSurf->pixels, GL_BGRA);
 
-				PixelStore::reset();
+				if (!subImage)
+				{
+					TEX::uploadSubImage(posRect.x, posRect.y,
+					                    posRect.w, posRect.h,
+					                    txtSurf->pixels, GL_BGRA);
+				}
+				else
+				{
+					GLMeta::subRectImageUpload(txtSurf->w, subSrcX, subSrcY,
+					                           posRect.x, posRect.y,
+					                           posRect.w, posRect.h,
+					                           txtSurf, GL_BGRA);
+					GLMeta::subRectImageFinish();
+				}
 			}
 		}
 		else
diff --git a/src/gl-fun.cpp b/src/gl-fun.cpp
index f95534b..637c116 100644
--- a/src/gl-fun.cpp
+++ b/src/gl-fun.cpp
@@ -95,6 +95,9 @@ void initGLFunctions()
 	else
 		parseExtensionsCompat(gl.GetString, ext);
 
+	// FIXME: Set based on GL kind
+	gl.unpack_subimage = true;
+
 #define HAVE_EXT(_ext) ext.contains("GL_" #_ext)
 
 	if (!HAVE_EXT(ARB_framebuffer_object))
diff --git a/src/gl-fun.h b/src/gl-fun.h
index 7f20ae1..611d7e3 100644
--- a/src/gl-fun.h
+++ b/src/gl-fun.h
@@ -146,6 +146,8 @@ struct GLFunctions
 	GL_VAO_FUN
 	GL_DEBUG_KHR_FUN
 
+	bool unpack_subimage;
+
 #undef GL_FUN
 };
 
diff --git a/src/gl-meta.h b/src/gl-meta.h
new file mode 100644
index 0000000..e29498e
--- /dev/null
+++ b/src/gl-meta.h
@@ -0,0 +1,65 @@
+/*
+** gl-meta.h
+**
+** This file is part of mkxp.
+**
+** Copyright (C) 2014 Jonas Kulla <Nyocurio@gmail.com>
+**
+** mkxp is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 2 of the License, or
+** (at your option) any later version.
+**
+** mkxp is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef GLMETA_H
+#define GLMETA_H
+
+#include "gl-fun.h"
+#include "gl-util.h"
+
+#include <SDL_surface.h>
+
+namespace GLMeta
+{
+
+inline void subRectImageUpload(GLint srcW, GLint srcX, GLint srcY,
+                               GLint dstX, GLint dstY, GLsizei dstW, GLsizei dstH,
+                               SDL_Surface *src, GLenum format)
+{
+	if (gl.unpack_subimage)
+	{
+		PixelStore::setupSubImage(srcW, srcX, srcY);
+		TEX::uploadSubImage(dstX, dstY, dstW, dstH, src->pixels, format);
+	}
+	else
+	{
+		SDL_PixelFormat *form = src->format;
+		SDL_Surface *tmp = SDL_CreateRGBSurface(0, dstW, dstH, form->BitsPerPixel,
+		                                        form->Rmask, form->Gmask, form->Bmask, form->Amask);
+		SDL_Rect srcRect = { srcX, srcY, dstW, dstH };
+
+		SDL_BlitSurface(src, &srcRect, tmp, 0);
+
+		TEX::uploadSubImage(dstX, dstY, dstW, dstH, tmp->pixels, format);
+
+		SDL_FreeSurface(tmp);
+	}
+}
+
+inline void subRectImageFinish()
+{
+	if (gl.unpack_subimage)
+		PixelStore::reset();
+}
+
+}
+
+#endif // GLMETA_H
diff --git a/src/tilemap.cpp b/src/tilemap.cpp
index 89cc7dd..bc74838 100644
--- a/src/tilemap.cpp
+++ b/src/tilemap.cpp
@@ -28,6 +28,7 @@
 #include "sharedstate.h"
 #include "glstate.h"
 #include "gl-util.h"
+#include "gl-meta.h"
 #include "global-ibo.h"
 #include "etc-internal.h"
 #include "quadarray.h"
@@ -616,12 +617,11 @@ struct TilemapPrivate
 			{
 				const TileAtlas::Blit &blitOp = blits[i];
 
-				PixelStore::setupSubImage(tsSurf->w, blitOp.src.x, blitOp.src.y);
-
-				TEX::uploadSubImage(blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf->pixels, GL_RGBA);
+				GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
+				                           blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
 			}
 
-			PixelStore::reset();
+			GLMeta::subRectImageFinish();
 		}
 		else
 		{