Overhaul of glRead/DrawBuffer() code. Now, swrast->Driver.SetBuffer()
[mesa.git] / src / mesa / swrast / s_span.c
1 /* $Id: s_span.c,v 1.45 2002/07/09 01:22:52 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 /**
29 * \file swrast/s_span.c
30 * \brief Span processing functions used by all rasterization functions.
31 * This is where all the per-fragment tests are performed
32 * \author Brian Paul
33 */
34
35 #include "glheader.h"
36 #include "colormac.h"
37 #include "context.h"
38 #include "macros.h"
39 #include "mmath.h"
40 #include "mem.h"
41
42 #include "s_alpha.h"
43 #include "s_alphabuf.h"
44 #include "s_blend.h"
45 #include "s_context.h"
46 #include "s_depth.h"
47 #include "s_fog.h"
48 #include "s_logic.h"
49 #include "s_masking.h"
50 #include "s_span.h"
51 #include "s_stencil.h"
52 #include "s_texture.h"
53
54
55 /**
56 * Init span's Z interpolation values to the RasterPos Z.
57 * Used during setup for glDraw/CopyPixels.
58 */
59 void
60 _mesa_span_default_z( GLcontext *ctx, struct sw_span *span )
61 {
62 if (ctx->Visual.depthBits <= 16)
63 span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax);
64 else
65 span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax);
66 span->zStep = 0;
67 span->interpMask |= SPAN_Z;
68 }
69
70
71 /**
72 * Init span's fog interpolation values to the RasterPos fog.
73 * Used during setup for glDraw/CopyPixels.
74 */
75 void
76 _mesa_span_default_fog( GLcontext *ctx, struct sw_span *span )
77 {
78 span->fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
79 span->fogStep = 0;
80 span->interpMask |= SPAN_FOG;
81 }
82
83
84 /**
85 * Init span's color or index interpolation values to the RasterPos color.
86 * Used during setup for glDraw/CopyPixels.
87 */
88 void
89 _mesa_span_default_color( GLcontext *ctx, struct sw_span *span )
90 {
91 if (ctx->Visual.rgbMode) {
92 GLchan r, g, b, a;
93 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
94 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
95 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
96 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
97 #if CHAN_TYPE == GL_FLOAT
98 span->red = r;
99 span->green = g;
100 span->blue = b;
101 span->alpha = a;
102 #else
103 span->red = IntToFixed(r);
104 span->green = IntToFixed(g);
105 span->blue = IntToFixed(b);
106 span->alpha = IntToFixed(a);
107 #endif
108 span->redStep = 0;
109 span->greenStep = 0;
110 span->blueStep = 0;
111 span->alphaStep = 0;
112 span->interpMask |= SPAN_RGBA;
113 }
114 else {
115 span->index = IntToFixed(ctx->Current.RasterIndex);
116 span->indexStep = 0;
117 span->interpMask |= SPAN_INDEX;
118 }
119 }
120
121
122 /**
123 * Init span's texcoord interpolation values to the RasterPos texcoords.
124 * Used during setup for glDraw/CopyPixels.
125 */
126 void
127 _mesa_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
128 {
129 GLuint i;
130 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
131 span->tex[i][0] = ctx->Current.RasterTexCoords[i][0];
132 span->tex[i][1] = ctx->Current.RasterTexCoords[i][1];
133 span->tex[i][2] = ctx->Current.RasterTexCoords[i][2];
134 span->tex[i][3] = ctx->Current.RasterTexCoords[i][3];
135 span->texStepX[i][0] = 0.0;
136 span->texStepX[i][1] = 0.0;
137 span->texStepX[i][2] = 0.0;
138 span->texStepX[i][3] = 0.0;
139 }
140 span->interpMask |= SPAN_TEXTURE;
141 }
142
143
144 /* Fill in the span.color.rgba array from the interpolation values */
145 static void
146 interpolate_colors(GLcontext *ctx, struct sw_span *span)
147 {
148 GLfixed r = span->red;
149 GLfixed g = span->green;
150 GLfixed b = span->blue;
151 GLfixed a = span->alpha;
152 const GLint dr = span->redStep;
153 const GLint dg = span->greenStep;
154 const GLint db = span->blueStep;
155 const GLint da = span->alphaStep;
156 const GLuint n = span->end;
157 GLchan (*rgba)[4] = span->color.rgba;
158 GLuint i;
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(r);
167 color[GCOMP] = FixedToChan(g);
168 color[BCOMP] = FixedToChan(b);
169 color[ACOMP] = FixedToChan(a);
170 for (i = 0; i < n; i++) {
171 COPY_CHAN4(span->color.rgba[i], color);
172 }
173 }
174 else {
175 /* interpolate */
176 for (i = 0; i < n; i++) {
177 rgba[i][RCOMP] = FixedToChan(r);
178 rgba[i][GCOMP] = FixedToChan(g);
179 rgba[i][BCOMP] = FixedToChan(b);
180 rgba[i][ACOMP] = FixedToChan(a);
181 r += dr;
182 g += dg;
183 b += db;
184 a += da;
185 }
186 }
187 span->arrayMask |= SPAN_RGBA;
188 }
189
190
191 /* Fill in the span.color.index array from the interpolation values */
192 static void
193 interpolate_indexes(GLcontext *ctx, struct sw_span *span)
194 {
195 GLfixed index = span->index;
196 const GLint indexStep = span->indexStep;
197 const GLuint n = span->end;
198 GLuint *indexes = span->color.index;
199 GLuint i;
200 ASSERT((span->interpMask & SPAN_INDEX) &&
201 !(span->arrayMask & SPAN_INDEX));
202
203 if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) {
204 /* constant color */
205 index = FixedToInt(index);
206 for (i = 0; i < n; i++) {
207 indexes[i] = index;
208 }
209 }
210 else {
211 /* interpolate */
212 for (i = 0; i < n; i++) {
213 indexes[i] = FixedToInt(index);
214 index += indexStep;
215 }
216 }
217 span->arrayMask |= SPAN_INDEX;
218 }
219
220
221 /* Fill in the span.specArray array from the interpolation values */
222 static void
223 interpolate_specular(GLcontext *ctx, struct sw_span *span)
224 {
225 if (span->interpMask & SPAN_FLAT) {
226 /* constant color */
227 const GLchan r = FixedToChan(span->specRed);
228 const GLchan g = FixedToChan(span->specGreen);
229 const GLchan b = FixedToChan(span->specBlue);
230 GLuint i;
231 for (i = 0; i < span->end; i++) {
232 span->specArray[i][RCOMP] = r;
233 span->specArray[i][GCOMP] = g;
234 span->specArray[i][BCOMP] = b;
235 }
236 }
237 else {
238 /* interpolate */
239 #if CHAN_TYPE == GL_FLOAT
240 GLfloat r = span->specRed;
241 GLfloat g = span->specGreen;
242 GLfloat b = span->specBlue;
243 #else
244 GLfixed r = span->specRed;
245 GLfixed g = span->specGreen;
246 GLfixed b = span->specBlue;
247 #endif
248 GLuint i;
249 for (i = 0; i < span->end; i++) {
250 span->specArray[i][RCOMP] = FixedToChan(r);
251 span->specArray[i][GCOMP] = FixedToChan(g);
252 span->specArray[i][BCOMP] = FixedToChan(b);
253 r += span->specRedStep;
254 g += span->specGreenStep;
255 b += span->specBlueStep;
256 }
257 }
258 span->arrayMask |= SPAN_SPEC;
259 }
260
261
262 /* Fill in the span.zArray array from the interpolation values */
263 void
264 _mesa_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
265 {
266 const GLuint n = span->end;
267 GLuint i;
268
269 ASSERT((span->interpMask & SPAN_Z) &&
270 !(span->arrayMask & SPAN_Z));
271
272 if (ctx->Visual.depthBits <= 16) {
273 GLfixed zval = span->z;
274 for (i = 0; i < n; i++) {
275 span->zArray[i] = FixedToInt(zval);
276 zval += span->zStep;
277 }
278 }
279 else {
280 /* Deep Z buffer, no fixed->int shift */
281 GLfixed zval = span->z;
282 for (i = 0; i < n; i++) {
283 span->zArray[i] = zval;
284 zval += span->zStep;
285 }
286 }
287 span->arrayMask |= SPAN_Z;
288 }
289
290
291 /*
292 * This the ideal solution, as given in the OpenGL spec.
293 */
294 #if 0
295 static GLfloat
296 compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
297 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
298 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
299 {
300 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
301 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
302 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
303 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
304 GLfloat x = sqrt(dudx * dudx + dvdx * dvdx);
305 GLfloat y = sqrt(dudy * dudy + dvdy * dvdy);
306 GLfloat rho = MAX2(x, y);
307 GLfloat lambda = LOG2(rho);
308 return lambda;
309 }
310 #endif
311
312
313 /*
314 * This is a faster approximation
315 */
316 static GLfloat
317 compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
318 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
319 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
320 {
321 GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
322 GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
323 GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
324 GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
325 GLfloat maxU, maxV, rho, lambda;
326 dsdx2 = FABSF(dsdx2);
327 dsdy2 = FABSF(dsdy2);
328 dtdx2 = FABSF(dtdx2);
329 dtdy2 = FABSF(dtdy2);
330 maxU = MAX2(dsdx2, dsdy2) * texW;
331 maxV = MAX2(dtdx2, dtdy2) * texH;
332 rho = MAX2(maxU, maxV);
333 lambda = LOG2(rho);
334 return lambda;
335 }
336
337 /*
338 * Fill in the span.texcoords array from the interpolation values.
339 * XXX We could optimize here for the case when dq = 0. That would
340 * usually be the case when using an orthographic projection.
341 */
342 static void
343 interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
344 {
345 ASSERT(span->interpMask & SPAN_TEXTURE);
346 ASSERT(!(span->arrayMask & SPAN_TEXTURE));
347
348 if (ctx->Texture._EnabledUnits > 1) {
349 /* multitexture */
350 GLuint u;
351 span->arrayMask |= SPAN_TEXTURE;
352 for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
353 if (ctx->Texture.Unit[u]._ReallyEnabled) {
354 const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current;
355 const struct gl_texture_image *img = obj->Image[obj->BaseLevel];
356 GLboolean needLambda = (obj->MinFilter != obj->MagFilter);
357 if (needLambda) {
358 const GLfloat texW = (GLfloat) img->WidthScale;
359 const GLfloat texH = (GLfloat) img->HeightScale;
360 const GLfloat dsdx = span->texStepX[u][0];
361 const GLfloat dsdy = span->texStepY[u][0];
362 const GLfloat dtdx = span->texStepX[u][1];
363 const GLfloat dtdy = span->texStepY[u][1];
364 const GLfloat drdx = span->texStepX[u][2];
365 const GLfloat dqdx = span->texStepX[u][3];
366 const GLfloat dqdy = span->texStepY[u][3];
367 GLfloat s = span->tex[u][0];
368 GLfloat t = span->tex[u][1];
369 GLfloat r = span->tex[u][2];
370 GLfloat q = span->tex[u][3];
371 GLuint i;
372 for (i = 0; i < span->end; i++) {
373 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
374 span->texcoords[u][i][0] = s * invQ;
375 span->texcoords[u][i][1] = t * invQ;
376 span->texcoords[u][i][2] = r * invQ;
377 span->lambda[u][i] = compute_lambda(dsdx, dsdy, dtdx, dtdy,
378 dqdx, dqdy, texW, texH,
379 s, t, q, invQ);
380 s += dsdx;
381 t += dtdx;
382 r += drdx;
383 q += dqdx;
384 }
385 span->arrayMask |= SPAN_LAMBDA;
386 }
387 else {
388 const GLfloat dsdx = span->texStepX[u][0];
389 const GLfloat dtdx = span->texStepX[u][1];
390 const GLfloat drdx = span->texStepX[u][2];
391 const GLfloat dqdx = span->texStepX[u][3];
392 GLfloat s = span->tex[u][0];
393 GLfloat t = span->tex[u][1];
394 GLfloat r = span->tex[u][2];
395 GLfloat q = span->tex[u][3];
396 GLuint i;
397 if (dqdx == 0.0) {
398 /* Ortho projection or polygon's parallel to window X axis */
399 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
400 for (i = 0; i < span->end; i++) {
401 span->texcoords[u][i][0] = s * invQ;
402 span->texcoords[u][i][1] = t * invQ;
403 span->texcoords[u][i][2] = r * invQ;
404 span->lambda[u][i] = 0.0;
405 s += dsdx;
406 t += dtdx;
407 r += drdx;
408 }
409 }
410 else {
411 for (i = 0; i < span->end; i++) {
412 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
413 span->texcoords[u][i][0] = s * invQ;
414 span->texcoords[u][i][1] = t * invQ;
415 span->texcoords[u][i][2] = r * invQ;
416 span->lambda[u][i] = 0.0;
417 s += dsdx;
418 t += dtdx;
419 r += drdx;
420 q += dqdx;
421 }
422 }
423 } /* lambda */
424 } /* if */
425 } /* for */
426 }
427 else {
428 /* single texture */
429 const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
430 const struct gl_texture_image *img = obj->Image[obj->BaseLevel];
431 GLboolean needLambda = (obj->MinFilter != obj->MagFilter);
432 span->arrayMask |= SPAN_TEXTURE;
433 if (needLambda) {
434 /* just texture unit 0, with lambda */
435 const GLfloat texW = (GLfloat) img->WidthScale;
436 const GLfloat texH = (GLfloat) img->HeightScale;
437 const GLfloat dsdx = span->texStepX[0][0];
438 const GLfloat dsdy = span->texStepY[0][0];
439 const GLfloat dtdx = span->texStepX[0][1];
440 const GLfloat dtdy = span->texStepY[0][1];
441 const GLfloat drdx = span->texStepX[0][2];
442 const GLfloat dqdx = span->texStepX[0][3];
443 const GLfloat dqdy = span->texStepY[0][3];
444 GLfloat s = span->tex[0][0];
445 GLfloat t = span->tex[0][1];
446 GLfloat r = span->tex[0][2];
447 GLfloat q = span->tex[0][3];
448 GLuint i;
449 for (i = 0; i < span->end; i++) {
450 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
451 span->lambda[0][i] = compute_lambda(dsdx, dsdy, dtdx, dtdy,
452 dqdx, dqdy, texW, texH,
453 s, t, q, invQ);
454 span->texcoords[0][i][0] = s * invQ;
455 span->texcoords[0][i][1] = t * invQ;
456 span->texcoords[0][i][2] = r * invQ;
457 s += dsdx;
458 t += dtdx;
459 r += drdx;
460 q += dqdx;
461 }
462 span->arrayMask |= SPAN_LAMBDA;
463 }
464 else {
465 /* just texture 0, without lambda */
466 const GLfloat dsdx = span->texStepX[0][0];
467 const GLfloat dtdx = span->texStepX[0][1];
468 const GLfloat drdx = span->texStepX[0][2];
469 const GLfloat dqdx = span->texStepX[0][3];
470 GLfloat s = span->tex[0][0];
471 GLfloat t = span->tex[0][1];
472 GLfloat r = span->tex[0][2];
473 GLfloat q = span->tex[0][3];
474 GLuint i;
475 if (dqdx == 0.0) {
476 /* Ortho projection or polygon's parallel to window X axis */
477 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
478 for (i = 0; i < span->end; i++) {
479 span->texcoords[0][i][0] = s * invQ;
480 span->texcoords[0][i][1] = t * invQ;
481 span->texcoords[0][i][2] = r * invQ;
482 s += dsdx;
483 t += dtdx;
484 r += drdx;
485 }
486 }
487 else {
488 for (i = 0; i < span->end; i++) {
489 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
490 span->texcoords[0][i][0] = s * invQ;
491 span->texcoords[0][i][1] = t * invQ;
492 span->texcoords[0][i][2] = r * invQ;
493 s += dsdx;
494 t += dtdx;
495 r += drdx;
496 q += dqdx;
497 }
498 }
499 }
500 }
501 }
502
503
504 /**
505 * Apply the current polygon stipple pattern to a span of pixels.
506 */
507 static void
508 stipple_polygon_span( GLcontext *ctx, struct sw_span *span )
509 {
510 const GLuint highbit = 0x80000000;
511 const GLuint stipple = ctx->PolygonStipple[span->y % 32];
512 GLuint i, m;
513
514 ASSERT(ctx->Polygon.StippleFlag);
515 ASSERT((span->arrayMask & SPAN_XY) == 0);
516
517 m = highbit >> (GLuint) (span->x % 32);
518
519 for (i = 0; i < span->end; i++) {
520 if ((m & stipple) == 0) {
521 span->mask[i] = 0;
522 }
523 m = m >> 1;
524 if (m == 0) {
525 m = highbit;
526 }
527 }
528 span->writeAll = GL_FALSE;
529 }
530
531
532 /**
533 * Clip a pixel span to the current buffer/window boundaries:
534 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
535 * window clipping and scissoring.
536 * Return: GL_TRUE some pixels still visible
537 * GL_FALSE nothing visible
538 */
539 static GLuint
540 clip_span( GLcontext *ctx, struct sw_span *span )
541 {
542 const GLint xmin = ctx->DrawBuffer->_Xmin;
543 const GLint xmax = ctx->DrawBuffer->_Xmax;
544 const GLint ymin = ctx->DrawBuffer->_Ymin;
545 const GLint ymax = ctx->DrawBuffer->_Ymax;
546
547 if (span->arrayMask & SPAN_XY) {
548 /* arrays of x/y pixel coords */
549 const GLint *x = span->xArray;
550 const GLint *y = span->yArray;
551 const GLint n = span->end;
552 GLubyte *mask = span->mask;
553 GLint i;
554 if (span->arrayMask & SPAN_MASK) {
555 /* note: using & intead of && to reduce branches */
556 for (i = 0; i < n; i++) {
557 mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
558 & (y[i] >= ymin) & (y[i] < ymax);
559 }
560 }
561 else {
562 /* note: using & intead of && to reduce branches */
563 for (i = 0; i < n; i++) {
564 mask[i] = (x[i] >= xmin) & (x[i] < xmax)
565 & (y[i] >= ymin) & (y[i] < ymax);
566 }
567 }
568 return GL_TRUE; /* some pixels visible */
569 }
570 else {
571 /* horizontal span of pixels */
572 const GLint x = span->x;
573 const GLint y = span->y;
574 const GLint n = span->end;
575
576 /* Trivial rejection tests */
577 if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
578 span->end = 0;
579 return GL_FALSE; /* all pixels clipped */
580 }
581
582 /* Clip to the left */
583 if (x < xmin) {
584 ASSERT(x + n > xmin);
585 span->writeAll = GL_FALSE;
586 BZERO(span->mask, (xmin - x) * sizeof(GLubyte));
587 }
588
589 /* Clip to right */
590 if (x + n > xmax) {
591 ASSERT(x < xmax);
592 span->end = xmax - x;
593 }
594
595 return GL_TRUE; /* some pixels visible */
596 }
597 }
598
599
600
601 /**
602 * Draw to more than one color buffer (or none).
603 */
604 static void
605 multi_write_index_span( GLcontext *ctx, struct sw_span *span )
606 {
607 SWcontext *swrast = SWRAST_CONTEXT(ctx);
608 GLuint bufferBit;
609
610 /* loop over four possible dest color buffers */
611 for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
612 if (bufferBit & ctx->Color._DrawDestMask) {
613 GLuint indexTmp[MAX_WIDTH];
614 ASSERT(span->end < MAX_WIDTH);
615
616 if (bufferBit == FRONT_LEFT_BIT)
617 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
618 else if (bufferBit == FRONT_RIGHT_BIT)
619 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
620 else if (bufferBit == BACK_LEFT_BIT)
621 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_LEFT);
622 else
623 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
624
625 /* make copy of incoming indexes */
626 MEMCPY( indexTmp, span->color.index, span->end * sizeof(GLuint) );
627
628 if (ctx->Color.IndexLogicOpEnabled) {
629 _mesa_logicop_ci_span(ctx, span, indexTmp);
630 }
631
632 if (ctx->Color.IndexMask != 0xffffffff) {
633 _mesa_mask_index_span(ctx, span, indexTmp);
634 }
635
636 if (span->arrayMask & SPAN_XY) {
637 /* array of pixel coords */
638 (*swrast->Driver.WriteCI32Pixels)(ctx, span->end,
639 span->xArray, span->yArray,
640 indexTmp, span->mask);
641 }
642 else {
643 /* horizontal run of pixels */
644 (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
645 indexTmp, span->mask);
646 }
647 }
648 }
649
650 /* restore default dest buffer */
651 _swrast_use_draw_buffer(ctx);
652 }
653
654
655 /**
656 * Draw to more than one RGBA color buffer (or none).
657 * All fragment operations, up to (but not) blending/logicop should
658 * have been done first.
659 */
660 static void
661 multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
662 {
663 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
664 GLuint bufferBit;
665 SWcontext *swrast = SWRAST_CONTEXT(ctx);
666
667 ASSERT(colorMask != 0x0);
668
669 if (ctx->Color.DrawBuffer == GL_NONE)
670 return;
671
672 /* loop over four possible dest color buffers */
673 for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
674 if (bufferBit & ctx->Color._DrawDestMask) {
675 GLchan rgbaTmp[MAX_WIDTH][4];
676 ASSERT(span->end < MAX_WIDTH);
677
678 if (bufferBit == FRONT_LEFT_BIT) {
679 ctx->Color._DriverDrawBuffer = GL_FRONT_LEFT;
680 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
681 }
682 else if (bufferBit == FRONT_RIGHT_BIT) {
683 ctx->Color._DriverDrawBuffer = GL_FRONT_RIGHT;
684 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
685 }
686 else if (bufferBit == BACK_LEFT_BIT) {
687 ctx->Color._DriverDrawBuffer = GL_BACK_LEFT;
688 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_LEFT);
689 }
690 else {
691 ctx->Color._DriverDrawBuffer = GL_BACK_RIGHT;
692 (*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
693 }
694
695 /* make copy of incoming colors */
696 MEMCPY( rgbaTmp, span->color.rgba, 4 * span->end * sizeof(GLchan) );
697
698 if (ctx->Color.ColorLogicOpEnabled) {
699 _mesa_logicop_rgba_span(ctx, span, rgbaTmp);
700 }
701 else if (ctx->Color.BlendEnabled) {
702 _mesa_blend_span(ctx, span, rgbaTmp);
703 }
704
705 if (colorMask != 0xffffffff) {
706 _mesa_mask_rgba_span(ctx, span, rgbaTmp);
707 }
708
709 if (span->arrayMask & SPAN_XY) {
710 /* array of pixel coords */
711 (*swrast->Driver.WriteRGBAPixels)(ctx, span->end,
712 span->xArray, span->yArray,
713 (const GLchan (*)[4]) rgbaTmp,
714 span->mask);
715 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
716 _mesa_write_alpha_pixels(ctx, span->end,
717 span->xArray, span->yArray,
718 (const GLchan (*)[4]) rgbaTmp,
719 span->mask);
720 }
721 }
722 else {
723 /* horizontal run of pixels */
724 (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
725 (const GLchan (*)[4]) rgbaTmp,
726 span->mask);
727 if (swrast->_RasterMask & ALPHABUF_BIT) {
728 _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
729 (const GLchan (*)[4]) rgbaTmp,
730 span->mask);
731 }
732 }
733 }
734 }
735
736 /* restore default dest buffer */
737 _swrast_use_draw_buffer(ctx);
738 }
739
740
741
742 /**
743 * This function may modify any of the array values in the span.
744 * span->interpMask and span->arrayMask may be changed but will be restored
745 * to their original values before returning.
746 */
747 void
748 _mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
749 {
750 SWcontext *swrast = SWRAST_CONTEXT(ctx);
751 const GLuint origInterpMask = span->interpMask;
752 const GLuint origArrayMask = span->arrayMask;
753
754 ASSERT(span->end <= MAX_WIDTH);
755 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
756 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
757 ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX);
758 ASSERT((span->interpMask & span->arrayMask) == 0);
759
760 if (span->arrayMask & SPAN_MASK) {
761 /* mask was initialized by caller, probably glBitmap */
762 span->writeAll = GL_FALSE;
763 }
764 else {
765 MEMSET(span->mask, 1, span->end);
766 span->writeAll = GL_TRUE;
767 }
768
769 /* Clipping */
770 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
771 if (!clip_span(ctx, span)) {
772 return;
773 }
774 }
775
776 #ifdef DEBUG
777 if (span->arrayMask & SPAN_XY) {
778 GLuint i;
779 for (i = 0; i < span->end; i++) {
780 if (span->mask[i]) {
781 assert(span->xArray[i] >= ctx->DrawBuffer->_Xmin);
782 assert(span->xArray[i] < ctx->DrawBuffer->_Xmax);
783 assert(span->yArray[i] >= ctx->DrawBuffer->_Ymin);
784 assert(span->yArray[i] < ctx->DrawBuffer->_Ymax);
785 }
786 }
787 }
788 #endif
789
790 /* Polygon Stippling */
791 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
792 stipple_polygon_span(ctx, span);
793 }
794
795 /* Depth test and stencil */
796 if (ctx->Depth.Test || ctx->Stencil.Enabled) {
797 if (span->interpMask & SPAN_Z)
798 _mesa_span_interpolate_z(ctx, span);
799
800 if (ctx->Stencil.Enabled) {
801 if (!_mesa_stencil_and_ztest_span(ctx, span)) {
802 span->arrayMask = origArrayMask;
803 return;
804 }
805 }
806 else {
807 ASSERT(ctx->Depth.Test);
808 if (!_mesa_depth_test_span(ctx, span)) {
809 span->arrayMask = origArrayMask;
810 return;
811 }
812 }
813 }
814
815 /* if we get here, something passed the depth test */
816 ctx->OcclusionResult = GL_TRUE;
817
818 /* we have to wait until after occlusion to do this test */
819 if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
820 /* write no pixels */
821 span->arrayMask = origArrayMask;
822 return;
823 }
824
825 /* Interpolate the color indexes if needed */
826 if (span->interpMask & SPAN_INDEX) {
827 interpolate_indexes(ctx, span);
828 /* clear the bit - this allows the WriteMonoCISpan optimization below */
829 span->interpMask &= ~SPAN_INDEX;
830 }
831
832 /* Fog */
833 if (ctx->Fog.Enabled) {
834 _mesa_fog_ci_span(ctx, span);
835 }
836
837 /* Antialias coverage application */
838 if (span->arrayMask & SPAN_COVERAGE) {
839 GLuint i;
840 GLuint *index = span->color.index;
841 for (i = 0; i < span->end; i++) {
842 ASSERT(span->coverage[i] < 16);
843 index[i] = (index[i] & ~0xf) | ((GLuint) (span->coverage[i]));
844 }
845 }
846
847 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
848 /* draw to zero or two or more buffers */
849 multi_write_index_span(ctx, span);
850 }
851 else {
852 /* normal situation: draw to exactly one buffer */
853 if (ctx->Color.IndexLogicOpEnabled) {
854 _mesa_logicop_ci_span(ctx, span, span->color.index);
855 }
856
857 if (ctx->Color.IndexMask != 0xffffffff) {
858 _mesa_mask_index_span(ctx, span, span->color.index);
859 }
860
861 /* write pixels */
862 if (span->arrayMask & SPAN_XY) {
863 /* array of pixel coords */
864 if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
865 /* all pixels have same color index */
866 (*swrast->Driver.WriteMonoCIPixels)(ctx, span->end,
867 span->xArray, span->yArray,
868 FixedToInt(span->index),
869 span->mask);
870 }
871 else {
872 (*swrast->Driver.WriteCI32Pixels)(ctx, span->end, span->xArray,
873 span->yArray, span->color.index,
874 span->mask );
875 }
876 }
877 else {
878 /* horizontal run of pixels */
879 if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
880 /* all pixels have same color index */
881 (*swrast->Driver.WriteMonoCISpan)(ctx, span->end, span->x, span->y,
882 FixedToInt(span->index),
883 span->mask);
884 }
885 else {
886 (*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
887 span->color.index, span->mask);
888 }
889 }
890 }
891
892 span->interpMask = origInterpMask;
893 span->arrayMask = origArrayMask;
894 }
895
896
897 /**
898 * This function may modify any of the array values in the span.
899 * span->interpMask and span->arrayMask may be changed but will be restored
900 * to their original values before returning.
901 */
902 void
903 _mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
904 {
905 SWcontext *swrast = SWRAST_CONTEXT(ctx);
906 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
907 const GLuint origInterpMask = span->interpMask;
908 const GLuint origArrayMask = span->arrayMask;
909 GLboolean monoColor;
910
911 ASSERT(span->end <= MAX_WIDTH);
912 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
913 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
914 ASSERT((span->interpMask & span->arrayMask) == 0);
915 ASSERT((span->interpMask | span->arrayMask) & SPAN_RGBA);
916 #ifdef DEBUG
917 if (ctx->Fog.Enabled)
918 ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
919 if (ctx->Depth.Test)
920 ASSERT((span->interpMask | span->arrayMask) & SPAN_Z);
921 #endif
922
923 /*
924 printf("%s() interp 0x%x array 0x%x p=0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask, span->primitive);
925 */
926
927 if (span->arrayMask & SPAN_MASK) {
928 /* mask was initialized by caller, probably glBitmap */
929 span->writeAll = GL_FALSE;
930 }
931 else {
932 MEMSET(span->mask, 1, span->end);
933 span->writeAll = GL_TRUE;
934 }
935
936 /* Determine if we have mono-chromatic colors */
937 monoColor = (span->interpMask & SPAN_RGBA) &&
938 span->redStep == 0 && span->greenStep == 0 &&
939 span->blueStep == 0 && span->alphaStep == 0;
940
941 /* Clipping */
942 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
943 if (!clip_span(ctx, span)) {
944 return;
945 }
946 }
947
948 #ifdef DEBUG
949 if (span->arrayMask & SPAN_XY) {
950 GLuint i;
951 for (i = 0; i < span->end; i++) {
952 if (span->mask[i]) {
953 assert(span->xArray[i] >= ctx->DrawBuffer->_Xmin);
954 assert(span->xArray[i] < ctx->DrawBuffer->_Xmax);
955 assert(span->yArray[i] >= ctx->DrawBuffer->_Ymin);
956 assert(span->yArray[i] < ctx->DrawBuffer->_Ymax);
957 }
958 }
959 }
960 #endif
961
962 /* Polygon Stippling */
963 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
964 stipple_polygon_span(ctx, span);
965 }
966
967 /* Do the alpha test */
968 if (ctx->Color.AlphaEnabled) {
969 if (!_mesa_alpha_test(ctx, span)) {
970 span->interpMask = origInterpMask;
971 span->arrayMask = origArrayMask;
972 return;
973 }
974 }
975
976 /* Stencil and Z testing */
977 if (ctx->Stencil.Enabled || ctx->Depth.Test) {
978 if (span->interpMask & SPAN_Z)
979 _mesa_span_interpolate_z(ctx, span);
980
981 if (ctx->Stencil.Enabled) {
982 if (!_mesa_stencil_and_ztest_span(ctx, span)) {
983 span->interpMask = origInterpMask;
984 span->arrayMask = origArrayMask;
985 return;
986 }
987 }
988 else {
989 ASSERT(ctx->Depth.Test);
990 ASSERT(span->arrayMask & SPAN_Z);
991 /* regular depth testing */
992 if (!_mesa_depth_test_span(ctx, span)) {
993 span->interpMask = origInterpMask;
994 span->arrayMask = origArrayMask;
995 return;
996 }
997 }
998 }
999
1000 /* if we get here, something passed the depth test */
1001 ctx->OcclusionResult = GL_TRUE;
1002
1003 /* can't abort span-writing until after occlusion testing */
1004 if (colorMask == 0x0) {
1005 span->interpMask = origInterpMask;
1006 span->arrayMask = origArrayMask;
1007 return;
1008 }
1009
1010 /* Now we may need to interpolate the colors */
1011 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) {
1012 interpolate_colors(ctx, span);
1013 /* clear the bit - this allows the WriteMonoCISpan optimization below */
1014 span->interpMask &= ~SPAN_RGBA;
1015 }
1016
1017 /* Fog */
1018 if (ctx->Fog.Enabled) {
1019 _mesa_fog_rgba_span(ctx, span);
1020 monoColor = GL_FALSE;
1021 }
1022
1023 /* Antialias coverage application */
1024 if (span->arrayMask & SPAN_COVERAGE) {
1025 GLchan (*rgba)[4] = span->color.rgba;
1026 GLuint i;
1027 for (i = 0; i < span->end; i++) {
1028 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]);
1029 }
1030 monoColor = GL_FALSE;
1031 }
1032
1033 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1034 multi_write_rgba_span(ctx, span);
1035 }
1036 else {
1037 /* normal: write to exactly one buffer */
1038 if (ctx->Color.ColorLogicOpEnabled) {
1039 _mesa_logicop_rgba_span(ctx, span, span->color.rgba);
1040 monoColor = GL_FALSE;
1041 }
1042 else if (ctx->Color.BlendEnabled) {
1043 _mesa_blend_span(ctx, span, span->color.rgba);
1044 monoColor = GL_FALSE;
1045 }
1046
1047 /* Color component masking */
1048 if (colorMask != 0xffffffff) {
1049 _mesa_mask_rgba_span(ctx, span, span->color.rgba);
1050 monoColor = GL_FALSE;
1051 }
1052
1053 /* write pixels */
1054 if (span->arrayMask & SPAN_XY) {
1055 /* array of pixel coords */
1056 /* XXX test for mono color */
1057 (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->xArray,
1058 span->yArray, (const GLchan (*)[4]) span->color.rgba, span->mask);
1059 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1060 _mesa_write_alpha_pixels(ctx, span->end,
1061 span->xArray, span->yArray,
1062 (const GLchan (*)[4]) span->color.rgba,
1063 span->mask);
1064 }
1065 }
1066 else {
1067 /* horizontal run of pixels */
1068 if (monoColor) {
1069 /* all pixels have same color */
1070 GLchan color[4];
1071 color[RCOMP] = FixedToChan(span->red);
1072 color[GCOMP] = FixedToChan(span->green);
1073 color[BCOMP] = FixedToChan(span->blue);
1074 color[ACOMP] = FixedToChan(span->alpha);
1075 (*swrast->Driver.WriteMonoRGBASpan)(ctx, span->end, span->x,
1076 span->y, color, span->mask);
1077 /* XXX software alpha buffer writes! */
1078 }
1079 else {
1080 /* each pixel is a different color */
1081 (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
1082 (const GLchan (*)[4]) span->color.rgba,
1083 span->writeAll ? ((const GLubyte *) NULL) : span->mask);
1084 if (swrast->_RasterMask & ALPHABUF_BIT) {
1085 _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
1086 (const GLchan (*)[4]) span->color.rgba,
1087 span->writeAll ? ((const GLubyte *) NULL) : span->mask);
1088 }
1089 }
1090 }
1091 }
1092
1093 span->interpMask = origInterpMask;
1094 span->arrayMask = origArrayMask;
1095 }
1096
1097
1098 /**
1099 * Add specular color to base color. This is used only when
1100 * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
1101 */
1102 static void
1103 add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] )
1104 {
1105 GLuint i;
1106 for (i = 0; i < n; i++) {
1107 #if CHAN_TYPE == GL_FLOAT
1108 /* no clamping */
1109 rgba[i][RCOMP] += specular[i][RCOMP];
1110 rgba[i][GCOMP] += specular[i][GCOMP];
1111 rgba[i][BCOMP] += specular[i][BCOMP];
1112 #else
1113 GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
1114 GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
1115 GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
1116 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1117 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1118 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1119 #endif
1120 }
1121 }
1122
1123
1124 /**
1125 * This function may modify any of the array values in the span.
1126 * span->interpMask and span->arrayMask may be changed but will be restored
1127 * to their original values before returning.
1128 */
1129 void
1130 _mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
1131 {
1132 const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
1133 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1134 const GLuint origArrayMask = span->arrayMask;
1135
1136 ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
1137 span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
1138 ASSERT(span->end <= MAX_WIDTH);
1139 ASSERT((span->interpMask & span->arrayMask) == 0);
1140 ASSERT(ctx->Texture._EnabledUnits);
1141
1142 /*
1143 printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask);
1144 */
1145
1146 if (span->arrayMask & SPAN_MASK) {
1147 /* mask was initialized by caller, probably glBitmap */
1148 span->writeAll = GL_FALSE;
1149 }
1150 else {
1151 MEMSET(span->mask, 1, span->end);
1152 span->writeAll = GL_TRUE;
1153 }
1154
1155 /* Clipping */
1156 if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
1157 if (!clip_span(ctx, span)) {
1158 return;
1159 }
1160 }
1161
1162 #ifdef DEBUG
1163 if (span->arrayMask & SPAN_XY) {
1164 GLuint i;
1165 for (i = 0; i < span->end; i++) {
1166 if (span->mask[i]) {
1167 assert(span->xArray[i] >= ctx->DrawBuffer->_Xmin);
1168 assert(span->xArray[i] < ctx->DrawBuffer->_Xmax);
1169 assert(span->yArray[i] >= ctx->DrawBuffer->_Ymin);
1170 assert(span->yArray[i] < ctx->DrawBuffer->_Ymax);
1171 }
1172 }
1173 }
1174 #endif
1175
1176 /* Polygon Stippling */
1177 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1178 stipple_polygon_span(ctx, span);
1179 }
1180
1181 /* Need texture coordinates now */
1182 if ((span->interpMask & SPAN_TEXTURE)
1183 && (span->arrayMask & SPAN_TEXTURE) == 0)
1184 interpolate_texcoords(ctx, span);
1185
1186 /* Texture with alpha test */
1187 if (ctx->Color.AlphaEnabled) {
1188
1189 /* Now we need the rgba array, fill it in if needed */
1190 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1191 interpolate_colors(ctx, span);
1192
1193 /* Texturing without alpha is done after depth-testing which
1194 * gives a potential speed-up.
1195 */
1196 _swrast_texture_span( ctx, span );
1197
1198 /* Do the alpha test */
1199 if (!_mesa_alpha_test(ctx, span)) {
1200 span->arrayMask = origArrayMask;
1201 return;
1202 }
1203 }
1204
1205 /* Stencil and Z testing */
1206 if (ctx->Stencil.Enabled || ctx->Depth.Test) {
1207 if (span->interpMask & SPAN_Z)
1208 _mesa_span_interpolate_z(ctx, span);
1209
1210 if (ctx->Stencil.Enabled) {
1211 if (!_mesa_stencil_and_ztest_span(ctx, span)) {
1212 span->arrayMask = origArrayMask;
1213 return;
1214 }
1215 }
1216 else {
1217 ASSERT(ctx->Depth.Test);
1218 ASSERT(span->arrayMask & SPAN_Z);
1219 /* regular depth testing */
1220 if (!_mesa_depth_test_span(ctx, span)) {
1221 span->arrayMask = origArrayMask;
1222 return;
1223 }
1224 }
1225 }
1226
1227 /* if we get here, some fragments passed the depth test */
1228 ctx->OcclusionResult = GL_TRUE;
1229
1230 /* We had to wait until now to check for glColorMask(F,F,F,F) because of
1231 * the occlusion test.
1232 */
1233 if (colorMask == 0x0) {
1234 span->arrayMask = origArrayMask;
1235 return;
1236 }
1237
1238 /* Texture without alpha test */
1239 if (!ctx->Color.AlphaEnabled) {
1240
1241 /* Now we need the rgba array, fill it in if needed */
1242 if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
1243 interpolate_colors(ctx, span);
1244
1245 _swrast_texture_span( ctx, span );
1246 }
1247
1248 ASSERT(span->arrayMask & SPAN_RGBA);
1249
1250 /* Add base and specular colors */
1251 if (ctx->Fog.ColorSumEnabled ||
1252 (ctx->Light.Enabled &&
1253 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1254 if (span->interpMask & SPAN_SPEC) {
1255 interpolate_specular(ctx, span);
1256 }
1257 ASSERT(span->arrayMask & SPAN_SPEC);
1258 add_colors( span->end, span->color.rgba, span->specArray );
1259 }
1260
1261 /* Fog */
1262 if (ctx->Fog.Enabled) {
1263 _mesa_fog_rgba_span(ctx, span);
1264 }
1265
1266 /* Antialias coverage application */
1267 if (span->arrayMask & SPAN_COVERAGE) {
1268 GLchan (*rgba)[4] = span->color.rgba;
1269 GLuint i;
1270 for (i = 0; i < span->end; i++) {
1271 rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * span->coverage[i]);
1272 }
1273 }
1274
1275 if (swrast->_RasterMask & MULTI_DRAW_BIT) {
1276 multi_write_rgba_span(ctx, span);
1277 }
1278 else {
1279 /* normal: write to exactly one buffer */
1280 if (ctx->Color.ColorLogicOpEnabled) {
1281 _mesa_logicop_rgba_span(ctx, span, span->color.rgba);
1282 }
1283 else if (ctx->Color.BlendEnabled) {
1284 _mesa_blend_span(ctx, span, span->color.rgba);
1285 }
1286
1287 if (colorMask != 0xffffffff) {
1288 _mesa_mask_rgba_span(ctx, span, span->color.rgba);
1289 }
1290
1291
1292 if (span->arrayMask & SPAN_XY) {
1293 /* array of pixel coords */
1294 (*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->xArray,
1295 span->yArray, (const GLchan (*)[4]) span->color.rgba, span->mask);
1296 if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
1297 _mesa_write_alpha_pixels(ctx, span->end,
1298 span->xArray, span->yArray,
1299 (const GLchan (*)[4]) span->color.rgba,
1300 span->mask);
1301 }
1302 }
1303 else {
1304 /* horizontal run of pixels */
1305 (*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
1306 (const GLchan (*)[4]) span->color.rgba,
1307 span->writeAll ? NULL : span->mask);
1308 if (swrast->_RasterMask & ALPHABUF_BIT) {
1309 _mesa_write_alpha_span(ctx, span->end, span->x, span->y,
1310 (const GLchan (*)[4]) span->color.rgba,
1311 span->writeAll ? NULL : span->mask);
1312 }
1313 }
1314 }
1315
1316 span->arrayMask = origArrayMask;
1317 }
1318
1319
1320
1321 /**
1322 * Read RGBA pixels from frame buffer. Clipping will be done to prevent
1323 * reading ouside the buffer's boundaries.
1324 */
1325 void
1326 _mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
1327 GLuint n, GLint x, GLint y, GLchan rgba[][4] )
1328 {
1329 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1330 const GLint bufWidth = (GLint) buffer->Width;
1331 const GLint bufHeight = (GLint) buffer->Height;
1332
1333 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1334 /* completely above, below, or right */
1335 /* XXX maybe leave undefined? */
1336 BZERO(rgba, 4 * n * sizeof(GLchan));
1337 }
1338 else {
1339 GLint skip, length;
1340 if (x < 0) {
1341 /* left edge clippping */
1342 skip = -x;
1343 length = (GLint) n - skip;
1344 if (length < 0) {
1345 /* completely left of window */
1346 return;
1347 }
1348 if (length > bufWidth) {
1349 length = bufWidth;
1350 }
1351 }
1352 else if ((GLint) (x + n) > bufWidth) {
1353 /* right edge clipping */
1354 skip = 0;
1355 length = bufWidth - x;
1356 if (length < 0) {
1357 /* completely to right of window */
1358 return;
1359 }
1360 }
1361 else {
1362 /* no clipping */
1363 skip = 0;
1364 length = (GLint) n;
1365 }
1366
1367 (*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
1368 if (buffer->UseSoftwareAlphaBuffers) {
1369 _mesa_read_alpha_span(ctx, length, x + skip, y, rgba + skip);
1370 }
1371 }
1372 }
1373
1374
1375 /**
1376 * Read CI pixels from frame buffer. Clipping will be done to prevent
1377 * reading ouside the buffer's boundaries.
1378 */
1379 void
1380 _mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
1381 GLuint n, GLint x, GLint y, GLuint indx[] )
1382 {
1383 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1384 const GLint bufWidth = (GLint) buffer->Width;
1385 const GLint bufHeight = (GLint) buffer->Height;
1386
1387 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1388 /* completely above, below, or right */
1389 BZERO(indx, n * sizeof(GLuint));
1390 }
1391 else {
1392 GLint skip, length;
1393 if (x < 0) {
1394 /* left edge clippping */
1395 skip = -x;
1396 length = (GLint) n - skip;
1397 if (length < 0) {
1398 /* completely left of window */
1399 return;
1400 }
1401 if (length > bufWidth) {
1402 length = bufWidth;
1403 }
1404 }
1405 else if ((GLint) (x + n) > bufWidth) {
1406 /* right edge clipping */
1407 skip = 0;
1408 length = bufWidth - x;
1409 if (length < 0) {
1410 /* completely to right of window */
1411 return;
1412 }
1413 }
1414 else {
1415 /* no clipping */
1416 skip = 0;
1417 length = (GLint) n;
1418 }
1419
1420 (*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
1421 }
1422 }