Click here to Skip to main content
15,893,923 members
Articles / Desktop Programming / MFC

PicZoom: A Photo Viewer Created in OpenGL

Rate me:
Please Sign up or sign in to vote.
4.86/5 (64 votes)
16 Feb 2011CPOL16 min read 160.9K   11.6K   151  
PicZoom: A Photo Viewer created in OpenGL
#include "StdAfx.h"
#include "SlideShow.h"
#include "GLTexture.h"
#include "GLVertexBuffer.h"
#include "GLExtension.h"
#include "PicZoomUtil.h"
#include "FileExplorer.h"
#include "BMPLoader.h"
#include "Consts.h"

const int ONE_SLIDE_DELAY = 200;

SlideShow::SlideShow( HWND hParent_i, FileExplorer* pFileExplorer_i )
{
    m_hParent = hParent_i;
    m_pFileExplorer = pFileExplorer_i;
    m_pTexture1 = new GLTexture;
    m_pTexture2 = new GLTexture;
    m_pVertexBuffer1 = new GLVertexBuffer;
    m_pVertexBuffer2 = new GLVertexBuffer;
}

SlideShow::~SlideShow(void)
{
}

void SlideShow::Start()
{
    // Reset old projection.
    glMatrixMode( GL_PROJECTION );
    glPushMatrix();
    // Set Repeat state of FileExplorer to On,
    m_pFileExplorer->SetRepeatState( true );

    RECT FullScreenRegion;
    ::GetWindowRect( ::GetDesktopWindow(), &FullScreenRegion );

    // Here initialize two textures with new current texture and next texture.
    CString csNextFile = m_pFileExplorer->GetCurrentName();
    BMPLoader Loader;
    {
        // Creating first texture with current texture.
        int nWidth, nHeight;
        BYTE* pbyData = 0;
        Loader.LoadBMP( csNextFile.GetBuffer( 0 ), nWidth, nHeight, pbyData );
        if( m_pTexture1 )
        {
            delete m_pTexture1;
            m_pTexture1 = 0;
        }
        m_pTexture1 = new GLTexture();
        m_pTexture1->Create( nWidth, nHeight, pbyData );
        delete[] pbyData;

        float fTextureXMax = 1.0;
        float fTextureYMax = 1.0;
        if( !GLExtension::GetInstance().m_bNonPowerOfTwo )
        {
            fTextureXMax = (float)nWidth / PicZoomUtil::GetNearestPowerOf2( nWidth );
            fTextureYMax = (float)nHeight / PicZoomUtil::GetNearestPowerOf2( nHeight );
        }
        // Create vertex buffer for full region window display.
        m_pVertexBuffer1->Create( 4 );
        m_pVertexBuffer1->SetAt( 0, -nWidth / 2, -nHeight / 2, 0.0, 0.0, 0.0 );
        m_pVertexBuffer1->SetAt( 1, -nWidth / 2,  nHeight / 2, 0.0, 0.0, fTextureYMax );
        m_pVertexBuffer1->SetAt( 2,  nWidth / 2,  nHeight / 2, 0.0, fTextureXMax, fTextureYMax );
        m_pVertexBuffer1->SetAt( 3,  nWidth / 2, -nHeight / 2, 0.0, fTextureXMax, 0.0 );

        // Find zoom factor for full screen window display.
        float fXDirZoom = FullScreenRegion.right / (float)nWidth;
        float fYDirZoom = FullScreenRegion.bottom / (float)nHeight;
        // Get minimum zoom, that can be used for displaying full screen Drawing.
        m_fZoom1 = min( fXDirZoom, fYDirZoom );
    }

    {
        // Creating second texture with next file.
        CString csNextFile = m_pFileExplorer->GetNextFileName();
        BMPLoader Loader;
        int nWidth, nHeight;
        BYTE* pbyData = 0;
        Loader.LoadBMP( csNextFile.GetBuffer( 0 ), nWidth, nHeight, pbyData );

        if( m_pTexture2 )
        {
            delete m_pTexture2;
            m_pTexture2 = 0;
        }
        m_pTexture2 = new GLTexture();
        m_pTexture2->Create( nWidth, nHeight, pbyData );
        delete[] pbyData;

        float fTextureXMax = 1.0;
        float fTextureYMax = 1.0;
        if( !GLExtension::GetInstance().m_bNonPowerOfTwo )
        {
            fTextureXMax = (float)nWidth / PicZoomUtil::GetNearestPowerOf2( nWidth );
            fTextureYMax = (float)nHeight / PicZoomUtil::GetNearestPowerOf2( nHeight );
        }

        // Create vertex buffer for full region window display.
        m_pVertexBuffer2->Create( 4 );
        m_pVertexBuffer2->SetAt( 0, -nWidth / 2, -nHeight / 2, 0.0, 0.0,          0.0 );
        m_pVertexBuffer2->SetAt( 1, -nWidth / 2,  nHeight / 2, 0.0, 0.0,          fTextureYMax );
        m_pVertexBuffer2->SetAt( 2,  nWidth / 2,  nHeight / 2, 0.0, fTextureXMax, fTextureYMax );
        m_pVertexBuffer2->SetAt( 3,  nWidth / 2, -nHeight / 2, 0.0, fTextureXMax, 0.0 );

        // Find zoom factor for full screen window display.
        float fXDirZoom = FullScreenRegion.right / (float)nWidth;
        float fYDirZoom = FullScreenRegion.bottom / (float)nHeight;
        // Get minimum zoom, that can be used for displaying full screen Drawing.
        m_fZoom2 = min( fXDirZoom, fYDirZoom );
    }

    // Get previous window state.
    ::GetWindowRect( m_hParent, &m_stPreviousWindowRegion );

    // Hold previous projection matrix.
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    // Setup projection matrix for full screen display.
    int nWidth = (float)FullScreenRegion.right / 2;
    int nHeight = (float)FullScreenRegion.bottom/ 2;
    glOrtho( -nWidth, nWidth, -nHeight, nHeight, 0.0, 2.0 );

    // take old viewport and set new one.
    glGetIntegerv( GL_VIEWPORT, m_nOldViewPortArray );
    glViewport( 0, 0, FullScreenRegion.right, FullScreenRegion.bottom );

    m_nOldWindowStyle = ::GetWindowLong( m_hParent, GWL_STYLE );

    // int nRemovedStyle = m_nOldWindowStyle 
    // Here change window style to overlapped.
    ::SetWindowLong( m_hParent,GWL_STYLE, WS_OVERLAPPED );

    // Here change width and height of current windoW to Full size.
    ::SetWindowPos( m_hParent, 0, 0, 0, FullScreenRegion.right, FullScreenRegion.bottom, SWP_SHOWWINDOW );



    // Start Timer with 20 ms delay.
    ::SetTimer( m_hParent, TIMER_SLIDE_SHOW, 20, 0 );

    // After 1 second changes the image.
    m_SlideShowTimer.SetMaxElapseTime( ONE_SLIDE_DELAY );

    // Hide mouse cursor
    ::ShowCursor( false );
}

