#include <unistd.h> #include <climits> #include <cstdint> #include <cmath> #include <vector> #include <iostream> #include <fstream> #include <SDL/SDL.h> #include <SDL/SDL_image.h> #include <SDL/SDL_gfxPrimitives.h> #define COLOR 10 #define SHAPE 10 #define ORDER 8 #define POINTS 3 #define SHAPES 50 #define CLAMP(val, min, max) ((val) < (min) ? (min) : (val) > (max) ? (max) : (val)) using namespace std; int32_t maxFit = -1; int32_t w, h; class Polygon { public: uint8_t getR(void) const { return this->r; } uint8_t getG(void) const { return this->g; } uint8_t getB(void) const { return this->b; } uint8_t getA(void) const { return this->a; } int16_t getX(uint32_t i) const { return this->x[i]; } int16_t getY(uint32_t i) const { return this->y[i]; } int16_t *getX(void) { return this->x; } int16_t *getY(void) { return this->y; } void setR(uint8_t r) { this->r = CLAMP(r, 0, 255); } void setG(uint8_t g) { this->g = CLAMP(g, 0, 255); } void setB(uint8_t b) { this->b = CLAMP(b, 0, 255); } void setA(uint8_t a) { this->a = CLAMP(a, 0, 255); } void setX(uint32_t i, int16_t x) { this->x[i] = CLAMP(x, 0, w); } void setY(uint32_t i, int16_t y) { this->y[i] = CLAMP(y, 0, h); } private: uint8_t r, g, b, a; int16_t x[POINTS]; int16_t y[POINTS]; int16_t bounds[2][2]; }; vector <Polygon> DNA; void DrawDNA(SDL_Surface *surf) { SDL_FillRect(surf, &surf->clip_rect, SDL_MapRGB(surf->format, 255, 255, 255)); for (auto p = DNA.begin(); p != DNA.end(); p++) { filledPolygonRGBA(surf, p->getX(), p->getY(), POINTS, p->getR(), p->getG(), p->getB(), p->getA()); } } int32_t diff(SDL_Surface *genetic, SDL_Surface *original) { uint8_t *g = (uint8_t *)genetic->pixels; uint8_t *o = (uint8_t *)original->pixels; int32_t d = 0; bool mf = false; if (maxFit == -1) { maxFit = 0; mf = true; } for(int32_t y = 0; y < h; y += 2) { for(int32_t x = 0; x < w; x += 2) { int32_t p = y * w * 4 + x * 4; if (mf) { maxFit += o[p] + o[p + 1] + o[p + 2]; } d += abs(g[p] - o[p]) + abs(g[p + 1] - o[p + 1]) + abs(g[p + 2] - o[p + 2]); } } return d; } int main(int argc, char ** argv) { srandom(getpid() + time(NULL)); SDL_Init(SDL_INIT_VIDEO); SDL_Surface *tgoal = IMG_Load(argv[1]); SDL_Surface *screen = SDL_SetVideoMode(tgoal->w * 2, tgoal->h, 32, SDL_HWSURFACE); SDL_Surface *goal = SDL_DisplayFormatAlpha(tgoal); SDL_Surface *genetic = SDL_DisplayFormat(tgoal); SDL_FreeSurface(tgoal); SDL_Event event; w = goal->w; h = goal->h; // Initialize the DNA Polygon p; for(int32_t i = 0; i < SHAPES; i++) { for(int32_t j = 0; j < POINTS; j++) { p.setX(j, rand() % (w + 1)); p.setY(j, rand() % (h + 1)); } p.setR(rand() % 256); p.setG(rand() % 256); p.setB(rand() % 256); p.setA(0); DNA.push_back(p); } DrawDNA(genetic); int32_t start, last; start = last = SDL_GetTicks(); int32_t bestDiff = INT_MAX; uint32_t steps = 0; // How many mutations have we done uint32_t good = 0; // How many mutations have been effective uint32_t bad = 0; // How many mutations have made the solution worse int32_t wasGood = 0; bool run = true; while (run) { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: run = false; break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { run = false; break; } if (event.key.keysym.sym == SDLK_SPACE) { SDL_SaveBMP(screen, (to_string(time(NULL)) + ".bmp").c_str()); break; } } } Polygon old; int32_t shape1; int32_t shape2 = -1; // Try to mutate same shape again if wasGood variable is greater than 0 if (wasGood <= 0) shape1 = rand() % (SHAPES + 1); wasGood--; bool soft = (rand() % 2 == 1); Polygon *shape = &DNA[shape1]; old = DNA[shape1]; uint32_t act = rand() % (COLOR + SHAPE + ORDER); if (act < COLOR) { switch (rand() % 4) { case 0: shape->setR(soft ? shape->getR() + rand() % 27 - 13 : rand() % 256); break; case 1: shape->setG(soft ? shape->getG() + rand() % 27 - 13 : rand() % 256); break; case 2: shape->setB(soft ? shape->getB() + rand() % 27 - 13 : rand() % 256); break; case 3: shape->setA(soft ? shape->getA() + rand() % 27 - 13 : rand() % 256); break; } } else if (act < COLOR + SHAPE) { int32_t i = rand() % (POINTS + 1); if (rand() % 2) { shape->setX(i, soft ? shape->getX(i) + rand() % (int(w / 10.0) + 1) - w / 20 : rand() % (w + 1)); } else { shape->setY(i, soft ? shape->getY(i) + rand() % (int(h / 10.0) + 1) - h / 20 : rand() % (h + 1)); } } else { int destination = rand() % (SHAPES + 1); swap(DNA[shape1], DNA[destination]); shape2 = destination; } DrawDNA(genetic); int32_t d = diff(genetic, goal); // Test if new result is better than the old one if(d < bestDiff) { good++; wasGood = 100; bestDiff = d; // Blit original image SDL_BlitSurface(goal, 0, screen, 0); SDL_Rect r; r.x = goal->w; r.y = 0; r.w = goal->w; r.h = goal->h; // Blit genetic image SDL_BlitSurface(genetic, 0, screen, &r); SDL_Flip(screen); } else { if(shape2 >= 0) { swap(DNA[shape1], DNA[shape2]); } else { DNA[shape1] = old; } } steps++; // Print some useful(?) info if (steps % 100 == 0) { cout << good << " / " << steps << " " << ((maxFit - bestDiff) / (float)maxFit) * 100 << " : " << SDL_GetTicks() - last << " - " << (double)(SDL_GetTicks() - start) / 1000.0 << endl; last = SDL_GetTicks(); } } // Save BMP SDL_SaveBMP(screen, (to_string(time(NULL)) + ".bmp").c_str()); // Dump triangle data to file ofstream out(to_string(time(NULL)) + "_dump"); out << SHAPES << " " << POINTS << endl; for (auto i = DNA.begin(); i != DNA.end(); i++) { out << (int32_t)i->getR() << " " << (int32_t)i->getG() << " " << (int32_t)i->getB() << " " << (int32_t)i->getA() << endl; for (int32_t j = 0; j < POINTS; j++) { out << i->getX(j) << " " << i->getY(j) << endl; } } // Free resources SDL_FreeSurface(goal); SDL_FreeSurface(genetic); // Shutdown SDL SDL_Quit(); return 0; }