Work around a bug in the Intel driver
[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 #define CIRCLE_FILLED_GEOM \
88         "#version 150\n"\
89         "\n"\
90         "layout(lines) in;\n"\
91         "layout(triangle_strip, max_vertices = 4) out;\n"\
92         "out vec2 objcoords;\n"\
93         "\n"\
94         "void main()\n"\
95         "{\n"\
96         "\tgl_Position = gl_in[0].gl_Position;\n"\
97         "\tobjcoords = vec2(-1.0, -1.0);\n"\
98         "\tEmitVertex();\n"\
99         "\tgl_Position = vec4(gl_in[0].gl_Position.x, gl_in[1].gl_Position.y, 0.0, 1.0);\n"\
100         "\tobjcoords = vec2(-1.0, 1.0);\n"\
101         "\tEmitVertex();\n"\
102         "\tgl_Position = vec4(gl_in[1].gl_Position.x, gl_in[0].gl_Position.y, 0.0, 1.0);\n"\
103         "\tobjcoords = vec2(1.0, -1.0);\n"\
104         "\tEmitVertex();\n"\
105         "\tgl_Position = gl_in[1].gl_Position;\n"\
106         "\tobjcoords = vec2(1.0, 1.0);\n"\
107         "\tEmitVertex();\n"\
108         "\tEndPrimitive();\n"\
109         "}\n"
110
111 #define CIRCLE_FRAG \
112         "#version 140\n"\
113         "\n"\
114         "in vec2 objcoords;\n"\
115         "out vec4 output_colour;\n"\
116         "\n"\
117         "uniform vec4 colour;\n"\
118         "\n"\
119         "void main()\n"\
120         "{\n"\
121         "\tif ((objcoords.x)*(objcoords.x) + (objcoords.y)*(objcoords.y) > 1.0)\n"\
122         "\t{\n"\
123         "\t\tdiscard;\n"\
124         "\t}\n"\
125         "\toutput_colour = colour;\n"\
126         "}\n"
127
128 void View::Translate(Real x, Real y)
129 {
130         x *= m_bounds.w;
131         y *= m_bounds.h;
132         m_bounds.x += x;
133         m_bounds.y += y;
134         Debug("View Bounds => %s", m_bounds.Str().c_str());
135         if (!m_use_gpu_transform)
136         {
137                 m_buffer_dirty = true;
138         }
139         m_bounds_dirty = true;
140 }
141
142 void View::ScaleAroundPoint(Real x, Real y, Real scaleAmt)
143 {
144         // x and y are coordinates in the window
145         // Convert to local coords.
146         x *= m_bounds.w;
147         y *= m_bounds.h;
148         x += m_bounds.x;
149         y += m_bounds.y;
150         
151         //Debug("Mouse wheel event %f %f %f\n", Float(x), Float(y), Float(scaleAmt));
152         
153         Real top = y - m_bounds.y;
154         Real left = x - m_bounds.x;
155         
156         top *= scaleAmt;
157         left *= scaleAmt;
158         
159         m_bounds.x = x - left;
160         m_bounds.y = y - top;
161         m_bounds.w *= scaleAmt;
162         m_bounds.h *= scaleAmt;
163         Debug("View Bounds => %s", m_bounds.Str().c_str());
164         if (!m_use_gpu_transform)
165                 m_buffer_dirty = true;
166         m_bounds_dirty = true;
167 }
168
169 Rect View::TransformToViewCoords(const Rect& inp) const
170 {
171         Rect out;
172         out.x = (inp.x - m_bounds.x) / m_bounds.w;
173         out.y = (inp.y - m_bounds.y) / m_bounds.h;
174
175         out.w = inp.w / m_bounds.w;
176         out.h = inp.h / m_bounds.h;
177         return out;
178 }
179
180 void View::DrawGrid()
181 {
182         //TODO: Implement this with OpenGL 3.1+
183 #if 0
184         // Draw some grid lines at fixed pixel positions
185         glMatrixMode(GL_PROJECTION);
186         glLoadIdentity();
187         glOrtho(0.0, 1.0, 1.0, 0.0, -1.f, 1.f);
188         glMatrixMode(GL_MODELVIEW);
189         glLoadIdentity();
190
191         glColor4f(0.9,0.9,0.9,0.1);
192         const float num_lines = 50.0;
193         for (float i = 0; i < num_lines; ++i)
194         {
195                 glBegin(GL_LINES);
196                 glVertex2f(i*(1.0/num_lines), 0.0);
197                 glVertex2f(i*(1.0/num_lines), 1.0);
198                 glEnd();
199                 glBegin(GL_LINES);
200                 glVertex2f(0.0,i*(1.0/num_lines));
201                 glVertex2f(1.0,i*(1.0/num_lines));
202                 glEnd();
203         
204         }
205 #endif
206 }
207
208 void View::Render(int width, int height)
209 {
210         if (width != m_cached_display.GetWidth() || height != m_cached_display.GetHeight())
211         {
212                 m_cached_display.Create(width, height);
213                 m_bounds_dirty = true;
214         }
215
216         if (!m_bounds_dirty)
217         {
218                 m_cached_display.UnBind();
219                 m_cached_display.Blit();
220                 return;
221         }
222         m_cached_display.Bind();
223         m_cached_display.Clear();
224
225         if (!m_render_inited)
226                 PrepareRender();
227
228         if (m_buffer_dirty)
229                 UpdateObjBoundsVBO();
230
231         if (m_bounds_dirty)
232         {
233                 if (m_use_gpu_transform)
234                 {
235                         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))};
236                         m_bounds_ubo.Upload(sizeof(float)*4, glbounds);
237                 }
238                 else
239                 {
240                         GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f};
241                         m_bounds_ubo.Upload(sizeof(float)*4, glbounds);
242                 }
243         }
244         m_bounds_dirty = false;
245
246         if (m_colour.a < 1.0f)
247         {
248                 glEnable(GL_BLEND);
249                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
250         }
251         m_objbounds_vbo.Bind();
252         m_bounds_ubo.Bind();
253         glEnableVertexAttribArray(0);
254         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
255
256         // Filled Circles
257         m_circle_filled_shader.Use();
258         m_circle_ibo.Bind();
259         glDrawElements(GL_LINES, m_rendered_circle*2, GL_UNSIGNED_INT, 0);
260
261         // Filled Rectangles
262         m_rect_filled_shader.Use();
263         m_filled_ibo.Bind();
264         glDrawElements(GL_LINES, m_rendered_filled*2, GL_UNSIGNED_INT, 0);
265
266         // Rectangle Outlines
267         m_rect_outline_shader.Use();
268         m_outline_ibo.Bind();
269         glDrawElements(GL_LINES, m_rendered_outline*2, GL_UNSIGNED_INT, 0);
270
271         glDisableVertexAttribArray(0);
272         if (m_colour.a < 1.0f)
273         {
274                 glDisable(GL_BLEND);
275         }
276         m_cached_display.UnBind();
277         m_cached_display.Blit();
278
279 }
280
281 struct GPUObjBounds
282 {
283         float x0, y0;
284         float x1, y1;
285 };
286
287 void View::UpdateObjBoundsVBO()
288 {
289         m_objbounds_vbo.Invalidate();
290         m_objbounds_vbo.SetType(GraphicsBuffer::BufferTypeVertex);
291         if (m_use_gpu_transform)
292         {
293                 m_objbounds_vbo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
294         }
295         else
296         {
297                 m_objbounds_vbo.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw);
298         }
299         m_objbounds_vbo.Resize(m_document.ObjectCount()*sizeof(GPUObjBounds));
300
301         BufferBuilder<GPUObjBounds> obj_bounds_builder(m_objbounds_vbo.Map(false, true, true), m_objbounds_vbo.GetSize());
302
303         for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
304         {
305                 Rect obj_bounds;
306                 if (m_use_gpu_transform)
307                 {
308                         obj_bounds = m_document.m_objects.bounds[id];
309                 }
310                 else
311                 {
312                         obj_bounds = TransformToViewCoords(m_document.m_objects.bounds[id]);
313                 }
314                 GPUObjBounds gpu_bounds = {
315                         (float)Float(obj_bounds.x),
316                         (float)Float(obj_bounds.y),
317                         (float)Float(obj_bounds.x + obj_bounds.w),
318                         (float)Float(obj_bounds.y + obj_bounds.h)
319                 };
320                 obj_bounds_builder.Add(gpu_bounds);
321
322         }
323         m_objbounds_vbo.UnMap();
324         m_buffer_dirty = false;
325 }
326
327 void View::PrepareRender()
328 {
329         // TODO: Error check here.
330         m_rect_outline_shader.AttachGeometryProgram(RECT_OUTLINE_GEOM);
331         m_rect_outline_shader.AttachVertexProgram(RECT_VERT);
332         m_rect_outline_shader.AttachFragmentProgram(RECT_FRAG);
333         m_rect_outline_shader.Link();
334         m_rect_outline_shader.Use();
335         glUniform4f(m_rect_outline_shader.GetUniformLocation("colour"), m_colour.r, m_colour.g, m_colour.b, m_colour.a);
336
337         m_rect_filled_shader.AttachGeometryProgram(RECT_FILLED_GEOM);
338         m_rect_filled_shader.AttachVertexProgram(RECT_VERT);
339         m_rect_filled_shader.AttachFragmentProgram(RECT_FRAG);
340         m_rect_filled_shader.Link();
341         m_rect_filled_shader.Use();
342         glUniform4f(m_rect_filled_shader.GetUniformLocation("colour"), m_colour.r, m_colour.g, m_colour.b, m_colour.a);
343
344         m_circle_filled_shader.AttachGeometryProgram(CIRCLE_FILLED_GEOM);
345         m_circle_filled_shader.AttachVertexProgram(RECT_VERT);
346         m_circle_filled_shader.AttachFragmentProgram(CIRCLE_FRAG);
347         m_circle_filled_shader.Link();
348         m_circle_filled_shader.Use();
349         glUniform4f(m_circle_filled_shader.GetUniformLocation("colour"), m_colour.r, m_colour.g, m_colour.b, m_colour.a);
350
351         m_bounds_ubo.SetType(GraphicsBuffer::BufferTypeUniform);
352         m_bounds_ubo.SetUsage(GraphicsBuffer::BufferUsageStreamDraw);
353
354         m_outline_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
355         m_outline_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
356         m_outline_ibo.Resize(m_document.ObjectCount() * 2 * sizeof(uint32_t));
357         BufferBuilder<uint32_t> outline_builder(m_outline_ibo.Map(false, true, true), m_outline_ibo.GetSize()); 
358
359         m_filled_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
360         m_filled_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
361         m_filled_ibo.Resize(m_document.ObjectCount() * 2 * sizeof(uint32_t));
362         BufferBuilder<uint32_t> filled_builder(m_filled_ibo.Map(false, true, true), m_filled_ibo.GetSize());
363
364         m_circle_ibo.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
365         m_circle_ibo.SetType(GraphicsBuffer::BufferTypeIndex);
366         m_circle_ibo.Resize(m_document.ObjectCount() * 2 * sizeof(uint32_t));
367         BufferBuilder<uint32_t> circle_builder(m_circle_ibo.Map(false, true, true), m_circle_ibo.GetSize());
368
369         m_rendered_filled = m_rendered_outline = m_rendered_circle = 0;
370         uint32_t currentIndex = 0;
371         for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
372         {
373                 if (m_document.m_objects.types[id] == RECT_OUTLINE)
374                 {
375                         outline_builder.Add(currentIndex++);
376                         outline_builder.Add(currentIndex++);
377                         m_rendered_outline++;
378                 }
379                 else if (m_document.m_objects.types[id] == RECT_FILLED)
380                 {
381                         filled_builder.Add(currentIndex++);
382                         filled_builder.Add(currentIndex++);
383                         m_rendered_filled++;
384                 }
385                 else
386                 {
387                         circle_builder.Add(currentIndex++);
388                         circle_builder.Add(currentIndex++);
389                         m_rendered_circle++;
390                 }
391
392         }
393         m_outline_ibo.UnMap();
394         m_filled_ibo.UnMap();
395         m_circle_ibo.UnMap();
396
397         m_render_inited = true;
398 }

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