ضمیمه A: برنامههای نمونه 8 تا 10، پیمایش درخت و قوری
ضمیمه A: برنامههای نمونهٔ ۸ تا ۱۰، پیمایش Tree و قوری
این بخش ادامهٔ کدهای نمونهٔ ضمیمه A است. برای حفظ قابلیت اجرای نمونهها، تمام شناسهها، دستورها، literalها و commentهای داخل code blockها عیناً نگه داشته شدهاند.
A.8 مکعب چرخان با Texture — ادامهٔ کد برنامه
A.8 Rotating Cube with Texture 639
#include "Angel.h"
const int NumTriangles = 12; // (6 faces)(2 triangles/face)
const int NumVertices = 3 * NumTriangles;
const int TextureSize = 64;
typedef Angel::vec4 point4;
typedef Angel::vec4 color4;
// Texture objects and storage for texture image
GLuint textures[2];
GLubyte image[TextureSize][TextureSize][3];
GLubyte image2[TextureSize][TextureSize][3];
// Vertex data arrays
point4 points[NumVertices];
color4 quad_colors[NumVertices];
vec2 tex_coords[NumVertices];
// Array of rotation angles (in degrees) for each coordinate axis
enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
int Axis = Xaxis;
GLfloat Theta[NumAxes] = { 0.0, 0.0, 0.0 };
GLuint theta;
//----------------------------------------------------------------------
int Index = 0;
void
quad( int a, int b, int c, int d )
{
point4 vertices[8] = {
point4( -0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, -0.5, -0.5, 1.0 ),
point4( -0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, -0.5, -0.5, 1.0 )
};
color4 colors[8] = {
color4( 0.0, 0.0, 0.0, 1.0 ), // black
color4( 1.0, 0.0, 0.0, 1.0 ), // red
color4( 1.0, 1.0, 0.0, 1.0 ), // yellow
color4( 0.0, 1.0, 0.0, 1.0 ), // green
640 Appendix A Sample Programs
color4( 0.0, 0.0, 1.0, 1.0 ), // blue
color4( 1.0, 0.0, 1.0, 1.0 ), // magenta
color4( 0.0, 1.0, 1.0, 1.0 ), // white
color4( 1.0, 1.0, 1.0, 1.0 ) // cyan
};
quad_colors[Index] = colors[a];
points[Index] = vertices[a];
tex_coords[Index] = vec2( 0.0, 0.0 );
Index++;
quad_colors[Index] = colors[a];
points[Index] = vertices[b];
tex_coords[Index] = vec2( 0.0, 1.0 );
Index++;
quad_colors[Index] = colors[a];
points[Index] = vertices[c];
tex_coords[Index] = vec2( 1.0, 1.0 );
Index++;
quad_colors[Index] = colors[a];
points[Index] = vertices[a];
tex_coords[Index] = vec2( 0.0, 0.0 );
Index++;
quad_colors[Index] = colors[a];
points[Index] = vertices[c];
tex_coords[Index] = vec2( 1.0, 1.0 );
Index++;
quad_colors[Index] = colors[a];
points[Index] = vertices[d];
tex_coords[Index] = vec2( 1.0, 0.0 );
Index++;
}
//----------------------------------------------------------------------
void
colorcube( void )
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
A.8 Rotating Cube with Texture 641
//----------------------------------------------------------------------
void
init( void )
{
colorcube( void );
// Create a checkerboard pattern
for ( int i = 0; i < 64; i++ ) {
for ( int j = 0; j < 64; j++ ) {
GLubyte c = (((i & 0x8) == 0) ^ ((j & 0x8) == 0)) * 255;
image[i][j][0] = c;
image[i][j][1] = c;
image[i][j][2] = c;
image2[i][j][0] = c;
image2[i][j][1] = 0;
image2[i][j][2] = c;
}
}
// Initialize texture objects
glGenTextures( 2, textures );
glBindTexture( GL_TEXTURE_2D, textures[0] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0,
GL_RGB, GL_UNSIGNED_BYTE, image );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glBindTexture( GL_TEXTURE_2D, textures[1] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0,
GL_RGB, GL_UNSIGNED_BYTE, image2 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, textures[0] );
// Create a vertex array object
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
// Create and initialize a buffer object
GLuint buffer;
642 Appendix A Sample Programs
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER,
sizeof(points) + sizeof(quad_colors) +
sizeof(tex_coords), NULL, GL_STATIC_DRAW );
// Specify an offset to keep track of where we’re placing data in
// our vertex array buffer. We’ll use the same technique when we
// associate the offsets with vertex attribute pointers.
GLintptr offset = 0;
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(points), points );
offset += sizeof(points);
glBufferSubData( GL_ARRAY_BUFFER, offset,
sizeof(quad_colors), quad_colors );
offset += sizeof(quad_colors);
glBufferSubData( GL_ARRAY_BUFFER, offset, sizeof(tex_coords),
tex_coords );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader71.glsl", "fshader71.glsl" );
glUseProgram( program );
// set up vertex arrays
offset = 0;
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
offset += sizeof(points);
GLuint vColor = glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
offset += sizeof(quad_colors);
GLuint vTexCoord = glGetAttribLocation( program, "vTexCoord" );
glEnableVertexAttribArray( vTexCoord );
glVertexAttribPointer( vTexCoord, 2, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(offset) );
// Set the value of the fragment shader texture sampler variable
// ("texture") to the appropriate texture unit. In this case,
// zero, for GL_TEXTURE0 which was previously set by calling
// glActiveTexture( void ).
glUniform1i( glGetUniformLocation(program, "texture"), 0 );
A.8 Rotating Cube with Texture 643
theta = glGetUniformLocation( program, "theta" );
glEnable( GL_DEPTH_TEST );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniform3fv( theta, 1, Theta );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glutSwapBuffers( void );
}
//----------------------------------------------------------------------
void
mouse( int button, int state, int x, int y )
{
if ( state == GLUT_DOWN ) {
switch( button ) {
case GLUT_LEFT_BUTTON: Axis = Xaxis; break;
case GLUT_MIDDLE_BUTTON: Axis = Yaxis; break;
case GLUT_RIGHT_BUTTON: Axis = Zaxis; break;
}
}
}
//----------------------------------------------------------------------
void
idle( void )
{
Theta[Axis] += 0.01;
if ( Theta[Axis] > 360.0 ) {
Theta[Axis] -= 360.0;
}
glutPostRedisplay( void );
}
//----------------------------------------------------------------------
void
keyboard( unsigned char key, int mousex, int mousey )
{
A.8.2 Vertex Shader
644 Appendix A Sample Programs
switch( key ) {
case 033: // Escape Key
case ’q’: case ’Q’:
exit( EXIT_SUCCESS );
break;
case ’1’:
glBindTexture( GL_TEXTURE_2D, textures[0] );
break;
case ’2’:
glBindTexture( GL_TEXTURE_2D, textures[1] );
break;
}
glutPostRedisplay( void );
}
//----------------------------------------------------------------------
int
main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize( 512, 512 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "Color Cube" );
glewInit( void );
init( void );
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutMouseFunc( mouse );
glutIdleFunc( idle );
glutMainLoop( void );
return 0;
}
A.8.2 Vertex Shader
#version 150
in vec4 vPosition;
in vec4 vColor;
in vec2 vTexCoord;
A.8.3 Fragment Shader
A.8 Rotating Cube with Texture 645
out vec4 color;
out vec2 texCoord;
uniform vec3 theta;
void main()
{
const float DegreesToRadians = 3.14159265 / 180.0;
vec3 c = cos( DegreesToRadians * theta );
vec3 s = sin( DegreesToRadians * theta );
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, -s.x, 0.0,
0.0, s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0);
mat4 ry = mat4( c.y, 0.0, s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
-s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, -s.z, 0.0, 0.0,
s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
color = vColor;
texCoord = vTexCoord;
gl_Position = rz * ry * rx * vPosition;
}
A.8.3 Fragment Shader
#version 150
in vec4 color;
in vec2 texCoord;
out vec4 fColor;
uniform sampler2D texture;
void main()
{
fColor = color * texture2D( texture, texCoord );
}
A.9 شکل با پیمایش Tree
A.9.1 کد برنامه
646 Appendix A Sample Programs
A.9 FIGURE WITH TREE TRAVERSAL
A.9.1 Application Code
#include "Angel.h"
#include <assert.h>
typedef Angel::vec4 point4;
typedef Angel::vec4 color4;
const int NumVertices = 36; //(6 faces)(2 triangles/face)
(3 vertices/triangle)
point4 points[NumVertices];
color4 colors[NumVertices];
point4 vertices[8] = {
point4( -0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, 0.5, 0.5, 1.0 ),
point4( 0.5, -0.5, 0.5, 1.0 ),
point4( -0.5, -0.5, -0.5, 1.0 ),
point4( -0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, 0.5, -0.5, 1.0 ),
point4( 0.5, -0.5, -0.5, 1.0 )
};
// RGBA colors
color4 vertex_colors[8] = {
color4( 0.0, 0.0, 0.0, 1.0 ), // black
color4( 1.0, 0.0, 0.0, 1.0 ), // red
color4( 1.0, 1.0, 0.0, 1.0 ), // yellow
color4( 0.0, 1.0, 0.0, 1.0 ), // green
color4( 0.0, 0.0, 1.0, 1.0 ), // blue
color4( 1.0, 0.0, 1.0, 1.0 ), // magenta
color4( 1.0, 1.0, 1.0, 1.0 ), // white
color4( 0.0, 1.0, 1.0, 1.0 ) // cyan
};
//----------------------------------------------------------------------
class MatrixStack {
int _index;
int _size;
mat4* _matrices;
public:
MatrixStack( int numMatrices = 32 ):_index(0), _size(numMatrices)
A.9 Figure with Tree Traversal 647
{ _matrices = new mat4[numMatrices]; }
~MatrixStack( void )
{ delete[]_matrices; }
mat4& push( const mat4& m ) {
assert( _index + 1 < _size );
_matrices[_index++] = m;
}
mat4& pop( void ) {
assert( _index - 1 >= 0 );
_index--;
return _matrices[_index + 1];
}
};
MatrixStack mvstack;
mat4 model_view;
GLuint ModelView, Projection;
//----------------------------------------------------------------------
#define TORSO_HEIGHT 5.0
#define TORSO_WIDTH 1.0
#define UPPER_ARM_HEIGHT 3.0
#define LOWER_ARM_HEIGHT 2.0
#define UPPER_LEG_WIDTH 0.5
#define LOWER_LEG_WIDTH 0.5
#define LOWER_LEG_HEIGHT 2.0
#define UPPER_LEG_HEIGHT 3.0
#define UPPER_LEG_WIDTH 0.5
#define UPPER_ARM_WIDTH 0.5
#define LOWER_ARM_WIDTH 0.5
#define HEAD_HEIGHT 1.5
#define HEAD_WIDTH 1.0
// Set up menu item indices, which we can also use with the joint angles
enum {
Torso = 0,
Head = 1,
Head1 = 1,
Head2 = 2,
LeftUpperArm = 3,
LeftLowerArm = 4,
RightUpperArm = 5,
RightLowerArm = 6,
LeftUpperLeg = 7,
648 Appendix A Sample Programs
LeftLowerLeg = 8,
RightUpperLeg = 9,
RightLowerLeg = 10,
NumNodes,
Quit
};
// Joint angles with initial values
GLfloat
theta[NumNodes] = {
0.0, // Torso
0.0, // Head1
0.0, // Head2
0.0, // LeftUpperArm
0.0, // LeftLowerArm
0.0, // RightUpperArm
0.0, // RightLowerArm
180.0, // LeftUpperLeg
0.0, // LeftLowerLeg
180.0, // RightUpperLeg
0.0 // RightLowerLeg
};
GLint angle = Head2;
//----------------------------------------------------------------------
struct Node {
mat4 transform;
void (*render)( void );
Node* sibling;
Node* child;
Node( void ) :
render(NULL), sibling(NULL), child(NULL) {}
Node( mat4& m, void (*render)( void ), Node* sibling, Node* child ) :
transform(m), render(render), sibling(sibling), child(child) {}
};
Node nodes[NumNodes];
//----------------------------------------------------------------------
int Index = 0;
void
quad( int a, int b, int c, int d )
A.9 Figure with Tree Traversal 649
{
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[d]; Index++;
}
void
colorcube( void )
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
//----------------------------------------------------------------------
void
traverse( Node* node )
{
if ( node == NULL ) { return; }
mvstack.push( model_view );
model_view *= node->transform;
node->render( void );
if ( node->child ) { traverse( node->child ); }
model_view = mvstack.pop( void );
if ( node->sibling ) { traverse( node->sibling ); }
}
//----------------------------------------------------------------------
void
torso( void )
{
mvstack.push( model_view );
mat4 instance = ( Translate( 0.0, 0.5 * TORSO_HEIGHT, 0.0 ) *
Scale( TORSO_WIDTH, TORSO_HEIGHT, TORSO_WIDTH ) );
650 Appendix A Sample Programs
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
head( void )
{
mvstack.push( model_view );
mat4 instance = (Translate( 0.0, 0.5 * HEAD_HEIGHT, 0.0 ) *
Scale( HEAD_WIDTH, HEAD_HEIGHT, HEAD_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
left_upper_arm( void )
{
mvstack.push( model_view );
mat4 instance = (Translate( 0.0, 0.5 * UPPER_ARM_HEIGHT, 0.0 ) *
Scale( UPPER_ARM_WIDTH,
UPPER_ARM_HEIGHT,
UPPER_ARM_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
left_lower_arm( void )
{
mvstack.push( model_view );
mat4 instance = ( Translate( 0.0, 0.5 * LOWER_ARM_HEIGHT, 0.0 ) *
Scale( LOWER_ARM_WIDTH,
LOWER_ARM_HEIGHT,
LOWER_ARM_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
A.9 Figure with Tree Traversal 651
model_view = mvstack.pop( void );
}
void
right_upper_arm( void )
{
mvstack.push( model_view );
mat4 instance = (Translate( 0.0, 0.5 * UPPER_ARM_HEIGHT, 0.0 ) *
Scale( UPPER_ARM_WIDTH,
UPPER_ARM_HEIGHT,
UPPER_ARM_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
right_lower_arm( void )
{
mvstack.push( model_view );
mat4 instance = (Translate( 0.0, 0.5 * LOWER_ARM_HEIGHT, 0.0 ) *
Scale( LOWER_ARM_WIDTH,
LOWER_ARM_HEIGHT,
LOWER_ARM_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
left_upper_leg( void )
{
mvstack.push( model_view );
mat4 instance = ( Translate( 0.0, 0.5 * UPPER_LEG_HEIGHT, 0.0 ) *
Scale( UPPER_LEG_WIDTH,
UPPER_LEG_HEIGHT,
UPPER_LEG_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
652 Appendix A Sample Programs
model_view = mvstack.pop( void );
}
void
left_lower_leg( void )
{
mvstack.push( model_view );
mat4 instance = (Translate( 0.0, 0.5 * LOWER_LEG_HEIGHT, 0.0 ) *
Scale( LOWER_LEG_WIDTH,
LOWER_LEG_HEIGHT,
LOWER_LEG_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
right_upper_leg( void )
{
mvstack.push( model_view );
mat4 instance = (Translate( 0.0, 0.5 * UPPER_LEG_HEIGHT, 0.0 ) *
Scale( UPPER_LEG_WIDTH,
UPPER_LEG_HEIGHT,
UPPER_LEG_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
void
right_lower_leg( void )
{
mvstack.push( model_view );
mat4 instance = ( Translate( 0.0, 0.5 * LOWER_LEG_HEIGHT, 0.0 ) *
Scale( LOWER_LEG_WIDTH,
LOWER_LEG_HEIGHT,
LOWER_LEG_WIDTH ) );
glUniformMatrix4fv( ModelView, 1, GL_TRUE, model_view * instance );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
model_view = mvstack.pop( void );
}
A.9 Figure with Tree Traversal 653
//----------------------------------------------------------------------
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
traverse( &nodes[Torso] );
glutSwapBuffers( void );
}
//----------------------------------------------------------------------
void
mouse( int button, int state, int x, int y )
{
if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
theta[angle] += 5.0;
if ( theta[angle] > 360.0 ) { theta[angle] -= 360.0; }
}
if ( button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN ) {
theta[angle] -= 5.0;
if ( theta[angle] < 0.0 ) { theta[angle] += 360.0; }
}
mvstack.push( model_view );
switch( angle ) {
case Torso:
nodes[Torso].transform =
RotateY( theta[Torso] );
break;
case Head1: case Head2:
nodes[Head].transform =
Translate(0.0, TORSO_HEIGHT+0.5*HEAD_HEIGHT, 0.0) *
RotateX(theta[Head1]) *
RotateY(theta[Head2]) *
Translate(0.0, -0.5*HEAD_HEIGHT, 0.0);
break;
case LeftUpperArm:
nodes[LeftUpperArm].transform =
Translate(-(TORSO_WIDTH+UPPER_ARM_WIDTH),
0.9*TORSO_HEIGHT, 0.0) *
RotateX(theta[LeftUpperArm]);
break;
case RightUpperArm:
nodes[RightUpperArm].transform =
654 Appendix A Sample Programs
Translate(TORSO_WIDTH+UPPER_ARM_WIDTH,
0.9*TORSO_HEIGHT, 0.0) *
RotateX(theta[RightUpperArm]);
break;
case RightUpperLeg:
nodes[RightUpperLeg].transform =
Translate(TORSO_WIDTH+UPPER_LEG_WIDTH,
0.1*UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[RightUpperLeg]);
break;
case LeftUpperLeg:
nodes[LeftUpperLeg].transform =
Translate(-(TORSO_WIDTH+UPPER_LEG_WIDTH),
0.1*UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[LeftUpperLeg]);
break;
case LeftLowerArm:
nodes[LeftLowerArm].transform =
Translate(0.0, UPPER_ARM_HEIGHT, 0.0) *
RotateX(theta[LeftLowerArm]);
break;
case LeftLowerLeg:
nodes[LeftLowerLeg].transform =
Translate(0.0, UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[LeftLowerLeg]);
break;
case RightLowerLeg:
nodes[RightLowerLeg].transform =
Translate(0.0, UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[RightLowerLeg]);
break;
case RightLowerArm:
nodes[RightLowerArm].transform =
Translate(0.0, UPPER_ARM_HEIGHT, 0.0) *
RotateX(theta[RightLowerArm]);
break;
}
model_view = mvstack.pop( void );
glutPostRedisplay( void );
}
//----------------------------------------------------------------------
A.9 Figure with Tree Traversal 655
void
menu( int option )
{
if ( option == Quit ) {
exit( EXIT_SUCCESS );
}
angle = option;
}
//----------------------------------------------------------------------
void
reshape( int width, int height )
{
glViewport( 0, 0, width, height );
GLfloat left = -10.0, right = 10.0;
GLfloat bottom = -10.0, top = 10.0;
GLfloat zNear = -10.0, zFar = 10.0;
GLfloat aspect = GLfloat( width ) / height;
if ( aspect > 1.0 ) {
left *= aspect;
right *= aspect;
}
else {
bottom /= aspect;
top /= aspect;
}
mat4 projection = Ortho( left, right, bottom, top, zNear, zFar );
glUniformMatrix4fv( Projection, 1, GL_TRUE, projection );
model_view = mat4( 1.0 ); // An Identity matrix
}
//----------------------------------------------------------------------
void
initNodes( void )
{
mat4 m;
m = RotateY( theta[Torso] );
nodes[Torso] = Node( m, torso, NULL, &nodes[Head1] );
m = Translate(0.0, TORSO_HEIGHT+0.5*HEAD_HEIGHT, 0.0) *
656 Appendix A Sample Programs
RotateX(theta[Head1]) *
RotateY(theta[Head2]);
nodes[Head1] = Node( m, head, &nodes[LeftUpperArm], NULL );
m = Translate(-(TORSO_WIDTH+UPPER_ARM_WIDTH), 0.9*TORSO_HEIGHT,
0.0) * RotateX(theta[LeftUpperArm]);
nodes[LeftUpperArm] =
Node( m, left_upper_arm, &nodes[RightUpperArm],
&nodes[LeftLowerArm] );
m = Translate(TORSO_WIDTH+UPPER_ARM_WIDTH, 0.9*TORSO_HEIGHT, 0.0) *
RotateX(theta[RightUpperArm]);
nodes[RightUpperArm] =
Node( m, right_upper_arm,
&nodes[LeftUpperLeg], &nodes[RightLowerArm] );
m = Translate(-(TORSO_WIDTH+UPPER_LEG_WIDTH),
0.1*UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[LeftUpperLeg]);
nodes[LeftUpperLeg] =
Node( m, left_upper_leg, &nodes[RightUpperLeg],
&nodes[LeftLowerLeg] );
m = Translate(TORSO_WIDTH+UPPER_LEG_WIDTH,
0.1*UPPER_LEG_HEIGHT, 0.0) * RotateX(theta[RightUpperLeg]);
nodes[RightUpperLeg] =
Node( m, right_upper_leg, NULL, &nodes[RightLowerLeg] );
m = Translate(0.0, UPPER_ARM_HEIGHT, 0.0) *
RotateX(theta[LeftLowerArm]);
nodes[LeftLowerArm] = Node( m, left_lower_arm, NULL, NULL );
m = Translate(0.0, UPPER_ARM_HEIGHT, 0.0) *
RotateX(theta[RightLowerArm]);
nodes[RightLowerArm] = Node( m, right_lower_arm, NULL, NULL );
m = Translate(0.0, UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[LeftLowerLeg]);
nodes[LeftLowerLeg] = Node( m, left_lower_leg, NULL, NULL );
m = Translate(0.0, UPPER_LEG_HEIGHT, 0.0) *
RotateX(theta[RightLowerLeg]);
nodes[RightLowerLeg] = Node( m, right_lower_leg, NULL, NULL );
}
//----------------------------------------------------------------------
void
init( void )
A.9 Figure with Tree Traversal 657
{
colorcube( void );
// Initialize tree
initNodes( void );
// Create a vertex array object
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(points) + sizeof(colors),
NULL, GL_DYNAMIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(points), points );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(points), sizeof(colors),
colors );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader83.glsl", "fshader83.glsl" );
glUseProgram( program );
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0) );
GLuint vColor = glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(points) );
ModelView = glGetUniformLocation( program, "ModelView" );
Projection = glGetUniformLocation( program, "Projection" );
glEnable( GL_DEPTH_TEST );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
//----------------------------------------------------------------------
void
keyboard( unsigned char key, int x, int y )
658 Appendix A Sample Programs
{
switch( key ) {
case 033: // Escape Key
case ’q’: case ’Q’:
exit( EXIT_SUCCESS );
break;
}
}
//----------------------------------------------------------------------
int
main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
glutInitWindowSize( 512, 512 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "robot" );
glewInit( void );
init( void );
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutKeyboardFunc( keyboard );
glutMouseFunc( mouse );
glutCreateMenu( menu );
glutAddMenuEntry( "torso", Torso );
glutAddMenuEntry( "head1", Head1 );
glutAddMenuEntry( "head2", Head2 );
glutAddMenuEntry( "right_upper_arm", RightUpperArm );
glutAddMenuEntry( "right_lower_arm", RightLowerArm );
glutAddMenuEntry( "left_upper_arm", LeftUpperArm );
glutAddMenuEntry( "left_lower_arm", LeftLowerArm );
glutAddMenuEntry( "right_upper_leg", RightUpperLeg );
glutAddMenuEntry( "right_lower_leg", RightLowerLeg );
glutAddMenuEntry( "left_upper_leg", LeftUpperLeg );
glutAddMenuEntry( "left_lower_leg", LeftLowerLeg );
glutAddMenuEntry( "quit", Quit );
glutAttachMenu( GLUT_MIDDLE_BUTTON );
glutMainLoop( void );
return 0;
}
A.9.2 Vertex Shader و A.9.3 Fragment Shader
A.10 رندرکنندهٔ قوری
A.10.1 کد برنامه
A.10 Teapot Renderer 659
A.9.2 Vertex Shader
#version 150
in vec4 vPosition;
in vec4 vColor;
out vec4 color;
uniform mat4 ModelView;
uniform mat4 Projection;
void main()
{
color = vColor;
gl_Position = Projection*ModelView*vPosition;
}
A.9.3 Fragment Shader
#version 150
in vec4 color;
out vec4 fColor;
void main()
{
fColor = color;
}
A.10 TEAPOT RENDERER
A.10.1 Application Code
#include "Angel.h"
typedef Angel::vec4 point4;
// Define a convenient type for referencing patch control points, which
// is used in the declaration of the vertices’ array (used in "vertices.h")
typedef GLfloat point3[3];
#include "vertices.h"
#include "patches.h"
const int NumTimesToSubdivide = 3;
const int PatchesPerSubdivision = 4;
const int NumQuadsPerPatch =
(int) pow( PatchesPerSubdivision, NumTimesToSubdivide );
const int NumTriangles =
660 Appendix A Sample Programs
( NumTeapotPatches * NumQuadsPerPatch * 2 // triangles / quad );
const int NumVertices =
( NumTriangles * 3 // vertices / triangle );
int Index = 0;
point4 points[NumVertices];
GLuint Projection;
enum { X = 0, Y = 1, Z = 2 };
//----------------------------------------------------------------------
void
divide_curve( point4 c[4], point4 r[4], point4 l[4] )
{
// Subdivide a Bezier curve into two equivalent Bezier curves:
// left (l) and right (r) sharing the midpoint of the middle
// control point
point4 t, mid = ( c[1] + c[2] ) / 2;
l[0] = c[0];
l[1] = ( c[0] + c[1] ) / 2;
l[2] = ( l[1] + mid ) / 2;
r[3] = c[3];
r[2] = ( c[2] + c[3] ) / 2;
r[1] = ( mid + r[2] ) / 2;
l[3] = r[0] = ( l[2] + r[1] ) / 2;
for ( int i = 0; i < 4; ++i ) {
l[i].w = 1.0;
r[i].w = 1.0;
}
}
//----------------------------------------------------------------------
void
draw_patch( point4 p[4][4] )
{
// Draw the quad (as two triangles) bounded by the corners of the
// Bezier patch.
points[Index++] = p[0][0];
points[Index++] = p[3][0];
points[Index++] = p[3][3];
points[Index++] = p[0][0];
points[Index++] = p[3][3];
A.10 Teapot Renderer 661
points[Index++] = p[0][3];
}
//----------------------------------------------------------------------
inline void
transpose( point4 a[4][4] )
{
for ( int i = 0; i < 4; i++ ) {
for ( int j = i; j < 4; j++ ) {
point4 t = a[i][j];
a[i][j] = a[j][i];
a[j][i] = t;
}
}
}
void
divide_patch( point4 p[4][4], int count )
{
if ( count > 0 ) {
point4 q[4][4], r[4][4], s[4][4], t[4][4];
point4 a[4][4], b[4][4];
// subdivide curves in u direction, transpose results, divide
// in u direction again (equivalent to subdivision in v)
for ( int k = 0; k < 4; ++k ) {
divide_curve( p[k], a[k], b[k] );
}
transpose( a );
transpose( b );
for ( int k = 0; k < 4; ++k ) {
divide_curve( a[k], q[k], r[k] );
divide_curve( b[k], s[k], t[k] );
}
// recursive division of 4 resulting patches
divide_patch( q, count - 1 );
divide_patch( r, count - 1 );
divide_patch( s, count - 1 );
divide_patch( t, count - 1 );
}
else {
draw_patch( p );
}
}
662 Appendix A Sample Programs
//----------------------------------------------------------------------
void
init( void )
{
for ( int n = 0; n < NumTeapotPatches; n++ ) {
point4 patch[4][4];
// Initialize each patch’s control point data
for ( int i = 0; i < 4; ++i ) {
for ( int j = 0; j < 4; ++j ) {
point3& v = vertices[indices[n][i][j]];
patch[i][j] = point4( v[X], v[Y], v[Z], 1.0 );
}
}
// Subdivide the patch
divide_patch( patch, NumTimesToSubdivide );
}
// Create a vertex array object
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(points), points,
GL_STATIC_DRAW );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader101.glsl", "fshader101.glsl" );
glUseProgram( program );
// set up vertex arrays
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0) );
Projection = glGetUniformLocation( program, "Projection" );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
A.10 Teapot Renderer 663
//----------------------------------------------------------------------
void
display( void )
{
glClear( GL_COLOR_BUFFER_BIT );
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
glutSwapBuffers( void );
}
//----------------------------------------------------------------------
void
reshape( int width, int height )
{
glViewport( 0, 0, width, height );
GLfloat left = -4.0, right = 4.0;
GLfloat bottom = -3.0, top = 5.0;
GLfloat zNear = -10.0, zFar = 10.0;
GLfloat aspect = GLfloat(width)/height;
if ( aspect > 0 ) {
left *= aspect;
right *= aspect;
}
else {
bottom /= aspect;
top /= aspect;
}
mat4 projection = Ortho( left, right, bottom, top, zNear, zFar );
glUniformMatrix4fv( Projection, 1, GL_TRUE, projection );
}
//----------------------------------------------------------------------
void
keyboard( unsigned char key, int x, int y )
{
switch ( key ) {
case ’q’: case ’Q’: case 033 // Escape key:
exit( EXIT_SUCCESS );
break;
}
}
//----------------------------------------------------------------------
A.10.2 Vertex Shader و A.10.3 Fragment Shader
664 Appendix A Sample Programs
int
main( int argc, char *argv[] )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 512, 512 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "teapot" );
glewInit( void );
init( void );
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutKeyboardFunc( keyboard );
glutMainLoop( void );
return 0;
}
A.10.2 Vertex Shader
#version 150
in vec4 vPosition;
uniform mat4 Projection;
void main()
{
gl_Position = Projection * vPosition;
}
A.10.3 Fragment Shader
#version 150
out vec4 fColor;
void main()
{
fColor = vec4( 0.0, 0.0, 0.0, 1.0 );
}