Subversion Repositories Kolibri OS

Rev

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