StPendl StPendl Jul 14, 2009 - "removed redefinition of gl.quads and gl.triangle, since they are already globally defined"

=OpenGL 3D Graphics in Liberty BASIC= ==Lesson Six: Creating Shapes== //by Robert McAllister// As mentioned in lesson 1, OpenGL only has functions for making a few basic surfaces. This leaves it up to the programer to build the shapes we need using these available functions. Luckily Liberty BASIC makes this a little less painful for us with subroutines. But first, read this quote from the OpenGL Redbook: //A normal vector (or normal, for short) is a vector that points in a direction that's perpendicular to a surface. For a flat surface, one perpendicular direction suffices for every point on the surface, but for a general curved surface, the normal direction might be different at each point. With OpenGL, you can specify a normal for each vertex. Vertices might share the same normal, but you can't assign normals anywhere other than at the vertices. An object's normal vectors define the orientation of its surface in space - in particular, its orientation relative to light sources. These vectors are used by OpenGL to determine how much light the object receives at its vertices. Lighting - a large topic by itself - is the subject of Chapter 6, and you might want to review the following information after you've read that chapter. Normal vectors are discussed briefly here because you generally define normal vectors for an object at the same time you define the object's geometry. You use glNormal*() to set the current normal to the value of the argument passed in. Subsequent calls to glVertex*() cause the specified vertices to be assigned the current normal...// As this quote mentions, lighting is a large topic so I'm not going to dig to far into it. In the [Initialize] branch of the program you will find these two lines of code: [[code format="vbnet"]] CALL glEnable GL.LIGHTING CALL glEnable GL.LIGHT0 [[code]] The first line enables lighting in general and the second line adds a light to the scene. Unless you plan on doing some special effects, these two lines along with 'Normal' calls are all you need to light up your scene. This bit of code demostrates how to create a cube with a call to a subroutine, and how the sub applies the normals to properly light it up. Run it as is and you will notice that most of the cube appears black. Un-comment the 6 "CALL glNormal..." lines and try it again. (Note: If you receive a "Cannot call undefined sub" error, you will need to download the latest version of the program from page one. I forgot to include the glNormal sub in the original version.) [[code format="vbnet"]] ' build a cube and spin it CALL ClearView eyeX , eyeY , eyeZ , centerX , centerY , centerZ , upX , upY , upZ Width = 1.5 Height = 1.5 Depth = 1.5 CubeCenterX = 0 CubeCenterY = 0 CubeCenterZ = 0 Red = .3 Green = .1 Blue = .2 CALL glGenLists 1 CALL glNewList 1 , 4865 CALL BuildCube Width , Height , Depth , CubeCenterX , CubeCenterY , CubeCenterZ , Red , Green , Blue CALL glEndList FOR a = 1 TO 360 CALL ClearView eyeX , eyeY , eyeZ , centerX , centerY , centerZ , upX , upY , upZ CALL glRotatef a , 1 , 0 , 0 'CALL glRotatef a , 0 , 1 , 0 CALL glRotatef a , 0 , 0 , 1 CALL glCallList 1 CALL RefreshView CALL Pause 15 NEXT a WAIT SUB BuildCube W , H , D , cX , cY , cZ , r , g , b CALL glColor4fv r , g , b , 1 GL.QUADS=7 'front CALL glBegin GL.QUADS 'CALL glNormal cX-(W/2),cY-(H/2),cZ+(D/2) , cX-(W/2),cY+(H/2),cZ+(D/2) , cX+(W/2),cY+(H/2),cZ+(D/2) CALL glVertex cX-(W/2) , cY+(H/2) , cZ+(D/2) CALL glVertex cX+(W/2) , cY+(H/2) , cZ+(D/2) CALL glVertex cX+(W/2) , cY-(H/2) , cZ+(D/2) CALL glVertex cX-(W/2) , cY-(H/2) , cZ+(D/2) CALL glEnd 'back CALL glBegin GL.QUADS 'CALL glNormal cX+(W/2),cY+(H/2),cZ-(D/2) , cX-(W/2),cY+(H/2),cZ-(D/2) , cX-(W/2),cY-(H/2),cZ-(D/2) CALL glVertex cX+(W/2) , cY+(H/2) , cZ-(D/2) CALL glVertex cX-(W/2) , cY+(H/2) , cZ-(D/2) CALL glVertex cX-(W/2) , cY-(H/2) , cZ-(D/2) CALL glVertex cX+(W/2) , cY-(H/2) , cZ-(D/2) CALL glEnd 'left CALL glBegin GL.QUADS 'CALL glNormal cX-(W/2),cY+(H/2),cZ-(D/2) , cX-(W/2),cY+(H/2),cZ+(D/2) , cX-(W/2),cY-(H/2),cZ+(D/2) CALL glVertex cX-(W/2) , cY+(H/2) , cZ-(D/2) CALL glVertex cX-(W/2) , cY+(H/2) , cZ+(D/2) CALL glVertex cX-(W/2) , cY-(H/2) , cZ+(D/2) CALL glVertex cX-(W/2) , cY-(H/2) , cZ-(D/2) CALL glEnd 'right CALL glBegin GL.QUADS 'CALL glNormal cX+(W/2),cY+(H/2),cZ+(D/2) , cX+(W/2),cY+(H/2),cZ-(D/2) , cX+(W/2),cY-(H/2),cZ-(D/2) CALL glVertex cX+(W/2) , cY+(H/2) , cZ+(D/2) CALL glVertex cX+(W/2) , cY+(H/2) , cZ-(D/2) CALL glVertex cX+(W/2) , cY-(H/2) , cZ-(D/2) CALL glVertex cX+(W/2) , cY-(H/2) , cZ+(D/2) CALL glEnd 'top CALL glBegin GL.QUADS 'CALL glNormal cX-(W/2),cY+(H/2),cZ+(D/2) , cX-(W/2),cY+(H/2),cZ-(D/2) , cX+(W/2),cY+(H/2),cZ-(D/2) CALL glVertex cX-(W/2) , cY+(H/2) , cZ+(D/2) CALL glVertex cX-(W/2) , cY+(H/2) , cZ-(D/2) CALL glVertex cX+(W/2) , cY+(H/2) , cZ-(D/2) CALL glVertex cX+(W/2) , cY+(H/2) , cZ+(D/2) CALL glEnd 'bottom CALL glBegin GL.QUADS 'CALL glNormal cX-(W/2),cY-(H/2),cZ+(D/2) , cX+(W/2),cY-(H/2),cZ+(D/2) , cX+(W/2),cY-(H/2),cZ-(D/2) CALL glVertex cX-(W/2) , cY-(H/2) , cZ+(D/2) CALL glVertex cX+(W/2) , cY-(H/2) , cZ+(D/2) CALL glVertex cX+(W/2) , cY-(H/2) , cZ-(D/2) CALL glVertex cX-(W/2) , cY-(H/2) , cZ-(D/2) CALL glEnd END SUB [[code]] In the [Initialize] branch you will find "CALL glEnable GL.NORMALIZE". Normals need to have a length of 1 to work properly. In other words, they should be 1 unit above the surface that is being created. With "GL.NORMALIZE" enabled, OpenGL automatically corrects their length. The sub "glNormal" takes 3 consecutive clockwise (from the front) vertices for the surface, calculates the normal vector and then makes the call to "glNormal3d". To keep it simple, I always create my surfaces in a clockwise direction and then use the values from the first 3 glVertex calls. This code will create a cylinder or oval, depending on the sizes entered. Can you figure out how to add a top and bottom to the cylinder using triangles? Hint: all the values are already being calculated for you. [[code format="vbnet"]] ' build a cylinder CALL ClearView eyeX , eyeY , eyeZ , centerX , centerY , centerZ , upX , upY , upZ Angle = 0 Width = 1 Depth = .75 Height = 1 OvalCenterX = 0 OvalCenterY = 0 OvalCenterZ = 0 Red = .5 Green = 0 Blue = 0 Sides = 120 CALL glGenLists 1 CALL glNewList 1 , 4865 CALL BuildCylinder Angle , Width , Depth , Height , OvalCenterX , OvalCenterY , OvalCenterZ , Red , Green , Blue , Sides CALL glEndList FOR a = 1 TO 360 CALL ClearView eyeX , eyeY , eyeZ , centerX , centerY , centerZ , upX , upY , upZ CALL glRotatef a , 1 , 0 , 0 CALL glRotatef a , 0 , 1 , 0 'CALL glRotatef a , 0 , 0 , 1 CALL glCallList 1 CALL RefreshView CALL Pause 15 NEXT a WAIT SUB BuildCylinder Angle , W , D , H , cX , cY , cZ , R , G , B , Sides CALL glColor4fv R , G , B , 1 GL.QUADS = 7 GL.TRIANGLES = 4 PI = 3.14159265 sin.angle = Sin(Angle * PI / 180) cos.angle = Cos(Angle * PI / 180) theta = 0 dtheta = 2 * PI / Sides XOval = W * Cos(theta) YOval = D * Sin(theta) X1 = cX + XOval * cos.angle + YOval * sin.angle Z1 = cZ - XOval * sin.angle + YOval * cos.angle While theta < 2 * PI theta = theta + dtheta XOval = W * Cos(theta) YOval = D * Sin(theta) X2 = cX + XOval * cos.angle + YOval * sin.angle Z2 = cZ - XOval * sin.angle + YOval * cos.angle CALL glBegin GL.QUADS CALL glNormal X1 , cY+(H/2) , Z1 , X1 , cY-(H/2) , Z1 , X2 , cY-(H/2) , Z2 CALL glVertex X1 , cY-(H/2) , Z1 CALL glVertex X2 , cY-(H/2) , Z2 CALL glVertex X2 , cY+(H/2) , Z2 CALL glVertex X1 , cY+(H/2) , Z1 CALL glEnd X1 = X2 Z1 = Z2 WEND END SUB [[code]] In the next lesson we will learn about "Texture mapping"