 	return t * dir + base;
 }
 
-vec4 cast_ray_with_latitude(float level, vec3 base, vec3 dir) {
-	vec3 pos = cast_ray_to_plane(level, base, dir);
-	Surface suf = get_surface(pos.xy);
-	return vec4(pos, suf.low_alt);
-}
-
 vec3 cast_ray_to_map(vec3 base, vec3 dir) {
-	vec4 a = cast_ray_with_latitude(u_TextureScale.z, base, dir);
-	vec4 b = cast_ray_with_latitude(0.0, base, dir);
-	vec4 step = (1.0 / float(c_NumForwardSteps + 1U)) * (b - a);
+	vec3 a = cast_ray_to_plane(u_TextureScale.z, base, dir);
+	vec3 b = cast_ray_to_plane(0.0, base, dir);
+	vec3 step = (1.0 / float(c_NumForwardSteps + 1U)) * (b - a);
+	bool above_surface = true;
 	for (uint i=0U; i<c_NumForwardSteps; ++i) {
-		vec4 c = a + step;
+		vec3 c = a + step;
 		Surface suf = get_surface(c.xy);
-		c.w = suf.low_alt;
-		if (c.z < c.w) {
+		if (c.z < suf.low_alt) {
 			b = c;
 			break;
-		}else {
+		} else {
 			a = c;
 		}
 	}
 	for (uint i=0U; i<c_NumBinarySteps; ++i) {
-		vec4 c = 0.5 * (a + b);
+		vec3 c = mix(a, b, 0.5);
 		Surface suf = get_surface(c.xy);
-		c.w = suf.low_alt;
-		if (c.z < c.w) {
+		if (c.z < suf.low_alt) {
 			b = c;
-		}else {
+		} else {
 			a = c;
 		}
 	}
 	//float t = a.z > a.w + 0.1 ? (b.w - a.w - b.z + a.z) / (a.z - a.w) : 0.5;
 	float t = 0.5;
-	return mix(a.xyz, b.xyz, t);
+	return mix(a, b, t);
 }
 
 void main() {

	tc.z = trunc(mod(tc.y, u_TextureScale.w));
	Surface suf;
	suf.tex_coord = tc;
	suf.high_alt = suf.delta = 0.0;
	uint meta = texture(t_Meta, tc).x;
	suf.low_type = get_terrain_type(meta);
	suf.high_type = 0U;
	if ((meta & c_DoubleLevelMask) != 0U) {
		if (mod(pos.x, 2.0) >= 1.0) {
			tc.x -= 1.0 / u_TextureScale.x;
			suf.high_type = suf.low_type;
			uint meta_low = texture(t_Meta, tc).x;
			suf.low_type = get_terrain_type(meta_low);
		}else {
			uint meta_high = textureOffset(t_Meta, tc, ivec2(1, 0)).x;
			suf.high_type = get_terrain_type(meta_high);
		}
		suf.low_alt = texture(t_Height, tc).x * u_TextureScale.z;
		suf.high_alt = textureOffset(t_Height, tc, ivec2(1, 0)).x * u_TextureScale.z;
	}else {
		suf.low_alt = texture(t_Height, tc).x * u_TextureScale.z;
	}
	return suf;
}

	float low_alt, high_alt, delta;
	uint low_type, high_type;
	vec3 tex_coord;
	bool is_shadowed;
};

uint get_terrain_type(uint meta) {
	return (meta >> c_TerrainShift) & ((1U << c_TerrainBits) - 1U);
}
uint get_delta(uint meta) {
	return (meta >> c_DeltaShift) & ((1U << c_DeltaBits) - 1U);
}

Surface get_surface(vec2 pos) {
