a7c5b7db039d1ef56cf34f86c5fefb1710e7aff6
[mesa.git] / src / mesa / tnl / t_imm_eval.c
1 /* $Id: t_imm_eval.c,v 1.4 2001/01/24 00:04:59 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #include "glheader.h"
29 #include "colormac.h"
30 #include "context.h"
31 #include "macros.h"
32 #include "mem.h"
33 #include "mmath.h"
34 #include "mtypes.h"
35 #include "math/m_eval.h"
36
37 #include "t_context.h"
38 #include "t_imm_eval.h"
39 #include "t_imm_exec.h"
40 #include "t_imm_fixup.h"
41
42
43 static void eval_points1( GLfloat outcoord[][4],
44 GLfloat coord[][4],
45 const GLuint *flags,
46 GLfloat du, GLfloat u1 )
47 {
48 GLuint i;
49 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
50 if (flags[i] & VERT_EVAL_ANY) {
51 outcoord[i][0] = coord[i][0];
52 outcoord[i][1] = coord[i][1];
53 if (flags[i] & VERT_EVAL_P1)
54 outcoord[i][0] = coord[i][0] * du + u1;
55 }
56 }
57
58 static void eval_points2( GLfloat outcoord[][4],
59 GLfloat coord[][4],
60 const GLuint *flags,
61 GLfloat du, GLfloat u1,
62 GLfloat dv, GLfloat v1 )
63 {
64 GLuint i;
65 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
66 if (flags[i] & VERT_EVAL_ANY) {
67 outcoord[i][0] = coord[i][0];
68 outcoord[i][1] = coord[i][1];
69 if (flags[i] & VERT_EVAL_P2) {
70 outcoord[i][0] = coord[i][0] * du + u1;
71 outcoord[i][1] = coord[i][1] * dv + v1;
72 }
73 }
74 }
75 }
76
77 static const GLubyte dirty_flags[5] = {
78 0, /* not possible */
79 VEC_DIRTY_0,
80 VEC_DIRTY_1,
81 VEC_DIRTY_2,
82 VEC_DIRTY_3
83 };
84
85
86 static void eval1_4f( GLvector4f *dest,
87 GLfloat coord[][4],
88 const GLuint *flags,
89 GLuint dimension,
90 struct gl_1d_map *map )
91 {
92 const GLfloat u1 = map->u1;
93 const GLfloat du = map->du;
94 GLfloat (*to)[4] = dest->data;
95 GLuint i;
96
97 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
98 if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
99 GLfloat u = (coord[i][0] - u1) * du;
100 ASSIGN_4V(to[i], 0,0,0,1);
101 _math_horner_bezier_curve(map->Points, to[i], u,
102 dimension, map->Order);
103 }
104
105 dest->size = MAX2(dest->size, dimension);
106 dest->flags |= dirty_flags[dimension];
107 }
108
109
110 static void eval1_1ui( GLvector1ui *dest,
111 GLfloat coord[][4],
112 const GLuint *flags,
113 struct gl_1d_map *map )
114 {
115 const GLfloat u1 = map->u1;
116 const GLfloat du = map->du;
117 GLuint *to = dest->data;
118 GLuint i;
119
120 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
121 if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
122 GLfloat u = (coord[i][0] - u1) * du;
123 GLfloat tmp;
124 _math_horner_bezier_curve(map->Points, &tmp, u, 1, map->Order);
125 to[i] = (GLuint) (GLint) tmp;
126 }
127
128 }
129
130 static void eval1_norm( GLvector3f *dest,
131 GLfloat coord[][4],
132 const GLuint *flags,
133 struct gl_1d_map *map )
134 {
135 const GLfloat u1 = map->u1;
136 const GLfloat du = map->du;
137 GLfloat (*to)[3] = dest->data;
138 GLuint i;
139
140 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
141 if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
142 GLfloat u = (coord[i][0] - u1) * du;
143 _math_horner_bezier_curve(map->Points, to[i], u, 3, map->Order);
144 }
145 }
146
147 static void eval1_color(
148 #if CHAN_TYPE == GL_UNSIGNED_BYTE
149 GLvector4ub *dest,
150 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
151 GLvector4us *dest,
152 #elif CHAN_TYPE == GL_FLOAT
153 GLvector4f *dest,
154 #endif
155 GLfloat coord[][4],
156 const GLuint *flags,
157 struct gl_1d_map *map )
158 {
159 const GLfloat u1 = map->u1;
160 const GLfloat du = map->du;
161 GLchan (*to)[4] = dest->data;
162 GLuint i;
163
164 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
165 if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
166 GLfloat u = (coord[i][0] - u1) * du;
167 GLfloat fcolor[4];
168 _math_horner_bezier_curve(map->Points, fcolor, u, 4, map->Order);
169 UNCLAMPED_FLOAT_TO_RGBA_CHAN(to[i], fcolor);
170 }
171 }
172 }
173
174
175
176
177 static void eval2_obj_norm( GLvector4f *obj_ptr,
178 GLvector3f *norm_ptr,
179 GLfloat coord[][4],
180 GLuint *flags,
181 GLuint dimension,
182 struct gl_2d_map *map )
183 {
184 const GLfloat u1 = map->u1;
185 const GLfloat du = map->du;
186 const GLfloat v1 = map->v1;
187 const GLfloat dv = map->dv;
188 GLfloat (*obj)[4] = obj_ptr->data;
189 GLfloat (*normal)[3] = norm_ptr->data;
190 GLuint i;
191
192 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
193 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
194 GLfloat u = (coord[i][0] - u1) * du;
195 GLfloat v = (coord[i][1] - v1) * dv;
196 GLfloat du[4], dv[4];
197
198 ASSIGN_4V(obj[i], 0,0,0,1);
199 _math_de_casteljau_surf(map->Points, obj[i], du, dv, u, v, dimension,
200 map->Uorder, map->Vorder);
201
202 CROSS3(normal[i], du, dv);
203 NORMALIZE_3FV(normal[i]);
204 }
205
206 obj_ptr->size = MAX2(obj_ptr->size, dimension);
207 obj_ptr->flags |= dirty_flags[dimension];
208 }
209
210
211 static void eval2_4f( GLvector4f *dest,
212 GLfloat coord[][4],
213 const GLuint *flags,
214 GLuint dimension,
215 struct gl_2d_map *map )
216 {
217 const GLfloat u1 = map->u1;
218 const GLfloat du = map->du;
219 const GLfloat v1 = map->v1;
220 const GLfloat dv = map->dv;
221 GLfloat (*to)[4] = dest->data;
222 GLuint i;
223
224 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
225 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
226 GLfloat u = (coord[i][0] - u1) * du;
227 GLfloat v = (coord[i][1] - v1) * dv;
228 _math_horner_bezier_surf(map->Points, to[i], u, v, dimension,
229 map->Uorder, map->Vorder);
230 }
231
232 dest->size = MAX2(dest->size, dimension);
233 dest->flags |= dirty_flags[dimension];
234 }
235
236
237 static void eval2_norm( GLvector3f *dest,
238 GLfloat coord[][4],
239 GLuint *flags,
240 struct gl_2d_map *map )
241 {
242 const GLfloat u1 = map->u1;
243 const GLfloat du = map->du;
244 const GLfloat v1 = map->v1;
245 const GLfloat dv = map->dv;
246 GLfloat (*to)[3] = dest->data;
247 GLuint i;
248
249 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
250 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
251 GLfloat u = (coord[i][0] - u1) * du;
252 GLfloat v = (coord[i][1] - v1) * dv;
253 _math_horner_bezier_surf(map->Points, to[i], u, v, 3,
254 map->Uorder, map->Vorder);
255 }
256
257 }
258
259
260 static void eval2_1ui( GLvector1ui *dest,
261 GLfloat coord[][4],
262 const GLuint *flags,
263 struct gl_2d_map *map )
264 {
265 const GLfloat u1 = map->u1;
266 const GLfloat du = map->du;
267 const GLfloat v1 = map->v1;
268 const GLfloat dv = map->dv;
269 GLuint *to = dest->data;
270 GLuint i;
271
272 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
273 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
274 GLfloat u = (coord[i][0] - u1) * du;
275 GLfloat v = (coord[i][1] - v1) * dv;
276 GLfloat tmp;
277 _math_horner_bezier_surf(map->Points, &tmp, u, v, 1,
278 map->Uorder, map->Vorder);
279
280 to[i] = (GLuint) (GLint) tmp;
281 }
282 }
283
284
285
286 static void eval2_color(
287 #if CHAN_TYPE == GL_UNSIGNED_BYTE
288 GLvector4ub *dest,
289 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
290 GLvector4us *dest,
291 #elif CHAN_TYPE == GL_FLOAT
292 GLvector4f *dest,
293 #endif
294 GLfloat coord[][4],
295 GLuint *flags,
296 struct gl_2d_map *map )
297 {
298 const GLfloat u1 = map->u1;
299 const GLfloat du = map->du;
300 const GLfloat v1 = map->v1;
301 const GLfloat dv = map->dv;
302 GLchan (*to)[4] = dest->data;
303 GLuint i;
304
305 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
306 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
307 GLfloat u = (coord[i][0] - u1) * du;
308 GLfloat v = (coord[i][1] - v1) * dv;
309 GLfloat fcolor[4];
310 _math_horner_bezier_surf(map->Points, fcolor, u, v, 4,
311 map->Uorder, map->Vorder);
312 UNCLAMPED_FLOAT_TO_RGBA_CHAN(to[i], fcolor);
313 }
314 }
315 }
316
317
318
319 static void copy_4f( GLfloat to[][4], GLfloat from[][4], GLuint count )
320 {
321 MEMCPY( to, from, count * sizeof(to[0]));
322 }
323
324 static void copy_3f( GLfloat to[][3], GLfloat from[][3], GLuint count )
325 {
326 MEMCPY( to, from, (count) * sizeof(to[0]));
327 }
328
329 static void copy_4chan( GLchan to[][4], GLchan from[][4], GLuint count )
330 {
331 MEMCPY( to, from, (count) * sizeof(to[0]));
332 }
333
334 static void copy_1ui( GLuint to[], GLuint from[], GLuint count )
335 {
336 MEMCPY( to, from, (count) * sizeof(to[0]));
337 }
338
339
340
341 /* Translate eval enabled flags to VERT_* flags.
342 */
343 static void update_eval( GLcontext *ctx )
344 {
345 TNLcontext *tnl = TNL_CONTEXT(ctx);
346 GLuint eval1 = 0, eval2 = 0;
347
348 if (ctx->Eval.Map1Index)
349 eval1 |= VERT_INDEX;
350
351 if (ctx->Eval.Map2Index)
352 eval2 |= VERT_INDEX;
353
354 if (ctx->Eval.Map1Color4)
355 eval1 |= VERT_RGBA;
356
357 if (ctx->Eval.Map2Color4)
358 eval2 |= VERT_RGBA;
359
360 if (ctx->Eval.Map1Normal)
361 eval1 |= VERT_NORM;
362
363 if (ctx->Eval.Map2Normal)
364 eval2 |= VERT_NORM;
365
366 if (ctx->Eval.Map1TextureCoord4 ||
367 ctx->Eval.Map1TextureCoord3 ||
368 ctx->Eval.Map1TextureCoord2 ||
369 ctx->Eval.Map1TextureCoord1)
370 eval1 |= VERT_TEX0;
371
372 if (ctx->Eval.Map2TextureCoord4 ||
373 ctx->Eval.Map2TextureCoord3 ||
374 ctx->Eval.Map2TextureCoord2 ||
375 ctx->Eval.Map2TextureCoord1)
376 eval2 |= VERT_TEX0;
377
378 if (ctx->Eval.Map1Vertex4)
379 eval1 |= VERT_OBJ_234;
380
381 if (ctx->Eval.Map1Vertex3)
382 eval1 |= VERT_OBJ_23;
383
384 if (ctx->Eval.Map2Vertex4) {
385 if (ctx->Eval.AutoNormal)
386 eval2 |= VERT_OBJ_234 | VERT_NORM;
387 else
388 eval2 |= VERT_OBJ_234;
389 }
390 else if (ctx->Eval.Map2Vertex3) {
391 if (ctx->Eval.AutoNormal)
392 eval2 |= VERT_OBJ_23 | VERT_NORM;
393 else
394 eval2 |= VERT_OBJ_23;
395 }
396
397 tnl->eval.EvalMap1Flags = eval1;
398 tnl->eval.EvalMap2Flags = eval2;
399 tnl->eval.EvalNewState = 0;
400 }
401
402
403 /* This looks a lot like a pipeline stage, but for various reasons is
404 * better handled outside the pipeline, and considered the final stage
405 * of fixing up an immediate struct for execution.
406 *
407 * Really want to cache the results of this function in display lists,
408 * at least for EvalMesh commands.
409 */
410 void _tnl_eval_vb( GLcontext *ctx,
411 GLfloat (*coord)[4],
412 GLuint orflag,
413 GLuint andflag )
414 {
415 TNLcontext *tnl = TNL_CONTEXT(ctx);
416 struct vertex_arrays *tmp = &tnl->imm_inputs;
417 struct tnl_eval_store *store = &tnl->eval;
418 GLuint *flags = tnl->vb.Flag;
419 GLuint count = tnl->vb.Count;
420 GLuint any_eval1 = orflag & (VERT_EVAL_C1|VERT_EVAL_P1);
421 GLuint any_eval2 = orflag & (VERT_EVAL_C2|VERT_EVAL_P2);
422 GLuint all_eval = andflag & VERT_EVAL_ANY; /* may have false negatives */
423 GLuint req = 0;
424 GLuint purge_flags = 0;
425
426 if (tnl->eval.EvalNewState & _NEW_EVAL)
427 update_eval( ctx );
428
429 /* Handle the degenerate cases.
430 */
431 if (any_eval1 && !ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
432 purge_flags = (VERT_EVAL_P1|VERT_EVAL_C1);
433
434 if (any_eval2 && !ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3)
435 purge_flags |= (VERT_EVAL_P1|VERT_EVAL_C1);
436
437 if (any_eval1)
438 req |= tnl->pipeline.inputs & tnl->eval.EvalMap1Flags;
439
440 if (any_eval2)
441 req |= tnl->pipeline.inputs & tnl->eval.EvalMap2Flags;
442
443
444 /* Translate points into coords. Use store->Coord to hold the
445 * new data.
446 */
447 if (any_eval1 && (orflag & VERT_EVAL_P1))
448 {
449 eval_points1( store->Coord, coord, flags,
450 ctx->Eval.MapGrid1du,
451 ctx->Eval.MapGrid1u1);
452
453 coord = store->Coord;
454 }
455
456 if (any_eval2 && (orflag & VERT_EVAL_P2))
457 {
458 eval_points2( store->Coord, coord, flags,
459 ctx->Eval.MapGrid2du,
460 ctx->Eval.MapGrid2u1,
461 ctx->Eval.MapGrid2dv,
462 ctx->Eval.MapGrid2v1 );
463
464 coord = store->Coord;
465 }
466
467
468 /* Perform the evaluations on active data elements.
469 */
470 if (req & VERT_INDEX)
471 {
472 if (!all_eval)
473 copy_1ui( store->Index, tmp->Index.data, count );
474
475 tmp->Index.data = store->Index;
476 tmp->Index.start = store->Index;
477
478 if (ctx->Eval.Map1Index && any_eval1)
479 eval1_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map1Index );
480
481 if (ctx->Eval.Map2Index && any_eval2)
482 eval2_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map2Index );
483
484 }
485
486 if (req & VERT_RGBA)
487 {
488 if (!all_eval)
489 copy_4chan( store->Color, tmp->Color.data, count );
490
491 tmp->Color.data = store->Color;
492 tmp->Color.start = (GLchan *) store->Color;
493
494 if (ctx->Eval.Map1Color4 && any_eval1)
495 eval1_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map1Color4 );
496
497 if (ctx->Eval.Map2Color4 && any_eval2)
498 eval2_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map2Color4 );
499 }
500
501
502 if (req & VERT_TEX(0))
503 {
504 if (!all_eval)
505 copy_4f( store->TexCoord, tmp->TexCoord[0].data, count );
506 else
507 tmp->TexCoord[0].size = 0;
508
509 tmp->TexCoord[0].data = store->TexCoord;
510 tmp->TexCoord[0].start = (GLfloat *)store->TexCoord;
511
512 if (any_eval1) {
513 if (ctx->Eval.Map1TextureCoord4) {
514 eval1_4f( &tmp->TexCoord[0], coord, flags, 4,
515 &ctx->EvalMap.Map1Texture4 );
516 }
517 else if (ctx->Eval.Map1TextureCoord3) {
518 eval1_4f( &tmp->TexCoord[0], coord, flags, 3,
519 &ctx->EvalMap.Map1Texture3 );
520 }
521 else if (ctx->Eval.Map1TextureCoord2) {
522 eval1_4f( &tmp->TexCoord[0], coord, flags, 2,
523 &ctx->EvalMap.Map1Texture2 );
524 }
525 else if (ctx->Eval.Map1TextureCoord1) {
526 eval1_4f( &tmp->TexCoord[0], coord, flags, 1,
527 &ctx->EvalMap.Map1Texture1 );
528 }
529 }
530
531 if (any_eval2) {
532 if (ctx->Eval.Map2TextureCoord4) {
533 eval2_4f( &tmp->TexCoord[0], coord, flags, 4,
534 &ctx->EvalMap.Map2Texture4 );
535 }
536 else if (ctx->Eval.Map2TextureCoord3) {
537 eval2_4f( &tmp->TexCoord[0], coord, flags, 3,
538 &ctx->EvalMap.Map2Texture3 );
539 }
540 else if (ctx->Eval.Map2TextureCoord2) {
541 eval2_4f( &tmp->TexCoord[0], coord, flags, 2,
542 &ctx->EvalMap.Map2Texture2 );
543 }
544 else if (ctx->Eval.Map2TextureCoord1) {
545 eval2_4f( &tmp->TexCoord[0], coord, flags, 1,
546 &ctx->EvalMap.Map2Texture1 );
547 }
548 }
549 }
550
551
552 if (req & VERT_NORM)
553 {
554 if (!all_eval)
555 copy_3f( store->Normal, tmp->Normal.data, count );
556
557 tmp->Normal.data = store->Normal;
558 tmp->Normal.start = (GLfloat *)store->Normal;
559
560 if (ctx->Eval.Map1Normal && any_eval1)
561 eval1_norm( &tmp->Normal, coord, flags,
562 &ctx->EvalMap.Map1Normal );
563
564 if (ctx->Eval.Map2Normal && any_eval2)
565 eval2_norm( &tmp->Normal, coord, flags,
566 &ctx->EvalMap.Map2Normal );
567 }
568
569
570
571 /* In the AutoNormal case, the copy and assignment of tmp->NormalPtr
572 * are done above.
573 */
574 if (req & VERT_OBJ)
575 {
576 if (!all_eval) {
577 copy_4f( store->Obj, tmp->Obj.data, count );
578 } else
579 tmp->Obj.size = 0;
580
581 tmp->Obj.data = store->Obj;
582 tmp->Obj.start = (GLfloat *)store->Obj;
583
584 if (any_eval1) {
585 if (ctx->Eval.Map1Vertex4) {
586 eval1_4f( &tmp->Obj, coord, flags, 4,
587 &ctx->EvalMap.Map1Vertex4 );
588 }
589 else if (ctx->Eval.Map1Vertex3) {
590 eval1_4f( &tmp->Obj, coord, flags, 3,
591 &ctx->EvalMap.Map1Vertex3 );
592 }
593 }
594
595 if (any_eval2) {
596 if (ctx->Eval.Map2Vertex4)
597 {
598 if (ctx->Eval.AutoNormal && (req & VERT_NORM))
599 eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 4,
600 &ctx->EvalMap.Map2Vertex4 );
601 else
602 eval2_4f( &tmp->Obj, coord, flags, 4,
603 &ctx->EvalMap.Map2Vertex4 );
604 }
605 else if (ctx->Eval.Map2Vertex3)
606 {
607 if (ctx->Eval.AutoNormal && (req & VERT_NORM))
608 eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 3,
609 &ctx->EvalMap.Map2Vertex3 );
610 else
611 eval2_4f( &tmp->Obj, coord, flags, 3,
612 &ctx->EvalMap.Map2Vertex3 );
613 }
614 }
615 }
616
617
618 {
619 GLuint i;
620 copy_1ui( store->Flag, flags, count );
621 tnl->vb.Flag = store->Flag;
622
623 /* This is overkill, but correct as fixup will have copied the
624 * values to all vertices in the VB - we may be falsely stating
625 * that some repeated values are new, but doing so is fairly
626 * harmless.
627 */
628 for (i = 0 ; i < count ; i++)
629 store->Flag[i] |= req;
630 }
631 }
632
633
634
635
636
637
638