38a7f95f273c699f2e167815e8e904c0ca041ea5
[mesa.git] / src / mesa / swrast / s_span.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 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 /**
27 * \file swrast/s_span.c
28 * \brief Span processing functions used by all rasterization functions.
29 * This is where all the per-fragment tests are performed
30 * \author Brian Paul
31 */
32
33 #include "glheader.h"
34 #include "colormac.h"
35 #include "context.h"
36 #include "macros.h"
37 #include "imports.h"
38
39 #include "s_atifragshader.h"
40 #include "s_alpha.h"
41 #include "s_blend.h"
42 #include "s_context.h"
43 #include "s_depth.h"
44 #include "s_fog.h"
45 #include "s_logic.h"
46 #include "s_masking.h"
47 #include "s_nvfragprog.h"
48 #include "s_span.h"
49 #include "s_stencil.h"
50 #include "s_texcombine.h"
51
52
53 /**
54 * Init span's Z interpolation values to the RasterPos Z.
55 * Used during setup for glDraw/CopyPixels.
56 */
57 void
58 _swrast_span_default_z( GLcontext *ctx, struct sw_span *span )
59 {
60 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
61 if (ctx->Visual.depthBits <= 16)
62 span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
63 else
64 span->z = (GLint) (ctx->Current.RasterPos[2] * depthMax + 0.5F);
65 span->zStep = 0;
66 span->interpMask |= SPAN_Z;
67 }
68
69
70 /**
71 * Init span's fog interpolation values to the RasterPos fog.
72 * Used during setup for glDraw/CopyPixels.
73 */
74 void
75 _swrast_span_default_fog( GLcontext *ctx, struct sw_span *span )
76 {
77 span->fog = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
78 span->fogStep = span->dfogdx = span->dfogdy = 0.0F;
79 span->interpMask |= SPAN_FOG;
80 }
81
82
83 /**
84 * Init span's rgba or index interpolation values to the RasterPos color.
85 * Used during setup for glDraw/CopyPixels.
86 */
87 void
88 _swrast_span_default_color( GLcontext *ctx, struct sw_span *span )
89 {
90 if (ctx->Visual.rgbMode) {
91 GLchan r, g, b, a;
92 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
93 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
94 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
95 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
96 #if CHAN_TYPE == GL_FLOAT
97 span->red = r;
98 span->green = g;
99 span->blue = b;
100 span->alpha = a;
101 #else
102 span->red = IntToFixed(r);
103 span->green = IntToFixed(g);
104 span->blue = IntToFixed(b);
105 span->alpha = IntToFixed(a);
106 #endif
107 span->redStep = 0;
108 span->greenStep = 0;
109 span->blueStep = 0;
110 span->alphaStep = 0;
111 span->interpMask |= SPAN_RGBA;
112 }
113 else {
114 span->index = FloatToFixed(ctx->Current.RasterIndex);
115 span->indexStep = 0;
116 span->interpMask |= SPAN_INDEX;
117 }
118 }
119
120
121 /**
122 * Init span's texcoord interpolation values to the RasterPos texcoords.
123 * Used during setup for glDraw/CopyPixels.
124 */
125 void
126 _swrast_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
127 {
128 GLuint i;
129 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
130 const GLfloat *tc = ctx->Current.RasterTexCoords[i];
131 if (ctx->FragmentProgram._Active || ctx->ATIFragmentShader._Enabled) {
132 COPY_4V(span->tex[i], tc);
133 }
134 else if (tc[3] > 0.0F) {
135 /* use (s/q, t/q, r/q, 1) */
136 span->tex[i][0] = tc[0] / tc[3];
137 span->tex[i][1] = tc[1] / tc[3];
138 span->tex[i][2] = tc[2] / tc[3];
139 span->tex[i][3] = 1.0;
140 }
141 else {
142 ASSIGN_4V(span->tex[i], 0.0F, 0.0F, 0.0F, 1.0F);
143 }
144 ASSIGN_4V(span->texStepX[i], 0.0F, 0.0F, 0.0F, 0.0F);
145 ASSIGN_4V(span->texStepY[i], 0.0F, 0.0F, 0.0F, 0.0F);
146 }
147 span->interpMask |= SPAN_TEXTURE;
148 }
149
150
151 /* Fill in the span.color.rgba array from the interpolation values */
152 static void
153 interpolate_colors(GLcontext *ctx, struct sw_span *span)
154 {
155 const GLuint n = span->end;
156 GLchan (*rgba)[4] = span->array->rgba;
157 GLuint i;
158 (void) ctx;
159
160 ASSERT((span->interpMask & SPAN_RGBA) &&
161 !(span->arrayMask & SPAN_RGBA));
162
163 if (span->interpMask & SPAN_FLAT) {
164 /* constant color */
165 GLchan color[4];
166 color[RCOMP] = FixedToChan(span->red);
167 color[GCOMP] = FixedToChan(span->green);
168 color[BCOMP] = FixedToChan(span->blue);
169 color[ACOMP] = FixedToChan(span->alpha);
170 for (i = 0; i < n; i++) {
171 COPY_CHAN4(span->array->rgba[i], color);
172 }
173 }
174 else {
175 /* interpolate */
176 #if CHAN_TYPE == GL_FLOAT
177 GLfloat r = span->red;
178 GLfloat g = span->green;
179 GLfloat b = span->blue;
180 GLfloat a = span->alpha;
181 const GLfloat dr = span->redStep;
182 const GLfloat dg = span->greenStep;
183 const GLfloat db = span->blueStep;
184 const GLfloat da = span->alphaStep;
185 #else
186 GLfixed r = span->red;
187 GLfixed g = span->green;
188 GLfixed b = span->blue;
189 GLfixed a = span->alpha;
190 const GLint dr = span->redStep;
191 const GLint dg = span->greenStep;
192 const GLint db = span->blueStep;
193 const GLint da = span->alphaStep;
194 #endif
195 for (i = 0; i < n; i++) {
196 rgba[i][RCOMP] = FixedToChan(r);
197 rgba[i][GCOMP] = FixedToChan(g);
198 rgba[i][BCOMP] = FixedToChan(b);
199 rgba[i][ACOMP] = FixedToChan(a);
200 r += dr;
201 g += dg;
202 b += db;
203 a += da;
204 }
205 }
206 span->arrayMask |= SPAN_RGBA;
207 }
208
209
210 /* Fill in the span.color.index array from the interpolation values */
211 static void
212 interpolate_indexes(GLcontext *ctx, struct sw_span *span)
213 {
214 GLfixed index = span->index;
215 const GLint indexStep = span->indexStep;
216 const GLuint n = span->end;
217 GLuint *indexes = span->array->index;
218 GLuint i;
219 (void) ctx;
220 ASSERT((span->interpMask & SPAN_INDEX) &&
221 !(span->arrayMask & SPAN_INDEX));
222
223 if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) {
224 /* constant color */
225 index = FixedToInt(index);
226 for (i = 0; i < n; i++) {
227 indexes[i] = index;
228 }
229 }
230 else {
231 /* interpolate */
232 for (i = 0; i < n; i++) {
233 indexes[i] = FixedToInt(index);
234 index += indexStep;
235 }
236 }
237 span->arrayMask |= SPAN_INDEX;
238 span->interpMask &= ~SPAN_INDEX;
239 }
240
241
242 /* Fill in the span.->array->spec array from the interpolation values */
243 static void
244 interpolate_specular(GLcontext *ctx, struct sw_span *span)
245 {
246 (void) ctx;
247 if (span->interpMask & SPAN_FLAT) {
248 /* constant color */
249 const GLchan r = FixedToChan(span->specRed);
250 const GLchan g = FixedToChan(span->specGreen);
251 const GLchan b = FixedToChan(span->specBlue);
252 GLuint i;
253 for (i = 0; i < span->end; i++) {
254 span->array->spec[i][RCOMP] = r;
255 span->array->spec[i][GCOMP] = g;
256 span->array->spec[i][BCOMP] = b;
257 }
258 }
259 else {
260 /* interpolate */
261 #if CHAN_TYPE == GL_FLOAT
262 GLfloat r = span->specRed;
263 GLfloat g = span->specGreen;
264 GLfloat b = span->specBlue;
265 #else
266 GLfixed r = span->specRed;
267 GLfixed g = span->specGreen;
268 GLfixed b = span->specBlue;
269 #endif
270 GLuint i;
271 for (i = 0; i < span->end; i++) {
272 span->array->spec[i][RCOMP] = FixedToChan(r);
273 span->array->spec[i][GCOMP] = FixedToChan(g);
274 span->array->spec[i][BCOMP] = FixedToChan(b);
275 r += span->specRedStep;
276 g += span->specGreenStep;
277 b += span->specBlueStep;
278 }
279 }
280 span->arrayMask |= SPAN_SPEC;
281 }
282
283
284 /* Fill in the span.array.fog values from the interpolation values */
285 static void
286 interpolate_fog(const GLcontext *ctx, struct sw_span *span)
287 {
288 GLfloat *fog = span->array->fog;
289 const GLfloat fogStep = span->fogStep;
290 GLfloat fogCoord = span->fog;
291 const GLuint haveW = (span->interpMask & SPAN_W);
292 const GLfloat wStep = haveW ? span->dwdx : 0.0F;
293 GLfloat w = haveW ? span->w : 1.0F;
294 GLuint i;
295 for (i = 0; i < span->end; i++) {
296 fog[i] = fogCoord / w;
297 fogCoord += fogStep;
298 w += wStep;
299 }
300 span->arrayMask |= SPAN_FOG;
301 }
302
303
304 /* Fill in the span.zArray array from the interpolation values */
305 void
306 _swrast_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
307 {
308 const GLuint n = span->end;
309 GLuint i;
310
311 ASSERT((span->interpMask & SPAN_Z) &&
312 !(span->arrayMask & SPAN_Z));
313
314 if (ctx->Visual.depthBits <= 16) {
315 GLfixed zval = span->z;
316 GLuint *z = span->array->z;
317 for (i = 0; i < n; i++) {
318 z[i] = FixedToInt(zval);
319 zval += span->zStep;
320 }
321 }
322 else {
323 /* Deep Z buffer, no fixed->int shift */
324 GLuint zval = span->z;
325 GLuint *z = span->array->z;
326 for (i = 0; i < n; i++) {
327 z[i] = zval;
328 zval += span->zStep;
329 }
330 }
331 span->arrayMask |= SPAN_Z;
332 }
333
334
335 /*
336 * This the ideal solution, as given in the OpenGL spec.
337 */
338 #if 0
339 static GLfloat
340 compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
341 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
342 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
343 {
344 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
345 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
346 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
347 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
348 GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx);
349 GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy);
350 GLfloat rho = MAX2(x, y);
351 GLfloat lambda = LOG2(rho);
352 return lambda;
353 }
354 #endif
355
356
357 /*
358 * This is a faster approximation
359 */
360 GLfloat
361 _swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
362 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
363 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
364 {
365 GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
366 GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
367 GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
368 GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
369 GLfloat maxU, maxV, rho, lambda;
370 dsdx2 = FABSF(dsdx2);
371 dsdy2 = FABSF(dsdy2);
372 dtdx2 = FABSF(dtdx2);
373 dtdy2 = FABSF(dtdy2);
374 maxU = MAX2(dsdx2, dsdy2) * texW;
375 maxV = MAX2(dtdx2, dtdy2) * texH;
376 rho = MAX2(maxU, maxV);
377 lambda = LOG2(rho);
378 return lambda;
379 }
380
381
382 /**
383 * Fill in the span.texcoords array from the interpolation values.
384 * Note: in the places where we divide by Q (or mult by invQ) we're
385 * really doing two things: perspective correction and texcoord
386 * projection. Remember, for texcoord (s,t,r,q) we need to index
387 * texels with (s/q, t/q, r/q).
388 * If we're using a fragment program, we never do the division
389 * for texcoord projection. That's done by the TXP instruction
390 * or user-written code.
391 */
392 static void
393 interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
394 {
395 ASSERT(span->interpMask & SPAN_TEXTURE);
396 ASSERT(!(span->arrayMask & SPAN_TEXTURE));
397
398 if (ctx->Texture._EnabledCoordUnits > 1) {
399 /* multitexture */
400 GLuint u;
401 span->arrayMask |= SPAN_TEXTURE;
402 for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
403 if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
404 const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current;
405 GLfloat texW, texH;
406 GLboolean needLambda;
407 if (obj) {
408 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
409 needLambda = (obj->MinFilter != obj->MagFilter)
410 || ctx->FragmentProgram._Active;
411 texW = img->WidthScale;
412 texH = img->HeightScale;
413 }
414 else {
415 /* using a fragment program */
416 texW = 1.0;
417 texH = 1.0;
418 needLambda = GL_FALSE;
419 }
420 if (needLambda) {
421 GLfloat (*texcoord)[4] = span->array->texcoords[u];
422 GLfloat *lambda = span->array->lambda[u];
423 const GLfloat dsdx = span->texStepX[u][0];
424 const GLfloat dsdy = span->texStepY[u][0];
425 const GLfloat dtdx = span->texStepX[u][1];
426 const GLfloat dtdy = span->texStepY[u][1];
427 const GLfloat drdx = span->texStepX[u][2];
428 const GLfloat dqdx = span->texStepX[u][3];
429 const GLfloat dqdy = span->texStepY[u][3];
430 GLfloat s = span->tex[u][0];
431 GLfloat t = span->tex[u][1];
432 GLfloat r = span->tex[u][2];
433 GLfloat q = span->tex[u][3];
434 GLuint i;
435 if (ctx->FragmentProgram._Active || ctx->ATIFragmentShader._Enabled) {
436 /* do perspective correction but don't divide s, t, r by q */
437 const GLfloat dwdx = span->dwdx;
438 GLfloat w = span->w;
439 for (i = 0; i < span->end; i++) {
440 const GLfloat invW = 1.0F / w;
441 texcoord[i][0] = s * invW;
442 texcoord[i][1] = t * invW;
443 texcoord[i][2] = r * invW;
444 texcoord[i][3] = q * invW;
445 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
446 dqdx, dqdy, texW, texH,
447 s, t, q, invW);
448 s += dsdx;
449 t += dtdx;
450 r += drdx;
451 q += dqdx;
452 w += dwdx;
453 }
454
455 }
456 else {
457 for (i = 0; i < span->end; i++) {
458 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
459 texcoord[i][0] = s * invQ;
460 texcoord[i][1] = t * invQ;
461 texcoord[i][2] = r * invQ;
462 texcoord[i][3] = q;
463 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
464 dqdx, dqdy, texW, texH,
465 s, t, q, invQ);
466 s += dsdx;
467 t += dtdx;
468 r += drdx;
469 q += dqdx;
470 }
471 }
472 span->arrayMask |= SPAN_LAMBDA;
473 }
474 else {
475 GLfloat (*texcoord)[4] = span->array->texcoords[u];
476 GLfloat *lambda = span->array->lambda[u];
477 const GLfloat dsdx = span->texStepX[u][0];
478 const GLfloat dtdx = span->texStepX[u][1];
479 const GLfloat drdx = span->texStepX[u][2];
480 const GLfloat dqdx = span->texStepX[u][3];
481 GLfloat s = span->tex[u][0];
482 GLfloat t = span->tex[u][1];
483 GLfloat r = span->tex[u][2];
484 GLfloat q = span->tex[u][3];
485 GLuint i;
486 if (ctx->FragmentProgram._Active || ctx->ATIFragmentShader._Enabled) {
487 /* do perspective correction but don't divide s, t, r by q */
488 const GLfloat dwdx = span->dwdx;
489 GLfloat w = span->w;
490 for (i = 0; i < span->end; i++) {
491 const GLfloat invW = 1.0F / w;
492 texcoord[i][0] = s * invW;
493 texcoord[i][1] = t * invW;
494 texcoord[i][2] = r * invW;
495 texcoord[i][3] = q * invW;
496 lambda[i] = 0.0;
497 s += dsdx;
498 t += dtdx;
499 r += drdx;
500 q += dqdx;
501 w += dwdx;
502 }
503 }
504 else if (dqdx == 0.0F) {
505 /* Ortho projection or polygon's parallel to window X axis */
506 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
507 for (i = 0; i < span->end; i++) {
508 texcoord[i][0] = s * invQ;
509 texcoord[i][1] = t * invQ;
510 texcoord[i][2] = r * invQ;
511 texcoord[i][3] = q;
512 lambda[i] = 0.0;
513 s += dsdx;
514 t += dtdx;
515 r += drdx;
516 }
517 }
518 else {
519 for (i = 0; i < span->end; i++) {
520 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
521 texcoord[i][0] = s * invQ;
522 texcoord[i][1] = t * invQ;
523 texcoord[i][2] = r * invQ;
524 texcoord[i][3] = q;
525 lambda[i] = 0.0;
526 s += dsdx;
527 t += dtdx;
528 r += drdx;
529 q += dqdx;
530 }
531 }
532 } /* lambda */
533 } /* if */
534 } /* for */
535 }
536 else {
537 /* single texture */
538 const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
539 GLfloat texW, texH;
540 GLboolean needLambda;
541 if (obj) {
542 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
543 needLambda = (obj->MinFilter != obj->MagFilter)
544 || ctx->FragmentProgram._Active;
545 texW = (GLfloat) img->WidthScale;
546 texH = (GLfloat) img->HeightScale;
547 }
548 else {
549 needLambda = GL_FALSE;
550 texW = texH = 1.0;
551 }
552 span->arrayMask |= SPAN_TEXTURE;
553 if (needLambda) {
554 /* just texture unit 0, with lambda */
555 GLfloat (*texcoord)[4] = span->array->texcoords[0];
556 GLfloat *lambda = span->array->lambda[0];
557 const GLfloat dsdx = span->texStepX[0][0];
558 const GLfloat dsdy = span->texStepY[0][0];
559 const GLfloat dtdx = span->texStepX[0][1];
560 const GLfloat dtdy = span->texStepY[0][1];
561 const GLfloat drdx = span->texStepX[0][2];
562 const GLfloat dqdx = span->texStepX[0][3];
563 const GLfloat dqdy = span->texStepY[0][3];
564 GLfloat s = span->tex[0][0];
565 GLfloat t = span->tex[0][1];
566 GLfloat r = span->tex[0][2];
567 GLfloat q = span->tex[0][3];
568 GLuint i;
569 if (ctx->FragmentProgram._Active || ctx->ATIFragmentShader._Enabled) {
570 /* do perspective correction but don't divide s, t, r by q */
571 const GLfloat dwdx = span->dwdx;
572 GLfloat w = span->w;
573 for (i = 0; i < span->end; i++) {
574 const GLfloat invW = 1.0F / w;
575 texcoord[i][0] = s * invW;
576 texcoord[i][1] = t * invW;
577 texcoord[i][2] = r * invW;
578 texcoord[i][3] = q * invW;
579 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
580 dqdx, dqdy, texW, texH,
581 s, t, q, invW);
582 s += dsdx;
583 t += dtdx;
584 r += drdx;
585 q += dqdx;
586 w += dwdx;
587 }
588 }
589 else {
590 /* tex.c */
591 for (i = 0; i < span->end; i++) {
592 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
593 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
594 dqdx, dqdy, texW, texH,
595 s, t, q, invQ);
596 texcoord[i][0] = s * invQ;
597 texcoord[i][1] = t * invQ;
598 texcoord[i][2] = r * invQ;
599 texcoord[i][3] = q;
600 s += dsdx;
601 t += dtdx;
602 r += drdx;
603 q += dqdx;
604 }
605 }
606 span->arrayMask |= SPAN_LAMBDA;
607 }
608 else {
609 /* just texture 0, without lambda */
610 GLfloat (*texcoord)[4] = span->array->texcoords[0];
611 const GLfloat dsdx = span->texStepX[0][0];
612 const GLfloat dtdx = span->texStepX[0][1];
613 const GLfloat drdx = span->texStepX[0][2];
614 const GLfloat dqdx = span->texStepX[0][3];
615 GLfloat s = span->tex[0][0];
616 GLfloat t = span->tex[0][1];
617 GLfloat r = span->tex[0][2];
618 GLfloat q = span->tex[0][3];
619 GLuint i;
620 if (ctx->FragmentProgram._Active || ctx->ATIFragmentShader._Enabled) {
621 /* do perspective correction but don't divide s, t, r by q */
622 const GLfloat dwdx = span->dwdx;
623 GLfloat w = span->w;
624 for (i = 0; i < span->end; i++) {
625 const GLfloat invW = 1.0F / w;
626 texcoord[i][0] = s * invW;
627 texcoord[i][1] = t * invW;
628 texcoord[i][2] = r * invW;
629 texcoord[i][3] = q * invW;
630 s += dsdx;
631 t += dtdx;
632 r += drdx;
633 q += dqdx;
634 w += dwdx;
635 }
636 }
637 else if (dqdx == 0.0F) {
638 /* Ortho projection or polygon's parallel to window X axis */
639 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
640 for (i = 0; i < span->end; i++) {
641 texcoord[i][0] = s * invQ;
642 texcoord[i][1] = t * invQ;
643 texcoord[i][2] = r * invQ;
644 texcoord[i][3] = q;
645 s += dsdx;
646 t += dtdx;
647 r += drdx;
648 }
649 }
650 else {
651 for (i = 0; i < span->end; i++) {
652 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
653 texcoord[i][0] = s * invQ;
654 texcoord[i][1] = t * invQ;
655 texcoord[i][2] = r * invQ;
656 texcoord[i][3] = q;
657 s += dsdx;
658 t += dtdx;
659 r += drdx;
660 q += dqdx;
661 }
662 }
663 }
664 }
665 }
666
667
668 /**
669 * Apply the current polygon stipple pattern to a span of pixels.
670 */
671 static void
672 stipple_polygon_span( GLcontext *ctx, struct sw_span *span )
673 {
674 const GLuint highbit = 0x80000000;
675 const GLuint stipple = ctx->PolygonStipple[span->y % 32];
676 GLubyte *mask = span->array->mask;
677 GLuint i, m;
678
679 ASSERT(ctx->Polygon.StippleFlag);
680 ASSERT((span->arrayMask & SPAN_XY) == 0);
681
682 m = highbit >> (GLuint) (span->x % 32);
683
684 for (i = 0; i < span->end; i++) {
685 if ((m & stipple) == 0) {
686 mask[i] = 0;
687 }
688 m = m >> 1;
689 if (m == 0) {
690 m = highbit;
691 }
692 }
693 span->writeAll = GL_FALSE;
694 }
695
696
697 /**
698 * Clip a pixel span to the current buffer/window boundaries:
699 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
700 * window clipping and scissoring.
701 * Return: GL_TRUE some pixels still visible
702 * GL_FALSE nothing visible
703 */
704 static GLuint
705 clip_span( GLcontext *ctx, struct sw_span *span )
706 {
707 const GLint xmin = ctx->DrawBuffer->_Xmin;
708 const GLint xmax = ctx->DrawBuffer->_Xmax;
709 const GLint ymin = ctx->DrawBuffer->_Ymin;
710 const GLint ymax = ctx->DrawBuffer->_Ymax;
711
712 if (span->arrayMask & SPAN_XY) {
713 /* arrays of x/y pixel coords */
714 const GLint *x = span->array->x;
715 const GLint *y = span->array->y;
716 const GLint n = span->end;
717 GLubyte *mask = span->array->mask;
718 GLint i;
719 if (span->arrayMask & SPAN_MASK) {
720 /* note: using & intead of && to reduce branches */
721 for (i = 0; i < n; i++) {
722 mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
723 & (y[i] >= ymin) & (y[i] < ymax);
724 }
725 }
726 else {
727 /* note: using & intead of && to reduce branches */
728 for (i = 0; i < n; i++) {
729 mask[i] = (x[i] >= xmin) & (x[i] < xmax)
730 & (y[i] >= ymin) & (y[i] < ymax);
731 }
732 }
733 return GL_TRUE; /* some pixels visible */
734 }
735 else {
736 /* horizontal span of pixels */
737 const GLint x = span->x;
738 const GLint y = span->y;
739 const GLint n = span->end;
740
741 /* Trivial rejection tests */
742 if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
743 span->end = 0;
744 return GL_FALSE; /* all pixels clipped */
745 }
746
747 /* Clip to the left */
748 if (x < xmin) {
749 ASSERT(x + n > xmin);
750 span->writeAll = GL_FALSE;
751 _mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte));
752 }
753
754 /* Clip to right */
755 if (x + n > xmax) {
756 ASSERT(x < xmax);
757 span->end = xmax - x;
758 }
759
760 return GL_TRUE; /* some pixels visible */
761 }
762 }
763
764
765 /**
766 * Apply all the per-fragment opertions to a span of color index fragments
767 * and write them to the enabled color drawbuffers.
768 * The 'span' parameter can be considered to be const. Note that
769 * span->interpMask and span->arrayMask may be changed but will be restored
770 * to their original values before returning.
771 */
772 void
773 _swrast_write_index_span( GLcontext *ctx, struct sw_span *span)
774 {
775 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
776 const struct gl_framebuffer *fb = ctx->DrawBuffer;
777 const GLuint output = 0;
778 const GLbitfield origInterpMask = span->interpMask;
779 const GLbitfield origArrayMask = span->arrayMask;
780 GLuint buf;
781
782 ASSERT(span->end <= MAX_WIDTH);
783 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
784 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
785 ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX);
786 ASSERT((span->interpMask & span->arrayMask) == 0);
787
788 if (span->arrayMask & SPAN_MASK) {
789 /* mask was initialized by caller, probably glBitmap */
790 span->writeAll = GL_FALSE;
791 }
792 else {
793 _mesa_memset(span->array->mask, 1, span->end);
794 span->writeAll = GL_TRUE;
795 }
796
797 /* Clipping */
798 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
799 if (!clip_span(ctx, span)) {
800 return;
801 }
802 }
803
804 /* Depth bounds test */
805 if (ctx->Depth.BoundsTest && ctx->Visual.depthBits > 0) {
806 if (!_swrast_depth_bounds_test(ctx, span)) {
807 return;
808 }
809 }
810
811 #ifdef DEBUG
812 /* Make sure all fragments are within window bounds */
813 if (span->arrayMask & SPAN_XY) {
814 GLuint i;
815 for (i = 0; i < span->end; i++) {
816 if (span->array->mask[i]) {
817 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
818 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
819 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
820 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
821 }
822 }
823 }
824 #endif
825
826 /* Polygon Stippling */
827 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
828 stipple_polygon_span(ctx, span);
829 }
830
831 /* Stencil and Z testing */
832 if (ctx->Depth.Test || ctx->Stencil.Enabled) {
833 if (span->interpMask & SPAN_Z)
834 _swrast_span_interpolate_z(ctx, span);
835
836 if (ctx->Stencil.Enabled) {
837 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
838 span->arrayMask = origArrayMask;
839 return;
840 }
841 }
842 else {
843 ASSERT(ctx->Depth.Test);
844 if (!_swrast_depth_test_span(ctx, span)) {
845 span->interpMask = origInterpMask;
846 span->arrayMask = origArrayMask;
847 return;
848 }
849 }
850 }
851
852 #if FEATURE_ARB_occlusion_query
853 if (ctx->Query.CurrentOcclusionObject) {
854 /* update count of 'passed' fragments */
855 struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
856 GLuint i;
857 for (i = 0; i < span->end; i++)
858 q->Result += span->array->mask[i];
859 }
860 #endif
861
862 /* we have to wait until after occlusion to do this test */
863 if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
864 /* write no pixels */
865 span->arrayMask = origArrayMask;
866 return;
867 }
868
869 /* Interpolate the color indexes if needed */
870 if (ctx->Fog.Enabled ||
871 ctx->Color.IndexLogicOpEnabled ||
872 ctx->Color.IndexMask != 0xffffffff ||
873 (span->arrayMask & SPAN_COVERAGE)) {
874 if (span->interpMask & SPAN_INDEX) {
875 interpolate_indexes(ctx, span);
876 }
877 }
878
879 /* Fog */
880 if (ctx->Fog.Enabled) {
881 _swrast_fog_ci_span(ctx, span);
882 }
883
884 /* Antialias coverage application */
885 if (span->arrayMask & SPAN_COVERAGE) {
886 const GLfloat *coverage = span->array->coverage;
887 GLuint *index = span->array->index;
888 GLuint i;
889 for (i = 0; i < span->end; i++) {
890 ASSERT(coverage[i] < 16);
891 index[i] = (index[i] & ~0xf) | ((GLuint) coverage[i]);
892 }
893 }
894
895 /* Loop over drawing buffers */
896 for (buf = 0; buf < fb->_NumColorDrawBuffers[output]; buf++) {
897 struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[output][buf];
898 GLuint indexTemp[MAX_WIDTH], *index32;
899
900 ASSERT(rb->_BaseFormat == GL_COLOR_INDEX);
901
902 if (ctx->Color.IndexLogicOpEnabled ||
903 ctx->Color.IndexMask != 0xffffffff) {
904 /* make copy of incoming indexes */
905 MEMCPY(indexTemp, span->array->index, span->end * sizeof(GLuint));
906
907 if (ctx->Color.IndexLogicOpEnabled) {
908 _swrast_logicop_ci_span(ctx, rb, span, indexTemp);
909 }
910
911 if (ctx->Color.IndexMask != 0xffffffff) {
912 _swrast_mask_ci_span(ctx, rb, span, indexTemp);
913 }
914 index32 = indexTemp;
915 }
916 else {
917 index32 = span->array->index;
918 }
919
920 if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
921 /* all fragments have same color index */
922 GLubyte index8;
923 GLushort index16;
924 GLuint index32;
925 void *value;
926
927 if (rb->DataType == GL_UNSIGNED_BYTE) {
928 index8 = FixedToInt(span->index);
929 value = &index8;
930 }
931 else if (rb->DataType == GL_UNSIGNED_SHORT) {
932 index16 = FixedToInt(span->index);
933 value = &index16;
934 }
935 else {
936 ASSERT(rb->DataType == GL_UNSIGNED_INT);
937 index32 = FixedToInt(span->index);
938 value = &index32;
939 }
940
941 if (span->arrayMask & SPAN_XY) {
942 rb->PutMonoValues(ctx, rb, span->end, span->array->x,
943 span->array->y, value, span->array->mask);
944 }
945 else {
946 rb->PutMonoRow(ctx, rb, span->end, span->x, span->y,
947 value, span->array->mask);
948 }
949 }
950 else {
951 /* each fragment is a different color */
952 GLubyte index8[MAX_WIDTH];
953 GLushort index16[MAX_WIDTH];
954 void *values;
955
956 if (rb->DataType == GL_UNSIGNED_BYTE) {
957 GLuint k;
958 for (k = 0; k < span->end; k++) {
959 index8[k] = (GLubyte) index32[k];
960 }
961 values = index8;
962 }
963 else if (rb->DataType == GL_UNSIGNED_SHORT) {
964 GLuint k;
965 for (k = 0; k < span->end; k++) {
966 index16[k] = (GLushort) index32[k];
967 }
968 values = index16;
969 }
970 else {
971 ASSERT(rb->DataType == GL_UNSIGNED_INT);
972 values = index32;
973 }
974
975 if (span->arrayMask & SPAN_XY) {
976 rb->PutValues(ctx, rb, span->end, span->array->x, span->array->y,
977 values, span->array->mask);
978 }
979 else {
980 rb->PutRow(ctx, rb, span->end, span->x, span->y,
981 values, span->array->mask);
982 }
983 }
984 }
985
986 span->interpMask = origInterpMask;
987 span->arrayMask = origArrayMask;
988 }
989
990
991 /**
992 * Add specular color to base color. This is used only when
993 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
994 */
995 static void
996 add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] )
997 {
998 GLuint i;
999 for (i = 0; i < n; i++) {
1000 #if CHAN_TYPE == GL_FLOAT
1001 /* no clamping */
1002 rgba[i][RCOMP] += specular[i][RCOMP];
1003 rgba[i][GCOMP] += specular[i][GCOMP];
1004 rgba[i][BCOMP] += specular[i][BCOMP];
1005 #else
1006 GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
1007 GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
1008 GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
1009 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1010 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1011 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1012 #endif
1013 }
1014 }
1015
1016
1017 /**
1018 * XXX merge this code into the _swrast_write_rgba_span() routine!
1019 *
1020 * Draw to more than one RGBA color buffer (or none).
1021 * All fragment operations, up to (but not) blending/logicop should
1022 * have been done first.
1023 */
1024 static void
1025 multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
1026 {
1027 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1028 struct gl_framebuffer *fb = ctx->DrawBuffer;
1029 const GLuint output = 0;
1030 GLuint i;
1031
1032 ASSERT(span->end < MAX_WIDTH);
1033 ASSERT(colorMask != 0x0);
1034
1035 for (i = 0; i < fb->_NumColorDrawBuffers[output]; i++) {
1036 struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[output][i];
1037 GLchan rgbaTmp[MAX_WIDTH][4];
1038
1039 /* make copy of incoming colors */
1040 MEMCPY( rgbaTmp, span->array->rgba, 4 * span->end * sizeof(GLchan) );
1041
1042 if (ctx->Color._LogicOpEnabled) {
1043 _swrast_logicop_rgba_span(ctx, rb, span, rgbaTmp);
1044 }
1045 else if (ctx->Color.BlendEnabled) {
1046 _swrast_blend_span(ctx, rb, span, rgbaTmp);
1047 }
1048
1049 if (colorMask != 0xffffffff) {
1050 _swrast_mask_rgba_span(ctx, rb, span, rgbaTmp);
1051 }
1052
1053 if (span->arrayMask & SPAN_XY) {
1054 /* array of pixel coords */
1055 ASSERT(rb->PutValues);
1056 rb->PutValues(ctx, rb, span->end, span->array->x,
1057 span->array->y, rgbaTmp, span->array->mask);
1058 }
1059 else {
1060 /* horizontal run of pixels */
1061 ASSERT(rb->PutRow);
1062 rb->PutRow(ctx, rb, span->end, span->x, span->y, rgbaTmp,
1063 span->array->mask);
1064 }
1065 }
1066 }
1067
1068
1069 /**
1070 * Apply all the per-fragment operations to a span.
1071 * This now includes texturing (_swrast_write_texture_span() is history).
1072 * This function may modify any of the array values in the span.
1073 * span->interpMask and span->arrayMask may be changed but will be restored
1074 * to their original values before returning.
1075 */
1076 void
1077 _swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span)
1078 {
1079 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1080 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1081 const GLbitfield origInterpMask = span->interpMask;
1082 const GLbitfield origArrayMask = span->arrayMask;
1083
1084 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
1085 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
1086 ASSERT(span->end <= MAX_WIDTH);
1087 ASSERT((span->interpMask & span->arrayMask) == 0);
1088
1089 /*
1090 printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__,
1091 span->interpMask, span->arrayMask);
1092 */
1093
1094 if (span->arrayMask & SPAN_MASK) {
1095 /* mask was initialized by caller, probably glBitmap */
1096 span->writeAll = GL_FALSE;
1097 }
1098 else {
1099 _mesa_memset(span->array->mask, 1, span->end);
1100 span->writeAll = GL_TRUE;
1101 }
1102
1103 /* Clip to window/scissor box */
1104 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
1105 if (!clip_span(ctx, span)) {
1106 return;
1107 }
1108 }
1109
1110 #ifdef DEBUG
1111 /* Make sure all fragments are within window bounds */
1112 if (span->arrayMask & SPAN_XY) {
1113 GLuint i;
1114 for (i = 0; i < span->end; i++) {
1115 if (span->array->mask[i]) {
1116 assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
1117 assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
1118 assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
1119 assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
1120 }
1121 }
1122 }
1123 #endif
1124
1125 /* Polygon Stippling */
1126 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1127 stipple_polygon_span(ctx, span);
1128 }
1129
1130 /* Interpolate texcoords? */
1131 if (ctx->Texture._EnabledCoordUnits
1132 && (span->interpMask & SPAN_TEXTURE)
1133 && (span->arrayMask & SPAN_TEXTURE) == 0) {
1134 interpolate_texcoords(ctx, span);
1135 }
1136
1137 /* If the alpha test is enabled, we have to compute the fragment colors
1138 * at this point and do the alpha test.
1139 * Else, if alpha test is not enabled, we'll try to defer fragment
1140 * color computation (by interpolation, texture mapping, fragment program)
1141 * until after the Z/stencil tests in the hope that many fragments will
1142 * get culled, leaving less work to do.
1143 */
1144 if (ctx->Color.AlphaEnabled) {
1145 /* Now we need the rgba array, fill it in if needed */
1146 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1147 interpolate_colors(ctx, span);
1148
1149 if (span->interpMask & SPAN_SPEC)
1150 interpolate_specular(ctx, span);
1151
1152 if (span->interpMask & SPAN_FOG)
1153 interpolate_fog(ctx, span);
1154
1155 /* Compute fragment colors with fragment program or texture lookups */
1156 if (ctx->FragmentProgram._Active)
1157 /* XXX interpolate depth values here??? */
1158 _swrast_exec_fragment_program( ctx, span );
1159 else if (ctx->ATIFragmentShader._Enabled)
1160 _swrast_exec_fragment_shader( ctx, span );
1161 else if (ctx->Texture._EnabledUnits && (span->arrayMask & SPAN_TEXTURE))
1162 _swrast_texture_span( ctx, span );
1163
1164 /* Do the alpha test */
1165 if (!_swrast_alpha_test(ctx, span)) {
1166 span->arrayMask = origArrayMask;
1167 return;
1168 }
1169 }
1170
1171 /* Stencil and Z testing */
1172 if (ctx->Stencil.Enabled || ctx->Depth.Test) {
1173 if (span->interpMask & SPAN_Z)
1174 _swrast_span_interpolate_z(ctx, span);
1175
1176 if (ctx->Stencil.Enabled && ctx->DrawBuffer->Visual.stencilBits > 0) {
1177 /* Combined Z/stencil tests */
1178 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1179 span->interpMask = origInterpMask;
1180 span->arrayMask = origArrayMask;
1181 return;
1182 }
1183 }
1184 else if (ctx->DrawBuffer->Visual.depthBits > 0) {
1185 /* Just regular depth testing */
1186 ASSERT(ctx->Depth.Test);
1187 ASSERT(span->arrayMask & SPAN_Z);
1188 if (!_swrast_depth_test_span(ctx, span)) {
1189 span->interpMask = origInterpMask;
1190 span->arrayMask = origArrayMask;
1191 return;
1192 }
1193 }
1194 }
1195
1196 #if FEATURE_ARB_occlusion_query
1197 if (ctx->Query.CurrentOcclusionObject) {
1198 /* update count of 'passed' fragments */
1199 struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
1200 GLuint i;
1201 for (i = 0; i < span->end; i++)
1202 q->Result += span->array->mask[i];
1203 }
1204 #endif
1205
1206 /* We had to wait until now to check for glColorMask(0,0,0,0) because of
1207 * the occlusion test.
1208 */
1209 if (colorMask == 0x0) {
1210 span->interpMask = origInterpMask;
1211 span->arrayMask = origArrayMask;
1212 return;
1213 }
1214
1215 /* If the alpha test isn't enabled, we're able to defer computing fragment
1216 * colors (by interpolation, texturing, fragment program) until now.
1217 * Hopefully, Z/stencil tests culled many of the fragments!
1218 */
1219 if (!ctx->Color.AlphaEnabled) {
1220 /* Now we need the rgba array, fill it in if needed */
1221 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1222 interpolate_colors(ctx, span);
1223
1224 if (span->interpMask & SPAN_SPEC)
1225 interpolate_specular(ctx, span);
1226
1227 if (span->interpMask & SPAN_FOG)
1228 interpolate_fog(ctx, span);
1229
1230 if (ctx->FragmentProgram._Active)
1231 _swrast_exec_fragment_program( ctx, span );
1232 else if (ctx->ATIFragmentShader._Enabled)
1233 _swrast_exec_fragment_shader( ctx, span );
1234 else if (ctx->Texture._EnabledUnits && (span->arrayMask & SPAN_TEXTURE))
1235 _swrast_texture_span( ctx, span );
1236 }
1237
1238 ASSERT(span->arrayMask & SPAN_RGBA);
1239
1240 if (!ctx->FragmentProgram._Enabled) {
1241 /* Add base and specular colors */
1242 if (ctx->Fog.ColorSumEnabled ||
1243 (ctx->Light.Enabled &&
1244 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1245 if (span->interpMask & SPAN_SPEC) {
1246 interpolate_specular(ctx, span);
1247 }
1248 if (span->arrayMask & SPAN_SPEC) {
1249 add_colors( span->end, span->array->rgba, span->array->spec );
1250 }
1251 else {
1252 /* We probably added the base/specular colors during the
1253 * vertex stage!
1254 */
1255 }
1256 }
1257 }
1258
1259 /* Fog */
1260 if (swrast->_FogEnabled) {
1261 _swrast_fog_rgba_span(ctx, span);
1262 }
1263
1264 /* Antialias coverage application */
1265 if (span->arrayMask & SPAN_COVERAGE) {
1266 GLchan (*rgba)[4] = span->array->rgba;
1267 GLfloat *coverage = span->array->coverage;
1268 GLuint i;
1269 for (i = 0; i < span->end; i++) {
1270 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]);
1271 }
1272 }
1273
1274 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1275 /* need to do blend/logicop separately for each color buffer */
1276 multi_write_rgba_span(ctx, span);
1277 }
1278 else {
1279 /* normal: write to exactly one buffer */
1280 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
1281
1282 if (ctx->Color._LogicOpEnabled) {
1283 _swrast_logicop_rgba_span(ctx, rb, span, span->array->rgba);
1284 }
1285 else if (ctx->Color.BlendEnabled) {
1286 _swrast_blend_span(ctx, rb, span, span->array->rgba);
1287 }
1288
1289 /* Color component masking */
1290 if (colorMask != 0xffffffff) {
1291 _swrast_mask_rgba_span(ctx, rb, span, span->array->rgba);
1292 }
1293
1294 /* Finally, write the pixels to a color buffer */
1295 if (span->arrayMask & SPAN_XY) {
1296 /* array of pixel coords */
1297 ASSERT(rb->PutValues);
1298 ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA);
1299 /* XXX check datatype */
1300 rb->PutValues(ctx, rb, span->end, span->array->x, span->array->y,
1301 span->array->rgba, span->array->mask);
1302 }
1303 else {
1304 /* horizontal run of pixels */
1305 ASSERT(rb->PutRow);
1306 ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA);
1307 /* XXX check datatype */
1308 rb->PutRow(ctx, rb, span->end, span->x, span->y, span->array->rgba,
1309 span->writeAll ? NULL : span->array->mask);
1310 }
1311 }
1312
1313 span->interpMask = origInterpMask;
1314 span->arrayMask = origArrayMask;
1315 }
1316
1317
1318
1319 /**
1320 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1321 * reading ouside the buffer's boundaries.
1322 */
1323 void
1324 _swrast_read_rgba_span( GLcontext *ctx, struct gl_renderbuffer *rb,
1325 GLuint n, GLint x, GLint y, GLchan rgba[][4] )
1326 {
1327 const GLint bufWidth = (GLint) rb->Width;
1328 const GLint bufHeight = (GLint) rb->Height;
1329
1330 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1331 /* completely above, below, or right */
1332 /* XXX maybe leave rgba values undefined? */
1333 _mesa_bzero(rgba, 4 * n * sizeof(GLchan));
1334 }
1335 else {
1336 GLint skip, length;
1337 if (x < 0) {
1338 /* left edge clipping */
1339 skip = -x;
1340 length = (GLint) n - skip;
1341 if (length < 0) {
1342 /* completely left of window */
1343 return;
1344 }
1345 if (length > bufWidth) {
1346 length = bufWidth;
1347 }
1348 }
1349 else if ((GLint) (x + n) > bufWidth) {
1350 /* right edge clipping */
1351 skip = 0;
1352 length = bufWidth - x;
1353 if (length < 0) {
1354 /* completely to right of window */
1355 return;
1356 }
1357 }
1358 else {
1359 /* no clipping */
1360 skip = 0;
1361 length = (GLint) n;
1362 }
1363
1364 ASSERT(rb);
1365 ASSERT(rb->GetRow);
1366 ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA);
1367 ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
1368 rb->GetRow(ctx, rb, length, x + skip, y, rgba + skip);
1369 }
1370 }
1371
1372
1373 /**
1374 * Read CI pixels from frame buffer. Clipping will be done to prevent
1375 * reading ouside the buffer's boundaries.
1376 */
1377 void
1378 _swrast_read_index_span( GLcontext *ctx, struct gl_renderbuffer *rb,
1379 GLuint n, GLint x, GLint y, GLuint index[] )
1380 {
1381 const GLint bufWidth = (GLint) rb->Width;
1382 const GLint bufHeight = (GLint) rb->Height;
1383
1384 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1385 /* completely above, below, or right */
1386 _mesa_bzero(index, n * sizeof(GLuint));
1387 }
1388 else {
1389 GLint skip, length;
1390 if (x < 0) {
1391 /* left edge clipping */
1392 skip = -x;
1393 length = (GLint) n - skip;
1394 if (length < 0) {
1395 /* completely left of window */
1396 return;
1397 }
1398 if (length > bufWidth) {
1399 length = bufWidth;
1400 }
1401 }
1402 else if ((GLint) (x + n) > bufWidth) {
1403 /* right edge clipping */
1404 skip = 0;
1405 length = bufWidth - x;
1406 if (length < 0) {
1407 /* completely to right of window */
1408 return;
1409 }
1410 }
1411 else {
1412 /* no clipping */
1413 skip = 0;
1414 length = (GLint) n;
1415 }
1416
1417 ASSERT(rb->GetRow);
1418 ASSERT(rb->_BaseFormat == GL_COLOR_INDEX);
1419
1420 if (rb->DataType == GL_UNSIGNED_BYTE) {
1421 GLubyte index8[MAX_WIDTH];
1422 GLint i;
1423 rb->GetRow(ctx, rb, length, x + skip, y, index8);
1424 for (i = 0; i < length; i++)
1425 index[skip + i] = index8[i];
1426 }
1427 else if (rb->DataType == GL_UNSIGNED_SHORT) {
1428 GLushort index16[MAX_WIDTH];
1429 GLint i;
1430 rb->GetRow(ctx, rb, length, x + skip, y, index16);
1431 for (i = 0; i < length; i++)
1432 index[skip + i] = index16[i];
1433 }
1434 else if (rb->DataType == GL_UNSIGNED_INT) {
1435 rb->GetRow(ctx, rb, length, x + skip, y, index + skip);
1436 }
1437 }
1438 }
1439
1440
1441 /**
1442 * Wrapper for gl_renderbuffer::GetValues() which does clipping to avoid
1443 * reading values outside the buffer bounds.
1444 * We can use this for reading any format/type of renderbuffer.
1445 * \param valueSize is the size in bytes of each value put into the
1446 * values array.
1447 */
1448 void
1449 _swrast_get_values(GLcontext *ctx, struct gl_renderbuffer *rb,
1450 GLuint count, const GLint x[], const GLint y[],
1451 void *values, GLuint valueSize)
1452 {
1453 GLuint i, inCount = 0, inStart = 0;
1454
1455 for (i = 0; i < count; i++) {
1456 if (x[i] >= 0 && y[i] >= 0 && x[i] < rb->Width && y[i] < rb->Height) {
1457 /* inside */
1458 if (inCount == 0)
1459 inStart = i;
1460 inCount++;
1461 }
1462 else {
1463 if (inCount > 0) {
1464 /* read [inStart, inStart + inCount) */
1465 rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
1466 (GLubyte *) values + inStart * valueSize);
1467 inCount = 0;
1468 }
1469 }
1470 }
1471 if (inCount > 0) {
1472 /* read last values */
1473 rb->GetValues(ctx, rb, inCount, x + inStart, y + inStart,
1474 (GLubyte *) values + inStart * valueSize);
1475 }
1476 }