Index: source/blender/blenkernel/BKE_texture.h =================================================================== --- source/blender/blenkernel/BKE_texture.h (revision 13881) +++ source/blender/blenkernel/BKE_texture.h (working copy) @@ -43,6 +43,20 @@ struct TexMapping; struct EnvMap; +/* Tiles precalculation data */ +typedef struct TilesPreCalc { + 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 */ +} TilesPreCalc; + /* in ColorBand struct */ #define MAXCOLORBAND 32 @@ -57,6 +71,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 +93,7 @@ #endif + + + + Index: source/blender/blenkernel/intern/texture.c =================================================================== --- source/blender/blenkernel/intern/texture.c (revision 13881) +++ source/blender/blenkernel/intern/texture.c (working copy) @@ -46,6 +46,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_rand.h" +#include "BLI_threads.h" #include "DNA_texture_types.h" #include "DNA_key_types.h" @@ -396,6 +397,12 @@ free_plugin_tex(tex->plugin); if(tex->coba) MEM_freeN(tex->coba); if(tex->env) BKE_free_envmap(tex->env); + if(tex->tilesdata) { + BLI_lock_thread(LOCK_CUSTOM1); + MEM_freeN(tex->tilesdata); + tex->tilesdata = NULL; + BLI_unlock_thread(LOCK_CUSTOM1); + } BKE_previewimg_free(&tex->preview); BKE_icon_delete((struct ID*)tex); tex->id.icon_id = 0; @@ -403,6 +410,144 @@ /* ------------------------------------------------------------------------- */ +void tiles_precalc(Tex *tex) +{ + float maxwidth, minwidth; + float maxheight, minheight; + float maxbump, minbump; + float w, h, b, r, sum; + float h1, s1, v1, h2, s2, v2; + float mh, ms, mv; + short i, j; + + if (!tex->tilesdata) { + tex->tilesdata = MEM_callocN(sizeof(TilesPreCalc), "tiles precalc data"); + } + + /* Compute a set of random widths for the tiles. The array tex->tilesdata->pat[] will + * accumulate the gap and tile widths in each cell starting at 0. + */ + maxwidth = tex->width + tex->widthvar * tex->width; + minwidth = tex->width - tex->widthvar * tex->width; + maxheight = tex->height + tex->heightvar * tex->height; + minheight = tex->height - tex->heightvar * tex->height; + maxbump = tex->bump + tex->bumpvar * tex->bump; + minbump = tex->bump - tex->bumpvar * tex->bump; + + 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 */ + tex->tilesdata->minw = MAX2(minwidth, maxwidth); + tex->tilesdata->maxw = 0; + tex->tilesdata->minh = MAX2(minheight, maxheight); + tex->tilesdata->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. + */ + tex->tilesdata->hpat[0] = 0; + sum = 0; + for (i = 1; i <= tex->hcount; i++) { + r = rng_getFloat(rng); + r = minwidth + w * r; + tex->tilesdata->hpat[i] = tex->hgap + tex->tilesdata->hpat[i - 1] + r; + sum += tex->hgap + r; + + tex->tilesdata->minw = MIN2(tex->tilesdata->minw, r); + tex->tilesdata->maxw = MAX2(tex->tilesdata->maxw, r); + } + if (tex->seamless) { + sum = 1.0/sum; + for (i = 1; i <= tex->hcount; i++) { + tex->tilesdata->hpat[i] *= sum; + } + tex->tilesdata->minw *= sum; + tex->tilesdata->maxw *= sum; + tex->tilesdata->hgap = tex->hgap * sum; + } + else { + tex->tilesdata->hgap = tex->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. + */ + tex->tilesdata->vpat[0] = 0; + sum = 0; + for (i = 1; i <= tex->vcount; i++) { + r = rng_getFloat(rng); + r = minheight + h * r; + tex->tilesdata->vpat[i] = tex->vgap + tex->tilesdata->vpat[i - 1] + r; + sum += tex->vgap + r; + + tex->tilesdata->minh = MIN2(tex->tilesdata->minh, r); + tex->tilesdata->maxh = MAX2(tex->tilesdata->maxh, r); + } + if (tex->seamless) { + sum = 1.0/sum; + for (i = 1; i <= tex->vcount; i++) { + tex->tilesdata->vpat[i] *= sum; + } + tex->tilesdata->minh *= sum; + tex->tilesdata->maxh *= sum; + tex->tilesdata->vgap = tex->vgap * sum; + } + else { + tex->tilesdata->vgap = tex->vgap; + } + + /* Compute random numbers between minbump and maxbump */ + for (i = 0; i < tex->hcount; i++) { + for (j = 0; j < tex->vcount; j++) { + r = rng_getFloat(rng); + tex->tilesdata->bpat[i][j] = minbump + b * r; + } + } + for (i = 0; i < 16; i++) { + r = rng_getFloat(rng); + tex->tilesdata->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(tex->colr1, tex->colg1, tex->colb1, &h1, &s1, &v1); + mh = 0.5 * tex->fhue; + ms = 0.5 * tex->fsat; + mv = 0.5 * tex->fval; + for (i = 0; i < tex->hcount; i++) { + for (j = 0; j < tex->vcount; j++) { + r = rng_getFloat(rng); + h2 = h1 + r * tex->fhue - mh; + s2 = s1 + r * tex->fsat - ms; + v2 = v1 + r * tex->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, &tex->tilesdata->r[i][j], &tex->tilesdata->g[i][j], &tex->tilesdata->b[i][j]); + } + } + + rng_free(rng); +} + void default_tex(Tex *tex) { PluginTex *pit; @@ -448,6 +593,38 @@ 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; if (tex->env) { tex->env->stype=ENV_STATIC; @@ -481,6 +658,7 @@ Tex *tex; tex= alloc_libblock(&G.main->tex, ID_TE, name); + tex->tilesdata = NULL; default_tex(tex); @@ -551,9 +729,15 @@ if(texn->coba) texn->coba= MEM_dupallocN(texn->coba); if(texn->env) texn->env= BKE_copy_envmap(texn->env); - + if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); + if(tex->tilesdata) { + BLI_lock_thread(LOCK_CUSTOM1); + texn->tilesdata = MEM_dupallocN(tex->tilesdata); + BLI_unlock_thread(LOCK_CUSTOM1); + } + return texn; } Index: source/blender/blenloader/intern/readfile.c =================================================================== --- source/blender/blenloader/intern/readfile.c (revision 13881) +++ source/blender/blenloader/intern/readfile.c (working copy) @@ -2421,7 +2421,7 @@ tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima); tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo); if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object); - + tex->tilesdata = NULL; tex->id.flag -= LIB_NEEDLINK; } tex= tex->id.next; @@ -2430,6 +2430,7 @@ static void direct_link_texture(FileData *fd, Tex *tex) { + tex->tilesdata = NULL; tex->plugin= newdataadr(fd, tex->plugin); if(tex->plugin) { tex->plugin->handle= 0; @@ -7403,6 +7404,48 @@ 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; + } + } + if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 10)) { Object *ob; Index: source/blender/makesdna/DNA_texture_types.h =================================================================== --- source/blender/makesdna/DNA_texture_types.h (revision 13881) +++ source/blender/makesdna/DNA_texture_types.h (working copy) @@ -36,6 +36,7 @@ #include "DNA_ID.h" #include "DNA_image_types.h" +#include "DNA_color_types.h" struct Ipo; struct PluginTex; @@ -154,7 +155,18 @@ short imaflag, flag; short type, stype; - + + short hcount, vcount, smooth; + short corner, pattern, bevoption; + float scale; + float width, widthvar, height, heightvar, bump, bumpvar; + float hgap, vgap, shift, bevel; + float colr1, colg1, colb1, colr2, colg2, colb2, fhue, fsat, fval; + float hcorner, vcorner; + unsigned int seed, alternate; + short seamless, bevelshading; + CurveMapping cumap; + float cropxmin, cropymin, cropxmax, cropymax; short xrepeat, yrepeat; short extend; @@ -175,6 +187,7 @@ struct ColorBand *coba; struct EnvMap *env; struct PreviewImage * preview; + struct TilesPreCalc * tilesdata; } Tex; @@ -211,6 +224,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 +324,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 +432,13 @@ #endif + + + + + + + + + + Index: source/blender/render/intern/include/texture.h =================================================================== --- source/blender/render/intern/include/texture.h (revision 13881) +++ 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,13 @@ #endif /* TEXTURE_EXT_H */ + + + + + + + + + + Index: source/blender/render/intern/source/texture.c =================================================================== --- source/blender/render/intern/source/texture.c (revision 13881) +++ 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 #include #include +#ifdef WIN32 +#define _USE_MATH_DEFINES +#endif #include #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,2160 @@ } +/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ +/* 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) && (ybevoption) + { + case TEX_BEVEL_UNIFORMMIN: + s = MIN2(tex->tilesdata->minw, tex->tilesdata->minh); + break; + case TEX_BEVEL_UNIFORMMAX: + s = MIN2(tex->tilesdata->maxw, tex->tilesdata->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->tilesdata->r[htileid][vtileid] * intens + tex->colr2 * intens1; + col[1] = tex->tilesdata->g[htileid][vtileid] * intens + tex->colg2 * intens1; + col[2] = tex->tilesdata->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->tilesdata->r[htileid][vtileid]; + col[1] = tex->tilesdata->g[htileid][vtileid]; + col[2] = tex->tilesdata->b[htileid][vtileid]; + s = tex->tilesdata->bpat[htileid][vtileid]; + + /* Add colours of neighbouring tiles and do uniform average */ + switch (id) { + case TILE_BELOW: + col[0] += tex->tilesdata->r[htileid][vtileidb]; + col[1] += tex->tilesdata->g[htileid][vtileidb]; + col[2] += tex->tilesdata->b[htileid][vtileidb]; + col[0] *= 0.5; + col[1] *= 0.5; + col[2] *= 0.5; + + s += tex->tilesdata->bpat[htileid][vtileidb]; + s *= 0.5; + + break; + case TILE_ABOVE: + col[0] += tex->tilesdata->r[htileid][vtileida]; + col[1] += tex->tilesdata->g[htileid][vtileida]; + col[2] += tex->tilesdata->b[htileid][vtileida]; + col[0] *= 0.5; + col[1] *= 0.5; + col[2] *= 0.5; + + s += tex->tilesdata->bpat[htileid][vtileida]; + s *= 0.5; + + break; + case TILE_LEFT: + col[0] += tex->tilesdata->r[htileidl][vtileid]; + col[1] += tex->tilesdata->g[htileidl][vtileid]; + col[2] += tex->tilesdata->b[htileidl][vtileid]; + col[0] *= 0.5; + col[1] *= 0.5; + col[2] *= 0.5; + + s += tex->tilesdata->bpat[htileidl][vtileid]; + s *= 0.5; + + break; + case TILE_RIGHT: + col[0] += tex->tilesdata->r[htileidr][vtileid]; + col[1] += tex->tilesdata->g[htileidr][vtileid]; + col[2] += tex->tilesdata->b[htileidr][vtileid]; + col[0] *= 0.5; + col[1] *= 0.5; + col[2] *= 0.5; + + s += tex->tilesdata->bpat[htileidr][vtileid]; + s *= 0.5; + + break; + case TILE_LEFT_BELOW: + col[0] += tex->tilesdata->r[htileidl][vtileid] + tex->tilesdata->r[htileidl][vtileidb] + tex->tilesdata->r[htileid][vtileidb]; + col[1] += tex->tilesdata->g[htileidl][vtileid] + tex->tilesdata->g[htileid][vtileidb] + tex->tilesdata->g[htileidl][vtileidb]; + col[2] += tex->tilesdata->b[htileidl][vtileid] + tex->tilesdata->b[htileidl][vtileidb] + tex->tilesdata->b[htileid][vtileidb]; + col[0] *= 0.25; + col[1] *= 0.25; + col[2] *= 0.25; + + s += tex->tilesdata->bpat[htileidl][vtileid] + tex->tilesdata->bpat[htileidl][vtileidb] + tex->tilesdata->bpat[htileid][vtileidb]; + s *= 0.25; + + break; + case TILE_LEFT_ABOVE: + col[0] += tex->tilesdata->r[htileidl][vtileid] + tex->tilesdata->r[htileidl][vtileida] + tex->tilesdata->r[htileid][vtileida]; + col[1] += tex->tilesdata->g[htileidl][vtileid] + tex->tilesdata->g[htileid][vtileida] + tex->tilesdata->g[htileidl][vtileida]; + col[2] += tex->tilesdata->b[htileidl][vtileid] + tex->tilesdata->b[htileidl][vtileida] + tex->tilesdata->b[htileid][vtileida]; + col[0] *= 0.25; + col[1] *= 0.25; + col[2] *= 0.25; + + s += tex->tilesdata->bpat[htileidl][vtileid] + tex->tilesdata->bpat[htileidl][vtileida] + tex->tilesdata->bpat[htileid][vtileida]; + s *= 0.25; + + break; + case TILE_RIGHT_BELOW: + col[0] += tex->tilesdata->r[htileidr][vtileid] + tex->tilesdata->r[htileidr][vtileidb] + tex->tilesdata->r[htileid][vtileidb]; + col[1] += tex->tilesdata->g[htileidr][vtileid] + tex->tilesdata->g[htileid][vtileidb] + tex->tilesdata->g[htileidr][vtileidb]; + col[2] += tex->tilesdata->b[htileidr][vtileid] + tex->tilesdata->b[htileidr][vtileidb] + tex->tilesdata->b[htileid][vtileidb]; + col[0] *= 0.25; + col[1] *= 0.25; + col[2] *= 0.25; + + s += tex->tilesdata->bpat[htileidr][vtileid] + tex->tilesdata->bpat[htileidr][vtileidb] + tex->tilesdata->bpat[htileid][vtileidb]; + s *= 0.25; + + break; + case TILE_RIGHT_ABOVE: + col[0] += tex->tilesdata->r[htileidr][vtileid] + tex->tilesdata->r[htileidr][vtileida] + tex->tilesdata->r[htileid][vtileida]; + col[1] += tex->tilesdata->g[htileidr][vtileid] + tex->tilesdata->g[htileid][vtileida] + tex->tilesdata->g[htileidr][vtileida]; + col[2] += tex->tilesdata->b[htileidr][vtileid] + tex->tilesdata->b[htileidr][vtileida] + tex->tilesdata->b[htileid][vtileida]; + col[0] *= 0.25; + col[1] *= 0.25; + col[2] *= 0.25; + + s += tex->tilesdata->bpat[htileidr][vtileid] + tex->tilesdata->bpat[htileidr][vtileida] + tex->tilesdata->bpat[htileid][vtileida]; + s *= 0.25; + + break; + } + *intens *= s; + + /* Additional random scaling */ + if (i >= 0) *intens *= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->vgap; + + /* Offset by half-gap */ + x -= tex->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->vgap * 0.5; + + /* Width of tile to right */ + htidr = (htileid + 1) % tex->hcount; + wr = tex->tilesdata->hpat[htidr + 1] - tex->tilesdata->hpat[htidr] - tex->tilesdata->hgap; + dr = wr * c; + /* Width of tile to left */ + htidl = (htileid - 1 + tex->hcount) % tex->hcount; + wl = tex->tilesdata->hpat[htidl + 1] - tex->tilesdata->hpat[htidl] - tex->tilesdata->hgap; + dl = wl * c; + /* Height of tile above */ + vtida = (vtileid + 1) % tex->vcount; + ha = tex->tilesdata->vpat[vtida + 1] - tex->tilesdata->vpat[vtida] - tex->tilesdata->vgap; + ra = ha * 0.5; + /* Height of tile below */ + vtidb = (vtileid - 1 + tex->vcount) % tex->vcount; + hb = tex->tilesdata->vpat[vtidb + 1] - tex->tilesdata->vpat[vtidb] - tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->vgap * 0.5; + + if ((x >= 0) && (x <= w) && (y >= 0) && (y <= h)) + { + /* Width of tile to right */ + htidr = (htileid + 1) % tex->hcount; + wr = tex->tilesdata->hpat[htidr + 1] - tex->tilesdata->hpat[htidr] - tex->tilesdata->hgap; + /* Width of tile to left */ + htidl = (htileid - 1 + tex->hcount) % tex->hcount; + wl = tex->tilesdata->hpat[htidl + 1] - tex->tilesdata->hpat[htidl] - tex->tilesdata->hgap; + /* Height of tile above */ + vtida = (vtileid + 1) % tex->vcount; + ha = tex->tilesdata->vpat[vtida + 1] - tex->tilesdata->vpat[vtida] - tex->tilesdata->vgap; + /* Height of tile below */ + vtidb = (vtileid - 1 + tex->vcount) % tex->vcount; + hb = tex->tilesdata->vpat[vtidb + 1] - tex->tilesdata->vpat[vtidb] - tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->hpat[htileid + 1] - tex->tilesdata->hpat[htileid] - tex->tilesdata->hgap; + float h = tex->tilesdata->vpat[vtileid + 1] - tex->tilesdata->vpat[vtileid] - tex->tilesdata->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->tilesdata->hpat[htidr + 1] - tex->tilesdata->hpat[htidr] - tex->tilesdata->hgap; + /* Width of tile to left */ + htidl = (htileid - 1 + tex->hcount) % tex->hcount; + wl = tex->tilesdata->hpat[htidl + 1] - tex->tilesdata->hpat[htidl] - tex->tilesdata->hgap; + /* Height of tile above */ + vtida = (vtileid + 1) % tex->vcount; + ha = tex->tilesdata->vpat[vtida + 1] - tex->tilesdata->vpat[vtida] - tex->tilesdata->vgap; + /* Height of tile below */ + vtidb = (vtileid - 1 + tex->vcount) % tex->vcount; + hb = tex->tilesdata->vpat[vtidb + 1] - tex->tilesdata->vpat[vtidb] - tex->tilesdata->vgap; + + /* Offset by half-gap */ + x -= tex->tilesdata->hgap * 0.5; + y -= tex->tilesdata->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->tilesdata->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->tilesdata->hpat[tex->hcount] - tex->tilesdata->hpat[0]; /* Width of tile pattern */ + float htot = tex->tilesdata->vpat[tex->vcount] - tex->tilesdata->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->tilesdata->vpat[i + 1]) { + break; + } + } + *y -= tex->tilesdata->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->tilesdata->hpat[i + 1]) { + break; + } + } + *x -= tex->tilesdata->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]; + + if (!tex->tilesdata) { + BLI_lock_thread(LOCK_CUSTOM1); + tiles_precalc(tex); + BLI_unlock_thread(LOCK_CUSTOM1); + } + + 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; @@ -1187,6 +3340,9 @@ retval= mg_distNoiseTex(tex, tmpvec, texres); break; + case TEX_TILES: + retval = tiles(tex, texvec, texres); + break; } if (tex->flag & TEX_COLORBAND) { @@ -1214,7 +3370,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]; @@ -1555,7 +3711,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 */ @@ -2023,7 +4179,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); @@ -2194,7 +4350,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); @@ -2373,7 +4529,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); } @@ -2458,7 +4614,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 13881) +++ 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) @@ -804,3 +804,5 @@ } + + Index: source/blender/src/buttons_shading.c =================================================================== --- source/blender/src/buttons_shading.c (revision 13881) +++ source/blender/src/buttons_shading.c (working copy) @@ -80,6 +80,7 @@ #include "BKE_image.h" #include "BLI_blenlib.h" +#include "BLI_threads.h" #include "BMF_Api.h" #include "BSE_filesel.h" @@ -728,7 +729,177 @@ 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) +{ + BLI_lock_thread(LOCK_CUSTOM1); + tiles_precalc((Tex *)tex); + BLI_unlock_thread(LOCK_CUSTOM1); +} +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); + + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_pattern_menu(), 10, 180, 120, 19, &tex->pattern, 0, 0, 0, 0, "Predefined pattern"); + uiButSetFunc(bt, texture_tiles_pattern, tex, NULL); + + bt = uiDefButS(block, TOG, B_TEXPRV, "Seamless", 140, 180, 120, 19, &tex->seamless, 0, 1, 0, 0, "Make texture seamless"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + + bt = uiDefButF(block, NUM, B_TEXPRV, "Scale:", 270, 180, 120, 19, &tex->scale, 0.0001, 10, 10, 0, "Scaling"); + + uiBlockBeginAlign(block); + bt = uiDefButS(block, NUM, B_TEXPRV, "Columns:", 10, 150, 180, 19, &tex->hcount, 1, 15, 10, 0, "Number of horizontal random tiles"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "Width:", 10, 130, 180, 19, &tex->width, 0.01, 10, 10, 0, "Average tile width"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "Variation:", 10, 110, 180, 19, &tex->widthvar, 0, 1, 10, 0, "Variation in tile width"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + bt = uiDefButS(block, NUM, B_TEXPRV, "Rows:", 210, 150, 180, 19, &tex->vcount, 1, 15, 10, 0, "Number of vertical random tiles"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "Height:", 210, 130, 180, 19, &tex->height, 0.01, 10, 10, 0, "Average tile height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "Variation:", 210, 110, 180, 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:", 10, 65, 180, 19, &tex->bump, 0, 1, 10, 0, "Average bump height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "Variation:", 10, 45, 180, 19, &tex->bumpvar, 0, 1, 10, 0, "Variation in bump height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + bt = uiDefBut(block, LABEL, 0, "Shift", 210, 85, 180, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "Offset:", 210, 65, 180, 19, &tex->shift, -10, 10, 10, 0, "Tile shift amount"); + bt = uiDefButI(block, NUM, B_TEXPRV, "Rows:", 210, 45, 180, 19, &tex->alternate, 0, 0x8000, 0, 0, "Number of tiles after which shifting starts again"); + uiBlockEndAlign(block); + + bt = uiDefBut(block, LABEL, 0, "Gap", 10, 20, 180, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "sizeX:", 10, 0, 180, 19, &tex->hgap, 0, 10, 10, 0, "Horizontal gap"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "sizeY:", 210, 0, 180, 19, &tex->vgap, 0, 10, 10, 0, "Vertical gap"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); +} +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 = uiDefBut(block, LABEL, 0, "Bevel Style", 10, 180, 180, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "Size:", 10, 160, 100, 19, &tex->bevel, 0, 0.5, 10, 0, "Tile bevel size"); + bt = uiDefButS(block, TOG, B_TEXPRV, "Smooth", 110, 160, 80, 19, &tex->smooth, 0, 1, 0, 0, "Smooth the bevel profile"); + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_bevopt_menu(), 10, 140, 180, 19, &tex->bevoption, 0, 0, 0, 0, "Controls uniformity of bevel size across tiles"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_bevel_menu(), 10, 120, 180, 19, &tex->bevelshading, 0, 0, 0, 0, "Bevel shading options"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + bt = uiDefBut(block, LABEL, 0, "Corner Style", 210, 180, 180, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "sizeX:", 210, 160, 90, 19, &tex->hcorner, 0, 0.5, 10, 0, "Horizontal size of corner shape"); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "sizeY:", 300, 160, 90, 19, &tex->vcorner, 0, 0.5, 10, 0, "Vertical size of corner shape"); + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_corner_menu(), 210, 140, 180, 19, &tex->corner, 0, 0, 0, 0, "Corner type"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + bt = uiDefBut(block, LABEL, 0, "Colors", 10, 95, 70, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, COL, B_TEXPRV, "", 10, 75, 70, 19, &tex->colr1, 0, 0, 0, 0, "Base color for brick"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, COL, B_TEXPRV, "", 10, 55, 70, 19, &tex->colr2, 0, 0, 0, 0, "Gap color"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + bt = uiDefBut(block, LABEL, 0, "Variation", 90, 95, 100, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "H:", 90, 75, 100, 19, &tex->fhue, 0, 1, 10, 0, "Hue"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "S:", 90, 55, 100, 19, &tex->fsat, 0, 1, 10, 0, "Saturation"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUMSLI, B_TEXPRV, "V:", 90, 35, 100, 19, &tex->fval, 0, 1, 10, 0, "Value"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + uiBlockEndAlign(block); + + bt = uiDefButI(block, NUM, B_TEXPRV, "Seed:", 10, 0, 180, 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: ", 210, 0, 180, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal"); +} + static char *layer_menu(RenderResult *rr, short *curlay) { RenderLayer *rl; @@ -1541,7 +1712,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 +1821,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 @@ -4387,6 +4574,10 @@ case TEX_VORONOI: texture_panel_voronoi(tex); break; + case TEX_TILES: + texture_panel_tiles(tex); + texture_panel_tiles_advanced(tex); + break; } } }