forked from skuhl/opengl-examples
/
ogl3-triangle.c
245 lines (208 loc) · 8.28 KB
/
ogl3-triangle.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <GL/glew.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/freeglut.h>
#endif
#include "kuhl-util.h"
#include "vecmat.h"
#include "dgr.h"
#include "projmat.h"
#include "viewmat.h"
GLuint program = 0; // id value for the GLSL program
kuhl_geometry triangle;
kuhl_geometry quad;
/* Called by GLUT whenever a key is pressed. */
void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case 'q':
case 'Q':
case 27: // ASCII code for Escape key
exit(0);
break;
}
/* Whenever any key is pressed, request that display() get
* called. */
glutPostRedisplay();
}
/* Called by GLUT whenever the window needs to be redrawn. This
* function should not be called directly by the programmer. Instead,
* we can call glutPostRedisplay() to request that GLUT call display()
* at some point. */
void display()
{
/* If we are using DGR, send or receive data to keep multiple
* processes/computers synchronized. */
dgr_update();
glClearColor(.2,.2,.2,0); // set clear color to grey
// Clear the screen to black, clear the depth buffer
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); // turn on depth testing
kuhl_errorcheck();
/* Render the scene once for each viewport. Frequently one
* viewport will fill the entire screen. However, this loop will
* run twice for HMDs (once for the left eye and once for the
* right. */
for(int viewportID=0; viewportID<viewmat_num_viewports(); viewportID++)
{
/* Where is the viewport that we are drawing onto and what is its size? */
int viewport[4]; // x,y of lower left corner, width, height
viewmat_get_viewport(viewport, viewportID);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
/* Get the frustum information which will be later used to generate a perspective projection matrix. */
float f[6]; // left, right, top, bottom, near>0, far>0
projmat_get_frustum(f, viewport[2], viewport[3]);
/* Get the view or camera matrix; update the frustum values if needed. */
float viewMat[16];
viewmat_get(viewMat, f, viewportID);
/* Create a 4x4 perspective projection matrix from the frustum values. */
float perspective[16];
mat4f_frustum_new(perspective,f[0], f[1], f[2], f[3], f[4], f[5]);
/* Calculate an angle to rotate the
* object. glutGet(GLUT_ELAPSED_TIME) is the number of
* milliseconds since glutInit() was called. */
int count = glutGet(GLUT_ELAPSED_TIME) % 10000; // get a counter that repeats every 10 seconds
float angle = count / 10000.0 * 360; // rotate 360 degrees every 10 seconds
/* Make sure all computers/processes use the same angle */
dgr_setget("angle", &angle, sizeof(GLfloat));
/* Create a 4x4 rotation matrix based on the angle we computed. */
float rotateMat[16];
mat4f_rotateAxis_new(rotateMat, angle, 0,1,0);
/* Create a scale matrix. */
float scaleMatrix[16];
mat4f_scale_new(scaleMatrix, 3, 3, 3);
// Modelview = (viewMatrix * scaleMatrix) * rotationMatrix
float modelview[16];
mat4f_mult_mat4f_new(modelview, viewMat, scaleMatrix);
mat4f_mult_mat4f_new(modelview, modelview, rotateMat);
kuhl_errorcheck();
glUseProgram(program);
kuhl_errorcheck();
/* Send the perspective projection matrix to the vertex program. */
glUniformMatrix4fv(kuhl_get_uniform("Projection"),
1, // number of 4x4 float matrices
0, // transpose
perspective); // value
/* Send the modelview matrix to the vertex program. */
glUniformMatrix4fv(kuhl_get_uniform("ModelView"),
1, // number of 4x4 float matrices
0, // transpose
modelview); // value
kuhl_errorcheck();
/* Draw the geometry using the matrices that we sent to the
* vertex programs immediately above */
kuhl_geometry_draw(&triangle);
kuhl_geometry_draw(&quad);
glUseProgram(0); // stop using a GLSL program.
} // finish viewport loop
/* Check for errors. If there are errors, consider adding more
* calls to kuhl_errorcheck() in your code. */
kuhl_errorcheck();
/* Display the buffer we just drew (necessary for double buffering). */
glutSwapBuffers();
/* Ask GLUT to call display() again. We shouldn't call display()
* ourselves recursively because it will not leave time for GLUT
* to call other callback functions for when a key is pressed, the
* window is resized, etc. */
glutPostRedisplay();
}
void init_geometryTriangle(kuhl_geometry *geom, GLuint program)
{
kuhl_geometry_new(geom, program, 3, // num vertices
GL_TRIANGLES); // primitive type
/* The data that we want to draw */
GLfloat vertexPositions[] = {0, 0, 0,
1, 0, 0,
1, 1, 0};
kuhl_geometry_attrib(geom, vertexPositions, // data
3, // number of components (x,y,z)
"in_Position", // GLSL variable
KG_WARN); // warn if attribute is missing in GLSL program?
}
/* This illustrates how to draw a quad by drawing two triangles and reusing vertices. */
void init_geometryQuad(kuhl_geometry *geom, GLuint program)
{
kuhl_geometry_new(geom, program,
4, // number of vertices
GL_TRIANGLES); // type of thing to draw
/* The data that we want to draw */
GLfloat vertexPositions[] = {0+1.1, 0, 0,
1+1.1, 0, 0,
1+1.1, 1, 0,
0+1.1, 1, 0 };
kuhl_geometry_attrib(geom, vertexPositions,
3, // number of components x,y,z
"in_Position", // GLSL variable
KG_WARN); // warn if attribute is missing in GLSL program?
GLuint indexData[] = { 0, 1, 2, // first triangle is index 0, 1, and 2 in the list of vertices
0, 2, 3 }; // indices of second triangle.
kuhl_geometry_indices(geom, indexData, 6);
kuhl_errorcheck();
}
int main(int argc, char** argv)
{
/* set up our GLUT window */
glutInit(&argc, argv);
glutInitWindowSize(512, 512);
/* Ask GLUT to for a double buffered, full color window that
* includes a depth buffer */
#ifdef __APPLE__
glutInitDisplayMode(GLUT_3_2_CORE_PROFILE | GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
#else
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitContextVersion(3,2);
glutInitContextProfile(GLUT_CORE_PROFILE);
#endif
glutCreateWindow(argv[0]); // set window title to executable name
/* Initialize GLEW */
glewExperimental = GL_TRUE;
GLenum glewError = glewInit();
if(glewError != GLEW_OK)
{
fprintf(stderr, "Error initializing GLEW: %s\n", glewGetErrorString(glewError));
exit(EXIT_FAILURE);
}
/* When experimental features are turned on in GLEW, the first
* call to glGetError() or kuhl_errorcheck() may incorrectly
* report an error. So, we call glGetError() to ensure that a
* later call to glGetError() will only see correct errors. For
* details, see:
* http://www.opengl.org/wiki/OpenGL_Loading_Library */
glGetError();
// setup callbacks
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
/* Compile and link a GLSL program composed of a vertex shader and
* a fragment shader. */
program = kuhl_create_program("ogl3-triangle.vert", "ogl3-triangle.frag");
glUseProgram(program);
kuhl_errorcheck();
/* Set the uniform variable in the shader that is named "red" to the value 1. */
glUniform1i(kuhl_get_uniform("red"), 1);
kuhl_errorcheck();
/* Good practice: Unbind objects until we really need them. */
glUseProgram(0);
/* Create kuhl_geometry structs for the objects that we want to
* draw. */
init_geometryTriangle(&triangle, program);
init_geometryQuad(&quad, program);
dgr_init(); /* Initialize DGR based on environment variables. */
projmat_init(); /* Figure out which projection matrix we should use based on environment variables */
float initCamPos[3] = {0,0,10}; // location of camera
float initCamLook[3] = {0,0,0}; // a point the camera is facing at
float initCamUp[3] = {0,1,0}; // a vector indicating which direction is up
viewmat_init(initCamPos, initCamLook, initCamUp);
/* Tell GLUT to start running the main loop and to call display(),
* keyboard(), etc callback methods as needed. */
glutMainLoop();
/* // An alternative approach:
while(1)
glutMainLoopEvent();
*/
exit(EXIT_SUCCESS);
}