1 // OpenSG Test Example: ShaderStorageBufferObject_Test
3 // This example allows to research the capabilities of the shader
4 // storage buffer object extension on your graphics platform.
6 // This example is similar to the ShaderStorageBufferObject_Test_1
7 // example. This one uses a non array block layout, whereas the
8 // test_1 example uses an even more complex setup with an array
11 // The example does use the ShaderStorageObjChunk which allows the
12 // host application to provide the shader storage block member values
13 // directly to the chunk. The layout of the shader storage block is determined
14 // by the shader code. Any of the layout values of the specification (shared,
15 // packed, std140, std430) are allowed.
17 // Outcome on running this example:
18 // 1. animated green cylinder and torus
19 // => your platform provides all GLSL capabilities used in this
20 // example. Congratulations :-)
22 // 2. animated red cylinder and torus
23 // => the shader is actively working but some detail is not
24 // working properly. E.g.:
25 // - On ATI/AMD the usage of bvec2 fails at the time of writing
26 // the example on the authors Radeon 5700 series
27 // platform, iff the 'std140' layout is used.
28 // - On ATI/AMD the usage of double and dvec2 fails at the time
29 // writing the example on the authors Radeon 5700 series
32 // 3. animated gold looking cylinder and torus
33 // => the shader is not working at all. Something is miserabely
34 // wrong on your platform.
36 // The example uses the following shader storage block named 'ExampleBlock'
37 // which is declared in the shader code below.
46 // layout(shared) buffer ExampleBlock {
69 // Test x[4]; // structs can not explicitely be nested but implicit nesting is fine
73 // For this example the values must be provided for the following data slots:
81 // "ExampleBlock.h[0]"
82 // "ExampleBlock.h[1]"
84 // "ExampleBlock.o[0].j"
85 // "ExampleBlock.o[0].k"
86 // "ExampleBlock.o[0].l[0]"
87 // "ExampleBlock.o[0].l[1]"
88 // "ExampleBlock.o[0].m"
89 // "ExampleBlock.o[0].n[0]"
90 // "ExampleBlock.o[0].n[1]"
91 // "ExampleBlock.o[1].j"
92 // "ExampleBlock.o[1].k"
93 // "ExampleBlock.o[1].l[0]"
94 // "ExampleBlock.o[1].l[1]"
95 // "ExampleBlock.o[1].m"
96 // "ExampleBlock.o[1].n[0]"
97 // "ExampleBlock.o[1].n[1]"
100 // "ExampleBlock.y.r"
101 // "ExampleBlock.y.s"
102 // "ExampleBlock.y.x[0].t"
103 // "ExampleBlock.y.x[0].v[0]"
104 // "ExampleBlock.y.x[0].v[1]"
105 // "ExampleBlock.y.x[0].v[2]"
106 // "ExampleBlock.y.x[0].w"
107 // "ExampleBlock.y.x[1].t"
108 // "ExampleBlock.y.x[1].v[0]"
109 // "ExampleBlock.y.x[1].v[1]"
110 // "ExampleBlock.y.x[1].v[2]"
111 // "ExampleBlock.y.x[1].w"
112 // "ExampleBlock.y.x[2].t"
113 // "ExampleBlock.y.x[2].v[0]"
114 // "ExampleBlock.y.x[2].v[1]"
115 // "ExampleBlock.y.x[2].v[2]"
116 // "ExampleBlock.y.x[2].w"
117 // "ExampleBlock.y.x[3].t"
118 // "ExampleBlock.y.x[3].v[0]"
119 // "ExampleBlock.y.x[3].v[1]"
120 // "ExampleBlock.y.x[3].v[2]"
121 // "ExampleBlock.y.x[3].w"
124 #ifdef OSG_BUILD_ACTIVE
127 #include <OSGConfig.h>
128 #include <OSGSimpleGeometry.h>
129 #include <OSGGLUTWindow.h>
130 #include <OSGSimpleSceneManager.h>
131 #include <OSGBaseFunctions.h>
132 #include <OSGTransform.h>
133 #include <OSGGroup.h>
136 #include <OSGGLEXT.h>
137 #include <OSGShaderProgramChunk.h>
138 #include <OSGShaderProgram.h>
139 #include <OSGShaderVariableOSG.h>
140 #include <OSGChunkMaterial.h>
141 #include <OSGMaterialGroup.h>
142 #include <OSGMaterialChunkOverrideGroup.h>
143 #include <OSGShaderStorageBufferObjChunk.h>
144 #include <OSGPolygonChunk.h>
145 #include <OSGDepthChunk.h>
146 #include <OSGShaderProgramVariableChunk.h>
150 #include <OpenSG/OSGGLUT.h>
151 #include <OpenSG/OSGConfig.h>
152 #include <OpenSG/OSGSimpleGeometry.h>
153 #include <OpenSG/OSGGLUTWindow.h>
154 #include <OpenSG/OSGSimpleSceneManager.h>
155 #include <OpenSG/OSGBaseFunctions.h>
156 #include <OpenSG/OSGTransform.h>
157 #include <OpenSG/OSGGroup.h>
160 #include <OpenSG/OSGGLEXT.h>
161 #include <OpenSG/OSGShaderProgramChunk.h>
162 #include <OpenSG/OSGShaderProgram.h>
163 #include <OpenSG/OSGShaderVariableOSG.h>
164 #include <OpenSG/OSGChunkMaterial.h>
165 #include <OpenSG/OSGMaterialGroup.h>
166 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
167 #include <OpenSG/OSGShaderStorageBufferObjChunk.h>
168 #include <OpenSG/OSGPolygonChunk.h>
169 #include <OpenSG/OSGDepthChunk.h>
170 #include <OpenSG/OSGShaderProgramVariableChunk.h>
173 #define HAS_FP64_EXTENSION
176 // The SimpleSceneManager to manage simple applications
178 OSG::SimpleSceneManagerRefPtr mgr
;
181 // Create a OpenSG ShaderStorageBufferObjChunk object which does
182 // perform the shader storage buffer object abstraction.
183 // For each block member entry (declared in the shader) a
184 // corresponding addXXX call is to be performed on the
185 // ssbo chunk. The cardinality for arrays must be provided
186 // to the function calls (defaults to 1).
187 // The matrix functions are defined in column-major order
188 // matching the default definition of GLSL. I.e. a addMat2x3(2)
189 // call would request space and layout for an array of two
190 // matrices with two columns and three rows.
192 OSG::ShaderStorageBufferObjChunkTransitPtr
create_example_block_state()
194 OSG::ShaderStorageBufferObjChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjChunk::create();
196 ssbo
->setBlockName("ExampleBlock");
197 ssbo
->setUsage(GL_STREAM_DRAW
);
199 ssbo
->addFloat ("ExampleBlock.a");
200 ssbo
->addVec2 ("ExampleBlock.b");
201 ssbo
->addVec3 ("ExampleBlock.c");
202 ssbo
->addInt ("ExampleBlock.f.d");
203 ssbo
->addBVec2 ("ExampleBlock.f.e");
204 ssbo
->addFloat ("ExampleBlock.g");
205 ssbo
->addFloat ("ExampleBlock.h", 2);
206 ssbo
->addMat2x3 ("ExampleBlock.i"); // 2 columns and 3 rows
207 ssbo
->addUVec3 ("ExampleBlock.o[0].j");
208 ssbo
->addVec2 ("ExampleBlock.o[0].k");
209 ssbo
->addFloat ("ExampleBlock.o[0].l", 2);
210 ssbo
->addVec2 ("ExampleBlock.o[0].m");
211 ssbo
->addMat3 ("ExampleBlock.o[0].n", 2);
213 ssbo
->addUVec3 ("ExampleBlock.o[1].j");
214 ssbo
->addVec2 ("ExampleBlock.o[1].k");
215 ssbo
->addFloat ("ExampleBlock.o[1].l", 2);
216 ssbo
->addVec2 ("ExampleBlock.o[1].m");
217 ssbo
->addMat3 ("ExampleBlock.o[1].n", 2);
219 #ifdef HAS_FP64_EXTENSION
220 ssbo
->addDouble ("ExampleBlock.p");
222 ssbo
->addBool ("ExampleBlock.q");
224 #ifdef HAS_FP64_EXTENSION
225 ssbo
->addDVec2 ("ExampleBlock.y.r");
227 ssbo
->addInt ("ExampleBlock.y.s");
229 ssbo
->addFloat ("ExampleBlock.y.x[0].t");
230 ssbo
->addIVec3 ("ExampleBlock.y.x[0].v", 3);
231 ssbo
->addInt ("ExampleBlock.y.x[0].w");
233 ssbo
->addFloat ("ExampleBlock.y.x[1].t");
234 ssbo
->addIVec3 ("ExampleBlock.y.x[1].v", 3);
235 ssbo
->addInt ("ExampleBlock.y.x[1].w");
237 ssbo
->addFloat ("ExampleBlock.y.x[2].t");
238 ssbo
->addIVec3 ("ExampleBlock.y.x[2].v", 3);
239 ssbo
->addInt ("ExampleBlock.y.x[2].w");
241 ssbo
->addFloat ("ExampleBlock.y.x[3].t");
242 ssbo
->addIVec3 ("ExampleBlock.y.x[3].v", 3);
243 ssbo
->addInt ("ExampleBlock.y.x[3].w");
245 return OSG::ShaderStorageBufferObjChunkTransitPtr(ssbo
);
249 // Fill the ssbo chunk with values.
251 void update_example_block_state(OSG::ShaderStorageBufferObjChunk
* ssbo
)
253 ssbo
->setFloat ("ExampleBlock.a", 23.7f
);
254 ssbo
->setVec2 ("ExampleBlock.b", OSG::Vec2f(1.4f
, 8.6f
));
255 ssbo
->setVec3 ("ExampleBlock.c", OSG::Vec3f(0.1f
, 0.2f
, 0.3f
));
257 ssbo
->setInt ("ExampleBlock.f.d", 14);
258 ssbo
->setBVec2 ("ExampleBlock.f.e", OSG::Vec2b(true, false));
259 ssbo
->setFloat ("ExampleBlock.g", 15.3f
);
260 ssbo
->setFloat ("ExampleBlock.h", 17.6f
, 0);
261 ssbo
->setFloat ("ExampleBlock.h", 19.3f
, 1);
263 // Matrix mxn (m rows and n columns):
264 // ----------------------------------
265 // test_mat = a11 a12 a13 a14
269 // OpenSG takes rows...
270 OSG::Matrix4f
mat1( 11,12,13,14, // row 1
271 21,22,23,24, // row 2
272 31,32,33,34, // row 3
273 41,42,43,44 ); // row 4
275 // ... and provides elements in column-major order
276 // OSG::Real32* storage = mat1.getValues();
277 OSG::Vec4f column1
= mat1
[1];
278 OSG::Vec4f column2
= mat1
[2];
279 OSG::Vec4f column3
= mat1
[3];
280 OSG::Vec4f column4
= mat1
[4];
282 // GLSL uses column-major layout, i.e. mat2x3 is a matrix with 2 colums and 3 rows
288 ssbo
->setMat2x3("ExampleBlock.i", mat1
);
290 ssbo
->setUVec3 ("ExampleBlock.o[0].j", OSG::Vec3u(1, 2, 3));
291 ssbo
->setVec2 ("ExampleBlock.o[0].k", OSG::Vec2f(1.1f
, 2.2f
));
292 ssbo
->setFloat ("ExampleBlock.o[0].l", 11.1f
, 0);
293 ssbo
->setFloat ("ExampleBlock.o[0].l", 22.2f
, 1);
294 ssbo
->setVec2 ("ExampleBlock.o[0].m", OSG::Vec2f(22.2f
, 33.3f
));
296 OSG::Matrix4f
mat2( 1.1f
, 1.2f
, 1.3f
, 1.4f
, // row 1
297 2.1f
, 2.2f
, 2.3f
, 2.4f
, // row 2
298 3.1f
, 3.2f
, 3.3f
, 3.4f
, // row 3
299 4.1f
, 4.2f
, 4.3f
, 4.4f
); // row 4
301 ssbo
->setMat3 ("ExampleBlock.o[0].n", mat2
, 0);
303 OSG::Matrix4f
mat3( 10.1f
, 10.2f
, 10.3f
, 10.4f
, // row 1
304 20.1f
, 20.2f
, 20.3f
, 20.4f
, // row 2
305 30.1f
, 30.2f
, 30.3f
, 30.4f
, // row 3
306 40.1f
, 40.2f
, 40.3f
, 40.4f
); // row 4
308 ssbo
->setMat3 ("ExampleBlock.o[0].n", mat3
, 1);
310 ssbo
->setUVec3 ("ExampleBlock.o[1].j", OSG::Vec3u(7, 8, 9));
311 ssbo
->setVec2 ("ExampleBlock.o[1].k", OSG::Vec2f(7.7f
, 8.8f
));
312 ssbo
->setFloat ("ExampleBlock.o[1].l", 77.7f
, 0);
313 ssbo
->setFloat ("ExampleBlock.o[1].l", 88.8f
, 1);
314 ssbo
->setVec2 ("ExampleBlock.o[1].m", OSG::Vec2f(88.8f
, 99.9f
));
316 OSG::Matrix4f
mat4( 100.1f
, 100.2f
, 100.3f
, 100.4f
, // row 1
317 200.1f
, 200.2f
, 200.3f
, 200.4f
, // row 2
318 300.1f
, 300.2f
, 300.3f
, 300.4f
, // row 3
319 400.1f
, 400.2f
, 400.3f
, 400.4f
); // row 4
321 ssbo
->setMat3 ("ExampleBlock.o[1].n", mat4
, 0);
323 OSG::Matrix4f
mat5( 1000.1f
, 1000.2f
, 1000.3f
, 1000.4f
, // row 1
324 2000.1f
, 2000.2f
, 2000.3f
, 2000.4f
, // row 2
325 3000.1f
, 3000.2f
, 3000.3f
, 3000.4f
, // row 3
326 4000.1f
, 4000.2f
, 4000.3f
, 4000.4f
); // row 4
328 ssbo
->setMat3 ("ExampleBlock.o[1].n", mat5
, 1);
330 #ifdef HAS_FP64_EXTENSION
331 ssbo
->setDouble("ExampleBlock.p", 17856.23456);
333 ssbo
->setBool ("ExampleBlock.q", true);
335 #ifdef HAS_FP64_EXTENSION
336 ssbo
->setDVec2 ("ExampleBlock.y.r", OSG::Vec2d(9567.123, 2345.63456));
338 ssbo
->setInt ("ExampleBlock.y.s", 123);
340 ssbo
->setFloat ("ExampleBlock.y.x[0].t", 1.001f
);
341 ssbo
->setIVec3 ("ExampleBlock.y.x[0].v", OSG::Vec3i(1,0,1), 0);
342 ssbo
->setIVec3 ("ExampleBlock.y.x[0].v", OSG::Vec3i(2,0,2), 1);
343 ssbo
->setIVec3 ("ExampleBlock.y.x[0].v", OSG::Vec3i(3,0,3), 2);
344 ssbo
->setInt ("ExampleBlock.y.x[0].w", 1);
346 ssbo
->setFloat ("ExampleBlock.y.x[1].t", 2.002f
);
347 ssbo
->setIVec3 ("ExampleBlock.y.x[1].v", OSG::Vec3i(4,0,4), 0);
348 ssbo
->setIVec3 ("ExampleBlock.y.x[1].v", OSG::Vec3i(5,0,5), 1);
349 ssbo
->setIVec3 ("ExampleBlock.y.x[1].v", OSG::Vec3i(6,0,6), 2);
350 ssbo
->setInt ("ExampleBlock.y.x[1].w", 2);
352 ssbo
->setFloat ("ExampleBlock.y.x[2].t", 3.003f
);
353 ssbo
->setIVec3 ("ExampleBlock.y.x[2].v", OSG::Vec3i(7,0,7), 0);
354 ssbo
->setIVec3 ("ExampleBlock.y.x[2].v", OSG::Vec3i(8,0,8), 1);
355 ssbo
->setIVec3 ("ExampleBlock.y.x[2].v", OSG::Vec3i(9,0,9), 2);
356 ssbo
->setInt ("ExampleBlock.y.x[2].w", 3);
358 ssbo
->setFloat ("ExampleBlock.y.x[3].t", 4.004f
);
359 ssbo
->setIVec3 ("ExampleBlock.y.x[3].v", OSG::Vec3i(1,4,6), 0);
360 ssbo
->setIVec3 ("ExampleBlock.y.x[3].v", OSG::Vec3i(2,5,7), 1);
361 ssbo
->setIVec3 ("ExampleBlock.y.x[3].v", OSG::Vec3i(3,6,8), 2);
362 ssbo
->setInt ("ExampleBlock.y.x[3].w", 4);
366 // vertex shader program.
368 std::string
get_vp_program();
371 // fragment shader program for bump mapping in surface local coordinates
373 std::string
get_fp_program();
376 // a separate transformation for every object
378 OSG::TransformRefPtr cyltrans
, tortrans
;
381 // forward declaration so we can have the interesting stuff upfront
383 int setupGLUT(int *argc
, char *argv
[]);
392 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
394 // set the transforms' matrices
395 m
.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t
/ 1000.f
) * 1.5),
396 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t
/ 500.f
));
398 cyltrans
->setMatrix(m
);
400 m
.setTransform(OSG::Vec3f(OSG::osgSin(t
/ 1000.f
), 0, 0),
401 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t
/ 1000.f
));
403 tortrans
->setMatrix(m
);
405 OSG::commitChanges();
411 // Initialize GLUT & OpenSG and set up the scene
413 int main(int argc
, char **argv
)
416 OSG::osgInit(argc
,argv
);
419 int winid
= setupGLUT(&argc
, argv
);
421 // open a new scope, because the pointers below should go out of scope
422 // before entering glutMainLoop.
423 // Otherwise OpenSG will complain about objects being alive after shutdown.
425 // the connection between GLUT and OpenSG
426 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
427 gwin
->setGlutId(winid
);
430 // create the SimpleSceneManager helper
431 mgr
= OSG::SimpleSceneManager::create();
432 mgr
->setWindow(gwin
);
434 // create a pretty simple graph: a Group with two Transforms as children,
435 // each of which carries a single Geometry.
439 OSG::NodeRefPtr scene
= OSG::Node::create();
441 // The cylinder and its transformation
442 OSG::NodeRefPtr cyl
= OSG::Node::create();
443 OSG::GeometryRefPtr cylgeo
= OSG::makeCylinderGeo( 1.4f
, .3f
, 24,
446 cyl
->setCore(cylgeo
);
448 cyltrans
= OSG::Transform::create();
450 OSG::NodeRefPtr cyltransnode
= OSG::Node::create();
451 cyltransnode
->setCore (cyltrans
);
452 cyltransnode
->addChild(cyl
);
454 // add it to the scene
455 scene
->addChild(cyltransnode
);
457 // The torus and its transformation
458 OSG::NodeRefPtr torus
= OSG::Node::create();
459 OSG::GeometryRefPtr torusgeo
= OSG::makeTorusGeo( .2f
, 1, 24, 36 );
461 torus
->setCore(torusgeo
);
463 tortrans
= OSG::Transform::create();
465 OSG::NodeRefPtr tortransnode
= OSG::Node::create();
466 tortransnode
->setCore (tortrans
);
467 tortransnode
->addChild(torus
);
469 // add it to the scene
470 scene
->addChild(tortransnode
);
473 // create the shader program
475 OSG::ShaderProgramChunkRefPtr prog_chunk
= OSG::ShaderProgramChunk::create();
476 OSG::ShaderProgramRefPtr vertShader
= OSG::ShaderProgram::createVertexShader();
477 OSG::ShaderProgramRefPtr fragShader
= OSG::ShaderProgram::createFragmentShader();
479 vertShader
->setProgram(get_vp_program());
480 fragShader
->setProgram(get_fp_program());
483 // binding the shader storage block to a buffer binding point can be performed
484 // either by calling the shaders's addShaderStorageBlock method or by
485 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
486 // In the following we use both variants for illustration.
488 fragShader
->addShaderStorageBlock("ExampleBlock", 1); // block binding point
490 prog_chunk
->addShader(vertShader
);
491 prog_chunk
->addShader(fragShader
);
494 // create shader storage buffer object for block 'ExampleBlock'
496 OSG::ShaderStorageBufferObjChunkRefPtr ssbo_example_block
= create_example_block_state();
498 update_example_block_state(ssbo_example_block
);
500 OSG::PolygonChunkRefPtr polygon_chunk
= OSG::PolygonChunk::create();
501 polygon_chunk
->setFrontMode(GL_FILL
);
502 polygon_chunk
->setBackMode(GL_FILL
);
503 polygon_chunk
->setCullFace(GL_NONE
);
505 OSG::DepthChunkRefPtr depth_chunk
= OSG::DepthChunk::create();
506 depth_chunk
->setEnable(true);
508 OSG::ChunkMaterialRefPtr prog_state
= OSG::ChunkMaterial::create();
509 prog_state
->addChunk(ssbo_example_block
, 1); // buffer binding point 1
510 prog_state
->addChunk(prog_chunk
);
511 prog_state
->addChunk(polygon_chunk
);
512 prog_state
->addChunk(depth_chunk
);
514 OSG::MaterialChunkOverrideGroupRefPtr mgrp
= OSG::MaterialChunkOverrideGroup::create();
515 mgrp
->setMaterial(prog_state
);
516 scene
->setCore(mgrp
);
518 OSG::commitChanges();
522 // show the whole scene
533 // GLUT callback functions
537 // react to size changes
539 void reshape(int w
, int h
)
546 // react to mouse button presses
548 void mouse(int button
, int state
, int x
, int y
)
551 mgr
->mouseButtonRelease(button
, x
, y
);
553 mgr
->mouseButtonPress(button
, x
, y
);
559 // react to mouse motions with pressed buttons
561 void motion(int x
, int y
)
563 mgr
->mouseMove(x
, y
);
570 void keyboard(unsigned char k
, int x
, int y
)
576 // clean up global variables
588 mgr
->setStatistics(!mgr
->getStatistics());
595 // setup the GLUT library which handles the windows for us
597 int setupGLUT(int *argc
, char *argv
[])
599 glutInit(argc
, argv
);
600 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
602 int winid
= glutCreateWindow("OpenSG");
604 glutReshapeFunc(reshape
);
605 glutDisplayFunc(display
);
606 glutMouseFunc(mouse
);
607 glutMotionFunc(motion
);
608 glutKeyboardFunc(keyboard
);
610 // call the redraw function whenever there's nothing else to do
611 glutIdleFunc(display
);
617 // vertex shader program.
619 std::string
get_vp_program()
621 std::string vp_program
=
623 "#version 330 compatibility\n"
625 "#extension GL_ARB_separate_shader_objects: enable\n"
626 "#extension GL_ARB_uniform_buffer_object: enable\n"
630 " gl_Position = ftransform();\n"
639 // fragment shader program for bump mapping in surface local coordinates
641 std::string
get_fp_program()
643 std::string fp_program
=
645 "#version 440 compatibility\n"
647 "#extension GL_ARB_separate_shader_objects: enable\n"
648 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
650 #ifdef HAS_FP64_EXTENSION
651 "#extension GL_ARB_gpu_shader_fp64: enable\n"
661 "layout (shared) buffer ExampleBlock\n"
680 #ifdef HAS_FP64_EXTENSION
685 #ifdef HAS_FP64_EXTENSION
689 " Test x[4]; // structs can not explicitely be nested but implicit nesting is fine\n"
693 "layout(location = 0) out vec4 vFragColor;\n"
698 " vec4 error = vec4(1.0, 0.0, 0.0, 1.0);\n"
699 " vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n"
702 " float a = example.a;\n"
703 " vec2 b = example.b;\n"
704 " vec3 c = example.c;\n"
705 " int d = example.f.d;\n"
706 " bvec2 e = example.f.e;\n"
707 " float g = example.g;\n"
708 " float h0 = example.h[0];\n"
709 " float h1 = example.h[1];\n"
710 " mat2x3 i = example.i;\n"
711 " uvec3 j0 = example.o[0].j;\n"
712 " vec2 k0 = example.o[0].k;\n"
713 " float l00 = example.o[0].l[0];\n"
714 " float l01 = example.o[0].l[1];\n"
715 " vec2 m0 = example.o[0].m;\n"
716 " mat3 n00 = example.o[0].n[0];\n"
717 " mat3 n01 = example.o[0].n[1];\n"
718 " uvec3 j1 = example.o[1].j;\n"
719 " vec2 k1 = example.o[1].k;\n"
720 " float l10 = example.o[1].l[0];\n"
721 " float l11 = example.o[1].l[1];\n"
722 " vec2 m1 = example.o[1].m;\n"
723 " mat3 n10 = example.o[1].n[0];\n"
724 " mat3 n11 = example.o[1].n[1];\n"
725 #ifdef HAS_FP64_EXTENSION
726 " double p = example.p;\n"
728 " bool q = example.q;\n"
729 #ifdef HAS_FP64_EXTENSION
730 " dvec2 r = example.y.r;\n"
732 " int s = example.y.s;\n"
733 " float t0 = example.y.x[0].t;\n"
734 " ivec3 v00 = example.y.x[0].v[0];\n"
735 " ivec3 v01 = example.y.x[0].v[1];\n"
736 " ivec3 v02 = example.y.x[0].v[2];\n"
737 " int w0 = example.y.x[0].w;\n"
738 " float t1 = example.y.x[1].t;\n"
739 " ivec3 v10 = example.y.x[1].v[0];\n"
740 " ivec3 v11 = example.y.x[1].v[1];\n"
741 " ivec3 v12 = example.y.x[1].v[2];\n"
742 " int w1 = example.y.x[1].w;\n"
743 " float t2 = example.y.x[2].t;\n"
744 " ivec3 v20 = example.y.x[2].v[0];\n"
745 " ivec3 v21 = example.y.x[2].v[1];\n"
746 " ivec3 v22 = example.y.x[2].v[2];\n"
747 " int w2 = example.y.x[2].w;\n"
748 " float t3 = example.y.x[3].t;\n"
749 " ivec3 v30 = example.y.x[3].v[0];\n"
750 " ivec3 v31 = example.y.x[3].v[1];\n"
751 " ivec3 v32 = example.y.x[3].v[2];\n"
752 " int w3 = example.y.x[3].w;\n"
758 " if (b != vec2(1.4, 8.6))\n"
761 " if (c != vec3(0.1, 0.2, 0.3))\n"
767 " if (e != bvec2(true, false))\n"
779 " if (i[0][0] != 11)\n"
782 " if (i[0][1] != 21)\n"
785 " if (i[0][2] != 31)\n"
788 " if (i[1][0] != 12)\n"
791 " if (i[1][1] != 22)\n"
794 " if (i[1][2] != 32)\n"
797 " if (j0 != uvec3(1, 2, 3))\n"
800 " if (k0 != vec2(1.1, 2.2))\n"
803 " if (l00 != 11.1)\n"
806 " if (l01 != 22.2)\n"
809 " if (m0 != vec2(22.2, 33.3))\n"
812 " if (n00[0][0] != 1.1)\n"
815 " if (n00[0][1] != 2.1)\n"
818 " if (n00[0][2] != 3.1)\n"
821 " if (n00[1][0] != 1.2)\n"
824 " if (n00[1][1] != 2.2)\n"
827 " if (n00[1][2] != 3.2)\n"
830 " if (n00[2][0] != 1.3)\n"
833 " if (n00[2][1] != 2.3)\n"
836 " if (n00[2][2] != 3.3)\n"
839 " if (n01[0][0] != 10.1)\n"
842 " if (n01[0][1] != 20.1)\n"
845 " if (n01[0][2] != 30.1)\n"
848 " if (n01[1][0] != 10.2)\n"
851 " if (n01[1][1] != 20.2)\n"
854 " if (n01[1][2] != 30.2)\n"
857 " if (n01[2][0] != 10.3)\n"
860 " if (n01[2][1] != 20.3)\n"
863 " if (n01[2][2] != 30.3)\n"
866 " if (j1 != uvec3(7, 8, 9))\n"
869 " if (k1 != vec2(7.7, 8.8))\n"
872 " if (l10 != 77.7)\n"
875 " if (l11 != 88.8)\n"
878 " if (m1 != vec2(88.8, 99.9))\n"
881 " if (n10[0][0] != 100.1)\n"
884 " if (n10[0][1] != 200.1)\n"
887 " if (n10[0][2] != 300.1)\n"
890 " if (n10[1][0] != 100.2)\n"
893 " if (n10[1][1] != 200.2)\n"
896 " if (n10[1][2] != 300.2)\n"
899 " if (n10[2][0] != 100.3)\n"
902 " if (n10[2][1] != 200.3)\n"
905 " if (n10[2][2] != 300.3)\n"
908 " if (n11[0][0] != 1000.1)\n"
911 " if (n11[0][1] != 2000.1)\n"
914 " if (n11[0][2] != 3000.1)\n"
917 " if (n11[1][0] != 1000.2)\n"
920 " if (n11[1][1] != 2000.2)\n"
923 " if (n11[1][2] != 3000.2)\n"
926 " if (n11[2][0] != 1000.3)\n"
929 " if (n11[2][1] != 2000.3)\n"
932 " if (n11[2][2] != 3000.3)\n"
935 #ifdef HAS_FP64_EXTENSION
936 " if (p != 17856.23456LF)\n"
943 #ifdef HAS_FP64_EXTENSION
944 " if (r != dvec2(9567.123LF, 2345.63456LF))\n"
951 " if (t0 != 1.001)\n"
954 " if (v00 != ivec3(1,0,1))\n"
957 " if (v01 != ivec3(2,0,2))\n"
960 " if (v02 != ivec3(3,0,3))\n"
966 " if (t1 != 2.002)\n"
969 " if (v10 != ivec3(4,0,4))\n"
972 " if (v11 != ivec3(5,0,5))\n"
975 " if (v12 != ivec3(6,0,6))\n"
981 " if (t2 != 3.003)\n"
984 " if (v20 != ivec3(7,0,7))\n"
987 " if (v21 != ivec3(8,0,8))\n"
990 " if (v22 != ivec3(9,0,9))\n"
996 " if (t3 != 4.004)\n"
999 " if (v30 != ivec3(1,4,6))\n"
1002 " if (v31 != ivec3(2,5,7))\n"
1005 " if (v32 != ivec3(3,6,8))\n"
1012 " vFragColor = color;\n"