2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Brian Paul Keith Whitwell <keithw@vmware.com>
29 * Regarding GL_NV_texgen_reflection:
31 * Portions of this software may use or implement intellectual
32 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
33 * any and all warranties with respect to such intellectual property,
34 * including any use thereof or modifications thereto.
37 #include "main/errors.h"
38 #include "main/glheader.h"
39 #include "main/macros.h"
40 #include "util/imports.h"
41 #include "main/mtypes.h"
43 #include "math/m_xform.h"
45 #include "t_context.h"
46 #include "t_pipeline.h"
49 /***********************************************************************
50 * Automatic texture coordinate generation (texgen) code.
54 struct texgen_stage_data
;
56 typedef void (*texgen_func
)( struct gl_context
*ctx
,
57 struct texgen_stage_data
*store
,
61 struct texgen_stage_data
{
63 /* Per-texunit derived state.
65 GLuint TexgenSize
[MAX_TEXTURE_COORD_UNITS
];
66 texgen_func TexgenFunc
[MAX_TEXTURE_COORD_UNITS
];
68 /* Temporary values used in texgen.
73 /* Buffered outputs of the stage.
75 GLvector4f texcoord
[MAX_TEXTURE_COORD_UNITS
];
79 #define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
83 static GLuint all_bits
[5] = {
91 #define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
93 #define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP)
94 #define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \
95 TEXGEN_REFLECTION_MAP_NV)
99 static void build_m3( GLfloat f
[][3], GLfloat m
[],
100 const GLvector4f
*normal
,
101 const GLvector4f
*eye
)
103 GLuint stride
= eye
->stride
;
104 GLfloat
*coord
= (GLfloat
*)eye
->start
;
105 GLuint count
= eye
->count
;
106 const GLfloat
*norm
= normal
->start
;
109 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
110 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
113 two_nu
= 2.0F
* DOT3(norm
,u
);
114 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
115 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
116 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
117 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
119 m
[i
] = 0.5F
* (1.0f
/ sqrtf(m
[i
]));
126 static void build_m2( GLfloat f
[][3], GLfloat m
[],
127 const GLvector4f
*normal
,
128 const GLvector4f
*eye
)
130 GLuint stride
= eye
->stride
;
131 GLfloat
*coord
= eye
->start
;
132 GLuint count
= eye
->count
;
134 GLfloat
*norm
= normal
->start
;
137 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
138 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
142 two_nu
= 2.0F
* DOT3(norm
,u
);
143 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
144 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
145 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
146 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
148 m
[i
] = 0.5F
* (1.0f
/ sqrtf(m
[i
]));
155 typedef void (*build_m_func
)( GLfloat f
[][3],
157 const GLvector4f
*normal
,
158 const GLvector4f
*eye
);
161 static build_m_func build_m_tab
[5] = {
170 /* This is unusual in that we respect the stride of the output vector
171 * (f). This allows us to pass in either a texcoord vector4f, or a
172 * temporary vector3f.
174 static void build_f3( GLfloat
*f
,
176 const GLvector4f
*normal
,
177 const GLvector4f
*eye
)
179 GLuint stride
= eye
->stride
;
180 GLfloat
*coord
= eye
->start
;
181 GLuint count
= eye
->count
;
183 GLfloat
*norm
= normal
->start
;
186 for (i
=0;i
<count
;i
++) {
187 GLfloat u
[3], two_nu
;
190 two_nu
= 2.0F
* DOT3(norm
,u
);
191 f
[0] = u
[0] - norm
[0] * two_nu
;
192 f
[1] = u
[1] - norm
[1] * two_nu
;
193 f
[2] = u
[2] - norm
[2] * two_nu
;
194 STRIDE_F(coord
,stride
);
196 STRIDE_F(norm
, normal
->stride
);
201 static void build_f2( GLfloat
*f
,
203 const GLvector4f
*normal
,
204 const GLvector4f
*eye
)
206 GLuint stride
= eye
->stride
;
207 GLfloat
*coord
= eye
->start
;
208 GLuint count
= eye
->count
;
209 GLfloat
*norm
= normal
->start
;
212 for (i
=0;i
<count
;i
++) {
214 GLfloat u
[3], two_nu
;
218 two_nu
= 2.0F
* DOT3(norm
,u
);
219 f
[0] = u
[0] - norm
[0] * two_nu
;
220 f
[1] = u
[1] - norm
[1] * two_nu
;
221 f
[2] = u
[2] - norm
[2] * two_nu
;
223 STRIDE_F(coord
,stride
);
225 STRIDE_F(norm
, normal
->stride
);
229 typedef void (*build_f_func
)( GLfloat
*f
,
231 const GLvector4f
*normal_vec
,
232 const GLvector4f
*eye
);
236 /* Just treat 4-vectors as 3-vectors.
238 static build_f_func build_f_tab
[5] = {
248 /* Special case texgen functions.
250 static void texgen_reflection_map_nv( struct gl_context
*ctx
,
251 struct texgen_stage_data
*store
,
254 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
255 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
256 GLvector4f
*out
= &store
->texcoord
[unit
];
258 build_f_tab
[VB
->EyePtr
->size
]( out
->start
,
260 VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
],
263 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
264 out
->count
= VB
->Count
;
265 out
->size
= MAX2(in
->size
, 3);
267 _mesa_copy_tab
[0x8]( out
, in
);
272 static void texgen_normal_map_nv( struct gl_context
*ctx
,
273 struct texgen_stage_data
*store
,
276 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
277 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
278 GLvector4f
*out
= &store
->texcoord
[unit
];
279 GLvector4f
*normal
= VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
];
280 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->start
;
281 GLuint count
= VB
->Count
;
283 const GLfloat
*norm
= normal
->start
;
285 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
286 texcoord
[i
][0] = norm
[0];
287 texcoord
[i
][1] = norm
[1];
288 texcoord
[i
][2] = norm
[2];
292 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
294 out
->size
= MAX2(in
->size
, 3);
296 _mesa_copy_tab
[0x8]( out
, in
);
300 static void texgen_sphere_map( struct gl_context
*ctx
,
301 struct texgen_stage_data
*store
,
304 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
305 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
306 GLvector4f
*out
= &store
->texcoord
[unit
];
307 GLfloat (*texcoord
)[4] = (GLfloat (*)[4]) out
->start
;
308 GLuint count
= VB
->Count
;
310 GLfloat (*f
)[3] = store
->tmp_f
;
311 GLfloat
*m
= store
->tmp_m
;
313 (build_m_tab
[VB
->EyePtr
->size
])( store
->tmp_f
,
315 VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
],
318 out
->size
= MAX2(in
->size
,2);
320 for (i
=0;i
<count
;i
++) {
321 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
322 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
326 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_2
;
328 _mesa_copy_tab
[all_bits
[in
->size
] & ~0x3]( out
, in
);
333 static void texgen( struct gl_context
*ctx
,
334 struct texgen_stage_data
*store
,
337 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
338 struct vertex_buffer
*VB
= &tnl
->vb
;
339 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
340 GLvector4f
*out
= &store
->texcoord
[unit
];
341 const struct gl_fixedfunc_texture_unit
*texUnit
=
342 &ctx
->Texture
.FixedFuncUnit
[unit
];
343 const GLvector4f
*obj
= VB
->AttribPtr
[_TNL_ATTRIB_POS
];
344 const GLvector4f
*eye
= VB
->EyePtr
;
345 const GLvector4f
*normal
= VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
];
346 const GLfloat
*m
= store
->tmp_m
;
347 const GLuint count
= VB
->Count
;
348 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->data
;
349 GLfloat (*f
)[3] = store
->tmp_f
;
352 if (texUnit
->_GenFlags
& TEXGEN_NEED_M
) {
353 build_m_tab
[eye
->size
]( store
->tmp_f
, store
->tmp_m
, normal
, eye
);
354 } else if (texUnit
->_GenFlags
& TEXGEN_NEED_F
) {
355 build_f_tab
[eye
->size
]( (GLfloat
*)store
->tmp_f
, 3, normal
, eye
);
359 out
->size
= MAX2(in
->size
, store
->TexgenSize
[unit
]);
360 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | texUnit
->TexGenEnabled
;
363 copy
= (all_bits
[in
->size
] & ~texUnit
->TexGenEnabled
);
365 _mesa_copy_tab
[copy
]( out
, in
);
367 if (texUnit
->TexGenEnabled
& S_BIT
) {
369 switch (texUnit
->GenS
.Mode
) {
370 case GL_OBJECT_LINEAR
:
371 _mesa_dotprod_tab
[obj
->size
]( (GLfloat
*)out
->data
,
372 sizeof(out
->data
[0]), obj
,
373 texUnit
->GenS
.ObjectPlane
);
376 _mesa_dotprod_tab
[eye
->size
]( (GLfloat
*)out
->data
,
377 sizeof(out
->data
[0]), eye
,
378 texUnit
->GenS
.EyePlane
);
381 for (i
= 0; i
< count
; i
++)
382 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
384 case GL_REFLECTION_MAP_NV
:
385 for (i
=0;i
<count
;i
++)
386 texcoord
[i
][0] = f
[i
][0];
388 case GL_NORMAL_MAP_NV
: {
389 const GLfloat
*norm
= normal
->start
;
390 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
391 texcoord
[i
][0] = norm
[0];
396 _mesa_problem(ctx
, "Bad S texgen");
400 if (texUnit
->TexGenEnabled
& T_BIT
) {
402 switch (texUnit
->GenT
.Mode
) {
403 case GL_OBJECT_LINEAR
:
404 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][1]),
405 sizeof(out
->data
[0]), obj
,
406 texUnit
->GenT
.ObjectPlane
);
409 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][1]),
410 sizeof(out
->data
[0]), eye
,
411 texUnit
->GenT
.EyePlane
);
414 for (i
= 0; i
< count
; i
++)
415 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
417 case GL_REFLECTION_MAP_NV
:
418 for (i
=0;i
<count
;i
++)
419 texcoord
[i
][1] = f
[i
][1];
421 case GL_NORMAL_MAP_NV
: {
422 const GLfloat
*norm
= normal
->start
;
423 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
424 texcoord
[i
][1] = norm
[1];
429 _mesa_problem(ctx
, "Bad T texgen");
433 if (texUnit
->TexGenEnabled
& R_BIT
) {
435 switch (texUnit
->GenR
.Mode
) {
436 case GL_OBJECT_LINEAR
:
437 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][2]),
438 sizeof(out
->data
[0]), obj
,
439 texUnit
->GenR
.ObjectPlane
);
442 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][2]),
443 sizeof(out
->data
[0]), eye
,
444 texUnit
->GenR
.EyePlane
);
446 case GL_REFLECTION_MAP_NV
:
447 for (i
=0;i
<count
;i
++)
448 texcoord
[i
][2] = f
[i
][2];
450 case GL_NORMAL_MAP_NV
: {
451 const GLfloat
*norm
= normal
->start
;
452 for (i
=0;i
<count
;i
++,STRIDE_F(norm
, normal
->stride
)) {
453 texcoord
[i
][2] = norm
[2];
458 _mesa_problem(ctx
, "Bad R texgen");
462 if (texUnit
->TexGenEnabled
& Q_BIT
) {
463 switch (texUnit
->GenQ
.Mode
) {
464 case GL_OBJECT_LINEAR
:
465 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][3]),
466 sizeof(out
->data
[0]), obj
,
467 texUnit
->GenQ
.ObjectPlane
);
470 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][3]),
471 sizeof(out
->data
[0]), eye
,
472 texUnit
->GenQ
.EyePlane
);
475 _mesa_problem(ctx
, "Bad Q texgen");
483 static GLboolean
run_texgen_stage( struct gl_context
*ctx
,
484 struct tnl_pipeline_stage
*stage
)
486 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
487 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
490 if (!ctx
->Texture
._TexGenEnabled
|| ctx
->VertexProgram
._Current
)
493 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
494 struct gl_fixedfunc_texture_unit
*texUnit
=
495 &ctx
->Texture
.FixedFuncUnit
[i
];
497 if (texUnit
->TexGenEnabled
) {
498 store
->TexgenFunc
[i
]( ctx
, store
, i
);
500 VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ i
] = &store
->texcoord
[i
];
508 static void validate_texgen_stage( struct gl_context
*ctx
,
509 struct tnl_pipeline_stage
*stage
)
511 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
514 if (!ctx
->Texture
._TexGenEnabled
|| ctx
->VertexProgram
._Current
)
517 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
518 struct gl_fixedfunc_texture_unit
*texUnit
=
519 &ctx
->Texture
.FixedFuncUnit
[i
];
521 if (texUnit
->TexGenEnabled
) {
524 if (texUnit
->TexGenEnabled
& Q_BIT
)
526 else if (texUnit
->TexGenEnabled
& R_BIT
)
528 else if (texUnit
->TexGenEnabled
& T_BIT
)
533 store
->TexgenSize
[i
] = sz
;
534 store
->TexgenFunc
[i
] = texgen
; /* general solution */
536 /* look for special texgen cases */
537 if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
|R_BIT
)) {
538 if (texUnit
->_GenFlags
== TEXGEN_REFLECTION_MAP_NV
) {
539 store
->TexgenFunc
[i
] = texgen_reflection_map_nv
;
541 else if (texUnit
->_GenFlags
== TEXGEN_NORMAL_MAP_NV
) {
542 store
->TexgenFunc
[i
] = texgen_normal_map_nv
;
545 else if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
) &&
546 texUnit
->_GenFlags
== TEXGEN_SPHERE_MAP
) {
547 store
->TexgenFunc
[i
] = texgen_sphere_map
;
557 /* Called the first time stage->run() is invoked.
559 static GLboolean
alloc_texgen_data( struct gl_context
*ctx
,
560 struct tnl_pipeline_stage
*stage
)
562 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
563 struct texgen_stage_data
*store
;
566 stage
->privatePtr
= calloc(1, sizeof(*store
));
567 store
= TEXGEN_STAGE_DATA(stage
);
571 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
572 _mesa_vector4f_alloc( &store
->texcoord
[i
], 0, VB
->Size
, 32 );
574 store
->tmp_f
= malloc(VB
->Size
* sizeof(GLfloat
) * 3);
575 store
->tmp_m
= malloc(VB
->Size
* sizeof(GLfloat
));
581 static void free_texgen_data( struct tnl_pipeline_stage
*stage
)
584 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
588 for (i
= 0 ; i
< MAX_TEXTURE_COORD_UNITS
; i
++)
589 if (store
->texcoord
[i
].data
)
590 _mesa_vector4f_free( &store
->texcoord
[i
] );
593 free( store
->tmp_f
);
594 free( store
->tmp_m
);
596 stage
->privatePtr
= NULL
;
602 const struct tnl_pipeline_stage _tnl_texgen_stage
=
605 NULL
, /* private data */
606 alloc_texgen_data
, /* destructor */
607 free_texgen_data
, /* destructor */
608 validate_texgen_stage
, /* check */
609 run_texgen_stage
/* run -- initially set to alloc data */