mesa: add support for ATI_envmap_bumpmap
authorRoland Scheidegger <sroland@vmware.com>
Thu, 12 Mar 2009 14:01:16 +0000 (15:01 +0100)
committerRoland Scheidegger <sroland@vmware.com>
Thu, 12 Mar 2009 14:01:16 +0000 (15:01 +0100)
add new entrypoints, new texture format, etc
translate in texenvprogram.c for drivers using the mesa-generated tex env
fragment program
also handled in swrast, but not tested (cannot work due to negative texel
results not handled correctly)

24 files changed:
src/mesa/glapi/gl_API.xml
src/mesa/main/api_exec.c
src/mesa/main/config.h
src/mesa/main/context.c
src/mesa/main/dlist.c
src/mesa/main/extensions.c
src/mesa/main/image.c
src/mesa/main/image.h
src/mesa/main/macros.h
src/mesa/main/mipmap.c
src/mesa/main/mtypes.h
src/mesa/main/texenv.c
src/mesa/main/texenv.h
src/mesa/main/texenvprogram.c
src/mesa/main/texformat.c
src/mesa/main/texformat.h
src/mesa/main/texformat_tmp.h
src/mesa/main/teximage.c
src/mesa/main/texstate.c
src/mesa/main/texstore.c
src/mesa/main/texstore.h
src/mesa/shader/prog_statevars.c
src/mesa/shader/prog_statevars.h
src/mesa/swrast/s_texcombine.c

index 8212fc24770d52e969cf72aeec43a20daa996060..cc3e3ae6bffbcffe9397007f8e1c5faf38bf7c3a 100644 (file)
     <enum name="DEPTH_STENCIL_TO_BGRA_NV"                 value="0x886F"/>
 </category>
 
+<category name="GL_ATI_envmap_bumpmap" number="244">
+    <enum name="BUMP_ROT_MATRIX_ATI"          count="4"   value="0x8775">
+        <size name="TexBumpParameterfv"/>
+        <size name="TexBumpParameteriv"/>
+        <size name="GetTexBumpParameterfv" mode="get"/>
+        <size name="GetTexBumpParameteriv" mode="get"/>
+    </enum>
+    <enum name="BUMP_ROT_MATRIX_SIZE_ATI"     count="1"   value="0x8776">
+        <size name="GetTexBumpParameterfv" mode="get"/>
+        <size name="GetTexBumpParameteriv" mode="get"/>
+    </enum>
+    <enum name="BUMP_NUM_TEX_UNITS_ATI"       count="1"   value="0x8777">
+        <size name="GetTexBumpParameterfv" mode="get"/>
+        <size name="GetTexBumpParameteriv" mode="get"/>
+    </enum>
+    <enum name="BUMP_TEX_UNITS_ATI"           count="-1"  value="0x8778">
+        <size name="GetTexBumpParameterfv" mode="get"/>
+        <size name="GetTexBumpParameteriv" mode="get"/>
+    </enum>
+    <enum name="DUDV_ATI"                                 value="0x8779"/>
+    <enum name="DU8DV8_ATI"                               value="0x877A"/>
+    <enum name="BUMP_ENVMAP_ATI"                          value="0x877B"/>
+    <enum name="BUMP_TARGET_ATI"              count="1"   value="0x877C">
+        <size name="TexEnviv"/>
+        <size name="TexEnvfv"/>
+        <size name="GetTexEnviv" mode="get"/>
+        <size name="GetTexEnvfv" mode="get"/>
+    </enum>
+    <function name="TexBumpParameterfvATI" offset="assign">
+      <param name="pname" type="GLenum"/>
+      <param name="param" type="const GLfloat *" variable_param="pname"/>
+      <glx ignore="true"/>
+    </function>
+    <function name="TexBumpParameterivATI" offset="assign">
+      <param name="pname" type="GLenum"/>
+      <param name="param" type="const GLint *" variable_param="pname"/>
+      <glx ignore="true"/>
+    </function>
+    <function name="GetTexBumpParameterfvATI" offset="assign">
+      <param name="pname" type="GLenum"/>
+      <param name="param" type="GLfloat *" variable_param="pname"/>
+      <glx ignore="true"/>
+    </function>
+    <function name="GetTexBumpParameterivATI" offset="assign">
+      <param name="pname" type="GLenum"/>
+      <param name="param" type="GLint *" variable_param="pname"/>
+      <glx ignore="true"/>
+    </function>
+</category>
+
 <category name="GL_ATI_fragment_shader" number="245">
     <function name="GenFragmentShadersATI" offset="assign">
       <return type="GLuint"/>
index e0715817adda192baf240653218353b8923376de..6f66ff47a0822c627b27022ff533b510fa2f88fa 100644 (file)
@@ -839,6 +839,12 @@ _mesa_init_exec_table(struct _glapi_table *exec)
    SET_SetFragmentShaderConstantATI(exec, _mesa_SetFragmentShaderConstantATI);
 #endif
 
+  /* GL_ATI_envmap_bumpmap */
+   SET_GetTexBumpParameterivATI(exec, _mesa_GetTexBumpParameterivATI);
+   SET_GetTexBumpParameterfvATI(exec, _mesa_GetTexBumpParameterfvATI);
+   SET_TexBumpParameterivATI(exec, _mesa_TexBumpParameterivATI);
+   SET_TexBumpParameterfvATI(exec, _mesa_TexBumpParameterfvATI);
+
 #if FEATURE_EXT_framebuffer_object
    SET_IsRenderbufferEXT(exec, _mesa_IsRenderbufferEXT);
    SET_BindRenderbufferEXT(exec, _mesa_BindRenderbufferEXT);
index 282ad9514c233dac5780750278cc283b31552206..fc31155b35bd88204adfdbae4201c98a7e5995ae 100644 (file)
 #define MAX_COLOR_ATTACHMENTS 8
 /*@}*/
 
-
+/** For GL_ATI_envmap_bump - support bump mapping on first 8 units */
+#define SUPPORTED_ATI_BUMP_UNITS 0xff
 
 /**
  * \name Mesa-specific parameters
index 9fd9e769d29d24945c0151debaa9e8a25b0251e4..84bf0205a8ea980bbc23c20327ccf1966ef32e34 100644 (file)
@@ -589,6 +589,9 @@ _mesa_init_constants(GLcontext *ctx)
    /* GL_ARB_framebuffer_object */
    ctx->Const.MaxSamples = 0;
 
+   /* GL_ATI_envmap_bumpmap */
+   ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
+
    /* sanity checks */
    ASSERT(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
                                              ctx->Const.MaxTextureCoordUnits));
index d4bd56be83a03b19c9d5db9ed9153d3f250c807b..ebcef0268a41bfa4d548104ce89f844b0fbb11fb 100644 (file)
@@ -320,6 +320,8 @@ typedef enum
    /* GL_ARB_draw_buffers */
    OPCODE_DRAW_BUFFERS_ARB,
    /* GL_ATI_fragment_shader */
+   OPCODE_TEX_BUMP_PARAMETER_ATI,
+   /* GL_ATI_fragment_shader */
    OPCODE_BIND_FRAGMENT_SHADER_ATI,
    OPCODE_SET_FRAGMENT_SHADER_CONSTANTS_ATI,
    /* OpenGL 2.0 */
@@ -4803,6 +4805,36 @@ save_DrawBuffersARB(GLsizei count, const GLenum * buffers)
    }
 }
 
