Changes to reduce the memory footprint of display lists
[mesa.git] / src / mesa / main / varray.c
1 /* $Id: varray.c,v 1.5 1999/10/19 18:37:05 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 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 #ifdef PC_HEADER
28 #include "all.h"
29 #else
30 #ifndef XFree86Server
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #else
35 #include "GL/xf86glx.h"
36 #endif
37 #include "context.h"
38 #include "api.h"
39 #include "cva.h"
40 #include "enable.h"
41 #include "enums.h"
42 #include "dlist.h"
43 #include "light.h"
44 #include "macros.h"
45 #include "mmath.h"
46 #include "pipeline.h"
47 #include "texstate.h"
48 #include "translate.h"
49 #include "types.h"
50 #include "varray.h"
51 #include "vb.h"
52 #include "vbfill.h"
53 #include "vbrender.h"
54 #include "vbindirect.h"
55 #include "vbxform.h"
56 #include "xform.h"
57 #ifdef XFree86Server
58 #include "GL/xf86glx.h"
59 #endif
60 #endif
61
62 #if defined(GLX_DIRECT_RENDERING) && !defined(XFree86Server) && !defined(GLX_USE_DLOPEN)
63 #define NEED_MESA_FUNCS_WRAPPED
64 #include "mesa_api.h"
65 #endif
66
67
68 void GLAPIENTRY glVertexPointer(CTX_ARG GLint size, GLenum type, GLsizei stride,
69 const GLvoid *ptr )
70 {
71 GLcontext *ctx;
72 GET_CONTEXT;
73 CHECK_CONTEXT;
74 ctx = CC;
75
76 if (size<2 || size>4) {
77 gl_error( ctx, GL_INVALID_VALUE, "glVertexPointer(size)" );
78 return;
79 }
80 if (stride<0) {
81 gl_error( ctx, GL_INVALID_VALUE, "glVertexPointer(stride)" );
82 return;
83 }
84
85 if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
86 fprintf(stderr, "glVertexPointer( sz %d type %s stride %d )\n", size,
87 gl_lookup_enum_by_nr( type ),
88 stride);
89
90 ctx->Array.Vertex.StrideB = stride;
91 if (!stride) {
92 switch (type) {
93 case GL_SHORT:
94 ctx->Array.Vertex.StrideB = size*sizeof(GLshort);
95 break;
96 case GL_INT:
97 ctx->Array.Vertex.StrideB = size*sizeof(GLint);
98 break;
99 case GL_FLOAT:
100 ctx->Array.Vertex.StrideB = size*sizeof(GLfloat);
101 break;
102 case GL_DOUBLE:
103 ctx->Array.Vertex.StrideB = size*sizeof(GLdouble);
104 break;
105 default:
106 gl_error( ctx, GL_INVALID_ENUM, "glVertexPointer(type)" );
107 return;
108 }
109 }
110 ctx->Array.Vertex.Size = size;
111 ctx->Array.Vertex.Type = type;
112 ctx->Array.Vertex.Stride = stride;
113 ctx->Array.Vertex.Ptr = (void *) ptr;
114 ctx->Array.VertexFunc = gl_trans_4f_tab[size][TYPE_IDX(type)];
115 ctx->Array.VertexEltFunc = gl_trans_elt_4f_tab[size][TYPE_IDX(type)];
116 ctx->Array.NewArrayState |= VERT_OBJ_ANY;
117 ctx->NewState |= NEW_CLIENT_STATE;
118 }
119
120
121
122
123 void GLAPIENTRY glNormalPointer(CTX_ARG GLenum type, GLsizei stride,
124 const GLvoid *ptr )
125 {
126 GLcontext *ctx;
127 GET_CONTEXT;
128 CHECK_CONTEXT;
129 ctx = CC;
130
131 if (stride<0) {
132 gl_error( ctx, GL_INVALID_VALUE, "glNormalPointer(stride)" );
133 return;
134 }
135
136 if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
137 fprintf(stderr, "glNormalPointer( type %s stride %d )\n",
138 gl_lookup_enum_by_nr( type ),
139 stride);
140
141 ctx->Array.Normal.StrideB = stride;
142 if (!stride) {
143 switch (type) {
144 case GL_BYTE:
145 ctx->Array.Normal.StrideB = 3*sizeof(GLbyte);
146 break;
147 case GL_SHORT:
148 ctx->Array.Normal.StrideB = 3*sizeof(GLshort);
149 break;
150 case GL_INT:
151 ctx->Array.Normal.StrideB = 3*sizeof(GLint);
152 break;
153 case GL_FLOAT:
154 ctx->Array.Normal.StrideB = 3*sizeof(GLfloat);
155 break;
156 case GL_DOUBLE:
157 ctx->Array.Normal.StrideB = 3*sizeof(GLdouble);
158 break;
159 default:
160 gl_error( ctx, GL_INVALID_ENUM, "glNormalPointer(type)" );
161 return;
162 }
163 }
164 ctx->Array.Normal.Type = type;
165 ctx->Array.Normal.Stride = stride;
166 ctx->Array.Normal.Ptr = (void *) ptr;
167 ctx->Array.NormalFunc = gl_trans_3f_tab[TYPE_IDX(type)];
168 ctx->Array.NormalEltFunc = gl_trans_elt_3f_tab[TYPE_IDX(type)];
169 ctx->Array.NewArrayState |= VERT_NORM;
170 ctx->NewState |= NEW_CLIENT_STATE;
171 }
172
173
174
175 void GLAPIENTRY glColorPointer(CTX_ARG GLint size, GLenum type, GLsizei stride,
176 const GLvoid *ptr )
177 {
178 GLcontext *ctx;
179 GET_CONTEXT;
180 CHECK_CONTEXT;
181 ctx = CC;
182 if (size<3 || size>4) {
183 gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(size)" );
184 return;
185 }
186 if (stride<0) {
187 gl_error( ctx, GL_INVALID_VALUE, "glColorPointer(stride)" );
188 return;
189 }
190
191 if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
192 fprintf(stderr, "glColorPointer( sz %d type %s stride %d )\n", size,
193 gl_lookup_enum_by_nr( type ),
194 stride);
195
196 ctx->Array.Color.StrideB = stride;
197 if (!stride) {
198 switch (type) {
199 case GL_BYTE:
200 ctx->Array.Color.StrideB = size*sizeof(GLbyte);
201 break;
202 case GL_UNSIGNED_BYTE:
203 ctx->Array.Color.StrideB = size*sizeof(GLubyte);
204 break;
205 case GL_SHORT:
206 ctx->Array.Color.StrideB = size*sizeof(GLshort);
207 break;
208 case GL_UNSIGNED_SHORT:
209 ctx->Array.Color.StrideB = size*sizeof(GLushort);
210 break;
211 case GL_INT:
212 ctx->Array.Color.StrideB = size*sizeof(GLint);
213 break;
214 case GL_UNSIGNED_INT:
215 ctx->Array.Color.StrideB = size*sizeof(GLuint);
216 break;
217 case GL_FLOAT:
218 ctx->Array.Color.StrideB = size*sizeof(GLfloat);
219 break;
220 case GL_DOUBLE:
221 ctx->Array.Color.StrideB = size*sizeof(GLdouble);
222 break;
223 default:
224 gl_error( ctx, GL_INVALID_ENUM, "glColorPointer(type)" );
225 return;
226 }
227 }
228 ctx->Array.Color.Size = size;
229 ctx->Array.Color.Type = type;
230 ctx->Array.Color.Stride = stride;
231 ctx->Array.Color.Ptr = (void *) ptr;
232 ctx->Array.ColorFunc = gl_trans_4ub_tab[size][TYPE_IDX(type)];
233 ctx->Array.ColorEltFunc = gl_trans_elt_4ub_tab[size][TYPE_IDX(type)];
234 ctx->Array.NewArrayState |= VERT_RGBA;
235 ctx->NewState |= NEW_CLIENT_STATE;
236 }
237
238
239
240 void GLAPIENTRY glIndexPointer(CTX_ARG GLenum type, GLsizei stride,
241 const GLvoid *ptr )
242 {
243 GLcontext *ctx;
244 GET_CONTEXT;
245 CHECK_CONTEXT;
246 ctx = CC;
247
248 if (stride<0) {
249 gl_error( ctx, GL_INVALID_VALUE, "glIndexPointer(stride)" );
250 return;
251 }
252
253 ctx->Array.Index.StrideB = stride;
254 if (!stride) {
255 switch (type) {
256 case GL_UNSIGNED_BYTE:
257 ctx->Array.Index.StrideB = sizeof(GLubyte);
258 break;
259 case GL_SHORT:
260 ctx->Array.Index.StrideB = sizeof(GLshort);
261 break;
262 case GL_INT:
263 ctx->Array.Index.StrideB = sizeof(GLint);
264 break;
265 case GL_FLOAT:
266 ctx->Array.Index.StrideB = sizeof(GLfloat);
267 break;
268 case GL_DOUBLE:
269 ctx->Array.Index.StrideB = sizeof(GLdouble);
270 break;
271 default:
272 gl_error( ctx, GL_INVALID_ENUM, "glIndexPointer(type)" );
273 return;
274 }
275 }
276 ctx->Array.Index.Type = type;
277 ctx->Array.Index.Stride = stride;
278 ctx->Array.Index.Ptr = (void *) ptr;
279 ctx->Array.IndexFunc = gl_trans_1ui_tab[TYPE_IDX(type)];
280 ctx->Array.IndexEltFunc = gl_trans_elt_1ui_tab[TYPE_IDX(type)];
281 ctx->Array.NewArrayState |= VERT_INDEX;
282 ctx->NewState |= NEW_CLIENT_STATE;
283 }
284
285
286
287 void GLAPIENTRY glTexCoordPointer(CTX_ARG GLint size, GLenum type,
288 GLsizei stride, const GLvoid *ptr )
289 {
290 GLuint texUnit;
291
292 GLcontext *ctx;
293 GET_CONTEXT;
294 CHECK_CONTEXT;
295 ctx = CC;
296
297 texUnit = ctx->Array.ActiveTexture;
298
299 if (size<1 || size>4) {
300 gl_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(size)" );
301 return;
302 }
303 if (stride<0) {
304 gl_error( ctx, GL_INVALID_VALUE, "glTexCoordPointer(stride)" );
305 return;
306 }
307
308 if (MESA_VERBOSE&(VERBOSE_VARRAY|VERBOSE_API))
309 fprintf(stderr, "glTexCoordPointer( unit %u sz %d type %s stride %d )\n",
310 texUnit,
311 size,
312 gl_lookup_enum_by_nr( type ),
313 stride);
314
315 ctx->Array.TexCoord[texUnit].StrideB = stride;
316 if (!stride) {
317 switch (type) {
318 case GL_SHORT:
319 ctx->Array.TexCoord[texUnit].StrideB = size*sizeof(GLshort);
320 break;
321 case GL_INT:
322 ctx->Array.TexCoord[texUnit].StrideB = size*sizeof(GLint);
323 break;
324 case GL_FLOAT:
325 ctx->Array.TexCoord[texUnit].StrideB = size*sizeof(GLfloat);
326 break;
327 case GL_DOUBLE:
328 ctx->Array.TexCoord[texUnit].StrideB = size*sizeof(GLdouble);
329 break;
330 default:
331 gl_error( ctx, GL_INVALID_ENUM, "glTexCoordPointer(type)" );
332 return;
333 }
334 }
335 ctx->Array.TexCoord[texUnit].Size = size;
336 ctx->Array.TexCoord[texUnit].Type = type;
337 ctx->Array.TexCoord[texUnit].Stride = stride;
338 ctx->Array.TexCoord[texUnit].Ptr = (void *) ptr;
339
340 ctx->Array.TexCoordFunc[texUnit] = gl_trans_4f_tab[size][TYPE_IDX(type)];
341 ctx->Array.TexCoordEltFunc[texUnit] = gl_trans_elt_4f_tab[size][TYPE_IDX(type)];
342 ctx->Array.NewArrayState |= PIPE_TEX(texUnit);
343 ctx->NewState |= NEW_CLIENT_STATE;
344 }
345
346
347
348
349 void GLAPIENTRY glEdgeFlagPointer(CTX_ARG GLsizei stride, const void *vptr )
350 {
351 const GLboolean *ptr = (GLboolean *)vptr;
352
353 GLcontext *ctx;
354 GET_CONTEXT;
355 CHECK_CONTEXT;
356 ctx = CC;
357
358 if (stride<0) {
359 gl_error( ctx, GL_INVALID_VALUE, "glEdgeFlagPointer(stride)" );
360 return;
361 }
362 ctx->Array.EdgeFlag.Stride = stride;
363 ctx->Array.EdgeFlag.StrideB = stride ? stride : sizeof(GLboolean);
364 ctx->Array.EdgeFlag.Ptr = (GLboolean *) ptr;
365 if (stride != sizeof(GLboolean)) {
366 ctx->Array.EdgeFlagFunc = gl_trans_1ub_tab[TYPE_IDX(GL_UNSIGNED_BYTE)];
367 } else {
368 ctx->Array.EdgeFlagFunc = 0;
369 }
370 ctx->Array.EdgeFlagEltFunc = gl_trans_elt_1ub_tab[TYPE_IDX(GL_UNSIGNED_BYTE)];
371 ctx->Array.NewArrayState |= VERT_EDGE;
372 ctx->NewState |= NEW_CLIENT_STATE;
373 }
374
375
376 /* Called only from gl_DrawElements
377 */
378 void gl_CVAEltPointer( GLcontext *ctx, GLenum type, const GLvoid *ptr )
379 {
380 switch (type) {
381 case GL_UNSIGNED_BYTE:
382 ctx->CVA.Elt.StrideB = sizeof(GLubyte);
383 break;
384 case GL_UNSIGNED_SHORT:
385 ctx->CVA.Elt.StrideB = sizeof(GLushort);
386 break;
387 case GL_UNSIGNED_INT:
388 ctx->CVA.Elt.StrideB = sizeof(GLuint);
389 break;
390 default:
391 gl_error( ctx, GL_INVALID_ENUM, "glEltPointer(type)" );
392 return;
393 }
394 ctx->CVA.Elt.Type = type;
395 ctx->CVA.Elt.Stride = 0;
396 ctx->CVA.Elt.Ptr = (void *) ptr;
397 ctx->CVA.EltFunc = gl_trans_1ui_tab[TYPE_IDX(type)];
398 ctx->Array.NewArrayState |= VERT_ELT; /* ??? */
399 }
400
401
402
403 /* KW: Batch function to exec all the array elements in the input
404 * buffer prior to transform. Done only the first time a vertex
405 * buffer is executed or compiled.
406 *
407 * KW: Have to do this after each glEnd if cva isn't active. (also
408 * have to do it after each full buffer)
409 */
410 void gl_exec_array_elements( GLcontext *ctx, struct immediate *IM,
411 GLuint start,
412 GLuint count)
413 {
414 GLuint *flags = IM->Flag;
415 GLuint *elts = IM->Elt;
416 GLuint translate = ctx->Array.Flags;
417 GLuint i;
418
419 if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
420 fprintf(stderr, "exec_array_elements %d .. %d\n", start, count);
421
422 if (translate & VERT_OBJ_ANY)
423 (ctx->Array.VertexEltFunc)( IM->Obj,
424 &ctx->Array.Vertex,
425 flags, elts, (VERT_ELT|VERT_OBJ_ANY),
426 start, count);
427
428 if (translate & VERT_NORM)
429 (ctx->Array.NormalEltFunc)( IM->Normal,
430 &ctx->Array.Normal,
431 flags, elts, (VERT_ELT|VERT_NORM),
432 start, count);
433
434 if (translate & VERT_EDGE)
435 (ctx->Array.EdgeFlagEltFunc)( IM->EdgeFlag,
436 &ctx->Array.EdgeFlag,
437 flags, elts, (VERT_ELT|VERT_EDGE),
438 start, count);
439
440 if (translate & VERT_RGBA)
441 (ctx->Array.ColorEltFunc)( IM->Color,
442 &ctx->Array.Color,
443 flags, elts, (VERT_ELT|VERT_RGBA),
444 start, count);
445
446 if (translate & VERT_INDEX)
447 (ctx->Array.IndexEltFunc)( IM->Index,
448 &ctx->Array.Index,
449 flags, elts, (VERT_ELT|VERT_INDEX),
450 start, count);
451
452 if (translate & VERT_TEX0_ANY)
453 (ctx->Array.TexCoordEltFunc[0])( IM->TexCoord[0],
454 &ctx->Array.TexCoord[0],
455 flags, elts, (VERT_ELT|VERT_TEX0_ANY),
456 start, count);
457
458 if (translate & VERT_TEX1_ANY)
459 (ctx->Array.TexCoordEltFunc[1])( IM->TexCoord[1],
460 &ctx->Array.TexCoord[1],
461 flags, elts, (VERT_ELT|VERT_TEX1_ANY),
462 start, count);
463
464 /* Lighting ignores the and-flag, so still need to do this.
465 */
466 /* fprintf(stderr, "start %d count %d\n", start, count); */
467 /* gl_print_vert_flags("translate", translate); */
468
469 for (i = start ; i < count ; i++)
470 if (flags[i] & VERT_ELT) {
471 /* flags[i] &= ~VERT_ELT; */
472 flags[i] |= translate;
473 }
474 }
475
476
477
478 /* KW: I think this is moving in the right direction, but it still feels
479 * like we are doing way too much work.
480 */
481 void gl_DrawArrays( GLcontext *ctx, GLenum mode, GLint start, GLsizei count )
482 {
483 struct vertex_buffer *VB = ctx->VB;
484 GLint i;
485
486 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawArrays");
487
488 if (count<0) {
489 gl_error( ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
490 return;
491 }
492
493 if (!ctx->CompileFlag && ctx->Array.Vertex.Enabled)
494 {
495 GLint remaining = count;
496 GLint i;
497 GLvector4f obj;
498 GLvector3f norm;
499 GLvector4f tc[MAX_TEXTURE_UNITS];
500 GLvector4ub col;
501 GLvector1ub edge;
502 GLvector1ui index;
503 GLuint update = 0, translate = 0;
504 struct vertex_array_pointers VSrc;
505 struct immediate *IM = VB->IM;
506 struct gl_client_array *client_data;
507 struct gl_pipeline *elt = &ctx->CVA.elt;
508 GLuint relock;
509 GLuint fallback, required;
510
511 if (ctx->NewState)
512 gl_update_state( ctx );
513
514 /* This will die miserably with CVA... Need more work to support this.
515 */
516 relock = ctx->CompileCVAFlag;
517 ctx->CompileCVAFlag = 0;
518
519 if (!elt->pipeline_valid || relock)
520 gl_build_immediate_pipeline( ctx );
521
522 required = elt->inputs;
523 fallback = (elt->inputs & ~ctx->Array.Summary);
524
525 VSrc.Color = &IM->v.Color;
526 VSrc.Index = &IM->v.Index;
527 VSrc.EdgeFlag = &IM->v.EdgeFlag;
528 VSrc.TexCoord[0] = &IM->v.TexCoord[0];
529 VSrc.TexCoord[1] = &IM->v.TexCoord[1];
530 VSrc.Obj = &IM->v.Obj;
531 VSrc.Normal = &IM->v.Normal;
532
533 if (required & VERT_RGBA)
534 {
535 client_data = &ctx->Array.Color;
536 if (fallback & VERT_RGBA)
537 client_data = &ctx->Fallback.Color;
538
539 if (client_data->Type == GL_UNSIGNED_BYTE &&
540 client_data->Size == 4)
541 {
542 VSrc.Color = &col;
543 col.data = (GLubyte (*)[4]) client_data->Ptr;
544 col.stride = client_data->StrideB;
545 col.flags = VEC_NOT_WRITABLE|VEC_GOOD_STRIDE;
546 if (client_data->StrideB != 4 * sizeof(GLubyte))
547 col.flags ^= VEC_STRIDE_FLAGS;
548
549 update |= VERT_RGBA;
550 } else {
551 translate |= VERT_RGBA;
552 }
553 }
554
555 if (required & VERT_INDEX)
556 {
557 client_data = &ctx->Array.Index;
558 if (fallback & VERT_INDEX)
559 client_data = &ctx->Fallback.Index;
560
561 if (client_data->Type == GL_UNSIGNED_INT)
562 {
563 VSrc.Index = &index;
564 index.data = (GLuint *) client_data->Ptr;
565 index.stride = client_data->StrideB;
566 index.flags = VEC_NOT_WRITABLE|VEC_GOOD_STRIDE;
567 if (client_data->StrideB != sizeof(GLuint))
568 index.flags ^= VEC_STRIDE_FLAGS;
569
570 update |= VERT_INDEX;
571 } else {
572 translate |= VERT_INDEX;
573 }
574 }
575
576 for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
577 {
578 GLuint flag = VERT_TEX_ANY(i);
579
580 if (required & flag) {
581
582 client_data = &ctx->Array.TexCoord[i];
583
584 if (fallback & flag)
585 {
586 client_data = &ctx->Fallback.TexCoord[i];
587 client_data->Size = gl_texcoord_size( ctx->Current.Flag, i );
588 }
589
590 if (client_data->Type == GL_FLOAT)
591 {
592 VSrc.TexCoord[i] = &tc[i];
593 tc[i].data = (GLfloat (*)[4]) client_data->Ptr;
594 tc[i].stride = client_data->StrideB;
595 tc[i].size = client_data->Size;
596 tc[i].flags = VEC_NOT_WRITABLE|VEC_GOOD_STRIDE;
597 if (tc[i].stride |= 4 * sizeof(GLfloat))
598 tc[i].flags ^= VEC_STRIDE_FLAGS;
599 update |= flag;
600 } else {
601 translate |= flag;
602 }
603 }
604 }
605
606 if (ctx->Array.Flags != ctx->Array.Flag[0])
607 for (i = 0 ; i < VB_MAX ; i++)
608 ctx->Array.Flag[i] = ctx->Array.Flags;
609
610
611 if (ctx->Array.Vertex.Type == GL_FLOAT)
612 {
613 VSrc.Obj = &obj;
614 obj.data = (GLfloat (*)[4]) ctx->Array.Vertex.Ptr;
615 obj.stride = ctx->Array.Vertex.StrideB;
616 obj.size = ctx->Array.Vertex.Size;
617 obj.flags = VEC_NOT_WRITABLE|VEC_GOOD_STRIDE;
618 if (obj.stride != 4 * sizeof(GLfloat))
619 obj.flags ^= VEC_STRIDE_FLAGS;
620
621 update |= VERT_OBJ_ANY;
622 }
623 else
624 {
625 translate |= VERT_OBJ_ANY;
626 }
627
628 if (required & VERT_NORM)
629 {
630 client_data = &ctx->Array.Normal;
631 if (fallback & VERT_NORM)
632 client_data = &ctx->Fallback.Normal;
633
634 if (client_data->Type == GL_FLOAT)
635 {
636 VSrc.Normal = &norm;
637 norm.flags = 0;
638 norm.data = (GLfloat (*)[3]) client_data->Ptr;
639 norm.stride = client_data->StrideB;
640 update |= VERT_NORM;
641 } else {
642 translate |= VERT_NORM;
643 }
644 }
645
646 if ( (required & VERT_EDGE) &&
647 (mode == GL_TRIANGLES ||
648 mode == GL_QUADS ||
649 mode == GL_POLYGON))
650 {
651 client_data = &ctx->Array.EdgeFlag;
652
653 if (fallback & VERT_EDGE)
654 client_data = &ctx->Fallback.EdgeFlag;
655
656 VSrc.EdgeFlag = &edge;
657 edge.data = (GLboolean *) client_data->Ptr;
658 edge.stride = client_data->StrideB;
659 edge.flags = VEC_NOT_WRITABLE|VEC_GOOD_STRIDE;
660 if (edge.stride != sizeof(GLubyte))
661 edge.flags ^= VEC_STRIDE_FLAGS;
662
663 update |= VERT_EDGE;
664 }
665
666 VB->Primitive = IM->Primitive;
667 VB->NextPrimitive = IM->NextPrimitive;
668 VB->MaterialMask = IM->MaterialMask;
669 VB->Material = IM->Material;
670 VB->BoundsPtr = 0;
671
672 while (remaining > 0) {
673 GLint vbspace = VB_MAX - VB_START;
674 GLuint count, n;
675
676
677 if (vbspace >= remaining) {
678 n = remaining;
679 VB->LastPrimitive = VB_START + n;
680 } else {
681 n = vbspace;
682 VB->LastPrimitive = VB_START;
683 }
684
685 VB->CullMode = 0;
686
687
688 /* Update pointers.
689 */
690 if (update) {
691 if (update & VERT_OBJ_ANY)
692 obj.start = VEC_ELT(&obj, GLfloat, start);
693
694 if (update & VERT_NORM)
695 norm.start = VEC_ELT(&norm, GLfloat, start);
696
697 if (update & VERT_EDGE)
698 edge.start = VEC_ELT(&edge, GLubyte, start);
699
700 if (update & VERT_RGBA)
701 col.start = VEC_ELT(&col, GLubyte, start);
702
703 if (update & VERT_INDEX)
704 index.start = VEC_ELT(&index, GLuint, start);
705
706 if (update & VERT_TEX0_ANY)
707 tc[0].start = VEC_ELT(&tc[0], GLfloat, start);
708
709 if (update & VERT_TEX1_ANY)
710 tc[1].start = VEC_ELT(&tc[1], GLfloat, start);
711 }
712
713
714 /* Translate data to fix up type and stride.
715 */
716 if (translate) {
717 if (translate & VERT_OBJ_ANY) {
718 ctx->Array.VertexFunc( IM->Obj + VB_START,
719 &ctx->Array.Vertex, start, n );
720 }
721
722 if (translate & VERT_NORM) {
723 ctx->Array.NormalFunc( IM->Normal + VB_START,
724 &ctx->Array.Normal, start, n );
725 }
726
727 if (translate & VERT_EDGE) {
728 ctx->Array.EdgeFlagFunc( IM->EdgeFlag + VB_START,
729 &ctx->Array.EdgeFlag, start, n );
730 }
731
732 if (translate & VERT_RGBA) {
733 ctx->Array.ColorFunc( IM->Color + VB_START,
734 &ctx->Array.Color, start, n );
735 }
736
737 if (translate & VERT_INDEX) {
738 ctx->Array.IndexFunc( IM->Index + VB_START,
739 &ctx->Array.Index, start, n );
740 }
741
742 if (translate & VERT_TEX0_ANY) {
743 IM->v.TexCoord[0].size = tc[0].size;
744 ctx->Array.TexCoordFunc[0]( IM->TexCoord[0] + VB_START,
745 &ctx->Array.TexCoord[0], start, n );
746 }
747
748 if (translate & VERT_TEX1_ANY) {
749 IM->v.TexCoord[1].size = tc[1].size;
750 ctx->Array.TexCoordFunc[1]( IM->TexCoord[1] + VB_START,
751 &ctx->Array.TexCoord[1], start, n );
752 }
753 }
754
755
756 VB->ObjPtr = VSrc.Obj;
757 VB->NormalPtr = VSrc.Normal;
758 VB->Color[0] = VB->Color[1] = VB->ColorPtr = VSrc.Color;
759 VB->IndexPtr = VSrc.Index;
760 VB->EdgeFlagPtr = VSrc.EdgeFlag;
761 VB->TexCoordPtr[0] = VSrc.TexCoord[0];
762 VB->TexCoordPtr[1] = VSrc.TexCoord[1];
763
764 VB->Flag = ctx->Array.Flag;
765 VB->OrFlag = ctx->Array.Flags;
766
767 count = VB->Count = VB_START + n;
768
769 VB->ObjPtr->count = count;
770 VB->NormalPtr->count = count;
771 VB->ColorPtr->count = count;
772 VB->IndexPtr->count = count;
773 VB->EdgeFlagPtr->count = count;
774 VB->TexCoordPtr[0]->count = count;
775 VB->TexCoordPtr[1]->count = count;
776
777 VB->Flag[count] |= VERT_END_VB;
778 VB->Flag[VB_START] |= VERT_NORM;
779
780 VB->NextPrimitive[VB->CopyStart] = VB->Count;
781 VB->Primitive[VB->CopyStart] = mode;
782
783 /* Transform and render.
784 */
785 gl_run_pipeline( VB );
786 gl_reset_vb( VB );
787
788 ctx->Array.Flag[count] = ctx->Array.Flags;
789 ctx->Array.Flag[VB_START] = ctx->Array.Flags;
790 IM->Flag[VB_START] = 0;
791
792 start += n;
793 remaining -= n;
794 }
795
796 ctx->CompileCVAFlag = relock;
797 }
798 else if (ctx->Array.Vertex.Enabled)
799 {
800 /* The GL_COMPILE and GL_COMPILE_AND_EXECUTE cases. These
801 * could be handled by the above code, but it gets a little
802 * complex.
803 */
804 /* No need to reset - never called from inside a display list */
805 gl_Begin( ctx, mode );
806 for (i=0;i<count;i++) {
807 gl_ArrayElement( ctx, start+i );
808 }
809 gl_End( ctx );
810 }
811 else
812 {
813 /* The degenerate case where vertices are not enabled - only
814 * need to process the very final array element, as all of the
815 * preceding ones would be overwritten anyway.
816 */
817 gl_Begin( ctx, mode );
818 gl_ArrayElement( ctx, start+count );
819 gl_End( ctx );
820 }
821 }
822
823
824
825 /* KW: Exactly fakes the effects of calling glArrayElement multiple times.
826 * Compilation is handled via. the IM->maybe_transform_vb() callback.
827 */
828 #define DRAW_ELT(FUNC, TYPE) \
829 static void FUNC( GLcontext *ctx, GLenum mode, \
830 TYPE *indices, GLuint count ) \
831 { \
832 GLuint i,j; \
833 \
834 if (count) gl_Begin( ctx, mode ); \
835 \
836 for (j = 0 ; j < count ; ) { \
837 GLuint nr = MIN2( VB_MAX, count - j + VB_START ); \
838 struct immediate *IM = ctx->input; \
839 GLuint sf = IM->Flag[VB_START]; \
840 IM->FlushElt |= IM->ArrayEltFlush; \
841 \
842 for (i = VB_START ; i < nr ; i++) { \
843 IM->Elt[i] = (GLuint) *indices++; \
844 IM->Flag[i] = VERT_ELT; \
845 } \
846 \
847 if (j == 0) IM->Flag[IM->Start] |= sf; \
848 \
849 IM->Count = nr; \
850 j += nr - VB_START; \
851 \
852 if (j == count) gl_End( ctx ); \
853 IM->maybe_transform_vb( IM ); \
854 } \
855 }
856
857 DRAW_ELT( draw_elt_ubyte, GLubyte )
858 DRAW_ELT( draw_elt_ushort, GLushort )
859 DRAW_ELT( draw_elt_uint, GLuint )
860
861
862 static GLuint natural_stride[0x10] =
863 {
864 sizeof(GLbyte), /* 0 */
865 sizeof(GLubyte), /* 1 */
866 sizeof(GLshort), /* 2 */
867 sizeof(GLushort), /* 3 */
868 sizeof(GLint), /* 4 */
869 sizeof(GLuint), /* 5 */
870 sizeof(GLfloat), /* 6 */
871 2 * sizeof(GLbyte), /* 7 */
872 3 * sizeof(GLbyte), /* 8 */
873 4 * sizeof(GLbyte), /* 9 */
874 sizeof(GLdouble), /* a */
875 0, /* b */
876 0, /* c */
877 0, /* d */
878 0, /* e */
879 0 /* f */
880 };
881
882 void GLAPIENTRY glDrawElements(CTX_ARG GLenum mode, GLsizei count,
883 GLenum type, const GLvoid *indices )
884 {
885 GLcontext *ctx;
886 struct gl_cva *cva;
887
888 GET_CONTEXT;
889 CHECK_CONTEXT;
890 ctx = CC;
891
892 cva = &ctx->CVA;
893 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawElements");
894
895 if (count <= 0) {
896 if (count < 0)
897 gl_error( ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
898 return;
899 }
900
901 if (mode < 0 || mode > GL_POLYGON) {
902 gl_error( ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
903 return;
904 }
905
906 if (type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT)
907 {
908 gl_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
909 return;
910 }
911
912 if (ctx->NewState)
913 gl_update_state(ctx);
914
915 if (ctx->CompileCVAFlag)
916 {
917 #if defined(MESA_CVA_PROF)
918 force_init_prof();
919 #endif
920
921 /* Treat VERT_ELT like a special client array.
922 */
923 ctx->Array.NewArrayState |= VERT_ELT;
924 ctx->Array.Summary |= VERT_ELT;
925 ctx->Array.Flags |= VERT_ELT;
926
927 cva->elt_mode = mode;
928 cva->elt_count = count;
929 cva->Elt.Type = type;
930 cva->Elt.Ptr = (void *) indices;
931 cva->Elt.StrideB = natural_stride[TYPE_IDX(type)];
932 cva->EltFunc = gl_trans_1ui_tab[TYPE_IDX(type)];
933
934 if (!cva->pre.pipeline_valid)
935 gl_build_precalc_pipeline( ctx );
936 else if (MESA_VERBOSE & VERBOSE_PIPELINE)
937 fprintf(stderr, ": dont rebuild\n");
938
939 gl_cva_force_precalc( ctx );
940
941 /* Did we 'precalculate' the render op?
942 */
943 if (ctx->CVA.pre.ops & PIPE_OP_RENDER) {
944 ctx->Array.NewArrayState |= VERT_ELT;
945 ctx->Array.Summary &= ~VERT_ELT;
946 ctx->Array.Flags &= ~VERT_ELT;
947 return;
948 }
949
950 if ( (MESA_VERBOSE&VERBOSE_VARRAY) )
951 printf("using immediate\n");
952 }
953
954
955 /* Otherwise, have to use the immediate path to render.
956 */
957 switch (type) {
958 case GL_UNSIGNED_BYTE:
959 {
960 GLubyte *ub_indices = (GLubyte *) indices;
961 if (ctx->Array.Summary & VERT_OBJ_ANY) {
962 draw_elt_ubyte( ctx, mode, ub_indices, count );
963 } else {
964 gl_ArrayElement( ctx, (GLuint) ub_indices[count-1] );
965 }
966 }
967 break;
968 case GL_UNSIGNED_SHORT:
969 {
970 GLushort *us_indices = (GLushort *) indices;
971 if (ctx->Array.Summary & VERT_OBJ_ANY) {
972 draw_elt_ushort( ctx, mode, us_indices, count );
973 } else {
974 gl_ArrayElement( ctx, (GLuint) us_indices[count-1] );
975 }
976 }
977 break;
978 case GL_UNSIGNED_INT:
979 {
980 GLuint *ui_indices = (GLuint *) indices;
981 if (ctx->Array.Summary & VERT_OBJ_ANY) {
982 draw_elt_uint( ctx, mode, ui_indices, count );
983 } else {
984 gl_ArrayElement( ctx, ui_indices[count-1] );
985 }
986 }
987 break;
988 default:
989 gl_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
990 break;
991 }
992
993 if (ctx->CompileCVAFlag) {
994 ctx->Array.NewArrayState |= VERT_ELT;
995 ctx->Array.Summary &= ~VERT_ELT;
996 }
997 }
998
999
1000
1001 void GLAPIENTRY glInterleavedArrays(CTX_ARG GLenum format, GLsizei stride,
1002 const GLvoid *pointer )
1003 {
1004 GLcontext *ctx;
1005 GLboolean tflag, cflag, nflag; /* enable/disable flags */
1006 GLint tcomps, ccomps, vcomps; /* components per texcoord, color, vertex */
1007
1008 GLenum ctype; /* color type */
1009 GLint coffset, noffset, voffset;/* color, normal, vertex offsets */
1010 GLint defstride; /* default stride */
1011 GLint c, f;
1012 GLint coordUnitSave;
1013
1014 GET_CONTEXT;
1015 CHECK_CONTEXT;
1016 ctx = CC;
1017
1018
1019 f = sizeof(GLfloat);
1020 c = f * ((4*sizeof(GLubyte) + (f-1)) / f);
1021
1022 if (stride<0) {
1023 gl_error( ctx, GL_INVALID_VALUE, "glInterleavedArrays(stride)" );
1024 return;
1025 }
1026
1027 switch (format) {
1028 case GL_V2F:
1029 tflag = GL_FALSE; cflag = GL_FALSE; nflag = GL_FALSE;
1030 tcomps = 0; ccomps = 0; vcomps = 2;
1031 voffset = 0;
1032 defstride = 2*f;
1033 break;
1034 case GL_V3F:
1035 tflag = GL_FALSE; cflag = GL_FALSE; nflag = GL_FALSE;
1036 tcomps = 0; ccomps = 0; vcomps = 3;
1037 voffset = 0;
1038 defstride = 3*f;
1039 break;
1040 case GL_C4UB_V2F:
1041 tflag = GL_FALSE; cflag = GL_TRUE; nflag = GL_FALSE;
1042 tcomps = 0; ccomps = 4; vcomps = 2;
1043 ctype = GL_UNSIGNED_BYTE;
1044 coffset = 0;
1045 voffset = c;
1046 defstride = c + 2*f;
1047 break;
1048 case GL_C4UB_V3F:
1049 tflag = GL_FALSE; cflag = GL_TRUE; nflag = GL_FALSE;
1050 tcomps = 0; ccomps = 4; vcomps = 3;
1051 ctype = GL_UNSIGNED_BYTE;
1052 coffset = 0;
1053 voffset = c;
1054 defstride = c + 3*f;
1055 break;
1056 case GL_C3F_V3F:
1057 tflag = GL_FALSE; cflag = GL_TRUE; nflag = GL_FALSE;
1058 tcomps = 0; ccomps = 3; vcomps = 3;
1059 ctype = GL_FLOAT;
1060 coffset = 0;
1061 voffset = 3*f;
1062 defstride = 6*f;
1063 break;
1064 case GL_N3F_V3F:
1065 tflag = GL_FALSE; cflag = GL_FALSE; nflag = GL_TRUE;
1066 tcomps = 0; ccomps = 0; vcomps = 3;
1067 noffset = 0;
1068 voffset = 3*f;
1069 defstride = 6*f;
1070 break;
1071 case GL_C4F_N3F_V3F:
1072 tflag = GL_FALSE; cflag = GL_TRUE; nflag = GL_TRUE;
1073 tcomps = 0; ccomps = 4; vcomps = 3;
1074 ctype = GL_FLOAT;
1075 coffset = 0;
1076 noffset = 4*f;
1077 voffset = 7*f;
1078 defstride = 10*f;
1079 break;
1080 case GL_T2F_V3F:
1081 tflag = GL_TRUE; cflag = GL_FALSE; nflag = GL_FALSE;
1082 tcomps = 2; ccomps = 0; vcomps = 3;
1083 voffset = 2*f;
1084 defstride = 5*f;
1085 break;
1086 case GL_T4F_V4F:
1087 tflag = GL_TRUE; cflag = GL_FALSE; nflag = GL_FALSE;
1088 tcomps = 4; ccomps = 0; vcomps = 4;
1089 voffset = 4*f;
1090 defstride = 8*f;
1091 break;
1092 case GL_T2F_C4UB_V3F:
1093 tflag = GL_TRUE; cflag = GL_TRUE; nflag = GL_FALSE;
1094 tcomps = 2; ccomps = 4; vcomps = 3;
1095 ctype = GL_UNSIGNED_BYTE;
1096 coffset = 2*f;
1097 voffset = c+2*f;
1098 defstride = c+5*f;
1099 break;
1100 case GL_T2F_C3F_V3F:
1101 tflag = GL_TRUE; cflag = GL_TRUE; nflag = GL_FALSE;
1102 tcomps = 2; ccomps = 3; vcomps = 3;
1103 ctype = GL_FLOAT;
1104 coffset = 2*f;
1105 voffset = 5*f;
1106 defstride = 8*f;
1107 break;
1108 case GL_T2F_N3F_V3F:
1109 tflag = GL_TRUE; cflag = GL_FALSE; nflag = GL_TRUE;
1110 tcomps = 2; ccomps = 0; vcomps = 3;
1111 noffset = 2*f;
1112 voffset = 5*f;
1113 defstride = 8*f;
1114 break;
1115 case GL_T2F_C4F_N3F_V3F:
1116 tflag = GL_TRUE; cflag = GL_TRUE; nflag = GL_TRUE;
1117 tcomps = 2; ccomps = 4; vcomps = 3;
1118 ctype = GL_FLOAT;
1119 coffset = 2*f;
1120 noffset = 6*f;
1121 voffset = 9*f;
1122 defstride = 12*f;
1123 break;
1124 case GL_T4F_C4F_N3F_V4F:
1125 tflag = GL_TRUE; cflag = GL_TRUE; nflag = GL_TRUE;
1126 tcomps = 4; ccomps = 4; vcomps = 4;
1127 ctype = GL_FLOAT;
1128 coffset = 4*f;
1129 noffset = 8*f;
1130 voffset = 11*f;
1131 defstride = 15*f;
1132 break;
1133 default:
1134 gl_error( ctx, GL_INVALID_ENUM, "glInterleavedArrays(format)" );
1135 return;
1136 }
1137
1138 if (stride==0) {
1139 stride = defstride;
1140 }
1141
1142 gl_DisableClientState( ctx, GL_EDGE_FLAG_ARRAY );
1143 gl_DisableClientState( ctx, GL_INDEX_ARRAY );
1144
1145 /* Texcoords */
1146 coordUnitSave = ctx->Array.ActiveTexture;
1147 if (tflag) {
1148 GLint i;
1149 GLint factor = ctx->Array.TexCoordInterleaveFactor;
1150 for (i = 0; i < factor; i++) {
1151 gl_ActiveTexture( ctx, (GLenum) (GL_TEXTURE0_ARB + i) );
1152 gl_EnableClientState( ctx, GL_TEXTURE_COORD_ARRAY );
1153 glTexCoordPointer(CTX_PRM tcomps, GL_FLOAT, stride,
1154 (GLubyte *) pointer + i * coffset );
1155 }
1156 for (i = factor; i < ctx->Const.MaxTextureUnits; i++) {
1157 gl_ActiveTexture( ctx, (GLenum) (GL_TEXTURE0_ARB + i) );
1158 gl_DisableClientState( ctx, GL_TEXTURE_COORD_ARRAY );
1159 }
1160 }
1161 else {
1162 GLint i;
1163 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
1164 gl_ActiveTexture( ctx, (GLenum) (GL_TEXTURE0_ARB + i) );
1165 gl_DisableClientState( ctx, GL_TEXTURE_COORD_ARRAY );
1166 }
1167 }
1168 /* Restore texture coordinate unit index */
1169 gl_ActiveTexture( ctx, (GLenum) (GL_TEXTURE0_ARB + coordUnitSave) );
1170
1171
1172 /* Color */
1173 if (cflag) {
1174 gl_EnableClientState( ctx, GL_COLOR_ARRAY );
1175 glColorPointer(CTX_PRM ccomps, ctype, stride,
1176 (GLubyte*) pointer + coffset );
1177 }
1178 else {
1179 gl_DisableClientState( ctx, GL_COLOR_ARRAY );
1180 }
1181
1182
1183 /* Normals */
1184 if (nflag) {
1185 gl_EnableClientState( ctx, GL_NORMAL_ARRAY );
1186 glNormalPointer(CTX_PRM GL_FLOAT, stride,
1187 (GLubyte*) pointer + noffset );
1188 }
1189 else {
1190 gl_DisableClientState( ctx, GL_NORMAL_ARRAY );
1191 }
1192
1193 gl_EnableClientState( ctx, GL_VERTEX_ARRAY );
1194 glVertexPointer(CTX_PRM vcomps, GL_FLOAT, stride,
1195 (GLubyte *) pointer + voffset );
1196 }
1197
1198
1199
1200 void GLAPIENTRY glDrawRangeElements(CTX_ARG GLenum mode, GLuint start,
1201 GLuint end, GLsizei count,
1202 GLenum type, const GLvoid *indices )
1203 {
1204 GLcontext *ctx;
1205 GET_CONTEXT;
1206 CHECK_CONTEXT;
1207 ctx = CC;
1208
1209 if (end < start) {
1210 gl_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements( end < start )");
1211 return;
1212 }
1213
1214 if (!ctx->Array.LockCount && 2*count > 3*(end-start)) {
1215 glLockArraysEXT(CTX_PRM start, end );
1216 glDrawElements(CTX_PRM mode, count, type, indices );
1217 glUnlockArraysEXT(CTX_VPRM );
1218 } else {
1219 glDrawElements(CTX_PRM mode, count, type, indices );
1220 }
1221 }
1222
1223
1224
1225 void gl_update_client_state( GLcontext *ctx )
1226 {
1227 static GLuint sz_flags[5] = { 0,
1228 0,
1229 VERT_OBJ_2,
1230 VERT_OBJ_23,
1231 VERT_OBJ_234 };
1232
1233 static GLuint tc_flags[5] = { 0,
1234 VERT_TEX0_1,
1235 VERT_TEX0_12,
1236 VERT_TEX0_123,
1237 VERT_TEX0_1234 };
1238
1239 ctx->Array.Flags = 0;
1240 ctx->Array.Summary = 0;
1241 ctx->input->ArrayIncr = 0;
1242
1243 if (ctx->Array.Normal.Enabled) ctx->Array.Flags |= VERT_NORM;
1244 if (ctx->Array.Color.Enabled) ctx->Array.Flags |= VERT_RGBA;
1245 if (ctx->Array.Index.Enabled) ctx->Array.Flags |= VERT_INDEX;
1246 if (ctx->Array.EdgeFlag.Enabled) ctx->Array.Flags |= VERT_EDGE;
1247 if (ctx->Array.Vertex.Enabled) {
1248 ctx->Array.Flags |= sz_flags[ctx->Array.Vertex.Size];
1249 ctx->input->ArrayIncr = 1;
1250 }
1251 if (ctx->Array.TexCoord[0].Enabled) {
1252 ctx->Array.Flags |= tc_flags[ctx->Array.TexCoord[0].Size];
1253 }
1254 if (ctx->Array.TexCoord[1].Enabled) {
1255 ctx->Array.Flags |= (tc_flags[ctx->Array.TexCoord[1].Size] << NR_TEXSIZE_BITS);
1256 }
1257
1258 /* Not really important any more:
1259 */
1260 ctx->Array.Summary = ctx->Array.Flags & VERT_DATA;
1261 ctx->input->ArrayAndFlags = ~ctx->Array.Flags;
1262 ctx->input->ArrayEltFlush = !(ctx->CompileCVAFlag);
1263 }
1264