#include "../headers/oglheaders.h"
#include "../headers/GeLight.h"
#include "../headers/PhysXWrapper.h"
#include <stdio.h>

int GeLight::nextIndex = GL_LIGHT0;

GeLight :: GeLight(void) {
	if (nextIndex < (GL_LIGHT0+GL_MAX_LIGHTS)) {
		index = nextIndex;
		nextIndex ++;
        valid = true;
	}
    else {
		index = -1;
        valid = false;
    }

    setDirectional(false);
    visible = false;
	active = false;
	setAmbient(0.0f, 0.0f, 0.0f);

	ac = 1.0;
	al = 0.0;
	aq = 0.0;	

	NxActorDesc actorDesc;
	NxSphereShapeDesc sphereDesc;

	sphereDesc.group = SHAPE_LIGHT_SPHERE;
	sphereDesc.radius = (NxReal)getRadius();
	sphereDesc.localPose.t = NxVec3(0, 0, 0);
	sphereDesc.mass = 0;
	sphereDesc.shapeFlags |= /*NX_SF_DISABLE_RESPONSE |*/ NX_SF_DISABLE_RAYCASTING;

    actorDesc.shapes.pushBack(&sphereDesc);

    actorDesc.body		= NULL;
    actorDesc.density 	= 0.0f;
    actorDesc.globalPose.t 	= NxVec3(0,0,0);
    actorDesc.group = TYPENO_LIGHT;
	actorDesc.userData = this;

	actor = physx.scene->createActor(actorDesc);
	sphereShape = actor->getShapes()[0]->isSphere();


}

GeLight :: ~GeLight(void) {


}
void GeLight :: render(void) {
    if (valid) {
		float* fpos = pos;
        glLightfv(index, GL_POSITION, fpos);
		delete fpos;
    }
}

void GeLight :: update(void) {
}

void GeLight :: setGlobalAmbient(MColor3* global_ambient) {
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float*)&global_ambient);
}

void GeLight :: setGlobalAmbient(float r, float g, float b) {
    GLfloat global_ambient[] = { r, g, b };
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
}

void GeLight :: setDirectional(bool directional) {
    if (directional) {
        // w == 0 => directional light (see opengl documentation)
        this->pos.w = 0;
    }
    else {
        // positional light
        this->pos.w = 1;
    }
}

void GeLight :: setPosition(float x, float y, float z) {
    this->pos.x = x;
    this->pos.y = y;
    this->pos.z = z;
	actor->setGlobalPosition(NxVec3(x, y, z));
}

void GeLight :: setAttenuation(GLenum type, float value) {
	glLightf(index, type, value);
	switch(type) {
		case GL_CONSTANT_ATTENUATION:
			ac = value;
			break;
		case GL_LINEAR_ATTENUATION:
			al = value;
			break;
		case GL_QUADRATIC_ATTENUATION:
			aq = value;
			break;
		default:
			break;
	}
	sphereShape->setRadius(getRadius());
}

void GeLight :: setAmbient(MColor3* ambient) {
    if (valid) {
        glLightfv(index, GL_AMBIENT, (float*)&ambient);
    }
}

void GeLight :: setAmbient(float r, float g, float b) {
    if (valid) {
        GLfloat ambient[] = { r, g, b };
        glLightfv(index, GL_AMBIENT, ambient);
    }
}

void GeLight :: setDiffuse(MColor4* diffuse) {
    if (valid) {
        glLightfv(index, GL_DIFFUSE, (float*)&diffuse);
    }
}

void GeLight :: setDiffuse(float r, float g, float b, float a) {
    if (valid) {
        GLfloat diffuse[] = { r, g, b, a };
        glLightfv(index, GL_DIFFUSE, diffuse);
    }
}

void GeLight :: setSpecular(MColor4* specular) {
    if (valid) {
        glLightfv(index, GL_SPECULAR, (float*)&specular);
    }
}

void GeLight :: setSpecular(float r, float g, float b, float a) {
    if (valid) {
        GLfloat specular[] = { r, g, b, a };
        glLightfv(index, GL_SPECULAR, specular);
    }
}

int GeLight :: getIndex() {
	return index-GL_LIGHT0;
}

float GeLight :: getRadius() {
		
	double res = -al/(2*aq);
	res += sqrt( al*al/(4*aq*aq) + 20*ac/aq);
	
	return res;
}

void GeLight :: show(void) {
    if (valid && active) {
        glEnable(index);
        visible = true;
    }
}

void GeLight :: hide(void) {
    glDisable(index);
    visible = false;
}

bool GeLight :: isVisible(void) {
    return visible;
}

void GeLight :: activate(void) {
	active = true;
	//show();
}

void GeLight :: deactivate(void) {
	active = false;
	//hide();
}

bool GeLight :: isActive(void) {
	return active;
}