+static void GLAPIENTRY
+save_TexBumpParameterfvATI(GLenum pname, const GLfloat *param)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   Node *n;
+
+   n = ALLOC_INSTRUCTION(ctx, OPCODE_TEX_BUMP_PARAMETER_ATI, 5);
+   if (n) {
+      n[1].ui = pname;
+      n[2].f = param[0];
+      n[3].f = param[1];
+      n[4].f = param[2];
+      n[5].f = param[3];
+   }
+   if (ctx->ExecuteFlag) {
+      CALL_TexBumpParameterfvATI(ctx->Exec, (pname, param));
+   }
+}
+
+static void GLAPIENTRY
+save_TexBumpParameterivATI(GLenum pname, const GLint *param)
+{
+   GLfloat p[4];
+   p[0] = INT_TO_FLOAT(param[0]);
+   p[1] = INT_TO_FLOAT(param[1]);
+   p[2] = INT_TO_FLOAT(param[2]);
+   p[3] = INT_TO_FLOAT(param[3]);
+   save_TexBumpParameterfvATI(pname, p);
+}
+
 #if FEATURE_ATI_fragment_shader
 static void GLAPIENTRY
 save_BindFragmentShaderATI(GLuint id)
@@ -6505,6 +6537,16 @@ execute_list(GLcontext *ctx, GLuint list)
                                                 n[9].i, n[10].e));
            break;
 #endif
+         case OPCODE_TEX_BUMP_PARAMETER_ATI:
+            {
+               GLfloat values[4];
+               GLuint i, pname = n[1].ui;
+
+               for (i = 0; i < 4; i++)
+                  values[i] = n[1 + i].f;
+               CALL_TexBumpParameterfvATI(ctx->Exec, (pname, values));
+            }
+            break;
 #if FEATURE_ATI_fragment_shader
          case OPCODE_BIND_FRAGMENT_SHADER_ATI:
             CALL_BindFragmentShaderATI(ctx->Exec, (n[1].i));
@@ -8043,6 +8085,10 @@ _mesa_init_dlist_table(struct _glapi_table *table)
    SET_VertexAttribPointerNV(table, _mesa_VertexAttribPointerNV);
 #endif
 
+   /* 244. GL_ATI_envmap_bumpmap */
+   SET_TexBumpParameterivATI(table, save_TexBumpParameterivATI);
+   SET_TexBumpParameterfvATI(table, save_TexBumpParameterfvATI);
+
    /* 245. GL_ATI_fragment_shader */
 #if FEATURE_ATI_fragment_shader
    SET_BindFragmentShaderATI(table, save_BindFragmentShaderATI);
index fbca924ad3db28d3fbdec8a5c681347ebba990d4..2d2bf517843152cdeeb34de3c0d85a6f929363a5 100644 (file)
@@ -137,6 +137,7 @@ static const struct {
    { ON,  "GL_APPLE_packed_pixels",            F(APPLE_packed_pixels) },
    { OFF, "GL_APPLE_vertex_array_object",      F(APPLE_vertex_array_object) },
    { OFF, "GL_ATI_blend_equation_separate",    F(EXT_blend_equation_separate) },
+   { OFF, "GL_ATI_envmap_bumpmap",             F(ATI_envmap_bumpmap) },
    { OFF, "GL_ATI_texture_env_combine3",       F(ATI_texture_env_combine3)},
    { OFF, "GL_ATI_texture_mirror_once",        F(ATI_texture_mirror_once)},
    { OFF, "GL_ATI_fragment_shader",            F(ATI_fragment_shader)},
@@ -229,6 +230,7 @@ _mesa_enable_sw_extensions(GLcontext *ctx)
    /*ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;*/
 #endif
    ctx->Extensions.APPLE_vertex_array_object = GL_TRUE;
+   ctx->Extensions.ATI_envmap_bumpmap = GL_TRUE;
 #if FEATURE_ATI_fragment_shader
    ctx->Extensions.ATI_fragment_shader = GL_TRUE;
 #endif
index 4d86c5477753960575998845fbcbdab0199bf997..ed0811660d2508029b147ff57db3c34b02b05df7 100644 (file)
@@ -293,6 +293,8 @@ _mesa_components_in_format( GLenum format )
          return 2;
       case GL_DEPTH_STENCIL_EXT:
          return 2;
+      case GL_DUDV_ATI:
+         return 2;
       default:
          return -1;
    }
@@ -503,6 +505,20 @@ _mesa_is_legal_format_and_type( GLcontext *ctx, GLenum format, GLenum type )
             return GL_TRUE;
          else
             return GL_FALSE;
+      case GL_DUDV_ATI:
+      case GL_DU8DV8_ATI:
+         switch (type) {
+            case GL_BYTE:
+            case GL_UNSIGNED_BYTE:
+            case GL_SHORT:
+            case GL_UNSIGNED_SHORT:
+            case GL_INT:
+            case GL_UNSIGNED_INT:
+            case GL_FLOAT:
+               return GL_TRUE;
+            default:
+               return GL_FALSE;
+         }
       default:
          ; /* fall-through */
    }
@@ -1674,8 +1690,19 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
    GLfloat luminance[MAX_WIDTH];
    const GLint comps = _mesa_components_in_format(dstFormat);
    GLuint i;
