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/glheader.h"
38 #include "main/macros.h"
39 #include "main/imports.h"
40 #include "main/mtypes.h"
42 #include "math/m_xform.h"
44 #include "t_context.h"
45 #include "t_pipeline.h"
48 /***********************************************************************
49 * Automatic texture coordinate generation (texgen) code.
53 struct texgen_stage_data
;
55 typedef void (*texgen_func
)( struct gl_context
*ctx
,
56 struct texgen_stage_data
*store
,
60 struct texgen_stage_data
{
62 /* Per-texunit derived state.
64 GLuint TexgenSize
[MAX_TEXTURE_COORD_UNITS
];
65 texgen_func TexgenFunc
[MAX_TEXTURE_COORD_UNITS
];
67 /* Temporary values used in texgen.
72 /* Buffered outputs of the stage.
74 GLvector4f texcoord
[MAX_TEXTURE_COORD_UNITS
];
78 #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)
92 #define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP)
93 #define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \
94 TEXGEN_REFLECTION_MAP_NV)
98 static void build_m3( GLfloat f
[][3], GLfloat m
[],
99 const GLvector4f
*normal
,
100 const GLvector4f
*eye
)
102 GLuint stride
= eye
->stride
;
103 GLfloat
*coord
= (GLfloat
*)eye
->start
;
104 GLuint count
= eye
->count
;
105 const GLfloat
*norm
= normal
->start
;
108 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
109 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
112 two_nu
= 2.0F
* DOT3(norm
,u
);
113 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
114 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
115 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
116 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
118 m
[i
] = 0.5F
* (1.0f
/ sqrtf(m
[i
]));
125 static void build_m2( GLfloat f
[][3], GLfloat m
[],
126 const GLvector4f
*normal
,
127 const GLvector4f
*eye
)
129 GLuint stride
= eye
->stride
;
130 GLfloat
*coord
= eye
->start
;
131 GLuint count
= eye
->count
;
133 GLfloat
*norm
= normal
->start
;
136 for (i
=0;i
<count
;i
++,STRIDE_F(coord
,stride
),STRIDE_F(norm
,normal
->stride
)) {
137 GLfloat u
[3], two_nu
, fx
, fy
, fz
;
141 two_nu
= 2.0F
* DOT3(norm
,u
);
142 fx
= f
[i
][0] = u
[0] - norm
[0] * two_nu
;
143 fy
= f
[i
][1] = u
[1] - norm
[1] * two_nu
;
144 fz
= f
[i
][2] = u
[2] - norm
[2] * two_nu
;
145 m
[i
] = fx
* fx
+ fy
* fy
+ (fz
+ 1.0F
) * (fz
+ 1.0F
);
147 m
[i
] = 0.5F
* (1.0f
/ sqrtf(m
[i
]));
154 typedef void (*build_m_func
)( GLfloat f
[][3],
156 const GLvector4f
*normal
,
157 const GLvector4f
*eye
);
160 static build_m_func build_m_tab
[5] = {
169 /* This is unusual in that we respect the stride of the output vector
170 * (f). This allows us to pass in either a texcoord vector4f, or a
171 * temporary vector3f.
173 static void build_f3( GLfloat
*f
,
175 const GLvector4f
*normal
,
176 const GLvector4f
*eye
)
178 GLuint stride
= eye
->stride
;
179 GLfloat
*coord
= eye
->start
;
180 GLuint count
= eye
->count
;
182 GLfloat
*norm
= normal
->start
;
185 for (i
=0;i
<count
;i
++) {
186 GLfloat u
[3], two_nu
;
189 two_nu
= 2.0F
* DOT3(norm
,u
);
190 f
[0] = u
[0] - norm
[0] * two_nu
;
191 f
[1] = u
[1] - norm
[1] * two_nu
;
192 f
[2] = u
[2] - norm
[2] * two_nu
;
193 STRIDE_F(coord
,stride
);
195 STRIDE_F(norm
, normal
->stride
);
200 static void build_f2( GLfloat
*f
,
202 const GLvector4f
*normal
,
203 const GLvector4f
*eye
)
205 GLuint stride
= eye
->stride
;
206 GLfloat
*coord
= eye
->start
;
207 GLuint count
= eye
->count
;
208 GLfloat
*norm
= normal
->start
;
211 for (i
=0;i
<count
;i
++) {
213 GLfloat u
[3], two_nu
;
217 two_nu
= 2.0F
* DOT3(norm
,u
);
218 f
[0] = u
[0] - norm
[0] * two_nu
;
219 f
[1] = u
[1] - norm
[1] * two_nu
;
220 f
[2] = u
[2] - norm
[2] * two_nu
;
222 STRIDE_F(coord
,stride
);
224 STRIDE_F(norm
, normal
->stride
);
228 typedef void (*build_f_func
)( GLfloat
*f
,
230 const GLvector4f
*normal_vec
,
231 const GLvector4f
*eye
);
235 /* Just treat 4-vectors as 3-vectors.
237 static build_f_func build_f_tab
[5] = {
247 /* Special case texgen functions.
249 static void texgen_reflection_map_nv( struct gl_context
*ctx
,
250 struct texgen_stage_data
*store
,
253 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
254 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
255 GLvector4f
*out
= &store
->texcoord
[unit
];
257 build_f_tab
[VB
->EyePtr
->size
]( out
->start
,
259 VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
],
262 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
263 out
->count
= VB
->Count
;
264 out
->size
= MAX2(in
->size
, 3);
266 _mesa_copy_tab
[0x8]( out
, in
);
271 static void texgen_normal_map_nv( struct gl_context
*ctx
,
272 struct texgen_stage_data
*store
,
275 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
276 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
277 GLvector4f
*out
= &store
->texcoord
[unit
];
278 GLvector4f
*normal
= VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
];
279 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->start
;
280 GLuint count
= VB
->Count
;
282 const GLfloat
*norm
= normal
->start
;
284 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
285 texcoord
[i
][0] = norm
[0];
286 texcoord
[i
][1] = norm
[1];
287 texcoord
[i
][2] = norm
[2];
291 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_3
;
293 out
->size
= MAX2(in
->size
, 3);
295 _mesa_copy_tab
[0x8]( out
, in
);
299 static void texgen_sphere_map( struct gl_context
*ctx
,
300 struct texgen_stage_data
*store
,
303 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
304 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
305 GLvector4f
*out
= &store
->texcoord
[unit
];
306 GLfloat (*texcoord
)[4] = (GLfloat (*)[4]) out
->start
;
307 GLuint count
= VB
->Count
;
309 GLfloat (*f
)[3] = store
->tmp_f
;
310 GLfloat
*m
= store
->tmp_m
;
312 (build_m_tab
[VB
->EyePtr
->size
])( store
->tmp_f
,
314 VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
],
317 out
->size
= MAX2(in
->size
,2);
319 for (i
=0;i
<count
;i
++) {
320 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
321 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
325 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | VEC_SIZE_2
;
327 _mesa_copy_tab
[all_bits
[in
->size
] & ~0x3]( out
, in
);
332 static void texgen( struct gl_context
*ctx
,
333 struct texgen_stage_data
*store
,
336 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
337 struct vertex_buffer
*VB
= &tnl
->vb
;
338 GLvector4f
*in
= VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ unit
];
339 GLvector4f
*out
= &store
->texcoord
[unit
];
340 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
341 const GLvector4f
*obj
= VB
->AttribPtr
[_TNL_ATTRIB_POS
];
342 const GLvector4f
*eye
= VB
->EyePtr
;
343 const GLvector4f
*normal
= VB
->AttribPtr
[_TNL_ATTRIB_NORMAL
];
344 const GLfloat
*m
= store
->tmp_m
;
345 const GLuint count
= VB
->Count
;
346 GLfloat (*texcoord
)[4] = (GLfloat (*)[4])out
->data
;
347 GLfloat (*f
)[3] = store
->tmp_f
;
350 if (texUnit
->_GenFlags
& TEXGEN_NEED_M
) {
351 build_m_tab
[eye
->size
]( store
->tmp_f
, store
->tmp_m
, normal
, eye
);
352 } else if (texUnit
->_GenFlags
& TEXGEN_NEED_F
) {
353 build_f_tab
[eye
->size
]( (GLfloat
*)store
->tmp_f
, 3, normal
, eye
);
357 out
->size
= MAX2(in
->size
, store
->TexgenSize
[unit
]);
358 out
->flags
|= (in
->flags
& VEC_SIZE_FLAGS
) | texUnit
->TexGenEnabled
;
361 copy
= (all_bits
[in
->size
] & ~texUnit
->TexGenEnabled
);
363 _mesa_copy_tab
[copy
]( out
, in
);
365 if (texUnit
->TexGenEnabled
& S_BIT
) {
367 switch (texUnit
->GenS
.Mode
) {
368 case GL_OBJECT_LINEAR
:
369 _mesa_dotprod_tab
[obj
->size
]( (GLfloat
*)out
->data
,
370 sizeof(out
->data
[0]), obj
,
371 texUnit
->GenS
.ObjectPlane
);
374 _mesa_dotprod_tab
[eye
->size
]( (GLfloat
*)out
->data
,
375 sizeof(out
->data
[0]), eye
,
376 texUnit
->GenS
.EyePlane
);
379 for (i
= 0; i
< count
; i
++)
380 texcoord
[i
][0] = f
[i
][0] * m
[i
] + 0.5F
;
382 case GL_REFLECTION_MAP_NV
:
383 for (i
=0;i
<count
;i
++)
384 texcoord
[i
][0] = f
[i
][0];
386 case GL_NORMAL_MAP_NV
: {
387 const GLfloat
*norm
= normal
->start
;
388 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
389 texcoord
[i
][0] = norm
[0];
394 _mesa_problem(ctx
, "Bad S texgen");
398 if (texUnit
->TexGenEnabled
& T_BIT
) {
400 switch (texUnit
->GenT
.Mode
) {
401 case GL_OBJECT_LINEAR
:
402 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][1]),
403 sizeof(out
->data
[0]), obj
,
404 texUnit
->GenT
.ObjectPlane
);
407 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][1]),
408 sizeof(out
->data
[0]), eye
,
409 texUnit
->GenT
.EyePlane
);
412 for (i
= 0; i
< count
; i
++)
413 texcoord
[i
][1] = f
[i
][1] * m
[i
] + 0.5F
;
415 case GL_REFLECTION_MAP_NV
:
416 for (i
=0;i
<count
;i
++)
417 texcoord
[i
][1] = f
[i
][1];
419 case GL_NORMAL_MAP_NV
: {
420 const GLfloat
*norm
= normal
->start
;
421 for (i
=0;i
<count
;i
++, STRIDE_F(norm
, normal
->stride
)) {
422 texcoord
[i
][1] = norm
[1];
427 _mesa_problem(ctx
, "Bad T texgen");
431 if (texUnit
->TexGenEnabled
& R_BIT
) {
433 switch (texUnit
->GenR
.Mode
) {
434 case GL_OBJECT_LINEAR
:
435 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][2]),
436 sizeof(out
->data
[0]), obj
,
437 texUnit
->GenR
.ObjectPlane
);
440 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][2]),
441 sizeof(out
->data
[0]), eye
,
442 texUnit
->GenR
.EyePlane
);
444 case GL_REFLECTION_MAP_NV
:
445 for (i
=0;i
<count
;i
++)
446 texcoord
[i
][2] = f
[i
][2];
448 case GL_NORMAL_MAP_NV
: {
449 const GLfloat
*norm
= normal
->start
;
450 for (i
=0;i
<count
;i
++,STRIDE_F(norm
, normal
->stride
)) {
451 texcoord
[i
][2] = norm
[2];
456 _mesa_problem(ctx
, "Bad R texgen");
460 if (texUnit
->TexGenEnabled
& Q_BIT
) {
461 switch (texUnit
->GenQ
.Mode
) {
462 case GL_OBJECT_LINEAR
:
463 _mesa_dotprod_tab
[obj
->size
]( &(out
->data
[0][3]),
464 sizeof(out
->data
[0]), obj
,
465 texUnit
->GenQ
.ObjectPlane
);
468 _mesa_dotprod_tab
[eye
->size
]( &(out
->data
[0][3]),
469 sizeof(out
->data
[0]), eye
,
470 texUnit
->GenQ
.EyePlane
);
473 _mesa_problem(ctx
, "Bad Q texgen");
481 static GLboolean
run_texgen_stage( struct gl_context
*ctx
,
482 struct tnl_pipeline_stage
*stage
)
484 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
485 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
488 if (!ctx
->Texture
._TexGenEnabled
|| ctx
->VertexProgram
._Current
)
491 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
492 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
494 if (texUnit
->TexGenEnabled
) {
496 store
->TexgenFunc
[i
]( ctx
, store
, i
);
498 VB
->AttribPtr
[VERT_ATTRIB_TEX0
+ i
] = &store
->texcoord
[i
];
506 static void validate_texgen_stage( struct gl_context
*ctx
,
507 struct tnl_pipeline_stage
*stage
)
509 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
512 if (!ctx
->Texture
._TexGenEnabled
|| ctx
->VertexProgram
._Current
)
515 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
516 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[i
];
518 if (texUnit
->TexGenEnabled
) {
521 if (texUnit
->TexGenEnabled
& Q_BIT
)
523 else if (texUnit
->TexGenEnabled
& R_BIT
)
525 else if (texUnit
->TexGenEnabled
& T_BIT
)
530 store
->TexgenSize
[i
] = sz
;
531 store
->TexgenFunc
[i
] = texgen
; /* general solution */
533 /* look for special texgen cases */
534 if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
|R_BIT
)) {
535 if (texUnit
->_GenFlags
== TEXGEN_REFLECTION_MAP_NV
) {
536 store
->TexgenFunc
[i
] = texgen_reflection_map_nv
;
538 else if (texUnit
->_GenFlags
== TEXGEN_NORMAL_MAP_NV
) {
539 store
->TexgenFunc
[i
] = texgen_normal_map_nv
;
542 else if (texUnit
->TexGenEnabled
== (S_BIT
|T_BIT
) &&
543 texUnit
->_GenFlags
== TEXGEN_SPHERE_MAP
) {
544 store
->TexgenFunc
[i
] = texgen_sphere_map
;
554 /* Called the first time stage->run() is invoked.
556 static GLboolean
alloc_texgen_data( struct gl_context
*ctx
,
557 struct tnl_pipeline_stage
*stage
)
559 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
560 struct texgen_stage_data
*store
;
563 stage
->privatePtr
= calloc(1, sizeof(*store
));
564 store
= TEXGEN_STAGE_DATA(stage
);
568 for (i
= 0 ; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++)
569 _mesa_vector4f_alloc( &store
->texcoord
[i
], 0, VB
->Size
, 32 );
571 store
->tmp_f
= malloc(VB
->Size
* sizeof(GLfloat
) * 3);
572 store
->tmp_m
= malloc(VB
->Size
* sizeof(GLfloat
));
578 static void free_texgen_data( struct tnl_pipeline_stage
*stage
)
581 struct texgen_stage_data
*store
= TEXGEN_STAGE_DATA(stage
);
585 for (i
= 0 ; i
< MAX_TEXTURE_COORD_UNITS
; i
++)
586 if (store
->texcoord
[i
].data
)
587 _mesa_vector4f_free( &store
->texcoord
[i
] );
590 free( store
->tmp_f
);
591 free( store
->tmp_m
);
593 stage
->privatePtr
= NULL
;
599 const struct tnl_pipeline_stage _tnl_texgen_stage
=
602 NULL
, /* private data */
603 alloc_texgen_data
, /* destructor */
604 free_texgen_data
, /* destructor */
605 validate_texgen_stage
, /* check */
606 run_texgen_stage
/* run -- initially set to alloc data */