//
// FlareImagePlugin.cpp
//
// Flare Image Plugin
//
// Copyright (c) 2000 - 2002 memon/moppi productions
//

//#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <commctrl.h>
#include <gl\gl.h>
#include <gl\glu.h>

// Demopaja headers
#include "DemopajaVersion.h"
#include "PajaTypes.h"
#include "ClassDescC.h"
#include "ImportableI.h"
#include "OpenGLDeviceC.h"
#include "OpenGLViewportC.h"
#include "FlareImagePlugin.h"
#include "FileIO.h"
#include "AutoGizmoC.h"
#include "ImportableImageI.h"
#include "FlareImageDialog.h"
#include "FlareRendererC.h"

using namespace PajaTypes;
using namespace PluginClass;
using namespace PajaSystem;
using namespace Edit;
using namespace Composition;
using namespace Import;
using namespace FileIO;

using namespace FlareImagePlugin;


//////////////////////////////////////////////////////////////////////////
//
//  Flare importer class descriptor.
//

FlareImageImportDescC::FlareImageImportDescC()
{
	// empty
}

FlareImageImportDescC::~FlareImageImportDescC()
{
	// empty
}

void*
FlareImageImportDescC::create()
{
	return FlareImageImportC::create_new();
}

int32
FlareImageImportDescC::get_classtype() const
{
	return CLASS_TYPE_FILEPROCEDURAL;
}

SuperClassIdC
FlareImageImportDescC::get_super_class_id() const
{
	return SUPERCLASS_IMAGE;
}

ClassIdC
FlareImageImportDescC::get_class_id() const
{
	return CLASS_FLAREIMAGE_IMPORT;
}

const char*
FlareImageImportDescC::get_name() const
{
	return "Flare Image";
}

const char*
FlareImageImportDescC::get_desc() const
{
	return "Procedural Flare Image";
}

const char*
FlareImageImportDescC::get_author_name() const
{
	return "Mikko \"memon\" Mononen";
}

const char*
FlareImageImportDescC::get_copyright_message() const
{
	return "Copyright (c) 2000-2002 Moppi Productions";
}

const char*
FlareImageImportDescC::get_url() const
{
	return "http://moppi.inside.org/demopaja/";
}

const char*
FlareImageImportDescC::get_help_filename() const
{
	return "res://Flarehelp.html";
}

uint32
FlareImageImportDescC::get_required_device_driver_count() const
{
	return 1;
}

const ClassIdC&
FlareImageImportDescC::get_required_device_driver( uint32 ui32Idx )
{
	return PajaSystem::CLASS_OPENGL_DEVICEDRIVER;
}

uint32
FlareImageImportDescC::get_ext_count() const
{
	return 0;
}

const char*
FlareImageImportDescC::get_ext( uint32 ui32Index ) const
{
	return 0;
}



//////////////////////////////////////////////////////////////////////////
//
// Global descriptors, which will be returned to the Demopaja.
//

FlareImageImportDescC	g_rFlareImportDesc;

#ifndef PAJAPLAYER

//////////////////////////////////////////////////////////////////////////
//
// The DLL
//


HINSTANCE	g_hInstance = 0;
bool		g_bControlsInit = false;

BOOL APIENTRY
DllMain( HANDLE hModule, DWORD ulReasonForCall, LPVOID lpReserved )
{
    switch( ulReasonForCall )
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:

			if( !g_bControlsInit ) {
				g_hInstance = (HINSTANCE)hModule;
				// Initialise common controls
				INITCOMMONCONTROLSEX	rInitCtrls;
				ZeroMemory( &rInitCtrls, sizeof( rInitCtrls ) );
				rInitCtrls.dwSize = sizeof( rInitCtrls );
				rInitCtrls.dwICC = ICC_WIN95_CLASSES;
				InitCommonControlsEx( &rInitCtrls );
				g_bControlsInit = true;
			}
			break;
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}


//
// Returns number of classes inside this plugin DLL.
//