-
-   if (dstType != GL_FLOAT || ctx->Color.ClampReadColor == GL_TRUE) {
+   /* clamping only applies to colors, not the dudv values, but still need
+      it if converting to unsigned values (which doesn't make much sense) */
+   if (dstFormat == GL_DUDV_ATI || dstFormat == GL_DU8DV8_ATI) {
+      switch (dstType) {
+         case GL_UNSIGNED_BYTE:
+         case GL_UNSIGNED_SHORT:
+         case GL_UNSIGNED_INT:
+            transferOps |= IMAGE_CLAMP_BIT;
+            break;
+            /* actually might want clamp to [-1,1] otherwise but shouldn't matter? */
+      }
+   }
+   else if (dstType != GL_FLOAT || ctx->Color.ClampReadColor == GL_TRUE) {
       /* need to clamp to [0, 1] */
       transferOps |= IMAGE_CLAMP_BIT;
    }
@@ -1774,6 +1801,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = FLOAT_TO_UBYTE(rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = FLOAT_TO_UBYTE(rgba[i][RCOMP]);
+                     dst[i*2+1] = FLOAT_TO_UBYTE(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -1847,6 +1881,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = FLOAT_TO_BYTE(rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = FLOAT_TO_BYTE(rgba[i][RCOMP]);
+                     dst[i*2+1] = FLOAT_TO_BYTE(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -1920,6 +1961,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      CLAMPED_FLOAT_TO_USHORT(dst[i*4+3], rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = FLOAT_TO_USHORT(rgba[i][RCOMP]);
+                     dst[i*2+1] = FLOAT_TO_USHORT(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -1993,6 +2041,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = FLOAT_TO_SHORT(rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = FLOAT_TO_SHORT(rgba[i][RCOMP]);
+                     dst[i*2+1] = FLOAT_TO_SHORT(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -2066,6 +2121,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = FLOAT_TO_UINT(rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = FLOAT_TO_UINT(rgba[i][RCOMP]);
+                     dst[i*2+1] = FLOAT_TO_UINT(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -2139,6 +2201,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = FLOAT_TO_INT(rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = FLOAT_TO_INT(rgba[i][RCOMP]);
+                     dst[i*2+1] = FLOAT_TO_INT(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -2212,6 +2281,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = rgba[i][RCOMP];
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = rgba[i][RCOMP];
+                     dst[i*2+1] = rgba[i][GCOMP];
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -2285,6 +2361,13 @@ _mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                      dst[i*4+3] = _mesa_float_to_half(rgba[i][RCOMP]);
                   }
                   break;
+               case GL_DUDV_ATI:
+               case GL_DU8DV8_ATI:
+                  for (i=0;i<n;i++) {
+                     dst[i*2+0] = _mesa_float_to_half(rgba[i][RCOMP]);
+                     dst[i*2+1] = _mesa_float_to_half(rgba[i][GCOMP]);
+                  }
+                  break;
                default:
                   _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n");
             }
@@ -2834,7 +2917,8 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4],
           srcFormat == GL_BGR ||
           srcFormat == GL_RGBA ||
           srcFormat == GL_BGRA ||
-          srcFormat == GL_ABGR_EXT);
+          srcFormat == GL_ABGR_EXT ||
+          srcFormat == GL_DUDV_ATI);
 
    ASSERT(srcType == GL_UNSIGNED_BYTE ||
           srcType == GL_BYTE ||
@@ -2949,6 +3033,13 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4],
          aComp = 0;
          stride = 4;
          break;
+      case GL_DUDV_ATI:
+         redIndex = 0;
+         greenIndex = 1;
+         blueIndex = -1;
+         alphaIndex = -1;
+         stride = 2;
+         break;
       default:
          _mesa_problem(NULL, "bad srcFormat in extract float data");
          return;
@@ -3877,6 +3968,62 @@ _mesa_unpack_color_span_float( GLcontext *ctx,
    }
 }
 
+/**
+ * Similar to _mesa_unpack_color_span_float(), but for dudv data instead of rgba,
+ * directly return GLbyte data, no transfer ops apply.
+ */
+void
+_mesa_unpack_dudv_span_byte( GLcontext *ctx,
+                             GLuint n, GLenum dstFormat, GLbyte dest[],
+                             GLenum srcFormat, GLenum srcType,
+                             const GLvoid *source,
+                             const struct gl_pixelstore_attrib *srcPacking,
+                             GLbitfield transferOps )
+{
+   ASSERT(dstFormat == GL_DUDV_ATI);
+   ASSERT(srcFormat == GL_DUDV_ATI);
+
+   ASSERT(srcType == GL_UNSIGNED_BYTE ||
+          srcType == GL_BYTE ||
+          srcType == GL_UNSIGNED_SHORT ||
+          srcType == GL_SHORT ||
+          srcType == GL_UNSIGNED_INT ||
+          srcType == GL_INT ||
+          srcType == GL_HALF_FLOAT_ARB ||
+          srcType == GL_FLOAT);
+
+   /* general solution */
+   {
+      GLint dstComponents;
+      GLfloat rgba[MAX_WIDTH][4];
+
+      dstComponents = _mesa_components_in_format( dstFormat );
+      /* source & dest image formats should have been error checked by now */
+      assert(dstComponents > 0);
+
+      /*
+       * Extract image data and convert to RGBA floats
+       */
+      assert(n <= MAX_WIDTH);
+      extract_float_rgba(n, rgba, srcFormat, srcType, source,
+                         srcPacking->SwapBytes);
+
+
+      /* Now determine which color channels we need to produce.
+       * And determine the dest index (offset) within each color tuple.
+       */
+
+      /* Now pack results in the requested dstFormat */
+      GLbyte *dst = dest;
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         /* not sure - need clamp[-1,1] here? */
+         dst[0] = FLOAT_TO_BYTE(rgba[i][RCOMP]);
+         dst[1] = FLOAT_TO_BYTE(rgba[i][GCOMP]);
+         dst += dstComponents;
+      }
+   }
+}
 
 /*
  * Unpack a row of color index data from a client buffer according to
index 0e0bbd96d85db1f7ea924bb9eaf81b9d45527830..b26c27e5a8ac7976781a076440e00b8ba66267cb 100644 (file)
@@ -198,6 +198,13 @@ _mesa_unpack_color_span_float( GLcontext *ctx,
                                const struct gl_pixelstore_attrib *srcPacking,
                                GLbitfield transferOps );
 
+extern void
+_mesa_unpack_dudv_span_byte( GLcontext *ctx,
+                             GLuint n, GLenum dstFormat, GLbyte dest[],
+                             GLenum srcFormat, GLenum srcType,
+                             const GLvoid *source,
+                             const struct gl_pixelstore_attrib *srcPacking,
+                             GLbitfield transferOps );
 
 extern void
 _mesa_unpack_index_span( const GLcontext *ctx, GLuint n,
index 2630855a0eab022fe29bc9e1f7204249c4509b07..bfd740870ec7dd0263856dd3396c8469a6c576c5 100644 (file)
@@ -54,13 +54,16 @@ extern GLfloat _mesa_ubyte_to_float_color_tab[256];
 #define FLOAT_TO_BYTE(X)    ( (((GLint) (255.0F * (X))) - 1) / 2 )
 
 
-/** Convert GLushort in [0,65536] to GLfloat in [0.0,1.0] */
+/** Convert GLushort in [0,65535] to GLfloat in [0.0,1.0] */
 #define USHORT_TO_FLOAT(S)  ((GLfloat) (S) * (1.0F / 65535.0F))
 
+/** Convert GLfloat in [0.0,1.0] to GLushort in [0, 65535] */
+#define FLOAT_TO_USHORT(X)   ((GLuint) ((X) * 65535.0))
+
 /** Convert GLshort in [-32768,32767] to GLfloat in [-1.0,1.0] */
 #define SHORT_TO_FLOAT(S)   ((2.0F * (S) + 1.0F) * (1.0F/65535.0F))
 
-/** Convert GLfloat in [0.0,1.0] to GLshort in [-32768,32767] */
+/** Convert GLfloat in [-1.0,1.0] to GLshort in [-32768,32767] */
 #define FLOAT_TO_SHORT(X)   ( (((GLint) (65535.0F * (X))) - 1) / 2 )
 
 
index 3dd4b3391b9b191af23cdb166bb33fa17d17346c..af2bf8fe2282f4db02bd338c87d8c7b158ab552d 100644 (file)
@@ -85,7 +85,7 @@ bytes_per_pixel(GLenum datatype, GLuint comps)
                                 rowC[j][e], rowC[k][e], \
                                 rowD[j][e], rowD[k][e]); \
    } while(0)
-   
+
 #define FILTER_F_3D(e) \
    do { \
       dst[i][e] = (rowA[j][e] + rowA[k][e] \
@@ -226,7 +226,6 @@ do_row(GLenum datatype, GLuint comps, GLint srcWidth,
          dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
       }
    }
-
    else if (datatype == GL_FLOAT && comps == 4) {
       GLuint i, j, k;
       const GLfloat(*rowA)[4] = (const GLfloat(*)[4]) srcRowA;
@@ -471,6 +470,17 @@ do_row(GLenum datatype, GLuint comps, GLint srcWidth,
          dst[i] = (blue << 5) | (green << 2) | red;
       }
    }
+   else if (datatype == GL_BYTE && comps == 2) {
+      GLuint i, j, k;
+      const GLbyte(*rowA)[2] = (const GLbyte(*)[2]) srcRowA;
+      const GLbyte(*rowB)[2] = (const GLbyte(*)[2]) srcRowB;
+      GLbyte(*dst)[2] = (GLbyte(*)[2]) dstRow;
+      for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+           i++, j += colStride, k += colStride) {
+         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2;
+         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2;
+      }
+   }
    else {
       _mesa_problem(NULL, "bad format in do_row()");
    }
index 9080c83da4e85b2b2bd8d39ad84d9a0b5076f235..169f1af057d4c63ebdad9354c149de9a5aaefd1e 100644 (file)
@@ -1390,6 +1390,8 @@ struct gl_texture_unit
    GLbitfield _GenFlags;       /**< Bitwise-OR of Gen[STRQ]._ModeBit */
 
    GLfloat LodBias;            /**< for biasing mipmap levels */
+   GLenum BumpTarget;
+   GLfloat RotMatrix[4]; /* 2x2 matrix */
 
    /** 
     * \name GL_EXT_texture_env_combine 
@@ -2388,6 +2390,8 @@ struct gl_constants
    GLuint MaxSamples;            /**< GL_ARB_framebuffer_object */
 
    GLuint MaxVarying;  /**< Number of float[4] varying parameters */
+
+   GLbitfield SupportedBumpUnits; /**> units supporting GL_ATI_envmap_bumpmap as targets */
 };
 
 
@@ -2484,6 +2488,7 @@ struct gl_extensions
    GLboolean APPLE_client_storage;
    GLboolean APPLE_packed_pixels;
    GLboolean APPLE_vertex_array_object;
+   GLboolean ATI_envmap_bumpmap;
    GLboolean ATI_texture_mirror_once;
    GLboolean ATI_texture_env_combine3;
    GLboolean ATI_fragment_shader;
index 95547a500ee3b15e6d5aed22b99d8c9817444818..c2960fc8208ae6d21f24714154a13998621f9eff 100644 (file)
@@ -142,7 +142,11 @@ set_combiner_mode(GLcontext *ctx,
    case GL_MODULATE_ADD_ATI:
    case GL_MODULATE_SIGNED_ADD_ATI:
    case GL_MODULATE_SUBTRACT_ATI:
-      legal =ctx->Extensions.ATI_texture_env_combine3;
+      legal = ctx->Extensions.ATI_texture_env_combine3;
+      break;
+   case GL_BUMP_ENVMAP_ATI:
+      legal = (ctx->Extensions.ATI_envmap_bumpmap &&
+               pname == GL_COMBINE_RGB);
       break;
    default:
       legal = GL_FALSE;
@@ -500,6 +504,26 @@ _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
       case GL_ALPHA_SCALE:
          set_combiner_scale(ctx, texUnit, pname, param[0]);
         break;
+      case GL_BUMP_TARGET_ATI:
+         if (!ctx->Extensions.ATI_envmap_bumpmap) {
+           _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
+           return;
+        }
+        if (((GLenum) (GLint) param[0] < GL_TEXTURE0) ||
+        ((GLenum) (GLint) param[0] > GL_TEXTURE31)) {
+           /* spec doesn't say this but it seems logical */
+           _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(param=0x%x)", (GLenum) (GLint) param[0]);
+           return;
+        }
+        if (!((1 << ((GLenum) (GLint) param[0] - GL_TEXTURE0)) & ctx->Const.SupportedBumpUnits)) {
+           _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", (GLenum) (GLint) param[0]);
+           return;
+        }
+        else {
+           FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+           texUnit->BumpTarget = (GLenum) (GLint) param[0];
+        }
+        break;
       default:
         _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" );
         return;
@@ -735,6 +759,16 @@ get_texenvi(GLcontext *ctx, const struct gl_texture_unit *texUnit,
          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
       }
       break;
+   case GL_BUMP_TARGET_ATI:
+      /* spec doesn't say so, but I think this should be queryable */
+      if (ctx->Extensions.ATI_envmap_bumpmap) {
+         return texUnit->BumpTarget;
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+
    default:
       ;
    }
@@ -874,4 +908,142 @@ _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
    }
 }
 
+/* why does ATI_envmap_bumpmap require new entrypoints? Should just
+   reuse TexEnv ones... */
+void GLAPIENTRY
+_mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
+{
+   GLfloat p[4];
+   if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      /* hope that conversion is correct here */
+      p[0] = INT_TO_FLOAT( param[0] );
+      p[1] = INT_TO_FLOAT( param[1] );
+      p[2] = INT_TO_FLOAT( param[2] );
+      p[3] = INT_TO_FLOAT( param[3] );
+   }
+   else {
+      p[0] = (GLfloat) param[0];
+      p[1] = p[2] = p[3] = 0;  /* init to zero, just to be safe */
+   }
+   _mesa_TexBumpParameterfvATI( pname, p );
+}
+
+void GLAPIENTRY
+_mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
+{
+   struct gl_texture_unit *texUnit;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   /* should return error if extension not supported? */
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
+   if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      if (TEST_EQ_4V(param, texUnit->RotMatrix))
+         return;
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      COPY_4FV(texUnit->RotMatrix, param);
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
+      return;
+   }
+   /* Drivers might want to know about this, instead of dedicated function
+      just shove it into TexEnv where it really belongs anyway */
+   if (ctx->Driver.TexEnv) {
+      (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
+   }
+}
+
+void GLAPIENTRY
+_mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
+{
+   const struct gl_texture_unit *texUnit;
+   GLint i;
+   GLint temp = 0;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   /* should return error if extension not supported? */
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
+   if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
+      /* spec leaves open to support larger matrices.
+         Don't think anyone would ever want to use it
+         (and apps almost certainly would not understand it and
+         thus fail to submit matrices correctly) so hardcode this. */
+      *param = 4;
+   }
+   else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      /* hope that conversion is correct here */
+      param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
+      param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
+      param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
+      param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
+   }
+   else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            temp++;
+         }
+      }
+      *param = temp;
+   }
+   else if (pname == GL_BUMP_TEX_UNITS_ATI) {
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            *param++ = i + GL_TEXTURE0;
+         }
+      }
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
+      return;
+   }
+}
+
+void GLAPIENTRY
+_mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
+{
+   const struct gl_texture_unit *texUnit;
+   GLint i;
+   GLint temp = 0;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   /* should return error if extension not supported? */
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
+   if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
+      /* spec leaves open to support larger matrices.
+         Don't think anyone would ever want to use it
+         (and apps might not understand it) so hardcode this. */
+      *param = (GLfloat) 4;
+   }
+   else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      param[0] = texUnit->RotMatrix[0];
+      param[1] = texUnit->RotMatrix[1];
+      param[2] = texUnit->RotMatrix[2];
+      param[3] = texUnit->RotMatrix[3];
+   }
+   else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            temp++;
+         }
+      }
+      *param = (GLfloat) temp;
+   }
+   else if (pname == GL_BUMP_TEX_UNITS_ATI) {
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            *param++ = (GLfloat) (i + GL_TEXTURE0);
+         }
+      }
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
+      return;
+   }
+}
 
