fixed: compile issue
[opensg.git] / Examples / Simple / shaderstoragebufferobject_std140.cpp
blob333706a0ac2abc73e6b54d71d009561d2afc905b
1 // OpenSG Tutorial Example: ShaderStorageBufferObject
2 //
3 // This example shows how to create a shader buffer block and binding it
4 // to a shader storage buffer object.
5 //
6 // The example does use the ShaderStorageBufferObjStdLayoutChunk which
7 // allows the host application to directly provide a buffer to the chunk
8 // according to the std140 or std430 specification. Which specification
9 // is used is determined by the buffer block layout declaration in the
10 // shader code.
12 // This example uses solely the std140 layout.
14 // We create a simple scene geometry consisting of a cylinder and a
15 // torus. The materials for these objects are indexed from a material
16 // database. The indices are part of the material state of the objects.
17 // In particular, the geometry objects do have chunk materials with
18 // exactly one ShaderStorageBufferObjStdLayoutChunk each, which only
19 // contain the index into the material database.
20 // The material database itself is also a ShaderStorageBufferObjStd-
21 // LayoutChunk as well as the active lights of the scene. These are
22 // added globally with the help of a MaterialChunkOverrideGroup for
23 // all geometry of the scene.
25 // Additionally, a ShaderStorageBufferObjStdLayoutChunk is also
26 // added to the MaterialChunkOverrideGroup that does access a shader
27 // storage test block with the same layout as in the OpenGL std140
28 // specification. The shader does check the content of this block.
29 // If the content is invalid the complete fragement color is switched
30 // to plain red, indicating an error.
32 // Remark:
33 // In real life one would probably not use a shader storage buffer
34 // for the geometry material index state. But this example should
35 // only use a couple of shader storage buffers for illustration
36 // purpose.
38 // Shader Storage buffer objects in this example:
39 // test block -> added to the MaterialChunkOverrideGroup
40 // material database -> added to the MaterialChunkOverrideGroup
41 // lights -> added to the MaterialChunkOverrideGroup
42 // geom (indices) states -> added to geometry material
44 // The example is roughly grouped into five parts:
46 // Part I: Declaration of structurs corresponding to buffer blocks in the shader.
47 // Part II: Some helper functions.
48 // Part III: Memory buffer handling and creation routines.
49 // Part IV: The main example application.
50 // Part V: The shader programs.
53 #include <boost/random/mersenne_twister.hpp>
54 #include <boost/random/uniform_int_distribution.hpp>
56 #ifdef OSG_BUILD_ACTIVE
57 // Headers
58 #include <OSGGLUT.h>
59 #include <OSGConfig.h>
60 #include <OSGSimpleGeometry.h>
61 #include <OSGGLUTWindow.h>
62 #include <OSGSimpleSceneManager.h>
63 #include <OSGBaseFunctions.h>
64 #include <OSGTransform.h>
65 #include <OSGGroup.h>
67 // new headers:
68 #include <OSGGLEXT.h>
69 #include <OSGShaderProgramChunk.h>
70 #include <OSGShaderProgram.h>
71 #include <OSGShaderVariableOSG.h>
72 #include <OSGChunkMaterial.h>
73 #include <OSGMaterialGroup.h>
74 #include <OSGMaterialChunkOverrideGroup.h>
75 #include <OSGShaderStorageBufferObjStdLayoutChunk.h>
76 #include <OSGPolygonChunk.h>
77 #include <OSGDepthChunk.h>
78 #include <OSGShaderProgramVariableChunk.h>
80 #else
81 // Headers
82 #include <OpenSG/OSGGLUT.h>
83 #include <OpenSG/OSGConfig.h>
84 #include <OpenSG/OSGSimpleGeometry.h>
85 #include <OpenSG/OSGGLUTWindow.h>
86 #include <OpenSG/OSGSimpleSceneManager.h>
87 #include <OpenSG/OSGBaseFunctions.h>
88 #include <OpenSG/OSGTransform.h>
89 #include <OpenSG/OSGGroup.h>
91 // new headers:
92 #include <OpenSG/OSGGLEXT.h>
93 #include <OpenSG/OSGShaderProgramChunk.h>
94 #include <OpenSG/OSGShaderProgram.h>
95 #include <OpenSG/OSGShaderVariableOSG.h>
96 #include <OpenSG/OSGChunkMaterial.h>
97 #include <OpenSG/OSGMaterialGroup.h>
98 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
99 #include <OpenSG/OSGShaderStorageBufferObjStdLayoutChunk.h>
100 #include <OpenSG/OSGPolygonChunk.h>
101 #include <OpenSG/OSGDepthChunk.h>
102 #include <OpenSG/OSGShaderProgramVariableChunk.h>
103 #endif
106 // The SimpleSceneManager to manage simple applications
108 OSG::SimpleSceneManagerRefPtr mgr;
111 // Part I: Declaration of
112 // struct TestBlock,
113 // struct Light and type VecLightsT,
114 // struct Material and type VecMaterialsT,
115 // struct GeomState
116 // and corresponding initialization routines.
120 // The OpenGL std140 specification test block
121 // Remark: Since OpenSG does not have a Matrix3f or a Matrix2x3f which
122 // are used in the specification, we provide dummy structs for
123 // them.
125 namespace OSG
127 struct Matrix3f
129 Vec3f row1;
130 Vec3f row2;
131 Vec3f row3;
133 Matrix3f(void) :
134 row1(0.f, 0.f, 0.f),
135 row2(0.f, 0.f, 0.f),
136 row3(0.f, 0.f, 0.f)
141 struct Matrix2x3f
143 Vec3f row1;
144 Vec3f row2;
146 Matrix2x3f(void) :
147 row1(0.f, 0.f, 0.f),
148 row2(0.f, 0.f, 0.f)
154 struct S0
156 OSG::Int32 d;
157 OSG::Vec2b e;
159 S0(void) :
160 d(0 ),
161 e(0, 0)
166 struct S1
168 OSG::Vec3u j;
169 OSG::Vec2f k;
170 OSG::Real32 l[2];
171 OSG::Vec2f m;
172 OSG::Matrix3f n[2];
174 S1(void) :
175 j(0, 0, 0),
176 k(0.f, 0.f, 0.f),
177 m(0.f, 0.f)
182 struct TestBlock
184 OSG::Real32 a;
185 OSG::Vec2f b;
186 OSG::Vec3f c;
187 S0 f;
188 OSG::Real32 g;
189 OSG::Real32 h[2];
190 OSG::Matrix2x3f i;
191 S1 o[2];
193 TestBlock(void) :
194 a(0.f),
195 b(0.f, 0.f),
196 c(0.f, 0.f, 0.f),
197 f(),
198 g(0.f),
199 i()
204 TestBlock initialize_test_block()
206 TestBlock test_block;
208 test_block.a = 27.4f;
209 test_block.b = OSG::Vec2f(15.3f, 12.8f);
210 test_block.c = OSG::Vec3f(11.4f, 21.9f, 10.5f);
212 test_block.f.d = 61;
213 test_block.f.e = OSG::Vec2b(true, false);
215 test_block.g = 57.3f;
217 test_block.h[0] = 9.1f;
218 test_block.h[1] = 17.56f;
220 test_block.i.row1 = OSG::Vec3f(19.43f, 1243.2f, 0.56f);
221 test_block.i.row2 = OSG::Vec3f(13.54f, 264.22f, 65.52f);
223 test_block.o[0].j = OSG::Vec3u(10, 11, 12);
224 test_block.o[0].k = OSG::Vec2f(64.62f, 275.21f);
225 test_block.o[0].l[0] = 41.346f;
226 test_block.o[0].l[1] = 67.9456f;
227 test_block.o[0].m = OSG::Vec2f(-56.62f, 768.276f);
228 test_block.o[0].n[0].row1 = OSG::Vec3f(-0.4f,-0.5f,-0.6f);
229 test_block.o[0].n[0].row2 = OSG::Vec3f(-0.7f,-0.8f,-0.9f);
230 test_block.o[0].n[0].row3 = OSG::Vec3f(-0.1f,-0.2f,-0.3f);
231 test_block.o[0].n[1].row1 = OSG::Vec3f( 1.1f, 2.2f, 3.3f);
232 test_block.o[0].n[1].row2 = OSG::Vec3f( 1.2f, 2.3f, 3.4f);
233 test_block.o[0].n[1].row3 = OSG::Vec3f( 1.3f, 2.4f, 3.5f);
235 test_block.o[1].j = OSG::Vec3u(20, 31, 42);
236 test_block.o[1].k = OSG::Vec2f(-96.62f,-658.456f);
237 test_block.o[1].l[0] = 88.34f;
238 test_block.o[1].l[1] = -488.21f;
239 test_block.o[1].m = OSG::Vec2f(777.7f, 888.8f);
240 test_block.o[1].n[0].row1 = OSG::Vec3f( 1.1f, 1.2f, 1.3f);
241 test_block.o[1].n[0].row2 = OSG::Vec3f( 2.1f, 2.2f, 2.3f);
242 test_block.o[1].n[0].row3 = OSG::Vec3f( 3.1f, 3.2f, 3.3f);
243 test_block.o[1].n[1].row1 = OSG::Vec3f(-1.1f,-1.2f,-1.3f);
244 test_block.o[1].n[1].row2 = OSG::Vec3f(-2.1f,-2.2f,-2.3f);
245 test_block.o[1].n[1].row3 = OSG::Vec3f(-3.1f,-3.2f,-3.3f);
247 return test_block;
250 TestBlock global_test_block = initialize_test_block();
253 // simple light data structure
255 struct Light
257 enum Type
259 directional_light = 0,
260 point_light,
261 spot_light,
262 no_light
265 Light()
266 : position(0.f, 0.f, 0.f)
267 , spot_direction(0.f, 1.f, 0.f)
268 , Ia(1.f, 1.f, 1.f)
269 , Id(1.f, 1.f, 1.f)
270 , Is(1.f, 1.f, 1.f)
271 , attenuation(1.f, 0.f, 0.f)
272 , spot_cos_cutoff(cosf(45.f))
273 , spot_exponent(1.f)
274 , type(no_light)
277 static Light create_light(Type e)
279 Light l;
280 l.type = e;
282 switch (e) {
283 case directional_light: l.spot_direction = OSG::Vec3f(1.f, 0.f, 0.f);
284 break;
285 case point_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f);
286 break;
287 case spot_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f); l.spot_direction = OSG::Pnt3f(0.f, 0.f, 0.f) - l.position;
288 break;
289 default:
290 break;
292 return l;
295 OSG::Pnt3f position; // in object space
296 OSG::Vec3f spot_direction; // in object space, also used for dir of directional lights (see shader code)
297 OSG::Color3f Ia; // ambient max. Intensity
298 OSG::Color3f Id; // diffuse max. Intensity
299 OSG::Color3f Is; // specular max. Intensity
301 OSG::Vec3f attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
302 OSG::Real32 spot_cos_cutoff; // cosine cut of angle
303 OSG::Real32 spot_exponent; // [0-128]
304 OSG::Int32 type; // directional_light, point_light, spot_light, no_light
307 typedef std::vector<Light> VecLightsT; // multiple lights
309 const std::size_t num_lights = 1; // simple example with just one light
311 VecLightsT initialize_lights() // helper to create lights
313 VecLightsT lights;
315 lights.push_back(Light::create_light(Light::directional_light));
317 assert(lights.size() == num_lights);
319 return lights;
322 VecLightsT lights = initialize_lights(); // the lights
326 // Simple material data structure
328 struct Material
330 Material()
331 : ambient (0.f, 0.f, 0.f)
332 , diffuse (0.f, 0.f, 0.f)
333 , specular(0.f, 0.f, 0.f)
334 , emissive(0.f, 0.f, 0.f)
335 , opacity(1.f)
336 , shininess(100.f)
339 OSG::Color3f ambient;
340 OSG::Color3f diffuse;
341 OSG::Color3f specular;
342 OSG::Color3f emissive;
344 OSG::Real32 opacity;
345 OSG::Real32 shininess;
348 typedef std::vector<Material> VecMaterialsT; // multiple materials
350 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
352 VecMaterialsT materials;
354 for (std::size_t i = 0; i < num; ++i)
356 Material m;
358 m.ambient = OSG::Color3f(0.1f, 0.1f, 0.1f);
359 m.diffuse.setRandom();
360 m.specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
361 m.emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
362 m.opacity = 1.f;
363 m.shininess = 80.f;
365 materials.push_back(m);
368 return materials;
371 const std::size_t num_materials = 500; // any number of materials
372 VecMaterialsT materials = initialize_materials(num_materials); // the material database
376 // Simple geometry state data structure
378 struct GeomState
380 GeomState()
381 : material_index(0)
384 OSG::UInt32 material_index;
389 // Part II: Some helper functions:
390 // Pnt3f transform_to_eye_space(const Pnt3f& p, SimpleSceneManager* pSSM)
391 // Vec3f transform_to_eye_space(const Vec3f& v, SimpleSceneManager* pSSM)
392 // size_t align_offset (size_t base_alignment, size_t base_offset)
396 // transform point from world space to eye space
398 OSG::Pnt3f transform_to_eye_space(const OSG::Pnt3f& p, OSG::SimpleSceneManager* pSSM)
400 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
401 return p;
403 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
405 OSG::Pnt3f p_es;
407 OSG::Matrix view;
408 OSG::Int16 width = pPort->calcPixelWidth();
409 OSG::Int16 height = pPort->calcPixelHeight();
411 pPort->getCamera()->getViewing(view, width, height);
413 view.multFull( p, p_es);
415 return p_es;
419 // transform vector from world space to eye space
421 OSG::Vec3f transform_to_eye_space(const OSG::Vec3f& v, OSG::SimpleSceneManager* pSSM)
423 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
424 return v;
426 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
428 OSG::Vec3f v_es;
430 OSG::Matrix view;
431 OSG::Int16 width = pPort->calcPixelWidth();
432 OSG::Int16 height = pPort->calcPixelHeight();
434 pPort->getCamera()->getViewing(view, width, height);
436 view.multFull( v, v_es);
438 return v_es;
442 // helper to calculate the correct buffer insert positions on std140 or std430
444 std::size_t align_offset(std::size_t base_alignment, std::size_t base_offset)
446 return base_alignment * ((base_alignment + base_offset - 1) / base_alignment);
451 // Part III: Some routines for handling of the memory buffer and the the creation of
452 // the ShaderStorageBufferObjStdLayoutChunk objects:
454 // i) calc_test_block_buffer_size,
455 // create_test_block_buffer,
456 // create_test_block_state,
457 // update_test_block_state
459 // ii) calc_light_buffer_size,
460 // create_light_buffer,
461 // create_light_state,
462 // update_light_state
464 // iii) calc_material_database_buffer_size,
465 // create_material_database_buffer,
466 // create_material_database_state,
467 // update_material_database_state
469 // iv) calc_geometry_material_buffer_size,
470 // create_geometry_material_buffer,
471 // create_geometry_material_state,
472 // update_geometry_material_state
476 // i) the test block shader storage buffer object
478 std::size_t calc_test_block_buffer_size(const TestBlock& test_block)
481 // Introduction to the std140 storage layout
482 // =========================================
484 // When using the "std140" storage layout, structures will be laid out in
485 // buffer storage with its members stored in monotonically increasing order
486 // based on their location in the declaration. A structure and each
487 // structure member have a base offset and a base alignment, from which an
488 // aligned offset is computed by rounding the base offset up to a multiple of
489 // the base alignment. The base offset of the first member of a structure is
490 // taken from the aligned offset of the structure itself. The base offset of
491 // all other structure members is derived by taking the offset of the last
492 // basic machine unit consumed by the previous member and adding one. Each
493 // structure member is stored in memory at its aligned offset. The members
494 // of a top-level shader storage block are laid out in buffer storage by treating
495 // the shader storage block as a structure with a base offset of zero.
497 // (1) If the member is a scalar consuming <N> basic machine units, the
498 // base alignment is <N>.
500 // (2) If the member is a two- or four-component vector with components
501 // consuming <N> basic machine units, the base alignment is 2<N> or
502 // 4<N>, respectively.
504 // (3) If the member is a three-component vector with components consuming
505 // <N> basic machine units, the base alignment is 4<N>.
507 // (4) If the member is an array of scalars or vectors, the base alignment
508 // and array stride are set to match the base alignment of a single
509 // array element, according to rules (1), (2), and (3), and rounded up
510 // to the base alignment of a vec4. The array may have padding at the
511 // end; the base offset of the member following the array is rounded up
512 // to the next multiple of the base alignment.
514 // (5) If the member is a column-major matrix with <C> columns and <R>
515 // rows, the matrix is stored identically to an array of <C> column
516 // vectors with <R> components each, according to rule (4).
518 // (6) If the member is an array of <S> column-major matrices with <C>
519 // columns and <R> rows, the matrix is stored identically to a row of
520 // <S>*<C> column vectors with <R> components each, according to rule
521 // (4).
523 // (7) If the member is a row-major matrix with <C> columns and <R> rows,
524 // the matrix is stored identically to an array of <R> row vectors
525 // with <C> components each, according to rule (4).
527 // (8) If the member is an array of <S> row-major matrices with <C> columns
528 // and <R> rows, the matrix is stored identically to a row of <S>*<R>
529 // row vectors with <C> components each, according to rule (4).
531 // (9) If the member is a structure, the base alignment of the structure is
532 // <N>, where <N> is the largest base alignment value of any of its
533 // members, and rounded up to the base alignment of a vec4. The
534 // individual members of this sub-structure are then assigned offsets
535 // by applying this set of rules recursively, where the base offset of
536 // the first member of the sub-structure is equal to the aligned offset
537 // of the structure. The structure may have padding at the end; the
538 // base offset of the member following the sub-structure is rounded up
539 // to the next multiple of the base alignment of the structure.
541 // (10) If the member is an array of <S> structures, the <S> elements of
542 // the array are laid out in order, according to rule (9).
544 // For shader storage blocks laid out according to these rules, the minimum buffer
545 // object size returned by the GL_BUFFER_DATA_SIZE query is derived by
546 // taking the offset of the last basic machine unit consumed by the last
547 // entry of the shader storage block (including any end-of-array or
548 // end-of-structure padding), adding one, and rounding up to the next
549 // multiple of the base alignment required for a vec4.
551 // Using Standard Layout Qualifiers
552 // ================================
553 // When you group a number of variables in a uniform buffer or shader
554 // storage buffer, and want to read or write their values outside a shader, you
555 // need to know the offset of each one. You can query these offsets, but for
556 // large collections of uniforms this process requires many queries and is
557 // cumbersome. As an alternative, the standard layout qualifiers request that
558 // the GLSL shader compiler organize the variables according to a set of rules,
559 // where you can predictably compute the offset of any member in the block.
560 // In order to qualify a block to use the std140 layout, you need to add a
561 // layout directive to its declaration, as demonstrated below:
563 // layout (std140) buffer UniformBlock {
564 // // declared variables
565 // };
567 // This std140 qualification also works for shader storage buffer objects.
569 // To use these, the offset of a member in the block is the accumulated total
570 // of the alignment and sizes of the previous members in the block (those
571 // declared before the variable in question), bumped up to the alignment of
572 // the member. The starting offset of the first member is always zero.
574 // The std140 Layout Rules
575 // =======================
576 // The set of rules shown in the table are used by the GLSL compiler to place
577 // members in an std140-qualified uniform block. This feature is available
578 // only with GLSL Version 1.40 or greater.
580 // Variable Type Variable Size and Alignment
581 // --------------------------------------------------------------------------------
582 // Scalar bool, int, uint, float and Both the size and alignment are the size
583 // double of the scalar in basic machine types
584 // (e.g., sizeof(GLfloat)).
586 // Two-component vectors (e.g., ivec2) Both the size and alignment are twice
587 // the size of the underlying scalar type.
589 // Three-component vectors (e.g., vec3) Both the size and alignment are four
590 // and times the size of the underlying scalar
591 // Four-component vectors (e.g., vec4) type.
593 // An array of scalars or vectors The size of each element in the array
594 // will be the size of the element type,
595 // rounded up to a multiple of the size of a
596 // vec4. This is also the array’s alignment.
597 // The array’s size will be this rounded-up
598 // element’s size times the number of
599 // elements in the array.
601 // A column-major matrix or an array Same layout as an array of N vectors
602 // of column-major matrices of size C each with R components, where N is
603 // columns and R rows the total number of columns present.
605 // A row-major matrix or an array of Same layout as an array of N vectors
606 // row-major matrices with R rows and C each with C components, where N is
607 // columns the total number of rows present.
609 // A single-structure definition, Structure alignment will be
610 // or an array of structures the alignment for the biggest structure
611 // member, according to the previous
612 // rules, rounded up to a multiple of the
613 // size of a vec4. Each structure will start
614 // on this alignment, and its size will be the
615 // space needed by its members, according
616 // to the previous rules, rounded up to
617 // a multiple of the structure alignment.
620 std::size_t ao = 0; // aligned offset
621 std::size_t bo = 0; // base offset
622 // layout(std140) uniform Example
623 // {
624 // // Base types below consume 4 basic machine units
625 // //
626 // // base base align
627 // // rule align off. off. bytes used
628 // // ---- ------ ---- ---- -----------------------
629 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // Real32 a; // 1 4 0 0 0..3
630 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // Vec2f b; // 2 8 4 8 8..15
631 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // Vec3f c; // 3 16 16 16 16..27
632 ao = align_offset(16, bo); bo = ao; // struct { // 9 16 28 32 (align begin)
633 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Int32); // Int32 d; // 1 4 32 32 32..35
634 ao = align_offset( 8, bo); bo = ao + 2*sizeof(OSG::Int32); // Vec2b e; // 2 8 36 40 40..47
635 ao = align_offset(16, bo); bo = ao; // } f; // 9 16 48 48 (pad end)
636 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // Real32 g; // 1 4 48 48 48..51
637 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Real32); // Real32 h[2]; // 4 16 52 64 64..67 (h[0])
638 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Real32); // // 16 68 80 80..83 (h[1])
639 ao = align_offset(16, bo); bo = ao; // // 4 16 84 96 (pad end of h)
640 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // Matrix2x3f i; // 5/4 16 96 96 96..107 (i, column 0)
641 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 108 112 112..123 (i, column 1)
642 ao = align_offset(16, bo); bo = ao; // // 5/4 16 124 128 (pad end of i)
643 ao = align_offset(16, bo); bo = ao; // struct { // 10 16 128 128 (align begin)
644 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3u); // Vec3u j; // 3 16 128 128 128..139 (o[0].j)
645 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // Vec2f k; // 2 8 140 144 144..151 (o[0].k)
646 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Real32); // Real32 l[2]; // 4 16 152 160 160..163 (o[0].l[0])
647 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Real32); // // 16 164 176 176..179 (o[0].l[1])
648 ao = align_offset(16, bo); bo = ao; // // 4 16 180 192 (pad end of o[0].l)
649 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // Vec2f m; // 2 8 192 192 192..199 (o[0].m)
650 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // Matrix3f n[2]; // 6/4 16 200 208 208..219 (o[0].n[0], column 0)
651 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 220 224 224..235 (o[0].n[0], column 1)
652 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 236 240 240..251 (o[0].n[0], column 2)
653 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 252 256 256..267 (o[0].n[1], column 0)
654 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 268 272 272..283 (o[0].n[1], column 1)
655 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 284 288 288..299 (o[0].n[1], column 2)
656 ao = align_offset(16, bo); bo = ao; // // 6/4 16 300 304 (pad end of o[0].n)
657 ao = align_offset(16, bo); bo = ao; // // 9 16 304 304 (pad end of o[0])
658 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3u); // // 3 16 304 304 304..315 (o[1].j)
659 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // // 2 8 316 320 320..327 (o[1].k)
660 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Real32); // // 4 16 328 336 336..339 (o[1].l[0])
661 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Real32); // // 16 340 352 352..355 (o[1].l[1])
662 ao = align_offset(16, bo); bo = ao; // // 4 16 356 368 (pad end of o[1].l)
663 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // // 2 8 368 368 368..375 (o[1].m)
664 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 6/4 16 376 384 384..395 (o[1].n[0], column 0)
665 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 396 400 400..411 (o[1].n[0], column 1)
666 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 412 416 416..427 (o[1].n[0], column 2)
667 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 428 432 432..443 (o[1].n[1], column 0)
668 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 444 448 448..459 (o[1].n[1], column 1)
669 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 460 464 464..475 (o[1].n[1], column 2)
670 ao = align_offset(16, bo); bo = ao; // // 6/4 16 476 480 (pad end of o[1].n)
671 ao = align_offset(16, bo); bo = ao; // // 9 16 480 480 (pad end of o[1])
672 // } o[2];
673 // };
674 return ao;
677 std::vector<OSG::UInt8> create_test_block_buffer(const TestBlock& test_block)
679 std::size_t size = calc_test_block_buffer_size(test_block);
681 std::vector<OSG::UInt8> buffer(size);
683 std::size_t ao = 0; // aligned offset
684 std::size_t bo = 0; // base offset
686 ao = align_offset( 4, bo);
687 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.a;
688 bo = ao + sizeof(OSG::Real32);
690 ao = align_offset( 8, bo);
691 memcpy(&buffer[0] + ao, &test_block.b[0], sizeof(OSG::Vec2f));
692 bo = ao + sizeof(OSG::Vec2f);
694 ao = align_offset(16, bo);
695 memcpy(&buffer[0] + ao, &test_block.c[0], sizeof(OSG::Vec3f));
696 bo = ao + sizeof(OSG::Vec3f);
698 ao = align_offset(16, bo);
699 bo = ao;
701 ao = align_offset( 4, bo);
702 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = test_block.f.d;
703 bo = ao + sizeof(OSG::Int32);
705 ao = align_offset( 8, bo);
706 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = test_block.f.e[0];
707 bo = ao + sizeof(OSG::Int32);
708 ao = bo;
709 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = test_block.f.e[1];
710 bo = ao + sizeof(OSG::Int32);
712 ao = align_offset(16, bo);
713 bo = ao;
715 ao = align_offset( 4, bo);
716 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.g;
717 bo = ao + sizeof(OSG::Real32);
719 ao = align_offset(16, bo);
720 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.h[0];
721 bo = ao + sizeof(OSG::Real32);
723 ao = align_offset(16, bo);
724 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.h[1];
725 bo = ao + sizeof(OSG::Real32);
727 ao = align_offset(16, bo);
728 bo = ao;
730 ao = align_offset(16, bo);
731 memcpy(&buffer[0] + ao, &test_block.i.row1[0], sizeof(OSG::Vec3f));
732 bo = ao + sizeof(OSG::Vec3f);
734 ao = align_offset(16, bo);
735 memcpy(&buffer[0] + ao, &test_block.i.row2[0], sizeof(OSG::Vec3f));
736 bo = ao + sizeof(OSG::Vec3f);
738 ao = align_offset(16, bo);
739 bo = ao;
741 ao = align_offset(16, bo);
742 bo = ao;
744 ao = align_offset(16, bo);
745 memcpy(&buffer[0] + ao, &test_block.o[0].j[0], sizeof(OSG::Vec3u));
746 bo = ao + sizeof(OSG::Vec3u);
748 ao = align_offset( 8, bo);
749 memcpy(&buffer[0] + ao, &test_block.o[0].k[0], sizeof(OSG::Vec2f));
750 bo = ao + sizeof(OSG::Vec2f);
752 ao = align_offset(16, bo);
753 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[0].l[0];
754 bo = ao + sizeof(OSG::Real32);
756 ao = align_offset(16, bo);
757 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[0].l[1];
758 bo = ao + sizeof(OSG::Real32);
760 ao = align_offset(16, bo);
761 bo = ao;
763 ao = align_offset( 8, bo);
764 memcpy(&buffer[0] + ao, &test_block.o[0].m[0], sizeof(OSG::Vec2f));
765 bo = ao + sizeof(OSG::Vec2f);
767 ao = align_offset(16, bo);
768 memcpy(&buffer[0] + ao, &test_block.o[0].n[0].row1[0], sizeof(OSG::Vec3f));
769 bo = ao + sizeof(OSG::Vec3f);
771 ao = align_offset(16, bo);
772 memcpy(&buffer[0] + ao, &test_block.o[0].n[0].row2[0], sizeof(OSG::Vec3f));
773 bo = ao + sizeof(OSG::Vec3f);
775 ao = align_offset(16, bo);
776 memcpy(&buffer[0] + ao, &test_block.o[0].n[0].row3[0], sizeof(OSG::Vec3f));
777 bo = ao + sizeof(OSG::Vec3f);
779 ao = align_offset(16, bo);
780 memcpy(&buffer[0] + ao, &test_block.o[0].n[1].row1[0], sizeof(OSG::Vec3f));
781 bo = ao + sizeof(OSG::Vec3f);
783 ao = align_offset(16, bo);
784 memcpy(&buffer[0] + ao, &test_block.o[0].n[1].row2[0], sizeof(OSG::Vec3f));
785 bo = ao + sizeof(OSG::Vec3f);
787 ao = align_offset(16, bo);
788 memcpy(&buffer[0] + ao, &test_block.o[0].n[1].row3[0], sizeof(OSG::Vec3f));
789 bo = ao + sizeof(OSG::Vec3f);
791 ao = align_offset(16, bo);
792 bo = ao;
794 ao = align_offset(16, bo);
795 bo = ao;
797 ao = align_offset(16, bo);
798 memcpy(&buffer[0] + ao, &test_block.o[1].j[0], sizeof(OSG::Vec3u));
799 bo = ao + sizeof(OSG::Vec3u);
801 ao = align_offset( 8, bo);
802 memcpy(&buffer[0] + ao, &test_block.o[1].k[0], sizeof(OSG::Vec2f));
803 bo = ao + sizeof(OSG::Vec2f);
805 ao = align_offset(16, bo);
806 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[1].l[0];
807 bo = ao + sizeof(OSG::Real32);
809 ao = align_offset(16, bo);
810 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[1].l[1];
811 bo = ao + sizeof(OSG::Real32);
813 ao = align_offset(16, bo);
814 bo = ao;
816 ao = align_offset( 8, bo);
817 memcpy(&buffer[0] + ao, &test_block.o[1].m[0], sizeof(OSG::Vec2f));
818 bo = ao + sizeof(OSG::Vec2f);
820 ao = align_offset(16, bo);
821 memcpy(&buffer[0] + ao, &test_block.o[1].n[0].row1[0], sizeof(OSG::Vec3f));
822 bo = ao + sizeof(OSG::Vec3f);
824 ao = align_offset(16, bo);
825 memcpy(&buffer[0] + ao, &test_block.o[1].n[0].row2[0], sizeof(OSG::Vec3f));
826 bo = ao + sizeof(OSG::Vec3f);
828 ao = align_offset(16, bo);
829 memcpy(&buffer[0] + ao, &test_block.o[1].n[0].row3[0], sizeof(OSG::Vec3f));
830 bo = ao + sizeof(OSG::Vec3f);
832 ao = align_offset(16, bo);
833 memcpy(&buffer[0] + ao, &test_block.o[1].n[1].row1[0], sizeof(OSG::Vec3f));
834 bo = ao + sizeof(OSG::Vec3f);
836 ao = align_offset(16, bo);
837 memcpy(&buffer[0] + ao, &test_block.o[1].n[1].row2[0], sizeof(OSG::Vec3f));
838 bo = ao + sizeof(OSG::Vec3f);
840 ao = align_offset(16, bo);
841 memcpy(&buffer[0] + ao, &test_block.o[1].n[1].row3[0], sizeof(OSG::Vec3f));
842 bo = ao + sizeof(OSG::Vec3f);
844 ao = align_offset(16, bo);
845 bo = ao;
847 ao = align_offset(16, bo);
848 bo = ao;
850 return buffer;
853 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_test_block_state(const TestBlock& test_block)
855 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
857 std::vector<OSG::UInt8> buffer = create_test_block_buffer(test_block);
859 ssbo->editMFBuffer()->setValues(buffer);
860 ssbo->setUsage(GL_DYNAMIC_DRAW);
862 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
865 void update_test_block_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const TestBlock& test_block)
867 if (ssbo) {
868 std::vector<OSG::UInt8> buffer = create_test_block_buffer(test_block);
869 ssbo->editMFBuffer()->setValues(buffer);
874 // ii) the light shader storage buffer object
876 std::size_t calc_light_buffer_size(const VecLightsT& vLights)
878 std::size_t ao = 0; // aligned offset
879 std::size_t bo = 0; // base offset
881 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Pnt4f); // OSG::Pnt3f position;
882 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f spot_direction;
883 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Ia;
884 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Id;
885 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Is;
886 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f attenuation;
887 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_cos_cutoff;
888 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_exponent;
889 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Int32); // OSG::Int32 type;
890 ao = align_offset( 16, bo); bo = ao; // padding
892 ao *= vLights.size(); bo = ao; // array
893 ao = align_offset( 16, bo); bo = ao; // padding
895 return ao;
898 std::vector<OSG::UInt8> create_light_buffer(const VecLightsT& vLights)
900 std::size_t size = calc_light_buffer_size(vLights);
902 std::vector<OSG::UInt8> buffer(size);
904 std::size_t ao = 0; // aligned offset
905 std::size_t bo = 0; // base offset
907 for (std::size_t i = 0; i < vLights.size(); ++i)
909 OSG::Pnt3f position_es = transform_to_eye_space(vLights[i].position, mgr);
910 OSG::Vec3f spot_direction_es = transform_to_eye_space(vLights[i].spot_direction, mgr);
912 ao = align_offset(16, bo);
913 memcpy(&buffer[0] + ao, &position_es[0], sizeof(OSG::Pnt3f));
914 bo = ao + sizeof(OSG::Pnt4f);
916 ao = align_offset(16, bo);
917 memcpy(&buffer[0] + ao, &spot_direction_es[0], sizeof(OSG::Vec3f));
918 bo = ao + sizeof(OSG::Vec4f);
920 ao = align_offset(16, bo);
921 memcpy(&buffer[0] + ao, &vLights[i].Ia[0], sizeof(OSG::Color3f));
922 bo = ao + sizeof(OSG::Color4f);
924 ao = align_offset(16, bo);
925 memcpy(&buffer[0] + ao, &vLights[i].Id[0], sizeof(OSG::Color3f));
926 bo = ao + sizeof(OSG::Color4f);
928 ao = align_offset(16, bo);
929 memcpy(&buffer[0] + ao, &vLights[i].Is[0], sizeof(OSG::Color3f));
930 bo = ao + sizeof(OSG::Color4f);
932 ao = align_offset(16, bo);
933 memcpy(&buffer[0] + ao, &vLights[i].attenuation[0], sizeof(OSG::Vec3f));
934 bo = ao + sizeof(OSG::Vec4f);
936 ao = align_offset( 4, bo);
937 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_cos_cutoff;
938 bo = ao + sizeof(OSG::Real32);
940 ao = align_offset( 4, bo);
941 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_exponent;
942 bo = ao + sizeof(OSG::Real32);
944 ao = align_offset( 4, bo);
945 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = vLights[i].type;
946 bo = ao + sizeof(OSG::Int32);
948 ao = align_offset( 16, bo); bo = ao; // padding
951 return buffer;
954 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_light_state(const VecLightsT& vLights)
956 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
958 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
960 ssbo->editMFBuffer()->setValues(buffer);
961 ssbo->setUsage(GL_DYNAMIC_DRAW);
963 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
966 void update_light_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const VecLightsT& vLights)
968 if (ssbo) {
969 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
970 ssbo->editMFBuffer()->setValues(buffer);
975 // iii) the material shader storage buffer object
977 std::size_t calc_material_database_buffer_size(const VecMaterialsT& vMaterials)
979 std::size_t ao = 0; // aligned offset
980 std::size_t bo = 0; // base offset
982 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f ambient;
983 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f diffuse;
984 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f specular;
985 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f emissive;
986 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 opacity;
987 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 shininess;
988 ao = align_offset( 16, bo); bo = ao; // padding
990 ao *= vMaterials.size(); bo = ao; // array
991 ao = align_offset( 16, bo); bo = ao; // padding
993 return ao;
996 std::vector<OSG::UInt8> create_material_database_buffer(const VecMaterialsT& vMaterials)
998 std::size_t size = calc_material_database_buffer_size(vMaterials);
1000 std::vector<OSG::UInt8> buffer(size);
1002 std::size_t ao = 0; // aligned offset
1003 std::size_t bo = 0; // base offset
1005 for (std::size_t i = 0; i < vMaterials.size(); ++i)
1007 ao = align_offset(16, bo);
1008 memcpy(&buffer[0] + ao, &vMaterials[i].ambient[0], sizeof(OSG::Color3f));
1009 bo = ao + sizeof(OSG::Color4f);
1011 ao = align_offset(16, bo);
1012 memcpy(&buffer[0] + ao, &vMaterials[i].diffuse[0], sizeof(OSG::Color3f));
1013 bo = ao + sizeof(OSG::Color4f);
1015 ao = align_offset(16, bo);
1016 memcpy(&buffer[0] + ao, &vMaterials[i].specular[0], sizeof(OSG::Color3f));
1017 bo = ao + sizeof(OSG::Color4f);
1019 ao = align_offset(16, bo);
1020 memcpy(&buffer[0] + ao, &vMaterials[i].emissive[0], sizeof(OSG::Color3f));
1021 bo = ao + sizeof(OSG::Color4f);
1023 ao = align_offset( 4, bo);
1024 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].opacity;
1025 bo = ao + sizeof(OSG::Real32);
1027 ao = align_offset( 4, bo);
1028 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].shininess;
1029 bo = ao + sizeof(OSG::Real32);
1031 ao = align_offset( 16, bo); bo = ao; // padding
1034 return buffer;
1037 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
1039 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1041 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
1043 ssbo->editMFBuffer()->setValues(buffer);
1044 ssbo->setUsage(GL_STATIC_DRAW);
1046 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
1049 void update_material_database_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const VecMaterialsT& vMaterials)
1051 if (ssbo) {
1052 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
1053 ssbo->editMFBuffer()->setValues(buffer);
1058 // iv) the geomertry shader storage buffer object
1060 std::size_t calc_geometry_material_buffer_size()
1062 std::size_t ao = 0; // aligned offset
1063 std::size_t bo = 0; // base offset
1065 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::UInt32); // OSG::UInt32 material_index;
1066 ao = align_offset( 16, bo); bo = ao; // padding
1068 return ao;
1071 std::vector<OSG::UInt8> create_geometry_material_buffer(const GeomState& geom_state)
1073 std::size_t size = calc_geometry_material_buffer_size();
1075 std::vector<OSG::UInt8> buffer(size);
1077 std::size_t ao = 0; // aligned offset
1078 std::size_t bo = 0; // base offset
1080 ao = align_offset( 4, bo);
1081 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = geom_state.material_index;
1082 bo = ao + sizeof(OSG::UInt32);
1084 return buffer;
1087 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
1089 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1091 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
1093 ssbo->editMFBuffer()->setValues(buffer);
1094 ssbo->setUsage(GL_DYNAMIC_DRAW);
1096 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
1099 void update_geometry_material_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const GeomState& geom_state)
1101 if (ssbo) {
1102 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
1103 ssbo->editMFBuffer()->setValues(buffer);
1108 // Part IV: The application starts here
1112 // vertex shader program.
1114 std::string get_vp_program();
1117 // fragment shader program for bump mapping in surface local coordinates
1119 std::string get_fp_program();
1122 // random number generator
1124 boost::random::mt19937 generator;
1125 boost::random::uniform_int_distribution<> dist(0, num_materials-1);
1128 // a separate transformation for every object
1130 OSG::TransformRefPtr cyltrans, tortrans;
1133 // Shader Storage buffer objects corresponding to transient shader blocks
1135 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_light_state = NULL;
1136 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_1 = NULL;
1137 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_2 = NULL;
1140 // forward declaration so we can have the interesting stuff upfront
1142 int setupGLUT(int *argc, char *argv[]);
1145 // redraw the window
1147 void display(void)
1149 // light spot direction and light position must be provided in eye space
1150 update_light_state(ssbo_light_state, lights);
1152 // create the matrix
1153 OSG::Matrix m;
1154 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME );
1156 // set the transforms' matrices
1157 m.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t / 1000.f) * 1.5),
1158 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t / 500.f));
1160 cyltrans->setMatrix(m);
1162 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 1000.f), 0, 0),
1163 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t / 1000.f));
1165 tortrans->setMatrix(m);
1167 OSG::commitChanges();
1169 mgr->redraw();
1173 // Initialize GLUT & OpenSG and set up the scene
1175 int main(int argc, char **argv)
1177 // OSG init
1178 OSG::osgInit(argc,argv);
1180 // GLUT init
1181 int winid = setupGLUT(&argc, argv);
1183 // open a new scope, because the pointers below should go out of scope
1184 // before entering glutMainLoop.
1185 // Otherwise OpenSG will complain about objects being alive after shutdown.
1187 // the connection between GLUT and OpenSG
1188 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
1189 gwin->setGlutId(winid);
1190 gwin->init();
1192 // create the SimpleSceneManager helper
1193 mgr = OSG::SimpleSceneManager::create();
1194 mgr->setWindow(gwin);
1196 // create a pretty simple graph: a Group with two Transforms as children,
1197 // each of which carries a single Geometry.
1199 // The scene
1201 OSG::NodeRefPtr scene = OSG::Node::create();
1203 // The cylinder and its transformation
1204 OSG::NodeRefPtr cyl = OSG::Node::create();
1205 OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24,
1206 true, true, true );
1208 cyl->setCore(cylgeo);
1210 cyltrans = OSG::Transform::create();
1212 OSG::NodeRefPtr cyltransnode = OSG::Node::create();
1213 cyltransnode->setCore (cyltrans);
1214 cyltransnode->addChild(cyl );
1216 // add it to the scene
1217 scene->addChild(cyltransnode);
1219 // The torus and its transformation
1220 OSG::NodeRefPtr torus = OSG::Node::create();
1221 OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
1223 torus->setCore(torusgeo);
1225 tortrans = OSG::Transform::create();
1227 OSG::NodeRefPtr tortransnode = OSG::Node::create();
1228 tortransnode->setCore (tortrans);
1229 tortransnode->addChild(torus );
1231 // add it to the scene
1232 scene->addChild(tortransnode);
1235 // create the shader program
1237 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
1238 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
1239 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
1241 vertShader->setProgram(get_vp_program());
1242 fragShader->setProgram(get_fp_program());
1245 // binding the shader storage block to a buffer binding point can be performed
1246 // either by calling the shaders's addShaderStorageBlock method or by
1247 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1248 // In the following we use both variants for illustration.
1250 fragShader->addShaderStorageBlock("Materials", 1); // block binding point
1251 fragShader->addShaderStorageBlock("Lights", 2); // block binding point
1254 // The following is replaced by adding ShaderProgramVariableChunk objects
1255 // to the chunk material. See below...
1257 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
1259 fragShader->addShaderStorageBlock("TestBlock", 4); // block binding point
1261 prog_chunk->addShader(vertShader);
1262 prog_chunk->addShader(fragShader);
1265 // create shader storage buffer objects and corresponding materials
1267 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_material_database = create_material_database_state(materials);
1268 ssbo_light_state = create_light_state(lights);
1270 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_test_block = create_test_block_state(global_test_block);
1272 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
1273 polygon_chunk->setFrontMode(GL_FILL);
1274 polygon_chunk->setBackMode(GL_FILL);
1275 polygon_chunk->setCullFace(GL_NONE);
1277 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
1278 depth_chunk->setEnable(true);
1280 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
1281 prog_state->addChunk(ssbo_material_database, 1); // buffer binding point 1
1282 prog_state->addChunk(ssbo_light_state, 2); // buffer binding point 2
1283 prog_state->addChunk(ssbo_test_block, 4); // buffer binding point 4
1284 prog_state->addChunk(prog_chunk);
1285 prog_state->addChunk(polygon_chunk);
1286 prog_state->addChunk(depth_chunk);
1288 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
1289 shader_var_chunk->addShaderStorageBlock("GeomState", 3);
1291 GeomState geom1; geom1.material_index = dist(generator);
1292 OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
1293 ssbo_geom_state_1 = create_geometry_material_state(geom1);
1294 geom1_state->addChunk(ssbo_geom_state_1, 3); // buffer binding point 3
1295 geom1_state->addChunk(shader_var_chunk); // block binding point
1297 GeomState geom2; geom2.material_index = dist(generator);
1298 OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
1299 ssbo_geom_state_2 = create_geometry_material_state(geom2);
1300 geom2_state->addChunk(ssbo_geom_state_2, 3); // buffer binding point 3
1301 geom2_state->addChunk(shader_var_chunk); // block binding point
1303 cylgeo ->setMaterial(geom1_state);
1304 torusgeo->setMaterial(geom2_state);
1306 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
1307 mgrp->setMaterial(prog_state);
1308 scene->setCore(mgrp);
1310 OSG::commitChanges();
1312 mgr->setRoot(scene);
1314 // show the whole scene
1315 mgr->showAll();
1318 // GLUT main loop
1319 glutMainLoop();
1321 return 0;
1325 // GLUT callback functions
1329 // react to size changes
1331 void reshape(int w, int h)
1333 mgr->resize(w, h);
1334 glutPostRedisplay();
1338 // react to mouse button presses
1340 void mouse(int button, int state, int x, int y)
1342 if (state)
1343 mgr->mouseButtonRelease(button, x, y);
1344 else
1345 mgr->mouseButtonPress(button, x, y);
1347 glutPostRedisplay();
1351 // react to mouse motions with pressed buttons
1353 void motion(int x, int y)
1355 mgr->mouseMove(x, y);
1356 glutPostRedisplay();
1360 // react to keys
1362 void keyboard(unsigned char k, int x, int y)
1364 switch(k)
1366 case 27:
1368 // clean up global variables
1369 cyltrans = NULL;
1370 tortrans = NULL;
1371 mgr = NULL;
1373 ssbo_light_state = NULL;
1374 ssbo_geom_state_1 = NULL;
1375 ssbo_geom_state_2 = NULL;
1377 OSG::osgExit();
1378 exit(0);
1380 break;
1382 case 'm':
1384 GeomState geom1; geom1.material_index = dist(generator);
1385 GeomState geom2; geom2.material_index = dist(generator);
1387 update_geometry_material_state(ssbo_geom_state_1, geom1);
1388 update_geometry_material_state(ssbo_geom_state_2, geom2);
1390 glutPostRedisplay();
1392 break;
1394 case 's':
1396 mgr->setStatistics(!mgr->getStatistics());
1398 break;
1403 // setup the GLUT library which handles the windows for us
1405 int setupGLUT(int *argc, char *argv[])
1407 glutInit(argc, argv);
1408 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
1410 int winid = glutCreateWindow("OpenSG");
1412 glutReshapeFunc(reshape);
1413 glutDisplayFunc(display);
1414 glutMouseFunc(mouse);
1415 glutMotionFunc(motion);
1416 glutKeyboardFunc(keyboard);
1418 // call the redraw function whenever there's nothing else to do
1419 glutIdleFunc(display);
1421 return winid;
1425 // Part V: The shader programs
1429 // vertex shader program.
1431 std::string get_vp_program()
1433 std::string vp_program =
1434 "\n"
1435 "#version 440 compatibility\n"
1436 "\n"
1437 "#extension GL_ARB_separate_shader_objects: enable\n"
1438 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1439 "\n"
1440 "smooth out vec3 vNormalES; // eye space normal\n"
1441 "smooth out vec3 vPositionES; // eye space position\n"
1442 "\n"
1443 "void main()\n"
1444 "{\n"
1445 " //\n"
1446 " // multiply the object space vertex position with the modelview matrix \n"
1447 " // to get the eye space vertex position\n"
1448 " //\n"
1449 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
1450 "\n"
1451 " //\n"
1452 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
1453 " // model view matrix) to get the eye space normal\n"
1454 " //\n"
1455 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
1456 "\n"
1457 " //\n"
1458 " // multiply the combiend modelview projection matrix with the object space vertex\n"
1459 " // position to get the clip space position\n"
1460 " //\n"
1461 " gl_Position = ftransform();\n"
1462 "}\n"
1463 "\n"
1465 return vp_program;
1469 // fragment shader program for bump mapping in surface local coordinates
1471 std::string get_fp_program()
1473 std::string fp_program =
1474 "\n"
1475 "#version 440 compatibility\n"
1476 "\n"
1477 "#extension GL_ARB_separate_shader_objects: enable\n"
1478 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1479 "\n"
1480 "smooth in vec3 vNormalES; // eye space normal\n"
1481 "smooth in vec3 vPositionES; // eye space position\n"
1482 "\n"
1483 "const int num_lights = 1;\n"
1484 "const int num_materials = 5000;\n"
1485 "\n"
1486 "const int directional_light = 0;\n"
1487 "const int point_light = 1;\n"
1488 "const int spot_light = 2;\n"
1489 "const int no_light = 3;\n"
1490 "\n"
1491 "struct Light\n"
1492 "{\n"
1493 " vec4 position; // in eye space\n"
1494 " vec4 spot_direction; // in eye space\n"
1495 "\n"
1496 " vec4 Ia; // ambient max. Intensity\n"
1497 " vec4 Id; // diffuse max. Intensity\n"
1498 " vec4 Is; // specular max. Intensity\n"
1499 "\n"
1500 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
1501 " \n"
1502 " float spot_cos_cutoff; // cosine cut of angle\n"
1503 "\n"
1504 " float spot_exponent; // [0-128]\n"
1505 " int type; // directional_light, point_light, spot_light, no_light\n"
1506 "};\n"
1507 "\n"
1508 "layout (std140) buffer Lights\n"
1509 "{\n"
1510 " Light light[num_lights];\n"
1511 "} lights;\n"
1512 "\n"
1513 "struct Material\n"
1514 "{\n"
1515 " vec4 ambient;\n"
1516 " vec4 diffuse;\n"
1517 " vec4 specular;\n"
1518 " vec4 emissive;\n"
1519 "\n"
1520 " float opacity;\n"
1521 " float shininess;\n"
1522 "};\n"
1523 "\n"
1524 "layout (std140) buffer Materials\n"
1525 "{\n"
1526 " Material material[num_materials];\n"
1527 "} materials;\n"
1528 "\n"
1529 "\n"
1530 "layout (std140) buffer GeomState\n"
1531 "{\n"
1532 " int material_index;\n"
1533 "} geom_state;\n"
1534 "\n"
1535 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
1536 "\n"
1537 "layout(location = 0) out vec4 vFragColor;\n"
1538 "\n"
1539 "//\n"
1540 "// The test block from the GL_ARB_uniform_buffer_object\n"
1541 "// specification. \n"
1542 "//\n"
1543 "struct S0\n"
1544 "{\n"
1545 " int d;\n"
1546 " bvec2 e;\n"
1547 "};\n"
1548 "\n"
1549 "struct S1\n"
1550 "{\n"
1551 " uvec3 j;\n"
1552 " vec2 k;\n"
1553 " float l[2];\n"
1554 " vec2 m;\n"
1555 " mat3 n[2];\n"
1556 "};\n"
1557 "\n"
1558 "layout (std140) buffer TestBlock\n"
1559 "{\n"
1560 " float a;\n"
1561 " vec2 b;\n"
1562 " vec3 c;\n"
1563 " S0 f;\n"
1564 " float g;\n"
1565 " float h[2];\n"
1566 " mat2x3 i;\n"
1567 " S1 o[2];\n"
1568 "} test_block;\n"
1569 "\n"
1570 "//\n"
1571 "// directional light contribution\n"
1572 "//\n"
1573 "vec3 directionalLight(\n"
1574 " in int i, // light identifier, i.e. current light\n"
1575 " in int j, // material identifier\n"
1576 " in vec3 n, // vertex normal in eye space\n"
1577 " in vec3 v) // view direction in eye space\n"
1578 "{\n"
1579 " if (lights.light[i].type != directional_light)\n"
1580 " return vec3(0.0, 0.0, 0.0);\n"
1581 "\n"
1582 " //\n"
1583 " // the light direction in eye space\n"
1584 " //\n"
1585 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
1586 "\n"
1587 " //\n"
1588 " // the half vector\n"
1589 " //\n"
1590 " vec3 h = normalize(l + v);\n"
1591 "\n"
1592 " float n_dot_l = max(0.0, dot(n, l));\n"
1593 " float n_dot_h = max(0.0, dot(n, h));\n"
1594 "\n"
1595 " float m = materials.material[j].shininess;\n"
1596 "\n"
1597 " float pf; // power factor\n"
1598 "\n"
1599 " if (n_dot_l == 0.0)\n"
1600 " pf = 0.0;\n"
1601 " else\n"
1602 " pf = pow(n_dot_h, m);\n"
1603 "\n"
1604 " return materials.material[j].emissive.rgb \n"
1605 " + lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1606 " + lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1607 " + lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1608 "}\n"
1609 "\n"
1610 "//\n"
1611 "// point light contribution\n"
1612 "//\n"
1613 "vec3 pointLight(\n"
1614 " in int i, // light identifier, i.e. current light\n"
1615 " in int j, // material identifier\n"
1616 " in vec3 n, // vertex normal in eye space\n"
1617 " in vec3 v, // view direction in eye space\n"
1618 " in vec3 p) // vertex position in eye space\n"
1619 "{\n"
1620 " if (lights.light[i].type != point_light)\n"
1621 " return vec3(0.0, 0.0, 0.0);\n"
1622 "\n"
1623 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1624 " float d = length(l); // distance from surface to light source\n"
1625 " l = normalize(l); // normalized direction from surface to light position\n"
1626 "\n"
1627 " //\n"
1628 " // the half vector\n"
1629 " //\n"
1630 " vec3 h = normalize(l + v);\n"
1631 "\n"
1632 " float n_dot_l = max(0.0, dot(n, l));\n"
1633 " float n_dot_h = max(0.0, dot(n, h));\n"
1634 "\n"
1635 " float m = materials.material[j].shininess;\n"
1636 "\n"
1637 " float pf; // power factor\n"
1638 "\n"
1639 " if (n_dot_l == 0.0)\n"
1640 " pf = 0.0;\n"
1641 " else\n"
1642 " pf = pow(n_dot_h, m);\n"
1643 "\n"
1644 " //\n"
1645 " // Compute attenuation\n"
1646 " //\n"
1647 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1648 " (lights.light[i].attenuation.y * d) + \n"
1649 " (lights.light[i].attenuation.z * d * d));\n"
1650 "\n"
1651 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1652 "\n"
1653 " return materials.material[j].emissive.rgb \n"
1654 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1655 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1656 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1657 "}\n"
1658 "\n"
1659 "//\n"
1660 "// spot light contribution\n"
1661 "//\n"
1662 "vec3 spotLight(\n"
1663 " in int i, // light identifier, i.e. current light\n"
1664 " in int j, // material identifier\n"
1665 " in vec3 n, // vertex normal in eye space\n"
1666 " in vec3 v, // view direction in eye space\n"
1667 " in vec3 p) // vertex position in eye space\n"
1668 "{\n"
1669 " if (lights.light[i].type != spot_light)\n"
1670 " return vec3(0.0, 0.0, 0.0);\n"
1671 "\n"
1672 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1673 " float d = length(l); // distance from surface to light source\n"
1674 " l = normalize(l); // normalized direction from surface to light position\n"
1675 " \n"
1676 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1677 "\n"
1678 " //\n"
1679 " // the half vector\n"
1680 " //\n"
1681 " vec3 h = normalize(l + v);\n"
1682 "\n"
1683 " float n_dot_l = max(0.0, dot(n, l));\n"
1684 " float n_dot_h = max(0.0, dot(n, h));\n"
1685 " float l_dot_s = dot(-l, s);\n"
1686 "\n"
1687 " float m = materials.material[j].shininess;\n"
1688 "\n"
1689 " float pf; // power factor\n"
1690 "\n"
1691 " if (n_dot_l == 0.0)\n"
1692 " pf = 0.0;\n"
1693 " else\n"
1694 " pf = pow(n_dot_h, m);\n"
1695 "\n"
1696 " //\n"
1697 " // Compute attenuation\n"
1698 " //\n"
1699 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1700 " (lights.light[i].attenuation.y * d) + \n"
1701 " (lights.light[i].attenuation.z * d * d));\n"
1702 "\n"
1703 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1704 "\n"
1705 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1706 " attenuation = 0.0;\n"
1707 " else\n"
1708 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
1709 "\n"
1710 " return materials.material[j].emissive.rgb \n"
1711 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1712 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1713 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1714 "}\n"
1715 "\n"
1716 "void main()\n"
1717 "{\n"
1718 " //\n"
1719 " // normalize the eye space normal\n"
1720 " //\n"
1721 " vec3 N = normalize(vNormalES);\n"
1722 "\n"
1723 " //\n"
1724 " // get the view vector and normalize it\n"
1725 " //\n"
1726 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
1727 "\n"
1728 " //\n"
1729 " // Integrate over all lights: Any unused light does not contribute and each light\n"
1730 " // contribute either from the directional light, the point light or the spot light.\n"
1731 " //\n"
1732 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
1733 " for (int i = 0; i < num_lights; ++i) {\n"
1734 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1735 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1736 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1737 " }\n"
1738 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1739 "\n"
1740 " //\n"
1741 " // Test TestBlock\n"
1742 " //\n"
1743 " if (test_block.a != 27.4) vFragColor = vec4(1, 0, 0, 1);\n"
1744 " if (test_block.b != vec2(15.3, 12.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1745 " if (test_block.c != vec3(11.4, 21.9, 10.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1746 "\n"
1747 " if (test_block.f.d != 61) vFragColor = vec4(1, 0, 0, 1);\n"
1748 " if (test_block.f.e != bvec2(true, false)) vFragColor = vec4(1, 0, 0, 1);\n"
1749 "\n"
1750 " if (test_block.g != 57.3) vFragColor = vec4(1, 0, 0, 1);\n"
1751 "\n"
1752 " if (test_block.h[0] != 9.1) vFragColor = vec4(1, 0, 0, 1);\n"
1753 " if (test_block.h[1] != 17.56) vFragColor = vec4(1, 0, 0, 1);\n"
1754 "\n"
1755 " if (test_block.i[0] != vec3(19.43,1243.2, 0.56)) vFragColor = vec4(1, 0, 0, 1);\n"
1756 " if (test_block.i[1] != vec3(13.54,264.22, 65.52)) vFragColor = vec4(1, 0, 0, 1);\n"
1757 "\n"
1758 " if (test_block.o[0].j != uvec3(10,11,12)) vFragColor = vec4(1, 0, 0, 1);\n"
1759 " if (test_block.o[0].k != vec2(64.62, 275.21)) vFragColor = vec4(1, 0, 0, 1);\n"
1760 " if (test_block.o[0].l[0] != 41.346) vFragColor = vec4(1, 0, 0, 1);\n"
1761 " if (test_block.o[0].l[1] != 67.9456) vFragColor = vec4(1, 0, 0, 1);\n"
1762 " if (test_block.o[0].m != vec2(-56.62, 768.276)) vFragColor = vec4(1, 0, 0, 1);\n"
1763 " if (test_block.o[0].n[0][0] != vec3(-0.4,-0.5,-0.6)) vFragColor = vec4(1, 0, 0, 1);\n"
1764 " if (test_block.o[0].n[0][1] != vec3(-0.7,-0.8,-0.9)) vFragColor = vec4(1, 0, 0, 1);\n"
1765 " if (test_block.o[0].n[0][2] != vec3(-0.1,-0.2,-0.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1766 " if (test_block.o[0].n[1][0] != vec3(1.1,2.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1767 " if (test_block.o[0].n[1][1] != vec3(1.2,2.3,3.4)) vFragColor = vec4(1, 0, 0, 1);\n"
1768 " if (test_block.o[0].n[1][2] != vec3(1.3,2.4,3.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1769 "\n"
1770 " if (test_block.o[1].j != uvec3(20,31,42)) vFragColor = vec4(1, 0, 0, 1);\n"
1771 " if (test_block.o[1].k != vec2(-96.62, -658.456)) vFragColor = vec4(1, 0, 0, 1);\n"
1772 " if (test_block.o[1].l[0] != 88.34) vFragColor = vec4(1, 0, 0, 1);\n"
1773 " if (test_block.o[1].l[1] != -488.21) vFragColor = vec4(1, 0, 0, 1);\n"
1774 " if (test_block.o[1].m != vec2(777.7, 888.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1775 " if (test_block.o[1].n[0][0] != vec3(1.1,1.2,1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1776 " if (test_block.o[1].n[0][1] != vec3(2.1,2.2,2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1777 " if (test_block.o[1].n[0][2] != vec3(3.1,3.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1778 " if (test_block.o[1].n[1][0] != vec3(-1.1,-1.2,-1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1779 " if (test_block.o[1].n[1][1] != vec3(-2.1,-2.2,-2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1780 " if (test_block.o[1].n[1][2] != vec3(-3.1,-3.2,-3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1781 "\n"
1782 "}\n"
1783 "\n"
1785 return fp_program;