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