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