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