1 #ifndef _POINTSTOBITMAP_H
2 #define _POINTSTOBITMAP_H
5 #include <algorithm> // for min/max_element
7 void AntiAlias(unsigned char * pixels, uint64_t w, uint64_t h, uint8_t stride = 4)
9 int ri = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 0 : 3;
10 int gi = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 1 : 2;
11 int bi = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 2 : 1;
12 for (uint64_t x = 1; x < w-1; ++x)
14 for (uint64_t y = 1; y < h-1; ++y)
16 uint64_t index = stride*(y*w + x);
23 * Map vector of points onto a Bitmap
24 * Because it was easier than working out the OpenGL stuff right now
25 * Points will be mapped according to the bounding rectangle.
26 * Should probably deal with possible aspect ratio difference... or just make sure to always use a square I guess
28 template <class T> void PointsToBitmap(const vector<pair<T, T> > & points, const T & scale = 1, uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, const char * filename = "bezier.bmp", bool overlay = false, uint64_t width = 400, uint64_t height = 400)
31 int ri = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 0 : 3;
32 int gi = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 1 : 2;
33 int bi = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 2 : 1;
34 //int ai = (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? 3 : 0; // No alpha in BMP
37 unsigned char * pixels = new unsigned char[width*height*4];
39 // Overlay indicates we should load the bitmap into the pixel buffer first
42 SDL_Surface * bmp = SDL_LoadBMP(filename);
45 overlay = false; // bmp (probably) doesn't exist -> not an error (we hope)
51 for (int i = 0; i < width*height*(bmp->format->BytesPerPixel); ++i)
53 // We're assuming the BMP was stored in the same Byteorder as we will save it
54 pixels[i] = *((unsigned char*)(bmp->pixels)+i);
60 for (int i = 0; i < width*height*4; ++i)
61 pixels[i] = 0xFF; // White pixels
65 typedef long double LD; // The temporary typedef, an underappreciated technique...
67 // Named lambdas... this is getting worrying...
68 auto lessx = [](const pair<T, T> & a, const pair<T, T> & b){return (a.first < b.first);};
69 auto lessy = [](const pair<T, T> & a, const pair<T, T> & b){return (a.second < b.second);};
71 // So I don't have to type as much here
72 pair<T,T> left = *min_element(points.begin(), points.end(), lessx);
73 pair<T,T> right = *max_element(points.begin(), points.end(), lessx);
74 pair<T,T> bottom = *min_element(points.begin(), points.end(), lessy);
75 pair<T,T> top = *max_element(points.begin(), points.end(),lessy);
77 pair<LD,LD> min(left.first, bottom.second);
78 pair<LD,LD> max(right.first, top.second);
80 if (max.first - min.first > max.second - min.second)
82 max.second = min.second + (max.first - min.first);
86 max.first = min.first + (max.second - min.second);
88 Debug("Bitmap: %llf %llf -> %llf %llf", min.first, min.second, max.first, max.second);
89 // Alternately, just do this:
91 pair<LD,LD> min(-scale, -scale);
92 pair<LD,LD> max(scale, scale);
95 // Map each point to a pixel position
96 for (auto i = 0; i < points.size(); ++i)
98 // Do maths with long double; this way any artefacts are more likely due to the creation of the bezier itself than this mapping operation
99 uint64_t x = llround(((LD)(points[i].first) - (LD)(min.first)) * (LD)(width-1)/((LD)max.first - (LD)min.first));
100 uint64_t y = llround(((LD)(points[i].second) - (LD)(min.second)) * (LD)(height-1)/((LD)max.second - (LD)min.second));
101 int index = 4*(y*width + x); // Get index into pixel array
103 pixels[index+ri] = r;
104 pixels[index+gi] = g;
105 pixels[index+bi] = b;
108 // Truly a thing of beauty
109 SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(pixels, width, height, 8*4, width*4,
110 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
111 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
113 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
114 #endif //SDL_BYTEORDER
118 Fatal("SDL_CreateRGBSurfaceFrom(pixels...) failed - %s", SDL_GetError());
119 if (SDL_SaveBMP(surf, filename) != 0)
120 Fatal("SDL_SaveBMP failed - %s", SDL_GetError());
123 SDL_FreeSurface(surf);
127 #endif //_POINTSTOBITMAP_H