Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
shape.cc
Go to the documentation of this file.
1 
18 #include <memory>
19 
20 #include "ion/base/datacontainer.h"
21 #include "ion/gfx/attributearray.h"
22 #include "ion/gfx/bufferobject.h"
23 #include "ion/gfx/indexbuffer.h"
24 #include "ion/gfx/node.h"
25 #include "ion/gfx/renderer.h"
26 #include "ion/gfx/sampler.h"
28 #include "ion/gfx/shaderprogram.h"
29 #include "ion/gfx/shape.h"
30 #include "ion/gfx/statetable.h"
31 #include "ion/gfx/texture.h"
32 #include "ion/gfx/uniform.h"
34 #include "ion/math/angle.h"
35 #include "ion/math/matrix.h"
36 #include "ion/math/range.h"
38 #include "ion/math/vector.h"
39 
41 #include "GL/freeglut.h"
42 
43 namespace {
44 
46 
51 
52 
53 struct GlobalState {
54  int window_width;
55  int window_height;
56  ion::gfx::NodePtr scene_root;
57  ion::gfx::RendererPtr renderer;
58 };
59 
60 static std::unique_ptr<GlobalState> s_global_state;
61 
63 
68 
69 
70 static const char* kVertexShaderString = (
71  "uniform mat4 uProjectionMatrix;\n"
72  "uniform mat4 uModelviewMatrix;\n"
73  "uniform mat4 uTextureMatrix;\n"
74  "attribute vec3 aVertex;\n"
75  "attribute vec2 aTexCoords;\n"
76  "attribute vec3 aNormal;\n"
77  "attribute float aOffsetAlongNormal;\n"
78  "varying vec3 vPosition;\n"
79  "varying vec2 vTexCoords;\n"
80  "varying vec3 vNormal;\n"
81  "\n"
82  "void main(void) {\n"
83  " vTexCoords = (uTextureMatrix * vec4(aTexCoords, 0., 1.)).st;\n"
84  " vPosition = aVertex + aOffsetAlongNormal * aNormal;\n"
85  " vNormal = aNormal;\n"
86  " gl_Position = uProjectionMatrix * uModelviewMatrix *\n"
87  " vec4(vPosition, 1.);\n"
88  "}\n");
89 
90 static const char* kFragmentShaderString = (
91  "#ifdef GL_ES\n"
92  "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
93  "precision highp float;\n"
94  "#else\n"
95  "precision mediump float;\n"
96  "#endif\n"
97  "#endif\n"
98  "\n"
99  "uniform sampler2D uSampler;\n"
100  "varying vec3 vPosition;\n"
101  "varying vec2 vTexCoords;\n"
102  "varying vec3 vNormal;\n"
103  "\n"
104  "void main(void) {\n"
105  " vec3 dir_to_light = normalize(vec3(6., 3., 10.));\n"
106  " float intensity = .3 * abs(dot(dir_to_light, vNormal));\n"
107  " gl_FragColor = intensity * texture2D(uSampler, vTexCoords);\n"
108  "}\n");
109 
111 
116 
117 
118 struct Vertex {
119  ion::math::Point3f position;
120  ion::math::Point2f texture_coords;
121  ion::math::Vector3f normal;
122  float offset_along_normal;
123 };
124 
125 static ion::gfx::BufferObjectPtr BuildPyramidBufferObject() {
126  const ion::math::Point3f apex(0.f, 1.f, 0.f);
127  const ion::math::Point3f back_left(-1.f, -1.f, -1.f);
128  const ion::math::Point3f back_right(1.f, -1.f, -1.f);
129  const ion::math::Point3f front_left(-1.f, -1.f, 1.f);
130  const ion::math::Point3f front_right(1.f, -1.f, 1.f);
131 
132  static const size_t kVertexCount = 12U; // 3 vertices for each of 4 sides.
133  Vertex vertices[kVertexCount];
134 
136  vertices[0].position = front_left; // Front side.
137  vertices[1].position = front_right;
138  vertices[2].position = apex;
139  vertices[3].position = front_right; // Right side.
140  vertices[4].position = back_right;
141  vertices[5].position = apex;
142  vertices[6].position = back_right; // Back side.
143  vertices[7].position = back_left;
144  vertices[8].position = apex;
145  vertices[9].position = back_left; // Left side.
146  vertices[10].position = front_left;
147  vertices[11].position = apex;
148 
150  for (int face = 0; face < 4; ++face) {
151  Vertex& v0 = vertices[3 * face + 0];
152  Vertex& v1 = vertices[3 * face + 1];
153  Vertex& v2 = vertices[3 * face + 2];
154  v0.normal = v1.normal = v2.normal = ion::math::Cross(
155  v1.position - v0.position, v2.position - v0.position);
156  v0.texture_coords.Set(0.f, 0.f);
157  v1.texture_coords.Set(1.f, 0.f);
158  v2.texture_coords.Set(.5f, 1.f);
159  }
160 
162  for (size_t v = 0; v < kVertexCount; ++v)
163  vertices[v].offset_along_normal = .05f * static_cast<float>(1U + v % 2U);
164 
165  ion::base::DataContainerPtr data_container =
166  ion::base::DataContainer::CreateAndCopy<Vertex>(
167  vertices, kVertexCount, true, ion::base::AllocatorPtr());
169  buffer_object->SetData(data_container, sizeof(vertices[0]), kVertexCount,
171  return buffer_object;
172 }
173 
174 const ion::gfx::AttributeArrayPtr BuildPyramidAttributeArray(
176  ion::gfx::BufferObjectPtr buffer_object = BuildPyramidBufferObject();
177 
179  Vertex v;
181  .Bind(v.position, "aVertex")
182  .Bind(v.texture_coords, "aTexCoords")
183  .Bind(v.normal, "aNormal")
184  .Bind(v.offset_along_normal, "aOffsetAlongNormal")
185  .Apply(reg, attribute_array, buffer_object);
186  return attribute_array;
187 }
188 
189 static const ion::gfx::IndexBufferPtr BuildPyramidIndexBuffer() {
191 
192  static const size_t kIndexCount = 12U;
193  uint16 indices[kIndexCount];
194  for (size_t i = 0; i < kIndexCount; ++i)
195  indices[i] = static_cast<uint16>(i);
196 
197  ion::base::DataContainerPtr data_container =
198  ion::base::DataContainer::CreateAndCopy<uint16>(
199  indices, kIndexCount, true, ion::base::AllocatorPtr());
200 
201  index_buffer->AddSpec(ion::gfx::BufferObject::kUnsignedShort, 1, 0);
202  index_buffer->SetData(data_container, sizeof(indices[0]), kIndexCount,
204 
205  return index_buffer;
206 }
207 
208 const ion::gfx::ShapePtr BuildPyramidShape(
211  shape->SetLabel("Pyramid");
212  shape->SetPrimitiveType(ion::gfx::Shape::kTriangles);
213  shape->SetAttributeArray(BuildPyramidAttributeArray(reg));
214  shape->SetIndexBuffer(BuildPyramidIndexBuffer());
215  return shape;
216 }
217 
218 static const ion::math::Matrix4f BuildTextureRotationMatrix(float degrees) {
219  return
220  ion::math::TranslationMatrix(ion::math::Vector3f(.5f, .5f, 0.f)) *
222  ion::math::Vector3f::AxisZ(),
223  ion::math::Anglef::FromDegrees(degrees)) *
224  ion::math::TranslationMatrix(ion::math::Vector3f(-.5f, -.5f, 0.f));
225 }
226 
227 static ion::gfx::TexturePtr BuildTexture() {
229  static const int kWidth = 2;
230  static const int kHeight = 2;
231  static const int kRowSize = kWidth * 3;
232  static const uint8 pixels[kHeight * kRowSize] = {
233  0xee, 0x22, 0xee, 0x00, 0x55, 0xdd, // Bottom row : magenta, blue.
234  0x00, 0xdd, 0xaa, 0xdd, 0xcc, 0x33, // Top row: green, yellow.
235  };
236 
238  ion::base::DataContainerPtr data_container =
239  ion::base::DataContainer::CreateAndCopy<uint8>(
240  pixels, sizeof(pixels), true, ion::base::AllocatorPtr());
241  image->Set(ion::gfx::Image::kRgb888, kWidth, kHeight, data_container);
242 
246  sampler->SetWrapS(ion::gfx::Sampler::kClampToEdge);
247  sampler->SetWrapT(ion::gfx::Sampler::kClampToEdge);
248 
250  texture->SetImage(0U, image);
251  texture->SetSampler(sampler);
252  return texture;
253 }
254 
255 static const ion::gfx::NodePtr BuildGraph(int window_width, int window_height) {
257 
258  ion::gfx::StateTablePtr state_table(
259  new ion::gfx::StateTable(window_width, window_height));
260  state_table->SetViewport(
261  ion::math::Range2i::BuildWithSize(ion::math::Point2i(0, 0),
262  ion::math::Vector2i(window_width,
263  window_height)));
264  state_table->SetClearColor(ion::math::Vector4f(0.3f, 0.3f, 0.5f, 1.0f));
265  state_table->SetClearDepthValue(1.f);
266  state_table->Enable(ion::gfx::StateTable::kDepthTest, true);
267  state_table->Enable(ion::gfx::StateTable::kCullFace, false);
268  root->SetStateTable(state_table);
269 
271  reg->IncludeGlobalRegistry();
273  "aOffsetAlongNormal", ion::gfx::kBufferObjectElementAttribute,
274  "Offset of each vertex along its surface normal vector"));
276  "uTextureMatrix", ion::gfx::kMatrix4x4Uniform,
277  "Matrix applied to texture coordinates"));
279  "uSampler", ion::gfx::kTextureUniform,
280  "Texture sampler"));
281  root->SetShaderProgram(
283  "Example shader", reg, kVertexShaderString,
284  kFragmentShaderString, ion::base::AllocatorPtr()));
285 
286  root->AddShape(BuildPyramidShape(reg));
287 
288  const ion::math::Matrix4f proj =
289  ion::math::PerspectiveMatrixFromView(ion::math::Anglef::FromDegrees(60.f),
290  1.f, .1f, 10.f);
291  const ion::math::Matrix4f view =
292  ion::math::LookAtMatrixFromCenter(ion::math::Point3f(3.f, 2.f, 5.f),
293  ion::math::Point3f::Zero(),
294  ion::math::Vector3f::AxisY());
295  const ion::math::Matrix4f tex_mtx = BuildTextureRotationMatrix(30.f);
296 
297  root->AddUniform(reg->Create<ion::gfx::Uniform>("uProjectionMatrix", proj));
298  root->AddUniform(reg->Create<ion::gfx::Uniform>("uModelviewMatrix", view));
299  root->AddUniform(reg->Create<ion::gfx::Uniform>("uTextureMatrix", tex_mtx));
300  root->AddUniform(reg->Create<ion::gfx::Uniform>("uSampler", BuildTexture()));
301 
302  return root;
303 }
304 
306 
311 
312 
313 static void Resize(int w, int h) {
314  s_global_state->window_width = w;
315  s_global_state->window_height = h;
316  glutPostRedisplay();
317 }
318 
319 static void Render() {
320  if (s_global_state.get())
321  s_global_state->renderer->DrawScene(s_global_state->scene_root);
322  glutSwapBuffers();
323 }
324 
325 static void Update() {
326  glutPostRedisplay();
327 }
328 
329 static void Keyboard(unsigned char key, int x, int y) {
330  glutPostRedisplay();
331 }
332 
333 static void KeyboardUp(unsigned char key, int x, int y) {
334  switch (key) {
335  case 27: // Escape.
336  s_global_state.reset(NULL);
337  glutLeaveMainLoop();
338  break;
339  }
340  glutPostRedisplay();
341 }
342 
343 } // anonymous namespace
344 
346 
351 
352 
353 int main(int argc, char* argv[]) {
354  glutInit(&argc, argv);
355 
356  s_global_state.reset(new GlobalState);
357  s_global_state->window_width = s_global_state->window_height = 800;
358  s_global_state->scene_root = BuildGraph(s_global_state->window_width,
359  s_global_state->window_height);
360 
361  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
362  glutSetOption(GLUT_MULTISAMPLE, 16);
363  glutInitWindowSize(s_global_state->window_width,
364  s_global_state->window_height);
365 
366  glutCreateWindow("Ion shape example");
367  glutDisplayFunc(Render);
368  glutReshapeFunc(Resize);
369  glutKeyboardFunc(Keyboard);
370  glutKeyboardUpFunc(KeyboardUp);
371  glutIdleFunc(Update);
372 
375  s_global_state->renderer.Reset(new ion::gfx::Renderer(graphics_manager));
376 
377  glutMainLoop();
378 }
GraphicsManager manages the graphics library for an application.
A Texture object represents the image data and mipmaps associated with a single texture.
Definition: texture.h:264
Vector3f normal
Definition: shapeutils.cc:81
This struct is stored for each registered ShaderInput.
An IndexBuffer is a type of BufferObject that contains the element indices of an array, e.g., a vertex index array.
Definition: indexbuffer.h:28
const Matrix< 4, T > RotationMatrixAxisAngleH(const Vector< 3, T > &axis, const Angle< T > &angle)
Returns a 4x4 Matrix representing a 3D rotation specified as axis and angle.
Point2f texture_coords
Definition: shapeutils.cc:74
A Uniform instance represents a uniform shader argument.
Definition: uniform.h:76
SharedPtr< Allocator > AllocatorPtr
Definition: allocator.h:51
ION_API const Matrix< 4, T > LookAtMatrixFromCenter(const Point< 3, T > &eye, const Point< 3, T > &center, const Vector< 3, T > &up)
View matrices.
An Image represents 2D image data that can be used in a texture supplied to a shader.
Definition: image.h:35
Point3f position
Definition: shapeutils.cc:67
A ShaderInputRegistry is used to manage a collection of shader inputs to a specific ShaderProgram (bo...
A BufferObject describes a generic array of data used, for example, to describe the vertices in a Sha...
Definition: bufferobject.h:67
The Matrix class defines a square N-dimensional matrix.
Definition: matrix.h:35
A Shape object represents a shape (vertices + indices) to draw.
Definition: shape.h:32
const Matrix< Dimension+1, T > TranslationMatrix(const VectorBase< Dimension, T > &t)
Affine transformation matrices.
ION_API const Matrix< 4, T > PerspectiveMatrixFromView(const Angle< T > &fovy, T aspect, T z_near, T z_far)
Returns a 4x4 perspective projection matrix based on the given parameters, which follow the conventio...
An AttributeArray represents a collection of Attributes used to describe the vertices of a Shape...
const Grid & image
The original monochrome image data, as doubles (0 - 1).
Definition: sdfutils.cc:90
BufferToAttributeBinder is a simple interface to insert a set of Attributes containing BufferObjectEl...
BufferToAttributeBinder & Bind(const FieldType &field, const std::string &attribute_name)
TexturePtr texture
The Texture to add sub-image data to.
Definition: fontimage.cc:107
static const ShaderProgramPtr BuildFromStrings(const std::string &id_string, const ShaderInputRegistryPtr &registry_ptr, const std::string &vertex_shader_string, const std::string &fragment_shader_string, const base::AllocatorPtr &allocator)
Convenience function that builds and returns a new ShaderProgram instance that uses the given ShaderI...
int main(int argc, char *argv[])
Mainline.
Definition: shape.cc:353
A StateTable represents a collection of graphical state items that affect OpenGL rendering.
Definition: statetable.h:48
Vector< 3, T > Cross(const Vector< 3, T > &v0, const Vector< 3, T > &v1)
Returns the 3-dimensional cross product of 2 Vectors.
Definition: vectorutils.h:48
A Node instance represents a node in a scene graph.
Definition: node.h:45
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
The Renderer class handles rendering ION scene graphs using OpenGL.
Definition: renderer.h:50
A Sampler object represents texture parameters that control how texture data is accessed in shaders...
Definition: sampler.h:29
void Apply(const gfx::ShaderInputRegistryPtr &reg, const gfx::AttributeArrayPtr &aa, const gfx::BufferObjectPtr &bo)