/*******************************************************************************
 **
 ** The source file for the Jahshaka glworld.cpp module
 ** The Jahshaka Project
 ** Copyright (C) 2000-2005 The Jahshaka Project
 ** Released under the GNU General Public License
 **
 *******************************************************************************/

#include "glworld.h"

#include <qslider.h>
#include <InputLCD.h>
#include "supergrangecontrol.h"
#include <qhbox.h>
#include <qfiledialog.h>
#include <qtimer.h>
#include <qpopupmenu.h>
#include <qlistview.h>
#include <qcheckbox.h>
#include <qlayout.h>

#include "pbuffer.h"
#include <sstream>

#include <widget.h>
#include <dialogs.h>
#include <jahformatter.h>
#include <valueFormatters.h>
#include <jahdataio.h>
#include <jahtimer.h>
#include <timelineSlider.h>

#include "glworldlists.h"
#include "glcore.h"
#include "jahrender.h"
#include "jahtranslate.h"
#include "jahpluginlib.h"
#include <openobjectlib.h>

#ifndef JAHPLAYER
#include "jahnodes.h"
#include "keyframer.h"
#endif

#include <openmedialib.h>

GLWorld::GLWorld( GLCore* jahcore, const char* name, QHBox* controller, int* globalclipnumber )
    : core( jahcore ),
      m_layerlist( NULL ),
      m_layer_list( NULL ),
      ModuleName( name ),
      m_controller( controller ),
      thegrid( NULL ),
      titlesafe( NULL ),
      textsafe( NULL ),
      camera( NULL ),
      activeLayers( NULL ),
      m_auto_save_timer( NULL ),
      renderSpace( NULL ),
      timer( NULL ),
      coretimer( NULL ),
      clipnumber( globalclipnumber ),
      m_active_layer( NULL ),
      controllerStartFrameControl( NULL ),
      controllerEndFrameControl( NULL ),
      m_animframe_lcd( NULL ),
      startFrameControl( NULL ),
      endFrameControl( NULL ),
      m_compositing_mode_select_button(NULL),
      m_cpu_effects_dispatch_table(EffectInfo::NOT_A_TYPE),
      m_mesh_effects_dispatch_table(EffectInfo::NOT_A_TYPE),
      m_gpu_effects_dispatch_table(EffectInfo::NOT_A_TYPE),
      m_cpu_effects_selection_vector(EffectInfo::NOT_A_TYPE),
      m_mesh_effects_selection_vector(EffectInfo::NOT_A_TYPE),
      m_gpu_effects_selection_vector(EffectInfo::NOT_A_TYPE),
      m_started( false )
{  
    jtrace = JahTrace::getInstance();	//set up tracer
    jt = JahTranslate::getInstance();	//set up translator
    
    jtrace->debug("Initializing Module",ModuleName);
    
    m_frames_per_second_name_vector[FRAMES_PER_SECOND_15] = "15 Frames/Sec";
    m_frames_per_second_name_vector[FRAMES_PER_SECOND_24] = "24 Frames/Sec";
    m_frames_per_second_name_vector[FRAMES_PER_SECOND_25] = "25 Frames/Sec";
    m_frames_per_second_name_vector[FRAMES_PER_SECOND_30] = "30 Frames/Sec";
    m_frames_per_second_name_vector[FRAMES_PER_SECOND_60] = "60 Frames/Sec";
    m_frames_per_second_name_vector[FRAMES_PER_SECOND_90] = "90 Frames/Sec";
    
    textEd = NULL;
    Globals::setAutoSaveEnable(true);
    
    curr_width_ = jahcore->width( );
    curr_height_ = jahcore->height( );

    for (int i = 0; i < 11; i++)
    {
        m_lighting_slider[i] = NULL;
    }
}

//pointer to jahpluginlib
JahPluginLib* GLWorld::jplugin;

GLWorld::~GLWorld(void) 
{
    if ( timer ) timer->stop( );
    if ( m_auto_save_timer ) m_auto_save_timer->stop( );
    
    delete coretimer;
    delete renderSpace;
    delete activeLayers;
    delete m_layerlist;
    delete m_layer_list;
    delete thegrid;
    delete titlesafe;
    delete textsafe;
    
    std::vector<EffectInfo*>::iterator it = m_cpu_effects_selection_vector.begin( );
    while ( it != m_cpu_effects_selection_vector.end( ) )
        delete *( it ++ );
    
    it = m_mesh_effects_selection_vector.begin( );
    while ( it != m_mesh_effects_selection_vector.end( ) )
        delete *( it ++ );
    
    it = m_gpu_effects_selection_vector.begin( );
    while ( it != m_gpu_effects_selection_vector.end( ) )
        delete *( it ++ );
};

