t_vb_light.c revision 790734045b69c47b1525fbf9106a7ca5a8eb7416
1 2/* 3 * Mesa 3-D graphics library 4 * Version: 5.1 5 * 6 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27 28#include "glheader.h" 29#include "colormac.h" 30#include "light.h" 31#include "macros.h" 32#include "imports.h" 33#include "simple_list.h" 34#include "mtypes.h" 35 36#include "math/m_translate.h" 37 38#include "t_context.h" 39#include "t_pipeline.h" 40 41#define LIGHT_TWOSIDE 0x1 42#define LIGHT_MATERIAL 0x2 43#define MAX_LIGHT_FUNC 0x4 44 45typedef void (*light_func)( GLcontext *ctx, 46 struct vertex_buffer *VB, 47 struct tnl_pipeline_stage *stage, 48 GLvector4f *input ); 49 50struct material_cursor { 51 const GLfloat *ptr; 52 GLuint stride; 53 GLfloat *current; 54}; 55 56struct light_stage_data { 57 GLvector4f Input; 58 GLvector4f LitColor[2]; 59 GLvector4f LitSecondary[2]; 60 GLvector4f LitIndex[2]; 61 light_func *light_func_tab; 62 63 struct material_cursor mat[MAT_ATTRIB_MAX]; 64 GLuint mat_count; 65 GLuint mat_bitmask; 66}; 67 68 69#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr)) 70 71 72 73/* In the case of colormaterial, the effected material attributes 74 * should already have been bound to point to the incoming color data, 75 * prior to running the pipeline. 76 */ 77static void update_materials( GLcontext *ctx, 78 struct light_stage_data *store ) 79{ 80 GLuint i; 81 82 for (i = 0 ; i < store->mat_count ; i++) { 83 COPY_4V(store->mat[i].current, store->mat[i].ptr); 84 STRIDE_F(store->mat[i].ptr, store->mat[i].stride); 85 } 86 87 _mesa_update_material( ctx, store->mat_bitmask ); 88 _mesa_validate_all_lighting_tables( ctx ); 89} 90 91static GLuint prepare_materials( GLcontext *ctx, 92 struct vertex_buffer *VB, 93 struct light_stage_data *store ) 94{ 95 GLuint i; 96 97 store->mat_count = 0; 98 store->mat_bitmask = 0; 99 100 /* If ColorMaterial enabled, overwrite affected AttrPtr's with 101 * the color pointer. This could be done earlier. 102 */ 103 if (ctx->Light.ColorMaterialEnabled) { 104 GLuint bitmask = ctx->Light.ColorMaterialBitmask; 105 for (i = 0 ; i < MAT_ATTRIB_MAX ; i++) 106 if (bitmask & (1<<i)) 107 VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] = VB->ColorPtr[0]; 108 } 109 110 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ; i < _TNL_ATTRIB_INDEX ; i++) { 111 if (VB->AttribPtr[i]->stride) { 112 GLuint j = store->mat_count++; 113 GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT; 114 store->mat[j].ptr = VB->AttribPtr[i]->start; 115 store->mat[j].stride = VB->AttribPtr[i]->stride; 116 store->mat[j].current = ctx->Light.Material.Attrib[attr]; 117 store->mat_bitmask |= (1<<attr); 118 } 119 } 120 121 122 /* FIXME: Is this already done? 123 */ 124 _mesa_update_material( ctx, ~0 ); 125 _mesa_validate_all_lighting_tables( ctx ); 126 127 return store->mat_count; 128} 129 130/* Tables for all the shading functions. 131 */ 132static light_func _tnl_light_tab[MAX_LIGHT_FUNC]; 133static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC]; 134static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC]; 135static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC]; 136static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC]; 137 138#define TAG(x) x 139#define IDX (0) 140#include "t_vb_lighttmp.h" 141 142#define TAG(x) x##_twoside 143#define IDX (LIGHT_TWOSIDE) 144#include "t_vb_lighttmp.h" 145 146#define TAG(x) x##_material 147#define IDX (LIGHT_MATERIAL) 148#include "t_vb_lighttmp.h" 149 150#define TAG(x) x##_twoside_material 151#define IDX (LIGHT_TWOSIDE|LIGHT_MATERIAL) 152#include "t_vb_lighttmp.h" 153 154 155static void init_lighting( void ) 156{ 157 static int done; 158 159 if (!done) { 160 init_light_tab(); 161 init_light_tab_twoside(); 162 init_light_tab_material(); 163 init_light_tab_twoside_material(); 164 done = 1; 165 } 166} 167 168 169static GLboolean run_lighting( GLcontext *ctx, 170 struct tnl_pipeline_stage *stage ) 171{ 172 struct light_stage_data *store = LIGHT_STAGE_DATA(stage); 173 TNLcontext *tnl = TNL_CONTEXT(ctx); 174 struct vertex_buffer *VB = &tnl->vb; 175 GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr; 176 GLuint idx; 177 178 /* Make sure we can talk about position x,y and z: 179 */ 180 if (stage->changed_inputs & _TNL_BIT_POS) { 181 if (input->size <= 2 && input == VB->ObjPtr) { 182 183 _math_trans_4f( store->Input.data, 184 VB->ObjPtr->data, 185 VB->ObjPtr->stride, 186 GL_FLOAT, 187 VB->ObjPtr->size, 188 0, 189 VB->Count ); 190 191 if (input->size <= 2) { 192 /* Clean z. 193 */ 194 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 2); 195 } 196 197 if (input->size <= 1) { 198 /* Clean y. 199 */ 200 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 1); 201 } 202 203 input = &store->Input; 204 } 205 } 206 207 idx = 0; 208 209 if (prepare_materials( ctx, VB, store )) 210 idx |= LIGHT_MATERIAL; 211 212 if (ctx->Light.Model.TwoSide) 213 idx |= LIGHT_TWOSIDE; 214 215 /* The individual functions know about replaying side-effects 216 * vs. full re-execution. 217 */ 218 store->light_func_tab[idx]( ctx, VB, stage, input ); 219 220 VB->AttribPtr[_TNL_ATTRIB_COLOR0] = VB->ColorPtr[0]; 221 VB->AttribPtr[_TNL_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0]; 222 VB->AttribPtr[_TNL_ATTRIB_INDEX] = VB->IndexPtr[0]; 223 224 return GL_TRUE; 225} 226 227 228/* Called in place of do_lighting when the light table may have changed. 229 */ 230static GLboolean run_validate_lighting( GLcontext *ctx, 231 struct tnl_pipeline_stage *stage ) 232{ 233 light_func *tab; 234 235 if (ctx->Visual.rgbMode) { 236 if (ctx->Light._NeedVertices) { 237 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) 238 tab = _tnl_light_spec_tab; 239 else 240 tab = _tnl_light_tab; 241 } 242 else { 243 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev) 244 tab = _tnl_light_fast_single_tab; 245 else 246 tab = _tnl_light_fast_tab; 247 } 248 } 249 else 250 tab = _tnl_light_ci_tab; 251 252 253 LIGHT_STAGE_DATA(stage)->light_func_tab = tab; 254 255 /* This and the above should only be done on _NEW_LIGHT: 256 */ 257 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx ); 258 259 /* Now run the stage... 260 */ 261 stage->run = run_lighting; 262 return stage->run( ctx, stage ); 263} 264 265 266 267/* Called the first time stage->run is called. In effect, don't 268 * allocate data until the first time the stage is run. 269 */ 270static GLboolean run_init_lighting( GLcontext *ctx, 271 struct tnl_pipeline_stage *stage ) 272{ 273 TNLcontext *tnl = TNL_CONTEXT(ctx); 274 struct light_stage_data *store; 275 GLuint size = tnl->vb.Size; 276 277 stage->privatePtr = MALLOC(sizeof(*store)); 278 store = LIGHT_STAGE_DATA(stage); 279 if (!store) 280 return GL_FALSE; 281 282 /* Do onetime init. 283 */ 284 init_lighting(); 285 286 _mesa_vector4f_alloc( &store->Input, 0, size, 32 ); 287 _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 ); 288 _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 ); 289 _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 ); 290 _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 ); 291 _mesa_vector4f_alloc( &store->LitIndex[0], 0, size, 32 ); 292 _mesa_vector4f_alloc( &store->LitIndex[1], 0, size, 32 ); 293 294 store->LitIndex[0].size = 1; 295 store->LitIndex[0].stride = sizeof(GLfloat); 296 store->LitIndex[1].size = 1; 297 store->LitIndex[1].stride = sizeof(GLfloat); 298 299 /* Now validate the stage derived data... 300 */ 301 stage->run = run_validate_lighting; 302 return stage->run( ctx, stage ); 303} 304 305 306 307/* 308 * Check if lighting is enabled. If so, configure the pipeline stage's 309 * type, inputs, and outputs. 310 */ 311static void check_lighting( GLcontext *ctx, struct tnl_pipeline_stage *stage ) 312{ 313 stage->active = ctx->Light.Enabled && !ctx->VertexProgram.Enabled; 314 if (stage->active) { 315 if (stage->privatePtr) 316 stage->run = run_validate_lighting; 317 stage->inputs = _TNL_BIT_NORMAL|_TNL_BITS_MAT_ANY; 318 if (ctx->Light._NeedVertices) 319 stage->inputs |= _TNL_BIT_POS; 320 if (ctx->Light.ColorMaterialEnabled) 321 stage->inputs |= _TNL_BIT_COLOR0; 322 323 stage->outputs = _TNL_BIT_COLOR0; 324 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) 325 stage->outputs |= _TNL_BIT_COLOR1; 326 } 327} 328 329 330static void dtr( struct tnl_pipeline_stage *stage ) 331{ 332 struct light_stage_data *store = LIGHT_STAGE_DATA(stage); 333 334 if (store) { 335 _mesa_vector4f_free( &store->Input ); 336 _mesa_vector4f_free( &store->LitColor[0] ); 337 _mesa_vector4f_free( &store->LitColor[1] ); 338 _mesa_vector4f_free( &store->LitSecondary[0] ); 339 _mesa_vector4f_free( &store->LitSecondary[1] ); 340 _mesa_vector4f_free( &store->LitIndex[0] ); 341 _mesa_vector4f_free( &store->LitIndex[1] ); 342 FREE( store ); 343 stage->privatePtr = 0; 344 } 345} 346 347const struct tnl_pipeline_stage _tnl_lighting_stage = 348{ 349 "lighting", /* name */ 350 _NEW_LIGHT, /* recheck */ 351 _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency 352 * otherwise not captured by inputs 353 * (which may be _TNL_BIT_POS) */ 354 GL_FALSE, /* active? */ 355 0, /* inputs */ 356 0, /* outputs */ 357 0, /* changed_inputs */ 358 NULL, /* private_data */ 359 dtr, /* destroy */ 360 check_lighting, /* check */ 361 run_init_lighting /* run -- initially set to ctr */ 362}; 363