RosettaCodeData/Task/Draw-a-sphere/C/draw-a-sphere-2.c
2015-02-20 00:35:01 -05:00

162 lines
2.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAXD 8
int g[] = { -1, 1, -1, 1 };
/* Perlin-like noise */
inline void
hashed(int *data, int *out, int len) {
# define ror(a, d) ((a << (d)) | (a >> (32 - d)))
register unsigned int h = 0x12345678, tmp;
unsigned int *d = (void*)data;
int i = len;
while (i--) {
tmp = *d++;
h += ror(h, 15) ^ ror(tmp, 5);
}
h ^= ror(h, 7);
h += ror(h, 23);
h ^= ror(h, 19);
h += ror(h, 11);
h ^= ror(h, 13);
h += ror(h, 17);
# undef ror
for (i = len; i--; ) {
out[i] = g[h & 3];
h >>= 2;
}
}
double scale[MAXD], scale_u[MAXD];
void noise_init()
{
int i;
for (i = 1; i < MAXD; i++) {
scale[i] = 1 / (1 + sqrt(i + 1));
scale_u[i] = scale[i] / sqrt(i + 1);
}
}
double noise(double *x, int d)
{
# define sum(s, x) for (s = 0, j = 0; j < d; j++) s += x
register int i, j;
int n[MAXD], o[MAXD], g[MAXD], tmp;
double s, r, t, w, ret, u[MAXD];
sum(s, x[j]);
s *= scale[d];
for (i = 0; i < d; i++) {
o[i] = i;
t = x[i] + s;
u[i] = t - (n[i] = floor(t));
}
o[d] = 0;
for (i = 0; i < d - 1; i++)
for (j = i; j < d; j++)
if (u[o[i]] < u[o[j]])
tmp = o[i], o[i] = o[j], o[j] = tmp;
ret = w = 0, r = 1;
for (s = 0, j = 0; j < d; j++) s += n[j];
s *= scale_u[d];
for (i = 0; i <= d; i++) {
for (j = 0; j < d; j++)
u[j] = x[j] + s - n[j];
for (t = (d + 1.) / (2 * d), j = 0; j < d; j++) {
t -= u[j] * u[j];
if (t <= 0) break;
}
if (t >= 0) {
r = 0;
hashed(n, g, d);
for (j = 0; j < d; j++)
if (g[j]) r += (g[j] == 1 ? u[j] : -u[j]);
t *= t;
ret += r * t * t;
}
if (i < d) {
n[o[i]]++;
s += scale_u[d];
}
}
return ret * (d * d);
}
double get_noise2(double x, double y)
{
int i, ws;
double r = 0, v[2];
for (i = 1, ws = 0; i <= 128; i <<= 1) {
v[0] = x * i, v[1] = y * i;
r += noise(v, 2);
ws ++;
}
r /= ws;
return r;
}
double get_noise3(double x, double y, double z)
{
int i, ws;
double r = 0, v[3], w;
for (i = 1, ws = 0; i <= 32; i <<= 1) {
v[0] = x * i, v[1] = y * i, v[2] = z * i;
w = 1./sqrt(i);
r += noise(v, 3) * w;
ws += w;
}
return r / ws;
}
int main(int c, char** v)
{
unsigned char pix[256 * 256], *p;
int i, j;
double x, y, z, w;
FILE *fp;
noise_init();
for (p = pix, i = 0; i < 256 * 256; i++) *p++ = 0;
for (p = pix, i = 0; i < 256; i++) {
y = (i - 128) / 125.;
for (j = 0; j < 256; j++, p++) {
x = (j - 128) / 125.;
*p = (get_noise2(i/256., j/256.) + 1) / 6 * i;
z = 1- x*x - y*y;
if (z < 0) continue;
z = sqrt(z);
w = get_noise3(x, y, z);
w = (w + 1) / 2;
w *= (1 + x - y + z) / 3.5;
if (w < 0) w = 0;
*p = w * 255;
}
}
fp = fopen("out.pgm", "w+");
fprintf(fp, "P5\n256 256\n255\n");
fwrite(pix, 1, 256 * 256, fp);
fclose(fp);
return 0;
}