void GLWorld::lazy( )
{
    //////////////////////////////////////////////////////////
    //set up ui effects options
    //should be done in the user interface code
    buildEffectsOptions();
    
    //////////////////////////////////////////////////////////
    //set up pointers to singletons for full class access
    
    //initalize the global vars from the prefs
    JahPrefs& jprefs = JahPrefs::getInstance();
    
    JahBasePath  = jprefs.getBasePath().data();
    JahMediaPath = jprefs.getMediaPath().data();
    JahRenderer  = jprefs.getRenderer();
    
    //start up using default resolution
    int jahres = jprefs.getJahResolution();
    hasResMenu = false;
    
    JahResolutionValue = jahres;
    
    projectData thedata;
    X_RESOLUTION = thedata.getXres(jahres);
    Y_RESOLUTION = thedata.getYres(jahres);
    PIXEL_RATIO  = thedata.getPixelRatio(jahres);
    
    HWFOG        = jprefs.getHwFog();
    HWALIASING   = jprefs.getHwAliasing();
    
    //initialize all global variables
    minFrame=1; 
    maxFrame=100;
    gridval = 0;
    
    renderpath = JahMediaPath+"media/renders/";
    
    //need to check this here as we dont have a JahScenesPAth pref yet
    QDir d( JahMediaPath+"scenes/" );                        // "./example"
    
    if ( d.exists() )
    {
        scenepath  = JahMediaPath+"scenes/";
    }
    else
    {
        scenepath = JahBasePath+"scenes/";
    }
    
    
    mmode = MOFF;
    forceplay = false;
    updateEffect = false;
    //useBuffering = false;
    
    //for gpu effects
    //gpusupport = false;
    //nv_gpusupport = false;
    m_gpuactive = false;
    
    gpusupport = jprefs.getGpusupport();
    nv_gpusupport = jprefs.getNVGpusupport();
    
    //for hardware anti aliasing support
    hwaliasing = false;
    
    // This list will supersede m_layerlist ASAP FIXME
    m_layer_list = new QPtrList<JahLayer>;
    m_layer_list->setAutoDelete(true);
    
    ///////////////////////////////////////////////
    // the linked list is here
    m_layerlist = new QPtrList<LayerListEntry>;
    getLayerList()->setAutoDelete( TRUE );     // delete items when they are removed
    
    camera = NULL;
    
    //note that these dont have  to be layers
    //and should be display lists
    thegrid     = new JahLayer;
    titlesafe   = new JahLayer;
    textsafe    = new JahLayer;
    
    //the renderspace
    renderSpace = new JahRender(this);
    
    //the active layers list
    activeLayers = new ActiveLayerList;
    
    //for ui options
    numUiOptions = 0;
    
    //for autosave
    m_auto_save_in_progress = false;
    
    //builds the controller
    buildController(m_controller);
    
    //initalize world objects
    initializeWorld();
    
    //set default render quality to uncompressed BMP
    renderquality = RENDER_QUALITY_BMP;
    
    //fog settings for the world view
    hfog = 0.0; 
    vfog = 0.0;
    
    //for the ui
    hasLabels = false;
    hasSliders = false;
    hasButtons = false;
    
    //for various interface widgets
    haskeyframer = false;
    hasnodeframer = false;
    
    /////////////////////////////////////////////////////////////////////
    //need to track and monitor this as well as control it for playback
    //controls the fps for scene playback
    //redrawWait=0;
    jahfps = 30;
    setRedrawDelay( (int)((1 / jahfps) * 1000) );
    
    timer = new QTimer( this );
    //connect( timer, SIGNAL(timeout()), SLOT(paintGL()) );
    connect( timer, SIGNAL(timeout()), this, SLOT(scheduleUpdate()) );
    timer->start( getRedrawDelay(), TRUE );
    
    m_auto_save_timer = new QTimer(this);
    connect( m_auto_save_timer, SIGNAL(timeout()), this, SLOT( autoSaveThisModule() ) );
    m_auto_save_timer->start(MODULE_AUTO_SAVE_FREQUENCY * 1000, true);
    
    /////////////////////////////////////////////
    //hook up core timer for fps feedback
    coretimer = new JahTimer;
    
    //for statistical feedback
    stats_showStats = false;
    
    m_vertex_shader = NULL;
    m_fragment_shader = NULL;
    m_shader_program = NULL;
    
    m_scene_save_indentation_depth = 0;
    
    Globals::setRendering(false);
    
    
    //for lights
    numberOfLights = 0;
    
    //for the render status
    m_render_at_image_resolution = false;
    
    //finished initializing
    jtrace->debug("Initialized Module",ModuleName);
    
    // Set the fps correctly
    TimecodeValueFormatter fmt;
    fmt.setFPS( thedata.getFPS( jahres ), thedata.getDropFrame( jahres ) );
    
    if ( controllerslider ) controllerslider->setFPS( thedata.getFPS( jahres ), thedata.getDropFrame( jahres ) );
    if ( startFrameControl ) startFrameControl->setFormatter( fmt );
    if ( controllerEndFrameControl ) controllerEndFrameControl->setFormatter( fmt );
    if ( controllerStartFrameControl ) controllerStartFrameControl->setFormatter( fmt );
    if ( endFrameControl ) endFrameControl->setFormatter( fmt );

    if ( m_animframe_lcd ) m_animframe_lcd->setFormatter( fmt );
    
    for (int slider_number = 0; slider_number < (int)NUMBER_OF_AXIS_SLIDERS; slider_number++)
    {
        JahSliders[slider_number] = NULL;
        JahSlidersLabel[slider_number] = NULL;
    }
    
    setRenderOnlyToSelectedEffect(false);
    setModuleUsesLighting(false);
    m_run_script_button = NULL;
    setStopScript(false);
    
    
    m_jah_gl_blend_mode_string_vector.push_back("GL_ZERO");
    m_jah_gl_blend_mode_string_vector.push_back("GL_ONE");
    m_jah_gl_blend_mode_string_vector.push_back("GL_SRC_COLOR");
    m_jah_gl_blend_mode_string_vector.push_back("GL_ONE_MINUS_SRC_COLOR");
    m_jah_gl_blend_mode_string_vector.push_back("GL_SRC_ALPHA");
    m_jah_gl_blend_mode_string_vector.push_back("GL_ONE_MINUS_SRC_ALPHA");
    m_jah_gl_blend_mode_string_vector.push_back("GL_DST_ALPHA");
    m_jah_gl_blend_mode_string_vector.push_back("GL_ONE_MINUS_DST_ALPHA");
    m_jah_gl_blend_mode_string_vector.push_back("GL_DST_COLOR");
    m_jah_gl_blend_mode_string_vector.push_back("GL_ONE_MINUS_DST_COLOR");
    
    m_jah_gl_blend_mode_value_vector.push_back(GL_ZERO);
    m_jah_gl_blend_mode_value_vector.push_back(GL_ONE);
    m_jah_gl_blend_mode_value_vector.push_back(GL_SRC_COLOR);
    m_jah_gl_blend_mode_value_vector.push_back(GL_ONE_MINUS_SRC_COLOR);
    m_jah_gl_blend_mode_value_vector.push_back(GL_SRC_ALPHA);
    m_jah_gl_blend_mode_value_vector.push_back(GL_ONE_MINUS_SRC_ALPHA);
    m_jah_gl_blend_mode_value_vector.push_back(GL_DST_ALPHA);
    m_jah_gl_blend_mode_value_vector.push_back(GL_ONE_MINUS_DST_ALPHA);
    m_jah_gl_blend_mode_value_vector.push_back(GL_DST_COLOR);
    m_jah_gl_blend_mode_value_vector.push_back(GL_ONE_MINUS_DST_COLOR);
    
    setStopRequested(false);
};

