No Description

main.c 8.0KB

    #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include <string.h> #include <stdbool.h> #include <unistd.h> #include "qdbmp.h" #include "engine.h" 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 randAddonX = w/2 - spawnSize/2; int randAddonY = h/2 - spawnSize/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++) { new.x = rand() % spawnSize + randAddonX; new.y = rand() % spawnSize + randAddonY; double dx = new.x - w / 2; double dy = new.y - h / 2; if(abs(dx) <= abs(dy)) { new.vx = (double)rand()/(double)(RAND_MAX/maxComponentV); new.vy = -new.vx * dx / dy; } else { new.vy = (double)rand()/(double)(RAND_MAX/maxComponentV); new.vx = -new.vy * dy / dx; } if(dx > dy) { new.vx *= -1; new.vy *= -1; } 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); } BMP *out; void addToImage() { 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; char curR = 0, curG = 0, curB = 0; if(nStarsAtLoc > 50) nStarsAtLoc = 50; curR = nStarsAtLoc * 5; curG = curR; curB = curR; //hsl_to_rgb(nStarsAtLoc, 1, nStarsAtLoc / (double)100, &curR, &curG, &curB); BMP_SetPixelRGB(out, starX, starY, curR, curG, curB); } } } void saveImage(double frame) { char filename[50]; char buffer[46]; strcpy(filename, "img/"); itoa(frame, buffer); strcat(filename, buffer); strcat(filename, ".bmp"); BMP_WriteFile(out, filename); BMP_Free(out); out = BMP_Create(w, h, 24); } 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); } out = BMP_Create(w, h, 24); //Runs until CTRL+C //TODO: CTRL+C should force autosave bool justStarted = true; while(1) { //iterate(); printf("Started gentree\n"); barnesIterate(stars, nStars, w, h); printf("Gentree finished\n"); //exit(1); addToImage(); //gives the next frame some iterations to build up //without justStarted, the loaded iteration is rerendered, but only from //a single iteration, which stands out quite a bit. if(justStarted) { justStarted = false; } else { if(iteration % 10 == 0) { saveImage(iteration / 10); } if(iteration % a == 0) { saveState(iteration); } } iteration++; } return 0; }