fixed: compile issue
[opensg.git] / Examples / Simple / shaderstoragebufferobject_std430.cpp
blobf19a7814adfc3f431a4d0a1a86a51ad02c31cb5f
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 std430 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 std430
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 std430 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 = 2; // 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));
316 lights.push_back(Light::create_light(Light::point_light));
318 assert(lights.size() == num_lights);
320 return lights;
323 VecLightsT lights = initialize_lights(); // the lights
327 // Simple material data structure
329 struct Material
331 Material()
332 : ambient (0.f, 0.f, 0.f)
333 , diffuse (0.f, 0.f, 0.f)
334 , specular(0.f, 0.f, 0.f)
335 , emissive(0.f, 0.f, 0.f)
336 , opacity(1.f)
337 , shininess(100.f)
340 OSG::Color3f ambient;
341 OSG::Color3f diffuse;
342 OSG::Color3f specular;
343 OSG::Color3f emissive;
345 OSG::Real32 opacity;
346 OSG::Real32 shininess;
349 typedef std::vector<Material> VecMaterialsT; // multiple materials
351 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
353 VecMaterialsT materials;
355 for (std::size_t i = 0; i < num; ++i)
357 Material m;
359 m.ambient = OSG::Color3f(0.1f, 0.1f, 0.1f);
360 m.diffuse.setRandom();
361 m.specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
362 m.emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
363 m.opacity = 1.f;
364 m.shininess = 80.f;
366 materials.push_back(m);
369 return materials;
372 const std::size_t num_materials = 5000; // any number of materials
373 VecMaterialsT materials = initialize_materials(num_materials); // the material database
377 // Simple geometry state data structure
379 struct GeomState
381 GeomState()
382 : material_index(0)
385 OSG::UInt32 material_index;
390 // Part II: Some helper functions:
391 // Pnt3f transform_to_eye_space(const Pnt3f& p, SimpleSceneManager* pSSM)
392 // Vec3f transform_to_eye_space(const Vec3f& v, SimpleSceneManager* pSSM)
393 // size_t align_offset (size_t base_alignment, size_t base_offset)
397 // transform point from world space to eye space
399 OSG::Pnt3f transform_to_eye_space(const OSG::Pnt3f& p, OSG::SimpleSceneManager* pSSM)
401 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
402 return p;
404 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
406 OSG::Pnt3f p_es;
408 OSG::Matrix view;
409 OSG::Int16 width = pPort->calcPixelWidth();
410 OSG::Int16 height = pPort->calcPixelHeight();
412 pPort->getCamera()->getViewing(view, width, height);
414 view.multFull( p, p_es);
416 return p_es;
420 // transform vector from world space to eye space
422 OSG::Vec3f transform_to_eye_space(const OSG::Vec3f& v, OSG::SimpleSceneManager* pSSM)
424 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
425 return v;
427 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
429 OSG::Vec3f v_es;
431 OSG::Matrix view;
432 OSG::Int16 width = pPort->calcPixelWidth();
433 OSG::Int16 height = pPort->calcPixelHeight();
435 pPort->getCamera()->getViewing(view, width, height);
437 view.multFull( v, v_es);
439 return v_es;
443 // helper to calculate the correct buffer insert positions on std140 or std430
445 std::size_t align_offset(std::size_t base_alignment, std::size_t base_offset)
447 return base_alignment * ((base_alignment + base_offset - 1) / base_alignment);
452 // Part III: Some routines for handling of the memory buffer and the the creation of
453 // the ShaderStorageBufferObjStdLayoutChunk objects:
455 // i) calc_test_block_buffer_size,
456 // create_test_block_buffer,
457 // create_test_block_state,
458 // update_test_block_state
460 // ii) calc_light_buffer_size,
461 // create_light_buffer,
462 // create_light_state,
463 // update_light_state
465 // iii) calc_material_database_buffer_size,
466 // create_material_database_buffer,
467 // create_material_database_state,
468 // update_material_database_state
470 // iv) calc_geometry_material_buffer_size,
471 // create_geometry_material_buffer,
472 // create_geometry_material_state,
473 // update_geometry_material_state
477 // i) the test block shader storage buffer object
479 std::size_t calc_test_block_buffer_size(const TestBlock& test_block)
482 // Introduction to the std430 storage layout
483 // =========================================
485 // When using the "std430" storage layout, structures will be laid out in
486 // buffer storage with its members stored in monotonically increasing order
487 // based on their location in the declaration. A structure and each
488 // structure member have a base offset and a base alignment, from which an
489 // aligned offset is computed by rounding the base offset up to a multiple of
490 // the base alignment. The base offset of the first member of a structure is
491 // taken from the aligned offset of the structure itself. The base offset of
492 // all other structure members is derived by taking the offset of the last
493 // basic machine unit consumed by the previous member and adding one. Each
494 // structure member is stored in memory at its aligned offset. The members
495 // of a top-level shader storage block are laid out in buffer storage by treating
496 // the shader storage block as a structure with a base offset of zero.
498 // When using the std430 storage layout, shader storage blocks will be laid out in
499 // buffer storage identically to uniform and shader storage blocks using the
500 // std140 layout, except that the base alignment and stride of arrays of scalars
501 // and vectors in rule 4 and of structures in rule 9 are not rounded up a multiple
502 // of the base alignment of a vec4.
504 // (1) If the member is a scalar consuming <N> basic machine units, the
505 // base alignment is <N>.
507 // (2) If the member is a two- or four-component vector with components
508 // consuming <N> basic machine units, the base alignment is 2<N> or
509 // 4<N>, respectively.
511 // (3) If the member is a three-component vector with components consuming
512 // <N> basic machine units, the base alignment is 4<N>.
514 // (4) If the member is an array of scalars or vectors, the base alignment
515 // and array stride are set to match the base alignment of a single
516 // array element, according to rules (1), (2), and (3), and are not rounded
517 // up to the base alignment of a vec4. The array may have padding at the
518 // end; the base offset of the member following the array is rounded up
519 // to the next multiple of the base alignment.
521 // (5) If the member is a column-major matrix with <C> columns and <R>
522 // rows, the matrix is stored identically to an array of <C> column
523 // vectors with <R> components each, according to rule (4).
525 // (6) If the member is an array of <S> column-major matrices with <C>
526 // columns and <R> rows, the matrix is stored identically to a row of
527 // <S>*<C> column vectors with <R> components each, according to rule
528 // (4).
530 // (7) If the member is a row-major matrix with <C> columns and <R> rows,
531 // the matrix is stored identically to an array of <R> row vectors
532 // with <C> components each, according to rule (4).
534 // (8) If the member is an array of <S> row-major matrices with <C> columns
535 // and <R> rows, the matrix is stored identically to a row of <S>*<R>
536 // row vectors with <C> components each, according to rule (4).
538 // (9) If the member is a structure, the base alignment of the structure is
539 // <N>, where <N> is the largest base alignment value of any of its
540 // members, and are not rounded up to the base alignment of a vec4. The
541 // individual members of this sub-structure are then assigned offsets
542 // by applying this set of rules recursively, where the base offset of
543 // the first member of the sub-structure is equal to the aligned offset
544 // of the structure. The structure may have padding at the end; the
545 // base offset of the member following the sub-structure is rounded up
546 // to the next multiple of the base alignment of the structure.
548 // (10) If the member is an array of <S> structures, the <S> elements of
549 // the array are laid out in order, according to rule (9).
551 // For shader storage blocks laid out according to these rules, the minimum buffer
552 // object size returned by the GL_BUFFER_DATA_SIZE query is derived by
553 // taking the offset of the last basic machine unit consumed by the last
554 // entry of the shader storage block (including any end-of-array or
555 // end-of-structure padding), adding one, and rounding up to the next
556 // multiple of the base alignment required for a vec4.
559 // Using Standard Layout Qualifiers
560 // ================================
561 // When you group a number of variables in a uniform buffer or shader
562 // storage buffer, and want to read or write their values outside a shader, you
563 // need to know the offset of each one. You can query these offsets, but for
564 // large collections of uniforms this process requires many queries and is
565 // cumbersome. As an alternative, the standard layout qualifiers request that
566 // the GLSL shader compiler organize the variables according to a set of rules,
567 // where you can predictably compute the offset of any member in the block.
568 // In order to qualify a block to use the std430 layout, you need to add a
569 // layout directive to its declaration, as demonstrated below:
571 // layout (std430) buffer BufferBlock {
572 // // declared variables
573 // };
575 // This std430 qualification only works for shader storage buffer objects.
577 // To use these, the offset of a member in the block is the accumulated total
578 // of the alignment and sizes of the previous members in the block (those
579 // declared before the variable in question), bumped up to the alignment of
580 // the member. The starting offset of the first member is always zero.
582 // The std430 Layout Rules
583 // =======================
584 // The set of rules shown in the table are used by the GLSL compiler to place
585 // members in an std430-qualified uniform block. This feature is available
586 // only with GLSL Version 4.30 or greater.
588 // Variable Type Variable Size and Alignment
589 // --------------------------------------------------------------------------------
590 // Scalar bool, int, uint, float and Both the size and alignment are the size
591 // double of the scalar in basic machine types
592 // (e.g., sizeof(GLfloat)).
594 // Two-component vectors (e.g., ivec2) Both the size and alignment are twice
595 // the size of the underlying scalar type.
597 // Three-component vectors (e.g., vec3) Both the size and alignment are four
598 // and times the size of the underlying scalar
599 // Four-component vectors (e.g., vec4) type. However, this is true only when
600 // the member is not part of an array or
601 // nested structure.
603 // An array of scalars or vectors The size of each element in the array
604 // will be the same size of the element
605 // type, where three-component vectors
606 // are not rounded up to the size of
607 // four-component vectors. This is also the
608 // array’s alignment. The array’s size will
609 // be the element’s size times the number
610 // of elements in the array.
612 // A column-major matrix or an array Same layout as an array of N vectors
613 // of column-major matrices of size C each with R components, where N is
614 // columns and R rows the total number of columns present.
616 // A row-major matrix or an array of Same layout as an array of N vectors
617 // row-major matrices with R rows and C each with C components, where N is
618 // columns the total number of rows present.
620 // A single-structure definition or Structure alignment is the same as the
621 // an array of structures alignment for the biggest structure
622 // member, where three-component
623 // vectors are not rounded up to the size of
624 // four-component vectors. Each structure
625 // will start on this alignment, and its size
626 // will be the space needed by its
627 // members, according to the previous
628 // rules, rounded up to a multiple of the
629 // structure alignment.
632 std::size_t ao = 0; // aligned offset
633 std::size_t bo = 0; // base offset
634 // layout(std430) uniform Example
635 // {
636 // // Base types below consume 4 basic machine units
637 // //
638 // // base base align
639 // // rule align off. off. bytes used
640 // // ---- ------ ---- ---- -----------------------
641 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // Real32 a; // 1 4 0 0 0..3
642 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // Vec2f b; // 2 8 4 8 8..15
643 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // Vec3f c; // 3 16 16 16 16..27
644 ao = align_offset( 8, bo); bo = ao; // struct { // 9 8 28 32 (align begin)
645 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Int32); // Int32 d; // 1 4 32 32 32..35
646 ao = align_offset( 8, bo); bo = ao + 2*sizeof(OSG::Int32); // Vec2b e; // 2 8 36 40 40..47
647 ao = align_offset( 8, bo); bo = ao; // } f; // 9 8 48 48 (pad end)
648 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // Real32 g; // 1 4 48 48 48..51
649 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // Real32 h[2]; // 4 4 52 52 52..55 (h[0])
650 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // // 4 56 56 56..59 (h[1])
651 ao = align_offset( 4, bo); bo = ao; // // 4 4 60 60 (pad end of h)
652 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // Matrix2x3f i; //5/4/3 16 60 64 64..75 (i, column 0)
653 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 76 80 80..91 (i, column 1)
654 ao = align_offset(16, bo); bo = ao; // // 5/4 16 92 96 (pad end of i)
655 ao = align_offset(16, bo); bo = ao; // struct { //10/9 16 96 96 (align begin)
656 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3u); // Vec3u j; // 3 16 96 96 96..107 (o[0].j)
657 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // Vec2f k; // 2 8 108 112 112..119 (o[0].k)
658 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // Real32 l[2]; // 4 4 120 120 120..123 (o[0].l[0])
659 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // // 4 124 124 124..127 (o[0].l[1])
660 ao = align_offset( 4, bo); bo = ao; // // 4 4 128 128 (pad end of o[0].l)
661 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // Vec2f m; // 2 8 128 128 128..135 (o[0].m)
662 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // Matrix3f n[2]; // 6/4 16 136 144 144..155 (o[0].n[0], column 0)
663 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 156 160 160..171 (o[0].n[0], column 1)
664 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 172 176 176..187 (o[0].n[0], column 2)
665 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 188 192 192..203 (o[0].n[1], column 0)
666 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 204 208 208..219 (o[0].n[1], column 1)
667 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 220 224 224..235 (o[0].n[1], column 2)
668 ao = align_offset(16, bo); bo = ao; // // 6/4 16 236 240 (pad end of o[0].n)
669 ao = align_offset(16, bo); bo = ao; // //10/9 16 240 240 (pad end of o[0])
670 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3u); // // 3 16 240 240 240..251 (o[1].j)
671 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // // 2 8 252 256 256..263 (o[1].k)
672 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // // 4 4 264 264 264..267 (o[1].l[0])
673 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // // 4 268 268 268..271 (o[1].l[1])
674 ao = align_offset( 4, bo); bo = ao; // // 4 4 272 272 (pad end of o[1].l)
675 ao = align_offset( 8, bo); bo = ao + sizeof(OSG::Vec2f); // // 2 8 272 272 272..279 (o[1].m)
676 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 6/4 16 280 288 288..299 o[1].n[0], column 0)
677 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 300 304 304..315 (o[1].n[0], column 1)
678 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 316 320 320..331 (o[1].n[0], column 2)
679 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 332 336 336..347 (o[1].n[1], column 0)
680 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 348 352 352..363 (o[1].n[1], column 1)
681 ao = align_offset(16, bo); bo = ao + sizeof(OSG::Vec3f); // // 16 364 368 368..379 (o[1].n[1], column 2)
682 ao = align_offset(16, bo); bo = ao; // // 6/4 16 380 384 (pad end of o[1].n)
683 ao = align_offset(16, bo); bo = ao; // //10/9 16 384 384 (pad end of o[1])
684 // } o[2];
685 // };
686 return ao;
689 std::vector<OSG::UInt8> create_test_block_buffer(const TestBlock& test_block)
691 std::size_t size = calc_test_block_buffer_size(test_block);
693 std::vector<OSG::UInt8> buffer(size);
695 std::size_t ao = 0; // aligned offset
696 std::size_t bo = 0; // base offset
698 ao = align_offset( 4, bo);
699 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.a;
700 bo = ao + sizeof(OSG::Real32);
702 ao = align_offset( 8, bo);
703 memcpy(&buffer[0] + ao, &test_block.b[0], sizeof(OSG::Vec2f));
704 bo = ao + sizeof(OSG::Vec2f);
706 ao = align_offset(16, bo);
707 memcpy(&buffer[0] + ao, &test_block.c[0], sizeof(OSG::Vec3f));
708 bo = ao + sizeof(OSG::Vec3f);
710 ao = align_offset( 8, bo);
711 bo = ao;
713 ao = align_offset( 4, bo);
714 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = test_block.f.d;
715 bo = ao + sizeof(OSG::Int32);
717 ao = align_offset( 8, bo);
718 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = test_block.f.e[0];
719 bo = ao + sizeof(OSG::Int32);
720 ao = bo;
721 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = test_block.f.e[1];
722 bo = ao + sizeof(OSG::Int32);
724 ao = align_offset( 8, bo);
725 bo = ao;
727 ao = align_offset( 4, bo);
728 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.g;
729 bo = ao + sizeof(OSG::Real32);
731 ao = align_offset( 4, bo);
732 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.h[0];
733 bo = ao + sizeof(OSG::Real32);
735 ao = align_offset( 4, bo);
736 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.h[1];
737 bo = ao + sizeof(OSG::Real32);
739 ao = align_offset( 4, bo);
740 bo = ao;
742 ao = align_offset(16, bo);
743 memcpy(&buffer[0] + ao, &test_block.i.row1[0], sizeof(OSG::Vec3f));
744 bo = ao + sizeof(OSG::Vec3f);
746 ao = align_offset(16, bo);
747 memcpy(&buffer[0] + ao, &test_block.i.row2[0], sizeof(OSG::Vec3f));
748 bo = ao + sizeof(OSG::Vec3f);
750 ao = align_offset(16, bo);
751 bo = ao;
753 ao = align_offset(16, bo);
754 bo = ao;
756 ao = align_offset(16, bo);
757 memcpy(&buffer[0] + ao, &test_block.o[0].j[0], sizeof(OSG::Vec3u));
758 bo = ao + sizeof(OSG::Vec3u);
760 ao = align_offset( 8, bo);
761 memcpy(&buffer[0] + ao, &test_block.o[0].k[0], sizeof(OSG::Vec2f));
762 bo = ao + sizeof(OSG::Vec2f);
764 ao = align_offset(4, bo);
765 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[0].l[0];
766 bo = ao + sizeof(OSG::Real32);
768 ao = align_offset(4, bo);
769 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[0].l[1];
770 bo = ao + sizeof(OSG::Real32);
772 ao = align_offset(4, bo);
773 bo = ao;
775 ao = align_offset( 8, bo);
776 memcpy(&buffer[0] + ao, &test_block.o[0].m[0], sizeof(OSG::Vec2f));
777 bo = ao + sizeof(OSG::Vec2f);
779 ao = align_offset(16, bo);
780 memcpy(&buffer[0] + ao, &test_block.o[0].n[0].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[0].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[0].row3[0], sizeof(OSG::Vec3f));
789 bo = ao + sizeof(OSG::Vec3f);
791 ao = align_offset(16, bo);
792 memcpy(&buffer[0] + ao, &test_block.o[0].n[1].row1[0], sizeof(OSG::Vec3f));
793 bo = ao + sizeof(OSG::Vec3f);
795 ao = align_offset(16, bo);
796 memcpy(&buffer[0] + ao, &test_block.o[0].n[1].row2[0], sizeof(OSG::Vec3f));
797 bo = ao + sizeof(OSG::Vec3f);
799 ao = align_offset(16, bo);
800 memcpy(&buffer[0] + ao, &test_block.o[0].n[1].row3[0], sizeof(OSG::Vec3f));
801 bo = ao + sizeof(OSG::Vec3f);
803 ao = align_offset(16, bo);
804 bo = ao;
806 ao = align_offset(16, bo);
807 bo = ao;
809 ao = align_offset(16, bo);
810 memcpy(&buffer[0] + ao, &test_block.o[1].j[0], sizeof(OSG::Vec3u));
811 bo = ao + sizeof(OSG::Vec3u);
813 ao = align_offset( 8, bo);
814 memcpy(&buffer[0] + ao, &test_block.o[1].k[0], sizeof(OSG::Vec2f));
815 bo = ao + sizeof(OSG::Vec2f);
817 ao = align_offset( 4, bo);
818 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[1].l[0];
819 bo = ao + sizeof(OSG::Real32);
821 ao = align_offset( 4, bo);
822 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = test_block.o[1].l[1];
823 bo = ao + sizeof(OSG::Real32);
825 ao = align_offset( 4, bo);
826 bo = ao;
828 ao = align_offset( 8, bo);
829 memcpy(&buffer[0] + ao, &test_block.o[1].m[0], sizeof(OSG::Vec2f));
830 bo = ao + sizeof(OSG::Vec2f);
832 ao = align_offset(16, bo);
833 memcpy(&buffer[0] + ao, &test_block.o[1].n[0].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[0].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[0].row3[0], sizeof(OSG::Vec3f));
842 bo = ao + sizeof(OSG::Vec3f);
844 ao = align_offset(16, bo);
845 memcpy(&buffer[0] + ao, &test_block.o[1].n[1].row1[0], sizeof(OSG::Vec3f));
846 bo = ao + sizeof(OSG::Vec3f);
848 ao = align_offset(16, bo);
849 memcpy(&buffer[0] + ao, &test_block.o[1].n[1].row2[0], sizeof(OSG::Vec3f));
850 bo = ao + sizeof(OSG::Vec3f);
852 ao = align_offset(16, bo);
853 memcpy(&buffer[0] + ao, &test_block.o[1].n[1].row3[0], sizeof(OSG::Vec3f));
854 bo = ao + sizeof(OSG::Vec3f);
856 ao = align_offset(16, bo);
857 bo = ao;
859 ao = align_offset(16, bo);
860 bo = ao;
862 return buffer;
865 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_test_block_state(const TestBlock& test_block)
867 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
869 std::vector<OSG::UInt8> buffer = create_test_block_buffer(test_block);
871 ssbo->editMFBuffer()->setValues(buffer);
872 ssbo->setUsage(GL_DYNAMIC_DRAW);
874 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
877 void update_test_block_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const TestBlock& test_block)
879 if (ssbo) {
880 std::vector<OSG::UInt8> buffer = create_test_block_buffer(test_block);
881 ssbo->editMFBuffer()->setValues(buffer);
886 // ii) the light shader storage buffer object
888 std::size_t calc_light_buffer_size(const VecLightsT& vLights)
890 std::size_t ao = 0; // aligned offset
891 std::size_t bo = 0; // base offset
893 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Pnt4f); // OSG::Pnt3f position;
894 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f spot_direction;
895 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Ia;
896 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Id;
897 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Is;
898 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f attenuation;
899 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_cos_cutoff;
900 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_exponent;
901 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Int32); // OSG::Int32 type;
902 ao = align_offset( 16, bo); bo = ao; // padding
904 ao *= vLights.size(); bo = ao; // array
905 ao = align_offset( 16, bo); bo = ao; // padding
907 return ao;
910 std::vector<OSG::UInt8> create_light_buffer(const VecLightsT& vLights)
912 std::size_t size = calc_light_buffer_size(vLights);
914 std::vector<OSG::UInt8> buffer(size);
916 std::size_t ao = 0; // aligned offset
917 std::size_t bo = 0; // base offset
919 for (std::size_t i = 0; i < vLights.size(); ++i)
921 OSG::Pnt3f position_es = transform_to_eye_space(vLights[i].position, mgr);
922 OSG::Vec3f spot_direction_es = transform_to_eye_space(vLights[i].spot_direction, mgr);
924 ao = align_offset(16, bo);
925 memcpy(&buffer[0] + ao, &position_es[0], sizeof(OSG::Pnt3f));
926 bo = ao + sizeof(OSG::Pnt4f);
928 ao = align_offset(16, bo);
929 memcpy(&buffer[0] + ao, &spot_direction_es[0], sizeof(OSG::Vec3f));
930 bo = ao + sizeof(OSG::Vec4f);
932 ao = align_offset(16, bo);
933 memcpy(&buffer[0] + ao, &vLights[i].Ia[0], sizeof(OSG::Color3f));
934 bo = ao + sizeof(OSG::Color4f);
936 ao = align_offset(16, bo);
937 memcpy(&buffer[0] + ao, &vLights[i].Id[0], sizeof(OSG::Color3f));
938 bo = ao + sizeof(OSG::Color4f);
940 ao = align_offset(16, bo);
941 memcpy(&buffer[0] + ao, &vLights[i].Is[0], sizeof(OSG::Color3f));
942 bo = ao + sizeof(OSG::Color4f);
944 ao = align_offset(16, bo);
945 memcpy(&buffer[0] + ao, &vLights[i].attenuation[0], sizeof(OSG::Vec3f));
946 bo = ao + sizeof(OSG::Vec4f);
948 ao = align_offset( 4, bo);
949 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_cos_cutoff;
950 bo = ao + sizeof(OSG::Real32);
952 ao = align_offset( 4, bo);
953 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_exponent;
954 bo = ao + sizeof(OSG::Real32);
956 ao = align_offset( 4, bo);
957 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = vLights[i].type;
958 bo = ao + sizeof(OSG::Int32);
960 ao = align_offset( 16, bo); bo = ao; // padding
963 return buffer;
966 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_light_state(const VecLightsT& vLights)
968 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
970 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
972 ssbo->editMFBuffer()->setValues(buffer);
973 ssbo->setUsage(GL_DYNAMIC_DRAW);
975 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
978 void update_light_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const VecLightsT& vLights)
980 if (ssbo) {
981 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
982 ssbo->editMFBuffer()->setValues(buffer);
987 // iii) the material shader storage buffer object
989 std::size_t calc_material_database_buffer_size(const VecMaterialsT& vMaterials)
991 std::size_t ao = 0; // aligned offset
992 std::size_t bo = 0; // base offset
994 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f ambient;
995 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f diffuse;
996 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f specular;
997 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f emissive;
998 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 opacity;
999 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 shininess;
1000 ao = align_offset( 16, bo); bo = ao; // padding
1002 ao *= vMaterials.size(); bo = ao; // array
1003 ao = align_offset( 16, bo); bo = ao; // padding
1005 return ao;
1008 std::vector<OSG::UInt8> create_material_database_buffer(const VecMaterialsT& vMaterials)
1010 std::size_t size = calc_material_database_buffer_size(vMaterials);
1012 std::vector<OSG::UInt8> buffer(size);
1014 std::size_t ao = 0; // aligned offset
1015 std::size_t bo = 0; // base offset
1017 for (std::size_t i = 0; i < vMaterials.size(); ++i)
1019 ao = align_offset(16, bo);
1020 memcpy(&buffer[0] + ao, &vMaterials[i].ambient[0], sizeof(OSG::Color3f));
1021 bo = ao + sizeof(OSG::Color4f);
1023 ao = align_offset(16, bo);
1024 memcpy(&buffer[0] + ao, &vMaterials[i].diffuse[0], sizeof(OSG::Color3f));
1025 bo = ao + sizeof(OSG::Color4f);
1027 ao = align_offset(16, bo);
1028 memcpy(&buffer[0] + ao, &vMaterials[i].specular[0], sizeof(OSG::Color3f));
1029 bo = ao + sizeof(OSG::Color4f);
1031 ao = align_offset(16, bo);
1032 memcpy(&buffer[0] + ao, &vMaterials[i].emissive[0], sizeof(OSG::Color3f));
1033 bo = ao + sizeof(OSG::Color4f);
1035 ao = align_offset( 4, bo);
1036 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].opacity;
1037 bo = ao + sizeof(OSG::Real32);
1039 ao = align_offset( 4, bo);
1040 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].shininess;
1041 bo = ao + sizeof(OSG::Real32);
1043 ao = align_offset( 16, bo); bo = ao; // padding
1046 return buffer;
1049 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
1051 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1053 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
1055 ssbo->editMFBuffer()->setValues(buffer);
1056 ssbo->setUsage(GL_STATIC_DRAW);
1058 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
1061 void update_material_database_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const VecMaterialsT& vMaterials)
1063 if (ssbo) {
1064 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
1065 ssbo->editMFBuffer()->setValues(buffer);
1070 // iv) the geomertry shader storage buffer object
1072 std::size_t calc_geometry_material_buffer_size()
1074 std::size_t ao = 0; // aligned offset
1075 std::size_t bo = 0; // base offset
1077 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::UInt32); // OSG::UInt32 material_index;
1078 ao = align_offset( 16, bo); bo = ao; // padding
1080 return ao;
1083 std::vector<OSG::UInt8> create_geometry_material_buffer(const GeomState& geom_state)
1085 std::size_t size = calc_geometry_material_buffer_size();
1087 std::vector<OSG::UInt8> buffer(size);
1089 std::size_t ao = 0; // aligned offset
1090 std::size_t bo = 0; // base offset
1092 ao = align_offset( 4, bo);
1093 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = geom_state.material_index;
1094 bo = ao + sizeof(OSG::UInt32);
1096 return buffer;
1099 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
1101 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1103 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
1105 ssbo->editMFBuffer()->setValues(buffer);
1106 ssbo->setUsage(GL_DYNAMIC_DRAW);
1108 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
1111 void update_geometry_material_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const GeomState& geom_state)
1113 if (ssbo) {
1114 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
1115 ssbo->editMFBuffer()->setValues(buffer);
1120 // Part IV: The application starts here
1124 // vertex shader program.
1126 std::string get_vp_program();
1129 // fragment shader program for bump mapping in surface local coordinates
1131 std::string get_fp_program();
1134 // random number generator
1136 boost::random::mt19937 generator;
1137 boost::random::uniform_int_distribution<> dist(0, num_materials-1);
1140 // a separate transformation for every object
1142 OSG::TransformRefPtr cyltrans, tortrans;
1145 // Shader Storage buffer objects corresponding to transient shader blocks
1147 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_light_state = NULL;
1148 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_1 = NULL;
1149 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_2 = NULL;
1152 // forward declaration so we can have the interesting stuff upfront
1154 int setupGLUT(int *argc, char *argv[]);
1157 // redraw the window
1159 void display(void)
1161 // light spot direction and light position must be provided in eye space
1162 update_light_state(ssbo_light_state, lights);
1164 // create the matrix
1165 OSG::Matrix m;
1166 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME );
1168 // set the transforms' matrices
1169 m.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t / 1000.f) * 1.5),
1170 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t / 500.f));
1172 cyltrans->setMatrix(m);
1174 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 1000.f), 0, 0),
1175 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t / 1000.f));
1177 tortrans->setMatrix(m);
1179 OSG::commitChanges();
1181 mgr->redraw();
1185 // Initialize GLUT & OpenSG and set up the scene
1187 int main(int argc, char **argv)
1189 // OSG init
1190 OSG::osgInit(argc,argv);
1192 // GLUT init
1193 int winid = setupGLUT(&argc, argv);
1195 // open a new scope, because the pointers below should go out of scope
1196 // before entering glutMainLoop.
1197 // Otherwise OpenSG will complain about objects being alive after shutdown.
1199 // the connection between GLUT and OpenSG
1200 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
1201 gwin->setGlutId(winid);
1202 gwin->init();
1204 // create the SimpleSceneManager helper
1205 mgr = OSG::SimpleSceneManager::create();
1206 mgr->setWindow(gwin);
1208 // create a pretty simple graph: a Group with two Transforms as children,
1209 // each of which carries a single Geometry.
1211 // The scene
1213 OSG::NodeRefPtr scene = OSG::Node::create();
1215 // The cylinder and its transformation
1216 OSG::NodeRefPtr cyl = OSG::Node::create();
1217 OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24,
1218 true, true, true );
1220 cyl->setCore(cylgeo);
1222 cyltrans = OSG::Transform::create();
1224 OSG::NodeRefPtr cyltransnode = OSG::Node::create();
1225 cyltransnode->setCore (cyltrans);
1226 cyltransnode->addChild(cyl );
1228 // add it to the scene
1229 scene->addChild(cyltransnode);
1231 // The torus and its transformation
1232 OSG::NodeRefPtr torus = OSG::Node::create();
1233 OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
1235 torus->setCore(torusgeo);
1237 tortrans = OSG::Transform::create();
1239 OSG::NodeRefPtr tortransnode = OSG::Node::create();
1240 tortransnode->setCore (tortrans);
1241 tortransnode->addChild(torus );
1243 // add it to the scene
1244 scene->addChild(tortransnode);
1247 // create the shader program
1249 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
1250 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
1251 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
1253 vertShader->setProgram(get_vp_program());
1254 fragShader->setProgram(get_fp_program());
1257 // binding the shader storage block to a buffer binding point can be performed
1258 // either by calling the shaders's addShaderStorageBlock method or by
1259 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1260 // In the following we use both variants for illustration.
1262 fragShader->addShaderStorageBlock("Materials", 1); // block binding point
1263 fragShader->addShaderStorageBlock("Lights", 2); // block binding point
1266 // The following is replaced by adding ShaderProgramVariableChunk objects
1267 // to the chunk material. See below...
1269 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
1271 fragShader->addShaderStorageBlock("TestBlock", 4); // block binding point
1273 prog_chunk->addShader(vertShader);
1274 prog_chunk->addShader(fragShader);
1277 // create shader storage buffer objects and corresponding materials
1279 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_material_database = create_material_database_state(materials);
1280 ssbo_light_state = create_light_state(lights);
1282 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_test_block = create_test_block_state(global_test_block);
1284 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
1285 polygon_chunk->setFrontMode(GL_FILL);
1286 polygon_chunk->setBackMode(GL_FILL);
1287 polygon_chunk->setCullFace(GL_NONE);
1289 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
1290 depth_chunk->setEnable(true);
1292 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
1293 prog_state->addChunk(ssbo_material_database, 1); // buffer binding point 1
1294 prog_state->addChunk(ssbo_light_state, 2); // buffer binding point 2
1295 prog_state->addChunk(ssbo_test_block, 4); // buffer binding point 4
1296 prog_state->addChunk(prog_chunk);
1297 prog_state->addChunk(polygon_chunk);
1298 prog_state->addChunk(depth_chunk);
1300 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
1301 shader_var_chunk->addShaderStorageBlock("GeomState", 3);
1303 GeomState geom1; geom1.material_index = dist(generator);
1304 OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
1305 ssbo_geom_state_1 = create_geometry_material_state(geom1);
1306 geom1_state->addChunk(ssbo_geom_state_1, 3); // buffer binding point 3
1307 geom1_state->addChunk(shader_var_chunk); // block binding point
1309 GeomState geom2; geom2.material_index = dist(generator);
1310 OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
1311 ssbo_geom_state_2 = create_geometry_material_state(geom2);
1312 geom2_state->addChunk(ssbo_geom_state_2, 3); // buffer binding point 3
1313 geom2_state->addChunk(shader_var_chunk); // block binding point
1315 cylgeo ->setMaterial(geom1_state);
1316 torusgeo->setMaterial(geom2_state);
1318 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
1319 mgrp->setMaterial(prog_state);
1320 scene->setCore(mgrp);
1322 OSG::commitChanges();
1324 mgr->setRoot(scene);
1326 // show the whole scene
1327 mgr->showAll();
1330 // GLUT main loop
1331 glutMainLoop();
1333 return 0;
1337 // GLUT callback functions
1341 // react to size changes
1343 void reshape(int w, int h)
1345 mgr->resize(w, h);
1346 glutPostRedisplay();
1350 // react to mouse button presses
1352 void mouse(int button, int state, int x, int y)
1354 if (state)
1355 mgr->mouseButtonRelease(button, x, y);
1356 else
1357 mgr->mouseButtonPress(button, x, y);
1359 glutPostRedisplay();
1363 // react to mouse motions with pressed buttons
1365 void motion(int x, int y)
1367 mgr->mouseMove(x, y);
1368 glutPostRedisplay();
1372 // react to keys
1374 void keyboard(unsigned char k, int x, int y)
1376 switch(k)
1378 case 27:
1380 // clean up global variables
1381 cyltrans = NULL;
1382 tortrans = NULL;
1383 mgr = NULL;
1385 ssbo_light_state = NULL;
1386 ssbo_geom_state_1 = NULL;
1387 ssbo_geom_state_2 = NULL;
1389 OSG::osgExit();
1390 exit(0);
1392 break;
1394 case 'm':
1396 GeomState geom1; geom1.material_index = dist(generator);
1397 GeomState geom2; geom2.material_index = dist(generator);
1399 update_geometry_material_state(ssbo_geom_state_1, geom1);
1400 update_geometry_material_state(ssbo_geom_state_2, geom2);
1402 glutPostRedisplay();
1404 break;
1406 case 's':
1408 mgr->setStatistics(!mgr->getStatistics());
1410 break;
1415 // setup the GLUT library which handles the windows for us
1417 int setupGLUT(int *argc, char *argv[])
1419 glutInit(argc, argv);
1420 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
1422 int winid = glutCreateWindow("OpenSG");
1424 glutReshapeFunc(reshape);
1425 glutDisplayFunc(display);
1426 glutMouseFunc(mouse);
1427 glutMotionFunc(motion);
1428 glutKeyboardFunc(keyboard);
1430 // call the redraw function whenever there's nothing else to do
1431 glutIdleFunc(display);
1433 return winid;
1437 // Part V: The shader programs
1441 // vertex shader program.
1443 std::string get_vp_program()
1445 std::string vp_program =
1446 "\n"
1447 "#version 440 compatibility\n"
1448 "\n"
1449 "#extension GL_ARB_separate_shader_objects: enable\n"
1450 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1451 "\n"
1452 "smooth out vec3 vNormalES; // eye space normal\n"
1453 "smooth out vec3 vPositionES; // eye space position\n"
1454 "\n"
1455 "void main()\n"
1456 "{\n"
1457 " //\n"
1458 " // multiply the object space vertex position with the modelview matrix \n"
1459 " // to get the eye space vertex position\n"
1460 " //\n"
1461 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
1462 "\n"
1463 " //\n"
1464 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
1465 " // model view matrix) to get the eye space normal\n"
1466 " //\n"
1467 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
1468 "\n"
1469 " //\n"
1470 " // multiply the combiend modelview projection matrix with the object space vertex\n"
1471 " // position to get the clip space position\n"
1472 " //\n"
1473 " gl_Position = ftransform();\n"
1474 "}\n"
1475 "\n"
1477 return vp_program;
1481 // fragment shader program for bump mapping in surface local coordinates
1483 std::string get_fp_program()
1485 std::string fp_program =
1486 "\n"
1487 "#version 440 compatibility\n"
1488 "\n"
1489 "#extension GL_ARB_separate_shader_objects: enable\n"
1490 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1491 "\n"
1492 "smooth in vec3 vNormalES; // eye space normal\n"
1493 "smooth in vec3 vPositionES; // eye space position\n"
1494 "\n"
1495 "const int num_lights = 2;\n"
1496 "const int num_materials = 5000;\n"
1497 "\n"
1498 "const int directional_light = 0;\n"
1499 "const int point_light = 1;\n"
1500 "const int spot_light = 2;\n"
1501 "const int no_light = 3;\n"
1502 "\n"
1503 "struct Light\n"
1504 "{\n"
1505 " vec4 position; // in eye space\n"
1506 " vec4 spot_direction; // in eye space\n"
1507 "\n"
1508 " vec4 Ia; // ambient max. Intensity\n"
1509 " vec4 Id; // diffuse max. Intensity\n"
1510 " vec4 Is; // specular max. Intensity\n"
1511 "\n"
1512 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
1513 " \n"
1514 " float spot_cos_cutoff; // cosine cut of angle\n"
1515 "\n"
1516 " float spot_exponent; // [0-128]\n"
1517 " int type; // directional_light, point_light, spot_light, no_light\n"
1518 "};\n"
1519 "\n"
1520 "layout (std430) buffer Lights\n"
1521 "{\n"
1522 " Light light[num_lights];\n"
1523 "} lights;\n"
1524 "\n"
1525 "struct Material\n"
1526 "{\n"
1527 " vec4 ambient;\n"
1528 " vec4 diffuse;\n"
1529 " vec4 specular;\n"
1530 " vec4 emissive;\n"
1531 "\n"
1532 " float opacity;\n"
1533 " float shininess;\n"
1534 "};\n"
1535 "\n"
1536 "layout (std430) buffer Materials\n"
1537 "{\n"
1538 " Material material[num_materials];\n"
1539 "} materials;\n"
1540 "\n"
1541 "\n"
1542 "layout (std430) buffer GeomState\n"
1543 "{\n"
1544 " int material_index;\n"
1545 "} geom_state;\n"
1546 "\n"
1547 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
1548 "\n"
1549 "layout(location = 0) out vec4 vFragColor;\n"
1550 "\n"
1551 "//\n"
1552 "// The test block from the GL_ARB_uniform_buffer_object\n"
1553 "// specification. \n"
1554 "//\n"
1555 "struct S0\n"
1556 "{\n"
1557 " int d;\n"
1558 " bvec2 e;\n"
1559 "};\n"
1560 "\n"
1561 "struct S1\n"
1562 "{\n"
1563 " uvec3 j;\n"
1564 " vec2 k;\n"
1565 " float l[2];\n"
1566 " vec2 m;\n"
1567 " mat3 n[2];\n"
1568 "};\n"
1569 "\n"
1570 "layout (std430) buffer TestBlock\n"
1571 "{\n"
1572 " float a;\n"
1573 " vec2 b;\n"
1574 " vec3 c;\n"
1575 " S0 f;\n"
1576 " float g;\n"
1577 " float h[2];\n"
1578 " mat2x3 i;\n"
1579 " S1 o[2];\n"
1580 "} test_block;\n"
1581 "\n"
1582 "//\n"
1583 "// directional light contribution\n"
1584 "//\n"
1585 "vec3 directionalLight(\n"
1586 " in int i, // light identifier, i.e. current light\n"
1587 " in int j, // material identifier\n"
1588 " in vec3 n, // vertex normal in eye space\n"
1589 " in vec3 v) // view direction in eye space\n"
1590 "{\n"
1591 " if (lights.light[i].type != directional_light)\n"
1592 " return vec3(0.0, 0.0, 0.0);\n"
1593 "\n"
1594 " //\n"
1595 " // the light direction in eye space\n"
1596 " //\n"
1597 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
1598 "\n"
1599 " //\n"
1600 " // the half vector\n"
1601 " //\n"
1602 " vec3 h = normalize(l + v);\n"
1603 "\n"
1604 " float n_dot_l = max(0.0, dot(n, l));\n"
1605 " float n_dot_h = max(0.0, dot(n, h));\n"
1606 "\n"
1607 " float m = materials.material[j].shininess;\n"
1608 "\n"
1609 " float pf; // power factor\n"
1610 "\n"
1611 " if (n_dot_l == 0.0)\n"
1612 " pf = 0.0;\n"
1613 " else\n"
1614 " pf = pow(n_dot_h, m);\n"
1615 "\n"
1616 " return materials.material[j].emissive.rgb \n"
1617 " + lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1618 " + lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1619 " + lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1620 "}\n"
1621 "\n"
1622 "//\n"
1623 "// point light contribution\n"
1624 "//\n"
1625 "vec3 pointLight(\n"
1626 " in int i, // light identifier, i.e. current light\n"
1627 " in int j, // material identifier\n"
1628 " in vec3 n, // vertex normal in eye space\n"
1629 " in vec3 v, // view direction in eye space\n"
1630 " in vec3 p) // vertex position in eye space\n"
1631 "{\n"
1632 " if (lights.light[i].type != point_light)\n"
1633 " return vec3(0.0, 0.0, 0.0);\n"
1634 "\n"
1635 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1636 " float d = length(l); // distance from surface to light source\n"
1637 " l = normalize(l); // normalized direction from surface to light position\n"
1638 "\n"
1639 " //\n"
1640 " // the half vector\n"
1641 " //\n"
1642 " vec3 h = normalize(l + v);\n"
1643 "\n"
1644 " float n_dot_l = max(0.0, dot(n, l));\n"
1645 " float n_dot_h = max(0.0, dot(n, h));\n"
1646 "\n"
1647 " float m = materials.material[j].shininess;\n"
1648 "\n"
1649 " float pf; // power factor\n"
1650 "\n"
1651 " if (n_dot_l == 0.0)\n"
1652 " pf = 0.0;\n"
1653 " else\n"
1654 " pf = pow(n_dot_h, m);\n"
1655 "\n"
1656 " //\n"
1657 " // Compute attenuation\n"
1658 " //\n"
1659 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1660 " (lights.light[i].attenuation.y * d) + \n"
1661 " (lights.light[i].attenuation.z * d * d));\n"
1662 "\n"
1663 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1664 "\n"
1665 " return materials.material[j].emissive.rgb \n"
1666 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1667 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1668 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1669 "}\n"
1670 "\n"
1671 "//\n"
1672 "// spot light contribution\n"
1673 "//\n"
1674 "vec3 spotLight(\n"
1675 " in int i, // light identifier, i.e. current light\n"
1676 " in int j, // material identifier\n"
1677 " in vec3 n, // vertex normal in eye space\n"
1678 " in vec3 v, // view direction in eye space\n"
1679 " in vec3 p) // vertex position in eye space\n"
1680 "{\n"
1681 " if (lights.light[i].type != spot_light)\n"
1682 " return vec3(0.0, 0.0, 0.0);\n"
1683 "\n"
1684 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1685 " float d = length(l); // distance from surface to light source\n"
1686 " l = normalize(l); // normalized direction from surface to light position\n"
1687 " \n"
1688 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1689 "\n"
1690 " //\n"
1691 " // the half vector\n"
1692 " //\n"
1693 " vec3 h = normalize(l + v);\n"
1694 "\n"
1695 " float n_dot_l = max(0.0, dot(n, l));\n"
1696 " float n_dot_h = max(0.0, dot(n, h));\n"
1697 " float l_dot_s = dot(-l, s);\n"
1698 "\n"
1699 " float m = materials.material[j].shininess;\n"
1700 "\n"
1701 " float pf; // power factor\n"
1702 "\n"
1703 " if (n_dot_l == 0.0)\n"
1704 " pf = 0.0;\n"
1705 " else\n"
1706 " pf = pow(n_dot_h, m);\n"
1707 "\n"
1708 " //\n"
1709 " // Compute attenuation\n"
1710 " //\n"
1711 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1712 " (lights.light[i].attenuation.y * d) + \n"
1713 " (lights.light[i].attenuation.z * d * d));\n"
1714 "\n"
1715 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1716 "\n"
1717 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1718 " attenuation = 0.0;\n"
1719 " else\n"
1720 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
1721 "\n"
1722 " return materials.material[j].emissive.rgb \n"
1723 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1724 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1725 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1726 "}\n"
1727 "\n"
1728 "void main()\n"
1729 "{\n"
1730 " //\n"
1731 " // normalize the eye space normal\n"
1732 " //\n"
1733 " vec3 N = normalize(vNormalES);\n"
1734 "\n"
1735 " //\n"
1736 " // get the view vector and normalize it\n"
1737 " //\n"
1738 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
1739 "\n"
1740 " //\n"
1741 " // Integrate over all lights: Any unused light does not contribute and each light\n"
1742 " // contribute either from the directional light, the point light or the spot light.\n"
1743 " //\n"
1744 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
1745 " for (int i = 0; i < num_lights; ++i) {\n"
1746 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1747 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1748 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1749 " }\n"
1750 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1751 "\n"
1752 " //\n"
1753 " // Test TestBlock\n"
1754 " //\n"
1755 " if (test_block.a != 27.4) vFragColor = vec4(1, 0, 0, 1);\n"
1756 " if (test_block.b != vec2(15.3, 12.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1757 " if (test_block.c != vec3(11.4, 21.9, 10.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1758 "\n"
1759 " if (test_block.f.d != 61) vFragColor = vec4(1, 0, 0, 1);\n"
1760 " if (test_block.f.e != bvec2(true, false)) vFragColor = vec4(1, 0, 0, 1);\n"
1761 "\n"
1762 " if (test_block.g != 57.3) vFragColor = vec4(1, 0, 0, 1);\n"
1763 "\n"
1764 " if (test_block.h[0] != 9.1) vFragColor = vec4(1, 0, 0, 1);\n"
1765 " if (test_block.h[1] != 17.56) vFragColor = vec4(1, 0, 0, 1);\n"
1766 "\n"
1767 " if (test_block.i[0] != vec3(19.43,1243.2, 0.56)) vFragColor = vec4(1, 0, 0, 1);\n"
1768 " if (test_block.i[1] != vec3(13.54,264.22, 65.52)) vFragColor = vec4(1, 0, 0, 1);\n"
1769 "\n"
1770 " if (test_block.o[0].j != uvec3(10,11,12)) vFragColor = vec4(1, 0, 0, 1);\n"
1771 " if (test_block.o[0].k != vec2(64.62, 275.21)) vFragColor = vec4(1, 0, 0, 1);\n"
1772 " if (test_block.o[0].l[0] != 41.346) vFragColor = vec4(1, 0, 0, 1);\n"
1773 " if (test_block.o[0].l[1] != 67.9456) vFragColor = vec4(1, 0, 0, 1);\n"
1774 " if (test_block.o[0].m != vec2(-56.62, 768.276)) vFragColor = vec4(1, 0, 0, 1);\n"
1775 " if (test_block.o[0].n[0][0] != vec3(-0.4,-0.5,-0.6)) vFragColor = vec4(1, 0, 0, 1);\n"
1776 " if (test_block.o[0].n[0][1] != vec3(-0.7,-0.8,-0.9)) vFragColor = vec4(1, 0, 0, 1);\n"
1777 " if (test_block.o[0].n[0][2] != vec3(-0.1,-0.2,-0.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1778 " if (test_block.o[0].n[1][0] != vec3(1.1,2.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1779 " if (test_block.o[0].n[1][1] != vec3(1.2,2.3,3.4)) vFragColor = vec4(1, 0, 0, 1);\n"
1780 " if (test_block.o[0].n[1][2] != vec3(1.3,2.4,3.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1781 "\n"
1782 " if (test_block.o[1].j != uvec3(20,31,42)) vFragColor = vec4(1, 0, 0, 1);\n"
1783 " if (test_block.o[1].k != vec2(-96.62, -658.456)) vFragColor = vec4(1, 0, 0, 1);\n"
1784 " if (test_block.o[1].l[0] != 88.34) vFragColor = vec4(1, 0, 0, 1);\n"
1785 " if (test_block.o[1].l[1] != -488.21) vFragColor = vec4(1, 0, 0, 1);\n"
1786 " if (test_block.o[1].m != vec2(777.7, 888.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1787 " if (test_block.o[1].n[0][0] != vec3(1.1,1.2,1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1788 " if (test_block.o[1].n[0][1] != vec3(2.1,2.2,2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1789 " if (test_block.o[1].n[0][2] != vec3(3.1,3.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1790 " if (test_block.o[1].n[1][0] != vec3(-1.1,-1.2,-1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1791 " if (test_block.o[1].n[1][1] != vec3(-2.1,-2.2,-2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1792 " if (test_block.o[1].n[1][2] != vec3(-3.1,-3.2,-3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1793 "\n"
1794 "}\n"
1795 "\n"
1797 return fp_program;