void GLWorld::headRender( int width, int height ) 
{ 
    glViewport( 0, 0, width, height );
 
	curr_width_  = width;
	curr_height_ = height;
    
    core->paintGL( ); 
    
   	curr_width_  = core->m_renderwidth;
	curr_height_ = core->m_renderheight;
}

void GLWorld::scheduleUpdate( )
{
    updatePosition( );
    updateGL( );
    schedulePosition( );
}

void GLWorld::initializePlugins( )
{
    static bool initialized = false;
    
    if ( initialized ) return;
    initialized = true;
    
    /////////////////////////////////////////////////////////////////
    //ok lets load the plugins in now...
    jtrace->info( ">Initializing Plugins");
    
    JahPluginLib* jplugin = JahPluginLib::getInstance();
    jplugin->initializePlugins();
    
    jtrace->info( ">Initialized Plugins");
    
    /////////////////////////////////////////////////////////////////
    //initialize the openobjectlib 
    //jtrace->info( ">Initializing OpenObjectLib");
    
    //OpenObjectLib* oolib = OpenObjectLib::getInstance();
    //oolib->initializePlugins();
    //oolib->listPlugins();
    
    //jtrace->info( ">Initialized OOlib Plugins");
}

//need to move into the ui generator code
void GLWorld::buildEffectsOptions(void)
{
    m_cpu_effects_dispatch_table[EffectInfo::GREY_CPU_TYPE] = &GLWorld::doGrey;
    m_cpu_effects_dispatch_table[EffectInfo::EDGE_DETECT_CPU_TYPE] = &GLWorld::doEdge;
    m_cpu_effects_dispatch_table[EffectInfo::SELECT_COLORS_CPU_TYPE] = &GLWorld::doColorSelect;
    m_cpu_effects_dispatch_table[EffectInfo::CONTRAST_CPU_TYPE] = &GLWorld::doContrast;
    m_cpu_effects_dispatch_table[EffectInfo::BRIGHTNESS_CPU_TYPE] = &GLWorld::doBrightness;
    m_cpu_effects_dispatch_table[EffectInfo::MATRIX_SHARPEN_CPU_TYPE] = &GLWorld::doMatrixSharpen;
    m_cpu_effects_dispatch_table[EffectInfo::MATRIX_BLUR_CPU_TYPE] = &GLWorld::doMatrixBlur;
    m_cpu_effects_dispatch_table[EffectInfo::MATRIX_EMBOSS_CPU_TYPE] = &GLWorld::doMatrixEmboss;
    m_cpu_effects_dispatch_table[EffectInfo::GAUSSIAN_BLUR_CPU_TYPE] = &GLWorld::doGaussianBlur;
    m_cpu_effects_dispatch_table[EffectInfo::MIRROR_CPU_TYPE] = &GLWorld::doMirror;
    m_cpu_effects_dispatch_table[EffectInfo::SWAP_RGB_CPU_TYPE] = &GLWorld::doSwapRGB;
    m_cpu_effects_dispatch_table[EffectInfo::NEGATIVE_CPU_TYPE] = &GLWorld::doNegative;
    m_cpu_effects_dispatch_table[EffectInfo::COLORIZE_CPU_TYPE] = &GLWorld::doCPUColorize;
    m_cpu_effects_dispatch_table[EffectInfo::CHROMA_KEYER_CPU_TYPE] = &GLWorld::doChromaKeyerCPU;
    
    m_mesh_effects_dispatch_table[EffectInfo::FLAG_MESH_TYPE] = &GLWorld::doFlagRt;
    m_mesh_effects_dispatch_table[EffectInfo::FISHEYE_MESH_TYPE] = &GLWorld::doFisheyeRt;
    m_mesh_effects_dispatch_table[EffectInfo::RIPPLE_MESH_TYPE] = &GLWorld::doRippleRt;
    m_mesh_effects_dispatch_table[EffectInfo::SWIRL_MESH_TYPE] = &GLWorld::doSwirlRt;
    
    m_gpu_effects_dispatch_table[EffectInfo::STRETCH_CROP_GPU_TYPE] = &GLWorld::doStretchCrop;
    m_gpu_effects_dispatch_table[EffectInfo::COLORIZE_GPU_TYPE] = &GLWorld::doColorizeGPU;
    m_gpu_effects_dispatch_table[EffectInfo::EARTHQUAKE_GPU_TYPE] = &GLWorld::doNV30EarthquakeGPU;
    m_gpu_effects_dispatch_table[EffectInfo::LIGHTING_GPU_TYPE] = &GLWorld::doNV30LightingGPU;
    m_gpu_effects_dispatch_table[EffectInfo::CHARCOAL_GPU_TYPE] = &GLWorld::doNV30CharcoalGPU;
    m_gpu_effects_dispatch_table[EffectInfo::CHROMA_KEYER_GLSL_SEPARATE_ALPHA_TYPE] = &GLWorld::doChromaKeyerGLSLSeparateAlpha;
    m_gpu_effects_dispatch_table[EffectInfo::CHROMA_KEYER_GLSL_TYPE] = &GLWorld::doChromaKeyerGLSL;
    
    EffectInfo* new_menu_item;
    
    int i;
    
    for (i = EffectInfo::CPU_TYPE_START + 1; i < EffectInfo::MESH_TYPE_START; i++)
    {
        new_menu_item = new EffectInfo( EffectInfo::EFFECT_TYPE(i) );
        m_cpu_effects_selection_vector[i] = new_menu_item;
    }
    
    for (i = EffectInfo::MESH_TYPE_START + 1; i < EffectInfo::GPU_TYPE_START; i++)
    {
        new_menu_item = new EffectInfo( EffectInfo::EFFECT_TYPE(i) );
        m_mesh_effects_selection_vector[i] = new_menu_item;
    }
    
    for (i = EffectInfo::GPU_TYPE_START + 1; i < EffectInfo::EFFECT_TYPE_END; i++)
    {
        new_menu_item = new EffectInfo( EffectInfo::EFFECT_TYPE(i) );
        m_gpu_effects_selection_vector[i] = new_menu_item;
    }
    
    
}

