/****************************************************************************
 * Copyright (c) 2025 MAK Technologies, Inc.
 * All rights reserved.
 ****************************************************************************/

/*********************************************************************/
/**
 *t  diguyGraphicsMesh
 **
 *b    Link against: libdiguy_graphics_api
 */

#pragma once

#ifdef SWIG
%module diguyGraphicsTexture
#else
#define CPLUSPLUS_ONLY
#endif

#ifdef CPLUSPLUS_ONLY
#include <diguy_constants.h>
#include <diguyGraphicsVertexFormats.h>
#include <declspec_diguy.h>
#include <stdlib.h>

class diguyGraphicsMesh;
class diguyGraphicsShaderProgram;
class diguyGraphicsShaderInstance;
class diguyGraphicsState;
class diguyGraphicsShape;
class bdiGeometryMesh;

#endif


//! \brief  A struct that represents the information that diguy puts together for an immediate mode draw call.
//! \ingroup libbdigeometry
struct BDI_DECLSPEC_diguy diguyDrawCallData
{
   diguyDrawCallData();

   //! The material/texture combination that can override the built-in material of the mesh.
   //! This needed to allow our texture/material swap system to work.
   diguyGraphicsState* m_state_override;

   //! The unique shape that is drawing this shared mesh, needed for some instancing functionality
   diguyGraphicsShape* m_shape;

   //! Is this a multi-draw call, allows instancing and non-instancing to share mesh drawing code.
   int m_num_instances;

   //! is this a draw instanced draw call
   bool m_instancing_draw;

   //! DI-Guy Scenario use only currently. Should this mesh allow itself to be queued up for a
   //! delayed instance draw pass.
   bool m_allow_instancing;

   //! DI-Guy Scenario instancing use only currently. VAO is already bound so don't setup.
   bool m_skip_vao_bind;

   //! Is this an opaque (0) or transparent (1) render pass when 2 passes are used.
   int m_render_pass;

   //! current lod
   int m_lod;

   //! how far into the LOD are we
   float m_lod_fraction;

   //! should this LOD fade out;
   bool m_fade_lod;

   float m_blend_shape_weights[4];

   int m_blend_shape_indexes[4];

   //! this is the current transform matrix relative to the body matrix, it can be the link matrix,
   //! or a connection point or the offset of a mesh attached to a link.
   float m_transform_matrix[16];

};


/****************************************************************************/
//! \brief  A class that represents a shared mesh object.
//! Can be subclassed by filling out the diguy_graphics_set_mesh_create_func().
//! \ingroup libbdigeometry
class BDI_DECLSPEC_diguy diguyGraphicsMesh
{
public:

/*****************************************************************************/
/**
 *2  Accessor Functions
 **
 **    The functions in this section provide access to data in this object.
 **    They are designed to be called by DI-Guy programmers.
 **
 */

   /*l
    *b  Description:
    **
    **    Returns the name of the mesh.  This pointer will
    **    never be NULL.
    **
    *b  Returns:
    **
    **    name of the mesh
    */
   const char* get_name();

   /*l
    *b  Description:
    **
    **    All meshes are assigned a unique identifier (uid)
    **    This function returns the uid of the mesh.
    **
    **    *Note*: uids will change between DI-Guy runs.
    **
    *b  Returns:
    **
    **     unique identifier of the object
    */
   long get_uid();

   /*l
    *b  Description:
    **
    **    This function returns the graphics state with which faces in this
    **    mesh should be drawn.  Specific information about material and
    **    texture can then be accessed from this object.
    **
    **    Some meshes may have multiple possible graphics states associated
    **    with them.  In effect this means that depending on a character's
    **    appearance, different textures or material settings may be used.
    **
    **    Call get_num_switched_graphics_states() to get the number of
    **    graphics states that are associated with this mesh.
    **
    **    This function is typically called during the Build stage for
    **    scene graph renderers, when geoset/mesh objects are being
    **    created and their graphics states set.
    **
    *b  Returns:
    **
    **    object of type diguyGraphicsState; NULL on failure
    */
   //! @{
   diguyGraphicsState* get_state( int graphics_state_switch_index = 0 );
   const diguyGraphicsState* get_state( int graphics_state_switch_index = 0 ) const;
   //! @}


