All pastes #916048 Raw Edit

Mine

public text v1 · immutable
#916048 ·published 2008-02-24 08:40 UTC
rendered paste body
Index: source/blender/blenkernel/BKE_texture.h
===================================================================
--- source/blender/blenkernel/BKE_texture.h	(revision 13811)
+++ source/blender/blenkernel/BKE_texture.h	(working copy)
@@ -57,6 +57,7 @@
 struct ColorBand *add_colorband(int rangetype);
 int do_colorband(struct ColorBand *coba, float in, float out[4]);
 
+void tiles_precalc(struct Tex *tex);
 void default_tex(struct Tex *tex);
 struct Tex *add_texture(char *name);
 void default_mtex(struct MTex *mtex);
@@ -78,3 +79,5 @@
 
 #endif
 
+
+
Index: source/blender/blenkernel/intern/texture.c
===================================================================
--- source/blender/blenkernel/intern/texture.c	(revision 13811)
+++ source/blender/blenkernel/intern/texture.c	(working copy)
@@ -403,6 +403,138 @@
 
 /* ------------------------------------------------------------------------- */
 
+void tiles_precalc(Tex *tex)
+{
+	/* Compute a set of random widths for the tiles. The array tex->precalc->pat[] will
+	 * accumulate the gap and tile widths in each cell starting at 0.
+	 */
+	Tex *t = (Tex *)tex;
+	float maxwidth = t->width + t->widthvar * t->width;
+	float minwidth = t->width - t->widthvar * t->width;
+	float maxheight = t->height + t->heightvar * t->height;
+	float minheight = t->height - t->heightvar * t->height;
+	float maxbump = t->bump + t->bumpvar * t->bump;
+	float minbump = t->bump - t->bumpvar * t->bump;
+
+    float w, h, b, r, sum;
+	float h1, s1, v1, h2, s2, v2;
+	float mh, ms, mv;
+	short i, j;
+
+	RNG *rng = rng_new(tex->seed);
+
+	/* Handle negative dimensions */
+	if (minwidth < 0) minwidth = 0;
+	if (minheight < 0) minheight = 0;
+
+	/* Handle bump limits */
+	if (minbump < 0) minbump = 0;
+	if (maxbump > 1) maxbump = 1;
+
+	/* Calculate ranges for width, height and bump */
+    w = maxwidth - minwidth;
+	h = maxheight - minheight;
+	b = maxbump - minbump;
+
+	/* Initialize min/max values */
+	t->precalc.minw = MAX2(minwidth, maxwidth);
+	t->precalc.maxw = 0;
+	t->precalc.minh = MAX2(minheight, maxheight);
+	t->precalc.maxh = 0;
+
+	/* Compute random numbers between minwidth and maxwidth. Keep a running total
+	 * of the width of the pattern. All the width's will then be scaled by this
+	 * to bring into the [0, 1] range; otherwise, the pattern won't be seamless 
+	 * for the 2D->3D texture mapping functions.
+	 */
+    t->precalc.hpat[0] = 0;
+	sum = 0;
+    for (i = 1; i <= t->hcount; i++) {
+		r = rng_getFloat(rng);
+		r = minwidth + w * r;
+		t->precalc.hpat[i] = t->hgap + t->precalc.hpat[i - 1] + r;
+		sum += t->hgap + r;
+
+		t->precalc.minw = MIN2(t->precalc.minw, r);
+		t->precalc.maxw = MAX2(t->precalc.maxw, r);		
+    }
+	if (tex->seamless) {
+		sum = 1.0/sum;
+		for (i = 1; i <= t->hcount; i++) {
+			t->precalc.hpat[i] *= sum;
+		}
+		t->precalc.minw *= sum;
+		t->precalc.maxw *= sum;
+		t->precalc.hgap = t->hgap * sum;
+	}
+	else {
+		t->precalc.hgap = t->hgap;
+	}
+
+	/* Compute random numbers between minheight and maxheight. Keep a running total
+	 * of the height of the pattern. All the height's will then be scaled by this
+	 * to bring into the [0, 1] range; otherwise, the pattern won't be seamless 
+	 * for the 2D->3D texture mapping functions.
+	 */
+    t->precalc.vpat[0] = 0;
+	sum = 0;
+    for (i = 1; i <= t->vcount; i++) {
+		r = rng_getFloat(rng);
+		r = minheight + h * r;
+		t->precalc.vpat[i] = t->vgap + t->precalc.vpat[i - 1] + r;
+		sum += t->vgap + r;
+ 
+		t->precalc.minh = MIN2(t->precalc.minh, r);
+		t->precalc.maxh = MAX2(t->precalc.maxh, r);
+	}
+	if (tex->seamless) {
+		sum = 1.0/sum;
+		for (i = 1; i <= t->vcount; i++) {
+			t->precalc.vpat[i] *= sum;
+		}
+		t->precalc.minh *= sum;
+		t->precalc.maxh *= sum;
+		t->precalc.vgap = t->vgap * sum;
+	}
+	else {
+		t->precalc.vgap = t->vgap;
+	}
+
+	/* Compute random numbers between minbump and maxbump */
+	for (i = 0; i < t->hcount; i++) {
+		for (j = 0; j < t->vcount; j++) {
+			r = rng_getFloat(rng);
+			t->precalc.bpat[i][j] = minbump + b * r;
+		}
+	}
+	for (i = 0; i < 16; i++) {
+		r = rng_getFloat(rng);
+		t->precalc.rpat[i] = minbump + b * r;
+	}
+
+	/* Compute random colours using the base colour [colr1, colg1, colb1] and the
+	 * percentage variation in hue, saturation and value.
+	 */
+	rgb_to_hsv(t->colr1, t->colg1, t->colb1, &h1, &s1, &v1);
+	mh = 0.5 * t->fhue;
+	ms = 0.5 * t->fsat;
+	mv = 0.5 * t->fval;
+	for (i = 0; i < t->hcount; i++) {
+		for (j = 0; j < t->vcount; j++) {
+			r = rng_getFloat(rng);
+			h2 = h1 + r * t->fhue - mh;
+			s2 = s1 + r * t->fsat - ms;
+			v2 = v1 + r * t->fval - mv;
+			if (h2 > 1.0) h2 -= 1.0; else if (h2 < 0.0) h2 += 1.0;
+			if (s2 > 1.0) s2 -= 1.0; else if (s2 < 0.0) s2 += 1.0;
+			if (v2 > 1.0) v2 -= 1.0; else if (v2 < 0.0) v2 += 1.0;
+			hsv_to_rgb(h2, s2, v2, &t->precalc.r[i][j], &t->precalc.g[i][j], &t->precalc.b[i][j]);
+		}
+	}
+
+	rng_free(rng);
+}
+
 void default_tex(Tex *tex)
 {
 	PluginTex *pit;
@@ -448,6 +580,39 @@
 	tex->vn_mexp = 2.5;
 	tex->vn_distm = 0;
 	tex->vn_coltype = 0;
+	/* tiles */
+	tex->scale = 1;
+	tex->hcount = 3;
+	tex->width = 0.2;
+	tex->widthvar = 0;
+	tex->vcount = 3;
+	tex->height = 0.1;
+	tex->heightvar = 0;
+	tex->hgap = 0.01;
+	tex->vgap = 0.01;
+	tex->shift = 0.1;
+	tex->bevel = 0.2;
+	tex->corner = TEX_CORNER_STRAIGHT;
+	tex->hcorner = 0;
+	tex->vcorner = 0;
+	tex->seed = 0;
+	tex->alternate = 1;
+	tex->curve = 0;
+	tex->smooth = 0;
+	tex->strength = 1;
+	tex->pattern = 0;
+	tex->bevoption = 0;
+	tex->colr1 = 1;
+	tex->colg1 = 1;
+	tex->colb1 = 1;
+	tex->colr2 = 0;
+	tex->colg2 = 0;
+	tex->colb2 = 0;
+	tex->bump = 1;
+	tex->bumpvar = 0;
+	tex->seamless = 1;
+	tex->bevelshading = TEX_BEVEL_DEFAULT;
+	tiles_precalc(tex);
 
 	if (tex->env) {
 		tex->env->stype=ENV_STATIC;
Index: source/blender/blenloader/intern/readfile.c
===================================================================
--- source/blender/blenloader/intern/readfile.c	(revision 13811)
+++ source/blender/blenloader/intern/readfile.c	(working copy)
@@ -5904,7 +5904,7 @@
 					}
 				}
 			}
-		}
+		}		
 	}
 
 
@@ -6976,7 +6976,7 @@
 				}
 			}
 		}		
-		
+
 		for(ma=main->mat.first; ma; ma= ma->id.next) {
 			if(ma->samp_gloss_mir == 0) {
 				ma->gloss_mir = ma->gloss_tra= 1.0;
@@ -7081,7 +7081,6 @@
 			sce->r.bg_stamp[3] = 0.25; /* make sure the background has full alpha */
 		}
 	}
-
 	
 	if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 6)) {
 		Scene *sce;
@@ -7394,6 +7393,48 @@
 					if(ma->mtex[a] && ma->mtex[a]->tex)
 						ma->mtex[a]->normapspace = MTEX_NSPACE_TANGENT;
 	}
+	if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 8)) {
+		Tex *tex;
+
+		/* Initialize Tiles texture */
+		for(tex= main->tex.first; tex; tex= tex->id.next) {
+			tex->scale = 1;
+			tex->hcount = 3;
+			tex->width = 0.2;
+			tex->widthvar = 0;
+			tex->vcount = 3;
+			tex->height = 0.1;
+			tex->heightvar = 0;
+			tex->hgap = 0.01;
+			tex->vgap = 0.01;
+			tex->shift = 0.1;
+			tex->bevel = 0.2;
+			tex->corner = TEX_CORNER_STRAIGHT;
+			tex->hcorner = 0;
+			tex->vcorner = 0;
+			tex->seed = 0;
+			tex->alternate = 1;
+			tex->curve = 0;
+			tex->smooth = 0;
+			tex->strength = 1;
+			tex->pattern = 0;
+			tex->bevoption = 0;
+			tex->colr1 = 1;
+			tex->colg1 = 1;
+			tex->colb1 = 1;
+			tex->colr2 = 0;
+			tex->colg2 = 0;
+			tex->colb2 = 0;
+			tex->fhue = 0;
+			tex->fsat = 0;
+			tex->fval = 0;
+			tex->bump = 1;
+			tex->bumpvar = 0;
+			tex->seamless = 1;
+			tex->bevelshading = TEX_BEVEL_DEFAULT;
+			tiles_precalc(tex);
+		}
+	}
 	
 	if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 10)) {
 		Object *ob;
@@ -7503,6 +7544,7 @@
 			if (image->flag & IMA_OLDFLAG) image->flag &= ~IMA_OLDFLAG;
 		}
 	}
+
 	/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
 	/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
 
Index: source/blender/makesdna/DNA_texture_types.h
===================================================================
--- source/blender/makesdna/DNA_texture_types.h	(revision 13811)
+++ source/blender/makesdna/DNA_texture_types.h	(working copy)
@@ -130,6 +130,21 @@
 	short recalc, lastsize;
 } EnvMap;
 
+/* --------------------------------------- Tiles Specific ---------------------------------------------- */
+typedef struct TexPreCalc {
+	float hpat[16];			/* Stores horizontal tile pattern */
+	float vpat[16];			/* Stores vertical tile pattern */
+	float bpat[16][16];		/* Stores the bump pattern */
+	float minw, minh;		/* Store overall min of width and height value */
+	float maxw, maxh;		/* Store overall max of width and height value */
+	float r[16][16];		/* Store colour pattern */
+	float g[16][16];
+	float b[16][16];
+	float rpat[16];			/* Stores the random numbers for anything else */
+	float hgap, vgap;		/* Stores gap values scaled by overall size of pattern */
+} TexPreCalc;
+/* --------------------------------------- Tiles Specific ---------------------------------------------- */
+
 typedef struct Tex {
 	ID id;
 	
@@ -154,7 +169,19 @@
 	
 	short imaflag, flag;
 	short type, stype;
-	
+
+	short hcount, vcount, smooth;
+	short corner, pattern, bevoption;
+	float scale;
+	float width, widthvar, height, heightvar, bump, bumpvar;
+	float curve;
+	float hgap, vgap, shift, bevel, strength;
+	float colr1, colg1, colb1, colr2, colg2, colb2, fhue, fsat, fval;
+	float hcorner, vcorner;
+	unsigned int seed, alternate;
+	short seamless, bevelshading;
+	struct TexPreCalc precalc;
+
 	float cropxmin, cropymin, cropxmax, cropymax;
 	short xrepeat, yrepeat;
 	short extend;
@@ -211,6 +238,7 @@
 #define TEX_MUSGRAVE	11
 #define TEX_VORONOI		12
 #define TEX_DISTNOISE	13
+#define TEX_TILES		14
 
 /* musgrave stype */
 #define TEX_MFRACTAL		0
@@ -310,6 +338,36 @@
 #define TEX_HALO		5
 #define TEX_RAD			6
 
+/* tex->stype in texture.c - corner types */
+#define TEX_CORNER_ROUND		0
+#define TEX_CORNER_ROUND_INV	1
+#define TEX_CORNER_ELLIPSE		2
+#define TEX_CORNER_ELLIPSE_INV	3
+#define TEX_CORNER_STRAIGHT		4
+
+#define TEX_TILES_NONE			0
+#define TEX_TILES_INTERLOCK1	1
+#define TEX_TILES_HEX			2
+#define TEX_TILES_HERRINGBONE1	3
+#define TEX_TILES_HERRINGBONE2	4
+#define TEX_TILES_HERRINGBONE3	5
+#define TEX_TILES_WEAVE			6
+#define TEX_TILES_INTERLOCK2	7
+#define TEX_TILES_INTERLOCK3	8
+#define TEX_TILES_INTERLOCK4	9
+#define TEX_TILES_CROSS1		10
+#define TEX_TILES_CROSS2		11
+#define TEX_TILES_STAR1			12
+
+#define TEX_BEVEL_DEFAULTMIN	0
+#define TEX_BEVEL_UNIFORMMIN	1
+#define TEX_BEVEL_UNIFORMMAX	2
+
+#define TEX_BEVEL_DEFAULT		0
+#define TEX_BEVEL_PATTERN		1 /* Used for predefined pattern so they can do what they want */
+#define TEX_BEVEL_HGRADIENT		2
+#define TEX_BEVEL_VGRADIENT		3
+
 /* tex->stype in texture.c - stucci types */
 #define TEX_PLASTIC		0
 #define TEX_WALLIN		1
@@ -388,3 +446,11 @@
 
 #endif
 
+
+
+
+
+
+
+
+
Index: source/blender/render/intern/include/texture.h
===================================================================
--- source/blender/render/intern/include/texture.h	(revision 13811)
+++ source/blender/render/intern/include/texture.h	(working copy)
@@ -49,6 +49,7 @@
 struct HaloRen;
 struct ShadeInput;
 struct TexResult;
+struct TexPreCalc;
 struct Tex;
 struct Image;
 struct ImBuf;
@@ -72,3 +73,11 @@
 
 #endif /* TEXTURE_EXT_H */
 
+
+
+
+
+
+
+
+
Index: source/blender/render/intern/source/texture.c
===================================================================
--- source/blender/render/intern/source/texture.c	(revision 13811)
+++ source/blender/render/intern/source/texture.c	(working copy)
@@ -5,7 +5,7 @@
  *
  * This program 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
+ * as published by the Free Software Foundation; either version 2iles
  * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -28,6 +28,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef WIN32
+#define _USE_MATH_DEFINES
+#endif
 #include <math.h>
 
 #include "MTC_matrixops.h"
@@ -74,9 +77,8 @@
 extern struct Render R;
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
+#define M_PI_OVER_180 0.0174532925199
 
-
-
 /* note; this is called WITH RENDER IS NULL in src/drawview.c for animated 
    background image, option should move to kernel */
 void init_render_texture(Render *re, Tex *tex)
@@ -691,9 +693,2154 @@
 
 }
 