index bdff7fdb82bd761db8e07ef19053712f0d8ed0d5..1e9c5faed7971ac472f942bd34a84a92fea83415 100644 (file)
@@ -48,5 +48,16 @@ _mesa_TexEnvi( GLenum target, GLenum pname, GLint param );
 extern void GLAPIENTRY
 _mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param );
 
+extern void GLAPIENTRY
+_mesa_TexBumpParameterivATI( GLenum pname, const GLint *param );
+
+extern void GLAPIENTRY
+_mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param );
+
+extern void GLAPIENTRY
+_mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param );
+
+extern void GLAPIENTRY
+_mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param );
 
 #endif /* TEXENV_H */
index 51c13a563d6c6ee686ac6223c42d5e61c664ba07..3fbd119b34797e78a785709932c87525cbbd476f 100644 (file)
@@ -94,11 +94,11 @@ struct state_key {
       GLuint ScaleShiftA:2;
 
       GLuint NumArgsRGB:3;
-      GLuint ModeRGB:4;
+      GLuint ModeRGB:5;
       struct mode_opt OptRGB[MAX_TERMS];
 
       GLuint NumArgsA:3;
-      GLuint ModeA:4;
+      GLuint ModeA:5;
       struct mode_opt OptA[MAX_TERMS];
    } unit[8];
 };
@@ -194,7 +194,8 @@ static GLuint translate_source( GLenum src )
 #define MODE_MODULATE_SUBTRACT_ATI      12  /* r = a0 * a2 - a1 */
 #define MODE_ADD_PRODUCTS               13  /* r = a0 * a1 + a2 * a3 */
 #define MODE_ADD_PRODUCTS_SIGNED        14  /* r = a0 * a1 + a2 * a3 - 0.5 */