void SlideShow::Stop()
{
    // Here delete all resources.
    delete m_pTexture1;
    delete m_pTexture2;
    delete m_pVertexBuffer1;
    delete m_pVertexBuffer2;

    // Make current displayed image as previous image.
//    m_pFileExplorer->GetPreviousFileName();
    m_pFileExplorer->SetRepeatState( false );

    ::SetWindowLong( m_hParent, GWL_STYLE, m_nOldWindowStyle );

    // Change window size to previous state.
    ::SetWindowPos( m_hParent, 0, m_stPreviousWindowRegion.left, m_stPreviousWindowRegion.top,
                    m_stPreviousWindowRegion.right, m_stPreviousWindowRegion.bottom, SWP_SHOWWINDOW );
    ::KillTimer( m_hParent, TIMER_SLIDE_SHOW );

    // Show mouse cursor.
    ::ShowCursor( true );

    // Reset old viewport.
    glViewport( m_nOldViewPortArray[0], m_nOldViewPortArray[1],
                m_nOldViewPortArray[2], m_nOldViewPortArray[3] );

    // Reset old projection.
    glMatrixMode( GL_PROJECTION );
    glPopMatrix();
}

void SlideShow::Display()
{
    glClearColor( 0.0, 0.0, 0.0, 0.0 );
    // Here clear the background with black.
    glClear( GL_COLOR_BUFFER_BIT );

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    glMatrixMode( GL_MODELVIEW );
    glPushMatrix();
    glLoadIdentity();

    // Apply First texture transparency.
    int nRemTime = m_SlideShowTimer.GetRemainingTime();

    if( 0 == nRemTime )
    {
        // Here loop completed, need to swap the textures and create a new texture with 
        // next image.
        CreateNextImage();
        m_SlideShowTimer.SetMaxElapseTime( ONE_SLIDE_DELAY );
        nRemTime = ONE_SLIDE_DELAY;
    }

    // last 100 clocks are used for interpolation.
    float fColorFactor = nRemTime / 100.0;
    fColorFactor = min( 1.0, fColorFactor );

    // glColor3f is used to make small amount of texture display.
    // This color factor is multiplied with texel color and get a shading effect.
    glColor4f( fColorFactor, fColorFactor, fColorFactor, fColorFactor );
    m_pTexture1->Enable();
    // Apply zoom1.
    glScalef( m_fZoom1, m_fZoom1, 0.0 );
    m_pVertexBuffer1->DrawVertexBuffer( GL_QUADS );
    glPopMatrix();

    if( nRemTime < 100 )
    {
        glPushMatrix();
        // When transparent display of second texture is required.
        float fTex2Color = 1.0 - fColorFactor;
        glColor4f( fTex2Color, fTex2Color, fTex2Color, fTex2Color );
        m_pTexture2->Enable();
        // Apply Zoom 2.
        glScalef( m_fZoom2, m_fZoom2, 0.0 );
        m_pVertexBuffer2->DrawVertexBuffer( GL_QUADS );
        glPopMatrix();
    }

    // After one display decrease Slideshow timer
    m_SlideShowTimer.ElapseTime();
    glDisable( GL_BLEND );
}

