1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 5 * 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: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 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. 23 * 24 * Authors: 25 * Brian Paul Keith Whitwell <keithw@vmware.com> 26 */ 27 28/* 29 * Regarding GL_NV_texgen_reflection: 30 * 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. 35 */ 36 37#include "main/errors.h" 38#include "main/glheader.h" 39#include "main/macros.h" 40 41#include "main/mtypes.h" 42 43#include "math/m_xform.h" 44 45#include "t_context.h" 46#include "t_pipeline.h" 47 48 49/*********************************************************************** 50 * Automatic texture coordinate generation (texgen) code. 51 */ 52 53 54struct texgen_stage_data; 55 56typedef void (*texgen_func)( struct gl_context *ctx, 57 struct texgen_stage_data *store, 58 GLuint unit); 59 60 61struct texgen_stage_data { 62 63 /* Per-texunit derived state. 64 */ 65 GLuint TexgenSize[MAX_TEXTURE_COORD_UNITS]; 66 texgen_func TexgenFunc[MAX_TEXTURE_COORD_UNITS]; 67 68 /* Temporary values used in texgen. 69 */ 70 GLfloat (*tmp_f)[3]; 71 GLfloat *tmp_m; 72 73 /* Buffered outputs of the stage. 74 */ 75 GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS]; 76}; 77 78 79#define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr) 80 81 82 83static GLuint all_bits[5] = { 84 0, 85 VEC_SIZE_1, 86 VEC_SIZE_2, 87 VEC_SIZE_3, 88 VEC_SIZE_4, 89}; 90 91#define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4) 92 93#define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP) 94#define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \ 95 TEXGEN_REFLECTION_MAP_NV) 96 97 98 99static void build_m3( GLfloat f[][3], GLfloat m[], 100 const GLvector4f *normal, 101 const GLvector4f *eye ) 102{ 103 GLuint stride = eye->stride; 104 GLfloat *coord = (GLfloat *)eye->start; 105 GLuint count = eye->count; 106 const GLfloat *norm = normal->start; 107 GLuint i; 108 109 for (i=0;i<count;i++,STRIDE_F(coord,stride),STRIDE_F(norm,normal->stride)) { 110 GLfloat u[3], two_nu, fx, fy, fz; 111 COPY_3V( u, coord ); 112 NORMALIZE_3FV( u ); 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); 118 if (m[i] != 0.0F) { 119 m[i] = 0.5F * (1.0f / sqrtf(m[i])); 120 } 121 } 122} 123 124 125 126static void build_m2( GLfloat f[][3], GLfloat m[], 127 const GLvector4f *normal, 128 const GLvector4f *eye ) 129{ 130 GLuint stride = eye->stride; 131 GLfloat *coord = eye->start; 132 GLuint count = eye->count; 133 134 GLfloat *norm = normal->start; 135 GLuint i; 136 137 for (i=0;i<count;i++,STRIDE_F(coord,stride),STRIDE_F(norm,normal->stride)) { 138 GLfloat u[3], two_nu, fx, fy, fz; 139 COPY_2V( u, coord ); 140 u[2] = 0; 141 NORMALIZE_3FV( u ); 142 two_nu = 2.0F * DOT3(norm,u); 143 fx = f[i][0] = u[0] - norm[0] * two_nu; 144 fy = f[i][1] = u[1] - norm[1] * two_nu; 145 fz = f[i][2] = u[2] - norm[2] * two_nu; 146 m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F); 147 if (m[i] != 0.0F) { 148 m[i] = 0.5F * (1.0f / sqrtf(m[i])); 149 } 150 } 151} 152 153 154 155typedef void (*build_m_func)( GLfloat f[][3], 156 GLfloat m[], 157 const GLvector4f *normal, 158 const GLvector4f *eye ); 159 160 161static build_m_func build_m_tab[5] = { 162 NULL, 163 NULL, 164 build_m2, 165 build_m3, 166 build_m3 167}; 168 169 170/* This is unusual in that we respect the stride of the output vector 171 * (f). This allows us to pass in either a texcoord vector4f, or a 172 * temporary vector3f. 173 */ 174static void build_f3( GLfloat *f, 175 GLuint fstride, 176 const GLvector4f *normal, 177 const GLvector4f *eye ) 178{ 179 GLuint stride = eye->stride; 180 GLfloat *coord = eye->start; 181 GLuint count = eye->count; 182 183 GLfloat *norm = normal->start; 184 GLuint i; 185 186 for (i=0;i<count;i++) { 187 GLfloat u[3], two_nu; 188 COPY_3V( u, coord ); 189 NORMALIZE_3FV( u ); 190 two_nu = 2.0F * DOT3(norm,u); 191 f[0] = u[0] - norm[0] * two_nu; 192 f[1] = u[1] - norm[1] * two_nu; 193 f[2] = u[2] - norm[2] * two_nu; 194 STRIDE_F(coord,stride); 195 STRIDE_F(f,fstride); 196 STRIDE_F(norm, normal->stride); 197 } 198} 199 200 201static void build_f2( GLfloat *f, 202 GLuint fstride, 203 const GLvector4f *normal, 204 const GLvector4f *eye ) 205{ 206 GLuint stride = eye->stride; 207 GLfloat *coord = eye->start; 208 GLuint count = eye->count; 209 GLfloat *norm = normal->start; 210 GLuint i; 211 212 for (i=0;i<count;i++) { 213 214 GLfloat u[3], two_nu; 215 COPY_2V( u, coord ); 216 u[2] = 0; 217 NORMALIZE_3FV( u ); 218 two_nu = 2.0F * DOT3(norm,u); 219 f[0] = u[0] - norm[0] * two_nu; 220 f[1] = u[1] - norm[1] * two_nu; 221 f[2] = u[2] - norm[2] * two_nu; 222 223 STRIDE_F(coord,stride); 224 STRIDE_F(f,fstride); 225 STRIDE_F(norm, normal->stride); 226 } 227} 228 229typedef void (*build_f_func)( GLfloat *f, 230 GLuint fstride, 231 const GLvector4f *normal_vec, 232 const GLvector4f *eye ); 233 234 235 236/* Just treat 4-vectors as 3-vectors. 237 */ 238static build_f_func build_f_tab[5] = { 239 NULL, 240 NULL, 241 build_f2, 242 build_f3, 243 build_f3 244}; 245 246 247 248/* Special case texgen functions. 249 */ 250static void texgen_reflection_map_nv( struct gl_context *ctx, 251 struct texgen_stage_data *store, 252 GLuint unit ) 253{ 254 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 255 GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; 256 GLvector4f *out = &store->texcoord[unit]; 257 258 build_f_tab[VB->EyePtr->size]( out->start, 259 out->stride, 260 VB->AttribPtr[_TNL_ATTRIB_NORMAL], 261 VB->EyePtr ); 262 263 out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; 264 out->count = VB->Count; 265 out->size = MAX2(in->size, 3); 266 if (in->size == 4) 267 _mesa_copy_tab[0x8]( out, in ); 268} 269 270 271 272static void texgen_normal_map_nv( struct gl_context *ctx, 273 struct texgen_stage_data *store, 274 GLuint unit ) 275{ 276 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 277 GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; 278 GLvector4f *out = &store->texcoord[unit]; 279 GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; 280 GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->start; 281 GLuint count = VB->Count; 282 GLuint i; 283 const GLfloat *norm = normal->start; 284 285 for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { 286 texcoord[i][0] = norm[0]; 287 texcoord[i][1] = norm[1]; 288 texcoord[i][2] = norm[2]; 289 } 290 291 292 out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; 293 out->count = count; 294 out->size = MAX2(in->size, 3); 295 if (in->size == 4) 296 _mesa_copy_tab[0x8]( out, in ); 297} 298 299 300static void texgen_sphere_map( struct gl_context *ctx, 301 struct texgen_stage_data *store, 302 GLuint unit ) 303{ 304 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 305 GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; 306 GLvector4f *out = &store->texcoord[unit]; 307 GLfloat (*texcoord)[4] = (GLfloat (*)[4]) out->start; 308 GLuint count = VB->Count; 309 GLuint i; 310 GLfloat (*f)[3] = store->tmp_f; 311 GLfloat *m = store->tmp_m; 312 313 (build_m_tab[VB->EyePtr->size])( store->tmp_f, 314 store->tmp_m, 315 VB->AttribPtr[_TNL_ATTRIB_NORMAL], 316 VB->EyePtr ); 317 318 out->size = MAX2(in->size,2); 319 320 for (i=0;i<count;i++) { 321 texcoord[i][0] = f[i][0] * m[i] + 0.5F; 322 texcoord[i][1] = f[i][1] * m[i] + 0.5F; 323 } 324 325 out->count = count; 326 out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_2; 327 if (in->size > 2) 328 _mesa_copy_tab[all_bits[in->size] & ~0x3]( out, in ); 329} 330 331 332 333static void texgen( struct gl_context *ctx, 334 struct texgen_stage_data *store, 335 GLuint unit ) 336{ 337 TNLcontext *tnl = TNL_CONTEXT(ctx); 338 struct vertex_buffer *VB = &tnl->vb; 339 GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; 340 GLvector4f *out = &store->texcoord[unit]; 341 const struct gl_fixedfunc_texture_unit *texUnit = 342 &ctx->Texture.FixedFuncUnit[unit]; 343 const GLvector4f *obj = VB->AttribPtr[_TNL_ATTRIB_POS]; 344 const GLvector4f *eye = VB->EyePtr; 345 const GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; 346 const GLfloat *m = store->tmp_m; 347 const GLuint count = VB->Count; 348 GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data; 349 GLfloat (*f)[3] = store->tmp_f; 350 GLuint copy; 351 352 if (texUnit->_GenFlags & TEXGEN_NEED_M) { 353 build_m_tab[eye->size]( store->tmp_f, store->tmp_m, normal, eye ); 354 } else if (texUnit->_GenFlags & TEXGEN_NEED_F) { 355 build_f_tab[eye->size]( (GLfloat *)store->tmp_f, 3, normal, eye ); 356 } 357 358 359 out->size = MAX2(in->size, store->TexgenSize[unit]); 360 out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled; 361 out->count = count; 362 363 copy = (all_bits[in->size] & ~texUnit->TexGenEnabled); 364 if (copy) 365 _mesa_copy_tab[copy]( out, in ); 366 367 if (texUnit->TexGenEnabled & S_BIT) { 368 GLuint i; 369 switch (texUnit->GenS.Mode) { 370 case GL_OBJECT_LINEAR: 371 _mesa_dotprod_tab[obj->size]( (GLfloat *)out->data, 372 sizeof(out->data[0]), obj, 373 texUnit->ObjectPlane[GEN_S] ); 374 break; 375 case GL_EYE_LINEAR: 376 _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data, 377 sizeof(out->data[0]), eye, 378 texUnit->EyePlane[GEN_S] ); 379 break; 380 case GL_SPHERE_MAP: 381 for (i = 0; i < count; i++) 382 texcoord[i][0] = f[i][0] * m[i] + 0.5F; 383 break; 384 case GL_REFLECTION_MAP_NV: 385 for (i=0;i<count;i++) 386 texcoord[i][0] = f[i][0]; 387 break; 388 case GL_NORMAL_MAP_NV: { 389 const GLfloat *norm = normal->start; 390 for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { 391 texcoord[i][0] = norm[0]; 392 } 393 break; 394 } 395 default: 396 _mesa_problem(ctx, "Bad S texgen"); 397 } 398 } 399 400 if (texUnit->TexGenEnabled & T_BIT) { 401 GLuint i; 402 switch (texUnit->GenT.Mode) { 403 case GL_OBJECT_LINEAR: 404 _mesa_dotprod_tab[obj->size]( &(out->data[0][1]), 405 sizeof(out->data[0]), obj, 406 texUnit->ObjectPlane[GEN_T] ); 407 break; 408 case GL_EYE_LINEAR: 409 _mesa_dotprod_tab[eye->size]( &(out->data[0][1]), 410 sizeof(out->data[0]), eye, 411 texUnit->EyePlane[GEN_T] ); 412 break; 413 case GL_SPHERE_MAP: 414 for (i = 0; i < count; i++) 415 texcoord[i][1] = f[i][1] * m[i] + 0.5F; 416 break; 417 case GL_REFLECTION_MAP_NV: 418 for (i=0;i<count;i++) 419 texcoord[i][1] = f[i][1]; 420 break; 421 case GL_NORMAL_MAP_NV: { 422 const GLfloat *norm = normal->start; 423 for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { 424 texcoord[i][1] = norm[1]; 425 } 426 break; 427 } 428 default: 429 _mesa_problem(ctx, "Bad T texgen"); 430 } 431 } 432 433 if (texUnit->TexGenEnabled & R_BIT) { 434 GLuint i; 435 switch (texUnit->GenR.Mode) { 436 case GL_OBJECT_LINEAR: 437 _mesa_dotprod_tab[obj->size]( &(out->data[0][2]), 438 sizeof(out->data[0]), obj, 439 texUnit->ObjectPlane[GEN_R] ); 440 break; 441 case GL_EYE_LINEAR: 442 _mesa_dotprod_tab[eye->size]( &(out->data[0][2]), 443 sizeof(out->data[0]), eye, 444 texUnit->EyePlane[GEN_R] ); 445 break; 446 case GL_REFLECTION_MAP_NV: 447 for (i=0;i<count;i++) 448 texcoord[i][2] = f[i][2]; 449 break; 450 case GL_NORMAL_MAP_NV: { 451 const GLfloat *norm = normal->start; 452 for (i=0;i<count;i++,STRIDE_F(norm, normal->stride)) { 453 texcoord[i][2] = norm[2]; 454 } 455 break; 456 } 457 default: 458 _mesa_problem(ctx, "Bad R texgen"); 459 } 460 } 461 462 if (texUnit->TexGenEnabled & Q_BIT) { 463 switch (texUnit->GenQ.Mode) { 464 case GL_OBJECT_LINEAR: 465 _mesa_dotprod_tab[obj->size]( &(out->data[0][3]), 466 sizeof(out->data[0]), obj, 467 texUnit->ObjectPlane[GEN_Q] ); 468 break; 469 case GL_EYE_LINEAR: 470 _mesa_dotprod_tab[eye->size]( &(out->data[0][3]), 471 sizeof(out->data[0]), eye, 472 texUnit->EyePlane[GEN_Q] ); 473 break; 474 default: 475 _mesa_problem(ctx, "Bad Q texgen"); 476 } 477 } 478} 479 480 481 482 483static GLboolean run_texgen_stage( struct gl_context *ctx, 484 struct tnl_pipeline_stage *stage ) 485{ 486 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 487 struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); 488 GLuint i; 489 490 if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current) 491 return GL_TRUE; 492 493 for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { 494 struct gl_fixedfunc_texture_unit *texUnit = 495 &ctx->Texture.FixedFuncUnit[i]; 496 497 if (texUnit->TexGenEnabled) { 498 store->TexgenFunc[i]( ctx, store, i ); 499 500 VB->AttribPtr[VERT_ATTRIB_TEX0 + i] = &store->texcoord[i]; 501 } 502 } 503 504 return GL_TRUE; 505} 506 507 508static void validate_texgen_stage( struct gl_context *ctx, 509 struct tnl_pipeline_stage *stage ) 510{ 511 struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); 512 GLuint i; 513 514 if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current) 515 return; 516 517 for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { 518 struct gl_fixedfunc_texture_unit *texUnit = 519 &ctx->Texture.FixedFuncUnit[i]; 520 521 if (texUnit->TexGenEnabled) { 522 GLuint sz; 523 524 if (texUnit->TexGenEnabled & Q_BIT) 525 sz = 4; 526 else if (texUnit->TexGenEnabled & R_BIT) 527 sz = 3; 528 else if (texUnit->TexGenEnabled & T_BIT) 529 sz = 2; 530 else 531 sz = 1; 532 533 store->TexgenSize[i] = sz; 534 store->TexgenFunc[i] = texgen; /* general solution */ 535 536 /* look for special texgen cases */ 537 if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT)) { 538 if (texUnit->_GenFlags == TEXGEN_REFLECTION_MAP_NV) { 539 store->TexgenFunc[i] = texgen_reflection_map_nv; 540 } 541 else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) { 542 store->TexgenFunc[i] = texgen_normal_map_nv; 543 } 544 } 545 else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) && 546 texUnit->_GenFlags == TEXGEN_SPHERE_MAP) { 547 store->TexgenFunc[i] = texgen_sphere_map; 548 } 549 } 550 } 551} 552 553 554 555 556 557/* Called the first time stage->run() is invoked. 558 */ 559static GLboolean alloc_texgen_data( struct gl_context *ctx, 560 struct tnl_pipeline_stage *stage ) 561{ 562 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 563 struct texgen_stage_data *store; 564 GLuint i; 565 566 stage->privatePtr = calloc(1, sizeof(*store)); 567 store = TEXGEN_STAGE_DATA(stage); 568 if (!store) 569 return GL_FALSE; 570 571 for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) 572 _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); 573 574 store->tmp_f = malloc(VB->Size * sizeof(GLfloat) * 3); 575 store->tmp_m = malloc(VB->Size * sizeof(GLfloat)); 576 577 return GL_TRUE; 578} 579 580 581static void free_texgen_data( struct tnl_pipeline_stage *stage ) 582 583{ 584 struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); 585 GLuint i; 586 587 if (store) { 588 for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++) 589 if (store->texcoord[i].data) 590 _mesa_vector4f_free( &store->texcoord[i] ); 591 592 593 free( store->tmp_f ); 594 free( store->tmp_m ); 595 free( store ); 596 stage->privatePtr = NULL; 597 } 598} 599 600 601 602const struct tnl_pipeline_stage _tnl_texgen_stage = 603{ 604 "texgen", /* name */ 605 NULL, /* private data */ 606 alloc_texgen_data, /* destructor */ 607 free_texgen_data, /* destructor */ 608 validate_texgen_stage, /* check */ 609 run_texgen_stage /* run -- initially set to alloc data */ 610}; 611