-#define MODE_UNKNOWN                    15
+#define MODE_BUMP_ENVMAP_ATI            15  /* special */
+#define MODE_UNKNOWN                    16
 
 /**
  * Translate GL combiner state into a MODE_x value
@@ -223,6 +224,7 @@ static GLuint translate_mode( GLenum envMode, GLenum mode )
    case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI;
    case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI;
    case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI;
+   case GL_BUMP_ENVMAP_ATI: return MODE_BUMP_ENVMAP_ATI;
    default:
       assert(0);
       return MODE_UNKNOWN;
@@ -383,7 +385,7 @@ static void make_state_key( GLcontext *ctx,  struct state_key *key )
         translate_mode(texUnit->EnvMode, texUnit->_CurrentCombine->ModeRGB);
       key->unit[i].ModeA =
         translate_mode(texUnit->EnvMode, texUnit->_CurrentCombine->ModeA);
-               
+
       key->unit[i].ScaleShiftRGB = texUnit->_CurrentCombine->ScaleShiftRGB;
       key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftA;
 
@@ -397,8 +399,18 @@ static void make_state_key( GLcontext *ctx,  struct state_key *key )
          key->unit[i].OptA[j].Source =
            translate_source(texUnit->_CurrentCombine->SourceA[j]);
       }
+
+      if (key->unit[i].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
+         /* requires some special translation */
+         key->unit[i].NumArgsRGB = 2;
+         key->unit[i].ScaleShiftRGB = 0;
+         key->unit[i].OptRGB[0].Operand = OPR_SRC_COLOR;
+         key->unit[i].OptRGB[0].Source = SRC_TEXTURE;
+         key->unit[i].OptRGB[1].Operand = OPR_SRC_COLOR;
+         key->unit[i].OptRGB[1].Source = texUnit->BumpTarget - GL_TEXTURE0 + SRC_TEXTURE0;
+       }
    }
-       
+
    if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
       key->separate_specular = 1;
       inputs_referenced |= FRAG_BIT_COL1;
@@ -464,6 +476,11 @@ struct texenv_fragment_program {
     * else undef.
     */
 
+   struct ureg texcoord_tex[MAX_TEXTURE_COORD_UNITS];
+   /* Reg containing texcoord for a texture unit,
+    * needed for bump mapping, else undef.
+    */
+
    struct ureg src_previous;   /**< Reg containing color from previous 
                                 * stage.  May need to be decl'd.
                                 */
@@ -756,6 +773,7 @@ static struct ureg emit_texld( struct texenv_fragment_program *p,
     */
    reserve_temp(p, dest);
 
+#if 0
    /* Is this a texture indirection?
     */
    if ((coord.file == PROGRAM_TEMPORARY &&
@@ -767,6 +785,7 @@ static struct ureg emit_texld( struct texenv_fragment_program *p,
       p->alu_temps = 0;
       assert(0);               /* KW: texture env crossbar */
    }
+#endif
 
    return dest;
 }
@@ -1052,6 +1071,10 @@ static struct ureg emit_combine( struct texenv_fragment_program *p,
          emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
       }
       return dest;
+   case MODE_BUMP_ENVMAP_ATI:
+      /* special - not handled here */
+      assert(0);
+      return src[0];
    default: 
       assert(0);
       return src[0];
@@ -1074,6 +1097,10 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
    if (!key->unit[unit].enabled) {
       return get_source(p, SRC_PREVIOUS, 0);
    }
+   if (key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
+      /* this isn't really a env stage delivering a color and handled elsewhere */
+      return get_source(p, SRC_PREVIOUS, 0);
+   }
    
    switch (key->unit[unit].ModeRGB) {
    case MODE_DOT3_RGB_EXT:
@@ -1163,9 +1190,17 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
 {
    if (is_undef(p->src_texture[unit])) {
       GLuint texTarget = p->state->unit[unit].source_index;
-      struct ureg texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit);
+      struct ureg texcoord;
       struct ureg tmp = get_tex_temp( p );
 
+      if (is_undef(p->texcoord_tex[unit])) {
+         texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit);
+      }
+      else {
+         /* might want to reuse this reg for tex output actually */
+         texcoord = p->texcoord_tex[unit];
+      }
+
       if (texTarget == TEXTURE_UNKNOWN_INDEX)
          program_error(p, "TexSrcBit");
                          
@@ -1233,7 +1268,7 @@ load_texunit_sources( struct texenv_fragment_program *p, int unit )
    GLuint i;
 
    for (i = 0; i < key->unit[unit].NumArgsRGB; i++) {
-      load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit);
+      load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit );
    }
 
    for (i = 0; i < key->unit[unit].NumArgsA; i++) {
@@ -1243,6 +1278,40 @@ load_texunit_sources( struct texenv_fragment_program *p, int unit )
    return GL_TRUE;
 }
 
+/**
+ * Generate instructions for loading bump map textures.
+ */
+static GLboolean
+load_texunit_bumpmap( struct texenv_fragment_program *p, int unit )
+{
+   struct state_key *key = p->state;
+   GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0;
+   struct ureg texcDst, bumpMapRes;
+   struct ureg constdudvcolor = register_const4f(p, 0.0, 0.0, 0.0, 1.0);
+   struct ureg texcSrc = register_input(p, FRAG_ATTRIB_TEX0 + bumpedUnitNr);
+   struct ureg rotMat0 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_0, unit );
+   struct ureg rotMat1 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_1, unit );
+
+   load_texenv_source( p, unit + SRC_TEXTURE0, unit );
+
+   bumpMapRes = get_source(p, key->unit[unit].OptRGB[0].Source, unit);
+   texcDst = get_tex_temp( p );
+   p->texcoord_tex[bumpedUnitNr] = texcDst;
+
+   /* apply rot matrix and add coords to be available in next phase */
+   /* dest = (Arg0.xxxx * rotMat0 + Arg1) + (Arg0.yyyy * rotMat1) */
+   /* note only 2 coords are affected the rest are left unchanged (mul by 0) */
+   emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0,
+               swizzle1(bumpMapRes, SWIZZLE_X), rotMat0, texcSrc );
+   emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0,
+               swizzle1(bumpMapRes, SWIZZLE_Y), rotMat1, texcDst );
+
+   /* move 0,0,0,1 into bumpmap src if someone (crossbar) is foolish
+      enough to access this later, should optimize away */
+   emit_arith( p, OPCODE_MOV, bumpMapRes, WRITEMASK_XYZW, 0, constdudvcolor, undef, undef );
+
+   return GL_TRUE;
+}
 
 /**
  * Generate a new fragment program which implements the context's
@@ -1267,7 +1336,7 @@ create_new_program(GLcontext *ctx, struct state_key *key,
     */
    p.program->Base.Instructions = instBuffer;
    p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB;
-   p.program->Base.NumTexIndirections = 1;     /* correct? */
+   p.program->Base.NumTexIndirections = 1;
    p.program->Base.NumTexInstructions = 0;
    p.program->Base.NumAluInstructions = 0;
    p.program->Base.String = NULL;
@@ -1280,8 +1349,10 @@ create_new_program(GLcontext *ctx, struct state_key *key,
    p.program->Base.InputsRead = 0;
    p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLOR;
 
-   for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
+   for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
       p.src_texture[unit] = undef;
+      p.texcoord_tex[unit] = undef;
+   }
 
    p.src_previous = undef;
    p.half = undef;
