From 5541626f63cc04cedf5a67c32b5b7508e880adbf Mon Sep 17 00:00:00 2001
From: DarkGod <darkgod@net-core.org>
Date: Fri, 8 Nov 2013 17:39:07 +0100
Subject: [PATCH] testing

---
 game/engines/default/engine/Entity.lua        |  14 +-
 game/modules/tome/class/Actor.lua             |   2 +-
 .../tome/data/gfx/shaders/awesomeaura.frag    | 166 ++++++++++++++-
 .../tome/data/gfx/shaders/awesomeaura.lua     |   1 +
 .../human_female/base_distancemap_01.png      | Bin 5068 -> 5238 bytes
 .../tome/data/talents/spells/wildfire.lua     |   2 +-
 game/profile-thread/Client.lua                |   2 +-
 src/core_lua.c                                | 193 ++++++++++++++++++
 src/map.c                                     |  32 ++-
 9 files changed, 396 insertions(+), 16 deletions(-)

diff --git a/game/engines/default/engine/Entity.lua b/game/engines/default/engine/Entity.lua
index e6daf7f723..40a7701421 100644
--- a/game/engines/default/engine/Entity.lua
+++ b/game/engines/default/engine/Entity.lua
@@ -278,24 +278,30 @@ function _M:makeMapObject(tiles, idx)
 
 	-- Texture 0 is always the normal image/ascii tile
 	-- we pcall it because some weird cases can not find a tile
-	local ok, tex, texx, texy, pos_x, pos_y = pcall(tiles.get, tiles, self.display, self.color_r, self.color_g, self.color_b, self.color_br, self.color_bg, self.color_bb, self.image, self._noalpha and 255, self.ascii_outline, true)
+	local ok, btex, btexx, btexy, bpos_x, bpos_y = pcall(tiles.get, tiles, self.display, self.color_r, self.color_g, self.color_b, self.color_br, self.color_bg, self.color_bb, self.image, self._noalpha and 255, self.ascii_outline, true)
 	if ok then
 		if self.anim then
-			self._mo:texture(0, tex, false, texx / self.anim.max, texy, pos_x, pos_y)
+			self._mo:texture(0, btex, false, btexx / self.anim.max, btexy, bpos_x, bpos_y)
 			self._mo:setAnim(0, self.anim.max, self.anim.speed or 1, self.anim.loop or -1)
 		else
-			self._mo:texture(0, tex, false, texx, texy, pos_x, pos_y)
+			self._mo:texture(0, btex, false, btexx, btexy, bpos_x, bpos_y)
 		end
 	end
 
 	-- Additional MO chained to the same Z order
 	if tiles.use_images and self.add_mos then
