#include "main.h"
#include "state.h"
#include "lua_core.h"
#include "lrlgl.h"

/*
## RLGL - Matrix operations
*/

/*
> success = RL.rlMatrixMode( int mode )

Choose the current matrix to be transformed

- Failure return false
- Success return true
*/
int lrlglMatrixMode( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlMatrixMode( int mode )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlMatrixMode( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlPushMatrix()

Push the current matrix to stack
*/
int lrlglPushMatrix( lua_State *L ) {
	rlPushMatrix();

	return 0;
}

/*
> RL.rlPopMatrix()

Pop latest inserted matrix from stack
*/
int lrlglPopMatrix( lua_State *L ) {
	rlPopMatrix();

	return 0;
}

/*
> RL.rlLoadIdentity()

Reset current matrix to identity matrix
*/
int lrlglLoadIdentity( lua_State *L ) {
	rlLoadIdentity();

	return 0;
}

/*
> success = RL.rlTranslatef( Vector3 translation )

Multiply the current matrix by a translation matrix

- Failure return false
- Success return true
*/
int lrlglTranslatef( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlTranslatef( Vector3 translation )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector3 translation = uluaGetVector3Index( L, 1 );

	rlTranslatef( translation.x, translation.y, translation.z );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlRotatef( float angle, Vector3 rotation )

Multiply the current matrix by a rotation matrix

- Failure return false
- Success return true
*/
int lrlglRotatef( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_istable( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlRotatef( float angle, Vector3 rotation )" );
		lua_pushboolean( L, false );
		return 1;
	}
	float angle = lua_tonumber( L, 1 );
	Vector3 rotation = uluaGetVector3Index( L, 2 );

	rlRotatef( angle, rotation.x, rotation.y, rotation.z );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlScalef( Vector3 scale )

Multiply the current matrix by a scaling matrix

- Failure return false
- Success return true
*/
int lrlglScalef( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlScalef( Vector3 scale )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector3 scale = uluaGetVector3Index( L, 1 );

	rlScalef( scale.x, scale.y, scale.z );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlMultMatrixf( Matrix matrix )

Multiply the current matrix by another matrix

- Failure return false
- Success return true
*/
int lrlglMultMatrixf( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlMultMatrixf( Matrix matrix )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Matrix matrix = uluaGetMatrixIndex( L, 1 );
	float matf[16] = {
		matrix.m0, matrix.m4, matrix.m8, matrix.m12,
		matrix.m1, matrix.m5, matrix.m9, matrix.m13,
		matrix.m2, matrix.m6, matrix.m10, matrix.m14,
		matrix.m3, matrix.m7, matrix.m11, matrix.m15
	};
	rlMultMatrixf( matf );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlFrustum( float left, float right, float bottom, float top, float znear, float zfar )

Multiply the current matrix by a perspective matrix generated by parameters

- Failure return false
- Success return true
*/
int lrlglFrustum( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 )
	|| !lua_isnumber( L, 4 ) || !lua_isnumber( L, 5 ) || !lua_isnumber( L, 6 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlFrustum( float left, float right, float bottom, float top, float znear, float zfar )" );
		lua_pushboolean( L, false );
		return 1;
	}
	double left = lua_tonumber( L, 1 );
	double right = lua_tonumber( L, 2 );
	double bottom = lua_tonumber( L, 3 );
	double top = lua_tonumber( L, 4 );
	double znear = lua_tonumber( L, 5 );
	double zfar = lua_tonumber( L, 6 );

	rlFrustum( left, right, bottom, top, znear, zfar );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlOrtho( float left, float right, float bottom, float top, float znear, float zfar )

Multiply the current matrix by an orthographic matrix generated by parameters

- Failure return false
- Success return true
*/
int lrlglOrtho( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 )
	|| !lua_isnumber( L, 4 ) || !lua_isnumber( L, 5 ) || !lua_isnumber( L, 6 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlOrtho( float left, float right, float bottom, float top, float znear, float zfar )" );
		lua_pushboolean( L, false );
		return 1;
	}
	double left = lua_tonumber( L, 1 );
	double right = lua_tonumber( L, 2 );
	double bottom = lua_tonumber( L, 3 );
	double top = lua_tonumber( L, 4 );
	double znear = lua_tonumber( L, 5 );
	double zfar = lua_tonumber( L, 6 );

	rlOrtho( left, right, bottom, top, znear, zfar );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlViewport( Rectangle viewport )

Set the viewport area ( transformation from normalized device coordinates to window coordinates )
NOTE: We store current viewport dimensions

- Failure return false
- Success return true
*/
int lrlglViewport( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlViewport( Rectangle viewport )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Rectangle rect = uluaGetRectangleIndex( L, 1 );

	rlViewport( rect.x, rect.y, rect.width, rect.height );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Vertex level operations
*/

/*
> success = RL.rlBegin( int mode )

Initialize drawing mode ( how to organize vertex )

- Failure return false
- Success return true
*/
int lrlglBegin( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlBegin( int mode )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlBegin( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlEnd()

Finish vertex providing
*/
int lrlglEnd( lua_State *L ) {
	rlEnd();

	return 0;
}

/*
> success = RL.rlVertex2f( Vector2 position )

Define one vertex ( position )

- Failure return false
- Success return true
*/
int lrlglVertex2f( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlVertex2f( Vector2 position )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector2 position = uluaGetVector2Index( L, 1 );

	rlVertex2f( position.x, position.y );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlVertex3f( Vector3 position )

Define one vertex ( position )

- Failure return false
- Success return true
*/
int lrlglVertex3f( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlVertex3f( Vector3 position )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector3 position = uluaGetVector3Index( L, 1 );

	rlVertex3f( position.x, position.y, position.z );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlTexCoord2f( Vector2 texCoord )

Define one vertex ( texture coordinate ) - 2 float

- Failure return false
- Success return true
*/
int lrlglTexCoord2f( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlTexCoord2f( Vector2 texCoord )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector2 texCoord = uluaGetVector2Index( L, 1 );

	rlTexCoord2f( texCoord.x, texCoord.y );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlNormal3f( Vector3 normal )

Define one vertex ( normal ) - 3 float

- Failure return false
- Success return true
*/
int lrlglNormal3f( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlNormal3f( Vector3 normal )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector3 normal = uluaGetVector3Index( L, 1 );

	rlNormal3f( normal.x, normal.y, normal.z );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlColor4ub( Color color )

Define one vertex ( color ) - 4 byte

- Failure return false
- Success return true
*/
int lrlglColor4ub( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlColor4ub( Color color )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Color color = uluaGetColorIndex( L, 1 );

	rlColor4ub( color.r, color.g, color.b, color.a );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlColor3f( Vector3 color )

Define one vertex ( color ) - 3 float

- Failure return false
- Success return true
*/
int lrlglColor3f( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlColor3f( Vector3 color )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector3 color = uluaGetVector3Index( L, 1 );

	rlColor3f( color.x, color.y, color.z );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlColor4f( Vector4 color )

Define one vertex ( color ) - 4 float

- Failure return false
- Success return true
*/
int lrlglColor4f( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlColor4f( Vector4 color )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Vector4 color = uluaGetVector4Index( L, 1 );

	rlColor4f( color.x, color.y, color.z, color.w );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Vertex buffers state
*/

/*
> supported = RL.rlEnableVertexArray( int vaoId )

Enable vertex array ( VAO, if supported )

- Failure return nil
- Success return bool
*/
int lrlglEnableVertexArray( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableVertexArray( int vaoId )" );
		lua_pushnil( L );
		return 1;
	}
	lua_pushboolean( L, rlEnableVertexArray( lua_tointeger( L, 1 ) ) );

	return 1;
}

/*
> RL.rlDisableVertexArray()

Disable vertex array ( VAO, if supported )
*/
int lrlglDisableVertexArray( lua_State *L ) {
	rlDisableVertexArray();

	return 0;
}

/*
> success = RL.rlEnableVertexBuffer( int id )

Enable vertex buffer ( VBO )

- Failure return false
- Success return true
*/
int lrlglEnableVertexBuffer( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableVertexBuffer( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableVertexBuffer( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlDisableVertexBuffer()

Disable vertex buffer ( VBO )
*/
int lrlglDisableVertexBuffer( lua_State *L ) {
	rlDisableVertexBuffer();

	return 0;
}

/*
> success = RL.rlEnableVertexBufferElement( int id )

Enable vertex buffer element ( VBO element )

- Failure return false
- Success return true
*/
int lrlglEnableVertexBufferElement( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableVertexBufferElement( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableVertexBufferElement( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlDisableVertexBufferElement()

Disable vertex buffer element ( VBO element )
*/
int lrlglDisableVertexBufferElement( lua_State *L ) {
	rlDisableVertexBufferElement();

	return 0;
}

/*
> success = RL.rlEnableVertexAttribute( int index )

Enable vertex attribute index

- Failure return false
- Success return true
*/
int lrlglEnableVertexAttribute( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableVertexAttribute( int index )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableVertexAttribute( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlDisableVertexAttribute( int index )

Disable vertex attribute index

- Failure return false
- Success return true
*/
int lrlglDisableVertexAttribute( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlDisableVertexAttribute( int index )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlDisableVertexAttribute( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Textures state
*/

/*
> success = RL.rlActiveTextureSlot( int slot )

Select and active a texture slot

- Failure return false
- Success return true
*/
int lrlglActiveTextureSlot( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlActiveTextureSlot( int slot )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlActiveTextureSlot( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlEnableTexture( int id )

Enable texture

- Failure return false
- Success return true
*/
int lrlglEnableTexture( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableTexture( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableTexture( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlDisableTexture()

Disable texture
*/
int lrlglDisableTexture( lua_State *L ) {
	rlDisableTexture();

	return 0;
}

/*
> success = RL.rlEnableTextureCubemap( int id )

Enable texture cubemap

- Failure return false
- Success return true
*/
int lrlglEnableTextureCubemap( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableTextureCubemap( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableTextureCubemap( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlDisableTextureCubemap()

Disable texture cubemap
*/
int lrlglDisableTextureCubemap( lua_State *L ) {
	rlDisableTextureCubemap();

	return 0;
}

/*
> success = RL.rlTextureParameters( int id, int param, int value )

Set texture parameters ( filter, wrap )

- Failure return false
- Success return true
*/
int lrlglTextureParameters( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlTextureParameters( int id, int param, int value )" );
		lua_pushboolean( L, false );
		return 1;
	}
	unsigned int id = lua_tointeger( L, 1 );
	int param = lua_tointeger( L, 2 );
	int value = lua_tointeger( L, 3 );

	rlTextureParameters( id, param, value );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlCubemapParameters( int id, int param, int value )

Set cubemap parameters ( filter, wrap )

- Failure return false
- Success return true
*/
int lrlglCubemapParameters( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlCubemapParameters( int id, int param, int value )" );
		lua_pushboolean( L, false );
		return 1;
	}
	unsigned int id = lua_tointeger( L, 1 );
	int param = lua_tointeger( L, 2 );
	int value = lua_tointeger( L, 3 );

	rlCubemapParameters( id, param, value );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Shader state
*/

/*
> success = RL.rlEnableShader( int id )

Enable shader program

- Failure return false
- Success return true
*/
int lrlglEnableShader( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableShader( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableShader( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlDisableShader()

Disable shader program
*/
int lrlglDisableShader( lua_State *L ) {
	rlDisableShader();

	return 0;
}

/*
## RLGL - Framebuffer state
*/

/*
> success = RL.rlEnableFramebuffer( int id )

Enable render texture (fbo)

- Failure return false
- Success return true
*/
int lrlglEnableFramebuffer( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlEnableFramebuffer( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlEnableFramebuffer( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlDisableFramebuffer()

Disable render texture (fbo), return to default framebuffer
*/
int lrlglDisableFramebuffer( lua_State *L ) {
	rlDisableFramebuffer();

	return 0;
}

/*
> success = RL.rlActiveDrawBuffers( int count )

Activate multiple draw color buffers

- Failure return false
- Success return true
*/
int lrlglActiveDrawBuffers( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlActiveDrawBuffers( int count )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlActiveDrawBuffers( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - General render state
*/

/*
> RL.rlEnableColorBlend()

Enable color blending
*/
int lrlglEnableColorBlend( lua_State *L ) {
	rlEnableColorBlend();

	return 0;
}

/*
> RL.rlDisableColorBlend()

Disable color blending
*/
int lrlglDisableColorBlend( lua_State *L ) {
	rlDisableColorBlend();

	return 0;
}

/*
> RL.rlEnableDepthTest()

Enable depth test
*/
int lrlglEnableDepthTest( lua_State *L ) {
	rlEnableDepthTest();

	return 0;
}

/*
> RL.rlDisableDepthTest()

Disable depth test
*/
int lrlglDisableDepthTest( lua_State *L ) {
	rlDisableDepthTest();

	return 0;
}

/*
> RL.rlEnableDepthMask()

Enable depth write
*/
int lrlglEnableDepthMask( lua_State *L ) {
	rlEnableDepthMask();

	return 0;
}

/*
> RL.rlDisableDepthMask()

Disable depth write
*/
int lrlglDisableDepthMask( lua_State *L ) {
	rlDisableDepthMask();

	return 0;
}

/*
> RL.rlEnableBackfaceCulling()

Enable backface culling
*/
int lrlglEnableBackfaceCulling( lua_State *L ) {
	rlEnableBackfaceCulling();

	return 0;
}

/*
> RL.rlDisableBackfaceCulling()

Disable backface culling
*/
int lrlglDisableBackfaceCulling( lua_State *L ) {
	rlDisableBackfaceCulling();

	return 0;
}

/*
> success = RL.rlSetCullFace( int mode )

Set face culling mode

- Failure return false
- Success return true
*/
int lrlglSetCullFace( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetCullFace( int mode )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetCullFace( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlEnableScissorTest()

Enable scissor test
*/
int lrlglEnableScissorTest( lua_State *L ) {
	rlEnableScissorTest();

	return 0;
}

/*
> RL.rlDisableScissorTest()

Disable scissor test
*/
int lrlglDisableScissorTest( lua_State *L ) {
	rlDisableScissorTest();

	return 0;
}

/*
> success = RL.rlScissor( Rectangle area )

Scissor test

- Failure return false
- Success return true
*/
int lrlglScissor( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlScissor( Rectangle area )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Rectangle area = uluaGetRectangleIndex( L, 1 );
	
	rlScissor( area.x, area.y, area.width, area.height );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlEnableWireMode()

Enable wire mode
*/
int lrlglEnableWireMode( lua_State *L ) {
	rlEnableWireMode();

	return 0;
}

/*
> RL.rlDisableWireMode()

Disable wire mode
*/
int lrlglDisableWireMode( lua_State *L ) {
	rlDisableWireMode();

	return 0;
}

/*
> success = RL.rlSetLineWidth( float width )

Set the line drawing width

- Failure return false
- Success return true
*/
int lrlglSetLineWidth( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetLineWidth( float width )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetLineWidth( lua_tonumber( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> width = RL.rlGetLineWidth()

Get the line drawing width

- Success return float
*/
int lrlglGetLineWidth( lua_State *L ) {
	lua_pushnumber( L, rlGetLineWidth() );

	return 1;
}

/*
> RL.rlEnableSmoothLines()

Enable line aliasing
*/
int lrlglEnableSmoothLines( lua_State *L ) {
	rlEnableSmoothLines();

	return 0;
}

/*
> RL.rlDisableSmoothLines()

Disable line aliasing
*/
int lrlglDisableSmoothLines( lua_State *L ) {
	rlDisableSmoothLines();

	return 0;
}

/*
> RL.rlEnableStereoRender()

Enable stereo rendering
*/
int lrlglEnableStereoRender( lua_State *L ) {
	rlEnableStereoRender();

	return 0;
}

/*
> RL.rlDisableStereoRender()

Enable stereo rendering
*/
int lrlglDisableStereoRender( lua_State *L ) {
	rlDisableStereoRender();

	return 0;
}

/*
> enabled = RL.rlIsStereoRenderEnabled()

Check if stereo render is enabled

- Success return bool
*/
int lrlglIsStereoRenderEnabled( lua_State *L ) {
	lua_pushboolean( L, rlIsStereoRenderEnabled() );

	return 1;
}

/*
> success = RL.rlClearColor( Color color )

Clear color buffer with color

- Failure return false
- Success return true
*/
int lrlglClearColor( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlClearColor( Color color )" );
		lua_pushboolean( L, false );
		return 1;
	}
	Color color = uluaGetColorIndex( L, 1 );

	rlClearColor( color.r, color.g, color.b, color.a );
	lua_pushboolean( L, true );

	return 1;
}

/*
> RL.rlClearScreenBuffers()

Clear used screen buffers ( color and depth )
*/
int lrlglClearScreenBuffers( lua_State *L ) {
	rlClearScreenBuffers();

	return 0;
}

/*
> RL.rlCheckErrors()

Check and log OpenGL error codes
*/
int lrlglCheckErrors( lua_State *L ) {
	rlCheckErrors();

	return 0;
}

/*
> success = RL.rlSetBlendMode( int mode )

Set blending mode

- Failure return false
- Success return true
*/
int lrlglSetBlendMode( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetBlendMode( int mode )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetBlendMode( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetBlendFactors( int glSrcFactor, int glDstFactor, int glEquation )

Set blending mode factor and equation ( using OpenGL factors )

- Failure return false
- Success return true
*/
int lrlglSetBlendFactors( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetBlendFactors( int glSrcFactor, int glDstFactor, int glEquation )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int glSrcFactor = lua_tointeger( L, 1 );
	int glDstFactor = lua_tointeger( L, 2 );
	int glEquation = lua_tointeger( L, 3 );

	rlSetBlendFactors( glSrcFactor, glDstFactor, glEquation );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetBlendFactorsSeparate( int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha )

Set blending mode factors and equations separately ( using OpenGL factors )

- Failure return false
- Success return true
*/
int lrlglSetBlendFactorsSeparate( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 )
	|| !lua_isnumber( L, 4 ) || !lua_isnumber( L, 5 ) || !lua_isnumber( L, 6 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetBlendFactorsSeparate( int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int glSrcRGB = lua_tointeger( L, 1 );
	int glDstRGB = lua_tointeger( L, 2 );
	int glSrcAlpha = lua_tointeger( L, 3 );
	int glDstAlpha = lua_tointeger( L, 4 );
	int glEqRGB = lua_tointeger( L, 5 );
	int glEqAlpha = lua_tointeger( L, 6 );

	rlSetBlendFactorsSeparate( glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha );
	lua_pushboolean( L, true );

	return 1;
}


/*
## RLGL - Initialization functions
*/

/*
> version = RL.rlGetVersion()

Get current OpenGL version

- Success return int
*/
int lrlglGetVersion( lua_State *L ) {
	lua_pushinteger( L, rlGetVersion() );

	return 1;
}

/*
## RLGL - Render batch management
*/

/*
> RL.rlDrawRenderBatchActive()

Update and draw internal render batch
*/
int lrlglDrawRenderBatchActive( lua_State *L ) {
	rlDrawRenderBatchActive();

	return 0;
}

/*
> overflow = RL.rlCheckRenderBatchLimit( int vCount )

Check internal buffer overflow for a given number of vertex and force a rlRenderBatch draw call if required

- Failure return nil
- Success return bool
*/
int lrlglCheckRenderBatchLimit( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlCheckRenderBatchLimit( int vCount )" );
		lua_pushnil( L );
		return 1;
	}
	lua_pushboolean( L, rlCheckRenderBatchLimit( lua_tointeger( L, 1 ) ) );

	return 1;
}

/*
> success = RL.rlSetTexture( int id )

Set current texture for render batch and check buffers limits

- Failure return false
- Success return true
*/
int lrlglSetTexture( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetTexture( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetTexture( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Vertex buffers management
*/

/*
> vaoId = RL.rlLoadVertexArray()

Load vertex array (vao) if supported

- Success return int
*/
int lrlglLoadVertexArray( lua_State *L ) {
	lua_pushinteger( L, rlLoadVertexArray() );

	return 1;
}

/*
> vboId = RL.rlLoadVertexBuffer( Buffer buffer, bool dynamic )

Load a vertex buffer attribute

- Failure return -1
- Success return int
*/
int lrlglLoadVertexBuffer( lua_State *L ) {
	if ( !lua_isuserdata( L, 1 ) || !lua_isboolean( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlLoadVertexBuffer( Buffer buffer, bool dynamic )" );
		lua_pushinteger( L, -1 );
		return 1;
	}
	Buffer *buffer = luaL_checkudata( L, 1, "Buffer" );
	bool dynamic = lua_tointeger( L, 2 );

	lua_pushinteger( L, rlLoadVertexBuffer( buffer->data, buffer->size, dynamic ) );

	return 1;
}

/*
> vboId = RL.rlLoadVertexBufferElement( Buffer buffer, bool dynamic )

Load a new attributes element buffer

- Failure return -1
- Success return int
*/
int lrlglLoadVertexBufferElement( lua_State *L ) {
	if ( !lua_isuserdata( L, 1 ) || !lua_isboolean( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlLoadVertexBufferElement( Buffer buffer, bool dynamic )" );
		lua_pushinteger( L, -1 );
		return 1;
	}
	Buffer *buffer = luaL_checkudata( L, 1, "Buffer" );
	bool dynamic = lua_tointeger( L, 2 );

	lua_pushinteger( L, rlLoadVertexBufferElement( buffer->data, buffer->size, dynamic ) );

	return 1;
}

/*
> success = RL.rlUpdateVertexBuffer( int bufferId, Buffer buffer, int offset )

Update GPU buffer with new data

- Failure return false
- Success return true
*/
int lrlglUpdateVertexBuffer( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isuserdata( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlUpdateVertexBuffer( int bufferId, Buffer buffer, int offset )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int bufferId = lua_tointeger( L, 1 );
	Buffer *buffer = luaL_checkudata( L, 2, "Buffer" );
	int offset = lua_tointeger( L, 3 );

	rlUpdateVertexBuffer( bufferId, buffer->data, buffer->size, offset );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlUpdateVertexBufferElements( int id, Buffer buffer, int offset )

Update vertex buffer elements with new data

- Failure return false
- Success return true
*/
int lrlglUpdateVertexBufferElements( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isuserdata( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlUpdateVertexBufferElements( int id, Buffer buffer, int offset )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int bufferId = lua_tointeger( L, 1 );
	Buffer *buffer = luaL_checkudata( L, 2, "Buffer" );
	int offset = lua_tointeger( L, 3 );

	rlUpdateVertexBufferElements( bufferId, buffer->data, buffer->size, offset );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlUnloadVertexArray( int vaoId )

Unload vertex array object (VAO)

- Failure return false
- Success return true
*/
int lrlglUnloadVertexArray( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlUnloadVertexArray( int vaoId )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlUnloadVertexArray( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlUnloadVertexBuffer( int vboId )

Unload vertex buffer (VBO)

- Failure return false
- Success return true
*/
int lrlglUnloadVertexBuffer( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlUnloadVertexBuffer( int vboId )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlUnloadVertexBuffer( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetVertexAttribute( int index, int compSize, int type, bool normalized, int stride, int pointer )

Set vertex attribute

- Failure return false
- Success return true
*/
int lrlglSetVertexAttribute( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 )
	|| !lua_isboolean( L, 4 ) || !lua_isnumber( L, 5 ) || !lua_isnumber( L, 6 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetVertexAttribute( int index, int compSize, int type, bool normalized, int stride, int pointer )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int index = lua_tointeger( L, 1 );
	int compSize = lua_tointeger( L, 2 );
	int type = lua_tointeger( L, 3 );
	bool normalized = lua_toboolean( L, 4 );
	int stride = lua_tointeger( L, 5 );
	int pointer = lua_tointeger( L, 6 );

	rlSetVertexAttribute( index, compSize, type, normalized, stride, &pointer );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetVertexAttributeDivisor( int index, int divisor )

Set vertex attribute divisor

- Failure return false
- Success return true
*/
int lrlglSetVertexAttributeDivisor( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetVertexAttributeDivisor( int index, int divisor )" );
		lua_pushboolean( L, false );
		return 1;
	}
	unsigned int index = (unsigned int)lua_tointeger( L, 1 );
	int divisor = lua_tointeger( L, 2 );

	rlSetVertexAttributeDivisor( index, divisor );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetVertexAttributeDefault( int locIndex, float{} value, int attribType )

Set vertex attribute default value

- Failure return false
- Success return true
*/
int lrlglSetVertexAttributeDefault( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_istable( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetVertexAttributeDefault( int locIndex, float{} value, int attribType )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int locIndex = lua_tointeger( L, 1 );
	int attribType = lua_tointeger( L, 3 );
	int count = uluaGetTableLenIndex( L, 2 );
	float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };

	int t = 2;
	int i = 0;
	lua_pushnil( L );

	while ( lua_next( L, t ) != 0 ) {
		value[i] = lua_tonumber( L, -1 );
		lua_pop( L, 1 );
		i++;
	}
	rlSetVertexAttributeDefault( locIndex, value, attribType, count );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlDrawVertexArray( int offset, int count )

Draw vertex array

- Failure return false
- Success return true
*/
int lrlglDrawVertexArray( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlDrawVertexArray( int offset, int count )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int offset = lua_tointeger( L, 1 );
	int count = lua_tointeger( L, 2 );

	rlDrawVertexArray( offset, count );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlDrawVertexArrayElements( int offset, int count, Buffer buffer )

Draw vertex array elements

- Failure return false
- Success return true
*/
int lrlglDrawVertexArrayElements( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isuserdata( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlDrawVertexArrayElements( int offset, int count, Buffer buffer )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int offset = lua_tointeger( L, 1 );
	int count = lua_tointeger( L, 2 );
	Buffer *buffer = luaL_checkudata( L, 3, "Buffer" );

	rlDrawVertexArrayElements( offset, count, buffer->data );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlDrawVertexArrayInstanced( int offset, int count, int instances )

Draw vertex array instanced

- Failure return false
- Success return true
*/
int lrlglDrawVertexArrayInstanced( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlDrawVertexArrayInstanced( int offset, int count, int instances )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int offset = lua_tointeger( L, 1 );
	int count = lua_tointeger( L, 2 );
	int instances = lua_tointeger( L, 3 );

	rlDrawVertexArrayInstanced( offset, count, instances );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlDrawVertexArrayElementsInstanced( int offset, int count, Buffer buffer, int instances )

Draw vertex array elements instanced

- Failure return false
- Success return true
*/
int lrlglDrawVertexArrayElementsInstanced( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isuserdata( L, 3 ) || !lua_isnumber( L, 4 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlDrawVertexArrayElementsInstanced( int offset, int count, Buffer buffer, int instances )" );
		lua_pushboolean( L, false );
		return 1;
	}
	int offset = lua_tointeger( L, 1 );
	int count = lua_tointeger( L, 2 );
	Buffer *buffer = luaL_checkudata( L, 3, "Buffer" );
	int instances = lua_tointeger( L, 4 );

	rlDrawVertexArrayElementsInstanced( offset, count, buffer->data, instances );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Textures management
*/

/*
> id = RL.rlLoadTexture( Vector2 size, int format, int mipmapCount )

Load texture in GPU

- Failure return -1
- Success return int
*/
int lrlglLoadTexture( lua_State *L ) {
	if ( !lua_istable( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlLoadTexture( Vector2 size, int format, int mipmapCount )" );
		lua_pushinteger( L, -1 );
		return 1;
	}
	Vector2 size = uluaGetVector2Index( L, 1 );
	int format = lua_tointeger( L, 2 );
	int mipmapCount = lua_tointeger( L, 3 );

	lua_pushinteger( L, rlLoadTexture( NULL, size.x, size.y, format, mipmapCount ) );

	return 1;
}

/*
> id = RL.rlLoadTextureDepth( Vector2 size, bool useRenderBuffer )

Load depth texture/renderbuffer ( to be attached to fbo )

- Failure return -1
- Success return int
*/
int lrlglLoadTextureDepth( lua_State *L ) {
	if ( !lua_istable( L, 1 ) || !lua_isboolean( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlLoadTextureDepth( Vector2 size, bool useRenderBuffer )" );
		lua_pushinteger( L, -1 );
		return 1;
	}
	Vector2 size = uluaGetVector2Index( L, 1 );
	bool useRenderBuffer = lua_toboolean( L, 2 );

	lua_pushinteger( L, rlLoadTextureDepth( size.x, size.y, useRenderBuffer ) );

	return 1;
}

/*
> success = RL.rlUnloadTexture( int id )

Unload texture from GPU memory

- Failure return false
- Success return true
*/
int lrlglUnloadTexture( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlUnloadTexture( int id )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlUnloadTexture( lua_tointeger( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Framebuffer management (fbo)
*/

/*
> fboId = RL.rlLoadFramebuffer( Vector2 size )

Load an empty framebuffer

- Failure return -1
- Success return int
*/
int lrlglLoadFramebuffer( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlLoadFramebuffer( Vector2 size )" );
		lua_pushinteger( L, -1 );
		return 1;
	}
	Vector2 size = uluaGetVector2Index( L, 1 );

	lua_pushinteger( L, rlLoadFramebuffer( size.x, size.y ) );

	return 1;
}

/*
> success = RL.rlFramebufferAttach( int fboId, int texId, int attachType, int texType, int mipLevel )

Attach texture/renderbuffer to a framebuffer

- Failure return false
- Success return true
*/
int lrlglFramebufferAttach( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) || !lua_isnumber( L, 2 ) || !lua_isnumber( L, 3 )
	|| !lua_isnumber( L, 4 ) || !lua_isnumber( L, 5 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlFramebufferAttach( int fboId, int texId, int attachType, int texType, int mipLevel )" );
		lua_pushboolean( L, false );
		return 1;
	}
	unsigned int fboId = lua_tointeger( L, 1 );
	unsigned int texId = lua_tointeger( L, 2 );
	int attachType = lua_tointeger( L, 3 );
	int texType = lua_tointeger( L, 4 );
	int mipLevel = lua_tointeger( L, 5 );

	rlFramebufferAttach( fboId, texId, attachType, texType, mipLevel );
	lua_pushboolean( L, true );

	return 1;
}

/*
> isComplete = RL.rlFramebufferComplete( int id )

Verify framebuffer is complete

- Failure return nil
- Success return bool
*/
int lrlglFramebufferComplete( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlFramebufferComplete( int id )" );
		lua_pushnil( L );
		return 1;
	}
	unsigned int id = lua_tointeger( L, 1 );

	lua_pushboolean( L, rlFramebufferComplete( id ) );

	return 1;
}

/*
> success = RL.rlUnloadFramebuffer( int id )

Delete framebuffer from GPU

- Failure return nil
- Success return bool
*/
int lrlglUnloadFramebuffer( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlUnloadFramebuffer( int id )" );
		lua_pushnil( L );
		return 1;
	}
	unsigned int id = lua_tointeger( L, 1 );

	rlUnloadFramebuffer( id );
	lua_pushboolean( L, true );

	return 1;
}

/*
## RLGL - Shaders management
*/

/*
> success = RL.rlLoadShaderCode( string vsCode, string fsCode )

Load shader from code strings

- Failure return nil
- Success return int
*/
// int lrlglUnloadFramebuffer( lua_State *L ) {
// 	if ( !lua_isstring( L, 1 ) || !lua_isstring( L, 2 ) ) {
// 		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlLoadShaderCode( string vsCode, string fsCode )" );
// 		lua_pushnil( L );
// 		return 1;
// 	}
// 	lua_pushinteger( L, rlLoadShaderCode( luaL_checkstring( L, 1 ), luaL_checkstring( L, 2 ) ) );

// 	return 1;
// }

/*
## RLGL - Matrix state management
*/

/*
> modelview = RL.rlGetMatrixModelview()

Get internal modelview matrix

- Success return Matrix
*/
int lrlglGetMatrixModelview( lua_State *L ) {
	uluaPushMatrix( L, rlGetMatrixModelview() );

	return 1;
}

/*
> projection = RL.rlGetMatrixProjection()

Get internal projection matrix

- Success return Matrix
*/
int lrlglGetMatrixProjection( lua_State *L ) {
	uluaPushMatrix( L, rlGetMatrixProjection() );

	return 1;
}

/*
> transform = RL.rlGetMatrixTransform()

Get internal accumulated transform matrix

- Success return Matrix
*/
int lrlglGetMatrixTransform( lua_State *L ) {
	uluaPushMatrix( L, rlGetMatrixTransform() );

	return 1;
}

/*
> projection = RL.rlGetMatrixProjectionStereo( int eye )

Get internal projection matrix for stereo render (selected eye)

- Failure return false
- Success return Matrix
*/
int lrlglGetMatrixProjectionStereo( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlGetMatrixProjectionStereo( int eye )" );
		lua_pushboolean( L, false );
		return 1;
	}
	uluaPushMatrix( L, rlGetMatrixProjectionStereo( lua_tointeger( L, 1 ) ) );

	return 1;
}

/*
> viewOffset = RL.rlGetMatrixViewOffsetStereo( int eye )

Get internal view offset matrix for stereo render (selected eye)

- Failure return false
- Success return Matrix
*/
int lrlglGetMatrixViewOffsetStereo( lua_State *L ) {
	if ( !lua_isnumber( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlGetMatrixViewOffsetStereo( int eye )" );
		lua_pushboolean( L, false );
		return 1;
	}
	uluaPushMatrix( L, rlGetMatrixViewOffsetStereo( lua_tointeger( L, 1 ) ) );

	return 1;
}

/*
> success = RL.rlSetMatrixProjection( Matrix proj )

Set a custom projection matrix (replaces internal projection matrix)

- Failure return false
- Success return true
*/
int lrlglSetMatrixProjection( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetMatrixProjection( Matrix proj )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetMatrixProjection( uluaGetMatrixIndex( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetMatrixModelview( Matrix view )

Set a custom modelview matrix (replaces internal modelview matrix)

- Failure return false
- Success return true
*/
int lrlglSetMatrixModelview( lua_State *L ) {
	if ( !lua_istable( L, 1 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetMatrixModelview( Matrix view )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetMatrixModelview( uluaGetMatrixIndex( L, 1 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetMatrixProjectionStereo( Matrix right, Matrix left )

Set eyes projection matrices for stereo rendering

- Failure return false
- Success return true
*/
int lrlglSetMatrixProjectionStereo( lua_State *L ) {
	if ( !lua_istable( L, 1 ) || !lua_istable( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetMatrixModelview( Matrix right, Matrix left )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetMatrixProjectionStereo( uluaGetMatrixIndex( L, 1 ), uluaGetMatrixIndex( L, 2 ) );
	lua_pushboolean( L, true );

	return 1;
}

/*
> success = RL.rlSetMatrixViewOffsetStereo( Matrix right, Matrix left )

Set eyes view offsets matrices for stereo rendering

- Failure return false
- Success return true
*/
int lrlglSetMatrixViewOffsetStereo( lua_State *L ) {
	if ( !lua_istable( L, 1 ) || !lua_istable( L, 2 ) ) {
		TraceLog( state->logLevelInvalid, "%s", "Bad call of function. RL.rlSetMatrixViewOffsetStereo( Matrix right, Matrix left )" );
		lua_pushboolean( L, false );
		return 1;
	}
	rlSetMatrixViewOffsetStereo( uluaGetMatrixIndex( L, 1 ), uluaGetMatrixIndex( L, 2 ) );
	lua_pushboolean( L, true );

	return 1;
}