@@ -1292,6 +1363,16 @@ create_new_program(GLcontext *ctx, struct state_key *key,
    release_temps(ctx, &p);
 
    if (key->enabled_units) {
+       GLboolean needbumpstage = GL_FALSE;
+      /* Zeroth pass - bump map textures first */
+      for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++)
+        if (key->unit[unit].enabled && key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
+           needbumpstage = GL_TRUE;
+           load_texunit_bumpmap( &p, unit );
+        }
+      if (needbumpstage)
+        p.program->Base.NumTexIndirections++;
+
       /* First pass - to support texture_env_crossbar, first identify
        * all referenced texture sources and emit texld instructions
        * for each:
index 16d05cc7d0702e55697e15da1966ea5ce8d4b819..61a12493a6bc7fce4cfea0eab9142affb4be6503 100644 (file)
@@ -696,6 +696,33 @@ const struct gl_texture_format _mesa_texformat_intensity_float16 = {
    store_texel_intensity_f16           /* StoreTexel */
 };
 
+const struct gl_texture_format _mesa_texformat_dudv8 = {
+   MESA_FORMAT_DUDV8,                  /* MesaFormat */
+   GL_DUDV_ATI,                                /* BaseFormat */
+   /* FIXME: spec doesn't say since that parameter didn't exist then,
+      but this should be something like SIGNED_NORMALIZED */
+   GL_UNSIGNED_NORMALIZED_ARB,         /* DataType */
+   /* maybe should add dudvBits field, but spec seems to be
+      lacking the ability to query with GetTexLevelParameter anyway */
+   0,                                  /* RedBits */
+   0,                                  /* GreenBits */
+   0,                                  /* BlueBits */
+   0,                                  /* AlphaBits */
+   0,                                  /* LuminanceBits */
+   0,                                  /* IntensityBits */
+   0,                                  /* IndexBits */
+   0,                                  /* DepthBits */
+   0,                                  /* StencilBits */
+   2,                                  /* TexelBytes */
+   _mesa_texstore_dudv8,               /* StoreTexImageFunc */
+   NULL,                               /* FetchTexel1D */
+   NULL,               /* FetchTexel2D */
+   NULL,                               /* FetchTexel3D */
+   NULL,                               /* FetchTexel1Df */
+   fetch_texel_2d_dudv8,               /* FetchTexel2Df */
+   NULL,                               /* FetchTexel3Df */
+   NULL                                        /* StoreTexel */
+};
 
 /*@}*/
 
@@ -1634,6 +1661,16 @@ _mesa_choose_tex_format( GLcontext *ctx, GLint internalFormat,
       }
    }
 