   /*l
    *b  Description:
    **
    **    This function returns the number of switched graphics states
    **    this mesh has.  There should always be at least one.
    **
    **    See get_state() for more information on switched graphics states.
    **
    *b  Returns:
    **
    **    number of switched graphics states this mesh has
    */
   int get_num_switched_graphics_states() const;

   /*l
    *b  Description:
    **
    **    This function returns whether or not the mesh is "skinned".
    **
    **    The position of vertices in a skinned mesh are determined
    **    at run-time by transforming them with multiple link transforms.
    **
    **    It is likely that some type of shader is required to render
    **    the mesh correctly.  The shader recommended for this mesh can be
    **    obtained by calling get_shader_program().
    **
    **    Though they sound similar, skinned meshes and deformable meshes
    **    are different.  The vertices in a deformable mesh have already
    **    been transformed when the draw() function is called; nothing
    **    more needs to be done.  The vertices in a skinned are not ready
    **    to be drawn, as they must first be transformed by a shader.
    **
    *b  Returns:
    **
    **    1 if mesh is skinned, 0 if not, -1 on failure
    */
   int get_is_skinned_mesh();

   /*l
    *b  Description:
    **
    **    This function returns whether or not the mesh is actually a morph object.
    **    the pos,normals and tangents will then just be the deltas from the base mesh.
    */
   int get_is_blend_shape();

   /*l
    *b  Description:
    **
    **    This function frees most memory allocated by the DI-Guy geometry
    **    loader for this object.
    **
    **    This function should only be called during or after the object's
    **    build() function has been called.  After it has been called, calls
    **    to many accessor functions will fail.
    */
   void free_loader_memory();


/*****************************************************************************/
/**
 *2  Geometry Data Accessor Functions
 **
 **    The functions in this section provide access to geometry data of this
 **    mesh, including vertex positions, normals, texture indices, etc.
 **
 **    They are designed to be called by DI-Guy programmers during the Build
 **    Stage.  Calling them before the Build Stage will return invalid
 **    results.
 **
 **    Functions that return pointers to data (get_vertex_buffer_data(),
 **    etc.) cannot be called after free_loader_memory() is called.
 **
 **    For in-depth examples of how these functions work, look at the
 **    following files in programming_examples/diguy_graphics_api:
 **
 *-    - ogl_examples/common/diguyOglGraphicsMesh.cpp
 *-    - osg_2_examples/common/diguyOsgGraphicsMesh.cpp
 **
 **    For more information on how the returned data is structured, refer
 **    to the documentation for the types diguyGraphicsVertexFormat and
 **    diguyGraphicsIndexType.
 **
 */

/*********************************************************************/
/**
 *3  Shader Accessor Functions
 **
 */

   /*l
    *b  Description:
    **
    **    This function returns a pointer to the shader program designated
    **    for this mesh, if any.  Shader programs are shared objects usable
    **    by many meshes.
    **
    *b  Returns:
    **
    **    pointer to diguyGraphicsShaderProgram, or NULL if this mesh
    **    does not have a shader specified
    */
   diguyGraphicsShaderProgram* get_shader_program();

   /*l
    *b  Description:
    **
    **    If this mesh has a shader program specified (see
    **    get_shader_program()), this function returns a pointer to the
    **    shader instance object specific to this mesh.
    **
    *b  Returns:
    **
    **    pointer to diguyGraphicsShaderInstance, or NULL if this mesh
    **    does not have a shader specified
    */
   diguyGraphicsShaderInstance* get_shader_instance();


/*********************************************************************/
/**
 *3  Vertex Buffer Data Accessor Functions
 **
 */

   /*l
    *b  Returns:
    **
    **    vertex format that describes the format of the data returned
    **    by the get_vertex_buffer_data() function
    */
   diguyGraphicsVertexFormat get_vertex_format();

   /*l
    *b  Returns:
    **
    **    how many vertices this mesh has
    */
   int get_vertex_count();

   /*l
    *b  Returns:
    **
    **    size, in bytes, of the data buffer returned by
    **    get_vertex_buffer_data()
    */
   int get_vertex_buffer_size();


   /*l
    *b  Returns:
    **
    **    Pointer to a blend shape mesh that represents the offsets from this mesh, currently
    **    we only have 1 of these which we use to adjust the weight of the character.
    */
   diguyGraphicsMesh* get_blend_shape( int index );

