
#include "glli.h"

#ifndef PandaWave_RESOURCES
#include "RevengeResources.h"
#endif

#include "RevengeApp.h"
#include <XMessages.h>
#include <assert.h>
#include <XPopup.h>
#include <XWindow.h>
#include "TBitmapView.h"
#include <math.h>

// ==============================  BYTE SWAPPING DATA  ========================================
static byte_swap_code glli_definition_byte_swapping_data[]=
{
	_begin_bs_array, 1,
	
	//	struct rgb_color ambient_color;
	_2byte, _2byte, _2byte, _2byte,
	
	//	struct rgb_color sky_color;
	_2byte, _2byte, _2byte, _2byte,
	
	//	struct rgb_color key_color;
	_2byte, _2byte, _2byte, _2byte,
	
	//	struct rgb_color fill_color;
	_2byte, _2byte, _2byte, _2byte,
	
	//	fixed_vector3d key_incident_direction;
	_4byte, _4byte, _4byte,
	
	//	fixed_vector3d key_incident_direction;
	_4byte, _4byte, _4byte,
	
	_end_bs_array
};


// ==============================  EDIT WINDOW  ========================================
void edit_glli( tag_entry* e )
{
	TglliEditForm* form = new TglliEditForm( e );
	form->AttachWindow( 1031 );
}


static glli_definition default_glli =
{
	{ 0x4000, 0x4000, 0x4000, 0 },
	{ 0x2000, 0x2000, 0x4000, 0 },
	{ 0x9fff, 0x9fff, 0x5fff, 0 },
	{ 0x4000, 0x3000, 0x2000, 0 },
	
	{ FLOAT_TO_FIXED(0.3), FLOAT_TO_FIXED(0.1), FLOAT_TO_FIXED(-0.4) },
	{ FLOAT_TO_FIXED(-1.0f), FLOAT_TO_FIXED(1.0f), FLOAT_TO_FIXED(-0.2f) }
};


void defaultnew_glli( tag_entry* e )
{
	glli_definition def;
	byte_swap_move_be( "glli", &def, &default_glli, sizeof(glli_definition), 1, glli_definition_byte_swapping_data);
	set_entry_data( e, &def, sizeof(def), false );
}


void dependency_glli( tag_entry *e )
{
#if 0 // no dependencies
	glli_definition def;
	read_glli_definition( &def, e );
#endif
}


// ==============================  READ TAG DATA  ========================================
bool read_glli_definition( glli_definition* def, tag_entry* e )
{
	return load_tag_data_into_struct( "glli", e, def, sizeof(glli_definition), 1, glli_definition_byte_swapping_data);
}


// ==============================  SAVE TAG DATA  ========================================
bool save_glli_definition( glli_definition* def, tag_entry* e )
{
	return save_tag_data_from_struct( "glli", e, def, sizeof(glli_definition), 1, glli_definition_byte_swapping_data);
}


// ==============================  READ TAG DATA (WITH ID) ========================================
bool read_glli_definition( glli_definition* def, tag id )
{
	tag_entry* e;
	
	assert( def );
	
	e = get_entry( 'glli', id );
	if( 0 == e ) {
		return FALSE;
	}
	
	return read_glli_definition( def, e );	
}


// ==============================  SAVE TAG DATA (WITH ID) ========================================
bool save_glli_definition( glli_definition* def, tag id )
{
	tag_entry* e;
	
	assert( def );
	
	e = get_entry( 'glli', id );
	if( 0 == e ) {
		return FALSE;
	}

	return save_glli_definition( def, e );
}


// ==============================  DISPATCH  ========================================
BEGINDISPATCH(TglliEditForm,TTagEditForm)
	DISPATCHTABLE(KXGControlClick,TglliEditForm::DoControlClick)
	DISPATCHTABLE(KXGKeyClick,TglliEditForm::DoKeyClick)
ENDDISPATCH


TglliEditForm::TglliEditForm( struct tag_entry *e ) : TTagEditForm( e )
{
}

// ==============================  INITIALIZE FORM =======================================
void TglliEditForm::DoFormInitialize()
{
	TTagEditForm::DoFormInitialize();

}