__declspec( dllexport )
int32
get_classdesc_count()
{
	return 1;
}


//
// Returns class descriptors of the plugin classes.
//

__declspec( dllexport )
ClassDescC*
get_classdesc( int32 i )
{
	if( i == 0 )
		return &g_rFlareImportDesc;
	return 0;
}


//
// Returns the API version this DLL was made with.
//

__declspec( dllexport )
int32
get_api_version()
{
	return DEMOPAJA_VERSION;
}

//
// Returns the DLL name.
//

__declspec( dllexport )
char*
get_dll_name()
{
	return "FlareImagePlugin.dll - Flare Image Plugin (c)2001 memon/moppi productions";
}

#endif


//////////////////////////////////////////////////////////////////////////
//
// Flare image Importer class implementation.
//

FlareImageImportC::FlareImageImportC() :
	m_ui32TextureId( 0 ),
	m_pData( 0 ),
	m_ui32Width( 0 ),
	m_ui32Height( 0 ),
	m_rGlowColor( 0.2f, 0.1f, 0.2f ),
	m_rSpotColor( 0.9f, 0.92f, 1.0f ),
	m_rSpikesColor( 0.9f, 0.92f, 1.0f ),
	m_rBGColor( 0, 0, 0, 0 )
{
	m_rTexBounds[0] = Vector2C( 0, 0 );
	m_rTexBounds[1] = Vector2C( 1, 1 );
}

FlareImageImportC::FlareImageImportC( EditableI* pOriginal ) :
	ImportableImageI( pOriginal ),
	m_ui32TextureId( 0 ),
	m_pData( 0 ),
	m_ui32Width( 0 ),
	m_ui32Height( 0 ),
	m_rGlowColor( 0.2f, 0.1f, 0.2f ),
	m_rSpotColor( 0.9f, 0.92f, 1.0f ),
	m_rSpikesColor( 0.9f, 0.92f, 1.0f ),
	m_rBGColor( 0, 0, 0, 0 )
{
	m_rTexBounds[0] = Vector2C( 0, 0 );
	m_rTexBounds[1] = Vector2C( 1, 1 );
}

FlareImageImportC::~FlareImageImportC()
{
	// Return if this is a clone.
	if( get_original() )
		return;

	// Delete creted texture.
	if( m_ui32TextureId )
		glDeleteTextures( 1, &m_ui32TextureId );

	delete [] m_pData;
}

FlareImageImportC*
FlareImageImportC::create_new()
{
	return new FlareImageImportC;
}

DataBlockI*
FlareImageImportC::create()
{
	return new FlareImageImportC;
}

DataBlockI*
FlareImageImportC::create( EditableI* pOriginal )
{
	return new FlareImageImportC( pOriginal );
}

void
FlareImageImportC::copy( EditableI* pEditable )
{
	FlareImageImportC*	pFile = (FlareImageImportC*)pEditable;

	m_sFileName = pFile->m_sFileName;

	m_ui32Width = pFile->m_ui32Width;
	m_ui32Height = pFile->m_ui32Height;
	m_rGlowColor = pFile->m_rGlowColor;
	m_rSpotColor = pFile->m_rSpotColor;
	m_rSpikesColor = pFile->m_rSpikesColor;
	m_rBGColor = pFile->m_rBGColor;

	// invalidate data
	invalidate_data();
}

void
FlareImageImportC::restore( EditableI* pEditable )
{
	FlareImageImportC*	pFile = (FlareImageImportC*)pEditable;

	m_ui32TextureId = pFile->m_ui32TextureId;
	m_sFileName = pFile->m_sFileName;

	m_ui32Width = pFile->m_ui32Width;
	m_ui32Height = pFile->m_ui32Height;
	m_rGlowColor = pFile->m_rGlowColor;
	m_rSpotColor = pFile->m_rSpotColor;
	m_rSpikesColor = pFile->m_rSpikesColor;
	m_rBGColor = pFile->m_rBGColor;

	// invalidate data
	if( !get_original() )
		invalidate_data();
}

