/*
 * Copyright 2017 RIS.
 * Authored by Ron Dahlgren <ron@red83.net>
 */
#ifndef ENTITIES_H_
#define ENTITIES_H_

#include "globals.h"
#include "rendering/rendering.h"
#include "animations/transform_animation.h"
#include "utility/c8math.h"

#include <gsl/gsl_matrix.h>

/**
 * This structure is used to manage all of the data associated with
 * a basic renderable entity. Comments below indicate which pointers
 * are optional and which are required. After calling entities.entity_alloc,
 * the resulting entity definition will be a basically zeroed but sane
 * copy of an internal prototype. Add some geometry and go to town.
 */
typedef struct entity_info {
  /* Required - specifies the material to use for rendering */
  shader_info shader;
  /* Required - should assume the projection matrix has already been set */
  render_func renderer;
  /* The animation state. Set current_cycle to actually use it */
  animation_state animation_state;
  /* Provides a reusable workspace for math operations */
  math_context math_context;
  /* Layout of these matrix arrays are row0, row1, row2, row3 */
  double transform[16]; /* Used in rendering */
  double reference_frame[16]; /* Animation solution is within this frame of ref */

  /* (OPT) Should claim additional resources needed by the entity */
  void (* initialize)(struct entity_info *);
  /* (OPT) Should release any claimed resources */
  void (* terminate)(struct entity_info *);

  /* (OPT) callback will be called (if set) before update */
  void (* pre_update)(double deltaT, struct entity_info *);
  /* (OPT) callback will be called (if set) after update */
  void (* post_update)(double deltaT, struct entity_info *);
  /* (OPT) Any additional data that may be needed */
  void* data;
} entity_info;

/**
 * Entity management operations are grouper here.
 */
typedef struct {
  /* Create an entity */
  entity_info* (* const entity_alloc)();
  /* Release an entity */
  void (__attribute__((nonnull(1)))* const entity_free)(entity_info* info);
  /* Add an entity */
  void (__attribute__((nonnull(1)))* const add_entity)(entity_info* info);
  /* Remove an entity */
  void (__attribute__((nonnull(1)))* const remove_entity)(entity_info* info);
  /* Conduct an update pass */
  void (* const update)(double deltaT);

  sd_result (* const initialize)(void);
  sd_result (* const release_resources)(void);
  sd_result (* const terminate)(void);
} entities_struct;

extern entities_struct const entities;
#endif