// ==============================  INPUT HANDLING  ========================================
long TglliEditForm::DoControlClick( long arg, void *ptr )
{
#ifdef __MWERKS__
	#pragma unused(ptr)
#endif

	return -1;
}

		
long TglliEditForm::DoKeyClick( long arg, void * )
{
	if (arg >= 2 && arg <= 22) {
		GetValues();
		UpdateColors();
		return 0;
	}
	return -1;
}

		
// ========================================  SAVE TO TAG  ==================================================
void TglliEditForm::CommitToTag()
{
	GetValues();
	save_glli_definition( &def, fEntry );
}


// ========================================  RELOAD TAG  ==================================================
void TglliEditForm::ReloadTag()
{
	read_glli_definition( &def, fEntry );
	SetValues();
}


// ========================================  TAG NEEDS UPDATING  ==================================================
bool TglliEditForm::NeedCommit()
{
	GetValues();
	return tag_data_needs_update( "glli", fEntry, &def, sizeof(glli_definition), 1, glli_definition_byte_swapping_data);
}



// ========================================  SET INTERFACE VALUES  ==================================================
void TglliEditForm::SetValues()
{
	SetInt( 2, def.ambient_color.red >> 8 );
	SetInt( 3, def.ambient_color.green >> 8 );
	SetInt( 4, def.ambient_color.blue >> 8 );
	
	SetInt( 6, def.sky_color.red >> 8 );
	SetInt( 7, def.sky_color.green >> 8 );
	SetInt( 8, def.sky_color.blue >> 8 );
	
	SetInt( 10, def.key_color.red >> 8 );
	SetInt( 11, def.key_color.green >> 8 );
	SetInt( 12, def.key_color.blue >> 8 );
	
	SetInt( 14, def.fill_color.red >> 8 );
	SetInt( 15, def.fill_color.green >> 8 );
	SetInt( 16, def.fill_color.blue >> 8 );
	
	SetFixed( 17, def.key_incident_direction.i );
	SetFixed( 18, def.key_incident_direction.j );
	SetFixed( 19, def.key_incident_direction.k );
	
	SetFixed( 20, def.fill_incident_direction.i );
	SetFixed( 21, def.fill_incident_direction.j );
	SetFixed( 22, def.fill_incident_direction.k );
	
	UpdateColors();
}


// ========================================  GET INTERFACE VALUES  ==================================================
void TglliEditForm::GetValues()
{
	def.ambient_color.red = GetInt( 2 ) * 0x101;
	def.ambient_color.green = GetInt( 3 ) * 0x101;
	def.ambient_color.blue = GetInt( 4 ) * 0x101;
	
	def.sky_color.red = GetInt( 6 ) * 0x101;
	def.sky_color.green = GetInt( 7 ) * 0x101;
	def.sky_color.blue = GetInt( 8 ) * 0x101;
	
	def.key_color.red = GetInt( 10 ) * 0x101;
	def.key_color.green = GetInt( 11 ) * 0x101;
	def.key_color.blue = GetInt( 12 ) * 0x101;
	
	def.fill_color.red = GetInt( 14 ) * 0x101;
	def.fill_color.green = GetInt( 15 ) * 0x101;
	def.fill_color.blue = GetInt( 16 ) * 0x101;
	
	def.key_incident_direction.i = GetFixed( 17 );
	def.key_incident_direction.j = GetFixed( 18 );
	def.key_incident_direction.k = GetFixed( 19 );
	
	def.fill_incident_direction.i = GetFixed( 20 );
	def.fill_incident_direction.j = GetFixed( 21 );
	def.fill_incident_direction.k = GetFixed( 22 );
}

