428 lines
9.3 KiB
C
428 lines
9.3 KiB
C
/*
|
|
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
|
|
*
|
|
* $Id: otable.c 2.9 1997/04/17 11:23:04 JOHNG Exp $
|
|
* $Locker: $
|
|
*
|
|
* order table support code
|
|
*/
|
|
#include "v1db.h"
|
|
#include "shortcut.h"
|
|
#include "brassert.h"
|
|
|
|
#include "math_ip.h"
|
|
#include "zsmacro.h"
|
|
|
|
BR_RCS_ID("$Id: otable.c 2.9 1997/04/17 11:23:04 JOHNG Exp $")
|
|
|
|
/*
|
|
* Smallest possible distance between Z bounds
|
|
*/
|
|
#define MINIMUM_RANGE 0.001
|
|
|
|
/*
|
|
* Allocate an order table
|
|
*/
|
|
br_order_table * BR_PUBLIC_ENTRY BrZsOrderTableAllocate(br_uint_16 size,br_uint_32 flags,br_uint_16 type)
|
|
{
|
|
br_order_table *order_table;
|
|
|
|
UASSERT_MESSAGE("Number of buckets are <= 0", size>0);
|
|
|
|
/*
|
|
* Allocate memory for order table structure
|
|
*/
|
|
order_table=BrResAllocate(v1db.res,sizeof(br_order_table),BR_MEMORY_ORDER_TABLE);
|
|
|
|
/*
|
|
* Allocate memory for bucket pointer table
|
|
*/
|
|
order_table->table=BrResAllocate(order_table,size*sizeof(br_primitive *),BR_MEMORY_ORDER_TABLE);
|
|
|
|
/*
|
|
* Fill in other order table members
|
|
*/
|
|
order_table->size=size;
|
|
order_table->next=NULL;
|
|
order_table->flags=flags;
|
|
order_table->type=type;
|
|
order_table->visits=0;
|
|
order_table->min_z=BR_SCALAR(0.0);
|
|
order_table->max_z=BR_SCALAR(0.0);
|
|
order_table->sort_z=BR_SCALAR(0.0);
|
|
order_table->scale=BR_SCALAR(0.0);
|
|
|
|
return order_table;
|
|
}
|
|
|
|
/*
|
|
* Free an order table
|
|
*/
|
|
void BR_PUBLIC_ENTRY BrZsOrderTableFree(br_order_table *order_table)
|
|
{
|
|
UASSERT_MESSAGE("BrZsOrderTableFree NULL pointer to an order table", order_table!=NULL);
|
|
|
|
BrResFree(order_table);
|
|
}
|
|
|
|
/*
|
|
* Set an actor's order table
|
|
*/
|
|
br_order_table * BR_PUBLIC_ENTRY BrZsActorOrderTableSet(br_actor *actor, br_order_table *order_table)
|
|
{
|
|
UASSERT(actor!=NULL);
|
|
|
|
actor->render_data=(void *)order_table;
|
|
|
|
return order_table;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get a pointer to an actor's order table
|
|
*/
|
|
br_order_table * BR_PUBLIC_ENTRY BrZsActorOrderTableGet(br_actor *actor)
|
|
{
|
|
UASSERT(actor!=NULL);
|
|
|
|
return (br_order_table *)actor->render_data;
|
|
}
|
|
|
|
|
|
/*
|
|
* Clear an order table
|
|
*/
|
|
br_order_table * BR_PUBLIC_ENTRY BrZsOrderTableClear(br_order_table *order_table)
|
|
{
|
|
UASSERT(order_table!=NULL);
|
|
|
|
BrMemSet(order_table->table,0,order_table->size*sizeof(br_primitive *));
|
|
|
|
return order_table;
|
|
}
|
|
|
|
/*
|
|
* Insert a primitive into an order table
|
|
*/
|
|
void BR_PUBLIC_ENTRY BrZsOrderTablePrimitiveInsert(br_order_table *order_table,
|
|
br_primitive *primitive,
|
|
br_uint_16 bucket)
|
|
{
|
|
UASSERT(primitive!=NULL);
|
|
UASSERT(order_table!=NULL);
|
|
UASSERT(bucket<order_table->size);
|
|
|
|
primitive->next=order_table->table[bucket];
|
|
order_table->table[bucket]=primitive;
|
|
}
|
|
|
|
/*
|
|
* Select a bucket, given vertices, bounds, size and sort type
|
|
*/
|
|
br_uint_16 BR_PUBLIC_ENTRY BrZsPrimitiveBucketSelect(br_scalar *z,
|
|
br_uint_16 type,
|
|
br_scalar min_z,
|
|
br_scalar max_z,
|
|
br_uint_16 size,
|
|
br_uint_16 sort_type)
|
|
{
|
|
br_uint_16 bucket;
|
|
br_scalar zprim,range,scale;
|
|
|
|
UASSERT(size>0);
|
|
UASSERT_MESSAGE("BrZsPrimitiveBucketSelect NULL pointer", z != NULL);
|
|
|
|
/*
|
|
* Determine sort value
|
|
*/
|
|
switch(type) {
|
|
|
|
case BR_PRIMITIVE_TRIANGLE:
|
|
SORT_VALUE_TRIANGLE(sort_type,z[0],z[1],z[2]);
|
|
break;
|
|
|
|
case BR_PRIMITIVE_LINE:
|
|
SORT_VALUE_EDGE(sort_type,z[0],z[1]);
|
|
break;
|
|
|
|
case BR_PRIMITIVE_POINT:
|
|
zprim=z[0];
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
* Calculate Z scale factor
|
|
*/
|
|
UASSERT_MESSAGE("Divide by zero error, max_z - min_z = 0", range != 0 );
|
|
range=BR_SUB(max_z,min_z);
|
|
if(range>BR_SCALAR(MINIMUM_RANGE)) scale=BR_DIV(BrIntToScalar(size),range);
|
|
else scale=BR_SCALAR(1.0/(float)MINIMUM_RANGE);
|
|
|
|
/*
|
|
* Select bucket and clamp to range
|
|
*/
|
|
zprim=BR_SUB(zprim,min_z);
|
|
if(zprim<BR_SCALAR(0.0)) zprim=BR_SCALAR(0.0);
|
|
bucket=BrScalarToInt(BR_MUL(scale,zprim));
|
|
if(bucket>=size) bucket=size-1;
|
|
|
|
return bucket;
|
|
}
|
|
|
|
|
|
/*
|
|
* Enable the primary order table
|
|
*/
|
|
void BR_PUBLIC_ENTRY BrZsOrderTablePrimaryEnable(br_order_table *order_table)
|
|
{
|
|
if(order_table) v1db.primary_order_table=order_table;
|
|
else v1db.primary_order_table=v1db.default_order_table;
|
|
}
|
|
|
|
/*
|
|
* Disable the primary order table
|
|
*/
|
|
void BR_PUBLIC_ENTRY BrZsOrderTablePrimaryDisable(void)
|
|
{
|
|
v1db.primary_order_table=NULL;
|
|
}
|
|
|
|
/*
|
|
* Add an order table to the list of order tables
|
|
*/
|
|
void InsertOrderTableList(br_order_table *order_table)
|
|
{
|
|
br_order_table *previous_table,*current_table;
|
|
|
|
ASSERT(order_table!=NULL);
|
|
|
|
/*
|
|
* Do not insert primary order table
|
|
*/
|
|
if(order_table==v1db.primary_order_table) return;
|
|
|
|
if(v1db.order_table_list==NULL) {
|
|
|
|
/*
|
|
* Add as the first order table
|
|
*/
|
|
v1db.order_table_list=order_table;
|
|
order_table->next=NULL;
|
|
|
|
} else {
|
|
|
|
current_table=v1db.order_table_list;
|
|
if(current_table->sort_z<order_table->sort_z) {
|
|
|
|
/*
|
|
* Insert at head of list
|
|
*/
|
|
order_table->next=current_table;
|
|
v1db.order_table_list=order_table;
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Search for position
|
|
*/
|
|
previous_table=current_table;
|
|
current_table=current_table->next;
|
|
|
|
while(current_table!=NULL) {
|
|
if(current_table->sort_z>=order_table->sort_z) {
|
|
previous_table=current_table;
|
|
current_table=current_table->next;
|
|
} else break;
|
|
}
|
|
|
|
previous_table->next=order_table;
|
|
order_table->next=current_table;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Set order table bounds and Z scale factor given a source bounds
|
|
*/
|
|
void SetOrderTableBounds(br_bounds *bounds, br_order_table *order_table)
|
|
{
|
|
br_uint_32 i;
|
|
br_scalar element;
|
|
br_scalar min_z,max_z;
|
|
br_vector3 *min,*max;
|
|
|
|
/*
|
|
* Set new bounds if necessary
|
|
*/
|
|
if((order_table->flags & BR_ORDER_TABLE_NEW_BOUNDS) ||
|
|
((order_table->flags & BR_ORDER_TABLE_INIT_BOUNDS) && (order_table->visits==1))) {
|
|
|
|
/*
|
|
* Calculate Z bounds in screen space by accumulating
|
|
* maximal and minimal products
|
|
*/
|
|
min=&bounds->min;
|
|
max=&bounds->max;
|
|
BrModelToScreenQuery(&v1db.model_to_screen);
|
|
min_z=max_z=v1db.model_to_screen.m[3][3];
|
|
|
|
for(i=0;i<3;i++) {
|
|
element=v1db.model_to_screen.m[i][3];
|
|
if(element>0) {
|
|
max_z=BR_ADD(max_z,BR_MUL(element,max->v[i]));
|
|
min_z=BR_ADD(min_z,BR_MUL(element,min->v[i]));
|
|
}
|
|
else {
|
|
max_z=BR_ADD(max_z,BR_MUL(element,min->v[i]));
|
|
min_z=BR_ADD(min_z,BR_MUL(element,max->v[i]));
|
|
}
|
|
}
|
|
|
|
order_table->min_z=min_z;
|
|
order_table->max_z=max_z;
|
|
|
|
}
|
|
|
|
SetOrderTableRange(order_table);
|
|
}
|
|
|
|
void SetOrderTableRange(br_order_table *order_table)
|
|
{
|
|
br_scalar range=BR_SUB(order_table->max_z,order_table->min_z);
|
|
|
|
/*
|
|
* Calculate Z scale factor
|
|
*/
|
|
if(range>BR_SCALAR(MINIMUM_RANGE))
|
|
order_table->scale=BR_DIV(BrIntToScalar(order_table->size),range);
|
|
else
|
|
order_table->scale=BR_SCALAR(1.0/(float)MINIMUM_RANGE);
|
|
|
|
/*
|
|
* Set order table sort value
|
|
*/
|
|
if((order_table->flags & BR_ORDER_TABLE_SORT_NEAR)!=0){
|
|
order_table->sort_z=order_table->min_z;
|
|
}else{
|
|
if((order_table->flags & BR_ORDER_TABLE_SORT_FAR)!=0){
|
|
order_table->sort_z=order_table->max_z;
|
|
}else{
|
|
if((order_table->flags & BR_ORDER_TABLE_SORT_CENTRE)!=0)
|
|
order_table->sort_z=BR_ADD(order_table->min_z,BR_MUL(range,BR_SCALAR(0.5)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Render primitives in the list of order tables
|
|
*/
|
|
void RenderOrderTableList(void)
|
|
{
|
|
br_order_table *order_table;
|
|
|
|
order_table=v1db.order_table_list;
|
|
|
|
while(order_table!=NULL) {
|
|
GeometryV1BucketsRender(v1db.format_buckets,v1db.renderer, order_table->table, order_table->size);
|
|
order_table->visits=0;
|
|
order_table=order_table->next;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Render primitives in the root order table and
|
|
* in the list of order tables
|
|
*/
|
|
void RenderPrimaryOrderTable(void)
|
|
{
|
|
br_uint_16 m,size;
|
|
br_scalar bucket_size;
|
|
br_scalar min_z,max_z;
|
|
br_primitive **bucket;
|
|
br_order_table *order_table;
|
|
|
|
ASSERT(v1db.primary_order_table);
|
|
ASSERT(v1db.primary_order_table->size>0);
|
|
|
|
/*
|
|
* If primary order table has never been visited,
|
|
* just render the list of order tables
|
|
*/
|
|
if(v1db.primary_order_table->visits==0) {
|
|
RenderOrderTableList();
|
|
return;
|
|
}
|
|
|
|
min_z=v1db.primary_order_table->min_z;
|
|
max_z=v1db.primary_order_table->max_z;
|
|
size=v1db.primary_order_table->size;
|
|
bucket=v1db.primary_order_table->table+(size-1);
|
|
|
|
/*
|
|
* Render order tables in list whose sort Z values
|
|
* are behind the far bound of the root order table
|
|
*/
|
|
order_table=v1db.order_table_list;
|
|
while(order_table!=NULL) {
|
|
|
|
if(order_table->sort_z < max_z) break;
|
|
|
|
GeometryV1BucketsRender(v1db.format_buckets,v1db.renderer, order_table->table,order_table->size);
|
|
order_table->visits=0;
|
|
order_table=order_table->next;
|
|
|
|
}
|
|
|
|
/*
|
|
* Render the root order table together with any order tables
|
|
* in the list whose sort Z values lie within the bounds of
|
|
* the root order table
|
|
*/
|
|
bucket_size=BR_DIV(BR_SUB(max_z,min_z),BrIntToScalar(size));
|
|
|
|
for(m=0;m<size;m++,bucket--) {
|
|
|
|
/*
|
|
* Render bucket
|
|
*/
|
|
if(*bucket)
|
|
GeometryV1BucketsRender(v1db.format_buckets,v1db.renderer,bucket,1);
|
|
|
|
/*
|
|
* Render order tables whose sort Z values lie in this bucket
|
|
*/
|
|
max_z-=bucket_size;
|
|
while(order_table!=NULL) {
|
|
|
|
if(order_table->sort_z < max_z) break;
|
|
|
|
GeometryV1BucketsRender(v1db.format_buckets,v1db.renderer,order_table->table,order_table->size);
|
|
order_table->visits=0;
|
|
order_table=order_table->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Render any remaining order tables in the list
|
|
*/
|
|
while(order_table!=NULL) {
|
|
|
|
GeometryV1BucketsRender(v1db.format_buckets,v1db.renderer,order_table->table,order_table->size);
|
|
order_table->visits=0;
|
|
order_table=order_table->next;
|
|
|
|
}
|
|
|
|
/*
|
|
* Reset visit count
|
|
*/
|
|
v1db.primary_order_table->visits=0;
|
|
}
|
|
|