/* generate_env_map2.c - Don Yang (uguu.org) 09/20/09 */ #include #include #include #include #define OUTPUT_SIZE 512 #define GRADIENT_SCALE 2.0 typedef struct { unsigned char c[3]; } Pixel; /* Convert value from one range to another */ static double ConvertRange(double input0, double input1, double output0, double output1, double x) { return ((output1 - output0) * (x - input0) / (input1 - input0)) + output0; } /* Set pixel from a gradient of 2 colors */ static void SetGradient(const double *color0, const double *color1, double p, /*@out@*/Pixel *output) { int i; for(i = 0; i < 3; i++) { output->c[i] = (unsigned char)ConvertRange(0.0, 1.0, color0[i], color1[i], p); } } /* Set pixel color based on gradient position in [-1, 1] */ static void SetPixel(double y, /*@out@*/Pixel *output) { static const double top[3] = {0.0, 255.0, 255.0}; static const double middle[3] = {255.0, 255.0, 255.0}; static const double bottom[3] = {0.0, 128.0, 64.0}; static const double t1 = 0.03; static const double t2 = -0.01; if( y > t1 ) { SetGradient(middle, top, ConvertRange(t1, 1.0, 0.0, 1.0, y), output); } else if( y > t2 ) { output->c[0] = (unsigned char)middle[0]; output->c[1] = (unsigned char)middle[1]; output->c[2] = (unsigned char)middle[2]; } else { SetGradient(bottom, middle, ConvertRange(-1.0, t2, 0.0, 1.0, y), output); } } /* Generate output map based on vertical reflection */ static Pixel *GenerateOutputMap(int output_size) { double dx, dy, r2, ly, ty; int x, y; Pixel *image, *p; /* Allocate image */ image = (Pixel*)malloc(output_size * output_size * sizeof(Pixel)); assert(image != NULL); p = image; for(y = 0; y < output_size; y++) { dy = ConvertRange(0.0, (double)(output_size-1), 1.0, -1.0, (double)y); for(x = 0; x < output_size; x++) { dx = ConvertRange(0.0, (double)(output_size-1), -1.0, 1.0, (double)x); r2 = dx * dx + dy * dy; if( r2 >= 1.0 ) { p->c[0] = p->c[1] = p->c[2] = (unsigned char)0; } else { ly = GRADIENT_SCALE * sqrt((1 - dx * dx) / (1 + GRADIENT_SCALE * GRADIENT_SCALE)); if( dy >= ly ) { SetPixel(1.0, p); } else if( dy <= -ly ) { SetPixel(-1.0, p); } else { ty = dy / (GRADIENT_SCALE * sqrt(1 - r2)); if( isnan(ty) != 0 || ty < -1.0 || ty > 1.0 ) SetPixel(dy, p); else SetPixel(ty, p); } } p++; } } return image; } /* Write image to output */ static void WriteImage(const Pixel *image, int width, int height, FILE *output) { int x, y; fprintf(output, "P3\n%d %d\n255\n", width, height); for(y = 0; y < height; y++) { for(x = 0; x < width; x++) { fprintf(output, "%d %d %d\n", (int)(image->c[0]), (int)(image->c[1]), (int)(image->c[2])); image++; } } } int main(void) { Pixel *output_image; output_image = GenerateOutputMap(OUTPUT_SIZE); WriteImage(output_image, OUTPUT_SIZE, OUTPUT_SIZE, stdout); free(output_image); return 0; }