1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Based on Simple_Texture2D.c from
8 // Book: OpenGL(R) ES 2.0 Programming Guide
9 // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
10 // ISBN-10: 0321502795
11 // ISBN-13: 9780321502797
12 // Publisher: Addison-Wesley Professional
13 // URLs: http://safari.informit.com/9780321563835
14 // http://www.opengles-book.com
15
16 #include "SampleApplication.h"
17
18 #include "common/vector_utils.h"
19 #include "texture_utils.h"
20 #include "util/shader_utils.h"
21
22 #include <cstring>
23 #include <iostream>
24 #include <vector>
25
26 using namespace angle;
27
28 class SimpleInstancingSample : public SampleApplication
29 {
30 public:
SimpleInstancingSample(int argc,char ** argv)31 SimpleInstancingSample(int argc, char **argv)
32 : SampleApplication("SimpleInstancing", argc, argv)
33 {}
34
initialize()35 bool initialize() override
36 {
37 // init instancing functions
38 char *extensionString = (char *)glGetString(GL_EXTENSIONS);
39 if (strstr(extensionString, "GL_ANGLE_instanced_arrays"))
40 {
41 mVertexAttribDivisorANGLE =
42 (PFNGLVERTEXATTRIBDIVISORANGLEPROC)eglGetProcAddress("glVertexAttribDivisorANGLE");
43 mDrawArraysInstancedANGLE =
44 (PFNGLDRAWARRAYSINSTANCEDANGLEPROC)eglGetProcAddress("glDrawArraysInstancedANGLE");
45 mDrawElementsInstancedANGLE = (PFNGLDRAWELEMENTSINSTANCEDANGLEPROC)eglGetProcAddress(
46 "glDrawElementsInstancedANGLE");
47 }
48
49 if (!mVertexAttribDivisorANGLE || !mDrawArraysInstancedANGLE ||
50 !mDrawElementsInstancedANGLE)
51 {
52 std::cerr << "Unable to load GL_ANGLE_instanced_arrays entry points.";
53 return false;
54 }
55
56 constexpr char kVS[] = R"(attribute vec3 a_position;
57 attribute vec2 a_texCoord;
58 attribute vec3 a_instancePos;
59 varying vec2 v_texCoord;
60 void main()
61 {
62 gl_Position = vec4(a_position.xyz + a_instancePos.xyz, 1.0);
63 v_texCoord = a_texCoord;
64 })";
65
66 constexpr char kFS[] = R"(precision mediump float;
67 varying vec2 v_texCoord;
68 uniform sampler2D s_texture;
69 void main()
70 {
71 gl_FragColor = texture2D(s_texture, v_texCoord);
72 })";
73
74 mProgram = CompileProgram(kVS, kFS);
75 if (!mProgram)
76 {
77 return false;
78 }
79
80 // Get the attribute locations
81 mPositionLoc = glGetAttribLocation(mProgram, "a_position");
82 mTexCoordLoc = glGetAttribLocation(mProgram, "a_texCoord");
83 mInstancePosLoc = glGetAttribLocation(mProgram, "a_instancePos");
84
85 // Get the sampler location
86 mSamplerLoc = glGetUniformLocation(mProgram, "s_texture");
87
88 // Load the texture
89 mTextureID = CreateSimpleTexture2D();
90
91 // Initialize the vertex and index vectors
92 const GLfloat quadRadius = 0.01f;
93
94 mVertices.push_back(Vector3(-quadRadius, quadRadius, 0.0f));
95 mVertices.push_back(Vector3(-quadRadius, -quadRadius, 0.0f));
96 mVertices.push_back(Vector3(quadRadius, -quadRadius, 0.0f));
97 mVertices.push_back(Vector3(quadRadius, quadRadius, 0.0f));
98
99 mTexcoords.push_back(Vector2(0.0f, 0.0f));
100 mTexcoords.push_back(Vector2(0.0f, 1.0f));
101 mTexcoords.push_back(Vector2(1.0f, 1.0f));
102 mTexcoords.push_back(Vector2(1.0f, 0.0f));
103
104 mIndices.push_back(0);
105 mIndices.push_back(1);
106 mIndices.push_back(2);
107 mIndices.push_back(0);
108 mIndices.push_back(2);
109 mIndices.push_back(3);
110
111 // Tile thousands of quad instances
112 for (float y = -1.0f + quadRadius; y < 1.0f - quadRadius; y += quadRadius * 3)
113 {
114 for (float x = -1.0f + quadRadius; x < 1.0f - quadRadius; x += quadRadius * 3)
115 {
116 mInstances.push_back(Vector3(x, y, 0.0f));
117 }
118 }
119
120 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
121
122 return true;
123 }
124
destroy()125 void destroy() override
126 {
127 glDeleteProgram(mProgram);
128 glDeleteTextures(1, &mTextureID);
129 }
130
draw()131 void draw() override
132 {
133 // Set the viewport
134 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
135
136 // Clear the color buffer
137 glClear(GL_COLOR_BUFFER_BIT);
138
139 // Use the program object
140 glUseProgram(mProgram);
141
142 // Load the vertex position
143 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, mVertices.data());
144 glEnableVertexAttribArray(mPositionLoc);
145
146 // Load the texture coordinate
147 glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, mTexcoords.data());
148 glEnableVertexAttribArray(mTexCoordLoc);
149
150 // Load the instance position
151 glVertexAttribPointer(mInstancePosLoc, 3, GL_FLOAT, GL_FALSE, 0, mInstances.data());
152 glEnableVertexAttribArray(mInstancePosLoc);
153
154 // Enable instancing
155 mVertexAttribDivisorANGLE(mInstancePosLoc, 1);
156
157 // Bind the texture
158 glActiveTexture(GL_TEXTURE0);
159 glBindTexture(GL_TEXTURE_2D, mTextureID);
160
161 // Set the sampler texture unit to 0
162 glUniform1i(mSamplerLoc, 0);
163
164 // Do the instanced draw
165 mDrawElementsInstancedANGLE(GL_TRIANGLES, static_cast<GLsizei>(mIndices.size()),
166 GL_UNSIGNED_SHORT, mIndices.data(),
167 static_cast<GLsizei>(mInstances.size()));
168 }
169
170 private:
171 // Handle to a program object
172 GLuint mProgram;
173
174 // Attribute locations
175 GLint mPositionLoc;
176 GLint mTexCoordLoc;
177
178 // Sampler location
179 GLint mSamplerLoc;
180
181 // Texture handle
182 GLuint mTextureID;
183
184 // Instance VBO
185 GLint mInstancePosLoc;
186
187 // Loaded entry points
188 PFNGLVERTEXATTRIBDIVISORANGLEPROC mVertexAttribDivisorANGLE;
189 PFNGLDRAWARRAYSINSTANCEDANGLEPROC mDrawArraysInstancedANGLE;
190 PFNGLDRAWELEMENTSINSTANCEDANGLEPROC mDrawElementsInstancedANGLE;
191
192 // Vertex data
193 std::vector<Vector3> mVertices;
194 std::vector<Vector2> mTexcoords;
195 std::vector<Vector3> mInstances;
196 std::vector<GLushort> mIndices;
197 };
198
main(int argc,char ** argv)199 int main(int argc, char **argv)
200 {
201 SimpleInstancingSample app(argc, argv);
202 return app.run();
203 }
204