void GLWorld::setResolution(int val)
{
    
    ///////////////////////////////////
    // projectData object
    projectData thedata;
    
    ///////////////////////////////////
    // error checking
    int numSettings;
    
    numSettings = thedata.getNumformats();
    if (val>numSettings)
    {
        val = thedata.getDefaultformat();
    }
    
    ////////////////////////////////////
    //update system and ui
    JahResolutionValue = val;
    
    X_RESOLUTION = thedata.getXres(JahResolutionValue);
    Y_RESOLUTION = thedata.getYres(JahResolutionValue);
    PIXEL_RATIO  = thedata.getPixelRatio(JahResolutionValue);

    TimecodeValueFormatter fmt;
    fmt.setFPS( thedata.getFPS( JahResolutionValue ), thedata.getDropFrame( JahResolutionValue ) );

    if ( controllerslider ) controllerslider->setFPS( thedata.getFPS( JahResolutionValue ), thedata.getDropFrame( JahResolutionValue ) );
    if ( startFrameControl ) startFrameControl->setFormatter( fmt );
    if ( endFrameControl ) endFrameControl->setFormatter( fmt );
    if ( m_animframe_lcd ) m_animframe_lcd->setFormatter( fmt );
    if ( controllerEndFrameControl ) controllerEndFrameControl->setFormatter( fmt );
    if ( controllerStartFrameControl ) controllerStartFrameControl->setFormatter( fmt );

    
    //a hack for the paint module here since it doesnt use a layer yet
    if (ModuleName=="Paint")
    {
        //if (core->glmode==1)
        core->setFixedSize( QSize( X_RESOLUTION, Y_RESOLUTION ) );
    }
    else
    {
        getLayerList()->at(0)->thelayer->updateResolution(JahResolutionValue);
        titlesafe->updateResolution(JahResolutionValue);
    }
    
    updateGL();
    
    
}

void GLWorld::updateResMenu(int val)
{
    if(hasResMenu)
    {
        JahresCombo->setCurrentItem(val);
    }
}

void GLWorld::changeZoom(int val)
{
    //val is -10 to 10 we need to compute this
    GLfloat value = GLfloat( val + 9 ) / 10.0f;

	if ( value <= 0.0f ) 
    {
        value = 0.1f;
    }

    core->setZoom( setZoom( value ) );
    updateGL();
}

void GLWorld::resetZoom(void)
{
    core->setZoom( 1.0f );
    updateGL();
}

//////////////////////////////////////////////
// Slider related

//not really slider but the main controller slider
void GLWorld::updateTimeSlider(int value)
{
    if ( value != controllerslider->value() )
        controllerslider->setValue(value);
    m_currentFrame = value;
}

//main controller slider selected
void GLWorld::sliderselected()
{ 
    m_animsliderselected = TRUE;
}

void GLWorld::slotTimeSliderReleased()
{
    m_animsliderselected = FALSE;
}

void GLWorld::sliderValueChanged(int)
{
//and not rendering
    if ( !getAnimating() && !Globals::getRendering() )
    {
        //debug("world slider value changed");
        int theframe;
        theframe = controllerslider->value();
        updateAnimation(theframe); 
        updateGL();
    }
}


////////////////////////////////////////////////
// Player related

void GLWorld::setForcePlay(bool forceit)  
{ 
    forceplay = forceit; 
    //forcedplay->setChecked(forceplay);
}

void GLWorld::toggleForcePlay()  
{ 
    forceplay = !forceplay;
    setForcePlay(forceplay); //make forcedplay call its not a endless loop
}


void GLWorld::firstframeanimation()  
{
    m_currentFrame = minFrame;
    
    updateAnimation(m_currentFrame);
    updateGL();
    
    if ( getAnimating() ) 
    { 
        toggleAnimation(FALSE); 
    }
}

void GLWorld::previousframeanimation()  
{
    m_currentFrame -= 1;
    
    if (m_currentFrame < minFrame)
    {
        m_currentFrame = maxFrame;
    }
    
    updateAnimation(m_currentFrame);
    updateGL();
    
    if ( getAnimating() ) 
    { 
        toggleAnimation(FALSE); 
    }
}

void GLWorld::nextframeanimation()  
{
    m_currentFrame++;	
    
    if (m_currentFrame > maxFrame)
    {
        m_currentFrame = minFrame;
    }
    
    updateAnimation(m_currentFrame);
    updateGL();
    
    if ( getAnimating() ) 
    { 
        toggleAnimation(FALSE); 
    }
}

void GLWorld::lastframeanimation()
{
    
    m_currentFrame = maxFrame;
    updateAnimation(m_currentFrame);
    updateGL();
    
    if ( getAnimating() ) 
    { 
        toggleAnimation(FALSE); 
    }
}

////////////////////////////////////////
// Font control routines
void 
GLWorld::setTextLayerText(JahLayer* text_layer, const char* text_string)
{
    QString text_qstring = text_string;
    text_layer->text->text = text_qstring;
    text_layer->getCheckListItem()->setText(0, text_string); 
    
    updateGL();  
}

void GLWorld::setText(const char* text_string) 
{ 
    QString text_qstring = text_string;
    getActiveJahLayer()->text->text = text_qstring;
    
    updateGL();  
}  

void GLWorld::setText(const QString& text_string) 
{ 
    getActiveJahLayer()->text->text = text_string;
    std::string first_twenty_characters = text_string.data();
    first_twenty_characters = first_twenty_characters.substr(0, 20);
    
    // Don't use new lines - they will make the listview look lousy
    size_t first_new_line = first_twenty_characters.find_first_of("\n");
    
    if (first_new_line != std::string::npos)
    {
        first_twenty_characters = first_twenty_characters.substr(0, first_new_line);
    }
    
    QString first_twenty_characters_qstring = first_twenty_characters.data();
    getActiveJahLayer()->getCheckListItem()->setText(0, first_twenty_characters_qstring); 
    
    updateGL();  
}  

void GLWorld::setFontColor() 
{ 
    setColor();
    
    updateGL(); 
} 

