simplify INIT_SPAN code
[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];
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; /* already clamped to user range */
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 ATTRIB_LOOP_BEGIN
103 if (attr >= FRAG_ATTRIB_TEX0 && attr < FRAG_ATTRIB_VAR0) {
104 const GLuint u = attr - FRAG_ATTRIB_TEX0;
105 /* a texcoord */
106 if (ctx->Point.CoordReplace[u]) {
107 GLfloat s, r, dsdx;
108
109 s = 0.0;
110 dsdx = 1.0 / size;
111
112 if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) {
113 t0 = 0.0;
114 dtdy = 1.0 / size;
115 }
116 else {
117 /* GL_UPPER_LEFT */
118 t0 = 1.0;
119 dtdy = -1.0 / size;
120 }
121 tCoords[numTcoords++] = attr;
122
123 if (ctx->Point.SpriteRMode == GL_ZERO)
124 r = 0.0F;
125 else if (ctx->Point.SpriteRMode == GL_S)
126 r = vert->attrib[attr][0];
127 else /* GL_R */
128 r = vert->attrib[attr][2];
129
130 span.attrStart[attr][0] = s;
131 span.attrStart[attr][1] = 0.0; /* overwritten below */
132 span.attrStart[attr][2] = r;
133 span.attrStart[attr][3] = 1.0;
134
135 span.attrStepX[attr][0] = dsdx;
136 span.attrStepX[attr][1] = 0.0;
137 span.attrStepX[attr][2] = 0.0;
138 span.attrStepX[attr][3] = 0.0;
139
140 span.attrStepY[attr][0] = 0.0;
141 span.attrStepY[attr][1] = dtdy;
142 span.attrStepY[attr][2] = 0.0;
143 span.attrStepY[attr][3] = 0.0;
144
145 continue;
146 }
147 }
148 /* use vertex's texcoord/attrib */
149 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
150 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
151 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
152 ATTRIB_LOOP_END
153
154 /* compute pos, bounds and render */
155 {
156 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
157 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
158 GLint iSize = (GLint) (size + 0.5F);
159 GLint xmin, xmax, ymin, ymax, iy;
160 GLint iRadius;
161 GLfloat tcoord = t0;
162
163 iSize = MAX2(1, iSize);
164 iRadius = iSize / 2;
165
166 if (iSize & 1) {
167 /* odd size */
168 xmin = (GLint) (x - iRadius);
169 xmax = (GLint) (x + iRadius);
170 ymin = (GLint) (y - iRadius);
171 ymax = (GLint) (y + iRadius);
172 }
173 else {
174 /* even size */
175 xmin = (GLint) x - iRadius + 1;
176 xmax = xmin + iSize - 1;
177 ymin = (GLint) y - iRadius + 1;
178 ymax = ymin + iSize - 1;
179 }
180
181 /* render spans */
182 for (iy = ymin; iy <= ymax; iy++) {
183 GLuint i;
184 /* setup texcoord T for this row */
185 for (i = 0; i < numTcoords; i++) {
186 span.attrStart[tCoords[i]][1] = tcoord;
187 }
188
189 /* these might get changed by span clipping */
190 span.x = xmin;
191 span.y = iy;
192 span.end = xmax - xmin + 1;
193
194 _swrast_write_rgba_span(ctx, &span);
195
196 tcoord += dtdy;
197 }
198 }
199 }
200
201
202 /**
203 * Draw smooth/antialiased point. RGB or CI mode.
204 */
205 static void
206 smooth_point(GLcontext *ctx, const SWvertex *vert)
207 {
208 SWcontext *swrast = SWRAST_CONTEXT(ctx);
209 const GLboolean ciMode = !ctx->Visual.rgbMode;
210 SWspan span;
211 GLfloat size, alphaAtten;
212
213 CULL_INVALID(vert);
214
215 /* z coord */
216 if (ctx->DrawBuffer->Visual.depthBits <= 16)
217 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
218 else
219 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
220 span.zStep = 0;
221
222 /* compute size */
223 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
224 /* use vertex's point size */
225 /* first, clamp attenuated size to the user-specifed range */
226 size = CLAMP(vert->pointSize, ctx->Point.MinSize, ctx->Point.MaxSize);
227 }
228 else {
229 /* use constant point size */
230 size = ctx->Point._Size; /* this is already clamped */
231 }
232 /* clamp to AA implementation limits */
233 size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA);
234
235 /* alpha attenuation / fade factor */
236 if (ctx->Multisample.Enabled) {
237 if (vert->pointSize >= ctx->Point.Threshold) {
238 alphaAtten = 1.0F;
239 }
240 else {
241 GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
242 alphaAtten = dsize * dsize;
243 }
244 }
245 else {
246 alphaAtten = 1.0;
247 }
248 (void) alphaAtten; /* not used */
249
250 /* span init */
251 INIT_SPAN(span, GL_POINT);
252 span.interpMask = SPAN_Z | SPAN_RGBA;
253 span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
254
255 span.red = ChanToFixed(vert->color[0]);
256 span.green = ChanToFixed(vert->color[1]);
257 span.blue = ChanToFixed(vert->color[2]);
258 span.alpha = ChanToFixed(vert->color[3]);
259 span.redStep = 0;
260 span.greenStep = 0;
261 span.blueStep = 0;
262 span.alphaStep = 0;
263
264 /* need these for fragment programs */
265 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
266 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
267 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
268
269 ATTRIB_LOOP_BEGIN
270 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
271 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
272 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
273 ATTRIB_LOOP_END
274
275 /* compute pos, bounds and render */
276 {
277 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
278 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
279 const GLfloat radius = 0.5F * size;
280 const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
281 const GLfloat rmax = radius + 0.7071F;
282 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
283 const GLfloat rmax2 = rmax * rmax;
284 const GLfloat cscale = 1.0F / (rmax2 - rmin2);
285 const GLint xmin = (GLint) (x - radius);
286 const GLint xmax = (GLint) (x + radius);
287 const GLint ymin = (GLint) (y - radius);
288 const GLint ymax = (GLint) (y + radius);
289 GLint ix, iy;
290
291 for (iy = ymin; iy <= ymax; iy++) {
292
293 /* these might get changed by span clipping */
294 span.x = xmin;
295 span.y = iy;
296 span.end = xmax - xmin + 1;
297
298 /* compute coverage for each pixel in span */
299 for (ix = xmin; ix <= xmax; ix++) {
300 const GLfloat dx = ix - x + 0.5F;
301 const GLfloat dy = iy - y + 0.5F;
302 const GLfloat dist2 = dx * dx + dy * dy;
303 GLfloat coverage;
304
305 if (dist2 < rmax2) {
306 if (dist2 >= rmin2) {
307 /* compute partial coverage */
308 coverage = 1.0F - (dist2 - rmin2) * cscale;
309 if (ciMode) {
310 /* coverage in [0,15] */
311 coverage *= 15.0;
312 }
313 }
314 else {
315 /* full coverage */
316 coverage = 1.0F;
317 }
318 span.array->mask[ix - xmin] = 1;
319 }
320 else {
321 /* zero coverage - fragment outside the radius */
322 coverage = 0.0;
323 span.array->mask[ix - xmin] = 0;
324 }
325 span.array->coverage[ix - xmin] = coverage;
326 }
327
328 /* render span */
329 _swrast_write_rgba_span(ctx, &span);
330
331 }
332 }
333 }
334
335
336 /**
337 * Draw large (size >= 1) non-AA point. RGB or CI mode.
338 */
339 static void
340 large_point(GLcontext *ctx, const SWvertex *vert)
341 {
342 SWcontext *swrast = SWRAST_CONTEXT(ctx);
343 const GLboolean ciMode = !ctx->Visual.rgbMode;
344 SWspan span;
345 GLfloat size;
346
347 CULL_INVALID(vert);
348
349 /* z coord */
350 if (ctx->DrawBuffer->Visual.depthBits <= 16)
351 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
352 else
353 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
354 span.zStep = 0;
355
356 /* compute size */
357 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
358 /* use vertex's point size */
359 /* first, clamp attenuated size to the user-specifed range */
360 size = CLAMP(vert->pointSize, ctx->Point.MinSize, ctx->Point.MaxSize);
361 }
362 else {
363 /* use constant point size */
364 size = ctx->Point._Size; /* already clamped to user range */
365 }
366 /* clamp to non-AA implementation limits */
367 size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
368
369 /* span init */
370 INIT_SPAN(span, GL_POINT);
371 span.arrayMask = SPAN_XY;
372
373 if (ciMode) {
374 span.interpMask = SPAN_Z | SPAN_INDEX;
375 span.index = FloatToFixed(vert->attrib[FRAG_ATTRIB_CI][0]);
376 span.indexStep = 0;
377 }
378 else {
379 span.interpMask = SPAN_Z | SPAN_RGBA;
380 span.red = ChanToFixed(vert->color[0]);
381 span.green = ChanToFixed(vert->color[1]);
382 span.blue = ChanToFixed(vert->color[2]);
383 span.alpha = ChanToFixed(vert->color[3]);
384 span.redStep = 0;
385 span.greenStep = 0;
386 span.blueStep = 0;
387 span.alphaStep = 0;
388 }
389
390 /* need these for fragment programs */
391 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
392 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
393 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
394
395 ATTRIB_LOOP_BEGIN
396 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
397 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
398 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
399 ATTRIB_LOOP_END
400
401 /* compute pos, bounds and render */
402 {
403 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
404 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
405 GLint iSize = (GLint) (size + 0.5F);
406 GLint xmin, xmax, ymin, ymax, ix, iy;
407 GLint iRadius;
408
409 iSize = MAX2(1, iSize);
410 iRadius = iSize / 2;
411
412 if (iSize & 1) {
413 /* odd size */
414 xmin = (GLint) (x - iRadius);
415 xmax = (GLint) (x + iRadius);
416 ymin = (GLint) (y - iRadius);
417 ymax = (GLint) (y + iRadius);
418 }
419 else {
420 /* even size */
421 xmin = (GLint) x - iRadius + 1;
422 xmax = xmin + iSize - 1;
423 ymin = (GLint) y - iRadius + 1;
424 ymax = ymin + iSize - 1;
425 }
426
427 /* generate fragments */
428 span.end = 0;
429 for (iy = ymin; iy <= ymax; iy++) {
430 for (ix = xmin; ix <= xmax; ix++) {
431 span.array->x[span.end] = ix;
432 span.array->y[span.end] = iy;
433 span.end++;
434 }
435 }
436 assert(span.end <= MAX_WIDTH);
437 _swrast_write_rgba_span(ctx, &span);
438 }
439 }
440
441
442 /**
443 * Draw size=1, single-pixel point
444 */
445 static void
446 pixel_point(GLcontext *ctx, const SWvertex *vert)
447 {
448 SWcontext *swrast = SWRAST_CONTEXT(ctx);
449 const GLboolean ciMode = !ctx->Visual.rgbMode;
450 /*
451 * Note that unlike the other functions, we put single-pixel points
452 * into a special span array in order to render as many points as
453 * possible with a single _swrast_write_rgba_span() call.
454 */
455 SWspan *span = &(swrast->PointSpan);
456 GLuint count;
457
458 CULL_INVALID(vert);
459
460 /* Span init */
461 span->interpMask = 0;
462 span->arrayMask = SPAN_XY | SPAN_Z;
463 if (ciMode)
464 span->arrayMask |= SPAN_INDEX;
465 else
466 span->arrayMask |= SPAN_RGBA;
467 /*span->arrayMask |= SPAN_LAMBDA;*/
468 span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
469
470 /* need these for fragment programs */
471 span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
472 span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
473 span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
474
475 /* check if we need to flush */
476 if (span->end >= MAX_WIDTH ||
477 (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT))) {
478 if (ciMode)
479 _swrast_write_index_span(ctx, span);
480 else
481 _swrast_write_rgba_span(ctx, span);
482 span->end = 0;
483 }
484
485 count = span->end;
486
487 /* fragment attributes */
488 if (ciMode) {
489 span->array->index[count] = (GLuint) vert->attrib[FRAG_ATTRIB_CI][0];
490 }
491 else {
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 <= MAX_WIDTH);
508 }
509
510
511 /**
512 * Add specular color to primary color, draw point, restore original
513 * primary color.
514 */
515 void
516 _swrast_add_spec_terms_point(GLcontext *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
542 _swrast_choose_point(GLcontext *ctx)
543 {
544 SWcontext *swrast = SWRAST_CONTEXT(ctx);
545
546 if (ctx->RenderMode == GL_RENDER) {
547 if (ctx->Point.PointSprite) {
548 swrast->Point = sprite_point;
549 }
550 else if (ctx->Point.SmoothFlag) {
551 swrast->Point = smooth_point;
552 }
553 else if (ctx->Point._Size > 1.0 ||
554 ctx->Point._Attenuated ||
555 ctx->VertexProgram.PointSizeEnabled) {
556 swrast->Point = large_point;
557 }
558 else {
559 swrast->Point = pixel_point;
560 }
561 }
562 else if (ctx->RenderMode == GL_FEEDBACK) {
563 swrast->Point = _swrast_feedback_point;
564 }
565 else {
566 /* GL_SELECT mode */
567 swrast->Point = _swrast_select_point;
568 }
569 }