SampleViewportFilter/SampleViewportFilter.cpp

//**************************************************************************/
// Copyright (c) 2008 Autodesk, Inc.
// All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk license
// agreement provided at the time of installation or download, or which
// otherwise accompanies this software in either electronic or hard copy form.
//
//**************************************************************************/
// DESCRIPTION:
// CREATED: October 2008
//**************************************************************************/
#define _USE_MATH_DEFINES
#include <cmath>

#include "SampleViewportFilter.h"

#include <QtCore/QDir>

using namespace mudbox;

// Filter plugin macros
IMPLEMENT_VCLASS( SampleViewPortFilter, ViewPortFilter, "Sample Viewport Filter", 1 );

MB_PLUGIN( "Sample Filter", "Sample Viewport Filter", "Autodesk", "http://www.mudbox3d.com", 0 );

// Render texture to screen to activate shaders.

static void drawFullScreenQuad() {
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glBegin( GL_QUADS );

    glTexCoord2f( 0, 0 );
    glVertex2f( -1, -1 );

    glTexCoord2f( 1, 0 );
    glVertex2f( 1, -1 );

    glTexCoord2f( 1, 1 );
    glVertex2f( 1, 1 );

    glTexCoord2f( 0, 1 );
    glVertex2f( -1, 1 );

    glEnd();
}

// Renders full screens quad to texture specified
static void gpuTransform(Texture* const outputTexture) {
    outputTexture->SetAsRenderTarget();
    drawFullScreenQuad();
    outputTexture->RestoreRenderTarget();
}

void SampleViewPortFilter::OnNodeEvent( const Attribute &cAttribute, NodeEventType eType ) {
    if(eType == etValueChanged) {
        {
            Kernel()->Redraw();
        }
    }
}

SampleViewPortFilter::SampleViewPortFilter() :
    m_aGaussianBlur(this, "Gaussian"),
    m_aBlurWidth(this, "Blur Width")
{
    // Cg context
    m_CGContext = cgCreateContext();
    cgGLSetDebugMode( CG_FALSE );

    cgGLSetManageTextureParameters(m_CGContext, CG_TRUE);
    cgSetParameterSettingMode(m_CGContext, CG_DEFERRED_PARAMETER_SETTING);

    /* Compile and load the vertex program. */
    m_FragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
    cgGLSetOptimalOptions(m_FragmentProfile);
    
    // Get the path to where the plug-in was loaded from
    QDir pluginDir( Kernel()->PluginDirectory("Sample Filter") );
    QFileInfo cgPath( pluginDir, QString("Blur.cg") );

    /* Compile and load the fragment program. */
    QByteArray qbaPath = QFile::encodeName(cgPath.filePath());
    m_BlurProgram =
        cgCreateProgramFromFile(
        m_CGContext,                /* Cg runtime context */
        CG_SOURCE,                  /* Program in human-readable form */
        qbaPath.constData(), /* Name of file containing program */
        m_FragmentProfile,/* Profile: OpenGL ARB vertex program */
        "main",      /* Entry function name */
        NULL);                      /* No extra compiler options */
        
    if ( m_BlurProgram == NULL ) Kernel()->Interface()->HUDMessageShow("Failed to load Blur.cg", mudbox::Interface::HUDmsgFade );


    cgGLLoadProgram(m_BlurProgram);

    m_BlurColorTextureParam = cgGetNamedParameter(m_BlurProgram, "colorTexture");
    m_BlurWidthParam = cgGetNamedParameter(m_BlurProgram, "BlurWidth");
    m_GaussianBlurParam = cgGetNamedParameter(m_BlurProgram, "GaussianBlur");

    m_aGaussianBlur = true;

    m_aBlurWidth.SetMax(.0050f);
    m_aBlurWidth.SetMin(.0001f);
    m_aBlurWidth = 0.0012f;

    // Create the output texture
    m_pResultTexture = CreateInstance<Texture>();
}

SampleViewPortFilter::~SampleViewPortFilter()
{
    if( m_pResultTexture )
        delete m_pResultTexture;

    if (m_CGContext)
        cgDestroyContext(m_CGContext);
};

void SampleViewPortFilter::Process( ViewPortState &s ) 
{
    enum Image::Format eFormat = s.m_bHDRNeeded ? Image::e16float : Image::e8integer;

    // Set of variables not actually used for anything other than to show
    // how to access the values.
    const float cameraNear = Kernel()->Scene()->ActiveCamera()->Near();
    const float cameraFar = Kernel()->Scene()->ActiveCamera()->Far();
    const float cameraFOV = Kernel()->Scene()->ActiveCamera()->FOV();
    const float cameraAspectRatio = Kernel()->Scene()->ActiveCamera()->AspectRatio();
    const float cameraHeight = tanf(cameraFOV / 2.0f) * cameraNear;
    const float cameraWidth = cameraHeight * cameraAspectRatio;
    const float cameraTop = -cameraHeight;
    const float cameraBottom = cameraHeight;
    const float cameraLeft = -cameraWidth;
    const float cameraRight = cameraWidth;
    
    // Ensure our output texture is same size & type as the incoming color buffer.
    // Get width and height of the viewport
    const int width = s.m_pColor->Width();
    const int height = s.m_pColor->Height();

    // Smallest of width and height
    const int extendMin = width < height ? width : height;

    // Logarithm of the SMALLER extend, in order to be at least 1 pixel in size in any dimension
    const int levelCountMax = (int)floorf(logf(float(extendMin)) / float(M_LN2));

    // See if the input size or format changed. If so, re-create the texture.
    if( m_pResultTexture->Width() != s.m_pColor->Width() || 
        m_pResultTexture->Height() != s.m_pColor->Height())
    {
        m_pResultTexture->Create(s.m_pColor->Width(), s.m_pColor->Height(), 4, eFormat);
    };
    m_pResultTexture->SetLocation( TexturePool::locationGPU );

    // Enable Cg fragment profile
    cgGLEnableProfile(m_FragmentProfile);

    // Set up some gl states
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_BLEND);
    glDisable(GL_CULL_FACE);

    cgGLBindProgram(m_BlurProgram);

    // Set the incoming color buffer on the shader
    cgGLSetTextureParameter(m_BlurColorTextureParam, s.m_pColor->OpenGLName());

    // Set blur width value
    cgSetParameter1f(m_BlurWidthParam, m_aBlurWidth);

    // Set Gaussian usage value
    cgSetParameter1i(m_GaussianBlurParam, m_aGaussianBlur);

    cgUpdateProgramParameters(m_BlurProgram);

    // Render to the resulting texture.  This activates the shader pass.
    gpuTransform(m_pResultTexture);
    
    cgGLDisableProfile(m_FragmentProfile);

    // Assign the resulting texture to the color buffer
    s.m_pColor = m_pResultTexture;
};

void SampleViewPortFilter::SetVisible( bool bVisible )
{
    ViewPortFilter::SetVisible( bVisible );

    if( bVisible )
    {
        if( !m_pResultTexture )
            m_pResultTexture = CreateInstance<Texture>();
    }
    else
    {
        delete m_pResultTexture;
        m_pResultTexture = 0;
    };
};