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