/* Wood2 ----- This script generates a tilable wooden floor texture. Author : Andreas Jonsson Created: July 1st, 2003 Updated: July 28th, 2005 Texture Generator version 1.1.0 */ // The final image size const uint imageSize = 256; // How much the turbulence affect the pattern const float turbulenceAltitude = 0.2f; const uint turbulenceOctaves = 2; // At what tangent radius the wood was cut const float woodRadius = 120.73f; // How much the radius differs between the top edge and the bottom edge const float woodRadiusDiff = 3.5f; // How much the cut was offset from the center of the tree const float woodOffCenter = 10.0f; // How much the wood ondulates const float woodBendAmplitude = 0.15f; const float woodBendFrequency = 1.278f; // The width of the wood cut const float woodWidth = 53.234f; // Number of wooden boards const uint boardsX = 8; const uint boardsY = 3; const float boardsDisplace = 0.3333f; // The color gradient and hue of the wood const string gradient = "\xFF\xFE\xFC\xFA\xF7\xEE\xDD\xBB\x77\x00\x66"; const float woodRed = 0.7f; const float woodGreen = 0.3f; const float woodBlue = 0.1f; // A global randomizer randomizer rnd; void boxBlurAlpha(image @img, uint bw, uint bh) { uint x, y; uint w = img.width; uint h = img.height; //-------------- // smooth x image @line = @image(w, 1); y = 0; while( y < h ) { // Copy original pixels to the line buffer x = 0; while( x < w ) { line.Alpha(uint(x), 0) = img.Alpha(uint(x), uint(y)); ++x; } // Compute sum of first bw pixels x = 0; float sum = 0.0; while( x < bw ) { sum += line.Alpha(uint(x), 0); ++x; } // Set blurred pixels x = 0; while( x < w ) { img.Alpha(uint((x+bw/2)%w), uint(y)) = sum/float(bw); sum -= line.Alpha(uint(x), 0); sum += line.Alpha(uint((x+bw)%w), 0); ++x; } ++y; } //--------------- // smooth y line = @image(1, h); x = 0; while( x < w ) { // Copy original pixels to the line buffer y = 0; while( y < h ) { line.Alpha(0, y) = img.Alpha(x, y); ++y; } // Compute sum of first bw pixels y = 0; float sum = 0.0; while( y < bh ) { sum += line.Alpha(0, y); ++y; } // Set blurred pixels y = 0; while( y < h ) { img.Alpha(x, (y+bh/2)%h) = sum/float(bh); sum -= line.Alpha(0, y); sum += line.Alpha(0, (y+bh)%h); ++y; } ++x; } } void addRandom(image @img, float amp) { uint x, y; uint w = img.width; uint h = img.height; x = 0; while( x < w ) { y = 0; while( y < h ) { float r = amp*(2.0*rnd.getNumber()-1.0); img.Alpha(x, y) += r; ++y; } ++x; } } image @turbulence(uint start, uint end, int octaves, float ampMod) { image @img = @image(start, start); float amp = 1.0; while( --octaves >= 0 ) { addRandom(@img, amp); img.Resize(img.width*2, img.height*2); boxBlurAlpha(@img, 3, 3); amp *= ampMod; } while( img.width < end ) { img.Resize(img.width*2, img.height*2); boxBlurAlpha(@img, 3, 3); } if( img.width > end ) img.Resize(end, end); // One last blurring boxBlurAlpha(@img, 3, 3); // bstrWrite("turbulence: "); // bstrWrite("w = " + bstrFormatUInt(img.width) + ", "); // bstrWrite("h = " + bstrFormatUInt(img.height) + "\n"); return @img; } void findMinMax(image @img, float &out min, float &out max) { uint x, y; uint w = img.width; uint h = img.height; // bstrWrite("findMinMax: "); // bstrWrite("w = " + bstrFormatUInt(img.width) + ", "); // bstrWrite("h = " + bstrFormatUInt(img.height) + "\n"); // find the highest and lowest values used float hi = 0.0, lo = 1.0; y = 0; while( y < h ) { x = 0; while( x < w ) { float v = img.Alpha(x, y); if( v < lo ) lo = v; if( v > hi ) hi = v; ++x; } ++y; } min = lo; max = hi; } void transform(image @img, float scale, float translateBefore, float translateAfter) { uint x, y; uint w = img.width; uint h = img.height; y = 0; while( y < h ) { x = 0; while( x < w ) { float v = img.Alpha(x, y); img.Alpha(x, y) = (v+translateBefore)*scale + translateAfter; ++x; } ++y; } } void wood(image @img, image @turb, uint sx, uint sy, uint woodW, uint woodH) { uint imgW = img.width; uint imgH = img.height; uint x, y; float dr = (woodRadiusDiff*(rnd.getNumber()*2.0-1.0))/float(woodH); float r = woodRadius-dr*float(woodH/2); float off = woodOffCenter * (rnd.getNumber()*2.0-1.0); float freq = 3.141592f*2.0f*woodBendFrequency/float(woodH); float a = rnd.getNumber()*3.141592f*2.0f; y = 0; while( y < woodH ) { x = 0; while( x < woodW ) { uint px = (x+sx)%imgW; uint py = (y+sy)%imgH; float t = turb.Alpha(px, py); float w = woodWidth * (float(x)/float(woodW) - 0.5) + off; float cr = r + woodBendAmplitude*sin(a + freq*float(y)); w = sqrt(w*w + cr*cr); img.Alpha(px, py) = t+w; ++x; } r += dr; ++y; } } void color(image @img) { uint x, y; uint w = img.width; uint h = img.height; string gr = gradient; uint len = gr.length(); float v, b1, b2; uint c1, c2; pixel p; p.a = 0; y = 0; while( y < w ) { x = 0; while( x < h ) { v = img.Alpha(x, y)%1.0; if( v < 0.0 ) v = 1.0 + v; c1 = uint(v*float(len)); c2 = c1 + 1; b1 = float(gr[c1%len])/256.0; b2 = float(gr[c2%len])/256.0; v = (v*float(len) - float(c1))/(float(c2) - float(c1)); v = (b1*(1.0-v) + b2*v); p.r = v*woodRed; p.g = v*woodGreen; p.b = v*woodBlue; img.Pixel(x, y) = p; ++x; } ++y; } } void highlight(image @img, uint sx, uint sy, uint woodW, uint woodH) { uint imgW = img.width; uint imgH = img.height; uint x, y; float hi = 0.1f; x = 0; uint py1 = sy%imgH; uint py2 = (sy+woodH-1)%imgH; pixel p; while( x < woodW ) { uint px = (x+sx)%imgW; p = img.Pixel(px, py1); p.r += hi; p.g += hi; p.b += hi; img.Pixel(px, py1) = p; p = img.Pixel(px, py2); p.r -= hi; p.g -= hi; p.b -= hi; img.Pixel(px, py2) = p; ++x; } y = 0; uint px1 = sx%imgW; uint px2 = (sx+woodW-1)%imgW; while( y < woodH ) { uint py = (y+sy)%imgH; p = img.Pixel(px1, py); p.r += hi; p.g += hi; p.b += hi; img.Pixel(px1, py) = p; p = img.Pixel(px2, py); p.r -= hi; p.g -= hi; p.b -= hi; img.Pixel(px2, py) = p; ++y; } } void main() { // Create a turbulence texture image @turb = @turbulence(imageSize/32, imageSize, turbulenceOctaves, 0.5); // bstrWrite("main: "); // bstrWrite("w = " + bstrFormatUInt(turb.width) + ", "); // bstrWrite("h = " + bstrFormatUInt(turb.height) + "\n"); float hi = 0, lo = 0; findMinMax(@turb, lo, hi); transform(@turb, 2.0*turbulenceAltitude/(hi-lo), -lo, -turbulenceAltitude); // Create the wood pattern uint displace = 0; uint ddisp = uint(float(imageSize/boardsY)*boardsDisplace); image @wd = @image(imageSize, imageSize); uint x = 0; float dx = float(imageSize)/float(boardsX); float dy = float(imageSize)/float(boardsY); while( x < boardsX ) { uint y = 0; while( y < boardsY ) { wood(@wd, @turb, uint(float(x)*dx), displace + uint(float(y)*dy), uint(float(x+1)*dx) - uint(float(x)*dx), uint(float(y+1)*dy) - uint(float(y)*dy)); ++y; } displace += ddisp; ++x; } // Color the pattern color(@wd); // Highlight the board edges displace = 0; x = 0; while( x < boardsX ) { uint y = 0; while( y < boardsY ) { highlight(@wd, uint(float(x)*dx), displace + uint(float(y)*dy), uint(float(x+1)*dx) - uint(float(x)*dx), uint(float(y+1)*dy) - uint(float(y)*dy)); ++y; } displace += ddisp; ++x; } wd.Show(); }