void GLWorld::loadFont() 
{
    //need to use a loader here... give the user a choice
    QString format = "ttf";
    
    QString filename = QFileDialog::getOpenFileName( 
        JahBasePath+"fonts",  QString( "*.%1" ).arg( format.lower() ), this );
    
    if ( !filename.isEmpty() ) 
    {
        getActiveJahLayer()->updateFont = true;
        getActiveJahLayer()->text->font = filename;
    }
    
    //refresh screen
    updateGL(); 
}

/////////////////////////////////////////
// 3D model control here

void GLWorld::changeParticleColors() 
{
    
    getActiveJahLayer()->ParticleColors = 
        !getActiveJahLayer()->ParticleColors;
    
}

//////////////////////////////////////////
// Clip and Key control

void GLWorld::setKeyStatus()
{
    //jtrace->debug( "GLWorld::","called setKeyStatus()");
    if ( getActiveJahLayer() != camera ) 
    {
        if ( getKeySelect() )
        {
            getActiveJahLayer()->drawtheKey = getKeySelect()->isOn();
        }
        else
        {
            getActiveJahLayer()->drawtheKey = !getActiveJahLayer()->drawtheKey;
        }
    }
    
    getActiveJahLayer()->setEffectsSlidersHaveChanged(true);
    updateGL();
}

void GLWorld::setClipStatus()         
{
    //jtrace->info( "GLWorld::","called setClipStatus()");
    
    if (getActiveJahLayer() != camera)
    {
        getActiveJahLayer()->drawtheLayer =  
            !getActiveJahLayer()->drawtheLayer;
    }
    
    updateGL();
}

void GLWorld::InvertKeyData()  
{ 
    getActiveJahLayer()->changeKeyStatus(); 
    updateGL();
}   

void GLWorld::addClip(assetData clip) 
{
    JahLayer* jah_layer = getActiveJahLayer();
    addClip(jah_layer, clip);
}

///////////////////////////////////////////////////////////
// why not just pass videodata to the layer?
// would be much cleaner

void GLWorld::addClip(JahLayer* jah_layer, assetData clip) 
{
    int endframe = clip.endframe - 1;
    
    if (endframe > maxFrame)
    {
        maxFrame = endframe;
        updatesliderEndframe(maxFrame);
        endFrameControl->setValue(maxFrame);
    }
    
    if (clip.startframe <= minFrame)
    {
        minFrame = clip.startframe;
		if ( minFrame < 1 ) minFrame = 1;
        updatesliderStartframe(minFrame);
        startFrameControl->setValue(minFrame);
    }
    
    if (jah_layer->getCategory() == ObjectCategory::EFFECT)
    {
        jah_layer = jah_layer->getParent();
    }
    
    jah_layer->assignAsset(clip, VideoCategory::IMAGE);
    
    jah_layer->LoadLayerAsset(VideoCategory::IMAGE);
    jah_layer->makeTexture();
    jah_layer->setFirstPass(true);
    
    updateGL();
    updateSliders();
    
}

void GLWorld::addClipKey(assetData clip)
{
    getActiveJahLayer()->assignAsset(clip, VideoCategory::KEY);
    
    getActiveJahLayer()->LoadLayerAsset(VideoCategory::KEY);
    getActiveJahLayer()->makeTexture();
    
    updateGL();
    updateSliders();
    
}


/////////////////////////////////////////////////
// Reset and clear layers

void GLWorld::ResetLayer() 
{
    //jtrace->info( "GLWorld::","called ResetLayer()");
    
    if (getActiveJahLayer() == camera) 
    { 
        resetkeys(camera);
    } 
    else 
    { 
        resetkeys(getActiveJahLayer()); 
    }
    
    m_animation = FALSE;
    updateGL();
    
}

void GLWorld::ResetAll() 
{
    //jtrace->info( "GLWorld::","called ResetAll()");
    
    if ( camera )
    	resetkeys(camera);
    
    for ( uint i = 0; i <= getLayerList()->count(); ++i )
    {
        if ( getLayerList()->at(i) ) 
        {
            resetkeys(getLayerList()->at(i)->thelayer); 
        }   
    }
    
    m_animation = FALSE;
    updateGL();
}

void GLWorld::ClearAll() 
{
    m_layer_listview->clear();
    getLayerList()->clear();
    delete m_layerlist;
    
    if (ModuleName=="Effects")
    {
#ifndef JAHPLAYER
#ifndef NEWWIREUPWIDGET
        thenodeframer->clear();
#endif
#endif
    }
    
    //recreate the variables
    m_layerlist = new QPtrList<LayerListEntry>;
    getLayerList()->setAutoDelete( TRUE );     // delete items when they are removed
    
    //initialize them now
    initializeObjects();
    initializeWorld();
    m_active_layer = getFirstJahLayer();
    
    setResolution(JahResolutionValue);
}

JahLayer*       
GLWorld::getFirstJahLayer()
{
    return( getLayerList()->first()->getJahLayer() );
}

void GLWorld::loadClearAll()
{
    jtrace->info( "GLWorld::","called LoadClearAll()");
    
    m_layer_listview->clear();
    getLayerList()->clear();
    delete m_layerlist;
    
    //recreate the variables
    m_layerlist = new QPtrList<LayerListEntry>;
    getLayerList()->setAutoDelete( TRUE );     // delete items when they are removed
    
    m_active_layer = NULL;
    
    m_chroma_settings_layer = NULL;
    m_chroma_key_layer = NULL;
    m_chroma_base_layer = NULL;
}

int
GLWorld::getActiveLayerNumber()
{
    LayerListEntry* layer_list_entry = getActiveJahLayer()->getLayerListEntry();
    int layer_number = getLayerList()->find(layer_list_entry);
    return layer_number;
}


void GLWorld::connectKeyframer( void ) 
{
#ifndef JAHPLAYER
    connect ( thekeyframer, SIGNAL(AddKeyframe(void)),    this, SLOT(addKeyframe(void)) );
    connect ( thekeyframer, SIGNAL(RemoveKeyframe(void)), this, SLOT(removeKeyframe(void)) );
    connect ( thekeyframer, SIGNAL(PrevKeyframe(void)),   this, SLOT(prevKeyframe(void)) );
    connect ( thekeyframer, SIGNAL(NextKeyframe(void)),   this, SLOT(nextKeyframe(void)) );
    connect ( thekeyframer, SIGNAL(signalKeyframeChanged(void)), this, SLOT( slotKeyframeChanged(void) ) );
    
    // tell keyframer to update its timeline
    connect( controllerslider,   SIGNAL(valueChanged(int)),  thekeyframer,  SLOT(movePlayLine(int)) );
#endif
}