const char*
FlareImageImportC::get_filename()
{
	return m_sFileName.c_str();
}

void
FlareImageImportC::set_filename( const char* szName )
{
	m_sFileName = szName;
}

bool
FlareImageImportC::create_file( DemoInterfaceC* pInterface )
{
	// Store interface pointer
	m_pDemoInterface = pInterface;

	m_sFileName = "Flare Image";
	return true;
}


bool
FlareImageImportC::prompt_properties()
{
	FlareDialogC	rDlg( m_pDemoInterface );

	rDlg.set_name( m_sFileName.c_str() );
	rDlg.set_width( m_ui32Width );
	rDlg.set_height( m_ui32Height );
	rDlg.set_bg_color( m_rBGColor );
	rDlg.set_glow_color( m_rGlowColor );
	rDlg.set_spot_color( m_rSpotColor );
	rDlg.set_spikes_color( m_rSpikesColor );

	if( rDlg.do_modal() ) {

		m_sFileName = rDlg.get_name();
		m_ui32Width = rDlg.get_width();
		m_ui32Height = rDlg.get_height();
		m_rBGColor = rDlg.get_bg_color();
		m_rGlowColor = rDlg.get_glow_color();
		m_rSpotColor = rDlg.get_spot_color();
		m_rSpikesColor = rDlg.get_spikes_color();

		invalidate_data();
		return true;
	}

	return false;
}

bool
FlareImageImportC::has_properties()
{
	return true;
}


void
FlareImageImportC::initialize( uint32 ui32Reason, DemoInterfaceC* pInterface )
{
	ImportableI::initialize( ui32Reason, pInterface );

	DeviceContextC* pContext = m_pDemoInterface->get_device_context();
	TimeContextC* pTimeContext = m_pDemoInterface->get_time_context();

	OpenGLDeviceC*	pDevice = (OpenGLDeviceC*)pContext->query_interface( CLASS_OPENGL_DEVICEDRIVER );
	if( !pDevice )
		return;

	if( ui32Reason == INIT_DEVICE_CHANGED ) {

		if( pDevice->get_state() == DEVICE_STATE_SHUTTINGDOWN ) {
			// Delete textures
			glDeleteTextures( 1, &m_ui32TextureId );
			m_ui32TextureId = 0;
		}

	}
	else if( ui32Reason == INIT_INITIAL_UPDATE ) {
		if( !m_pData ) {
			m_pData = new uint8[m_ui32Width * m_ui32Height * 4];
			FlareRendererC::render_flare( m_pData, m_ui32Width, m_ui32Height, m_rBGColor, m_rGlowColor, m_rSpotColor, m_rSpikesColor, false );
		}
	}
}

ClassIdC
FlareImageImportC::get_class_id()
{
	return CLASS_FLAREIMAGE_IMPORT;
}

const char*
FlareImageImportC::get_class_name()
{
	return "SDK Flare Image";
}

float32
FlareImageImportC::get_width()
{
	return (float32)m_ui32Width;
}

float32
FlareImageImportC::get_height()
{
	return (float32)m_ui32Height;
}

int32
FlareImageImportC::get_data_width()
{
	return m_ui32Width;
}

int32
FlareImageImportC::get_data_height()
{
	return m_ui32Height;
}

int32
FlareImageImportC::get_data_pitch()
{
	return m_ui32Width;
}

BBox2C&
FlareImageImportC::get_tex_coord_bounds()
{
	return m_rTexBounds;
}

int32
FlareImageImportC::get_data_bpp()
{
	return 32;
}

uint8*
FlareImageImportC::get_data()
{
	return m_pData;
}


