1 /* $Id: t_vb_texgen.c,v 1.19 2003/03/31 16:48:35 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Keith Whitwell <keith@tungstengraphics.com>
39 #include "math/m_xform.h"
41 #include "t_context.h"
42 #include "t_pipeline.h"
45 /***********************************************************************
46 * Automatic texture coordinate generation (texgen) code.
50 struct texgen_stage_data
;
52 typedef void (*texgen_func
)( GLcontext
*ctx
,
53 struct texgen_stage_data
*store
,
57 struct texgen_stage_data
{
59 /* Per-texunit derived state.
61 GLuint TexgenSize
[MAX_TEXTURE_COORD_UNITS
];
62 GLuint TexgenHoles
[MAX_TEXTURE_COORD_UNITS
];
63 texgen_func TexgenFunc
[MAX_TEXTURE_COORD_UNITS
];
65 /* Temporary values used in texgen.
70 /* Buffered outputs of the stage.
72 GLvector4f texcoord
[MAX_TEXTURE_COORD_UNITS
];
76 #define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
80 static GLuint all_bits
[5] = {
88 #define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
90 #define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP)
91 #define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \
92 TEXGEN_REFLECTION_MAP_NV)
96 static void build_m3( GLfloat f
[][3], GLfloat m
[],
97 const GLvector4f
*normal
,
98 const GLvector4f
*eye
)
100 GLuint stride
= eye
->stride
;
101 GLfloat
*coord
= (GLfloat
*)eye
->start
;
102 GLuint count
= eye
->count
;
103 const GLfloat
*norm
= normal
->start
;
106 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
107 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
110 two_nu
= 2.0F
* DOT3(norm
,u
);
111 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
112 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
113 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
114 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
116 m
[i
] = 0.5F
* _mesa_inv_sqrtf(m
[i
]);
123 static void build_m2( GLfloat f
[][3], GLfloat m
[],
124 const GLvector4f
*normal
,
125 const GLvector4f
*eye
)
127 GLuint stride
= eye
->stride
;
128 GLfloat
*coord
= eye
->start
;
129 GLuint count
= eye
->count
;
131 GLfloat
*norm
= normal
->start
;
134 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
135 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
139 two_nu
= 2.0F
* DOT3(norm
,u
);
140 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
141 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
142 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
143 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
145 m
[i
] = 0.5F
* _mesa_inv_sqrtf(m
[i
]);
152 typedef void (*build_m_func
)( GLfloat f
[][3],
154 const GLvector4f
*normal
,
155 const GLvector4f
*eye
);
158 static build_m_func build_m_tab
[5] = {
167 /* This is unusual in that we respect the stride of the output vector
168 * (f). This allows us to pass in either a texcoord vector4f, or a
169 * temporary vector3f.
171 static void build_f3( GLfloat
*f
,
173 const GLvector4f
*normal
,
174 const GLvector4f
*eye
)
176 GLuint stride
= eye
->stride
;
177 GLfloat
*coord
= eye
->start
;
178 GLuint count
= eye
->count
;
180 GLfloat
*norm
= normal
->start
;
183 for (i
=0;i
<count
;i
++) {
184 GLfloat u
[3], two_nu
;
187 two_nu
= 2.0F
* DOT3(norm
,u
);
188 f
[0] = u
[0] - norm
[0] * two_nu
;
189 f
[1] = u
[1] - norm
[1] * two_nu
;
190 f
[2] = u
[2] - norm
[2] * two_nu
;
191 STRIDE_F(coord
,stride
);
193 STRIDE_F(norm
, normal
->stride
);
198 static void build_f2( GLfloat
*f
,
200 const GLvector4f
*normal
,
201 const GLvector4f
*eye
)
203 GLuint stride
= eye
->stride
;
204 GLfloat
*coord
= eye
->start
;
205 GLuint count
= eye
->count
;
206 GLfloat
*norm
= normal
->start
;
209 for (i
=0;i
<count
;i
++) {
211 GLfloat u
[3], two_nu
;
215 two_nu
= 2.0F
* DOT3(norm
,u
);
216 f
[0] = u
[0] - norm
[0] * two_nu
;
217 f
[1] = u
[1] - norm
[1] * two_nu
;
218 f
[2] = u
[2] - norm
[2] * two_nu
;
220 STRIDE_F(coord
,stride
);
222 STRIDE_F(norm
, normal
->stride
);
226 typedef void (*build_f_func
)( GLfloat
*f
,
228 const GLvector4f
*normal_vec
,
229 const GLvector4f
*eye
);
233 /* Just treat 4-vectors as 3-vectors.
235 static build_f_func build_f_tab
[5] = {
244 /* Special case texgen functions.
246 static void texgen_reflection_map_nv( GLcontext
*ctx
,
247 struct texgen_stage_data
*store
,
250 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
251 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
252 GLvector4f
*out
= &store
->texcoord
[unit
];
254 build_f_tab
[VB
->EyePtr
->size
]( out
->start
,
260 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
261 out
->count
= in
->count
;
262 out
->size
= MAX2(in
->size
, 3);
264 _mesa_copy_tab
[0x8]( out
, in
);
267 out
->flags
|= VEC_SIZE_3
;
269 out
->count
= in
->count
;
276 static void texgen_normal_map_nv( GLcontext
*ctx
,
277 struct texgen_stage_data
*store
,
280 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
281 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
282 GLvector4f
*out
= &store
->texcoord
[unit
];
283 GLvector4f
*normal
= VB
->NormalPtr
;
284 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->start
;
285 GLuint count
= VB
->Count
;
287 const GLfloat
*norm
= normal
->start
;
289 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
290 texcoord
[i
][0] = norm
[0];
291 texcoord
[i
][1] = norm
[1];
292 texcoord
[i
][2] = norm
[2];
297 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
298 out
->count
= in
->count
;
299 out
->size
= MAX2(in
->size
, 3);
301 _mesa_copy_tab
[0x8]( out
, in
);
304 out
->flags
|= VEC_SIZE_3
;
306 out
->count
= in
->count
;
311 static void texgen_sphere_map( GLcontext
*ctx
,
312 struct texgen_stage_data
*store
,
315 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
316 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
317 GLvector4f
*out
= &store
->texcoord
[unit
];
318 GLfloat (*texcoord
)[4] = (GLfloat (*)[4]) out
->start
;
319 GLuint count
= VB
->Count
;
321 GLfloat (*f
)[3] = store
->tmp_f
;
322 GLfloat
*m
= store
->tmp_m
;
324 /* _mesa_debug(NULL, "%s normstride %d eyestride %d\n", */
325 /* __FUNCTION__, VB->NormalPtr->stride, */
326 /* VB->EyePtr->stride); */
328 (build_m_tab
[VB
->EyePtr
->size
])( store
->tmp_f
,
333 for (i
=0;i
<count
;i
++) {
334 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
335 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
339 out
->size
= MAX2(in
->size
,2);
340 out
->count
= in
->count
;
341 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_2
;
343 _mesa_copy_tab
[all_bits
[in
->size
] & ~0x3]( out
, in
);
346 out
->flags
|= VEC_SIZE_2
;
347 out
->count
= in
->count
;
353 static void texgen( GLcontext
*ctx
,
354 struct texgen_stage_data
*store
,
357 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
358 struct vertex_buffer
*VB
= &tnl
->vb
;
359 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
360 GLvector4f
*out
= &store
->texcoord
[unit
];
361 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
362 const GLvector4f
*obj
= VB
->ObjPtr
;
363 const GLvector4f
*eye
= VB
->EyePtr
;
364 const GLvector4f
*normal
= VB
->NormalPtr
;
365 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->data
;
367 GLuint count
= VB
->Count
;
368 GLfloat (*f
)[3] = store
->tmp_f
;
369 GLfloat
*m
= store
->tmp_m
;
373 if (texUnit
->_GenFlags
& TEXGEN_NEED_M
) {
374 build_m_tab
[in
->size
]( store
->tmp_f
, store
->tmp_m
, normal
, eye
);
375 } else if (texUnit
->_GenFlags
& TEXGEN_NEED_F
) {
376 build_f_tab
[in
->size
]( (GLfloat
*)store
->tmp_f
, 3, normal
, eye
);
382 in
->count
= VB
->Count
;
384 out
->size
= store
->TexgenSize
[unit
];
385 out
->flags
|= texUnit
->TexGenEnabled
;
386 out
->count
= VB
->Count
;
387 holes
= store
->TexgenHoles
[unit
];
390 GLuint copy
= (all_bits
[in
->size
] & ~texUnit
->TexGenEnabled
);
392 _mesa_copy_tab
[copy
]( out
, in
);
394 out
->size
= MAX2(in
->size
, store
->TexgenSize
[unit
]);
395 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | texUnit
->TexGenEnabled
;
396 out
->count
= in
->count
;
398 holes
= ~all_bits
[in
->size
] & store
->TexgenHoles
[unit
];
402 if (holes
& VEC_DIRTY_3
) _mesa_vector4f_clean_elem(out
, count
, 3);
403 if (holes
& VEC_DIRTY_2
) _mesa_vector4f_clean_elem(out
, count
, 2);
404 if (holes
& VEC_DIRTY_1
) _mesa_vector4f_clean_elem(out
, count
, 1);
405 if (holes
& VEC_DIRTY_0
) _mesa_vector4f_clean_elem(out
, count
, 0);
408 if (texUnit
->TexGenEnabled
& S_BIT
) {
410 switch (texUnit
->GenModeS
) {
411 case GL_OBJECT_LINEAR
:
412 _mesa_dotprod_tab
[obj
->size
]( (GLfloat
*)out
->data
,
413 sizeof(out
->data
[0]), obj
,
414 texUnit
->ObjectPlaneS
);
417 _mesa_dotprod_tab
[eye
->size
]( (GLfloat
*)out
->data
,
418 sizeof(out
->data
[0]), eye
,
419 texUnit
->EyePlaneS
);
422 for (indata
=in
->start
,i
=0 ; i
<count
;i
++, STRIDE_F(indata
,in
->stride
))
423 texcoord
[i
][0] = indata
[0] * m
[i
] + 0.5F
;
425 case GL_REFLECTION_MAP_NV
:
426 for (i
=0;i
<count
;i
++)
427 texcoord
[i
][0] = f
[i
][0];
429 case GL_NORMAL_MAP_NV
: {
430 const GLfloat
*norm
= normal
->start
;
431 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
432 texcoord
[i
][0] = norm
[0];
437 _mesa_problem(ctx
, "Bad S texgen");
441 if (texUnit
->TexGenEnabled
& T_BIT
) {
443 switch (texUnit
->GenModeT
) {
444 case GL_OBJECT_LINEAR
:
445 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][1]),
446 sizeof(out
->data
[0]), obj
,
447 texUnit
->ObjectPlaneT
);
450 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][1]),
451 sizeof(out
->data
[0]), eye
,
452 texUnit
->EyePlaneT
);
455 for (indata
=in
->start
,i
=0; i
<count
;i
++,STRIDE_F(indata
,in
->stride
))
456 texcoord
[i
][1] = indata
[1] * m
[i
] + 0.5F
;
458 case GL_REFLECTION_MAP_NV
:
459 for (i
=0;i
<count
;i
++)
460 texcoord
[i
][0] = f
[i
][0];
462 case GL_NORMAL_MAP_NV
: {
463 const GLfloat
*norm
= normal
->start
;
464 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
465 texcoord
[i
][1] = norm
[1];
470 _mesa_problem(ctx
, "Bad T texgen");
474 if (texUnit
->TexGenEnabled
& R_BIT
) {
476 switch (texUnit
->GenModeR
) {
477 case GL_OBJECT_LINEAR
:
478 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][2]),
479 sizeof(out
->data
[0]), obj
,
480 texUnit
->ObjectPlaneR
);
483 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][2]),
484 sizeof(out
->data
[0]), eye
,
485 texUnit
->EyePlaneR
);
487 case GL_REFLECTION_MAP_NV
:
488 for (i
=0;i
<count
;i
++)
489 texcoord
[i
][2] = f
[i
][2];
491 case GL_NORMAL_MAP_NV
: {
492 const GLfloat
*norm
= normal
->start
;
493 for (i
=0;i
<count
;i
++,STRIDE_F(norm
, normal
->stride
)) {
494 texcoord
[i
][2] = norm
[2];
499 _mesa_problem(ctx
, "Bad R texgen");
503 if (texUnit
->TexGenEnabled
& Q_BIT
) {
504 switch (texUnit
->GenModeQ
) {
505 case GL_OBJECT_LINEAR
:
506 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][3]),
507 sizeof(out
->data
[0]), obj
,
508 texUnit
->ObjectPlaneQ
);
511 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][3]),
512 sizeof(out
->data
[0]), eye
,
513 texUnit
->EyePlaneQ
);
516 _mesa_problem(ctx
, "Bad Q texgen");
523 static GLboolean
run_texgen_stage( GLcontext
*ctx
,
524 struct gl_pipeline_stage
*stage
)
526 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
527 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA( stage
);
530 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++)
531 if (ctx
->Texture
._TexGenEnabled
& ENABLE_TEXGEN(i
)) {
532 if (stage
->changed_inputs
& (VERT_BIT_EYE
| VERT_BIT_NORMAL
| VERT_BIT_TEX(i
)))
533 store
->TexgenFunc
[i
]( ctx
, store
, i
);
535 VB
->TexCoordPtr
[i
] = &store
->texcoord
[i
];
544 static GLboolean
run_validate_texgen_stage( GLcontext
*ctx
,
545 struct gl_pipeline_stage
*stage
)
547 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
550 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
551 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
553 if (texUnit
->TexGenEnabled
) {
556 if (texUnit
->TexGenEnabled
& R_BIT
)
558 else if (texUnit
->TexGenEnabled
& Q_BIT
)
560 else if (texUnit
->TexGenEnabled
& T_BIT
)
565 store
->TexgenSize
[i
] = sz
;
566 store
->TexgenHoles
[i
] = (all_bits
[sz
] & ~texUnit
->TexGenEnabled
);
567 store
->TexgenFunc
[i
] = texgen
;
569 if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
|R_BIT
)) {
570 if (texUnit
->_GenFlags
== TEXGEN_REFLECTION_MAP_NV
) {
571 store
->TexgenFunc
[i
] = texgen_reflection_map_nv
;
573 else if (texUnit
->_GenFlags
== TEXGEN_NORMAL_MAP_NV
) {
574 store
->TexgenFunc
[i
] = texgen_normal_map_nv
;
577 else if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
) &&
578 texUnit
->_GenFlags
== TEXGEN_SPHERE_MAP
) {
579 store
->TexgenFunc
[i
] = texgen_sphere_map
;
584 stage
->run
= run_texgen_stage
;
585 return stage
->run( ctx
, stage
);
589 static void check_texgen( GLcontext
*ctx
, struct gl_pipeline_stage
*stage
)
594 if (ctx
->Texture
._TexGenEnabled
&& !ctx
->VertexProgram
.Enabled
) {
598 if (ctx
->Texture
._GenFlags
& TEXGEN_OBJ_LINEAR
)
599 inputs
|= VERT_BIT_POS
;
601 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_EYE_COORD
)
602 inputs
|= VERT_BIT_EYE
;
604 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_NORMALS
)
605 inputs
|= VERT_BIT_NORMAL
;
607 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++)
608 if (ctx
->Texture
._TexGenEnabled
& ENABLE_TEXGEN(i
))
610 outputs
|= VERT_BIT_TEX(i
);
612 /* Need the original input in case it contains a Q coord:
615 inputs
|= VERT_BIT_TEX(i
);
617 /* Something for Feedback? */
620 if (stage
->privatePtr
)
621 stage
->run
= run_validate_texgen_stage
;
623 stage
->inputs
= inputs
;
624 stage
->outputs
= outputs
;
631 /* Called the first time stage->run() is invoked.
633 static GLboolean
alloc_texgen_data( GLcontext
*ctx
,
634 struct gl_pipeline_stage
*stage
)
636 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
637 struct texgen_stage_data
*store
;
640 stage
->privatePtr
= CALLOC(sizeof(*store
));
641 store
= TEXGEN_STAGE_DATA(stage
);
645 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++)
646 _mesa_vector4f_alloc( &store
->texcoord
[i
], 0, VB
->Size
, 32 );
648 store
->tmp_f
= (GLfloat (*)[3]) MALLOC(VB
->Size
* sizeof(GLfloat
) * 3);
649 store
->tmp_m
= (GLfloat
*) MALLOC(VB
->Size
* sizeof(GLfloat
));
651 /* Now validate and run the stage.
653 stage
->run
= run_validate_texgen_stage
;
654 return stage
->run( ctx
, stage
);
658 static void free_texgen_data( struct gl_pipeline_stage
*stage
)
661 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
665 for (i
= 0 ; i
< MAX_TEXTURE_COORD_UNITS
; i
++)
666 if (store
->texcoord
[i
].data
)
667 _mesa_vector4f_free( &store
->texcoord
[i
] );
670 if (store
->tmp_f
) FREE( store
->tmp_f
);
671 if (store
->tmp_m
) FREE( store
->tmp_m
);
673 stage
->privatePtr
= NULL
;
679 const struct gl_pipeline_stage _tnl_texgen_stage
=
682 _NEW_TEXTURE
, /* when to call check() */
683 _NEW_TEXTURE
, /* when to invalidate stored data */
684 GL_FALSE
, /* active? */
687 0, /* changed_inputs */
688 NULL
, /* private data */
689 free_texgen_data
, /* destructor */
690 check_texgen
, /* check */
691 alloc_texgen_data
/* run -- initially set to alloc data */