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