1 #include <QtGui/QGuiApplication>
2 #include <QtGui/QKeyEvent>
3 #include <QtGui/QOpenGLWindow>
4 #include <QtGui/QOpenGLBuffer>
5 #include <QtGui/QOpenGLFunctions>
6 #include <QtGui/QOpenGLShaderProgram>
7 #include <QtGui/QOpenGLVertexArrayObject>
8 static QString vertexShader =
11 "attribute vec3 vertexPosition;\n"
12 "attribute vec3 vertexNormal;\n"
13 "attribute vec3 vertexColor;\n"
14 "attribute vec2 texCoord2d;\n"
16 "uniform mat4 modelViewMatrix;\n"
17 "uniform mat3 normalMatrix;\n"
18 "uniform mat4 projectionMatrix;\n"
20 "struct LightSource\n"
27 "uniform LightSource lightSource;\n"
33 "uniform LightModel lightModel;\n"
40 "uniform Material material;\n"
42 "varying vec3 v_color;\n"
43 "varying vec2 v_texCoord2d;\n"
47 " vec3 normal = normalize(normalMatrix * vertexNormal); // normal vector \n"
48 " vec3 position = vec3(modelViewMatrix * vec4(vertexPosition, 1)); // vertex pos in eye coords \n"
49 " vec3 halfVector = normalize(lightSource.position + vec3(0,0,1)); // light half vector \n"
50 " float nDotVP = dot(normal, normalize(lightSource.position)); // normal . light direction \n"
51 " float nDotHV = max(0.f, dot(normal, halfVector)); // normal . light half vector \n"
52 " float pf = mix(0.f, pow(nDotHV, material.shininess), step(0.f, nDotVP)); // power factor \n"
54 " vec3 ambient = lightSource.ambient;\n"
55 " vec3 diffuse = lightSource.diffuse * nDotVP;\n"
56 " vec3 specular = lightSource.specular * pf;\n"
57 " vec3 sceneColor = material.emission + vertexColor * lightModel.ambient;\n"
59 " v_color = clamp(sceneColor + \n"
60 " ambient * vertexColor + \n"
61 " diffuse * vertexColor + \n"
62 " specular * material.specular, 0.f, 1.f );\n"
64 " v_texCoord2d = texCoord2d;\n"
66 " gl_Position = projectionMatrix * modelViewMatrix * vec4(vertexPosition, 1);\n"
69 static QString fragmentShader =
71 "precision lowp vec3;\n"
72 "precision lowp vec2;\n"
73 "uniform sampler2D texUnit;\n"
75 "varying vec3 v_color;\n"
76 "varying vec2 v_texCoord2d;\n"
80 " gl_FragColor = vec4(v_color, 1) * texture2D(texUnit, v_texCoord2d);\n"
84 * Texture copied and modifided modified from:
85 * <a href="https://www.opengl.org/archives/resources/code/samples/mjktips/TexShadowReflectLight.html
87 static char *circles[] = {
105 struct Window : QOpenGLWindow, QOpenGLFunctions
108 m_vbo(QOpenGLBuffer::VertexBuffer),
109 m_ibo(QOpenGLBuffer::IndexBuffer)
112 void createShaderProgram()
114 if ( !m_pgm.addShaderFromSourceCode( QOpenGLShader::Vertex, vertexShader)) {
115 qDebug() << "Error in vertex shader:" << m_pgm.log();
118 if ( !m_pgm.addShaderFromSourceCode( QOpenGLShader::Fragment, fragmentShader)) {
119 qDebug() << "Error in fragment shader:" << m_pgm.log();
122 if ( !m_pgm.link() ) {
123 qDebug() << "Error linking shader program:" << m_pgm.log();
127 void createGeometry()
129 // Initialize and bind the VAO that's going to capture all this vertex state
132 // we need 24 vertices, 24 normals, and 24 colors (6 faces, 4 vertices per face)
133 // since we can't share normal data at the corners (each corner gets 3 normals)
134 // and since we're not using glVertexAttribDivisor (not available in ES 2.0)
141 // Top face (y = 1.0f)
142 { { 1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f} }, // Green
143 { {-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f} }, // Green
144 { {-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 1.0f, 1.0f} }, // Green
145 { { 1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f} }, // Green
146 // Bottom face (y = -1.0f)
147 { { 1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 0.0f, 0.0f} }, // Orange
148 { {-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 0.0f, 1.0f} }, // Orange
149 { {-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 1.0f, 1.0f} }, // Orange
150 { { 1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 1.0f, 0.0f} }, // Orange
151 // Front face (z = 1.0f)
152 { { 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f} }, // Red
153 { {-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 0.0f, 1.0f} }, // Red
154 { {-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f} }, // Red
155 { { 1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f} }, // Red
156 // Back face (z = -1.0f)
157 { { 1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 0.0f, 0.0f} }, // Yellow
158 { {-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 0.0f, 1.0f} }, // Yellow
159 { {-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 1.0f, 1.0f} }, // Yellow
160 { { 1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 1.0f, 0.0f} }, // Yellow
161 // Left face (x = -1.0f)
162 { {-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f} }, // Blue
163 { {-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 0.0f, 1.0f} }, // Blue
164 { {-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 1.0f, 1.0f} }, // Blue
165 { {-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f} }, // Blue
166 // Right face (x = 1.0f)
167 { {1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 0.0f, 0.0f} }, // Magenta
168 { {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 0.0f, 1.0f} }, // Magenta
169 { {1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 1.0f, 1.0f} }, // Magenta
170 { {1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 1.0f, 0.0f} }, // Magenta
172 // Put all the attribute data in a FBO
174 m_vbo.setUsagePattern( QOpenGLBuffer::StaticDraw );
176 m_vbo.allocate(&attribs, sizeof(attribs));
177 // Configure the vertex streams for this attribute data layout
178 m_pgm.enableAttributeArray("vertexPosition");
179 m_pgm.setAttributeBuffer("vertexPosition", GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex) );
180 m_pgm.enableAttributeArray("vertexNormal");
181 m_pgm.setAttributeBuffer("vertexNormal", GL_FLOAT, offsetof(Vertex, normal), 3, sizeof(Vertex) );
182 m_pgm.enableAttributeArray("vertexColor");
183 m_pgm.setAttributeBuffer("vertexColor", GL_FLOAT, offsetof(Vertex, color), 3, sizeof(Vertex) );
184 m_pgm.enableAttributeArray("texCoord2d");
185 m_pgm.setAttributeBuffer("texCoord2d", GL_FLOAT, offsetof(Vertex, texcoord), 3, sizeof(Vertex) );
186 // we need 36 indices (6 faces, 2 triangles per face, 3 vertices per triangle)
190 m_cnt=0; for (GLsizei i=0, v=0; v<6*4; v+=4)
192 // first triangle (ccw winding)
193 indices.cube[i++] = v + 0;
194 indices.cube[i++] = v + 1;
195 indices.cube[i++] = v + 2;
196 // second triangle (ccw winding)
197 indices.cube[i++] = v + 0;
198 indices.cube[i++] = v + 2;
199 indices.cube[i++] = v + 3;
202 // Put all the index data in a IBO
204 m_ibo.setUsagePattern( QOpenGLBuffer::StaticDraw );
206 m_ibo.allocate(&indices, sizeof(indices));
207 // Okay, we've finished setting up the vao
210 void createTexture(void)
212 GLubyte image[16][16][3];
215 /* Setup RGB image for the texture. */
216 loc = (GLubyte*) image;
217 for (t = 0; t < 16; t++) {
218 for (s = 0; s < 16; s++) {
219 if (circles[t][s] == 'x') {
233 glGenTextures (1, &m_tex);
234 glBindTexture (GL_TEXTURE_2D, m_tex);
235 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
236 glTexImage2D (GL_TEXTURE_2D, 0, 3, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
244 QOpenGLFunctions::initializeOpenGLFunctions();
245 createShaderProgram(); m_pgm.bind();
246 // Set lighting information
247 m_pgm.setUniformValue("lightSource.ambient", QVector3D( 0.0f, 0.0f, 0.0f )); // opengl fixed-function default
248 m_pgm.setUniformValue("lightSource.diffuse", QVector3D( 1.0f, 1.0f, 1.0f )); // opengl fixed-function default
249 m_pgm.setUniformValue("lightSource.specular", QVector3D( 1.0f, 1.0f, 1.0f )); // opengl fixed-function default
250 m_pgm.setUniformValue("lightSource.position", QVector3D( 1.0f, 1.0f, 1.0f )); // NOT DEFAULT VALUE
251 m_pgm.setUniformValue("lightModel.ambient", QVector3D( 0.2f, 0.2f, 0.2f )); // opengl fixed-function default
252 m_pgm.setUniformValue("material.emission", QVector3D( 0.0f, 0.0f, 0.0f )); // opengl fixed-function default
253 m_pgm.setUniformValue("material.specular", QVector3D( 1.0f, 1.0f, 1.0f )); // NOT DEFAULT VALUE
254 m_pgm.setUniformValue("material.shininess", 10.0f); // NOT DEFAULT VALUE
256 m_view.setToIdentity();
257 glEnable(GL_DEPTH_TEST);
258 glEnable(GL_TEXTURE_2D);
259 glActiveTexture(GL_TEXTURE0);
260 m_pgm.setUniformValue("texUnit", 0);
262 glClearColor(.5f,.5f,.5f,1.f);
264 void resizeGL(int w, int h)
266 glViewport(0, 0, w, h);
267 m_projection.setToIdentity();
269 m_projection.ortho(-2.f, 2.f, -2.f*h/w, 2.f*h/w, -2.f, 2.f);
271 m_projection.ortho(-2.f*w/h, 2.f*w/h, -2.f, 2.f, -2.f, 2.f);
277 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
278 glActiveTexture(GL_TEXTURE0);
279 glBindTexture(GL_TEXTURE_2D, m_tex);
281 model.rotate(cnt%360, 1,0,0);
282 model.rotate(45, 0,0,1);
283 QMatrix4x4 mv = m_view * model;
285 m_pgm.setUniformValue("modelViewMatrix", mv);
286 m_pgm.setUniformValue("normalMatrix", mv.normalMatrix());
287 m_pgm.setUniformValue("projectionMatrix", m_projection);
289 glDrawElements(GL_TRIANGLES, m_cnt, GL_UNSIGNED_BYTE, 0);
293 void keyPressEvent(QKeyEvent * ev)
300 QOpenGLWindow::keyPressEvent(ev);
304 QMatrix4x4 m_projection, m_view;
305 QOpenGLShaderProgram m_pgm;
306 QOpenGLVertexArrayObject m_vao;
312 int main(int argc, char *argv[])
314 QGuiApplication a(argc,argv);
316 w.setWidth(640); w.setHeight(480);