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