Bugfixes for CPU rendering
[ipdf/code.git] / src / objectrenderer.cpp
1 /**
2  * @file objectrenderer.cpp
3  * @brief Implements ObjectRenderer and derived classes
4  */
5
6 #include "objectrenderer.h"
7 #include "view.h"
8
9 using namespace std;
10
11 namespace IPDF
12 {
13
14 /**
15  * ObjectRenderer constructor
16  * Note the ShaderProgram constructor which compiles the shaders for GPU rendering (if they exist)
17  */
18 ObjectRenderer::ObjectRenderer(const ObjectType & type, 
19                 const char * vert_glsl_file, const char * frag_glsl_file, const char * geom_glsl_file)
20                 : m_type(type), m_shader_program(), m_indexes(), m_buffer_builder(NULL)
21 {
22         m_shader_program.InitialiseShaders(vert_glsl_file, frag_glsl_file, geom_glsl_file);
23         m_shader_program.Use();
24         glUniform4f(m_shader_program.GetUniformLocation("colour"), 0,0,0,1); //TODO: Allow different colours
25 }
26
27 /**
28  * Render using GPU
29  */
30 void ObjectRenderer::RenderUsingGPU()
31 {
32         if (!m_shader_program.Valid())
33                 Warn("Shader is invalid (objects are of type %d)", m_type);
34         m_shader_program.Use();
35         m_ibo.Bind();
36         glDrawElements(GL_LINES, m_indexes.size()*2, GL_UNSIGNED_INT, 0);
37 }
38
39 /**
40  * Helper structuretransforms coordinates to pixels
41  */
42
43 ObjectRenderer::CPURenderBounds::CPURenderBounds(const Rect & bounds, const View & view, const CPURenderTarget & target)
44 {
45         Rect view_bounds = view.TransformToViewCoords(bounds);
46         x = view_bounds.x * Real(target.w);
47         y = view_bounds.y * Real(target.h);
48         w = view_bounds.w * Real(target.w);
49         h = view_bounds.h * Real(target.h);
50         Debug("CPURenderBounds %s -> %s -> {%li,%li,%li,%li}", bounds.Str().c_str(), view_bounds.Str().c_str(), x, y, w, h);
51 }
52
53 /**
54  * Default implementation for rendering using CPU
55  */
56 void ObjectRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
57 {
58         Error("Cannot render objects of type %d on CPU", m_type);
59 }
60
61 /**
62  * Prepare index buffers for both CPU and GPU rendering to receive indexes (but don't add any yet!)
63  */
64 void ObjectRenderer::PrepareBuffers(unsigned max_objects)
65 {
66         if (m_buffer_builder != NULL) // We already have a BufferBuilder
67         {
68                 Fatal("Has been called before, without FinaliseBuffers being called since!");
69         }
70         // Empty and reserve the indexes vector (for CPU rendering)
71         m_indexes.clear();
72         m_indexes.reserve(max_objects); //TODO: Can probably make this smaller? Or leave it out? Do we care?
73
74         // Initialise and resize the ibo (for GPU rendering)
75         m_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
76         m_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
77         m_ibo.Resize(max_objects * 2 * sizeof(uint32_t));
78         // BufferBuilder is used to construct the ibo
79         m_buffer_builder = new BufferBuilder<uint32_t>(m_ibo.Map(false, true, true), m_ibo.GetSize()); // new matches delete in ObjectRenderer::FinaliseBuffers
80
81 }
82
83 /**
84  * Add object index to the buffers for CPU and GPU rendering
85  */
86 void ObjectRenderer::AddObjectToBuffers(unsigned index)
87 {
88         if (m_buffer_builder == NULL) // No BufferBuilder!
89         {
90                 Fatal("Called without calling PrepareBuffers");
91         }
92         m_buffer_builder->Add(2*index); // ibo for GPU rendering
93         m_buffer_builder->Add(2*index+1);
94         m_indexes.push_back(index); // std::vector of indices for CPU rendering
95 }
96
97 /**
98  * Finalise the index buffers for CPU and GPU rendering
99  */
100 void ObjectRenderer::FinaliseBuffers()
101 {
102         if (m_buffer_builder == NULL) // No BufferBuilder!
103         {
104                 Fatal("Called without calling PrepareBuffers");
105         }
106         // For GPU rendering, UnMap the ibo
107         m_ibo.UnMap();
108         // ... and delete the BufferBuilder used to create it
109         delete m_buffer_builder; // delete matches new in ObjectRenderer::PrepareBuffers
110         m_buffer_builder = NULL;
111         
112         // Nothing is necessary for CPU rendering
113 }
114
115
116 /**
117  * Rectangle (filled)
118  */
119 void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
120 {
121         for (unsigned i = 0; i < m_indexes.size(); ++i)
122         {
123                 CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target);
124                 for (int64_t x = max(0L, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x)
125                 {
126                         for (int64_t y = max(0L, bounds.y); y <= min(bounds.y+bounds.h, target.h-1); ++y)
127                         {
128                                 int index = (x+target.w*y)*4;
129                                 target.pixels[index+0] = 0;
130                                 target.pixels[index+1] = 0;
131                                 target.pixels[index+2] = 0;
132                                 target.pixels[index+3] = 255;
133                         }
134                 }
135         }
136 }
137
138 /**
139  * Rectangle (outine)
140  */
141 void RectOutlineRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
142 {
143         for (unsigned i = 0; i < m_indexes.size(); ++i)
144         {
145                 CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target);
146                 for (int64_t x = max(0L, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x)
147                 {
148                         int64_t top = (x+target.w*bounds.y)*4;
149                         int64_t bottom = (x+target.w*(bounds.y+bounds.h))*4;
150
151                         if (top >= 0L && top <4*target.w*target.h)
152                         {
153                                 for (int j = 0; j < 3; ++j)
154                                         target.pixels[top+j] = 0;
155                                 target.pixels[top+3] = 255;
156                         }
157                         if (bottom >= 0L && bottom <4*target.w*target.h)
158                         {
159                                 for (int j = 0; j < 3; ++j)
160                                         target.pixels[bottom+j] = 0;
161                                 target.pixels[bottom+3] = 255;
162                         }
163                 }
164
165                 for (int64_t y = max(0L, bounds.y); y <= min(bounds.y+bounds.h, target.h-1); ++y)
166                 {
167                         int64_t left = (bounds.x >= 0L && bounds.x < target.w) ? (bounds.x + target.w*y)*4 : -1L;
168                         int64_t right = (bounds.x+bounds.w >= 0L && bounds.x+bounds.w < target.w) ? (bounds.x+bounds.w + target.w*y)*4 : -1L;
169                         if (left >= 0L && left <4*target.w*target.h)
170                         {
171                                 for (int j = 0; j < 3; ++j)
172                                         target.pixels[left+j] = 0;
173                                 target.pixels[left+3] = 255;
174                         }
175                         if (right >= 0L && right <4*target.w*target.h)
176                         {
177                                 for (int j = 0; j < 3; ++j)
178                                         target.pixels[right+j] = 0;
179                                 target.pixels[right+3] = 255;
180                         }
181                 }
182         }
183 }
184
185 /**
186  * Circle (filled)
187  */
188 void CircleFilledRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
189 {
190         for (unsigned i = 0; i < m_indexes.size(); ++i)
191         {
192                 CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target);
193                 int64_t centre_x = bounds.x + bounds.w / 2;
194                 int64_t centre_y = bounds.y + bounds.h / 2;
195                 
196                 Debug("Centre is %d, %d", centre_x, centre_y);
197                 Debug("Bounds are %d,%d,%d,%d", bounds.x, bounds.y, bounds.w, bounds.h);
198                 Debug("Windos is %d,%d", target.w, target.h);
199                 for (int64_t x = max(0L, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x)
200                 {
201                         for (int64_t y = max(0L, bounds.y); y <= min(bounds.y + bounds.h, target.h-1); ++y)
202                         {
203                                 double dx = 2.0*(double)(x - centre_x)/(double)(bounds.w);
204                                 double dy = 2.0*(double)(y - centre_y)/(double)(bounds.h);
205                                 int64_t index = (x+target.w*y)*4;
206                                 
207                                 if (dx*dx + dy*dy <= 1.0)
208                                 {
209                                         target.pixels[index+0] = 0;
210                                         target.pixels[index+1] = 0;
211                                         target.pixels[index+2] = 0;
212                                         target.pixels[index+3] = 255;
213
214                                 }
215                         }
216                 }
217         }
218 }
219
220
221 /**
222  * For debug, save pixels to bitmap
223  */
224 void ObjectRenderer::SaveBMP(const CPURenderTarget & target, const char * filename)
225 {
226         SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(target.pixels, target.w, target.h, 8*4, target.w*4,
227         #if SDL_BYTEORDER == SDL_LIL_ENDIAN
228                 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
229         #else
230                 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
231         #endif //SDL_BYTEORDER  
232         );      
233         if (surf == NULL)
234                 Fatal("SDL_CreateRGBSurfaceFrom(pixels...) failed - %s", SDL_GetError());
235         if (SDL_SaveBMP(surf, filename) != 0)
236                 Fatal("SDL_SaveBMP failed - %s", SDL_GetError());
237
238         // Cleanup
239         SDL_FreeSurface(surf);
240 }
241
242 }

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