+		local tex, texx, texy, pos_x, pos_y
 		local cmo = self._mo
 		for i = 1, #self.add_mos do
 			local amo = self.add_mos[i]
 			-- Create a simple additional chained MO
 			local mo = core.map.newObject(self.uid, 1 + (tiles.use_images and amo.textures and #amo.textures or 0), false, false, false, amo.display_x or 0, amo.display_y or 0, amo.display_w or 1, amo.display_h or 1, amo.display_scale or 1)
-			tex, texx, texy, pos_x, pos_y = tiles:get("", 0, 0, 0, 0, 0, 0, amo.image, false, false, true)
+			if amo.image then
+				tex, texx, texy, pos_x, pos_y = tiles:get("", 0, 0, 0, 0, 0, 0, amo.image, false, false, true)
+			elseif amo.image_alter == "sdm" then
+				tex, texx, texy, pos_x, pos_y = btex:generateSDM()
+				texx, texy, pos_x, pos_y = btexx, btexy * 2, bpos_x, bpos_y
+			end
 			mo:texture(0, tex, false, texx, texy, pos_x, pos_y)
 			if amo.particle then
 				local args = amo.particle_args or {}
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index f1f5d0eaa7..abf493fe35 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -2889,7 +2889,7 @@ function _M:updateModdableTile()
 
 	if self.shader_auras and next(self.shader_auras) then
 		for _, def in pairs(self.shader_auras) do
-			add[#add+1] = {image = base.."base_distancemap_01.png", shader=def.shader, textures=def.textures, display_h=2, display_y=-1}
+			add[#add+1] = {image_alter="sdm", shader=def.shader, textures=def.textures, display_h=2, display_y=-1}
 		end
 	end
 
diff --git a/game/modules/tome/data/gfx/shaders/awesomeaura.frag b/game/modules/tome/data/gfx/shaders/awesomeaura.frag
index 1fc95481e9..4b86c16308 100644
--- a/game/modules/tome/data/gfx/shaders/awesomeaura.frag
+++ b/game/modules/tome/data/gfx/shaders/awesomeaura.frag
@@ -1,7 +1,169 @@
 uniform sampler2D tex;
 uniform sampler2D flames;
 
-void main(void)
+uniform float tick;
+uniform float time_factor;
+
+vec4 permute( vec4 x ) {
+
+	return mod( ( ( x * 34.0 ) + 1.0 ) * x, 289.0 );
+
+} 
+
+vec4 taylorInvSqrt( vec4 r ) {
+
+	return 1.79284291400159 - 0.85373472095314 * r;
+
+}
+
+float snoise( vec3 v ) {
+
+	const vec2 C = vec2( 1.0 / 6.0, 1.0 / 3.0 );
+	const vec4 D = vec4( 0.0, 0.5, 1.0, 2.0 );
+
+	// First corner
+
+	vec3 i  = floor( v + dot( v, C.yyy ) );
+	vec3 x0 = v - i + dot( i, C.xxx );
+
+	// Other corners
+
+	vec3 g = step( x0.yzx, x0.xyz );
+	vec3 l = 1.0 - g;
+	vec3 i1 = min( g.xyz, l.zxy );
+	vec3 i2 = max( g.xyz, l.zxy );
+
+	vec3 x1 = x0 - i1 + 1.0 * C.xxx;
+	vec3 x2 = x0 - i2 + 2.0 * C.xxx;
+	vec3 x3 = x0 - 1. + 3.0 * C.xxx;
+
+	// Permutations
+
+	i = mod( i, 289.0 );
+	vec4 p = permute( permute( permute(
+		i.z + vec4( 0.0, i1.z, i2.z, 1.0 ) )
+		+ i.y + vec4( 0.0, i1.y, i2.y, 1.0 ) )
+		+ i.x + vec4( 0.0, i1.x, i2.x, 1.0 ) );
+
+	// Gradients
+	// ( N*N points uniformly over a square, mapped onto an octahedron.)
+
+	float n_ = 1.0 / 7.0; // N=7
+
+	vec3 ns = n_ * D.wyz - D.xzx;
+
+	vec4 j = p - 49.0 * floor( p * ns.z *ns.z );  //  mod(p,N*N)
+
+	vec4 x_ = floor( j * ns.z );
+	vec4 y_ = floor( j - 7.0 * x_ );    // mod(j,N)
+
+	vec4 x = x_ *ns.x + ns.yyyy;
+	vec4 y = y_ *ns.x + ns.yyyy;
+	vec4 h = 1.0 - abs( x ) - abs( y );
+
+	vec4 b0 = vec4( x.xy, y.xy );
+	vec4 b1 = vec4( x.zw, y.zw );
+
+
+	vec4 s0 = floor( b0 ) * 2.0 + 1.0;
+	vec4 s1 = floor( b1 ) * 2.0 + 1.0;
+	vec4 sh = -step( h, vec4( 0.0 ) );
+
+	vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
+	vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
+
+	vec3 p0 = vec3( a0.xy, h.x );
+	vec3 p1 = vec3( a0.zw, h.y );
+	vec3 p2 = vec3( a1.xy, h.z );
+	vec3 p3 = vec3( a1.zw, h.w );
+
+	// Normalise gradients
+
+	vec4 norm = taylorInvSqrt( vec4( dot( p0, p0 ), dot( p1, p1 ), dot( p2, p2 ), dot( p3, p3 ) ) );
+	p0 *= norm.x;
+	p1 *= norm.y;
+	p2 *= norm.z;
+	p3 *= norm.w;
+
+	// Mix final noise value
+
+	vec4 m = max( 0.6 - vec4( dot( x0, x0 ), dot( x1, x1 ), dot( x2, x2 ), dot( x3, x3 ) ), 0.0 );
+	m = m * m;
+	return 42.0 * dot( m*m, vec4( dot( p0, x0 ), dot( p1, x1 ),
+		dot( p2, x2 ), dot( p3, x3 ) ) );
+
+}  
+
+vec2 snoise2(vec3 pos)
 {
-	gl_FragColor = texture2D(tex, gl_TexCoord[0].xy) * texture2D(flames, gl_TexCoord[0].xy) + 0.2;
+	return vec2(snoise(pos), snoise(pos + vec3(0.0, 0.0, 1.0)));
 }
+
+float GetFireDelta(float currTime, vec2 pos, float freqMult, float stretchMult, float scrollSpeed, float evolutionSpeed)
+{
+	//firewall
+	float delta = 0.0;
+//	pos.y += (1.0 - pos.y) * 0.5;
+	//pos.y += 0.5;
+	pos.y /= stretchMult;
+	pos *= freqMult;
+	pos.y -= currTime * scrollSpeed;
+//	pos.y -= currTime * 3.0;
+
+	
+	delta += snoise(vec3(pos * 1.0, currTime * 1.0 * evolutionSpeed)) * 1.5;
+	delta += snoise(vec3(pos * 2.0, currTime * 2.0 * evolutionSpeed)) * 1.5;
+	delta += snoise(vec3(pos * 4.0, currTime * 4.0 * evolutionSpeed)) * 1.5;	
+	delta += snoise(vec3(pos * 8.0, currTime * 8.0 * evolutionSpeed)) * 1.5;
+	delta += snoise(vec3(pos * 16.0, currTime * 16.0 * evolutionSpeed)) * 0.5;
+
+	return delta;
+}
+
+vec4 GetFireAuraColor(float currTime, vec2 planarPos, float freqMult, float stretchMult, float ampMult, float power, float scrollSpeed, float paletteCoord)
+{		
+	float delta =  
+		GetFireDelta(currTime, planarPos + vec2(currTime * scrollSpeed * 0, 0.0), freqMult, stretchMult, 2.5, 0.5) * (1.0 - planarPos.x)	+ 
+		GetFireDelta(currTime, vec2(planarPos.x + currTime * scrollSpeed * 0.0 - 1.0, planarPos.y), freqMult, stretchMult, 2.5, 0.5) * planarPos.x;
+		
+	delta *= min(1.0, max(0.0, 1.0 * (1.0 - planarPos.y)));
+	delta *= min(1.0, max(0.0, 1.0 * (0.0 + planarPos.y)));
+
+	float verticalPos = 1.0 - planarPos.y + delta * ampMult;	
+	verticalPos = min(0.99, verticalPos);
+	verticalPos = max(0.01, verticalPos);
+	
+	return texture2D(flames, vec2(paletteCoord, verticalPos));
+}
+
+
+vec4 Uberblend(vec4 col0, vec4 col1)
+{
+//	return vec4((1.0 - col0.a) * (col1.rgb) + col0.a * (col1.rgb * col1.a + col0.rgb * (1.0 - col1.a)), min(1.0, col0.a + col1.a));
+//	return vec4((1.0 - col1.a) * (col0.rgb) + col1.a * (col1.rgb * col1.a + col0.rgb * (1.0 - col1.a)), min(1.0, col0.a + col1.a));
+	return vec4(
+		(1.0 - col0.a) * (1.0 - col1.a) * (col0.rgb * col0.a + col1.rgb * col1.a) / (col0.a + col1.a + 1e-1) +
+		(1.0 - col0.a) * (0.0 + col1.a) * (col1.rgb) +
+		(0.0 + col0.a) * (1.0 - col1.a) * (col0.rgb * (1.0 - col1.a) + col1.rgb * col1.a) +
+		(0.0 + col0.a) * (0.0 + col1.a) * (col1.rgb),
+		min(1.0, col0.a + col1.a));
+}
+
+
+void main(void)
+{
+	vec2 radius = gl_TexCoord[0].xy - vec2(0.5, 0.5);
+	float innerRadius = 0.25;
+	float outerRadius = 0.5;
+	
+	vec2 planarPos;
+	vec4 displacement = texture2D(tex, gl_TexCoord[0].xy);
+	planarPos.x = displacement.b;
+	planarPos.y = displacement.a * 3.0 * (1.0 + 10.0 * pow((planarPos.x) * (1.0 - planarPos.x) * 4.0, 1.0));
+	
+	vec4 resultColor = vec4(0.0, 0.0, 0.0, 0.0);
+		
+	resultColor = GetFireAuraColor(tick / time_factor, planarPos, 6.0, 15.0, 1.0, 1.0, 1.0, 0.75);//texture2D(tex, gl_TexCoord[0].xy) * texture2D(flames, gl_TexCoord[0].xy) + 0.2;
+	
+	gl_FragColor = resultColor;
+}
\ No newline at end of file
diff --git a/game/modules/tome/data/gfx/shaders/awesomeaura.lua b/game/modules/tome/data/gfx/shaders/awesomeaura.lua
index 2a8b63a019..a4f88bc942 100644
--- a/game/modules/tome/data/gfx/shaders/awesomeaura.lua
+++ b/game/modules/tome/data/gfx/shaders/awesomeaura.lua
@@ -23,6 +23,7 @@ return {
 	args = {
 		tex = { texture = 0 },
 		flames = { texture = 1 },
+		time_factor = time_factor or 4000,
 	},
 	clone = false,
 }
diff --git a/game/modules/tome/data/gfx/shockbolt/player/human_female/base_distancemap_01.png b/game/modules/tome/data/gfx/shockbolt/player/human_female/base_distancemap_01.png
index 9fc102a5a83b8f15f6eedbc0e813748880392bae..da5709d26fa7f6dd8561615e6eb883ceff96d0c2 100644
GIT binary patch
delta 5166
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

delta 4994
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
M07*qoM6N<$f-FX0w*UYD

diff --git a/game/modules/tome/data/talents/spells/wildfire.lua b/game/modules/tome/data/talents/spells/wildfire.lua
index 99f54faa6d..3d66f573f7 100644
--- a/game/modules/tome/data/talents/spells/wildfire.lua
+++ b/game/modules/tome/data/talents/spells/wildfire.lua
@@ -77,7 +77,7 @@ newTalent{
 		game:playSoundNear(self, "talents/fire")
 		local cft = self:getTalentFromId(self.T_CLEANSING_FLAMES)
 		self.shader_auras = self.shader_auras or {}
-		self.shader_auras.burning_wake = {shader="awesomeaura", textures={{"image", "particles_images/flamesgeneric.png"}}}
+		self.shader_auras.burning_wake = {shader="awesomeaura", textures={{"image", "particles_images/flamesshockwave.png"}}}
 		self:updateModdableTile()
 		return {
 			bw = self:addTemporaryValue("burning_wake", t.getDamage(self, t)),
diff --git a/game/profile-thread/Client.lua b/game/profile-thread/Client.lua
index 742afa8b67..5f6ceaa69f 100644
--- a/game/profile-thread/Client.lua
+++ b/game/profile-thread/Client.lua
@@ -23,7 +23,7 @@ local UserChat = require "profile-thread.UserChat"
 
 module(..., package.seeall, class.make)
 
-local debug = true
+local debug = false
 
 local mport = debug and 2259 or 2257
 local pport = debug and 2260 or 2258
diff --git a/src/core_lua.c b/src/core_lua.c
index 44b6798ec8..b8af189a68 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -1196,6 +1196,198 @@ static int gl_texture_to_sdl(lua_State *L)
 	return 1;
 }
 
+typedef struct
+{
+	int x, y;
+} Vector;
+static inline float clamp(float val, float min, float max) { return val < min ? min : (val > max ? max : val); }
+static void build_sdm_ex(const unsigned char *texData, int srcWidth, int srcHeight, unsigned char *sdmTexData, int dstWidth, int dstHeight, int dstx, int dsty)
+{
+
+	int maxSize = dstWidth > dstHeight ? dstWidth : dstHeight;
+	int minSize = dstWidth < dstHeight ? dstWidth : dstHeight;
+
+	Vector *pixelStack = (Vector *)malloc(dstWidth * dstHeight * sizeof(Vector));
+	Vector *vectorMap = (Vector *)malloc(dstWidth * dstHeight * sizeof(Vector));
+	int *pixelStackIndex = (int *) malloc(dstWidth * dstHeight * sizeof(int));
+	
+	int currSize = 0;
+	int prevSize = 0;
+	int newSize = 0;
+
+	int x, y;
+	for(y = 0; y < dstHeight; y++)
+	{
+		for(x = 0; x < dstWidth; x++)
+		{
+			pixelStackIndex[x + y * dstWidth] = -1;
+			vectorMap[x + y * dstWidth].x = 0;
+			vectorMap[x + y * dstWidth].y = 0;
+
+			int srcx = dstx + x;
+			int srcy = dsty + y;
+			if(srcx < 0 || srcx >= srcWidth || srcy < 0 || srcy >= srcHeight) continue;
+
+			if(texData[(x + y * srcWidth) * 4 + 3] > 128)
+			{
+				pixelStackIndex[x + y * dstWidth] = currSize;
+				pixelStack[currSize].x = x;
+				pixelStack[currSize].y = y;
+				currSize++;
+			}
+		}
+	}
+	int dist = 0;
+	bool done = 0;
+	while(!done)
+	{
+		dist++;
+		int newSize = currSize;
+		int pixelIndex;
+		int neighbourNumber;
+		for(pixelIndex = prevSize; pixelIndex < currSize; pixelIndex++)
+		{
+			for(neighbourNumber = 0; neighbourNumber < 8; neighbourNumber++)
+			{
+				int xoffset = 0;
+				int yoffset = 0;
+				switch(neighbourNumber)
+				{
+					case 0: xoffset =  1; yoffset =  0; break;
+					case 1: xoffset =  0; yoffset =  1; break;
+					case 2: xoffset = -1; yoffset =  0; break;
+					case 3: xoffset =  0; yoffset = -1; break;
+					case 4: xoffset =  1; yoffset =  1; break;
+					case 5: xoffset = -1; yoffset =  1; break;
+					case 6: xoffset = -1; yoffset = -1; break;
+					case 7: xoffset =  1; yoffset = -1; break;
+				}
+				if(pixelStack[pixelIndex].x + xoffset >= dstWidth  || pixelStack[pixelIndex].x + xoffset < 0 ||
+					 pixelStack[pixelIndex].y + yoffset >= dstHeight || pixelStack[pixelIndex].y + yoffset < 0) continue;
+
+				int currIndex = pixelStack[pixelIndex].x + pixelStack[pixelIndex].y * dstWidth;
+				int neighbourIndex = (pixelStack[pixelIndex].x + xoffset) + (pixelStack[pixelIndex].y + yoffset) * dstWidth;
+				
+				Vector currOffset;
+				currOffset.x = vectorMap[currIndex].x + xoffset;
+				currOffset.y = vectorMap[currIndex].y + yoffset;
+				if(pixelStackIndex[neighbourIndex] == -1)
+				{
+					vectorMap[neighbourIndex] = currOffset;
+
+					pixelStackIndex[neighbourIndex] = newSize;
+
+					pixelStack[newSize].x = pixelStack[pixelIndex].x + xoffset;
+					pixelStack[newSize].y = pixelStack[pixelIndex].y + yoffset;
+					newSize++;
+				}else
+				{
+					if(vectorMap[neighbourIndex].x * vectorMap[neighbourIndex].x + vectorMap[neighbourIndex].y * vectorMap[neighbourIndex].y >
+						 currOffset.x * currOffset.x + currOffset.y * currOffset.y)
+					{
+						vectorMap[neighbourIndex] = currOffset;
+						/*float weight0 = sqrtf(vectorMap[neighbourIndex].x * vectorMap[neighbourIndex].x + vectorMap[neighbourIndex].y * vectorMap[neighbourIndex].y);
+						float weight1 = sqrtf(currOffset.x * currOffset.x + currOffset.y * currOffset.y);
+						vectorMap[neighbourIndex].x = vectorMap[neighbourIndex].x * weight1 / (weight0 + weight1) + currOffset.x * weight0 / (weight0 + weight1);
+						vectorMap[neighbourIndex].y = vectorMap[neighbourIndex].y * weight1 / (weight0 + weight1) + currOffset.y * weight0 / (weight0 + weight1);*/
+					}
+				}        
+			}
+		}
+		if(currSize == newSize)
+		{
+			done = 1;
+		}
+		prevSize = currSize;
+		currSize = newSize;
+	}
+
+	for(y = 0; y < dstHeight; y++)
+	{
+		for(x = 0; x < dstWidth; x++)
+		{
+			Vector offset = vectorMap[x + y * dstWidth];
+			float offsetLen = sqrtf((float)(offset.x * offset.x + offset.y * offset.y));
+
+			Vector currPoint;
+			currPoint.x = x;
+			currPoint.y = y;
+
+
+			Vector basePoint;
+			basePoint.x = currPoint.x - offset.x*0;
+			basePoint.y = currPoint.y - offset.y*0;
+
+			Vector centerPoint;
+			centerPoint.x = dstx + srcWidth  / 2;
+			centerPoint.y = dsty + srcHeight / 2;
+			float ang = atan2((float)(basePoint.x - centerPoint.x), -(float)(basePoint.y - centerPoint.y)); //0 is at up
+			//float ang = atan2((float)(offset.x), -(float)(offset.y));
+			sdmTexData[(x + y * dstWidth) * 4 + 0] = 127 + (float)(-vectorMap[x + y * dstWidth].x) / maxSize * 127;
+			sdmTexData[(x + y * dstWidth) * 4 + 1] = 127 + (float)(-vectorMap[x + y * dstWidth].y) / maxSize * 127;
+			sdmTexData[(x + y * dstWidth) * 4 + 2] = (unsigned char)(clamp(ang / 3.141592f * 0.5f + 0.5f, 0.0f, 1.0f) * 255);
+			sdmTexData[(x + y * dstWidth) * 4 + 3] = (unsigned char)(offsetLen / sqrtf(dstWidth * dstWidth + dstHeight * dstHeight) * 255);
+		}
+	}
+
+	/*for(y = 0; y < dstHeight; y++)
+	{
+		for(x = 0; x < dstWidth; x++)
+		{
+			int dstPointx = x + (sdmTexData[(x + y * dstWidth) * 4 + 0] / 255.0 - 0.5) * maxSize;
+			int dstPointy = y + (sdmTexData[(x + y * dstWidth) * 4 + 1] / 255.0 - 0.5) * maxSize;
+
+			float planarx = sdmTexData[(x + y * dstWidth) * 4 + 2] / 255.0;
+			float planary = sdmTexData[(x + y * dstWidth) * 4 + 3] / 255.0;
+			
+			char resultColor[4];
+			GetBackgroundColor(Vector2f(planarx, planary), 0.1f, resultColor);
+
+
+			for(int componentIndex = 0; componentIndex < 4; componentIndex++)
+			{
+				sdmTexData[(x + y * dstWidth) * 4 + componentIndex] = resultColor[componentIndex];
+			}
+		}
+	}*/
+	free(pixelStack);
+	free(vectorMap);
+	free(pixelStackIndex);
+}
+
+
+static int gl_texture_alter_sdm(lua_State *L) {
+	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 1);
+
+	// Bind the texture to read
+	tglBindTexture(GL_TEXTURE_2D, *t);
+
+	// Get texture size
+	GLint w, h;
+	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
+	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
+	GLubyte *tmp = calloc(w*h*4, sizeof(GLubyte));
+	glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp);
+
+	GLubyte *sdm = calloc(w*h*2*4, sizeof(GLubyte));
+	build_sdm_ex(tmp, w, h, sdm, w, h * 2, 0, 0);
+
+	GLuint *st = (GLuint*)lua_newuserdata(L, sizeof(GLuint));
+	auxiliar_setclass(L, "gl{texture}", -1);
+
+	glGenTextures(1, st);
+	tfglBindTexture(GL_TEXTURE_2D, *st);
+	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, sdm);
+
+	free(tmp);
+	free(sdm);
+
+	lua_pushnumber(L, w);
+	lua_pushnumber(L, h * 2);
+
+	return 3;
+}
+
 static int gl_tex_white = 0;
 int init_blank_surface()
 {
@@ -2685,6 +2877,7 @@ static const struct luaL_Reg sdl_texture_reg[] =
 	{"toScreenHighlightHex", sdl_texture_toscreen_highlight_hex},
 	{"makeOutline", sdl_texture_outline},
 	{"toSurface", gl_texture_to_sdl},
+	{"generateSDM", gl_texture_alter_sdm},
 	{"bind", sdl_texture_bind},
 	{NULL, NULL},
 };
diff --git a/src/map.c b/src/map.c
index 7f2efc8a2c..103296514b 100644
--- a/src/map.c
+++ b/src/map.c
@@ -415,7 +415,7 @@ static int map_objects_toscreen(lua_State *L)
 		map_object *dm;
 
 		int z;
-		if (allow_shader && m->shader) useShader(m->shader, 1, 1, 1, 1, 1, 1, 1, 1);
+		if (allow_shader && m->shader) useShader(m->shader, 0, 0, w, h, 1, 1, 1, a);
 		for (z = (!shaders_active) ? 0 : (m->nb_textures - 1); z >= 0; z--)
 		{
 			if (multitexture_active && shaders_active) tglActiveTexture(GL_TEXTURE0+z);
@@ -426,13 +426,24 @@ static int map_objects_toscreen(lua_State *L)
 		dm = m;
 		while (dm)
 		{
-			tglBindTexture(GL_TEXTURE_2D, dm->textures[0]);
-
 			int dx = x + dm->dx * w, dy = y + dm->dy * h;
 			float dw = w * dm->dw;
 			float dh = h * dm->dh;
 			int dz = moid;
 
+		 	if (m != dm && dm->shader) {
+				for (z = dm->nb_textures - 1; z > 0; z--)
+				{
+					if (multitexture_active) tglActiveTexture(GL_TEXTURE0+z);
+					tglBindTexture(dm->textures_is3d[z] ? GL_TEXTURE_3D : GL_TEXTURE_2D, dm->textures[z]);
+				}
+				if (dm->nb_textures && multitexture_active) tglActiveTexture(GL_TEXTURE0); // Switch back to default texture unit
+
+		 		useShader(dm->shader, 0, 0, w, h, 1, 1, 1, a);
+		 	}
+
+			tglBindTexture(GL_TEXTURE_2D, dm->textures[0]);
+
 			texcoords[0] = dm->tex_x[0]; texcoords[1] = dm->tex_y[0];
 			texcoords[2] = dm->tex_x[0] + dm->tex_factorx[0]; texcoords[3] = dm->tex_y[0];
 			texcoords[4] = dm->tex_x[0] + dm->tex_factorx[0]; texcoords[5] = dm->tex_y[0] + dm->tex_factory[0];
@@ -444,6 +455,11 @@ static int map_objects_toscreen(lua_State *L)
 			vertices[9] = dx; vertices[10] = dh + dy; vertices[11] = dz;
 			glDrawArrays(GL_QUADS, 0, 4);
 
+			if (m != dm) {
+		 		if (m->shader) useShader(m->shader, 0, 0, w, h, 1, 1, 1, a);
+		 		else glUseProgramObjectARB(0);
+		 	}
+
 			if (allow_cb && (dm->cb_ref != LUA_NOREF))
 			{
 				if (allow_shader && m->shader) glUseProgramObjectARB(0);
@@ -469,7 +485,7 @@ static int map_objects_toscreen(lua_State *L)
 				}
 				lua_pop(L, 1);
 
-				if (allow_shader && m->shader) useShader(m->shader, 1, 1, 1, 1, 1, 1, 1, 1);
+				if (allow_shader && m->shader) useShader(m->shader, 0, 0, w, h, 1, 1, 1, a);
 			}
 
 			dm = dm->next;
@@ -1480,7 +1496,7 @@ void display_map_quad(lua_State *L, GLuint *cur_tex, int *vert_idx, int *col_idx
 	dm = m;
 	while (dm)
 	{
-	 	if (dm->shader) {
+	 	if (m != dm && dm->shader) {
 			glDrawArrays(GL_QUADS, 0, (*vert_idx) / 2);
 			(*vert_idx) = 0;
 			(*col_idx) = 0;
@@ -1520,8 +1536,10 @@ void display_map_quad(lua_State *L, GLuint *cur_tex, int *vert_idx, int *col_idx
 			r, g, b, ((dm->dy < 0) && up_important) ? a / 3 : a,
 			(m->next || dm->shader) ? 1 : 0,
 			i, j);
-	 	if (m->shader) useShader(m->shader, dx, dy, map->tile_w, map->tile_h, r, g, b, a);
-	 	else glUseProgramObjectARB(0);
+		if (m != dm) {
+	 		if (m->shader) useShader(m->shader, dx, dy, map->tile_w, map->tile_h, r, g, b, a);
+	 		else glUseProgramObjectARB(0);
+	 	}
 		dm->animdx = animdx;
 		dm->animdy = animdy;
 		dm = dm->next;
-- 
GitLab