diff --git a/src/Control.cpp b/src/Control.cpp index 0ab3c3f..7365623 100644 --- a/src/Control.cpp +++ b/src/Control.cpp @@ -27,7 +27,8 @@ float Control::barMargin = 4; Control::Control(float winW, float winH, std::string name) : - screenSetup(this) + screenSetup(this), + screenGenerations(this) { this->window.create(sf::VideoMode(winW, winH), name); @@ -54,6 +55,14 @@ Control::~Control() } +sf::Vector2f Control::getSizeWithBar() +{ + sf::Vector2f size = sf::Vector2f(this->window.getSize()); + size -= sf::Vector2f(0, this->leftText.getCharacterSize() + 2*Control::barMargin); + return size; +} + + void Control::interactive() { this->currentScreen = nullptr; diff --git a/src/Control.hpp b/src/Control.hpp index 0ce68e5..8e7a328 100644 --- a/src/Control.hpp +++ b/src/Control.hpp @@ -35,8 +35,10 @@ public: static float barMargin; sf::RenderWindow window; + sf::Vector2f getSizeWithBar(); ScreenSetup screenSetup; + ScreenGenerations screenGenerations; Control(float winW, float winH, std::string name); // creates a window ~Control(); diff --git a/src/Fitness.cpp b/src/Fitness.cpp index 3a3d9bd..c34736a 100644 --- a/src/Fitness.cpp +++ b/src/Fitness.cpp @@ -106,6 +106,12 @@ bool Fitness::loadTarget(std::string filename) } +bool Fitness::saveChromosome(std::string filename) +{ + return this->chromosome.getTexture().copyToImage().saveToFile(filename); +} + + void Fitness::render(const Chromosome& chr) { this->chromosome.clear(Fitness::backgroundColor); diff --git a/src/Fitness.hpp b/src/Fitness.hpp index bfb626c..ce881c6 100644 --- a/src/Fitness.hpp +++ b/src/Fitness.hpp @@ -13,6 +13,7 @@ public: Fitness(); bool loadShader(std::string filename); bool loadTarget(std::string filename); + bool saveChromosome(std::string filename); void render(const Chromosome& chr); unsigned long long compute(); diff --git a/src/Screens.cpp b/src/Screens.cpp index d52ec5a..69ff2b3 100644 --- a/src/Screens.cpp +++ b/src/Screens.cpp @@ -17,11 +17,7 @@ Screen::~Screen() -// ScreenSetup setup screen -// const sf::Vector2f ScreenSetup::offset(20, 20); -// const float ScreenSetup::distance = 50; -// const int ScreenSetup::items = 3; - +// ScreenSetup screen ScreenSetup::ScreenSetup(Control* controlptr) : Screen(controlptr), @@ -40,7 +36,6 @@ ScreenSetup::ScreenSetup(Control* controlptr) : void ScreenSetup::enter() { - std::cout << "ENTERED!" << std::endl; this->rect.setSize( sf::Vector2f( this->control->window.getSize().x, @@ -139,7 +134,7 @@ void ScreenSetup::executeItem(int position) case 2: break; // spacing placeholder case 3: if (Chromosome::isAnyGeneTypeAllowed()) { -// this->control->switchScreen(Control::screenGenerations); + this->control->switchScreen(this->control->screenGenerations); } else { this->control->setText("Allow at least one gene type to continue."); this->warnTimer = sf::seconds(3); @@ -186,3 +181,197 @@ void ScreenSetup::drawMenuItem(sf::RenderTarget& target, sf::RenderStates states this->text.setPosition(position); target.draw(text, states); } + + + +// ScreenGenerations screen + +ScreenGenerations::ScreenGenerations(Control* controlptr) : + Screen(controlptr) +{ + this->targetSprite.setTexture(Control::fitness->target.getTexture()); + this->chromoSprite.setTexture(Control::fitness->chromosome.getTexture()); + + this->currentGeneration = 0; + + this->snapshotMode = true; // fullscreen + this->automaticSnapshots = false; + this->manualSnapshotCount = 0; + this->automaticSnapshotCount = 0; + + this->lastBestFitness = -1; + std::cout << std::to_string(lastBestFitness) << std::endl; +} + + +void ScreenGenerations::enter() +{ + this->paused = true; + this->updateStatus(); + this->updateSpriteSize(); +} + + +void ScreenGenerations::event(sf::Event& event) +{ + if (event.type == sf::Event::KeyPressed) { + this->keyPressed(event); + } +} + + +void ScreenGenerations::update(sf::Time dt) +{ + if (!this->paused) { + Control::generation->advance(); + ++this->currentGeneration; + this->updateStatus(); + + if (this->automaticSnapshots && Control::generation->individuals[0].fitnessEvaluated) { + unsigned long long fitness = Control::generation->individuals[0].fitness; + if (fitness < this->lastBestFitness) { + std::cout << "Fitness decreased to " << std::to_string(fitness) + << " -> taking snapshot!" << std::endl; + this->takeSnapshot(false); + this->lastBestFitness = fitness; + } + } + } +} + + +void ScreenGenerations::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + Control::fitness->render(Control::generation->individuals[0].chromosome); + target.draw(this->targetSprite, states); + target.draw(this->chromoSprite, states); + this->control->drawBar(target, states); +} + + +void ScreenGenerations::exit() +{ +} + + +void ScreenGenerations::keyPressed(sf::Event& event) +{ + switch (event.key.code) { + // close window, stop program + case sf::Keyboard::Q: + this->control->close(); + return; + + case sf::Keyboard::P: + this->paused = !this->paused; + this->updateStatus(); + break; + + case sf::Keyboard::M: + this->snapshotMode = !this->snapshotMode; + this->updateStatus(); + break; + + case sf::Keyboard::S: + this->takeSnapshot(true); + break; + + case sf::Keyboard::A: + this->automaticSnapshots = !this->automaticSnapshots; + this->updateStatus(); + break; + + default: break; + } +} + + +void ScreenGenerations::updateSpriteSize() +{ + sf::Vector2f size = sf::Vector2f(Control::fitness->target.getSize()); + sf::Vector2f windowSize = this->control->getSizeWithBar(); + + float scale; + sf::Vector2f spritePos; + if (2*size.x/size.y > windowSize.x/windowSize.y) { + std::cout << "wider" << std::endl; + // the images are wider than the window + // display is calculated based on width + scale = windowSize.x/(2*size.x); + spritePos.x = 0; + spritePos.y = (windowSize.y - scale*size.y)/2; + } else { + std::cout << "higher" << std::endl; + // the images are higher than the window + // display is calculated based on height + scale = windowSize.y/size.y; + spritePos.x = (windowSize.x - (2*scale*size.x))/2; + spritePos.y = 0; + } + + this->targetSprite.setScale(sf::Vector2f(scale, scale)); + this->chromoSprite.setScale(sf::Vector2f(scale, scale)); + + this->targetSprite.setPosition(spritePos); + spritePos.x += scale*size.x; + this->chromoSprite.setPosition(spritePos); +} + + +void ScreenGenerations::updateStatus() +{ + std::string text = "Generation: "; + text += std::to_string(this->currentGeneration); + text += " (Genes: "; + text += std::to_string(Control::generation->individuals[0].chromosome.length()); + text += ")"; + this->control->setLeftText(text); + + text = "["; + text += (this->paused)?"P":"-"; + text += (this->automaticSnapshots)?"A":"-"; + text += (this->snapshotMode)?"f":"c"; + text += "]"; + this->control->setRightText(text); +} + + +void ScreenGenerations::takeSnapshot(bool manual) +{ + // name for image file - count + std::string filename; + std::string count; + if (manual) { + filename = "manual_"; + count = std::to_string(this->manualSnapshotCount); + ++this->manualSnapshotCount; + } else { + filename = "automatic_"; + count = std::to_string(this->automaticSnapshotCount); + ++this->automaticSnapshotCount; + } + if (count.length() < 5) { + filename += std::string(5 - count.length(), '0'); + } + filename += count; + + // name for image file - generation and chromosome size + filename += "_gen_"; + filename += std::to_string(this->currentGeneration); + filename += "_chr_"; + filename += std::to_string(Control::generation->individuals[0].chromosome.length()); + filename += ".png"; + + // actually save snapshot + if (this->snapshotMode) { + // fullscreen + sf::Texture tex; + sf::Vector2u size = this->control->window.getSize(); + tex.create(size.x, size.y); + tex.update(this->control->window); + tex.copyToImage().saveToFile(filename); + } else { + // chromosome only + Control::fitness->saveChromosome(filename); + } +} diff --git a/src/Screens.hpp b/src/Screens.hpp index 5522bf3..7c52c15 100644 --- a/src/Screens.hpp +++ b/src/Screens.hpp @@ -61,6 +61,33 @@ private: class ScreenGenerations : public Screen { +public: + ScreenGenerations(Control* controlptr); + + virtual void enter(); + virtual void event(sf::Event& event); + virtual void update(sf::Time dt); + virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; + virtual void exit(); + +private: + bool paused; + unsigned int currentGeneration; + + bool snapshotMode; + bool automaticSnapshots; + unsigned long long lastBestFitness; + unsigned int manualSnapshotCount; + unsigned int automaticSnapshotCount; + + sf::Sprite targetSprite; + sf::Sprite chromoSprite; + + void keyPressed(sf::Event& event); + void updateSpriteSize(); + void updateStatus(); + + void takeSnapshot(bool manual); }; diff --git a/src/main.cpp b/src/main.cpp index 32b8b96..7b6ba6b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,8 +8,17 @@ #include "Generation.hpp" #include "Control.hpp" -int main() +int main(int argc, char** argv) { + std::string filename; + if (argc != 2) { + std::cout << "u dun goofed" << std::endl; + return 1; + } else { + filename = argv[1]; + std::cout << "Using image: " << filename << std::endl; + } + std::minstd_rand randomEngine; randomEngine.seed(time(nullptr)); @@ -18,16 +27,15 @@ int main() Generation::re = &randomEngine; // Chromosome::allowGeneType(Gene::Circle); - Chromosome::allowGeneType(Gene::Triangle); +// Chromosome::allowGeneType(Gene::Triangle); Generation::size = 100; Generation::living = 10; Generation::crossover = 0.0; Fitness fitn; - fitn.loadTarget("firefox.png"); -// fitn.loadTarget("tom-face.png"); -// fitn.loadTarget("goldman_sachs.jpg"); +// fitn.loadTarget("firefox.png"); + fitn.loadTarget(filename); fitn.loadShader("compare.glsl"); Gene::size = sf::Vector2f(fitn.target.getSize()); @@ -44,52 +52,3 @@ int main() con.interactive(); } - -/* -// Chromosome a; -// for (int i=0; i<1000; ++i) a.mutate(); -// Chromosome b(a); -// for (int i=0; i<10; ++i) b.mutate(); -// Chromosome c(a); -// Chromosome d(a, b); - -// std::cout << a.length() << " | " << b.length() << " | " << c.length() << " | " << d.length() << std::endl; - - sf::Sprite ts(fitn.target.getTexture()); - sf::Sprite cs(fitn.chromosome.getTexture()); - - sf::RenderWindow window(sf::VideoMode(winW, winH), "gross"); -// window.setMouseCursorVisible(false); - - int gencnt = 0; - - while (window.isOpen()) { - sf::Event event; - while (window.pollEvent(event)) { -// if (event.type == sf::Event::KeyPressed) { -// std::cout << "Trying to advance generation" << std::endl; -// gen.advance(); -// std::cout << "Advanced generation" << std::endl; -// } - } - - - gen.advance(); - std::cout << "Generation: " << ++gencnt << " (length: " << gen.individuals[0].chromosome.length() << ")" << std::endl; - - // display results - window.clear(); - ts.setPosition( 0, 0); window.draw(ts); - fitn.render(gen.individuals[0].chromosome); cs.setPosition(240, 0); window.draw(cs); - fitn.render(gen.individuals[9].chromosome); cs.setPosition(240, 240); window.draw(cs); -// fitn.render(a); cs.setPosition( 0, 0); window.draw(cs); -// fitn.render(b); cs.setPosition(240, 0); window.draw(cs); -// fitn.render(c); cs.setPosition( 0, 240); window.draw(cs); -// fitn.render(d); cs.setPosition(240, 240); window.draw(cs); - window.display(); - -// std::cout << "Generation finished: " << ++gencnt << " (winner's length: " -// std::cout << genr.individuals[0].chromosome.length() << ")" << std::endl; - } -} -*/