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