   //!  Returns: Number of blend shapes associated with this mesh, currently max of 1.
   int get_num_blend_shapes();

#ifdef CPLUSPLUS_ONLY

   //! this is necessary for the new SSBO based implementation of blend shapes that has a specific layout
   float* get_data_as_blend_shape_verts();

#endif

   //! this is necessary for the new SSBO based implementation of blend shapes that has a specific layout
   //! \returns -1 if the underlying mesh is invalid.
   int get_blend_shape_vertex_buffer_size();

#ifdef CPLUSPLUS_ONLY

   /*l
    *b  Description:
    **
    **    This function returns a pointer to the raw vertex buffer data
    **    of this mesh.  The format of the data can be obtained by calling
    **    get_vertex_format().
    **
    **    Type-correct pointers into the data can be obtained by calling
    **    get_first_vertex(), get_first_normal(), etc.
    **
    *b  Returns:
    **
    **    pointer to raw vertex buffer data
    */
   void* get_vertex_buffer_data();

   /*l
    *b  Description:
    **
    **    This function returns a pointer to vertex position data of the
    **    first vertex in the raw vertex buffer data returned by
    **    get_vertex_buffer_data().
    **
    **    The XYZ position of the first vertex is stored in the first three
    **    values of the returned pointer.  The XYZ positions of subsequent
    **    vertices need to be obtained by consecutively adding the
    **    vertex stride to this returned pointer, as returned by
    **    get_vertex_stride().
    **
    **    *NOTE*: get_vertex_stride() returns a value in *bytes*, not
    **    sizeof(float), so be careful about pointer arithmetic.
    **
    **    This approach is also used for the first normal, texture indices,
    **    link index, and link weight of the vertex data.
    **
    **    An alternative approach to getting a pointer to the first vertex
    **    position is to use get_vertex_offset().  See that function for
    **    more information.
    **
    *b  Returns:
    **
    **    pointer to vertex position of first vertex in vertex buffer data
    */
   float* get_first_vertex();

   /*l
    *b  Description:
    **
    **    This function returns how many bytes the first vertex position
    **    is into the raw vertex buffer data returned by
    **    get_vertex_buffer_data().
    **
    **    The XYZ positions of subsequent vertices need to be obtained by
    **    consecutively adding the vertex stride to this offset, as
    **    returned by get_vertex_stride().
    **
    **    *NOTE*: get_vertex_stride() returns a value in *bytes*, not
    **    sizeof(float), so be careful about pointer arithmetic.
    **
    **    This approach is also used for the first normal, texture indices,
    **    link index, and link weight offsets into the vertex data.
    **
    **    An alternative approach to getting a pointer to the first vertex
    **    position is to use get_first_vertex() to get a type-correct
    **    pointer.
    **
    *b  Returns:
    **
    **    offset in bytes of the first vertex position in raw vertex buffer
    **    data
    */
   int get_vertex_offset();

   /*l
    *b  Description:
    **
    **    This function returns how many bytes there are between each
    **    vertex position in the raw data returned by
    **    get_vertex_buffer_data().
    **
    **    See get_first_vertex() and get_vertex_offset() for more
    **    information.
    **
    **    *NOTE*: this function returns a value in *bytes*, not
    **    sizeof(float), so be careful about pointer arithmetic.
    **
    *b  Returns:
    **
    **    stride in bytes between each vertex position in raw vertex buffer
    **    data
    */
   int get_vertex_stride();

   /*l
    *b  Returns:
    **
    **    pointer to normal of first vertex in vertex buffer data; see
    **    get_first_vertex() for more information
    */
   float* get_first_normal();

   /*l
    *b  Returns:
    **
    **    offset in bytes of the first normal in raw vertex buffer data;
    **    see get_vertex_offset() for more information
    */
   int get_normal_offset();


   /*l
    *b  Returns:
    **
    **    pointer to texture indices of first vertex in vertex buffer data
    */
   float* get_first_texture_indices();

   /*l
    *b  Returns:
    **
    **    offset in bytes of the first texture indices in raw vertex buffer
    **    data; see get_vertex_offset() for more information
    */
   int get_texture_indices_offset();


   /*l
    *b  Returns:
    **
    **    pointer to link index of first vertex in vertex buffer data, in
    **    float form
    */
   float* get_first_link_index();

   /*l
    *b  Returns:
    **
    **    offset in bytes of the first link index in raw vertex buffer data;
    **    see get_vertex_offset() for more information
    */
   int get_link_index_offset();



   /*l
    *b  Returns:
    **
    **    pointer to link weight of first vertex in vertex buffer data
    */
   float* get_first_link_weight();

   /*l
    *b  Returns:
    **
    **    offset in bytes of the first link weight offset in raw vertex buffer data;
    **    see get_vertex_offset() for more information
    */
   int get_link_weight_offset();

   /*l
    *b  Description:
    **
    **    Returns a pointer to the UV tangent and flip bit of first vertex in
    **    the vertex buffer data.
    **
    **    There are 3 floats representing the tangent, and one for UV
    **    mirroring.  See
    **    http://www.dhpoware.com/demos/glslNormalMapping.html for an outline
    **    of how tangents are calculated.  Binormals are calculated in the
    **    vertex shader making their storage unnecessary.  Tangents should
    **    exist for all skinned/dae models.
    **
    **    See get_first_vertex() for more information about how to interpret
    **    tangent pointers and strides.
    */
   float* get_first_tangent();

   /*l
    *b  Returns:
    **
    **    offset in bytes of the first tangent in raw vertex buffer data;
    **    see get_vertex_offset() for more information
    */
   int get_tangent_offset();


#endif


   /*********************************************************************/
   /**
    *3  Index Buffer Data Accessor Functions
    **
    */


   /*l
    *b  Returns:
    **
    **    index type used in data returned by the get_index_buffer_data()
    **    function
    */
   diguyGraphicsIndexType get_index_type();

   /*l
    *b  Description:
    **
    **    This function returns how many indices there are in this mesh.
    **    The number of triangles in this mesh can be derived by dividing
    **    this value by 3.
    **
    **    Note that indices in index buffer data are different than the
    **    indices contained in vertex buffer data.  Index buffer indices
    **    specify which *vertices* in vertex buffer data are used to create
    **    polygons in a mesh (e.g., for the first triangle, use vertices 0,
    **    1, and 2), while indices stored in vertex buffer data specify
    **    which *links* affect the final position of the vertex.
    **
    *b  Returns:
    **
    **    number of indices in index buffer data returned by
    **    get_index_buffer_data()
    */
   int get_index_count();

#ifdef CPLUSPLUS_ONLY

   /*l
    *b  Returns:
    **
    **    size, in bytes, of the data buffer returned by
    **    get_index_buffer_data()
    */
   int get_index_buffer_size();

   /*l
    *b  Description:
    **
    **    This function returns a pointer to the raw index buffer data of
    **    this mesh.  The format of the data can be obtained by calling
    **    get_index_type().
    **
    *b  Returns:
    **
    **    pointer to raw index buffer data
    */
   void* get_index_buffer_data();

#endif


/*****************************************************************************/
/**
 *2  Virtual Functions
 **
 **    The functions in this section are all virtual functions that will
 **    be called by DI-Guy at various times during DI-Guy execution.
 **
 **    Because the functions are all virtual, DI-Guy programmers can create
 **    a subclass of this class and override them.  Unless otherwise stated,
 **    the base class functions do not need to be called.
 */

#ifdef CPLUSPLUS_ONLY

   /*l
    *b  Description:
    **
    **    This function will be called by DI-Guy when it is time for a
    **    renderer-specific mesh object to be created.  All information
    **    necessary to build the mesh should be available via the
    **    Accessor Functions above when this function is called.
    **
    *i  Immediate Mode:
    **
    **    Immediate mode renderers may override this function, to
    **    create an object that may be invoked by draw().
    **
    *i  Scene Graph:
    **
    **    Scene graph renderers usually do override this function, to
    **    create a geometry object that gets associated with a
    **    diguyGraphicsState object obtained by calling get_state().
    **
    *b  Callable From:
    **
    *-    - N/A (automatically called by DI-Guy Graphics API during
    *-      the Build Stage)
    */
   virtual void build();

   /*l
    *b  Description:
    **
    **    This function will be called by DI-Guy when it is time for a
    **    renderer-specific mesh object to be destroyed.
    **
    *i  Immediate Mode:
    **
    **    Immediate mode renderers may override this function, to
    **    destroy any object that may have been created by build().
    **
    *i  Scene Graph:
    **
    **    Scene graph renderers usually do override this function, to
    **    destroy any object that may have been created by build().
    **
    *b  Callable From:
    **
    *-    - N/A (automatically called by DI-Guy Graphics API during
    *-      the Unbuild Stage)
    */
   virtual void unbuild();

   /*l
    *b  Description:
    **
    **    This function will be called by DI-Guy when the mesh should
    **    be drawn.  For scene graph renderers, most likely nothing
    **    more needs to be done by this function.
    **
    *b  Callable From:
    **
    *-    - N/A (automatically called by DI-Guy Graphics API during
    *-      Draw Stage)
    */
   virtual void draw( diguyDrawCallData* draw_data );

#endif

/****************************************************************************/
/*****************************************************************************/
/**
 *2  Deprecated Functions
 **
 **  The following functions are deprecated.
 **
 **  As these functions may disappear in a future version of DI-Guy,
 **   it is recommended that you remove calls to these functions from
 **   your application.
 **
 */
/****************************************************************************/
/****************************************************************************/

   // This seems like a mistake in retrospect. Please let MaK support know if you needed
   // it's functionality
   /*l
   *b  Description:
   **
   **    This function returns the last bound graphic state object this mesh
   **    used.  There should always be at least one. This can be used by
   **    immediate mode renderers during draw calls to find out more about
   **    the properties of the mesh.
   **
   **    See get_state() for more information on switched graphics states.
   **
   *b  Returns:
   **
   **    object of type diguyGraphicsState; NULL on failure
   */
   //diguyGraphicsState* get_current_graphics_state();

/****************************************************************************/
/*****************************************************************************/
/**
 *2  Experimental Functions
 **
 **  The following functions are experimental and may change or
 **  disappear with no warning.
 **
 */
   int get_bounding_box( float* bbox_min_x, float* bbox_min_y, float* bbox_min_z,
      float* bbox_max_x, float* bbox_max_y, float* bbox_max_z );

/****************************************************************************/
/****************************************************************************/

   //// Deprecated as of 13.2.0 - replaced by a more complex default draw function
   //virtual void draw_instance_group( int num_instances );

   //! deprecated as of 13.2.0 since we've always laid out data with vnt/vnt/vnt type layouts, strides are always
   //! the same.
   int get_normal_stride() { return get_vertex_stride(); }
   int get_texture_indices_stride() { return get_vertex_stride(); }
   int get_tangent_stride() { return get_vertex_stride(); }
   int get_link_weight_stride() { return get_vertex_stride(); }
   int get_link_index_stride() { return get_vertex_stride(); }

   /*l
   *b  Description:
   **
   **    This function returns whether or not the mesh is deformable.
   **
   **    The position of vertices in a deformable mesh may shift from
   **    frame to frame and therefore should not be put into a
   **    renderer-specific object that cannot be updated.  (For example,
   **    vertex buffer objects in OpenGL.)
   **
   **    The position of vertices in a non-deformable, non-skinned mesh
   **    remain fixed from frame to frame.
   **
   **    Though they sound similar, skinned meshes and deformable meshes
   **    are different.  The vertices in a deformable mesh have already
   **    been transformed when the draw() function is called; nothing
   **    more needs to be done.  The vertices in a skinned mesh are not
   **    ready to be drawn, as they must first be transformed by a
   **    shader.
   **
   **    We don't currently ever have deformable meshes... and you'd
   **    still need to stream them to the videocard.
   **
   *b  Returns:
   **
   **    1 if mesh is deformable, 0 if not, -1 on failure
   */
   int get_is_deformable();

/**
 *x  The functions and variables past this point are for internal use only.
 **   No external access to them is expected or necessary.
 */
#ifdef CPLUSPLUS_ONLY

   bdiGeometryMesh* get_scripted_object() { return m_scripted_object; }

protected:

   /*l
    **    A protected constructor.  Constructors are called automatically
    **    by DI-Guy.
    */
   diguyGraphicsMesh( void* internal_data );

   /*l
    **    A protected destructor.  Destructors are called automatically
    **    by DI-Guy.
    */
   virtual ~diguyGraphicsMesh();

private:

   /*l
    **    A pointer to internal data.
    */
   bdiGeometryMesh* m_scripted_object;

   friend class bdiGeometryGeosetMesh;
   friend class bdiGeometryMesh;
   friend class bdiGeometryFactory;
   friend class diguyGraphicsMeshArray;

#endif

};
