17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
2601e04c3fSmrg#include "c99_math.h"
27c1f859d4Smrg#include "main/glheader.h"
28c1f859d4Smrg#include "main/light.h"
29c1f859d4Smrg#include "main/macros.h"
307ec681f3Smrg
3101e04c3fSmrg#include "util/simple_list.h"
32c1f859d4Smrg#include "main/mtypes.h"
337117f1b4Smrg
347117f1b4Smrg#include "math/m_translate.h"
357117f1b4Smrg
3601e04c3fSmrg#include "util/bitscan.h"
3701e04c3fSmrg
387117f1b4Smrg#include "t_context.h"
397117f1b4Smrg#include "t_pipeline.h"
40af69d88dSmrg#include "tnl.h"
417117f1b4Smrg
427117f1b4Smrg#define LIGHT_TWOSIDE       0x1
437117f1b4Smrg#define LIGHT_MATERIAL      0x2
447117f1b4Smrg#define MAX_LIGHT_FUNC      0x4
457117f1b4Smrg
463464ebd5Sriastradhtypedef void (*light_func)( struct gl_context *ctx,
477117f1b4Smrg			    struct vertex_buffer *VB,
487117f1b4Smrg			    struct tnl_pipeline_stage *stage,
497117f1b4Smrg			    GLvector4f *input );
507117f1b4Smrg
517117f1b4Smrg/**
527117f1b4Smrg * Information for updating current material attributes from vertex color,
537117f1b4Smrg * for GL_COLOR_MATERIAL.
547117f1b4Smrg */
557117f1b4Smrgstruct material_cursor {
567117f1b4Smrg   const GLfloat *ptr;    /* points to src vertex color (in VB array) */
577117f1b4Smrg   GLuint stride;         /* stride to next vertex color (bytes) */
587117f1b4Smrg   GLfloat *current;      /* points to material attribute to update */
597117f1b4Smrg   GLuint size;           /* vertex/color size: 1, 2, 3 or 4 */
607117f1b4Smrg};
617117f1b4Smrg
627117f1b4Smrg/**
637117f1b4Smrg * Data private to this pipeline stage.
647117f1b4Smrg */
657117f1b4Smrgstruct light_stage_data {
667117f1b4Smrg   GLvector4f Input;
677117f1b4Smrg   GLvector4f LitColor[2];
687117f1b4Smrg   GLvector4f LitSecondary[2];
697117f1b4Smrg   light_func *light_func_tab;
707117f1b4Smrg
717117f1b4Smrg   struct material_cursor mat[MAT_ATTRIB_MAX];
727117f1b4Smrg   GLuint mat_count;
737117f1b4Smrg   GLuint mat_bitmask;
747117f1b4Smrg};
757117f1b4Smrg
767117f1b4Smrg
777117f1b4Smrg#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
787117f1b4Smrg
797117f1b4Smrg
807117f1b4Smrg
81af69d88dSmrg/**********************************************************************/
82af69d88dSmrg/*****                  Lighting computation                      *****/
83af69d88dSmrg/**********************************************************************/
84af69d88dSmrg
85af69d88dSmrg
86af69d88dSmrg/*
87af69d88dSmrg * Notes:
88af69d88dSmrg *   When two-sided lighting is enabled we compute the color (or index)
89af69d88dSmrg *   for both the front and back side of the primitive.  Then, when the
90af69d88dSmrg *   orientation of the facet is later learned, we can determine which
91af69d88dSmrg *   color (or index) to use for rendering.
92af69d88dSmrg *
93af69d88dSmrg *   KW: We now know orientation in advance and only shade for
94af69d88dSmrg *       the side or sides which are actually required.
95af69d88dSmrg *
96af69d88dSmrg * Variables:
97af69d88dSmrg *   n = normal vector
98af69d88dSmrg *   V = vertex position
99af69d88dSmrg *   P = light source position
100af69d88dSmrg *   Pe = (0,0,0,1)
101af69d88dSmrg *
102af69d88dSmrg * Precomputed:
103af69d88dSmrg *   IF P[3]==0 THEN
104af69d88dSmrg *       // light at infinity
105af69d88dSmrg *       IF local_viewer THEN
106af69d88dSmrg *           _VP_inf_norm = unit vector from V to P      // Precompute
107af69d88dSmrg *       ELSE
108af69d88dSmrg *           // eye at infinity
109af69d88dSmrg *           _h_inf_norm = Normalize( VP + <0,0,1> )     // Precompute
110af69d88dSmrg *       ENDIF
111af69d88dSmrg *   ENDIF
112af69d88dSmrg *
113af69d88dSmrg * Functions:
114af69d88dSmrg *   Normalize( v ) = normalized vector v
115af69d88dSmrg *   Magnitude( v ) = length of vector v
116af69d88dSmrg */
117af69d88dSmrg
118af69d88dSmrg
119af69d88dSmrg
120af69d88dSmrgstatic void
121af69d88dSmrgvalidate_shine_table( struct gl_context *ctx, GLuint side, GLfloat shininess )
122af69d88dSmrg{
123af69d88dSmrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
124af69d88dSmrg   struct tnl_shine_tab *list = tnl->_ShineTabList;
125af69d88dSmrg   struct tnl_shine_tab *s;
126af69d88dSmrg
12701e04c3fSmrg   assert(side < 2);
128af69d88dSmrg
129af69d88dSmrg   foreach(s, list)
130af69d88dSmrg      if ( s->shininess == shininess )
131af69d88dSmrg	 break;
132af69d88dSmrg
133af69d88dSmrg   if (s == list) {
134af69d88dSmrg      GLint j;
135af69d88dSmrg      GLfloat *m;
136af69d88dSmrg
137af69d88dSmrg      foreach(s, list)
138af69d88dSmrg	 if (s->refcount == 0)
139af69d88dSmrg	    break;
140af69d88dSmrg
141af69d88dSmrg      m = s->tab;
14201e04c3fSmrg      m[0] = 0.0F;
14301e04c3fSmrg      if (shininess == 0.0F) {
144af69d88dSmrg	 for (j = 1 ; j <= SHINE_TABLE_SIZE ; j++)
14501e04c3fSmrg	    m[j] = 1.0F;
146af69d88dSmrg      }
147af69d88dSmrg      else {
148af69d88dSmrg	 for (j = 1 ; j < SHINE_TABLE_SIZE ; j++) {
14901e04c3fSmrg            GLfloat t, x = j / (GLfloat) (SHINE_TABLE_SIZE - 1);
15001e04c3fSmrg            if (x < 0.005F) /* underflow check */
15101e04c3fSmrg               x = 0.005F;
15201e04c3fSmrg            t = powf(x, shininess);
15301e04c3fSmrg	    if (t > 1e-20F)
15401e04c3fSmrg	       m[j] = t;
155af69d88dSmrg	    else
15601e04c3fSmrg	       m[j] = 0.0F;
157af69d88dSmrg	 }
15801e04c3fSmrg	 m[SHINE_TABLE_SIZE] = 1.0F;
159af69d88dSmrg      }
160af69d88dSmrg
161af69d88dSmrg      s->shininess = shininess;
162af69d88dSmrg   }
163af69d88dSmrg
164af69d88dSmrg   if (tnl->_ShineTable[side])
165af69d88dSmrg      tnl->_ShineTable[side]->refcount--;
166af69d88dSmrg
167af69d88dSmrg   tnl->_ShineTable[side] = s;
168af69d88dSmrg   move_to_tail( list, s );
169af69d88dSmrg   s->refcount++;
170af69d88dSmrg}
171af69d88dSmrg
172af69d88dSmrg
173af69d88dSmrgvoid
174af69d88dSmrg_tnl_validate_shine_tables( struct gl_context *ctx )
175af69d88dSmrg{
176af69d88dSmrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
177af69d88dSmrg   GLfloat shininess;
1787ec681f3Smrg
179af69d88dSmrg   shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
180af69d88dSmrg   if (!tnl->_ShineTable[0] || tnl->_ShineTable[0]->shininess != shininess)
181af69d88dSmrg      validate_shine_table( ctx, 0, shininess );
182af69d88dSmrg
183af69d88dSmrg   shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
184af69d88dSmrg   if (!tnl->_ShineTable[1] || tnl->_ShineTable[1]->shininess != shininess)
185af69d88dSmrg      validate_shine_table( ctx, 1, shininess );
186af69d88dSmrg}
187af69d88dSmrg
188af69d88dSmrg
1897117f1b4Smrg/**
1907117f1b4Smrg * In the case of colormaterial, the effected material attributes
1917117f1b4Smrg * should already have been bound to point to the incoming color data,
1927117f1b4Smrg * prior to running the pipeline.
1937117f1b4Smrg * This function copies the vertex's color to the material attributes
1947117f1b4Smrg * which are tracking glColor.
1957117f1b4Smrg * It's called per-vertex in the lighting loop.
1967117f1b4Smrg */
1977117f1b4Smrgstatic void
1983464ebd5Sriastradhupdate_materials(struct gl_context *ctx, struct light_stage_data *store)
1997117f1b4Smrg{
2007117f1b4Smrg   GLuint i;
2017117f1b4Smrg
2027117f1b4Smrg   for (i = 0 ; i < store->mat_count ; i++) {
2037117f1b4Smrg      /* update the material */
2047117f1b4Smrg      COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr);
2057117f1b4Smrg      /* increment src vertex color pointer */
2067117f1b4Smrg      STRIDE_F(store->mat[i].ptr, store->mat[i].stride);
2077117f1b4Smrg   }
2087ec681f3Smrg
2097117f1b4Smrg   /* recompute derived light/material values */
2107117f1b4Smrg   _mesa_update_material( ctx, store->mat_bitmask );
2117117f1b4Smrg   /* XXX we should only call this if we're tracking/changing the specular
2127117f1b4Smrg    * exponent.
2137117f1b4Smrg    */
214af69d88dSmrg   _tnl_validate_shine_tables( ctx );
2157117f1b4Smrg}
2167117f1b4Smrg
2177117f1b4Smrg
2187117f1b4Smrg/**
2197117f1b4Smrg * Prepare things prior to running the lighting stage.
2207117f1b4Smrg * Return number of material attributes which will track vertex color.
2217117f1b4Smrg */
2227117f1b4Smrgstatic GLuint
2233464ebd5Sriastradhprepare_materials(struct gl_context *ctx,
2247117f1b4Smrg                  struct vertex_buffer *VB, struct light_stage_data *store)
2257117f1b4Smrg{
2267117f1b4Smrg   GLuint i;
2277ec681f3Smrg
2287117f1b4Smrg   store->mat_count = 0;
2297117f1b4Smrg   store->mat_bitmask = 0;
2307117f1b4Smrg
231af69d88dSmrg   /* Examine the _ColorMaterialBitmask to determine which materials
2327117f1b4Smrg    * track vertex color.  Override the material attribute's pointer
2337117f1b4Smrg    * with the color pointer for each one.
2347117f1b4Smrg    */
2357117f1b4Smrg   if (ctx->Light.ColorMaterialEnabled) {
23601e04c3fSmrg      GLbitfield bitmask = ctx->Light._ColorMaterialBitmask;
23701e04c3fSmrg      while (bitmask) {
23801e04c3fSmrg         const int i = u_bit_scan(&bitmask);
23901e04c3fSmrg         VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
24001e04c3fSmrg            VB->AttribPtr[_TNL_ATTRIB_COLOR0];
24101e04c3fSmrg      }
2427117f1b4Smrg   }
2437117f1b4Smrg
2447117f1b4Smrg   /* Now, for each material attribute that's tracking vertex color, save
2457117f1b4Smrg    * some values (ptr, stride, size, current) that we'll need in
2467117f1b4Smrg    * update_materials(), above, that'll actually copy the vertex color to
2477117f1b4Smrg    * the material attribute(s).
2487117f1b4Smrg    */
2497117f1b4Smrg   for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) {
2507117f1b4Smrg      if (VB->AttribPtr[i]->stride) {
2517117f1b4Smrg	 const GLuint j = store->mat_count++;
2527117f1b4Smrg	 const GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
2537117f1b4Smrg	 store->mat[j].ptr    = VB->AttribPtr[i]->start;
2547117f1b4Smrg	 store->mat[j].stride = VB->AttribPtr[i]->stride;
2557117f1b4Smrg	 store->mat[j].size   = VB->AttribPtr[i]->size;
2567117f1b4Smrg	 store->mat[j].current = ctx->Light.Material.Attrib[attr];
2577117f1b4Smrg	 store->mat_bitmask |= (1<<attr);
2587117f1b4Smrg      }
2597117f1b4Smrg   }
2607117f1b4Smrg
2617117f1b4Smrg   /* FIXME: Is this already done?
2627117f1b4Smrg    */
2637117f1b4Smrg   _mesa_update_material( ctx, ~0 );
264af69d88dSmrg
265af69d88dSmrg   _tnl_validate_shine_tables( ctx );
2667117f1b4Smrg
2677117f1b4Smrg   return store->mat_count;
2687117f1b4Smrg}
2697117f1b4Smrg
270af69d88dSmrg/*
271af69d88dSmrg * Compute dp ^ SpecularExponent.
272af69d88dSmrg * Lerp between adjacent values in the f(x) lookup table, giving a
273af69d88dSmrg * continuous function, with adequate overall accuracy.  (Though still
274af69d88dSmrg * pretty good compared to a straight lookup).
275af69d88dSmrg */
276af69d88dSmrgstatic inline GLfloat
277af69d88dSmrglookup_shininess(const struct gl_context *ctx, GLuint face, GLfloat dp)
278af69d88dSmrg{
279af69d88dSmrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
280af69d88dSmrg   const struct tnl_shine_tab *tab = tnl->_ShineTable[face];
281af69d88dSmrg   float f = dp * (SHINE_TABLE_SIZE - 1);
282af69d88dSmrg   int k = (int) f;
283af69d88dSmrg   if (k < 0 /* gcc may cast an overflow float value to negative int value */
284af69d88dSmrg	|| k > SHINE_TABLE_SIZE - 2)
285af69d88dSmrg      return powf(dp, tab->shininess);
286af69d88dSmrg   else
287af69d88dSmrg      return tab->tab[k] + (f - k) * (tab->tab[k+1] - tab->tab[k]);
288af69d88dSmrg}
289af69d88dSmrg
2907117f1b4Smrg/* Tables for all the shading functions.
2917117f1b4Smrg */
2927117f1b4Smrgstatic light_func _tnl_light_tab[MAX_LIGHT_FUNC];
2937117f1b4Smrgstatic light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
2947117f1b4Smrgstatic light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
2957117f1b4Smrgstatic light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
2967117f1b4Smrg
2977117f1b4Smrg#define TAG(x)           x
2987117f1b4Smrg#define IDX              (0)
2997117f1b4Smrg#include "t_vb_lighttmp.h"
3007117f1b4Smrg
3017117f1b4Smrg#define TAG(x)           x##_twoside
3027117f1b4Smrg#define IDX              (LIGHT_TWOSIDE)
3037117f1b4Smrg#include "t_vb_lighttmp.h"
3047117f1b4Smrg
3057117f1b4Smrg#define TAG(x)           x##_material
3067117f1b4Smrg#define IDX              (LIGHT_MATERIAL)
3077117f1b4Smrg#include "t_vb_lighttmp.h"
3087117f1b4Smrg
3097117f1b4Smrg#define TAG(x)           x##_twoside_material
3107117f1b4Smrg#define IDX              (LIGHT_TWOSIDE|LIGHT_MATERIAL)
3117117f1b4Smrg#include "t_vb_lighttmp.h"
3127117f1b4Smrg
3137117f1b4Smrg
3147117f1b4Smrgstatic void init_lighting_tables( void )
3157117f1b4Smrg{
3167117f1b4Smrg   static int done;
3177117f1b4Smrg
3187117f1b4Smrg   if (!done) {
3197117f1b4Smrg      init_light_tab();
3207117f1b4Smrg      init_light_tab_twoside();
3217117f1b4Smrg      init_light_tab_material();
3227117f1b4Smrg      init_light_tab_twoside_material();
3237117f1b4Smrg      done = 1;
3247117f1b4Smrg   }
3257117f1b4Smrg}
3267117f1b4Smrg
3277117f1b4Smrg
3287ec681f3Smrgstatic GLboolean run_lighting( struct gl_context *ctx,
3297117f1b4Smrg			       struct tnl_pipeline_stage *stage )
3307117f1b4Smrg{
3317117f1b4Smrg   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
3327117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
3337117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;
334cdc920a0Smrg   GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->AttribPtr[_TNL_ATTRIB_POS];
3357117f1b4Smrg   GLuint idx;
3367117f1b4Smrg
3377117f1b4Smrg   if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
3387117f1b4Smrg      return GL_TRUE;
3397117f1b4Smrg
3407117f1b4Smrg   /* Make sure we can talk about position x,y and z:
3417117f1b4Smrg    */
342cdc920a0Smrg   if (input->size <= 2 && input == VB->AttribPtr[_TNL_ATTRIB_POS]) {
3437117f1b4Smrg
3447117f1b4Smrg      _math_trans_4f( store->Input.data,
345cdc920a0Smrg		      VB->AttribPtr[_TNL_ATTRIB_POS]->data,
346cdc920a0Smrg		      VB->AttribPtr[_TNL_ATTRIB_POS]->stride,
3477117f1b4Smrg		      GL_FLOAT,
348cdc920a0Smrg		      VB->AttribPtr[_TNL_ATTRIB_POS]->size,
3497117f1b4Smrg		      0,
3507117f1b4Smrg		      VB->Count );
3517117f1b4Smrg
3527117f1b4Smrg      if (input->size <= 2) {
3537117f1b4Smrg	 /* Clean z.
3547117f1b4Smrg	  */
3557117f1b4Smrg	 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 2);
3567117f1b4Smrg      }
3577ec681f3Smrg
3587117f1b4Smrg      if (input->size <= 1) {
3597117f1b4Smrg	 /* Clean y.
3607117f1b4Smrg	  */
3617117f1b4Smrg	 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 1);
3627117f1b4Smrg      }
3637117f1b4Smrg
3647117f1b4Smrg      input = &store->Input;
3657117f1b4Smrg   }
3667ec681f3Smrg
3677117f1b4Smrg   idx = 0;
3687117f1b4Smrg
3697117f1b4Smrg   if (prepare_materials( ctx, VB, store ))
3707117f1b4Smrg      idx |= LIGHT_MATERIAL;
3717117f1b4Smrg
3727117f1b4Smrg   if (ctx->Light.Model.TwoSide)
3737117f1b4Smrg      idx |= LIGHT_TWOSIDE;
3747117f1b4Smrg
3757117f1b4Smrg   /* The individual functions know about replaying side-effects
3767ec681f3Smrg    * vs. full re-execution.
3777117f1b4Smrg    */
3787117f1b4Smrg   store->light_func_tab[idx]( ctx, VB, stage, input );
3797117f1b4Smrg
3807117f1b4Smrg   return GL_TRUE;
3817117f1b4Smrg}
3827117f1b4Smrg
3837117f1b4Smrg
3847117f1b4Smrg/* Called in place of do_lighting when the light table may have changed.
3857117f1b4Smrg */
3863464ebd5Sriastradhstatic void validate_lighting( struct gl_context *ctx,
3877117f1b4Smrg					struct tnl_pipeline_stage *stage )
3887117f1b4Smrg{
3897117f1b4Smrg   light_func *tab;
3907117f1b4Smrg
3917117f1b4Smrg   if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
3927117f1b4Smrg      return;
3937117f1b4Smrg
394cdc920a0Smrg   if (ctx->Light._NeedVertices) {
395cdc920a0Smrg      if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
396cdc920a0Smrg	 tab = _tnl_light_spec_tab;
397cdc920a0Smrg      else
398cdc920a0Smrg	 tab = _tnl_light_tab;
399cdc920a0Smrg   }
400cdc920a0Smrg   else {
40101e04c3fSmrg      /* Power of two means only a single active light. */
4027ec681f3Smrg      if (util_is_power_of_two_or_zero(ctx->Light._EnabledLights))
403cdc920a0Smrg	 tab = _tnl_light_fast_single_tab;
404cdc920a0Smrg      else
405cdc920a0Smrg	 tab = _tnl_light_fast_tab;
4067117f1b4Smrg   }
4077117f1b4Smrg
4087117f1b4Smrg
4097117f1b4Smrg   LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
4107117f1b4Smrg
4117117f1b4Smrg   /* This and the above should only be done on _NEW_LIGHT:
4127117f1b4Smrg    */
4137117f1b4Smrg   TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
4147117f1b4Smrg}
4157117f1b4Smrg
4167117f1b4Smrg
4177117f1b4Smrg
4187117f1b4Smrg/* Called the first time stage->run is called.  In effect, don't
4197117f1b4Smrg * allocate data until the first time the stage is run.
4207117f1b4Smrg */
4213464ebd5Sriastradhstatic GLboolean init_lighting( struct gl_context *ctx,
4227117f1b4Smrg				struct tnl_pipeline_stage *stage )
4237117f1b4Smrg{
4247117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
4257117f1b4Smrg   struct light_stage_data *store;
4267117f1b4Smrg   GLuint size = tnl->vb.Size;
4277117f1b4Smrg
428af69d88dSmrg   stage->privatePtr = malloc(sizeof(*store));
4297117f1b4Smrg   store = LIGHT_STAGE_DATA(stage);
4307117f1b4Smrg   if (!store)
4317117f1b4Smrg      return GL_FALSE;
4327117f1b4Smrg
4337117f1b4Smrg   /* Do onetime init.
4347117f1b4Smrg    */
4357117f1b4Smrg   init_lighting_tables();
4367117f1b4Smrg
4377117f1b4Smrg   _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
4387117f1b4Smrg   _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
4397117f1b4Smrg   _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
4407117f1b4Smrg   _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
4417117f1b4Smrg   _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
4427117f1b4Smrg
4437117f1b4Smrg   store->LitColor[0].size = 4;
4447117f1b4Smrg   store->LitColor[1].size = 4;
4457117f1b4Smrg   store->LitSecondary[0].size = 3;
4467117f1b4Smrg   store->LitSecondary[1].size = 3;
4477117f1b4Smrg
4487117f1b4Smrg   return GL_TRUE;
4497117f1b4Smrg}
4507117f1b4Smrg
4517117f1b4Smrg
4527117f1b4Smrg
4537117f1b4Smrg
4547117f1b4Smrgstatic void dtr( struct tnl_pipeline_stage *stage )
4557117f1b4Smrg{
4567117f1b4Smrg   struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
4577117f1b4Smrg
4587117f1b4Smrg   if (store) {
4597117f1b4Smrg      _mesa_vector4f_free( &store->Input );
4607117f1b4Smrg      _mesa_vector4f_free( &store->LitColor[0] );
4617117f1b4Smrg      _mesa_vector4f_free( &store->LitColor[1] );
4627117f1b4Smrg      _mesa_vector4f_free( &store->LitSecondary[0] );
4637117f1b4Smrg      _mesa_vector4f_free( &store->LitSecondary[1] );
464af69d88dSmrg      free( store );
4657117f1b4Smrg      stage->privatePtr = NULL;
4667117f1b4Smrg   }
4677117f1b4Smrg}
4687117f1b4Smrg
4697117f1b4Smrgconst struct tnl_pipeline_stage _tnl_lighting_stage =
4707117f1b4Smrg{
4717117f1b4Smrg   "lighting",			/* name */
4727117f1b4Smrg   NULL,			/* private_data */
4737117f1b4Smrg   init_lighting,
4747117f1b4Smrg   dtr,				/* destroy */
4757117f1b4Smrg   validate_lighting,
4767117f1b4Smrg   run_lighting
4777117f1b4Smrg};
478