+/* ------------------------------------------------------------------------- */
 
 /* ------------------------------------------------------------------------- */
 
+/* Determines which side of the line a point is. Assume +ve for left of vector pointing from pa to pb. */
+#define SIDE_OF_LINE(pa,pb,pp)		((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
+
+/* Determines if a point p0 is inside a triangle (p1, p2, p3). */
+#define POINT_IN_TRI(p0,p1,p2,p3)	((SIDE_OF_LINE(p1,p2,p0)>=0) && (SIDE_OF_LINE(p2,p3,p0)>=0) && (SIDE_OF_LINE(p3,p1,p0)>=0))
+
+/* Signed distance of point (x, y) from line Ax + By + C = 0. */
+#define DIST_POINT_TO_LINE(A, B, C, x, y) (((A) * (x) + (B) * (y) + (C)) / sqrt((A) * (A) + (B) * (B)))
+
+/* Given signed distance d from a line and bevel width b, compute a linear gradient for the positive 
+ * side of the line. Points on the negative side will have intensity 0 and points beyond distance
+ * b will have intensity 1.
+ */
+#define LINE_BEVEL(d, b) d = (d < 0) ? 0 : ((d <= b) && (b > 0)) ? (d) / (b) : 1
+
+/* Determines if a point (x, y) is inside, outside or on a circle with center (cx, cy) and radius r. */
+#define POINT_IN_CIRCLE(x, y, cx, cy, r)     (((x) - (cx)) * ((x) - (cx)) + ((y) - (cy)) * ((y) - (cy)) <  (r) * (r))
+#define POINT_ON_CIRCLE(x, y, cx, cy, r)     (((x) - (cx)) * ((x) - (cx)) + ((y) - (cy)) * ((y) - (cy)) == (r) * (r))
+#define POINT_NOT_IN_CIRCLE(x, y, cx, cy, r) (((x) - (cx)) * ((x) - (cx)) + ((y) - (cy)) * ((y) - (cy)) >  (r) * (r))
+/* Determines if a point (x, y) is inside, outside or on an ellipse with center (cx, cy) and radii rx, ry. */
+#define POINT_IN_ELLIPSE(x, y, cx, cy, rx, ry)     (((x) - (cx)) * ((x) - (cx)) / ((rx) * (rx)) + ((y) - (cy)) * ((y) - (cy)) / ((ry) * (ry)) <  1)
+#define POINT_ON_ELLIPSE(x, y, cx, cy, rx, ry)     (((x) - (cx)) * ((x) - (cx)) / ((rx) * (rx)) + ((y) - (cy)) * ((y) - (cy)) / ((ry) * (ry)) == 1)
+#define POINT_NOT_IN_ELLIPSE(x, y, cx, cy, rx, ry) (((x) - (cx)) * ((x) - (cx)) / ((rx) * (rx)) + ((y) - (cy)) * ((y) - (cy)) / ((ry) * (ry)) >  1)
+
+/* Used to identify how neighbouring tiles are used to compute bump and colour */
+#define TILE_CURRENT		0
+#define TILE_ABOVE			1
+#define TILE_BELOW			2
+#define TILE_LEFT			3
+#define TILE_RIGHT			4
+#define TILE_RIGHT_ABOVE	5
+#define TILE_RIGHT_BELOW	6
+#define TILE_LEFT_ABOVE		7
+#define TILE_LEFT_BELOW		8
+
+static float mod(float a, float b)
+{
+	/* Calculate a mod b for floating point numbers.
+	 * NOTE: a can be negative however I'm not sure what behaviour this function
+	 * has if b is negative
+	 *
+	 * NOTE: Copied from plugin brick.c by Unicorn. The original code was in Public 
+	 * Domain and is supplied with the Blender Texture Plugins repository.
+	 */
+    int n = (int)(a / b);
+    a -= n * b;
+    if (a < 0) a += b;
+    return a;
+}
+
+static float smoothstep(float x, float a, float b)
+{
+	/* Calculate a step function as follows:
+	*    y = 0             for x < 0
+	*    y = -2x^2 + 3x^3  for 0 <= x <= 1
+	*    y = 1             for x > 1
+	*
+	* Since we're using an interval of [a, b] instead of [0, 1]
+	* we have to transform x with (x - a) / (b - a).
+	*/
+	float e;
+
+    if (a == b)
+    {
+		return (x < a) ? 0 : 1;
+    }
+
+    if (x < a) return 0;
+    if (x > b) return 1;
+
+    e = (x - a) / (b - a);
+    return e * e * (3 - 2 * e);
+}
+
+static int point_in_concave_polygon(float x, float y, float *vx, float *vy, short n)
+{
+	int i, j, c = 0;
+	for (i = 0, j = n-1; i < n; j = i++) {
+		if ((((vy[i]<=y) && (y<vy[j])) ||
+				((vy[j]<=y) && (y<vy[i]))) &&
+				(x < (vx[j] - vx[i]) * (y - vy[i]) / (vy[j] - vy[i]) + vx[i]))
+			c = !c;
+	}
+	return c;
+}
+
+static float tiles_bevel_dim(Tex *tex, float w, float h)
+{
+	/* Determine the dimension of the tiles used to compute the bevel */
+	float s;
+	switch (tex->bevoption)
+	{
+		case TEX_BEVEL_UNIFORMMIN:
+			s = MIN2(tex->precalc.minw, tex->precalc.minh);
+			break;
+		case TEX_BEVEL_UNIFORMMAX:
+			s = MIN2(tex->precalc.maxw, tex->precalc.maxh);
+			break;
+		default:
+			s = MIN2(w, h);
+			break;
+	}
+	return s;
+}
+
+static float tiles_rect_func(float x, float y, float w, float h, float b, short bs)
+{
+	/* Calculate signed distance from the 4 sides of the rectangle bounded by:
+	 *   x = 0, y = 0, x = w, y = h.
+	 * The sign indicates whether point is inside, on or outside the rectangle
+	 * aiding us in applying gradients based on sidedness.
+	 *
+	 * NOTE: This is optimized version of tiles_poly_func()
+	 */
+	float dx1 = x;
+	float dy1 = y;
+	float dx2 = w - x;
+	float dy2 = h - y;
+	float v = 0;
+
+	/* Find minimum distance to point from the 4 sides */
+	float dmin;
+
+	if ((x < 0) || (x > w) || (y < 0) || (y > h)) return 0;
+
+	switch (bs)
+	{
+	case TEX_BEVEL_HGRADIENT:
+		dmin = MIN2(dx1, dx2);
+		break;
+	case TEX_BEVEL_VGRADIENT:
+		dmin = MIN2(dy1, dy2);
+		break;
+	default:
+		dmin = MIN4(dx1, dx2, dy1, dy2);
+		break;
+	}
+
+	if (dmin > b) {
+		v = 1;
+	}
+	else if ((dmin >= 0) && (b > 0)) {
+		v = dmin / b;
+	}
+	
+	return v;
+}
+
+static float tiles_rect_func2(float x, float y, float w, float h, float b, float sx, float sy, short bs)
+{
+	/* Calculate signed distance from the 8 lines:
+	 *    x = 0, y = 0, x = w, y = h, 
+	 *    sy * x + sx * y - sx * sy  = 0,
+	 *    sy * x - sx * y + sx * (h - sy) = 0,
+	 *   -sy * x + sx * y + sy * (w - sx) = 0,
+	 *   -sy * x - sx * y + sy * (w - sx) + sx * h = 0
+	 *
+	 * The sign indicates whether point is inside, on or outside the rectangle
+	 * aiding us in applying gradients based on sidedness.
+	 *
+	 * NOTE: This is optimized version of tiles_poly_func()
+	 */
+	float v = tiles_rect_func(x, y, w, h, b, bs);
+ 	float d1 = DIST_POINT_TO_LINE(sy, sx, -sx * sy, x, y);
+	float d2 = DIST_POINT_TO_LINE(sy, -sx, sx * (h - sy), x, y);
+	float d3 = DIST_POINT_TO_LINE(-sy, sx, sy * (w - sx), x, y);
+	float d4 = DIST_POINT_TO_LINE(-sy, -sx, sy * (w - sx) + sx * h, x, y);
+	float d;
+
+	switch (bs) {
+		case TEX_BEVEL_HGRADIENT:
+		case TEX_BEVEL_VGRADIENT:
+			if ((d1 < 0) || (d2 < 0) || (d3 < 0) || (d4 < 0)) d = 0;
+			else d = v;
+			break;
+		default:
+			LINE_BEVEL(d1, b);
+			LINE_BEVEL(d2, b);
+			LINE_BEVEL(d3, b);
+			LINE_BEVEL(d4, b);
+
+			d = MIN4(d1, d2, d3, d4);
+			break;
+	}
+
+	return MIN2(v, d);
+}
+
+static float tiles_poly_func(float x, float y, float *vx, float *vy, short n, float b, short bs)
+{
+	/* Do a linear gradient for an n-sided polygon from 0 for outer edge to 1
+	 * for a distance b from outer edge inside the polygon. Any point beyond
+	 * distance b inside the polygon gets intensity 1.
+	 *
+	 * NOTE: Specify polygon vertices counter-clockwise and n >= 3.
+	 */
+	int i, i1;
+	float p[2], p1[2], p2[2];
+	float m, d, d1, dx;
+	float xmin, xmax, ymin, ymax, w, h;
+
+	/* Determine if p lies in the polygon */
+	p[0] = x;
+	p[1] = y;
+
+	switch (bs) {
+		case TEX_BEVEL_HGRADIENT:
+		case TEX_BEVEL_VGRADIENT:
+			xmin = vx[0];
+			ymin = vy[0];
+			xmax = xmin;
+			ymax = ymin;
+			for (i = 0; i < n; i++)
+			{
+				/* If point lies outside boundary just return 0. */
+				i1 = (i + 1) % n;		
+				p1[0] = vx[i];
+				p1[1] = vy[i];
+				p2[0] = vx[i1];
+				p2[1] = vy[i1];
+				if (SIDE_OF_LINE(p1, p2, p) < 0) {
+					return 0;
+				}
+
+				xmin = MIN2(xmin, vx[i]);
+				ymin = MIN2(ymin, vy[i]);
+				xmax = MAX2(xmax, vx[i]);
+				ymax = MAX2(ymax, vy[i]);
+			}
+
+			w = xmax - xmin;
+			h = ymax - ymin;
+			d = tiles_rect_func(x - xmin, y - ymin, w, h, b, bs);
+			break;
+
+		default:
+			for (i = 0; i < n; i++)
+			{
+				/* If point lies outside boundary just return 0. */
+				i1 = (i + 1) % n;		
+				p1[0] = vx[i];
+				p1[1] = vy[i];
+				p2[0] = vx[i1];
+				p2[1] = vy[i1];
+				if (SIDE_OF_LINE(p1, p2, p) < 0) {
+					return 0;
+				}
+
+				/* Compute distance to the line containing current side */
+				dx = p1[0] - p2[0];
+				if (fabs(dx) > 0) {
+					m = (p1[1] - p2[1]) / dx;
+					d1 = fabs(DIST_POINT_TO_LINE(m, -1, p1[1] - p1[0] * m, x, y));
+				}
+				else
+				{
+					d1 = fabs(x - p1[0]);
+				}
+
+				/* Take minimum distance so far */
+				d = (i == 0) ? d1 : MIN2(d, d1);
+			}
+
+			LINE_BEVEL(d, b);
+			break;
+	}
+	return d;
+}
+
+static float tiles_concave_poly_helper(float x, float y, float *vx, float *vy, int i, int n, float b)
+{
+	int j = i - 1;
+	int k = i + 1;
+	float l;
+	float v1[2], v2[2], v1p[2], v2p[2], vh[2];
+	float p1[2], p2[2], p3[2], p4[2], p[2];
+	float d1, dx, m;
+
+	/* Determine points on either side of point i */
+	if (j < 0) j = n - 1;
+	if (k >= n) k = 0;
+
+	/* Contruct vectors from i to neighbouring points j and k */
+	v1[0] = vx[j] - vx[i]; v1[1] = vy[j] - vy[i];
+	v2[0] = vx[k] - vx[i]; v2[1] = vy[k] - vy[i];
+
+	/* Scale to length b */
+	l = b / sqrt(v1[0] * v1[0] + v1[1] * v1[1]);
+	v1[0] *= l;
+	v1[1] *= l;
+    
+	l = b / sqrt(v2[0] * v2[0] + v2[1] * v2[1]);
+	v2[0] *= l;
+	v2[1] *= l;
+
+	/* Calculate perpendicular vectors (whose length will be b).
+	 * Note the order of signs, we're trying to get vectors that lie inside
+	 * the convex polygon.
+	 */
+	v1p[0] =  v1[1]; v1p[1] = -v1[0];
+	v2p[0] = -v2[1]; v2p[1] =  v2[0];
+
+	/* Add the 2 vectors to get a vector that is halfway between v1p and v2p.
+	 * It is the opposite vector of v1 and v2's angle bisector.
+	 */
+	vh[0] = v1p[0] + v2p[0];
+    vh[1] = v1p[1] + v2p[1];
+    
+	/* p1, p2, p3, p4 define the quad in which points require beveling. */
+	p[0]  = x;				p[1]  = y;
+    p1[0] = vx[i];			p1[1] = vy[i];
+	p2[0] = p1[0] + v2p[0];	p2[1] = p1[1] + v2p[1];
+	p3[0] = p1[0] + vh[0];	p3[1] = p1[1] + vh[1];
+	p4[0] = p1[0] + v1p[0];	p4[1] = p1[1] + v1p[1];
+	
+	/* Depending on which side of the vector vh the point falls, apply a bevel with
+	 * corresponding side of the polygon.
+	 */
+	d1 = 1;
+	if (POINT_IN_TRI(p, p1, p2, p3)) {
+		dx = vx[i] - vx[k];
+		if (fabs(dx) > 0) {
+			m = (vy[i] - vy[k]) / dx;
+			d1 = fabs(DIST_POINT_TO_LINE(m, -1, vy[i] - vx[i] * m, x, y));
+		}
+		else {
+			d1 = fabs(x - vx[i]);
+		}
+	}
+	else if (POINT_IN_TRI(p, p1, p3, p4)) {
+		dx = vx[j] - vx[i];
+		if (fabs(dx) > 0) {
+			m = (vy[j] - vy[i]) / dx;
+			d1 = fabs(DIST_POINT_TO_LINE(m, -1, vy[j] - vx[j] * m, x, y));
+		}
+		else {
+			d1 = fabs(x - vx[j]);
+		}
+	}
+
+	return d1;
+}
+
+static float tiles_concave_poly_func(float x, float y, float *vx, float *vy, short n, float b, short bs)
+{
+	/* Handles both convex, concave and overlapping polygons */
+	int i, j, c = 0, set = 0;
+	float d = 0, d1, dx, m;
+	float doti, dotj;
+	float xmin, xmax, ymin, ymax, w, h;
+
+	switch (bs) {
+		case TEX_BEVEL_HGRADIENT:
+		case TEX_BEVEL_VGRADIENT:
+			xmin = vx[0];
+			ymin = vy[0];
+			xmax = xmin;
+			ymax = ymin;
+			for (i = 0, j = n-1; i < n; j = i++) {
+				if ((((vy[i] <= y) && (y < vy[j])) || 
+					((vy[j] <= y) && (y < vy[i]))) &&
+					(x < (vx[j] - vx[i]) * (y - vy[i]) / (vy[j] - vy[i]) + vx[i]))
+				{
+					c = !c;
+				}
+
+				xmin = MIN2(xmin, vx[i]);
+				ymin = MIN2(ymin, vy[i]);
+				xmax = MAX2(xmax, vx[i]);
+				ymax = MAX2(ymax, vy[i]);
+			}
+			if (c) {
+				w = xmax - xmin;
+				h = ymax - ymin;
+				d = tiles_rect_func(x - xmin, y - ymin, w, h, b, bs);
+			}
+			else {
+				d = 0;
+			}			
+			break;
+
+		default:
+			for (i = 0, j = n-1; i < n; j = i++) {
+				if ((((vy[i] <= y) && (y < vy[j])) || 
+					((vy[j] <= y) && (y < vy[i]))) &&
+					(x < (vx[j] - vx[i]) * (y - vy[i]) / (vy[j] - vy[i]) + vx[i]))
+				{
+					c = !c;
+				}
+				
+				/* Check if angles formed at points on the segment are obtuse to determine if
+				* the point falls between perpendicular lines at segment endpoints.
+				*/
+				doti = (vx[j] - vx[i]) * (x - vx[i]) + (vy[j] - vy[i]) * (y - vy[i]);
+				dotj = (vx[i] - vx[j]) * (x - vx[j]) + (vy[i] - vy[j]) * (y - vy[j]);
+
+				if ((doti >= 0) && (dotj >= 0)) {
+					/* Compute distance to the line containing current side */
+					dx = vx[j] - vx[i];
+					if (fabs(dx) > 0) {
+						m = (vy[j] - vy[i]) / dx;
+						d1 = fabs(DIST_POINT_TO_LINE(m, -1, vy[j] - vx[j] * m, x, y));
+					}
+					else {
+						d1 = fabs(x - vx[j]);
+					}
+					
+					/* Take minimum distance so far */
+					d = set ? MIN2(d, d1) : d1;
+					set = 1;
+				}
+				else if (doti < 0) {
+					d1 = tiles_concave_poly_helper(x, y, vx, vy, i, n, b);
+					d = set ? MIN2(d, d1) : d1;
+					set = 1;
+				}
+				else {
+					d1 = tiles_concave_poly_helper(x, y, vx, vy, j, n, b);
+					d = set ? MIN2(d, d1) : d1;
+					set = 1;
+				}
+			}
+			if (c) {
+				LINE_BEVEL(d, b);
+			}
+			else {
+				d = 0;
+			}			
+			break;
+	}
+	return d;
+}
+
+static float tiles_circle_func1(float x, float y, float cx, float cy, float b, float r)
+{
+	/* Calculate signed distance from the circle bounded by:
+	 *   (x - cx)^2 + (y - cy)^2 = r^2
+	 * The sign indicates whether point is inside, on or outside the circle
+	 * aiding us in applying gradients based on sidedness.
+	 *
+	 * For points that lie within a distance of r - b from the center the intensity is 1.
+	 * For points at distance of r - b to r, the intensity is linear from 1 to 0.
+	 * For all other points the intensity is 0.
+	 */
+	float dx = (x - cx);
+    float dy = (y - cy);
+    float d = r - sqrt(dx * dx + dy * dy);
+	
+	float v = 0;
+	if (d > b) {
+		v = 1;
+	}
+	else if ((d >= 0) && (b > 0)) {
+		v = d / b;
+	}
+
+	return v;
+}
+
+static float tiles_circle_func2(float x, float y, float cx, float cy, float b, float r)
+{
+	/* Calculate signed distance from the circle bounded by:
+	 *   (x - cx)^2 + (y - cy)^2 = r^2
+	 * The sign indicates whether point is inside, on or outside the circle
+	 * aiding us in applying gradients based on sidedness.
+	 *
+	 * For points that lie within a distance of r - b from the center the intensity is 0.
+	 * For points at distance of r - b to r, the intensity is linear from 0 to 1.
+	 * For all other points the intensity is 1.
+	 */
+	float dx = (x - cx);
+    float dy = (y - cy);
+    float d = sqrt(dx * dx + dy * dy) - r;
+	
+	float v = 0;
+	if (d > b) {
+		v = 1;
+	}
+	else if ((d >= 0) && (b > 0)) {
+		v = d / b;
+	}
+
+	return v;
+}
+
+static float tiles_roundrect_func(float x, float y, float w, float h, float b, float r, short flip, short bs)
+{
+	/* First compute the intensity inside the rectangle bounded by (0, 0) and (w, h). */
+	float v = tiles_rect_func(x, y, w, h, b, bs);
+	float t = v;
+	float hw = w * 0.5;
+	float hh = h * 0.5;
+
+	if (flip) {
+		switch (bs) {
+			case TEX_BEVEL_HGRADIENT:
+			case TEX_BEVEL_VGRADIENT:
+				/* For points that lie inside the four corners determine if they fall inside the circle
+				 * centered at the corners use black.
+				 */
+				if ((x >= 0) && (x <= hw)) {
+					if ((y >= 0) && (y <= hh)) {
+						if (POINT_IN_CIRCLE(x, y, 0, 0, r)) t = 0;
+					}
+					else if ((y > hh) && (y <= h)) {
+						if (POINT_IN_CIRCLE(x, y, 0, h, r)) t = 0;
+					}
+				}
+				else if ((x > hw) && (x <= w)) {
+					if ((y >= 0) && (y <= hh)) {
+						if (POINT_IN_CIRCLE(x, y, w, 0, r)) t = 0;
+					}
+					else if ((y > hh) && (y <= h)) {
+						if (POINT_IN_CIRCLE(x, y, w, h, r)) t = 0;
+					}
+				}
+				break;
+			default:
+				/* For points that lie inside the four corners determine if they fall inside the circle
+				 * centered at the corners and apply a linear gradient. This does the inverted circular
+				 * shape.
+				 */
+				if ((x >= 0) && (x <= hw)) {
+					if ((y >= 0) && (y <= hh)) {
+						t = tiles_circle_func2(x, y, 0, 0, b, r);
+					}
+					else if ((y > hh) && (y <= h)) {
+						t = tiles_circle_func2(x, y, 0, h, b, r);
+					}
+				}
+				else if ((x > hw) && (x <= w)) {
+					if ((y >= 0) && (y <= hh)) {
+						t = tiles_circle_func2(x, y, w, 0, b, r);
+					}
+					else if ((y > hh) && (y <= h)) {
+						t = tiles_circle_func2(x, y, w, h, b, r);
+					}
+				}
+				break;
+		}
+	}
+	else {
+		switch (bs) {
+			case TEX_BEVEL_HGRADIENT:
+			case TEX_BEVEL_VGRADIENT:
+				/* For points that lie inside the four corners determine if they fall outside the circle
+				 * centered at the offset by the radius use black.
+				 */
+				if ((x >= 0) && (x <= r)) {
+					if ((y >= 0) && (y <= r)) {
+						if (POINT_NOT_IN_CIRCLE(x, y, r, r, r)) t = 0;
+					}
+					else if ((y >= h - r) && (y <= h)) {
+						if (POINT_NOT_IN_CIRCLE(x, y, r, h - r, r)) t = 0;
+					}
+				}
+				else if ((x >= w - r) && (x <= w)) {
+					if ((y >= 0) && (y <= r)) {
+						if (POINT_NOT_IN_CIRCLE(x, y, w - r, r, r)) t = 0;
+					}
+					else if ((y >= h - r) && (y <= h)) {
+						if (POINT_NOT_IN_CIRCLE(x, y, w - r, h - r, r)) t = 0;
+					}
+				}
+				break;
+			default:
+				/* For points that lie inside the four corners determine if they fall inside the circle
+				 * centered at the offset by the radius and apply a linear gradient.
+				 */
+				if ((x >= 0) && (x <= r)) {
+					if ((y >= 0) && (y <= r)) {
+						t = tiles_circle_func1(x, y, r, r, b, r);
+					}
+					else if ((y >= h - r) && (y <= h)) {
+						t = tiles_circle_func1(x, y, r, h - r, b, r);
+					}
+				}
+				else if ((x >= w - r) && (x <= w)) {
+					if ((y >= 0) && (y <= r)) {
+						t = tiles_circle_func1(x, y, w - r, r, b, r);
+					}
+					else if ((y >= h - r) && (y <= h)) {
+						t = tiles_circle_func1(x, y, w - r, h - r, b, r);
+					}
+				}
+				break;
+		}
+	}
+	return MIN2(t, v);
+}
+
+static float tiles_ellipse_func1(float x, float y, float cx, float cy, float b, float rx, float ry)
+{
+	/* Calculate signed distance from the ellipse bounded by:
+	 *   [(x - cx) / rx]^2 + [(y - cy) / ry]^2 = 1
+	 * The sign indicates whether point is inside, on or outside the ellipse
+	 * aiding us in applying gradients based on sidedness.
+	 *
+	 * For points inside the ellipse from the center to distance b from the curve, intensity is 1.
+	 * For points starting at distance b from the curve to the curve, the intensity is linear from 1 to 0.
+	 * For all other points the intensity is 0.
+	 */
+	float v, c, x1, y1, d, f, r2;
+
+	/* Shift origin to (0, 0) */
+	x -= cx;
+	y -= cy;
+
+	/* Compute the point (x1, y1) on the ellipse that forms a line through
+	 * (0, 0) and (x, y).
+	 */
+	f = sqrt(x * x * ry * ry + y * y * rx * rx);
+	r2 = rx * ry;
+	c = r2 / f;
+	x1 = x * c;
+	y1 = y * c;
+
+	/* Compute distance between the given point and computed point */
+	d = sqrt((x - x1)*(x - x1) + (y - y1)*(y - y1));
+
+	v = 0;
+
+	/* Test signed distance to see if point is inside or outside the ellipse */
+	if (f <= r2) {
+		/* Apply linear gradient */
+		if (d > b) {
+			v = 1;
+		}
+		else if (b > 0) {
+			v = d / b;
+		}
+	}
+
+	return v;
+}
+
+static float tiles_ellipse_func2(float x, float y, float cx, float cy, float b, float rx, float ry)
+{
+	/* Calculate signed distance from the ellipse bounded by:
+	 *   [(x - cx) / rx]^2 + [(y - cy) / ry]^2 = 1
+	 * The sign indicates whether point is inside, on or outside the ellipse
+	 * aiding us in applying gradients based on sidedness.
+	 *
+	 * For points inside the ellipse from the center to distance b from the curve, intensity is 0.
+	 * For points starting at distance b from the curve to the curve, the intensity is linear from 0 to 1.
+	 * For all other points the intensity is 1.
+	 */
+	float v, c, x1, y1, d, f, r2;
+
+	/* Shift origin to (0, 0) */
+	x -= cx;
+	y -= cy;
+
+	/* Compute the point (x1, y1) on the ellipse that forms a line through
+	 * (0, 0) and (x, y).
+	 */
+	f = sqrt(x * x * ry * ry + y * y * rx * rx);
+	r2 = rx * ry;
+	c = r2 / f;
+	x1 = x * c;
+	y1 = y * c;
+
+	/* Compute distance between the given point and computed point */
+	d = sqrt((x - x1)*(x - x1) + (y - y1)*(y - y1));
+
+	v = 0;
+
+	/* Test signed distance to see if point is inside or outside the ellipse */
+	if (f >= r2) {
+		/* Apply linear gradient */
+		if (d > b) {
+			v = 1;
+		}
+		else if (b > 0) {
+			v = d / b;
+		}
+	}
+
+	return v;
+}
+
+static float tiles_ellipserect_func(float x, float y, float w, float h, float b, float rx, float ry, short flip, short bs)
+{
+	/* First compute the intensity inside the rectangle bounded by (0, 0) and (w, h). */
+	float v = tiles_rect_func(x, y, w, h, b, bs);
+	float t = v;
+	float hw = w * 0.5;
+	float hh = h * 0.5;
+
+	if (flip) {
+		switch (bs) {
+			case TEX_BEVEL_HGRADIENT:
+			case TEX_BEVEL_VGRADIENT:
+				/* For points that lie inside the four corners determine if they fall inside the ellipse
+				 * centered at the corners use black.
+				 */
+				if ((x >= 0) && (x <= hw)) {
+					if ((y >= 0) && (y <= hh)) {
+						if (POINT_IN_ELLIPSE(x, y, 0, 0, rx, ry)) t = 0;
+					}
+					else if ((y > hh) && (y <= h)) {
+						if (POINT_IN_ELLIPSE(x, y, 0, h, rx, ry)) t = 0;
+					}
+				}
+				else if ((x > hw) && (x <= w)) {
+					if ((y >= 0) && (y <= hh)) {
+						if (POINT_IN_ELLIPSE(x, y, w, 0, rx, ry)) t = 0;
+					}
+					else if ((y > hh) && (y <= h)) {
+						if (POINT_IN_ELLIPSE(x, y, w, h, rx, ry)) t = 0;
+					}
+				}
+				break;
+
+			default:
+				/* For points that lie inside the four corners determine if they fall inside the ellipse
+				 * centered at the corners and apply a linear gradient. This does the inverted circular
+				 * shape.
+				 */
+				if ((x >= 0) && (x <= hw)) {
+					if ((y >= 0) && (y <= hh)) {
+						t = tiles_ellipse_func2(x, y, 0, 0, b, rx, ry);
+					}
+					else if ((y > hh) && (y <= h)) {
+						t = tiles_ellipse_func2(x, y, 0, h, b, rx, ry);
+					}
+				}
+				else if ((x > hw) && (x <= w)) {
+					if ((y >= 0) && (y <= hh)) {
+						t = tiles_ellipse_func2(x, y, w, 0, b, rx, ry);
+					}
+					else if ((y > hh) && (y <= h)) {
+						t = tiles_ellipse_func2(x, y, w, h, b, rx, ry);
+					}
+				}
+				break;
+		}
+	}
+	else {
+		switch (bs) {
+			case TEX_BEVEL_HGRADIENT:
+			case TEX_BEVEL_VGRADIENT:
+				/* For points that lie inside the four corners determine if they fall outside the ellipse
+				 * centered at the offset by the radius use black.
+				 */
+				if ((x >= 0) && (x <= rx)) {
+					if ((y >= 0) && (y <= ry)) {
+						if (POINT_NOT_IN_ELLIPSE(x, y, rx, ry, rx, ry)) t = 0;
+					}
+					else if ((y >= h - ry) && (y <= h)) {
+						if (POINT_NOT_IN_ELLIPSE(x, y, rx, h - ry, rx, ry)) t = 0;
+					}
+				}
+				else if ((x >= w - rx) && (x <= w)) {
+					if ((y >= 0) && (y <= ry)) {
+						if (POINT_NOT_IN_ELLIPSE(x, y, w - rx, ry, rx, ry)) t = 0;
+					}
+					else if ((y >= h - ry) && (y <= h)) {
+						if (POINT_NOT_IN_ELLIPSE(x, y, w - rx, h - ry, rx, ry)) t = 0;
+					}
+				}
+				break;
+			default:
+				/* For points that lie inside the four corners determine if they fall inside the ellipse
+				 * centered at the offset (rx, ry) and apply a linear gradient.
+				 */
+				if ((x >= 0) && (x <= rx)) {
+					if ((y >= 0) && (y <= ry)) {
+						t = tiles_ellipse_func1(x, y, rx, ry, b, rx, ry);
+					}
+					else if ((y >= h - ry) && (y <= h)) {
+						t = tiles_ellipse_func1(x, y, rx, h - ry, b, rx, ry);
+					}
+				}
+				else if ((x >= w - rx) && (x <= w)) {
+					if ((y >= 0) && (y <= ry)) {
+						t = tiles_ellipse_func1(x, y, w - rx, ry, b, rx, ry);
+					}
+					else if ((y >= h - ry) && (y <= h)) {
+						t = tiles_ellipse_func1(x, y, w - rx, h - ry, b, rx, ry);
+					}
+				}
+				break;
+		}
+	}
+	return MIN2(t, v);
+}
+
+/* Note: bs will override tex->bevelshading. To avoid that pass in tex->bevelshading for this param */
+static float tiles_recthelper_int(Tex *tex, float x, float y, float w, float h, float dim, float b, short bs)
+{
+	float rx, ry, intens;
+
+	switch (tex->corner) {
+		case TEX_CORNER_ROUND:
+			if (tex->hcorner == tex->vcorner) {
+                rx = tex->hcorner * dim;
+				intens = tiles_roundrect_func(x, y, w, h, b, rx, 0, bs);
+			}
+			else {
+				rx = tex->hcorner * dim;
+				ry = tex->vcorner * dim;
+				intens = tiles_ellipserect_func(x, y, w, h, b, rx, ry, 0, bs);
+			}			
+			break;
+		case TEX_CORNER_ROUND_INV:
+			if (tex->hcorner == tex->vcorner) {
+                rx = tex->hcorner * dim;
+				intens = tiles_roundrect_func(x, y, w, h, b, rx, 1, bs);
+			}
+			else {
+				rx = tex->hcorner * dim;
+				ry = tex->vcorner * dim;
+				intens = tiles_ellipserect_func(x, y, w, h, b, rx, ry, 1, bs);
+			}			
+			break;
+		case TEX_CORNER_ELLIPSE:
+			rx = tex->hcorner * w;
+			ry = tex->vcorner * h;
+			intens = tiles_ellipserect_func(x, y, w, h, b, rx, ry, 0, bs);
+			break;
+		case TEX_CORNER_ELLIPSE_INV:
+			rx = tex->hcorner * w;
+			ry = tex->vcorner * h;
+			intens = tiles_ellipserect_func(x, y, w, h, b, rx, ry, 1, bs);
+			break;
+		case TEX_CORNER_STRAIGHT:
+			rx = tex->hcorner * w;
+			ry = tex->vcorner * h;
+			intens = tiles_rect_func2(x, y, w, h, b, rx, ry, bs);
+			break;
+		default:
+			intens = tiles_rect_func(x, y, w, h, b, bs);
+			break;
+	}
+
+	return intens;
+}
+
+static void tiles_default_col(Tex *tex, float intens, short htileid, short vtileid, float *col)
+{
+	float intens1 = 1.0 - intens;
+	col[0] = tex->precalc.r[htileid][vtileid] * intens + tex->colr2 * intens1;
+	col[1] = tex->precalc.g[htileid][vtileid] * intens + tex->colg2 * intens1;
+	col[2] = tex->precalc.b[htileid][vtileid] * intens + tex->colb2 * intens1;
+}
+
+static void tiles_neighbour_col(Tex *tex, float *intens, short htileid, short vtileid, short id, short i, float *col)
+{
+	float intens1 = 1.0 - (*intens);
+	float s;
+	short htileidl, htileidr, vtileida, vtileidb;
+
+	/* Compute indices of neighbouring tiles */
+	htileidr = (htileid + 1) % tex->hcount;					/* Right */
+	htileidl = (htileid - 1 + tex->hcount) % tex->hcount;	/* Left  */
+	vtileida = (vtileid + 1) % tex->vcount;					/* Above */
+	vtileidb = (vtileid - 1 + tex->vcount) % tex->vcount;	/* Below */
+
+	/* Default colour of current tile */
+	col[0] = tex->precalc.r[htileid][vtileid];
+	col[1] = tex->precalc.g[htileid][vtileid];
+	col[2] = tex->precalc.b[htileid][vtileid];
+	s = tex->precalc.bpat[htileid][vtileid];
+
+	/* Add colours of neighbouring tiles and do uniform average */
+	switch (id) {
+		case TILE_BELOW:
+			col[0] += tex->precalc.r[htileid][vtileidb];
+			col[1] += tex->precalc.g[htileid][vtileidb];
+			col[2] += tex->precalc.b[htileid][vtileidb];
+			col[0] *= 0.5;
+			col[1] *= 0.5;
+			col[2] *= 0.5;
+
+			s += tex->precalc.bpat[htileid][vtileidb];
+			s *= 0.5;
+
+			break;
+		case TILE_ABOVE:
+			col[0] += tex->precalc.r[htileid][vtileida];
+			col[1] += tex->precalc.g[htileid][vtileida];
+			col[2] += tex->precalc.b[htileid][vtileida];
+			col[0] *= 0.5;
+			col[1] *= 0.5;
+			col[2] *= 0.5;
+
+			s += tex->precalc.bpat[htileid][vtileida];
+			s *= 0.5;
+
+			break;
+		case TILE_LEFT:
+			col[0] += tex->precalc.r[htileidl][vtileid];
+			col[1] += tex->precalc.g[htileidl][vtileid];
+			col[2] += tex->precalc.b[htileidl][vtileid];
+			col[0] *= 0.5;
+			col[1] *= 0.5;
+			col[2] *= 0.5;
+
+			s += tex->precalc.bpat[htileidl][vtileid];
+			s *= 0.5;
+
+			break;
+		case TILE_RIGHT:
+			col[0] += tex->precalc.r[htileidr][vtileid];
+			col[1] += tex->precalc.g[htileidr][vtileid];
+			col[2] += tex->precalc.b[htileidr][vtileid];
+			col[0] *= 0.5;
+			col[1] *= 0.5;
+			col[2] *= 0.5;
+
+			s += tex->precalc.bpat[htileidr][vtileid];
+			s *= 0.5;
+
+			break;
+		case TILE_LEFT_BELOW:
+			col[0] += tex->precalc.r[htileidl][vtileid] + tex->precalc.r[htileidl][vtileidb] + tex->precalc.r[htileid][vtileidb];
+			col[1] += tex->precalc.g[htileidl][vtileid] + tex->precalc.g[htileid][vtileidb] + tex->precalc.g[htileidl][vtileidb];
+			col[2] += tex->precalc.b[htileidl][vtileid] + tex->precalc.b[htileidl][vtileidb] + tex->precalc.b[htileid][vtileidb];
+			col[0] *= 0.25;
+			col[1] *= 0.25;
+			col[2] *= 0.25;
+
+			s += tex->precalc.bpat[htileidl][vtileid] + tex->precalc.bpat[htileidl][vtileidb] + tex->precalc.bpat[htileid][vtileidb];
+			s *= 0.25;
+
+			break;
+		case TILE_LEFT_ABOVE:
+			col[0] += tex->precalc.r[htileidl][vtileid] + tex->precalc.r[htileidl][vtileida] + tex->precalc.r[htileid][vtileida];
+			col[1] += tex->precalc.g[htileidl][vtileid] + tex->precalc.g[htileid][vtileida] + tex->precalc.g[htileidl][vtileida];
+			col[2] += tex->precalc.b[htileidl][vtileid] + tex->precalc.b[htileidl][vtileida] + tex->precalc.b[htileid][vtileida];
+			col[0] *= 0.25;
+			col[1] *= 0.25;
+			col[2] *= 0.25;
+
+			s += tex->precalc.bpat[htileidl][vtileid] + tex->precalc.bpat[htileidl][vtileida] + tex->precalc.bpat[htileid][vtileida];
+			s *= 0.25;
+
+			break;
+		case TILE_RIGHT_BELOW:
+			col[0] += tex->precalc.r[htileidr][vtileid] + tex->precalc.r[htileidr][vtileidb] + tex->precalc.r[htileid][vtileidb];
+			col[1] += tex->precalc.g[htileidr][vtileid] + tex->precalc.g[htileid][vtileidb] + tex->precalc.g[htileidr][vtileidb];			
+			col[2] += tex->precalc.b[htileidr][vtileid] + tex->precalc.b[htileidr][vtileidb] + tex->precalc.b[htileid][vtileidb];
+			col[0] *= 0.25;
+			col[1] *= 0.25;
+			col[2] *= 0.25;
+
+			s += tex->precalc.bpat[htileidr][vtileid] + tex->precalc.bpat[htileidr][vtileidb] + tex->precalc.bpat[htileid][vtileidb];
+			s *= 0.25;
+
+			break;
+		case TILE_RIGHT_ABOVE:
+			col[0] += tex->precalc.r[htileidr][vtileid] + tex->precalc.r[htileidr][vtileida] + tex->precalc.r[htileid][vtileida];
+			col[1] += tex->precalc.g[htileidr][vtileid] + tex->precalc.g[htileid][vtileida] + tex->precalc.g[htileidr][vtileida];
+			col[2] += tex->precalc.b[htileidr][vtileid] + tex->precalc.b[htileidr][vtileida] + tex->precalc.b[htileid][vtileida];
+			col[0] *= 0.25;
+			col[1] *= 0.25;
+			col[2] *= 0.25;
+
+			s += tex->precalc.bpat[htileidr][vtileid] + tex->precalc.bpat[htileidr][vtileida] + tex->precalc.bpat[htileid][vtileida];
+			s *= 0.25;
+
+			break;
+	}
+	*intens *= s;
+
+	/* Additional random scaling */
+	if (i >= 0) *intens *= tex->precalc.rpat[i];
+
+	/* Linearly interpolate the 2 colours */
+	col[0] = col[0] * (*intens) + tex->colr2 * intens1;
+	col[1] = col[1] * (*intens) + tex->colg2 * intens1;
+	col[2] = col[2] * (*intens) + tex->colb2 * intens1;
+}
+
+static float tiles_bevel_func(Tex *tex, float intens)
+{
+	float icubic1, icubic2, i;
+
+	/* Apply bevel strength and center the result in [0, 1] */
+	intens *= tex->strength;
+	intens += (1.0 - tex->strength) * 0.5;
+
+	/* Map the intensity x to the 2 functions: x^3, 1+(x-1)^3. */
+	icubic1 = intens * intens * intens;
+	icubic2 = intens - 1.0;
+	icubic2 *= icubic2 * icubic2;
+	icubic2 += 1.0;
+
+	if (tex->curve <= 0) {
+		/* Do a linear blend between 1 + (x - 1)^3 and x functions */
+		i = tex->curve + 1;
+		intens = (1 - i) * icubic2 + i * intens;
+	}
+	else {
+		/* Do a linear blend between x and xi^3 functions */
+		i = tex->curve;
+		intens = (1 - i) * intens + i * icubic1;
+	}
+
+	/* Smooth out the result using a cubic step function */
+	if (tex->smooth) {
+		intens = smoothstep(intens, 0, 1);
+	}
+
+	return intens;
+}
+
+static float tiles_default_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	/* This handles the default tiling with different corner styles */
+	float intens;
+	float w, h, dim;
+
+	/* Compute tile dimensions */
+	w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	/* Bevel */
+	dim = tiles_bevel_dim(tex, w, h);
+
+	/* Compute intensity. */
+	intens = tiles_recthelper_int(tex, x, y, w, h, dim, dim * tex->bevel, tex->bevelshading);
+	intens *= tex->precalc.bpat[htileid][vtileid];
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_default_col(tex, intens, htileid, vtileid, col);
+
+	return intens;
+}
+
+static float tiles_cross1_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float dim = tiles_bevel_dim(tex, w, h);
+	float b = dim * tex->bevel;
+	float intens = 0;
+	short id = TILE_CURRENT;
+	short bs = tex->bevelshading;
+	float vx[12], vy[12];
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	vx[0] = w * 0.25;	vy[0] = 0;
+	vx[1] = w * 0.75;	vy[1] = 0;
+	vx[2] = w * 0.75;	vy[2] = h * 0.25;
+	vx[3] = w;			vy[3] = h * 0.25;
+	vx[4] = w;			vy[4] = h * 0.75;
+	vx[5] = w * 0.75;	vy[5] = h * 0.75;
+	vx[6] = w * 0.75;	vy[6] = h;
+	vx[7] = w * 0.25;	vy[7] = h;
+	vx[8] = w * 0.25;	vy[8] = h * 0.75;
+	vx[9] = 0;			vy[9] = h * 0.75;
+	vx[10]= 0;			vy[10]= h * 0.25;
+	vx[11]= w * 0.25;	vy[11]= h * 0.25;
+
+	intens = tiles_concave_poly_func(x, y, vx, vy, 12, b, bs);
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+
+	return intens;
+}
+
+static float tiles_cross2_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float dim = tiles_bevel_dim(tex, w, h);
+	float b = dim * tex->bevel;
+	float intens = 0;
+	short id = TILE_CURRENT;
+	short bs = tex->bevelshading;
+	float vx[12], vy[12];
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	vx[0] = w * 0.15;	vy[0] = 0;
+	vx[1] = w * 0.85;	vy[1] = 0;
+	vx[2] = w * 0.75;	vy[2] = h * 0.25;
+	vx[3] = w;			vy[3] = h * 0.15;
+	vx[4] = w;			vy[4] = h * 0.85;
+	vx[5] = w * 0.75;	vy[5] = h * 0.75;
+	vx[6] = w * 0.85;	vy[6] = h;
+	vx[7] = w * 0.15;	vy[7] = h;
+	vx[8] = w * 0.25;	vy[8] = h * 0.75;
+	vx[9] = 0;			vy[9] = h * 0.85;
+	vx[10]= 0;			vy[10]= h * 0.15;
+	vx[11]= w * 0.25;	vy[11]= h * 0.25;
+
+	intens = tiles_concave_poly_func(x, y, vx, vy, 12, b, bs);
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+
+	return intens;
+}
+
+static float tiles_hex_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	/* The tight honeycomb pattern is generated using tiles that are not shifted every
+	 * row. So assuming, the rows are not being shifted, we can do a "lollipop" shape
+	 * with a hexagon which will stretch from one rectangular cell to another but will
+	 * remain seamless as long as tex->hgap = tex->vgap = 0.
+	 *     _______
+	 *    /       \
+	 *   /         \_______
+	 *   \         /
+	 *    \_______/
+	 *     
+	 * Now note that points that fall above and below the "stick" AND points that fall
+	 * to the left of the hexagon have to be tested inside a hexagon that is in the neighbouring
+	 * tile. A total of 5 hexagon's need to tested for inclusion of given point.
+	 */
+	float c = 1.0 / 6.0;
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float d = w * c;
+	float r = h * 0.5;
+	float b = tiles_bevel_dim(tex, 4 * d, h) * tex->bevel;	/* Hex part is 4*d wide */
+	float wl, wr, dl, dr;
+	float ha, hb, ra, rb;
+	short htidl, htidr, vtida, vtidb;
+	float intens = 0;
+	float intens2;
+	short id = TILE_CURRENT; /* Determines how to use color and bump info from neighbouring tiles */
+	float vx[6], vy[6];
+	short bs = tex->bevelshading;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	/* Width of tile to right */
+	htidr = (htileid + 1) % tex->hcount;
+	wr = tex->precalc.hpat[htidr + 1] - tex->precalc.hpat[htidr] - tex->precalc.hgap;
+    dr = wr * c;
+	/* Width of tile to left */
+	htidl = (htileid - 1 + tex->hcount) % tex->hcount;
+	wl = tex->precalc.hpat[htidl + 1] - tex->precalc.hpat[htidl] - tex->precalc.hgap;
+	dl = wl * c;
+	/* Height of tile above */
+	vtida = (vtileid + 1) % tex->vcount;
+	ha = tex->precalc.vpat[vtida + 1] - tex->precalc.vpat[vtida] - tex->precalc.vgap;
+	ra = ha * 0.5;
+	/* Height of tile below */
+	vtidb = (vtileid - 1 + tex->vcount) % tex->vcount;
+	hb = tex->precalc.vpat[vtidb + 1] - tex->precalc.vpat[vtidb] - tex->precalc.vgap;
+	rb = hb * 0.5;
+
+	/* Handle hexagon in current tile */
+	vx[0] = d;		vy[0] = 0;
+	vx[1] = 3 * d;	vy[1] = 0;
+	vx[2] = 4 * d;	vy[2] = r;
+	vx[3] = 3 * d;	vy[3] = h;
+	vx[4] = d;		vy[4] = h;
+	vx[5] = 0;		vy[5] = r;
+	intens = tiles_poly_func(x, y, vx, vy, 6, b, bs);
+
+	/* Handle sections that overlap with other tiles. Note that we do a MAX of current
+	 * intens value with the next tile in question. This cleans up the code and seems
+	 * to fix up any artifacts in the bevels.
+	 */
+	if ((x >= 3 * d) && (x <= w)) {
+		/* Take the width of the next tile to the right into consideration */
+		if ((y >= 0) && (y <= r)) {
+			/* Take the height of the next tile below into consideration */
+			b = tiles_bevel_dim(tex, 3 * d + dr, r + rb) * tex->bevel;
+			vx[0] = 4 * d;	vy[0] = -rb;
+			vx[1] = w;		vy[1] = -rb;
+			vx[2] = w + dr;	vy[2] =  0;
+			vx[3] = w;		vy[3] =  r;
+			vx[4] = 4 * d;	vy[4] =  r;
+			vx[5] = 3 * d;	vy[5] =  0;
+			intens2 = tiles_poly_func(x, y, vx, vy, 6, b, bs);
+			if (intens2 > intens) {
+				intens = intens2;
+                id = TILE_RIGHT_BELOW;
+			}
+		}
+		else if ((y > r) && (y <= h)) {
+			/* Take the height of the next tile above into consideration */
+			b = tiles_bevel_dim(tex, 3 * d + dr, r + ra) * tex->bevel;
+			vx[0] = 4 * d;	vy[0] = r;
+			vx[1] = w;		vy[1] = r;
+			vx[2] = w + dr;	vy[2] = h;
+			vx[3] = w;		vy[3] = h + ra;
+			vx[4] = 4 * d;	vy[4] = h + ra;
+			vx[5] = 3 * d;	vy[5] = h;
+			intens2 = tiles_poly_func(x, y, vx, vy, 6, b, bs);
+			if (intens2 > intens) {
+				intens = intens2;
+                id = TILE_RIGHT_ABOVE;
+			}
+		}
+	}
+	else if ((x >= 0) && (x <= d)) {
+		/* Take the width of the next tile to the left into consideration */
+		if ((y >= 0) && (y <= r)) {
+			/* Take the height of the next tile below into consideration */
+			b = tiles_bevel_dim(tex, 3 * dl + d, r + rb) * tex->bevel;
+			vx[0] =  d;			vy[0] =  0;
+			vx[1] =  0;			vy[1] =  r;
+			vx[2] = -2 * dl;	vy[2] =  r;
+			vx[3] = -3 * dl;	vy[3] =  0;
+			vx[4] = -2 * dl;	vy[4] = -rb;
+			vx[5] =  0;			vy[5] = -rb;
+			intens2 = tiles_poly_func(x, y, vx, vy, 6, b, bs);
+			if (intens2 > intens) {
+				intens = intens2;
+                id = TILE_LEFT_BELOW;
+			}
+		}
+		else if ((y > r) && (y <= h)) {
+			/* Take the height of the next tile above into consideration */
+			b = tiles_bevel_dim(tex, 3 * dl + d, r + ra) * tex->bevel;
+			vx[0] =  d;			vy[0] = h;
+			vx[1] =  0;			vy[1] = h + ra;
+			vx[2] = -2 * dl;	vy[2] = h + ra;
+			vx[3] = -3 * dl;	vy[3] = h;
+			vx[4] = -2 * dl;	vy[4] = r;
+			vx[5] =  0;			vy[5] = r;
+			intens2 = tiles_poly_func(x, y, vx, vy, 6, b, bs);
+			if (intens2 > intens) {
+				intens = intens2;
+                id = TILE_LEFT_ABOVE;
+			}
+		}
+	}
+	
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+	
+	return intens;
+}
+
+static float tiles_herringbone_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, short n, float *col)
+{
+	/* Creates a nx1 seamless pattern for herringbone tiling where n >= 2. */
+
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float w1 = 0.5 * w;
+	float h1 = 0.5 * h;
+	float half_over_n = 0.5 / (float)n;
+	float xstep = w * half_over_n;
+	float ystep = h * half_over_n;
+	float dim, b;
+	short loop = 1;
+	float xi, yi;
+	float intens = 0;
+	short i = -1;	/* Used to determine sections that cross seams */
+	short id = TILE_CURRENT;
+	short bs;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	while (loop) {
+		if ((x < 0) || (x > w) || (y < 0) || (y > h)) break;
+
+		/* Handle horizontal bars */
+		dim = tiles_bevel_dim(tex, w1, ystep);
+		if (tex->bevelshading == TEX_BEVEL_PATTERN) {
+			bs = (tex->corner == TEX_CORNER_STRAIGHT) ? TEX_BEVEL_VGRADIENT : TEX_BEVEL_HGRADIENT;
+			b = w1 * tex->bevel;
+		}
+		else {
+			bs = tex->bevelshading;
+			b = dim * tex->bevel;
+		}
+		
+		yi = 0;
+		i = 0;
+		if (tex->bevoption != TEX_BEVEL_DEFAULTMIN) dim *= half_over_n;
+		for (xi = 0; xi < w + xstep; xi += xstep)
+		{
+			intens = tiles_recthelper_int(tex, x - xi, y - yi, w1, ystep, dim, b, bs);
+			if (intens > 0) {
+				if (i > n) id = TILE_RIGHT;
+				i = i % 16;
+				break;
+			}
+			yi += ystep;
+			i++;
+		}
+		if (intens > 0) break;
+
+		/* Handle the seamless sections of horizontal bars */
+		yi = h - (n - 1) * ystep;
+		i = n + 1;
+		for (xi = (1 - n) * xstep; xi < 0; xi += xstep)
+		{
+			intens = tiles_recthelper_int(tex, x - xi, y - yi, w1, ystep, dim, b, bs);
+			if (intens > 0) {
+				id = TILE_LEFT;
+				i = i % 16;
+				break;
+			}
+			yi += ystep;
+			i++;
+		}
+		if (intens > 0) break;
+
+		/* Handle vertical bars */
+		dim = tiles_bevel_dim(tex, xstep, h1);
+		if (tex->bevelshading == TEX_BEVEL_PATTERN) {
+			bs = (tex->corner == TEX_CORNER_STRAIGHT) ? TEX_BEVEL_HGRADIENT : TEX_BEVEL_VGRADIENT;
+			b = h1 * tex->bevel;
+		}
+		else {
+			bs = tex->bevelshading;
+			b = dim * tex->bevel;
+		}	
+
+		xi = 0;
+		i = 0;
+		if (tex->bevoption != TEX_BEVEL_DEFAULTMIN) dim *= half_over_n;
+		for (yi = ystep; yi < h + ystep; yi += ystep)
+		{
+			intens = tiles_recthelper_int(tex, x - xi, y - yi, xstep, h1, dim, b, bs);
+			if (intens > 0) {
+				if (i >= n) id = TILE_ABOVE;
+				i = 15 - i % 16;
+				break;
+			}
+			xi += xstep;
+			i++;
+		}
+		if (intens > 0) break;
+
+		/* Handle the seamless sections of vertical bars */
+		xi = w1;
+		i = n;
+		for (yi = (1 - n) * ystep; yi < ystep; yi += ystep)
+		{
+			intens = tiles_recthelper_int(tex, x - xi, y - yi, xstep, h1, dim, b, bs);
+			if (intens > 0) {
+				if (i < 2*n-1) id = TILE_BELOW;
+				i = 15 - i % 16;
+				break;
+			}
+			xi += xstep;
+			i++;
+		}
+		if (intens > 0) break;
+
+		/* Important: End loop */
+		loop = 0;
+		i = -1;
+	}
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, i, col);
+
+	return intens;
+}
+
+static float tiles_interlock1_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	/* Generate a pattern as follows:
+	 *    _______
+	 *   |       | 
+	 *   |_______|
+	 *   |   |   |
+	 *   |___|___|
+	 * The pattern rotates 90 degrees and after 4 tile repitions it repeats.
+	 * If tex->hcount is not a multiple of 4, the repitions will stop before
+	 * multiple of 360 degrees is reached.
+	 */
+
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float w2 = 0.5 * w;
+	float h2 = 0.5 * h;
+	float dim = tiles_bevel_dim(tex, w2, h2);
+	float b = dim * tex->bevel;
+	float intens = 0;
+	short i = htileid % 4;
+	short id;
+	short bs = tex->bevelshading;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	if (i == 0) {
+		if (y >= h2) {
+			intens = tiles_recthelper_int(tex, x, y - h2, w, h2, dim, b, bs);
+			id = TILE_ABOVE;
+		}
+		else if (x <= w2) {
+			intens = tiles_recthelper_int(tex, x, y, w2, h2, dim, b, bs);
+			id = TILE_LEFT;
+		}
+		else {
+			intens = tiles_recthelper_int(tex, x - w2, y, w2, h2, dim, b, bs);
+			id = TILE_RIGHT;
+		}
+	}
+	else if (i == 1) {
+		if (x >= w2) {
+			intens = tiles_recthelper_int(tex, x - w2, y, w2, h, dim, b, bs);
+			id = TILE_LEFT;
+		}
+		else if (y <= h2) {
+			intens = tiles_recthelper_int(tex, x, y, w2, h2, dim, b, bs);
+			id = TILE_RIGHT;
+		}
+		else {
+			intens = tiles_recthelper_int(tex, x, y - h2, w2, h2, dim, b, bs);
+			id = TILE_ABOVE;
+		}
+	}
+	else if (i == 2) {
+		if (y <= h2) {
+			intens = tiles_recthelper_int(tex, x, y, w, h2, dim, b, bs);
+			id = TILE_BELOW;
+		}
+		else if (x <= w2) {
+			intens = tiles_recthelper_int(tex, x, y - h2, w2, h2, dim, b, bs);
+			id = TILE_LEFT;
+		}
+		else {
+			intens = tiles_recthelper_int(tex, x - w2, y - h2, w2, h2, dim, b, bs);
+			id = TILE_RIGHT;
+		}
+	}
+	else {
+		if (x <= w2) {
+			intens = tiles_recthelper_int(tex, x, y, w2, h, dim, b, bs);
+			id = TILE_RIGHT;
+		}
+		else if (y <= h2) {
+			intens = tiles_recthelper_int(tex, x - w2, y, w2, h2, dim, b, bs);
+			id = TILE_BELOW;
+		}
+		else {
+			intens = tiles_recthelper_int(tex, x - w2, y - h2, w2, h2, dim, b, bs);
+			id = TILE_ABOVE;
+		}
+	}
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+
+	return intens;
+}
+
+static float tiles_interlock2_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, short n, float *col)
+{
+	/* Generate a pattern of n blocks as follows:
+	 *    ___ ___ ___ ___
+	 *   |   |   |   |   |
+	 *   |   |   |   |   | ....
+	 *   |   |   |   |   |
+	 *   |___|___|___|___|
+	 * The pattern rotates 90 degrees and after 2 tile repitions it repeats.
+	 * If tex->hcount is not a multiple of 2, the repitions will stop before
+	 * multiple of 180 degrees is reached.
+	 */
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float factor = 1.0 / (float)n;
+	float w2 = factor * w;
+	float h2 = factor * h;
+	float dim, b;
+	float intens = 0;
+	short i = htileid % 2;
+	short id = TILE_CURRENT;
+	short k;
+	short r = 0;
+	short bs = tex->bevelshading;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	if (i == 0) {
+		/* I don't understand why the following doesn't work:
+		 *   intens = tiles_recthelper_int(tex, x, y - floor(y / h2) * h2, w, h2, dim, tex->bevelshading);
+		 * Hence the looped version.
+		 */
+		if (bs == TEX_BEVEL_PATTERN) bs = TEX_BEVEL_VGRADIENT;
+		dim = tiles_bevel_dim(tex, w, h2);
+		b = dim * tex->bevel;
+		for (k = 0; k < n; k++) {
+			if (y <= (k + 1) * h2) {				
+				intens = tiles_recthelper_int(tex, x, y - k * h2, w, h2, dim, b, bs);
+				r = k;
+				break;
+			}
+		}
+	}
+	else {
+		if (bs == TEX_BEVEL_PATTERN) bs = TEX_BEVEL_HGRADIENT;
+		dim = tiles_bevel_dim(tex, w2, h);
+		b = dim * tex->bevel;
+		for (k = 0; k < n; k++) {
+			if (x <= (k + 1) * w2) {				
+				intens = tiles_recthelper_int(tex, x - k * w2, y, w2, h, dim, b, bs);
+				r = k;
+				break;
+			}
+		}
+	}
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, r % 16, col);
+
+	return intens;
+}
+
+static float tiles_interlock3_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	/* Assuming, the rows are not being shifted, we can do the following pattern
+	 * which will stretch from one rectangular cell to another but will
+	 * remain seamless as long as tex->hgap = tex->vgap = 0.
+	 *    |__|
+	 * __/    \__
+	 * __|    |__
+	 *   \____/
+	 *    |  |
+	 * 
+	 * The figure above is ugly but it generates regular octagons interlocked with squares and
+	 * the edge length of squares and octagons will be equal.
+	 */
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float intens = 0;
+	short id = TILE_CURRENT;
+	short bs = tex->bevelshading;
+	float s1 = 0;		/* Don't ask how I came up with these numbers :) */
+	float s2 = 0.14645;
+	float s3 = 0.35356;
+	float s4 = 0.64644;
+	float s5 = 0.85355;
+	float s6 = 1;
+	float s = s4 - s3;	/* Edge length of octagons and squares */
+	float sh = s * 0.5;
+	float sr = s * M_SQRT1_2;
+	float wl, wr, dl, dr;
+	float ha, hb, ra, rb;
+	short htidl, htidr, vtida, vtidb;
+	float vx[8], vy[8];
+	float b;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	if ((x >= 0) && (x <= w) && (y >= 0) && (y <= h))
+	{
+		/* Width of tile to right */
+		htidr = (htileid + 1) % tex->hcount;
+		wr = tex->precalc.hpat[htidr + 1] - tex->precalc.hpat[htidr] - tex->precalc.hgap;
+		/* Width of tile to left */
+		htidl = (htileid - 1 + tex->hcount) % tex->hcount;
+		wl = tex->precalc.hpat[htidl + 1] - tex->precalc.hpat[htidl] - tex->precalc.hgap;
+		/* Height of tile above */
+		vtida = (vtileid + 1) % tex->vcount;
+		ha = tex->precalc.vpat[vtida + 1] - tex->precalc.vpat[vtida] - tex->precalc.vgap;
+		/* Height of tile below */
+		vtidb = (vtileid - 1 + tex->vcount) % tex->vcount;
+		hb = tex->precalc.vpat[vtidb + 1] - tex->precalc.vpat[vtidb] - tex->precalc.vgap;
+
+		/* NOTE: All polygons are defined counter-clockwise */
+
+		/* Central octagon */
+		vx[0] = s3 * w;		vy[0] = s2 * h;
+		vx[1] = s4 * w;		vy[1] = s2 * h;
+		vx[2] = s5 * w;		vy[2] = s3 * h;
+		vx[3] = s5 * w;		vy[3] = s4 * h;
+		vx[4] = s4 * w;		vy[4] = s5 * h;
+		vx[5] = s3 * w;		vy[5] = s5 * h;
+		vx[6] = s2 * w;		vy[6] = s4 * h;
+		vx[7] = s2 * w;		vy[7] = s3 * h;
+		b = tiles_bevel_dim(tex, vx[2] - vx[6], vy[4] - vy[0]) * tex->bevel;
+		intens = tiles_poly_func(x, y, vx, vy, 8, b, bs);
+
+		/* Squares (rectangles if random widths/heights) */
+		if (intens <= 0) {
+			/* Bottom */
+			vx[0] = s4 * w;		vy[0] = s2 * h;
+			vx[1] = s3 * w;		vy[1] = vy[0];
+			vx[2] = vx[1];		vy[2] = vy[1] - sh * (h + hb);
+			vx[3] = vx[0];		vy[3] = vy[2];
+			b = tiles_bevel_dim(tex, s, sh * (h + hb)) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 4, b, bs);
+			id = TILE_BELOW;
+		}
+		if (intens <= 0) {
+			/* Top */
+			vx[0] = s3 * w;		vy[0] = s5 * h;
+			vx[1] = s4 * w;		vy[1] = vy[0];
+			vx[2] = vx[1];		vy[2] = vy[1] + sh * (h + ha);
+			vx[3] = vx[0];		vy[3] = vy[2];
+			b = tiles_bevel_dim(tex, s, sh * (h + ha)) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 4, b, bs);
+			id = TILE_ABOVE;
+		}
+		if (intens <= 0) {
+			/* Left */
+			vx[0] = s2 * w;					vy[0] = s3 * h;
+			vx[1] = vx[0];					vy[1] = s4 * h;
+			vx[2] = vx[1] - sh * (w + wl);	vy[2] = vy[1];
+			vx[3] = vx[2];					vy[3] = vy[0];
+			b = tiles_bevel_dim(tex, s, sh * (w + wl)) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 4, b, bs);
+			id = TILE_LEFT;
+		}
+		if (intens <= 0) {
+			/* Right */
+			vx[0] = s5 * w;					vy[0] = s3 * h;
+			vx[1] = vx[0] + sh * (w + wr);	vy[1] = vy[0];
+			vx[2] = vx[1];					vy[2] = s4 * h;
+			vx[3] = vx[0];					vy[3] = vy[2];
+			b = tiles_bevel_dim(tex, s, sh * (w + wr)) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 4, b, bs);
+			id = TILE_RIGHT;
+		}
+
+		/* More octagons */
+		if (intens <= 0) {
+			/* Bottom Left */
+			vx[0] = s3 * w;					vy[0] = s2 * h;
+			vx[1] = s2 * w;					vy[1] = s3 * h;
+			vx[2] = vx[1] - sh * (w + wl);	vy[2] = vy[1];
+			vx[3] = vx[2] - sr * wl;		vy[3] = vy[0];
+			vx[4] = vx[3];					vy[4] = vy[3] - sh * (h + hb);
+			vx[5] = vx[2];					vy[5] = vy[4] - sr * hb;
+			vx[6] = vx[1];					vy[6] = vy[5];
+			vx[7] = vx[0];					vy[7] = vy[4];
+
+			b = tiles_bevel_dim(tex, vx[0] - vx[4], vy[1] - vy[5]) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 8, b, bs);
+			id = TILE_LEFT_BELOW;
+		}
+		if (intens <= 0) {
+			/* Bottom Right */
+			vx[0] = s5 * w;					vy[0] = s3 * h;
+			vx[1] = s4 * w;					vy[1] = s2 * h;
+			vx[2] = vx[1];					vy[2] = vy[1] - sh * (h + hb);
+			vx[3] = vx[0];					vy[3] = vy[4] - sr * hb;
+			vx[4] = vx[3] + sh * (w + wr);	vy[4] = vy[3];
+			vx[5] = vx[4] + sr * wr;		vy[5] = vy[2];
+			vx[6] = vx[5];					vy[6] = vy[1];
+			vx[7] = vx[4];					vy[7] = vy[0];
+
+			b = tiles_bevel_dim(tex, vx[5] - vx[1], vy[0] - vy[4]) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 8, b, bs);
+			id = TILE_RIGHT_BELOW;
+		}
+		if (intens <= 0) {
+			/* Top Left */
+			vx[0] = s2 * w;					vy[0] = s4 * h;
+			vx[1] = s3 * w;					vy[1] = s5 * h;
+			vx[2] = vx[1];					vy[2] = vy[1] + sh * (h + ha);
+			vx[3] = vx[0];					vy[3] = vy[2] + sr * ha;
+			vx[4] = vx[3] - sh * (w + wl);	vy[4] = vy[3];
+			vx[5] = vx[4] - sr * wl;		vy[5] = vy[2];
+			vx[6] = vx[5];					vy[6] = vy[1];
+			vx[7] = vx[4];					vy[7] = vy[0];
+
+			b = tiles_bevel_dim(tex, vx[1] - vx[5], vy[4] - vy[0]) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 8, b, bs);
+			id = TILE_LEFT_ABOVE;
+		}
+		if (intens <= 0) {
+			/* Top Right */
+			vx[0] = s4 * w;					vy[0] = s5 * h;
+			vx[1] = s5 * w;					vy[1] = s4 * h;
+			vx[2] = vx[1] + sh * (w + wr);	vy[2] = vy[1];
+			vx[3] = vx[2] + sr * wr;		vy[3] = vy[0];
+			vx[4] = vx[3];					vy[4] = vy[3] + sh * (h + ha);
+			vx[5] = vx[2];					vy[5] = vy[4] + sr * ha;
+			vx[6] = vx[1];					vy[6] = vy[5];
+			vx[7] = vx[0];					vy[7] = vy[4];
+
+			b = tiles_bevel_dim(tex, vx[4] - vx[0], vy[5] - vy[1]) * tex->bevel;
+			intens = tiles_poly_func(x, y, vx, vy, 8, b, bs);
+			id = TILE_RIGHT_ABOVE;
+		}
+	}
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+
+	return intens;
+}
+
+static float tiles_star1_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float w2 = 0.5 * w;
+	float h2 = 0.5 * h;
+	float dim = tiles_bevel_dim(tex, w, h);
+	float b = dim * tex->bevel;
+	float intens = 0;
+	short id = TILE_CURRENT;
+	short bs = tex->bevelshading;
+	float vx[10], vy[10];
+	int j;
+	float step = 0.2 * M_PI;
+	float theta = 0;
+	float r1, r2;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	if (htileid % 2) theta += step;
+	for (j = 0; j < 10; j++, theta += step) {
+		r1 = w2;
+		r2 = h2;
+		if (j % 2) {
+			r1 *= 0.5;
+			r2 *= 0.5;
+		}
+
+		vx[j] = w2 + r1 * cos(theta);
+		vy[j] = h2 + r2 * sin(theta);
+	}
+	intens = tiles_concave_poly_func(x, y, vx, vy, 10, b, bs);
+
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+
+	return intens;
+}
+
+static float tiles_weave_int(Tex *tex, float x, float y, float z, short htileid, short vtileid, float *col)
+{
+	float w = tex->precalc.hpat[htileid + 1] - tex->precalc.hpat[htileid] - tex->precalc.hgap;
+	float h = tex->precalc.vpat[vtileid + 1] - tex->precalc.vpat[vtileid] - tex->precalc.vgap;
+	float dim, b;
+	float intens = 0;
+	short htidl, htidr, vtida, vtidb;
+	float wr, wl, ha, hb;
+	float xi, yi, wi, hi;
+	short loop = 1;
+	short id = TILE_CURRENT;
+	short bs;
+
+	/* Width of tile to right */
+	htidr = (htileid + 1) % tex->hcount;
+	wr = tex->precalc.hpat[htidr + 1] - tex->precalc.hpat[htidr] - tex->precalc.hgap;
+	/* Width of tile to left */
+	htidl = (htileid - 1 + tex->hcount) % tex->hcount;
+	wl = tex->precalc.hpat[htidl + 1] - tex->precalc.hpat[htidl] - tex->precalc.hgap;
+	/* Height of tile above */
+	vtida = (vtileid + 1) % tex->vcount;
+	ha = tex->precalc.vpat[vtida + 1] - tex->precalc.vpat[vtida] - tex->precalc.vgap;
+	/* Height of tile below */
+	vtidb = (vtileid - 1 + tex->vcount) % tex->vcount;
+	hb = tex->precalc.vpat[vtidb + 1] - tex->precalc.vpat[vtidb] - tex->precalc.vgap;
+
+	/* Offset by half-gap */
+	x -= tex->precalc.hgap * 0.5;
+	y -= tex->precalc.vgap * 0.5;
+
+	while (loop) {
+		if ((x < 0) || (x > w) || (y < 0) || (y > h)) break;
+
+		/* Horizontal Tiles */
+
+		/* Compute dimension for bevel and shading */
+		if (tex->bevelshading == TEX_BEVEL_PATTERN) {
+			bs = (tex->corner == TEX_CORNER_STRAIGHT) ? TEX_BEVEL_VGRADIENT : TEX_BEVEL_HGRADIENT;
+			dim = tiles_bevel_dim(tex, w, MIN2(wl, wr));
+		}
+		else {
+			bs =  tex->bevelshading;
+			dim = tiles_bevel_dim(tex, MIN3(w, wl, wr), MIN3(h, ha, hb));
+		}
+		b = dim * tex->bevel;
+		dim *= 0.25;
+
+		/* Bottom Center */
+		xi = 0.125 * w;
+		yi = -0.125 * hb;
+		wi = 0.75 * w;
+		hi = 0.125 * (h + hb);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_BELOW;
+			break;
+		}
+
+		/* Top Center */
+		xi = 0.125 * w; 
+		yi = 0.875 * h;
+		hi = 0.125 * (h + ha);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_ABOVE;
+			break;
+		}
+
+		/* Middle Left */
+		xi = -0.375 * wl;
+		yi = 0.375 * h;
+		wi = 0.375 * (w + wl);
+		hi = 0.25 * h;
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_LEFT;
+			break;
+		}
+
+		/* Middle Right */
+		xi = 0.625 * w;
+		yi = 0.375 * h;
+		wi = 0.375 * (w + wr);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_RIGHT;
+			break;
+		}
+
+
+		/* Vertical Tiles */
+
+		/* Compute dimension for bevel and shading */
+		if (tex->bevelshading == TEX_BEVEL_PATTERN) {
+			bs = (tex->corner == TEX_CORNER_STRAIGHT) ? TEX_BEVEL_HGRADIENT : TEX_BEVEL_VGRADIENT;
+			dim = tiles_bevel_dim(tex, h, MIN2(ha, hb));
+		}
+		else {
+			bs =  tex->bevelshading;
+			dim = tiles_bevel_dim(tex, MIN3(w, wl, wr), MIN3(h, ha, hb));
+		}
+		b = dim * tex->bevel;
+		dim *= 0.25;
+
+		/* Center */
+		xi = 0.375 * w;
+		yi = 0.125 * h;
+		wi = 0.25 * w;
+		hi = 0.75 * h;
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_CURRENT;
+			break;
+		}
+		
+		/* Bottom Left */
+		xi = -0.125 * wl;
+		yi = -0.375 * hb;
+		wi = 0.125 * (w + wl);
+		hi = 0.375 * (h + hb);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_LEFT_BELOW;
+			break;
+		}
+
+		/* Bottom Right */
+		xi = 0.875 * w;
+		yi = -0.375 * hb;
+		wi = 0.125 * (w + wr);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_RIGHT_BELOW;
+			break;
+		}
+		
+		/* Top Left */
+		xi = -0.125 * wl;
+		yi = 0.625 * h;
+		wi = 0.125 * (w + wl);
+		hi = 0.375 * (h + ha);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_LEFT_ABOVE;
+			break;
+		}
+
+		/* Top Right */
+		xi = 0.875 * w;
+		yi = 0.625 * h;
+		wi = 0.125 * (w + wr);
+		intens = tiles_recthelper_int(tex, x - xi, y - yi, wi, hi, dim, b, bs);
+		if (intens > 0) {
+			id = TILE_RIGHT_ABOVE;
+			break;
+		}
+
+		loop = 0;
+	}
+	
+	/* Bevel function */
+	intens = tiles_bevel_func(tex, intens);
+
+	/* Compute colour */
+	tiles_neighbour_col(tex, &intens, htileid, vtileid, id, -1, col);
+
+	return intens;
+}
+
+static float tiles_turb_seamless(Tex * tex, float x, float y, float z, float w, float h, float d)
+{
+	/* F_tile(x,y,z) = (
+		  (w - x) * (h - y) * (d - z) * F(x,     y    , z    ) +
+		  (w - x) * (h - y) * (    z) * F(x,     y    , z - d) +
+		  (w - x) * (    y) * (d - z) * F(x,     y - h, z    ) +
+		  (w - x) * (    y) * (    z) * F(x,     y - h, z - d) +
+		  (    x) * (h - y) * (d - z) * F(x - w, y    , z    ) +
+		  (    x) * (h - y) * (    z) * F(x - w, y    , z - d) +
+		  (    x) * (    y) * (d - z) * F(x - w, y - h, z    ) +
+		  (    x) * (    y) * (    z) * F(x - w, y - h, z - d)
+		 ) / whd
+
+		The function tiles every w units in x-direction, h units in y-direction and d units in z-direction.
+	*/
+	int hard = (tex->noisetype!=TEX_NOISESOFT);
+	float wx = w - x;
+	float hy = h - y;
+	float dz = d - z;
+
+	return 
+		(
+			wx * hy * dz * BLI_gTurbulence(tex->noisesize,   x,   y,   z, tex->noisedepth, hard, tex->noisebasis) +
+			wx * hy *  z * BLI_gTurbulence(tex->noisesize,   x,   y, -dz, tex->noisedepth, hard, tex->noisebasis) +
+			wx *  y * dz * BLI_gTurbulence(tex->noisesize,   x, -hy,   z, tex->noisedepth, hard, tex->noisebasis) +
+   			wx *  y *  z * BLI_gTurbulence(tex->noisesize,   x, -hy, -dz, tex->noisedepth, hard, tex->noisebasis) +
+			 x * hy * dz * BLI_gTurbulence(tex->noisesize, -wx,   y,   z, tex->noisedepth, hard, tex->noisebasis) +
+			 x * hy *  z * BLI_gTurbulence(tex->noisesize, -wx,   y, -dz, tex->noisedepth, hard, tex->noisebasis) +
+			 x *  y * dz * BLI_gTurbulence(tex->noisesize, -wx, -hy,   z, tex->noisedepth, hard, tex->noisebasis) +
+   			 x *  y *  z * BLI_gTurbulence(tex->noisesize, -wx, -hy, -dz, tex->noisedepth, hard, tex->noisebasis)
+		) / (w * h * d);
+}
+static void tiles_transform(Tex *tex, float *x, float *y, float *z)
+{
+	float angle, sinval, cosval, scale;
+	float x1, y1;
+
+	/* Move origin to (0.5, 0.5) */
+	*x -= 0.5;
+	*y -= 0.5;
+	*z -= 0.5;
+	
+	/* Apply texture coordinate scale */
+	scale = 1.0 / tex->scale;
+	*x *= scale;
+	*y *= scale;
+	*z *= scale;
+
+	/* Move origin back to (0, 0) */
+	*x += 0.5;
+	*y += 0.5;
+	*z += 0.5;
+}
+
+static void tiles_calc(Tex *tex, float *x, float *y, float *z, short *htileid, short *vtileid)
+{
+	/* Given points (x, y, z) determines where in the tile pattern, tex->precalc.hpat[], 
+	 * the point belongs. It returns the index of the tile in htileid, vtileid and x, y, z 
+	 * will contain the relative offset for the tile.
+	 * NOTE: currently z is ignored as this is a 2D texture.
+	 */
+    float wtot = tex->precalc.hpat[tex->hcount] - tex->precalc.hpat[0]; /* Width of tile pattern */
+	float htot = tex->precalc.vpat[tex->vcount] - tex->precalc.vpat[0]; /* Height of tile pattern */
+	float y1;
+    short i;
+	int row;
+	
+	/* Center the pattern */
+	*x += (wtot * 0.5);
+	*y += (htot * 0.5);
+
+	y1 = *y;
+	
+	/* Compute relative y offset for current tile */
+	*y = mod(*y, htot);
+
+    /* Determine vertical start of the tile */
+	for (i = 0; i < tex->vcount; i++) {
+		if (*y <= tex->precalc.vpat[i + 1]) {
+			break;
+		}
+    }
+	*y -= tex->precalc.vpat[i];
+    *vtileid = i;
+
+	/* Calculate row number */
+	row = (int)floor(y1 / htot) * tex->vcount + i;
+
+    /* Shift rows */
+	if ( tex->alternate > 0 ) {
+		*x += (mod(row, tex->alternate) * tex->shift);
+	}
+	else {
+		/* Shift every row */
+		*x += (row * tex->shift);
+	}
+
+    /* Compute relative x offset for current tile */
+    *x = mod(*x, wtot);
+
+    /* Determine horizontal start of the tile */
+    for (i = 0; i < tex->hcount; i++) {
+		if (*x <= tex->precalc.hpat[i + 1]) {
+			break;
+		}
+    }
+	*x -= tex->precalc.hpat[i];
+    *htileid = i;
+}
+static float tiles_int(Tex *tex, float x, float y, float z, float *col)
+{
+	short htileid, vtileid;
+	float intens;
+
+	/* Compute coordinates in "tile-space"; i.e. relative to the tile containing
+	 * the texture coordinates.
+	 */
+	tiles_transform(tex, &x, &y, &z);
+	tiles_calc(tex, &x, &y, &z, &htileid, &vtileid);
+
+	/* Handle predefined patterns and default tiling function */
+	switch (tex->pattern) {
+		case TEX_TILES_CROSS1:
+			intens = tiles_cross1_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		case TEX_TILES_CROSS2:
+			intens = tiles_cross2_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		case TEX_TILES_HERRINGBONE1:
+			intens = tiles_herringbone_int(tex, x, y, z, htileid, vtileid, 2, col);
+			break;
+		case TEX_TILES_HERRINGBONE2:
+			intens = tiles_herringbone_int(tex, x, y, z, htileid, vtileid, 4, col);
+			break;
+		case TEX_TILES_HERRINGBONE3:
+			intens = tiles_herringbone_int(tex, x, y, z, htileid, vtileid, 5, col);
+			break;
+		case TEX_TILES_HEX:
+			intens = tiles_hex_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		case TEX_TILES_INTERLOCK1:
+			intens = tiles_interlock1_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		case TEX_TILES_INTERLOCK2:
+			intens = tiles_interlock2_int(tex, x, y, z, htileid, vtileid, 2, col);
+			break;
+		case TEX_TILES_INTERLOCK3:
+			intens = tiles_interlock2_int(tex, x, y, z, htileid, vtileid, 4, col);
+			break;
+		case TEX_TILES_INTERLOCK4:
+			intens = tiles_interlock3_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		case TEX_TILES_STAR1:
+			intens = tiles_star1_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		case TEX_TILES_WEAVE:
+			intens = tiles_weave_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+		default:
+			intens = tiles_default_int(tex, x, y, z, htileid, vtileid, col);
+			break;
+	}
+
+	/* Clamp to [0, 1] range. The clamping prevents artifacts around the border 
+	 * in case negative numbers are generated by the tile functions.
+	 */
+	CLAMP(intens, 0, 1);
+	CLAMP(col[0], 0, 1);
+	CLAMP(col[1], 0, 1);
+	CLAMP(col[2], 0, 1);
+
+	return intens;
+}
+
+static int tiles(Tex *tex, float *texvec, TexResult *texres)
+{
+	int rv = TEX_INT;
+	float col[3];
+
+	texres->tin = tiles_int(tex, texvec[0], texvec[1], texvec[2], col);
+
+	texres->tr = col[0];
+	texres->tg = col[1];
+	texres->tb = col[2];
+	texres->ta = 1.0;
+	rv |= TEX_RGB;
+
+	if (texres->nor!=NULL) {
+		/* calculate bumpnormal */
+		texres->nor[0] = tiles_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2], col);
+		texres->nor[1] = tiles_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2], col);
+		texres->nor[2] = tiles_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla, col);
+
+		tex_normal_derivate(tex, texres);
+		rv |= TEX_NOR;
+	}
+
+	BRICONTRGB;
+
+	BRICONT;
+
+	return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
 static int texnoise(Tex *tex, TexResult *texres)
 {
 	float div=3.0;
@@ -1194,6 +3341,9 @@
 		
 		retval= mg_distNoiseTex(tex, tmpvec, texres);
 		break;
+	case TEX_TILES:
+		retval = tiles(tex, texvec, texres);
+		break;
 	}
 
 	if (tex->flag & TEX_COLORBAND) {
@@ -1221,7 +3371,7 @@
 	}
 	
 	/* Image requires 2d mapping conversion */
