Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25.  
  26.  
  27. #include "main/glheader.h"
  28. #include "main/colormac.h"
  29. #include "main/light.h"
  30. #include "main/macros.h"
  31. #include "main/imports.h"
  32. #include "main/simple_list.h"
  33. #include "main/mtypes.h"
  34.  
  35. #include "math/m_translate.h"
  36.  
  37. #include "t_context.h"
  38. #include "t_pipeline.h"
  39. #include "tnl.h"
  40.  
  41. #define LIGHT_TWOSIDE       0x1
  42. #define LIGHT_MATERIAL      0x2
  43. #define MAX_LIGHT_FUNC      0x4
  44.  
  45. typedef void (*light_func)( struct gl_context *ctx,
  46.                             struct vertex_buffer *VB,
  47.                             struct tnl_pipeline_stage *stage,
  48.                             GLvector4f *input );
  49.  
  50. /**
  51.  * Information for updating current material attributes from vertex color,
  52.  * for GL_COLOR_MATERIAL.
  53.  */
  54. struct material_cursor {
  55.    const GLfloat *ptr;    /* points to src vertex color (in VB array) */
  56.    GLuint stride;         /* stride to next vertex color (bytes) */
  57.    GLfloat *current;      /* points to material attribute to update */
  58.    GLuint size;           /* vertex/color size: 1, 2, 3 or 4 */
  59. };
  60.  
  61. /**
  62.  * Data private to this pipeline stage.
  63.  */
  64. struct light_stage_data {
  65.    GLvector4f Input;
  66.    GLvector4f LitColor[2];
  67.    GLvector4f LitSecondary[2];
  68.    light_func *light_func_tab;
  69.  
  70.    struct material_cursor mat[MAT_ATTRIB_MAX];
  71.    GLuint mat_count;
  72.    GLuint mat_bitmask;
  73. };
  74.  
  75.  
  76. #define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
  77.  
  78.  
  79.  
  80. /**********************************************************************/
  81. /*****                  Lighting computation                      *****/
  82. /**********************************************************************/
  83.  
  84.  
  85. /*
  86.  * Notes:
  87.  *   When two-sided lighting is enabled we compute the color (or index)
  88.  *   for both the front and back side of the primitive.  Then, when the
  89.  *   orientation of the facet is later learned, we can determine which
  90.  *   color (or index) to use for rendering.
  91.  *
  92.  *   KW: We now know orientation in advance and only shade for
  93.  *       the side or sides which are actually required.
  94.  *
  95.  * Variables:
  96.  *   n = normal vector
  97.  *   V = vertex position
  98.  *   P = light source position
  99.  *   Pe = (0,0,0,1)
  100.  *
  101.  * Precomputed:
  102.  *   IF P[3]==0 THEN
  103.  *       // light at infinity
  104.  *       IF local_viewer THEN
  105.  *           _VP_inf_norm = unit vector from V to P      // Precompute
  106.  *       ELSE
  107.  *           // eye at infinity
  108.  *           _h_inf_norm = Normalize( VP + <0,0,1> )     // Precompute
  109.  *       ENDIF
  110.  *   ENDIF
  111.  *
  112.  * Functions:
  113.  *   Normalize( v ) = normalized vector v
  114.  *   Magnitude( v ) = length of vector v
  115.  */
  116.  
  117.  
  118.  
  119. static void
  120. validate_shine_table( struct gl_context *ctx, GLuint side, GLfloat shininess )
  121. {
  122.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  123.    struct tnl_shine_tab *list = tnl->_ShineTabList;
  124.    struct tnl_shine_tab *s;
  125.  
  126.    ASSERT(side < 2);
  127.  
  128.    foreach(s, list)
  129.       if ( s->shininess == shininess )
  130.          break;
  131.  
  132.    if (s == list) {
  133.       GLint j;
  134.       GLfloat *m;
  135.  
  136.       foreach(s, list)
  137.          if (s->refcount == 0)
  138.             break;
  139.  
  140.       m = s->tab;
  141.       m[0] = 0.0;
  142.       if (shininess == 0.0) {
  143.          for (j = 1 ; j <= SHINE_TABLE_SIZE ; j++)
  144.             m[j] = 1.0;
  145.       }
  146.       else {
  147.          for (j = 1 ; j < SHINE_TABLE_SIZE ; j++) {
  148.             GLdouble t, x = j / (GLfloat) (SHINE_TABLE_SIZE - 1);
  149.             if (x < 0.005) /* underflow check */
  150.                x = 0.005;
  151.             t = pow(x, shininess);
  152.             if (t > 1e-20)
  153.                m[j] = (GLfloat) t;
  154.             else
  155.                m[j] = 0.0;
  156.          }
  157.          m[SHINE_TABLE_SIZE] = 1.0;
  158.       }
  159.  
  160.       s->shininess = shininess;
  161.    }
  162.  
  163.    if (tnl->_ShineTable[side])
  164.       tnl->_ShineTable[side]->refcount--;
  165.  
  166.    tnl->_ShineTable[side] = s;
  167.    move_to_tail( list, s );
  168.    s->refcount++;
  169. }
  170.  
  171.  
  172. void
  173. _tnl_validate_shine_tables( struct gl_context *ctx )
  174. {
  175.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  176.    GLfloat shininess;
  177.    
  178.    shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
  179.    if (!tnl->_ShineTable[0] || tnl->_ShineTable[0]->shininess != shininess)
  180.       validate_shine_table( ctx, 0, shininess );
  181.  
  182.    shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
  183.    if (!tnl->_ShineTable[1] || tnl->_ShineTable[1]->shininess != shininess)
  184.       validate_shine_table( ctx, 1, shininess );
  185. }
  186.  
  187.  
  188. /**
  189.  * In the case of colormaterial, the effected material attributes
  190.  * should already have been bound to point to the incoming color data,
  191.  * prior to running the pipeline.
  192.  * This function copies the vertex's color to the material attributes
  193.  * which are tracking glColor.
  194.  * It's called per-vertex in the lighting loop.
  195.  */
  196. static void
  197. update_materials(struct gl_context *ctx, struct light_stage_data *store)
  198. {
  199.    GLuint i;
  200.  
  201.    for (i = 0 ; i < store->mat_count ; i++) {
  202.       /* update the material */
  203.       COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr);
  204.       /* increment src vertex color pointer */
  205.       STRIDE_F(store->mat[i].ptr, store->mat[i].stride);
  206.    }
  207.      
  208.    /* recompute derived light/material values */
  209.    _mesa_update_material( ctx, store->mat_bitmask );
  210.    /* XXX we should only call this if we're tracking/changing the specular
  211.     * exponent.
  212.     */
  213.    _tnl_validate_shine_tables( ctx );
  214. }
  215.  
  216.  
  217. /**
  218.  * Prepare things prior to running the lighting stage.
  219.  * Return number of material attributes which will track vertex color.
  220.  */
  221. static GLuint
  222. prepare_materials(struct gl_context *ctx,
  223.                   struct vertex_buffer *VB, struct light_stage_data *store)
  224. {
  225.    GLuint i;
  226.    
  227.    store->mat_count = 0;
  228.    store->mat_bitmask = 0;
  229.  
  230.    /* Examine the _ColorMaterialBitmask to determine which materials
  231.     * track vertex color.  Override the material attribute's pointer
  232.     * with the color pointer for each one.
  233.     */
  234.    if (ctx->Light.ColorMaterialEnabled) {
  235.       const GLuint bitmask = ctx->Light._ColorMaterialBitmask;
  236.       for (i = 0 ; i < MAT_ATTRIB_MAX ; i++)
  237.          if (bitmask & (1<<i))
  238.             VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] = VB->AttribPtr[_TNL_ATTRIB_COLOR0];
  239.    }
  240.  
  241.    /* Now, for each material attribute that's tracking vertex color, save
  242.     * some values (ptr, stride, size, current) that we'll need in
  243.     * update_materials(), above, that'll actually copy the vertex color to
  244.     * the material attribute(s).
  245.     */
  246.    for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) {
  247.       if (VB->AttribPtr[i]->stride) {
  248.          const GLuint j = store->mat_count++;
  249.          const GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
  250.          store->mat[j].ptr    = VB->AttribPtr[i]->start;
  251.          store->mat[j].stride = VB->AttribPtr[i]->stride;
  252.          store->mat[j].size   = VB->AttribPtr[i]->size;
  253.          store->mat[j].current = ctx->Light.Material.Attrib[attr];
  254.          store->mat_bitmask |= (1<<attr);
  255.       }
  256.    }
  257.  
  258.    /* FIXME: Is this already done?
  259.     */
  260.    _mesa_update_material( ctx, ~0 );
  261.  
  262.    _tnl_validate_shine_tables( ctx );
  263.  
  264.    return store->mat_count;
  265. }
  266.  
  267. /*
  268.  * Compute dp ^ SpecularExponent.
  269.  * Lerp between adjacent values in the f(x) lookup table, giving a
  270.  * continuous function, with adequate overall accuracy.  (Though still
  271.  * pretty good compared to a straight lookup).
  272.  */
  273. static inline GLfloat
  274. lookup_shininess(const struct gl_context *ctx, GLuint face, GLfloat dp)
  275. {
  276.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  277.    const struct tnl_shine_tab *tab = tnl->_ShineTable[face];
  278.    float f = dp * (SHINE_TABLE_SIZE - 1);
  279.    int k = (int) f;
  280.    if (k < 0 /* gcc may cast an overflow float value to negative int value */
  281.         || k > SHINE_TABLE_SIZE - 2)
  282.       return powf(dp, tab->shininess);
  283.    else
  284.       return tab->tab[k] + (f - k) * (tab->tab[k+1] - tab->tab[k]);
  285. }
  286.  
  287. /* Tables for all the shading functions.
  288.  */
  289. static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
  290. static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
  291. static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
  292. static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
  293.  
  294. #define TAG(x)           x
  295. #define IDX              (0)
  296. #include "t_vb_lighttmp.h"
  297.  
  298. #define TAG(x)           x##_twoside
  299. #define IDX              (LIGHT_TWOSIDE)
  300. #include "t_vb_lighttmp.h"
  301.  
  302. #define TAG(x)           x##_material
  303. #define IDX              (LIGHT_MATERIAL)
  304. #include "t_vb_lighttmp.h"
  305.  
  306. #define TAG(x)           x##_twoside_material
  307. #define IDX              (LIGHT_TWOSIDE|LIGHT_MATERIAL)
  308. #include "t_vb_lighttmp.h"
  309.  
  310.  
  311. static void init_lighting_tables( void )
  312. {
  313.    static int done;
  314.  
  315.    if (!done) {
  316.       init_light_tab();
  317.       init_light_tab_twoside();
  318.       init_light_tab_material();
  319.       init_light_tab_twoside_material();
  320.       done = 1;
  321.    }
  322. }
  323.  
  324.  
  325. static GLboolean run_lighting( struct gl_context *ctx,
  326.                                struct tnl_pipeline_stage *stage )
  327. {
  328.    struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
  329.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  330.    struct vertex_buffer *VB = &tnl->vb;
  331.    GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->AttribPtr[_TNL_ATTRIB_POS];
  332.    GLuint idx;
  333.  
  334.    if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
  335.       return GL_TRUE;
  336.  
  337.    /* Make sure we can talk about position x,y and z:
  338.     */
  339.    if (input->size <= 2 && input == VB->AttribPtr[_TNL_ATTRIB_POS]) {
  340.  
  341.       _math_trans_4f( store->Input.data,
  342.                       VB->AttribPtr[_TNL_ATTRIB_POS]->data,
  343.                       VB->AttribPtr[_TNL_ATTRIB_POS]->stride,
  344.                       GL_FLOAT,
  345.                       VB->AttribPtr[_TNL_ATTRIB_POS]->size,
  346.                       0,
  347.                       VB->Count );
  348.  
  349.       if (input->size <= 2) {
  350.          /* Clean z.
  351.           */
  352.          _mesa_vector4f_clean_elem(&store->Input, VB->Count, 2);
  353.       }
  354.          
  355.       if (input->size <= 1) {
  356.          /* Clean y.
  357.           */
  358.          _mesa_vector4f_clean_elem(&store->Input, VB->Count, 1);
  359.       }
  360.  
  361.       input = &store->Input;
  362.    }
  363.    
  364.    idx = 0;
  365.  
  366.    if (prepare_materials( ctx, VB, store ))
  367.       idx |= LIGHT_MATERIAL;
  368.  
  369.    if (ctx->Light.Model.TwoSide)
  370.       idx |= LIGHT_TWOSIDE;
  371.  
  372.    /* The individual functions know about replaying side-effects
  373.     * vs. full re-execution.
  374.     */
  375.    store->light_func_tab[idx]( ctx, VB, stage, input );
  376.  
  377.    return GL_TRUE;
  378. }
  379.  
  380.  
  381. /* Called in place of do_lighting when the light table may have changed.
  382.  */
  383. static void validate_lighting( struct gl_context *ctx,
  384.                                         struct tnl_pipeline_stage *stage )
  385. {
  386.    light_func *tab;
  387.  
  388.    if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
  389.       return;
  390.  
  391.    if (ctx->Light._NeedVertices) {
  392.       if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
  393.          tab = _tnl_light_spec_tab;
  394.       else
  395.          tab = _tnl_light_tab;
  396.    }
  397.    else {
  398.       if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
  399.          tab = _tnl_light_fast_single_tab;
  400.       else
  401.          tab = _tnl_light_fast_tab;
  402.    }
  403.  
  404.  
  405.    LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
  406.  
  407.    /* This and the above should only be done on _NEW_LIGHT:
  408.     */
  409.    TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
  410. }
  411.  
  412.  
  413.  
  414. /* Called the first time stage->run is called.  In effect, don't
  415.  * allocate data until the first time the stage is run.
  416.  */
  417. static GLboolean init_lighting( struct gl_context *ctx,
  418.                                 struct tnl_pipeline_stage *stage )
  419. {
  420.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  421.    struct light_stage_data *store;
  422.    GLuint size = tnl->vb.Size;
  423.  
  424.    stage->privatePtr = malloc(sizeof(*store));
  425.    store = LIGHT_STAGE_DATA(stage);
  426.    if (!store)
  427.       return GL_FALSE;
  428.  
  429.    /* Do onetime init.
  430.     */
  431.    init_lighting_tables();
  432.  
  433.    _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
  434.    _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
  435.    _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
  436.    _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
  437.    _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
  438.  
  439.    store->LitColor[0].size = 4;
  440.    store->LitColor[1].size = 4;
  441.    store->LitSecondary[0].size = 3;
  442.    store->LitSecondary[1].size = 3;
  443.  
  444.    return GL_TRUE;
  445. }
  446.  
  447.  
  448.  
  449.  
  450. static void dtr( struct tnl_pipeline_stage *stage )
  451. {
  452.    struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
  453.  
  454.    if (store) {
  455.       _mesa_vector4f_free( &store->Input );
  456.       _mesa_vector4f_free( &store->LitColor[0] );
  457.       _mesa_vector4f_free( &store->LitColor[1] );
  458.       _mesa_vector4f_free( &store->LitSecondary[0] );
  459.       _mesa_vector4f_free( &store->LitSecondary[1] );
  460.       free( store );
  461.       stage->privatePtr = NULL;
  462.    }
  463. }
  464.  
  465. const struct tnl_pipeline_stage _tnl_lighting_stage =
  466. {
  467.    "lighting",                  /* name */
  468.    NULL,                        /* private_data */
  469.    init_lighting,
  470.    dtr,                         /* destroy */
  471.    validate_lighting,
  472.    run_lighting
  473. };
  474.