/******************************************************************************
 *
 * 9998sketch/scene.h
 *
 * (c) Eugene K. Ressler, Jr. 2004, 2005
 *
 * A program related to the book
 *
 * Fundamentals of Virtual World Simulation
 * by Eugene K. Ressler, Jr.
 *
 * No warranty of correctness or capability of any kind is expressed or implied.
 *
 * The author grants free use of this code for any purpose as long any text,
 * executable program, library file, or source code distributed to others 
 * and employing any portion of this code clearly cites the book named above.
 *
 ******************************************************************************/

#ifndef __SCENE_H
#define __SCENE_H

#include "opts.h"
#include "error.h"
#include "geometry.h"
#include "expr.h"
#include "bsp.h"
#include "dynarray.h"
#include "global.h"

typedef struct point_list_3d_t {
  DYNAMIC_2D_ARRAY_FIELDS(POINT_3D, v, n_pts);
} POINT_LIST_3D;

DECLARE_DYNAMIC_2D_ARRAY_PROTOS(POINT_LIST_3D, POINT_3D, FLOAT, point_list_3d, v, n_pts)

typedef struct transform_list_t {
  DYNAMIC_2D_ARRAY_FIELDS(TRANSFORM, xf, n_xfs);
} TRANSFORM_LIST;

DECLARE_DYNAMIC_2D_ARRAY_PROTOS(TRANSFORM_LIST, TRANSFORM, FLOAT, transform_list, xf, n_xfs)

// object_type_str[] definition in scene.c must match!
typedef enum object_type_t {
  O_BASE,
  O_TAG_DEF,
  O_OPTS_DEF,
  O_SCALAR_DEF,
  O_POINT_DEF,
  O_VECTOR_DEF,
  O_TRANSFORM_DEF,
  O_DOTS,
  O_LINE,
  O_CURVE,
  O_POLYGON,
  O_SPECIAL,
  O_SWEEP,
  O_REPEAT,
  O_COMPOUND,
} OBJECT_TYPE;

#define is_drawable(P)  ((P)->tag >= O_DOTS)

extern char *object_type_str[];

#define BASE_OBJECT_FIELDS  \
  struct object_t *sibling; \
  OBJECT_TYPE tag

typedef struct object_t {
  BASE_OBJECT_FIELDS;
} OBJECT;

typedef OBJECT TAG_DEF;
OBJECT *new_tag_def(void);

typedef struct opts_def_t {
  BASE_OBJECT_FIELDS;
  OPTS *opts;
} OPTS_DEF;

OBJECT *new_opts_def(char *opts_str, SRC_LINE line);

typedef struct scalar_def_t {
  BASE_OBJECT_FIELDS;
  FLOAT val;
} SCALAR_DEF;

OBJECT *new_scalar_def(FLOAT val);

typedef struct point_def_t {
  BASE_OBJECT_FIELDS;
  POINT_3D p;
} POINT_DEF;

OBJECT *new_point_def(POINT_3D p);

typedef struct vector_def_t {
  BASE_OBJECT_FIELDS;
  VECTOR_3D v;
} VECTOR_DEF;

OBJECT *new_vector_def(VECTOR_3D v);

typedef struct transform_def_t {
  BASE_OBJECT_FIELDS;
  TRANSFORM xf;
} TRANSFORM_DEF;

OBJECT *new_transform_def(TRANSFORM xf);

typedef struct dots_t {
  BASE_OBJECT_FIELDS;
  OPTS *opts;
  POINT_LIST_3D pts[1];
} DOTS_OBJECT;

OBJECT *new_dots(OPTS *opts, OBJECT *pts);

typedef struct line_object_t {
  BASE_OBJECT_FIELDS;
  OPTS *opts;
  POINT_LIST_3D pts[1];
} LINE_OBJECT;

OBJECT *new_line(OPTS *opts, OBJECT *pts);

typedef struct curve_t {
  BASE_OBJECT_FIELDS;
  OPTS *opts;
  POINT_LIST_3D pts[1];
} CURVE_OBJECT;

OBJECT *new_curve(OPTS *opts, OBJECT *pts);

typedef struct polygon_t {
  BASE_OBJECT_FIELDS;
  OPTS *opts;
  int border_p;
  POINT_LIST_3D pts[1];
} POLYGON_OBJECT;

OBJECT *new_polygon(OPTS *opts, OBJECT *pts);

typedef struct special_t {
  BASE_OBJECT_FIELDS;
  char *code;
  OPTS *opts;
  POINT_LIST_3D pts[1];
} SPECIAL_OBJECT;

OBJECT *new_special(char *code, OPTS *opts, OBJECT *pts, SRC_LINE line);

typedef struct sweep_t {
  BASE_OBJECT_FIELDS;
  OPTS *opts;
  int n_slices;
  int closed_p;
  TRANSFORM_LIST xforms[1];
  OBJECT *swept;
} SWEEP_OBJECT;

OBJECT *new_sweep(OPTS *opts, int n_slices, int closed_p, OBJECT *xfs, OBJECT *swept);

typedef struct repeat_t {
  BASE_OBJECT_FIELDS;
  int n;
  TRANSFORM_LIST xforms[1];
  OBJECT *repeated;
} REPEAT_OBJECT;

OBJECT *new_repeat(int n, OBJECT *xfs, OBJECT *repeated);

typedef struct compound_t {
  BASE_OBJECT_FIELDS;
  TRANSFORM xform;
  OBJECT *child;
} COMPOUND_OBJECT;

OBJECT *new_compound(TRANSFORM xform, OBJECT *child);

OBJECT *copy_drawable(OBJECT *obj);
OBJECT *cat_objects(OBJECT *lft, OBJECT *rgt);
OBJECT *sibling_reverse(OBJECT *obj);
OBJECT *object_from_expr(EXPR_VAL *val);

OBJECT *flat_scene(OBJECT *obj, GLOBAL_ENV *env);
OBJECT *hsr_scene_with_bsp(OBJECT *scene);
OBJECT *hsr_scene_with_depth_sort(OBJECT *scene);
void get_extent(OBJECT *obj, BOX_3D *e, int *n_obj);
int xy_overlap_p(OBJECT *obj, BOX_3D *e);

#endif