+   if (ctx->Extensions.ATI_envmap_bumpmap) {
+      switch (internalFormat) {
+         case GL_DUDV_ATI:
+         case GL_DU8DV8_ATI:
+            return &_mesa_texformat_dudv8;
+         default:
+            ; /* fallthrough */
+      }
+   }
+
 #if FEATURE_EXT_texture_sRGB
    if (ctx->Extensions.EXT_texture_sRGB) {
       switch (internalFormat) {
@@ -1778,6 +1815,11 @@ _mesa_format_to_type_and_comps(const struct gl_texture_format *format,
       *comps = 1;
       return;
 
+   case MESA_FORMAT_DUDV8:
+      *datatype = GL_BYTE;
+      *comps = 2;
+      return;
+
 #if FEATURE_EXT_texture_sRGB
    case MESA_FORMAT_SRGB8:
       *datatype = GL_UNSIGNED_BYTE;
index 31364c36b1a902ba546545a01473108ffb1a68b5..7fa70ad4fee3f8680f03f8a2c225fd0d6e950634 100644 (file)
@@ -161,7 +161,14 @@ enum _format {
    MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32,
    MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16,
    MESA_FORMAT_INTENSITY_FLOAT32,
-   MESA_FORMAT_INTENSITY_FLOAT16
+   MESA_FORMAT_INTENSITY_FLOAT16,
+   /*@}*/
+
+   /**
+    * \name Signed fixed point texture formats.
+    */
+   /*@{*/
+   MESA_FORMAT_DUDV8
    /*@}*/
 };
 
@@ -209,6 +216,11 @@ extern const struct gl_texture_format _mesa_texformat_intensity_float32;
 extern const struct gl_texture_format _mesa_texformat_intensity_float16;
 /*@}*/
 
+/** Signed fixed point texture formats */
+/*@{*/
+extern const struct gl_texture_format _mesa_texformat_dudv8;
+/*@}*/
+
 /** \name Assorted hardware-friendly formats */
 /*@{*/
 extern const struct gl_texture_format _mesa_texformat_rgba8888;
index 275340cabd383383ea37892a7d696be0713eb0d9..f9f9d5b1f8efb384038ec20e61b14c1404520f75 100644 (file)
@@ -1269,7 +1269,7 @@ static void FETCH(sl8)(const struct gl_texture_image *texImage,
    texel[RCOMP] = 
    texel[GCOMP] = 
    texel[BCOMP] = nonlinear_to_linear(src[0]);
-   texel[ACOMP] = CHAN_MAX;
+   texel[ACOMP] = 1.0F;
 }
 
 #if DIM == 3
@@ -1308,7 +1308,22 @@ static void store_texel_sla8(struct gl_texture_image *texImage,
 
 #endif /* FEATURE_EXT_texture_sRGB */
 
+#if DIM == 2
+/* MESA_FORMAT_DUDV8 ********************************************************/
+
+/* this format by definition produces 0,0,0,1 as rgba values,
+   however we'll return the dudv values as rg and fix up elsewhere */
+static void FETCH(dudv8)(const struct gl_texture_image *texImage,
+                         GLint i, GLint j, GLint k, GLfloat *texel )
+{
+   const GLbyte *src = TEXEL_ADDR(GLbyte, texImage, i, j, k, 2);
+   texel[RCOMP] = BYTE_TO_FLOAT(src[0]);
+   texel[GCOMP] = BYTE_TO_FLOAT(src[1]);
+   texel[BCOMP] = 0;
+   texel[ACOMP] = 0;
 
+}
+#endif
 
 /* MESA_FORMAT_YCBCR *********************************************************/
 
index e3d440475981396369eb96c070b37a9a58961e90..2ed72280ec91e1fb6c74f77967eac7b4751dede2 100644 (file)
@@ -339,6 +339,17 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
       }
    }
 
+   if (ctx->Extensions.ATI_envmap_bumpmap) {
+      switch (internalFormat) {
+         case GL_DUDV_ATI:
+         case GL_DU8DV8_ATI:
+            return GL_DUDV_ATI;
+         default:
+            ; /* fallthrough */
+      }
+   }
+
+
    if (ctx->Extensions.EXT_packed_depth_stencil) {
       switch (internalFormat) {
          case GL_DEPTH_STENCIL_EXT:
@@ -568,6 +579,20 @@ is_depthstencil_format(GLenum format)
    }
 }
 
+/**
+ * Test if the given image format is a dudv format.
+ */
+static GLboolean
+is_dudv_format(GLenum format)
+{
+   switch (format) {
+      case GL_DUDV_ATI:
+      case GL_DU8DV8_ATI:
+         return GL_TRUE;
+      default:
+         return GL_FALSE;
+   }
+}
 
 
 /**
@@ -1539,7 +1564,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
        (is_index_format(internalFormat) && !indexFormat) ||
        (is_depth_format(internalFormat) != is_depth_format(format)) ||
        (is_ycbcr_format(internalFormat) != is_ycbcr_format(format)) ||
-       (is_depthstencil_format(internalFormat) != is_depthstencil_format(format))) {
+       (is_depthstencil_format(internalFormat) != is_depthstencil_format(format)) ||
+       (is_dudv_format(internalFormat) != is_dudv_format(format))) {
       if (!isProxy)
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexImage(internalFormat/format)");
@@ -2273,6 +2299,12 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
       return;
    }
 
+   if (!ctx->Extensions.ATI_envmap_bumpmap
+       && is_dudv_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return;
+   }
+
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
@@ -2313,6 +2345,11 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
         _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
         goto out;
       }
+      else if (is_dudv_format(format)
+              && !is_dudv_format(texImage->TexFormat->BaseFormat)) {
+        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+        goto out;
+      }
 
       if (ctx->Pack.BufferObj->Name) {
         /* packing texture image into a PBO */
index d71f9530cb334c184ee57168813254405720dc09..a5af6229104fa9f35eddd6a9b1043f862b8e285b 100644 (file)
@@ -95,6 +95,11 @@ _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst )
       /* GL_EXT_texture_env_combine */
       dst->Texture.Unit[u].Combine = src->Texture.Unit[u].Combine;
 
+      /* GL_ATI_envmap_bumpmap - need this? */
+      dst->Texture.Unit[u].BumpTarget = src->Texture.Unit[u].BumpTarget;
+      COPY_4V(dst->Texture.Unit[u].RotMatrix, src->Texture.Unit[u].RotMatrix);
+
+
       /* copy texture object bindings, not contents of texture objects */
       _mesa_lock_context_textures(dst);
 
@@ -411,6 +416,10 @@ update_tex_combine(GLcontext *ctx, struct gl_texture_unit *texUnit)
    case GL_MODULATE_SUBTRACT_ATI:
       combine->_NumArgsRGB = 3;
       break;
+   case GL_BUMP_ENVMAP_ATI:
+      /* no real arguments for this case */
+      combine->_NumArgsRGB = 0;
+      break;
    default:
       combine->_NumArgsRGB = 0;
       _mesa_problem(ctx, "invalid RGB combine mode in update_texture_state");
@@ -682,6 +691,7 @@ init_texture_unit( GLcontext *ctx, GLuint unit )
    texUnit->Combine = default_combine_state;
    texUnit->_EnvMode = default_combine_state;
    texUnit->_CurrentCombine = & texUnit->_EnvMode;
+   texUnit->BumpTarget = GL_TEXTURE0;
 
    texUnit->TexGenEnabled = 0x0;
    texUnit->GenS.Mode = GL_EYE_LINEAR;
@@ -702,6 +712,16 @@ init_texture_unit( GLcontext *ctx, GLuint unit )
    ASSIGN_4V( texUnit->GenT.EyePlane, 0.0, 1.0, 0.0, 0.0 );
    ASSIGN_4V( texUnit->GenR.EyePlane, 0.0, 0.0, 0.0, 0.0 );
    ASSIGN_4V( texUnit->GenQ.EyePlane, 0.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenS.ObjectPlane, 1.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenT.ObjectPlane, 0.0, 1.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenR.ObjectPlane, 0.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenQ.ObjectPlane, 0.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenS.EyePlane, 1.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenT.EyePlane, 0.0, 1.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenR.EyePlane, 0.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( texUnit->GenQ.EyePlane, 0.0, 0.0, 0.0, 0.0 );
+   /* no mention of this in spec, but maybe id matrix expected? */
+   ASSIGN_4V( texUnit->RotMatrix, 1.0, 0.0, 0.0, 1.0 );
 
    /* initialize current texture object ptrs to the shared default objects */
    for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
index 6360ca15f8137ed7f3e121f7a4043fb0a4916f01..cc3c6958c7df16da10e115406ebd58d6b0e8c324 100644 (file)
@@ -2471,6 +2471,95 @@ _mesa_texstore_ycbcr(TEXSTORE_PARAMS)
    return GL_TRUE;
 }
 
+GLboolean
+_mesa_texstore_dudv8(TEXSTORE_PARAMS)
+{
+   const GLboolean littleEndian = _mesa_little_endian();
+
+   ASSERT(dstFormat == &_mesa_texformat_dudv8);
+   ASSERT(dstFormat->TexelBytes == 2);
+   ASSERT(ctx->Extensions.ATI_envmap_bumpmap);
+   ASSERT((srcFormat == GL_DU8DV8_ATI) ||
+         (srcFormat == GL_DUDV_ATI));
+   ASSERT(baseInternalFormat == GL_DUDV_ATI);
+
+   if (!srcPacking->SwapBytes && srcType == GL_BYTE &&
+       littleEndian) {
+      /* simple memcpy path */
+      memcpy_texture(ctx, dims,
+                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
+                     dstRowStride,
+                     dstImageOffsets,
+                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
+                     srcAddr, srcPacking);
+   }
+   else if (srcType == GL_BYTE) {
+
+      GLubyte dstmap[4];
+
+      /* dstmap - how to swizzle from RGBA to dst format:
+       */
+      if (littleEndian) {
+        dstmap[0] = 0;
+        dstmap[1] = 3;
+      }
+      else {
+        dstmap[0] = 3;
+        dstmap[1] = 0;
+      }
+      dstmap[2] = ZERO;                /* ? */
+      dstmap[3] = ONE;         /* ? */
+      
+      _mesa_swizzle_ubyte_image(ctx, dims,
+                               GL_LUMINANCE_ALPHA, /* hack */
+                               GL_UNSIGNED_BYTE, /* hack */
+                               GL_LUMINANCE_ALPHA, /* hack */
+                               dstmap, 2,
+                               dstAddr, dstXoffset, dstYoffset, dstZoffset,
+                               dstRowStride, dstImageOffsets,
+                               srcWidth, srcHeight, srcDepth, srcAddr,
+                               srcPacking);      
+   }   
+   else {
+      /* general path - note this is defined for 2d textures only */
+      const GLint components = _mesa_components_in_format(baseInternalFormat);
+      const GLint srcStride = _mesa_image_row_stride(srcPacking,
+                                                 srcWidth, srcFormat, srcType);
+      GLbyte *tempImage, *dst, *src;
+      GLint row;
+
+      tempImage = (GLbyte *) _mesa_malloc(srcWidth * srcHeight * srcDepth
+                                          * components * sizeof(GLbyte));
+      if (!tempImage)
+         return GL_FALSE;
+
+      src = (GLbyte *) _mesa_image_address(dims, srcPacking, srcAddr,
+                                           srcWidth, srcHeight,
+                                           srcFormat, srcType,
+                                           0, 0, 0);
+
+      dst = tempImage;
+      for (row = 0; row < srcHeight; row++) {
+         _mesa_unpack_dudv_span_byte(ctx, srcWidth, baseInternalFormat,
+                                     dst, srcFormat, srcType, src,
+                                     srcPacking, 0);
+         dst += srcWidth * components;
+         src += srcStride;
+      }
+      src = tempImage;
+      dst = (GLbyte *) dstAddr
+            + dstYoffset * dstRowStride
+            + dstXoffset * dstFormat->TexelBytes;
+      for (row = 0; row < srcHeight; row++) {
+         memcpy(dst, src, srcWidth * dstFormat->TexelBytes);
+         dst += dstRowStride;
+         src += srcWidth * dstFormat->TexelBytes;
+      }
+      _mesa_free((void *) tempImage);
+   }
+   return GL_TRUE;
+}
 
 
 /**
@@ -3882,7 +3971,7 @@ _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
                GLint col;
                GLbitfield transferOps = 0x0;
 
-               if (type == GL_FLOAT && 
+               if (type == GL_FLOAT && texImage->TexFormat->BaseFormat != GL_DUDV_ATI &&
                    ((ctx->Color.ClampReadColor == GL_TRUE) ||
                     (ctx->Color.ClampReadColor == GL_FIXED_ONLY_ARB &&
                      texImage->TexFormat->DataType != GL_FLOAT)))
index b03386b2acc4c107849f3d694a2ca6f641a390cb..c9e639be4e066ae8c91b104f04c9a1c87474d258 100644 (file)
@@ -78,7 +78,7 @@ extern GLboolean _mesa_texstore_sargb8(TEXSTORE_PARAMS);
 extern GLboolean _mesa_texstore_sl8(TEXSTORE_PARAMS);
 extern GLboolean _mesa_texstore_sla8(TEXSTORE_PARAMS);
 #endif
-
+extern GLboolean _mesa_texstore_dudv8(TEXSTORE_PARAMS);
 
 extern GLchan *
 _mesa_make_temp_chan_image(GLcontext *ctx, GLuint dims,
index 1f7d87ccc94d679ce95b2299a2d1a9912de9f799..f51d9e265129b7b230100bd588896aa27e1e406d 100644 (file)
@@ -506,6 +506,26 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
             }
          }
          return;
+      case STATE_ROT_MATRIX_0:
+         {
+            const int unit = (int) state[2];
+            GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix;
+            value[0] = rotMat22[0]; 
+            value[1] = rotMat22[2];
+            value[2] = 0.0;
+            value[3] = 0.0;
+         }
+         break;
+      case STATE_ROT_MATRIX_1:
+         {
+            const int unit = (int) state[2];
+            GLfloat *rotMat22 = ctx->Texture.Unit[unit].RotMatrix;
+            value[0] = rotMat22[1];
+            value[1] = rotMat22[3];
+            value[2] = 0.0;
+            value[3] = 0.0;
+         }
+         break;
 
          /* XXX: make sure new tokens added here are also handled in the 
           * _mesa_program_state_flags() switch, below.
@@ -591,6 +611,8 @@ _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH])
 
       case STATE_TEXRECT_SCALE:
       case STATE_SHADOW_AMBIENT:
+      case STATE_ROT_MATRIX_0:
+      case STATE_ROT_MATRIX_1:
         return _NEW_TEXTURE;
       case STATE_FOG_PARAMS_OPTIMIZED:
         return _NEW_FOG;
@@ -806,6 +828,12 @@ append_token(char *dst, gl_state_index k)
    case STATE_SHADOW_AMBIENT:
       append(dst, "CompareFailValue");
       break;
+   case STATE_ROT_MATRIX_0:
+      append(dst, "rotMatrixRow0");
+      break;
+   case STATE_ROT_MATRIX_1:
+      append(dst, "rotMatrixRow1");
+      break;
    default:
       /* probably STATE_INTERNAL_DRIVER+i (driver private state) */
       append(dst, "driverState");
index d5358a1d042c1cc6643a75638ae3e23b8c89d696..d563080db1c69d8588cac8e39748fa871f9ffc70 100644 (file)
@@ -117,6 +117,8 @@ typedef enum gl_state_index_ {
    STATE_PCM_SCALE,             /**< Post color matrix RGBA scale */
    STATE_PCM_BIAS,              /**< Post color matrix RGBA bias */
    STATE_SHADOW_AMBIENT,        /**< ARB_shadow_ambient fail value; token[2] is texture unit index */
+   STATE_ROT_MATRIX_0,          /**< ATI_envmap_bumpmap, rot matrix row 0 */
+   STATE_ROT_MATRIX_1,          /**< ATI_envmap_bumpmap, rot matrix row 1 */
    STATE_INTERNAL_DRIVER       /* first available state index for drivers (must be last) */
 } gl_state_index;
 
index 38b5633887f4fde7d3f8e4f130d4852f7344692b..aa28311672d3d2f49822ce2367a1c45821e6c5af 100644 (file)
@@ -591,6 +591,25 @@ texture_combine( const GLcontext *ctx, GLuint unit, GLuint n,
             }
         }
          break;
+      case GL_BUMP_ENVMAP_ATI:
+         {
+            /* this produces a fixed rgba color, and the coord calc is done elsewhere */
+            for (i = 0; i < n; i++) {
+            /* rgba result is 0,0,0,1 */
+#if CHAN_TYPE == GL_FLOAT
+               rgba[i][RCOMP] = 0.0;
+               rgba[i][GCOMP] = 0.0;
+               rgba[i][BCOMP] = 0.0;
+               rgba[i][ACOMP] = 1.0;
+#else
+               rgba[i][RCOMP] = 0;
+               rgba[i][GCOMP] = 0;
+               rgba[i][BCOMP] = 0;
+               rgba[i][ACOMP] = CHAN_MAX;
+#endif
+            }
+        }
+         return; /* no alpha processing */
       default:
          _mesa_problem(ctx, "invalid combine mode");
    }
@@ -1218,12 +1237,86 @@ _swrast_texture_span( GLcontext *ctx, SWspan *span )
    if (swrast->_AnyTextureCombine)
       MEMCPY(primary_rgba, span->array->rgba, 4 * span->end * sizeof(GLchan));
 
+   /* First must sample all bump maps */
+   for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+      if (ctx->Texture.Unit[unit]._ReallyEnabled &&
+         ctx->Texture.Unit[unit]._CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) {
+         const GLfloat (*texcoords)[4]
+            = (const GLfloat (*)[4])
+            span->array->attribs[FRAG_ATTRIB_TEX0 + unit];
+         GLfloat (*targetcoords)[4]
+            = (GLfloat (*)[4])
+            span->array->attribs[FRAG_ATTRIB_TEX0 +
+               ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0];
+
+         const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+         const struct gl_texture_object *curObj = texUnit->_Current;
+         GLfloat *lambda = span->array->lambda[unit];
+         GLchan (*texels)[4] = (GLchan (*)[4])
+            (swrast->TexelBuffer + unit * (span->end * 4 * sizeof(GLchan)));
+         GLuint i;
+         GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0];
+         GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1];
+         GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2];
+         GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3];
+
+         /* adjust texture lod (lambda) */
+         if (span->arrayMask & SPAN_LAMBDA) {
+            if (texUnit->LodBias + curObj->LodBias != 0.0F) {
+               /* apply LOD bias, but don't clamp yet */
+               const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias,
+                                          -ctx->Const.MaxTextureLodBias,
+                                          ctx->Const.MaxTextureLodBias);
+               GLuint i;
+               for (i = 0; i < span->end; i++) {
+                  lambda[i] += bias;
+               }
+            }
+
+            if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) {
+               /* apply LOD clamping to lambda */
+               const GLfloat min = curObj->MinLod;
+               const GLfloat max = curObj->MaxLod;
+               GLuint i;
+               for (i = 0; i < span->end; i++) {
+                  GLfloat l = lambda[i];
+                  lambda[i] = CLAMP(l, min, max);
+               }
+            }
+         }
+
+         /* Sample the texture (span->end = number of fragments) */
+         swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end,
+                                      texcoords, lambda, texels );
+
+         /* manipulate the span values of the bump target
+            not sure this can work correctly even ignoring
+            the problem that channel is unsigned */
+         for (i = 0; i < span->end; i++) {
+#if CHAN_TYPE == GL_FLOAT
+            targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] *
+                                  rotMatrix01) / targetcoords[i][3];
+            targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] *
+                                  rotMatrix11) / targetcoords[i][3];
+#else
+            targetcoords[i][0] += (CHAN_TO_FLOAT(texels[i][1]) * rotMatrix00 +
+                                  CHAN_TO_FLOAT(texels[i][1]) * rotMatrix01) /
+                                  targetcoords[i][3];
+            targetcoords[i][1] += (CHAN_TO_FLOAT(texels[i][0]) * rotMatrix10 + 
+                                  CHAN_TO_FLOAT(texels[i][1]) * rotMatrix11) /
+                                  targetcoords[i][3];
+#endif
+         }
+      }
+   }
+
    /*
     * Must do all texture sampling before combining in order to
     * accomodate GL_ARB_texture_env_crossbar.
     */
    for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
-      if (ctx->Texture.Unit[unit]._ReallyEnabled) {
+      if (ctx->Texture.Unit[unit]._ReallyEnabled &&
+         ctx->Texture.Unit[unit]._CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) {
          const GLfloat (*texcoords)[4]
             = (const GLfloat (*)[4])
             span->array->attribs[FRAG_ATTRIB_TEX0 + unit];