void GLWorld::addKeyframer( QWidget *parentwidget ) 
{
#ifndef JAHPLAYER
    thekeyframer = new JahKeyframer( this, parentwidget, "keyframer" );
    
    haskeyframer = true; //let the world know its there
    
    connectKeyframer();
#endif
}

////////////////////////////////////////////////////
// creates a instance of the nodeframer
// for modules that want to use the widget
void GLWorld::initializeNodes( QHBox* parent2)
{
#ifndef JAHPLAYER
//#ifndef WIN32
    
    
    
#ifdef NEWWIREUPWIDGET
    thewireup = new WireWidget( parent2, "keyframer" );
    thewireup->setFixedSize( QSize( 980, 600 ) );    //was 955,486
    
    haswireup = true;
    hasnodeframer = false;
#else
    
    thenodeframer = new JahNodes( parent2, "keyframer" );
    thenodeframer->setFixedSize( QSize( 0, 0 ) );    //was 955,486
    
    hasnodeframer = true;
    haswireup = false;
    
    // pick up signals from user clicking on the effect node canvas view.
    connect ( thenodeframer->nodeeditor, SIGNAL( nodeClicked ( int ) ) , this, SLOT ( effectNodeClicked ( int )));
    
    
#endif
    
#endif 
}

int
GLWorld::findEffectParent(JahLayer* layer)
{
    if (layer->objtype == ObjectCategory::EFFECT)
    {
        JahLayer* parent = layer->getParent();
        return( findLayer(parent) );
    }
    
    return findLayer(layer);
}

void GLWorld::SetGpuSelect(void)
{
    if (gpusupport || nv_gpusupport)
    {
        m_gpuactive = GpuSelect->isChecked();
    }
    
    if ( getLayerList()->at(1) && getGpuActive() )
    {
        getLayerList()->at(1)->thelayer->usedagpu = true;
    }
    else
    {
        getLayerList()->at(1)->thelayer->usedagpu = false;
    }
    
    updateGL();
}

bool            
GLWorld::canAcceptEffects(ObjectCategory::TYPE object_category)
{
    if (   object_category == ObjectCategory::JAHLAYER
        || object_category == ObjectCategory::MESHLAYER
        || object_category == ObjectCategory::CUBE
        || object_category == ObjectCategory::SPHERE
        || object_category == ObjectCategory::CYLINDER
        )
    {
        return true;
    }
    
    return false;
}

int 
GLWorld::getJahLayerNumber(JahLayer* jah_layer)
{
    LayerListEntry* layerlist_layer = getLayerList()->first();
    
    for (; layerlist_layer; layerlist_layer = getLayerList()->next())
    {
        if (layerlist_layer->thelayer == jah_layer)
        {
            return getLayerList()->at();
        }
    }
    
    return(-1);
}


LayerListEntry* 
GLWorld::findLayerListEntry(QListViewItem* item)
{
    for (LayerListEntry* layer_list_entry = getLayerList()->first(); layer_list_entry; layer_list_entry = getLayerList()->next() )
    {
        if (layer_list_entry->thelayer->getCheckListItem() == item)
        {
            return layer_list_entry;
        }
    }
    
    return NULL;
}

LayerListEntry* 
GLWorld::findLayerListEntry(JahLayer* jah_layer)
{
    for (LayerListEntry* layer_list_entry = getLayerList()->first(); layer_list_entry; layer_list_entry = getLayerList()->next() )
    {
        if (layer_list_entry->getJahLayer() == jah_layer)
        {
            return layer_list_entry;
        }
    }
    
    return NULL;
}




void 
GLWorld::setSelectColorsIndividually(void)
{
    JahLayer* active_layer = getActiveJahLayer();
    m_select_colors_individually = m_select_colors_individually_qcheckbox->isChecked();
    active_layer->setSelectColorsIndividually(m_select_colors_individually);
    
    updateGL();
}

QCheckBox* 
GLWorld::getKeySelect()
{
    return NULL;
}


void
GLWorld::autoSaveThisModule()
{
    if (ModuleName == "Animation" || ModuleName == "Effects")
    {
        if ( !Globals::getRendering() && Globals::getAutoSaveEnable() )
        {
            setAutoSaveInProgress(true);
            std::ostringstream save_filename;
            save_filename.str("");
            save_filename << scenepath.data() << ModuleName.data() << "_backup.jsf";
            std::ostringstream save_filename2;
            save_filename2.str("");
            save_filename2 << scenepath.data() << ModuleName.data() << "_backup2.jsf";
            char system_command[1000];
            char copy_command[50];
#ifdef WIN32
            sprintf(copy_command, "copy");
#else
            sprintf(copy_command, "cp");
#endif
            sprintf( system_command, "%s %s %s", copy_command, save_filename.str().c_str(), save_filename2.str().c_str() );
            //system(system_command);
            setSceneSaveExport(false);
            saveSceneFile( save_filename.str() );
            setAutoSaveInProgress(false);
        }
        
        getAutoSaveTimer()->start(MODULE_AUTO_SAVE_FREQUENCY * 1000, true);
    }
}

void 
GLWorld::setUsePbuffer(void)
{
    bool use_pbuffer = m_pbuffer_select_checkbox->isChecked();
    
    JahLayer* active_layer = getActiveJahLayer();
    JahLayer* parent_layer = active_layer->getParent();
    JahLayer* image_layer = parent_layer ? parent_layer : active_layer;
    image_layer->setUsePbuffer(use_pbuffer);
    image_layer->setEffectsSlidersHaveChanged(true);
    updateGL();
}

