Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1901 serge 1
/*
2
 * Mesa 3-D graphics library
3
 * Version:  6.5
4
 *
5
 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *    Brian Paul
26
 *    Keith Whitwell 
27
 */
28
 
29
/*
30
 * Regarding GL_NV_texgen_reflection:
31
 *
32
 * Portions of this software may use or implement intellectual
33
 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
34
 * any and all warranties with respect to such intellectual property,
35
 * including any use thereof or modifications thereto.
36
 */
37
 
38
#include "main/glheader.h"
39
#include "main/colormac.h"
40
#include "main/macros.h"
41
#include "main/imports.h"
42
#include "main/mtypes.h"
43
 
44
#include "math/m_xform.h"
45
 
46
#include "t_context.h"
47
#include "t_pipeline.h"
48
 
49
 
50
/***********************************************************************
51
 * Automatic texture coordinate generation (texgen) code.
52
 */
53
 
54
 
55
struct texgen_stage_data;
56
 
57
typedef void (*texgen_func)( struct gl_context *ctx,
58
			     struct texgen_stage_data *store,
59
			     GLuint unit);
60
 
61
 
62
struct texgen_stage_data {
63
 
64
   /* Per-texunit derived state.
65
    */
66
   GLuint TexgenSize[MAX_TEXTURE_COORD_UNITS];
67
   texgen_func TexgenFunc[MAX_TEXTURE_COORD_UNITS];
68
 
69
   /* Temporary values used in texgen.
70
    */
71
   GLfloat (*tmp_f)[3];
72
   GLfloat *tmp_m;
73
 
74
   /* Buffered outputs of the stage.
75
    */
76
   GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS];
77
};
78
 
79
 
80
#define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
81
 
82
 
83
 
84
static GLuint all_bits[5] = {
85
   0,
86
   VEC_SIZE_1,
87
   VEC_SIZE_2,
88
   VEC_SIZE_3,
89
   VEC_SIZE_4,
90
};
91
 
92
#define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
93
 
94
#define TEXGEN_NEED_M            (TEXGEN_SPHERE_MAP)
95
#define TEXGEN_NEED_F            (TEXGEN_SPHERE_MAP        | \
96
				  TEXGEN_REFLECTION_MAP_NV)
97
 
98
 
99
 
100
static void build_m3( GLfloat f[][3], GLfloat m[],
101
		      const GLvector4f *normal,
102
		      const GLvector4f *eye )
103
{
104
   GLuint stride = eye->stride;
105
   GLfloat *coord = (GLfloat *)eye->start;
106
   GLuint count = eye->count;
107
   const GLfloat *norm = normal->start;
108
   GLuint i;
109
 
110
   for (i=0;istride)) {
111
      GLfloat u[3], two_nu, fx, fy, fz;
112
      COPY_3V( u, coord );
113
      NORMALIZE_3FV( u );
114
      two_nu = 2.0F * DOT3(norm,u);
115
      fx = f[i][0] = u[0] - norm[0] * two_nu;
116
      fy = f[i][1] = u[1] - norm[1] * two_nu;
117
      fz = f[i][2] = u[2] - norm[2] * two_nu;
118
      m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F);
119
      if (m[i] != 0.0F) {
120
	 m[i] = 0.5F * _mesa_inv_sqrtf(m[i]);
121
      }
122
   }
123
}
124
 
125
 
126
 
127
static void build_m2( GLfloat f[][3], GLfloat m[],
128
		      const GLvector4f *normal,
129
		      const GLvector4f *eye )
130
{
131
   GLuint stride = eye->stride;
132
   GLfloat *coord = eye->start;
133
   GLuint count = eye->count;
134
 
135
   GLfloat *norm = normal->start;
136
   GLuint i;
137
 
138
   for (i=0;istride)) {
139
      GLfloat u[3], two_nu, fx, fy, fz;
140
      COPY_2V( u, coord );
141
      u[2] = 0;
142
      NORMALIZE_3FV( u );
143
      two_nu = 2.0F * DOT3(norm,u);
144
      fx = f[i][0] = u[0] - norm[0] * two_nu;
145
      fy = f[i][1] = u[1] - norm[1] * two_nu;
146
      fz = f[i][2] = u[2] - norm[2] * two_nu;
147
      m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F);
148
      if (m[i] != 0.0F) {
149
	 m[i] = 0.5F * _mesa_inv_sqrtf(m[i]);
150
      }
151
   }
152
}
153
 
154
 
155
 
156
typedef void (*build_m_func)( GLfloat f[][3],
157
			      GLfloat m[],
158
			      const GLvector4f *normal,
159
			      const GLvector4f *eye );
160
 
161
 
162
static build_m_func build_m_tab[5] = {
163
   NULL,
164
   NULL,
165
   build_m2,
166
   build_m3,
167
   build_m3
168
};
169
 
170
 
171
/* This is unusual in that we respect the stride of the output vector
172
 * (f).  This allows us to pass in either a texcoord vector4f, or a
173
 * temporary vector3f.
174
 */