-	if(tex->type==TEX_IMAGE) {
+	if(tex->type==TEX_IMAGE || tex->type==TEX_TILES) {
 		MTex mtex;
 		float texvec_l[3], dxt_l[3], dyt_l[3];
 		
@@ -1560,7 +3710,7 @@
 				co= tempvec;
 			}
 			
-			if(tex->type==TEX_IMAGE) {
+			if(tex->type==TEX_IMAGE || tex->type==TEX_TILES) {
 
 				/* new: first swap coords, then map, then trans/scale */
 
@@ -2028,7 +4178,7 @@
 
 	}
 
-	if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
+	if(mtex->tex->type==TEX_IMAGE || mtex->tex->type==TEX_TILES) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
 	
 	rgb= multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres);
 
@@ -2199,7 +4349,7 @@
 			else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
 			
 			/* texture */
-			if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
+			if(mtex->tex->type==TEX_IMAGE || mtex->tex->type==TEX_TILES) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
 		
 			rgb= multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres);
 			
@@ -2378,7 +4528,7 @@
 			}
 			
 			/* texture */
-			if(tex->type==TEX_IMAGE) {
+			if(tex->type==TEX_IMAGE || tex->type==TEX_TILES) {
 				do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
 			}
 			
@@ -2463,7 +4613,7 @@
 	else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
 	
 	/* texture */
-	if(tex->type==TEX_IMAGE) {
+	if(tex->type==TEX_IMAGE || tex->type==TEX_TILES) {
 		do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
 	}
 	
Index: source/blender/src/butspace.c
===================================================================
--- source/blender/src/butspace.c	(revision 13811)
+++ source/blender/src/butspace.c	(working copy)
@@ -95,7 +95,7 @@
 
 char texstr[20][12]= {"None"  , "Clouds" , "Wood", "Marble", "Magic"  , "Blend",
 					 "Stucci", "Noise"  , "Image", "Plugin", "EnvMap" , "Musgrave",
-					 "Voronoi", "DistNoise", "", "", "", "", "", ""};
+					 "Voronoi", "DistNoise", "Tiles", "", "", "", "", ""};
 /*  ---------------------------------------------------------------------- */
 
 void test_idbutton_cb(void *namev, void *arg2)
Index: source/blender/src/buttons_shading.c
===================================================================
--- source/blender/src/buttons_shading.c	(revision 13811)
+++ source/blender/src/buttons_shading.c	(working copy)
@@ -728,7 +728,182 @@
 	uiDefButF(block, NUMSLI, B_TEXPRV, "W4: ", 10, 10, 150, 19, &tex->vn_w4, -2.0, 2.0, 10, 0, "Sets feature weight 4");
 }
 
