Migration

This commit is contained in:
COW_ILLUMINATI 2024-04-28 11:07:03 -04:00
commit e828632e0c
19 changed files with 201001 additions and 0 deletions

2
.gitignore vendored Normal file

@ -0,0 +1,2 @@
*.out
Post_Processing/*.blend1

3
Gal_data/Sim_Settings Normal file

@ -0,0 +1,3 @@
0.5
75
0

4
Gal_data/UI_Settings Normal file

@ -0,0 +1,4 @@
1920
1080
24
0

100012
Gal_data/Universe Normal file

File diff suppressed because it is too large Load Diff

4
Makefile Normal file

@ -0,0 +1,4 @@
build_program:
g++ src/Simulator.cpp -lSDL2 -fopenmp -o simulator.out
g++ src/Creator.cpp -lSDL2 -fopenmp -o creator.out

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

28
README.md Normal file

@ -0,0 +1,28 @@
# GalaxySimulator
A very basic N-Body simulator for visualizing galaxy collisions.
This simulator was made for my astrophysics project. Do not use it -- it sucks.
It is entirely CPU-based since I don't have a graphics card to test it on. The code is threaded.
Run ``./creator.out`` to configure the simulator.
You will need to use the "Prepare Universe" option to add custom galaxies to the simulation, it is not done automatically.
Run ``./simulator.out`` to simulate the system. If no window is created and you are using Nvidia hardware, ``chmod +x`` the program and try running it through Proton Experimental.
Build with ``make``, do not install the program. It is designed to be portable.
Controls:
Arrow keys to rotate
Page up/down to zoom
Space to play/pause
Enter to change focus
For best results:
- Use low timesteps -- this will allow for the simulator to take more samples of every interaction and improve paths. [Linear]
- Use high budgets -- this will improve feild estimation, giving a better approximation of the shape of the system. [Quadratic]
- Use a high radius -- this will improve floating-point precision. Don't go *too* high though! [Linear]
- Make the galaxy's mass no more than 25% of the black hole -- the initial velocities used in galaxy creation are calculated from elliptic curve approximation and are not designed for exotic ratios. This could be changed in the code for your specific ratios. [Free]
You should expect to have to timelapse your simulations.

Binary file not shown.

BIN
WindowsBinaries/Creator_FR.exe Executable file

Binary file not shown.

@ -0,0 +1,3 @@
0.01
150
0

@ -0,0 +1,4 @@
1920
1080
24
0

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

BIN
WindowsBinaries/SDL2.dll Normal file

Binary file not shown.

Binary file not shown.

379
src/Creator.cpp Normal file

@ -0,0 +1,379 @@
// some good params for the collision:
// G1: p[0,0,0], v[0,0,0]
// G2: p[250,0,250], v[0,-0.5,0]
// In general, it's good to have the velocity be perpendicular to the positions
#include <omp.h>
#include <iostream>
#include <stdlib.h>
#include <ctime>
#include <random>
#include <list>
#include <vector>
#include <algorithm>
#include <string>
#include <SDL2/SDL.h>
#include <fstream>
#include <string>
using namespace std;
// Quick input lib
string ask(string prompt){
string answer;
cout << prompt << endl;
cin >> answer;
return answer;
}
int askInt(string prompt){
int answer;
cout << prompt << endl;
cin >> answer;
return answer;
}
float askFloat(string prompt){
float answer;
cout << prompt << endl;
cin >> answer;
return answer;
}
// Big-ass Vector3 library (naming is not confusing!!! ghaaa)
// Fairly self-explanatory
struct Vector3
{
float x, y, z;
Vector3(){x=0;y=0;z=0;}
Vector3(float sx, float sy, float sz) {
x=sx; y=sy; z=sz;
}
Vector3 operator+(Vector3 target){
return Vector3(x+target.x,y+target.y,z+target.z);
}
Vector3 operator-(Vector3 target){
return Vector3(x-target.x,y-target.y,z-target.z);
}
Vector3 operator*(float target){
return Vector3(x*target,y*target,z*target);
}
Vector3 operator/(float target){
return Vector3(x/target,y/target,z/target);
}
bool operator==(Vector3 target){
return ((x == target.x) && (y == target.y) && (z == target.z));
}
bool operator!=(Vector3 target){
return !((x == target.x) && (y == target.y) && (z == target.z));
}
std::string to_String(){
return "( " + std::to_string(x) + " ; " + std::to_string(y) + " ; " + std::to_string(z) + " )";
}
float Dot (Vector3 target) {
return target.x*x + target.y*y + target.z*z;
}
Vector3 Cross (Vector3 target) {
Vector3 tmp = Vector3(0,0,0);
tmp.x = y * target.z - z * target.y;
tmp.y = z * target.x - x * target.z;
tmp.z = x * target.y - y * target.x;
return tmp;
}
float SqrMagnitude () {
return Vector3(x,y,z).Dot(Vector3(x,y,z));
}
Vector3 Normalized () {
return Vector3(x,y,z) * (1.0/sqrt(Vector3(x,y,z).SqrMagnitude()));
}
Vector3 Rotate(Vector3 eulerAngles){
float xx, yy, zz = 0;
Vector3 tmpVector3 = Vector3 (x,y,z);
xx = tmpVector3.x;
yy = tmpVector3.y * cos(eulerAngles.x) - tmpVector3.z * sin(eulerAngles.x);
zz = tmpVector3.y * sin(eulerAngles.x) + tmpVector3.z * cos(eulerAngles.x);
tmpVector3.x=xx; tmpVector3.y = yy; tmpVector3.z=zz;
xx = tmpVector3.x * cos(eulerAngles.y) + tmpVector3.z * sin(eulerAngles.y);
yy = tmpVector3.y;
zz = -tmpVector3.x * sin(eulerAngles.y) + tmpVector3.z * cos(eulerAngles.y);
tmpVector3.x=xx; tmpVector3.y = yy; tmpVector3.z=zz;
xx = tmpVector3.x * cos(eulerAngles.z) - tmpVector3.y * sin(eulerAngles.z);
yy = tmpVector3.x * sin(eulerAngles.z) + tmpVector3.y * cos(eulerAngles.z);
zz = tmpVector3.z;
return Vector3 (xx, yy, zz);
}
};
int main () {
// Preps the reader
ofstream fileEditor;
char choice;
cout << "---------- Profile Editor ----------" << endl;
cout << "Galaxy Creation................. [a]" << endl;
cout << "Simulator Settings.............. [b]" << endl;
cout << "UI Settings..................... [c]" << endl;
cout << "Prepare Universe................ [d]" << endl;
cout << endl << endl<< endl<< endl<< endl;
cout << "Simulator loads Gal_data/Universe" << endl;
cin >> choice;
if (choice == 'a'){
//Galaxy creator
cout << "------------- Galaxy Creation ----------" << endl;
fileEditor.open ("Gal_data/Galaxy_" + ask ("Galaxy name? "));
int seed = askInt("Seed (0 for random)? [ 0] ");
if ( seed == 0 ) {seed = time(NULL);}
srand (seed);
// 1 black hole per galaxy
int sigStars = 1;
int massBH = askInt("Black Hole Mass? [ 100 ] ");
float massStars = askFloat("Other Mass? [10] ");
int otherStars = askInt("Star Count? [10000] ");
int radius = askInt("Radius? [ 100 ] ");
float zDistribution = askFloat("Z Distribution (%)? [ 0.1 ] ");
int colorCount = askInt("Color Count? [ 8 ] ");
/*
starCount
sigStars
{
x
y
z
vx
vy
vz
mass
colorx
colory
colorz
}
*/
fileEditor << sigStars + otherStars<< endl;
fileEditor << sigStars<< endl;
fileEditor << 0<< endl;
fileEditor << 0<< endl;
fileEditor << 0<< endl;
fileEditor << 0<< endl;
fileEditor << 0<< endl;
fileEditor << 0<< endl;
fileEditor << massBH<< endl;
fileEditor << 255<< endl;
fileEditor << 255<< endl;
fileEditor << 255<< endl;
Vector3 lastColor = Vector3(random()%64+128,random()%128+128,random()%128+128);
for (int i = 0 ; i < otherStars ; i++) {
printf("Generating body pass 1 %10d/%d\r",i+1, otherStars);
Vector3 posTmp = Vector3(radius*10,0,0);
// Makes sure it's in a circle!
while (posTmp.SqrMagnitude()>radius*radius/4){
posTmp = Vector3(
rand()%10000/10000.0 * radius - radius/2,
rand()%10000/10000.0 * radius - radius/2,
(rand()%10000/10000.0 * radius - radius/2) * zDistribution
);
}
fileEditor << posTmp.x<< endl;
fileEditor << posTmp.y<< endl;
fileEditor << posTmp.z<< endl;
// Rotation
Vector3 velTmp = posTmp.Cross(Vector3(0,0,1)).Normalized() *
sqrt(
(
// Black hole
massBH
// Other stars
+ massStars * (sqrt(posTmp.SqrMagnitude()) / (radius / 2))*(sqrt(posTmp.SqrMagnitude()) / (radius / 2))
)
/ sqrt(posTmp.SqrMagnitude())
);
fileEditor << velTmp.x<< endl;
fileEditor << velTmp.y<< endl;
fileEditor << velTmp.z<< endl;
fileEditor << massStars << endl;
if ((int)(i % ((int)(otherStars/colorCount))) == 0) {
lastColor = Vector3(random()%64+128,random()%128+128,random()%128+128);
}
fileEditor << lastColor.x<< endl;
fileEditor << lastColor.y<< endl;
fileEditor << lastColor.z<< endl;
}
} else if (choice == 'b'){
// Simulator settings
cout << "-------- Simulator Settings --------" << endl;
cout << "(Universes will require recreation! )" << endl;
fileEditor.open ("Gal_data/Sim_Settings");
fileEditor << ask("Timestep? [0.01] ") << endl;
fileEditor << ask("Star budget? [150] ") << endl;
fileEditor << ask("Mode? [0 = full; 1 = black holes only] ") << endl;
} else if (choice == 'c'){
// UI settings
cout << "------------- UI settings ----------" << endl;
fileEditor.open ("Gal_data/UI_Settings");
fileEditor << ask("Screen size x? [1920] ") << endl;
fileEditor << ask("Screen size y? [1080] ") << endl;
fileEditor << ask("Target framerate? [ 24 ] ") << endl;
//fileEditor << ask("Render simulation?[ 0-1] ") << endl;
} else if (choice == 'd') {
cout << "--------- Prepare Universe ---------" << endl;
fileEditor.open ("Gal_data/Universe");
int galCount = askInt("Galaxy amount? ");
ifstream galaxies[galCount];
int sigStars[galCount];
int starCount[galCount];
Vector3 offset[galCount];
Vector3 angle[galCount];
Vector3 velocity[galCount];
char comma;
for (int i = 0 ; i < galCount ; i ++){
galaxies[i].open(("Gal_data/Galaxy_" + ask ("Galaxy a name? ")));
cout << "Position offset [x,y,z]" << endl;
cin >> offset[i].x >> comma >> offset[i].y >> comma >> offset[i].z;
cout << "Angle (radians) [x,y,z]" << endl;
cin >> angle[i].x >> comma >> angle[i].y >> comma >> angle[i].z;
cout << "Velocity [x,y,z]" << endl;
cin >> velocity[i].x >> comma >> velocity[i].y >> comma >> velocity[i].z;
}
/*
starCount + starCount
sigStars + sigStars
2 x {
x
y
z
vx
vy
vz
mass
colorx
colory
colorz
}
*/
// StarCount
int tmpStarCount = 0;
for (int i=0;i<galCount;i++){
galaxies[i] >> starCount[i];
tmpStarCount += starCount[i];
}
fileEditor << tmpStarCount << endl;
// SigStars
tmpStarCount=0;
for (int i=0;i<galCount;i++){
galaxies[i] >> sigStars[i];
tmpStarCount += sigStars[i];
}
fileEditor << tmpStarCount << endl;
// Sequential to preserve contiguity
float tmp=0;
Vector3 vtmp;
// Sigstars
for (int i = 0 ; i < galCount; i ++){
for (int j = 0 ; j < sigStars[i]; j ++){
// Pos
galaxies[i]>>vtmp.x;
galaxies[i]>>vtmp.y;
galaxies[i]>>vtmp.z;
vtmp = vtmp.Rotate(angle[i]) + offset[i];
fileEditor<<vtmp.x<< endl;
fileEditor<<vtmp.y<< endl;
fileEditor<<vtmp.z<< endl;
// Vel
galaxies[i]>>vtmp.x;
galaxies[i]>>vtmp.y;
galaxies[i]>>vtmp.z;
vtmp = vtmp.Rotate(angle[i]) + velocity[i];
fileEditor<<vtmp.x<< endl;
fileEditor<<vtmp.y<< endl;
fileEditor<<vtmp.z<< endl;
// Mass
galaxies[i]>>tmp;
fileEditor<<tmp<< endl;
// Color
galaxies[i]>>vtmp.x;
galaxies[i]>>vtmp.y;
galaxies[i]>>vtmp.z;
fileEditor<<vtmp.x<< endl;
fileEditor<<vtmp.y<< endl;
fileEditor<<vtmp.z<< endl;
}
}
// other stars:
for (int i = 0 ; i < galCount; i ++){
for (int j = 0 ; j < starCount[i] - sigStars[i]; j ++){
// Pos
galaxies[i]>>vtmp.x;
galaxies[i]>>vtmp.y;
galaxies[i]>>vtmp.z;
vtmp = vtmp.Rotate(angle[i]) + offset[i];
fileEditor<<vtmp.x<< endl;
fileEditor<<vtmp.y<< endl;
fileEditor<<vtmp.z<< endl;
// Vel
galaxies[i]>>vtmp.x;
galaxies[i]>>vtmp.y;
galaxies[i]>>vtmp.z;
vtmp = vtmp.Rotate(angle[i]) + velocity[i];
fileEditor<<vtmp.x<< endl;
fileEditor<<vtmp.y<< endl;
fileEditor<<vtmp.z<< endl;
// Mass
galaxies[i]>>tmp;
fileEditor<<tmp<< endl;
// Color
galaxies[i]>>vtmp.x;
galaxies[i]>>vtmp.y;
galaxies[i]>>vtmp.z;
fileEditor<<vtmp.x<< endl;
fileEditor<<vtmp.y<< endl;
fileEditor<<vtmp.z<< endl;
}
}
}
fileEditor.close();
return 0;
}

