Store material attributes in an Attrib[] style array. This is a
[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_FLAGS 0x1 /* must be first */
42 #define LIGHT_TWOSIDE 0x2
43 #define LIGHT_COLORMATERIAL 0x4
44 #define MAX_LIGHT_FUNC 0x8
45
46 typedef void (*light_func)( GLcontext *ctx,
47 struct vertex_buffer *VB,
48 struct gl_pipeline_stage *stage,
49 GLvector4f *input );
50
51 struct light_stage_data {
52 struct gl_client_array FloatColor;
53 struct gl_client_array LitColor[2];
54 struct gl_client_array LitSecondary[2];
55 GLvector1ui LitIndex[2];
56 light_func *light_func_tab;
57 };
58
59
60 #define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
61
62
63 static void import_color_material( GLcontext *ctx,
64 struct gl_pipeline_stage *stage )
65 {
66 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
67 struct gl_client_array *to = &LIGHT_STAGE_DATA(stage)->FloatColor;
68 struct gl_client_array *from = VB->ColorPtr[0];
69 GLuint count = VB->Count;
70
71 if (!to->Ptr) {
72 to->Ptr = ALIGN_MALLOC( VB->Size * 4 * sizeof(GLfloat), 32 );
73 to->Type = GL_FLOAT;
74 }
75
76 /* No need to transform the same value 3000 times.
77 */
78 if (!from->StrideB) {
79 to->StrideB = 0;
80 count = 1;
81 }
82 else
83 to->StrideB = 4 * sizeof(GLfloat);
84
85 _math_trans_4f( (GLfloat (*)[4]) to->Ptr,
86 from->Ptr,
87 from->StrideB,
88 from->Type,
89 from->Size,
90 0,
91 count);
92
93 VB->ColorPtr[0] = to;
94 }
95
96
97 static void update_materials( GLcontext *ctx,
98 const struct gl_material *src,
99 GLuint bitmask )
100 {
101 _mesa_copy_materials( &ctx->Light.Material, src, bitmask );
102 _mesa_update_material( ctx, bitmask );
103 }
104
105 /* Tables for all the shading functions.
106 */
107 static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
108 static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
109 static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
110 static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
111 static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC];
112
113 #define TAG(x) x
114 #define IDX (0)
115 #include "t_vb_lighttmp.h"
116
117 #define TAG(x) x##_tw
118 #define IDX (LIGHT_TWOSIDE)
119 #include "t_vb_lighttmp.h"
120
121 #define TAG(x) x##_fl
122 #define IDX (LIGHT_FLAGS)
123 #include "t_vb_lighttmp.h"
124
125 #define TAG(x) x##_tw_fl
126 #define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE)
127 #include "t_vb_lighttmp.h"
128
129 #define TAG(x) x##_cm
130 #define IDX (LIGHT_COLORMATERIAL)
131 #include "t_vb_lighttmp.h"
132
133 #define TAG(x) x##_tw_cm
134 #define IDX (LIGHT_TWOSIDE|LIGHT_COLORMATERIAL)
135 #include "t_vb_lighttmp.h"
136
137 #define TAG(x) x##_fl_cm
138 #define IDX (LIGHT_FLAGS|LIGHT_COLORMATERIAL)
139 #include "t_vb_lighttmp.h"
140
141 #define TAG(x) x##_tw_fl_cm
142 #define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE|LIGHT_COLORMATERIAL)
143 #include "t_vb_lighttmp.h"
144
145
146 static void init_lighting( void )
147 {
148 static int done;
149
150 if (!done) {
151 init_light_tab();
152 init_light_tab_tw();
153 init_light_tab_fl();
154 init_light_tab_tw_fl();
155 init_light_tab_cm();
156 init_light_tab_tw_cm();
157 init_light_tab_fl_cm();
158 init_light_tab_tw_fl_cm();
159 done = 1;
160 }
161 }
162
163
164 static GLboolean run_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage )
165 {
166 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
167 TNLcontext *tnl = TNL_CONTEXT(ctx);
168 struct vertex_buffer *VB = &tnl->vb;
169 GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
170 GLuint ind;
171
172 /* _tnl_print_vert_flags( __FUNCTION__, stage->changed_inputs ); */
173
174 /* Make sure we can talk about elements 0..2 in the vector we are
175 * lighting.
176 */
177 if (stage->changed_inputs & (VERT_BIT_EYE|VERT_BIT_POS)) {
178 if (input->size <= 2) {
179 if (input->flags & VEC_NOT_WRITEABLE) {
180 ASSERT(VB->importable_data & VERT_BIT_POS);
181
182 VB->import_data( ctx, VERT_BIT_POS, VEC_NOT_WRITEABLE );
183 input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
184
185 ASSERT((input->flags & VEC_NOT_WRITEABLE) == 0);
186 }
187
188 _mesa_vector4f_clean_elem(input, VB->Count, 2);
189 }
190 }
191
192 if (VB->Flag)
193 ind = LIGHT_FLAGS;
194 else
195 ind = 0;
196
197 /* The individual functions know about replaying side-effects
198 * vs. full re-execution.
199 */
200 store->light_func_tab[ind]( ctx, VB, stage, input );
201
202 return GL_TRUE;
203 }
204
205
206 /* Called in place of do_lighting when the light table may have changed.
207 */
208 static GLboolean run_validate_lighting( GLcontext *ctx,
209 struct gl_pipeline_stage *stage )
210 {
211 GLuint ind = 0;
212 light_func *tab;
213
214 if (ctx->Visual.rgbMode) {
215 if (ctx->Light._NeedVertices) {
216 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
217 tab = _tnl_light_spec_tab;
218 else
219 tab = _tnl_light_tab;
220 }
221 else {
222 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
223 tab = _tnl_light_fast_single_tab;
224 else
225 tab = _tnl_light_fast_tab;
226 }
227 }
228 else
229 tab = _tnl_light_ci_tab;
230
231 if (ctx->Light.ColorMaterialEnabled)
232 ind |= LIGHT_COLORMATERIAL;
233
234 if (ctx->Light.Model.TwoSide)
235 ind |= LIGHT_TWOSIDE;
236
237 LIGHT_STAGE_DATA(stage)->light_func_tab = &tab[ind];
238
239 /* This and the above should only be done on _NEW_LIGHT:
240 */
241 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
242
243 /* Now run the stage...
244 */
245 stage->run = run_lighting;
246 return stage->run( ctx, stage );
247 }
248
249 static void alloc_4chan( struct gl_client_array *a, GLuint sz )
250 {
251 a->Ptr = ALIGN_MALLOC( sz * sizeof(GLchan) * 4, 32 );
252 a->Size = 4;
253 a->Type = CHAN_TYPE;
254 a->Stride = 0;
255 a->StrideB = sizeof(GLchan) * 4;
256 a->Enabled = 0;
257 a->Flags = 0;
258 }
259
260
261 /* Called the first time stage->run is called. In effect, don't
262 * allocate data until the first time the stage is run.
263 */
264 static GLboolean run_init_lighting( GLcontext *ctx,
265 struct gl_pipeline_stage *stage )
266 {
267 TNLcontext *tnl = TNL_CONTEXT(ctx);
268 struct light_stage_data *store;
269 GLuint size = tnl->vb.Size;
270
271 stage->privatePtr = MALLOC(sizeof(*store));
272 store = LIGHT_STAGE_DATA(stage);
273 if (!store)
274 return GL_FALSE;
275
276 /* Do onetime init.
277 */
278 init_lighting();
279
280 store->FloatColor.Ptr = 0;
281
282 alloc_4chan( &store->LitColor[0], size );
283 alloc_4chan( &store->LitColor[1], size );
284 alloc_4chan( &store->LitSecondary[0], size );
285 alloc_4chan( &store->LitSecondary[1], size );
286
287 _mesa_vector1ui_alloc( &store->LitIndex[0], 0, size, 32 );
288 _mesa_vector1ui_alloc( &store->LitIndex[1], 0, size, 32 );
289
290 /* Now validate the stage derived data...
291 */
292 stage->run = run_validate_lighting;
293 return stage->run( ctx, stage );
294 }
295
296
297
298 /*
299 * Check if lighting is enabled. If so, configure the pipeline stage's
300 * type, inputs, and outputs.
301 */
302 static void check_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage )
303 {
304 stage->active = ctx->Light.Enabled && !ctx->VertexProgram.Enabled;
305 if (stage->active) {
306 if (stage->privatePtr)
307 stage->run = run_validate_lighting;
308 stage->inputs = VERT_BIT_NORMAL|VERT_BIT_MATERIAL;
309 if (ctx->Light._NeedVertices)
310 stage->inputs |= VERT_BIT_EYE; /* effectively, even when lighting in obj */
311 if (ctx->Light.ColorMaterialEnabled)
312 stage->inputs |= VERT_BIT_COLOR0;
313
314 stage->outputs = VERT_BIT_COLOR0;
315 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
316 stage->outputs |= VERT_BIT_COLOR1;
317 }
318 }
319
320
321 static void dtr( struct gl_pipeline_stage *stage )
322 {
323 struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
324
325 if (store) {
326 ALIGN_FREE( store->LitColor[0].Ptr );
327 ALIGN_FREE( store->LitColor[1].Ptr );
328 ALIGN_FREE( store->LitSecondary[0].Ptr );
329 ALIGN_FREE( store->LitSecondary[1].Ptr );
330
331 if (store->FloatColor.Ptr)
332 ALIGN_FREE( store->FloatColor.Ptr );
333
334 _mesa_vector1ui_free( &store->LitIndex[0] );
335 _mesa_vector1ui_free( &store->LitIndex[1] );
336 FREE( store );
337 stage->privatePtr = 0;
338 }
339 }
340
341 const struct gl_pipeline_stage _tnl_lighting_stage =
342 {
343 "lighting", /* name */
344 _NEW_LIGHT, /* recheck */
345 _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency
346 * otherwise not captured by inputs
347 * (which may be VERT_BIT_POS) */
348 GL_FALSE, /* active? */
349 0, /* inputs */
350 0, /* outputs */
351 0, /* changed_inputs */
352 NULL, /* private_data */
353 dtr, /* destroy */
354 check_lighting, /* check */
355 run_init_lighting /* run -- initially set to ctr */
356 };