No Description

main.c 9.1KB

    #include <png.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include <string.h> #include <stdbool.h> #include <unistd.h> #include <stdint.h> //#include "qdbmp.h" #include "engine.h" typedef struct { uint8_t red; uint8_t green; uint8_t blue; } pixel_t; void reverse(char s[]) { int i, j; char c; for (i = 0, j = strlen(s)-1; i<j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } /* itoa: convert n to characters in s */ void itoa(int n, char s[]) { int i, sign; if ((sign = n) < 0) /* record sign */ n = -n; /* make n positive */ i = 0; do { /* generate digits in reverse order */ s[i++] = n % 10 + '0'; /* get next digit */ } while ((n /= 10) > 0); /* delete it */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); } //END SO //Data that needs to be saved and loaded typedef struct config { int nStars; int imgW, imgH; int savePeriod; int iteration; char saveFile[255]; } config_t; /* DEFAULT CONFIGURATION OPTIONS */ int nStars = 100; int w = 1920; int h = 1080; int spawnSize = 500; double maxComponentV = 10; long m = 500; int a = 100; int iteration = 0; char s[255]; //save filename char l[255]; //load filename /* END DEFAULT CONFIGURATION OPTIONS */ //Allocate these arrays later! RigidMass_t *stars; int *starsAtPixel; void generateStars() { int maxRadius = spawnSize / 2; int randAddonX = w/2; int randAddonY = h/2; RigidMass_t new; new.mass = m; new.dvx = 0; new.dvy = 0; new.tick_time = 0.05; for(int i = 0; i < nStars; i++) { //Generate radius between 0 and maxRadius double radius = (double)rand() / RAND_MAX * maxRadius; //Generate random x - must be less than r //Otherwise we end up with sqrt(<0) which makes a big mess double x = ((double)rand() / RAND_MAX * radius * 2) - radius; //Use x to make y which satisfies x and r double yRange = sqrt(radius * radius - x * x); double y = (double)rand() / RAND_MAX * 2 * yRange - yRange; new.x = x + randAddonX; new.y = y + randAddonY; new.vx = y / maxRadius * maxComponentV; //Scale velocities new.vy = -x / maxRadius * maxComponentV; stars[i] = new; } } void hsl_to_rgb(int h, double s, double l, char *rOut, char *gOut, char *bOut) { if(h == 360) h = 0; if(s > 1) s = 1; if(l > 1) l = 1; double c = (1 - abs(2 * l - 1)) * s; double x = c * (1 - fabs(fmod(((double)h)/60, 2) - 1)); double m = l - c / 2; double r, g, b; int q = h / 60; switch(q) { case(0): r = c; g = x; b = 0; break; case(1): r = x; g = c; b = 0; break; case(2): r = 0; g = c; b = x; break; case(3): r = 0; g = x; b = c; break; case(4): r = x; g = 0; b = c; break; case(5): r = c; g = 0; b = x; } *rOut = 255 * (r + m); *gOut = 255 * (g + m); *bOut = 255 * (b + m); } pixel_t *out; void addToImage() { memset(out, 0, sizeof(pixel_t) * w * h); memset(starsAtPixel, 0, sizeof(int) * w * h); #define IMAGE_INC_AMOUNT 50 for(int a = 0; a < nStars; a++) { int starX = stars[a].x; int starY = stars[a].y; if(starX > 0 && starX < w && starY > 0 && starY < h) { starsAtPixel[starX * h + starY]++; } } for(int a = 0; a < nStars; a++) { //pixel colour depends on how many stars are at that location int starX = stars[a].x; int starY = stars[a].y; if(starX > 0 && starX < w && starY > 0 && starY < h) { int nStarsAtLoc = starsAtPixel[starX * h + starY] * 10; //if(nStarsAtLoc > 360) nStarsAtLoc = 360; pixel_t p = {.red = 0, .green = 0, .blue = 0}; if(nStarsAtLoc > 50) nStarsAtLoc = 50; p.red = nStarsAtLoc * 5; p.green = p.red; p.blue = p.red; //hsl_to_rgb(nStarsAtLoc, 1, nStarsAtLoc / (double)100, &curR, &curG, &curB); out[starX + starY * w] = p; } } } void saveImage(double frame) { char filename[50]; char buffer[46]; strcpy(filename, "img/"); itoa(frame, buffer); strcat(filename, buffer); strcat(filename, ".png"); FILE *fp; fp = fopen(filename, "wb"); if(!fp) { printf("ERROR: Could not save image!\r\n"); return; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_ptr = png_create_info_struct(png_ptr); png_set_IHDR (png_ptr, info_ptr, w, //image width h, //height 8, //bit depth PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_byte **row_pointers = png_malloc (png_ptr, h * sizeof (png_byte *)); for(int y = 0; y < h; y++) { png_byte *row = png_malloc (png_ptr, sizeof(uint8_t) * w * 3); row_pointers[y] = row; for(int x = 0; x < w; x++) { pixel_t pixel = out[x + w*y]; *row++ = pixel.red; *row++ = pixel.green; *row++ = pixel.blue; } } png_init_io (png_ptr, fp); png_set_rows (png_ptr, info_ptr, row_pointers); png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); fclose(fp); //Free memory for(int y = 0; y < h; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); } void saveState(int it) { FILE *fp; char filename[300]; //lots of room char buffer[15]; strcpy(filename, "saves/"); strcat(filename, s); itoa(it, buffer); strcat(filename, buffer); strcat(filename, "-ID.sgs"); fp = fopen(filename, "wb"); //first, write the config parameters config_t conf; conf.nStars = nStars; conf.imgW = w; conf.imgH = h; conf.savePeriod = a; conf.iteration = it; strcpy(conf.saveFile, s); fwrite(&conf, sizeof(conf), 1, fp); //then, write all the stars fwrite(stars, sizeof(RigidMass_t), nStars, fp); //close the file fclose(fp); } void prnHelp(char *name) { //TODO: iterations per frame //ticktime? printf("Usage: %s [OPTION]\r\n", name); printf("Available options:\r\n"); printf("N\t New simulation\r\n"); printf("n\t Number of stars\r\n"); printf("w WDTH\t Image width\r\n"); printf("h HGHT\t Image height\r\n"); printf("p SIZE\t Spawn size - Where new stars are put\r\n"); printf("v VEL\t Maximum component velocity of new stars\r\n"); printf("m MASS\t Mass of stars\r\n"); printf("s FILE\t Filename for autosaves\r\n"); printf("a PER\t How often to autosave, in iterations\r\n"); printf("L FILE\t Load previous simulation\r\n"); exit(0); } int main(int argc, char **argv) { printf("\t\tStephen's Gravitational Engine\r\n"); printf("\t\t\twww.scd31.com\r\n"); //Process commandline arguments bool success = false; bool new = false; bool load = false; strcpy(s, "sim"); //default autosave filename char c; while((c = getopt(argc, argv, "Nn:w:h:p:v:m:a:L:s:")) != -1) { success = true; switch(c) { case 'N': new = true; break; case 'n': nStars = atoi(optarg); break; case 'w': w = atoi(optarg); break; case 'h': h = atoi(optarg); break; case 'p': spawnSize = atoi(optarg); break; case 'v': maxComponentV = atof(optarg); break; case 'm': m = atol(optarg); break; case 'a': a = atoi(optarg); break; case 's': if(strlen(optarg) >= 255) { printf("ERROR: Save filename too long.\r\n"); } else strcpy(s, optarg); break; case 'L': load = true; if(strlen(optarg) >= 255) { printf("ERROR: Load filename too long.\r\n"); } else strcpy(l, optarg); break; default: prnHelp(argv[0]); } } if(!success) { prnHelp(argv[0]); } //Command validation if(!new && !load) { printf("ERROR: Either start a new simulation or load an old one.\r\n"); exit(1); } if(new && load) { printf("ERROR: Cannot start a new simulation and load an old one at the same time!\r\n"); exit(1); } if(new) { printf("Starting a new simulation with the following parameters:\r\n"); printf("\t N = %d\r\n", nStars); printf("\t W = %d, H = %d\r\n", w, h); printf("\t spawn = %d\r\n", spawnSize); printf("\t vComponentMax = %f\r\n", maxComponentV); printf("\t m = %ldE8 kg\r\n", m); printf("\t Autosave: %s-ID.sgs every %d iterations\r\n", s, a); //allocate arrays stars = malloc(sizeof(RigidMass_t) * nStars); starsAtPixel = malloc(sizeof(int) * w * h); srand(time(NULL)); generateStars(); } else if(load) //technically redundant. can never be too sure { printf("Continuing %s...\r\n", l); FILE *fp; fp = fopen(l, "r"); //first, read the config parameters config_t conf; fread(&conf, sizeof(conf), 1, fp); nStars = conf.nStars; w = conf.imgW; h = conf.imgH; a = conf.savePeriod; iteration = conf.iteration; strcpy(s, conf.saveFile); //second, read the stars stars = malloc(sizeof(RigidMass_t) * nStars); fread(stars, sizeof(RigidMass_t), nStars, fp); starsAtPixel = malloc(sizeof(int) * w * h); //close the file fclose(fp); printf("%d stars loaded.\r\n", nStars); printf("Continuing from i=%d\r\n", iteration); } //malloc some space for our output image out = malloc(w * h * sizeof(pixel_t)); //Runs until CTRL+C //TODO: CTRL+C should force autosave while(1) { //iterate(); printf("Started gentree\n"); barnesIterate(stars, nStars, w, h); printf("Gentree finished\n"); //exit(1); addToImage(); saveImage(iteration); if(iteration % a == 0) { saveState(iteration); } iteration++; } return 0; }