Fix TCL_LIGHT_MODEL_CTL setting in radeonColorMaterial.
[mesa.git] / src / mesa / tnl / t_vb_light.c
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
45 typedef void (*light_func)( GLcontext *ctx,
46 struct vertex_buffer *VB,
47 struct tnl_pipeline_stage *stage,
48 GLvector4f *input );
49
50 struct material_cursor {
51 const GLfloat *ptr;
52 GLuint stride;
53 GLfloat *current;
54 };
55
56 struct 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 */
77 static 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
91 static 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 */
132 static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
133 static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
134 static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
135 static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
136 static 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
155 static 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
169 static 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 return GL_TRUE;
221 }
222
223
224 /* Called in place of do_lighting when the light table may have changed.
225 */
226 static GLboolean run_validate_lighting( GLcontext *ctx,
227 struct tnl_pipeline_stage *stage )
228 {
229 light_func *tab;
230
231 if (ctx->Visual.rgbMode) {
232 if (ctx->Light._NeedVertices) {
233 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
234 tab = _tnl_light_spec_tab;
235 else
236 tab = _tnl_light_tab;
237 }
238 else {
239 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
240 tab = _tnl_light_fast_single_tab;
241 else
242 tab = _tnl_light_fast_tab;
243 }
244 }
245 else
246 tab = _tnl_light_ci_tab;
247
248
249 LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
250
251 /* This and the above should only be done on _NEW_LIGHT:
252 */
253 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
254
255 /* Now run the stage...
256 */
257 stage->run = run_lighting;
258 return stage->run( ctx, stage );
259 }
260
261
262
263 /* Called the first time stage->run is called. In effect, don't
264 * allocate data until the first time the stage is run.
265 */
266 static GLboolean run_init_lighting( GLcontext *ctx,
267 struct tnl_pipeline_stage *stage )
268 {
269 TNLcontext *tnl = TNL_CONTEXT(ctx);
270 struct light_stage_data *store;
271 GLuint size = tnl->vb.Size;
272
273 stage->privatePtr = MALLOC(sizeof(*store));
274 store = LIGHT_STAGE_DATA(stage);
275 if (!store)
276 return GL_FALSE;
277
278 /* Do onetime init.
279 */
280 init_lighting();
281
282 _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
283 _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
284 _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
285 _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
286 _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
287 _mesa_vector4f_alloc( &store->LitIndex[0], 0, size, 32 );
288 _mesa_vector4f_alloc( &store->LitIndex[1], 0, size, 32 );
289
290 store->LitIndex[0].size = 1;
291 store->LitIndex[0].stride = sizeof(GLfloat);
292 store->LitIndex[1].size = 1;
293 store->LitIndex[1].stride = sizeof(GLfloat);
294
295 /* Now validate the stage derived data...
296 */
297 stage->run = run_validate_lighting;
298 return stage->run( ctx, stage );
299 }
300
301
302
303 /*
304 * Check if lighting is enabled. If so, configure the pipeline stage's
305 * type, inputs, and outputs.
306 */
307 static void check_lighting( GLcontext *ctx, struct tnl_pipeline_stage *stage )
308 {
309 stage->active = ctx->Light.Enabled && !ctx->VertexProgram.Enabled;
310 if (stage->active) {
311 if (stage->privatePtr)
312 stage->run = run_validate_lighting;
313 stage->inputs = _TNL_BIT_NORMAL|_TNL_BITS_MAT_ANY;
314 if (ctx->Light._NeedVertices)
315 stage->inputs |= _TNL_BIT_POS;
316 if (ctx->Light.ColorMaterialEnabled)
317 stage->inputs |= _TNL_BIT_COLOR0;
318
319 stage->outputs = _TNL_BIT_COLOR0;
320 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
321 stage->outputs |= _TNL_BIT_COLOR1;
322 }
323 }
324
325
326 static void dtr( struct tnl_pipeline_stage *stage )
327 {
328 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
329
330 if (store) {
331 _mesa_vector4f_free( &store->Input );
332 _mesa_vector4f_free( &store->LitColor[0] );
333 _mesa_vector4f_free( &store->LitColor[1] );
334 _mesa_vector4f_free( &store->LitSecondary[0] );
335 _mesa_vector4f_free( &store->LitSecondary[1] );
336 _mesa_vector4f_free( &store->LitIndex[0] );
337 _mesa_vector4f_free( &store->LitIndex[1] );
338 FREE( store );
339 stage->privatePtr = 0;
340 }
341 }
342
343 const struct tnl_pipeline_stage _tnl_lighting_stage =
344 {
345 "lighting", /* name */
346 _NEW_LIGHT, /* recheck */
347 _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency
348 * otherwise not captured by inputs
349 * (which may be _TNL_BIT_POS) */
350 GL_FALSE, /* active? */
351 0, /* inputs */
352 0, /* outputs */
353 0, /* changed_inputs */
354 NULL, /* private_data */
355 dtr, /* destroy */
356 check_lighting, /* check */
357 run_init_lighting /* run -- initially set to ctr */
358 };