+static void texture_tiles_precalc(void *tex, void *unused) 
+{
+	tiles_precalc((Tex *)tex);
+}
+static void texture_tiles_pattern(void *tex, void *unused)
+{
+	Tex *t = (Tex *)tex;
 
+	/* Setup parameters for preset patterns. */
+	switch (t->pattern)
+	{
+		case TEX_TILES_HEX:
+		case TEX_TILES_HERRINGBONE1:
+		case TEX_TILES_HERRINGBONE2:
+		case TEX_TILES_HERRINGBONE3:
+		case TEX_TILES_INTERLOCK4:
+			t->hgap = 0;
+			t->vgap = 0;
+			t->alternate = 1;
+			t->bevelshading = TEX_BEVEL_DEFAULT;
+			break;
+		case TEX_TILES_WEAVE:
+			t->hgap = 0;
+			t->vgap = 0;
+			t->alternate = 1;
+			t->bevelshading = TEX_BEVEL_PATTERN;
+			break;
+		case TEX_TILES_INTERLOCK1:
+		case TEX_TILES_INTERLOCK2:
+		case TEX_TILES_INTERLOCK3:
+		case TEX_TILES_CROSS1:
+		case TEX_TILES_CROSS2:
+		case TEX_TILES_STAR1:
+			t->bevelshading = TEX_BEVEL_DEFAULT;
+			break;
+	}
+
+	texture_tiles_precalc(tex, unused);
+}
+static char* tiles_corner_menu()
+{
+	static char nbmenu[256];
+	sprintf(nbmenu, "Corner Style %%t|Round Inverted %%x%d|Round %%x%d|Ellipse Inverted %%x%d|Ellipse %%x%d|Straight %%x%d", TEX_CORNER_ROUND_INV, TEX_CORNER_ROUND, TEX_CORNER_ELLIPSE_INV, TEX_CORNER_ELLIPSE, TEX_CORNER_STRAIGHT);
+	return nbmenu;
+}
+static char* tiles_pattern_menu()
+{
+	static char nbmenu[256];
+	sprintf(nbmenu, "Pattern %%t|No Pattern %%x%d|Weave %%x%d|Star 1 %%x%d|Interlock 4 %%x%d|Interlock 3 %%x%d|Interlock 2 %%x%d|Interlock 1 %%x%d|Honeycomb %%x%d|Herringbone 3 %%x%d|Herringbone 2 %%x%d|Herringbone 1 %%x%d|Cross 2 %%x%d|Cross 1 %%x%d", TEX_TILES_NONE, TEX_TILES_WEAVE, TEX_TILES_STAR1, TEX_TILES_INTERLOCK4, TEX_TILES_INTERLOCK3, TEX_TILES_INTERLOCK2, TEX_TILES_INTERLOCK1, TEX_TILES_HEX, TEX_TILES_HERRINGBONE3, TEX_TILES_HERRINGBONE2, TEX_TILES_HERRINGBONE1, TEX_TILES_CROSS2, TEX_TILES_CROSS1);
+	return nbmenu;
+}
+static char* tiles_bevopt_menu()
+{
+	static char nbmenu[256];
+	sprintf(nbmenu, "Bevel Option %%t|Non-uniform %%x%d|Uniform Min %%x%d|Uniform Max %%x%d", TEX_BEVEL_DEFAULTMIN, TEX_BEVEL_UNIFORMMIN, TEX_BEVEL_UNIFORMMAX);
+	return nbmenu;
+}
+static char* tiles_bevel_menu()
+{
+	static char nbmenu[256];
+	sprintf(nbmenu, "Bevel Shading %%t|Default Shading %%x%d|H Gradient %%x%d|V Gradient %%x%d|Pattern %%x%d", TEX_BEVEL_DEFAULT, TEX_BEVEL_HGRADIENT, TEX_BEVEL_VGRADIENT, TEX_BEVEL_PATTERN);
+	return nbmenu;
+}
+static void texture_panel_tiles(Tex *tex)
+{
+	uiBut *bt;
+	uiBlock *block;
+	
+	block= uiNewBlock(&curarea->uiblocks, "texture_panel_tiles", UI_EMBOSS, UI_HELV, curarea->win);
+	if(uiNewPanel(curarea, block, "Tiles Basic", "Texture", 640, 0, 318, 204)==0) return;
+	
+	uiSetButLock(tex->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButS(block, MENU, B_TEXPRV, tiles_pattern_menu(),	 10, 180, 130, 19, &tex->pattern, 0, 0, 0, 0, "Predefined pattern");
+	uiButSetFunc(bt, texture_tiles_pattern, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Scale:",			    140, 180, 130, 19, &tex->scale, 0.0001, 10, 10, 0, "Scaling");
+	bt = uiDefButS(block, TOG, B_TEXPRV, "Seamless",			270, 180, 120, 19, &tex->seamless, 0, 1, 0, 0, "Make texture seamless");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButS(block, NUMSLI, B_TEXPRV, "Rows:",     50, 156, 150, 19, &tex->hcount,   1,    15, 10, 0, "Number of horizontal random tiles");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);	
+	bt = uiDefButS(block, NUMSLI, B_TEXPRV, "Cols:",	200, 156, 150, 19, &tex->vcount,    1,    15, 10, 0, "Number of vertical random tiles");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Width:",		 50, 132, 150, 19, &tex->width,    0.01, 10, 10, 0, "Average tile width");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Variation:",	200, 132, 150, 19, &tex->widthvar, 0,     1, 10, 0, "Variation in tile width");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Height:",		 50, 108, 150, 19, &tex->height,    0.01, 10, 10, 0, "Average tile height");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Variation:",	200, 108, 150, 19, &tex->heightvar, 0,     1, 10, 0, "Variation in tile height");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Bump:",		 50,  84, 150, 19, &tex->bump,    0, 1, 10, 0, "Average bump height");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Variation:",	200,  84, 150, 19, &tex->bumpvar, 0, 1, 10, 0, "Variation in bump height");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "H Gap:",		 50,  60, 150, 19, &tex->hgap, 0, 10, 10, 0, "Horizontal gap");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "V Gap:",		200,  60, 150, 19, &tex->vgap, 0, 10, 10, 0, "Vertical gap");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Shift:",		 50,  36, 150, 19, &tex->shift,    -10,     10, 10, 0, "Tile shift amount");
+	bt = uiDefButI(block, NUM, B_TEXPRV, "Alternate:",	200,  36, 150, 19, &tex->alternate,  0, 0x8000,  0, 0, "Number of tiles after which shifting starts again");
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButI(block, NUM, B_TEXPRV, "Seed:",		 50,  12, 150, 19, &tex->seed, 0, 0x80000000, 10, 0, "Seed for random number generator");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);	
+	bt = uiDefButF(block, NUM, B_NOP, "Nabla:",			200,  12, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+	uiBlockEndAlign(block);
+}
+static void texture_panel_tiles_advanced(Tex *tex)
+{
+	uiBut *bt;
+	uiBlock *block;
+	
+	block= uiNewBlock(&curarea->uiblocks, "texture_panel_tiles_advanced", UI_EMBOSS, UI_HELV, curarea->win);
+	uiNewPanelTabbed("Tiles Basic", "Texture");
+	if(uiNewPanel(curarea, block, "Tiles Advanced", "Texture", 1280, 0, 318, 204)==0) return;
+	
+	uiSetButLock(tex->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Bevel:",	 50, 180, 150, 19, &tex->bevel,    0, 0.5, 10, 0, "Tile bevel factor");
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Profile:",200, 180, 150, 19, &tex->curve,   -1, 1,   10, 0, "Adjust the bevel profile");
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "Strength:", 50, 156, 150, 19, &tex->strength,     0, 1, 10, 0, "Strength of bevel");
+	bt = uiDefButS(block, TOG, B_TEXPRV, "Smooth",	 200, 156, 150, 19, &tex->smooth,   0, 1,    0, 0, "Smooth the bevel profile");
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButS(block, MENU, B_TEXPRV, tiles_bevopt_menu(), 50, 132, 150, 19, &tex->bevoption,    0, 0,  0, 0, "Controls uniformity of bevel across tiles");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButS(block, MENU, B_TEXPRV, tiles_bevel_menu(), 200, 132, 150, 19, &tex->bevelshading, 0, 0,  0, 0, "Bevel shading options");
+	uiBlockEndAlign(block);
+
+	uiBlockBeginAlign(block);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "H Corner:",		    50, 108, 150, 19, &tex->hcorner, 0, 0.5, 10, 0, "Tile corner horizontal factor");
+	bt = uiDefButF(block, NUM, B_TEXPRV, "V Corner:",		   200, 108, 150, 19, &tex->vcorner, 0, 0.5, 10, 0, "Tile corner vertical factor");
+	bt = uiDefButS(block, MENU, B_TEXPRV, tiles_corner_menu(), 200,  84, 150, 19, &tex->corner,  0, 0,    0, 0, "Tile corner type");
+	uiBlockEndAlign(block);
+	
+	bt = uiDefBut(block, LABEL, 0, "Base Color",  50, 60, 100, 19, 0, 0.0, 0.0, 0, 0, "");
+	bt = uiDefButF(block, COL, B_TEXPRV, "",     150, 60,  19, 19, &tex->colr1, 0, 0, 0, 0, "Base color for brick");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+
+	bt = uiDefBut(block, LABEL, 0, "Gap Color",   50, 36, 100, 19, 0, 0.0, 0.0, 0, 0, "");
+	bt = uiDefButF(block, COL, B_TEXPRV, "",     150, 36,  19, 19, &tex->colr2, 0, 0, 0, 0, "Gap color");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+
+	bt = uiDefButF(block, NUM, B_TEXPRV, "H Variation:", 200, 60, 150, 19, &tex->fhue, 0, 1, 10, 0, "Hue variation");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "S Variation:", 200, 36, 150, 19, &tex->fsat, 0, 1, 10, 0, "Saturation variation");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+	bt = uiDefButF(block, NUM, B_TEXPRV, "V Variation:", 200, 12, 150, 19, &tex->fval, 0, 1, 10, 0, "Value variation");
+	uiButSetFunc(bt, texture_tiles_precalc, tex, NULL);
+}
+
 static char *layer_menu(RenderResult *rr, short *curlay)
 {
 	RenderLayer *rl;
@@ -1541,7 +1716,22 @@
 	uiDefButF(block, NUMSLI, B_TEXPRV, "Contr",			160,10,150,20, &tex->contrast, 0.01, 5.0, 0, 0, "Changes the contrast of the color or intensity of a texture");
 }
 
