brender-v1.1.2/FW/RENDSUPT.C
2022-05-04 18:14:23 -07:00

909 lines
20 KiB
C

/*
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
*
* $Id: rendsupt.c 1.36 1995/02/22 21:42:33 sam Exp $
* $Locker: $
*
* Misc. support routines for renderer
*/
#include <string.h>
#include "fw.h"
#include "brassert.h"
#include "datafile.h"
static char rscid[] = "$Id: rendsupt.c 1.36 1995/02/22 21:42:33 sam Exp $";
/*
* Accumulate the transform between an actor and the root
*
* XXX Could accumulate a flag to say that matrix is only rotation
* and translation - makes invertion cheaper
*
* Returns a flag to indicate if the actor did have world
* as an ancestor
*/
int BrActorToRoot(br_actor *a, br_actor *world, br_matrix34 *m)
{
UASSERT(a != NULL);
UASSERT(world != NULL);
UASSERT(m != NULL);
/*
* Catch stupid case
*/
if(a == world) {
BrMatrix34Identity(m);
return 1;
}
/*
* Start with actor's transform
*/
BrMatrix34Transform(m,&a->t);
a = a->parent;
/*
* Accumulate all the transforms up to the root (ignoring any
* identity transforms)
*/
for( ; a && a != world; a = a->parent )
if(a->t.type != BR_TRANSFORM_IDENTITY)
BrMatrix34PostTransform(m,&a->t);
return (a == world);
}
/*
* Invoke a callback for each one of an actors children
*/
br_uint_32 BR_PUBLIC_ENTRY BrActorEnum(br_actor *parent,
br_actor_enum_cbfn *callback, void *arg)
{
br_actor *a;
br_uint_32 r;
UASSERT(parent != NULL);
UASSERT(callback != NULL);
BR_FOR_SIMPLELIST(&parent->children,a)
if((r = callback(a,arg)))
return r;
return 0;
}
/*
* Find all the named actors matching a pattern in the given hierachy
*
*/
int BR_PUBLIC_ENTRY BrActorSearchMany(br_actor *root, char *pattern, br_actor **actors, int max)
{
br_actor *a;
char *sub;
int n,remaining = max;
UASSERT(root != NULL);
UASSERT(actors != NULL);
/*
* Take first component of path, and match it against all children
* of the root actor
*/
while(*pattern =='/')
pattern++;
for(sub=pattern; (*sub != '\0') && (*sub != '/'); sub++)
;
while(*sub == '/')
sub++;
BR_FOR_SIMPLELIST(&root->children,a) {
/*
* Abort if no more space for results
*/
if(remaining <= 0)
break;
if(NamePatternMatch(pattern,a->identifier)) {
/*
* If there is more path
* recurse with remainder of path
* else
* add actor to accumulated list
*/
if(*sub != '\0') {
n = BrActorSearchMany(a,sub,actors,remaining);
actors += n;
remaining -= n;
} else {
*actors++ = a;
remaining--;
}
}
}
return max - remaining;
}
/*
* Find the first named actor matching a pattern in the given hierachy
*/
br_actor * BR_PUBLIC_ENTRY BrActorSearch(br_actor *root, char *pattern)
{
br_actor *a;
UASSERT(root != NULL);
if(BrActorSearchMany(root,pattern,&a,1) == 1)
return a;
else
return NULL;
}
/*
* Recursive function to propgate depth number down a hierachy
*/
STATIC void RenumberActor(br_actor *a,int d)
{
br_actor *ac;
a->depth = d;
BR_FOR_SIMPLELIST(&a->children,ac)
RenumberActor(ac,d+1);
}
/*
* Add an actor to the children of the given parent
*/
br_actor * BR_PUBLIC_ENTRY BrActorAdd(br_actor *parent, br_actor *a)
{
br_actor *ac;
UASSERT(a != NULL);
UASSERT(parent != NULL);
UASSERT(a->prev == NULL);
/*
* Link this actor into sibling list of parent
*/
BR_SIMPLEADDHEAD(&parent->children,a);
a->parent = parent;
/*
* Update depth for added hierachy
*/
a->depth = parent->depth+1;
BR_FOR_SIMPLELIST(&a->children,ac)
RenumberActor(ac,a->depth+1);
return a;
}
br_actor * BR_PUBLIC_ENTRY BrActorRemove(br_actor *a)
{
br_actor *ac;
UASSERT(a != NULL);
UASSERT(a->prev != NULL);
BR_SIMPLEREMOVE(a);
/*
* Renumber the removed hierachy
*/
a->depth = 0;
BR_FOR_SIMPLELIST(&a->children,ac)
RenumberActor(ac,1);
return a;
}
/*
* Move an actor in the heirachy, but preserve it's apparent world
* transform by manipulating the transform
*/
void BR_PUBLIC_ENTRY BrActorRelink(br_actor *parent,br_actor *a)
{
}
/*
* Allocate a new actor structure and return a pointer to it
*
* Model actors are allocated from a pool associated with the renderer -
* this is a very common case and is worth the speedup
*
* All other actor types come from the normal heap - and include any
* type specific data bocks
*
*/
br_actor * BR_PUBLIC_ENTRY BrActorAllocate(br_uint_8 type, void *type_data)
{
br_actor *a = NULL;
br_light *light;
br_camera *camera;
br_bounds *bounds;
br_vector4 *clip_plane;
UASSERT(type < BR_ACTOR_MAX);
a = BrResAllocate(fw.res,sizeof(*a),BR_MEMORY_ACTOR);
/*
* Initialise common fields
*/
BrSimpleNewList((struct br_simple_list *) &a->children);
a->type = type;
a->depth = 0;
a->t.type = BR_TRANSFORM_MATRIX34;
BrMatrix34Identity(&a->t.t.mat);
if(type_data) {
/*
* Fill in the type_data pointer
*/
a->type_data = type_data;
} else {
/*
* No type data - allocate a default
*/
switch(type) {
case BR_ACTOR_LIGHT:
/*
* Setup to be a directional light source
*/
light = BrResAllocate(a, sizeof(*light), BR_MEMORY_LIGHT);
a->type_data = light;
light->type = BR_LIGHT_DIRECT;
light->colour = BR_COLOUR_RGB(255,255,255);
light->attenuation_c = BR_SCALAR(1.0);
light->cone_outer = BR_ANGLE_DEG(15.0);
light->cone_inner = BR_ANGLE_DEG(10.0);
break;
case BR_ACTOR_CAMERA:
/*
* Perspective camera, 45 degree FOV
*/
camera = BrResAllocate(a, sizeof(*camera), BR_MEMORY_CAMERA);
a->type_data = camera;
camera->type = BR_CAMERA_PERSPECTIVE;
camera->field_of_view = BR_ANGLE_DEG(45);
camera->hither_z = BR_SCALAR(1.0);
camera->yon_z = BR_SCALAR(10.0);
camera->aspect = BR_SCALAR(1.0);
break;
case BR_ACTOR_BOUNDS:
/*
* Allocate a bounds structure
*/
bounds = BrResAllocate(a, sizeof(*bounds), BR_MEMORY_BOUNDS);
a->type_data = bounds;
break;
case BR_ACTOR_CLIP_PLANE:
/*
* Allocate a 4-vector
*/
clip_plane = BrResAllocate(a, sizeof(*clip_plane), BR_MEMORY_BOUNDS);
a->type_data = clip_plane;
break;
}
}
return a;
}
/*
* Free an actor
*/
STATIC void InternalActorFree(br_actor *a)
{
/*
* Release any children
*/
while(BR_SIMPLEHEAD(&a->children))
InternalActorFree(BR_SIMPLEREMOVE(a->children));
/*
* Release this actor
*/
BrResFree(a);
}
void BR_PUBLIC_ENTRY BrActorFree(br_actor *a)
{
UASSERT(a->prev == NULL);
InternalActorFree(a);
}
/**
** Specific versions of registry calls for each class
**/
#if 0
/*
* Macro to define all the calls except BrXXXAdd()
*/
#define REG_CALLS(class,type,reg)\
\
type * BR_PUBLIC_ENTRY Br##class##Remove(type *##lname##)\
{ return RegistryRemove(&fw.reg,##lname##); }\
\
type * BR_PUBLIC_ENTRY Br##class##Find(char *pattern)\
{ return RegistryFind(&fw.reg,pattern); }\
\
int BR_PUBLIC_ENTRY Br##class##AddMany(type **items, int n)\
{ return RegistryAddMany(&fw.reg, items, n); }\
\
int BR_PUBLIC_ENTRY Br##class##RemoveMany(type **items, int n)\
{ return RegistryRemoveMany(&fw.reg, items, n); }\
\
int BR_PUBLIC_ENTRY Br##class##FindMany(char *pattern, type **items, int max)\
{ return RegistryFindMany(&fw.reg, pattern, items, max); }\
\
int BR_PUBLIC_ENTRY Br##class##Count(char *pattern)\
{ return RegistryCount(&fw.reg,pattern); }\
\
int BR_PUBLIC_ENTRY Br##class##Enum(char *pattern,\
int (*callback)(type *item, void *arg), void *arg)\
{ return RegistryEnum(&fw.reg,pattern,callback,arg); }
#endif
/*
* Models
*/
br_model * BR_PUBLIC_ENTRY BrModelAdd(br_model *model)
{
RegistryAdd(&fw.reg_models,model);
BrModelPrepare(model,BR_MPREP_ALL);
return model;
}
br_model * BR_PUBLIC_ENTRY BrModelRemove(br_model *model)
{ return RegistryRemove(&fw.reg_models,model); }
br_model * BR_PUBLIC_ENTRY BrModelFind(char *pattern)
{ return RegistryFind(&fw.reg_models,pattern); }
br_model_find_cbfn * BR_PUBLIC_ENTRY BrModelFindHook(br_model_find_cbfn *hook)
{
br_model_find_cbfn * old = (br_model_find_cbfn *) fw.reg_models.find_failed_hook;
fw.reg_models.find_failed_hook = (br_find_failed_cbfn *)hook;
return old;
}
int BR_PUBLIC_ENTRY BrModelAddMany(br_model **items, int n)
{
int i,r=0;
for(i=0; i < n; i++)
if(BrModelAdd(*items++) != NULL)
r++;
return r;
}
int BR_PUBLIC_ENTRY BrModelRemoveMany(br_model **items, int n)
{ return RegistryRemoveMany(&fw.reg_models, (void **)items, n); }
int BR_PUBLIC_ENTRY BrModelFindMany(char *pattern, br_model **items, int max)
{ return RegistryFindMany(&fw.reg_models, pattern, (void **)items, max); }
int BR_PUBLIC_ENTRY BrModelCount(char *pattern)
{ return RegistryCount(&fw.reg_models,pattern); }
int BR_PUBLIC_ENTRY BrModelEnum(char *pattern,
br_model_enum_cbfn *callback, void *arg)
{ return RegistryEnum(&fw.reg_models,pattern,(br_enum_cbfn *)callback,arg); }
/*
* Materials
*/
br_material * BR_PUBLIC_ENTRY BrMaterialAdd(br_material *material)
{
BrMaterialPrepare(material,0);
return RegistryAdd(&fw.reg_materials,material);
}
br_material * BR_PUBLIC_ENTRY BrMaterialRemove(br_material *material)
{
return RegistryRemove(&fw.reg_materials,material);
}
br_material * BR_PUBLIC_ENTRY BrMaterialFind(char *pattern)
{
return RegistryFind(&fw.reg_materials,pattern);
}
br_material_find_cbfn * BR_PUBLIC_ENTRY BrMaterialFindHook(br_material_find_cbfn *hook)
{
br_material_find_cbfn * old = (br_material_find_cbfn *) fw.reg_materials.find_failed_hook;
fw.reg_materials.find_failed_hook = (br_find_failed_cbfn *)hook;
return old;
}
int BR_PUBLIC_ENTRY BrMaterialAddMany(br_material **items, int n)
{
int i,r=0;
for(i=0; i < n; i++)
if(BrMaterialAdd(*items++) != NULL)
r++;
return r;
}
int BR_PUBLIC_ENTRY BrMaterialRemoveMany(br_material **items, int n)
{
return RegistryRemoveMany(&fw.reg_materials, (void**)items, n);
}
int BR_PUBLIC_ENTRY BrMaterialFindMany(char *pattern, br_material **items, int max)
{
return RegistryFindMany(&fw.reg_materials, pattern, (void **)items, max);
}
int BR_PUBLIC_ENTRY BrMaterialCount(char *pattern)
{
return RegistryCount(&fw.reg_materials,pattern);
}
int BR_PUBLIC_ENTRY BrMaterialEnum(char *pattern,
br_material_enum_cbfn *callback, void *arg)
{
return RegistryEnum(&fw.reg_materials,pattern,(br_enum_cbfn *)callback,arg);
}
/*
* Textures
*/
br_pixelmap * BR_PUBLIC_ENTRY BrMapAdd(br_pixelmap *pixelmap)
{
return RegistryAdd(&fw.reg_textures,pixelmap);
}
br_pixelmap * BR_PUBLIC_ENTRY BrMapRemove(br_pixelmap *pixelmap)
{
return RegistryRemove(&fw.reg_textures,pixelmap);
}
br_pixelmap * BR_PUBLIC_ENTRY BrMapFind(char *pattern)
{
return RegistryFind(&fw.reg_textures,pattern);
}
br_map_find_cbfn * BR_PUBLIC_ENTRY BrMapFindHook(br_map_find_cbfn *hook)
{
br_map_find_cbfn * old = (br_map_find_cbfn *) fw.reg_textures.find_failed_hook;
fw.reg_textures.find_failed_hook = (br_find_failed_cbfn *)hook;
return old;
}
int BR_PUBLIC_ENTRY BrMapAddMany(br_pixelmap **items, int n)
{
return RegistryAddMany(&fw.reg_textures, (void**)items, n);
}
int BR_PUBLIC_ENTRY BrMapRemoveMany(br_pixelmap **items, int n)
{
return RegistryRemoveMany(&fw.reg_textures, (void **)items, n);
}
int BR_PUBLIC_ENTRY BrMapFindMany(char *pattern, br_pixelmap **items, int max)
{
return RegistryFindMany(&fw.reg_textures, pattern, (void **)items, max);
}
int BR_PUBLIC_ENTRY BrMapCount(char *pattern)
{
return RegistryCount(&fw.reg_textures,pattern);
}
int BR_PUBLIC_ENTRY BrMapEnum(char *pattern,
br_map_enum_cbfn *callback, void *arg)
{
return RegistryEnum(&fw.reg_textures,pattern,(br_enum_cbfn *)callback,arg);
}
/*
* Tables
*/
br_pixelmap * BR_PUBLIC_ENTRY BrTableAdd(br_pixelmap *pixelmap)
{
return RegistryAdd(&fw.reg_tables,pixelmap);
}
br_pixelmap * BR_PUBLIC_ENTRY BrTableRemove(br_pixelmap *pixelmap)
{
return RegistryRemove(&fw.reg_tables,pixelmap);
}
br_pixelmap * BR_PUBLIC_ENTRY BrTableFind(char *pattern)
{
return RegistryFind(&fw.reg_tables,pattern);
}
br_table_find_cbfn * BR_PUBLIC_ENTRY BrTableFindHook(br_table_find_cbfn *hook)
{
br_table_find_cbfn * old = (br_table_find_cbfn *) fw.reg_tables.find_failed_hook;
fw.reg_tables.find_failed_hook = (br_find_failed_cbfn *)hook;
return old;
}
int BR_PUBLIC_ENTRY BrTableAddMany(br_pixelmap **items, int n)
{
return RegistryAddMany(&fw.reg_tables, (void **)items, n);
}
int BR_PUBLIC_ENTRY BrTableRemoveMany(br_pixelmap **items, int n)
{
return RegistryRemoveMany(&fw.reg_tables, (void **)items, n);
}
int BR_PUBLIC_ENTRY BrTableFindMany(char *pattern, br_pixelmap **items, int max)
{
return RegistryFindMany(&fw.reg_tables, pattern, (void **)items, max);
}
int BR_PUBLIC_ENTRY BrTableCount(char *pattern)
{
return RegistryCount(&fw.reg_tables,pattern);
}
int BR_PUBLIC_ENTRY BrTableEnum(char *pattern,
br_table_enum_cbfn *callback, void *arg)
{
return RegistryEnum(&fw.reg_tables,pattern,(br_enum_cbfn *)callback,arg);
}
/*
* Resource Classes
*/
br_resource_class * BR_PUBLIC_ENTRY BrResClassAdd(br_resource_class *rclass)
{
br_resource_class *r;
UASSERT(rclass != NULL);
/*
* The registry resource is initally faked
*/
UASSERT(rclass->res_class == BR_MEMORY_REGISTRY ||
rclass->res_class == BR_MEMORY_ANCHOR ||
fw.resource_class_index[rclass->res_class] == NULL);
r = RegistryAdd(&fw.reg_resource_classes,rclass);
if(r != NULL)
fw.resource_class_index[rclass->res_class] = r;
return r;
}
br_resource_class * BR_PUBLIC_ENTRY BrResClassRemove(br_resource_class *rclass)
{
br_resource_class *r;
UASSERT(rclass != NULL);
UASSERT(fw.resource_class_index[rclass->res_class] != NULL);
r = RegistryRemove(&fw.reg_resource_classes,rclass);
if(r != NULL)
fw.resource_class_index[rclass->res_class] = NULL;
return r;
}
br_resource_class * BR_PUBLIC_ENTRY BrResClassFind(char *pattern)
{
return RegistryFind(&fw.reg_resource_classes,pattern);
}
br_resclass_find_cbfn * BR_PUBLIC_ENTRY BrResClassFindHook(br_resclass_find_cbfn *hook)
{
br_resclass_find_cbfn * old =
(br_resclass_find_cbfn *) fw.reg_resource_classes.find_failed_hook;
fw.reg_resource_classes.find_failed_hook = (br_find_failed_cbfn *)hook;
return old;
}
int BR_PUBLIC_ENTRY BrResClassAddMany(br_resource_class **items, int n)
{
int i;
for(i=0; i < n; i++)
BrResClassAdd(*items++);
return n;
}
int BR_PUBLIC_ENTRY BrResClassRemoveMany(br_resource_class **items, int n)
{
int i,r;
for(i=0, r=0; i < n; i++)
if(BrResClassRemove(*items++))
r++;
return r;
}
int BR_PUBLIC_ENTRY BrResClassFindMany(char *pattern, br_resource_class **items, int max)
{
return RegistryFindMany(&fw.reg_resource_classes, pattern, (void **)items, max);
}
int BR_PUBLIC_ENTRY BrResClassCount(char *pattern)
{
return RegistryCount(&fw.reg_resource_classes,pattern);
}
int BR_PUBLIC_ENTRY BrResClassEnum(char *pattern,
br_resclass_enum_cbfn *callback, void *arg)
{
return RegistryEnum(&fw.reg_resource_classes,pattern,(br_enum_cbfn *)callback,arg);
}
/*
* Generate U and V values for a model's vertices.
*
* The vertices are optionally transformed by a 3x4 matrix
*
* The u,v values are then assigned according to one of the
* following schemes -
*
* Planar mapping:
* u = (x+1)/2
* v = (y+1)/2
*
* Spherical mapping:
* u = atan2(-z,x)/2*pi
* v = 1-atan2(sqrt(x*x+z*z),y)/pi
*
* Cylindrical mapping:
* u = atan2(-z,x)/2*pi
* v = (y+1)/2
*/
void BR_PUBLIC_ENTRY BrModelApplyMap(br_model *model,int map_type, br_matrix34 *xform)
{
int v;
br_vertex *vp;
br_vector3 mv;
br_matrix34 default_xform;
br_scalar d;
UASSERT(model != NULL);
UASSERT(model->vertices != NULL);
UASSERT(map_type >= 0 && map_type <= BR_APPLYMAP_CYLINDER);
/*
* If no default provided, use identity
*/
if(xform == NULL) {
BrMatrix34Identity(&default_xform);
xform = &default_xform;
}
/*
* Set mapping for each vertex
*/
for(v=0, vp=model->vertices; v < model->nvertices; v++, vp++) {
BrMatrix34ApplyP(&mv,&vp->p,xform);
switch(map_type) {
case BR_APPLYMAP_PLANE:
/*
* Planar mapping:
* u = (x+1)/2
* v = (y+1)/2
*/
vp->map.v[0] = BR_MUL(mv.v[0]+BR_SCALAR(1.0),
BrFractionToScalar(BR_FRACTION(0.5)));
vp->map.v[1] = BR_MUL(mv.v[1]+BR_SCALAR(1.0),
BrFractionToScalar(BR_FRACTION(0.5)));
break;
case BR_APPLYMAP_SPHERE:
/*
* Spherical mapping:
* u = atan2(-z,x)/2*pi
* v = 1-atan2(sqrt(x*x+z*z),y)/pi
*/
vp->map.v[0] = BR_DIV(
BrAngleToDegree(BR_ATAN2(-mv.v[2],mv.v[0])),
BR_SCALAR(360.0));
d = BR_LENGTH2(mv.v[0],mv.v[2]);
vp->map.v[1] = BR_SCALAR(1.0) - BR_DIV(
BrAngleToDegree(BR_ATAN2(d,mv.v[1])),
BR_SCALAR(180.0));
break;
case BR_APPLYMAP_CYLINDER:
/*
* Cylindrical mapping:
* u = atan2(-z,x)/2*pi
* v = (y+1)/2
*/
vp->map.v[0] = BR_DIV(
BrAngleToDegree(BR_ATAN2(-mv.v[2],mv.v[0])),
BR_SCALAR(360.0));
vp->map.v[1] = BR_MUL(mv.v[1]+BR_SCALAR(1.0),
BrFractionToScalar(BR_FRACTION(0.5)));
break;
}
}
}
/*
* Work out a transform such that it can be fed to BrModelApplyMap
* and have the mapping type fit the bounds of the model exactly
*
* The two axis along which the mapping can be applied are provided -
*
* BR_FITMAP_PLUS_X,
* BR_FITMAP_PLUS_Y,
* BR_FITMAP_PLUS_Z,
* BR_FITMAP_MINUS_X,
* BR_FITMAP_MINUS_Y,
* BR_FITMAP_MINUS_Z,
*
* Returns the supplied pointer to 'transform'
*/
br_matrix34 * BR_PUBLIC_ENTRY BrModelFitMap(br_model *model, int axis_0, int axis_1, br_matrix34 *transform)
{
br_vector3 axis_3;
br_vector3 tr;
br_vector3 sc;
int i;
static br_vector3 axis_vectors[] = {
BR_VECTOR3( 1, 0, 0), /* +X */
BR_VECTOR3( 0, 1, 0), /* +Y */
BR_VECTOR3( 0, 0, 1), /* +Z */
BR_VECTOR3(-1, 0, 0), /* -X */
BR_VECTOR3( 0,-1, 0), /* -Y */
BR_VECTOR3( 0, 0,-1), /* -Z */
};
UASSERT(model != NULL);
UASSERT(transform != NULL);
UASSERT(axis_0 >= BR_FITMAP_PLUS_X && axis_0 <= BR_FITMAP_MINUS_Z);
UASSERT(axis_1 >= BR_FITMAP_PLUS_X && axis_1 <= BR_FITMAP_MINUS_Z);
/*
* Start the mapping transform by filling in the two user
* supplied axes (as columns), and then using a cross product to generate
* the third column.
*/
BrMatrix34Identity(transform);
BrVector3Cross(&axis_3,
axis_vectors + axis_0,
axis_vectors + axis_1);
for(i=0; i< 3; i++) {
transform->m[i][0] = axis_vectors[axis_0].v[i];
transform->m[i][1] = axis_vectors[axis_1].v[i];
transform->m[i][2] = axis_3.v[i];
}
/*
* Find the translation to align the object with the mapping
*/
for(i=0; i< 3; i++)
tr.v[i] = -(BR_CONST_DIV(model->bounds.max.v[i],2) +
BR_CONST_DIV(model->bounds.min.v[i],2));
/*
* Find the scale to fit object to the mapping
*/
for(i=0; i< 3; i++)
if(model->bounds.max.v[i] != model->bounds.min.v[i])
sc.v[i] = BR_RCP(BR_CONST_DIV(model->bounds.max.v[i],2) -
BR_CONST_DIV(model->bounds.min.v[i],2));
else
sc.v[i] = BR_SCALAR(1.0);
BrMatrix34PreScale(transform,sc.v[0],sc.v[1],sc.v[2]);
BrMatrix34PreTranslate(transform,tr.v[0],tr.v[1],tr.v[2]);
return transform;
}
/*
* Free a model
*/
void BR_PUBLIC_ENTRY BrModelFree(br_model *m)
{
UASSERT(m != NULL);
BrResFree(m);
}
/*
* Allocate a model of a given size
*/
br_model * BR_PUBLIC_ENTRY BrModelAllocate(char *name, int nvertices, int nfaces)
{
br_model *m;
UASSERT(nvertices >= 0);
UASSERT(nfaces >= 0);
m = BrResAllocate(fw.res,sizeof(*m),BR_MEMORY_MODEL);
m->nvertices = nvertices;
m->nfaces = nfaces;
if(name)
m->identifier = BrResStrDup(m, name);
if(nvertices)
m->vertices = BrResAllocate(m, nvertices*sizeof(*m->vertices),BR_MEMORY_VERTICES);
if(nfaces)
m->faces = BrResAllocate(m, nfaces * sizeof(*m->faces),BR_MEMORY_FACES);
return m;
}
/*
* Allocate a material
*/
br_material * BR_PUBLIC_ENTRY BrMaterialAllocate(char *name)
{
br_material *m;
m = BrResAllocate(fw.res,sizeof(*m),BR_MEMORY_MATERIAL);
if(name)
m->identifier = BrResStrDup(m, name);
return m;
}
/*
* Free a material
*/
void BR_PUBLIC_ENTRY BrMaterialFree(br_material *m)
{
UASSERT(m != NULL);
BrResFree(m);
}