2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
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"
35 * Used to cull points with invalid coords
37 #define CULL_INVALID(V) \
39 float tmp = (V)->attrib[VARYING_SLOT_POS][0] \
40 + (V)->attrib[VARYING_SLOT_POS][1]; \
41 if (IS_INF_OR_NAN(tmp)) \
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.
54 get_size(const struct gl_context
*ctx
, const SWvertex
*vert
, GLboolean smoothed
)
58 if (ctx
->Point
._Attenuated
|| ctx
->VertexProgram
.PointSizeEnabled
) {
59 /* use vertex's point size */
60 size
= vert
->pointSize
;
63 /* use constant point size */
64 size
= ctx
->Point
.Size
;
66 /* always clamp to user-specified limits */
67 size
= CLAMP(size
, ctx
->Point
.MinSize
, ctx
->Point
.MaxSize
);
68 /* clamp to implementation limits */
70 size
= CLAMP(size
, ctx
->Const
.MinPointSizeAA
, ctx
->Const
.MaxPointSizeAA
);
72 size
= CLAMP(size
, ctx
->Const
.MinPointSize
, ctx
->Const
.MaxPointSize
);
82 sprite_point(struct gl_context
*ctx
, const SWvertex
*vert
)
84 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
87 GLuint tCoords
[MAX_TEXTURE_COORD_UNITS
+ 1];
88 GLuint numTcoords
= 0;
94 if (ctx
->DrawBuffer
->Visual
.depthBits
<= 16)
95 span
.z
= FloatToFixed(vert
->attrib
[VARYING_SLOT_POS
][2] + 0.5F
);
97 span
.z
= (GLuint
) (vert
->attrib
[VARYING_SLOT_POS
][2] + 0.5F
);
100 size
= get_size(ctx
, vert
, GL_FALSE
);
103 INIT_SPAN(span
, GL_POINT
);
104 span
.interpMask
= SPAN_Z
| SPAN_RGBA
;
106 span
.facing
= swrast
->PointLineFacing
;
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]);
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
;
125 /* texcoord / pointcoord interpolants */
128 if (ctx
->Point
.SpriteOrigin
== GL_LOWER_LEFT
) {
135 t0
= 1.0F
+ 0.5F
* dtdy
;
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
;
146 if (ctx
->Point
.SpriteRMode
== GL_ZERO
)
148 else if (ctx
->Point
.SpriteRMode
== GL_S
)
149 r
= vert
->attrib
[attr
][0];
151 r
= vert
->attrib
[attr
][2];
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;
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;
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;
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
;
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);
189 /* compute pos, bounds and render */
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
;
198 iSize
= MAX2(1, iSize
);
203 xmin
= (GLint
) (x
- iRadius
);
204 xmax
= (GLint
) (x
+ iRadius
);
205 ymin
= (GLint
) (y
- iRadius
);
206 ymax
= (GLint
) (y
+ iRadius
);
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;
218 for (iy
= ymin
; iy
<= ymax
; iy
++) {
220 /* setup texcoord T for this row */
221 for (i
= 0; i
< numTcoords
; i
++) {
222 span
.attrStart
[tCoords
[i
]][1] = tcoord
;
225 /* these might get changed by span clipping */
228 span
.end
= xmax
- xmin
+ 1;
230 _swrast_write_rgba_span(ctx
, &span
);
239 * Draw smooth/antialiased point. RGB or CI mode.
242 smooth_point(struct gl_context
*ctx
, const SWvertex
*vert
)
244 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
246 GLfloat size
, alphaAtten
;
251 if (ctx
->DrawBuffer
->Visual
.depthBits
<= 16)
252 span
.z
= FloatToFixed(vert
->attrib
[VARYING_SLOT_POS
][2] + 0.5F
);
254 span
.z
= (GLuint
) (vert
->attrib
[VARYING_SLOT_POS
][2] + 0.5F
);
257 size
= get_size(ctx
, vert
, GL_TRUE
);
259 /* alpha attenuation / fade factor */
260 if (_mesa_is_multisample_enabled(ctx
)) {
261 if (vert
->pointSize
>= ctx
->Point
.Threshold
) {
265 GLfloat dsize
= vert
->pointSize
/ ctx
->Point
.Threshold
;
266 alphaAtten
= dsize
* dsize
;
272 (void) alphaAtten
; /* not used */
275 INIT_SPAN(span
, GL_POINT
);
276 span
.interpMask
= SPAN_Z
| SPAN_RGBA
;
277 span
.arrayMask
= SPAN_COVERAGE
| SPAN_MASK
;
279 span
.facing
= swrast
->PointLineFacing
;
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]);
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
;
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);
301 /* compute pos, bounds and render */
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
);
317 for (iy
= ymin
; iy
<= ymax
; iy
++) {
319 /* these might get changed by span clipping */
322 span
.end
= xmax
- xmin
+ 1;
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
;
332 if (dist2
>= rmin2
) {
333 /* compute partial coverage */
334 coverage
= 1.0F
- (dist2
- rmin2
) * cscale
;
340 span
.array
->mask
[ix
- xmin
] = 1;
343 /* zero coverage - fragment outside the radius */
345 span
.array
->mask
[ix
- xmin
] = 0;
347 span
.array
->coverage
[ix
- xmin
] = coverage
;
351 _swrast_write_rgba_span(ctx
, &span
);
359 * Draw large (size >= 1) non-AA point. RGB or CI mode.
362 large_point(struct gl_context
*ctx
, const SWvertex
*vert
)
364 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
371 if (ctx
->DrawBuffer
->Visual
.depthBits
<= 16)
372 span
.z
= FloatToFixed(vert
->attrib
[VARYING_SLOT_POS
][2] + 0.5F
);
374 span
.z
= (GLuint
) (vert
->attrib
[VARYING_SLOT_POS
][2] + 0.5F
);
377 size
= get_size(ctx
, vert
, GL_FALSE
);
380 INIT_SPAN(span
, GL_POINT
);
381 span
.arrayMask
= SPAN_XY
;
382 span
.facing
= swrast
->PointLineFacing
;
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]);
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
;
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);
405 /* compute pos, bounds and render */
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
;
413 iSize
= MAX2(1, iSize
);
418 xmin
= (GLint
) (x
- iRadius
);
419 xmax
= (GLint
) (x
+ iRadius
);
420 ymin
= (GLint
) (y
- iRadius
);
421 ymax
= (GLint
) (y
+ iRadius
);
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;
432 /* generate fragments */
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
;
441 assert(span
.end
<= SWRAST_MAX_WIDTH
);
442 _swrast_write_rgba_span(ctx
, &span
);
448 * Draw size=1, single-pixel point
451 pixel_point(struct gl_context
*ctx
, const SWvertex
*vert
)
453 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
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.
459 SWspan
*span
= &(swrast
->PointSpan
);
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 */
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
;
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
) {
481 _swrast_write_rgba_span(ctx
, span
);
488 span
->facing
= swrast
->PointLineFacing
;
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];
497 COPY_4V(span
->array
->attribs
[attr
][count
], vert
->attrib
[attr
]);
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
);
505 span
->end
= count
+ 1;
506 assert(span
->end
<= SWRAST_MAX_WIDTH
);
511 * Add specular color to primary color, draw point, restore original
515 _swrast_add_spec_terms_point(struct gl_context
*ctx
, const SWvertex
*v0
)
517 SWvertex
*ncv0
= (SWvertex
*) v0
; /* cast away const */
518 GLfloat rSum
, gSum
, bSum
;
522 COPY_CHAN4(cSave
, ncv0
->color
);
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
);
531 SWRAST_CONTEXT(ctx
)->SpecPoint(ctx
, ncv0
);
533 COPY_CHAN4(ncv0
->color
, cSave
);
538 * Examine current state to determine which point drawing function to use.
541 _swrast_choose_point(struct gl_context
*ctx
)
543 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
544 const GLfloat size
= CLAMP(ctx
->Point
.Size
,
548 if (ctx
->RenderMode
== GL_RENDER
) {
549 if (ctx
->Point
.PointSprite
) {
550 swrast
->Point
= sprite_point
;
552 else if (ctx
->Point
.SmoothFlag
) {
553 swrast
->Point
= smooth_point
;
555 else if (size
> 1.0F
||
556 ctx
->Point
._Attenuated
||
557 ctx
->VertexProgram
.PointSizeEnabled
) {
558 swrast
->Point
= large_point
;
561 swrast
->Point
= pixel_point
;
564 else if (ctx
->RenderMode
== GL_FEEDBACK
) {
565 swrast
->Point
= _swrast_feedback_point
;
569 swrast
->Point
= _swrast_select_point
;