1 /* $Id: t_vb_texgen.c,v 1.6 2001/03/12 00:48:44 gareth Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 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.
27 * Brian Paul <brian@valinux.com>
28 * Keith Whitwell <keithw@valinux.com>
40 #include "math/m_xform.h"
42 #include "t_context.h"
43 #include "t_pipeline.h"
46 /***********************************************************************
47 * Automatic texture coordinate generation (texgen) code.
51 struct texgen_stage_data
;
53 typedef void (*texgen_func
)( GLcontext
*ctx
,
54 struct texgen_stage_data
*store
,
58 struct texgen_stage_data
{
60 /* Per-texunit derived state.
62 GLuint TexgenSize
[MAX_TEXTURE_UNITS
];
63 GLuint TexgenHoles
[MAX_TEXTURE_UNITS
];
64 texgen_func TexgenFunc
[MAX_TEXTURE_UNITS
];
66 /* Temporary values used in texgen.
71 /* Buffered outputs of the stage.
73 GLvector4f texcoord
[MAX_TEXTURE_UNITS
];
77 #define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
82 static GLuint all_bits
[5] = {
90 #define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
94 static void build_m3(GLfloat f
[][3], GLfloat m
[],
95 const GLvector3f
*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
;
105 /* KW: Had to rearrange this loop to avoid a compiler bug with gcc
106 * 2.7.3.1 at -O3 optimization. Using -fno-strength-reduce
107 * also fixed the bug - is this generally necessary?
109 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,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
/ (GLfloat
) GL_SQRT(m
[i
]);
122 STRIDE_F(norm
, normal
->stride
);
128 static void build_m2(GLfloat f
[][3], GLfloat m
[],
129 const GLvector3f
*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
)) {
141 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
145 two_nu
= 2.0F
* DOT3(norm
,u
);
146 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
147 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
148 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
149 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
151 m
[i
] = 0.5F
/ (GLfloat
) GL_SQRT(m
[i
]);
154 STRIDE_F(norm
, normal
->stride
);
160 typedef void (*build_m_func
)(GLfloat f
[][3],
162 const GLvector3f
*normal
,
163 const GLvector4f
*eye
);
167 static build_m_func build_m_tab
[5] = {
176 /* This is unusual in that we respect the stride of the output vector
177 * (f). This allows us to pass in either a texcoord vector4f, or a
178 * temporary vector3f.
180 static void build_f3( GLfloat
*f
,
182 const GLvector3f
*normal
,
183 const GLvector4f
*eye
)
185 GLuint stride
= eye
->stride
;
186 GLfloat
*coord
= eye
->start
;
187 GLuint count
= eye
->count
;
189 GLfloat
*norm
= normal
->start
;
192 for (i
=0;i
<count
;i
++) {
193 GLfloat u
[3], two_nu
;
196 two_nu
= 2.0F
* DOT3(norm
,u
);
197 f
[0] = u
[0] - norm
[0] * two_nu
;
198 f
[1] = u
[1] - norm
[1] * two_nu
;
199 f
[2] = u
[2] - norm
[2] * two_nu
;
200 STRIDE_F(coord
,stride
);
202 STRIDE_F(norm
, normal
->stride
);
207 static void build_f2( GLfloat
*f
,
209 const GLvector3f
*normal
,
210 const GLvector4f
*eye
)
212 GLuint stride
= eye
->stride
;
213 GLfloat
*coord
= eye
->start
;
214 GLuint count
= eye
->count
;
215 GLfloat
*norm
= normal
->start
;
218 for (i
=0;i
<count
;i
++) {
220 GLfloat u
[3], two_nu
;
224 two_nu
= 2.0F
* DOT3(norm
,u
);
225 f
[0] = u
[0] - norm
[0] * two_nu
;
226 f
[1] = u
[1] - norm
[1] * two_nu
;
227 f
[2] = u
[2] - norm
[2] * two_nu
;
229 STRIDE_F(coord
,stride
);
231 STRIDE_F(norm
, normal
->stride
);
235 typedef void (*build_f_func
)( GLfloat
*f
,
237 const GLvector3f
*normal_vec
,
238 const GLvector4f
*eye
);
242 /* Just treat 4-vectors as 3-vectors.
244 static build_f_func build_f_tab
[5] = {
253 /* Special case texgen functions.
255 static void texgen_reflection_map_nv( GLcontext
*ctx
,
256 struct texgen_stage_data
*store
,
259 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
260 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
261 GLvector4f
*out
= &store
->texcoord
[unit
];
263 build_f_tab
[VB
->EyePtr
->size
]( out
->start
,
269 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
270 out
->count
= in
->count
;
271 out
->size
= MAX2(in
->size
, 3);
273 _mesa_copy_tab
[0][0x8](out
, in
, 0);
276 out
->flags
|= VEC_SIZE_3
;
278 out
->count
= in
->count
;
285 static void texgen_normal_map_nv( GLcontext
*ctx
,
286 struct texgen_stage_data
*store
,
289 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
290 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
291 GLvector4f
*out
= &store
->texcoord
[unit
];
292 GLvector3f
*normal
= VB
->NormalPtr
;
293 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->start
;
294 GLuint count
= VB
->Count
;
296 const GLfloat
*norm
= normal
->start
;
298 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
299 texcoord
[i
][0] = norm
[0];
300 texcoord
[i
][1] = norm
[1];
301 texcoord
[i
][2] = norm
[2];
306 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
307 out
->count
= in
->count
;
308 out
->size
= MAX2(in
->size
, 3);
310 _mesa_copy_tab
[0][0x8](out
, in
, 0);
313 out
->flags
|= VEC_SIZE_3
;
315 out
->count
= in
->count
;
320 static void texgen_sphere_map( GLcontext
*ctx
,
321 struct texgen_stage_data
*store
,
324 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
325 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
326 GLvector4f
*out
= &store
->texcoord
[unit
];
327 GLfloat (*texcoord
)[4] = (GLfloat (*)[4]) out
->start
;
328 GLuint count
= VB
->Count
;
330 GLfloat (*f
)[3] = store
->tmp_f
;
331 GLfloat
*m
= store
->tmp_m
;
333 (build_m_tab
[VB
->EyePtr
->size
])( store
->tmp_f
,
338 for (i
=0;i
<count
;i
++) {
339 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
340 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
344 out
->size
= MAX2(in
->size
,2);
345 out
->count
= in
->count
;
346 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_2
;
348 _mesa_copy_tab
[0][all_bits
[in
->size
] & ~0x3](out
, in
, 0);
351 out
->flags
|= VEC_SIZE_2
;
352 out
->count
= in
->count
;
358 static void texgen( GLcontext
*ctx
,
359 struct texgen_stage_data
*store
,
362 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
363 struct vertex_buffer
*VB
= &tnl
->vb
;
364 GLvector4f
*in
= VB
->TexCoordPtr
[unit
];
365 GLvector4f
*out
= &store
->texcoord
[unit
];
366 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
367 const GLvector4f
*obj
= VB
->ObjPtr
;
368 const GLvector4f
*eye
= VB
->EyePtr
;
369 const GLvector3f
*normal
= VB
->NormalPtr
;
370 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->data
;
372 GLuint count
= VB
->Count
;
373 GLfloat (*f
)[3] = store
->tmp_f
;
374 GLfloat
*m
= store
->tmp_m
;
378 if (texUnit
->_GenFlags
& TEXGEN_NEED_M
) {
379 build_m_tab
[in
->size
]( store
->tmp_f
, store
->tmp_m
, normal
, eye
);
380 } else if (texUnit
->_GenFlags
& TEXGEN_NEED_F
) {
381 build_f_tab
[in
->size
]( (GLfloat
*)store
->tmp_f
, 3, normal
, eye
);
387 in
->count
= VB
->Count
;
389 out
->size
= store
->TexgenSize
[unit
];
390 out
->flags
|= texUnit
->TexGenEnabled
;
391 out
->count
= VB
->Count
;
392 holes
= store
->TexgenHoles
[unit
];
395 GLuint copy
= (all_bits
[in
->size
] & ~texUnit
->TexGenEnabled
);
397 _mesa_copy_tab
[0][copy
](out
, in
, 0);
399 out
->size
= MAX2(in
->size
, store
->TexgenSize
[unit
]);
400 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | texUnit
->TexGenEnabled
;
401 out
->count
= in
->count
;
403 holes
= ~all_bits
[in
->size
] & store
->TexgenHoles
[unit
];
407 if (holes
& VEC_DIRTY_2
) _mesa_vector4f_clean_elem(out
, count
, 2);
408 if (holes
& VEC_DIRTY_1
) _mesa_vector4f_clean_elem(out
, count
, 1);
409 if (holes
& VEC_DIRTY_0
) _mesa_vector4f_clean_elem(out
, count
, 0);
412 if (texUnit
->TexGenEnabled
& S_BIT
) {
414 switch (texUnit
->GenModeS
) {
415 case GL_OBJECT_LINEAR
:
416 (_mesa_dotprod_tab
[0][obj
->size
])((GLfloat
*)out
->data
,
417 sizeof(out
->data
[0]), obj
,
418 texUnit
->ObjectPlaneS
, 0);
421 (_mesa_dotprod_tab
[0][eye
->size
])((GLfloat
*)out
->data
,
422 sizeof(out
->data
[0]), eye
,
423 texUnit
->EyePlaneS
, 0);
426 for (indata
=in
->start
,i
=0 ; i
<count
;i
++, STRIDE_F(indata
,in
->stride
))
427 texcoord
[i
][0] = indata
[0] * m
[i
] + 0.5F
;
429 case GL_REFLECTION_MAP_NV
:
430 for (i
=0;i
<count
;i
++)
431 texcoord
[i
][0] = f
[i
][0];
433 case GL_NORMAL_MAP_NV
: {
434 const GLfloat
*norm
= normal
->start
;
435 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
436 texcoord
[i
][0] = norm
[0];
441 _mesa_problem(ctx
, "Bad S texgen");
445 if (texUnit
->TexGenEnabled
& T_BIT
) {
447 switch (texUnit
->GenModeT
) {
448 case GL_OBJECT_LINEAR
:
449 (_mesa_dotprod_tab
[0][obj
->size
])(&(out
->data
[0][1]),
450 sizeof(out
->data
[0]), obj
,
451 texUnit
->ObjectPlaneT
, 0);
454 (_mesa_dotprod_tab
[0][eye
->size
])(&(out
->data
[0][1]),
455 sizeof(out
->data
[0]), eye
,
456 texUnit
->EyePlaneT
, 0);
459 for (indata
=in
->start
,i
=0; i
<count
;i
++,STRIDE_F(indata
,in
->stride
))
460 texcoord
[i
][1] = indata
[1] * m
[i
] + 0.5F
;
462 case GL_REFLECTION_MAP_NV
:
463 for (i
=0;i
<count
;i
++)
464 texcoord
[i
][0] = f
[i
][0];
466 case GL_NORMAL_MAP_NV
: {
467 const GLfloat
*norm
= normal
->start
;
468 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
469 texcoord
[i
][1] = norm
[1];
474 _mesa_problem(ctx
, "Bad T texgen");
478 if (texUnit
->TexGenEnabled
& R_BIT
) {
480 switch (texUnit
->GenModeR
) {
481 case GL_OBJECT_LINEAR
:
482 (_mesa_dotprod_tab
[0][obj
->size
])(&(out
->data
[0][2]),
483 sizeof(out
->data
[0]), obj
,
484 texUnit
->ObjectPlaneR
, 0);
487 (_mesa_dotprod_tab
[0][eye
->size
])(&(out
->data
[0][2]),
488 sizeof(out
->data
[0]), eye
,
489 texUnit
->EyePlaneR
, 0);
491 case GL_REFLECTION_MAP_NV
:
492 for (i
=0;i
<count
;i
++)
493 texcoord
[i
][2] = f
[i
][2];
495 case GL_NORMAL_MAP_NV
: {
496 const GLfloat
*norm
= normal
->start
;
497 for (i
=0;i
<count
;i
++,STRIDE_F(norm
, normal
->stride
)) {
498 texcoord
[i
][2] = norm
[2];
503 _mesa_problem(ctx
, "Bad R texgen");
507 if (texUnit
->TexGenEnabled
& Q_BIT
) {
508 switch (texUnit
->GenModeQ
) {
509 case GL_OBJECT_LINEAR
:
510 (_mesa_dotprod_tab
[0][obj
->size
])(&(out
->data
[0][3]),
511 sizeof(out
->data
[0]), obj
,
512 texUnit
->ObjectPlaneQ
, 0);
515 (_mesa_dotprod_tab
[0][eye
->size
])(&(out
->data
[0][3]),
516 sizeof(out
->data
[0]), eye
,
517 texUnit
->EyePlaneQ
, 0);
520 _mesa_problem(ctx
, "Bad Q texgen");
527 static GLboolean
run_texgen_stage( GLcontext
*ctx
,
528 struct gl_pipeline_stage
*stage
)
530 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
531 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA( stage
);
534 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++)
535 if (ctx
->_Enabled
& ENABLE_TEXGEN(i
)) {
536 if (stage
->changed_inputs
& (VERT_EYE
| VERT_NORM
| VERT_TEX(i
)))
537 store
->TexgenFunc
[i
]( ctx
, store
, i
);
539 VB
->TexCoordPtr
[i
] = &store
->texcoord
[i
];
548 static GLboolean
run_validate_texgen_stage( GLcontext
*ctx
,
549 struct gl_pipeline_stage
*stage
)
551 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
554 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
555 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
557 if (texUnit
->TexGenEnabled
) {
560 if (texUnit
->TexGenEnabled
& R_BIT
)
562 else if (texUnit
->TexGenEnabled
& Q_BIT
)
564 else if (texUnit
->TexGenEnabled
& T_BIT
)
569 store
->TexgenSize
[i
] = sz
;
570 store
->TexgenHoles
[i
] = (all_bits
[sz
] & ~texUnit
->TexGenEnabled
);
571 store
->TexgenFunc
[i
] = texgen
;
573 if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
|R_BIT
)) {
574 if (texUnit
->_GenFlags
== TEXGEN_REFLECTION_MAP_NV
) {
575 store
->TexgenFunc
[i
] = texgen_reflection_map_nv
;
577 else if (texUnit
->_GenFlags
== TEXGEN_NORMAL_MAP_NV
) {
578 store
->TexgenFunc
[i
] = texgen_normal_map_nv
;
581 else if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
) &&
582 texUnit
->_GenFlags
== TEXGEN_SPHERE_MAP
) {
583 store
->TexgenFunc
[i
] = texgen_sphere_map
;
588 stage
->run
= run_texgen_stage
;
589 return stage
->run( ctx
, stage
);
593 static void check_texgen( GLcontext
*ctx
, struct gl_pipeline_stage
*stage
)
598 if (ctx
->_Enabled
& ENABLE_TEXGEN_ANY
) {
602 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_VERTICES
)
605 if (ctx
->Texture
._GenFlags
& TEXGEN_NEED_NORMALS
)
608 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++)
609 if (ctx
->_Enabled
& ENABLE_TEXGEN(i
))
611 outputs
|= VERT_TEX(i
);
613 /* Need the original input in case it contains a Q coord:
616 /* if ((ctx->Texture.Unit[i]._ReallyEnabled|Q_BIT) & */
617 /* ~ctx->Texture.Unit[i].TexGenEnabled) */
618 inputs
|= VERT_TEX(i
);
620 /* Something for Feedback? */
623 if (stage
->privatePtr
)
624 stage
->run
= run_validate_texgen_stage
;
626 stage
->inputs
= inputs
;
627 stage
->outputs
= outputs
;
634 /* Called the first time stage->run() is invoked.
636 static GLboolean
alloc_texgen_data( GLcontext
*ctx
,
637 struct gl_pipeline_stage
*stage
)
639 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
640 struct texgen_stage_data
*store
;
643 stage
->privatePtr
= CALLOC(sizeof(*store
));
644 store
= TEXGEN_STAGE_DATA(stage
);
648 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++)
649 _mesa_vector4f_alloc( &store
->texcoord
[i
], 0, VB
->Size
, 32 );
651 store
->tmp_f
= (GLfloat (*)[3]) MALLOC(VB
->Size
* sizeof(GLfloat
) * 3);
652 store
->tmp_m
= (GLfloat
*) MALLOC(VB
->Size
* sizeof(GLfloat
));
654 /* Now validate and run the stage.
656 stage
->run
= run_validate_texgen_stage
;
657 return stage
->run( ctx
, stage
);
661 static void free_texgen_data( struct gl_pipeline_stage
*stage
)
664 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
668 for (i
= 0 ; i
< MAX_TEXTURE_UNITS
; i
++)
669 if (store
->texcoord
[i
].data
)
670 _mesa_vector4f_free( &store
->texcoord
[i
] );
673 if (store
->tmp_f
) FREE( store
->tmp_f
);
674 if (store
->tmp_m
) FREE( store
->tmp_m
);
676 stage
->privatePtr
= NULL
;
682 const struct gl_pipeline_stage _tnl_texgen_stage
=
685 _NEW_TEXTURE
, /* when to call check() */
686 _NEW_TEXTURE
, /* when to invalidate stored data */
687 0,0,0, /* active, inputs, outputs */
688 0,0, /* changed_inputs, private */
689 free_texgen_data
, /* destructor */
690 check_texgen
, /* check */
691 alloc_texgen_data
/* run -- initially set to alloc data */