// Wild Magic Source Code
// David Eberly
// http://www.geometrictools.com
// Copyright (c) 1998-2007
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.  The license is available for reading at
// either of the locations:
//     http://www.gnu.org/copyleft/lgpl.html
//     http://www.geometrictools.com/License/WildMagicLicense.pdf
//
// Version: 4.0.2 (2007/06/16)

#include "Wm4OpenGLRendererPCH.h"
#include "Wm4OpenGLRenderer.h"
#include "Wm4OpenGLResources.h"
using namespace Wm4;

//----------------------------------------------------------------------------
void OpenGLRenderer::SetVProgramConstant (int eCType, int iBaseRegister,
    int iRegisterQuantity, float* afData)
{
    if (eCType != Renderer::CT_NUMERICAL)
    {
        for (int j = 0; j < iRegisterQuantity; j++)
        {
            glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB,
                (GLuint)iBaseRegister,afData);
            iBaseRegister++;
            afData += 4;
        }
    }
}
//----------------------------------------------------------------------------
void OpenGLRenderer::SetPProgramConstant (int eCType, int iBaseRegister,
    int iRegisterQuantity, float* afData)
{
    if (eCType != Renderer::CT_NUMERICAL)
    {
        for (int j = 0; j < iRegisterQuantity; j++)
        {
            glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB,
                (GLuint)iBaseRegister,afData);
            iBaseRegister++;
            afData += 4;
        }
    }
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnEnableVProgram (ResourceIdentifier* pkID)
{
    VProgramID* pkResource = (VProgramID*)pkID;
    glEnable(GL_VERTEX_PROGRAM_ARB);
    glBindProgramARB(GL_VERTEX_PROGRAM_ARB,pkResource->ID);
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnDisableVProgram (ResourceIdentifier*)
{
    glDisable(GL_VERTEX_PROGRAM_ARB);
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnEnablePProgram (ResourceIdentifier* pkID)
{
    PProgramID* pkResource = (PProgramID*)pkID;
    glEnable(GL_FRAGMENT_PROGRAM_ARB);
    glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,pkResource->ID);
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnDisablePProgram (ResourceIdentifier*)
{
    glDisable(GL_FRAGMENT_PROGRAM_ARB);
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnEnableTexture (ResourceIdentifier* pkID)
{
    TextureID* pkResource = (TextureID*)pkID;
    Texture* pkTexture = pkResource->TextureObject;

    SamplerInformation* pkSI = pkTexture->GetSamplerInformation();
    SamplerInformation::Type eSType = pkSI->GetType();
    int iTextureUnit = pkSI->GetTextureUnit();
    int eTarget = ms_aeSamplerTypes[eSType];

    glActiveTexture(GL_TEXTURE0 + iTextureUnit);
    glBindTexture(eTarget,pkResource->ID);
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnDisableTexture (ResourceIdentifier*)
{
    // Nothing to do.
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnEnableVBuffer (ResourceIdentifier* pkID)
{
    // Bind the current vertex buffer.
    VBufferID* pkResource = (VBufferID*)pkID;
    glBindBuffer(GL_ARRAY_BUFFER,pkResource->ID);

    const Attributes& rkRAttr = pkResource->IAttr;
    GLsizei iSize = (GLsizei)(sizeof(float)*rkRAttr.GetChannelQuantity());
    const float* afData = 0;

    if (rkRAttr.HasPosition())
    {
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(rkRAttr.GetPositionChannels(),GL_FLOAT,iSize,
            afData + rkRAttr.GetPositionOffset());
    }

    if (rkRAttr.HasBlendWeight())
    {
        glEnableClientState(GL_WEIGHT_ARRAY_ARB);
        glWeightPointerARB(rkRAttr.GetBlendWeightChannels(),GL_FLOAT,iSize,
            afData + rkRAttr.GetBlendWeightOffset());
    }

    if (rkRAttr.HasNormal())
    {
        // Using vertex attributes to allow the number of channels to be
        // different from 3.
        // glEnableClientState(GL_NORMAL_ARRAY);
        // glNormalPointer(GL_FLOAT,iSize,afData + rkRAttr.GetNormalOffset());
        glEnableVertexAttribArrayARB(2);
        glVertexAttribPointerARB(2,rkRAttr.GetNormalChannels(),GL_FLOAT,
            GL_FALSE,iSize,afData + rkRAttr.GetNormalOffset());
    }

    if (rkRAttr.HasColor(0))
    {
        glEnableClientState(GL_COLOR_ARRAY);
        glColorPointer(rkRAttr.GetColorChannels(0),GL_FLOAT,iSize,
            afData + rkRAttr.GetColorOffset(0));
    }

    if (rkRAttr.HasColor(1))
    {
        glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
        glSecondaryColorPointer(rkRAttr.GetColorChannels(1),GL_FLOAT,iSize,
            afData + rkRAttr.GetColorOffset(1));
    }

    if (rkRAttr.HasFog())
    {
        glEnableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
        glFogCoordPointerEXT(GL_FLOAT,iSize,afData + rkRAttr.GetFogOffset());
    }

    if (rkRAttr.HasPSize())
    {
        glEnableVertexAttribArrayARB(6);
        glVertexAttribPointerARB(6,rkRAttr.GetPSizeChannels(),GL_FLOAT,
            GL_FALSE,iSize,afData + rkRAttr.GetPSizeOffset());
    }

    if (rkRAttr.HasBlendIndices())
    {
        glEnableClientState(GL_MATRIX_INDEX_ARRAY_ARB);
        glMatrixIndexPointerARB(rkRAttr.GetBlendIndicesChannels(),GL_FLOAT,
            iSize,afData + rkRAttr.GetBlendIndicesOffset());
    }

    for (int iUnit = 0; iUnit < rkRAttr.GetMaxTCoords(); iUnit++)
    {
        if (rkRAttr.HasTCoord(iUnit))
        {
            glClientActiveTexture(GL_TEXTURE0 + iUnit);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
            glTexCoordPointer(rkRAttr.GetTCoordChannels(iUnit),GL_FLOAT,iSize,
                afData + rkRAttr.GetTCoordOffset(iUnit));
        }
    }

    if (rkRAttr.HasTangent())
    {
        glEnableVertexAttribArrayARB(14);
        glVertexAttribPointerARB(14,rkRAttr.GetTangentChannels(),GL_FLOAT,
            GL_FALSE,iSize,afData + rkRAttr.GetTangentOffset());
    }

    if (rkRAttr.HasBitangent())
    {
        glEnableVertexAttribArrayARB(15);
        glVertexAttribPointerARB(15,rkRAttr.GetBitangentChannels(),GL_FLOAT,
            GL_FALSE,iSize,afData + rkRAttr.GetBitangentOffset());
    }
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnDisableVBuffer (ResourceIdentifier* pkID)
{
    VBufferID* pkResource = (VBufferID*)pkID;
    const Attributes& rkRAttr = pkResource->IAttr;

    // Unbind the current vertex buffer.
    glBindBuffer(GL_ARRAY_BUFFER,0);

    if (rkRAttr.HasPosition())
    {
        glDisableClientState(GL_VERTEX_ARRAY);
    }

    if (rkRAttr.HasBlendWeight())
    {
        glDisableClientState(GL_WEIGHT_ARRAY_ARB);
    }

    if (rkRAttr.HasNormal())
    {
        glDisableVertexAttribArrayARB(2);
    }

    if (rkRAttr.HasColor(0))
    {
        glDisableClientState(GL_COLOR_ARRAY);
    }

    if (rkRAttr.HasColor(1))
    {
        glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
    }

    if (rkRAttr.HasFog())
    {
        glDisableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
    }

    if (rkRAttr.HasPSize())
    {
        glDisableVertexAttribArrayARB(6);
    }

    if (rkRAttr.HasBlendIndices())
    {
        glDisableClientState(GL_MATRIX_INDEX_ARRAY_ARB);
    }

    for (int iUnit = 0; iUnit < rkRAttr.GetMaxTCoords(); iUnit++)
    {
        if (rkRAttr.HasTCoord(iUnit))
        {
            glClientActiveTexture(GL_TEXTURE0 + iUnit);
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        }
    }

    if (rkRAttr.HasTangent())
    {
        glDisableVertexAttribArrayARB(14);
    }

    if (rkRAttr.HasBitangent())
    {
        glDisableVertexAttribArrayARB(15);
    }
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnEnableIBuffer (ResourceIdentifier* pkID)
{
    // Bind the current index buffer.
    IBufferID* pkResource = (IBufferID*)pkID;
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,pkResource->ID);
}
//----------------------------------------------------------------------------
void OpenGLRenderer::OnDisableIBuffer (ResourceIdentifier*)
{
    // Unbind the current index buffer.
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
}
//----------------------------------------------------------------------------
