[MSHTML_WINETEST]
[reactos.git] / reactos / dll / opengl / 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 "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
55 get_size(const struct gl_context *ctx, const SWvertex *vert, GLboolean smoothed)
56 {
57 GLfloat size;
58
59 if (ctx->Point._Attenuated) {
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
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;
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[FRAG_ATTRIB_WPOS][2] + 0.5F);
96 else
97 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][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[FRAG_ATTRIB_WPOS][3] = 1.0F;
119 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
120 span.attrStepY[FRAG_ATTRIB_WPOS][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 == FRAG_ATTRIB_TEX) {
140 /* a texcoord attribute */
141 if (ctx->Point.CoordReplace) {
142 tCoords = attr;
143
144 if (ctx->Point.SpriteRMode == GL_ZERO)
145 r = 0.0F;
146 else if (ctx->Point.SpriteRMode == GL_S)
147 r = vert->attrib[attr][0];
148 else /* GL_R */
149 r = vert->attrib[attr][2];
150
151 span.attrStart[attr][0] = s;
152 span.attrStart[attr][1] = 0.0; /* overwritten below */
153 span.attrStart[attr][2] = r;
154 span.attrStart[attr][3] = 1.0;
155
156 span.attrStepX[attr][0] = dsdx;
157 span.attrStepX[attr][1] = 0.0;
158 span.attrStepX[attr][2] = 0.0;
159 span.attrStepX[attr][3] = 0.0;
160
161 span.attrStepY[attr][0] = 0.0;
162 span.attrStepY[attr][1] = dtdy;
163 span.attrStepY[attr][2] = 0.0;
164 span.attrStepY[attr][3] = 0.0;
165
166 continue;
167 }
168 }
169 else if (attr == FRAG_ATTRIB_PNTC) {
170 /* GLSL gl_PointCoord.xy (.zw undefined) */
171 span.attrStart[FRAG_ATTRIB_PNTC][0] = 0.0;
172 span.attrStart[FRAG_ATTRIB_PNTC][1] = 0.0; /* t0 set below */
173 span.attrStepX[FRAG_ATTRIB_PNTC][0] = dsdx;
174 span.attrStepX[FRAG_ATTRIB_PNTC][1] = 0.0;
175 span.attrStepY[FRAG_ATTRIB_PNTC][0] = 0.0;
176 span.attrStepY[FRAG_ATTRIB_PNTC][1] = dtdy;
177 tCoords = FRAG_ATTRIB_PNTC;
178 continue;
179 }
180 /* use vertex's texcoord/attrib */
181 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
182 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
183 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
184 ATTRIB_LOOP_END;
185 }
186
187 /* compute pos, bounds and render */
188 {
189 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
190 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
191 GLint iSize = (GLint) (size + 0.5F);
192 GLint xmin, xmax, ymin, ymax, iy;
193 GLint iRadius;
194 GLfloat tcoord = t0;
195
196 iSize = MAX2(1, iSize);
197 iRadius = iSize / 2;
198
199 if (iSize & 1) {
200 /* odd size */
201 xmin = (GLint) (x - iRadius);
202 xmax = (GLint) (x + iRadius);
203 ymin = (GLint) (y - iRadius);
204 ymax = (GLint) (y + iRadius);
205 }
206 else {
207 /* even size */
208 /* 0.501 factor allows conformance to pass */
209 xmin = (GLint) (x + 0.501) - iRadius;
210 xmax = xmin + iSize - 1;
211 ymin = (GLint) (y + 0.501) - iRadius;
212 ymax = ymin + iSize - 1;
213 }
214
215 /* render spans */
216 for (iy = ymin; iy <= ymax; iy++) {
217 /* setup texcoord T for this row */
218 span.attrStart[tCoords][1] = tcoord;
219
220 /* these might get changed by span clipping */
221 span.x = xmin;
222 span.y = iy;
223 span.end = xmax - xmin + 1;
224
225 _swrast_write_rgba_span(ctx, &span);
226
227 tcoord += dtdy;
228 }
229 }
230 }
231
232
233 /**
234 * Draw smooth/antialiased point. RGB or CI mode.
235 */
236 static void
237 smooth_point(struct gl_context *ctx, const SWvertex *vert)
238 {
239 SWcontext *swrast = SWRAST_CONTEXT(ctx);
240 SWspan span;
241 GLfloat size, alphaAtten;
242
243 CULL_INVALID(vert);
244
245 /* z coord */
246 if (ctx->DrawBuffer->Visual.depthBits <= 16)
247 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
248 else
249 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
250 span.zStep = 0;
251
252 size = get_size(ctx, vert, GL_TRUE);
253
254 /* alpha attenuation / fade factor */
255 if (ctx->Multisample._Enabled) {
256 if (vert->pointSize >= ctx->Point.Threshold) {
257 alphaAtten = 1.0F;
258 }
259 else {
260 GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
261 alphaAtten = dsize * dsize;
262 }
263 }
264 else {
265 alphaAtten = 1.0;
266 }
267 (void) alphaAtten; /* not used */
268
269 /* span init */
270 INIT_SPAN(span, GL_POINT);
271 span.interpMask = SPAN_Z | SPAN_RGBA;
272 span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
273
274 span.facing = swrast->PointLineFacing;
275
276 span.red = ChanToFixed(vert->color[0]);
277 span.green = ChanToFixed(vert->color[1]);
278 span.blue = ChanToFixed(vert->color[2]);
279 span.alpha = ChanToFixed(vert->color[3]);
280 span.redStep = 0;
281 span.greenStep = 0;
282 span.blueStep = 0;
283 span.alphaStep = 0;
284
285 /* need these for fragment programs */
286 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
287 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
288 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
289
290 ATTRIB_LOOP_BEGIN
291 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
292 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
293 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
294 ATTRIB_LOOP_END
295
296 /* compute pos, bounds and render */
297 {
298 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
299 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
300 const GLfloat radius = 0.5F * size;
301 const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
302 const GLfloat rmax = radius + 0.7071F;
303 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
304 const GLfloat rmax2 = rmax * rmax;
305 const GLfloat cscale = 1.0F / (rmax2 - rmin2);
306 const GLint xmin = (GLint) (x - radius);
307 const GLint xmax = (GLint) (x + radius);
308 const GLint ymin = (GLint) (y - radius);
309 const GLint ymax = (GLint) (y + radius);
310 GLint ix, iy;
311
312 for (iy = ymin; iy <= ymax; iy++) {
313
314 /* these might get changed by span clipping */
315 span.x = xmin;
316 span.y = iy;
317 span.end = xmax - xmin + 1;
318
319 /* compute coverage for each pixel in span */
320 for (ix = xmin; ix <= xmax; ix++) {
321 const GLfloat dx = ix - x + 0.5F;
322 const GLfloat dy = iy - y + 0.5F;
323 const GLfloat dist2 = dx * dx + dy * dy;
324 GLfloat coverage;
325
326 if (dist2 < rmax2) {
327 if (dist2 >= rmin2) {
328 /* compute partial coverage */
329 coverage = 1.0F - (dist2 - rmin2) * cscale;
330 }
331 else {
332 /* full coverage */
333 coverage = 1.0F;
334 }
335 span.array->mask[ix - xmin] = 1;
336 }
337 else {
338 /* zero coverage - fragment outside the radius */
339 coverage = 0.0;
340 span.array->mask[ix - xmin] = 0;
341 }
342 span.array->coverage[ix - xmin] = coverage;
343 }
344
345 /* render span */
346 _swrast_write_rgba_span(ctx, &span);
347
348 }
349 }
350 }
351
352
353 /**
354 * Draw large (size >= 1) non-AA point. RGB or CI mode.
355 */
356 static void
357 large_point(struct gl_context *ctx, const SWvertex *vert)
358 {
359 SWcontext *swrast = SWRAST_CONTEXT(ctx);
360 SWspan span;
361 GLfloat size;
362
363 CULL_INVALID(vert);
364
365 /* z coord */
366 if (ctx->DrawBuffer->Visual.depthBits <= 16)
367 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
368 else
369 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
370 span.zStep = 0;
371
372 size = get_size(ctx, vert, GL_FALSE);
373
374 /* span init */
375 INIT_SPAN(span, GL_POINT);
376 span.arrayMask = SPAN_XY;
377 span.facing = swrast->PointLineFacing;
378
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 /* need these for fragment programs */
390 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
391 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
392 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
393
394 ATTRIB_LOOP_BEGIN
395 COPY_4V(span.attrStart[attr], vert->attrib[attr]);
396 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
397 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
398 ATTRIB_LOOP_END
399
400 /* compute pos, bounds and render */
401 {
402 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0];
403 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1];
404 GLint iSize = (GLint) (size + 0.5F);
405 GLint xmin, xmax, ymin, ymax, ix, iy;
406 GLint iRadius;
407
408 iSize = MAX2(1, iSize);
409 iRadius = iSize / 2;
410
411 if (iSize & 1) {
412 /* odd size */
413 xmin = (GLint) (x - iRadius);
414 xmax = (GLint) (x + iRadius);
415 ymin = (GLint) (y - iRadius);
416 ymax = (GLint) (y + iRadius);
417 }
418 else {
419 /* even size */
420 /* 0.501 factor allows conformance to pass */
421 xmin = (GLint) (x + 0.501) - iRadius;
422 xmax = xmin + iSize - 1;
423 ymin = (GLint) (y + 0.501) - iRadius;
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(struct gl_context *ctx, const SWvertex *vert)
447 {
448 SWcontext *swrast = SWRAST_CONTEXT(ctx);
449 /*
450 * Note that unlike the other functions, we put single-pixel points
451 * into a special span array in order to render as many points as
452 * possible with a single _swrast_write_rgba_span() call.
453 */
454 SWspan *span = &(swrast->PointSpan);
455 GLuint count;
456
457 CULL_INVALID(vert);
458
459 /* Span init */
460 span->interpMask = 0;
461 span->arrayMask = SPAN_XY | SPAN_Z;
462 span->arrayMask |= SPAN_RGBA;
463 /*span->arrayMask |= SPAN_LAMBDA;*/
464 span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
465
466 /* need these for fragment programs */
467 span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F;
468 span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F;
469 span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F;
470
471 /* check if we need to flush */
472 if (span->end >= MAX_WIDTH ||
473 (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) ||
474 span->facing != swrast->PointLineFacing) {
475 if (span->end > 0) {
476 _swrast_write_rgba_span(ctx, span);
477 span->end = 0;
478 }
479 }
480
481 count = span->end;
482
483 span->facing = swrast->PointLineFacing;
484
485 /* fragment attributes */
486 span->array->rgba[count][RCOMP] = vert->color[0];
487 span->array->rgba[count][GCOMP] = vert->color[1];
488 span->array->rgba[count][BCOMP] = vert->color[2];
489 span->array->rgba[count][ACOMP] = vert->color[3];
490
491 ATTRIB_LOOP_BEGIN
492 COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
493 ATTRIB_LOOP_END
494
495 /* fragment position */
496 span->array->x[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][0];
497 span->array->y[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][1];
498 span->array->z[count] = (GLint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
499
500 span->end = count + 1;
501 ASSERT(span->end <= MAX_WIDTH);
502 }
503
504
505 /**
506 * Add specular color to primary color, draw point, restore original
507 * primary color.
508 */
509 void
510 _swrast_add_spec_terms_point(struct gl_context *ctx, const SWvertex *v0)
511 {
512 SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
513 GLfloat rSum, gSum, bSum;
514 GLchan cSave[4];
515
516 /* save */
517 COPY_CHAN4(cSave, ncv0->color);
518 /* sum */
519 rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
520 gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
521 bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
522 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
523 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
524 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
525 /* draw */
526 SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
527 /* restore */
528 COPY_CHAN4(ncv0->color, cSave);
529 }
530
531
532 /**
533 * Examine current state to determine which point drawing function to use.
534 */
535 void
536 _swrast_choose_point(struct gl_context *ctx)
537 {
538 SWcontext *swrast = SWRAST_CONTEXT(ctx);
539 const GLfloat size = CLAMP(ctx->Point.Size,
540 ctx->Point.MinSize,
541 ctx->Point.MaxSize);
542
543 if (ctx->RenderMode == GL_RENDER) {
544 if (ctx->Point.PointSprite) {
545 swrast->Point = sprite_point;
546 }
547 else if (ctx->Point.SmoothFlag) {
548 swrast->Point = smooth_point;
549 }
550 else if (size > 1.0 ||
551 ctx->Point._Attenuated) {
552 swrast->Point = large_point;
553 }
554 else {
555 swrast->Point = pixel_point;
556 }
557 }
558 else if (ctx->RenderMode == GL_FEEDBACK) {
559 swrast->Point = _swrast_feedback_point;
560 }
561 else {
562 /* GL_SELECT mode */
563 swrast->Point = _swrast_select_point;
564 }
565 }