void
FlareImageImportC::bind_texture( DeviceInterfaceI* pInterface, PajaTypes::uint32 ui32Stage, uint32 ui32Properties )
{
	if( !pInterface || pInterface->get_class_id() != CLASS_OPENGL_DEVICEDRIVER )
		return;

	if( !m_ui32TextureId || !m_pData ) {

		if( !m_pData ) {
			m_pData = new uint8[m_ui32Width * m_ui32Height * 4];
			FlareRendererC::render_flare( m_pData, m_ui32Width, m_ui32Height, m_rBGColor, m_rGlowColor, m_rSpotColor, m_rSpikesColor, false );
		}

		glGenTextures( 1, &m_ui32TextureId );

		glBindTexture( GL_TEXTURE_2D, m_ui32TextureId );
		glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

		glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, m_ui32Width, m_ui32Height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, m_pData );
	}
	else {
		glBindTexture( GL_TEXTURE_2D, m_ui32TextureId );
		glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
	}

	if( ui32Properties & IMAGE_LINEAR ) {
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	}
	else {
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
	}

	if( ui32Properties & IMAGE_CLAMP ) {
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
	}
	else {
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
	}
}

const char*
FlareImageImportC::get_info()
{
	static char	szInfo[256];
	_snprintf( szInfo, 255, "%d x %d", m_ui32Width, m_ui32Height );
	return szInfo;
}

ClassIdC
FlareImageImportC::get_default_effect()
{
	return CLASS_IMAGE_EFFECT;
}

void
FlareImageImportC::eval_state( int32 i32Time )
{
	// empty
}

bool
FlareImageImportC::equals( ImportableI* pImp )
{
	if( pImp->get_class_id() == get_class_id() ) {
		FlareImageImportC*	pFlareImp = (FlareImageImportC*)pImp;

		if( m_ui32Width == pFlareImp->m_ui32Width &&
			m_ui32Height == pFlareImp->m_ui32Height &&
			m_rGlowColor == pFlareImp->m_rGlowColor &&
			m_rBGColor == pFlareImp->m_rBGColor &&
			m_rSpotColor == pFlareImp->m_rSpotColor &&
			m_rSpikesColor == pFlareImp->m_rSpikesColor )
			return true;
	}
	return false;
}

int32
FlareImageImportC::get_duration()
{
	return 0;
}

float32
FlareImageImportC::get_start_label()
{
	return 0;
}

float32
FlareImageImportC::get_end_label()
{
	return 0;
}

void
FlareImageImportC::invalidate_data()
{
	delete [] m_pData;
	m_pData = 0;
}


enum FlareImageImportChunksE {
	CHUNK_FLAREIMAGEIMPORT_BASE =	0x1000,
	CHUNK_FLAREIMAGEIMPORT_DATA =	0x2000,
};

const uint32	FLAREIMAGEIMPORT_VERSION_1 = 1;
const uint32	FLAREIMAGEIMPORT_VERSION = 2;