175
static void build_f3( GLfloat *f,
176
		      GLuint fstride,
177
		      const GLvector4f *normal,
178
		      const GLvector4f *eye )
179
{
180
   GLuint stride = eye->stride;
181
   GLfloat *coord = eye->start;
182
   GLuint count = eye->count;
183
 
184
   GLfloat *norm = normal->start;
185
   GLuint i;
186
 
187
   for (i=0;i
188
      GLfloat u[3], two_nu;
189
      COPY_3V( u, coord );
190
      NORMALIZE_3FV( u );
191
      two_nu = 2.0F * DOT3(norm,u);
192
      f[0] = u[0] - norm[0] * two_nu;
193
      f[1] = u[1] - norm[1] * two_nu;
194
      f[2] = u[2] - norm[2] * two_nu;
195
      STRIDE_F(coord,stride);
196
      STRIDE_F(f,fstride);
197
      STRIDE_F(norm, normal->stride);
198
   }
199
}
200
 
201
 
202
static void build_f2( GLfloat *f,
203
		      GLuint fstride,
204
		      const GLvector4f *normal,
205
		      const GLvector4f *eye )
206
{
207
   GLuint stride = eye->stride;
208
   GLfloat *coord = eye->start;
209
   GLuint count = eye->count;
210
   GLfloat *norm = normal->start;
211
   GLuint i;
212
 
213
   for (i=0;i
214
 
215
      GLfloat u[3], two_nu;
216
      COPY_2V( u, coord );
217
      u[2] = 0;
218
      NORMALIZE_3FV( u );
219
      two_nu = 2.0F * DOT3(norm,u);
220
      f[0] = u[0] - norm[0] * two_nu;
221
      f[1] = u[1] - norm[1] * two_nu;
222
      f[2] = u[2] - norm[2] * two_nu;
223
 
224
      STRIDE_F(coord,stride);
225
      STRIDE_F(f,fstride);
226
      STRIDE_F(norm, normal->stride);
227
   }
228
}
229
 
230
typedef void (*build_f_func)( GLfloat *f,
231
			      GLuint fstride,
232
			      const GLvector4f *normal_vec,
233
			      const GLvector4f *eye );
234
 
235
 
236
 
237
/* Just treat 4-vectors as 3-vectors.
238
 */
239
static build_f_func build_f_tab[5] = {
240
   NULL,
241
   NULL,
242
   build_f2,
243
   build_f3,
244
   build_f3
245
};
246
 
247
 
248
 
249
/* Special case texgen functions.
250
 */
251
static void texgen_reflection_map_nv( struct gl_context *ctx,
252
				      struct texgen_stage_data *store,
253
				      GLuint unit )
254
{
255
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
256
   GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit];
257
   GLvector4f *out = &store->texcoord[unit];
258
 
259
   build_f_tab[VB->EyePtr->size]( out->start,
260
				  out->stride,
261
				  VB->AttribPtr[_TNL_ATTRIB_NORMAL],
262
				  VB->EyePtr );
263
 
264
   out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3;
265
   out->count = VB->Count;
266
   out->size = MAX2(in->size, 3);
267
   if (in->size == 4)
268
      _mesa_copy_tab[0x8]( out, in );
269
}
270
 
271
 
272
 
273
static void texgen_normal_map_nv( struct gl_context *ctx,
274
				  struct texgen_stage_data *store,
275
				  GLuint unit )
276
{
277
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
278
   GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit];
279
   GLvector4f *out = &store->texcoord[unit];
280
   GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL];
281
   GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->start;
282
   GLuint count = VB->Count;
283
   GLuint i;
284
   const GLfloat *norm = normal->start;
285
 
286
   for (i=0;istride)) {
287
      texcoord[i][0] = norm[0];
288
      texcoord[i][1] = norm[1];
289
      texcoord[i][2] = norm[2];
290
   }
291
 
292
 
293
   out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3;
294
   out->count = count;
295
   out->size = MAX2(in->size, 3);
296
   if (in->size == 4)
297
      _mesa_copy_tab[0x8]( out, in );
298
}
299
 
300
 
301
static void texgen_sphere_map( struct gl_context *ctx,
302
			       struct texgen_stage_data *store,
303
			       GLuint unit )
304
{
305
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
306
   GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit];
307
   GLvector4f *out = &store->texcoord[unit];
308
   GLfloat (*texcoord)[4] = (GLfloat (*)[4]) out->start;
309
   GLuint count = VB->Count;
310
   GLuint i;
311
   GLfloat (*f)[3] = store->tmp_f;
312
   GLfloat *m = store->tmp_m;
313
 
314
   (build_m_tab[VB->EyePtr->size])( store->tmp_f,
315
				    store->tmp_m,
316
				    VB->AttribPtr[_TNL_ATTRIB_NORMAL],
317
				    VB->EyePtr );
318
 
