t_vb_light.c revision 53560311294814ae0daa8457307a2b25077bf4e9
1/* $Id: t_vb_light.c,v 1.15 2001/07/17 19:39:32 keithw Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28 29#include "glheader.h" 30#include "colormac.h" 31#include "light.h" 32#include "macros.h" 33#include "mem.h" 34#include "mmath.h" 35#include "simple_list.h" 36#include "mtypes.h" 37 38#include "math/m_translate.h" 39 40#include "t_context.h" 41#include "t_pipeline.h" 42 43#define LIGHT_FLAGS 0x1 /* must be first */ 44#define LIGHT_TWOSIDE 0x2 45#define LIGHT_COLORMATERIAL 0x4 46#define MAX_LIGHT_FUNC 0x8 47 48typedef void (*light_func)( GLcontext *ctx, 49 struct vertex_buffer *VB, 50 struct gl_pipeline_stage *stage, 51 GLvector4f *input ); 52 53struct light_stage_data { 54 struct gl_client_array FloatColor; 55 struct gl_client_array LitColor[2]; 56 struct gl_client_array LitSecondary[2]; 57 GLvector1ui LitIndex[2]; 58 light_func *light_func_tab; 59}; 60 61 62#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr)) 63 64 65static void import_color_material( GLcontext *ctx, 66 struct gl_pipeline_stage *stage ) 67{ 68 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 69 struct gl_client_array *to = &LIGHT_STAGE_DATA(stage)->FloatColor; 70 struct gl_client_array *from = VB->ColorPtr[0]; 71 GLuint count = VB->Count; 72 73 if (!to->Ptr) { 74 to->Ptr = ALIGN_MALLOC( VB->Size * 4 * sizeof(GLfloat), 32 ); 75 to->Type = GL_FLOAT; 76 } 77 78 /* No need to transform the same value 3000 times. 79 */ 80 if (!from->StrideB) { 81 to->StrideB = 0; 82 count = 1; 83 } 84 else 85 to->StrideB = 4 * sizeof(GLfloat); 86 87 _math_trans_4f( (GLfloat (*)[4]) to->Ptr, 88 from->Ptr, 89 from->StrideB, 90 from->Type, 91 from->Size, 92 0, 93 count); 94 95 VB->ColorPtr[0] = to; 96} 97 98 99/* Tables for all the shading functions. 100 */ 101static light_func _tnl_light_tab[MAX_LIGHT_FUNC]; 102static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC]; 103static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC]; 104static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC]; 105static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC]; 106 107#define TAG(x) x 108#define IDX (0) 109#include "t_vb_lighttmp.h" 110 111#define TAG(x) x##_tw 112#define IDX (LIGHT_TWOSIDE) 113#include "t_vb_lighttmp.h" 114 115#define TAG(x) x##_fl 116#define IDX (LIGHT_FLAGS) 117#include "t_vb_lighttmp.h" 118 119#define TAG(x) x##_tw_fl 120#define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE) 121#include "t_vb_lighttmp.h" 122 123#define TAG(x) x##_cm 124#define IDX (LIGHT_COLORMATERIAL) 125#include "t_vb_lighttmp.h" 126 127#define TAG(x) x##_tw_cm 128#define IDX (LIGHT_TWOSIDE|LIGHT_COLORMATERIAL) 129#include "t_vb_lighttmp.h" 130 131#define TAG(x) x##_fl_cm 132#define IDX (LIGHT_FLAGS|LIGHT_COLORMATERIAL) 133#include "t_vb_lighttmp.h" 134 135#define TAG(x) x##_tw_fl_cm 136#define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE|LIGHT_COLORMATERIAL) 137#include "t_vb_lighttmp.h" 138 139 140static void init_lighting( void ) 141{ 142 static int done; 143 144 if (!done) { 145 init_light_tab(); 146 init_light_tab_tw(); 147 init_light_tab_fl(); 148 init_light_tab_tw_fl(); 149 init_light_tab_cm(); 150 init_light_tab_tw_cm(); 151 init_light_tab_fl_cm(); 152 init_light_tab_tw_fl_cm(); 153 done = 1; 154 } 155} 156 157 158static GLboolean run_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage ) 159{ 160 struct light_stage_data *store = LIGHT_STAGE_DATA(stage); 161 TNLcontext *tnl = TNL_CONTEXT(ctx); 162 struct vertex_buffer *VB = &tnl->vb; 163 GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr; 164 GLuint ind; 165 166/* _tnl_print_vert_flags( __FUNCTION__, stage->changed_inputs ); */ 167 168 /* Make sure we can talk about elements 0..2 in the vector we are 169 * lighting. 170 */ 171 if (stage->changed_inputs & (VERT_EYE|VERT_OBJ)) { 172 if (input->size <= 2) { 173 if (input->flags & VEC_NOT_WRITEABLE) { 174 ASSERT(VB->importable_data & VERT_OBJ); 175 176 VB->import_data( ctx, VERT_OBJ, VEC_NOT_WRITEABLE ); 177 input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr; 178 179 ASSERT((input->flags & VEC_NOT_WRITEABLE) == 0); 180 } 181 182 _mesa_vector4f_clean_elem(input, VB->Count, 2); 183 } 184 } 185 186 if (VB->Flag) 187 ind = LIGHT_FLAGS; 188 else 189 ind = 0; 190 191 /* The individual functions know about replaying side-effects 192 * vs. full re-execution. 193 */ 194 store->light_func_tab[ind]( ctx, VB, stage, input ); 195 196 return GL_TRUE; 197} 198 199 200/* Called in place of do_lighting when the light table may have changed. 201 */ 202static GLboolean run_validate_lighting( GLcontext *ctx, 203 struct gl_pipeline_stage *stage ) 204{ 205 GLuint ind = 0; 206 light_func *tab; 207 208 if (ctx->Visual.rgbMode) { 209 if (ctx->Light._NeedVertices) { 210 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) 211 tab = _tnl_light_spec_tab; 212 else 213 tab = _tnl_light_tab; 214 } 215 else { 216 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev) 217 tab = _tnl_light_fast_single_tab; 218 else 219 tab = _tnl_light_fast_tab; 220 } 221 } 222 else 223 tab = _tnl_light_ci_tab; 224 225 if (ctx->Light.ColorMaterialEnabled) 226 ind |= LIGHT_COLORMATERIAL; 227 228 if (ctx->Light.Model.TwoSide) 229 ind |= LIGHT_TWOSIDE; 230 231 LIGHT_STAGE_DATA(stage)->light_func_tab = &tab[ind]; 232 233 /* This and the above should only be done on _NEW_LIGHT: 234 */ 235 _mesa_validate_all_lighting_tables( ctx ); 236 237 /* Now run the stage... 238 */ 239 stage->run = run_lighting; 240 return stage->run( ctx, stage ); 241} 242 243static void alloc_4chan( struct gl_client_array *a, GLuint sz ) 244{ 245 a->Ptr = ALIGN_MALLOC( sz * sizeof(GLchan) * 4, 32 ); 246 a->Size = 4; 247 a->Type = CHAN_TYPE; 248 a->Stride = 0; 249 a->StrideB = sizeof(GLchan) * 4; 250 a->Enabled = 0; 251 a->Flags = 0; 252} 253 254 255/* Called the first time stage->run is called. In effect, don't 256 * allocate data until the first time the stage is run. 257 */ 258static GLboolean run_init_lighting( GLcontext *ctx, 259 struct gl_pipeline_stage *stage ) 260{ 261 TNLcontext *tnl = TNL_CONTEXT(ctx); 262 struct light_stage_data *store; 263 GLuint size = tnl->vb.Size; 264 265 stage->privatePtr = MALLOC(sizeof(*store)); 266 store = LIGHT_STAGE_DATA(stage); 267 if (!store) 268 return GL_FALSE; 269 270 /* Do onetime init. 271 */ 272 init_lighting(); 273 274 store->FloatColor.Ptr = 0; 275 276 alloc_4chan( &store->LitColor[0], size ); 277 alloc_4chan( &store->LitColor[1], size ); 278 alloc_4chan( &store->LitSecondary[0], size ); 279 alloc_4chan( &store->LitSecondary[1], size ); 280 281 _mesa_vector1ui_alloc( &store->LitIndex[0], 0, size, 32 ); 282 _mesa_vector1ui_alloc( &store->LitIndex[1], 0, size, 32 ); 283 284 /* Now validate the stage derived data... 285 */ 286 stage->run = run_validate_lighting; 287 return stage->run( ctx, stage ); 288} 289 290 291 292/* 293 * Check if lighting is enabled. If so, configure the pipeline stage's 294 * type, inputs, and outputs. 295 */ 296static void check_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage ) 297{ 298 stage->active = ctx->Light.Enabled; 299 if (stage->active) { 300 if (stage->privatePtr) 301 stage->run = run_validate_lighting; 302 stage->inputs = VERT_NORM|VERT_MATERIAL; 303 if (ctx->Light._NeedVertices) 304 stage->inputs |= VERT_EYE; /* effectively, even when lighting in obj */ 305 if (ctx->Light.ColorMaterialEnabled) 306 stage->inputs |= VERT_RGBA; 307 308 stage->outputs = VERT_RGBA; 309 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) 310 stage->outputs |= VERT_SPEC_RGB; 311 } 312} 313 314 315static void dtr( struct gl_pipeline_stage *stage ) 316{ 317 struct light_stage_data *store = LIGHT_STAGE_DATA(stage); 318 319 if (store) { 320 ALIGN_FREE( store->LitColor[0].Ptr ); 321 ALIGN_FREE( store->LitColor[1].Ptr ); 322 ALIGN_FREE( store->LitSecondary[0].Ptr ); 323 ALIGN_FREE( store->LitSecondary[1].Ptr ); 324 325 if (store->FloatColor.Ptr) 326 ALIGN_FREE( store->FloatColor.Ptr ); 327 328 _mesa_vector1ui_free( &store->LitIndex[0] ); 329 _mesa_vector1ui_free( &store->LitIndex[1] ); 330 FREE( store ); 331 stage->privatePtr = 0; 332 } 333} 334 335const struct gl_pipeline_stage _tnl_lighting_stage = 336{ 337 "lighting", 338 _NEW_LIGHT, /* recheck */ 339 _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency 340 * otherwise not captured by inputs 341 * (which may be VERT_OBJ) */ 342 0,0,0, /* active, inputs, outputs */ 343 0,0, /* changed_inputs, private_data */ 344 dtr, /* destroy */ 345 check_lighting, /* check */ 346 run_init_lighting /* run -- initially set to ctr */ 347}; 348