ViewScene/GlFunctions.cxx

/****************************************************************************************

Copyright (C) 2010 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.

****************************************************************************************/

//
// This file contains the functions to encapsulate the GLUT and OpenGL
// functions calls needed to set the camera and draw the various elements 
// of a scene.
//

#include <math.h>

#include <fbxsdk.h>

#define GLUT_DISABLE_ATEXIT_HACK
#if defined(__MACH__)
#include <GLUT/glut.h>
#else
#include "GL/glut.h"
#endif

#include <fbxfilesdk/fbxfilesdk_nsuse.h>

#include "GlFunctions.h"
#include "Texture.h"

// On Irix GL_BGR_EXT does not exit it has to be GL_BGR
#ifndef GL_BGR_EXT
#define GL_BGR_EXT GL_BGR
#endif

extern ShadingManager * gShadingManager;

void GlGetWindowSize(int& pWidth, int& pHeight)
{
    pWidth = glutGet(GLUT_WINDOW_WIDTH);
    pHeight = glutGet(GLUT_WINDOW_HEIGHT);      
}


void GlSetCameraPerspective(double pFieldOfViewY,
                            double pAspect,
                            double pNearPlane,
                            double pFarPlane,
                            KFbxVector4& pEye,
                            KFbxVector4& pCenter,
                            KFbxVector4& pUp)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();  
    gluPerspective(pFieldOfViewY, 
        pAspect, 
        pNearPlane, 
        pFarPlane);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(pEye[0], pEye[1], pEye[2],
        pCenter[0], pCenter[1], pCenter[2],
        pUp[0], pUp[1], pUp[2]);
}


void GlSetCameraOrthogonal(double pLeftPlane,
                           double pRightPlane,
                           double pBottomPlane,
                           double pTopPlane,
                           double pNearPlane,
                           double pFarPlane,
                           KFbxVector4& pEye,
                           KFbxVector4& pCenter,
                           KFbxVector4& pUp)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();  
    glOrtho(pLeftPlane, 
        pRightPlane, 
        pBottomPlane, 
        pTopPlane, 
        pNearPlane, 
        pFarPlane); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(pEye[0], pEye[1], pEye[2],
        pCenter[0], pCenter[1], pCenter[2],
        pUp[0], pUp[1], pUp[2]);
}


void GlDrawMarker(KFbxXMatrix& pGlobalPosition)
{
    glColor3f(0.0, 1.0, 1.0);
    glLineWidth(1.0);

    glPushMatrix();
    glMultMatrixd((double*) pGlobalPosition);

    glutWireCube(2.0);

    glPopMatrix();
}


void GlDrawLimbNode(KFbxXMatrix& pGlobalBasePosition, KFbxXMatrix& pGlobalEndPosition)
{
    glColor3f(1.0, 0.0, 0.0);
    glLineWidth(2.0);

    glBegin(GL_LINES);

    glVertex3dv((GLdouble *)pGlobalBasePosition.GetT());
    glVertex3dv((GLdouble *)pGlobalEndPosition.GetT());

    glEnd();
}