-
+static void texture_type_select(void *tex, void *unused) 
+{
+	Tex *t = (Tex *)tex;
+	if (t->type == TEX_TILES) {
+		/* We have to do this because do_2d_mapping() will mess up the texture mapping
+		 * for Tiles texture
+		 */		
+		t->extend = TEX_REPEAT;
+		t->cropxmin = 0.0;
+		t->cropxmax = 1.0;
+		t->cropymin = 0.0;
+		t->cropymax = 1.0;
+		t->xrepeat = 1.0;
+		t->yrepeat = 1.0;
+	}
+}
 static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br, SculptData *sd)
 {
 	MTex *mt=NULL;
@@ -1635,16 +1825,17 @@
 	if(id) {
 		char textypes[512];
 		Tex *tex= (Tex *)id;
+		uiBut *bt;
 
 		uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
 		
 		/* newnoise: all texture types as menu, not enough room for more buttons.
 		 * Can widen panel, but looks ugly when other panels overlap it */
 		
-		sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE);
+		sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Tiles %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_TILES);
 		uiDefBut(block, LABEL, 0, "Texture Type",		160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, "");
-		uiDefButS(block, MENU, B_TEXTYPE, textypes,	160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
-
+		bt = uiDefButS(block, MENU, B_TEXTYPE, textypes,	160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
+        uiButSetFunc(bt, texture_type_select, tex, NULL);	
 	}
 	else {
 		// label to avoid centering
@@ -4386,6 +4577,10 @@
 			case TEX_VORONOI:
 				texture_panel_voronoi(tex);
 				break;
+			case TEX_TILES:
+				texture_panel_tiles(tex);
+				texture_panel_tiles_advanced(tex);
+				break;
 			}
 		}
 	}