1757ae0eaa60bf6dca0357fb21e4f4dd391c3ef9
[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 * target.w;
47         y = view_bounds.y * target.h;
48         w = view_bounds.w * target.w;
49         h = view_bounds.h * target.h;
50 }
51
52 /**
53  * Default implementation for rendering using CPU
54  */
55 void ObjectRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
56 {
57         Error("Cannot render objects of type %d on CPU", m_type);
58 }
59
60 /**
61  * Prepare index buffers for both CPU and GPU rendering to receive indexes (but don't add any yet!)
62  */
63 void ObjectRenderer::PrepareBuffers(unsigned max_objects)
64 {
65         if (m_buffer_builder != NULL) // We already have a BufferBuilder
66         {
67                 Fatal("Has been called before, without FinaliseBuffers being called since!");
68         }
69         // Empty and reserve the indexes vector (for CPU rendering)
70         m_indexes.clear();
71         m_indexes.reserve(max_objects); //TODO: Can probably make this smaller? Or leave it out? Do we care?
72
73         // Initialise and resize the ibo (for GPU rendering)
74         m_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
75         m_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
76         m_ibo.Resize(max_objects * 2 * sizeof(uint32_t));
77         // BufferBuilder is used to construct the ibo
78         m_buffer_builder = new BufferBuilder<uint32_t>(m_ibo.Map(false, true, true), m_ibo.GetSize()); // new matches delete in ObjectRenderer::FinaliseBuffers
79
80 }
81
82 /**
83  * Add object index to the buffers for CPU and GPU rendering
84  */
85 void ObjectRenderer::AddObjectToBuffers(unsigned index)
86 {
87         if (m_buffer_builder == NULL) // No BufferBuilder!
88         {
89                 Fatal("Called without calling PrepareBuffers");
90         }
91         m_buffer_builder->Add(2*index); // ibo for GPU rendering
92         m_buffer_builder->Add(2*index+1);
93         m_indexes.push_back(index); // std::vector of indices for CPU rendering
94 }
95
96 /**
97  * Finalise the index buffers for CPU and GPU rendering
98  */
99 void ObjectRenderer::FinaliseBuffers()
100 {
101         if (m_buffer_builder == NULL) // No BufferBuilder!
102         {
103                 Fatal("Called without calling PrepareBuffers");
104         }
105         // For GPU rendering, UnMap the ibo
106         m_ibo.UnMap();
107         // ... and delete the BufferBuilder used to create it
108         delete m_buffer_builder; // delete matches new in ObjectRenderer::PrepareBuffers
109         m_buffer_builder = NULL;
110         
111         // Nothing is necessary for CPU rendering
112 }
113
114
115 /**
116  * Rectangle (filled)
117  */
118 void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
119 {
120         for (unsigned i = 0; i < m_indexes.size(); ++i)
121         {
122                 CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target);
123                 for (int x = max(0, bounds.x); x < min(bounds.x+bounds.w, target.w); ++x)
124                 {
125                         for (int y = max(0, bounds.y); y < min(bounds.y+bounds.h, target.h); ++y)
126                         {
127                                 int index = (x+target.w*y)*4;
128                                 target.pixels[index+0] = 0;
129                                 target.pixels[index+1] = 0;
130                                 target.pixels[index+2] = 0;
131                                 target.pixels[index+3] = 255;
132                         }
133                 }
134         }
135 }
136
137 /**
138  * Rectangle (outine)
139  */
140 void RectOutlineRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
141 {
142         for (unsigned i = 0; i < m_indexes.size(); ++i)
143         {
144                 CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target);
145                 for (int x = max(0, bounds.x); x < min(bounds.x+bounds.w, target.w); ++x)
146                 {
147                         int top = (x+target.w*max(0, bounds.y))*4;
148                         int bottom = (x+target.w*min(bounds.y+bounds.h, target.h))*4;
149                         for (int j = 0; j < 3; ++j)
150                         {
151                                 target.pixels[top+j] = 0;
152                                 target.pixels[bottom+j] = 0;
153                         }
154                         target.pixels[top+3] = 255;
155                         target.pixels[bottom+3] = 255;
156                 }
157
158                 for (int y = max(0, bounds.y); y < min(bounds.y+bounds.h, target.h); ++y)
159                 {
160                         int left = (max(0, bounds.x)+target.w*y)*4;
161                         int right = (min(bounds.x+bounds.w, target.w)+target.w*y)*4;
162                         for (int j = 0; j < 3; ++j)
163                         {
164                                 target.pixels[left+j] = 0;
165                                 target.pixels[right+j] = 0;
166                         }
167                         target.pixels[left+3] = 255;
168                         target.pixels[right+3] = 255;
169                         
170                 }
171         }
172 }
173
174 /**
175  * Circle (filled)
176  */
177 void CircleFilledRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target)
178 {
179         for (unsigned i = 0; i < m_indexes.size(); ++i)
180         {
181                 CPURenderBounds bounds(objects.bounds[m_indexes[i]], view, target);
182                 int centre_x = bounds.x + bounds.w / 2;
183                 int centre_y = bounds.y + bounds.h / 2;
184                 
185                 Debug("Centre is %d, %d", centre_x, centre_y);
186                 Debug("Bounds are %d,%d,%d,%d", bounds.x, bounds.y, bounds.w, bounds.h);
187                 Debug("Windos is %d,%d", target.w, target.h);
188                 for (int x = max(0, bounds.x); x < min(bounds.x+bounds.w, target.w); ++x)
189                 {
190                         for (int y = max(0, bounds.y); y < min(bounds.y + bounds.h, target.h); ++y)
191                         {
192                                 double dx = 2.0*(double)(x - centre_x)/(double)(bounds.w);
193                                 double dy = 2.0*(double)(y - centre_y)/(double)(bounds.h);
194                                 int index = (x+target.w*y)*4;
195                                 
196                                 if (dx*dx + dy*dy <= 1.0)
197                                 {
198                                         target.pixels[index+0] = 0;
199                                         target.pixels[index+1] = 0;
200                                         target.pixels[index+2] = 0;
201                                         target.pixels[index+3] = 255;
202
203                                 }
204                         }
205                 }
206         }
207 }
208
209
210 /**
211  * For debug, save pixels to bitmap
212  */
213 void ObjectRenderer::SaveBMP(const CPURenderTarget & target, const char * filename)
214 {
215         SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(target.pixels, target.w, target.h, 8*4, target.w*4,
216         #if SDL_BYTEORDER == SDL_LIL_ENDIAN
217                 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
218         #else
219                 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
220         #endif //SDL_BYTEORDER  
221         );      
222         if (surf == NULL)
223                 Fatal("SDL_CreateRGBSurfaceFrom(pixels...) failed - %s", SDL_GetError());
224         if (SDL_SaveBMP(surf, filename) != 0)
225                 Fatal("SDL_SaveBMP failed - %s", SDL_GetError());
226
227         // Cleanup
228         SDL_FreeSurface(surf);
229 }
230
231 }

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