void 
GLWorld::slotSetSrcBlendFactor()
{
    QPopupMenu *menu = new QPopupMenu( 0 );
    
    menu->insertItem( "GL_ZERO", JAH_GL_ZERO);
    menu->insertItem( "GL_ONE", JAH_GL_ONE);
    menu->insertItem( "GL_SRC_COLOR", JAH_GL_SRC_COLOR);
    menu->insertItem( "GL_ONE_MINUS_SRC_COLOR", JAH_GL_ONE_MINUS_SRC_COLOR);
    menu->insertItem( "GL_SRC_ALPHA", JAH_GL_SRC_ALPHA);
    menu->insertItem( "GL_ONE_MINUS_SRC_ALPHA", JAH_GL_ONE_MINUS_SRC_ALPHA);
    menu->insertItem( "GL_DST_ALPHA", JAH_GL_DST_ALPHA);
    menu->insertItem( "GL_ONE_MINUS_DST_ALPHA", JAH_GL_ONE_MINUS_DST_ALPHA);
    menu->insertItem( "GL_DST_COLOR", JAH_GL_DST_COLOR);
    menu->insertItem( "GL_ONE_MINUS_DST_COLOR", JAH_GL_ONE_MINUS_DST_COLOR);
    
    
    menu->setMouseTracking( TRUE );
    JAH_GL_BLEND_MODE factor = 
        (JAH_GL_BLEND_MODE)menu->exec( m_src_blend_mode_select_button->mapToGlobal( QPoint( 0, m_src_blend_mode_select_button->height() + 1 ) ) );
    
    if ( factor >= JAH_GL_ZERO ) 
    {
        setSrcBlendFactor(factor);
    }
    
    delete menu;
    updateGL();  //redraw scene
}

void 
GLWorld::slotResetBlendFactor()
{
    setSrcBlendFactor(JAH_GL_SRC_ALPHA);
    setDstBlendFactor(JAH_GL_ONE_MINUS_SRC_ALPHA);
}

void 
GLWorld::slotSetDstBlendFactor()
{
    QPopupMenu *menu = new QPopupMenu( 0 );
    
    menu->insertItem( "GL_ZERO", JAH_GL_ZERO);
    menu->insertItem( "GL_ONE", JAH_GL_ONE);
    menu->insertItem( "GL_SRC_COLOR", JAH_GL_SRC_COLOR);
    menu->insertItem( "GL_ONE_MINUS_SRC_COLOR", JAH_GL_ONE_MINUS_SRC_COLOR);
    menu->insertItem( "GL_SRC_ALPHA", JAH_GL_SRC_ALPHA);
    menu->insertItem( "GL_ONE_MINUS_SRC_ALPHA", JAH_GL_ONE_MINUS_SRC_ALPHA);
    menu->insertItem( "GL_DST_ALPHA", JAH_GL_DST_ALPHA);
    menu->insertItem( "GL_ONE_MINUS_DST_ALPHA", JAH_GL_ONE_MINUS_DST_ALPHA);
    menu->insertItem( "GL_DST_COLOR", JAH_GL_DST_COLOR);
    menu->insertItem( "GL_ONE_MINUS_DST_COLOR", JAH_GL_ONE_MINUS_DST_COLOR);
    
    
    menu->setMouseTracking( TRUE );
    JAH_GL_BLEND_MODE factor = 
        (JAH_GL_BLEND_MODE)menu->exec( m_dst_blend_mode_select_button->mapToGlobal( QPoint( 0, m_dst_blend_mode_select_button->height() + 1 ) ) );
    
    if ( factor >= JAH_GL_ZERO ) 
    {
        setDstBlendFactor(factor);
    }
    
    delete menu;
    updateGL();  //redraw scene
}

void 
GLWorld::configureModuleEngine()
{
}

void            
GLWorld::updateCompositeButton(CompositeType::TYPE type)
{
    QString name = CompositeType::getName(type).data();

    if(m_compositing_mode_select_button)
    {
        m_compositing_mode_select_button->setText(name);
    }
}

void            
GLWorld::setCompositeType(CompositeType::TYPE type)
{
    getActiveJahLayer()->setCompositeType(type);
    updateGL();
}

void
GLWorld::slotSetCompositingMode()
{
    QPopupMenu *menu = new QPopupMenu( 0 );
    
    menu->insertItem( "Reset", CompositeType::STANDARD_COMPOSITE_TYPE);
    menu->insertItem( "A", CompositeType::A_COMPOSITE_TYPE);
    menu->insertItem( "B", CompositeType::B_COMPOSITE_TYPE);
    menu->insertItem( "A over B", CompositeType::A_OVER_B_COMPOSITE_TYPE);
    menu->insertItem( "B over A", CompositeType::B_OVER_A_COMPOSITE_TYPE);
    menu->insertItem( "A in B", CompositeType::A_IN_B_COMPOSITE_TYPE);
    menu->insertItem( "B in A", CompositeType::B_IN_A_COMPOSITE_TYPE);
    menu->insertItem( "A out B", CompositeType::A_OUT_B_COMPOSITE_TYPE);
    menu->insertItem( "B out A", CompositeType::B_OUT_A_COMPOSITE_TYPE);
    menu->insertItem( "A atop B", CompositeType::A_ATOP_B_COMPOSITE_TYPE);
    menu->insertItem( "B atop A", CompositeType::B_ATOP_A_COMPOSITE_TYPE);
    menu->insertItem( "A xor B", CompositeType::A_XOR_B_COMPOSITE_TYPE);
    
    
    menu->setMouseTracking( TRUE );
    
    CompositeType::TYPE type = 
        (CompositeType::TYPE)menu->exec( m_compositing_mode_select_button->mapToGlobal( QPoint( 0, m_compositing_mode_select_button->height() + 1 ) ) );
    
    if ( type >= CompositeType::A_COMPOSITE_TYPE ) 
    {
        setCompositeType(type);
        updateCompositeButton(type);
    }
}

void            
GLWorld::setSrcBlendFactor(JAH_GL_BLEND_MODE factor) 
{ 
    m_src_blend_factor = getJahGlBlendModeValueVector(factor);
    m_src_blend_mode_select_button->setText( getJahGlBlendModeStringVector(factor).data() );
    getActiveJahLayer()->setSrcBlendFactor(m_src_blend_factor);
}

