/*****************************************************************************
 * $LastChangedDate: 2011-08-20 12:07:38 -0400 (Sat, 20 Aug 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Macros/functions to assist and simplify writing glue code between C++ and Lua.
 * @remarks Indeed, macros.cc is a C++ file.
 *------------------------------------------------------------------------------
 * REMEMBER: Indexs of tables passed between C++ and Lua must be ## ZERO-BASED ##.
 * Lua scripts must define special Lua classes such as Vec3 with zero-based indexs
 * because passing array-like one-based Lua tables to zero-based C++ is wrong.
 *------------------------------------------------------------------------------
 *//*
 * LEGAL:   COPYRIGHT (C) 2008 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

// Avoid lua_/LUA_ which is reserved by Lua.

#define LUABIND_MACROS_PROGRAM_CC 1
#include "base/module.hh"
using namespace base;
#include "math/module.hh"
#include "math/matrix_defs.hh"
using namespace math;
#include "world/defs.hh"  // LAT/LON etc
using namespace world;
#include "lua_bind/module.hh"
#include "lua_bind/bind.hh"

namespace lua {
namespace bind {

/*****************************************************************************
 * Pop RGBA from either 4 floats or a table with 4 elements.
 *****************************************************************************/
RGBA
POP_RGBA( lua_State* L )
{
    if ( EX( IF_TABLE( L, -1 ) ) )
    {
        fp rgba_f[4];
        rgba_f[RR] = GET_MEMBER_AS_NUMBER( L, int(RR) );  // ZERO-BASED
        rgba_f[GG] = GET_MEMBER_AS_NUMBER( L, int(GG) );
        rgba_f[BB] = GET_MEMBER_AS_NUMBER( L, int(BB) );
        rgba_f[AA] = GET_MEMBER_AS_NUMBER( L, int(AA) );
        lua_pop( L, 1 );  // pop RGBA table
        return RGBA( rgba_f );
    }
    else
    {
        // Pop in reverse order.
        fp a = POP_FP( L );  // ZERO-BASED
        fp b = POP_FP( L );
        fp g = POP_FP( L );
        fp r = POP_FP( L );
        return RGBA(r,g,b,a);
    }
}

/*****************************************************************************
 * Pop Lua table into Rect<int>.
 *****************************************************************************/
Rect<int>
POP_TABLE_INTO_RECT( lua_State* L )
{
#if DEBUG
const int stackTop = lua_gettop(L);
#endif
    const Rect<int> rect ( GET_MEMBER_AS_NUMBER( L, "x1" ),
                           GET_MEMBER_AS_NUMBER( L, "y1" ),
                           GET_MEMBER_AS_NUMBER( L, "x2" ),
                           GET_MEMBER_AS_NUMBER( L, "y2" ) );

ASSERT( stackTop == lua_gettop(L) );

    // Pop table.
    lua_pop( L, 1 );

    return rect;
}

/*****************************************************************************
 * Pop SphereVertex (heterogenous members).
 *****************************************************************************/
#if COMPILE_PALOMINO
SphereVertex
POP_SPHERE_VERTEX( lua_State* L )
{
    const Vector3 v = POP_VECTOR3<Vector3>( L );
    return SphereVertex( Degree(v[XX]), Degree(v[YY]), Meter(v[ZZ]) );  // ZERO-BASED
}
#endif // COMPILE_PALOMINO

/*****************************************************************************
 * Push a spherical vertex as table with index starting at ZERO (0).
 *****************************************************************************/
#if COMPILE_PALOMINO
void
PUSH_SPHERE_VERTEX( lua_State* L, const SphereVertex& sv )
{
    lua_newtable( L );
    SET_MEMBER_AS_NUMBER( L, int(LAT), sv.mLat.FP() );  // ZERO-BASED
    SET_MEMBER_AS_NUMBER( L, int(LON), sv.mLon.FP() );
    SET_MEMBER_AS_NUMBER( L, int(ALT), sv.mAlt.FP() );
}
#endif // COMPILE_PALOMINO

/*****************************************************************************
 * Pop a table containing a 4x4 matrix.
 *****************************************************************************/
void
POP_TABLE_INTO_MATRIX( lua_State* L, Matrix& matrix/*OUT*/ )
{
#if DEBUG
const int stackTop = lua_gettop(L);
#endif

    // Copy Lua table into C++ matrix.
    for ( int i = math::MATRIX_ELEMS-1; i >= 0; --i )  // reversed, signed index
    {
        matrix[i] = GET_MEMBER_AS_NUMBER( L, i );  // ZERO-BASED
    }

ASSERT( stackTop == lua_gettop(L) );

    // Pop table.
    lua_pop( L, 1 );
}

/*****************************************************************************
 * Push a table containing a 4x4 matrix.
 *****************************************************************************/
void
PUSH_TABLE_FROM_MATRIX( lua_State* L, const Matrix& matrix )
{
    lua_newtable( L );

#if DEBUG
const int stackTop = lua_gettop(L);
#endif

    for ( int i = 0; i < int(math::MATRIX_ELEMS); ++i )
    {
        SET_MEMBER_AS_NUMBER( L, i, matrix[i] );  // ZERO-BASED
    }

ASSERT( stackTop == lua_gettop(L) );
}

} // namespace bind
} // namespace lua
