Index: source/blender/render/intern/source/texture.c =================================================================== --- source/blender/render/intern/source/texture.c (revision 12233) +++ source/blender/render/intern/source/texture.c (working copy) @@ -28,6 +28,9 @@ #include #include #include +#ifdef WIN32 +#define _USE_MATH_DEFINES +#endif #include #include "MTC_matrixops.h" @@ -73,9 +76,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) @@ -690,9 +692,1750 @@ } +/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ +/* 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); +} + +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 w = fabs(t->maxwidth - t->minwidth); + float h = fabs(t->maxheight - t->minheight); + float b = fabs(t->maxbump - t->minbump); + float r; + float sum; + float h1, s1, v1, h2, s2, v2; + float mh, ms, mv; + short i, j; + RNG *rng = rng_new(tex->seed); + + /* Initialize min/max values */ + t->precalc.minw = MAX2(t->minwidth, t->maxwidth); + t->precalc.maxw = 0; + t->precalc.minh = MAX2(t->minheight, t->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 = t->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 = t->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] = t->minbump + b * r; + } + } + for (i = 0; i < 16; i++) { + r = rng_getFloat(rng); + t->precalc.rpat[i] = t->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); +} + +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_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, short bs) +{ + float b = dim * tex->bevel; + float rx, ry, intens; + + switch (tex->corner) { + case TEX_CORNER_ROUND1: + 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_ROUND2: + 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_ELLIPSE1: + 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_ELLIPSE2: + 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; + } + + /* Apply wave function */ + intens += tex->amp * sin(M_2_PI * intens * tex->freq); + + /* 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, 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_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 intens = 0; + short i = htileid % 4; + short id; + + /* 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, tex->bevelshading); + id = TILE_ABOVE; + } + else if (x <= w2) { + intens = tiles_recthelper_int(tex, x, y, w2, h2, dim, tex->bevelshading); + id = TILE_LEFT; + } + else { + intens = tiles_recthelper_int(tex, x - w2, y, w2, h2, dim, tex->bevelshading); + id = TILE_RIGHT; + } + } + else if (i == 1) { + if (x >= w2) { + intens = tiles_recthelper_int(tex, x - w2, y, w2, h, dim, tex->bevelshading); + id = TILE_LEFT; + } + else if (y <= h2) { + intens = tiles_recthelper_int(tex, x, y, w2, h2, dim, tex->bevelshading); + id = TILE_RIGHT; + } + else { + intens = tiles_recthelper_int(tex, x, y - h2, w2, h2, dim, tex->bevelshading); + id = TILE_ABOVE; + } + } + else if (i == 2) { + if (y <= h2) { + intens = tiles_recthelper_int(tex, x, y, w, h2, dim, tex->bevelshading); + id = TILE_BELOW; + } + else if (x <= w2) { + intens = tiles_recthelper_int(tex, x, y - h2, w2, h2, dim, tex->bevelshading); + id = TILE_LEFT; + } + else { + intens = tiles_recthelper_int(tex, x - w2, y - h2, w2, h2, dim, tex->bevelshading); + id = TILE_RIGHT; + } + } + else { + if (x <= w2) { + intens = tiles_recthelper_int(tex, x, y, w2, h, dim, tex->bevelshading); + id = TILE_RIGHT; + } + else if (y <= h2) { + intens = tiles_recthelper_int(tex, x - w2, y, w2, h2, dim, tex->bevelshading); + id = TILE_BELOW; + } + else { + intens = tiles_recthelper_int(tex, x - w2, y - h2, w2, h2, dim, tex->bevelshading); + 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; + 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_PRESET) bs = TEX_BEVEL_VGRADIENT; + for (k = 0; k < n; k++) { + if (y <= (k + 1) * h2) { + dim = tiles_bevel_dim(tex, w, h2); + intens = tiles_recthelper_int(tex, x, y - k * h2, w, h2, dim, bs); + r = k; + break; + } + } + } + else { + if (bs == TEX_BEVEL_PRESET) bs = TEX_BEVEL_HGRADIENT; + for (k = 0; k < n; k++) { + if (x <= (k + 1) * w2) { + dim = tiles_bevel_dim(tex, w2, h); + intens = tiles_recthelper_int(tex, x - k * w2, y, w2, h, dim, 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_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; + 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 */ + if (tex->bevelshading == TEX_BEVEL_PRESET) { + bs = TEX_BEVEL_HGRADIENT; + dim = w1; + } + else { + bs = tex->bevelshading; + dim = tiles_bevel_dim(tex, w1, ystep); + } + 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, 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, bs); + if (intens > 0) { + id = TILE_LEFT; + i = i % 16; + break; + } + yi += ystep; + i++; + } + if (intens > 0) break; + + /* Handle vertical bars */ + if (tex->bevelshading == TEX_BEVEL_PRESET) { + bs = TEX_BEVEL_VGRADIENT; + dim = h1; + } + else { + tex->bevelshading; + dim = tiles_bevel_dim(tex, xstep, h1); + } + 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, 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, 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_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; + 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_PRESET) { + bs = TEX_BEVEL_HGRADIENT; + dim = tiles_bevel_dim(tex, w, MIN2(wl, wr)) * 0.25; + } + else { + bs = tex->bevelshading; + dim = tiles_bevel_dim(tex, MIN3(w, wl, wr), MIN3(h, ha, hb)) * 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, 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, 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, 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, bs); + if (intens > 0) { + id = TILE_RIGHT; + break; + } + + + /* Vertical Tiles */ + + /* Compute dimension for bevel and shading */ + if (tex->bevelshading == TEX_BEVEL_PRESET) { + bs = TEX_BEVEL_VGRADIENT; + dim = tiles_bevel_dim(tex, h, MIN2(ha, hb)) * 0.25; + } + else { + bs = tex->bevelshading; + dim = tiles_bevel_dim(tex, MIN3(w, wl, wr), MIN3(h, ha, hb)) * 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, 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, 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, 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, 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, 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 void tiles_transform(Tex *tex, float *x, float *y, float *z) +{ + float angle, sinval, cosval, x1, y1, scale; + + /* Move origin to (0.5, 0.5) */ + *x -= 0.5; + *y -= 0.5; + + /* Apply texture coordinates rotation. */ + angle = tex->rotate * M_PI_OVER_180; + sinval = sin(angle); + cosval = cos(angle); + x1 = (*x) * cosval - (*y) * sinval; + y1 = (*y) * cosval + (*x) * sinval; + + /* Apply texture coordinates offset */ + x1 += tex->hoffset; + y1 += tex->voffset; + + /* Apply texture coordinates skew */ + *x = x1 + y1 * tex->hskew; + *y = y1 + x1 * tex->vskew; + + /* 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; +} + +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 preset patterns and default tiling function */ + switch (tex->preset) { + 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_HEX: + intens = tiles_hex_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_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; @@ -1186,6 +2929,9 @@ retval= mg_distNoiseTex(tex, tmpvec, texres); break; + case TEX_TILES: + retval = tiles(tex, texvec, texres); + break; } if (tex->flag & TEX_COLORBAND) { @@ -1211,7 +2957,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]; @@ -1499,7 +3245,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 */ @@ -1952,7 +3698,7 @@ } - if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, dxt, dyt); + if(mtex->tex->type==TEX_IMAGE || mtex->tex->type==TEX_TILES) do_2d_mapping(mtex, texvec, NULL, dxt, dyt); rgb= multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres); @@ -2123,7 +3869,7 @@ else texvec[2]= mtex->size[2]*(mtex->ofs[2]); /* texture */ - if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, dxt, dyt); + if(mtex->tex->type==TEX_IMAGE || mtex->tex->type==TEX_TILES) do_2d_mapping(mtex, texvec, NULL, dxt, dyt); rgb= multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres); @@ -2302,7 +4048,7 @@ } /* texture */ - if(tex->type==TEX_IMAGE) { + if(tex->type==TEX_IMAGE || tex->type==TEX_TILES) { do_2d_mapping(mtex, texvec, NULL, dxt, dyt); } @@ -2387,7 +4133,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, dxt, dyt); } Index: source/blender/render/intern/include/texture.h =================================================================== --- source/blender/render/intern/include/texture.h (revision 12233) +++ 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; Index: source/blender/blenkernel/BKE_blender.h =================================================================== --- source/blender/blenkernel/BKE_blender.h (revision 12233) +++ source/blender/blenkernel/BKE_blender.h (working copy) @@ -44,7 +44,7 @@ struct MemFile; #define BLENDER_VERSION 245 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 4 #define BLENDER_MINVERSION 240 #define BLENDER_MINSUBVERSION 0 Index: source/blender/blenkernel/intern/texture.c =================================================================== --- source/blender/blenkernel/intern/texture.c (revision 12233) +++ source/blender/blenkernel/intern/texture.c (working copy) @@ -441,6 +441,46 @@ tex->vn_mexp = 2.5; tex->vn_distm = 0; tex->vn_coltype = 0; + /* tiles */ + tex->scale = 1; + tex->hcount = 3; + tex->minwidth = 0.2; + tex->maxwidth = 0.3; + tex->vcount = 3; + tex->minheight = 0.1; + tex->maxheight = 0.2; + tex->hgap = 0.05; + tex->vgap = 0.05; + tex->shift = 0.1; + tex->bevel = 0.2; + tex->corner = 0; + tex->hcorner = 0.25; + tex->vcorner = 0.25; + tex->rotate = 0; + tex->seed = 0; + tex->alternate = 2; + tex->hskew = 0; + tex->vskew = 0; + tex->curve = 0; + tex->smooth = 0; + tex->freq = 0; + tex->amp = 0; + tex->hoffset = 0; + tex->voffset = 0; + tex->strength = 1; + tex->preset = 0; + tex->bevoption = 0; + tex->colr1 = 1; + tex->colg1 = 1; + tex->colb1 = 1; + tex->colr2 = 0; + tex->colg2 = 0; + tex->colb2 = 0; + tex->minbump = 0; + tex->maxbump = 1; + tex->seamless = 1; + tex->bevelshading = TEX_BEVEL_DEFAULT; + tiles_precalc(tex); if (tex->env) { tex->env->stype=ENV_STATIC; Index: source/blender/makesdna/DNA_texture_types.h =================================================================== --- source/blender/makesdna/DNA_texture_types.h (revision 12233) +++ source/blender/makesdna/DNA_texture_types.h (working copy) @@ -128,6 +128,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; @@ -152,7 +167,20 @@ short imaflag, flag; short type, stype; - + + short hcount, vcount, smooth; + short corner, preset, bevoption; + float scale, rotate, hskew, vskew, hoffset, voffset; + float minwidth, maxwidth, minheight, maxheight, minbump, maxbump; + float curve, freq, amp; + 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; + float pad4; + struct TexPreCalc precalc; + float cropxmin, cropymin, cropxmax, cropymax; short xrepeat, yrepeat; short extend; @@ -176,6 +204,8 @@ } Tex; +void tiles_precalc(Tex *tex); + /* used for mapping node. note: rot is in degrees */ typedef struct TexMapping { @@ -209,6 +239,7 @@ #define TEX_MUSGRAVE 11 #define TEX_VORONOI 12 #define TEX_DISTNOISE 13 +#define TEX_TILES 14 /* musgrave stype */ #define TEX_MFRACTAL 0 @@ -307,6 +338,32 @@ #define TEX_HALO 5 #define TEX_RAD 6 +/* tex->stype in texture.c - corner types */ +#define TEX_CORNER_ROUND1 0 +#define TEX_CORNER_ROUND2 1 +#define TEX_CORNER_ELLIPSE1 2 +#define TEX_CORNER_ELLIPSE2 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_BEVEL_DEFAULTMIN 0 +#define TEX_BEVEL_UNIFORMMIN 1 +#define TEX_BEVEL_UNIFORMMAX 2 + +#define TEX_BEVEL_DEFAULT 0 +#define TEX_BEVEL_PRESET 1 /* Used for presets 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 Index: source/blender/src/buttons_shading.c =================================================================== --- source/blender/src/buttons_shading.c (revision 12233) +++ source/blender/src/buttons_shading.c (working copy) @@ -720,7 +720,171 @@ 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_preset(void *tex, void *unused) +{ + Tex *t = (Tex *)tex; + /* Setup parameters for preset patterns. */ + switch (t->preset) + { + case TEX_TILES_HEX: + case TEX_TILES_HERRINGBONE1: + case TEX_TILES_HERRINGBONE2: + case TEX_TILES_HERRINGBONE3: + t->hgap = 0; + t->vgap = 0; + t->alternate = 1; + break; + case TEX_TILES_WEAVE: + t->hgap = 0; + t->vgap = 0; + t->alternate = 1; + t->bevelshading = TEX_BEVEL_PRESET; + break; + case TEX_TILES_INTERLOCK1: + case TEX_TILES_INTERLOCK2: + case TEX_TILES_INTERLOCK3: + break; + } + + texture_tiles_precalc(tex, unused); +} +static char* tiles_corner_menu() +{ + static char nbmenu[256]; + sprintf(nbmenu, "Corner Style %%t|Round 1 %%x%d|Round 2 %%x%d|Ellipse 1 %%x%d|Ellipse 2 %%x%d|Straight %%x%d", TEX_CORNER_ROUND1, TEX_CORNER_ROUND2, TEX_CORNER_ELLIPSE1, TEX_CORNER_ELLIPSE2, TEX_CORNER_STRAIGHT); + return nbmenu; +} +static char* tiles_preset_menu() +{ + static char nbmenu[256]; + sprintf(nbmenu, "Preset %%t|None %%x%d|Interlock 1 %%x%d|Interlock 2 %%x%d|Interlock 3 %%x%d|Honeycomb %%x%d|Herringbone 1 %%x%d|Herringbone 2 %%x%d|Herringbone 3 %%x%d|Weave %%x%d", TEX_TILES_NONE, TEX_TILES_INTERLOCK1, TEX_TILES_INTERLOCK2, TEX_TILES_INTERLOCK3, TEX_TILES_HEX, TEX_TILES_HERRINGBONE1, TEX_TILES_HERRINGBONE2, TEX_TILES_HERRINGBONE3, TEX_TILES_WEAVE); + return nbmenu; +} +static char* tiles_bevopt_menu() +{ + static char nbmenu[256]; + sprintf(nbmenu, "Bevel Option %%t|Default %%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 %%x%d|H Gradient %%x%d|V Gradient %%x%d|Preset %%x%d", TEX_BEVEL_DEFAULT, TEX_BEVEL_HGRADIENT, TEX_BEVEL_VGRADIENT, TEX_BEVEL_PRESET); + 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, 400, 204)==0) return; + + uiSetButLock(tex->id.lib!=NULL, ERROR_LIBDATA_MESSAGE); + + bt = uiDefBut(block, LABEL, 0, "Preset", -40, 180, 60, 19, 0, 0, 0, 0, 0, ""); + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_preset_menu(), 10, 180, 100, 19, &tex->preset, 0, 0, 0, 0, "Tile preset"); + uiButSetFunc(bt, texture_tiles_preset, tex, NULL); + + bt = uiDefBut(block, LABEL, 0, "Scale", 210, 180, 50, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "%:", 250, 180, 80, 19, &tex->scale, 0.0001, 10, 10, 0, "Scaling"); + + bt = uiDefBut(block, LABEL, 0, "Width", -40, 156, 60, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "Lo:", 10, 156, 80, 19, &tex->minwidth, 0.01, 10, 10, 0, "Minimum tile width"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "Hi:", 100, 156, 80, 19, &tex->maxwidth, 0.01, 10, 10, 0, "Maximum tile width"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButS(block, NUMSLI, B_TEXPRV, "N:", 190, 156, 80, 19, &tex->hcount, 1, 15, 10, 0, "Number of horizontal random tiles"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + + bt = uiDefBut(block, LABEL, 0, "Height", -40, 132, 60, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "Lo:", 10, 132, 80, 19, &tex->minheight, 0.01, 10, 10, 0, "Minimum tile height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "Hi:", 100, 132, 80, 19, &tex->maxheight, 0.01, 10, 10, 0, "Maximum tile height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButS(block, NUMSLI, B_TEXPRV, "N:", 190, 132, 80, 19, &tex->vcount, 1, 15, 10, 0, "Number of vertical random tiles"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + + bt = uiDefBut(block, LABEL, 0, "Bump", -40, 108, 60, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "Lo:", 10, 108, 80, 19, &tex->minbump, 0, 1, 10, 0, "Minimum bump height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "Hi:", 100, 108, 80, 19, &tex->maxbump, 0, 1, 10, 0, "Maximum bump height"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButS(block, TOG, B_TEXPRV, "Seamless", 190, 108, 80, 19, &tex->seamless, 0, 1, 0, 0, "Make texture seamless"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + + bt = uiDefBut(block, LABEL, 0, "Gap", -40, 84, 60, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "H:", 10, 84, 80, 19, &tex->hgap, 0, 10, 10, 0, "Horizontal gap"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "V:", 100, 84, 80, 19, &tex->vgap, 0, 10, 10, 0, "Vertical gap"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + + bt = uiDefBut(block, LABEL, 0, "Shift", -40, 60, 60, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "D:", 10, 60, 80, 19, &tex->shift, -10, 10, 10, 0, "Tile shift amount"); + bt = uiDefButI(block, NUM, B_TEXPRV, "N:", 100, 60, 80, 19, &tex->alternate, 0, 0x8000, 0, 0, "Number of tiles after which shifting starts again"); + + bt = uiDefBut(block, LABEL, 0, "Color", -40, 36, 40, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, COL, B_TEXPRV, "", 10, 36, 19, 19, &tex->colr1, 0, 0, 0, 0, "Base color for brick"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, COL, B_TEXPRV, "", 40, 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%:", 70, 36, 80, 19, &tex->fhue, 0, 1, 10, 0, "Hue variation"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "S%:", 160, 36, 80, 19, &tex->fsat, 0, 1, 10, 0, "Saturation variation"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + bt = uiDefButF(block, NUM, B_TEXPRV, "V%:", 250, 36, 80, 19, &tex->fval, 0, 1, 10, 0, "Value variation"); + uiButSetFunc(bt, texture_tiles_precalc, tex, NULL); + + bt = uiDefButI(block, NUM, B_TEXPRV, "Seed:", -40, 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:", 180, 12,150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal"); +} +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, 400, 204)==0) return; + + uiSetButLock(tex->id.lib!=NULL, ERROR_LIBDATA_MESSAGE); + + bt = uiDefBut(block, LABEL, 0, "Bevel", 10, 180, 80, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "%:", 90, 180, 80, 19, &tex->bevel, 0, 0.5, 10, 0, "Tile bevel factor"); + bt = uiDefButF(block, NUM, B_TEXPRV, "C:", 180, 180, 80, 19, &tex->curve, -1, 1, 10, 0, "Adjust the bevel profile"); + bt = uiDefButS(block, TOG, B_TEXPRV, "Smooth", 270, 180, 80, 19, &tex->smooth, 0, 1, 0, 0, "Smooth the bevel profile"); + bt = uiDefButF(block, NUM, B_TEXPRV, "Freq:", 90, 156, 80, 19, &tex->freq, 0, 100, 10, 0, "Frequency of wave function for bevel"); + bt = uiDefButF(block, NUM, B_TEXPRV, "Amp:", 180, 156, 80, 19, &tex->amp, 0, 100, 10, 0, "Amplitude of wave function for bevel"); + bt = uiDefButF(block, NUM, B_TEXPRV, "S:", 270, 156, 80, 19, &tex->strength, 0, 1, 10, 0, "Strength of bevel"); + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_bevopt_menu(), 90, 132,170, 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(), 270, 132, 80, 19, &tex->bevelshading, 0, 0, 0, 0, "Bevel shading options"); + + bt = uiDefBut(block, LABEL, 0, "Corner", 10, 108, 80, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "H%:", 90, 108, 80, 19, &tex->hcorner, 0, 0.5, 10, 0, "Tile corner horizontal factor"); + bt = uiDefButF(block, NUM, B_TEXPRV, "V%:", 180, 108, 80, 19, &tex->vcorner, 0, 0.5, 10, 0, "Tile corner vertical factor"); + bt = uiDefButS(block, MENU, B_TEXPRV, tiles_corner_menu(), 270, 108, 80, 19, &tex->corner, 0, 0, 0, 0, "Tile corner type"); + + bt = uiDefBut(block, LABEL, 0, "Rotate", 10, 60, 80, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "Deg:", 90, 60, 80, 19, &tex->rotate, 0, 360, 100, 0, "Texture rotation in degrees"); + + bt = uiDefBut(block, LABEL, 0, "Skew", 10, 36, 80, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "H:", 90, 36, 80, 19, &tex->hskew, -100, 100, 10, 0, "Horizontal skew"); + bt = uiDefButF(block, NUM, B_TEXPRV, "V:", 180, 36, 80, 19, &tex->vskew, -100, 100, 10, 0, "Vertical skew"); + + bt = uiDefBut(block, LABEL, 0, "Offset", 10, 12, 80, 19, 0, 0.0, 0.0, 0, 0, ""); + bt = uiDefButF(block, NUM, B_TEXPRV, "H:", 90, 12, 80, 19, &tex->hoffset, -100, 100, 10, 0, "Horizontal offset"); + bt = uiDefButF(block, NUM, B_TEXPRV, "V:", 180, 12, 80, 19, &tex->voffset, -100, 100, 10, 0, "Vertical offset"); +} + static char *layer_menu(RenderResult *rr, short *curlay) { RenderLayer *rl; @@ -1525,7 +1689,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; @@ -1619,16 +1798,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 @@ -4174,6 +4354,10 @@ case TEX_VORONOI: texture_panel_voronoi(tex); break; + case TEX_TILES: + texture_panel_tiles(tex); + texture_panel_tiles_advanced(tex); + break; } } } Index: source/blender/blenloader/intern/readfile.c =================================================================== --- source/blender/blenloader/intern/readfile.c (revision 12233) +++ source/blender/blenloader/intern/readfile.c (working copy) @@ -5644,7 +5644,7 @@ } } } - } + } } @@ -6729,6 +6729,55 @@ } } + if(main->versionfile != 245 || main->subversionfile < 4) { + /* Initialize Tiles texture */ + Tex *tex; + for(tex= main->tex.first; tex; tex= tex->id.next) { + tex->scale = 1; + tex->hcount = 3; + tex->minwidth = 0.2; + tex->maxwidth = 0.3; + tex->vcount = 3; + tex->minheight = 0.1; + tex->maxheight = 0.2; + tex->hgap = 0.05; + tex->vgap = 0.05; + tex->shift = 0.1; + tex->bevel = 0.2; + tex->corner = 0; + tex->hcorner = 0.25; + tex->vcorner = 0.25; + tex->rotate = 0; + tex->seed = 0; + tex->alternate = 2; + tex->hskew = 0; + tex->vskew = 0; + tex->curve = 0; + tex->smooth = 0; + tex->freq = 0; + tex->amp = 0; + tex->hoffset = 0; + tex->voffset = 0; + tex->strength = 1; + tex->preset = 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->minbump = 0; + tex->maxbump = 1; + tex->seamless = 1; + tex->bevelshading = TEX_BEVEL_DEFAULT; + tiles_precalc(tex); + } + } + for(ma=main->mat.first; ma; ma= ma->id.next) { if (ma->samp_gloss_mir == 0) { ma->gloss_mir = ma->gloss_tra= 1.0;