Tizen 2.1 base
[sdk/emulator/qemu.git] / gl / mesa / src / mesa / tnl / t_vb_light.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.5
4  *
5  * Copyright (C) 1999-2006  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 "main/glheader.h"
28 #include "main/colormac.h"
29 #include "main/light.h"
30 #include "main/macros.h"
31 #include "main/imports.h"
32 #include "main/simple_list.h"
33 #include "main/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)( struct gl_context *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    light_func *light_func_tab;
68
69    struct material_cursor mat[MAT_ATTRIB_MAX];
70    GLuint mat_count;
71    GLuint mat_bitmask;
72 };
73
74
75 #define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
76
77
78
79 /**
80  * In the case of colormaterial, the effected material attributes
81  * should already have been bound to point to the incoming color data,
82  * prior to running the pipeline.
83  * This function copies the vertex's color to the material attributes
84  * which are tracking glColor.
85  * It's called per-vertex in the lighting loop.
86  */
87 static void
88 update_materials(struct gl_context *ctx, struct light_stage_data *store)
89 {
90    GLuint i;
91
92    for (i = 0 ; i < store->mat_count ; i++) {
93       /* update the material */
94       COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr);
95       /* increment src vertex color pointer */
96       STRIDE_F(store->mat[i].ptr, store->mat[i].stride);
97    }
98       
99    /* recompute derived light/material values */
100    _mesa_update_material( ctx, store->mat_bitmask );
101    /* XXX we should only call this if we're tracking/changing the specular
102     * exponent.
103     */
104    _mesa_validate_all_lighting_tables( ctx );
105 }
106
107
108 /**
109  * Prepare things prior to running the lighting stage.
110  * Return number of material attributes which will track vertex color.
111  */
112 static GLuint
113 prepare_materials(struct gl_context *ctx,
114                   struct vertex_buffer *VB, struct light_stage_data *store)
115 {
116    GLuint i;
117    
118    store->mat_count = 0;
119    store->mat_bitmask = 0;
120
121    /* Examine the ColorMaterialBitmask to determine which materials
122     * track vertex color.  Override the material attribute's pointer
123     * with the color pointer for each one.
124     */
125    if (ctx->Light.ColorMaterialEnabled) {
126       const GLuint bitmask = ctx->Light.ColorMaterialBitmask;
127       for (i = 0 ; i < MAT_ATTRIB_MAX ; i++)
128          if (bitmask & (1<<i))
129             VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] = VB->AttribPtr[_TNL_ATTRIB_COLOR0];
130    }
131
132    /* Now, for each material attribute that's tracking vertex color, save
133     * some values (ptr, stride, size, current) that we'll need in
134     * update_materials(), above, that'll actually copy the vertex color to
135     * the material attribute(s).
136     */
137    for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) {
138       if (VB->AttribPtr[i]->stride) {
139          const GLuint j = store->mat_count++;
140          const GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
141          store->mat[j].ptr    = VB->AttribPtr[i]->start;
142          store->mat[j].stride = VB->AttribPtr[i]->stride;
143          store->mat[j].size   = VB->AttribPtr[i]->size;
144          store->mat[j].current = ctx->Light.Material.Attrib[attr];
145          store->mat_bitmask |= (1<<attr);
146       }
147    }
148
149    /* FIXME: Is this already done?
150     */
151    _mesa_update_material( ctx, ~0 );
152    _mesa_validate_all_lighting_tables( ctx );
153
154    return store->mat_count;
155 }
156
157 /* Tables for all the shading functions.
158  */
159 static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
160 static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
161 static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
162 static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
163
164 #define TAG(x)           x
165 #define IDX              (0)
166 #include "t_vb_lighttmp.h"
167
168 #define TAG(x)           x##_twoside
169 #define IDX              (LIGHT_TWOSIDE)
170 #include "t_vb_lighttmp.h"
171
172 #define TAG(x)           x##_material
173 #define IDX              (LIGHT_MATERIAL)
174 #include "t_vb_lighttmp.h"
175
176 #define TAG(x)           x##_twoside_material
177 #define IDX              (LIGHT_TWOSIDE|LIGHT_MATERIAL)
178 #include "t_vb_lighttmp.h"
179
180
181 static void init_lighting_tables( void )
182 {
183    static int done;
184
185    if (!done) {
186       init_light_tab();
187       init_light_tab_twoside();
188       init_light_tab_material();
189       init_light_tab_twoside_material();
190       done = 1;
191    }
192 }
193
194
195 static GLboolean run_lighting( struct gl_context *ctx, 
196                                struct tnl_pipeline_stage *stage )
197 {
198    struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
199    TNLcontext *tnl = TNL_CONTEXT(ctx);
200    struct vertex_buffer *VB = &tnl->vb;
201    GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->AttribPtr[_TNL_ATTRIB_POS];
202    GLuint idx;
203
204    if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
205       return GL_TRUE;
206
207    /* Make sure we can talk about position x,y and z:
208     */
209    if (input->size <= 2 && input == VB->AttribPtr[_TNL_ATTRIB_POS]) {
210
211       _math_trans_4f( store->Input.data,
212                       VB->AttribPtr[_TNL_ATTRIB_POS]->data,
213                       VB->AttribPtr[_TNL_ATTRIB_POS]->stride,
214                       GL_FLOAT,
215                       VB->AttribPtr[_TNL_ATTRIB_POS]->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    idx = 0;
235
236    if (prepare_materials( ctx, VB, store ))
237       idx |= LIGHT_MATERIAL;
238
239    if (ctx->Light.Model.TwoSide)
240       idx |= LIGHT_TWOSIDE;
241
242    /* The individual functions know about replaying side-effects
243     * vs. full re-execution. 
244     */
245    store->light_func_tab[idx]( ctx, VB, stage, input );
246
247    return GL_TRUE;
248 }
249
250
251 /* Called in place of do_lighting when the light table may have changed.
252  */
253 static void validate_lighting( struct gl_context *ctx,
254                                         struct tnl_pipeline_stage *stage )
255 {
256    light_func *tab;
257
258    if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
259       return;
260
261    if (ctx->Light._NeedVertices) {
262       if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
263          tab = _tnl_light_spec_tab;
264       else
265          tab = _tnl_light_tab;
266    }
267    else {
268       if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
269          tab = _tnl_light_fast_single_tab;
270       else
271          tab = _tnl_light_fast_tab;
272    }
273
274
275    LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
276
277    /* This and the above should only be done on _NEW_LIGHT:
278     */
279    TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
280 }
281
282
283
284 /* Called the first time stage->run is called.  In effect, don't
285  * allocate data until the first time the stage is run.
286  */
287 static GLboolean init_lighting( struct gl_context *ctx,
288                                 struct tnl_pipeline_stage *stage )
289 {
290    TNLcontext *tnl = TNL_CONTEXT(ctx);
291    struct light_stage_data *store;
292    GLuint size = tnl->vb.Size;
293
294    stage->privatePtr = MALLOC(sizeof(*store));
295    store = LIGHT_STAGE_DATA(stage);
296    if (!store)
297       return GL_FALSE;
298
299    /* Do onetime init.
300     */
301    init_lighting_tables();
302
303    _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
304    _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
305    _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
306    _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
307    _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
308
309    store->LitColor[0].size = 4;
310    store->LitColor[1].size = 4;
311    store->LitSecondary[0].size = 3;
312    store->LitSecondary[1].size = 3;
313
314    return GL_TRUE;
315 }
316
317
318
319
320 static void dtr( struct tnl_pipeline_stage *stage )
321 {
322    struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
323
324    if (store) {
325       _mesa_vector4f_free( &store->Input );
326       _mesa_vector4f_free( &store->LitColor[0] );
327       _mesa_vector4f_free( &store->LitColor[1] );
328       _mesa_vector4f_free( &store->LitSecondary[0] );
329       _mesa_vector4f_free( &store->LitSecondary[1] );
330       FREE( store );
331       stage->privatePtr = NULL;
332    }
333 }
334
335 const struct tnl_pipeline_stage _tnl_lighting_stage =
336 {
337    "lighting",                  /* name */
338    NULL,                        /* private_data */
339    init_lighting,
340    dtr,                         /* destroy */
341    validate_lighting,
342    run_lighting
343 };