1 // OpenSG Test Example: UniformBufferObject_Test
3 // This example allows to research the capabilities of the uniform
4 // buffer object extension on your graphics platform.
6 // The example does use the UniformBufferObjChunk which allows the
7 // host application to provide the uniform block member values directly
8 // to the chunk. The layout of the uniform block is determined by the
9 // shader code. Any of the layout values of the specification (shared,
10 // packed, std140) are allowed.
12 // Outcome on running this example:
13 // 1. animated green cylinder and torus
14 // => your platform provides all GLSL capabilities used in this
15 // example. Congratulations :-)
17 // 2. animated red cylinder and torus
18 // => the shader is actively working but some detail is not
19 // working properly. E.g.:
20 // - On ATI/AMD the usage of bvec2 fails at the time of writing
21 // the example on the authors Radeon 5700 series
22 // platform, iff the 'std140' layout is used.
23 // - On ATI/AMD the usage of double and dvec2 fails at the time
24 // writing the example on the authors Radeon 5700 series
26 // 3. animated gold looking cylinder and torus
27 // => the shader is not working at all. Something is miserabely
28 // wrong on your platform.
30 // The example uses the following uniform block named 'ExampleBlock'
31 // which is declared in the shader code below.
40 // layout(shared) uniform ExampleBlock {
63 // Test x[4]; // structs can not explicitely be nested but implicit nesting is fine
67 // For this example the values must be provided in the exact order for the
68 // following data slots:
76 // "ExampleBlock.h[0]"
77 // "ExampleBlock.h[1]"
79 // "ExampleBlock.o[0].j"
80 // "ExampleBlock.o[0].k"
81 // "ExampleBlock.o[0].l[0]"
82 // "ExampleBlock.o[0].l[1]"
83 // "ExampleBlock.o[0].m"
84 // "ExampleBlock.o[0].n[0]"
85 // "ExampleBlock.o[0].n[1]"
86 // "ExampleBlock.o[1].j"
87 // "ExampleBlock.o[1].k"
88 // "ExampleBlock.o[1].l[0]"
89 // "ExampleBlock.o[1].l[1]"
90 // "ExampleBlock.o[1].m"
91 // "ExampleBlock.o[1].n[0]"
92 // "ExampleBlock.o[1].n[1]"
97 // "ExampleBlock.y.x[0].t"
98 // "ExampleBlock.y.x[0].v[0]"
99 // "ExampleBlock.y.x[0].v[1]"
100 // "ExampleBlock.y.x[0].v[2]"
101 // "ExampleBlock.y.x[0].w"
102 // "ExampleBlock.y.x[1].t"
103 // "ExampleBlock.y.x[1].v[0]"
104 // "ExampleBlock.y.x[1].v[1]"
105 // "ExampleBlock.y.x[1].v[2]"
106 // "ExampleBlock.y.x[1].w"
107 // "ExampleBlock.y.x[2].t"
108 // "ExampleBlock.y.x[2].v[0]"
109 // "ExampleBlock.y.x[2].v[1]"
110 // "ExampleBlock.y.x[2].v[2]"
111 // "ExampleBlock.y.x[2].w"
112 // "ExampleBlock.y.x[3].t"
113 // "ExampleBlock.y.x[3].v[0]"
114 // "ExampleBlock.y.x[3].v[1]"
115 // "ExampleBlock.y.x[3].v[2]"
116 // "ExampleBlock.y.x[3].w"
118 #ifdef OSG_BUILD_ACTIVE
121 #include <OSGConfig.h>
122 #include <OSGSimpleGeometry.h>
123 #include <OSGGLUTWindow.h>
124 #include <OSGSimpleSceneManager.h>
125 #include <OSGBaseFunctions.h>
126 #include <OSGTransform.h>
127 #include <OSGGroup.h>
130 #include <OSGGLEXT.h>
131 #include <OSGShaderProgramChunk.h>
132 #include <OSGShaderProgram.h>
133 #include <OSGShaderVariableOSG.h>
134 #include <OSGChunkMaterial.h>
135 #include <OSGMaterialGroup.h>
136 #include <OSGMaterialChunkOverrideGroup.h>
137 #include <OSGUniformBufferObjChunk.h>
138 #include <OSGPolygonChunk.h>
139 #include <OSGDepthChunk.h>
140 #include <OSGShaderProgramVariableChunk.h>
144 #include <OpenSG/OSGGLUT.h>
145 #include <OpenSG/OSGConfig.h>
146 #include <OpenSG/OSGSimpleGeometry.h>
147 #include <OpenSG/OSGGLUTWindow.h>
148 #include <OpenSG/OSGSimpleSceneManager.h>
149 #include <OpenSG/OSGBaseFunctions.h>
150 #include <OpenSG/OSGTransform.h>
151 #include <OpenSG/OSGGroup.h>
154 #include <OpenSG/OSGGLEXT.h>
155 #include <OpenSG/OSGShaderProgramChunk.h>
156 #include <OpenSG/OSGShaderProgram.h>
157 #include <OpenSG/OSGShaderVariableOSG.h>
158 #include <OpenSG/OSGChunkMaterial.h>
159 #include <OpenSG/OSGMaterialGroup.h>
160 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
161 #include <OpenSG/OSGUniformBufferObjChunk.h>
162 #include <OpenSG/OSGPolygonChunk.h>
163 #include <OpenSG/OSGDepthChunk.h>
164 #include <OpenSG/OSGShaderProgramVariableChunk.h>
167 //#define HAS_FP64_EXTENSION
170 // The SimpleSceneManager to manage simple applications
172 OSG::SimpleSceneManagerRefPtr mgr
;
175 // Create a OpenSG UniformBufferObjChunk object which does
176 // perform the uniform buffer object abstraction.
177 // For each block member entry (declared in the shader) a
178 // corresponding addXXX call is to be performed on the
179 // ubo chunk. These order of these calls must match the
180 // the order of the members in the block declaration.
181 // Additionally, the cardinality for arrays must be provided
182 // to the function calls (defaults to 1).
183 // The matrix functions are defined in column-major order
184 // matching the default definition of GLSL. I.e. a addMat2x3(2)
185 // call would request space and layout for an array of two
186 // matrices with two columns and three rows.
188 OSG::UniformBufferObjChunkTransitPtr
create_example_block_state()
190 OSG::UniformBufferObjChunkRefPtr ubo
= OSG::UniformBufferObjChunk::create();
192 ubo
->setBlockName("ExampleBlock");
193 ubo
->setUsage(GL_STREAM_DRAW
);
195 ubo
->addFloat ("ExampleBlock.a");
196 ubo
->addVec2 ("ExampleBlock.b");
197 ubo
->addVec3 ("ExampleBlock.c");
198 ubo
->addInt ("ExampleBlock.f.d");
199 ubo
->addBVec2 ("ExampleBlock.f.e");
201 ubo
->addFloat ("ExampleBlock.g");
202 ubo
->addFloat ("ExampleBlock.h", 2);
203 ubo
->addMat2x3 ("ExampleBlock.i"); // 2 columns and 3 rows
205 ubo
->addUVec3 ("ExampleBlock.o[0].j");
206 ubo
->addVec2 ("ExampleBlock.o[0].k");
207 ubo
->addFloat ("ExampleBlock.o[0].l", 2);
208 ubo
->addVec2 ("ExampleBlock.o[0].m");
209 ubo
->addMat3 ("ExampleBlock.o[0].n", 2);
211 ubo
->addUVec3 ("ExampleBlock.o[1].j");
212 ubo
->addVec2 ("ExampleBlock.o[1].k");
213 ubo
->addFloat ("ExampleBlock.o[1].l", 2);
214 ubo
->addVec2 ("ExampleBlock.o[1].m");
215 ubo
->addMat3 ("ExampleBlock.o[1].n", 2);
217 #ifdef HAS_FP64_EXTENSION
218 ubo
->addDouble ("ExampleBlock.p");
220 ubo
->addBool ("ExampleBlock.q");
222 #ifdef HAS_FP64_EXTENSION
223 ubo
->addDVec2 ("ExampleBlock.y.r");
225 ubo
->addInt ("ExampleBlock.y.s");
227 ubo
->addFloat ("ExampleBlock.y.x[0].t");
228 ubo
->addIVec3 ("ExampleBlock.y.x[0].v", 3);
229 ubo
->addInt ("ExampleBlock.y.x[0].w");
231 ubo
->addFloat ("ExampleBlock.y.x[1].t");
232 ubo
->addIVec3 ("ExampleBlock.y.x[1].v", 3);
233 ubo
->addInt ("ExampleBlock.y.x[1].w");
235 ubo
->addFloat ("ExampleBlock.y.x[2].t");
236 ubo
->addIVec3 ("ExampleBlock.y.x[2].v", 3);
237 ubo
->addInt ("ExampleBlock.y.x[2].w");
239 ubo
->addFloat ("ExampleBlock.y.x[3].t");
240 ubo
->addIVec3 ("ExampleBlock.y.x[3].v", 3);
241 ubo
->addInt ("ExampleBlock.y.x[3].w");
243 return OSG::UniformBufferObjChunkTransitPtr(ubo
);
247 // Fill the ubo chunk with values.
249 void update_example_block_state(OSG::UniformBufferObjChunk
* ubo
)
251 ubo
->setFloat ("ExampleBlock.a", 23.7f
);
252 ubo
->setVec2 ("ExampleBlock.b", OSG::Vec2f(1.4f
, 8.6f
));
253 ubo
->setVec3 ("ExampleBlock.c", OSG::Vec3f(0.1f
, 0.2f
, 0.3f
));
255 ubo
->setInt ("ExampleBlock.f.d", 14);
256 ubo
->setBVec2 ("ExampleBlock.f.e", OSG::Vec2b(true, false));
258 ubo
->setFloat ("ExampleBlock.g", 15.3f
);
259 ubo
->setFloat ("ExampleBlock.h", 17.6f
, 0);
260 ubo
->setFloat ("ExampleBlock.h", 19.3f
, 1);
262 // Matrix mxn (m rows and n columns):
263 // ----------------------------------
264 // test_mat = a11 a12 a13 a14
268 // OpenSG takes rows...
269 OSG::Matrix4f
mat1( 11,12,13,14, // row 1
270 21,22,23,24, // row 2
271 31,32,33,34, // row 3
272 41,42,43,44 ); // row 4
274 // ... and provides elements in column-major order
275 // OSG::Real32* storage = mat1.getValues();
276 OSG::Vec4f column1
= mat1
[1];
277 OSG::Vec4f column2
= mat1
[2];
278 OSG::Vec4f column3
= mat1
[3];
279 OSG::Vec4f column4
= mat1
[4];
281 // GLSL uses column-major layout, i.e. mat2x3 is a matrix with 2 colums and 3 rows
287 ubo
->setMat2x3("ExampleBlock.i", mat1
);
289 ubo
->setUVec3 ("ExampleBlock.o[0].j", OSG::Vec3u(1, 2, 3));
290 ubo
->setVec2 ("ExampleBlock.o[0].k", OSG::Vec2f(1.1f
, 2.2f
));
291 ubo
->setFloat ("ExampleBlock.o[0].l", 11.1f
, 0);
292 ubo
->setFloat ("ExampleBlock.o[0].l", 22.2f
, 1);
293 ubo
->setVec2 ("ExampleBlock.o[0].m", OSG::Vec2f(22.2f
, 33.3f
));
295 OSG::Matrix4f
mat2( 1.1f
, 1.2f
, 1.3f
, 1.4f
, // row 1
296 2.1f
, 2.2f
, 2.3f
, 2.4f
, // row 2
297 3.1f
, 3.2f
, 3.3f
, 3.4f
, // row 3
298 4.1f
, 4.2f
, 4.3f
, 4.4f
); // row 4
300 ubo
->setMat3 ("ExampleBlock.o[0].n", mat2
, 0);
302 OSG::Matrix4f
mat3( 10.1f
, 10.2f
, 10.3f
, 10.4f
, // row 1
303 20.1f
, 20.2f
, 20.3f
, 20.4f
, // row 2
304 30.1f
, 30.2f
, 30.3f
, 30.4f
, // row 3
305 40.1f
, 40.2f
, 40.3f
, 40.4f
); // row 4
307 ubo
->setMat3 ("ExampleBlock.o[0].n", mat3
, 1);
309 ubo
->setUVec3 ("ExampleBlock.o[1].j", OSG::Vec3u(7, 8, 9));
310 ubo
->setVec2 ("ExampleBlock.o[1].k", OSG::Vec2f(7.7f
, 8.8f
));
311 ubo
->setFloat ("ExampleBlock.o[1].l", 77.7f
, 0);
312 ubo
->setFloat ("ExampleBlock.o[1].l", 88.8f
, 1);
313 ubo
->setVec2 ("ExampleBlock.o[1].m", OSG::Vec2f(88.8f
, 99.9f
));
315 OSG::Matrix4f
mat4( 100.1f
, 100.2f
, 100.3f
, 100.4f
, // row 1
316 200.1f
, 200.2f
, 200.3f
, 200.4f
, // row 2
317 300.1f
, 300.2f
, 300.3f
, 300.4f
, // row 3
318 400.1f
, 400.2f
, 400.3f
, 400.4f
); // row 4
320 ubo
->setMat3 ("ExampleBlock.o[1].n", mat4
, 0);
322 OSG::Matrix4f
mat5( 1000.1f
, 1000.2f
, 1000.3f
, 1000.4f
, // row 1
323 2000.1f
, 2000.2f
, 2000.3f
, 2000.4f
, // row 2
324 3000.1f
, 3000.2f
, 3000.3f
, 3000.4f
, // row 3
325 4000.1f
, 4000.2f
, 4000.3f
, 4000.4f
); // row 4
327 ubo
->setMat3 ("ExampleBlock.o[1].n", mat5
, 1);
329 #ifdef HAS_FP64_EXTENSION
330 ubo
->setDouble("ExampleBlock.p", 17856.23456);
332 ubo
->setBool ("ExampleBlock.q", true);
334 #ifdef HAS_FP64_EXTENSION
335 ubo
->setDVec2 ("ExampleBlock.y.r", OSG::Vec2d(9567.123, 2345.63456));
337 ubo
->setInt ("ExampleBlock.y.s", 123);
339 ubo
->setFloat ("ExampleBlock.y.x[0].t", 1.001f
);
340 ubo
->setIVec3 ("ExampleBlock.y.x[0].v", OSG::Vec3i(1,0,1), 0);
341 ubo
->setIVec3 ("ExampleBlock.y.x[0].v", OSG::Vec3i(2,0,2), 1);
342 ubo
->setIVec3 ("ExampleBlock.y.x[0].v", OSG::Vec3i(3,0,3), 2);
343 ubo
->setInt ("ExampleBlock.y.x[0].w", 1);
345 ubo
->setFloat ("ExampleBlock.y.x[1].t", 2.002f
);
346 ubo
->setIVec3 ("ExampleBlock.y.x[1].v", OSG::Vec3i(4,0,4), 0);
347 ubo
->setIVec3 ("ExampleBlock.y.x[1].v", OSG::Vec3i(5,0,5), 1);
348 ubo
->setIVec3 ("ExampleBlock.y.x[1].v", OSG::Vec3i(6,0,6), 2);
349 ubo
->setInt ("ExampleBlock.y.x[1].w", 2);
351 ubo
->setFloat ("ExampleBlock.y.x[2].t", 3.003f
);
352 ubo
->setIVec3 ("ExampleBlock.y.x[2].v", OSG::Vec3i(7,0,7), 0);
353 ubo
->setIVec3 ("ExampleBlock.y.x[2].v", OSG::Vec3i(8,0,8), 1);
354 ubo
->setIVec3 ("ExampleBlock.y.x[2].v", OSG::Vec3i(9,0,9), 2);
355 ubo
->setInt ("ExampleBlock.y.x[2].w", 3);
357 ubo
->setFloat ("ExampleBlock.y.x[3].t", 4.004f
);
358 ubo
->setIVec3 ("ExampleBlock.y.x[3].v", OSG::Vec3i(1,4,6), 0);
359 ubo
->setIVec3 ("ExampleBlock.y.x[3].v", OSG::Vec3i(2,5,7), 1);
360 ubo
->setIVec3 ("ExampleBlock.y.x[3].v", OSG::Vec3i(3,6,8), 2);
361 ubo
->setInt ("ExampleBlock.y.x[3].w", 4);
365 // vertex shader program.
367 std::string
get_vp_program();
370 // fragment shader program for bump mapping in surface local coordinates
372 std::string
get_fp_program();
375 // a separate transformation for every object
377 OSG::TransformRefPtr cyltrans
, tortrans
;
380 // forward declaration so we can have the interesting stuff upfront
382 int setupGLUT(int *argc
, char *argv
[]);
391 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
393 // set the transforms' matrices
394 m
.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t
/ 1000.f
) * 1.5),
395 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t
/ 500.f
));
397 cyltrans
->setMatrix(m
);
399 m
.setTransform(OSG::Vec3f(OSG::osgSin(t
/ 1000.f
), 0, 0),
400 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t
/ 1000.f
));
402 tortrans
->setMatrix(m
);
404 OSG::commitChanges();
410 // Initialize GLUT & OpenSG and set up the scene
412 int main(int argc
, char **argv
)
415 OSG::osgInit(argc
,argv
);
418 int winid
= setupGLUT(&argc
, argv
);
420 // open a new scope, because the pointers below should go out of scope
421 // before entering glutMainLoop.
422 // Otherwise OpenSG will complain about objects being alive after shutdown.
424 // the connection between GLUT and OpenSG
425 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
426 gwin
->setGlutId(winid
);
429 // create the SimpleSceneManager helper
430 mgr
= OSG::SimpleSceneManager::create();
431 mgr
->setWindow(gwin
);
433 // create a pretty simple graph: a Group with two Transforms as children,
434 // each of which carries a single Geometry.
438 OSG::NodeRefPtr scene
= OSG::Node::create();
440 // The cylinder and its transformation
441 OSG::NodeRefPtr cyl
= OSG::Node::create();
442 OSG::GeometryRefPtr cylgeo
= OSG::makeCylinderGeo( 1.4f
, .3f
, 24,
445 cyl
->setCore(cylgeo
);
447 cyltrans
= OSG::Transform::create();
449 OSG::NodeRefPtr cyltransnode
= OSG::Node::create();
450 cyltransnode
->setCore (cyltrans
);
451 cyltransnode
->addChild(cyl
);
453 // add it to the scene
454 scene
->addChild(cyltransnode
);
456 // The torus and its transformation
457 OSG::NodeRefPtr torus
= OSG::Node::create();
458 OSG::GeometryRefPtr torusgeo
= OSG::makeTorusGeo( .2f
, 1, 24, 36 );
460 torus
->setCore(torusgeo
);
462 tortrans
= OSG::Transform::create();
464 OSG::NodeRefPtr tortransnode
= OSG::Node::create();
465 tortransnode
->setCore (tortrans
);
466 tortransnode
->addChild(torus
);
468 // add it to the scene
469 scene
->addChild(tortransnode
);
472 // create the shader program
474 OSG::ShaderProgramChunkRefPtr prog_chunk
= OSG::ShaderProgramChunk::create();
475 OSG::ShaderProgramRefPtr vertShader
= OSG::ShaderProgram::createVertexShader();
476 OSG::ShaderProgramRefPtr fragShader
= OSG::ShaderProgram::createFragmentShader();
478 vertShader
->setProgram(get_vp_program());
479 fragShader
->setProgram(get_fp_program());
482 // binding the unifrom block to a buffer binding point can be performed
483 // either by calling the shaders's addUniformBlock method or by
484 // adding a 'uniform block' variable to a ShaderProgramVariableChunk.
485 // In the following we use both variants for illustration.
487 fragShader
->addUniformBlock("ExampleBlock", 1); // block binding point
489 prog_chunk
->addShader(vertShader
);
490 prog_chunk
->addShader(fragShader
);
493 // create uniform buffer object for uniform block 'ExampleBlock'
495 OSG::UniformBufferObjChunkRefPtr ubo_example_block
= create_example_block_state();
497 update_example_block_state(ubo_example_block
);
499 OSG::PolygonChunkRefPtr polygon_chunk
= OSG::PolygonChunk::create();
500 polygon_chunk
->setFrontMode(GL_FILL
);
501 polygon_chunk
->setBackMode(GL_FILL
);
502 polygon_chunk
->setCullFace(GL_NONE
);
504 OSG::DepthChunkRefPtr depth_chunk
= OSG::DepthChunk::create();
505 depth_chunk
->setEnable(true);
507 OSG::ChunkMaterialRefPtr prog_state
= OSG::ChunkMaterial::create();
508 prog_state
->addChunk(ubo_example_block
, 1); // buffer binding point 1
509 prog_state
->addChunk(prog_chunk
);
510 prog_state
->addChunk(polygon_chunk
);
511 prog_state
->addChunk(depth_chunk
);
513 OSG::MaterialChunkOverrideGroupRefPtr mgrp
= OSG::MaterialChunkOverrideGroup::create();
514 mgrp
->setMaterial(prog_state
);
515 scene
->setCore(mgrp
);
517 OSG::commitChanges();
521 // show the whole scene
532 // GLUT callback functions
536 // react to size changes
538 void reshape(int w
, int h
)
545 // react to mouse button presses
547 void mouse(int button
, int state
, int x
, int y
)
550 mgr
->mouseButtonRelease(button
, x
, y
);
552 mgr
->mouseButtonPress(button
, x
, y
);
558 // react to mouse motions with pressed buttons
560 void motion(int x
, int y
)
562 mgr
->mouseMove(x
, y
);
569 void keyboard(unsigned char k
, int x
, int y
)
575 // clean up global variables
587 mgr
->setStatistics(!mgr
->getStatistics());
594 // setup the GLUT library which handles the windows for us
596 int setupGLUT(int *argc
, char *argv
[])
598 glutInit(argc
, argv
);
599 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
601 int winid
= glutCreateWindow("OpenSG");
603 glutReshapeFunc(reshape
);
604 glutDisplayFunc(display
);
605 glutMouseFunc(mouse
);
606 glutMotionFunc(motion
);
607 glutKeyboardFunc(keyboard
);
609 // call the redraw function whenever there's nothing else to do
610 glutIdleFunc(display
);
616 // vertex shader program.
618 std::string
get_vp_program()
620 std::string vp_program
=
622 "#version 330 compatibility\n"
624 "#extension GL_ARB_separate_shader_objects: enable\n"
625 "#extension GL_ARB_uniform_buffer_object: enable\n"
629 " gl_Position = ftransform();\n"
638 // fragment shader program for bump mapping in surface local coordinates
640 std::string
get_fp_program()
642 std::string fp_program
=
644 "#version 330 compatibility\n"
646 "#extension GL_ARB_separate_shader_objects: enable\n"
647 "#extension GL_ARB_uniform_buffer_object: enable\n"
648 #ifdef HAS_FP64_EXTENSION
649 "#extension GL_ARB_gpu_shader_fp64: enable\n"
659 "layout(shared) uniform ExampleBlock\n"
678 #ifdef HAS_FP64_EXTENSION
683 #ifdef HAS_FP64_EXTENSION
687 " Test x[4]; // structs can not explicitely be nested but implicit nesting is fine\n"
691 "layout(location = 0) out vec4 vFragColor;\n"
696 " vec4 error = vec4(1.0, 0.0, 0.0, 1.0);\n"
697 " vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n"
700 " float a = example.a;\n"
701 " vec2 b = example.b;\n"
702 " vec3 c = example.c;\n"
703 " int d = example.f.d;\n"
704 " bvec2 e = example.f.e;\n"
705 " float g = example.g;\n"
706 " float h0 = example.h[0];\n"
707 " float h1 = example.h[1];\n"
708 " mat2x3 i = example.i;\n"
709 " uvec3 j0 = example.o[0].j;\n"
710 " vec2 k0 = example.o[0].k;\n"
711 " float l00 = example.o[0].l[0];\n"
712 " float l01 = example.o[0].l[1];\n"
713 " vec2 m0 = example.o[0].m;\n"
714 " mat3 n00 = example.o[0].n[0];\n"
715 " mat3 n01 = example.o[0].n[1];\n"
716 " uvec3 j1 = example.o[1].j;\n"
717 " vec2 k1 = example.o[1].k;\n"
718 " float l10 = example.o[1].l[0];\n"
719 " float l11 = example.o[1].l[1];\n"
720 " vec2 m1 = example.o[1].m;\n"
721 " mat3 n10 = example.o[1].n[0];\n"
722 " mat3 n11 = example.o[1].n[1];\n"
723 #ifdef HAS_FP64_EXTENSION
724 " double p = example.p;\n"
726 " bool q = example.q;\n"
727 #ifdef HAS_FP64_EXTENSION
728 " dvec2 r = example.y.r;\n"
730 " int s = example.y.s;\n"
731 " float t0 = example.y.x[0].t;\n"
732 " ivec3 v00 = example.y.x[0].v[0];\n"
733 " ivec3 v01 = example.y.x[0].v[1];\n"
734 " ivec3 v02 = example.y.x[0].v[2];\n"
735 " int w0 = example.y.x[0].w;\n"
736 " float t1 = example.y.x[1].t;\n"
737 " ivec3 v10 = example.y.x[1].v[0];\n"
738 " ivec3 v11 = example.y.x[1].v[1];\n"
739 " ivec3 v12 = example.y.x[1].v[2];\n"
740 " int w1 = example.y.x[1].w;\n"
741 " float t2 = example.y.x[2].t;\n"
742 " ivec3 v20 = example.y.x[2].v[0];\n"
743 " ivec3 v21 = example.y.x[2].v[1];\n"
744 " ivec3 v22 = example.y.x[2].v[2];\n"
745 " int w2 = example.y.x[2].w;\n"
746 " float t3 = example.y.x[3].t;\n"
747 " ivec3 v30 = example.y.x[3].v[0];\n"
748 " ivec3 v31 = example.y.x[3].v[1];\n"
749 " ivec3 v32 = example.y.x[3].v[2];\n"
750 " int w3 = example.y.x[3].w;\n"
756 " if (b != vec2(1.4, 8.6))\n"
759 " if (c != vec3(0.1, 0.2, 0.3))\n"
765 " if (e != bvec2(true, false))\n"
777 " if (i[0][0] != 11)\n"
780 " if (i[0][1] != 21)\n"
783 " if (i[0][2] != 31)\n"
786 " if (i[1][0] != 12)\n"
789 " if (i[1][1] != 22)\n"
792 " if (i[1][2] != 32)\n"
795 " if (j0 != uvec3(1, 2, 3))\n"
798 " if (k0 != vec2(1.1, 2.2))\n"
801 " if (l00 != 11.1)\n"
804 " if (l01 != 22.2)\n"
807 " if (m0 != vec2(22.2, 33.3))\n"
810 " if (n00[0][0] != 1.1)\n"
813 " if (n00[0][1] != 2.1)\n"
816 " if (n00[0][2] != 3.1)\n"
819 " if (n00[1][0] != 1.2)\n"
822 " if (n00[1][1] != 2.2)\n"
825 " if (n00[1][2] != 3.2)\n"
828 " if (n00[2][0] != 1.3)\n"
831 " if (n00[2][1] != 2.3)\n"
834 " if (n00[2][2] != 3.3)\n"
837 " if (n01[0][0] != 10.1)\n"
840 " if (n01[0][1] != 20.1)\n"
843 " if (n01[0][2] != 30.1)\n"
846 " if (n01[1][0] != 10.2)\n"
849 " if (n01[1][1] != 20.2)\n"
852 " if (n01[1][2] != 30.2)\n"
855 " if (n01[2][0] != 10.3)\n"
858 " if (n01[2][1] != 20.3)\n"
861 " if (n01[2][2] != 30.3)\n"
864 " if (j1 != uvec3(7, 8, 9))\n"
867 " if (k1 != vec2(7.7, 8.8))\n"
870 " if (l10 != 77.7)\n"
873 " if (l11 != 88.8)\n"
876 " if (m1 != vec2(88.8, 99.9))\n"
879 " if (n10[0][0] != 100.1)\n"
882 " if (n10[0][1] != 200.1)\n"
885 " if (n10[0][2] != 300.1)\n"
888 " if (n10[1][0] != 100.2)\n"
891 " if (n10[1][1] != 200.2)\n"
894 " if (n10[1][2] != 300.2)\n"
897 " if (n10[2][0] != 100.3)\n"
900 " if (n10[2][1] != 200.3)\n"
903 " if (n10[2][2] != 300.3)\n"
906 " if (n11[0][0] != 1000.1)\n"
909 " if (n11[0][1] != 2000.1)\n"
912 " if (n11[0][2] != 3000.1)\n"
915 " if (n11[1][0] != 1000.2)\n"
918 " if (n11[1][1] != 2000.2)\n"
921 " if (n11[1][2] != 3000.2)\n"
924 " if (n11[2][0] != 1000.3)\n"
927 " if (n11[2][1] != 2000.3)\n"
930 " if (n11[2][2] != 3000.3)\n"
933 #ifdef HAS_FP64_EXTENSION
934 " if (p != 17856.23456LF)\n"
941 #ifdef HAS_FP64_EXTENSION
942 " if (r != dvec2(9567.123LF, 2345.63456LF))\n"
949 " if (t0 != 1.001)\n"
952 " if (v00 != ivec3(1,0,1))\n"
955 " if (v01 != ivec3(2,0,2))\n"
958 " if (v02 != ivec3(3,0,3))\n"
964 " if (t1 != 2.002)\n"
967 " if (v10 != ivec3(4,0,4))\n"
970 " if (v11 != ivec3(5,0,5))\n"
973 " if (v12 != ivec3(6,0,6))\n"
979 " if (t2 != 3.003)\n"
982 " if (v20 != ivec3(7,0,7))\n"
985 " if (v21 != ivec3(8,0,8))\n"
988 " if (v22 != ivec3(9,0,9))\n"
994 " if (t3 != 4.004)\n"
997 " if (v30 != ivec3(1,4,6))\n"
1000 " if (v31 != ivec3(2,5,7))\n"
1003 " if (v32 != ivec3(3,6,8))\n"
1010 " vFragColor = color;\n"