t_vb_light.c revision 53560311294814ae0daa8457307a2b25077bf4e9
1/* $Id: t_vb_light.c,v 1.15 2001/07/17 19:39:32 keithw Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.5
6 *
7 * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28
29#include "glheader.h"
30#include "colormac.h"
31#include "light.h"
32#include "macros.h"
33#include "mem.h"
34#include "mmath.h"
35#include "simple_list.h"
36#include "mtypes.h"
37
38#include "math/m_translate.h"
39
40#include "t_context.h"
41#include "t_pipeline.h"
42
43#define LIGHT_FLAGS         0x1	/* must be first */
44#define LIGHT_TWOSIDE       0x2
45#define LIGHT_COLORMATERIAL 0x4
46#define MAX_LIGHT_FUNC      0x8
47
48typedef void (*light_func)( GLcontext *ctx,
49			    struct vertex_buffer *VB,
50			    struct gl_pipeline_stage *stage,
51			    GLvector4f *input );
52
53struct light_stage_data {
54   struct gl_client_array FloatColor;
55   struct gl_client_array LitColor[2];
56   struct gl_client_array LitSecondary[2];
57   GLvector1ui LitIndex[2];
58   light_func *light_func_tab;
59};
60
61
62#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
63
64
65static void import_color_material( GLcontext *ctx,
66				   struct gl_pipeline_stage *stage )
67{
68   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
69   struct gl_client_array *to = &LIGHT_STAGE_DATA(stage)->FloatColor;
70   struct gl_client_array *from = VB->ColorPtr[0];
71   GLuint count = VB->Count;
72
73   if (!to->Ptr) {
74      to->Ptr = ALIGN_MALLOC( VB->Size * 4 * sizeof(GLfloat), 32 );
75      to->Type = GL_FLOAT;
76   }
77
78   /* No need to transform the same value 3000 times.
79    */
80   if (!from->StrideB) {
81      to->StrideB = 0;
82      count = 1;
83   }
84   else
85      to->StrideB = 4 * sizeof(GLfloat);
86
87   _math_trans_4f( (GLfloat (*)[4]) to->Ptr,
88		   from->Ptr,
89		   from->StrideB,
90		   from->Type,
91		   from->Size,
92		   0,
93		   count);
94
95   VB->ColorPtr[0] = to;
96}
97
98
99/* Tables for all the shading functions.
100 */
101static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
102static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
103static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
104static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
105static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC];
106
107#define TAG(x)           x
108#define IDX              (0)
109#include "t_vb_lighttmp.h"
110
111#define TAG(x)           x##_tw
112#define IDX              (LIGHT_TWOSIDE)
113#include "t_vb_lighttmp.h"
114
115#define TAG(x)           x##_fl
116#define IDX              (LIGHT_FLAGS)
117#include "t_vb_lighttmp.h"
118
119#define TAG(x)           x##_tw_fl
120#define IDX              (LIGHT_FLAGS|LIGHT_TWOSIDE)
121#include "t_vb_lighttmp.h"
122
123#define TAG(x)           x##_cm
124#define IDX              (LIGHT_COLORMATERIAL)
125#include "t_vb_lighttmp.h"
126
127#define TAG(x)           x##_tw_cm
128#define IDX              (LIGHT_TWOSIDE|LIGHT_COLORMATERIAL)
129#include "t_vb_lighttmp.h"
130
131#define TAG(x)           x##_fl_cm
132#define IDX              (LIGHT_FLAGS|LIGHT_COLORMATERIAL)
133#include "t_vb_lighttmp.h"
134
135#define TAG(x)           x##_tw_fl_cm
136#define IDX              (LIGHT_FLAGS|LIGHT_TWOSIDE|LIGHT_COLORMATERIAL)
137#include "t_vb_lighttmp.h"
138
139
140static void init_lighting( void )
141{
142   static int done;
143
144   if (!done) {
145      init_light_tab();
146      init_light_tab_tw();
147      init_light_tab_fl();
148      init_light_tab_tw_fl();
149      init_light_tab_cm();
150      init_light_tab_tw_cm();
151      init_light_tab_fl_cm();
152      init_light_tab_tw_fl_cm();
153      done = 1;
154   }
155}
156
157
158static GLboolean run_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage )
159{
160   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
161   TNLcontext *tnl = TNL_CONTEXT(ctx);
162   struct vertex_buffer *VB = &tnl->vb;
163   GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
164   GLuint ind;
165
166/*     _tnl_print_vert_flags( __FUNCTION__, stage->changed_inputs ); */
167
168   /* Make sure we can talk about elements 0..2 in the vector we are
169    * lighting.
170    */
171   if (stage->changed_inputs & (VERT_EYE|VERT_OBJ)) {
172      if (input->size <= 2) {
173	 if (input->flags & VEC_NOT_WRITEABLE) {
174	    ASSERT(VB->importable_data & VERT_OBJ);
175
176	    VB->import_data( ctx, VERT_OBJ, VEC_NOT_WRITEABLE );
177	    input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
178
179	    ASSERT((input->flags & VEC_NOT_WRITEABLE) == 0);
180	 }
181
182	 _mesa_vector4f_clean_elem(input, VB->Count, 2);
183      }
184   }
185
186   if (VB->Flag)
187      ind = LIGHT_FLAGS;
188   else
189      ind = 0;
190
191   /* The individual functions know about replaying side-effects
192    * vs. full re-execution.
193    */
194   store->light_func_tab[ind]( ctx, VB, stage, input );
195
196   return GL_TRUE;
197}
198
199
200/* Called in place of do_lighting when the light table may have changed.
201 */
202static GLboolean run_validate_lighting( GLcontext *ctx,
203					struct gl_pipeline_stage *stage )
204{
205   GLuint ind = 0;
206   light_func *tab;
207
208   if (ctx->Visual.rgbMode) {
209      if (ctx->Light._NeedVertices) {
210	 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
211	    tab = _tnl_light_spec_tab;
212	 else
213	    tab = _tnl_light_tab;
214      }
215      else {
216	 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
217	    tab = _tnl_light_fast_single_tab;
218	 else
219	    tab = _tnl_light_fast_tab;
220      }
221   }
222   else
223      tab = _tnl_light_ci_tab;
224
225   if (ctx->Light.ColorMaterialEnabled)
226      ind |= LIGHT_COLORMATERIAL;
227
228   if (ctx->Light.Model.TwoSide)
229      ind |= LIGHT_TWOSIDE;
230
231   LIGHT_STAGE_DATA(stage)->light_func_tab = &tab[ind];
232
233   /* This and the above should only be done on _NEW_LIGHT:
234    */
235   _mesa_validate_all_lighting_tables( ctx );
236
237   /* Now run the stage...
238    */
239   stage->run = run_lighting;
240   return stage->run( ctx, stage );
241}
242
243static void alloc_4chan( struct gl_client_array *a, GLuint sz )
244{
245   a->Ptr = ALIGN_MALLOC( sz * sizeof(GLchan) * 4, 32 );
246   a->Size = 4;
247   a->Type = CHAN_TYPE;
248   a->Stride = 0;
249   a->StrideB = sizeof(GLchan) * 4;
250   a->Enabled = 0;
251   a->Flags = 0;
252}
253
254
255/* Called the first time stage->run is called.  In effect, don't
256 * allocate data until the first time the stage is run.
257 */
258static GLboolean run_init_lighting( GLcontext *ctx,
259				    struct gl_pipeline_stage *stage )
260{
261   TNLcontext *tnl = TNL_CONTEXT(ctx);
262   struct light_stage_data *store;
263   GLuint size = tnl->vb.Size;
264
265   stage->privatePtr = MALLOC(sizeof(*store));
266   store = LIGHT_STAGE_DATA(stage);
267   if (!store)
268      return GL_FALSE;
269
270   /* Do onetime init.
271    */
272   init_lighting();
273
274   store->FloatColor.Ptr = 0;
275
276   alloc_4chan( &store->LitColor[0], size );
277   alloc_4chan( &store->LitColor[1], size );
278   alloc_4chan( &store->LitSecondary[0], size );
279   alloc_4chan( &store->LitSecondary[1], size );
280
281   _mesa_vector1ui_alloc( &store->LitIndex[0], 0, size, 32 );
282   _mesa_vector1ui_alloc( &store->LitIndex[1], 0, size, 32 );
283
284   /* Now validate the stage derived data...
285    */
286   stage->run = run_validate_lighting;
287   return stage->run( ctx, stage );
288}
289
290
291
292/*
293 * Check if lighting is enabled.  If so, configure the pipeline stage's
294 * type, inputs, and outputs.
295 */
296static void check_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage )
297{
298   stage->active = ctx->Light.Enabled;
299   if (stage->active) {
300      if (stage->privatePtr)
301	 stage->run = run_validate_lighting;
302      stage->inputs = VERT_NORM|VERT_MATERIAL;
303      if (ctx->Light._NeedVertices)
304	 stage->inputs |= VERT_EYE; /* effectively, even when lighting in obj */
305      if (ctx->Light.ColorMaterialEnabled)
306	 stage->inputs |= VERT_RGBA;
307
308      stage->outputs = VERT_RGBA;
309      if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
310	 stage->outputs |= VERT_SPEC_RGB;
311   }
312}
313
314
315static void dtr( struct gl_pipeline_stage *stage )
316{
317   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
318
319   if (store) {
320      ALIGN_FREE( store->LitColor[0].Ptr );
321      ALIGN_FREE( store->LitColor[1].Ptr );
322      ALIGN_FREE( store->LitSecondary[0].Ptr );
323      ALIGN_FREE( store->LitSecondary[1].Ptr );
324
325      if (store->FloatColor.Ptr)
326	 ALIGN_FREE( store->FloatColor.Ptr );
327
328      _mesa_vector1ui_free( &store->LitIndex[0] );
329      _mesa_vector1ui_free( &store->LitIndex[1] );
330      FREE( store );
331      stage->privatePtr = 0;
332   }
333}
334
335const struct gl_pipeline_stage _tnl_lighting_stage =
336{
337   "lighting",
338   _NEW_LIGHT,			/* recheck */
339   _NEW_LIGHT|_NEW_MODELVIEW,	/* recalc -- modelview dependency
340				 * otherwise not captured by inputs
341				 * (which may be VERT_OBJ) */
342   0,0,0,			/* active, inputs, outputs */
343   0,0,				/* changed_inputs, private_data */
344   dtr,				/* destroy */
345   check_lighting,		/* check */
346   run_init_lighting		/* run -- initially set to ctr */
347};
348