909 lines
20 KiB
C
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);
|
|
}
|
|
|
|
|