void GlDrawMesh(const KFbxXMatrix& pGlobalPosition, const KFbxMesh* pMesh, const KFbxVector4* pVertexArray)
{
    ShadingManager::ShadingMode lDrawMode = gShadingManager->GetShadingMode();
    if (pMesh->GetNode()->GetMaterialCount() == 0)
        lDrawMode = ShadingManager::SHADING_MODE_WIREFRAME;

    const int lGLPrimitive = lDrawMode == ShadingManager::SHADING_MODE_WIREFRAME ? GL_LINE_LOOP : GL_POLYGON;

    glColor3f(0.5, 0.5, 0.5);
    glLineWidth(1.0);

    glPushMatrix();
    glMultMatrixd((const double*)pGlobalPosition);

    const bool lHasNormal = pMesh->GetElementNormalCount() > 0;
    const bool lHasUV = pMesh->GetElementUVCount() > 0;
    KStringList lUVNames;
    pMesh->GetUVSetNames(lUVNames);
    KFbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;
    KFbxGeometryElement::EMappingMode lMaterialMappingMode = KFbxGeometryElement::eNONE;

    if (lDrawMode == ShadingManager::SHADING_MODE_SHADED)
    {
        if (pMesh->GetElementMaterial())
        {
            pMesh->GetMaterialIndices(&lMaterialIndice);
            lMaterialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
        }

        if (lHasNormal)
        {
            glEnable(GL_NORMALIZE);
        }

        if (lHasUV)
        {
            glEnable(GL_TEXTURE_2D);
        }

        glEnable(GL_LIGHTING);
    }

    if (lDrawMode == ShadingManager::SHADING_MODE_SHADED)
    {
        if (lMaterialMappingMode == KFbxGeometryElement::eNONE)
        {
            gShadingManager->SetMaterial(pMesh->GetNode(), 0);
        }
        else if (lMaterialMappingMode == KFbxGeometryElement::eALL_SAME && lMaterialIndice)
        {
            gShadingManager->SetMaterial(pMesh->GetNode(), lMaterialIndice->GetAt(0));
        }
    }

    KFbxVector2 lCurrentUV;
    KFbxVector4 lCurrentNormal;
    const int lPolygonCount = pMesh->GetPolygonCount();
    for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
    {
        if (lDrawMode == ShadingManager::SHADING_MODE_SHADED && lMaterialMappingMode == KFbxGeometryElement::eBY_POLYGON)
        {
            const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex);
            gShadingManager->SetMaterial(pMesh->GetNode(), lMaterialIndex);
        }

        glBegin(lGLPrimitive);

        const int lVerticeCount = pMesh->GetPolygonSize(lPolygonIndex);
        for (int lVerticeIndex = 0; lVerticeIndex < lVerticeCount; ++lVerticeIndex)
        {
            if (lDrawMode == ShadingManager::SHADING_MODE_SHADED)
            {
                if (lHasUV && pMesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVNames[0].Buffer(), lCurrentUV))
                {
                    glTexCoord2dv(lCurrentUV.mData);
                }

                if (lHasNormal && pMesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal))
                {
                    glNormal3d(lCurrentNormal[0], lCurrentNormal[1], lCurrentNormal[2]);
                }
            }

            glVertex3dv((const GLdouble *)pVertexArray[pMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex)]);
        }

        glEnd();
    }

    if (lDrawMode == ShadingManager::SHADING_MODE_SHADED)
    {
        glDisable(GL_LIGHTING);

        if (lHasUV)
        {
            glDisable(GL_TEXTURE_2D);
        }

        if (lHasNormal)
        {
            glDisable(GL_NORMALIZE);
        }
    }

    if (gShadingManager->IsDrawNormal())
    {
        GLfloat lCurrentColor[4];
        glGetFloatv(GL_CURRENT_COLOR, lCurrentColor);

        glColor3f(0.5f, 0.5f, 0.0f);
        KFbxVector4 lCurrentNormal;
        const int lPolygonCount = pMesh->GetPolygonCount();
        for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
        {
            glBegin(GL_LINES);
            const int lVerticeCount = pMesh->GetPolygonSize(lPolygonIndex);
            for (int lVerticeIndex = 0; lVerticeIndex < lVerticeCount; ++lVerticeIndex)
            {
                const KFbxVector4 p1 = pVertexArray[pMesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex)];
                pMesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal);
                lCurrentNormal.Normalize();
                const double lNormalScale = gShadingManager->GetNormalScale();
                const KFbxVector4 p2 = p1 + lCurrentNormal * lNormalScale;
                glVertex3dv(p1);
                glVertex3dv(p2);
            }
            glEnd();
        }

        glColor4fv(lCurrentColor);
    }

    glPopMatrix();
}


void GlDrawCamera(KFbxXMatrix& pGlobalPosition, double pRoll)
{
    glColor3d(1.0, 1.0, 1.0);
    glLineWidth(1.0);

    glPushMatrix();
    glMultMatrixd((double*) pGlobalPosition);
    glRotated(pRoll, 1.0, 0.0, 0.0);

    int i;
    float lCamera[10][2] = {{ 0, 5.5 }, { -3, 4.5 },
    { -3, 7.5 }, { -6, 10.5 }, { -23, 10.5 },
    { -23, -4.5 }, { -20, -7.5 }, { -3, -7.5 },
    { -3, -4.5 }, { 0, -5.5 }   };

    glBegin( GL_LINE_LOOP );
    {
        for (i = 0; i < 10; i++)
        {
            glVertex3f(lCamera[i][0], lCamera[i][1], 4.5);
        }
    }
    glEnd();

    glBegin( GL_LINE_LOOP );
    {
        for (i = 0; i < 10; i++)
        {
            glVertex3f(lCamera[i][0], lCamera[i][1], -4.5);
        }
    }
    glEnd();

    for (i = 0; i < 10; i++)
    {
        glBegin( GL_LINES );
        {
            glVertex3f(lCamera[i][0], lCamera[i][1], -4.5);
            glVertex3f(lCamera[i][0], lCamera[i][1], 4.5);
        }
        glEnd();
    }

    glPopMatrix();
}