void            
GLWorld::setDstBlendFactor(JAH_GL_BLEND_MODE factor) 
{ 
    m_dst_blend_factor = getJahGlBlendModeValueVector(factor);
    m_dst_blend_mode_select_button->setText( getJahGlBlendModeStringVector(factor).data() );
    getActiveJahLayer()->setDstBlendFactor(m_dst_blend_factor);
}


bool        
GLWorld::getUseLighting()
{
    return m_use_lighting_checkbox->isChecked();
}

bool        
GLWorld::getShowLights()
{
    return getShowLightsCheckbox()->isChecked();
}

void        
GLWorld::hideAllLightingSliders()
{
    for (int i = 0; i < (int)NUMBER_OF_LIGHTING_SLIDERS; i++)
    {
        getLightingSliderPtr(i)->hide();
        getLightingLcdPtr(i)->hide();
        getLightingSliderLabelPtr(i)->hide();
    }
}

void        
GLWorld::showAllLightingSliders()
{
    for (int i = 0; i < (int)NUMBER_OF_LIGHTING_SLIDERS; i++)
    {
        getLightingSliderPtr(i)->show();
        getLightingLcdPtr(i)->show();
        getLightingSliderLabelPtr(i)->show();
    }
}

void
GLWorld::createTrackerPointLayers()
{
}

void GLWorld::makeCurrent( void ) 
{ 
    core->makeCurrent( );
}

void GLWorld::updateGL( void ) 
{
    if ( usesVideoHead( ) )
        emit showInHead( this );

    core->updateGL( );
    
   	curr_width_  = core->m_renderwidth;
	curr_height_ = core->m_renderheight;
}

JahLayer *GLWorld::getJahLayer( int layer_number ) 
{ 
    return getLayerList()->at(layer_number)->thelayer; 
}

LayerListEntry *GLWorld::getActiveLayer( )
{
    return m_active_layer->getLayerListEntry();
}

int             
GLWorld::getNumberOfLayers() 
{ 
    return getLayerList()->count(); 
}

void 
GLWorld::slotChooseFramesPerSecond()
{
    QPopupMenu *menu = new QPopupMenu( 0 );
    
    menu->insertItem( "15", FRAMES_PER_SECOND_15, 0 );
    menu->insertItem( "24", FRAMES_PER_SECOND_24, 0 );
    menu->insertItem( "25", FRAMES_PER_SECOND_25, 0 );
    menu->insertItem( "30", FRAMES_PER_SECOND_30, 0 );
    menu->insertItem( "60", FRAMES_PER_SECOND_60, 0 );
    menu->insertItem( "90", FRAMES_PER_SECOND_90, 0 );
    
    menu->setMouseTracking( TRUE );
    QPoint qpoint = QPoint( 0, m_select_fps_pushbutton->height() + 1 );
    int id = menu->exec( m_select_fps_pushbutton->mapToGlobal(qpoint) );
    
    int new_frames_per_second;
    // Values are just estmates.  Actually delay times are difficult to compute because of scene 
    // Complexity. 
    int redraw_delay = 28;
    
    if ( id != -1 ) 
    {
        switch(id) 
        {
        case FRAMES_PER_SECOND_15   : 
        { 
            new_frames_per_second = 15; 
            redraw_delay = 60;
            break; 
        }
        case FRAMES_PER_SECOND_24   : 
        { 
            new_frames_per_second = 24; 
            redraw_delay = 35;
            break; 
        }
        case FRAMES_PER_SECOND_25   : 
        { 
            new_frames_per_second = 25; 
            redraw_delay = 32;
            break; 
        }
        case FRAMES_PER_SECOND_30   : 
        { 
            new_frames_per_second = 30; 
            redraw_delay = 28;
            break; 
        }
        case FRAMES_PER_SECOND_60   : 
        { 
            new_frames_per_second = 60; 
            redraw_delay = 12;
            break; 
        }
        case FRAMES_PER_SECOND_90   : 
        { 
            new_frames_per_second = 90; 
            redraw_delay = 5;
            break; 
        }
        default  : 
        { 
            new_frames_per_second = 30; 
            redraw_delay = 28;
            break; 
        }
        }
    }
    else
    {
        new_frames_per_second = 30;
        id = FRAMES_PER_SECOND_30;
    }
    
    delete menu;
    
    QString text_string = getFramesPerSecondName( FRAMES_PER_SECOND(id) ).data();
    m_select_fps_pushbutton->setText(text_string);
    
    setFramesPerSecond(new_frames_per_second);
    m_select_fps_pushbutton->setDown(false);
    
    setRedrawDelay(redraw_delay);
}

std::vector<std::string> 
GLWorld::m_frames_per_second_name_vector(FRAMES_PER_SECOND_90 + 1);

void            
GLWorld::startSingleShotTimer()
{
    // If video needs to be loaded, it will occupy most of the time delay
    // This needs to be scaled to compensate for an estimated delay based
    // on the scene characteristics
    int layer_count = getLayerList()->count();
    int delay = getRedrawDelay();
    
    // Take off 3ms delay for each layer
    delay -= (layer_count * 3);
    
    if (delay < 0)
    {
        delay = 0;
    }
    
    timer->start( delay, TRUE );
}

void GLWorld::slotUpdateListviewCheckboxes()
{
    LayerListEntry* layer_list_entry = getLayerList()->first();
    
    for ( ; layer_list_entry; layer_list_entry = getLayerList()->next() )
    {
        JahLayer* jah_layer = layer_list_entry->getJahLayer();
        QCheckListItem* check_list_item = (QCheckListItem*)jah_layer->getCheckListItem();
        motionNode* motion_node = jah_layer->layernodes->m_node;
        
        if (check_list_item && motion_node)
        {
            check_list_item->setOn(motion_node->layer_enabled);
        }
    }
}

JahLayer* GLWorld::createALayer(LAYER_TYPE, JahLayer*)
{
    return (JahLayer*)NULL;
}

void GLWorld::slotSetShowLights()
{
    Globals::setShowLights( getShowLights() );
    updateGL();
}


void GLWorld::slotLightColorAmbient(QColor )
{
}

void GLWorld::slotLightColorDiffuse(QColor )
{
}

void GLWorld::slotLightColorSpecular(QColor )
{
}
