2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
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"
38 * Used to cull points with invalid coords
40 #define CULL_INVALID(V) \
42 float tmp = (V)->attrib[FRAG_ATTRIB_WPOS][0] \
43 + (V)->attrib[FRAG_ATTRIB_WPOS][1]; \
44 if (IS_INF_OR_NAN(tmp)) \
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.
57 get_size(const GLcontext
*ctx
, const SWvertex
*vert
, GLboolean smoothed
)
61 if (ctx
->Point
._Attenuated
|| ctx
->VertexProgram
.PointSizeEnabled
) {
62 /* use vertex's point size */
63 size
= vert
->pointSize
;
66 /* use constant point size */
67 size
= ctx
->Point
.Size
;
69 /* always clamp to user-specified limits */
70 size
= CLAMP(size
, ctx
->Point
.MinSize
, ctx
->Point
.MaxSize
);
71 /* clamp to implementation limits */
73 size
= CLAMP(size
, ctx
->Const
.MinPointSizeAA
, ctx
->Const
.MaxPointSizeAA
);
75 size
= CLAMP(size
, ctx
->Const
.MinPointSize
, ctx
->Const
.MaxPointSize
);
85 sprite_point(GLcontext
*ctx
, const SWvertex
*vert
)
87 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
90 GLuint tCoords
[MAX_TEXTURE_COORD_UNITS
+ 1];
91 GLuint numTcoords
= 0;
97 if (ctx
->DrawBuffer
->Visual
.depthBits
<= 16)
98 span
.z
= FloatToFixed(vert
->attrib
[FRAG_ATTRIB_WPOS
][2] + 0.5F
);
100 span
.z
= (GLuint
) (vert
->attrib
[FRAG_ATTRIB_WPOS
][2] + 0.5F
);
103 size
= get_size(ctx
, vert
, GL_FALSE
);
106 INIT_SPAN(span
, GL_POINT
);
107 span
.interpMask
= SPAN_Z
| SPAN_RGBA
;
109 span
.facing
= swrast
->PointLineFacing
;
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]);
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
;
128 /* texcoord / pointcoord interpolants */
131 if (ctx
->Point
.SpriteOrigin
== GL_LOWER_LEFT
) {
138 t0
= 1.0 + 0.5 * dtdy
;
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
;
149 if (ctx
->Point
.SpriteRMode
== GL_ZERO
)
151 else if (ctx
->Point
.SpriteRMode
== GL_S
)
152 r
= vert
->attrib
[attr
][0];
154 r
= vert
->attrib
[attr
][2];
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;
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;
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;
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
;
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);
192 /* compute pos, bounds and render */
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
;
201 iSize
= MAX2(1, iSize
);
206 xmin
= (GLint
) (x
- iRadius
);
207 xmax
= (GLint
) (x
+ iRadius
);
208 ymin
= (GLint
) (y
- iRadius
);
209 ymax
= (GLint
) (y
+ iRadius
);
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;
221 for (iy
= ymin
; iy
<= ymax
; iy
++) {
223 /* setup texcoord T for this row */
224 for (i
= 0; i
< numTcoords
; i
++) {
225 span
.attrStart
[tCoords
[i
]][1] = tcoord
;
228 /* these might get changed by span clipping */
231 span
.end
= xmax
- xmin
+ 1;
233 _swrast_write_rgba_span(ctx
, &span
);
242 * Draw smooth/antialiased point. RGB or CI mode.
245 smooth_point(GLcontext
*ctx
, const SWvertex
*vert
)
247 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
248 const GLboolean ciMode
= !ctx
->Visual
.rgbMode
;
250 GLfloat size
, alphaAtten
;
255 if (ctx
->DrawBuffer
->Visual
.depthBits
<= 16)
256 span
.z
= FloatToFixed(vert
->attrib
[FRAG_ATTRIB_WPOS
][2] + 0.5F
);
258 span
.z
= (GLuint
) (vert
->attrib
[FRAG_ATTRIB_WPOS
][2] + 0.5F
);
261 size
= get_size(ctx
, vert
, GL_TRUE
);
263 /* alpha attenuation / fade factor */
264 if (ctx
->Multisample
._Enabled
) {
265 if (vert
->pointSize
>= ctx
->Point
.Threshold
) {
269 GLfloat dsize
= vert
->pointSize
/ ctx
->Point
.Threshold
;
270 alphaAtten
= dsize
* dsize
;
276 (void) alphaAtten
; /* not used */
279 INIT_SPAN(span
, GL_POINT
);
280 span
.interpMask
= SPAN_Z
| SPAN_RGBA
;
281 span
.arrayMask
= SPAN_COVERAGE
| SPAN_MASK
;
283 span
.facing
= swrast
->PointLineFacing
;
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]);
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
;
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);
305 /* compute pos, bounds and render */
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
);
321 for (iy
= ymin
; iy
<= ymax
; iy
++) {
323 /* these might get changed by span clipping */
326 span
.end
= xmax
- xmin
+ 1;
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
;
336 if (dist2
>= rmin2
) {
337 /* compute partial coverage */
338 coverage
= 1.0F
- (dist2
- rmin2
) * cscale
;
340 /* coverage in [0,15] */
348 span
.array
->mask
[ix
- xmin
] = 1;
351 /* zero coverage - fragment outside the radius */
353 span
.array
->mask
[ix
- xmin
] = 0;
355 span
.array
->coverage
[ix
- xmin
] = coverage
;
359 _swrast_write_rgba_span(ctx
, &span
);
367 * Draw large (size >= 1) non-AA point. RGB or CI mode.
370 large_point(GLcontext
*ctx
, const SWvertex
*vert
)
372 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
373 const GLboolean ciMode
= !ctx
->Visual
.rgbMode
;
380 if (ctx
->DrawBuffer
->Visual
.depthBits
<= 16)
381 span
.z
= FloatToFixed(vert
->attrib
[FRAG_ATTRIB_WPOS
][2] + 0.5F
);
383 span
.z
= (GLuint
) (vert
->attrib
[FRAG_ATTRIB_WPOS
][2] + 0.5F
);
386 size
= get_size(ctx
, vert
, GL_FALSE
);
389 INIT_SPAN(span
, GL_POINT
);
390 span
.arrayMask
= SPAN_XY
;
391 span
.facing
= swrast
->PointLineFacing
;
394 span
.interpMask
= SPAN_Z
| SPAN_INDEX
;
395 span
.index
= FloatToFixed(vert
->attrib
[FRAG_ATTRIB_CI
][0]);
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]);
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
;
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);
421 /* compute pos, bounds and render */
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
;
429 iSize
= MAX2(1, iSize
);
434 xmin
= (GLint
) (x
- iRadius
);
435 xmax
= (GLint
) (x
+ iRadius
);
436 ymin
= (GLint
) (y
- iRadius
);
437 ymax
= (GLint
) (y
+ iRadius
);
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;
448 /* generate fragments */
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
;
457 assert(span
.end
<= MAX_WIDTH
);
458 _swrast_write_rgba_span(ctx
, &span
);
464 * Draw size=1, single-pixel point
467 pixel_point(GLcontext
*ctx
, const SWvertex
*vert
)
469 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
470 const GLboolean ciMode
= !ctx
->Visual
.rgbMode
;
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.
476 SWspan
*span
= &(swrast
->PointSpan
);
482 span
->interpMask
= 0;
483 span
->arrayMask
= SPAN_XY
| SPAN_Z
;
485 span
->arrayMask
|= SPAN_INDEX
;
487 span
->arrayMask
|= SPAN_RGBA
;
488 /*span->arrayMask |= SPAN_LAMBDA;*/
489 span
->arrayAttribs
= swrast
->_ActiveAttribMask
; /* we'll produce these vals */
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
;
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
) {
502 _swrast_write_index_span(ctx
, span
);
504 _swrast_write_rgba_span(ctx
, span
);
511 span
->facing
= swrast
->PointLineFacing
;
513 /* fragment attributes */
515 span
->array
->index
[count
] = (GLuint
) vert
->attrib
[FRAG_ATTRIB_CI
][0];
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];
524 COPY_4V(span
->array
->attribs
[attr
][count
], vert
->attrib
[attr
]);
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
);
532 span
->end
= count
+ 1;
533 ASSERT(span
->end
<= MAX_WIDTH
);
538 * Add specular color to primary color, draw point, restore original
542 _swrast_add_spec_terms_point(GLcontext
*ctx
, const SWvertex
*v0
)
544 SWvertex
*ncv0
= (SWvertex
*) v0
; /* cast away const */
545 GLfloat rSum
, gSum
, bSum
;
549 COPY_CHAN4(cSave
, ncv0
->color
);
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
);
558 SWRAST_CONTEXT(ctx
)->SpecPoint(ctx
, ncv0
);
560 COPY_CHAN4(ncv0
->color
, cSave
);
565 * Examine current state to determine which point drawing function to use.
568 _swrast_choose_point(GLcontext
*ctx
)
570 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
571 const GLfloat size
= CLAMP(ctx
->Point
.Size
,
575 if (ctx
->RenderMode
== GL_RENDER
) {
576 if (ctx
->Point
.PointSprite
) {
577 swrast
->Point
= sprite_point
;
579 else if (ctx
->Point
.SmoothFlag
) {
580 swrast
->Point
= smooth_point
;
582 else if (size
> 1.0 ||
583 ctx
->Point
._Attenuated
||
584 ctx
->VertexProgram
.PointSizeEnabled
) {
585 swrast
->Point
= large_point
;
588 swrast
->Point
= pixel_point
;
591 else if (ctx
->RenderMode
== GL_FEEDBACK
) {
592 swrast
->Point
= _swrast_feedback_point
;
596 swrast
->Point
= _swrast_select_point
;