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 (at) 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/glheader.h" 38 #include "main/macros.h" 39 #include "main/imports.h" 40 #include "main/mtypes.h" 41 42 #include "math/m_xform.h" 43 44 #include "t_context.h" 45 #include "t_pipeline.h" 46 47 48 /*********************************************************************** 49 * Automatic texture coordinate generation (texgen) code. 50 */ 51 52 53 struct texgen_stage_data; 54 55 typedef void (*texgen_func)( struct gl_context *ctx, 56 struct texgen_stage_data *store, 57 GLuint unit); 58 59 60 struct texgen_stage_data { 61 62 /* Per-texunit derived state. 63 */ 64 GLuint TexgenSize[MAX_TEXTURE_COORD_UNITS]; 65 texgen_func TexgenFunc[MAX_TEXTURE_COORD_UNITS]; 66 67 /* Temporary values used in texgen. 68 */ 69 GLfloat (*tmp_f)[3]; 70 GLfloat *tmp_m; 71 72 /* Buffered outputs of the stage. 73 */ 74 GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS]; 75 }; 76 77 78 #define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr) 79 80 81 82 static GLuint all_bits[5] = { 83 0, 84 VEC_SIZE_1, 85 VEC_SIZE_2, 86 VEC_SIZE_3, 87 VEC_SIZE_4, 88 }; 89 90 #define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4) 91 92 #define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP) 93 #define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \ 94 TEXGEN_REFLECTION_MAP_NV) 95 96 97 98 static void build_m3( GLfloat f[][3], GLfloat m[], 99 const GLvector4f *normal, 100 const GLvector4f *eye ) 101 { 102 GLuint stride = eye->stride; 103 GLfloat *coord = (GLfloat *)eye->start; 104 GLuint count = eye->count; 105 const GLfloat *norm = normal->start; 106 GLuint i; 107 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; 110 COPY_3V( u, coord ); 111 NORMALIZE_3FV( u ); 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); 117 if (m[i] != 0.0F) { 118 m[i] = 0.5F * (1.0f / sqrtf(m[i])); 119 } 120 } 121 } 122 123 124 125 static void build_m2( GLfloat f[][3], GLfloat m[], 126 const GLvector4f *normal, 127 const GLvector4f *eye ) 128 { 129 GLuint stride = eye->stride; 130 GLfloat *coord = eye->start; 131 GLuint count = eye->count; 132 133 GLfloat *norm = normal->start; 134 GLuint i; 135 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; 138 COPY_2V( u, coord ); 139 u[2] = 0; 140 NORMALIZE_3FV( u ); 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); 146 if (m[i] != 0.0F) { 147 m[i] = 0.5F * (1.0f / sqrtf(m[i])); 148 } 149 } 150 } 151 152 153 154 typedef void (*build_m_func)( GLfloat f[][3], 155 GLfloat m[], 156 const GLvector4f *normal, 157 const GLvector4f *eye ); 158 159 160 static build_m_func build_m_tab[5] = { 161 NULL, 162 NULL, 163 build_m2, 164 build_m3, 165 build_m3 166 }; 167 168 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. 172 */ 173 static void build_f3( GLfloat *f, 174 GLuint fstride, 175 const GLvector4f *normal, 176 const GLvector4f *eye ) 177 { 178 GLuint stride = eye->stride; 179 GLfloat *coord = eye->start; 180 GLuint count = eye->count; 181 182 GLfloat *norm = normal->start; 183 GLuint i; 184 185 for (i=0;i<count;i++) { 186 GLfloat u[3], two_nu; 187 COPY_3V( u, coord ); 188 NORMALIZE_3FV( u ); 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); 194 STRIDE_F(f,fstride); 195 STRIDE_F(norm, normal->stride); 196 } 197 } 198 199 200 static void build_f2( GLfloat *f, 201 GLuint fstride, 202 const GLvector4f *normal, 203 const GLvector4f *eye ) 204 { 205 GLuint stride = eye->stride; 206 GLfloat *coord = eye->start; 207 GLuint count = eye->count; 208 GLfloat *norm = normal->start; 209 GLuint i; 210 211 for (i=0;i<count;i++) { 212 213 GLfloat u[3], two_nu; 214 COPY_2V( u, coord ); 215 u[2] = 0; 216 NORMALIZE_3FV( u ); 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; 221 222 STRIDE_F(coord,stride); 223 STRIDE_F(f,fstride); 224 STRIDE_F(norm, normal->stride); 225 } 226 } 227 228 typedef void (*build_f_func)( GLfloat *f, 229 GLuint fstride, 230 const GLvector4f *normal_vec, 231 const GLvector4f *eye ); 232 233 234 235 /* Just treat 4-vectors as 3-vectors. 236 */ 237 static build_f_func build_f_tab[5] = { 238 NULL, 239 NULL, 240 build_f2, 241 build_f3, 242 build_f3 243 }; 244 245 246 247 /* Special case texgen functions. 248 */ 249 static void texgen_reflection_map_nv( struct gl_context *ctx, 250 struct texgen_stage_data *store, 251 GLuint unit ) 252 { 253 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 254 GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; 255 GLvector4f *out = &store->texcoord[unit]; 256 257 build_f_tab[VB->EyePtr->size]( out->start, 258 out->stride, 259 VB->AttribPtr[_TNL_ATTRIB_NORMAL], 260 VB->EyePtr ); 261 262 out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; 263 out->count = VB->Count; 264 out->size = MAX2(in->size, 3); 265 if (in->size == 4) 266 _mesa_copy_tab[0x8]( out, in ); 267 } 268 269 270 271 static void texgen_normal_map_nv( struct gl_context *ctx, 272 struct texgen_stage_data *store, 273 GLuint unit ) 274 { 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; 281 GLuint i; 282 const GLfloat *norm = normal->start; 283 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]; 288 } 289 290 291 out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; 292 out->count = count; 293 out->size = MAX2(in->size, 3); 294 if (in->size == 4) 295 _mesa_copy_tab[0x8]( out, in ); 296 } 297 298 299 static void texgen_sphere_map( struct gl_context *ctx, 300 struct texgen_stage_data *store, 301 GLuint unit ) 302 { 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; 308 GLuint i; 309 GLfloat (*f)[3] = store->tmp_f; 310 GLfloat *m = store->tmp_m; 311 312 (build_m_tab[VB->EyePtr->size])( store->tmp_f, 313 store->tmp_m, 314 VB->AttribPtr[_TNL_ATTRIB_NORMAL], 315 VB->EyePtr ); 316 317 out->size = MAX2(in->size,2); 318 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; 322 } 323 324 out->count = count; 325 out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_2; 326 if (in->size > 2) 327 _mesa_copy_tab[all_bits[in->size] & ~0x3]( out, in ); 328 } 329 330 331 332 static void texgen( struct gl_context *ctx, 333 struct texgen_stage_data *store, 334 GLuint unit ) 335 { 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; 348 GLuint copy; 349 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 ); 354 } 355 356 357 out->size = MAX2(in->size, store->TexgenSize[unit]); 358 out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled; 359 out->count = count; 360 361 copy = (all_bits[in->size] & ~texUnit->TexGenEnabled); 362 if (copy) 363 _mesa_copy_tab[copy]( out, in ); 364 365 if (texUnit->TexGenEnabled & S_BIT) { 366 GLuint i; 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 ); 372 break; 373 case GL_EYE_LINEAR: 374 _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data, 375 sizeof(out->data[0]), eye, 376 texUnit->GenS.EyePlane ); 377 break; 378 case GL_SPHERE_MAP: 379 for (i = 0; i < count; i++) 380 texcoord[i][0] = f[i][0] * m[i] + 0.5F; 381 break; 382 case GL_REFLECTION_MAP_NV: 383 for (i=0;i<count;i++) 384 texcoord[i][0] = f[i][0]; 385 break; 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]; 390 } 391 break; 392 } 393 default: 394 _mesa_problem(ctx, "Bad S texgen"); 395 } 396 } 397 398 if (texUnit->TexGenEnabled & T_BIT) { 399 GLuint i; 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 ); 405 break; 406 case GL_EYE_LINEAR: 407 _mesa_dotprod_tab[eye->size]( &(out->data[0][1]), 408 sizeof(out->data[0]), eye, 409 texUnit->GenT.EyePlane ); 410 break; 411 case GL_SPHERE_MAP: 412 for (i = 0; i < count; i++) 413 texcoord[i][1] = f[i][1] * m[i] + 0.5F; 414 break; 415 case GL_REFLECTION_MAP_NV: 416 for (i=0;i<count;i++) 417 texcoord[i][1] = f[i][1]; 418 break; 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]; 423 } 424 break; 425 } 426 default: 427 _mesa_problem(ctx, "Bad T texgen"); 428 } 429 } 430 431 if (texUnit->TexGenEnabled & R_BIT) { 432 GLuint i; 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 ); 438 break; 439 case GL_EYE_LINEAR: 440 _mesa_dotprod_tab[eye->size]( &(out->data[0][2]), 441 sizeof(out->data[0]), eye, 442 texUnit->GenR.EyePlane ); 443 break; 444 case GL_REFLECTION_MAP_NV: 445 for (i=0;i<count;i++) 446 texcoord[i][2] = f[i][2]; 447 break; 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]; 452 } 453 break; 454 } 455 default: 456 _mesa_problem(ctx, "Bad R texgen"); 457 } 458 } 459 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 ); 466 break; 467 case GL_EYE_LINEAR: 468 _mesa_dotprod_tab[eye->size]( &(out->data[0][3]), 469 sizeof(out->data[0]), eye, 470 texUnit->GenQ.EyePlane ); 471 break; 472 default: 473 _mesa_problem(ctx, "Bad Q texgen"); 474 } 475 } 476 } 477 478 479 480 481 static GLboolean run_texgen_stage( struct gl_context *ctx, 482 struct tnl_pipeline_stage *stage ) 483 { 484 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 485 struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); 486 GLuint i; 487 488 if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current) 489 return GL_TRUE; 490 491 for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { 492 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; 493 494 if (texUnit->TexGenEnabled) { 495 496 store->TexgenFunc[i]( ctx, store, i ); 497 498 VB->AttribPtr[VERT_ATTRIB_TEX0 + i] = &store->texcoord[i]; 499 } 500 } 501 502 return GL_TRUE; 503 } 504 505 506 static void validate_texgen_stage( struct gl_context *ctx, 507 struct tnl_pipeline_stage *stage ) 508 { 509 struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); 510 GLuint i; 511 512 if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current) 513 return; 514 515 for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { 516 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; 517 518 if (texUnit->TexGenEnabled) { 519 GLuint sz; 520 521 if (texUnit->TexGenEnabled & Q_BIT) 522 sz = 4; 523 else if (texUnit->TexGenEnabled & R_BIT) 524 sz = 3; 525 else if (texUnit->TexGenEnabled & T_BIT) 526 sz = 2; 527 else 528 sz = 1; 529 530 store->TexgenSize[i] = sz; 531 store->TexgenFunc[i] = texgen; /* general solution */ 532 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; 537 } 538 else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) { 539 store->TexgenFunc[i] = texgen_normal_map_nv; 540 } 541 } 542 else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) && 543 texUnit->_GenFlags == TEXGEN_SPHERE_MAP) { 544 store->TexgenFunc[i] = texgen_sphere_map; 545 } 546 } 547 } 548 } 549 550 551 552 553 554 /* Called the first time stage->run() is invoked. 555 */ 556 static GLboolean alloc_texgen_data( struct gl_context *ctx, 557 struct tnl_pipeline_stage *stage ) 558 { 559 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; 560 struct texgen_stage_data *store; 561 GLuint i; 562 563 stage->privatePtr = calloc(1, sizeof(*store)); 564 store = TEXGEN_STAGE_DATA(stage); 565 if (!store) 566 return GL_FALSE; 567 568 for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) 569 _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); 570 571 store->tmp_f = malloc(VB->Size * sizeof(GLfloat) * 3); 572 store->tmp_m = malloc(VB->Size * sizeof(GLfloat)); 573 574 return GL_TRUE; 575 } 576 577 578 static void free_texgen_data( struct tnl_pipeline_stage *stage ) 579 580 { 581 struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); 582 GLuint i; 583 584 if (store) { 585 for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++) 586 if (store->texcoord[i].data) 587 _mesa_vector4f_free( &store->texcoord[i] ); 588 589 590 free( store->tmp_f ); 591 free( store->tmp_m ); 592 free( store ); 593 stage->privatePtr = NULL; 594 } 595 } 596 597 598 599 const struct tnl_pipeline_stage _tnl_texgen_stage = 600 { 601 "texgen", /* name */ 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 */ 607 }; 608