uint32
FlareImageImportC::save( SaveC* pSave )
{
	uint32		ui32Error = IO_OK;
	std::string	sStr;
	uint8		ui8Temp4[4];

	// file base
	pSave->begin_chunk( CHUNK_FLAREIMAGEIMPORT_BASE, FLAREIMAGEIMPORT_VERSION );
		sStr = m_sFileName;
		if( sStr.size() > 255 )
			sStr.resize( 255 );
		ui32Error = pSave->write_str( sStr.c_str() );
	pSave->end_chunk();

	// file data
	pSave->begin_chunk( CHUNK_FLAREIMAGEIMPORT_DATA, FLAREIMAGEIMPORT_VERSION );
		// Width
		ui32Error = pSave->write( &m_ui32Width, sizeof( m_ui32Width ) );
		// Height
		ui32Error = pSave->write( &m_ui32Height, sizeof( m_ui32Height ) );
		// Glow color
		ui8Temp4[0] = (uint8)(m_rGlowColor[0] * 255.0f);
		ui8Temp4[1] = (uint8)(m_rGlowColor[1] * 255.0f);
		ui8Temp4[2] = (uint8)(m_rGlowColor[2] * 255.0f);
		ui8Temp4[3] = (uint8)(m_rGlowColor[3] * 255.0f);
		ui32Error = pSave->write( ui8Temp4, sizeof( ui8Temp4 ) );
		// Spot color
		ui8Temp4[0] = (uint8)(m_rSpotColor[0] * 255.0f);
		ui8Temp4[1] = (uint8)(m_rSpotColor[1] * 255.0f);
		ui8Temp4[2] = (uint8)(m_rSpotColor[2] * 255.0f);
		ui8Temp4[3] = (uint8)(m_rSpotColor[3] * 255.0f);
		ui32Error = pSave->write( ui8Temp4, sizeof( ui8Temp4 ) );
		// Spikes color
		ui8Temp4[0] = (uint8)(m_rSpikesColor[0] * 255.0f);
		ui8Temp4[1] = (uint8)(m_rSpikesColor[1] * 255.0f);
		ui8Temp4[2] = (uint8)(m_rSpikesColor[2] * 255.0f);
		ui8Temp4[3] = (uint8)(m_rSpikesColor[3] * 255.0f);
		ui32Error = pSave->write( ui8Temp4, sizeof( ui8Temp4 ) );
		// BG color
		ui8Temp4[0] = (uint8)(m_rBGColor[0] * 255.0f);
		ui8Temp4[1] = (uint8)(m_rBGColor[1] * 255.0f);
		ui8Temp4[2] = (uint8)(m_rBGColor[2] * 255.0f);
		ui8Temp4[3] = (uint8)(m_rBGColor[3] * 255.0f);
		ui32Error = pSave->write( ui8Temp4, sizeof( ui8Temp4 ) );
	pSave->end_chunk();


	return ui32Error;
}

uint32
FlareImageImportC::load( LoadC* pLoad )
{
	uint32	ui32Error = IO_OK;
	char	szStr[256];
	uint8	ui8Temp4[4];

	while( (ui32Error = pLoad->open_chunk()) == IO_OK ) {

		switch( pLoad->get_chunk_id() ) {
		case CHUNK_FLAREIMAGEIMPORT_BASE:
			{
				if( pLoad->get_chunk_version() <= FLAREIMAGEIMPORT_VERSION ) {
					ui32Error = pLoad->read_str( szStr );
					m_sFileName = szStr;
				}
			}
			break;

		case CHUNK_FLAREIMAGEIMPORT_DATA:
			{
				if( pLoad->get_chunk_version() <= FLAREIMAGEIMPORT_VERSION ) {

					// Width
					ui32Error = pLoad->read( &m_ui32Width, sizeof( m_ui32Width ) );
					// Height
					ui32Error = pLoad->read( &m_ui32Height, sizeof( m_ui32Height ) );
					// Glow color
					ui32Error = pLoad->read( ui8Temp4, sizeof( ui8Temp4 ) );
					m_rGlowColor.convert_from_uint8( ui8Temp4[0], ui8Temp4[1], ui8Temp4[2], ui8Temp4[3] );
					// Spot color
					ui32Error = pLoad->read( ui8Temp4, sizeof( ui8Temp4 ) );
					m_rSpotColor.convert_from_uint8( ui8Temp4[0], ui8Temp4[1], ui8Temp4[2], ui8Temp4[3] );
					// Spikes color
					ui32Error = pLoad->read( ui8Temp4, sizeof( ui8Temp4 ) );
					m_rSpikesColor.convert_from_uint8( ui8Temp4[0], ui8Temp4[1], ui8Temp4[2], ui8Temp4[3] );

					if( pLoad->get_chunk_version() > FLAREIMAGEIMPORT_VERSION_1 ) {
						// BG color
						ui32Error = pLoad->read( ui8Temp4, sizeof( ui8Temp4 ) );
						m_rBGColor.convert_from_uint8( ui8Temp4[0], ui8Temp4[1], ui8Temp4[2], ui8Temp4[3] );
					}
				}
			}
			break;

		default:
			assert( 0 );
		}

		pLoad->close_chunk();

		if( ui32Error != IO_OK && ui32Error != IO_END ) {
			return ui32Error;
		}
	}

	return ui32Error;
}


