////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mark@danks.org
//
// Implementation file
//
//    Copyright (c) 1997-1999 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "gemwin.h"

// I hate Microsoft...I shouldn't have to do this!
#ifdef _WINDOWS
#include <windows.h>
#endif

#include <GL/gl.h>

#include "Base/GemMan.h"

CPPEXTERN_NEW_WITH_ONE_ARG(gemwin, t_floatarg, A_DEFFLOAT)

/////////////////////////////////////////////////////////
//
// gemwin
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemwin :: gemwin(t_floatarg framespersecond)
{
    if (framespersecond <= 0.) framespersecond = 20.;
    GemMan::frameRate((float)framespersecond);
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemwin :: ~gemwin()
{
    GemMan::destroyWindow();
}

/////////////////////////////////////////////////////////
// bangMess
//
/////////////////////////////////////////////////////////
void gemwin :: bangMess()
{
    if ( GemMan::windowExists() )
    {
        GemMan::swapBuffers();
    }
    else 
		error("GEM: no window");
}

/////////////////////////////////////////////////////////
// intMess
//
/////////////////////////////////////////////////////////
void gemwin :: intMess(int state)
{
    if (state) GemMan::startRendering();
    else GemMan::stopRendering();
}

/////////////////////////////////////////////////////////
// createMess
//
/////////////////////////////////////////////////////////
void gemwin :: createMess()
{
    if ( !GemMan::windowExists() )
    {
		GemMan::m_stereo = 0;
        if ( !GemMan::createWindow() )
        {
            error("GEM: gemwin: no window made");
            return;
        }
        GemMan::swapBuffers();	
        GemMan::swapBuffers();	
        post("GEM: window created");
    }
    else
		error("GEM: gemwin: window already made");
}

/////////////////////////////////////////////////////////
// createStereoMess
//
/////////////////////////////////////////////////////////
void gemwin :: createStereoMess()
{
    if ( !GemMan::windowExists() )
    {
		GemMan::m_stereo = 1;
        if ( !GemMan::createWindow() )
        {
            error("GEM: gemwin: no window made");
            return;
        }
        GemMan::swapBuffers();	
        GemMan::swapBuffers();	
        post("GEM: stereo window created");
    }
    else
		error("GEM: gemwin: window already made");
}

/////////////////////////////////////////////////////////
// bufferMess
//
/////////////////////////////////////////////////////////
void gemwin :: bufferMess(int buf)
{
    if (buf == 1)
		GemMan::m_buffer = 1;
    else
		GemMan::m_buffer = 2;
}

/////////////////////////////////////////////////////////
// dimensionsMess
//
/////////////////////////////////////////////////////////
void gemwin :: dimensionsMess(int width, int height)
{
    if (width <= 0)
    {
        error("GEM: gemwin: width must be greater than 0");
        return;
    }
    
    if (height <= 0 )
    {
        error ("GEM: gemwin: height must be greater than 0");
        return;
    }
    GemMan::m_width = width;
    GemMan::m_height = height;
}

/////////////////////////////////////////////////////////
// colorMess
//
/////////////////////////////////////////////////////////
void gemwin :: colorMess(float red, float green, float blue)
{
    glClearColor(red, green, blue, 0.);
    GemMan::m_clear_color[0] = red;
    GemMan::m_clear_color[1] = green;
    GemMan::m_clear_color[2] = blue;
}

/////////////////////////////////////////////////////////
// ambientMess
//
/////////////////////////////////////////////////////////
void gemwin :: ambientMess(float red, float green, float blue)
{
    GemMan::m_mat_ambient[0] = red;
    GemMan::m_mat_ambient[1] = green;
    GemMan::m_mat_ambient[2] = blue;
}

/////////////////////////////////////////////////////////
// specularMess
//
/////////////////////////////////////////////////////////
void gemwin :: specularMess(float red, float green, float blue)
{
    GemMan::m_mat_specular[0] = red;
    GemMan::m_mat_specular[1] = green;
    GemMan::m_mat_specular[2] = blue;
}

/////////////////////////////////////////////////////////
// shininessMess
//
/////////////////////////////////////////////////////////
void gemwin :: shininessMess(float val)
{
    GemMan::m_mat_shininess = val;
}

/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemwin :: obj_setupCallback(t_class *classPtr)
{
    class_addbang(classPtr, (t_method)&gemwin::bangMessCallback);
    class_addfloat(classPtr, (t_method)&gemwin::floatMessCallback);

    class_addmethod(classPtr, (t_method)&gemwin::createMessCallback,
    	    gensym("create"), A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::createStereoMessCallback,
    	    gensym("createStereo"), A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::createStereoMessCallback,
    	    gensym("createstereo"), A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::bufferMessCallback,
    	    gensym("buffer"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::dimensionsMessCallback,
    	    gensym("dimen"), A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::colorMessCallback,
    	    gensym("color"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::perspectiveMessCallback,
    	    gensym("perspec"), A_GIMME, A_NULL);

    class_addmethod(classPtr, (t_method)&gemwin::ambientMessCallback,
    	    gensym("ambient"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::specularMessCallback,
    	    gensym("specular"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::shininessMessCallback,
    	    gensym("shininess"), A_FLOAT, A_NULL);

    // just call GemMan directly
    class_addmethod(classPtr, (t_method)&gemwin::resetMessCallback,
    	    gensym("reset"), A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::destroyMessCallback,
    	    gensym("destroy"), A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::printMessCallback,
    	    gensym("print"), A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::profileMessCallback, 
    	    gensym("profile"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::lightingMessCallback, 
    	    gensym("lighting"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::stereoSepMessCallback, 
    	    gensym("stereoSep"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::stereoFocMessCallback, 
    	    gensym("stereoFoc"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::stereoSepMessCallback, 
    	    gensym("stereosep"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::stereoFocMessCallback, 
    	    gensym("stereofoc"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::borderMessCallback, 
    	    gensym("border"), A_FLOAT, A_NULL);
    class_addmethod(classPtr, (t_method)&gemwin::frameMessCallback,
    	    gensym("frame"), A_FLOAT, A_NULL);
}
void gemwin :: printMessCallback(void *)
{
    GemMan::printInfo();
}
void gemwin :: profileMessCallback(void *, t_floatarg state)
{
	GemMan::m_profile = (int)state;
}
void gemwin :: lightingMessCallback(void *, t_floatarg state)
{
    GemMan::lightingOnOff((int)state);
}
void gemwin :: stereoSepMessCallback(void *, t_floatarg state)
{
    GemMan::m_stereoSep = state;
}
void gemwin :: stereoFocMessCallback(void *, t_floatarg state)
{
    GemMan::m_stereoFocal = state;
}
void gemwin :: borderMessCallback(void *, t_floatarg state)
{
    GemMan::m_border = (int)state;
}
void gemwin :: destroyMessCallback(void *)
{
    GemMan::destroyWindow();
}
void gemwin :: resetMessCallback(void *)
{
    GemMan::resetState();
}
void gemwin :: frameMessCallback(void *, t_floatarg rate)
{
    GemMan::frameRate((float)rate);
}
void gemwin :: perspectiveMessCallback(void *, t_symbol *, int argc, t_atom *argv)
{
	if (argc != 6)
	{
		error("GEM: perspec message needs 6 arguments");
		return;
	}
	GemMan::m_perspect[0] = atom_getfloat(&argv[0]);	// left
	GemMan::m_perspect[1] = atom_getfloat(&argv[1]);	// right
	GemMan::m_perspect[2] = atom_getfloat(&argv[2]);	// bottom
	GemMan::m_perspect[3] = atom_getfloat(&argv[3]);	// top
	GemMan::m_perspect[4] = atom_getfloat(&argv[4]);	// front
	GemMan::m_perspect[5] = atom_getfloat(&argv[5]);	// back
}

void gemwin :: bangMessCallback(void *data)
{
    GetMyClass(data)->bangMess();
}
void gemwin :: floatMessCallback(void *data, t_float state)
{
    GetMyClass(data)->intMess((int)state);
}
void gemwin :: createMessCallback(void *data)
{
    GetMyClass(data)->createMess();
}
void gemwin :: createStereoMessCallback(void *data)
{
    GetMyClass(data)->createStereoMess();
}
void gemwin :: bufferMessCallback(void *data, t_floatarg buf)
{
    GetMyClass(data)->bufferMess((int)buf);
}
void gemwin :: dimensionsMessCallback(void *data, t_floatarg width, t_floatarg height)
{
    GetMyClass(data)->dimensionsMess((int)width, (int)height);
}
void gemwin :: colorMessCallback(void *data, t_floatarg red, t_floatarg green, t_floatarg blue)
{
    GetMyClass(data)->colorMess((float)red, (float)green, (float)blue);
}
void gemwin :: ambientMessCallback(void *data, t_floatarg red, t_floatarg green, t_floatarg blue)
{
    GetMyClass(data)->ambientMess((float)red, (float)green, (float)blue);
}
void gemwin :: specularMessCallback(void *data, t_floatarg red, t_floatarg green, t_floatarg blue)
{
    GetMyClass(data)->specularMess((float)red, (float)green, (float)blue);
}
void gemwin :: shininessMessCallback(void *data, t_floatarg val)
{
    GetMyClass(data)->shininessMess((float)val);
}