void GlDrawLight(const KFbxXMatrix& pGlobalPosition, const KFbxLight* pLight,
                 const KFbxColor& pColor, double pConeAngle)
{
    glColor3d(pColor.mRed, pColor.mGreen, pColor.mBlue);
    glLineWidth(1.0);

    glPushMatrix();
    glMultMatrixd((const double*)pGlobalPosition);

    if (pLight->LightType.Get() == KFbxLight::eSPOT)
    {
        const double lRadians = 3.1416 * pConeAngle / 180.0;
        const double lHeight = 15.0;
        const double lBase = lHeight * tan(lRadians / 2);
        glutWireCone(lBase, lHeight, 18, 1);
    }
    else
    {
        glutWireSphere(1.0, 10, 10);
    }

    gShadingManager->SetLight(pLight->LightType.Get(), pColor, pConeAngle);

    glPopMatrix();
}


void GlDrawCrossHair(KFbxXMatrix& pGlobalPosition)
{
    glColor3f(1.0, 1.0, 1.0);
    glLineWidth(1.0);

    glPushMatrix();
    glMultMatrixd((double*) pGlobalPosition);

    double lCrossHair[6][3] = { { -3, 0, 0 }, { 3, 0, 0 },
    { 0, -3, 0 }, { 0, 3, 0 },
    { 0, 0, -3 }, { 0, 0, 3 } };

    glBegin(GL_LINES);

    glVertex3dv(lCrossHair[0]);
    glVertex3dv(lCrossHair[1]);

    glEnd();

    glBegin(GL_LINES);

    glVertex3dv(lCrossHair[2]);
    glVertex3dv(lCrossHair[3]);

    glEnd();

    glBegin(GL_LINES);

    glVertex3dv(lCrossHair[4]);
    glVertex3dv(lCrossHair[5]);

    glEnd();

    glPopMatrix();
}

void GlDrawGrid(KFbxXMatrix& pGlobalPosition)
{
    glPushMatrix();
    glMultMatrixd((double*) pGlobalPosition);

    // Draw a grid 500*500
    glColor3f(0.3, 0.3, 0.3);
    glLineWidth(1.0);
    const int hw = 500;
    const int step = 20;
    const int bigstep = 100;
    int       i;

    // Draw Grid
    for (i = -hw; i <= hw; i+=step) {

        if (i % bigstep == 0) {
            glLineWidth(2.0);
        } else {
            glLineWidth(1.0);
        }
        glBegin(GL_LINES);
        glVertex3f(i,0,-hw);
        glVertex3f(i,0,hw);
        glEnd();
        glBegin(GL_LINES);
        glVertex3f(-hw,0,i);
        glVertex3f(hw,0,i);
        glEnd();

    }

    // Write some grid info
    const int zoffset = -2;
    const int xoffset = 1;
    for (i = -hw; i <= hw; i+=bigstep) {

        KString scoord;
        int is, lCount;

        // Don't display origin
        //if (i == 0) continue;
        if (i == 0) {
            scoord = "0";
            lCount = (int)scoord.GetLen();
            glPushMatrix();
            glTranslatef(i+xoffset,0,zoffset);
            glRotatef(-90,1,0,0);
            glScalef(.03,.03,.03);
            for (is = 0; is < lCount; is++) {
                char lC = scoord.Buffer()[is];
                glutStrokeCharacter(GLUT_STROKE_ROMAN, lC);
            }
            glPopMatrix();

            continue;
        }

        // X coordinates
        scoord = "X: ";
        scoord += i;
        lCount = (int)scoord.GetLen();

        glPushMatrix();
        glTranslatef(i+xoffset,0,zoffset);
        glRotatef(-90,1,0,0);
        glScalef(.03,.03,.03);
        for (is = 0; is < lCount; is++) {
            char lC = scoord.Buffer()[is];
            glutStrokeCharacter(GLUT_STROKE_ROMAN, lC);
        }
        glPopMatrix();

        // Z coordinates
        scoord = "Z: ";
        scoord += i;
        lCount = (int)scoord.GetLen();

        glPushMatrix();
        glTranslatef(xoffset,0,i+zoffset);
        glRotatef(-90,1,0,0);
        glScalef(.03,.03,.03);
        for (is = 0; is < lCount; is++) {
            char lC = scoord.Buffer()[is];
            glutStrokeCharacter(GLUT_STROKE_ROMAN, lC);
        }
        glPopMatrix();

    }

    glPopMatrix();
}