Also comment-out some code for __SPU__ to reduce code size Added btContactConstraint (only used on PS3 SPU right now, better to use btPersistentManifold directly for contact constraints) Improved readblend utility library (see also usage in http://gamekit.googlecode.com with Irrlicht) Fix for btConvexConvexAlgorithm, potential division by zero Thanks linzner http://code.google.com/p/bullet/issues/detail?id=260
493 lines
17 KiB
C++
493 lines
17 KiB
C++
/***************************************************************
|
|
* readblend.h --
|
|
* ReadBlend, a data extraction API for Blender's .blend files
|
|
*
|
|
* (c) 2003 Adam D. Moss <adam@gimp.org> <aspirin@icculus.org>
|
|
*
|
|
*/
|
|
|
|
/* VERSION HISTORY
|
|
* 2003-04-05 : v1.0
|
|
* 2008-10-05 : v1.1-beta
|
|
*/
|
|
|
|
/* Blender files are 'curiously' structured and this is mirrored in
|
|
* the low-level data access API (the section labelled 'Low-level
|
|
* querying functions').
|
|
*
|
|
* The mid-level data access API (the section labelled 'Mid-level
|
|
* querying functions') tries to provide some handy utilities to
|
|
* ease your data-extraction pain, and finally the (partially written)
|
|
* high-level data access API incorporates semantic knowledge of Blender's
|
|
* useful high-level types such as Meshes and Materials to shield you
|
|
* from the full horror.
|
|
*/
|
|
#ifndef _READBLEND_H
|
|
#define _READBLEND_H
|
|
|
|
#include <stdlib.h>
|
|
//#include <stdint.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>//size_t for MSVC 6.0
|
|
|
|
//#include <cfloat>
|
|
#include <float.h>
|
|
|
|
#include "abs-file.h"
|
|
|
|
/* TODO: Doxygen me. */
|
|
|
|
|
|
#include "blendtype.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
|
|
/**************************************/
|
|
/* .blend handle load/free functions */
|
|
/*************************************/
|
|
|
|
|
|
/* Pass in an already-opened file handle; this function will then
|
|
examine the file to check that it is a Blender file and scan the
|
|
entire file to extract all vital information (quite expensive)
|
|
before any query operations can be performed. The resulting
|
|
.blend data handle is returned.
|
|
*/
|
|
|
|
BlendFile* blend_read(MY_FILETYPE* file);
|
|
|
|
|
|
/* Free all of the given BlendFile data (note: obviously, do not attempt
|
|
to extract data from a BlendFile which has been freed!) */
|
|
|
|
void blend_free(BlendFile* blend_file);
|
|
|
|
|
|
/********************************/
|
|
/* Public data querying types */
|
|
/********************************/
|
|
|
|
|
|
/* heed this enum well. */
|
|
typedef enum {
|
|
/* you're unlikely to encounter these in the wild. */
|
|
BLEND_OBJ_NULL,
|
|
BLEND_OBJ_OPAQUE,
|
|
|
|
/* these object types are fetchable as-is */
|
|
BLEND_OBJ_UCHAR8,
|
|
BLEND_OBJ_CHAR8,
|
|
BLEND_OBJ_USHORT16,
|
|
BLEND_OBJ_SHORT16,
|
|
BLEND_OBJ_ULONG32,
|
|
BLEND_OBJ_LONG32,
|
|
BLEND_OBJ_FLOAT,
|
|
BLEND_OBJ_DOUBLE,
|
|
BLEND_OBJ_POINTER,
|
|
|
|
/* you'll need to extract the fields from these individually */
|
|
BLEND_OBJ_STRUCT
|
|
} BlendObjType;
|
|
|
|
typedef void* BlendBlockPointer;
|
|
|
|
/* note: treat this as an opaque type and you'll live longer. */
|
|
typedef struct {
|
|
long type; long name; BlendBlockPointer block;
|
|
long entry_index; long field_index;
|
|
} BlendObject;
|
|
|
|
|
|
/* The callback type for passing to blend_foreach_block() (the callback
|
|
should return zero if it doesn't want to see any more blocks.) */
|
|
#define BLENDBLOCKCALLBACK_RETURN int
|
|
#define BLENDBLOCKCALLBACK_ARGS BlendBlockPointer block, \
|
|
BlendFile* blend_file, \
|
|
void* userdata
|
|
typedef BLENDBLOCKCALLBACK_RETURN(BlendBlockCallback)
|
|
(BLENDBLOCKCALLBACK_ARGS);
|
|
|
|
|
|
/********************************/
|
|
/* File info dumping functions */
|
|
/********************************/
|
|
|
|
/* these functions simply print dumps of information about the given
|
|
BlendFile. These are vital for familiarising yourself with the
|
|
structure of Blender's various scene objects if you're using the
|
|
low/mid-level APIs to construct queries to extract information about
|
|
specific types of objects that haven't been conveniently abstracted by
|
|
the high-level API yet. (That is, most of them right now, particularly
|
|
the more obscure or deprecated ones.) */
|
|
|
|
/* print out the size, field-types and field-names of all of the varieties
|
|
of types (atomic and struct) represented within this BlendFile. The
|
|
sizes are the in-file representations; the in-memory representations
|
|
are potentially subject to additional padding and conversions.
|
|
*/
|
|
void blend_dump_typedefs(BlendFile* bf);
|
|
|
|
/* For every top-level block of data in the file, print the block's
|
|
tag, its in-memory address, its type, and the number of entries of that
|
|
type. (Every pointer in a structure should point to one of these
|
|
in-memory block addresses because we convert from in-file pointers to
|
|
in-memory pointers automagically; a few in-file pointers within structures
|
|
do actually point somewhere into the middle of a block or nowhere, which we
|
|
don't currently support and silently convert to NULL.) Also, any structs
|
|
at the top-level with an id->name have that name printed out. */
|
|
void blend_dump_blocks(BlendFile* bf);
|
|
|
|
|
|
/********************************/
|
|
/* Low-level querying functions */
|
|
/********************************/
|
|
|
|
|
|
/* Calls the user-supplied callback function for every top-level
|
|
data block in the .blend file. You can use this to count blocks
|
|
(which is pretty pointless) or search for a particular block you're
|
|
interested in. */
|
|
void blend_foreach_block(BlendFile* blend_file,
|
|
BlendBlockCallback* func,
|
|
void* userdata);
|
|
|
|
/* Returns the tag-name ('IM', 'DATA', 'ME', etc) for the given
|
|
top-level data block. */
|
|
const char* blend_block_get_tagname(BlendFile* blend_file,
|
|
BlendBlockPointer block);
|
|
|
|
/* Returns the type of the given top-level data block in raw
|
|
string form ('uchar', 'float', 'MFace', 'Mesh', etc). */
|
|
const char* blend_block_get_typename(BlendFile* blend_file,
|
|
BlendBlockPointer block);
|
|
|
|
/* Translate a pointer from the file's raw data into a BlendBlockPointer
|
|
that you can query via the API. You will usually NOT need to ever
|
|
use this unless you're manually extracting pointers from opaque raw data
|
|
types. Returns NULL on failure or if the input pointer is really NULL. */
|
|
BlendBlockPointer blend_block_from_blendpointer(BlendFile *blend_file,
|
|
uint32_t blendpointer);
|
|
|
|
/* Returns the number of entries there are in the given top-level
|
|
data block (a top-level data block is like an array of entries of a specific
|
|
Blender type, this type usually being one of Blender's structs). */
|
|
int blend_block_get_entry_count(BlendFile* blend_file,
|
|
BlendBlockPointer block);
|
|
|
|
/* This gets an object handle on the Nth piece of data (in the range
|
|
0..TOTAL-1, where TOTAL is the figure returned by
|
|
blend_block_get_entry_count() ) in the given top-level block. */
|
|
BlendObject blend_block_get_object(BlendFile* blend_file,
|
|
BlendBlockPointer block,
|
|
int entry_index);
|
|
|
|
/* Returns a BlendObjType enum handy for checking that the general type
|
|
of the object you have a handle on is what you're expecting. */
|
|
BlendObjType blend_object_type(BlendFile* blend_file,
|
|
BlendObject obj);
|
|
|
|
/* Given a BlendObject of type BLEND_OBJ_STRUCT in 'obj', fill in the
|
|
BlendObject pointed to by 'result' with a handle to the named
|
|
field of that structure (note that the resulting data object might
|
|
itself be a structure!). 0 is returned on failure (i.e. this structure
|
|
does not have a field of the requested name, or you supplied an
|
|
object which is not a structure). */
|
|
int blend_object_structure_getfield(BlendFile* blend_file,
|
|
BlendObject *result,
|
|
BlendObject obj,
|
|
const char* field_name);
|
|
|
|
/* Gets the size (in elements) of an object which is a 1D or 2D array.
|
|
A non-array is equivalent to an array of size 1x1. A 1D array will
|
|
always have dim1 == 1. */
|
|
void blend_object_array_getdims(BlendFile* blend_file,
|
|
BlendObject obj,
|
|
int* dim1, int* dim2);
|
|
|
|
/* This fetches a piece of data from the .blend file in a format
|
|
suitable for your architecture (i.e. ints will be of proper size
|
|
and endianness, pointers are transformed to valid BlendBlockPointers
|
|
or NULL, etc) into the address pointed to by dest. It's up to you to
|
|
check that the data you're asking for will fit into the type you're
|
|
trying to put it in (use blend_object_type() and see the BlendObjType
|
|
enum to check that the object's type is the one you're expecting.)
|
|
|
|
Composite structures (BLEND_OBJ_STRUCT) are not handled atomically;
|
|
use blend_object_structure_getfield() to extract each named field from
|
|
a structure individually.
|
|
|
|
1 is returned on success. Failure occurs when you try to extract
|
|
data from a structure (see blend_object_structure_getfield()) or
|
|
an array (use blend_object_array_getdata()).
|
|
*/
|
|
int blend_object_getdata(BlendFile* blend_file,
|
|
void* dest, BlendObject obj);
|
|
|
|
/* This operates like blend_object_getdata() except that it is happy
|
|
to copy an item of data out of an array. The array is always treated
|
|
as two-dimensional (data[dimension1][dimension2]); if you're accessing
|
|
a one-dimensional array then simply specify dim_index_1 as 0.
|
|
(Indices are in the range 0..DIMSIZE-1.)
|
|
|
|
Similarly, plain non-array data can be fetched by specifying
|
|
dim_index_1 == dim_index_2 == 0. This makes
|
|
blend_object_array_getdata(bf, dest, obj, 0, 0) equivalent to
|
|
blend_object_getdata(bf, dest, obj) except that it is happy to
|
|
be called with an array, from which it will extract the first
|
|
element.
|
|
|
|
Like blend_object_getdata(), it will not fetch a structure (from
|
|
an array of structures; fortunately I've not seen a .blend file
|
|
featuring an array of structures so we'll bridge that API gap
|
|
when we come to it).
|
|
*/
|
|
int blend_object_array_getdata(BlendFile* blend_file,
|
|
void* dest, BlendObject obj,
|
|
int dim_index_1, int dim_index_2);
|
|
|
|
/********************************/
|
|
/* Mid-level querying functions */
|
|
/********************************/
|
|
|
|
typedef unsigned long BlendLayerMask;
|
|
|
|
/* extract a string from a char-array or uchar-array object, up to
|
|
max_chars in length including the \0 terminator. If the object is
|
|
a two-dimensional array then the first string is extracted. Returns
|
|
0 on failure.
|
|
*/
|
|
int blend_object_getstring(BlendFile* blend_file,
|
|
BlendObject obj,
|
|
char *dest, int max_chars);
|
|
|
|
/* Searches the file for a top-level object with the given ID name.
|
|
Typical ID names are 'OBCamera', 'MECircle.003', 'MAplastic', 'TEgrass' etc.
|
|
The first two characters of an ID name keep the namespaces separate,
|
|
so that a material (MA) with the name 'metal' is distinguishable from
|
|
a texture (TE) with the name 'metal'. That's a foible of Blender itself.
|
|
|
|
blend_object_get_by_IDname() returns 0 on failure. It only returns one
|
|
object of the given IDname; there should indeed be only one, as Blender
|
|
enforces this uniqueness.
|
|
*/
|
|
int blend_object_get_by_IDname(BlendFile* blend_file,
|
|
BlendObject *result,
|
|
const char* IDname);
|
|
/* get string from [obj].ID.name -- caller allocs/frees */
|
|
int blend_object_get_IDname(BlendFile* blend_file,
|
|
BlendObject obj,
|
|
char *dest, int max_chars);
|
|
|
|
/* returns !0 if the blender Object whose handle is objobj is a top-level
|
|
object -- that is, it's not a child of another Object. */
|
|
int blend_obj_is_rootobject(BlendFile *bf, BlendObject *objobj);
|
|
/* return the layers (bitmask) that an Object lives on. */
|
|
BlendLayerMask blend_obj_get_layermask(BlendFile *bf, BlendObject *objobj);
|
|
|
|
/* These functions can be a bit slow -- each one requires a linear scan
|
|
of the file's blocks. But they're handy... */
|
|
/* Return number of children that this Object has. Can be 0. */
|
|
int blend_obj_get_childcount(BlendFile *bf, BlendObject *objobj);
|
|
/* Gets child number childnum of the Object. childnum=0 returns
|
|
the first, childnum=1 returns the second, etc. */
|
|
BlendBlockPointer blend_obj_get_child(BlendFile *bf, BlendObject *objobj,
|
|
int childnum);
|
|
|
|
/*********************************/
|
|
/* High-level querying functions */
|
|
/*********************************/
|
|
|
|
typedef struct {
|
|
int bone_id;
|
|
float weight;
|
|
} bDeformWeight;
|
|
|
|
typedef struct {
|
|
float xyz[3];
|
|
float cnormal[3]; /* cosmetic normal */
|
|
int mat;
|
|
bDeformWeight* deform_weights;
|
|
int deform_weights_count;
|
|
} bVert;
|
|
|
|
|
|
#define BVERT_HAS_CNORMAL(BV) ((BV)->cnormal[0] != 0.0f || \
|
|
(BV)->cnormal[1] != 0.0f || \
|
|
(BV)->cnormal[2] != 0.0f)
|
|
|
|
#define BFACE_FLAG_SMOOTH 0x01
|
|
|
|
typedef struct _bImage {
|
|
|
|
void* m_packedImagePtr;
|
|
int m_sizePackedImage;
|
|
char m_imagePathName [128];
|
|
|
|
int m_ok;
|
|
|
|
int m_xrep;
|
|
int m_yrep;
|
|
|
|
} bImage;
|
|
|
|
typedef struct {
|
|
int v[4];
|
|
float rgba[4][4]; /* vertex colours */
|
|
float rgba2[4][4]; /* texture face colours (errrr...?) */
|
|
float uv[4][2];
|
|
bImage* m_image;
|
|
int mat;
|
|
unsigned char flags;
|
|
int m_flag;
|
|
int m_mode;
|
|
BlendBlockPointer image_id;
|
|
} bFace;
|
|
|
|
|
|
#define BFACE_HAS_TEXTURE(BF) ((BF)->image_id != NULL)
|
|
#define BFACE_IS_QUAD(BF) ((BF)->v[3] != 0)
|
|
#define BFACE_IS_TRI(BF) ((BF)->v[2] != 0 && (BF)->v[3] == 0)
|
|
#define BFACE_IS_LINE(BF) ((BF)->v[1] != 0 && (BF)->v[2] == 0)
|
|
|
|
typedef enum {
|
|
BTEX_AFFECT_COLOUR = 0x01,
|
|
BTEX_AFFECT_ALPHA = 0x02,
|
|
BTEX_AFFECT_EMIT = 0x04,
|
|
BTEX_AFFECT_NORMAL = 0x08,
|
|
BTEX_AFFECT_NEGNORM = 0x10,
|
|
BTEX_AFFECT_STENCIL = 0x20 /* not really an 'affect' in blender, but it is */
|
|
} bTexLayerAffects;
|
|
|
|
typedef enum {
|
|
BTEX_BLEND_NORMAL, /* 'mix' */
|
|
BTEX_BLEND_MULTIPLY, /* 'mul' -- modulate. */
|
|
BTEX_BLEND_ADD,
|
|
BTEX_BLEND_SUB
|
|
} bTexLayerBlendmode;
|
|
|
|
typedef enum {
|
|
BTEX_COORDS_NONE,
|
|
BTEX_COORDS_UV,
|
|
BTEX_COORDS_REFLECT
|
|
} bTexLayerCoordsType;
|
|
|
|
typedef enum {
|
|
BIMG_FLAG_INTERPOLATE = 0x01, /* upsample */
|
|
BIMG_FLAG_ANTIALIAS = 0x02, /* downsample */
|
|
BIMG_FLAG_MIPMAP = 0x04 /* use mipmaps */
|
|
} bTexImageFlags;
|
|
|
|
typedef struct {
|
|
char *filename; /* image file name -- absolute path! -- NULL if not image. */
|
|
bTexLayerAffects affects_mask;
|
|
bTexLayerBlendmode blend_mode;
|
|
bTexLayerCoordsType coords_type;
|
|
/* Tex substruct */
|
|
int is_st_clamped; /* otherwise, repeat... (GL texwrap mode.) */
|
|
bTexImageFlags flags;
|
|
short Nflags, Ntype; /* not decoded yet */
|
|
short xrepeat, yrepeat; /* amounts to scale texcoords by, really */
|
|
} bTexLayer;
|
|
|
|
typedef enum {
|
|
BMAT_FEATURE_VCOLLIGHT = 0x01,
|
|
BMAT_FEATURE_VCOLPAINT = 0x02,
|
|
BMAT_FEATURE_TEXFACE = 0x04,
|
|
BMAT_FEATURE_SHADELESS = 0x08,
|
|
BMAT_FEATURE_WIRE = 0x10 /* wireframe rendering */
|
|
} bMatFeatureMask;
|
|
|
|
#define BLENDER_MAX_TEX_LAYERS 8
|
|
typedef struct {
|
|
bTexLayer *tex_layer[BLENDER_MAX_TEX_LAYERS];
|
|
bMatFeatureMask feature_mask;
|
|
float colour_rgba[4]; /* main material colour */
|
|
float emit; /* emissive strength, 0..1 */
|
|
} bMaterial;
|
|
|
|
typedef float bMatrix[4][4];
|
|
|
|
typedef struct _bMesh{
|
|
bVert *vert;
|
|
int vert_count;
|
|
bFace *face;
|
|
int face_count;
|
|
bMaterial *material; /* or NULL if none */
|
|
} bMesh;
|
|
|
|
typedef enum {
|
|
BOBJ_TYPE_UNKNOWN,
|
|
BOBJ_TYPE_NULL, /* indicates object has no data associated with it! */
|
|
BOBJ_TYPE_MESH,
|
|
BOBJ_TYPE_INVALID_MESH,
|
|
BOBJ_TYPE_CAMERA,
|
|
BOBJ_TYPE_LAMP
|
|
} bObjType;
|
|
|
|
typedef enum {
|
|
BAQ_INCLUDE_CHILDREN = 0x0001
|
|
} bAcquireFlags;
|
|
|
|
typedef struct _bObj{
|
|
bObjType type;
|
|
char *name;
|
|
|
|
bMatrix transform; /* local transformation matrix */
|
|
bMatrix parentimat; /* parent's inverse transform matrix */
|
|
float scaling[3]; /* scaling component of transform */
|
|
float rotphr[3]; /* pitch/head/roll rotation component of transform (use for normals) */
|
|
float location[3]; /* location component of transform */
|
|
unsigned char transflags; /* NOT DECODED YET, RAW BYTE */
|
|
float mass;//used for rigid body dynamics
|
|
int gameflag; //used to detect object type (static, ghost, dynamic, rigid body, soft body)
|
|
int boundtype; //used to detect collision shape type
|
|
|
|
union {
|
|
void *dummy;
|
|
bMesh *mesh;
|
|
} data;
|
|
|
|
} bObj;
|
|
|
|
|
|
bObj *blend_alloc_obj(void);
|
|
void blend_init_obj(bObj *obj);
|
|
void blend_free_obj(bObj *obj);
|
|
void blend_free_obj_inner(bObj *obj);
|
|
void blend_acquire_obj_from_obj(BlendFile *bf, BlendObject *objobj,
|
|
bObj *outobj,
|
|
/* malloc'd BlendObject will be written here if pointer if non-NULL: */ BlendObject **outblendobject);
|
|
|
|
bMesh *blend_alloc_mesh(void);
|
|
void blend_init_mesh(bMesh *mesh);
|
|
void blend_free_mesh_inner(bMesh *mesh);
|
|
void blend_free_mesh(bMesh *mesh);
|
|
void blend_acquire_mesh(const char *fname, const char *want_name, bMesh *mesh);
|
|
void blend_acquire_mesh_from_obj(BlendFile *bf,
|
|
BlendObject *meobj,
|
|
bMesh *mesh);
|
|
/* apply transformation found in 'obj' to 'mesh' */
|
|
void blend_transform_mesh_from_obj(bMesh *mesh, bObj *obj);
|
|
|
|
bMaterial *blend_alloc_material(void);
|
|
void blend_init_material(bMaterial *mat);
|
|
void blend_free_material(bMaterial *mat);
|
|
void blend_acquire_material_from_obj(BlendFile *bf, BlendObject *meobj,
|
|
bMaterial *mat);
|
|
|
|
bTexLayer *blend_alloc_texlayer(void);
|
|
void blend_init_texlayer(bTexLayer *tl);
|
|
void blend_free_texlayer(bTexLayer *tl);
|
|
void blend_acquire_texlayer_from_obj(BlendFile *bf, BlendObject *tlobj,
|
|
bTexLayer *tl);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|