2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Keith Whitwell <keith@tungstengraphics.com>
30 * Regarding GL_NV_texgen_reflection:
32 * Portions of this software may use or implement intellectual
33 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
34 * any and all warranties with respect to such intellectual property,
35 * including any use thereof or modifications thereto.
45 #include "math/m_xform.h"
47 #include "t_context.h"
48 #include "t_pipeline.h"
51 /***********************************************************************
52 * Automatic texture coordinate generation (texgen) code.
56 struct texgen_stage_data
;
58 typedef void (*texgen_func
)( GLcontext
*ctx
,
59 struct texgen_stage_data
*store
,
63 struct texgen_stage_data
{
65 /* Per-texunit derived state.
67 GLuint TexgenSize
[MAX_TEXTURE_COORD_UNITS
];
68 texgen_func TexgenFunc
[MAX_TEXTURE_COORD_UNITS
];
70 /* Temporary values used in texgen.
75 /* Buffered outputs of the stage.
77 GLvector4f texcoord
[MAX_TEXTURE_COORD_UNITS
];
81 #define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
85 static GLuint all_bits
[5] = {
93 #define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
95 #define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP)
96 #define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \
97 TEXGEN_REFLECTION_MAP_NV)
101 static void build_m3( GLfloat f
[][3], GLfloat m
[],
102 const GLvector4f
*normal
,
103 const GLvector4f
*eye
)
105 GLuint stride
= eye
->stride
;
106 GLfloat
*coord
= (GLfloat
*)eye
->start
;
107 GLuint count
= eye
->count
;
108 const GLfloat
*norm
= normal
->start
;
111 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
112 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
115 two_nu
= 2.0F
* DOT3(norm
,u
);
116 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
117 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
118 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
119 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
121 m
[i
] = 0.5F
* _mesa_inv_sqrtf(m
[i
]);
128 static void build_m2( GLfloat f
[][3], GLfloat m
[],
129 const GLvector4f
*normal
,
130 const GLvector4f
*eye
)
132 GLuint stride
= eye
->stride
;
133 GLfloat
*coord
= eye
->start
;
134 GLuint count
= eye
->count
;
136 GLfloat
*norm
= normal
->start
;
139 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
140 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
144 two_nu
= 2.0F
* DOT3(norm
,u
);
145 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
146 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
147 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
148 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
150 m
[i
] = 0.5F
* _mesa_inv_sqrtf(m
[i
]);
157 typedef void (*build_m_func
)( GLfloat f
[][3],
159 const GLvector4f
*normal
,
160 const GLvector4f
*eye
);
163 static build_m_func build_m_tab
[5] = {
172 /* This is unusual in that we respect the stride of the output vector
173 * (f). This allows us to pass in either a texcoord vector4f, or a
174 * temporary vector3f.
176 static void build_f3( GLfloat
*f
,
178 const GLvector4f
*normal
,
179 const GLvector4f
*eye
)
181 GLuint stride
= eye
->stride
;
182 GLfloat
*coord
= eye
->start
;
183 GLuint count
= eye
->count
;
185 GLfloat
*norm
= normal
->start
;
188 for (i
=0;i
<count
;i
++) {
189 GLfloat u
[3], two_nu
;
192 two_nu
= 2.0F
* DOT3(norm
,u
);
193 f
[0] = u
[0] - norm
[0] * two_nu
;
194 f
[1] = u
[1] - norm
[1] * two_nu
;
195 f
[2] = u
[2] - norm
[2] * two_nu
;
196 STRIDE_F(coord
,stride
);
198 STRIDE_F(norm
, normal
->stride
);
203 static void build_f2( GLfloat
*f
,
205 const GLvector4f
*normal
,
206 const GLvector4f
*eye
)
208 GLuint stride
= eye
->stride
;
209 GLfloat
*coord
= eye
->start
;
210 GLuint count
= eye
->count
;
211 GLfloat
*norm
= normal
->start
;
214 for (i
=0;i
<count
;i
++) {
216 GLfloat u
[3], two_nu
;
220 two_nu
= 2.0F
* DOT3(norm
,u
);
221 f
[0] = u
[0] - norm
[0] * two_nu
;
222 f
[1] = u
[1] - norm
[1] * two_nu
;
223 f
[2] = u
[2] - norm
[2] * two_nu
;
225 STRIDE_F(coord
,stride
);
227 STRIDE_F(norm
, normal
->stride
);
231 typedef void (*build_f_func
)( GLfloat
*f
,
233 const GLvector4f
*normal_vec
,
234 const GLvector4f
*eye
);
238 /* Just treat 4-vectors as 3-vectors.
240 static build_f_func build_f_tab
[5] = {
250 /* Special case texgen functions.
252 static void texgen_reflection_map_nv( GLcontext
*ctx
,
253 struct texgen_stage_data
*store
,
256 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
257 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
258 GLvector4f
*out
= &store
->texcoord
[unit
];
260 build_f_tab
[VB
->EyePtr
->size
]( out
->start
,
265 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
266 out
->count
= VB
->Count
;
267 out
->size
= MAX2(in
->size
, 3);
269 _mesa_copy_tab
[0x8]( out
, in
);
274 static void texgen_normal_map_nv( GLcontext
*ctx
,
275 struct texgen_stage_data
*store
,
278 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
279 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
280 GLvector4f
*out
= &store
->texcoord
[unit
];
281 GLvector4f
*normal
= VB
->NormalPtr
;
282 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->start
;
283 GLuint count
= VB
->Count
;
285 const GLfloat
*norm
= normal
->start
;
287 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
288 texcoord
[i
][0] = norm
[0];
289 texcoord
[i
][1] = norm
[1];
290 texcoord
[i
][2] = norm
[2];
294 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
296 out
->size
= MAX2(in
->size
, 3);
298 _mesa_copy_tab
[0x8]( out
, in
);
302 static void texgen_sphere_map( GLcontext
*ctx
,
303 struct texgen_stage_data
*store
,
306 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
307 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
308 GLvector4f
*out
= &store
->texcoord
[unit
];
309 GLfloat (*texcoord
)[4] = (GLfloat (*)[4]) out
->start
;
310 GLuint count
= VB
->Count
;
312 GLfloat (*f
)[3] = store
->tmp_f
;
313 GLfloat
*m
= store
->tmp_m
;
315 (build_m_tab
[VB
->EyePtr
->size
])( store
->tmp_f
,
320 out
->size
= MAX2(in
->size
,2);
322 for (i
=0;i
<count
;i
++) {
323 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
324 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
328 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_2
;
330 _mesa_copy_tab
[all_bits
[in
->size
] & ~0x3]( out
, in
);
335 static void texgen( GLcontext
*ctx
,
336 struct texgen_stage_data
*store
,
339 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
340 struct vertex_buffer
*VB
= &tnl
->vb
;
341 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
342 GLvector4f
*out
= &store
->texcoord
[unit
];
343 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
344 const GLvector4f
*obj
= VB
->ObjPtr
;
345 const GLvector4f
*eye
= VB
->EyePtr
;
346 const GLvector4f
*normal
= VB
->NormalPtr
;
347 const GLfloat
*m
= store
->tmp_m
;
348 const GLuint count
= VB
->Count
;
349 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->data
;
350 GLfloat (*f
)[3] = store
->tmp_f
;
353 if (texUnit
->_GenFlags
& TEXGEN_NEED_M
) {
354 build_m_tab
[eye
->size
]( store
->tmp_f
, store
->tmp_m
, normal
, eye
);
355 } else if (texUnit
->_GenFlags
& TEXGEN_NEED_F
) {
356 build_f_tab
[eye
->size
]( (GLfloat
*)store
->tmp_f
, 3, normal
, eye
);
360 out
->size
= MAX2(in
->size
, store
->TexgenSize
[unit
]);
361 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | texUnit
->TexGenEnabled
;
364 copy
= (all_bits
[in
->size
] & ~texUnit
->TexGenEnabled
);
366 _mesa_copy_tab
[copy
]( out
, in
);
368 if (texUnit
->TexGenEnabled
& S_BIT
) {
370 switch (texUnit
->GenModeS
) {
371 case GL_OBJECT_LINEAR
:
372 _mesa_dotprod_tab
[obj
->size
]( (GLfloat
*)out
->data
,
373 sizeof(out
->data
[0]), obj
,
374 texUnit
->ObjectPlaneS
);
377 _mesa_dotprod_tab
[eye
->size
]( (GLfloat
*)out
->data
,
378 sizeof(out
->data
[0]), eye
,
379 texUnit
->EyePlaneS
);
382 for (i
= 0; i
< count
; i
++)
383 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
385 case GL_REFLECTION_MAP_NV
:
386 for (i
=0;i
<count
;i
++)
387 texcoord
[i
][0] = f
[i
][0];
389 case GL_NORMAL_MAP_NV
: {
390 const GLfloat
*norm
= normal
->start
;
391 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
392 texcoord
[i
][0] = norm
[0];
397 _mesa_problem(ctx
, "Bad S texgen");
401 if (texUnit
->TexGenEnabled
& T_BIT
) {
403 switch (texUnit
->GenModeT
) {
404 case GL_OBJECT_LINEAR
:
405 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][1]),
406 sizeof(out
->data
[0]), obj
,
407 texUnit
->ObjectPlaneT
);
410 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][1]),
411 sizeof(out
->data
[0]), eye
,
412 texUnit
->EyePlaneT
);
415 for (i
= 0; i
< count
; i
++)
416 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
418 case GL_REFLECTION_MAP_NV
:
419 for (i
=0;i
<count
;i
++)
420 texcoord
[i
][1] = f
[i
][1];
422 case GL_NORMAL_MAP_NV
: {
423 const GLfloat
*norm
= normal
->start
;
424 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
425 texcoord
[i
][1] = norm
[1];
430 _mesa_problem(ctx
, "Bad T texgen");
434 if (texUnit
->TexGenEnabled
& R_BIT
) {
436 switch (texUnit
->GenModeR
) {
437 case GL_OBJECT_LINEAR
:
438 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][2]),
439 sizeof(out
->data
[0]), obj
,
440 texUnit
->ObjectPlaneR
);
443 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][2]),
444 sizeof(out
->data
[0]), eye
,
445 texUnit
->EyePlaneR
);
447 case GL_REFLECTION_MAP_NV
:
448 for (i
=0;i
<count
;i
++)
449 texcoord
[i
][2] = f
[i
][2];
451 case GL_NORMAL_MAP_NV
: {
452 const GLfloat
*norm
= normal
->start
;
453 for (i
=0;i
<count
;i
++,STRIDE_F(norm
, normal
->stride
)) {
454 texcoord
[i
][2] = norm
[2];
459 _mesa_problem(ctx
, "Bad R texgen");
463 if (texUnit
->TexGenEnabled
& Q_BIT
) {
464 switch (texUnit
->GenModeQ
) {
465 case GL_OBJECT_LINEAR
:
466 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][3]),
467 sizeof(out
->data
[0]), obj
,
468 texUnit
->ObjectPlaneQ
);
471 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][3]),
472 sizeof(out
->data
[0]), eye
,
473 texUnit
->EyePlaneQ
);
476 _mesa_problem(ctx
, "Bad Q texgen");
483 static GLboolean
run_texgen_stage( GLcontext
*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 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
491 if (ctx
->Texture
._TexGenEnabled
& ENABLE_TEXGEN(i
)) {
492 if (stage
->changed_inputs
& (_TNL_BIT_POS
| _TNL_BIT_NORMAL
| _TNL_BIT_TEX(i
)))
493 store
->TexgenFunc
[i
]( ctx
, store
, i
);
495 VB
->AttribPtr
[VERT_ATTRIB_TEX0
+i
] =
496 VB
->TexCoordPtr
[i
] = &store
->texcoord
[i
];
505 static GLboolean
run_validate_texgen_stage( GLcontext
*ctx
,
506 struct tnl_pipeline_stage
*stage
)
508 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
511 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
512 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
514 if (texUnit
->TexGenEnabled
) {
517 if (texUnit
->TexGenEnabled
& Q_BIT
)
519 else if (texUnit
->TexGenEnabled
& R_BIT
)
521 else if (texUnit
->TexGenEnabled
& T_BIT
)
526 store
->TexgenSize
[i
] = sz
;
527 store
->TexgenFunc
[i
] = texgen
; /* general solution */
529 /* look for special texgen cases */
530 if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
|R_BIT
)) {
531 if (texUnit
->_GenFlags
== TEXGEN_REFLECTION_MAP_NV
) {
532 store
->TexgenFunc
[i
] = texgen_reflection_map_nv
;
534 else if (texUnit
->_GenFlags
== TEXGEN_NORMAL_MAP_NV
) {
535 store
->TexgenFunc
[i
] = texgen_normal_map_nv
;
538 else if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
) &&
539 texUnit
->_GenFlags
== TEXGEN_SPHERE_MAP
) {
540 store
->TexgenFunc
[i
] = texgen_sphere_map
;
545 stage
->run
= run_texgen_stage
;
546 return stage
->run( ctx
, stage
);
550 static void check_texgen( GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
555 if (ctx
->Texture
._TexGenEnabled
&& !ctx
->VertexProgram
._Enabled
) {
559 if (ctx
->Texture
._GenFlags
& (TEXGEN_OBJ_LINEAR
| TEXGEN_NEED_EYE_COORD
))
560 inputs
|= _TNL_BIT_POS
;
562 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_NORMALS
)
563 inputs
|= _TNL_BIT_NORMAL
;
565 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
566 if (ctx
->Texture
._TexGenEnabled
& ENABLE_TEXGEN(i
))
568 outputs
|= _TNL_BIT_TEX(i
);
570 /* Need the original input in case it contains a Q coord:
573 inputs
|= _TNL_BIT_TEX(i
);
575 /* Something for Feedback? */
578 if (stage
->privatePtr
)
579 stage
->run
= run_validate_texgen_stage
;
581 stage
->inputs
= inputs
;
582 stage
->outputs
= outputs
;
589 /* Called the first time stage->run() is invoked.
591 static GLboolean
alloc_texgen_data( GLcontext
*ctx
,
592 struct tnl_pipeline_stage
*stage
)
594 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
595 struct texgen_stage_data
*store
;
598 stage
->privatePtr
= CALLOC(sizeof(*store
));
599 store
= TEXGEN_STAGE_DATA(stage
);
603 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
604 _mesa_vector4f_alloc( &store
->texcoord
[i
], 0, VB
->Size
, 32 );
606 store
->tmp_f
= (GLfloat (*)[3]) MALLOC(VB
->Size
* sizeof(GLfloat
) * 3);
607 store
->tmp_m
= (GLfloat
*) MALLOC(VB
->Size
* sizeof(GLfloat
));
609 /* Now validate and run the stage.
611 stage
->run
= run_validate_texgen_stage
;
612 return stage
->run( ctx
, stage
);
616 static void free_texgen_data( struct tnl_pipeline_stage
*stage
)
619 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
623 for (i
= 0 ; i
< MAX_TEXTURE_COORD_UNITS
; i
++)
624 if (store
->texcoord
[i
].data
)
625 _mesa_vector4f_free( &store
->texcoord
[i
] );
628 if (store
->tmp_f
) FREE( store
->tmp_f
);
629 if (store
->tmp_m
) FREE( store
->tmp_m
);
631 stage
->privatePtr
= NULL
;
637 const struct tnl_pipeline_stage _tnl_texgen_stage
=
640 _NEW_TEXTURE
|_NEW_PROGRAM
, /* when to call check() */
641 _NEW_TEXTURE
, /* when to invalidate stored data */
642 GL_FALSE
, /* active? */
645 0, /* changed_inputs */
646 NULL
, /* private data */
647 free_texgen_data
, /* destructor */
648 check_texgen
, /* check */
649 alloc_texgen_data
/* run -- initially set to alloc data */