// $Id: noise1.cpp 751 2006-03-31 15:43:49Z alex $ // noise1.cpp // // Author : Mike // Purpose : Implemetation of low level noise function calls. // It uses a quadratic B-Spline instead of the cubic Hermite interpolant // implied by Perlin. Also note that DNoise is just the x, y, and z // derivatives of Noise (which are also B-Splines). /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // Version : 1.0 // Started : 20/01/96 #include "camtypes.h" #include "macros.h" #include "vector3d.h" #include "noisebas.h" #include "noise1.h" #define TABLEWIDTH 50 // we can reduce this at the expense #define MAXPTS (TABLEWIDTH*TABLEWIDTH) // of randomness. /************************************************************************************** > NoiseGen1::NoiseGen1() ***************************************************************************************/ NoiseGen1::NoiseGen1() { RTable=NULL; } /************************************************************************************** > NoiseGen1::~NoiseGen1() ***************************************************************************************/ NoiseGen1::~NoiseGen1() { if (RTable!=NULL) { free((void*)RTable); RTable=NULL; } } /************************************************************************************** > virtual BOOL NoiseGen1::Initialise() Aurthor: Mike Created: 07/07/96 Purpose: Initialise all the data tables we need to get this noise generator going. This particular table holds random float values in the range [0..1] ***************************************************************************************/ BOOL NoiseGen1::Initialise() { // allocate some space big enough RTable = (float*)malloc(MAXPTS * sizeof(float)); if (RTable==NULL) return FALSE; // create the table SeedTable(0); return TRUE; } /************************************************************************************** > void NoiseGen1::SeedTable(UINT32 seed) Aurthor: Mike Created: 07/07/96 Inputs: seed = the seed to use as an initial value in our random number table Purpose: Seed the random number table we use. ***************************************************************************************/ void NoiseGen1::SeedTable(UINT32 seed) { if (RTable!=NULL) { // seed the random number generator for consitency srand(seed); // now create those random impulses! // ok I'm assuming rand() will be compiled in and not a opsys level call. for (INT32 i=0; i double NoiseGen1::VNoise1D(const Vector3D &p, double scale) Author: Mike_Kenny (Xara Group Ltd) Created: 27/01/97 Inputs: p = a three dimensional vector scale = a scaling factor Returns: A double f, 0<=f<=1.0 Notes: Uses 2d quadratic B-Spline smoothing 1d quadratic bsplines are defined as... C0 = 1 - 2u + u^2 C1 = 1 + 2u - 2u^2 C2 = u^2 v = (C0*p0 + C1*p1 + C2*p2)/2 0<=u<=1 Note, this spline is a none-interpolating spline, i.e. it tends towards the points but never passes through any! This doesn't matter to us as we're interpolating random impulses. To make our tile cyclic, wrap coordinates at the edges. Also note, give points { p0,p1,p2 } the curve lives in the region [p0,p1] i.e. it is does not cover all p0..p2. To get segment [p1,p2] you'll need { p1,p2,p3 } Calculating the cyclic curve through p0,p1,p2,p3 fit... [p0,p1] = CF{ p0,p1,p2 } [p1,p2] = CF{ p1,p2,p3 } [p2,p3] = CF{ p2,p3,p0 } [P3,P0] = CF{ p3,p0,p1 } i.e. 4 input points = 4 curves = 4 intervals ***************************************************************************************/ double NoiseGen1::VNoise1D(const Vector3D &p, double scale) { float x2, x1, x0, y2, y1, y0, xf, yf; float p00, p01, p02; INT32 ax, bx, cx; INT32 ay, by, cy; INT32 samplerange; // multiplying by TABLEWIDTH rather than (TABLEWIDTH-1) // forces a wrapping as our range is 0..TABLEWIDTH-1 samplerange = (INT32)(scale); // *TABLEWIDTH); if (samplerange<1) return 0.0; // essentially ignore p.z (the calling routine sets it to 0) xf = ((float)p.x) * samplerange; yf = ((float)p.y) * samplerange; // index the 9 random impulses we'll used for (xf,yf) ax = (INT32)floor(xf); ay = (INT32)floor(yf); // calculate the 2d bspline blending coefs xf = xf - ax; // u (i.e. fract(p.x) 0..1) yf = yf - ay; // v (i.e. fract(p.y) 0..1) x1 = xf * xf; // u^2 y1 = yf * yf; // v^2 x2 = 0.5f * x1; // u^2/2 y2 = 0.5f * y1; // v^2/2 x1 = 0.5f + xf - x1; // 0.5 + u - u^2 y1 = 0.5f + yf - y1; // 0.5 + v - v^2 x0 = 0.5f - xf + x2; // 0.5 - u + u^2/2 y0 = 0.5f - yf + y2; // 0.5 - v + v^2/2 // get the next neighbours bx = ax + 1; by = ay + 1; cx = bx + 1; cy = by + 1; // do a potential double modulus as follows... // // 0 1 2 3 4 5 6 7 8 9 a b c d e f index into impulse table // 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 ... samplerange == 8 // 0 1 2 3 4 0 1 2 0 1 2 3 4 0 1 2 ... tablewidth == 5 // ^ ^ // notice the important symmetry of the values at either end of sample range // this gives tileable noise. ax = ax % samplerange; // all 0 if samplerange == 1 ay = ay % samplerange; bx = bx % samplerange; by = by % samplerange; cx = cx % samplerange; cy = cy % samplerange; if (samplerange==1) // do something at zero if poss cx=cy=1; if (TABLEWIDTH=width) { cx-=width; if (bx>=width) { bx-=width; if (ax>=width) ax-=width; } } if (cy>=width) { cy-=width; if (by>=width) { by-=width; if (ay>=width) ay-=width; } } // calculate the 2d bspline blending coefs xf = xf - ax; // u (i.e. fract(p.x) 0..1) yf = yf - ay; // v (i.e. fract(p.y) 0..1) x1 = xf * xf; // u^2 y1 = yf * yf; // v^2 x2 = 0.5f * x1; // u^2/2 y2 = 0.5f * y1; // v^2/2 x1 = 0.5f + xf - x1; // 0.5 + u - u^2 y1 = 0.5f + yf - y1; // 0.5 + v - v^2 x0 = 0.5f - xf + x2; // 0.5 - u + u^2/2 y0 = 0.5f - yf + y2; // 0.5 - v + v^2/2 ay*=TABLEWIDTH; by*=TABLEWIDTH; cy*=TABLEWIDTH; // read and interpolate the impulse values p00 = RTable[ax+ay]; p01 = RTable[bx+ay]; p02 = RTable[cx+ay]; xf = y0 * (x0*p00 + x1*p01 + x2*p02); p00 = RTable[ax+by]; p01 = RTable[bx+by]; p02 = RTable[cx+by]; xf += y1 * (x0*p00 + x1*p01 + x2*p02); p00 = RTable[ax+cy]; p01 = RTable[bx+cy]; p02 = RTable[cx+cy]; xf += y2 * (x0*p00 + x1*p01 + x2*p02); return (double)xf; } */ /************************************************************************************** > Vector3D NoiseGen1::VNoise3D(const Vector3D &v) Purpose: Vector-valued version of "Noise" ***************************************************************************************/ Vector3D NoiseGen1::VNoise3D(const Vector3D &p) { return Vector3D(0,0,0); }