2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2003 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>
37 #include "math/m_xform.h"
39 #include "t_context.h"
40 #include "t_pipeline.h"
43 /***********************************************************************
44 * Automatic texture coordinate generation (texgen) code.
48 struct texgen_stage_data
;
50 typedef void (*texgen_func
)( GLcontext
*ctx
,
51 struct texgen_stage_data
*store
,
55 struct texgen_stage_data
{
57 /* Per-texunit derived state.
59 GLuint TexgenSize
[MAX_TEXTURE_COORD_UNITS
];
60 GLuint TexgenHoles
[MAX_TEXTURE_COORD_UNITS
];
61 texgen_func TexgenFunc
[MAX_TEXTURE_COORD_UNITS
];
63 /* Temporary values used in texgen.
68 /* Buffered outputs of the stage.
70 GLvector4f texcoord
[MAX_TEXTURE_COORD_UNITS
];
74 #define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
78 static GLuint all_bits
[5] = {
86 #define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
88 #define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP)
89 #define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \
90 TEXGEN_REFLECTION_MAP_NV)
94 static void build_m3( GLfloat f
[][3], GLfloat m
[],
95 const GLvector4f
*normal
,
96 const GLvector4f
*eye
)
98 GLuint stride
= eye
->stride
;
99 GLfloat
*coord
= (GLfloat
*)eye
->start
;
100 GLuint count
= eye
->count
;
101 const GLfloat
*norm
= normal
->start
;
104 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
105 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
108 two_nu
= 2.0F
* DOT3(norm
,u
);
109 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
110 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
111 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
112 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
114 m
[i
] = 0.5F
* _mesa_inv_sqrtf(m
[i
]);
121 static void build_m2( GLfloat f
[][3], GLfloat m
[],
122 const GLvector4f
*normal
,
123 const GLvector4f
*eye
)
125 GLuint stride
= eye
->stride
;
126 GLfloat
*coord
= eye
->start
;
127 GLuint count
= eye
->count
;
129 GLfloat
*norm
= normal
->start
;
132 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
133 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
137 two_nu
= 2.0F
* DOT3(norm
,u
);
138 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
139 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
140 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
141 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
143 m
[i
] = 0.5F
* _mesa_inv_sqrtf(m
[i
]);
150 typedef void (*build_m_func
)( GLfloat f
[][3],
152 const GLvector4f
*normal
,
153 const GLvector4f
*eye
);
156 static build_m_func build_m_tab
[5] = {
165 /* This is unusual in that we respect the stride of the output vector
166 * (f). This allows us to pass in either a texcoord vector4f, or a
167 * temporary vector3f.
169 static void build_f3( GLfloat
*f
,
171 const GLvector4f
*normal
,
172 const GLvector4f
*eye
)
174 GLuint stride
= eye
->stride
;
175 GLfloat
*coord
= eye
->start
;
176 GLuint count
= eye
->count
;
178 GLfloat
*norm
= normal
->start
;
181 for (i
=0;i
<count
;i
++) {
182 GLfloat u
[3], two_nu
;
185 two_nu
= 2.0F
* DOT3(norm
,u
);
186 f
[0] = u
[0] - norm
[0] * two_nu
;
187 f
[1] = u
[1] - norm
[1] * two_nu
;
188 f
[2] = u
[2] - norm
[2] * two_nu
;
189 STRIDE_F(coord
,stride
);
191 STRIDE_F(norm
, normal
->stride
);
196 static void build_f2( GLfloat
*f
,
198 const GLvector4f
*normal
,
199 const GLvector4f
*eye
)
201 GLuint stride
= eye
->stride
;
202 GLfloat
*coord
= eye
->start
;
203 GLuint count
= eye
->count
;
204 GLfloat
*norm
= normal
->start
;
207 for (i
=0;i
<count
;i
++) {
209 GLfloat u
[3], two_nu
;
213 two_nu
= 2.0F
* DOT3(norm
,u
);
214 f
[0] = u
[0] - norm
[0] * two_nu
;
215 f
[1] = u
[1] - norm
[1] * two_nu
;
216 f
[2] = u
[2] - norm
[2] * two_nu
;
218 STRIDE_F(coord
,stride
);
220 STRIDE_F(norm
, normal
->stride
);
224 typedef void (*build_f_func
)( GLfloat
*f
,
226 const GLvector4f
*normal_vec
,
227 const GLvector4f
*eye
);
231 /* Just treat 4-vectors as 3-vectors.
233 static build_f_func build_f_tab
[5] = {
242 /* Special case texgen functions.
244 static void texgen_reflection_map_nv( GLcontext
*ctx
,
245 struct texgen_stage_data
*store
,
248 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
249 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
250 GLvector4f
*out
= &store
->texcoord
[unit
];
252 build_f_tab
[VB
->EyePtr
->size
]( out
->start
,
258 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
259 out
->count
= in
->count
;
260 out
->size
= MAX2(in
->size
, 3);
262 _mesa_copy_tab
[0x8]( out
, in
);
265 out
->flags
|= VEC_SIZE_3
;
267 out
->count
= in
->count
;
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];
295 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
296 out
->count
= in
->count
;
297 out
->size
= MAX2(in
->size
, 3);
299 _mesa_copy_tab
[0x8]( out
, in
);
302 out
->flags
|= VEC_SIZE_3
;
304 out
->count
= in
->count
;
309 static void texgen_sphere_map( GLcontext
*ctx
,
310 struct texgen_stage_data
*store
,
313 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
314 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
315 GLvector4f
*out
= &store
->texcoord
[unit
];
316 GLfloat (*texcoord
)[4] = (GLfloat (*)[4]) out
->start
;
317 GLuint count
= VB
->Count
;
319 GLfloat (*f
)[3] = store
->tmp_f
;
320 GLfloat
*m
= store
->tmp_m
;
322 /* _mesa_debug(NULL, "%s normstride %d eyestride %d\n", */
323 /* __FUNCTION__, VB->NormalPtr->stride, */
324 /* VB->EyePtr->stride); */
326 (build_m_tab
[VB
->EyePtr
->size
])( store
->tmp_f
,
331 for (i
=0;i
<count
;i
++) {
332 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
333 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
337 out
->size
= MAX2(in
->size
,2);
338 out
->count
= in
->count
;
339 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_2
;
341 _mesa_copy_tab
[all_bits
[in
->size
] & ~0x3]( out
, in
);
344 out
->flags
|= VEC_SIZE_2
;
345 out
->count
= in
->count
;
351 static void texgen( GLcontext
*ctx
,
352 struct texgen_stage_data
*store
,
355 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
356 struct vertex_buffer
*VB
= &tnl
->vb
;
357 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
358 GLvector4f
*out
= &store
->texcoord
[unit
];
359 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
360 const GLvector4f
*obj
= VB
->ObjPtr
;
361 const GLvector4f
*eye
= VB
->EyePtr
;
362 const GLvector4f
*normal
= VB
->NormalPtr
;
363 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->data
;
365 GLuint count
= VB
->Count
;
366 GLfloat (*f
)[3] = store
->tmp_f
;
367 GLfloat
*m
= store
->tmp_m
;
371 if (texUnit
->_GenFlags
& TEXGEN_NEED_M
) {
372 build_m_tab
[in
->size
]( store
->tmp_f
, store
->tmp_m
, normal
, eye
);
373 } else if (texUnit
->_GenFlags
& TEXGEN_NEED_F
) {
374 build_f_tab
[in
->size
]( (GLfloat
*)store
->tmp_f
, 3, normal
, eye
);
380 in
->count
= VB
->Count
;
382 out
->size
= store
->TexgenSize
[unit
];
383 out
->flags
|= texUnit
->TexGenEnabled
;
384 out
->count
= VB
->Count
;
385 holes
= store
->TexgenHoles
[unit
];
388 GLuint copy
= (all_bits
[in
->size
] & ~texUnit
->TexGenEnabled
);
390 _mesa_copy_tab
[copy
]( out
, in
);
392 out
->size
= MAX2(in
->size
, store
->TexgenSize
[unit
]);
393 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | texUnit
->TexGenEnabled
;
394 out
->count
= in
->count
;
396 holes
= ~all_bits
[in
->size
] & store
->TexgenHoles
[unit
];
400 if (holes
& VEC_DIRTY_3
) _mesa_vector4f_clean_elem(out
, count
, 3);
401 if (holes
& VEC_DIRTY_2
) _mesa_vector4f_clean_elem(out
, count
, 2);
402 if (holes
& VEC_DIRTY_1
) _mesa_vector4f_clean_elem(out
, count
, 1);
403 if (holes
& VEC_DIRTY_0
) _mesa_vector4f_clean_elem(out
, count
, 0);
406 if (texUnit
->TexGenEnabled
& S_BIT
) {
408 switch (texUnit
->GenModeS
) {
409 case GL_OBJECT_LINEAR
:
410 _mesa_dotprod_tab
[obj
->size
]( (GLfloat
*)out
->data
,
411 sizeof(out
->data
[0]), obj
,
412 texUnit
->ObjectPlaneS
);
415 _mesa_dotprod_tab
[eye
->size
]( (GLfloat
*)out
->data
,
416 sizeof(out
->data
[0]), eye
,
417 texUnit
->EyePlaneS
);
420 for (indata
=in
->start
,i
=0 ; i
<count
;i
++, STRIDE_F(indata
,in
->stride
))
421 texcoord
[i
][0] = indata
[0] * m
[i
] + 0.5F
;
423 case GL_REFLECTION_MAP_NV
:
424 for (i
=0;i
<count
;i
++)
425 texcoord
[i
][0] = f
[i
][0];
427 case GL_NORMAL_MAP_NV
: {
428 const GLfloat
*norm
= normal
->start
;
429 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
430 texcoord
[i
][0] = norm
[0];
435 _mesa_problem(ctx
, "Bad S texgen");
439 if (texUnit
->TexGenEnabled
& T_BIT
) {
441 switch (texUnit
->GenModeT
) {
442 case GL_OBJECT_LINEAR
:
443 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][1]),
444 sizeof(out
->data
[0]), obj
,
445 texUnit
->ObjectPlaneT
);
448 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][1]),
449 sizeof(out
->data
[0]), eye
,
450 texUnit
->EyePlaneT
);
453 for (indata
=in
->start
,i
=0; i
<count
;i
++,STRIDE_F(indata
,in
->stride
))
454 texcoord
[i
][1] = indata
[1] * m
[i
] + 0.5F
;
456 case GL_REFLECTION_MAP_NV
:
457 for (i
=0;i
<count
;i
++)
458 texcoord
[i
][0] = f
[i
][0];
460 case GL_NORMAL_MAP_NV
: {
461 const GLfloat
*norm
= normal
->start
;
462 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
463 texcoord
[i
][1] = norm
[1];
468 _mesa_problem(ctx
, "Bad T texgen");
472 if (texUnit
->TexGenEnabled
& R_BIT
) {
474 switch (texUnit
->GenModeR
) {
475 case GL_OBJECT_LINEAR
:
476 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][2]),
477 sizeof(out
->data
[0]), obj
,
478 texUnit
->ObjectPlaneR
);
481 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][2]),
482 sizeof(out
->data
[0]), eye
,
483 texUnit
->EyePlaneR
);
485 case GL_REFLECTION_MAP_NV
:
486 for (i
=0;i
<count
;i
++)
487 texcoord
[i
][2] = f
[i
][2];
489 case GL_NORMAL_MAP_NV
: {
490 const GLfloat
*norm
= normal
->start
;
491 for (i
=0;i
<count
;i
++,STRIDE_F(norm
, normal
->stride
)) {
492 texcoord
[i
][2] = norm
[2];
497 _mesa_problem(ctx
, "Bad R texgen");
501 if (texUnit
->TexGenEnabled
& Q_BIT
) {
502 switch (texUnit
->GenModeQ
) {
503 case GL_OBJECT_LINEAR
:
504 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][3]),
505 sizeof(out
->data
[0]), obj
,
506 texUnit
->ObjectPlaneQ
);
509 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][3]),
510 sizeof(out
->data
[0]), eye
,
511 texUnit
->EyePlaneQ
);
514 _mesa_problem(ctx
, "Bad Q texgen");
521 static GLboolean
run_texgen_stage( GLcontext
*ctx
,
522 struct gl_pipeline_stage
*stage
)
524 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
525 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA( stage
);
528 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
529 if (ctx
->Texture
._TexGenEnabled
& ENABLE_TEXGEN(i
)) {
530 if (stage
->changed_inputs
& (VERT_BIT_EYE
| VERT_BIT_NORMAL
| VERT_BIT_TEX(i
)))
531 store
->TexgenFunc
[i
]( ctx
, store
, i
);
533 VB
->TexCoordPtr
[i
] = &store
->texcoord
[i
];
542 static GLboolean
run_validate_texgen_stage( GLcontext
*ctx
,
543 struct gl_pipeline_stage
*stage
)
545 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
548 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
549 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
551 if (texUnit
->TexGenEnabled
) {
554 if (texUnit
->TexGenEnabled
& R_BIT
)
556 else if (texUnit
->TexGenEnabled
& Q_BIT
)
558 else if (texUnit
->TexGenEnabled
& T_BIT
)
563 store
->TexgenSize
[i
] = sz
;
564 store
->TexgenHoles
[i
] = (all_bits
[sz
] & ~texUnit
->TexGenEnabled
);
565 store
->TexgenFunc
[i
] = texgen
;
567 if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
|R_BIT
)) {
568 if (texUnit
->_GenFlags
== TEXGEN_REFLECTION_MAP_NV
) {
569 store
->TexgenFunc
[i
] = texgen_reflection_map_nv
;
571 else if (texUnit
->_GenFlags
== TEXGEN_NORMAL_MAP_NV
) {
572 store
->TexgenFunc
[i
] = texgen_normal_map_nv
;
575 else if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
) &&
576 texUnit
->_GenFlags
== TEXGEN_SPHERE_MAP
) {
577 store
->TexgenFunc
[i
] = texgen_sphere_map
;
582 stage
->run
= run_texgen_stage
;
583 return stage
->run( ctx
, stage
);
587 static void check_texgen( GLcontext
*ctx
, struct gl_pipeline_stage
*stage
)
592 if (ctx
->Texture
._TexGenEnabled
&& !ctx
->VertexProgram
.Enabled
) {
596 if (ctx
->Texture
._GenFlags
& TEXGEN_OBJ_LINEAR
)
597 inputs
|= VERT_BIT_POS
;
599 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_EYE_COORD
)
600 inputs
|= VERT_BIT_EYE
;
602 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_NORMALS
)
603 inputs
|= VERT_BIT_NORMAL
;
605 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
606 if (ctx
->Texture
._TexGenEnabled
& ENABLE_TEXGEN(i
))
608 outputs
|= VERT_BIT_TEX(i
);
610 /* Need the original input in case it contains a Q coord:
613 inputs
|= VERT_BIT_TEX(i
);
615 /* Something for Feedback? */
618 if (stage
->privatePtr
)
619 stage
->run
= run_validate_texgen_stage
;
621 stage
->inputs
= inputs
;
622 stage
->outputs
= outputs
;
629 /* Called the first time stage->run() is invoked.
631 static GLboolean
alloc_texgen_data( GLcontext
*ctx
,
632 struct gl_pipeline_stage
*stage
)
634 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
635 struct texgen_stage_data
*store
;
638 stage
->privatePtr
= CALLOC(sizeof(*store
));
639 store
= TEXGEN_STAGE_DATA(stage
);
643 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
644 _mesa_vector4f_alloc( &store
->texcoord
[i
], 0, VB
->Size
, 32 );
646 store
->tmp_f
= (GLfloat (*)[3]) MALLOC(VB
->Size
* sizeof(GLfloat
) * 3);
647 store
->tmp_m
= (GLfloat
*) MALLOC(VB
->Size
* sizeof(GLfloat
));
649 /* Now validate and run the stage.
651 stage
->run
= run_validate_texgen_stage
;
652 return stage
->run( ctx
, stage
);
656 static void free_texgen_data( struct gl_pipeline_stage
*stage
)
659 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
663 for (i
= 0 ; i
< MAX_TEXTURE_COORD_UNITS
; i
++)
664 if (store
->texcoord
[i
].data
)
665 _mesa_vector4f_free( &store
->texcoord
[i
] );
668 if (store
->tmp_f
) FREE( store
->tmp_f
);
669 if (store
->tmp_m
) FREE( store
->tmp_m
);
671 stage
->privatePtr
= NULL
;
677 const struct gl_pipeline_stage _tnl_texgen_stage
=
680 _NEW_TEXTURE
, /* when to call check() */
681 _NEW_TEXTURE
, /* when to invalidate stored data */
682 GL_FALSE
, /* active? */
685 0, /* changed_inputs */
686 NULL
, /* private data */
687 free_texgen_data
, /* destructor */
688 check_texgen
, /* check */
689 alloc_texgen_data
/* run -- initially set to alloc data */