12,454,091 members (57,592 online)

67K views
87 bookmarked
Posted

# A New Perspective on Viewing

, 6 Oct 2009 CPOL
Simple yet comprehensive viewing code for OpenGL and Direct3D.
 ```// Main.cpp // // High level code for the NewView demo // // Copyright (C) 2009 John Hilton // // CMainImpl : IGfx::ICallbacks // m_GfxWinOpenGL CGfxWin : CGfxOpenGLf, CWindowImpl // m_GfxWinDirect3D CGfxWin : CGfxDirect3Df, CWindowImpl // CGfxOpenGLf : IGfx // CGfxDirect3Df : IGfx // CGfxOpenGLImpl : CGfxSubclass // CGfxDirect3DImpl : CGfxSubclass // CGfxSubclass : CWindowImpl #include "stdafx.h" #include "Main.h" #include "Gfx.h" #include "Interact.h" #define _USE_MATH_DEFINES #include "math.h" #pragma region SpatialMath template< typename T > union TVec3 { T v3[3]; struct { T x, y, z; }; }; template< typename T > union TRotTrn { T v12[12]; T m4x3[4][3]; struct { T m3x3[3][3]; union { T v3[3]; struct { T x, y, z; }; }; }; }; template< typename T > TVec3 operator/( TVec3& vec, TRotTrn& RotTrn ) { // Translate vec by -trn TVec3 vA = { vec.x-RotTrn.x, vec.y-RotTrn.y, vec.z-RotTrn.z }; // Rotate vA by Inverse(rot) TVec3 vB; for (int i=0; i<3; i++) vB.v3[i] = vA.x * RotTrn.m3x3[i][0] + vA.y * RotTrn.m3x3[i][1] + vA.z * RotTrn.m3x3[i][2]; return vB; } typedef TVec3 TVec3f; typedef TRotTrn TRotTrnf; #pragma endregion static DWORD Cube[] = { // Front, back, bottom, top, left and right faces //GFXCOLOR(1.0,0.5,0.9), GFXTRIANGLESTRIP(2), GFXV(0,0,1), GFXV(0,1,1), GFXV(1,0,1), GFXV(1,1,1), GFXCOLOR(0.5,0.9,0.8), GFXTRIANGLESTRIP(2), GFXV(0,0,0), GFXV(1,0,0), GFXV(0,1,0), GFXV(1,1,0), GFXCOLOR(0.7,0.4,0.2), GFXTRIANGLESTRIP(2), GFXV(0,0,0), GFXV(0,0,1), GFXV(1,0,0), GFXV(1,0,1), GFXCOLOR(0.3,0.8,0.5), GFXTRIANGLESTRIP(2), GFXV(0,1,0), GFXV(1,1,0), GFXV(0,1,1), GFXV(1,1,1), GFXCOLOR(1.0,1.0,1.0), GFXTRIANGLESTRIP(2), GFXV(0,0,0), GFXV(0,1,0), GFXV(0,0,1), GFXV(0,1,1), GFXCOLOR(0.9,0.2,0.4), GFXTRIANGLESTRIP(2), GFXV(1,0,0), GFXV(1,0,1), GFXV(1,1,0), GFXV(1,1,1) }; static int Cubelength = sizeof(Cube)/sizeof(*Cube); struct IGfxWinCallbacks { virtual void OnLbuttonDown( HWND hWnd, UINT nFlags, POINTS Points, IGfx& gfx ) = 0; virtual void OnMouseMove( HWND hWnd, UINT nFlags, POINTS Points, IGfx& gfx ) = 0; }; // CGfxWin - combines CWindowImpl<> with an IGfx derived object template< typename TGfx > class CGfxWin : public TGfx, public CWindowImpl> { public: IGfxWinCallbacks* m_pGfxWinCallbacks; CGfxWin( typename TGfx::ICallbacks& GfxCallbacks, typename IGfxWinCallbacks& GfxWinCallbacks ) : TGfx(GfxCallbacks) , m_pGfxWinCallbacks(&GfxWinCallbacks) { } void Create( HWND hWndParent, RECT& rect ) { CWindowImpl::Create( hWndParent, rect ); TGfx::Attach(m_hWnd); } BEGIN_MSG_MAP(CGfxWin) MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove ); MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBkgnd ); MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLbuttonDown ); MESSAGE_HANDLER( WM_LBUTTONUP, OnLbuttonUp ); END_MSG_MAP() LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { uMsg; wParam; lParam; bHandled; // do nothing - don't draw the background return 0L; } LRESULT OnLbuttonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { uMsg; bHandled; UINT nFlags = (UINT) wParam; POINTS MousePos = MAKEPOINTS(lParam); m_pGfxWinCallbacks->OnLbuttonDown( m_hWnd, nFlags, MousePos, *this ); SetCapture(); return 0L; } LRESULT OnLbuttonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { uMsg; wParam; lParam; bHandled; ReleaseCapture(); return 0L; } LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { uMsg; bHandled; UINT nFlags = (UINT) wParam; // Ignore the mouse move unless the left mouse button is down if (~nFlags & MK_LBUTTON) return 0L; POINTS MousePos = MAKEPOINTS(lParam); m_pGfxWinCallbacks->OnMouseMove( m_hWnd, nFlags, MousePos, *this ); return 0L; } }; class CMainImpl : public IGfx::ICallbacks , public IGfxWinCallbacks , public CWindowImpl // intercept WM_SIZE , public CInteract { public: CGfxWin m_GfxWinOpenGL; CGfxWin m_GfxWinDirect3D; float m_ViewAngle; // radians float m_HalfViewSize; float m_ViewVolume[7]; float m_ViewToWorld[4][3]; BEGIN_MSG_MAP(CMainImpl) MESSAGE_HANDLER( WM_SIZE, OnSize ); MESSAGE_HANDLER( WM_CHAR, OnChar ); END_MSG_MAP() CMainImpl( HWND hWnd ) // constructor : CInteract() , m_GfxWinOpenGL( *this, *this ) , m_GfxWinDirect3D( *this, *this ) { ResetView(); VERIFY(SubclassWindow( hWnd )); // Get the client rectangle RECT rectClient; GetClientRect( &rectClient ); // Split it vertically in two LONG width = rectClient.right; LONG height = rectClient.bottom; LONG mid = width / 2; // Create the OpenGL window and attach it to the CGfxOpenGL object RECT rectOpenGL = { 0, 0, mid, height }; m_GfxWinOpenGL.Create( hWnd, rectOpenGL ); // Create the Direct3D window and attach it to the CGfxDirect3D object RECT rectDirect3D = { mid, 0, width, height }; m_GfxWinDirect3D.Create( hWnd, rectDirect3D ); } ~CMainImpl() { if (m_hWnd) UnsubclassWindow(); } LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { wParam; nMsg; bHandled; lParam; //int cx = LOWORD(lParam); int cy = HIWORD(lParam); if (!m_hWnd || !cy) return 0L; // Get the client rectangle RECT rectClient; GetClientRect( &rectClient ); // Split it vertically in two LONG width = rectClient.right; LONG height = rectClient.bottom; LONG mid = width / 2; // Create the OpenGL window and attach it to the CGfxOpenGL object RECT rectOpenGL = { 0, 0, mid, height }; m_GfxWinOpenGL.MoveWindow( &rectOpenGL ); // Create the Direct3D window and attach it to the CGfxDirect3D object RECT rectDirect3D = { mid, 0, width, height }; m_GfxWinDirect3D.MoveWindow( &rectDirect3D ); bHandled = FALSE; // pass on to default handler return 0L; } LRESULT OnChar(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { nMsg; lParam; bHandled; switch (wParam) { case ' ': ResetView(); break; case 'P': case 'p': TogglePerspective(); break; } return 0L; } void ResetView() { m_ViewAngle = 45 * (float)M_PI/180; m_HalfViewSize = 10; static const float identity[4][3] = {{1,0,0},{0,1,0},{0,0,1},{0,0,0}}; struct Tv12 { float v12[12]; }; *(Tv12*) m_ViewToWorld = *(Tv12*) identity; if (IsWindow()) Invalidate(FALSE); } void TogglePerspective() { if (m_ViewAngle) m_ViewAngle = 0; else m_ViewAngle = 45 * (float)M_PI/180; Invalidate(FALSE); } virtual void OnPaint( IGfx& gfx ) { float ViewVolume[7]; CalcViewVolume( ViewVolume, gfx ); gfx.ConfigureView( ViewVolume, m_ViewToWorld ); gfx.Push(); gfx.Translate( -4, 0, 0 ); gfx.Scale( 4 ); gfx.Translate( -0.5, -0.5, -0.5 ); gfx.Render( Cube, Cubelength ); gfx.Pop(); gfx.Translate( 4, 0, 0 ); gfx.Scale( 4 ); gfx.Translate( -0.5, -0.5, -0.5 ); gfx.Render( Cube, Cubelength ); } void CalcViewVolume( float ViewVolume[7], IGfx& gfx ) { TViewVolumef& vv = *(TViewVolumef*) ViewVolume; vv.hw = vv.hh = m_HalfViewSize; vv.zn = 10; vv.zf = -10; vv.iez = tan(0.5f*m_ViewAngle)/m_HalfViewSize; vv.tsx = vv.tsy = 0; // Match the aspect ratio by extending hw or hh // Get the client rectangle RECT rectClient; if (&gfx == &m_GfxWinOpenGL) m_GfxWinOpenGL.GetClientRect( &rectClient ); else m_GfxWinDirect3D.GetClientRect( &rectClient ); float width = (float) rectClient.right; float height = (float) rectClient.bottom; // Scale the width or height up to match the aspect ratio if (width >= height) vv.hw *= width / height; else vv.hh *= height / width; } virtual void IGfx::ICallbacks::OnFinalMessage( HWND hWnd ) { hWnd; // do nothing } virtual void IGfxWinCallbacks::OnLbuttonDown( HWND hWnd, UINT nFlags, POINTS MousePos, IGfx& gfx ) { hWnd; nFlags; gfx; CInteract::OnLbuttonDown( MousePos ); } virtual void IGfxWinCallbacks::OnMouseMove( HWND hWnd, UINT nFlags, POINTS MousePos, IGfx& gfx ) { TViewVolumef ViewVolume; CalcViewVolume( ViewVolume.v7, gfx ); BOOL Redraw = CInteract::OnMouseMove( hWnd, nFlags, MousePos, ViewVolume.v7, m_ViewToWorld ); m_HalfViewSize = min( ViewVolume.hw, ViewVolume.hh ); if (Redraw) InvalidateRect( NULL, FALSE ); } }; CMain::CMain( HWND hWnd ) { m_pImpl = new CMainImpl( hWnd ); ASSERT(m_pImpl); MessageBox( NULL, _T("The left window is rendered with OpenGL and the right with Direct3D.\r\n") _T("Use the left mouse button (LMB) to pan, LMB+SHIFT to zoom/spinZ and\r\n") _T("LMB+CTRL to spinXY.\r\n") _T("Press SPACE to reset the view and P to toggle perspective.\r\n"), _T("NewView"), MB_OK ); } CMain::~CMain() { if (m_pImpl) delete m_pImpl; } ```

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

## Share

 Founder Spatial Freedom Australia
Software engineer, mechanical engineer, electronics engineer, inventor, manager, entrepreneur, husband, father, friend.
B.Sc. B.E.(Hons) M.Eng.Sc.
Some things I've done
- Invented the Spaceball(R)/1983 and Astroid(R)/2002 3D mice
- Patents: 3D mouse, data compression, acoustic transducer
- Wrote animation software in mid 1980s for TV commercials
- Wrote a basic CAD drawing program in 1980s
- Lived in Boston, Massachusetts for 11 years
- Architected and managed full custom ASIC chip
- Reviewed bionic eye technology for investment purposes
- Product development on CPR aid for heart attacks
- Developed an electronic sports whistle
- Was actually stranded on a deserted Pacific island
- Software: lots - embedded, device driver, applications
Some things I want to do
- Develop more cool hardware/software products
- Solve the 3D mouse software barrier to proliferate 3D mice
- Help bring 3D to the masses
- Help others

## You may also be interested in...

 Pro Pro