void TglliEditForm::BuildBitmap( int view_num,
								 const float i[3],
								 const float j[3],
								 const float k[3] )
{
	TBitmapView *bmp = dynamic_cast<TBitmapView *>(GetWindow()->FindViewByID( view_num ));
	if (!bmp) return;
	XRect r = bmp->GetContentRect();
	XGDraw draw(GetWindow(),true);
	Color back = draw.ColorFromPalette( KXGColorBtnFace );
	float lx = FIXED_TO_FLOAT( def.key_incident_direction.i );
	float ly = FIXED_TO_FLOAT( def.key_incident_direction.j );
	float lz = FIXED_TO_FLOAT( def.key_incident_direction.k );
	float s = 1.0/sqrt( lx*lx + ly*ly + lz*lz );
	lx *= s;
	ly *= s;
	lz *= s;
	float flx = FIXED_TO_FLOAT( def.fill_incident_direction.i );
	float fly = FIXED_TO_FLOAT( def.fill_incident_direction.j );
	float flz = FIXED_TO_FLOAT( def.fill_incident_direction.k );
	float fs = 1.0/sqrt( flx*flx + fly*fly + flz*flz );
	flx *= fs;
	fly *= fs;
	flz *= fs;
	void *buf = malloc( (r.right - r.left) * (r.bottom - r.top) * 3 );
	unsigned char *out = (unsigned char *)buf;
	for (int y = 0; y < r.bottom - r.top; ++y) {
		float fy = -1.0f + y * (2.0f / (r.bottom - r.top));
		for (int x = 0; x < r.right - r.left; ++x) {
			float fx = -1.0f + x * (2.0f / (r.right - r.left));
			float fz = 1.0f - (fx*fx+fy*fy);
			if (fz > 0.0f) {
				float nx = fx * i[0] + fy * j[0] + fz * k[0];
				float ny = fx * i[1] + fy * j[1] + fz * k[1];
				float nz = fx * i[2] + fy * j[2] + fz * k[2];
				float sky = 0.5f - 0.5f * nz;
				float key = lx * nx + ly * ny + lz * nz;
				float fill = flx * nx + fly * ny + flz * nz;
				if (key < 0.0f) key = 0.0f;
				if (fill < 0.0f) fill = 0.0f;
				int r = def.ambient_color.red   + (int)(sky * def.sky_color.red)   + (int)(key * def.key_color.red)   + (int)(fill * def.fill_color.red);
				int g = def.ambient_color.green + (int)(sky * def.sky_color.green) + (int)(key * def.key_color.green) + (int)(fill * def.fill_color.green);
				int b = def.ambient_color.blue  + (int)(sky * def.sky_color.blue)  + (int)(key * def.key_color.blue)  + (int)(fill * def.fill_color.blue);
				r |= -(r >> 16);
				g |= -(g >> 16);
				b |= -(b >> 16);
				out[0] = r >> 8;
				out[1] = g >> 8;
				out[2] = b >> 8;
			} else {
				out[0] = GetRValue(back);
				out[1] = GetGValue(back);
				out[2] = GetBValue(back);
			}
			out += 3;
		}
	}
	
	bmp->SetBitmapRGB( buf, r.right-r.left, r.bottom - r.top );
	free( buf );
	
	bmp->InvalView();
}

void TglliEditForm::UpdateColors()
{
	SetColor( 1, def.ambient_color );
	SetColor( 5, def.sky_color );
	SetColor( 9, def.key_color );
	SetColor( 13, def.fill_color );
	
	static const float pos_x[3] = { 1, 0, 0 };
	static const float pos_y[3] = { 0, 1, 0 };
	static const float pos_z[3] = { 0, 0, 1 };
	static const float neg_x[3] = { -1, 0, 0 };
	static const float neg_y[3] = { 0, -1, 0 };
	static const float neg_z[3] = { 0, 0, -1 };
	
	BuildBitmap( 23, pos_x, neg_y, neg_z );
	float lx = FIXED_TO_FLOAT( def.key_incident_direction.i );
	float ly = FIXED_TO_FLOAT( def.key_incident_direction.j );
	float lz = FIXED_TO_FLOAT( def.key_incident_direction.k );
	if (lx*lx+ly*ly < 0.001f * lz*lz) {
		BuildBitmap( 24, pos_x, pos_z, pos_y );
		BuildBitmap( 25, neg_y, pos_z, pos_x );
		BuildBitmap( 26, neg_x, pos_z, neg_y );
	} else {
		lz = 1.0f / sqrt(lx*lx + ly*ly);
		lx *= lz;
		ly *= lz;
		
		float front[3] = { lx, ly, 0 };
		float back[3] = { -lx, -ly, 0 };
		float left[3] = { ly, -lx, 0 };
		float right[3] = { -ly, lx, 0 };
		BuildBitmap( 24, left, pos_z, front );
		BuildBitmap( 25, front, pos_z, right );
		BuildBitmap( 26, right, pos_z, back );
		
	}
}

