首页 > 代码库 > outdated: 48.ArcBall Rotation

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 librarytypedef 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-5inline 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
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;        }    }}
ArcBall.cpp
技术分享
#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 applicationvoid ToggleFullscreen(GL_Window* window);          // Toggle fullscreen / Windowed modeBOOL Initialize(GL_Window* window, Keys* keys);void Deinitialize(void);void Update(DWORD milliseconds);void Draw(void);#endif
Previous.h
技术分享
#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 modestatic BOOL g_isProgramLooping;                           // Window creation loop, for fullscreen / windowed modestatic BOOL g_createFullScreen;                           // If true, then create windowextern 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 callbackLRESULT 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;}
Previous.cpp
技术分享
#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();}
Main.cpp

Thanks for Nehe‘s tutorials, this is his home.

outdated: 48.ArcBall Rotation