550
src/Simulator.cpp Normal file

@ -0,0 +1,550 @@
#include <omp.h>
#include <iostream>
#include <stdlib.h>
#include <ctime>
#include <random>
#include <list>
#include <vector>
#include <algorithm>
#include <string>
#include <SDL2/SDL.h>
#include <fstream>
#include <string>
class Vector3;
// Starts the clock
std::clock_t startTime = std::clock();
// Defines a pointer to the screen size (needs to be accessible everywhere, but the Vector3 class is still undefined!)
Vector3 *screenSize;
// Creates the window & renderer, will be assigned later
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
// Stolen from Stackoverflow, can't be bothered to make it myself... :P
void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius)
{
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while (x >= y)
{
SDL_RenderDrawPoint(renderer, centreX + x, centreY - y);
SDL_RenderDrawPoint(renderer, centreX + x, centreY + y);
SDL_RenderDrawPoint(renderer, centreX - x, centreY - y);
SDL_RenderDrawPoint(renderer, centreX - x, centreY + y);
SDL_RenderDrawPoint(renderer, centreX + y, centreY - x);
SDL_RenderDrawPoint(renderer, centreX + y, centreY + x);
SDL_RenderDrawPoint(renderer, centreX - y, centreY - x);
SDL_RenderDrawPoint(renderer, centreX - y, centreY + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
// Oki, after this it's all code from me!!
// Big-ass Vector3 library
// Fairly self-explanatory
struct Vector3
{
float x, y, z;
Vector3(){x=0;y=0;z=0;}
Vector3(float sx, float sy, float sz) {
x=sx; y=sy; z=sz;
}
Vector3 operator+(Vector3 target){
return Vector3(x+target.x,y+target.y,z+target.z);
}
Vector3 operator-(Vector3 target){
return Vector3(x-target.x,y-target.y,z-target.z);
}
Vector3 operator*(float target){
return Vector3(x*target,y*target,z*target);
}
Vector3 operator/(float target){
return Vector3(x/target,y/target,z/target);
}
bool operator==(Vector3 target){
return ((x == target.x) && (y == target.y) && (z == target.z));
}
bool operator!=(Vector3 target){
return !((x == target.x) && (y == target.y) && (z == target.z));
}
std::string to_String(){
return "( " + std::to_string(x) + " ; " + std::to_string(y) + " ; " + std::to_string(z) + " )";
}
float Dot (Vector3 target) {
return target.x*x + target.y*y + target.z*z;
}
Vector3 Cross (Vector3 target) {
Vector3 tmp = Vector3(0,0,0);
tmp.x = y * target.z - z * target.y;
tmp.y = z * target.x - x * target.z;
tmp.z = x * target.y - y * target.x;
return tmp;
}
float SqrMagnitude () {
return Vector3(x,y,z).Dot(Vector3(x,y,z));
}
Vector3 Normalized () {
return Vector3(x,y,z) * (1.0/sqrt(Vector3(x,y,z).SqrMagnitude()));
}
Vector3 Rotate(Vector3 eulerAngles){ // Ghaaaaa
float xx, yy, zz = 0;
Vector3 tmpVector3 = Vector3 (x,y,z);
xx = tmpVector3.x;
yy = tmpVector3.y * cos(eulerAngles.x) - tmpVector3.z * sin(eulerAngles.x);
zz = tmpVector3.y * sin(eulerAngles.x) + tmpVector3.z * cos(eulerAngles.x);
tmpVector3.x=xx; tmpVector3.y = yy; tmpVector3.z=zz;
xx = tmpVector3.x * cos(eulerAngles.y) + tmpVector3.z * sin(eulerAngles.y);
yy = tmpVector3.y;
zz = -tmpVector3.x * sin(eulerAngles.y) + tmpVector3.z * cos(eulerAngles.y);
tmpVector3.x=xx; tmpVector3.y = yy; tmpVector3.z=zz;
xx = tmpVector3.x * cos(eulerAngles.z) - tmpVector3.y * sin(eulerAngles.z);
yy = tmpVector3.x * sin(eulerAngles.z) + tmpVector3.y * cos(eulerAngles.z);
zz = tmpVector3.z;
return Vector3 (xx, yy, zz);
}
};
// Library to map 3D space to screen space ("Camera")
class Rasterizer {
private:
// Two screen axis for othographic projection (perspective is overkill)
Vector3 projectionX = Vector3 (1, 0, 0);
Vector3 projectionY = Vector3 (0, 1, 0);
// Keeps track of the last color since switching is expensive AF
Vector3 lastColor = Vector3 (255, 255, 255);
// Rotation of the 'camera'
Vector3 eulerAngles = Vector3 (-1, 0, -0.55f);
// We use a function to check the active color (more readable this way)
void ChangeColor(Vector3 newCol){
if (newCol != lastColor){
SDL_SetRenderDrawColor(renderer,newCol.x,newCol.y,newCol.z,255);
lastColor = newCol;
}
}
// This function takes 3D coordinates and maps them to the screen.
Vector3 Project(Vector3 position, Vector3 projectionAxisX, Vector3 projectionAxisY){
return ToScreenCoords(Vector3( // Orthographic rendering, could be changed if needed
position.Dot(projectionAxisX),
position.Dot(projectionAxisY),
0)
);
}
// Converts [-1; 1] --> [Screenspace]
// This makes it possible to resize the screen without wanting to commit suicide
Vector3 ToScreenCoords(Vector3 fromRange){
return Vector3((fromRange.x + 1) * screenSize->x / 2,(fromRange.y + 1) * screenSize->y / 2, 0);
}
public:
// Position of the camera
Vector3 worldPosition = Vector3(0,0,0);
// Low-level method for placing single 3D pixels on a 2D screen
void PutPoint(Vector3 position, Vector3 color){
position = position - worldPosition;
// Projects them onto 2d
position = Rasterizer::Project(position, projectionX.Rotate(eulerAngles), projectionY.Rotate(eulerAngles));
//Color
ChangeColor(color);
// Adds itself to the buffer
SDL_RenderDrawPoint(renderer, position.x, position.y);
}
// Same, but for lines
void PutLine(Vector3 start, Vector3 end, Vector3 color){
start = start - worldPosition;
end = end - worldPosition;
// Projects them onto 2d
start = Rasterizer::Project(start, projectionX.Rotate(eulerAngles), projectionY.Rotate(eulerAngles));
end = Rasterizer::Project(end, projectionX.Rotate(eulerAngles), projectionY.Rotate(eulerAngles));
// Sets the color
ChangeColor(color);
// Adds itself to the buffer
SDL_RenderDrawLine(renderer, start.x, start.y, end.x, end.y);
}
// Same, with circles (Note:: they will always face the camera!)
void PutCircle(Vector3 center, float radius, Vector3 color){
center = center - worldPosition;
// Projects them onto 2d
center = Rasterizer::Project(center, projectionX.Rotate(eulerAngles), projectionY.Rotate(eulerAngles));
// Sets the color
ChangeColor(color);
// Adds itself to the buffer
DrawCircle(renderer, center.x, center.y, radius);
}
// Rotates the camera
void Rotate(Vector3 angle){
eulerAngles = eulerAngles + angle;
}
// Zooming
void Zoom(float scale) {
projectionX = projectionX * scale;
projectionY = projectionY * scale;
}
// Updates the aspect ratio
void SetRatio(Vector3 scale){
scale=scale.Normalized();
projectionX = projectionX / scale.x;
projectionY = projectionY / scale.y;
}
};
// Stars!!!
struct Star
{
Vector3 position = Vector3 (0,0,0);
Vector3 velocity = Vector3 (0,0,0);
Vector3 acceleration = Vector3 (0,0,0);
Vector3 color = Vector3(0,0,0);
float mass = 1;
// Default constructor
Star() {}
// Called ever subframe
void tick(float dt) {
// Calc intégral lets gooo
position = position + velocity * dt + acceleration * dt * dt * 0.5;
velocity = velocity + acceleration * dt;
acceleration = Vector3 (0,0,0);
}
// Calculates the field at a point in space
static Vector3 Solve(Vector3 location, Star b, float dt){
// avoids divisions by 0!
if (location != b.position) {
Vector3 r = b.position-location;
// \/-- distance cannot be smaller than the timestep!
float inv_n_r = 1.0/sqrt((r.SqrMagnitude() + dt));
return r * inv_n_r * inv_n_r * inv_n_r * b.mass;
}
// If the position is the same as the object, the field is 0 at that point
return Vector3(0,0,0);
}
};
// Rendering
void SaveWindowToBMP(SDL_Window* window, SDL_Renderer* renderer, const std::string& filename) {
SDL_Surface* surface = SDL_GetWindowSurface(window);
if (!surface) {
printf("Unable to create surface: %s\n", SDL_GetError());
return;
}
SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_ARGB8888, surface->pixels, surface->pitch);
if (SDL_SaveBMP(surface, filename.c_str()) != 0) {
printf("Unable to save bitmap: %s\n", SDL_GetError());
return;
}
SDL_FreeSurface(surface);
}
int main() {
// Sets the screenSize pointer to an object in memory
screenSize = new Vector3(0,0,0);
// Loading stuff
std::cout<< "Opening files.." <<std::endl;
std::ifstream universe;
universe.open("Gal_data/Universe");
std::ifstream uiSettings;
uiSettings.open("Gal_data/UI_Settings");
std::ifstream simSettings;
simSettings.open("Gal_data/Sim_Settings");
// UI
std::cout<< "UI settings" <<std::endl;
// Grabs the screen size
uiSettings >> screenSize->x;
uiSettings >> screenSize->y;
// Grabs the target framerate
int tfps;
uiSettings >> tfps;
//int saveFrames;
//uiSettings >> saveFrames;
uiSettings.close();
// Sim
std::cout<< "Simulator settings" <<std::endl;
float timestep;
int budget;
int mode;
// Gets the timestep
simSettings >> timestep;
simSettings >> budget;
// Gets the 'mode', either 0 = full simulation, -1 = significant only, anything else = limited simulation.
simSettings >> mode;
simSettings.close();
// Stars
std::cout<< "Stars.." <<std::endl;
int starCount;
// Gets the TOTAL amount of objects
universe >> starCount;
int sigStars;
// Gets the significant stars
universe >> sigStars;
// Quick log
std::cout<< "Found stars: " << starCount << std::endl;
// Creates the vector (I hear these are better than arrays, might change it if I get time to do benchmarks)
std::vector <Star> stars;
stars.reserve(starCount);
// Itterator for array access
int i = 0; // THIS STUPID INITIALIZATION CAUSED 12 FUCKING HOURS OF DEBUGGING OVER DISCORD GHAA KILL ME
while (true)
{
// Logs the currently parsed object
std::cout<< "Star: " << i << "\r";
// If we're done, we can exit
if( universe.eof() ) break;
// Adds cell to the vector
stars.push_back(Star());
// Positions
universe >> stars[i].position.x;
universe >> stars[i].position.y;
universe >> stars[i].position.z;
// Velocities
universe >> stars[i].velocity.x;
universe >> stars[i].velocity.y;
universe >> stars[i].velocity.z;
// Mass
universe >> stars[i].mass;
if (i >= sigStars){
// Ignores black holes
// Ex.: If a galaxy has a mass of 200, and 10 stars are parsed, it'll act like those stars had a mass of 20 (x10)
stars[i].mass=stars[i].mass/budget;
}
// Color
universe >> stars[i].color.x;
universe >> stars[i].color.y;
universe >> stars[i].color.z;
// At the end, since we want to start at 0
i ++;
}
// Sets the mode
// Acts as an override to starCount, where it stops the parser at a given point during the process
// This allows the planning of camera motions
if (mode == 1){
starCount = sigStars;
budget = sigStars;
}
// SDL output
std::cout << std::endl << "Bodies generated!" << std::endl;
std::cout << "SDL init : " << SDL_Init(SDL_INIT_VIDEO) << std::endl;
std::cout << "SDL Wind : " << SDL_CreateWindowAndRenderer(screenSize->x, screenSize->y, 0, &window,&renderer) << std::endl;
std::cout << "SDL size : " << SDL_RenderSetScale(renderer,1,1) << std::endl;
std::cout << std::endl;
// Spawns a input listener
SDL_Event event;
// Spawns the camera
Rasterizer rasterizer;
rasterizer.SetRatio(*screenSize);
// Makes sure the sim starts stopped
bool playing = false;
// Starts the deltaTime system
std::clock_t prevClock = startTime;
bool pushframe = false;
// Camera will be centered on this star
int trackedStar = 0;
// Initialize the camera position
Vector3 cameraPosition = Vector3(0,0,0);
// Predeclaration of the parser array
Star *parseStars[budget];
int tick = 0; // Tracks the #tick
while (true) {
tick++;
// Should the next frame be pushed to the renderer?
pushframe = (std::clock() - prevClock) / (float)CLOCKS_PER_SEC > (1.0/tfps);
if (pushframe) {
// Starts the frame
SDL_SetRenderDrawColor(renderer,0,0,0,255);
SDL_RenderClear(renderer);
// Centers camera
rasterizer.worldPosition = cameraPosition;
// Draws the origin
rasterizer.PutLine(Vector3(0,0,0),Vector3(1,0,0),Vector3(255,0,0));
rasterizer.PutLine(Vector3(0,0,0),Vector3(0,1,0),Vector3(0,255,0));
rasterizer.PutLine(Vector3(0,0,0),Vector3(0,0,1),Vector3(0,0,255));
}
if (playing){
// Which stars will be parsed this frame?
// Picks them at random -- this appears stupid but is actually __very__ accurate
for (int i = 0 ; i < budget ; i ++){
parseStars[i] = &stars[ (rand() % (starCount - sigStars)) + sigStars];
}
// Adds the black holes to the stack
for (int i = 0 ; i < sigStars ; i ++) {
parseStars[i]=&stars[i];
}
// Can't be fucked to parallelize myself
#pragma omp parallel for collapse(2)
// Each star vs budget
for (int i = 0 ; i < starCount ; i++) {
for (int j = 0 ; j < budget ; j++){
// Solves the new acceleration for each star
stars[i].acceleration = stars[i].acceleration +
(
Star::Solve(stars[i].position, *parseStars[j], timestep)
)
;
}
}
// Must update everything at the same time
#pragma omp parallel for
for (int i = 0 ; i < starCount ; i++) {
stars[i].tick(timestep);
}
// Camera motion (on ticks instead of frames, better camera planning):
rasterizer.Rotate(Vector3(0,0,0.007f * timestep));
}
// Draws
if (pushframe) {
// Every star -- cannot be threaded! (bottleneck)
for (int i = 0 ; i < starCount ; i++) {
if (i < sigStars) {
// Black holes are highlighted
rasterizer.PutCircle(stars[i].position, 2 , stars[i].color);
} else {
rasterizer.PutPoint(stars[i].position, stars[i].color);
}
}
// New position
cameraPosition = stars[trackedStar].position;
// Pushes the frame
SDL_RenderPresent(renderer);
// Updates the time
prevClock = std::clock();
/*
// Renders
if (saveFrames == 1){
SaveWindowToBMP(window,renderer, "/tmp/Simulation_" + std::to_string(tick) + ".bmp");
}*/
}
// Queries the event listener
// ''While'' to clear the buffer
while(SDL_PollEvent( &event )){
// 'What just happened?'
switch( event.type ){
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
// Camera block
case SDLK_LEFT:
rasterizer.Rotate(Vector3(0,0,0.05f));
break;
case SDLK_RIGHT:
rasterizer.Rotate(Vector3(0,0,-0.05f));
break;
case SDLK_UP:
rasterizer.Rotate(Vector3(0.05f,0,0));
break;
case SDLK_DOWN:
rasterizer.Rotate(Vector3(-0.05f,0,0));
break;
case SDLK_PAGEDOWN:
rasterizer.Zoom(1/1.1f);
break;
case SDLK_PAGEUP:
rasterizer.Zoom(1.1f);
break;
case SDLK_SPACE:
playing = !playing;
break;
case SDLK_RETURN:
trackedStar = rand() % starCount;
break;
}
break;
case SDL_QUIT:
return 0;
break;
default:
break;
}
}
}
return 0;
}