par_bluenoise.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. // BLUENOISE :: https://github.com/prideout/par
  2. // Generator for infinite 2D point sequences using Recursive Wang Tiles.
  3. //
  4. // In addition to this source code, you'll need to download one of the following
  5. // tilesets, the first being 2 MB while the other is 257 KB. The latter cheats
  6. // by referencing the point sequence from the first tile for all 8 tiles. This
  7. // obviously produces poor results, but in many contexts, it isn't noticeable.
  8. //
  9. // http://github.prideout.net/assets/bluenoise.bin
  10. // http://github.prideout.net/assets/bluenoise.trimmed.bin
  11. //
  12. // The code herein is an implementation of the algorithm described in:
  13. //
  14. // Recursive Wang Tiles for Real-Time Blue Noise
  15. // Johannes Kopf, Daniel Cohen-Or, Oliver Deussen, Dani Lischinski
  16. // ACM Transactions on Graphics 25, 3 (Proc. SIGGRAPH 2006)
  17. //
  18. // If you use this software for research purposes, please cite the above paper
  19. // in any resulting publication.
  20. //
  21. // EXAMPLE
  22. //
  23. // Generate point samples whose density is guided by a 512x512 grayscale image:
  24. //
  25. // int npoints;
  26. // float* points;
  27. // int maxpoints = 1e6;
  28. // float density = 30000;
  29. // par_bluenoise_context* ctx;
  30. // ctx = par_bluenoise_from_file("bluenoise.bin", maxpoints);
  31. // par_bluenoise_density_from_gray(ctx, source_pixels, 512, 512, 1);
  32. // points = par_bluenoise_generate(ctx, density, &npoints);
  33. // ... Draw points here. Each point is a three-tuple of (X Y RANK).
  34. // par_bluenoise_free(ctx);
  35. //
  36. #ifndef PAR_BLUENOISE_H
  37. #define PAR_BLUENOISE_H
  38. #ifdef __cplusplus
  39. extern "C" {
  40. #endif
  41. // -----------------------------------------------------------------------------
  42. // BEGIN PUBLIC API
  43. // -----------------------------------------------------------------------------
  44. typedef unsigned char par_byte;
  45. // Encapsulates a tile set and an optional density function.
  46. typedef struct par_bluenoise_context_s par_bluenoise_context;
  47. // Creates a bluenoise context using the given tileset. The first argument is
  48. // the file path the bin file. The second argument is the maximum number of
  49. // points that you expect to ever be generated.
  50. par_bluenoise_context* par_bluenoise_from_file(char const* path, int maxpts);
  51. // Creates a bluenoise context using the given tileset. The first and second
  52. // arguments describe a memory buffer containing the contents of the bin file.
  53. // The third argument is the maximum number of points that you expect to ever
  54. // be generated.
  55. par_bluenoise_context* par_bluenoise_from_buffer(
  56. par_byte const* buffer, int nbytes, int maxpts);
  57. // Sets up a scissoring rectangle using the given lower-left and upper-right
  58. // coordinates. By default the scissor encompasses [-0.5, -0.5] - [0.5, 0.5],
  59. // which is the entire sampling domain for the two "generate" methods.
  60. void par_bluenoise_set_viewport(
  61. par_bluenoise_context*, float left, float bottom, float right, float top);
  62. // Sets up a reference window size. The only purpose of this is to ensure
  63. // that apparent density remains constant when the window gets resized.
  64. // Clients should call this *before* calling par_bluenoise_set_viewport.
  65. void par_bluenoise_set_window(par_bluenoise_context*, int width, int height);
  66. // Frees all memory associated with the given bluenoise context.
  67. void par_bluenoise_free(par_bluenoise_context* ctx);
  68. // Copies a grayscale image into the bluenoise context to guide point density.
  69. // Darker regions generate a higher number of points. The given bytes-per-pixel
  70. // value is the stride between pixels.
  71. void par_bluenoise_density_from_gray(par_bluenoise_context* ctx,
  72. const unsigned char* pixels, int width, int height, int bpp);
  73. // Creates a binary mask to guide point density. The given bytes-per-pixel
  74. // value is the stride between pixels, which must be 4 or less.
  75. void par_bluenoise_density_from_color(par_bluenoise_context* ctx,
  76. const unsigned char* pixels, int width, int height, int bpp,
  77. unsigned int background_color, int invert);
  78. // Generates samples using Recursive Wang Tiles. This is really fast!
  79. // The returned pointer is a list of three-tuples, where XY are in [-0.5, +0.5]
  80. // and Z is a rank value that can be used to create a progressive ordering.
  81. // The caller should not free the returned pointer.
  82. float* par_bluenoise_generate(
  83. par_bluenoise_context* ctx, float density, int* npts);
  84. // Generates an ordered sequence of tuples with the specified sequence length.
  85. // This is slower than the other "generate" method because it uses a dumb
  86. // backtracking method to determine a reasonable density value, and it
  87. // automatically sorts the output by rank. The dims argument must be 2 or more;
  88. // it represents the desired stride (in floats) between consecutive verts in the
  89. // returned data buffer.
  90. float* par_bluenoise_generate_exact(
  91. par_bluenoise_context* ctx, int npts, int dims);
  92. // Performs an in-place sort of 3-tuples, based on the 3rd component, then
  93. // replaces the 3rd component with an index.
  94. void par_bluenoise_sort_by_rank(float* pts, int npts);
  95. #ifndef PAR_PI
  96. #define PAR_PI (3.14159265359)
  97. #define PAR_MIN(a, b) (a > b ? b : a)
  98. #define PAR_MAX(a, b) (a > b ? a : b)
  99. #define PAR_CLAMP(v, lo, hi) PAR_MAX(lo, PAR_MIN(hi, v))
  100. #define PAR_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
  101. #define PAR_SQR(a) ((a) * (a))
  102. #endif
  103. #ifndef PAR_MALLOC
  104. #define PAR_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
  105. #define PAR_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
  106. #define PAR_REALLOC(T, BUF, N) ((T*) realloc(BUF, sizeof(T) * (N)))
  107. #define PAR_FREE(BUF) free(BUF)
  108. #endif
  109. #ifdef __cplusplus
  110. }
  111. #endif
  112. // -----------------------------------------------------------------------------
  113. // END PUBLIC API
  114. // -----------------------------------------------------------------------------
  115. #ifdef PAR_BLUENOISE_IMPLEMENTATION
  116. #include <stdio.h>
  117. #include <stdlib.h>
  118. #include <assert.h>
  119. #include <math.h>
  120. #include <string.h>
  121. #define PAR_MINI(a, b) ((a < b) ? a : b)
  122. #define PAR_MAXI(a, b) ((a > b) ? a : b)
  123. typedef struct {
  124. float x;
  125. float y;
  126. } par_vec2;
  127. typedef struct {
  128. float x;
  129. float y;
  130. float rank;
  131. } par_vec3;
  132. typedef struct {
  133. int n, e, s, w;
  134. int nsubtiles, nsubdivs, npoints, nsubpts;
  135. int** subdivs;
  136. par_vec2* points;
  137. par_vec2* subpts;
  138. } par_tile;
  139. struct par_bluenoise_context_s {
  140. par_vec3* points;
  141. par_tile* tiles;
  142. float global_density;
  143. float left, bottom, right, top;
  144. int ntiles, nsubtiles, nsubdivs;
  145. int npoints;
  146. int maxpoints;
  147. int density_width;
  148. int density_height;
  149. unsigned char* density;
  150. float mag;
  151. int window_width;
  152. int window_height;
  153. int abridged;
  154. };
  155. static float sample_density(par_bluenoise_context* ctx, float x, float y)
  156. {
  157. unsigned char* density = ctx->density;
  158. if (!density) {
  159. return 1;
  160. }
  161. int width = ctx->density_width;
  162. int height = ctx->density_height;
  163. y = 1 - y;
  164. x -= 0.5;
  165. y -= 0.5;
  166. float tx = x * PAR_MAXI(width, height);
  167. float ty = y * PAR_MAXI(width, height);
  168. x += 0.5;
  169. y += 0.5;
  170. tx += width / 2;
  171. ty += height / 2;
  172. int ix = PAR_CLAMP((int) tx, 0, width - 2);
  173. int iy = PAR_CLAMP((int) ty, 0, height - 2);
  174. return density[iy * width + ix] / 255.0f;
  175. }
  176. static void recurse_tile(
  177. par_bluenoise_context* ctx, par_tile* tile, float x, float y, int level)
  178. {
  179. float left = ctx->left, right = ctx->right;
  180. float top = ctx->top, bottom = ctx->bottom;
  181. float mag = ctx->mag;
  182. float tileSize = 1.f / powf(ctx->nsubtiles, level);
  183. if (x + tileSize < left || x > right || y + tileSize < bottom || y > top) {
  184. return;
  185. }
  186. float depth = powf(ctx->nsubtiles, 2 * level);
  187. float threshold = mag / depth * ctx->global_density - tile->npoints;
  188. int ntests = PAR_MINI(tile->nsubpts, threshold);
  189. float factor = 1.f / mag * depth / ctx->global_density;
  190. for (int i = 0; i < ntests; i++) {
  191. float px = x + tile->subpts[i].x * tileSize;
  192. float py = y + tile->subpts[i].y * tileSize;
  193. if (px < left || px > right || py < bottom || py > top) {
  194. continue;
  195. }
  196. if (sample_density(ctx, px, py) < (i + tile->npoints) * factor) {
  197. continue;
  198. }
  199. ctx->points[ctx->npoints].x = px - 0.5;
  200. ctx->points[ctx->npoints].y = py - 0.5;
  201. ctx->points[ctx->npoints].rank = (level + 1) + i * factor;
  202. ctx->npoints++;
  203. if (ctx->npoints >= ctx->maxpoints) {
  204. return;
  205. }
  206. }
  207. const float scale = tileSize / ctx->nsubtiles;
  208. if (threshold <= tile->nsubpts) {
  209. return;
  210. }
  211. level++;
  212. for (int ty = 0; ty < ctx->nsubtiles; ty++) {
  213. for (int tx = 0; tx < ctx->nsubtiles; tx++) {
  214. int tileIndex = tile->subdivs[0][ty * ctx->nsubtiles + tx];
  215. par_tile* subtile = &ctx->tiles[tileIndex];
  216. recurse_tile(ctx, subtile, x + tx * scale, y + ty * scale, level);
  217. }
  218. }
  219. }
  220. void par_bluenoise_set_window(par_bluenoise_context* ctx, int width, int height)
  221. {
  222. ctx->window_width = width;
  223. ctx->window_height = height;
  224. }
  225. void par_bluenoise_set_viewport(par_bluenoise_context* ctx, float left,
  226. float bottom, float right, float top)
  227. {
  228. // Transform [-.5, +.5] to [0, 1]
  229. left = ctx->left = left + 0.5;
  230. right = ctx->right = right + 0.5;
  231. bottom = ctx->bottom = bottom + 0.5;
  232. top = ctx->top = top + 0.5;
  233. // Determine magnification factor BEFORE clamping.
  234. float scale = 1000 * (top - bottom) / ctx->window_height;
  235. ctx->mag = powf(scale, -2);
  236. // The density function is only sampled in [0, +1].
  237. ctx->left = PAR_CLAMP(left, 0, 1);
  238. ctx->right = PAR_CLAMP(right, 0, 1);
  239. ctx->bottom = PAR_CLAMP(bottom, 0, 1);
  240. ctx->top = PAR_CLAMP(top, 0, 1);
  241. }
  242. float* par_bluenoise_generate(
  243. par_bluenoise_context* ctx, float density, int* npts)
  244. {
  245. ctx->global_density = density;
  246. ctx->npoints = 0;
  247. float left = ctx->left;
  248. float right = ctx->right;
  249. float bottom = ctx->bottom;
  250. float top = ctx->top;
  251. float mag = ctx->mag;
  252. int ntests = PAR_MINI(ctx->tiles[0].npoints, mag * ctx->global_density);
  253. float factor = 1.f / mag / ctx->global_density;
  254. for (int i = 0; i < ntests; i++) {
  255. float px = ctx->tiles[0].points[i].x;
  256. float py = ctx->tiles[0].points[i].y;
  257. if (px < left || px > right || py < bottom || py > top) {
  258. continue;
  259. }
  260. if (sample_density(ctx, px, py) < (i + 1) * factor) {
  261. continue;
  262. }
  263. ctx->points[ctx->npoints].x = px - 0.5;
  264. ctx->points[ctx->npoints].y = py - 0.5;
  265. ctx->points[ctx->npoints].rank = i * factor;
  266. ctx->npoints++;
  267. if (ctx->npoints >= ctx->maxpoints) {
  268. break;
  269. }
  270. }
  271. recurse_tile(ctx, &ctx->tiles[0], 0, 0, 0);
  272. *npts = ctx->npoints;
  273. return &ctx->points->x;
  274. }
  275. #define freadi() \
  276. *((int*) ptr); \
  277. ptr += sizeof(int)
  278. #define freadf() \
  279. *((float*) ptr); \
  280. ptr += sizeof(float)
  281. static par_bluenoise_context* par_bluenoise_create(
  282. char const* filepath, int nbytes, int maxpts)
  283. {
  284. par_bluenoise_context* ctx = PAR_MALLOC(par_bluenoise_context, 1);
  285. ctx->maxpoints = maxpts;
  286. ctx->points = PAR_MALLOC(par_vec3, maxpts);
  287. ctx->density = 0;
  288. ctx->abridged = 0;
  289. par_bluenoise_set_window(ctx, 1024, 768);
  290. par_bluenoise_set_viewport(ctx, -.5, -.5, .5, .5);
  291. char* buf = 0;
  292. if (nbytes == 0) {
  293. FILE* fin = fopen(filepath, "rb");
  294. assert(fin);
  295. fseek(fin, 0, SEEK_END);
  296. nbytes = (int) ftell(fin);
  297. fseek(fin, 0, SEEK_SET);
  298. buf = PAR_MALLOC(char, nbytes);
  299. int consumed = (int) fread(buf, nbytes, 1, fin);
  300. assert(consumed == 1);
  301. fclose(fin);
  302. }
  303. char const* ptr = buf ? buf : filepath;
  304. int ntiles = ctx->ntiles = freadi();
  305. int nsubtiles = ctx->nsubtiles = freadi();
  306. int nsubdivs = ctx->nsubdivs = freadi();
  307. par_tile* tiles = ctx->tiles = PAR_MALLOC(par_tile, ntiles);
  308. for (int i = 0; i < ntiles; i++) {
  309. tiles[i].n = freadi();
  310. tiles[i].e = freadi();
  311. tiles[i].s = freadi();
  312. tiles[i].w = freadi();
  313. tiles[i].subdivs = PAR_MALLOC(int*, nsubdivs);
  314. for (int j = 0; j < nsubdivs; j++) {
  315. int* subdiv = PAR_MALLOC(int, PAR_SQR(nsubtiles));
  316. for (int k = 0; k < PAR_SQR(nsubtiles); k++) {
  317. subdiv[k] = freadi();
  318. }
  319. tiles[i].subdivs[j] = subdiv;
  320. }
  321. tiles[i].npoints = freadi();
  322. tiles[i].points = PAR_MALLOC(par_vec2, tiles[i].npoints);
  323. for (int j = 0; j < tiles[i].npoints; j++) {
  324. tiles[i].points[j].x = freadf();
  325. tiles[i].points[j].y = freadf();
  326. }
  327. tiles[i].nsubpts = freadi();
  328. tiles[i].subpts = PAR_MALLOC(par_vec2, tiles[i].nsubpts);
  329. for (int j = 0; j < tiles[i].nsubpts; j++) {
  330. tiles[i].subpts[j].x = freadf();
  331. tiles[i].subpts[j].y = freadf();
  332. }
  333. // The following hack allows for an optimization whereby
  334. // the first tile's point set is re-used for every other tile.
  335. // This goes against the entire purpose of Recursive Wang Tiles,
  336. // but in many applications the qualatitive loss is not
  337. // observable, and the footprint savings are huge (10x).
  338. if (tiles[i].npoints == 0) {
  339. ctx->abridged = 1;
  340. tiles[i].npoints = tiles[0].npoints;
  341. tiles[i].points = tiles[0].points;
  342. tiles[i].nsubpts = tiles[0].nsubpts;
  343. tiles[i].subpts = tiles[0].subpts;
  344. }
  345. }
  346. free(buf);
  347. return ctx;
  348. }
  349. par_bluenoise_context* par_bluenoise_from_file(char const* path, int maxpts)
  350. {
  351. return par_bluenoise_create(path, 0, maxpts);
  352. }
  353. par_bluenoise_context* par_bluenoise_from_buffer(
  354. par_byte const* buffer, int nbytes, int maxpts)
  355. {
  356. return par_bluenoise_create((char const*) buffer, nbytes, maxpts);
  357. }
  358. void par_bluenoise_density_from_gray(par_bluenoise_context* ctx,
  359. const unsigned char* pixels, int width, int height, int bpp)
  360. {
  361. ctx->density_width = width;
  362. ctx->density_height = height;
  363. ctx->density = PAR_MALLOC(unsigned char, width * height);
  364. unsigned char* dst = ctx->density;
  365. for (int j = 0; j < height; j++) {
  366. for (int i = 0; i < width; i++) {
  367. *dst++ = 255 - (*pixels);
  368. pixels += bpp;
  369. }
  370. }
  371. }
  372. void par_bluenoise_density_from_color(par_bluenoise_context* ctx,
  373. const unsigned char* pixels, int width, int height, int bpp,
  374. unsigned int background_color, int invert)
  375. {
  376. unsigned int bkgd = background_color;
  377. ctx->density_width = width;
  378. ctx->density_height = height;
  379. ctx->density = PAR_MALLOC(unsigned char, width * height);
  380. unsigned char* dst = ctx->density;
  381. unsigned int mask = 0x000000ffu;
  382. if (bpp > 1) {
  383. mask |= 0x0000ff00u;
  384. }
  385. if (bpp > 2) {
  386. mask |= 0x00ff0000u;
  387. }
  388. if (bpp > 3) {
  389. mask |= 0xff000000u;
  390. }
  391. assert(bpp <= 4);
  392. for (int j = 0; j < height; j++) {
  393. for (int i = 0; i < width; i++) {
  394. unsigned int val = (*((unsigned int*) pixels)) & mask;
  395. val = invert ? (val == bkgd) : (val != bkgd);
  396. *dst++ = val ? 255 : 0;
  397. pixels += bpp;
  398. }
  399. }
  400. }
  401. void par_bluenoise_free(par_bluenoise_context* ctx)
  402. {
  403. free(ctx->points);
  404. for (int t = 0; t < ctx->ntiles; t++) {
  405. for (int s = 0; s < ctx->nsubdivs; s++) {
  406. free(ctx->tiles[t].subdivs[s]);
  407. }
  408. free(ctx->tiles[t].subdivs);
  409. if (t == 0 || !ctx->abridged) {
  410. free(ctx->tiles[t].points);
  411. free(ctx->tiles[t].subpts);
  412. }
  413. }
  414. free(ctx->tiles);
  415. free(ctx->density);
  416. }
  417. int cmp(const void* a, const void* b)
  418. {
  419. const par_vec3* v1 = (const par_vec3*) a;
  420. const par_vec3* v2 = (const par_vec3*) b;
  421. if (v1->rank < v2->rank) {
  422. return -1;
  423. }
  424. if (v1->rank > v2->rank) {
  425. return 1;
  426. }
  427. return 0;
  428. }
  429. void par_bluenoise_sort_by_rank(float* floats, int npts)
  430. {
  431. par_vec3* vecs = (par_vec3*) floats;
  432. qsort(vecs, npts, sizeof(vecs[0]), cmp);
  433. for (int i = 0; i < npts; i++) {
  434. vecs[i].rank = i;
  435. }
  436. }
  437. float* par_bluenoise_generate_exact(
  438. par_bluenoise_context* ctx, int npts, int stride)
  439. {
  440. assert(stride >= 2);
  441. int maxpoints = npts * 2;
  442. if (ctx->maxpoints < maxpoints) {
  443. free(ctx->points);
  444. ctx->maxpoints = maxpoints;
  445. ctx->points = PAR_MALLOC(par_vec3, maxpoints);
  446. }
  447. int ngenerated = 0;
  448. int nprevious = 0;
  449. int ndesired = npts;
  450. float density = 2048;
  451. while (ngenerated < ndesired) {
  452. par_bluenoise_generate(ctx, density, &ngenerated);
  453. // Might be paranoid, but break if something fishy is going on:
  454. if (ngenerated == nprevious) {
  455. return 0;
  456. }
  457. // Perform crazy heuristic to approach a nice density:
  458. if (ndesired / ngenerated >= 2) {
  459. density *= 2;
  460. } else {
  461. density += density / 10;
  462. }
  463. nprevious = ngenerated;
  464. }
  465. par_bluenoise_sort_by_rank(&ctx->points->x, ngenerated);
  466. if (stride != 3) {
  467. int nbytes = sizeof(float) * stride * ndesired;
  468. float* pts = PAR_MALLOC(float, stride * ndesired);
  469. float* dst = pts;
  470. const float* src = &ctx->points->x;
  471. for (int i = 0; i < ndesired; i++, src++) {
  472. *dst++ = *src++;
  473. *dst++ = *src++;
  474. if (stride > 3) {
  475. *dst++ = *src;
  476. dst += stride - 3;
  477. }
  478. }
  479. memcpy(ctx->points, pts, nbytes);
  480. free(pts);
  481. }
  482. return &ctx->points->x;
  483. }
  484. #undef PAR_MINI
  485. #undef PAR_MAXI
  486. #endif // PAR_BLUENOISE_IMPLEMENTATION
  487. #endif // PAR_BLUENOISE_H