/////////////////////////////////////////////////////////////////////////////////// // File : BLUE_NOISE.h /////////////////////////////////////////////////////////////////////////////////// // // LumosQuad - A Lightning Generator // Copyright 2007 // The University of North Carolina at Chapel Hill // /////////////////////////////////////////////////////////////////////////////////// // // 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 of the License, or // (at your option) any later version. // // This program is 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 this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // The University of North Carolina at Chapel Hill makes no representations // about the suitability of this software for any purpose. It is provided // "as is" without express or implied warranty. // // Permission to use, copy, modify and distribute this software and its // documentation for educational, research and non-profit purposes, without // fee, and without a written agreement is hereby granted, provided that the // above copyright notice and the following three paragraphs appear in all // copies. // // THE UNIVERSITY OF NORTH CAROLINA SPECIFICALLY DISCLAIM ANY WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN // "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA HAS NO OBLIGATION TO // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. // // Please send questions and comments about LumosQuad to kim@cs.unc.edu. // /////////////////////////////////////////////////////////////////////////////////// // // This program uses OpenEXR, which has the following restrictions: // // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas // Digital Ltd. LLC // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Industrial Light & Magic nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // /////////////////////////////////////////////////////////////////////////////////// // // This class is a very thin wrapper to Daniel Dunbar's blue noise generator. // With the exception of BLUE_NOISE.h and BLUE_NOISE.cpp, the other files // in this directory are unmodified copies of his code. // // For the original, untainted code, see: // http://www.cs.virginia.edu/~gfx/pubs/antimony/ // /////////////////////////////////////////////////////////////////////////////////// // $Id: PDSampling.cpp,v 1.12 2006/07/11 16:45:22 zr Exp $ #define _USE_MATH_DEFINES #include #include #include "BLUE_NOISE.h" #include "RangeList.h" #include "ScallopedSector.h" #include "WeightedDiscretePDF.h" typedef std::vector IntVector; /// BLUE_NOISE::BLUE_NOISE(float _radius, bool _isTiled, bool usesGrid) : m_rng(123456), radius(_radius), isTiled(_isTiled) { if (usesGrid) { // grid size is chosen so that 4*radius search only // requires searching adjacent cells, this also // determines max points per cell m_gridSize = (int) ceil(2./(4.*_radius)); if (m_gridSize<2) m_gridSize = 2; m_gridCellSize = 2.0f/m_gridSize; m_grid = new int[m_gridSize*m_gridSize][kMaxPointsPerCell]; for (int y=0; y=a.x && 1>=a.y; } Vec2 BLUE_NOISE::randomPoint() { return Vec2(2*m_rng.getFloatL()-1, 2*m_rng.getFloatL()-1); } Vec2 BLUE_NOISE::getTiled(Vec2 v) { float x = v.x, y = v.y; if (isTiled) { if (x<-1) x += 2; else if (x>1) x -= 2; if (y<-1) y += 2; else if (y>1) y -= 2; } return Vec2(x,y); } void BLUE_NOISE::getGridXY(Vec2 &v, int *gx_out, int *gy_out) { int gx = *gx_out = (int) floor(.5*(v.x + 1)*m_gridSize); int gy = *gy_out = (int) floor(.5*(v.y + 1)*m_gridSize); if (gx<0 || gx>=m_gridSize || gy<0 || gy>=m_gridSize) { printf("Internal error, point outside grid was generated, ignoring.\n"); } } void BLUE_NOISE::addPoint(Vec2 pt) { int i, gx, gy, *cell; points.push_back(pt); if (m_grid) { getGridXY(pt, &gx, &gy); cell = m_grid[gy*m_gridSize + gx]; for (i=0; i(m_gridSize>>1)) N = m_gridSize>>1; m_neighbors.clear(); getGridXY(pt, &gx, &gy); for (j=-N; j<=N; j++) { for (i=-N; i<=N; i++) { int cx = (gx+i+m_gridSize)%m_gridSize; int cy = (gy+j+m_gridSize)%m_gridSize; int *cell = m_grid[cy*m_gridSize + cx]; for (k=0; k(m_gridSize>>1)) N = m_gridSize>>1; getGridXY(pt, &gx, &gy); for (j=-N; j<=N; j++) { for (i=-N; i<=N; i++) { int cx = (gx+i+m_gridSize)%m_gridSize; int cy = (gy+j+m_gridSize)%m_gridSize; int *cell = m_grid[cy*m_gridSize + cx]; for (k=0; k(m_gridSize>>1)) N = m_gridSize>>1; getGridXY(candidate, &gx, &gy); int xSide = (candidate.x - (-1 + gx*m_gridCellSize))>m_gridCellSize*.5; int ySide = (candidate.y - (-1 + gy*m_gridCellSize))>m_gridCellSize*.5; int iy = 1; for (j=-N; j<=N; j++) { int ix = 1; if (j==0) iy = ySide; else if (j==1) iy = 0; for (i=-N; i<=N; i++) { if (i==0) ix = xSide; else if (i==1) ix = 0; // offset to closest cell point float dx = candidate.x - (-1 + (gx+i+ix)*m_gridCellSize); float dy = candidate.y - (-1 + (gy+j+iy)*m_gridCellSize); if (dx*dx+dy*dy relaxTmpOut.txt"); tmp = fopen("relaxTmpOut.txt", "r"); fscanf(tmp, "%d\n%d\n", &dim, &numVerts); if (dim!=2) { printf("Error calling out to qvoronoi, skipping relaxation.\n"); goto exit; } verts = new Vec2[numVerts]; for (int i=0; i RegionMap; void BLUE_NOISE::complete() { RangeList rl(0,0); IntVector candidates; addPoint(randomPoint()); candidates.push_back((int) points.size()-1); while (candidates.size()) { int c = m_rng.getInt32()%candidates.size(); int index = candidates[c]; Vec2 candidate = points[index]; candidates[c] = candidates[candidates.size()-1]; candidates.pop_back(); rl.reset(0, (float) M_PI*2); findNeighborRanges(index, rl); while (rl.numRanges) { RangeEntry &re = rl.ranges[m_rng.getInt32()%rl.numRanges]; float angle = re.min + (re.max-re.min)*m_rng.getFloatL(); Vec2 pt = getTiled(Vec2(candidate.x + cos(angle)*2*radius, candidate.y + sin(angle)*2*radius)); addPoint(pt); candidates.push_back((int) points.size()-1); rl.subtract(angle - (float) M_PI/3, angle + (float) M_PI/3); } } } void BLUE_NOISE::writeToBool(bool* noise, int size) { // wipe int index = 0; for (index = 0; index < size * size; index++) noise[index] = false; for (int x = 0; x < points.size(); x++) { int i = (points[x].x + 1.0f) * 0.5f * size; int j = (points[x].y + 1.0f) * 0.5f * size; index = i + j * size; noise[index] = true; } }