No more pointer arithmetic in GL/use geom shaders
[ipdf/code.git] / src / view.cpp
1 #include "view.h"
2 #include "bufferbuilder.h"
3
4 #include "gl_core44.h"
5
6 using namespace IPDF;
7 using namespace std;
8 #define RECT_VERT \
9         "#version 140\n"\
10         "#extension GL_ARB_shading_language_420pack : require\n"\
11         "#extension GL_ARB_explicit_attrib_location : require\n"\
12         "\n"\
13         "layout(std140, binding=0) uniform ViewBounds\n"\
14         "{\n"\
15         "\tfloat bounds_x;\n"\
16         "\tfloat bounds_y;\n"\
17         "\tfloat bounds_w;\n"\
18         "\tfloat bounds_h;\n"\
19         "};\n"\
20         "\n"\
21         "layout(location = 0) in vec2 position;\n"\
22         "\n"\
23         "void main()\n"\
24         "{\n"\
25         "\tvec2 transformed_position;\n"\
26         "\ttransformed_position.x = (position.x - bounds_x) / bounds_w;\n"\
27         "\ttransformed_position.y = (position.y - bounds_y) / bounds_h;\n"\
28         "\t// Transform to clip coordinates (-1,1, -1,1).\n"\
29         "\tgl_Position.x = (transformed_position.x*2) - 1;\n"\
30         "\tgl_Position.y = 1 - (transformed_position.y*2);\n"\
31         "\tgl_Position.z = 0.0;\n"\
32         "\tgl_Position.w = 1.0;\n"\
33         "}\n"
34
35 #define RECT_FRAG \
36         "#version 140\n"\
37         "\n"\
38         "out vec4 output_colour;\n"\
39         "\n"\
40         "uniform vec4 colour;\n"\
41         "\n"\
42         "void main()\n"\
43         "{\n"\
44         "\toutput_colour = colour;\n"\
45         "}\n"
46
47 #define RECT_OUTLINE_GEOM \
48         "#version 150\n"\
49         "\n"\
50         "layout(lines) in;\n"\
51         "layout(line_strip, max_vertices = 5) out;\n"\
52         "\n"\
53         "void main()\n"\
54         "{\n"\
55         "\tgl_Position = gl_in[0].gl_Position;\n"\
56         "\tEmitVertex();\n"\
57         "\tgl_Position = vec4(gl_in[0].gl_Position.x, gl_in[1].gl_Position.y, 0.0, 1.0);\n"\
58         "\tEmitVertex();\n"\
59         "\tgl_Position = gl_in[1].gl_Position;\n"\
60         "\tEmitVertex();\n"\
61         "\tgl_Position = vec4(gl_in[1].gl_Position.x, gl_in[0].gl_Position.y, 0.0, 1.0);\n"\
62         "\tEmitVertex();\n"\
63         "\tgl_Position = gl_in[0].gl_Position;\n"\
64         "\tEmitVertex();\n"\
65         "\tEndPrimitive();\n"\
66         "}\n"
67
68 #define RECT_FILLED_GEOM \
69         "#version 150\n"\
70         "\n"\
71         "layout(lines) in;\n"\
72         "layout(triangle_strip, max_vertices = 4) out;\n"\
73         "\n"\
74         "void main()\n"\
75         "{\n"\
76         "\tgl_Position = gl_in[0].gl_Position;\n"\
77         "\tEmitVertex();\n"\
78         "\tgl_Position = vec4(gl_in[0].gl_Position.x, gl_in[1].gl_Position.y, 0.0, 1.0);\n"\
79         "\tEmitVertex();\n"\
80         "\tgl_Position = vec4(gl_in[1].gl_Position.x, gl_in[0].gl_Position.y, 0.0, 1.0);\n"\
81         "\tEmitVertex();\n"\
82         "\tgl_Position = gl_in[1].gl_Position;\n"\
83         "\tEmitVertex();\n"\
84         "\tEndPrimitive();\n"\
85         "}\n"
86
87 void View::Translate(Real x, Real y)
88 {
89         x *= m_bounds.w;
90         y *= m_bounds.h;
91         m_bounds.x += x;
92         m_bounds.y += y;
93         Debug("View Bounds => %s", m_bounds.Str().c_str());
94         if (!m_use_gpu_transform)
95         {
96                 m_buffer_dirty = true;
97         }
98         m_bounds_dirty = true;
99 }
100
101 void View::ScaleAroundPoint(Real x, Real y, Real scaleAmt)
102 {
103         // x and y are coordinates in the window
104         // Convert to local coords.
105         x *= m_bounds.w;
106         y *= m_bounds.h;
107         x += m_bounds.x;
108         y += m_bounds.y;
109         
110         //Debug("Mouse wheel event %f %f %f\n", Float(x), Float(y), Float(scaleAmt));
111         
112         Real top = y - m_bounds.y;
113         Real left = x - m_bounds.x;
114         
115         top *= scaleAmt;
116         left *= scaleAmt;
117         
118         m_bounds.x = x - left;
119         m_bounds.y = y - top;
120         m_bounds.w *= scaleAmt;
121         m_bounds.h *= scaleAmt;
122         Debug("View Bounds => %s", m_bounds.Str().c_str());
123         if (!m_use_gpu_transform)
124                 m_buffer_dirty = true;
125         m_bounds_dirty = true;
126 }
127
128 Rect View::TransformToViewCoords(const Rect& inp) const
129 {
130         Rect out;
131         out.x = (inp.x - m_bounds.x) / m_bounds.w;
132         out.y = (inp.y - m_bounds.y) / m_bounds.h;
133
134         out.w = inp.w / m_bounds.w;
135         out.h = inp.h / m_bounds.h;
136         return out;
137 }
138
139 void View::DrawGrid()
140 {
141         //TODO: Implement this with OpenGL 3.1+
142 #if 0
143         // Draw some grid lines at fixed pixel positions
144         glMatrixMode(GL_PROJECTION);
145         glLoadIdentity();
146         glOrtho(0.0, 1.0, 1.0, 0.0, -1.f, 1.f);
147         glMatrixMode(GL_MODELVIEW);
148         glLoadIdentity();
149
150         glColor4f(0.9,0.9,0.9,0.1);
151         const float num_lines = 50.0;
152         for (float i = 0; i < num_lines; ++i)
153         {
154                 glBegin(GL_LINES);
155                 glVertex2f(i*(1.0/num_lines), 0.0);
156                 glVertex2f(i*(1.0/num_lines), 1.0);
157                 glEnd();
158                 glBegin(GL_LINES);
159                 glVertex2f(0.0,i*(1.0/num_lines));
160                 glVertex2f(1.0,i*(1.0/num_lines));
161                 glEnd();
162         
163         }
164 #endif
165 }
166
167 void View::Render(int width, int height)
168 {
169         if (width != m_cached_display.GetWidth() || height != m_cached_display.GetHeight())
170         {
171                 m_cached_display.Create(width, height);
172                 m_bounds_dirty = true;
173         }
174
175         if (!m_bounds_dirty)
176         {
177                 m_cached_display.UnBind();
178                 m_cached_display.Blit();
179                 return;
180         }
181         m_cached_display.Bind();
182         m_cached_display.Clear();
183
184         if (!m_render_inited)
185                 PrepareRender();
186
187         if (m_buffer_dirty)
188                 UpdateObjBoundsVBO();
189
190         if (m_bounds_dirty)
191         {
192                 if (m_use_gpu_transform)
193                 {
194                         GLfloat glbounds[] = {static_cast<GLfloat>(Float(m_bounds.x)), static_cast<GLfloat>(Float(m_bounds.y)), static_cast<GLfloat>(Float(m_bounds.w)), static_cast<GLfloat>(Float(m_bounds.h))};
195                         m_bounds_ubo.Upload(sizeof(float)*4, glbounds);
196                 }
197                 else
198                 {
199                         GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f};
200                         m_bounds_ubo.Upload(sizeof(float)*4, glbounds);
201                 }
202         }
203         m_bounds_dirty = false;
204
205         if (m_colour.a < 1.0f)
206         {
207                 glEnable(GL_BLEND);
208                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
209         }
210         m_objbounds_vbo.Bind();
211         m_bounds_ubo.Bind();
212         glEnableVertexAttribArray(0);
213         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
214
215         // Filled Rectangles
216         m_rect_filled_shader.Use();
217         m_filled_ibo.Bind();
218         glDrawElements(GL_LINES, m_rendered_filled*2, GL_UNSIGNED_INT, 0);
219
220         // Rectangle Outlines
221         m_rect_outline_shader.Use();
222         m_outline_ibo.Bind();
223         glDrawElements(GL_LINES, m_rendered_outline*2, GL_UNSIGNED_INT, 0);
224         glDisableVertexAttribArray(0);
225         if (m_colour.a < 1.0f)
226         {
227                 glDisable(GL_BLEND);
228         }
229         m_cached_display.UnBind();
230         m_cached_display.Blit();
231
232 }
233
234 struct GPUObjBounds
235 {
236         float x0, y0;
237         float x1, y1;
238 };
239
240 void View::UpdateObjBoundsVBO()
241 {
242         m_objbounds_vbo.Invalidate();
243         m_objbounds_vbo.SetType(GraphicsBuffer::BufferTypeVertex);
244         if (m_use_gpu_transform)
245         {
246                 m_objbounds_vbo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
247         }
248         else
249         {
250                 m_objbounds_vbo.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw);
251         }
252         m_objbounds_vbo.Resize(m_document.ObjectCount()*sizeof(GPUObjBounds));
253
254         BufferBuilder<GPUObjBounds> obj_bounds_builder(m_objbounds_vbo.Map(false, true, true), m_objbounds_vbo.GetSize());
255
256         for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
257         {
258                 Rect obj_bounds;
259                 if (m_use_gpu_transform)
260                 {
261                         obj_bounds = m_document.m_objects.bounds[id];
262                 }
263                 else
264                 {
265                         obj_bounds = TransformToViewCoords(m_document.m_objects.bounds[id]);
266                 }
267                 GPUObjBounds gpu_bounds = {
268                         (float)Float(obj_bounds.x),
269                         (float)Float(obj_bounds.y),
270                         (float)Float(obj_bounds.x + obj_bounds.w),
271                         (float)Float(obj_bounds.y + obj_bounds.h)
272                 };
273                 obj_bounds_builder.Add(gpu_bounds);
274
275         }
276         m_objbounds_vbo.UnMap();
277         m_buffer_dirty = false;
278 }
279
280 void View::PrepareRender()
281 {
282         // TODO: Error check here.
283         m_rect_outline_shader.AttachGeometryProgram(RECT_OUTLINE_GEOM);
284         m_rect_outline_shader.AttachVertexProgram(RECT_VERT);
285         m_rect_outline_shader.AttachFragmentProgram(RECT_FRAG);
286         m_rect_outline_shader.Link();
287         m_rect_outline_shader.Use();
288         glUniform4f(m_rect_outline_shader.GetUniformLocation("colour"), m_colour.r, m_colour.g, m_colour.b, m_colour.a);
289
290         m_rect_filled_shader.AttachGeometryProgram(RECT_FILLED_GEOM);
291         m_rect_filled_shader.AttachVertexProgram(RECT_VERT);
292         m_rect_filled_shader.AttachFragmentProgram(RECT_FRAG);
293         m_rect_filled_shader.Link();
294         m_rect_filled_shader.Use();
295         glUniform4f(m_rect_filled_shader.GetUniformLocation("colour"), m_colour.r, m_colour.g, m_colour.b, m_colour.a);
296
297         m_bounds_ubo.SetType(GraphicsBuffer::BufferTypeUniform);
298         m_bounds_ubo.SetUsage(GraphicsBuffer::BufferUsageStreamDraw);
299
300         m_outline_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
301         m_outline_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
302         m_outline_ibo.Resize(m_document.ObjectCount() * 2 * sizeof(uint32_t));
303         BufferBuilder<uint32_t> outline_builder(m_outline_ibo.Map(false, true, true), m_outline_ibo.GetSize()); 
304
305         m_filled_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
306         m_filled_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
307         m_filled_ibo.Resize(m_document.ObjectCount() * 2 * sizeof(uint32_t));
308         BufferBuilder<uint32_t> filled_builder(m_filled_ibo.Map(false, true, true), m_filled_ibo.GetSize());
309
310
311         m_rendered_filled = m_rendered_outline = 0;
312         uint32_t currentIndex = 0;
313         for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
314         {
315                 if (m_document.m_objects.types[id] != RECT_FILLED)
316                 {
317                         outline_builder.Add(currentIndex++);
318                         outline_builder.Add(currentIndex++);
319                         m_rendered_outline++;
320                 }
321                 else
322                 {
323                         filled_builder.Add(currentIndex++);
324                         filled_builder.Add(currentIndex++);
325                         m_rendered_filled++;
326                 }
327
328         }
329         m_outline_ibo.UnMap();
330         m_filled_ibo.UnMap();
331
332         m_render_inited = true;
333 }

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