crystal/crystal-ng.c

204 lines
4.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* crystal-ng.c
*
* Ⓒ 2023 konomo
* EUPL-1.2
**/
#include<stdio.h> /* printf; fprintf */
#include<stdlib.h> /* atoi; rand; srand */
#include<time.h> /* time */
#include<math.h> /* lround */
#include "crystal-ng.h"
#include "bmp.h"
/* how many colours, max at 256 */
int colors = 256;
/* generate_bitmap() from bmp.c */
/* extern void line(int x0, int y0, int x1, int y1, unsigned char clr); /\* bres.c *\/ */
char new_sprout(int id);
void process(int x, int y);
int check_pixel(int x, int y);
int paint_pixel(int x, int y, unsigned char clr);
unsigned char image[HEIGHT][WIDTH][BPP];
int main(void)
{
if(colors<3) colors = 3;
if(colors>256) colors = 256;
char *file_name = (char*) "output.bmp";
srand(time(NULL));
for(int i=0; i<SPROUTS; ++i)
{
char err = new_sprout(i);
if(err==1) fprintf(stderr, "sprouting failed for id %d\n", i);
}
/* iterate through image grid. if on colored spot, check for empty spots and
expand as far as possible by velocity */
for(int x=0; x<WIDTH; ++x)
{
printf("%d\n", x);
for(int y=0; y<HEIGHT; ++y)
{
process(x, y);
}
}
generate_bitmap((unsigned char*)image, HEIGHT, WIDTH, file_name);
printf("image generation done.\n");
return 0;
}
/* color limiting code */
unsigned char generate_color()
{
unsigned char clr = rand() % colors /* + colors */;
clr*=(unsigned char)lround( (256/colors) );
return clr;
}
char new_sprout(int id)
{
if(id >= SPROUTS) return 1;
int x = rand() % WIDTH + 1;
int y = rand() % HEIGHT + 1;
unsigned char clr = generate_color();
printf("sprout %d at (%d|%d)\n", id, x, y);
paint_pixel(x, y, clr);
return 0;
}
int order_check(int var, int c, int order)
{
if(order==-1)
return check_pixel(c, var);
return check_pixel(var, c);
}
/* this function will first check the variables plus the total calculated
velocity (velocity in this function simply means a value that is added to (var).
if this does not work, (v) is reduced until it is 0, attempting to find the
closest uncoloured/empty pixel. once it is found (or is 0), a line is drawn.
this is how a crystal grows.
var is a variable value, c is constant value, v is velocity, order is the
order in which these values are to be checked ( [order_check] ). clr is
the color. */
void id_and_proceed(int var, int c, int v, int order, unsigned char clr)
{
if(var + v < 0)
return;
/* guard */
/* if(order==-1) /\* y-axis *\/ */
/* { */
/* if(var + v < 0) */
/* return; */
/* } */
/* else /\* x-axis *\/ */
/* { */
/* } */
int r = 2;
r = order_check(var+v, c, order);
/* if(order==-1) */
/* r = check_pixel(c, var); */
/* else */
/* r = check_pixel(var, c); */
/* if(r==2) return; */
/* find most far away empty pixel */
while(r!=0 && v > 0)
{
--v;
v-=1;
if(v<0) v=0; /* just in case */
r=order_check(var+v, c, order);
/* r=check_pixel(x, y); */
}
do
{
if(order==-1)
paint_pixel(c, var+v, clr);
else
paint_pixel(var+v, c, clr);
--v;
}
while(v>=0);
}
void process(int x, int y)
{
unsigned char clr = 0;
switch(check_pixel(x, y))
{
case 0: /* empty/black/background pixel */
case 2: /* invalid coordinates */
return;
case 1: /* colored pixel */
clr = image[y][x][0];
break;
default:
fprintf(stderr, "process(): this case should never be met.\n");
return;
}
id_and_proceed(y, x, velocity[0] * (-1), -1, clr); /* north */
id_and_proceed(x, y, velocity[1], 1, clr); /* east */
id_and_proceed(y, x, velocity[2], -1, clr); /* south */
id_and_proceed(x, y, velocity[3] * (-1), 1, clr); /* west */
/* int y_north = y - velocity[0]; */
/* int x_east = x + velocity[1]; */
/* int y_south = y + velocity[2]; */
/* int x_west = x - velocity[3]; */
return;
}
/* returns 0 if the given pixel is black (0)
returns 1 if it is coloured
returns 2 if the coordinates are invalid */
int check_pixel(int x, int y)
{
/* printf("Checking (%u|%u)\n", x, y); */
if(x>=WIDTH || y>=HEIGHT)
{
fprintf(stderr, "coords (%d|%d) exceed image size %d×%d.\n", x, y, WIDTH, HEIGHT);
return 2;
}
/* as the image will be grayscaled, it works to check only one layer */
/* this implies the background colour is 0 */
if(image[y][x][0]!=0)
{
return 1;
}
return 0;
}
int paint_pixel(int x, int y, unsigned char clr)
{
/* printf("paint_pixel called\n"); */
if(check_pixel(x, y)) return 1;
image[y][x][0]=clr;
image[y][x][1]=clr;
image[y][x][2]=clr;
return 0;
}