Merge branch 'mesa_7_7_branch'
[mesa.git] / src / mesa / swrast / s_points.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "main/glheader.h"
27 #include "main/colormac.h"
28 #include "main/context.h"
29 #include "main/macros.h"
30 #include "s_context.h"
31 #include "s_feedback.h"
32 #include "s_points.h"
33 #include "s_span.h"
34
35
36 /**
37 * Used to cull points with invalid coords
38 */
39 #define CULL_INVALID(V) \
40 do { \
41 float tmp = (V)->attrib[FRAG_ATTRIB_WPOS][0] \
42 + (V)->attrib[FRAG_ATTRIB_WPOS][1]; \
43 if (IS_INF_OR_NAN(tmp)) \
44 return; \
45 } while(0)
46
47
48
49 /**
50 * Get/compute the point size.
51 * The size may come from a vertex shader, or computed with attentuation
52 * or just the glPointSize value.
53 * Must also clamp to user-defined range and implmentation limits.
54 */
55 static INLINE GLfloat
56 get_size(const GLcontext *ctx, const SWvertex *vert, GLboolean smoothed)
57 {
58 GLfloat size;
59
60 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
61 /* use vertex's point size */
62 size = vert->pointSize;
63 }
64 else {
65 /* use constant point size */
66 size = ctx->Point.Size;
67 }
68 /* always clamp to user-specified limits */
69 size = CLAMP(size, ctx->Point.MinSize, ctx->Point.MaxSize);
70 /* clamp to implementation limits */
71 if (smoothed)
72 size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA);
73 else
74 size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
75
76 return size;
77 }
78
79
80 /**
81 * Draw a point sprite
82 */
83 static void
84 sprite_point(GLcontext *ctx, const SWvertex *vert)
85 {
86 SWcontext *swrast = SWRAST_CONTEXT(ctx);
87 SWspan span;
88 GLfloat size;
89 GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1];
90 GLuint numTcoords = 0;
91 GLfloat t0, dtdy;
92
93 CULL_INVALID(vert);
94
95 /* z coord */
96 if (ctx->DrawBuffer->Visual.depthBits <= 16)
97 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
98 else
99 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
100 span.zStep = 0;
101
102 size = get_size(ctx, vert, GL_FALSE);
103
104 /* span init */
105 INIT_SPAN(span, GL_POINT);
106 span.interpMask = SPAN_Z | SPAN_RGBA;
107
108 span.facing = swrast->PointLineFacing;
109
110 span.red = ChanToFixed(vert->color[0]);
111 span.green = ChanToFixed(vert->color[1]);
112 span.blue = ChanToFixed(vert->color[2]);
113 span.alpha = ChanToFixed(vert->color[3]);
114 span.redStep = 0;
115 span.greenStep = 0;
116 span.blueStep = 0;
117 span.alphaStep = 0;
118
119 /* need these for fragment programs */
120 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
121 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
122 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
123
124 {
125 GLfloat s, r, dsdx;
126
127 /* texcoord / pointcoord interpolants */
128 s = 0.0;
129 dsdx = 1.0 / size;
130 if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) {
131 dtdy = 1.0 / size;
132 t0 = 0.5 * dtdy;
133 }
134 else {
135 /* GL_UPPER_LEFT */
136 dtdy = -1.0 / size;
137 t0 = 1.0 + 0.5 * dtdy;
138 }
139
140 ATTRIB_LOOP_BEGIN
141 if (attr >= FRAG_ATTRIB_TEX0 && attr <= FRAG_ATTRIB_TEX7) {
142 /* a texcoord attribute */
143 const GLuint u = attr - FRAG_ATTRIB_TEX0;
144 ASSERT(u < Elements(ctx->Point.CoordReplace));
145 if (ctx->Point.CoordReplace[u]) {
146 tCoords[numTcoords++] = attr;
147
148 if (ctx->Point.SpriteRMode == GL_ZERO)
149 r = 0.0F;
150 else if (ctx->Point.SpriteRMode == GL_S)
151 r = vert->attrib[attr][0];
152 else /* GL_R */
153 r = vert->attrib[attr][2];
154
155 span.attrStart[attr][0] = s;
156 span.attrStart[attr][1] = 0.0; /* overwritten below */
157 span.attrStart[attr][2] = r;
158 span.attrStart[attr][3] = 1.0;
159
160 span.attrStepX[attr][0] = dsdx;
161 span.attrStepX[attr][1] = 0.0;
162 span.attrStepX[attr][2] = 0.0;
163 span.attrStepX[attr][3] = 0.0;
164
165 span.attrStepY[attr][0] = 0.0;
166 span.attrStepY[attr][1] = dtdy;
167 span.attrStepY[attr][2] = 0.0;
168 span.attrStepY[attr][3] = 0.0;
169
170 continue;
171 }
172 }
173 else if (attr == FRAG_ATTRIB_PNTC) {
174 /* GLSL gl_PointCoord.xy (.zw undefined) */
175 span.attrStart[FRAG_ATTRIB_PNTC][0] = 0.0;
176 span.attrStart[FRAG_ATTRIB_PNTC][1] = 0.0; /* t0 set below */
177 span.attrStepX[FRAG_ATTRIB_PNTC][0] = dsdx;
178 span.attrStepX[FRAG_ATTRIB_PNTC][1] = 0.0;
179 span.attrStepY[FRAG_ATTRIB_PNTC][0] = 0.0;
180 span.attrStepY[FRAG_ATTRIB_PNTC][1] = dtdy;
181 tCoords[numTcoords++] = FRAG_ATTRIB_PNTC;
182 continue;
183 }
184 /* use vertex's texcoord/attrib */
185 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
186 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
187 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
188 ATTRIB_LOOP_END;
189 }
190
191 /* compute pos, bounds and render */
192 {
193 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
194 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
195 GLint iSize = (GLint) (size + 0.5F);
196 GLint xmin, xmax, ymin, ymax, iy;
197 GLint iRadius;
198 GLfloat tcoord = t0;
199
200 iSize = MAX2(1, iSize);
201 iRadius = iSize / 2;
202
203 if (iSize & 1) {
204 /* odd size */
205 xmin = (GLint) (x - iRadius);
206 xmax = (GLint) (x + iRadius);
207 ymin = (GLint) (y - iRadius);
208 ymax = (GLint) (y + iRadius);
209 }
210 else {
211 /* even size */
212 /* 0.501 factor allows conformance to pass */
213 xmin = (GLint) (x + 0.501) - iRadius;
214 xmax = xmin + iSize - 1;
215 ymin = (GLint) (y + 0.501) - iRadius;
216 ymax = ymin + iSize - 1;
217 }
218
219 /* render spans */
220 for (iy = ymin; iy <= ymax; iy++) {
221 GLuint i;
222 /* setup texcoord T for this row */
223 for (i = 0; i < numTcoords; i++) {
224 span.attrStart[tCoords[i]][1] = tcoord;
225 }
226
227 /* these might get changed by span clipping */
228 span.x = xmin;
229 span.y = iy;
230 span.end = xmax - xmin + 1;
231
232 _swrast_write_rgba_span(ctx, &span);
233
234 tcoord += dtdy;
235 }
236 }
237 }
238
239
240 /**
241 * Draw smooth/antialiased point. RGB or CI mode.
242 */
243 static void
244 smooth_point(GLcontext *ctx, const SWvertex *vert)
245 {
246 SWcontext *swrast = SWRAST_CONTEXT(ctx);
247 const GLboolean ciMode = !ctx->Visual.rgbMode;
248 SWspan span;
249 GLfloat size, alphaAtten;
250
251 CULL_INVALID(vert);
252
253 /* z coord */
254 if (ctx->DrawBuffer->Visual.depthBits <= 16)
255 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
256 else
257 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
258 span.zStep = 0;
259
260 size = get_size(ctx, vert, GL_TRUE);
261
262 /* alpha attenuation / fade factor */
263 if (ctx->Multisample._Enabled) {
264 if (vert->pointSize >= ctx->Point.Threshold) {
265 alphaAtten = 1.0F;
266 }
267 else {
268 GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
269 alphaAtten = dsize * dsize;
270 }
271 }
272 else {
273 alphaAtten = 1.0;
274 }
275 (void) alphaAtten; /* not used */
276
277 /* span init */
278 INIT_SPAN(span, GL_POINT);
279 span.interpMask = SPAN_Z | SPAN_RGBA;
280 span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
281
282 span.facing = swrast->PointLineFacing;
283
284 span.red = ChanToFixed(vert->color[0]);
285 span.green = ChanToFixed(vert->color[1]);
286 span.blue = ChanToFixed(vert->color[2]);
287 span.alpha = ChanToFixed(vert->color[3]);
288 span.redStep = 0;
289 span.greenStep = 0;
290 span.blueStep = 0;
291 span.alphaStep = 0;
292
293 /* need these for fragment programs */
294 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
295 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
296 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
297
298 ATTRIB_LOOP_BEGIN
299 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
300 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
301 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
302 ATTRIB_LOOP_END
303
304 /* compute pos, bounds and render */
305 {
306 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
307 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
308 const GLfloat radius = 0.5F * size;
309 const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
310 const GLfloat rmax = radius + 0.7071F;
311 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
312 const GLfloat rmax2 = rmax * rmax;
313 const GLfloat cscale = 1.0F / (rmax2 - rmin2);
314 const GLint xmin = (GLint) (x - radius);
315 const GLint xmax = (GLint) (x + radius);
316 const GLint ymin = (GLint) (y - radius);
317 const GLint ymax = (GLint) (y + radius);
318 GLint ix, iy;
319
320 for (iy = ymin; iy <= ymax; iy++) {
321
322 /* these might get changed by span clipping */
323 span.x = xmin;
324 span.y = iy;
325 span.end = xmax - xmin + 1;
326
327 /* compute coverage for each pixel in span */
328 for (ix = xmin; ix <= xmax; ix++) {
329 const GLfloat dx = ix - x + 0.5F;
330 const GLfloat dy = iy - y + 0.5F;
331 const GLfloat dist2 = dx * dx + dy * dy;
332 GLfloat coverage;
333
334 if (dist2 < rmax2) {
335 if (dist2 >= rmin2) {
336 /* compute partial coverage */
337 coverage = 1.0F - (dist2 - rmin2) * cscale;
338 if (ciMode) {
339 /* coverage in [0,15] */
340 coverage *= 15.0;
341 }
342 }
343 else {
344 /* full coverage */
345 coverage = 1.0F;
346 }
347 span.array->mask[ix - xmin] = 1;
348 }
349 else {
350 /* zero coverage - fragment outside the radius */
351 coverage = 0.0;
352 span.array->mask[ix - xmin] = 0;
353 }
354 span.array->coverage[ix - xmin] = coverage;
355 }
356
357 /* render span */
358 _swrast_write_rgba_span(ctx, &span);
359
360 }
361 }
362 }
363
364
365 /**
366 * Draw large (size >= 1) non-AA point. RGB or CI mode.
367 */
368 static void
369 large_point(GLcontext *ctx, const SWvertex *vert)
370 {
371 SWcontext *swrast = SWRAST_CONTEXT(ctx);
372 const GLboolean ciMode = !ctx->Visual.rgbMode;
373 SWspan span;
374 GLfloat size;
375
376 CULL_INVALID(vert);
377
378 /* z coord */
379 if (ctx->DrawBuffer->Visual.depthBits <= 16)
380 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
381 else
382 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
383 span.zStep = 0;
384
385 size = get_size(ctx, vert, GL_FALSE);
386
387 /* span init */
388 INIT_SPAN(span, GL_POINT);
389 span.arrayMask = SPAN_XY;
390 span.facing = swrast->PointLineFacing;
391
392 if (ciMode) {
393 span.interpMask = SPAN_Z | SPAN_INDEX;
394 span.index = FloatToFixed(vert->attrib[FRAG_ATTRIB_CI][0]);
395 span.indexStep = 0;
396 }
397 else {
398 span.interpMask = SPAN_Z | SPAN_RGBA;
399 span.red = ChanToFixed(vert->color[0]);
400 span.green = ChanToFixed(vert->color[1]);
401 span.blue = ChanToFixed(vert->color[2]);
402 span.alpha = ChanToFixed(vert->color[3]);
403 span.redStep = 0;
404 span.greenStep = 0;
405 span.blueStep = 0;
406 span.alphaStep = 0;
407 }
408
409 /* need these for fragment programs */
410 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
411 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
412 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
413
414 ATTRIB_LOOP_BEGIN
415 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
416 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
417 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
418 ATTRIB_LOOP_END
419
420 /* compute pos, bounds and render */
421 {
422 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
423 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
424 GLint iSize = (GLint) (size + 0.5F);
425 GLint xmin, xmax, ymin, ymax, ix, iy;
426 GLint iRadius;
427
428 iSize = MAX2(1, iSize);
429 iRadius = iSize / 2;
430
431 if (iSize & 1) {
432 /* odd size */
433 xmin = (GLint) (x - iRadius);
434 xmax = (GLint) (x + iRadius);
435 ymin = (GLint) (y - iRadius);
436 ymax = (GLint) (y + iRadius);
437 }
438 else {
439 /* even size */
440 /* 0.501 factor allows conformance to pass */
441 xmin = (GLint) (x + 0.501) - iRadius;
442 xmax = xmin + iSize - 1;
443 ymin = (GLint) (y + 0.501) - iRadius;
444 ymax = ymin + iSize - 1;
445 }
446
447 /* generate fragments */
448 span.end = 0;
449 for (iy = ymin; iy <= ymax; iy++) {
450 for (ix = xmin; ix <= xmax; ix++) {
451 span.array->x[span.end] = ix;
452 span.array->y[span.end] = iy;
453 span.end++;
454 }
455 }
456 assert(span.end <= MAX_WIDTH);
457 _swrast_write_rgba_span(ctx, &span);
458 }
459 }
460
461
462 /**
463 * Draw size=1, single-pixel point
464 */
465 static void
466 pixel_point(GLcontext *ctx, const SWvertex *vert)
467 {
468 SWcontext *swrast = SWRAST_CONTEXT(ctx);
469 const GLboolean ciMode = !ctx->Visual.rgbMode;
470 /*
471 * Note that unlike the other functions, we put single-pixel points
472 * into a special span array in order to render as many points as
473 * possible with a single _swrast_write_rgba_span() call.
474 */
475 SWspan *span = &(swrast->PointSpan);
476 GLuint count;
477
478 CULL_INVALID(vert);
479
480 /* Span init */
481 span->interpMask = 0;
482 span->arrayMask = SPAN_XY | SPAN_Z;
483 if (ciMode)
484 span->arrayMask |= SPAN_INDEX;
485 else
486 span->arrayMask |= SPAN_RGBA;
487 /*span->arrayMask |= SPAN_LAMBDA;*/
488 span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
489
490 /* need these for fragment programs */
491 span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
492 span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
493 span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
494
495 /* check if we need to flush */
496 if (span->end >= MAX_WIDTH ||
497 (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) ||
498 span->facing != swrast->PointLineFacing) {
499 if (span->end > 0) {
500 if (ciMode)
501 _swrast_write_index_span(ctx, span);
502 else
503 _swrast_write_rgba_span(ctx, span);
504 span->end = 0;
505 }
506 }
507
508 count = span->end;
509
510 span->facing = swrast->PointLineFacing;
511
512 /* fragment attributes */
513 if (ciMode) {
514 span->array->index[count] = (GLuint) vert->attrib[FRAG_ATTRIB_CI][0];
515 }
516 else {
517 span->array->rgba[count][RCOMP] = vert->color[0];
518 span->array->rgba[count][GCOMP] = vert->color[1];
519 span->array->rgba[count][BCOMP] = vert->color[2];
520 span->array->rgba[count][ACOMP] = vert->color[3];
521 }
522 ATTRIB_LOOP_BEGIN
523 COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
524 ATTRIB_LOOP_END
525
526 /* fragment position */
527 span->array->x[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][0];
528 span->array->y[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][1];
529 span->array->z[count] = (GLint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
530
531 span->end = count + 1;
532 ASSERT(span->end <= MAX_WIDTH);
533 }
534
535
536 /**
537 * Add specular color to primary color, draw point, restore original
538 * primary color.
539 */
540 void
541 _swrast_add_spec_terms_point(GLcontext *ctx, const SWvertex *v0)
542 {
543 SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
544 GLfloat rSum, gSum, bSum;
545 GLchan cSave[4];
546
547 /* save */
548 COPY_CHAN4(cSave, ncv0->color);
549 /* sum */
550 rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
551 gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
552 bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
553 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
554 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
555 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
556 /* draw */
557 SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
558 /* restore */
559 COPY_CHAN4(ncv0->color, cSave);
560 }
561
562
563 /**
564 * Examine current state to determine which point drawing function to use.
565 */
566 void
567 _swrast_choose_point(GLcontext *ctx)
568 {
569 SWcontext *swrast = SWRAST_CONTEXT(ctx);
570 const GLfloat size = CLAMP(ctx->Point.Size,
571 ctx->Point.MinSize,
572 ctx->Point.MaxSize);
573
574 if (ctx->RenderMode == GL_RENDER) {
575 if (ctx->Point.PointSprite) {
576 swrast->Point = sprite_point;
577 }
578 else if (ctx->Point.SmoothFlag) {
579 swrast->Point = smooth_point;
580 }
581 else if (size > 1.0 ||
582 ctx->Point._Attenuated ||
583 ctx->VertexProgram.PointSizeEnabled) {
584 swrast->Point = large_point;
585 }
586 else {
587 swrast->Point = pixel_point;
588 }
589 }
590 else if (ctx->RenderMode == GL_FEEDBACK) {
591 swrast->Point = _swrast_feedback_point;
592 }
593 else {
594 /* GL_SELECT mode */
595 swrast->Point = _swrast_select_point;
596 }
597 }