319
   out->size = MAX2(in->size,2);
320
 
321
   for (i=0;i
322
      texcoord[i][0] = f[i][0] * m[i] + 0.5F;
323
      texcoord[i][1] = f[i][1] * m[i] + 0.5F;
324
   }
325
 
326
   out->count = count;
327
   out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_2;
328
   if (in->size > 2)
329
      _mesa_copy_tab[all_bits[in->size] & ~0x3]( out, in );
330
}
331
 
332
 
333
 
334
static void texgen( struct gl_context *ctx,
335
		    struct texgen_stage_data *store,
336
		    GLuint unit )
337
{
338
   TNLcontext *tnl = TNL_CONTEXT(ctx);
339
   struct vertex_buffer *VB = &tnl->vb;
340
   GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit];
341
   GLvector4f *out = &store->texcoord[unit];
342
   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[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->GenS.ObjectPlane );
374
	 break;
375
      case GL_EYE_LINEAR:
376
	 _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data,
377
				       sizeof(out->data[0]), eye,
378
				       texUnit->GenS.EyePlane );
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
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;istride)) {
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->GenT.ObjectPlane );
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->GenT.EyePlane );
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
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;istride)) {
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->GenR.ObjectPlane );
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->GenR.EyePlane );
445
	 break;
446
      case GL_REFLECTION_MAP_NV:
447
	 for (i=0;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;istride)) {
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->GenQ.ObjectPlane );
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->GenQ.EyePlane );
473
	 break;
474
      default:
475
	 _mesa_problem(ctx, "Bad Q texgen");
476
      }
477
   }
478
}
479
 
480
 
481
 
482
 
483
static 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_texture_unit *texUnit = &ctx->Texture.Unit[i];
495
 
496
      if (texUnit->TexGenEnabled) {
497
 
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
 
508
static 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_texture_unit *texUnit = &ctx->Texture.Unit[i];
519
 
520
      if (texUnit->TexGenEnabled) {
521
	 GLuint sz;
522
 
523
	 if (texUnit->TexGenEnabled & Q_BIT)
524
	    sz = 4;
525
	 else if (texUnit->TexGenEnabled & R_BIT)
526
	    sz = 3;
527
	 else if (texUnit->TexGenEnabled & T_BIT)
528
	    sz = 2;
529
	 else
530
	    sz = 1;
531
 
532
	 store->TexgenSize[i] = sz;
533
	 store->TexgenFunc[i] = texgen; /* general solution */
534
 
535
         /* look for special texgen cases */
536
	 if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT)) {
537
	    if (texUnit->_GenFlags == TEXGEN_REFLECTION_MAP_NV) {
538
	       store->TexgenFunc[i] = texgen_reflection_map_nv;
539
	    }
540
	    else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) {
541
	       store->TexgenFunc[i] = texgen_normal_map_nv;
542
	    }
543
	 }
544
	 else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) &&
545
		  texUnit->_GenFlags == TEXGEN_SPHERE_MAP) {
546
	    store->TexgenFunc[i] = texgen_sphere_map;
547
	 }
548
      }
549
   }
550
}
551
 
552
 
553
 
554
 
555
 
556
/* Called the first time stage->run() is invoked.
557
 */
558
static GLboolean alloc_texgen_data( struct gl_context *ctx,
559
				    struct tnl_pipeline_stage *stage )
560
{
561
   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
562
   struct texgen_stage_data *store;
563
   GLuint i;
564
 
565
   stage->privatePtr = CALLOC(sizeof(*store));
566
   store = TEXGEN_STAGE_DATA(stage);
567
   if (!store)
568
      return GL_FALSE;
569
 
570
   for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
571
      _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
572
 
573
   store->tmp_f = (GLfloat (*)[3]) MALLOC(VB->Size * sizeof(GLfloat) * 3);
574
   store->tmp_m = (GLfloat *) MALLOC(VB->Size * sizeof(GLfloat));
575
 
576
   return GL_TRUE;
577
}
578
 
579
 
580
static void free_texgen_data( struct tnl_pipeline_stage *stage )
581
 
582
{
583
   struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
584
   GLuint i;
585
 
586
   if (store) {
587
      for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++)
588
	 if (store->texcoord[i].data)
589
	    _mesa_vector4f_free( &store->texcoord[i] );
590
 
591
 
592
      if (store->tmp_f) FREE( store->tmp_f );
593
      if (store->tmp_m) FREE( store->tmp_m );
594
      FREE( store );
595
      stage->privatePtr = NULL;
596
   }
597
}
598
 
599
 
600
 
601
const struct tnl_pipeline_stage _tnl_texgen_stage =
602
{
603
   "texgen",			/* name */
604
   NULL,			/* private data */
605
   alloc_texgen_data,		/* destructor */
606
   free_texgen_data,		/* destructor */
607
   validate_texgen_stage,		/* check */
608
   run_texgen_stage		/* run -- initially set to alloc data */
609
};