avoid the patch if Mesa_DXTn flag is set
[mesa.git] / src / mesa / tnl / t_vb_light.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 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 struct material_cursor {
50 const GLfloat *ptr;
51 GLuint stride;
52 GLfloat *current;
53 };
54
55 struct light_stage_data {
56 GLvector4f Input;
57 GLvector4f LitColor[2];
58 GLvector4f LitSecondary[2];
59 GLvector4f LitIndex[2];
60 light_func *light_func_tab;
61
62 struct material_cursor mat[MAT_ATTRIB_MAX];
63 GLuint mat_count;
64 GLuint mat_bitmask;
65 };
66
67
68 #define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
69
70
71
72 /* In the case of colormaterial, the effected material attributes
73 * should already have been bound to point to the incoming color data,
74 * prior to running the pipeline.
75 */
76 static void update_materials( GLcontext *ctx,
77 struct light_stage_data *store )
78 {
79 GLuint i;
80
81 for (i = 0 ; i < store->mat_count ; i++) {
82 COPY_4V(store->mat[i].current, store->mat[i].ptr);
83 STRIDE_F(store->mat[i].ptr, store->mat[i].stride);
84 }
85
86 _mesa_update_material( ctx, store->mat_bitmask );
87 _mesa_validate_all_lighting_tables( ctx );
88 }
89
90 static GLuint prepare_materials( GLcontext *ctx,
91 struct vertex_buffer *VB,
92 struct light_stage_data *store )
93 {
94 GLuint i;
95
96 store->mat_count = 0;
97 store->mat_bitmask = 0;
98
99 /* If ColorMaterial enabled, overwrite affected AttrPtr's with
100 * the color pointer. This could be done earlier.
101 */
102 if (ctx->Light.ColorMaterialEnabled) {
103 GLuint bitmask = ctx->Light.ColorMaterialBitmask;
104 for (i = 0 ; i < MAT_ATTRIB_MAX ; i++)
105 if (bitmask & (1<<i))
106 VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] = VB->ColorPtr[0];
107 }
108
109 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ; i < _TNL_ATTRIB_INDEX ; i++) {
110 if (VB->AttribPtr[i]->stride) {
111 GLuint j = store->mat_count++;
112 GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
113 store->mat[j].ptr = VB->AttribPtr[i]->start;
114 store->mat[j].stride = VB->AttribPtr[i]->stride;
115 store->mat[j].current = ctx->Light.Material.Attrib[attr];
116 store->mat_bitmask |= (1<<attr);
117 }
118 }
119
120
121 /* FIXME: Is this already done?
122 */
123 _mesa_update_material( ctx, ~0 );
124 _mesa_validate_all_lighting_tables( ctx );
125
126 return store->mat_count;
127 }
128
129 /* Tables for all the shading functions.
130 */
131 static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
132 static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
133 static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
134 static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
135 static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC];
136
137 #define TAG(x) x
138 #define IDX (0)
139 #include "t_vb_lighttmp.h"
140
141 #define TAG(x) x##_twoside
142 #define IDX (LIGHT_TWOSIDE)
143 #include "t_vb_lighttmp.h"
144
145 #define TAG(x) x##_material
146 #define IDX (LIGHT_MATERIAL)
147 #include "t_vb_lighttmp.h"
148
149 #define TAG(x) x##_twoside_material
150 #define IDX (LIGHT_TWOSIDE|LIGHT_MATERIAL)
151 #include "t_vb_lighttmp.h"
152
153
154 static void init_lighting( void )
155 {
156 static int done;
157
158 if (!done) {
159 init_light_tab();
160 init_light_tab_twoside();
161 init_light_tab_material();
162 init_light_tab_twoside_material();
163 done = 1;
164 }
165 }
166
167
168 static GLboolean run_lighting( GLcontext *ctx,
169 struct tnl_pipeline_stage *stage )
170 {
171 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
172 TNLcontext *tnl = TNL_CONTEXT(ctx);
173 struct vertex_buffer *VB = &tnl->vb;
174 GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
175 GLuint idx;
176
177 /* Make sure we can talk about position x,y and z:
178 */
179 if (stage->changed_inputs & _TNL_BIT_POS) {
180 if (input->size <= 2 && input == VB->ObjPtr) {
181
182 _math_trans_4f( store->Input.data,
183 VB->ObjPtr->data,
184 VB->ObjPtr->stride,
185 GL_FLOAT,
186 VB->ObjPtr->size,
187 0,
188 VB->Count );
189
190 if (input->size <= 2) {
191 /* Clean z.
192 */
193 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 2);
194 }
195
196 if (input->size <= 1) {
197 /* Clean y.
198 */
199 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 1);
200 }
201
202 input = &store->Input;
203 }
204 }
205
206 idx = 0;
207
208 if (prepare_materials( ctx, VB, store ))
209 idx |= LIGHT_MATERIAL;
210
211 if (ctx->Light.Model.TwoSide)
212 idx |= LIGHT_TWOSIDE;
213
214 /* The individual functions know about replaying side-effects
215 * vs. full re-execution.
216 */
217 store->light_func_tab[idx]( ctx, VB, stage, input );
218
219 VB->AttribPtr[_TNL_ATTRIB_COLOR0] = VB->ColorPtr[0];
220 VB->AttribPtr[_TNL_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0];
221 VB->AttribPtr[_TNL_ATTRIB_INDEX] = VB->IndexPtr[0];
222
223 return GL_TRUE;
224 }
225
226
227 /* Called in place of do_lighting when the light table may have changed.
228 */
229 static GLboolean run_validate_lighting( GLcontext *ctx,
230 struct tnl_pipeline_stage *stage )
231 {
232 light_func *tab;
233
234 if (ctx->Visual.rgbMode) {
235 if (ctx->Light._NeedVertices) {
236 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
237 tab = _tnl_light_spec_tab;
238 else
239 tab = _tnl_light_tab;
240 }
241 else {
242 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
243 tab = _tnl_light_fast_single_tab;
244 else
245 tab = _tnl_light_fast_tab;
246 }
247 }
248 else
249 tab = _tnl_light_ci_tab;
250
251
252 LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
253
254 /* This and the above should only be done on _NEW_LIGHT:
255 */
256 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
257
258 /* Now run the stage...
259 */
260 stage->run = run_lighting;
261 return stage->run( ctx, stage );
262 }
263
264
265
266 /* Called the first time stage->run is called. In effect, don't
267 * allocate data until the first time the stage is run.
268 */
269 static GLboolean run_init_lighting( GLcontext *ctx,
270 struct tnl_pipeline_stage *stage )
271 {
272 TNLcontext *tnl = TNL_CONTEXT(ctx);
273 struct light_stage_data *store;
274 GLuint size = tnl->vb.Size;
275
276 stage->privatePtr = MALLOC(sizeof(*store));
277 store = LIGHT_STAGE_DATA(stage);
278 if (!store)
279 return GL_FALSE;
280
281 /* Do onetime init.
282 */
283 init_lighting();
284
285 _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
286 _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
287 _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
288 _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
289 _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
290 _mesa_vector4f_alloc( &store->LitIndex[0], 0, size, 32 );
291 _mesa_vector4f_alloc( &store->LitIndex[1], 0, size, 32 );
292
293 store->LitColor[0].size = 4;
294 store->LitColor[1].size = 4;
295 store->LitSecondary[0].size = 3;
296 store->LitSecondary[1].size = 3;
297
298 store->LitIndex[0].size = 1;
299 store->LitIndex[0].stride = sizeof(GLfloat);
300 store->LitIndex[1].size = 1;
301 store->LitIndex[1].stride = sizeof(GLfloat);
302
303 /* Now validate the stage derived data...
304 */
305 stage->run = run_validate_lighting;
306 return stage->run( ctx, stage );
307 }
308
309
310
311 /*
312 * Check if lighting is enabled. If so, configure the pipeline stage's
313 * type, inputs, and outputs.
314 */
315 static void check_lighting( GLcontext *ctx, struct tnl_pipeline_stage *stage )
316 {
317 stage->active = ctx->Light.Enabled && !ctx->VertexProgram._Enabled;
318 if (stage->active) {
319 if (stage->privatePtr)
320 stage->run = run_validate_lighting;
321 stage->inputs = _TNL_BIT_NORMAL|_TNL_BITS_MAT_ANY;
322 if (ctx->Light._NeedVertices)
323 stage->inputs |= _TNL_BIT_POS;
324 if (ctx->Light.ColorMaterialEnabled)
325 stage->inputs |= _TNL_BIT_COLOR0;
326
327 stage->outputs = _TNL_BIT_COLOR0;
328 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
329 stage->outputs |= _TNL_BIT_COLOR1;
330 }
331 }
332
333
334 static void dtr( struct tnl_pipeline_stage *stage )
335 {
336 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
337
338 if (store) {
339 _mesa_vector4f_free( &store->Input );
340 _mesa_vector4f_free( &store->LitColor[0] );
341 _mesa_vector4f_free( &store->LitColor[1] );
342 _mesa_vector4f_free( &store->LitSecondary[0] );
343 _mesa_vector4f_free( &store->LitSecondary[1] );
344 _mesa_vector4f_free( &store->LitIndex[0] );
345 _mesa_vector4f_free( &store->LitIndex[1] );
346 FREE( store );
347 stage->privatePtr = 0;
348 }
349 }
350
351 const struct tnl_pipeline_stage _tnl_lighting_stage =
352 {
353 "lighting", /* name */
354 _NEW_LIGHT|_NEW_PROGRAM, /* recheck */
355 _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency
356 * otherwise not captured by inputs
357 * (which may be _TNL_BIT_POS) */
358 GL_FALSE, /* active? */
359 0, /* inputs */
360 0, /* outputs */
361 0, /* changed_inputs */
362 NULL, /* private_data */
363 dtr, /* destroy */
364 check_lighting, /* check */
365 run_init_lighting /* run -- initially set to ctr */
366 };