Horribly unreliable Arbint's and Rational<Arbint>'s
[ipdf/code.git] / src / tests / pointstobitmap.h
1 #ifndef _POINTSTOBITMAP_H
2 #define _POINTSTOBITMAP_H
3
4 #include <SDL.h>
5 #include <algorithm> // for min/max_element
6
7 void AntiAlias(unsigned char * pixels, uint64_t w, uint64_t h, uint8_t stride = 4)
8 {
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)
13         {
14                 for (uint64_t y = 1; y < h-1; ++y)
15                 {
16                         uint64_t index = stride*(y*w + x);
17                         
18                 }
19         }
20 }
21
22 /**
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
27  */
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)
29 {
30
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
35
36         // Pixel buffer
37         unsigned char * pixels = new unsigned char[width*height*4];
38
39         // Overlay indicates we should load the bitmap into the pixel buffer first
40         if (overlay)
41         {
42                 SDL_Surface * bmp = SDL_LoadBMP(filename);
43                 if (bmp == NULL)
44                 {
45                         overlay = false; // bmp (probably) doesn't exist -> not an error (we hope)
46                 }
47                 else
48                 {
49                         width = bmp->w;
50                         height = bmp->h;
51                         for (int i = 0; i < width*height*(bmp->format->BytesPerPixel); ++i)
52                         {
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); 
55                         }
56                 }
57         }
58         if (!overlay)
59         {
60                 for (int i = 0; i < width*height*4; ++i)
61                         pixels[i] = 0xFF; // White pixels
62         }
63
64
65         typedef long double LD; // The temporary typedef, an underappreciated technique...
66
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);};     
70         
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);
76
77         pair<LD,LD> min(left.first, bottom.second);
78         pair<LD,LD> max(right.first, top.second);
79         // Force to be square
80         if (max.first - min.first > max.second - min.second)
81         {
82                 max.second = min.second + (max.first - min.first);
83         }
84         else
85         {
86                 max.first = min.first + (max.second - min.second);
87         }
88         Debug("Bitmap: %llf %llf -> %llf %llf", min.first, min.second, max.first, max.second);
89         // Alternately, just do this:
90         /* 
91         pair<LD,LD> min(-scale, -scale);
92         pair<LD,LD> max(scale, scale);
93         */
94
95         // Map each point to a pixel position
96         for (auto i = 0; i < points.size(); ++i)
97         {
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
102                 // Set colour
103                 pixels[index+ri] = r;
104                 pixels[index+gi] = g;
105                 pixels[index+bi] = b;
106         }
107
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
112         #else
113                 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
114         #endif //SDL_BYTEORDER  
115         );
116
117         if (surf == NULL)
118                 Fatal("SDL_CreateRGBSurfaceFrom(pixels...) failed - %s", SDL_GetError());
119         if (SDL_SaveBMP(surf, filename) != 0)
120                 Fatal("SDL_SaveBMP failed - %s", SDL_GetError());
121
122         // Cleanup
123         SDL_FreeSurface(surf);
124         delete [] pixels;
125 }
126
127 #endif //_POINTSTOBITMAP_H

UCC git Repository :: git.ucc.asn.au