1
2/*
3 * Mesa 3-D graphics library
4 * Version:  5.1
5 *
6 * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27/*
28 * eval.c was written by
29 * Bernd Barsuhn (bdbarsuh@cip.informatik.uni-erlangen.de) and
30 * Volker Weiss (vrweiss@cip.informatik.uni-erlangen.de).
31 *
32 * My original implementation of evaluators was simplistic and didn't
33 * compute surface normal vectors properly.  Bernd and Volker applied
34 * used more sophisticated methods to get better results.
35 *
36 * Thanks guys!
37 */
38
39
40#include "glheader.h"
41#include "imports.h"
42#include "colormac.h"
43#include "context.h"
44#include "eval.h"
45#include "macros.h"
46#include "mfeatures.h"
47#include "mtypes.h"
48#include "main/dispatch.h"
49
50
51#if FEATURE_evaluators
52
53
54/*
55 * Return the number of components per control point for any type of
56 * evaluator.  Return 0 if bad target.
57 * See table 5.1 in the OpenGL 1.2 spec.
58 */
59GLuint _mesa_evaluator_components( GLenum target )
60{
61   switch (target) {
62      case GL_MAP1_VERTEX_3:		return 3;
63      case GL_MAP1_VERTEX_4:		return 4;
64      case GL_MAP1_INDEX:		return 1;
65      case GL_MAP1_COLOR_4:		return 4;
66      case GL_MAP1_NORMAL:		return 3;
67      case GL_MAP1_TEXTURE_COORD_1:	return 1;
68      case GL_MAP1_TEXTURE_COORD_2:	return 2;
69      case GL_MAP1_TEXTURE_COORD_3:	return 3;
70      case GL_MAP1_TEXTURE_COORD_4:	return 4;
71      case GL_MAP2_VERTEX_3:		return 3;
72      case GL_MAP2_VERTEX_4:		return 4;
73      case GL_MAP2_INDEX:		return 1;
74      case GL_MAP2_COLOR_4:		return 4;
75      case GL_MAP2_NORMAL:		return 3;
76      case GL_MAP2_TEXTURE_COORD_1:	return 1;
77      case GL_MAP2_TEXTURE_COORD_2:	return 2;
78      case GL_MAP2_TEXTURE_COORD_3:	return 3;
79      case GL_MAP2_TEXTURE_COORD_4:	return 4;
80      default:				break;
81   }
82
83   /* XXX need to check for the vertex program extension
84   if (!ctx->Extensions.NV_vertex_program)
85      return 0;
86   */
87
88   if (target >= GL_MAP1_VERTEX_ATTRIB0_4_NV &&
89       target <= GL_MAP1_VERTEX_ATTRIB15_4_NV)
90      return 4;
91
92   if (target >= GL_MAP2_VERTEX_ATTRIB0_4_NV &&
93       target <= GL_MAP2_VERTEX_ATTRIB15_4_NV)
94      return 4;
95
96   return 0;
97}
98
99
100/*
101 * Return pointer to the gl_1d_map struct for the named target.
102 */
103static struct gl_1d_map *
104get_1d_map( struct gl_context *ctx, GLenum target )
105{
106   switch (target) {
107      case GL_MAP1_VERTEX_3:
108         return &ctx->EvalMap.Map1Vertex3;
109      case GL_MAP1_VERTEX_4:
110         return &ctx->EvalMap.Map1Vertex4;
111      case GL_MAP1_INDEX:
112         return &ctx->EvalMap.Map1Index;
113      case GL_MAP1_COLOR_4:
114         return &ctx->EvalMap.Map1Color4;
115      case GL_MAP1_NORMAL:
116         return &ctx->EvalMap.Map1Normal;
117      case GL_MAP1_TEXTURE_COORD_1:
118         return &ctx->EvalMap.Map1Texture1;
119      case GL_MAP1_TEXTURE_COORD_2:
120         return &ctx->EvalMap.Map1Texture2;
121      case GL_MAP1_TEXTURE_COORD_3:
122         return &ctx->EvalMap.Map1Texture3;
123      case GL_MAP1_TEXTURE_COORD_4:
124         return &ctx->EvalMap.Map1Texture4;
125      case GL_MAP1_VERTEX_ATTRIB0_4_NV:
126      case GL_MAP1_VERTEX_ATTRIB1_4_NV:
127      case GL_MAP1_VERTEX_ATTRIB2_4_NV:
128      case GL_MAP1_VERTEX_ATTRIB3_4_NV:
129      case GL_MAP1_VERTEX_ATTRIB4_4_NV:
130      case GL_MAP1_VERTEX_ATTRIB5_4_NV:
131      case GL_MAP1_VERTEX_ATTRIB6_4_NV:
132      case GL_MAP1_VERTEX_ATTRIB7_4_NV:
133      case GL_MAP1_VERTEX_ATTRIB8_4_NV:
134      case GL_MAP1_VERTEX_ATTRIB9_4_NV:
135      case GL_MAP1_VERTEX_ATTRIB10_4_NV:
136      case GL_MAP1_VERTEX_ATTRIB11_4_NV:
137      case GL_MAP1_VERTEX_ATTRIB12_4_NV:
138      case GL_MAP1_VERTEX_ATTRIB13_4_NV:
139      case GL_MAP1_VERTEX_ATTRIB14_4_NV:
140      case GL_MAP1_VERTEX_ATTRIB15_4_NV:
141         if (!ctx->Extensions.NV_vertex_program)
142            return NULL;
143         return &ctx->EvalMap.Map1Attrib[target - GL_MAP1_VERTEX_ATTRIB0_4_NV];
144      default:
145         return NULL;
146   }
147}
148
149
150/*
151 * Return pointer to the gl_2d_map struct for the named target.
152 */
153static struct gl_2d_map *
154get_2d_map( struct gl_context *ctx, GLenum target )
155{
156   switch (target) {
157      case GL_MAP2_VERTEX_3:
158         return &ctx->EvalMap.Map2Vertex3;
159      case GL_MAP2_VERTEX_4:
160         return &ctx->EvalMap.Map2Vertex4;
161      case GL_MAP2_INDEX:
162         return &ctx->EvalMap.Map2Index;
163      case GL_MAP2_COLOR_4:
164         return &ctx->EvalMap.Map2Color4;
165      case GL_MAP2_NORMAL:
166         return &ctx->EvalMap.Map2Normal;
167      case GL_MAP2_TEXTURE_COORD_1:
168         return &ctx->EvalMap.Map2Texture1;
169      case GL_MAP2_TEXTURE_COORD_2:
170         return &ctx->EvalMap.Map2Texture2;
171      case GL_MAP2_TEXTURE_COORD_3:
172         return &ctx->EvalMap.Map2Texture3;
173      case GL_MAP2_TEXTURE_COORD_4:
174         return &ctx->EvalMap.Map2Texture4;
175      case GL_MAP2_VERTEX_ATTRIB0_4_NV:
176      case GL_MAP2_VERTEX_ATTRIB1_4_NV:
177      case GL_MAP2_VERTEX_ATTRIB2_4_NV:
178      case GL_MAP2_VERTEX_ATTRIB3_4_NV:
179      case GL_MAP2_VERTEX_ATTRIB4_4_NV:
180      case GL_MAP2_VERTEX_ATTRIB5_4_NV:
181      case GL_MAP2_VERTEX_ATTRIB6_4_NV:
182      case GL_MAP2_VERTEX_ATTRIB7_4_NV:
183      case GL_MAP2_VERTEX_ATTRIB8_4_NV:
184      case GL_MAP2_VERTEX_ATTRIB9_4_NV:
185      case GL_MAP2_VERTEX_ATTRIB10_4_NV:
186      case GL_MAP2_VERTEX_ATTRIB11_4_NV:
187      case GL_MAP2_VERTEX_ATTRIB12_4_NV:
188      case GL_MAP2_VERTEX_ATTRIB13_4_NV:
189      case GL_MAP2_VERTEX_ATTRIB14_4_NV:
190      case GL_MAP2_VERTEX_ATTRIB15_4_NV:
191         if (!ctx->Extensions.NV_vertex_program)
192            return NULL;
193         return &ctx->EvalMap.Map2Attrib[target - GL_MAP2_VERTEX_ATTRIB0_4_NV];
194      default:
195         return NULL;
196   }
197}
198
199
200/**********************************************************************/
201/***            Copy and deallocate control points                  ***/
202/**********************************************************************/
203
204
205/*
206 * Copy 1-parametric evaluator control points from user-specified
207 * memory space to a buffer of contiguous control points.
208 * \param see glMap1f for details
209 * \return pointer to buffer of contiguous control points or NULL if out
210 *          of memory.
211 */
212GLfloat *_mesa_copy_map_points1f( GLenum target, GLint ustride, GLint uorder,
213                                  const GLfloat *points )
214{
215   GLfloat *buffer, *p;
216   GLint i, k, size = _mesa_evaluator_components(target);
217
218   if (!points || !size)
219      return NULL;
220
221   buffer = (GLfloat *) MALLOC(uorder * size * sizeof(GLfloat));
222
223   if (buffer)
224      for (i = 0, p = buffer; i < uorder; i++, points += ustride)
225	for (k = 0; k < size; k++)
226	  *p++ = points[k];
227
228   return buffer;
229}
230
231
232
233/*
234 * Same as above but convert doubles to floats.
235 */
236GLfloat *_mesa_copy_map_points1d( GLenum target, GLint ustride, GLint uorder,
237                                  const GLdouble *points )
238{
239   GLfloat *buffer, *p;
240   GLint i, k, size = _mesa_evaluator_components(target);
241
242   if (!points || !size)
243      return NULL;
244
245   buffer = (GLfloat *) MALLOC(uorder * size * sizeof(GLfloat));
246
247   if (buffer)
248      for (i = 0, p = buffer; i < uorder; i++, points += ustride)
249	for (k = 0; k < size; k++)
250	  *p++ = (GLfloat) points[k];
251
252   return buffer;
253}
254
255
256
257/*
258 * Copy 2-parametric evaluator control points from user-specified
259 * memory space to a buffer of contiguous control points.
260 * Additional memory is allocated to be used by the horner and
261 * de Casteljau evaluation schemes.
262 *
263 * \param see glMap2f for details
264 * \return pointer to buffer of contiguous control points or NULL if out
265 *          of memory.
266 */
267GLfloat *_mesa_copy_map_points2f( GLenum target,
268                                  GLint ustride, GLint uorder,
269                                  GLint vstride, GLint vorder,
270                                  const GLfloat *points )
271{
272   GLfloat *buffer, *p;
273   GLint i, j, k, size, dsize, hsize;
274   GLint uinc;
275
276   size = _mesa_evaluator_components(target);
277
278   if (!points || size==0) {
279      return NULL;
280   }
281
282   /* max(uorder, vorder) additional points are used in      */
283   /* horner evaluation and uorder*vorder additional */
284   /* values are needed for de Casteljau                     */
285   dsize = (uorder == 2 && vorder == 2)? 0 : uorder*vorder;
286   hsize = (uorder > vorder ? uorder : vorder)*size;
287
288   if(hsize>dsize)
289     buffer = (GLfloat *) MALLOC((uorder*vorder*size+hsize)*sizeof(GLfloat));
290   else
291     buffer = (GLfloat *) MALLOC((uorder*vorder*size+dsize)*sizeof(GLfloat));
292
293   /* compute the increment value for the u-loop */
294   uinc = ustride - vorder*vstride;
295
296   if (buffer)
297      for (i=0, p=buffer; i<uorder; i++, points += uinc)
298	 for (j=0; j<vorder; j++, points += vstride)
299	    for (k=0; k<size; k++)
300	       *p++ = points[k];
301
302   return buffer;
303}
304
305
306
307/*
308 * Same as above but convert doubles to floats.
309 */
310GLfloat *_mesa_copy_map_points2d(GLenum target,
311                                 GLint ustride, GLint uorder,
312                                 GLint vstride, GLint vorder,
313                                 const GLdouble *points )
314{
315   GLfloat *buffer, *p;
316   GLint i, j, k, size, hsize, dsize;
317   GLint uinc;
318
319   size = _mesa_evaluator_components(target);
320
321   if (!points || size==0) {
322      return NULL;
323   }
324
325   /* max(uorder, vorder) additional points are used in      */
326   /* horner evaluation and uorder*vorder additional */
327   /* values are needed for de Casteljau                     */
328   dsize = (uorder == 2 && vorder == 2)? 0 : uorder*vorder;
329   hsize = (uorder > vorder ? uorder : vorder)*size;
330
331   if(hsize>dsize)
332     buffer = (GLfloat *) MALLOC((uorder*vorder*size+hsize)*sizeof(GLfloat));
333   else
334     buffer = (GLfloat *) MALLOC((uorder*vorder*size+dsize)*sizeof(GLfloat));
335
336   /* compute the increment value for the u-loop */
337   uinc = ustride - vorder*vstride;
338
339   if (buffer)
340      for (i=0, p=buffer; i<uorder; i++, points += uinc)
341	 for (j=0; j<vorder; j++, points += vstride)
342	    for (k=0; k<size; k++)
343	       *p++ = (GLfloat) points[k];
344
345   return buffer;
346}
347
348
349
350
351/**********************************************************************/
352/***                      API entry points                          ***/
353/**********************************************************************/
354
355
356/*
357 * This does the work of glMap1[fd].
358 */
359static void
360map1(GLenum target, GLfloat u1, GLfloat u2, GLint ustride,
361     GLint uorder, const GLvoid *points, GLenum type )
362{
363   GET_CURRENT_CONTEXT(ctx);
364   GLint k;
365   GLfloat *pnts;
366   struct gl_1d_map *map = NULL;
367
368   ASSERT_OUTSIDE_BEGIN_END(ctx);
369   ASSERT(type == GL_FLOAT || type == GL_DOUBLE);
370
371   if (u1 == u2) {
372      _mesa_error( ctx, GL_INVALID_VALUE, "glMap1(u1,u2)" );
373      return;
374   }
375   if (uorder < 1 || uorder > MAX_EVAL_ORDER) {
376      _mesa_error( ctx, GL_INVALID_VALUE, "glMap1(order)" );
377      return;
378   }
379   if (!points) {
380      _mesa_error( ctx, GL_INVALID_VALUE, "glMap1(points)" );
381      return;
382   }
383
384   k = _mesa_evaluator_components( target );
385   if (k == 0) {
386      _mesa_error( ctx, GL_INVALID_ENUM, "glMap1(target)" );
387   }
388
389   if (ustride < k) {
390      _mesa_error( ctx, GL_INVALID_VALUE, "glMap1(stride)" );
391      return;
392   }
393
394   if (ctx->Texture.CurrentUnit != 0) {
395      /* See OpenGL 1.2.1 spec, section F.2.13 */
396      _mesa_error( ctx, GL_INVALID_OPERATION, "glMap2(ACTIVE_TEXTURE != 0)" );
397      return;
398   }
399
400   map = get_1d_map(ctx, target);
401   if (!map) {
402      _mesa_error( ctx, GL_INVALID_ENUM, "glMap1(target)" );
403      return;
404   }
405
406   /* make copy of the control points */
407   if (type == GL_FLOAT)
408      pnts = _mesa_copy_map_points1f(target, ustride, uorder, (GLfloat*) points);
409   else
410      pnts = _mesa_copy_map_points1d(target, ustride, uorder, (GLdouble*) points);
411
412
413   FLUSH_VERTICES(ctx, _NEW_EVAL);
414   map->Order = uorder;
415   map->u1 = u1;
416   map->u2 = u2;
417   map->du = 1.0F / (u2 - u1);
418   if (map->Points)
419      FREE( map->Points );
420   map->Points = pnts;
421}
422
423
424
425static void GLAPIENTRY
426_mesa_Map1f( GLenum target, GLfloat u1, GLfloat u2, GLint stride,
427             GLint order, const GLfloat *points )
428{
429   map1(target, u1, u2, stride, order, points, GL_FLOAT);
430}
431
432
433static void GLAPIENTRY
434_mesa_Map1d( GLenum target, GLdouble u1, GLdouble u2, GLint stride,
435             GLint order, const GLdouble *points )
436{
437   map1(target, (GLfloat) u1, (GLfloat) u2, stride, order, points, GL_DOUBLE);
438}
439
440
441static void
442map2( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder,
443      GLfloat v1, GLfloat v2, GLint vstride, GLint vorder,
444      const GLvoid *points, GLenum type )
445{
446   GET_CURRENT_CONTEXT(ctx);
447   GLint k;
448   GLfloat *pnts;
449   struct gl_2d_map *map = NULL;
450
451   ASSERT_OUTSIDE_BEGIN_END(ctx);
452   ASSERT(type == GL_FLOAT || type == GL_DOUBLE);
453
454   if (u1==u2) {
455      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(u1,u2)" );
456      return;
457   }
458
459   if (v1==v2) {
460      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(v1,v2)" );
461      return;
462   }
463
464   if (uorder<1 || uorder>MAX_EVAL_ORDER) {
465      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(uorder)" );
466      return;
467   }
468
469   if (vorder<1 || vorder>MAX_EVAL_ORDER) {
470      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(vorder)" );
471      return;
472   }
473
474   k = _mesa_evaluator_components( target );
475   if (k==0) {
476      _mesa_error( ctx, GL_INVALID_ENUM, "glMap2(target)" );
477   }
478
479   if (ustride < k) {
480      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(ustride)" );
481      return;
482   }
483   if (vstride < k) {
484      _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(vstride)" );
485      return;
486   }
487
488   if (ctx->Texture.CurrentUnit != 0) {
489      /* See OpenGL 1.2.1 spec, section F.2.13 */
490      _mesa_error( ctx, GL_INVALID_OPERATION, "glMap2(ACTIVE_TEXTURE != 0)" );
491      return;
492   }
493
494   map = get_2d_map(ctx, target);
495   if (!map) {
496      _mesa_error( ctx, GL_INVALID_ENUM, "glMap2(target)" );
497      return;
498   }
499
500   /* make copy of the control points */
501   if (type == GL_FLOAT)
502      pnts = _mesa_copy_map_points2f(target, ustride, uorder,
503                                  vstride, vorder, (GLfloat*) points);
504   else
505      pnts = _mesa_copy_map_points2d(target, ustride, uorder,
506                                  vstride, vorder, (GLdouble*) points);
507
508
509   FLUSH_VERTICES(ctx, _NEW_EVAL);
510   map->Uorder = uorder;
511   map->u1 = u1;
512   map->u2 = u2;
513   map->du = 1.0F / (u2 - u1);
514   map->Vorder = vorder;
515   map->v1 = v1;
516   map->v2 = v2;
517   map->dv = 1.0F / (v2 - v1);
518   if (map->Points)
519      FREE( map->Points );
520   map->Points = pnts;
521}
522
523
524static void GLAPIENTRY
525_mesa_Map2f( GLenum target,
526             GLfloat u1, GLfloat u2, GLint ustride, GLint uorder,
527             GLfloat v1, GLfloat v2, GLint vstride, GLint vorder,
528             const GLfloat *points)
529{
530   map2(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder,
531        points, GL_FLOAT);
532}
533
534
535static void GLAPIENTRY
536_mesa_Map2d( GLenum target,
537             GLdouble u1, GLdouble u2, GLint ustride, GLint uorder,
538             GLdouble v1, GLdouble v2, GLint vstride, GLint vorder,
539             const GLdouble *points )
540{
541   map2(target, (GLfloat) u1, (GLfloat) u2, ustride, uorder,
542	(GLfloat) v1, (GLfloat) v2, vstride, vorder, points, GL_DOUBLE);
543}
544
545
546
547static void GLAPIENTRY
548_mesa_GetnMapdvARB( GLenum target, GLenum query, GLsizei bufSize, GLdouble *v )
549{
550   GET_CURRENT_CONTEXT(ctx);
551   struct gl_1d_map *map1d;
552   struct gl_2d_map *map2d;
553   GLint i, n;
554   GLfloat *data;
555   GLuint comps;
556   GLsizei numBytes;
557
558   ASSERT_OUTSIDE_BEGIN_END(ctx);
559
560   comps = _mesa_evaluator_components(target);
561   if (!comps) {
562      _mesa_error( ctx, GL_INVALID_ENUM, "glGetMapdv(target)" );
563      return;
564   }
565
566   map1d = get_1d_map(ctx, target);
567   map2d = get_2d_map(ctx, target);
568   ASSERT(map1d || map2d);
569
570   switch (query) {
571      case GL_COEFF:
572         if (map1d) {
573            data = map1d->Points;
574            n = map1d->Order * comps;
575         }
576         else {
577            data = map2d->Points;
578            n = map2d->Uorder * map2d->Vorder * comps;
579         }
580	 if (data) {
581            numBytes = n * sizeof *v;
582            if (bufSize < numBytes)
583               goto overflow;
584	    for (i=0;i<n;i++) {
585	       v[i] = data[i];
586	    }
587	 }
588         break;
589      case GL_ORDER:
590         if (map1d) {
591            numBytes = 1 * sizeof *v;
592            if (bufSize < numBytes)
593               goto overflow;
594            v[0] = (GLdouble) map1d->Order;
595         }
596         else {
597            numBytes = 2 * sizeof *v;
598            if (bufSize < numBytes)
599               goto overflow;
600            v[0] = (GLdouble) map2d->Uorder;
601            v[1] = (GLdouble) map2d->Vorder;
602         }
603         break;
604      case GL_DOMAIN:
605         if (map1d) {
606            numBytes = 2 * sizeof *v;
607            if (bufSize < numBytes)
608              goto overflow;
609            v[0] = (GLdouble) map1d->u1;
610            v[1] = (GLdouble) map1d->u2;
611         }
612         else {
613            numBytes = 4 * sizeof *v;
614            if (bufSize < numBytes)
615               goto overflow;
616            v[0] = (GLdouble) map2d->u1;
617            v[1] = (GLdouble) map2d->u2;
618            v[2] = (GLdouble) map2d->v1;
619            v[3] = (GLdouble) map2d->v2;
620         }
621         break;
622      default:
623         _mesa_error( ctx, GL_INVALID_ENUM, "glGetMapdv(query)" );
624   }
625   return;
626
627overflow:
628   _mesa_error( ctx, GL_INVALID_OPERATION,
629               "glGetnMapdvARB(out of bounds: bufSize is %d,"
630               " but %d bytes are required)", bufSize, numBytes );
631}
632
633static void GLAPIENTRY
634_mesa_GetMapdv( GLenum target, GLenum query, GLdouble *v )
635{
636   _mesa_GetnMapdvARB(target, query, INT_MAX, v);
637}
638
639static void GLAPIENTRY
640_mesa_GetnMapfvARB( GLenum target, GLenum query, GLsizei bufSize, GLfloat *v )
641{
642   GET_CURRENT_CONTEXT(ctx);
643   struct gl_1d_map *map1d;
644   struct gl_2d_map *map2d;
645   GLint i, n;
646   GLfloat *data;
647   GLuint comps;
648   GLsizei numBytes;
649
650   ASSERT_OUTSIDE_BEGIN_END(ctx);
651
652   comps = _mesa_evaluator_components(target);
653   if (!comps) {
654      _mesa_error( ctx, GL_INVALID_ENUM, "glGetMapfv(target)" );
655      return;
656   }
657
658   map1d = get_1d_map(ctx, target);
659   map2d = get_2d_map(ctx, target);
660   ASSERT(map1d || map2d);
661
662   switch (query) {
663      case GL_COEFF:
664         if (map1d) {
665            data = map1d->Points;
666            n = map1d->Order * comps;
667         }
668         else {
669            data = map2d->Points;
670            n = map2d->Uorder * map2d->Vorder * comps;
671         }
672	 if (data) {
673            numBytes = n * sizeof *v;
674            if (bufSize < numBytes)
675               goto overflow;
676	    for (i=0;i<n;i++) {
677	       v[i] = data[i];
678	    }
679	 }
680         break;
681      case GL_ORDER:
682         if (map1d) {
683            numBytes = 1 * sizeof *v;
684            if (bufSize < numBytes)
685               goto overflow;
686            v[0] = (GLfloat) map1d->Order;
687         }
688         else {
689            numBytes = 2 * sizeof *v;
690            if (bufSize < numBytes)
691               goto overflow;
692            v[0] = (GLfloat) map2d->Uorder;
693            v[1] = (GLfloat) map2d->Vorder;
694         }
695         break;
696      case GL_DOMAIN:
697         if (map1d) {
698            numBytes = 2 * sizeof *v;
699            if (bufSize < numBytes)
700               goto overflow;
701            v[0] = map1d->u1;
702            v[1] = map1d->u2;
703         }
704         else {
705            numBytes = 4 * sizeof *v;
706            if (bufSize < numBytes)
707               goto overflow;
708            v[0] = map2d->u1;
709            v[1] = map2d->u2;
710            v[2] = map2d->v1;
711            v[3] = map2d->v2;
712         }
713         break;
714      default:
715         _mesa_error( ctx, GL_INVALID_ENUM, "glGetMapfv(query)" );
716   }
717   return;
718
719overflow:
720   _mesa_error( ctx, GL_INVALID_OPERATION,
721               "glGetnMapfvARB(out of bounds: bufSize is %d,"
722               " but %d bytes are required)", bufSize, numBytes );
723}
724
725
726static void GLAPIENTRY
727_mesa_GetMapfv( GLenum target, GLenum query, GLfloat *v )
728{
729   _mesa_GetnMapfvARB(target, query, INT_MAX, v);
730}
731
732
733static void GLAPIENTRY
734_mesa_GetnMapivARB( GLenum target, GLenum query, GLsizei bufSize, GLint *v )
735{
736   GET_CURRENT_CONTEXT(ctx);
737   struct gl_1d_map *map1d;
738   struct gl_2d_map *map2d;
739   GLuint i, n;
740   GLfloat *data;
741   GLuint comps;
742   GLsizei numBytes;
743
744   ASSERT_OUTSIDE_BEGIN_END(ctx);
745
746   comps = _mesa_evaluator_components(target);
747   if (!comps) {
748      _mesa_error( ctx, GL_INVALID_ENUM, "glGetMapiv(target)" );
749      return;
750   }
751
752   map1d = get_1d_map(ctx, target);
753   map2d = get_2d_map(ctx, target);
754   ASSERT(map1d || map2d);
755
756   switch (query) {
757      case GL_COEFF:
758         if (map1d) {
759            data = map1d->Points;
760            n = map1d->Order * comps;
761         }
762         else {
763            data = map2d->Points;
764            n = map2d->Uorder * map2d->Vorder * comps;
765         }
766	 if (data) {
767            numBytes = n * sizeof *v;
768            if (bufSize < numBytes)
769               goto overflow;
770	    for (i=0;i<n;i++) {
771	       v[i] = IROUND(data[i]);
772	    }
773	 }
774         break;
775      case GL_ORDER:
776         if (map1d) {
777            numBytes = 1 * sizeof *v;
778            if (bufSize < numBytes)
779               goto overflow;
780            v[0] = map1d->Order;
781         }
782         else {
783            numBytes = 2 * sizeof *v;
784            if (bufSize < numBytes)
785               goto overflow;
786            v[0] = map2d->Uorder;
787            v[1] = map2d->Vorder;
788         }
789         break;
790      case GL_DOMAIN:
791         if (map1d) {
792            numBytes = 2 * sizeof *v;
793            if (bufSize < numBytes)
794               goto overflow;
795            v[0] = IROUND(map1d->u1);
796            v[1] = IROUND(map1d->u2);
797         }
798         else {
799            numBytes = 4 * sizeof *v;
800            if (bufSize < numBytes)
801               goto overflow;
802            v[0] = IROUND(map2d->u1);
803            v[1] = IROUND(map2d->u2);
804            v[2] = IROUND(map2d->v1);
805            v[3] = IROUND(map2d->v2);
806         }
807         break;
808      default:
809         _mesa_error( ctx, GL_INVALID_ENUM, "glGetMapiv(query)" );
810   }
811   return;
812
813overflow:
814   _mesa_error( ctx, GL_INVALID_OPERATION,
815               "glGetnMapivARB(out of bounds: bufSize is %d,"
816               " but %d bytes are required)", bufSize, numBytes );
817}
818
819
820static void GLAPIENTRY
821_mesa_GetMapiv( GLenum target, GLenum query, GLint *v )
822{
823   _mesa_GetnMapivARB(target, query, INT_MAX, v);
824}
825
826
827static void GLAPIENTRY
828_mesa_MapGrid1f( GLint un, GLfloat u1, GLfloat u2 )
829{
830   GET_CURRENT_CONTEXT(ctx);
831   ASSERT_OUTSIDE_BEGIN_END(ctx);
832
833   if (un<1) {
834      _mesa_error( ctx, GL_INVALID_VALUE, "glMapGrid1f" );
835      return;
836   }
837   FLUSH_VERTICES(ctx, _NEW_EVAL);
838   ctx->Eval.MapGrid1un = un;
839   ctx->Eval.MapGrid1u1 = u1;
840   ctx->Eval.MapGrid1u2 = u2;
841   ctx->Eval.MapGrid1du = (u2 - u1) / (GLfloat) un;
842}
843
844
845static void GLAPIENTRY
846_mesa_MapGrid1d( GLint un, GLdouble u1, GLdouble u2 )
847{
848   _mesa_MapGrid1f( un, (GLfloat) u1, (GLfloat) u2 );
849}
850
851
852static void GLAPIENTRY
853_mesa_MapGrid2f( GLint un, GLfloat u1, GLfloat u2,
854                 GLint vn, GLfloat v1, GLfloat v2 )
855{
856   GET_CURRENT_CONTEXT(ctx);
857   ASSERT_OUTSIDE_BEGIN_END(ctx);
858
859   if (un<1) {
860      _mesa_error( ctx, GL_INVALID_VALUE, "glMapGrid2f(un)" );
861      return;
862   }
863   if (vn<1) {
864      _mesa_error( ctx, GL_INVALID_VALUE, "glMapGrid2f(vn)" );
865      return;
866   }
867
868   FLUSH_VERTICES(ctx, _NEW_EVAL);
869   ctx->Eval.MapGrid2un = un;
870   ctx->Eval.MapGrid2u1 = u1;
871   ctx->Eval.MapGrid2u2 = u2;
872   ctx->Eval.MapGrid2du = (u2 - u1) / (GLfloat) un;
873   ctx->Eval.MapGrid2vn = vn;
874   ctx->Eval.MapGrid2v1 = v1;
875   ctx->Eval.MapGrid2v2 = v2;
876   ctx->Eval.MapGrid2dv = (v2 - v1) / (GLfloat) vn;
877}
878
879
880static void GLAPIENTRY
881_mesa_MapGrid2d( GLint un, GLdouble u1, GLdouble u2,
882                 GLint vn, GLdouble v1, GLdouble v2 )
883{
884   _mesa_MapGrid2f( un, (GLfloat) u1, (GLfloat) u2,
885		    vn, (GLfloat) v1, (GLfloat) v2 );
886}
887
888
889void
890_mesa_install_eval_vtxfmt(struct _glapi_table *disp,
891                          const GLvertexformat *vfmt)
892{
893   SET_EvalCoord1f(disp, vfmt->EvalCoord1f);
894   SET_EvalCoord1fv(disp, vfmt->EvalCoord1fv);
895   SET_EvalCoord2f(disp, vfmt->EvalCoord2f);
896   SET_EvalCoord2fv(disp, vfmt->EvalCoord2fv);
897   SET_EvalPoint1(disp, vfmt->EvalPoint1);
898   SET_EvalPoint2(disp, vfmt->EvalPoint2);
899
900   SET_EvalMesh1(disp, vfmt->EvalMesh1);
901   SET_EvalMesh2(disp, vfmt->EvalMesh2);
902}
903
904
905void
906_mesa_init_eval_dispatch(struct _glapi_table *disp)
907{
908   SET_GetMapdv(disp, _mesa_GetMapdv);
909   SET_GetMapfv(disp, _mesa_GetMapfv);
910   SET_GetMapiv(disp, _mesa_GetMapiv);
911   SET_Map1d(disp, _mesa_Map1d);
912   SET_Map1f(disp, _mesa_Map1f);
913   SET_Map2d(disp, _mesa_Map2d);
914   SET_Map2f(disp, _mesa_Map2f);
915   SET_MapGrid1d(disp, _mesa_MapGrid1d);
916   SET_MapGrid1f(disp, _mesa_MapGrid1f);
917   SET_MapGrid2d(disp, _mesa_MapGrid2d);
918   SET_MapGrid2f(disp, _mesa_MapGrid2f);
919
920   /* GL_ARB_robustness */
921   SET_GetnMapdvARB(disp, _mesa_GetnMapdvARB);
922   SET_GetnMapfvARB(disp, _mesa_GetnMapfvARB);
923   SET_GetnMapivARB(disp, _mesa_GetnMapivARB);
924}
925
926
927#endif /* FEATURE_evaluators */
928
929
930/**********************************************************************/
931/*****                      Initialization                        *****/
932/**********************************************************************/
933
934/**
935 * Initialize a 1-D evaluator map.
936 */
937static void
938init_1d_map( struct gl_1d_map *map, int n, const float *initial )
939{
940   map->Order = 1;
941   map->u1 = 0.0;
942   map->u2 = 1.0;
943   map->Points = (GLfloat *) MALLOC(n * sizeof(GLfloat));
944   if (map->Points) {
945      GLint i;
946      for (i=0;i<n;i++)
947         map->Points[i] = initial[i];
948   }
949}
950
951
952/**
953 * Initialize a 2-D evaluator map
954 */
955static void
956init_2d_map( struct gl_2d_map *map, int n, const float *initial )
957{
958   map->Uorder = 1;
959   map->Vorder = 1;
960   map->u1 = 0.0;
961   map->u2 = 1.0;
962   map->v1 = 0.0;
963   map->v2 = 1.0;
964   map->Points = (GLfloat *) MALLOC(n * sizeof(GLfloat));
965   if (map->Points) {
966      GLint i;
967      for (i=0;i<n;i++)
968         map->Points[i] = initial[i];
969   }
970}
971
972
973void _mesa_init_eval( struct gl_context *ctx )
974{
975   int i;
976
977   /* Evaluators group */
978   ctx->Eval.Map1Color4 = GL_FALSE;
979   ctx->Eval.Map1Index = GL_FALSE;
980   ctx->Eval.Map1Normal = GL_FALSE;
981   ctx->Eval.Map1TextureCoord1 = GL_FALSE;
982   ctx->Eval.Map1TextureCoord2 = GL_FALSE;
983   ctx->Eval.Map1TextureCoord3 = GL_FALSE;
984   ctx->Eval.Map1TextureCoord4 = GL_FALSE;
985   ctx->Eval.Map1Vertex3 = GL_FALSE;
986   ctx->Eval.Map1Vertex4 = GL_FALSE;
987   memset(ctx->Eval.Map1Attrib, 0, sizeof(ctx->Eval.Map1Attrib));
988   ctx->Eval.Map2Color4 = GL_FALSE;
989   ctx->Eval.Map2Index = GL_FALSE;
990   ctx->Eval.Map2Normal = GL_FALSE;
991   ctx->Eval.Map2TextureCoord1 = GL_FALSE;
992   ctx->Eval.Map2TextureCoord2 = GL_FALSE;
993   ctx->Eval.Map2TextureCoord3 = GL_FALSE;
994   ctx->Eval.Map2TextureCoord4 = GL_FALSE;
995   ctx->Eval.Map2Vertex3 = GL_FALSE;
996   ctx->Eval.Map2Vertex4 = GL_FALSE;
997   memset(ctx->Eval.Map2Attrib, 0, sizeof(ctx->Eval.Map2Attrib));
998   ctx->Eval.AutoNormal = GL_FALSE;
999   ctx->Eval.MapGrid1un = 1;
1000   ctx->Eval.MapGrid1u1 = 0.0;
1001   ctx->Eval.MapGrid1u2 = 1.0;
1002   ctx->Eval.MapGrid2un = 1;
1003   ctx->Eval.MapGrid2vn = 1;
1004   ctx->Eval.MapGrid2u1 = 0.0;
1005   ctx->Eval.MapGrid2u2 = 1.0;
1006   ctx->Eval.MapGrid2v1 = 0.0;
1007   ctx->Eval.MapGrid2v2 = 1.0;
1008
1009   /* Evaluator data */
1010   {
1011      static GLfloat vertex[4] = { 0.0, 0.0, 0.0, 1.0 };
1012      static GLfloat normal[3] = { 0.0, 0.0, 1.0 };
1013      static GLfloat index[1] = { 1.0 };
1014      static GLfloat color[4] = { 1.0, 1.0, 1.0, 1.0 };
1015      static GLfloat texcoord[4] = { 0.0, 0.0, 0.0, 1.0 };
1016      static GLfloat attrib[4] = { 0.0, 0.0, 0.0, 1.0 };
1017
1018      init_1d_map( &ctx->EvalMap.Map1Vertex3, 3, vertex );
1019      init_1d_map( &ctx->EvalMap.Map1Vertex4, 4, vertex );
1020      init_1d_map( &ctx->EvalMap.Map1Index, 1, index );
1021      init_1d_map( &ctx->EvalMap.Map1Color4, 4, color );
1022      init_1d_map( &ctx->EvalMap.Map1Normal, 3, normal );
1023      init_1d_map( &ctx->EvalMap.Map1Texture1, 1, texcoord );
1024      init_1d_map( &ctx->EvalMap.Map1Texture2, 2, texcoord );
1025      init_1d_map( &ctx->EvalMap.Map1Texture3, 3, texcoord );
1026      init_1d_map( &ctx->EvalMap.Map1Texture4, 4, texcoord );
1027      for (i = 0; i < 16; i++)
1028         init_1d_map( ctx->EvalMap.Map1Attrib + i, 4, attrib );
1029
1030      init_2d_map( &ctx->EvalMap.Map2Vertex3, 3, vertex );
1031      init_2d_map( &ctx->EvalMap.Map2Vertex4, 4, vertex );
1032      init_2d_map( &ctx->EvalMap.Map2Index, 1, index );
1033      init_2d_map( &ctx->EvalMap.Map2Color4, 4, color );
1034      init_2d_map( &ctx->EvalMap.Map2Normal, 3, normal );
1035      init_2d_map( &ctx->EvalMap.Map2Texture1, 1, texcoord );
1036      init_2d_map( &ctx->EvalMap.Map2Texture2, 2, texcoord );
1037      init_2d_map( &ctx->EvalMap.Map2Texture3, 3, texcoord );
1038      init_2d_map( &ctx->EvalMap.Map2Texture4, 4, texcoord );
1039      for (i = 0; i < 16; i++)
1040         init_2d_map( ctx->EvalMap.Map2Attrib + i, 4, attrib );
1041   }
1042}
1043
1044
1045void _mesa_free_eval_data( struct gl_context *ctx )
1046{
1047   int i;
1048
1049   /* Free evaluator data */
1050   if (ctx->EvalMap.Map1Vertex3.Points)
1051      FREE( ctx->EvalMap.Map1Vertex3.Points );
1052   if (ctx->EvalMap.Map1Vertex4.Points)
1053      FREE( ctx->EvalMap.Map1Vertex4.Points );
1054   if (ctx->EvalMap.Map1Index.Points)
1055      FREE( ctx->EvalMap.Map1Index.Points );
1056   if (ctx->EvalMap.Map1Color4.Points)
1057      FREE( ctx->EvalMap.Map1Color4.Points );
1058   if (ctx->EvalMap.Map1Normal.Points)
1059      FREE( ctx->EvalMap.Map1Normal.Points );
1060   if (ctx->EvalMap.Map1Texture1.Points)
1061      FREE( ctx->EvalMap.Map1Texture1.Points );
1062   if (ctx->EvalMap.Map1Texture2.Points)
1063      FREE( ctx->EvalMap.Map1Texture2.Points );
1064   if (ctx->EvalMap.Map1Texture3.Points)
1065      FREE( ctx->EvalMap.Map1Texture3.Points );
1066   if (ctx->EvalMap.Map1Texture4.Points)
1067      FREE( ctx->EvalMap.Map1Texture4.Points );
1068   for (i = 0; i < 16; i++)
1069      FREE((ctx->EvalMap.Map1Attrib[i].Points));
1070
1071   if (ctx->EvalMap.Map2Vertex3.Points)
1072      FREE( ctx->EvalMap.Map2Vertex3.Points );
1073   if (ctx->EvalMap.Map2Vertex4.Points)
1074      FREE( ctx->EvalMap.Map2Vertex4.Points );
1075   if (ctx->EvalMap.Map2Index.Points)
1076      FREE( ctx->EvalMap.Map2Index.Points );
1077   if (ctx->EvalMap.Map2Color4.Points)
1078      FREE( ctx->EvalMap.Map2Color4.Points );
1079   if (ctx->EvalMap.Map2Normal.Points)
1080      FREE( ctx->EvalMap.Map2Normal.Points );
1081   if (ctx->EvalMap.Map2Texture1.Points)
1082      FREE( ctx->EvalMap.Map2Texture1.Points );
1083   if (ctx->EvalMap.Map2Texture2.Points)
1084      FREE( ctx->EvalMap.Map2Texture2.Points );
1085   if (ctx->EvalMap.Map2Texture3.Points)
1086      FREE( ctx->EvalMap.Map2Texture3.Points );
1087   if (ctx->EvalMap.Map2Texture4.Points)
1088      FREE( ctx->EvalMap.Map2Texture4.Points );
1089   for (i = 0; i < 16; i++)
1090      FREE((ctx->EvalMap.Map2Attrib[i].Points));
1091}
1092