1207a9ab158353a5a64c6d9f9c7755f89b061194
[mesa.git] / src / mesa / tnl / t_imm_eval.c
1 /* $Id: t_imm_eval.c,v 1.5 2001/02/20 18:28:52 keithw 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( GLvector4chan *dest,
148 GLfloat coord[][4],
149 const GLuint *flags,
150 struct gl_1d_map *map )
151 {
152 const GLfloat u1 = map->u1;
153 const GLfloat du = map->du;
154 GLchan (*to)[4] = dest->data;
155 GLuint i;
156
157 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
158 if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
159 GLfloat u = (coord[i][0] - u1) * du;
160 GLfloat fcolor[4];
161 _math_horner_bezier_curve(map->Points, fcolor, u, 4, map->Order);
162 UNCLAMPED_FLOAT_TO_RGBA_CHAN(to[i], fcolor);
163 }
164 }
165 }
166
167
168
169
170 static void eval2_obj_norm( GLvector4f *obj_ptr,
171 GLvector3f *norm_ptr,
172 GLfloat coord[][4],
173 GLuint *flags,
174 GLuint dimension,
175 struct gl_2d_map *map )
176 {
177 const GLfloat u1 = map->u1;
178 const GLfloat du = map->du;
179 const GLfloat v1 = map->v1;
180 const GLfloat dv = map->dv;
181 GLfloat (*obj)[4] = obj_ptr->data;
182 GLfloat (*normal)[3] = norm_ptr->data;
183 GLuint i;
184
185 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
186 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
187 GLfloat u = (coord[i][0] - u1) * du;
188 GLfloat v = (coord[i][1] - v1) * dv;
189 GLfloat du[4], dv[4];
190
191 ASSIGN_4V(obj[i], 0,0,0,1);
192 _math_de_casteljau_surf(map->Points, obj[i], du, dv, u, v, dimension,
193 map->Uorder, map->Vorder);
194
195 CROSS3(normal[i], du, dv);
196 NORMALIZE_3FV(normal[i]);
197 }
198
199 obj_ptr->size = MAX2(obj_ptr->size, dimension);
200 obj_ptr->flags |= dirty_flags[dimension];
201 }
202
203
204 static void eval2_4f( GLvector4f *dest,
205 GLfloat coord[][4],
206 const GLuint *flags,
207 GLuint dimension,
208 struct gl_2d_map *map )
209 {
210 const GLfloat u1 = map->u1;
211 const GLfloat du = map->du;
212 const GLfloat v1 = map->v1;
213 const GLfloat dv = map->dv;
214 GLfloat (*to)[4] = dest->data;
215 GLuint i;
216
217 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
218 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
219 GLfloat u = (coord[i][0] - u1) * du;
220 GLfloat v = (coord[i][1] - v1) * dv;
221 _math_horner_bezier_surf(map->Points, to[i], u, v, dimension,
222 map->Uorder, map->Vorder);
223 }
224
225 dest->size = MAX2(dest->size, dimension);
226 dest->flags |= dirty_flags[dimension];
227 }
228
229
230 static void eval2_norm( GLvector3f *dest,
231 GLfloat coord[][4],
232 GLuint *flags,
233 struct gl_2d_map *map )
234 {
235 const GLfloat u1 = map->u1;
236 const GLfloat du = map->du;
237 const GLfloat v1 = map->v1;
238 const GLfloat dv = map->dv;
239 GLfloat (*to)[3] = dest->data;
240 GLuint i;
241
242 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
243 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
244 GLfloat u = (coord[i][0] - u1) * du;
245 GLfloat v = (coord[i][1] - v1) * dv;
246 _math_horner_bezier_surf(map->Points, to[i], u, v, 3,
247 map->Uorder, map->Vorder);
248 }
249
250 }
251
252
253 static void eval2_1ui( GLvector1ui *dest,
254 GLfloat coord[][4],
255 const GLuint *flags,
256 struct gl_2d_map *map )
257 {
258 const GLfloat u1 = map->u1;
259 const GLfloat du = map->du;
260 const GLfloat v1 = map->v1;
261 const GLfloat dv = map->dv;
262 GLuint *to = dest->data;
263 GLuint i;
264
265 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
266 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
267 GLfloat u = (coord[i][0] - u1) * du;
268 GLfloat v = (coord[i][1] - v1) * dv;
269 GLfloat tmp;
270 _math_horner_bezier_surf(map->Points, &tmp, u, v, 1,
271 map->Uorder, map->Vorder);
272
273 to[i] = (GLuint) (GLint) tmp;
274 }
275 }
276
277
278
279 static void eval2_color( GLvector4chan *dest,
280 GLfloat coord[][4],
281 GLuint *flags,
282 struct gl_2d_map *map )
283 {
284 const GLfloat u1 = map->u1;
285 const GLfloat du = map->du;
286 const GLfloat v1 = map->v1;
287 const GLfloat dv = map->dv;
288 GLchan (*to)[4] = dest->data;
289 GLuint i;
290
291 for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
292 if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
293 GLfloat u = (coord[i][0] - u1) * du;
294 GLfloat v = (coord[i][1] - v1) * dv;
295 GLfloat fcolor[4];
296 _math_horner_bezier_surf(map->Points, fcolor, u, v, 4,
297 map->Uorder, map->Vorder);
298 UNCLAMPED_FLOAT_TO_RGBA_CHAN(to[i], fcolor);
299 }
300 }
301 }
302
303
304
305 static void copy_4f( GLfloat to[][4], GLfloat from[][4], GLuint count )
306 {
307 MEMCPY( to, from, count * sizeof(to[0]));
308 }
309
310 static void copy_3f( GLfloat to[][3], GLfloat from[][3], GLuint count )
311 {
312 MEMCPY( to, from, (count) * sizeof(to[0]));
313 }
314
315 static void copy_4chan( GLchan to[][4], GLchan from[][4], GLuint count )
316 {
317 MEMCPY( to, from, (count) * sizeof(to[0]));
318 }
319
320 static void copy_1ui( GLuint to[], GLuint from[], GLuint count )
321 {
322 MEMCPY( to, from, (count) * sizeof(to[0]));
323 }
324
325
326
327 /* Translate eval enabled flags to VERT_* flags.
328 */
329 static void update_eval( GLcontext *ctx )
330 {
331 TNLcontext *tnl = TNL_CONTEXT(ctx);
332 GLuint eval1 = 0, eval2 = 0;
333
334 if (ctx->Eval.Map1Index)
335 eval1 |= VERT_INDEX;
336
337 if (ctx->Eval.Map2Index)
338 eval2 |= VERT_INDEX;
339
340 if (ctx->Eval.Map1Color4)
341 eval1 |= VERT_RGBA;
342
343 if (ctx->Eval.Map2Color4)
344 eval2 |= VERT_RGBA;
345
346 if (ctx->Eval.Map1Normal)
347 eval1 |= VERT_NORM;
348
349 if (ctx->Eval.Map2Normal)
350 eval2 |= VERT_NORM;
351
352 if (ctx->Eval.Map1TextureCoord4 ||
353 ctx->Eval.Map1TextureCoord3 ||
354 ctx->Eval.Map1TextureCoord2 ||
355 ctx->Eval.Map1TextureCoord1)
356 eval1 |= VERT_TEX0;
357
358 if (ctx->Eval.Map2TextureCoord4 ||
359 ctx->Eval.Map2TextureCoord3 ||
360 ctx->Eval.Map2TextureCoord2 ||
361 ctx->Eval.Map2TextureCoord1)
362 eval2 |= VERT_TEX0;
363
364 if (ctx->Eval.Map1Vertex4)
365 eval1 |= VERT_OBJ_234;
366
367 if (ctx->Eval.Map1Vertex3)
368 eval1 |= VERT_OBJ_23;
369
370 if (ctx->Eval.Map2Vertex4) {
371 if (ctx->Eval.AutoNormal)
372 eval2 |= VERT_OBJ_234 | VERT_NORM;
373 else
374 eval2 |= VERT_OBJ_234;
375 }
376 else if (ctx->Eval.Map2Vertex3) {
377 if (ctx->Eval.AutoNormal)
378 eval2 |= VERT_OBJ_23 | VERT_NORM;
379 else
380 eval2 |= VERT_OBJ_23;
381 }
382
383 tnl->eval.EvalMap1Flags = eval1;
384 tnl->eval.EvalMap2Flags = eval2;
385 tnl->eval.EvalNewState = 0;
386 }
387
388
389 /* This looks a lot like a pipeline stage, but for various reasons is
390 * better handled outside the pipeline, and considered the final stage
391 * of fixing up an immediate struct for execution.
392 *
393 * Really want to cache the results of this function in display lists,
394 * at least for EvalMesh commands.
395 */
396 void _tnl_eval_vb( GLcontext *ctx,
397 GLfloat (*coord)[4],
398 GLuint orflag,
399 GLuint andflag )
400 {
401 TNLcontext *tnl = TNL_CONTEXT(ctx);
402 struct vertex_arrays *tmp = &tnl->imm_inputs;
403 struct tnl_eval_store *store = &tnl->eval;
404 GLuint *flags = tnl->vb.Flag;
405 GLuint count = tnl->vb.Count;
406 GLuint any_eval1 = orflag & (VERT_EVAL_C1|VERT_EVAL_P1);
407 GLuint any_eval2 = orflag & (VERT_EVAL_C2|VERT_EVAL_P2);
408 GLuint all_eval = andflag & VERT_EVAL_ANY; /* may have false negatives */
409 GLuint req = 0;
410 GLuint purge_flags = 0;
411
412 if (tnl->eval.EvalNewState & _NEW_EVAL)
413 update_eval( ctx );
414
415 /* Handle the degenerate cases.
416 */
417 if (any_eval1 && !ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
418 purge_flags = (VERT_EVAL_P1|VERT_EVAL_C1);
419
420 if (any_eval2 && !ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3)
421 purge_flags |= (VERT_EVAL_P1|VERT_EVAL_C1);
422
423 if (any_eval1)
424 req |= tnl->pipeline.inputs & tnl->eval.EvalMap1Flags;
425
426 if (any_eval2)
427 req |= tnl->pipeline.inputs & tnl->eval.EvalMap2Flags;
428
429
430 /* Translate points into coords. Use store->Coord to hold the
431 * new data.
432 */
433 if (any_eval1 && (orflag & VERT_EVAL_P1))
434 {
435 eval_points1( store->Coord, coord, flags,
436 ctx->Eval.MapGrid1du,
437 ctx->Eval.MapGrid1u1);
438
439 coord = store->Coord;
440 }
441
442 if (any_eval2 && (orflag & VERT_EVAL_P2))
443 {
444 eval_points2( store->Coord, coord, flags,
445 ctx->Eval.MapGrid2du,
446 ctx->Eval.MapGrid2u1,
447 ctx->Eval.MapGrid2dv,
448 ctx->Eval.MapGrid2v1 );
449
450 coord = store->Coord;
451 }
452
453
454 /* Perform the evaluations on active data elements.
455 */
456 if (req & VERT_INDEX)
457 {
458 if (!all_eval)
459 copy_1ui( store->Index, tmp->Index.data, count );
460
461 tmp->Index.data = store->Index;
462 tmp->Index.start = store->Index;
463
464 if (ctx->Eval.Map1Index && any_eval1)
465 eval1_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map1Index );
466
467 if (ctx->Eval.Map2Index && any_eval2)
468 eval2_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map2Index );
469
470 }
471
472 if (req & VERT_RGBA)
473 {
474 if (!all_eval)
475 copy_4chan( store->Color, tmp->Color.data, count );
476
477 tmp->Color.data = store->Color;
478 tmp->Color.start = (GLchan *) store->Color;
479
480 if (ctx->Eval.Map1Color4 && any_eval1)
481 eval1_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map1Color4 );
482
483 if (ctx->Eval.Map2Color4 && any_eval2)
484 eval2_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map2Color4 );
485 }
486
487
488 if (req & VERT_TEX(0))
489 {
490 if (!all_eval)
491 copy_4f( store->TexCoord, tmp->TexCoord[0].data, count );
492 else
493 tmp->TexCoord[0].size = 0;
494
495 tmp->TexCoord[0].data = store->TexCoord;
496 tmp->TexCoord[0].start = (GLfloat *)store->TexCoord;
497
498 if (any_eval1) {
499 if (ctx->Eval.Map1TextureCoord4) {
500 eval1_4f( &tmp->TexCoord[0], coord, flags, 4,
501 &ctx->EvalMap.Map1Texture4 );
502 }
503 else if (ctx->Eval.Map1TextureCoord3) {
504 eval1_4f( &tmp->TexCoord[0], coord, flags, 3,
505 &ctx->EvalMap.Map1Texture3 );
506 }
507 else if (ctx->Eval.Map1TextureCoord2) {
508 eval1_4f( &tmp->TexCoord[0], coord, flags, 2,
509 &ctx->EvalMap.Map1Texture2 );
510 }
511 else if (ctx->Eval.Map1TextureCoord1) {
512 eval1_4f( &tmp->TexCoord[0], coord, flags, 1,
513 &ctx->EvalMap.Map1Texture1 );
514 }
515 }
516
517 if (any_eval2) {
518 if (ctx->Eval.Map2TextureCoord4) {
519 eval2_4f( &tmp->TexCoord[0], coord, flags, 4,
520 &ctx->EvalMap.Map2Texture4 );
521 }
522 else if (ctx->Eval.Map2TextureCoord3) {
523 eval2_4f( &tmp->TexCoord[0], coord, flags, 3,
524 &ctx->EvalMap.Map2Texture3 );
525 }
526 else if (ctx->Eval.Map2TextureCoord2) {
527 eval2_4f( &tmp->TexCoord[0], coord, flags, 2,
528 &ctx->EvalMap.Map2Texture2 );
529 }
530 else if (ctx->Eval.Map2TextureCoord1) {
531 eval2_4f( &tmp->TexCoord[0], coord, flags, 1,
532 &ctx->EvalMap.Map2Texture1 );
533 }
534 }
535 }
536
537
538 if (req & VERT_NORM)
539 {
540 if (!all_eval)
541 copy_3f( store->Normal, tmp->Normal.data, count );
542
543 tmp->Normal.data = store->Normal;
544 tmp->Normal.start = (GLfloat *)store->Normal;
545
546 if (ctx->Eval.Map1Normal && any_eval1)
547 eval1_norm( &tmp->Normal, coord, flags,
548 &ctx->EvalMap.Map1Normal );
549
550 if (ctx->Eval.Map2Normal && any_eval2)
551 eval2_norm( &tmp->Normal, coord, flags,
552 &ctx->EvalMap.Map2Normal );
553 }
554
555
556
557 /* In the AutoNormal case, the copy and assignment of tmp->NormalPtr
558 * are done above.
559 */
560 if (req & VERT_OBJ)
561 {
562 if (!all_eval) {
563 copy_4f( store->Obj, tmp->Obj.data, count );
564 } else
565 tmp->Obj.size = 0;
566
567 tmp->Obj.data = store->Obj;
568 tmp->Obj.start = (GLfloat *)store->Obj;
569
570 if (any_eval1) {
571 if (ctx->Eval.Map1Vertex4) {
572 eval1_4f( &tmp->Obj, coord, flags, 4,
573 &ctx->EvalMap.Map1Vertex4 );
574 }
575 else if (ctx->Eval.Map1Vertex3) {
576 eval1_4f( &tmp->Obj, coord, flags, 3,
577 &ctx->EvalMap.Map1Vertex3 );
578 }
579 }
580
581 if (any_eval2) {
582 if (ctx->Eval.Map2Vertex4)
583 {
584 if (ctx->Eval.AutoNormal && (req & VERT_NORM))
585 eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 4,
586 &ctx->EvalMap.Map2Vertex4 );
587 else
588 eval2_4f( &tmp->Obj, coord, flags, 4,
589 &ctx->EvalMap.Map2Vertex4 );
590 }
591 else if (ctx->Eval.Map2Vertex3)
592 {
593 if (ctx->Eval.AutoNormal && (req & VERT_NORM))
594 eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 3,
595 &ctx->EvalMap.Map2Vertex3 );
596 else
597 eval2_4f( &tmp->Obj, coord, flags, 3,
598 &ctx->EvalMap.Map2Vertex3 );
599 }
600 }
601 }
602
603
604 {
605 GLuint i;
606 copy_1ui( store->Flag, flags, count );
607 tnl->vb.Flag = store->Flag;
608
609 /* This is overkill, but correct as fixup will have copied the
610 * values to all vertices in the VB - we may be falsely stating
611 * that some repeated values are new, but doing so is fairly
612 * harmless.
613 */
614 for (i = 0 ; i < count ; i++)
615 store->Flag[i] |= req;
616 }
617 }
618
619
620
621
622
623
624