📄 openglapp.dpr
字号:
//------------------------------------------------------------------------
//
// OBJECT PICKING TUTORIAL
// Author: Ben Humphrey - http://www.gametutorials.com
// Delphi Converter: David "DavesLord" Caouette - http://blueberry.sourceforge.net
// OpenGL Template Author: Jan Horn - http://www.sulaco.co.za
//
//------------------------------------------------------------------------
program OpenGLApp;
uses
Windows,
Messages,
OpenGL,
Textures;
const
WND_TITLE = 'OpenGL App by Jan Horn';
FPS_TIMER = 1; // Timer to calculate FPS
FPS_INTERVAL = 1000; // Calculate FPS every 1000 ms
SUN = 100; // This is the object ID for the SUN
EARTH = 101; // This is the object ID for the EARTH
PLUTO = 102; // This is the object ID for PLUTO
var
h_Wnd : HWND; // Global window handle
h_DC : HDC; // Global device context
h_RC : HGLRC; // OpenGL rendering context
keys : Array[0..255] of Boolean; // Holds keystrokes
FPSCount : Integer = 0; // Counter for FPS
ElapsedTime : cardinal; // Elapsed time between frames
// Textures
SunTex : glUInt;
EarthTex: glUInt;
PlutoTex: glUInt;
// User variables
pObj: GLUQuadricObj;
SunRotation : single = 90; // This holds our sun's current rotation
EarthRotation : single = 90; // This holds our earth's current rotation
PlutoRotation : single = 90; // This holds pluto's current rotation
g_Fullscreen: boolean;
{$R *.RES}
procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32;
{------------------------------------------------------------------}
{ Function to convert int to string. (No sysutils = smaller EXE) }
{------------------------------------------------------------------}
function IntToStr(Num : Integer) : String; // using SysUtils increase file size by 100K
begin
Str(Num, result);
end;
{------------------------------------------------------------------}
{ Function to draw the actual scene }
{------------------------------------------------------------------}
procedure glDraw();
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The matrix
// We make our position a bit high and back to view the whole scene
// Position View Up Vector
gluLookAt(0, 3, 6, 0, 0, 0, 0, 1, 0); // This determines where the camera's position and view is
glInitNames(); // This clears the name stack so we always start with 0 names.
// This next line is important. If you don't push on at least ONE name,
// The selection won't work. Instead of glLoadName()/glEnd() you can use
// glPushName(TheID) and glPopName(); Then you don't need to glPushName(0);
glPushName(0); // This starts off the first object in the stack
pObj := gluNewQuadric(); // Get a new Quadric off the stack
gluQuadricTexture(pObj, true); // This turns on texture coordinates for our Quadrics
// Bind the sun texture to the sun quadratic
glBindTexture(GL_TEXTURE_2D, SunTex); // Bind the Sun texture to the sun
// Below we call glLoadName(). We need to pass in an ID that we can check later that will
// be associated with the polygons drawn next. Here is how it works. We call glLoadName()
// and pass an ID. Then we draw any primitives or shapes, then we call glEnd() which
// stops assigning polys to that object name. We now have a group of polygons that are
// given an ID. Our ID SUN now refers to the sun Quadric we draw below.
glLoadName(SUN); // Push on our SUN label (IMPORTANT)
// If we use glLoadName(), then we need to end it with glEnd(). There is a problem
// though with some video cards that MUST have a glBegin()/glEnd() between
// the calls to glLoadName()/glEnd(). This is strange but some cards grind
// to a 2 FPS speed (VoodooCards). Since we are using Quadrics there is
// no glBegin()/glEnd() being called explicitly, so we need to fake it.
// *Remember, you only have to do this if you are using Quadrics.* So, to fix
// this we just put a empty glBegin()/glEnd() statement between each object ID passed in.
glBegin(GL_LINES);
glEnd();
// Here we push on a new matrix so we don't affect any other quadrics.
// We first translate the quadric to the origin (0, 0, 0), Then we rotate it
// about the Y axis. This gives it the spinning effect. Then we draw the
// largest of the spheres. This represents the sun with its texture map.
glPushMatrix(); // Push on a new matrix scope
glTranslatef(0, 0, 0); // Translate this sphere to the left
glRotatef(SunRotation, 0, 1.0, 0); // Rotate the sphere around the Y axis to make it spin
gluSphere(pObj, 0.5, 20, 20); // Draw the sunwith a radius of 0.5
glPopMatrix(); // End the current scope of this matrix
// Now that we drew the sun, we want to end our Object name. We call glPopName()
// to do that. Now nothing else will be associated with the SUN ID.
glEnd(); // Stop assigning polygons to the SUN label (IMPORTANT)
// Next, we want to bind the Earth texture to our Earth sphere
glBindTexture(GL_TEXTURE_2D, EarthTex);
// Once again, we want to create a object ID for our earth, so we push on the EARTH ID.
// Now, when we draw the next sphere, it will be associated with the EARTH ID.
glLoadName(EARTH); // Push on our EARTH label (IMPORTANT)
// Pass in our empty glBegin()/glEnd() statement because we are using Quadrics.
// If we don't do this when using glLoadName(), it will grind to a hault on some cards.
glBegin(GL_LINES);
glEnd();
// Once again, we want to pop on a new matrix as not to affect any other spheres.
// We rotate the sphere by its current rotation value FIRST before we translate it.
// This makes it rotate around the origin, which is where the sun is.
// Then we rotate it again about the Y-axis to make it spin around itself.
glPushMatrix(); // Push on a new matrix scope
glRotatef(EarthRotation / 3, 0, 1.0, 0); // Rotate the sphere around the origin (the sun)
glTranslatef(-2, 0, 0); // Translate this sphere to the left
glRotatef(EarthRotation, 0, 1.0, 0); // Rotate the sphere to make it spin
gluSphere(pObj, 0.2, 20, 20); // Draw the sphere with a radius of 0.2 so it's smaller than the sun
glPopMatrix(); // End the current scope of this matrix
// We are done assigning the EARTH object, so we need
// to stop assigning polygons to the current ID.
glEnd(); // Stop assigning polygons to the EARTH label (IMPORTANT)
// Bind the pluto texture to the last sphere
glBindTexture(GL_TEXTURE_2D, PlutoTex);
// Finally, we want to be able to click on Pluto, so we need a pluto ID.
glLoadName(PLUTO); // Push on our PLUTO label (IMPORTANT)
// Like we did with the earth, we rotate Pluto around the sun first,
// then we translate it farther away from the sun. Next, we rotate Pluto
// around the Y axis to give it some spin.
// Pass in our empty glBegin()/glEnd() statement because we are using Quadrics.
// If we don't do this when using glLoadName(), it will grind to a hault on some cards.
glBegin(GL_LINES);
glEnd();
glPushMatrix(); // Push on a new matrix scope
glRotatef(PlutoRotation / 2, 0, 1.0, 0); // Rotate the sphere around the sun
glTranslatef(3, 0, 0); // Translate this sphere farther away from the sun than the earth
glRotatef(PlutoRotation, 0, 1.0, 0); // Rotate the sphere around itself to produce the spin
gluSphere(pObj, 0.1, 20, 20); // Draw the sphere with a radius of 0.1 (smallest planet)
glPopMatrix(); // End the current scope of this matrix
// We are finished with the PLUTO object ID, so we need to pop it off the name stack.
glEnd(); // Stop assigning polygons to our PLUTO label (IMPORTANT)
//SwapBuffers(h_DC); // Swap the backbuffers to the foreground
gluDeleteQuadric(pObj); // Free the Quadric
glPopName(); // We pushed a name on the stack, we must pop it back off
// Below we increase the rotations for each sphere.
SunRotation := SunRotation + 0.2; // Rotate the sun slowly
EarthRotation := EarthRotation + 0.5; // Increase the rotation for the each
PlutoRotation := PlutoRotation + 0.6; // Make pluto go the fastest
end;
function RetrieveObjectID(x, y: integer): integer;
var
objectsFound: integer;
viewportCoords: array [0..3] of integer;
selectBuffer: array[0..31] of cardinal;
lowestDepth: cardinal;
selectedObject: cardinal;
i: integer;
begin
objectsFound := 0; // This will hold the amount of objects clicked
ZeroMemory(@viewportCoords, sizeof(viewportCoords)); // We need an array to hold our view port coordinates
ZeroMemory(@selectBuffer, sizeof(selectBuffer));
// This will hold the ID's of the objects we click on.
// We make it an arbitrary number of 32 because openGL also stores other information
// that we don't care about. There is about 4 slots of info for every object ID taken up.
// glSelectBuffer is what we register our selection buffer with. The first parameter
// is the size of our array. The next parameter is the buffer to store the information found.
// More information on the information that will be stored in selectBuffer is further below.
glSelectBuffer(32, @selectBuffer); // Setup our selection buffer to accept object ID's
// This function returns information about many things in OpenGL. We pass in GL_VIEWPORT
// to get the view port coordinates. It saves it like a RECT with {top, left, bottom, right}
glGetIntegerv(GL_VIEWPORT, @viewportCoords); // Get the current view port coordinates
// Now we want to get out of our GL_MODELVIEW matrix and start effecting our
// GL_PROJECTION matrix. This allows us to check our X and Y coords against 3D space.
glMatrixMode(GL_PROJECTION); // We want to now effect our projection matrix
glPushMatrix(); // We push on a new matrix so we don't effect our 3D projection
// This makes it so it doesn't change the frame buffer if we render into it, instead,
// a record of the names of primitives that would have been drawn if the render mode was
// GL_RENDER are now stored in the selection array (selectBuffer).
glRenderMode(GL_SELECT); // Allows us to render the objects, but not change the frame buffer
glLoadIdentity(); // Reset our projection matrix
// gluPickMatrix allows us to create a projection matrix that is around our
// cursor. This basically only allows rendering in the region that we specify.
// If an object is rendered into that region, then it saves that objects ID for us (The magic).
// The first 2 parameters are the X and Y position to start from, then the next 2
// are the width and height of the region from the starting point. The last parameter is
// of course our view port coordinates. You will notice we subtract "y" from the
// BOTTOM view port coordinate. We do this to flip the Y coordinates around. The 0 y
// coordinate starts from the bottom, which is opposite to window's coordinates.
// We also give a 2 by 2 region to look for an object in. This can be changed to preference.
gluPickMatrix(x, viewportCoords[3]-y-Integer(not g_Fullscreen)*(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1), 2, 2, @viewportCoords);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -