//  *** LIGHTING--lit, shaded cube or sphere ***
// Lighting03View.cpp : implementation of the CLighting03View class
//

#include "stdafx.h"
#include "Lighting03.h"

#include "Lighting03Doc.h"
#include "Lighting03View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include <math.h>
#include <gl\glaux.h>

/////////////////////////////////////////////////////////////////////////////
// CLighting03View

IMPLEMENT_DYNCREATE(CLighting03View, CView)

BEGIN_MESSAGE_MAP(CLighting03View, CView)
        //{{AFX_MSG_MAP(CLighting03View)
        ON_WM_CREATE()
        ON_WM_DESTROY()
        ON_WM_SIZE()
        ON_COMMAND(ID_OBJECT_CUBE, OnObjectCube)
        ON_COMMAND(ID_OBJECT_SPHERE, OnObjectSphere)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLighting03View construction/destruction

CLighting03View::CLighting03View()
{
        // TODO: add construction code here

        // Lighting and material properties
    m_currentObject = Sphere;
    m_materialAmbient[0] = 1.0f;
    m_materialAmbient[1] = 0.0f;
    m_materialAmbient[2] = 0.0f;
    m_materialAmbient[3] = 1.0f;
    m_materialSpecular[0] = 1.0f;
    m_materialSpecular[1] = 1.0f;
    m_materialSpecular[2] = 1.0f;
    m_materialSpecular[3] = 1.0f;
    m_materialEmitted[0] = 0.0f;
    m_materialEmitted[1] = 0.0f;
    m_materialEmitted[2] = 0.0f;
    m_materialEmitted[3] = 1.0f;
    m_ambientLight0[0] = 0.2f;
    m_ambientLight0[1] = 0.2f;
    m_ambientLight0[2] = 0.2f;
    m_ambientLight0[3] = 1.0f;
    m_diffuseLight0[0] = 1.0f;
    m_diffuseLight0[1] = 1.0f;
    m_diffuseLight0[2] = 1.0f;
    m_diffuseLight0[3] = 1.0f;
    m_specularLight0[0] = 1.0f;
    m_specularLight0[1] = 1.0f;
    m_specularLight0[2] = 1.0f;
    m_specularLight0[3] = 1.0f;
    m_positionLight0[0] = 1.0f;
    m_positionLight0[1] = 1.0f;
    m_positionLight0[2] = 1.0f;
    m_positionLight0[3] = 1.0f;
    m_shininess = 20.0f;


}

CLighting03View::~CLighting03View()
{
}

BOOL CLighting03View::PreCreateWindow(CREATESTRUCT& cs)
{
        // TODO: Modify the Window class or styles here by modifying
        //  the CREATESTRUCT cs

        return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CLighting03View drawing

void CLighting03View::OnDraw(CDC* pDC)
{
        CLighting03Doc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        // TODO: add draw code for native data here

    wglMakeCurrent(pDC->m_hDC, m_hRC);
    DrawWithOpenGL();
    wglMakeCurrent(pDC->m_hDC, NULL);
}

/////////////////////////////////////////////////////////////////////////////
// CLighting03View diagnostics

#ifdef _DEBUG
void CLighting03View::AssertValid() const
{
        CView::AssertValid();
}

void CLighting03View::Dump(CDumpContext& dc) const
{
        CView::Dump(dc);
}

CLighting03Doc* CLighting03View::GetDocument() // non-debug version is inline
{
        ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLighting03Doc)));
        return (CLighting03Doc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CLighting03View message handlers

int CLighting03View::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
        if (CView::OnCreate(lpCreateStruct) == -1)
                return -1;
        
        // TODO: Add your specialized creation code here
        
    PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR), // Structure size.
        1,                             // Structure version number.
        PFD_DRAW_TO_WINDOW |           // Property flags.
            PFD_SUPPORT_OPENGL,
        PFD_TYPE_RGBA,
        24,                            // 24-bit color.
        0, 0, 0, 0, 0, 0,              // Not concerned with these.
        0, 0, 0, 0, 0, 0, 0,           // No alpha or accum buffer.
        32,                            // 32-bit depth buffer.
        0, 0,                          // No stencil or aux buffer.
        PFD_MAIN_PLANE,                // Main layer type.
        0,                             // Reserved.
        0, 0, 0                        // Unsupported.
    };

    CClientDC clientDC(this);

    int pixelFormat =
        ChoosePixelFormat(clientDC.m_hDC, &pfd);
    BOOL success =
        SetPixelFormat(clientDC.m_hDC, pixelFormat, &pfd);
    DescribePixelFormat(clientDC.m_hDC, pixelFormat,
        sizeof(pfd), &pfd);

    m_hRC = wglCreateContext(clientDC.m_hDC);
        return 0;
}

void CLighting03View::OnDestroy() 
{
        CView::OnDestroy();
        
        // TODO: Add your message handler code here
    wglDeleteContext(m_hRC);
        
}

void CLighting03View::OnSize(UINT nType, int cx, int cy) 
{
        CView::OnSize(nType, cx, cy);
        
        // TODO: Add your message handler code here
    CClientDC clientDC(this);
    wglMakeCurrent(clientDC.m_hDC, m_hRC);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 7.0);
    glViewport(0, 0, cx, cy);
    wglMakeCurrent(NULL, NULL);
        
}

void CLighting03View::OnObjectCube() 
{
        // TODO: Add your command handler code here
    m_currentObject = Cube;
    Invalidate();

}

