/* * Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved. * * $Id: setup.c 1.2 1997/08/11 14:26:06 jon Exp JON $ * $Locker: JON $ * */ #include #include #include "drv.h" #include "shortcut.h" #include "brassert.h" #include "vecifns.h" BR_RCS_ID("$Id: setup.c 1.2 1997/08/11 14:26:06 jon Exp JON $"); #define COUNTERS 0 #if COUNTERS int CounterCache; int CounterPerScene; int CounterPerModel; int CounterViewToModel; int CounterModelToScreen; #endif /* * Global scratch block for renderer */ _rend BR_ASM_DATA rend; /* * Global static cache for renderer */ _static_cache BR_ASM_DATA scache; /* * Find centre of projection in model space */ static void eyeInModel(br_renderer *self) { br_matrix4 s2m; /* * Spot special, easy, cases */ if(self->state.matrix.model_to_view_hint == BRT_LENGTH_PRESERVING) { if(self->state.matrix.view_to_screen_hint == BRT_PERSPECTIVE) { scache.eye_m.v[0] = -BR_MAC3( self->state.matrix.model_to_view.m[3][0],self->state.matrix.model_to_view.m[0][0], self->state.matrix.model_to_view.m[3][1],self->state.matrix.model_to_view.m[0][1], self->state.matrix.model_to_view.m[3][Z],self->state.matrix.model_to_view.m[0][2]); scache.eye_m.v[1] = -BR_MAC3( self->state.matrix.model_to_view.m[3][0],self->state.matrix.model_to_view.m[1][0], self->state.matrix.model_to_view.m[3][1],self->state.matrix.model_to_view.m[1][1], self->state.matrix.model_to_view.m[3][Z],self->state.matrix.model_to_view.m[1][2]); scache.eye_m.v[2] = -BR_MAC3( self->state.matrix.model_to_view.m[3][0],self->state.matrix.model_to_view.m[2][0], self->state.matrix.model_to_view.m[3][1],self->state.matrix.model_to_view.m[2][1], self->state.matrix.model_to_view.m[3][Z],self->state.matrix.model_to_view.m[2][2]); scache.eye_m.v[3] = BR_SCALAR(1.0); return; } if(self->state.matrix.view_to_screen_hint == BRT_PARALLEL) { BrVector3CopyMat34Col((br_vector3 *)&scache.eye_m, &self->state.matrix.model_to_view,2); scache.eye_m.v[3] = BR_SCALAR(0.0); return; } } else { if(self->state.matrix.view_to_screen_hint == BRT_PERSPECTIVE) { ViewToModelUpdate(self); BrVector3CopyMat34Row((br_vector3 *)&scache.eye_m, &scache.view_to_model,3); scache.eye_m.v[3] = BR_SCALAR(1.0); return; } if(self->state.matrix.view_to_screen_hint == BRT_PARALLEL) { ViewToModelUpdate(self); BrVector3CopyMat34Row((br_vector3 *)&scache.eye_m, &scache.view_to_model,2); scache.eye_m.v[3] = BR_SCALAR(0.0); return; } } /* * If reached here, then we need to invert model_to_screen */ ModelToScreenUpdate(self); BrMatrix4Inverse(&s2m, &scache.model_to_screen); scache.eye_m.v[0] = s2m.m[Z][0]; scache.eye_m.v[1] = s2m.m[Z][1]; scache.eye_m.v[2] = s2m.m[Z][2]; scache.eye_m.v[3] = s2m.m[Z][3]; } void StaticCacheUpdate_PerScene(br_renderer *self) { int i; #if COUNTERS CounterPerScene++; #endif /* * Initialise values used for scaling screen vertices */ if (self->state.out.colour != NULL) { scache.sx_scale = self->state.out.colour->pm_width / 2.0f; scache.sx_offset = self->state.out.colour->pm_base_x + scache.sx_scale; scache.sy_scale = -self->state.out.colour->pm_height / 2.0f; scache.sy_offset = (self->state.out.colour->pm_base_y - scache.sy_scale) * (1.0 - FLT_EPSILON); } /* * See if any user-defined clip planes are active */ scache.user_clip_active = BR_FALSE; for(i = 0; i < MAX_STATE_CLIP_PLANES; i++) if(self->state.clip[i].type == BRT_PLANE) scache.user_clip_active = BR_TRUE; /* * Lighting setup */ ActiveLightsFind(self); } void StaticCacheUpdate_PerModel(br_renderer *self) { #if COUNTERS CounterPerModel++; #endif if(!scache.valid_v2m) { ViewToModelUpdate(self); scache.valid_v2m = BR_TRUE; } if(!scache.valid_m2s) { ModelToScreenUpdate(self); scache.valid_m2s = BR_TRUE; } eyeInModel(self); BrVector3Normalise(&scache.eye_m_normalised, &scache.eye_m); if(self->state.matrix.view_to_environment_hint != BRT_DONT_CARE) { BrMatrix34Mul(&scache.model_to_environment, &self->state.matrix.model_to_view, &self->state.matrix.view_to_environment); } /* * Lighting setup */ ActiveLightsUpdate(self); } br_error CacheUpdate(br_renderer *self) { #if COUNTERS CounterCache++; #endif /* * Fast exit if nothing has changed */ if(!rend.block_changed && !rend.range_changed && self->state.cache.valid) return BRE_OK; /* * Work out what components should be clipped based on what * the rasteriser needs per vertex - SX,SY,SZ are mapped to X,Y,Z * and W is always set */ self->state.cache.clip_slots = ComponentMaskToSlots(CM_W | CM_Z | COMP_S2V(rend.block->vertex_components)); /* * Cache transformed corners of unit quad, if quad mapping * * N.B. Actually use 0.0 .. 1.0-epsilon to avoid wrapping */ if (self->state.surface.mapping_source == BRT_QUAD) { self->state.cache.quad_transformed[0].v[0] = self->state.surface.map_transform.m[2][0]; self->state.cache.quad_transformed[0].v[1] = self->state.surface.map_transform.m[2][1]; self->state.cache.quad_transformed[1].v[0] = BR_ADD(BR_MUL(rend.renderer->state.surface.map_transform.m[1][0], BR_SCALAR(1.0)-BR_SCALAR_EPSILON), rend.renderer->state.surface.map_transform.m[2][0]); self->state.cache.quad_transformed[1].v[1] = BR_ADD(BR_MUL(rend.renderer->state.surface.map_transform.m[1][1], BR_SCALAR(1.0)-BR_SCALAR_EPSILON), rend.renderer->state.surface.map_transform.m[2][1]); self->state.cache.quad_transformed[2].v[0] = BR_ADD(BR_MUL(BR_ADD(rend.renderer->state.surface.map_transform.m[0][0], rend.renderer->state.surface.map_transform.m[1][0]), BR_SCALAR(1.0)-BR_SCALAR_EPSILON), rend.renderer->state.surface.map_transform.m[2][0]); self->state.cache.quad_transformed[2].v[1] = BR_ADD(BR_MUL(BR_ADD(rend.renderer->state.surface.map_transform.m[0][1], rend.renderer->state.surface.map_transform.m[1][1]), BR_SCALAR(1.0)-BR_SCALAR_EPSILON), rend.renderer->state.surface.map_transform.m[2][1]); self->state.cache.quad_transformed[3].v[0] = BR_ADD(BR_MUL(rend.renderer->state.surface.map_transform.m[0][0], BR_SCALAR(1.0)-BR_SCALAR_EPSILON), rend.renderer->state.surface.map_transform.m[2][0]); self->state.cache.quad_transformed[3].v[1] = BR_ADD(BR_MUL(rend.renderer->state.surface.map_transform.m[0][1], BR_SCALAR(1.0)-BR_SCALAR_EPSILON), rend.renderer->state.surface.map_transform.m[2][1]); } /* * Surface component functions */ self->state.cache.nvertex_fns = GenerateSurfaceFunctions(self, self->state.cache.vertex_fns, rend.block->vertex_components); self->state.cache.nconstant_fns = GenerateSurfaceFunctions(self, self->state.cache.constant_fns, rend.block->constant_components); return BRE_OK; } void ViewToModelUpdate(br_renderer *self) { #if COUNTERS CounterViewToModel++; #endif BrMatrix34Inverse(&scache.view_to_model, &self->state.matrix.model_to_view); } void ModelToScreenUpdate(br_renderer *self) { #if COUNTERS CounterModelToScreen++; #endif /* * Model to screen matrix */ BrMatrix4Mul34(&scache.model_to_screen, &self->state.matrix.model_to_view, &self->state.matrix.view_to_screen); } void ActiveLightsFind(br_renderer *self) { int l; struct state_light *lp; struct active_light *alp = scache.lights; scache.nlights_model = 0; scache.nlights_view = 0; /* * Find all model space lights */ for(l=0, lp = self->state.light; l < MAX_STATE_LIGHTS; l++, lp++) { if(!(lp->type != BRT_NONE && lp->lighting_space == BRT_MODEL)) continue; alp->s = lp; alp->intensity = BR_RCP(lp->attenuation_c); alp->type = lp->type; #if 0 ActiveLightAccumulateIndexSet(alp); #endif ActiveLightAccumulateColourSet(alp); alp++; scache.nlights_model++; } /* * Find all view space lights */ for(l=0, lp = self->state.light; l < MAX_STATE_LIGHTS; l++, lp++) { if(!(lp->type != BRT_NONE && lp->lighting_space == BRT_VIEW)) continue; alp->s = lp; alp->intensity = BR_RCP(lp->attenuation_c); alp->type = lp->type; alp->position = lp->position; if(lp->type == BRT_DIRECT) BrVector3Scale(&alp->direction,&lp->direction,alp->intensity); else alp->direction = lp->direction; #if 0 ActiveLightAccumulateIndexSet(alp); #endif ActiveLightAccumulateColourSet(alp); alp++; scache.nlights_view++; } /* * Set a flag to indicate special case of 1 directional model light */ scache.light_1md = (scache.nlights_view == 0) && (scache.nlights_model == 1) && (scache.lights[0].type == BRT_DIRECT); } void ActiveLightsUpdate(br_renderer *self) { struct active_light *alp = scache.lights; int i; for(i=0; i < scache.nlights_model; i++, alp++) { switch(alp->type) { case BRT_DIRECT: /* * Transform light's direction */ BrMatrix34TApplyV(&alp->direction,&alp->s->direction,&self->state.matrix.model_to_view); BrVector3Normalise(&alp->direction,&alp->direction); /* * Work out a unit half vector */ BrVector3Add(&alp->half,&alp->direction,&scache.eye_m_normalised); BrVector3Normalise(&alp->half,&alp->half); /* * Scale direction vector by light intensity */ BrVector3Scale(&alp->direction,&alp->direction,alp->intensity); break; case BRT_SPOT: /* * Transform light's direction and position */ BrMatrix34TApplyV(&alp->direction,&alp->s->direction,&self->state.matrix.model_to_view); BrVector3Normalise(&alp->direction,&alp->direction); /* FALL THROUGH */ case BRT_POINT: /* * Transform light's position */ BrMatrix34ApplyP(&alp->position,&alp->s->position,&scache.view_to_model); break; } } for(i=0; i < scache.nlights_view; i++, alp++) { if(alp->type == BRT_DIRECT) { /* * Work out a unit half vector: * eye = (0,0,1) * half = normalise(light_direection + eye) */ alp->half = alp->s->direction; alp->half.v[Z] += BR_SCALAR(1.0); BrVector3Normalise(&alp->half,&alp->half); } } } /* * Build the tables of functions that evaluate per-vertex and per-primitive components */ #if BASED_FIXED static br_boolean isPowerof2(br_int_32 x) { return !((x-1) & x); } static br_uint_8 findShift(br_int_32 x) { br_uint_8 b; for(b=0; x; b++) x /= 2; return b; } #endif br_int_32 GenerateSurfaceFunctions(br_renderer *self, surface_fn **fns, br_uint_32 mask) { br_int_32 f = 0; br_matrix23 *m; /* U,V */ if(mask & (CM_U|CM_V)) { switch(self->state.surface.mapping_source) { case BRT_ENVIRONMENT_LOCAL: fns[f++] = SurfaceMapEnvironmentLocal; break; case BRT_ENVIRONMENT_INFINITE: fns[f++] = SurfaceMapEnvironmentInfinite; break; case BRT_GEOMETRY_MAP: fns[f++] = SurfaceMapGeometryMap; m = &self->state.surface.map_transform; if(m->m[0][1] == BR_SCALAR(0) && m->m[1][0] == BR_SCALAR(0)) { /* * Can at least use this version */ fns[f-1] = SurfaceMapGeometryMapScaleTranslate; /* * Spot zero translation */ if(m->m[2][0] == BR_SCALAR(0) && m->m[2][1] == BR_SCALAR(0)) fns[f-1] = SurfaceMapGeometryMapScale; #if BASED_FIXED /* * Spot case where shifts can be used */ if( m->m[0][0] > BR_SCALAR(1) && m->m[1][1] > BR_SCALAR(1) && isPowerof2(m->m[0][0]) && isPowerof2(m->m[1][1])) { self->state.cache.u_shift = findShift(m->m[0][0]) - 17; self->state.cache.v_shift = findShift(m->m[1][1]) - 17; fns[f-1] = SurfaceMapGeometryMapShift; } #endif /* * Spot identity transform */ if(m->m[0][0] == BR_SCALAR(1) && m->m[1][1] == BR_SCALAR(1) && m->m[2][0] == BR_SCALAR(0) && m->m[2][1] == BR_SCALAR(0)) { fns[f-1] = SurfaceMapGeometryMapCopy; } } break; case BRT_GEOMETRY_X: fns[f++] = SurfaceMapGeometryX; break; case BRT_GEOMETRY_Y: fns[f++] = SurfaceMapGeometryY; break; case BRT_GEOMETRY_Z: default: fns[f++] = SurfaceMapGeometryZ; break; case BRT_QUAD: break; } } #if 0 /* I */ if(mask & CM_I) { if(self->state.surface.lighting) { fns[f++] = SurfaceIndexLit; } else if(self->state.surface.colour_source == BRT_GEOMETRY) { fns[f++] = SurfaceIndexUnlit; } else { fns[f++] = SurfaceIndexZero; } } else if(mask & CM_UI) { /* Unlit I */ if(self->state.surface.colour_source == BRT_GEOMETRY) { fns[f++] = SurfaceIndexUnlit; } else { fns[f++] = SurfaceIndexZero; } } #endif /* RGB */ if(mask & (CM_R|CM_G|CM_B)) { if(self->state.surface.lighting) fns[f++] = SurfaceColourLit; else fns[f++] = SurfaceColourUnlit; } else if(mask & (CM_UR|CM_UG|CM_UB)) { /* Unlit RGB */ fns[f++] = SurfaceColourUnlit; } else /* Alpha */ if(mask & CM_A) fns[f++] = SurfaceAlpha; /* Linear Z */ #if 0 if(mask & CM_SW) fns[f++] = SurfaceLinearDepth; #endif /* Terminate List with a NULL */ fns[f] = NULL; return f; } /* * Convert a component mask (CM_*) to a mask of bits per component entry */ br_uint_32 ComponentMaskToSlots(br_uint_32 cm) { br_uint_32 m; int i; static br_uint_32 bits[] = { 1<state.cache.ngeometry_fns = 0; renderer->state.cache.ngeometry_fns_onscreen = 0; } void GeometryFunctionAdd(br_renderer *renderer, geometry_fn *fn) { ASSERT(renderer->state.cache.ngeometry_fns < BR_ASIZE(renderer->state.cache.geometry_fns)); renderer->state.cache.geometry_fns[renderer->state.cache.ngeometry_fns++] = fn; } void GeometryFunctionOnScreenAdd(br_renderer *renderer, geometry_fn *fn) { ASSERT(renderer->state.cache.ngeometry_fns_onscreen < BR_ASIZE(renderer->state.cache.geometry_fns_onscreen)); renderer->state.cache.geometry_fns_onscreen[renderer->state.cache.ngeometry_fns_onscreen++] = fn; } void GeometryFunctionBothAdd(br_renderer *renderer, geometry_fn *fn) { GeometryFunctionAdd(renderer, fn); GeometryFunctionOnScreenAdd(renderer, fn); } /* * Functions to chain primitive blocks together */ void PrimBlockReset(br_renderer *renderer) { renderer->state.cache.nface_blocks = 0; renderer->state.cache.nface_blocks_onscreen = 0; } void PrimBlockAdd(br_renderer *renderer, brp_render_fn *render, brp_render_fn *render_indexed) { int f; ASSERT(renderer->state.cache.nface_blocks < (BR_ASIZE(renderer->state.cache.face_blocks)-1)); f = renderer->state.cache.nface_blocks; renderer->state.cache.face_blocks[f].render = render; renderer->state.cache.face_blocks[f].render_indexed = render_indexed; renderer->state.cache.face_blocks[f+1].chain = (brp_block *)(renderer->state.cache.face_blocks+f); renderer->state.cache.nface_blocks = f+1; } void PrimBlockOnScreenAdd(br_renderer *renderer, brp_render_fn *render, brp_render_fn *render_indexed) { int f; ASSERT(renderer->state.cache.nface_blocks_onscreen < (BR_ASIZE(renderer->state.cache.face_blocks_onscreen)-1)); f = renderer->state.cache.nface_blocks_onscreen; renderer->state.cache.face_blocks_onscreen[f].render = render; renderer->state.cache.face_blocks_onscreen[f].render_indexed = render_indexed; renderer->state.cache.face_blocks_onscreen[f+1].chain = (brp_block *)(renderer->state.cache.face_blocks_onscreen+f); renderer->state.cache.nface_blocks_onscreen = f+1; } void PrimBlockAddBoth(br_renderer *renderer, brp_render_fn *render, brp_render_fn *render_indexed) { PrimBlockAdd(renderer, render, render_indexed); PrimBlockOnScreenAdd(renderer, render, render_indexed); }