6690b2a10252da731f039c868a0062a17f4723c5
[mesa.git] / src / mesa / main / points.c
1 /* $Id: points.c,v 1.2 1999/09/18 20:41:23 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
28
29
30
31 #ifdef PC_HEADER
32 #include "all.h"
33 #else
34 #include "context.h"
35 #include "feedback.h"
36 #include "macros.h"
37 #include "pb.h"
38 #include "span.h"
39 #include "texstate.h"
40 #include "types.h"
41 #include "vb.h"
42 #include "mmath.h"
43 #ifdef XFree86Server
44 #include "GL/xf86glx.h"
45 #endif
46 #endif
47
48
49
50 void gl_PointSize( GLcontext *ctx, GLfloat size )
51 {
52 if (size<=0.0) {
53 gl_error( ctx, GL_INVALID_VALUE, "glPointSize" );
54 return;
55 }
56 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPointSize");
57
58 if (ctx->Point.Size != size) {
59 ctx->Point.Size = size;
60 ctx->TriangleCaps &= ~DD_POINT_SIZE;
61 if (size != 1.0) ctx->TriangleCaps |= DD_POINT_SIZE;
62 ctx->NewState |= NEW_RASTER_OPS;
63 }
64 }
65
66
67
68 void gl_PointParameterfvEXT( GLcontext *ctx, GLenum pname,
69 const GLfloat *params)
70 {
71 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPointParameterfvEXT");
72 if(pname==GL_DISTANCE_ATTENUATION_EXT) {
73 GLboolean tmp = ctx->Point.Attenuated;
74 COPY_3V(ctx->Point.Params,params);
75 ctx->Point.Attenuated = (params[0] != 1.0 ||
76 params[1] != 0.0 ||
77 params[2] != 0.0);
78
79 if (tmp != ctx->Point.Attenuated) {
80 ctx->Enabled ^= ENABLE_POINT_ATTEN;
81 ctx->TriangleCaps ^= DD_POINT_ATTEN;
82 ctx->NewState |= NEW_RASTER_OPS;
83 }
84 } else {
85 if (*params<0.0 ) {
86 gl_error( ctx, GL_INVALID_VALUE, "glPointParameterfvEXT" );
87 return;
88 }
89 switch (pname) {
90 case GL_POINT_SIZE_MIN_EXT:
91 ctx->Point.MinSize=*params;
92 break;
93 case GL_POINT_SIZE_MAX_EXT:
94 ctx->Point.MaxSize=*params;
95 break;
96 case GL_POINT_FADE_THRESHOLD_SIZE_EXT:
97 ctx->Point.Threshold=*params;
98 break;
99 default:
100 gl_error( ctx, GL_INVALID_ENUM, "glPointParameterfvEXT" );
101 return;
102 }
103 }
104 ctx->NewState |= NEW_RASTER_OPS;
105 }
106
107
108 /**********************************************************************/
109 /***** Rasterization *****/
110 /**********************************************************************/
111
112
113 /*
114 * There are 3 pairs (RGBA, CI) of point rendering functions:
115 * 1. simple: size=1 and no special rasterization functions (fastest)
116 * 2. size1: size=1 and any rasterization functions
117 * 3. general: any size and rasterization functions (slowest)
118 *
119 * All point rendering functions take the same two arguments: first and
120 * last which specify that the points specified by VB[first] through
121 * VB[last] are to be rendered.
122 */
123
124
125
126
127
128 /*
129 * CI points with size == 1.0
130 */
131 void size1_ci_points( GLcontext *ctx, GLuint first, GLuint last )
132 {
133 struct vertex_buffer *VB = ctx->VB;
134 struct pixel_buffer *PB = ctx->PB;
135 GLfloat *win;
136 GLint *pbx = PB->x, *pby = PB->y;
137 GLdepth *pbz = PB->z;
138 GLuint *pbi = PB->i;
139 GLuint pbcount = PB->count;
140 GLuint i;
141
142 win = &VB->Win.data[first][0];
143 for (i=first;i<=last;i++) {
144 if (VB->ClipMask[i]==0) {
145 pbx[pbcount] = (GLint) win[0];
146 pby[pbcount] = (GLint) win[1];
147 pbz[pbcount] = (GLint) (win[2] + ctx->PointZoffset);
148 pbi[pbcount] = VB->IndexPtr->data[i];
149 pbcount++;
150 }
151 win += 3;
152 }
153 PB->count = pbcount;
154 PB_CHECK_FLUSH(ctx, PB);
155 }
156
157
158
159 /*
160 * RGBA points with size == 1.0
161 */
162 static void size1_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
163 {
164 struct vertex_buffer *VB = ctx->VB;
165 struct pixel_buffer *PB = ctx->PB;
166 GLuint i;
167
168 for (i=first;i<=last;i++) {
169 if (VB->ClipMask[i]==0) {
170 GLint x, y, z;
171 GLint red, green, blue, alpha;
172
173 x = (GLint) VB->Win.data[i][0];
174 y = (GLint) VB->Win.data[i][1];
175 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
176
177 red = VB->ColorPtr->data[i][0];
178 green = VB->ColorPtr->data[i][1];
179 blue = VB->ColorPtr->data[i][2];
180 alpha = VB->ColorPtr->data[i][3];
181
182 PB_WRITE_RGBA_PIXEL( PB, x, y, z, red, green, blue, alpha );
183 }
184 }
185 PB_CHECK_FLUSH(ctx,PB);
186 }
187
188
189
190 /*
191 * General CI points.
192 */
193 static void general_ci_points( GLcontext *ctx, GLuint first, GLuint last )
194 {
195 struct vertex_buffer *VB = ctx->VB;
196 struct pixel_buffer *PB = ctx->PB;
197 GLuint i;
198 GLint isize = (GLint) (CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE) + 0.5F);
199 GLint radius = isize >> 1;
200
201 for (i=first;i<=last;i++) {
202 if (VB->ClipMask[i]==0) {
203 GLint x, y, z;
204 GLint x0, x1, y0, y1;
205 GLint ix, iy;
206
207 x = (GLint) VB->Win.data[i][0];
208 y = (GLint) VB->Win.data[i][1];
209 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
210
211 if (isize & 1) {
212 /* odd size */
213 x0 = x - radius;
214 x1 = x + radius;
215 y0 = y - radius;
216 y1 = y + radius;
217 }
218 else {
219 /* even size */
220 x0 = (GLint) (x + 1.5F) - radius;
221 x1 = x0 + isize - 1;
222 y0 = (GLint) (y + 1.5F) - radius;
223 y1 = y0 + isize - 1;
224 }
225
226 PB_SET_INDEX( ctx, PB, VB->IndexPtr->data[i] );
227
228 for (iy=y0;iy<=y1;iy++) {
229 for (ix=x0;ix<=x1;ix++) {
230 PB_WRITE_PIXEL( PB, ix, iy, z );
231 }
232 }
233 PB_CHECK_FLUSH(ctx,PB);
234 }
235 }
236 }
237
238
239 /*
240 * General RGBA points.
241 */
242 static void general_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
243 {
244 struct vertex_buffer *VB = ctx->VB;
245 struct pixel_buffer *PB = ctx->PB;
246 GLuint i;
247 GLint isize = (GLint) (CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE) + 0.5F);
248 GLint radius = isize >> 1;
249
250 for (i=first;i<=last;i++) {
251 if (VB->ClipMask[i]==0) {
252 GLint x, y, z;
253 GLint x0, x1, y0, y1;
254 GLint ix, iy;
255
256 x = (GLint) VB->Win.data[i][0];
257 y = (GLint) VB->Win.data[i][1];
258 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
259
260 if (isize & 1) {
261 /* odd size */
262 x0 = x - radius;
263 x1 = x + radius;
264 y0 = y - radius;
265 y1 = y + radius;
266 }
267 else {
268 /* even size */
269 x0 = (GLint) (x + 1.5F) - radius;
270 x1 = x0 + isize - 1;
271 y0 = (GLint) (y + 1.5F) - radius;
272 y1 = y0 + isize - 1;
273 }
274
275 PB_SET_COLOR( ctx, PB,
276 VB->ColorPtr->data[i][0],
277 VB->ColorPtr->data[i][1],
278 VB->ColorPtr->data[i][2],
279 VB->ColorPtr->data[i][3] );
280
281 for (iy=y0;iy<=y1;iy++) {
282 for (ix=x0;ix<=x1;ix++) {
283 PB_WRITE_PIXEL( PB, ix, iy, z );
284 }
285 }
286 PB_CHECK_FLUSH(ctx,PB);
287 }
288 }
289 }
290
291
292
293
294 /*
295 * Textured RGBA points.
296 */
297 static void textured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
298 {
299 struct vertex_buffer *VB = ctx->VB;
300 struct pixel_buffer *PB = ctx->PB;
301 GLuint i;
302
303 for (i=first;i<=last;i++) {
304 if (VB->ClipMask[i]==0) {
305 GLint x, y, z;
306 GLint x0, x1, y0, y1;
307 GLint ix, iy;
308 GLint isize, radius;
309 GLint red, green, blue, alpha;
310 GLfloat s, t, u;
311
312 x = (GLint) VB->Win.data[i][0];
313 y = (GLint) VB->Win.data[i][1];
314 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
315
316 isize = (GLint)
317 (CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE) + 0.5F);
318 if (isize<1) {
319 isize = 1;
320 }
321 radius = isize >> 1;
322
323 if (isize & 1) {
324 /* odd size */
325 x0 = x - radius;
326 x1 = x + radius;
327 y0 = y - radius;
328 y1 = y + radius;
329 }
330 else {
331 /* even size */
332 x0 = (GLint) (x + 1.5F) - radius;
333 x1 = x0 + isize - 1;
334 y0 = (GLint) (y + 1.5F) - radius;
335 y1 = y0 + isize - 1;
336 }
337
338 red = VB->ColorPtr->data[i][0];
339 green = VB->ColorPtr->data[i][1];
340 blue = VB->ColorPtr->data[i][2];
341 alpha = VB->ColorPtr->data[i][3];
342
343 switch (VB->TexCoordPtr[0]->size) {
344 case 4:
345 s = VB->TexCoordPtr[0]->data[i][0]/VB->TexCoordPtr[0]->data[i][3];
346 t = VB->TexCoordPtr[0]->data[i][1]/VB->TexCoordPtr[0]->data[i][3];
347 u = VB->TexCoordPtr[0]->data[i][2]/VB->TexCoordPtr[0]->data[i][3];
348 break;
349 case 3:
350 s = VB->TexCoordPtr[0]->data[i][0];
351 t = VB->TexCoordPtr[0]->data[i][1];
352 u = VB->TexCoordPtr[0]->data[i][2];
353 break;
354 case 2:
355 s = VB->TexCoordPtr[0]->data[i][0];
356 t = VB->TexCoordPtr[0]->data[i][1];
357 u = 0.0;
358 break;
359 case 1:
360 s = VB->TexCoordPtr[0]->data[i][0];
361 t = 0.0;
362 u = 0.0;
363 break;
364 }
365
366
367
368
369 /* don't think this is needed
370 PB_SET_COLOR( red, green, blue, alpha );
371 */
372
373 for (iy=y0;iy<=y1;iy++) {
374 for (ix=x0;ix<=x1;ix++) {
375 PB_WRITE_TEX_PIXEL( PB, ix, iy, z, red, green, blue, alpha, s, t, u );
376 }
377 }
378 PB_CHECK_FLUSH(ctx,PB);
379 }
380 }
381 }
382
383
384 /*
385 * Multitextured RGBA points.
386 */
387 static void multitextured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
388 {
389 struct vertex_buffer *VB = ctx->VB;
390 struct pixel_buffer *PB = ctx->PB;
391 GLuint i;
392
393 for (i=first;i<=last;i++) {
394 if (VB->ClipMask[i]==0) {
395 GLint x, y, z;
396 GLint x0, x1, y0, y1;
397 GLint ix, iy;
398 GLint isize, radius;
399 GLint red, green, blue, alpha;
400 GLfloat s, t, u;
401 GLfloat s1, t1, u1;
402
403 x = (GLint) VB->Win.data[i][0];
404 y = (GLint) VB->Win.data[i][1];
405 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
406
407 isize = (GLint)
408 (CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE) + 0.5F);
409 if (isize<1) {
410 isize = 1;
411 }
412 radius = isize >> 1;
413
414 if (isize & 1) {
415 /* odd size */
416 x0 = x - radius;
417 x1 = x + radius;
418 y0 = y - radius;
419 y1 = y + radius;
420 }
421 else {
422 /* even size */
423 x0 = (GLint) (x + 1.5F) - radius;
424 x1 = x0 + isize - 1;
425 y0 = (GLint) (y + 1.5F) - radius;
426 y1 = y0 + isize - 1;
427 }
428
429 red = VB->ColorPtr->data[i][0];
430 green = VB->ColorPtr->data[i][1];
431 blue = VB->ColorPtr->data[i][2];
432 alpha = VB->ColorPtr->data[i][3];
433
434 switch (VB->TexCoordPtr[0]->size) {
435 case 4:
436 s = VB->TexCoordPtr[0]->data[i][0]/VB->TexCoordPtr[0]->data[i][3];
437 t = VB->TexCoordPtr[0]->data[i][1]/VB->TexCoordPtr[0]->data[i][3];
438 u = VB->TexCoordPtr[0]->data[i][2]/VB->TexCoordPtr[0]->data[i][3];
439 break;
440 case 3:
441 s = VB->TexCoordPtr[0]->data[i][0];
442 t = VB->TexCoordPtr[0]->data[i][1];
443 u = VB->TexCoordPtr[0]->data[i][2];
444 break;
445 case 2:
446 s = VB->TexCoordPtr[0]->data[i][0];
447 t = VB->TexCoordPtr[0]->data[i][1];
448 u = 0.0;
449 break;
450 case 1:
451 s = VB->TexCoordPtr[0]->data[i][0];
452 t = 0.0;
453 u = 0.0;
454 break;
455 }
456
457 switch (VB->TexCoordPtr[1]->size) {
458 case 4:
459 s1 = VB->TexCoordPtr[1]->data[i][0]/VB->TexCoordPtr[1]->data[i][3];
460 t1 = VB->TexCoordPtr[1]->data[i][1]/VB->TexCoordPtr[1]->data[i][3];
461 u1 = VB->TexCoordPtr[1]->data[i][2]/VB->TexCoordPtr[1]->data[i][3];
462 break;
463 case 3:
464 s1 = VB->TexCoordPtr[1]->data[i][0];
465 t1 = VB->TexCoordPtr[1]->data[i][1];
466 u1 = VB->TexCoordPtr[1]->data[i][2];
467 break;
468 case 2:
469 s1 = VB->TexCoordPtr[1]->data[i][0];
470 t1 = VB->TexCoordPtr[1]->data[i][1];
471 u1 = 0.0;
472 break;
473 case 1:
474 s1 = VB->TexCoordPtr[1]->data[i][0];
475 t1 = 0.0;
476 u1 = 0.0;
477 break;
478 }
479
480 for (iy=y0;iy<=y1;iy++) {
481 for (ix=x0;ix<=x1;ix++) {
482 PB_WRITE_MULTITEX_PIXEL( PB, ix, iy, z, red, green, blue, alpha, s, t, u, s1, t1, u1 );
483 }
484 }
485 PB_CHECK_FLUSH(ctx,PB);
486 }
487 }
488 }
489
490
491
492
493 /*
494 * Antialiased points with or without texture mapping.
495 */
496 static void antialiased_rgba_points( GLcontext *ctx,
497 GLuint first, GLuint last )
498 {
499 struct vertex_buffer *VB = ctx->VB;
500 struct pixel_buffer *PB = ctx->PB;
501 GLuint i;
502 GLfloat radius, rmin, rmax, rmin2, rmax2, cscale;
503
504 radius = CLAMP( ctx->Point.Size, MIN_POINT_SIZE, MAX_POINT_SIZE ) * 0.5F;
505 rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
506 rmax = radius + 0.7071F;
507 rmin2 = rmin*rmin;
508 rmax2 = rmax*rmax;
509 cscale = 256.0F / (rmax2-rmin2);
510
511 if (ctx->Texture.ReallyEnabled) {
512 for (i=first;i<=last;i++) {
513 if (VB->ClipMask[i]==0) {
514 GLint xmin, ymin, xmax, ymax;
515 GLint x, y, z;
516 GLint red, green, blue, alpha;
517 GLfloat s, t, u;
518 GLfloat s1, t1, u1;
519
520 xmin = (GLint) (VB->Win.data[i][0] - radius);
521 xmax = (GLint) (VB->Win.data[i][0] + radius);
522 ymin = (GLint) (VB->Win.data[i][1] - radius);
523 ymax = (GLint) (VB->Win.data[i][1] + radius);
524 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
525
526 red = VB->ColorPtr->data[i][0];
527 green = VB->ColorPtr->data[i][1];
528 blue = VB->ColorPtr->data[i][2];
529
530 switch (VB->TexCoordPtr[0]->size) {
531 case 4:
532 s = (VB->TexCoordPtr[0]->data[i][0]/
533 VB->TexCoordPtr[0]->data[i][3]);
534 t = (VB->TexCoordPtr[0]->data[i][1]/
535 VB->TexCoordPtr[0]->data[i][3]);
536 u = (VB->TexCoordPtr[0]->data[i][2]/
537 VB->TexCoordPtr[0]->data[i][3]);
538 break;
539 case 3:
540 s = VB->TexCoordPtr[0]->data[i][0];
541 t = VB->TexCoordPtr[0]->data[i][1];
542 u = VB->TexCoordPtr[0]->data[i][2];
543 break;
544 case 2:
545 s = VB->TexCoordPtr[0]->data[i][0];
546 t = VB->TexCoordPtr[0]->data[i][1];
547 u = 0.0;
548 break;
549 case 1:
550 s = VB->TexCoordPtr[0]->data[i][0];
551 t = 0.0;
552 u = 0.0;
553 break;
554 }
555
556 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
557 /* Multitextured! This is probably a slow enough path that
558 there's no reason to specialize the multitexture case. */
559 switch (VB->TexCoordPtr[1]->size) {
560 case 4:
561 s1 = ( VB->TexCoordPtr[1]->data[i][0] /
562 VB->TexCoordPtr[1]->data[i][3]);
563 t1 = ( VB->TexCoordPtr[1]->data[i][1] /
564 VB->TexCoordPtr[1]->data[i][3]);
565 u1 = ( VB->TexCoordPtr[1]->data[i][2] /
566 VB->TexCoordPtr[1]->data[i][3]);
567 break;
568 case 3:
569 s1 = VB->TexCoordPtr[1]->data[i][0];
570 t1 = VB->TexCoordPtr[1]->data[i][1];
571 u1 = VB->TexCoordPtr[1]->data[i][2];
572 break;
573 case 2:
574 s1 = VB->TexCoordPtr[1]->data[i][0];
575 t1 = VB->TexCoordPtr[1]->data[i][1];
576 u1 = 0.0;
577 break;
578 case 1:
579 s1 = VB->TexCoordPtr[1]->data[i][0];
580 t1 = 0.0;
581 u1 = 0.0;
582 break;
583 }
584 }
585
586 for (y=ymin;y<=ymax;y++) {
587 for (x=xmin;x<=xmax;x++) {
588 GLfloat dx = x/*+0.5F*/ - VB->Win.data[i][0];
589 GLfloat dy = y/*+0.5F*/ - VB->Win.data[i][1];
590 GLfloat dist2 = dx*dx + dy*dy;
591 if (dist2<rmax2) {
592 alpha = VB->ColorPtr->data[i][3];
593 if (dist2>=rmin2) {
594 GLint coverage = (GLint) (256.0F-(dist2-rmin2)*cscale);
595 /* coverage is in [0,256] */
596 alpha = (alpha * coverage) >> 8;
597 }
598 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
599 PB_WRITE_MULTITEX_PIXEL( PB, x,y,z, red, green, blue,
600 alpha, s, t, u, s1, t1, u1 );
601 } else {
602 PB_WRITE_TEX_PIXEL( PB, x,y,z, red, green, blue,
603 alpha, s, t, u );
604 }
605 }
606 }
607 }
608
609 PB_CHECK_FLUSH(ctx,PB);
610 }
611 }
612 }
613 else {
614 /* Not texture mapped */
615 for (i=first;i<=last;i++) {
616 if (VB->ClipMask[i]==0) {
617 GLint xmin, ymin, xmax, ymax;
618 GLint x, y, z;
619 GLint red, green, blue, alpha;
620
621 xmin = (GLint) (VB->Win.data[i][0] - radius);
622 xmax = (GLint) (VB->Win.data[i][0] + radius);
623 ymin = (GLint) (VB->Win.data[i][1] - radius);
624 ymax = (GLint) (VB->Win.data[i][1] + radius);
625 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
626
627 red = VB->ColorPtr->data[i][0];
628 green = VB->ColorPtr->data[i][1];
629 blue = VB->ColorPtr->data[i][2];
630
631 for (y=ymin;y<=ymax;y++) {
632 for (x=xmin;x<=xmax;x++) {
633 GLfloat dx = x/*+0.5F*/ - VB->Win.data[i][0];
634 GLfloat dy = y/*+0.5F*/ - VB->Win.data[i][1];
635 GLfloat dist2 = dx*dx + dy*dy;
636 if (dist2<rmax2) {
637 alpha = VB->ColorPtr->data[i][3];
638 if (dist2>=rmin2) {
639 GLint coverage = (GLint) (256.0F-(dist2-rmin2)*cscale);
640 /* coverage is in [0,256] */
641 alpha = (alpha * coverage) >> 8;
642 }
643 PB_WRITE_RGBA_PIXEL( PB, x, y, z, red, green, blue,
644 alpha );
645 }
646 }
647 }
648 PB_CHECK_FLUSH(ctx,PB);
649 }
650 }
651 }
652 }
653
654
655
656 /*
657 * Null rasterizer for measuring transformation speed.
658 */
659 static void null_points( GLcontext *ctx, GLuint first, GLuint last )
660 {
661 (void) ctx;
662 (void) first;
663 (void) last;
664 }
665
666
667
668 /* Definition of the functions for GL_EXT_point_parameters */
669
670 /* Calculates the distance attenuation formula of a vector of points in
671 * eye space coordinates
672 */
673 static void dist3(GLfloat *out, GLuint first, GLuint last,
674 const GLcontext *ctx, const GLvector4f *v)
675 {
676 GLuint stride = v->stride;
677 GLfloat *p = VEC_ELT(v, GLfloat, first);
678 GLuint i;
679
680 for (i = first ; i <= last ; i++, STRIDE_F(p, stride) )
681 {
682 GLfloat dist = GL_SQRT(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]);
683 out[i] = 1/(ctx->Point.Params[0]+
684 dist * (ctx->Point.Params[1] +
685 dist * ctx->Point.Params[2]));
686 }
687 }
688
689 static void dist2(GLfloat *out, GLuint first, GLuint last,
690 const GLcontext *ctx, const GLvector4f *v)
691 {
692 GLuint stride = v->stride;
693 GLfloat *p = VEC_ELT(v, GLfloat, first);
694 GLuint i;
695
696 for (i = first ; i <= last ; i++, STRIDE_F(p, stride) )
697 {
698 GLfloat dist = GL_SQRT(p[0]*p[0]+p[1]*p[1]);
699 out[i] = 1/(ctx->Point.Params[0]+
700 dist * (ctx->Point.Params[1] +
701 dist * ctx->Point.Params[2]));
702 }
703 }
704
705
706 typedef void (*dist_func)(GLfloat *out, GLuint first, GLuint last,
707 const GLcontext *ctx, const GLvector4f *v);
708
709
710 static dist_func eye_dist_tab[5] = {
711 0,
712 0,
713 dist2,
714 dist3,
715 dist3
716 };
717
718
719 static void clip_dist(GLfloat *out, GLuint first, GLuint last,
720 const GLcontext *ctx, GLvector4f *clip)
721 {
722 /* this is never called */
723 gl_problem(NULL, "clip_dist() called - dead code!\n");
724
725 (void) out;
726 (void) first;
727 (void) last;
728 (void) ctx;
729 (void) clip;
730
731 #if 0
732 GLuint i;
733 const GLfloat *from = (GLfloat *)clip_vec->start;
734 const GLuint stride = clip_vec->stride;
735
736 for (i = first ; i <= last ; i++ )
737 {
738 GLfloat dist = win[i][2];
739 out[i] = 1/(ctx->Point.Params[0]+
740 dist * (ctx->Point.Params[1] +
741 dist * ctx->Point.Params[2]));
742 }
743 #endif
744 }
745
746
747
748 /*
749 * Distance Attenuated General CI points.
750 */
751 static void dist_atten_general_ci_points( GLcontext *ctx, GLuint first,
752 GLuint last )
753 {
754 struct vertex_buffer *VB = ctx->VB;
755 struct pixel_buffer *PB = ctx->PB;
756 GLuint i;
757 GLfloat psize,dsize;
758 GLfloat dist[VB_SIZE];
759 psize=CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE);
760
761 if (ctx->NeedEyeCoords)
762 (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
763 else
764 clip_dist( dist, first, last, ctx, VB->ClipPtr );
765
766 for (i=first;i<=last;i++) {
767 if (VB->ClipMask[i]==0) {
768 GLint x, y, z;
769 GLint x0, x1, y0, y1;
770 GLint ix, iy;
771 GLint isize, radius;
772
773 x = (GLint) VB->Win.data[i][0];
774 y = (GLint) VB->Win.data[i][1];
775 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
776
777 dsize=psize*dist[i];
778 if(dsize>=ctx->Point.Threshold) {
779 isize=(GLint) (MIN2(dsize,ctx->Point.MaxSize)+0.5F);
780 } else {
781 isize=(GLint) (MAX2(ctx->Point.Threshold,ctx->Point.MinSize)+0.5F);
782 }
783 radius = isize >> 1;
784
785 if (isize & 1) {
786 /* odd size */
787 x0 = x - radius;
788 x1 = x + radius;
789 y0 = y - radius;
790 y1 = y + radius;
791 }
792 else {
793 /* even size */
794 x0 = (GLint) (x + 1.5F) - radius;
795 x1 = x0 + isize - 1;
796 y0 = (GLint) (y + 1.5F) - radius;
797 y1 = y0 + isize - 1;
798 }
799
800 PB_SET_INDEX( ctx, PB, VB->IndexPtr->data[i] );
801
802 for (iy=y0;iy<=y1;iy++) {
803 for (ix=x0;ix<=x1;ix++) {
804 PB_WRITE_PIXEL( PB, ix, iy, z );
805 }
806 }
807 PB_CHECK_FLUSH(ctx,PB);
808 }
809 }
810 }
811
812 /*
813 * Distance Attenuated General RGBA points.
814 */
815 static void dist_atten_general_rgba_points( GLcontext *ctx, GLuint first,
816 GLuint last )
817 {
818 struct vertex_buffer *VB = ctx->VB;
819 struct pixel_buffer *PB = ctx->PB;
820 GLuint i;
821 GLubyte alpha;
822 GLfloat psize,dsize;
823 GLfloat dist[VB_SIZE];
824 psize=CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE);
825
826 if (ctx->NeedEyeCoords)
827 (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
828 else
829 clip_dist( dist, first, last, ctx, VB->ClipPtr );
830
831 for (i=first;i<=last;i++) {
832 if (VB->ClipMask[i]==0) {
833 GLint x, y, z;
834 GLint x0, x1, y0, y1;
835 GLint ix, iy;
836 GLint isize, radius;
837
838 x = (GLint) VB->Win.data[i][0];
839 y = (GLint) VB->Win.data[i][1];
840 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
841 dsize=psize*dist[i];
842 if (dsize >= ctx->Point.Threshold) {
843 isize = (GLint) (MIN2(dsize,ctx->Point.MaxSize)+0.5F);
844 alpha = VB->ColorPtr->data[i][3];
845 }
846 else {
847 isize = (GLint) (MAX2(ctx->Point.Threshold,ctx->Point.MinSize)+0.5F);
848 dsize /= ctx->Point.Threshold;
849 alpha = (GLint) (VB->ColorPtr->data[i][3]* (dsize*dsize));
850 }
851 radius = isize >> 1;
852
853 if (isize & 1) {
854 /* odd size */
855 x0 = x - radius;
856 x1 = x + radius;
857 y0 = y - radius;
858 y1 = y + radius;
859 }
860 else {
861 /* even size */
862 x0 = (GLint) (x + 1.5F) - radius;
863 x1 = x0 + isize - 1;
864 y0 = (GLint) (y + 1.5F) - radius;
865 y1 = y0 + isize - 1;
866 }
867
868 PB_SET_COLOR( ctx, PB,
869 VB->ColorPtr->data[i][0],
870 VB->ColorPtr->data[i][1],
871 VB->ColorPtr->data[i][2],
872 alpha );
873
874 for (iy=y0;iy<=y1;iy++) {
875 for (ix=x0;ix<=x1;ix++) {
876 PB_WRITE_PIXEL( PB, ix, iy, z );
877 }
878 }
879 PB_CHECK_FLUSH(ctx,PB);
880 }
881 }
882 }
883
884 /*
885 * Distance Attenuated Textured RGBA points.
886 */
887 static void dist_atten_textured_rgba_points( GLcontext *ctx, GLuint first,
888 GLuint last )
889 {
890 struct vertex_buffer *VB = ctx->VB;
891 struct pixel_buffer *PB = ctx->PB;
892 GLuint i;
893 GLfloat psize,dsize;
894 GLfloat dist[VB_SIZE];
895 psize=CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE);
896
897 if (ctx->NeedEyeCoords)
898 (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
899 else
900 clip_dist( dist, first, last, ctx, VB->ClipPtr );
901
902 for (i=first;i<=last;i++) {
903 if (VB->ClipMask[i]==0) {
904 GLint x, y, z;
905 GLint x0, x1, y0, y1;
906 GLint ix, iy;
907 GLint isize, radius;
908 GLint red, green, blue, alpha;
909 GLfloat s, t, u;
910 GLfloat s1, t1, u1;
911
912 x = (GLint) VB->Win.data[i][0];
913 y = (GLint) VB->Win.data[i][1];
914 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
915
916 dsize=psize*dist[i];
917 if(dsize>=ctx->Point.Threshold) {
918 isize=(GLint) (MIN2(dsize,ctx->Point.MaxSize)+0.5F);
919 alpha=VB->ColorPtr->data[i][3];
920 } else {
921 isize=(GLint) (MAX2(ctx->Point.Threshold,ctx->Point.MinSize)+0.5F);
922 dsize/=ctx->Point.Threshold;
923 alpha = (GLint) (VB->ColorPtr->data[i][3]* (dsize*dsize));
924 }
925
926 if (isize<1) {
927 isize = 1;
928 }
929 radius = isize >> 1;
930
931 if (isize & 1) {
932 /* odd size */
933 x0 = x - radius;
934 x1 = x + radius;
935 y0 = y - radius;
936 y1 = y + radius;
937 }
938 else {
939 /* even size */
940 x0 = (GLint) (x + 1.5F) - radius;
941 x1 = x0 + isize - 1;
942 y0 = (GLint) (y + 1.5F) - radius;
943 y1 = y0 + isize - 1;
944 }
945
946 red = VB->ColorPtr->data[i][0];
947 green = VB->ColorPtr->data[i][1];
948 blue = VB->ColorPtr->data[i][2];
949
950 switch (VB->TexCoordPtr[0]->size) {
951 case 4:
952 s = (VB->TexCoordPtr[0]->data[i][0]/
953 VB->TexCoordPtr[0]->data[i][3]);
954 t = (VB->TexCoordPtr[0]->data[i][1]/
955 VB->TexCoordPtr[0]->data[i][3]);
956 u = (VB->TexCoordPtr[0]->data[i][2]/
957 VB->TexCoordPtr[0]->data[i][3]);
958 break;
959 case 3:
960 s = VB->TexCoordPtr[0]->data[i][0];
961 t = VB->TexCoordPtr[0]->data[i][1];
962 u = VB->TexCoordPtr[0]->data[i][2];
963 break;
964 case 2:
965 s = VB->TexCoordPtr[0]->data[i][0];
966 t = VB->TexCoordPtr[0]->data[i][1];
967 u = 0.0;
968 break;
969 case 1:
970 s = VB->TexCoordPtr[0]->data[i][0];
971 t = 0.0;
972 u = 0.0;
973 break;
974 }
975
976 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
977 /* Multitextured! This is probably a slow enough path that
978 there's no reason to specialize the multitexture case. */
979 switch (VB->TexCoordPtr[1]->size) {
980 case 4:
981 s1 = ( VB->TexCoordPtr[1]->data[i][0] /
982 VB->TexCoordPtr[1]->data[i][3] );
983 t1 = ( VB->TexCoordPtr[1]->data[i][1] /
984 VB->TexCoordPtr[1]->data[i][3] );
985 u1 = ( VB->TexCoordPtr[1]->data[i][2] /
986 VB->TexCoordPtr[1]->data[i][3] );
987 break;
988 case 3:
989 s1 = VB->TexCoordPtr[1]->data[i][0];
990 t1 = VB->TexCoordPtr[1]->data[i][1];
991 u1 = VB->TexCoordPtr[1]->data[i][2];
992 break;
993 case 2:
994 s1 = VB->TexCoordPtr[1]->data[i][0];
995 t1 = VB->TexCoordPtr[1]->data[i][1];
996 u1 = 0.0;
997 break;
998 case 1:
999 s1 = VB->TexCoordPtr[1]->data[i][0];
1000 t1 = 0.0;
1001 u1 = 0.0;
1002 break;
1003 }
1004 }
1005
1006 /* don't think this is needed
1007 PB_SET_COLOR( red, green, blue, alpha );
1008 */
1009
1010 for (iy=y0;iy<=y1;iy++) {
1011 for (ix=x0;ix<=x1;ix++) {
1012 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
1013 PB_WRITE_MULTITEX_PIXEL( PB, ix, iy, z, red, green, blue, alpha, s, t, u, s1, t1, u1 );
1014 } else {
1015 PB_WRITE_TEX_PIXEL( PB, ix, iy, z, red, green, blue, alpha, s, t, u );
1016 }
1017 }
1018 }
1019 PB_CHECK_FLUSH(ctx,PB);
1020 }
1021 }
1022 }
1023
1024 /*
1025 * Distance Attenuated Antialiased points with or without texture mapping.
1026 */
1027 static void dist_atten_antialiased_rgba_points( GLcontext *ctx,
1028 GLuint first, GLuint last )
1029 {
1030 struct vertex_buffer *VB = ctx->VB;
1031 struct pixel_buffer *PB = ctx->PB;
1032 GLuint i;
1033 GLfloat radius, rmin, rmax, rmin2, rmax2, cscale;
1034 GLfloat psize,dsize,alphaf;
1035 GLfloat dist[VB_SIZE];
1036 psize=CLAMP(ctx->Point.Size,MIN_POINT_SIZE,MAX_POINT_SIZE);
1037
1038 if (ctx->NeedEyeCoords)
1039 (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
1040 else
1041 clip_dist( dist, first, last, ctx, VB->ClipPtr );
1042
1043 if (ctx->Texture.ReallyEnabled) {
1044 for (i=first;i<=last;i++) {
1045 if (VB->ClipMask[i]==0) {
1046 GLint xmin, ymin, xmax, ymax;
1047 GLint x, y, z;
1048 GLint red, green, blue, alpha;
1049 GLfloat s, t, u;
1050 GLfloat s1, t1, u1;
1051
1052 dsize=psize*dist[i];
1053 if(dsize>=ctx->Point.Threshold) {
1054 radius=(MIN2(dsize,ctx->Point.MaxSize)*0.5F);
1055 alphaf=1.0;
1056 } else {
1057 radius=(MAX2(ctx->Point.Threshold,ctx->Point.MinSize)*0.5F);
1058 dsize/=ctx->Point.Threshold;
1059 alphaf=(dsize*dsize);
1060 }
1061 rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
1062 rmax = radius + 0.7071F;
1063 rmin2 = rmin*rmin;
1064 rmax2 = rmax*rmax;
1065 cscale = 256.0F / (rmax2-rmin2);
1066
1067 xmin = (GLint) (VB->Win.data[i][0] - radius);
1068 xmax = (GLint) (VB->Win.data[i][0] + radius);
1069 ymin = (GLint) (VB->Win.data[i][1] - radius);
1070 ymax = (GLint) (VB->Win.data[i][1] + radius);
1071 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
1072
1073 red = VB->ColorPtr->data[i][0];
1074 green = VB->ColorPtr->data[i][1];
1075 blue = VB->ColorPtr->data[i][2];
1076
1077 switch (VB->TexCoordPtr[0]->size) {
1078 case 4:
1079 s = (VB->TexCoordPtr[0]->data[i][0]/
1080 VB->TexCoordPtr[0]->data[i][3]);
1081 t = (VB->TexCoordPtr[0]->data[i][1]/
1082 VB->TexCoordPtr[0]->data[i][3]);
1083 u = (VB->TexCoordPtr[0]->data[i][2]/
1084 VB->TexCoordPtr[0]->data[i][3]);
1085 break;
1086 case 3:
1087 s = VB->TexCoordPtr[0]->data[i][0];
1088 t = VB->TexCoordPtr[0]->data[i][1];
1089 u = VB->TexCoordPtr[0]->data[i][2];
1090 break;
1091 case 2:
1092 s = VB->TexCoordPtr[0]->data[i][0];
1093 t = VB->TexCoordPtr[0]->data[i][1];
1094 u = 0.0;
1095 break;
1096 case 1:
1097 s = VB->TexCoordPtr[0]->data[i][0];
1098 t = 0.0;
1099 u = 0.0;
1100 break;
1101 }
1102
1103 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
1104 /* Multitextured! This is probably a slow enough path that
1105 there's no reason to specialize the multitexture case. */
1106 switch (VB->TexCoordPtr[1]->size) {
1107 case 4:
1108 s1 = ( VB->TexCoordPtr[1]->data[i][0] /
1109 VB->TexCoordPtr[1]->data[i][3] );
1110 t1 = ( VB->TexCoordPtr[1]->data[i][1] /
1111 VB->TexCoordPtr[1]->data[i][3] );
1112 u1 = ( VB->TexCoordPtr[1]->data[i][2] /
1113 VB->TexCoordPtr[1]->data[i][3] );
1114 break;
1115 case 3:
1116 s1 = VB->TexCoordPtr[1]->data[i][0];
1117 t1 = VB->TexCoordPtr[1]->data[i][1];
1118 u1 = VB->TexCoordPtr[1]->data[i][2];
1119 break;
1120 case 2:
1121 s1 = VB->TexCoordPtr[1]->data[i][0];
1122 t1 = VB->TexCoordPtr[1]->data[i][1];
1123 u1 = 0.0;
1124 break;
1125 case 1:
1126 s1 = VB->TexCoordPtr[1]->data[i][0];
1127 t1 = 0.0;
1128 u1 = 0.0;
1129 break;
1130 }
1131 }
1132
1133 for (y=ymin;y<=ymax;y++) {
1134 for (x=xmin;x<=xmax;x++) {
1135 GLfloat dx = x/*+0.5F*/ - VB->Win.data[i][0];
1136 GLfloat dy = y/*+0.5F*/ - VB->Win.data[i][1];
1137 GLfloat dist2 = dx*dx + dy*dy;
1138 if (dist2<rmax2) {
1139 alpha = VB->ColorPtr->data[i][3];
1140 if (dist2>=rmin2) {
1141 GLint coverage = (GLint) (256.0F-(dist2-rmin2)*cscale);
1142 /* coverage is in [0,256] */
1143 alpha = (alpha * coverage) >> 8;
1144 }
1145 alpha = (GLint) (alpha * alphaf);
1146 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
1147 PB_WRITE_MULTITEX_PIXEL( PB, x,y,z, red, green, blue, alpha, s, t, u, s1, t1, u1 );
1148 } else {
1149 PB_WRITE_TEX_PIXEL( PB, x,y,z, red, green, blue, alpha, s, t, u );
1150 }
1151 }
1152 }
1153 }
1154 PB_CHECK_FLUSH(ctx,PB);
1155 }
1156 }
1157 }
1158 else {
1159 /* Not texture mapped */
1160 for (i=first;i<=last;i++) {
1161 if (VB->ClipMask[i]==0) {
1162 GLint xmin, ymin, xmax, ymax;
1163 GLint x, y, z;
1164 GLint red, green, blue, alpha;
1165
1166 dsize=psize*dist[i];
1167 if(dsize>=ctx->Point.Threshold) {
1168 radius=(MIN2(dsize,ctx->Point.MaxSize)*0.5F);
1169 alphaf=1.0;
1170 } else {
1171 radius=(MAX2(ctx->Point.Threshold,ctx->Point.MinSize)*0.5F);
1172 dsize/=ctx->Point.Threshold;
1173 alphaf=(dsize*dsize);
1174 }
1175 rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
1176 rmax = radius + 0.7071F;
1177 rmin2 = rmin*rmin;
1178 rmax2 = rmax*rmax;
1179 cscale = 256.0F / (rmax2-rmin2);
1180
1181 xmin = (GLint) (VB->Win.data[i][0] - radius);
1182 xmax = (GLint) (VB->Win.data[i][0] + radius);
1183 ymin = (GLint) (VB->Win.data[i][1] - radius);
1184 ymax = (GLint) (VB->Win.data[i][1] + radius);
1185 z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
1186
1187 red = VB->ColorPtr->data[i][0];
1188 green = VB->ColorPtr->data[i][1];
1189 blue = VB->ColorPtr->data[i][2];
1190
1191 for (y=ymin;y<=ymax;y++) {
1192 for (x=xmin;x<=xmax;x++) {
1193 GLfloat dx = x/*+0.5F*/ - VB->Win.data[i][0];
1194 GLfloat dy = y/*+0.5F*/ - VB->Win.data[i][1];
1195 GLfloat dist2 = dx*dx + dy*dy;
1196 if (dist2<rmax2) {
1197 alpha = VB->ColorPtr->data[i][3];
1198 if (dist2>=rmin2) {
1199 GLint coverage = (GLint) (256.0F-(dist2-rmin2)*cscale);
1200 /* coverage is in [0,256] */
1201 alpha = (alpha * coverage) >> 8;
1202 }
1203 alpha = (GLint) (alpha * alphaf);
1204 PB_WRITE_RGBA_PIXEL( PB, x, y, z, red, green, blue, alpha )
1205 ;
1206 }
1207 }
1208 }
1209 PB_CHECK_FLUSH(ctx,PB);
1210 }
1211 }
1212 }
1213 }
1214
1215
1216 /*
1217 * Examine the current context to determine which point drawing function
1218 * should be used.
1219 */
1220 void gl_set_point_function( GLcontext *ctx )
1221 {
1222 GLboolean rgbmode = ctx->Visual->RGBAflag;
1223
1224 if (ctx->RenderMode==GL_RENDER) {
1225 if (ctx->NoRaster) {
1226 ctx->Driver.PointsFunc = null_points;
1227 return;
1228 }
1229 if (ctx->Driver.PointsFunc) {
1230 /* Device driver will draw points. */
1231 ctx->IndirectTriangles &= ~DD_POINT_SW_RASTERIZE;
1232 return;
1233 }
1234
1235 if (!ctx->Point.Attenuated) {
1236 if (ctx->Point.SmoothFlag && rgbmode) {
1237 ctx->Driver.PointsFunc = antialiased_rgba_points;
1238 }
1239 else if (ctx->Texture.ReallyEnabled) {
1240 if (ctx->Texture.ReallyEnabled >= TEXTURE1_1D) {
1241 ctx->Driver.PointsFunc = multitextured_rgba_points;
1242 }
1243 else {
1244 ctx->Driver.PointsFunc = textured_rgba_points;
1245 }
1246 }
1247 else if (ctx->Point.Size==1.0) {
1248 /* size=1, any raster ops */
1249 if (rgbmode)
1250 ctx->Driver.PointsFunc = size1_rgba_points;
1251 else
1252 ctx->Driver.PointsFunc = size1_ci_points;
1253 }
1254 else {
1255 /* every other kind of point rendering */
1256 if (rgbmode)
1257 ctx->Driver.PointsFunc = general_rgba_points;
1258 else
1259 ctx->Driver.PointsFunc = general_ci_points;
1260 }
1261 }
1262 else if(ctx->Point.SmoothFlag && rgbmode) {
1263 ctx->Driver.PointsFunc = dist_atten_antialiased_rgba_points;
1264 }
1265 else if (ctx->Texture.ReallyEnabled) {
1266 ctx->Driver.PointsFunc = dist_atten_textured_rgba_points;
1267 }
1268 else {
1269 /* every other kind of point rendering */
1270 if (rgbmode)
1271 ctx->Driver.PointsFunc = dist_atten_general_rgba_points;
1272 else
1273 ctx->Driver.PointsFunc = dist_atten_general_ci_points;
1274 }
1275 }
1276 else if (ctx->RenderMode==GL_FEEDBACK) {
1277 ctx->Driver.PointsFunc = gl_feedback_points;
1278 }
1279 else {
1280 /* GL_SELECT mode */
1281 ctx->Driver.PointsFunc = gl_select_points;
1282 }
1283
1284 }
1285