// This function is called when display of two textures are completed, and now
// need require a new texture for interpolation.
// This function create a new texture with NextFile() of FileExplorer.
// And Swaps texture 2 to Texture 1.
void SlideShow::CreateNextImage()
{
    delete m_pTexture1;
    m_pTexture1 = 0;
    delete m_pVertexBuffer1;
    m_pVertexBuffer1 = 0;


    // Copy texture2 parameters to texture 1.
    m_pTexture1 = m_pTexture2;
    m_pVertexBuffer1 = m_pVertexBuffer2;
    m_fZoom1 = m_fZoom2;

    m_pTexture2 = 0;
    m_pVertexBuffer2 = 0;
    // Create new texture with next image.
    {
        RECT FullScreenRegion;
        ::GetWindowRect( ::GetDesktopWindow(), &FullScreenRegion );

        m_pVertexBuffer2 = new GLVertexBuffer;
        m_pTexture2 = new GLTexture;
        // Creating second texture with next file.
        CString csNextFile = m_pFileExplorer->GetNextFileName();
        BMPLoader Loader;
        int nWidth, nHeight;
        BYTE* pbyData = 0;
        Loader.LoadBMP( csNextFile.GetBuffer( 0 ), nWidth, nHeight, pbyData );
        m_pTexture2->Create( nWidth, nHeight, pbyData );
        delete[] pbyData;

        float fTextureXMax = 1.0;
        float fTextureYMax = 1.0;
        if( !GLExtension::GetInstance().m_bNonPowerOfTwo )
        {
            fTextureXMax = (float)nWidth / PicZoomUtil::GetNearestPowerOf2( nWidth );
            fTextureYMax = (float)nHeight / PicZoomUtil::GetNearestPowerOf2( nHeight );
        }

        // Create vertex buffer for full region window display.
        m_pVertexBuffer2->Create( 4 );
        m_pVertexBuffer2->SetAt( 0, -nWidth / 2, -nHeight / 2, 0.0, 0.0,          0.0 );
        m_pVertexBuffer2->SetAt( 1, -nWidth / 2,  nHeight / 2, 0.0, 0.0,          fTextureYMax );
        m_pVertexBuffer2->SetAt( 2,  nWidth / 2,  nHeight / 2, 0.0, fTextureXMax, fTextureYMax );
        m_pVertexBuffer2->SetAt( 3,  nWidth / 2, -nHeight / 2, 0.0, fTextureXMax, 0.0 );

        // Find zoom factor for full screen window display.
        float fXDirZoom = FullScreenRegion.right / (float)nWidth;
        float fYDirZoom = FullScreenRegion.bottom / (float)nHeight;
        // Get minimum zoom, that can be used for displaying full screen Drawing.
        m_fZoom2 = min( fXDirZoom, fYDirZoom );
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions