Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 
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/colormac.h"
39
#include "main/macros.h"
40
#include "main/imports.h"
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
 
54
struct texgen_stage_data;
55
 
56
typedef void (*texgen_func)( struct gl_context *ctx,
57
			     struct texgen_stage_data *store,
58
			     GLuint unit);
59
 
60
 
61
struct 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
 
83
static 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
 
99
static 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;istride)) {
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 * INV_SQRTF(m[i]);
120
      }
121
   }
122
}
123
 
124
 
125
 
126
static 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;istride)) {
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 * INV_SQRTF(m[i]);
149
      }
150
   }
151
}
152
 
153
 
154
 
155
typedef void (*build_m_func)( GLfloat f[][3],
156
			      GLfloat m[],
157
			      const GLvector4f *normal,
158
			      const GLvector4f *eye );
159
 
160
 
161
static 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
 */
174
static 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
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
 
201
static 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
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
 
229
typedef 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
 */
238
static 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
 */
250
static 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
 
272
static 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;istride)) {
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
 
300
static 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
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
 
333
static 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_texture_unit *texUnit = &ctx->Texture.Unit[unit];
342
   const GLvector4f *obj = VB->AttribPtr[_TNL_ATTRIB_POS];
343
   const GLvector4f *eye = VB->EyePtr;
344
   const GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL];
345
   const GLfloat *m = store->tmp_m;
346
   const GLuint count = VB->Count;
347
   GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data;
348
   GLfloat (*f)[3] = store->tmp_f;
349
   GLuint copy;
350
 
351
   if (texUnit->_GenFlags & TEXGEN_NEED_M) {
352
      build_m_tab[eye->size]( store->tmp_f, store->tmp_m, normal, eye );
353
   } else if (texUnit->_GenFlags & TEXGEN_NEED_F) {
354
      build_f_tab[eye->size]( (GLfloat *)store->tmp_f, 3, normal, eye );
355
   }
356
 
357
 
358
   out->size = MAX2(in->size, store->TexgenSize[unit]);
359
   out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled;
360
   out->count = count;
361
 
362
   copy = (all_bits[in->size] & ~texUnit->TexGenEnabled);
363
   if (copy)
364
      _mesa_copy_tab[copy]( out, in );
365
 
366
   if (texUnit->TexGenEnabled & S_BIT) {
367
      GLuint i;
368
      switch (texUnit->GenS.Mode) {
369
      case GL_OBJECT_LINEAR:
370
	 _mesa_dotprod_tab[obj->size]( (GLfloat *)out->data,
371
				       sizeof(out->data[0]), obj,
372
				       texUnit->GenS.ObjectPlane );
373
	 break;
374
      case GL_EYE_LINEAR:
375
	 _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data,
376
				       sizeof(out->data[0]), eye,
377
				       texUnit->GenS.EyePlane );
378
	 break;
379
      case GL_SPHERE_MAP:
380
         for (i = 0; i < count; i++)
381
            texcoord[i][0] = f[i][0] * m[i] + 0.5F;
382
	 break;
383
      case GL_REFLECTION_MAP_NV:
384
	 for (i=0;i
385
	     texcoord[i][0] = f[i][0];
386
	 break;
387
      case GL_NORMAL_MAP_NV: {
388
	 const GLfloat *norm = normal->start;
389
	 for (i=0;istride)) {
390
	     texcoord[i][0] = norm[0];
391
	 }
392
	 break;
393
      }
394
      default:
395
	 _mesa_problem(ctx, "Bad S texgen");
396
      }
397
   }
398
 
399
   if (texUnit->TexGenEnabled & T_BIT) {
400
      GLuint i;
401
      switch (texUnit->GenT.Mode) {
402
      case GL_OBJECT_LINEAR:
403
	 _mesa_dotprod_tab[obj->size]( &(out->data[0][1]),
404
				       sizeof(out->data[0]), obj,
405
				       texUnit->GenT.ObjectPlane );
406
	 break;
407
      case GL_EYE_LINEAR:
408
	 _mesa_dotprod_tab[eye->size]( &(out->data[0][1]),
409
				       sizeof(out->data[0]), eye,
410
				       texUnit->GenT.EyePlane );
411
	 break;
412
      case GL_SPHERE_MAP:
413
         for (i = 0; i < count; i++)
414
            texcoord[i][1] = f[i][1] * m[i] + 0.5F;
415
	 break;
416
      case GL_REFLECTION_MAP_NV:
417
	 for (i=0;i
418
	     texcoord[i][1] = f[i][1];
419
	 break;
420
      case GL_NORMAL_MAP_NV: {
421
	 const GLfloat *norm = normal->start;
422
	 for (i=0;istride)) {
423
	     texcoord[i][1] = norm[1];
424
	 }
425
	 break;
426
      }
427
      default:
428
	 _mesa_problem(ctx, "Bad T texgen");
429
      }
430
   }
431
 
