outdated: 48.ArcBall Rotation
认认真真地把这教程过一遍还真是费事啊...
终于到最后一章了,鼠标拖动可实现物体旋转。
下面为代码,
#ifndef _ArcBall_h #define _ArcBall_h // Only support assertions in debug builds #ifdef _DEBUG #include <assert.h> #else #define assert(x) { } #endif // _DEBUG #include <GL\glut.h> #include <math.h> // Math types derived from the KempoApi tMath library typedef union Tuple2f_t { struct { GLfloat X, Y; } s; GLfloat T[2]; } Tuple2fT; typedef union Tuple3f_t { struct { GLfloat X, Y, Z; } s; GLfloat T[3]; } Tuple3fT; typedef union Tuple4f_t { struct { GLfloat X, Y, Z, W; } s; GLfloat T[4]; } Tuple4fT; typedef union Matrix3f_t { struct { // Column major union { GLfloat M00; GLfloat XX; GLfloat SX; }; // XAxis.X and Scale X union { GLfloat M10; GLfloat XY; }; // XAxis.Y union { GLfloat M20; GLfloat XZ; }; // XAxis.Z union { GLfloat M01; GLfloat YX; }; // YAxis.X union { GLfloat M11; GLfloat YY; GLfloat SY; }; // YAxis.Y and Scale Y union { GLfloat M21; GLfloat YZ; }; // YAxis.Z union { GLfloat M02; GLfloat ZX; }; // ZAxis.X union { GLfloat M12; GLfloat ZY; }; // ZAxis.Y union { GLfloat M22; GLfloat ZZ; GLfloat SZ; }; // ZAxis.Z and Scale Z } s; GLfloat M[9]; } Matrix3fT; typedef union Matrix4f_t { struct { // Column major union { GLfloat M00; GLfloat XX; GLfloat SX; }; // XAxis.X and Scale X union { GLfloat M10; GLfloat XY; }; // XAxis.Y union { GLfloat M20; GLfloat XZ; }; // XAxis.Z union { GLfloat M30; GLfloat XW; }; // XAxis.W union { GLfloat M01; GLfloat YX; }; // YAxis.X union { GLfloat M11; GLfloat YY; GLfloat SY; }; // YAxis.Y and Scale Y union { GLfloat M21; GLfloat YZ; }; // YAxis.Z union { GLfloat M31; GLfloat YW; }; // YAxis.W union { GLfloat M02; GLfloat ZX; }; // ZAxis.X union { GLfloat M12; GLfloat ZY; }; // ZAxis.Y union { GLfloat M22; GLfloat ZZ; GLfloat SZ; }; // ZAxis.Z and Scale Z union { GLfloat M32; GLfloat ZW; }; // ZAxis.W union { GLfloat M03; GLfloat TX; }; // Trans.X union { GLfloat M13; GLfloat TY; }; // Trans.Y union { GLfloat M23; GLfloat TZ; }; // Trans.Z union { GLfloat M33; GLfloat TW; GLfloat SW; }; // Trans.W and Scale W } s; GLfloat M[16]; } Matrix4fT; // A 2 element point that is represented by single precision floating point x,y coordinates #define Point2fT Tuple2fT // A 4 element unit quaternion represented by single precision floating point x,y,z,w coordinates #define Quat4fT Tuple4fT // A 2-element vector that is represented by single-precision floating point x,y coordinates #define Vector2fT Tuple2fT // A 3-element vector that is represented by single-precision floating point x,y,z coordinates #define Vector3fT Tuple3fT // Custom math, or speed overrides #define FuncSqrt sqrtf // assuming IEEE-754(GLfloat), which i believe has max precision of 7 bits #define Epsilon 1.0e-5 inline static void Point2fAdd(Point2fT* NewObj, const Tuple2fT* t1) { assert(NewObj && t1); NewObj->s.X += t1->s.X; NewObj->s.Y += t1->s.Y; } inline static void Point2fSub(Point2fT* NewObj, const Tuple2fT* t1) { assert(NewObj && t1); NewObj->s.X -= t1->s.X; NewObj->s.Y -= t1->s.Y; } inline static void Vector3fCross(Vector3fT* NewObj, const Vector3fT* v1, const Vector3fT* v2) { Vector3fT Result; assert(NewObj && v1 && v2); Result.s.X = (v1->s.Y * v2->s.Z) - (v1->s.Z * v2->s.Y); Result.s.Y = (v1->s.Z * v2->s.X) - (v1->s.X * v2->s.Z); Result.s.Z = (v1->s.X * v2->s.Y) - (v1->s.Y * v2->s.X); *NewObj = Result; } inline static GLfloat Vector3fDot(const Vector3fT* NewObj, const Vector3fT* v1) { assert(NewObj && v1); return (NewObj->s.X * v1->s.X) + (NewObj->s.Y * v1->s.Y) + (NewObj->s.Z * v1->s.Z); } inline static GLfloat Vector3fLengthSquared(const Vector3fT* NewObj) { assert(NewObj); return (NewObj->s.X * NewObj->s.X) + (NewObj->s.Y * NewObj->s.Y) + (NewObj->s.Z * NewObj->s.Z); } inline static GLfloat Vector3fLength(const Vector3fT* NewObj) { assert(NewObj); return FuncSqrt(Vector3fLengthSquared(NewObj)); } inline static void Matrix3fSetZero(Matrix3fT* NewObj) { NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 = NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 = NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = 0.0f; } inline static void Matrix3fSetIdentity(Matrix3fT* NewObj) { Matrix3fSetZero(NewObj); NewObj->s.M00 = NewObj->s.M11 = NewObj->s.M22 = 1.0f; } inline static void Matrix3fSetRotationFromQuat4f(Matrix3fT* NewObj, const Quat4fT* q1) { GLfloat n, s; GLfloat xs, ys, zs; GLfloat wx, wy, wz; GLfloat xx, xy, xz; GLfloat yy, yz, zz; assert(NewObj && q1); n = (q1->s.X * q1->s.X) + (q1->s.Y * q1->s.Y) + (q1->s.Z * q1->s.Z) + (q1->s.W * q1->s.W); s = (n > 0.0f) ? (2.0f / n) : 0.0f; xs = q1->s.X * s; ys = q1->s.Y * s; zs = q1->s.Z * s; wx = q1->s.W * xs; wy = q1->s.W * ys; wz = q1->s.W * zs; xx = q1->s.X * xs; xy = q1->s.X * ys; xz = q1->s.X * zs; yy = q1->s.Y * ys; yz = q1->s.Y * zs; zz = q1->s.Z * zs; NewObj->s.XX = 1.0f - (yy + zz); NewObj->s.YX = xy - wz; NewObj->s.ZX = xz + wy; NewObj->s.XY = xy + wz; NewObj->s.YY = 1.0f - (xx + zz); NewObj->s.ZY = yz - wx; NewObj->s.XZ = xz - wy; NewObj->s.YZ = yz + wx; NewObj->s.ZZ = 1.0f - (xx + yy); } inline static void Matrix3fMulMatrix3f(Matrix3fT* NewObj, const Matrix3fT* m1) { Matrix3fT Result; assert(NewObj && m1); // Alias-safe way Result.s.M00 = (NewObj->s.M00 * m1->s.M00) + (NewObj->s.M01 * m1->s.M10) + (NewObj->s.M02 * m1->s.M20); Result.s.M01 = (NewObj->s.M00 * m1->s.M01) + (NewObj->s.M01 * m1->s.M11) + (NewObj->s.M02 * m1->s.M21); Result.s.M02 = (NewObj->s.M00 * m1->s.M02) + (NewObj->s.M01 * m1->s.M12) + (NewObj->s.M02 * m1->s.M22); Result.s.M10 = (NewObj->s.M10 * m1->s.M00) + (NewObj->s.M11 * m1->s.M10) + (NewObj->s.M12 * m1->s.M20); Result.s.M11 = (NewObj->s.M10 * m1->s.M01) + (NewObj->s.M11 * m1->s.M11) + (NewObj->s.M12 * m1->s.M21); Result.s.M12 = (NewObj->s.M10 * m1->s.M02) + (NewObj->s.M11 * m1->s.M12) + (NewObj->s.M12 * m1->s.M22); Result.s.M20 = (NewObj->s.M20 * m1->s.M00) + (NewObj->s.M21 * m1->s.M10) + (NewObj->s.M22 * m1->s.M20); Result.s.M21 = (NewObj->s.M20 * m1->s.M01) + (NewObj->s.M21 * m1->s.M11) + (NewObj->s.M22 * m1->s.M21); Result.s.M22 = (NewObj->s.M20 * m1->s.M02) + (NewObj->s.M21 * m1->s.M12) + (NewObj->s.M22 * m1->s.M22); *NewObj = Result; } inline static void Matrix4fSetRotationScaleFromMatrix4f(Matrix4fT* NewObj, const Matrix4fT* m1) { assert(NewObj && m1); NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX; NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY; NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ; } inline static GLfloat Matrix4fSVD(const Matrix4fT* NewObj, Matrix3fT* rot3, Matrix4fT* rot4) { GLfloat s, n; assert(NewObj); s = FuncSqrt( ((NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) + (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) + (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ)) / 3.0f); if (rot3) { // This->getRotationScale(rot3); rot3->s.XX = NewObj->s.XX; rot3->s.XY = NewObj->s.XY; rot3->s.XZ = NewObj->s.XZ; rot3->s.YX = NewObj->s.YX; rot3->s.YY = NewObj->s.YY; rot3->s.YZ = NewObj->s.YZ; rot3->s.ZX = NewObj->s.ZX; rot3->s.ZY = NewObj->s.ZY; rot3->s.ZZ = NewObj->s.ZZ; // Zero-div may occur. n = 1.0f / FuncSqrt((NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ)); rot3->s.XX *= n; rot3->s.XY *= n; rot3->s.XZ *= n; n = 1.0f / FuncSqrt((NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ)); rot3->s.YX *= n; rot3->s.YY *= n; rot3->s.YZ *= n; n = 1.0f / FuncSqrt((NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ)); rot3->s.ZX *= n; rot3->s.ZY *= n; rot3->s.ZZ *= n; } if (rot4) { if (rot4 != NewObj) { Matrix4fSetRotationScaleFromMatrix4f(rot4, NewObj); // Private method } // Zero-div may occur. n = 1.0f / FuncSqrt((NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ)); rot4->s.XX *= n; rot4->s.XY *= n; rot4->s.XZ *= n; n = 1.0f / FuncSqrt((NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ)); rot4->s.YX *= n; rot4->s.YY *= n; rot4->s.YZ *= n; n = 1.0f / FuncSqrt((NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ)); rot4->s.ZX *= n; rot4->s.ZY *= n; rot4->s.ZZ *= n; } return s; } inline static void Matrix4fSetRotationScaleFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) { assert(NewObj && m1); NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX; NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY; NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ; } inline static void Matrix4fMulRotationScale(Matrix4fT* NewObj, GLfloat scale) { assert(NewObj); NewObj->s.XX *= scale; NewObj->s.YX *= scale; NewObj->s.ZX *= scale; NewObj->s.XY *= scale; NewObj->s.YY *= scale; NewObj->s.ZY *= scale; NewObj->s.XZ *= scale; NewObj->s.YZ *= scale; NewObj->s.ZZ *= scale; } inline static void Matrix4fSetRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1) { GLfloat scale; assert(NewObj && m1); scale = Matrix4fSVD(NewObj, NULL, NULL); Matrix4fSetRotationScaleFromMatrix3f(NewObj, m1); Matrix4fMulRotationScale(NewObj, scale); } typedef class ArcBall_t { protected: inline void _mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const; public: ArcBall_t(GLfloat NewWidth, GLfloat NewHeight); ~ArcBall_t() { }; inline void setBounds(GLfloat NewWidth, GLfloat NewHeight) { assert((NewWidth > 1.0f) && (NewHeight > 1.0f)); // Set adjustment factor for width/height this->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f); this->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f); } //Mouse down void click(const Point2fT* NewPt); //Mouse drag, calculate rotation void drag(const Point2fT* NewPt, Quat4fT* NewRot); protected: Vector3fT StVec; // Click vector Vector3fT EnVec; //Drag vector GLfloat AdjustWidth; // Mouse bounds width GLfloat AdjustHeight; // Mouse bounds height } ArcBallT; #endif // !_ArcBall_h
#include <Windows.h> #include <gl\glew.h> #include <GL\glut.h> #include <GL\GLUAX.H> #include <math.h> #include "ArcBall.h" void ArcBall_t::_mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const { Point2fT TempPt; GLfloat length; TempPt = *NewPt; // Adjust point coords and scale down to range of [-1 ... 1] TempPt.s.X = (TempPt.s.X * this->AdjustWidth) - 1.0f; TempPt.s.Y = 1.0f - (TempPt.s.Y * this->AdjustHeight); // Compute the square of the length of the vector to the point from the center length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y); // If the point is mapped outside of the sphere... (length > radius squared) if (length > 1.0f) { GLfloat norm; // Compute a normalizing factor (radius / sqrt(length)) norm = 1.0f / FuncSqrt(length); // Return the "normalized" vector, a point on the sphere NewVec->s.X = TempPt.s.X * norm; NewVec->s.Y = TempPt.s.Y * norm; NewVec->s.Z = 0.0f; } else { // Return a vector to a point mapped inside the sphere sqrt(radius squared - length) NewVec->s.X = TempPt.s.X; NewVec->s.Y = TempPt.s.Y; NewVec->s.Z = FuncSqrt(1.0f - length); } } ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight) { this->StVec.s.X = this->StVec.s.Y = this->StVec.s.Z = this->EnVec.s.X = this->EnVec.s.Y = this->EnVec.s.Z = 0.0f; this->setBounds(NewWidth, NewHeight); } void ArcBall_t::click(const Point2fT* NewPt) { this->_mapToSphere(NewPt, &this->StVec); } void ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot) { // Map the point to the sphere this->_mapToSphere(NewPt, &this->EnVec); // Return the quaternion equivalent to the rotation if (NewRot) { Vector3fT Perp; // Compute the vector perpendicular to the begin and end vectors Vector3fCross(&Perp, &this->StVec, &this->EnVec); // Compute the length of the perpendicular vector if (Vector3fLength(&Perp) > Epsilon) { NewRot->s.X = Perp.s.X; NewRot->s.Y = Perp.s.Y; NewRot->s.Z = Perp.s.Z; // In the quaternion values, w is cosine (theta / 2), where theta is rotation angle NewRot->s.W = Vector3fDot(&this->StVec, &this->EnVec); } else { NewRot->s.X = NewRot->s.Y = NewRot->s.Z = NewRot->s.W = 0.0f; } } }
#ifndef GL_FRAMEWORK_INCLUDED #define GL_FRAMEWORK_INCLUDED #ifndef CDS_FULLSCREEN #define CDS_FULLSCREEN 4 #endif #include <windows.h> typedef struct { // Structure for keyboard stuff BOOL keyDown[256]; } Keys; typedef struct { // Contains information vital to applications HMODULE hInstance; // Application Instance const char* className; } Application; typedef struct { // Window creation info Application* application; char* title; int width; int height; int bitsPerPixel; BOOL isFullScreen; } GL_WindowInit; typedef struct { // Contains information vital to a window Keys* keys; HWND hWnd; // Windows handle HDC hDC; // Device context HGLRC hRC; // Rendering context GL_WindowInit init; BOOL isVisible; // Window visiable? DWORD lastTickCount; // Tick counter } GL_Window; void TerminateApplication(GL_Window* window); // Terminate the application void ToggleFullscreen(GL_Window* window); // Toggle fullscreen / Windowed mode BOOL Initialize(GL_Window* window, Keys* keys); void Deinitialize(void); void Update(DWORD milliseconds); void Draw(void); #endif
#include <Windows.h> #include <GL\glew.h> #include <GL\glut.h> #include <math.h> #include "Previous.h" #include "ArcBall.h" #define WM_TOGGLEFULLSCREEN (WM_USER+1) // Application define message for toggling // between fulscreen / windowed mode static BOOL g_isProgramLooping; // Window creation loop, for fullscreen / windowed mode static BOOL g_createFullScreen; // If true, then create window extern ArcBallT ArcBall; extern Point2fT MousePt; extern bool isClicked; extern bool isRClicked; void TerminateApplication(GL_Window* window) // Terminate the application { PostMessage(window->hWnd, WM_QUIT, 0, 0); // Send a WM_QUIT message g_isProgramLooping = FALSE; // Stop looping of the program } void ToggleFullscreen(GL_Window* window) // Toggle fullscreen /windowed mode { PostMessage(window->hWnd, WM_TOGGLEFULLSCREEN, 0, 0); // Send a WM_TOGGLEFULLSCREEN message } void ReshapeGL(int width, int height) // Reshape the window when it's moved or resized { glViewport(0, 0, (GLsizei)(width), (GLsizei)(height)); // Reset the current viewport glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Calcutate the aspect ratio of the window gluPerspective(45.0f, (GLfloat)(width) / (GLfloat)(height), 1.0, 1000.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } BOOL ChangeScreenResolution(int width, int height, int bitsPerPixel) // Change the screen resolution { DEVMODE dmScreenSettings; // Device mode ZeroMemory(&dmScreenSettings, sizeof(DEVMODE)); // Make sure memory is cleared dmScreenSettings.dmSize = sizeof(DEVMODE); // Size of the devmode structure dmScreenSettings.dmPelsWidth = width; dmScreenSettings.dmPelsHeight = height; dmScreenSettings.dmBitsPerPel = bitsPerPixel; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { return FALSE; // Display change failed } return TRUE; } BOOL CreateWindowGL(GL_Window* window) { __int64 timer; DWORD windowStyle = WS_OVERLAPPEDWINDOW; // Define window style DWORD windowExtendedStyle = WS_EX_APPWINDOW; // Define the window's extended style PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size of this pixel format descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format must support window PFD_SUPPORT_OPENGL | // Format must support openGL PFD_DOUBLEBUFFER, // Must support double buffering PFD_TYPE_RGBA, // Request an RGBA format window->init.bitsPerPixel, // Select color depth 0, 0, 0, 0, 0, 0, // Color bits ignored 0, // No alpha buffer 0, // Shift bit ignored 0, // No accumulation buffer 0, 0, 0, 0, // Accumulation bits ignored 16, // 16bits Z-buffer (depth buffer) 0, // No stencil buffer 0, // No auxiliary buffer PFD_MAIN_PLANE, // Main drawing layer 0, // Reserved 0, 0, 0 // Layer masks ignored }; RECT windowRect = { 0, 0, window->init.width, window->init.height }; // Window coordiantes GLuint PixelFormat; if (window->init.isFullScreen == TRUE) { if (ChangeScreenResolution(window->init.width, window->init.height, window->init.bitsPerPixel) == FALSE) { // Fullscreen mode failed, run in windowed mode instead MessageBox(HWND_DESKTOP, "Mode Switch Failed.\nRuning In Windowed Mode.", "Error", MB_OK | MB_ICONEXCLAMATION); window->init.isFullScreen = FALSE; } else { ShowCursor(FALSE); windowStyle = WS_POPUP; // Popup window windowExtendedStyle |= WS_EX_TOPMOST; } } else { // Adjust window, account for window borders AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle); } // Create Opengl window window->hWnd = CreateWindowEx(windowExtendedStyle, // Extended style window->init.application->className, // Class name window->init.title, // Window title windowStyle, // Window style 0, 0, // Window X,Y position windowRect.right - windowRect.left, // Window width windowRect.bottom - windowRect.top, // Window height HWND_DESKTOP, // Desktop is window's parent 0, // No menu window->init.application->hInstance, // Pass the window instance window); if (window->hWnd == 0) { // Was window creation a success? return FALSE; } window->hDC = GetDC(window->hWnd); if (window->hDC == 0) { DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } PixelFormat = ChoosePixelFormat(window->hDC, &pfd); // Find a compatible pixel format if (PixelFormat == 0) { ReleaseDC(window->hWnd, window->hDC); // Release device context window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } if (SetPixelFormat(window->hDC, PixelFormat, &pfd) == FALSE) { // Try to set the pixel format ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } window->hRC = wglCreateContext(window->hDC); // Try to get a rendering context if (window->hRC == 0) { ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } // Make the rendering context our current rendering context if (wglMakeCurrent(window->hDC, window->hRC) == FALSE) { wglDeleteContext(window->hRC); // Delete the rendering context window->hRC = 0; ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } ShowWindow(window->hWnd, SW_NORMAL); // Make the window visiable window->isVisible = TRUE; ReshapeGL(window->init.width, window->init.height); // Reshape our GL window ZeroMemory(window->keys, sizeof(Keys)); // Clear all keys /**************************************************************************************************************/ /**************************************************************************************************************/ window->lastTickCount = GetTickCount(); /**************************************************************************************************************/ /**************************************************************************************************************/ return TRUE; } BOOL DestroyWindowGL(GL_Window* window) { if (window->hWnd != 0) { if (window->hDC != 0) { wglMakeCurrent(window->hDC, 0); // Setting current active rendering context to zero if (window->hRC != 0) { wglDeleteContext(window->hRC); window->hRC = 0; } ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; } DestroyWindow(window->hWnd); window->hWnd = 0; } if (window->init.isFullScreen) { ChangeDisplaySettings(NULL, 0); // Switch back to desktop resolution ShowCursor(TRUE); } return TRUE; } // Process window message callback LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Get the window context GL_Window* window = (GL_Window*)(GetWindowLong(hWnd, GWL_USERDATA)); switch (uMsg) { // Evaluate window message case WM_MOUSEMOVE: MousePt.s.X = (GLfloat)LOWORD(lParam); MousePt.s.Y = (GLfloat)HIWORD(lParam); isClicked = (LOWORD(wParam) & MK_LBUTTON) ? true : false; isRClicked = (LOWORD(wParam) & MK_RBUTTON) ? true : false; break; case WM_LBUTTONUP: isClicked = false; break; case WM_RBUTTONUP: isRClicked = false; break; case WM_LBUTTONDOWN: isClicked = true; break; case WM_RBUTTONDOWN: isRClicked = true; break; case WM_SYSCOMMAND: // Intercept system commands { switch (wParam) { // Check system calls case SC_SCREENSAVE: // Screensaver trying to start? case SC_MONITORPOWER: // Mointer trying to enter powersave? return 0; // Prevent form happening } break; } return 0; case WM_CREATE: { CREATESTRUCT* creation = (CREATESTRUCT*)(lParam); // Store window structure pointer window = (GL_Window*)(creation->lpCreateParams); SetWindowLong(hWnd, GWL_USERDATA, (LONG)(window)); } return 0; case WM_CLOSE: TerminateApplication(window); return 0; case WM_SIZE: switch (wParam) { case SIZE_MINIMIZED: // Was window minimized? window->isVisible = FALSE; return 0; case SIZE_MAXIMIZED: window->isVisible = TRUE; ReshapeGL(LOWORD(lParam), HIWORD(lParam)); return 0; case SIZE_RESTORED: window->isVisible = TRUE; ReshapeGL(LOWORD(lParam), HIWORD(lParam)); return 0; } break; case WM_KEYDOWN: if ((wParam >= 0) && (wParam <= 255)) { window->keys->keyDown[wParam] = TRUE; // Set the selected key(wParam) to true return 0; } break; case WM_KEYUP: if ((wParam >= 0) && (wParam <= 255)) { window->keys->keyDown[wParam] = FALSE; return 0; } break; case WM_TOGGLEFULLSCREEN: g_createFullScreen = (g_createFullScreen == TRUE) ? FALSE : TRUE; PostMessage(hWnd, WM_QUIT, 0, 0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); // Pass unhandle message to DefWindowProc } BOOL RegisterWindowClass(Application* application) { WNDCLASSEX windowClass; ZeroMemory(&windowClass, sizeof(WNDCLASSEX)); // Make sure memory is cleared windowClass.cbSize = sizeof(WNDCLASSEX); // Size of the windowClass structure windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraws the window for any movement / resizing windowClass.lpfnWndProc = (WNDPROC)(WindowProc); // WindowProc handles message windowClass.hInstance = application->hInstance; // Set the instance windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);// Class background brush color windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the arrow pointer windowClass.lpszClassName = application->className; // Sets the application className if (RegisterClassEx(&windowClass) == 0) { MessageBox(HWND_DESKTOP, "RegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; } return TRUE; } int WINAPI WinMain(HINSTANCE hIstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { Application application; GL_Window window; Keys keys; BOOL isMessagePumpActive; MSG msg; DWORD tickCount; application.className = "OpenGL"; application.hInstance = hIstance; ZeroMemory(&window, sizeof(GL_Window)); window.keys = &keys; // Window key structure window.init.application = &application; // Window application window.init.title = "Resource File"; // Window title window.init.width = 640; // Window width window.init.height = 480; // Window height window.init.bitsPerPixel = 16; // Bits per pixel window.init.isFullScreen = TRUE; // Fullscreen? (set to TRUE) ZeroMemory(&keys, sizeof(Keys)); if (MessageBox(HWND_DESKTOP, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO | MB_ICONQUESTION) == IDNO) { window.init.isFullScreen = FALSE; } if (RegisterWindowClass(&application) == FALSE) { MessageBox(HWND_DESKTOP, "Error Registering Window Class!", "Error", MB_OK | MB_ICONEXCLAMATION); return -1; } g_isProgramLooping = TRUE; g_createFullScreen = window.init.isFullScreen; while (g_isProgramLooping) { // Loop until WM_QUIT is received window.init.isFullScreen = g_createFullScreen; // Set init param of window creation to fullscreen? if (CreateWindowGL(&window) == TRUE) { // Was window creation successful? // At this point we should have a window that is setup to render OpenGL if (Initialize(&window, &keys) == FALSE) { TerminateApplication(&window); // Close window, this will handle the shutdown } else { isMessagePumpActive = TRUE; while (isMessagePumpActive == TRUE) { // Success creating window. Check for window messages if (PeekMessage(&msg, window.hWnd, 0, 0, PM_REMOVE) != 0) { if (msg.message != WM_QUIT) { DispatchMessage(&msg); } else { isMessagePumpActive = FALSE; // Terminate the message pump } } else { if (window.isVisible == FALSE) { WaitMessage(); // Application is minimized wait for a message } else { // Process application loop tickCount = GetTickCount(); // Get the tick count Update(tickCount - window.lastTickCount); // Update the counter window.lastTickCount = tickCount;// Set last count to current count Draw(); // Draw screen SwapBuffers(window.hDC); } } } } // Application is finished Deinitialize(); DestroyWindowGL(&window); } else { MessageBox(HWND_DESKTOP, "Error Creating OpenGL Window", "Error", MB_OK | MB_ICONEXCLAMATION); g_isProgramLooping = FALSE; } } UnregisterClass(application.className, application.hInstance); // UnRegister window class return 0; }
#include <windows.h> #include <stdio.h> #include <math.h> #include <gl/glew.h> #include <gl/glut.h> #include <GL/GLUAX.H> #include <mmsystem.h> #include "Previous.h" #include "ArcBall.h" #pragma comment(lib, "legacy_stdio_definitions.lib") GL_Window* g_window; Keys* g_keys; GLUquadricObj *quadratic; const float PI2 = 2.0*3.1415926535f; Matrix4fT Transform = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix3fT LastRot = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix3fT ThisRot = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; ArcBallT ArcBall(640.0f, 480.0f); Point2fT MousePt; bool isClicked = false; bool isRClicked = false; bool isDragging = false; BOOL Initialize(GL_Window* window, Keys* keys) { g_window = window; g_keys = keys; isClicked = false; isDragging = false; glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); quadratic = gluNewQuadric(); gluQuadricNormals(quadratic, GLU_SMOOTH); gluQuadricTexture(quadratic, GL_TRUE); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); return TRUE; } void Deinitialize(void) { gluDeleteQuadric(quadratic); } void Update(DWORD milliseconds) { if (g_keys->keyDown[VK_ESCAPE] == TRUE) { TerminateApplication(g_window); } if (g_keys->keyDown[VK_F1] == TRUE) { ToggleFullscreen(g_window); } if (isRClicked) { Matrix3fSetIdentity(&LastRot); Matrix3fSetIdentity(&ThisRot); Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); } if (!isDragging) { if (isClicked){ isDragging = true; LastRot = ThisRot; ArcBall.click(&MousePt); } } else { if (isClicked) { Quat4fT ThisQuat; ArcBall.drag(&MousePt, &ThisQuat); Matrix3fSetRotationFromQuat4f(&ThisRot, &ThisQuat); Matrix3fMulMatrix3f(&ThisRot, &LastRot); Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); } else { isDragging = false; } } } void Torus(float MinorRadius, float MajorRadius) // Draw a torus with normals { int i, j; glBegin(GL_TRIANGLE_STRIP); for (i = 0; i<20; i++) { for (j = -1; j<20; j++) { float wrapFrac = (j % 20) / (float)20; float phi = PI2*wrapFrac; float sinphi = float(sin(phi)); float cosphi = float(cos(phi)); float r = MajorRadius + MinorRadius*cosphi; glNormal3f(float(sin(PI2*(i % 20 + wrapFrac) / (float)20))*cosphi, sinphi, float(cos(PI2*(i % 20 + wrapFrac) / (float)20))*cosphi); glVertex3f(float(sin(PI2*(i % 20 + wrapFrac) / (float)20))*r, MinorRadius*sinphi, float(cos(PI2*(i % 20 + wrapFrac) / (float)20))*r); glNormal3f(float(sin(PI2*(i + 1 % 20 + wrapFrac) / (float)20))*cosphi, sinphi, float(cos(PI2*(i + 1 % 20 + wrapFrac) / (float)20))*cosphi); glVertex3f(float(sin(PI2*(i + 1 % 20 + wrapFrac) / (float)20))*r, MinorRadius*sinphi, float(cos(PI2*(i + 1 % 20 + wrapFrac) / (float)20))*r); } } glEnd(); } void Draw(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(-1.5f, 0.0f, -6.0f); glPushMatrix(); glMultMatrixf(Transform.M); glColor3f(0.75f, 0.75f, 1.0f); Torus(0.30f, 1.00f); glPopMatrix(); glLoadIdentity(); glTranslatef(1.5f, 0.0f, -6.0f); glPushMatrix(); glMultMatrixf(Transform.M); glColor3f(1.0f, 0.75f, 0.75f); gluSphere(quadratic, 1.3f, 20, 20); glPopMatrix(); glFlush(); }
Thanks for Nehe's tutorials, this is his home.