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