432
   if (texUnit->TexGenEnabled & R_BIT) {
433
      GLuint i;
434
      switch (texUnit->GenR.Mode) {
435
      case GL_OBJECT_LINEAR:
436
	 _mesa_dotprod_tab[obj->size]( &(out->data[0][2]),
437
				       sizeof(out->data[0]), obj,
438
				       texUnit->GenR.ObjectPlane );
439
	 break;
440
      case GL_EYE_LINEAR:
441
	 _mesa_dotprod_tab[eye->size]( &(out->data[0][2]),
442
				       sizeof(out->data[0]), eye,
443
				       texUnit->GenR.EyePlane );
444
	 break;
445
      case GL_REFLECTION_MAP_NV:
446
	 for (i=0;i
447
	     texcoord[i][2] = f[i][2];
448
	 break;
449
      case GL_NORMAL_MAP_NV: {
450
	 const GLfloat *norm = normal->start;
451
	 for (i=0;istride)) {
452
	     texcoord[i][2] = norm[2];
453
	 }
454
	 break;
455
      }
456
      default:
457
	 _mesa_problem(ctx, "Bad R texgen");
458
      }
459
   }
460
 
461
   if (texUnit->TexGenEnabled & Q_BIT) {
462
      switch (texUnit->GenQ.Mode) {
463
      case GL_OBJECT_LINEAR:
464
	 _mesa_dotprod_tab[obj->size]( &(out->data[0][3]),
465
				       sizeof(out->data[0]), obj,
466
				       texUnit->GenQ.ObjectPlane );
467
	 break;
468
      case GL_EYE_LINEAR:
469
	 _mesa_dotprod_tab[eye->size]( &(out->data[0][3]),
470
				       sizeof(out->data[0]), eye,
471
				       texUnit->GenQ.EyePlane );
472
	 break;
473
      default:
474
	 _mesa_problem(ctx, "Bad Q texgen");
475
      }
476
   }
477
}
478
 
479
 
480
 
481
 
482
static GLboolean run_texgen_stage( struct gl_context *ctx,
483
				   struct tnl_pipeline_stage *stage )
484
{
485
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
486
   struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
487
   GLuint i;
488
 
489
   if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current)
490
      return GL_TRUE;
491
 
492
   for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) {
493
      struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
494
 
495
      if (texUnit->TexGenEnabled) {
496
 
497
	 store->TexgenFunc[i]( ctx, store, i );
498
 
499
         VB->AttribPtr[VERT_ATTRIB_TEX0 + i] = &store->texcoord[i];
500
      }
501
   }
502
 
503
   return GL_TRUE;
504
}
505
 
506
 
507
static void validate_texgen_stage( struct gl_context *ctx,
508
				   struct tnl_pipeline_stage *stage )
509
{
510
   struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
511
   GLuint i;
512
 
513
   if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current)
514
      return;
515
 
516
   for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) {
517
      struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
518
 
519
      if (texUnit->TexGenEnabled) {
520
	 GLuint sz;
521
 
522
	 if (texUnit->TexGenEnabled & Q_BIT)
523
	    sz = 4;
524
	 else if (texUnit->TexGenEnabled & R_BIT)
525
	    sz = 3;
526
	 else if (texUnit->TexGenEnabled & T_BIT)
527
	    sz = 2;
528
	 else
529
	    sz = 1;
530
 
531
	 store->TexgenSize[i] = sz;
532
	 store->TexgenFunc[i] = texgen; /* general solution */
533
 
534
         /* look for special texgen cases */
535
	 if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT)) {
536
	    if (texUnit->_GenFlags == TEXGEN_REFLECTION_MAP_NV) {
537
	       store->TexgenFunc[i] = texgen_reflection_map_nv;
538
	    }
539
	    else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) {
540
	       store->TexgenFunc[i] = texgen_normal_map_nv;
541
	    }
542
	 }
543
	 else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) &&
544
		  texUnit->_GenFlags == TEXGEN_SPHERE_MAP) {
545
	    store->TexgenFunc[i] = texgen_sphere_map;
546
	 }
547
      }
548
   }
549
}
550
 
551
 
552
 
553
 
554
 
555
/* Called the first time stage->run() is invoked.
556
 */
557
static GLboolean alloc_texgen_data( struct gl_context *ctx,
558
				    struct tnl_pipeline_stage *stage )
559
{
560
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
561
   struct texgen_stage_data *store;
562
   GLuint i;
563
 
564
   stage->privatePtr = calloc(1, sizeof(*store));
565
   store = TEXGEN_STAGE_DATA(stage);
566
   if (!store)
567
      return GL_FALSE;
568
 
569
   for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
570
      _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
571
 
572
   store->tmp_f = malloc(VB->Size * sizeof(GLfloat) * 3);
573
   store->tmp_m = malloc(VB->Size * sizeof(GLfloat));
574
 
575
   return GL_TRUE;
576
}
577
 
578
 
579
static void free_texgen_data( struct tnl_pipeline_stage *stage )
580
 
581
{
582
   struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
583
   GLuint i;
584
 
585
   if (store) {
586
      for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++)
587
	 if (store->texcoord[i].data)
588
	    _mesa_vector4f_free( &store->texcoord[i] );
589
 
590
 
591
      free( store->tmp_f );
592
      free( store->tmp_m );
593
      free( store );
594
      stage->privatePtr = NULL;
595
   }
596
}
597
 
598
 
599
 
600
const struct tnl_pipeline_stage _tnl_texgen_stage =
601
{
602
   "texgen",			/* name */
603
   NULL,			/* private data */
604
   alloc_texgen_data,		/* destructor */
605
   free_texgen_data,		/* destructor */
606
   validate_texgen_stage,		/* check */
607
   run_texgen_stage		/* run -- initially set to alloc data */
608
};