Re-commit t_vertex.[ch] changes to fd.o server.
[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 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 */
230 static 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 */
270 static 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 */
311 static 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
330 static 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
347 const 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 };