void CLighting03View::OnObjectSphere() 
{
        // TODO: Add your command handler code here
    m_currentObject = Sphere;
    Invalidate();
        
}

void CLighting03View::DrawWithOpenGL()
{
    glShadeModel(GL_SMOOTH);  //could be GL_FLAT
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
        m_materialAmbient);
    glMaterialfv(GL_FRONT, GL_SPECULAR, m_materialSpecular);
    glMaterialfv(GL_FRONT, GL_EMISSION, m_materialEmitted);
    glMaterialf(GL_FRONT, GL_SHININESS, m_shininess);

    glLightfv(GL_LIGHT0, GL_AMBIENT, m_ambientLight0);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, m_diffuseLight0);
    glLightfv(GL_LIGHT0, GL_SPECULAR, m_specularLight0);
    glLightfv(GL_LIGHT0, GL_POSITION, m_positionLight0);
               
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    if (m_currentObject == Cube)
        DrawCube();
    else
        DrawSphere();

    glFlush();
}

void CLighting03View::DrawCube()
{
    glTranslatef(0.0f, 0.0f, -3.5f);
    glRotatef(30.0f, -1.0f, 1.0f, 0.0f);
    glRotatef(45.0f, 0.0f, 0.0f, 1.0f);

    double p1[] = {-0.5, 0.5, 0.5};
    double p2[] = {-0.5, -0.5, 0.5};
    double p3[] = {0.5, -0.5, 0.5};
    double n[3];
    CalcNormal(p1, p2, p3, n);

    glBegin(GL_POLYGON);
        glNormal3f((GLfloat)n[0], (GLfloat)n[1], (GLfloat)n[2]);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, 0.5f);
    glEnd();

    p1[0] = 0.5;  p1[1] = 0.5;   p1[2] = 0.5;
    p2[0] = 0.5,  p2[1] = -0.5;  p2[2] = 0.5;
    p3[0] = 0.5;  p3[1] = -0.5;  p3[2] = -0.5;
    CalcNormal(p1, p2, p3, n);

    glBegin(GL_POLYGON);
        glNormal3f((GLfloat)n[0], (GLfloat)n[1], (GLfloat)n[2]);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
    glEnd();

    p1[0] = 0.5;  p1[1] = 0.5;   p1[2] = -0.5;
    p2[0] = 0.5,  p2[1] = -0.5;  p2[2] = -0.5;
    p3[0] = -0.5;  p3[1] = -0.5;  p3[2] = -0.5;
    CalcNormal(p1, p2, p3, n);

    glBegin(GL_POLYGON);
        glNormal3f((GLfloat)n[0], (GLfloat)n[1], (GLfloat)n[2]);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
    glEnd();

    p1[0] = -0.5;  p1[1] = 0.5;   p1[2] = -0.5;
    p2[0] = -0.5,  p2[1] = -0.5;  p2[2] = -0.5;
    p3[0] = -0.5;  p3[1] = -0.5;  p3[2] = 0.5;
    CalcNormal(p1, p2, p3, n);

    glBegin(GL_POLYGON);
        glNormal3f((GLfloat)n[0], (GLfloat)n[1], (GLfloat)n[2]);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
    glEnd();

    p1[0] = -0.5;  p1[1] = -0.5;   p1[2] = 0.5;
    p2[0] = -0.5,  p2[1] = -0.5;  p2[2] = -0.5;
    p3[0] = 0.5;  p3[1] = -0.5;  p3[2] = -0.5;
    CalcNormal(p1, p2, p3, n);

    glBegin(GL_POLYGON);
        glNormal3f((GLfloat)n[0], (GLfloat)n[1], (GLfloat)n[2]);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
    glEnd();

    p1[0] = -0.5;  p1[1] = 0.5;   p1[2] = -0.5;
    p2[0] = -0.5,  p2[1] = 0.5;  p2[2] = 0.5;
    p3[0] = 0.5;  p3[1] = 0.5;  p3[2] = 0.5;
    CalcNormal(p1, p2, p3, n);

    glBegin(GL_POLYGON);
        glNormal3f((GLfloat)n[0], (GLfloat)n[1], (GLfloat)n[2]);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
    glEnd();
}

void CLighting03View::DrawSphere()
{
    glTranslatef(0.0f, 0.0f, -3.5f);
        glScalef(1.0,1.5,1.0);

        GLUquadricObj *mySphere;
        mySphere=gluNewQuadric();
        gluQuadricDrawStyle(mySphere,GLU_FILL);
        gluSphere(mySphere,1.0,12,12);

}

void CLighting03View::CalcNormal(double *p1, double *p2, double *p3, double *n)
{
    // Form two vectors from the points.
    double a[3], b[3];
    a[0] = p2[0] - p1[0];
    a[1] = p2[1] - p1[1];
    a[2] = p2[2] - p1[2];
    b[0] = p3[0] - p1[0];
    b[1] = p3[1] - p1[1];
    b[2] = p3[2] - p1[2];

    // Calculate the cross product of the two vectors.
    n[0] = a[1] * b[2] - a[2] * b[1];
    n[1] = a[2] * b[0] - a[0] * b[2];
    n[2] = a[0] * b[1] - a[1] * b[0];

    // Normalize the new vector.
    double length = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
    if (length != 0)
    {
        n[0] = n[0] / length;
        n[1] = n[1] / length;
        n[2] = n[2] / length;
    }
}