086ed0b33d7477dab0af85222d690f110b3b10f2
[mesa.git] / src / mesa / swrast / s_texcombine.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.5
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #include "main/glheader.h"
28 #include "main/context.h"
29 #include "main/colormac.h"
30 #include "main/imports.h"
31 #include "main/pixeltransfer.h"
32 #include "program/prog_instruction.h"
33
34 #include "s_context.h"
35 #include "s_texcombine.h"
36
37
38 /**
39 * Pointer to array of float[4]
40 * This type makes the code below more concise and avoids a lot of casting.
41 */
42 typedef float (*float4_array)[4];
43
44
45 /**
46 * Return array of texels for given unit.
47 */
48 static INLINE float4_array
49 get_texel_array(SWcontext *swrast, GLuint unit)
50 {
51 return (float4_array) (swrast->TexelBuffer + unit * MAX_WIDTH * 4);
52 }
53
54
55
56 /**
57 * Do texture application for:
58 * GL_EXT_texture_env_combine
59 * GL_ARB_texture_env_combine
60 * GL_EXT_texture_env_dot3
61 * GL_ARB_texture_env_dot3
62 * GL_ATI_texture_env_combine3
63 * GL_NV_texture_env_combine4
64 * conventional GL texture env modes
65 *
66 * \param ctx rendering context
67 * \param unit the texture combiner unit
68 * \param n number of fragments to process (span width)
69 * \param primary_rgba incoming fragment color array
70 * \param texelBuffer pointer to texel colors for all texture units
71 *
72 * \param rgba incoming/result fragment colors
73 */
74 static void
75 texture_combine( struct gl_context *ctx, GLuint unit, GLuint n,
76 const float4_array primary_rgba,
77 const GLfloat *texelBuffer,
78 GLchan (*rgbaChan)[4] )
79 {
80 SWcontext *swrast = SWRAST_CONTEXT(ctx);
81 const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
82 const struct gl_tex_env_combine_state *combine = textureUnit->_CurrentCombine;
83 float4_array argRGB[MAX_COMBINER_TERMS];
84 float4_array argA[MAX_COMBINER_TERMS];
85 const GLfloat scaleRGB = (GLfloat) (1 << combine->ScaleShiftRGB);
86 const GLfloat scaleA = (GLfloat) (1 << combine->ScaleShiftA);
87 const GLuint numArgsRGB = combine->_NumArgsRGB;
88 const GLuint numArgsA = combine->_NumArgsA;
89 float4_array ccolor[4], rgba;
90 GLuint i, term;
91
92 /* alloc temp pixel buffers */
93 rgba = (float4_array) malloc(4 * n * sizeof(GLfloat));
94 if (!rgba) {
95 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
96 return;
97 }
98
99 for (i = 0; i < numArgsRGB || i < numArgsA; i++) {
100 ccolor[i] = (float4_array) malloc(4 * n * sizeof(GLfloat));
101 if (!ccolor[i]) {
102 while (i) {
103 free(ccolor[i]);
104 i--;
105 }
106 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
107 return;
108 }
109 }
110
111 for (i = 0; i < n; i++) {
112 rgba[i][RCOMP] = CHAN_TO_FLOAT(rgbaChan[i][RCOMP]);
113 rgba[i][GCOMP] = CHAN_TO_FLOAT(rgbaChan[i][GCOMP]);
114 rgba[i][BCOMP] = CHAN_TO_FLOAT(rgbaChan[i][BCOMP]);
115 rgba[i][ACOMP] = CHAN_TO_FLOAT(rgbaChan[i][ACOMP]);
116 }
117
118 /*
119 printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n",
120 combine->ModeRGB,
121 combine->ModeA,
122 combine->SourceRGB[0],
123 combine->SourceA[0],
124 combine->SourceRGB[1],
125 combine->SourceA[1]);
126 */
127
128 /*
129 * Do operand setup for up to 4 operands. Loop over the terms.
130 */
131 for (term = 0; term < numArgsRGB; term++) {
132 const GLenum srcRGB = combine->SourceRGB[term];
133 const GLenum operandRGB = combine->OperandRGB[term];
134
135 switch (srcRGB) {
136 case GL_TEXTURE:
137 argRGB[term] = get_texel_array(swrast, unit);
138 break;
139 case GL_PRIMARY_COLOR:
140 argRGB[term] = primary_rgba;
141 break;
142 case GL_PREVIOUS:
143 argRGB[term] = rgba;
144 break;
145 case GL_CONSTANT:
146 {
147 float4_array c = ccolor[term];
148 GLfloat red = textureUnit->EnvColor[0];
149 GLfloat green = textureUnit->EnvColor[1];
150 GLfloat blue = textureUnit->EnvColor[2];
151 GLfloat alpha = textureUnit->EnvColor[3];
152 for (i = 0; i < n; i++) {
153 ASSIGN_4V(c[i], red, green, blue, alpha);
154 }
155 argRGB[term] = ccolor[term];
156 }
157 break;
158 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
159 */
160 case GL_ZERO:
161 {
162 float4_array c = ccolor[term];
163 for (i = 0; i < n; i++) {
164 ASSIGN_4V(c[i], 0.0F, 0.0F, 0.0F, 0.0F);
165 }
166 argRGB[term] = ccolor[term];
167 }
168 break;
169 case GL_ONE:
170 {
171 float4_array c = ccolor[term];
172 for (i = 0; i < n; i++) {
173 ASSIGN_4V(c[i], 1.0F, 1.0F, 1.0F, 1.0F);
174 }
175 argRGB[term] = ccolor[term];
176 }
177 break;
178 default:
179 /* ARB_texture_env_crossbar source */
180 {
181 const GLuint srcUnit = srcRGB - GL_TEXTURE0;
182 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
183 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
184 goto end;
185 argRGB[term] = get_texel_array(swrast, srcUnit);
186 }
187 }
188
189 if (operandRGB != GL_SRC_COLOR) {
190 float4_array src = argRGB[term];
191 float4_array dst = ccolor[term];
192
193 /* point to new arg[term] storage */
194 argRGB[term] = ccolor[term];
195
196 switch (operandRGB) {
197 case GL_ONE_MINUS_SRC_COLOR:
198 for (i = 0; i < n; i++) {
199 dst[i][RCOMP] = 1.0F - src[i][RCOMP];
200 dst[i][GCOMP] = 1.0F - src[i][GCOMP];
201 dst[i][BCOMP] = 1.0F - src[i][BCOMP];
202 }
203 break;
204 case GL_SRC_ALPHA:
205 for (i = 0; i < n; i++) {
206 dst[i][RCOMP] =
207 dst[i][GCOMP] =
208 dst[i][BCOMP] = src[i][ACOMP];
209 }
210 break;
211 case GL_ONE_MINUS_SRC_ALPHA:
212 for (i = 0; i < n; i++) {
213 dst[i][RCOMP] =
214 dst[i][GCOMP] =
215 dst[i][BCOMP] = 1.0F - src[i][ACOMP];
216 }
217 break;
218 default:
219 _mesa_problem(ctx, "Bad operandRGB");
220 }
221 }
222 }
223
224 /*
225 * Set up the argA[term] pointers
226 */
227 for (term = 0; term < numArgsA; term++) {
228 const GLenum srcA = combine->SourceA[term];
229 const GLenum operandA = combine->OperandA[term];
230
231 switch (srcA) {
232 case GL_TEXTURE:
233 argA[term] = get_texel_array(swrast, unit);
234 break;
235 case GL_PRIMARY_COLOR:
236 argA[term] = primary_rgba;
237 break;
238 case GL_PREVIOUS:
239 argA[term] = rgba;
240 break;
241 case GL_CONSTANT:
242 {
243 float4_array c = ccolor[term];
244 GLfloat alpha = textureUnit->EnvColor[3];
245 for (i = 0; i < n; i++)
246 c[i][ACOMP] = alpha;
247 argA[term] = ccolor[term];
248 }
249 break;
250 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
251 */
252 case GL_ZERO:
253 {
254 float4_array c = ccolor[term];
255 for (i = 0; i < n; i++)
256 c[i][ACOMP] = 0.0F;
257 argA[term] = ccolor[term];
258 }
259 break;
260 case GL_ONE:
261 {
262 float4_array c = ccolor[term];
263 for (i = 0; i < n; i++)
264 c[i][ACOMP] = 1.0F;
265 argA[term] = ccolor[term];
266 }
267 break;
268 default:
269 /* ARB_texture_env_crossbar source */
270 {
271 const GLuint srcUnit = srcA - GL_TEXTURE0;
272 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
273 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
274 goto end;
275 argA[term] = get_texel_array(swrast, srcUnit);
276 }
277 }
278
279 if (operandA == GL_ONE_MINUS_SRC_ALPHA) {
280 float4_array src = argA[term];
281 float4_array dst = ccolor[term];
282 argA[term] = ccolor[term];
283 for (i = 0; i < n; i++) {
284 dst[i][ACOMP] = 1.0F - src[i][ACOMP];
285 }
286 }
287 }
288
289 /* RGB channel combine */
290 {
291 float4_array arg0 = argRGB[0];
292 float4_array arg1 = argRGB[1];
293 float4_array arg2 = argRGB[2];
294 float4_array arg3 = argRGB[3];
295
296 switch (combine->ModeRGB) {
297 case GL_REPLACE:
298 for (i = 0; i < n; i++) {
299 rgba[i][RCOMP] = arg0[i][RCOMP] * scaleRGB;
300 rgba[i][GCOMP] = arg0[i][GCOMP] * scaleRGB;
301 rgba[i][BCOMP] = arg0[i][BCOMP] * scaleRGB;
302 }
303 break;
304 case GL_MODULATE:
305 for (i = 0; i < n; i++) {
306 rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * scaleRGB;
307 rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * scaleRGB;
308 rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * scaleRGB;
309 }
310 break;
311 case GL_ADD:
312 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
313 /* (a * b) + (c * d) */
314 for (i = 0; i < n; i++) {
315 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] +
316 arg2[i][RCOMP] * arg3[i][RCOMP]) * scaleRGB;
317 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] +
318 arg2[i][GCOMP] * arg3[i][GCOMP]) * scaleRGB;
319 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] +
320 arg2[i][BCOMP] * arg3[i][BCOMP]) * scaleRGB;
321 }
322 }
323 else {
324 /* 2-term addition */
325 for (i = 0; i < n; i++) {
326 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * scaleRGB;
327 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * scaleRGB;
328 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * scaleRGB;
329 }
330 }
331 break;
332 case GL_ADD_SIGNED:
333 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
334 /* (a * b) + (c * d) - 0.5 */
335 for (i = 0; i < n; i++) {
336 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] +
337 arg2[i][RCOMP] * arg3[i][RCOMP] - 0.5F) * scaleRGB;
338 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] +
339 arg2[i][GCOMP] * arg3[i][GCOMP] - 0.5F) * scaleRGB;
340 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] +
341 arg2[i][BCOMP] * arg3[i][BCOMP] - 0.5F) * scaleRGB;
342 }
343 }
344 else {
345 for (i = 0; i < n; i++) {
346 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5F) * scaleRGB;
347 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5F) * scaleRGB;
348 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5F) * scaleRGB;
349 }
350 }
351 break;
352 case GL_INTERPOLATE:
353 for (i = 0; i < n; i++) {
354 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] +
355 arg1[i][RCOMP] * (1.0F - arg2[i][RCOMP])) * scaleRGB;
356 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] +
357 arg1[i][GCOMP] * (1.0F - arg2[i][GCOMP])) * scaleRGB;
358 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] +
359 arg1[i][BCOMP] * (1.0F - arg2[i][BCOMP])) * scaleRGB;
360 }
361 break;
362 case GL_SUBTRACT:
363 for (i = 0; i < n; i++) {
364 rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * scaleRGB;
365 rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * scaleRGB;
366 rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * scaleRGB;
367 }
368 break;
369 case GL_DOT3_RGB_EXT:
370 case GL_DOT3_RGBA_EXT:
371 /* Do not scale the result by 1 2 or 4 */
372 for (i = 0; i < n; i++) {
373 GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) +
374 (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) +
375 (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F))
376 * 4.0F;
377 dot = CLAMP(dot, 0.0F, 1.0F);
378 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot;
379 }
380 break;
381 case GL_DOT3_RGB:
382 case GL_DOT3_RGBA:
383 /* DO scale the result by 1 2 or 4 */
384 for (i = 0; i < n; i++) {
385 GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) +
386 (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) +
387 (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F))
388 * 4.0F * scaleRGB;
389 dot = CLAMP(dot, 0.0F, 1.0F);
390 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot;
391 }
392 break;
393 case GL_MODULATE_ADD_ATI:
394 for (i = 0; i < n; i++) {
395 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) +
396 arg1[i][RCOMP]) * scaleRGB;
397 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) +
398 arg1[i][GCOMP]) * scaleRGB;
399 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) +
400 arg1[i][BCOMP]) * scaleRGB;
401 }
402 break;
403 case GL_MODULATE_SIGNED_ADD_ATI:
404 for (i = 0; i < n; i++) {
405 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) +
406 arg1[i][RCOMP] - 0.5F) * scaleRGB;
407 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) +
408 arg1[i][GCOMP] - 0.5F) * scaleRGB;
409 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) +
410 arg1[i][BCOMP] - 0.5F) * scaleRGB;
411 }
412 break;
413 case GL_MODULATE_SUBTRACT_ATI:
414 for (i = 0; i < n; i++) {
415 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) -
416 arg1[i][RCOMP]) * scaleRGB;
417 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) -
418 arg1[i][GCOMP]) * scaleRGB;
419 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) -
420 arg1[i][BCOMP]) * scaleRGB;
421 }
422 break;
423 case GL_BUMP_ENVMAP_ATI:
424 /* this produces a fixed rgba color, and the coord calc is done elsewhere */
425 for (i = 0; i < n; i++) {
426 /* rgba result is 0,0,0,1 */
427 rgba[i][RCOMP] = 0.0;
428 rgba[i][GCOMP] = 0.0;
429 rgba[i][BCOMP] = 0.0;
430 rgba[i][ACOMP] = 1.0;
431 }
432 goto end; /* no alpha processing */
433 default:
434 _mesa_problem(ctx, "invalid combine mode");
435 }
436 }
437
438 /* Alpha channel combine */
439 {
440 float4_array arg0 = argA[0];
441 float4_array arg1 = argA[1];
442 float4_array arg2 = argA[2];
443 float4_array arg3 = argA[3];
444
445 switch (combine->ModeA) {
446 case GL_REPLACE:
447 for (i = 0; i < n; i++) {
448 rgba[i][ACOMP] = arg0[i][ACOMP] * scaleA;
449 }
450 break;
451 case GL_MODULATE:
452 for (i = 0; i < n; i++) {
453 rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * scaleA;
454 }
455 break;
456 case GL_ADD:
457 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
458 /* (a * b) + (c * d) */
459 for (i = 0; i < n; i++) {
460 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] +
461 arg2[i][ACOMP] * arg3[i][ACOMP]) * scaleA;
462 }
463 }
464 else {
465 /* two-term add */
466 for (i = 0; i < n; i++) {
467 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * scaleA;
468 }
469 }
470 break;
471 case GL_ADD_SIGNED:
472 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
473 /* (a * b) + (c * d) - 0.5 */
474 for (i = 0; i < n; i++) {
475 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] +
476 arg2[i][ACOMP] * arg3[i][ACOMP] -
477 0.5F) * scaleA;
478 }
479 }
480 else {
481 /* a + b - 0.5 */
482 for (i = 0; i < n; i++) {
483 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * scaleA;
484 }
485 }
486 break;
487 case GL_INTERPOLATE:
488 for (i = 0; i < n; i++) {
489 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] +
490 arg1[i][ACOMP] * (1.0F - arg2[i][ACOMP]))
491 * scaleA;
492 }
493 break;
494 case GL_SUBTRACT:
495 for (i = 0; i < n; i++) {
496 rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * scaleA;
497 }
498 break;
499 case GL_MODULATE_ADD_ATI:
500 for (i = 0; i < n; i++) {
501 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP])
502 + arg1[i][ACOMP]) * scaleA;
503 }
504 break;
505 case GL_MODULATE_SIGNED_ADD_ATI:
506 for (i = 0; i < n; i++) {
507 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) +
508 arg1[i][ACOMP] - 0.5F) * scaleA;
509 }
510 break;
511 case GL_MODULATE_SUBTRACT_ATI:
512 for (i = 0; i < n; i++) {
513 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP])
514 - arg1[i][ACOMP]) * scaleA;
515 }
516 break;
517 default:
518 _mesa_problem(ctx, "invalid combine mode");
519 }
520 }
521
522 /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
523 * This is kind of a kludge. It would have been better if the spec
524 * were written such that the GL_COMBINE_ALPHA value could be set to
525 * GL_DOT3.
526 */
527 if (combine->ModeRGB == GL_DOT3_RGBA_EXT ||
528 combine->ModeRGB == GL_DOT3_RGBA) {
529 for (i = 0; i < n; i++) {
530 rgba[i][ACOMP] = rgba[i][RCOMP];
531 }
532 }
533
534 for (i = 0; i < n; i++) {
535 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][RCOMP], rgba[i][RCOMP]);
536 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][GCOMP], rgba[i][GCOMP]);
537 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][BCOMP], rgba[i][BCOMP]);
538 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][ACOMP], rgba[i][ACOMP]);
539 }
540
541 end:
542 for (i = 0; i < numArgsRGB || i < numArgsA; i++) {
543 free(ccolor[i]);
544 }
545 free(rgba);
546 }
547
548
549 /**
550 * Apply X/Y/Z/W/0/1 swizzle to an array of colors/texels.
551 * See GL_EXT_texture_swizzle.
552 */
553 static void
554 swizzle_texels(GLuint swizzle, GLuint count, float4_array texels)
555 {
556 const GLuint swzR = GET_SWZ(swizzle, 0);
557 const GLuint swzG = GET_SWZ(swizzle, 1);
558 const GLuint swzB = GET_SWZ(swizzle, 2);
559 const GLuint swzA = GET_SWZ(swizzle, 3);
560 GLfloat vector[6];
561 GLuint i;
562
563 vector[SWIZZLE_ZERO] = 0;
564 vector[SWIZZLE_ONE] = 1.0F;
565
566 for (i = 0; i < count; i++) {
567 vector[SWIZZLE_X] = texels[i][0];
568 vector[SWIZZLE_Y] = texels[i][1];
569 vector[SWIZZLE_Z] = texels[i][2];
570 vector[SWIZZLE_W] = texels[i][3];
571 texels[i][RCOMP] = vector[swzR];
572 texels[i][GCOMP] = vector[swzG];
573 texels[i][BCOMP] = vector[swzB];
574 texels[i][ACOMP] = vector[swzA];
575 }
576 }
577
578
579 /**
580 * Apply texture mapping to a span of fragments.
581 */
582 void
583 _swrast_texture_span( struct gl_context *ctx, SWspan *span )
584 {
585 SWcontext *swrast = SWRAST_CONTEXT(ctx);
586 float4_array primary_rgba;
587 GLuint unit;
588
589 primary_rgba = (float4_array) malloc(span->end * 4 * sizeof(GLfloat));
590
591 if (!primary_rgba) {
592 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span");
593 return;
594 }
595
596 ASSERT(span->end <= MAX_WIDTH);
597
598 /*
599 * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
600 */
601 if (swrast->_TextureCombinePrimary) {
602 GLuint i;
603 for (i = 0; i < span->end; i++) {
604 primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]);
605 primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]);
606 primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]);
607 primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]);
608 }
609 }
610
611 /* First must sample all bump maps */
612 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
613 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
614
615 if (texUnit->_ReallyEnabled &&
616 texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) {
617 const GLfloat (*texcoords)[4] = (const GLfloat (*)[4])
618 span->array->attribs[FRAG_ATTRIB_TEX0 + unit];
619 float4_array targetcoords =
620 span->array->attribs[FRAG_ATTRIB_TEX0 +
621 ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0];
622
623 const struct gl_texture_object *curObj = texUnit->_Current;
624 GLfloat *lambda = span->array->lambda[unit];
625 float4_array texels = get_texel_array(swrast, unit);
626 GLuint i;
627 GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0];
628 GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1];
629 GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2];
630 GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3];
631
632 /* adjust texture lod (lambda) */
633 if (span->arrayMask & SPAN_LAMBDA) {
634 if (texUnit->LodBias + curObj->Sampler.LodBias != 0.0F) {
635 /* apply LOD bias, but don't clamp yet */
636 const GLfloat bias = CLAMP(texUnit->LodBias + curObj->Sampler.LodBias,
637 -ctx->Const.MaxTextureLodBias,
638 ctx->Const.MaxTextureLodBias);
639 GLuint i;
640 for (i = 0; i < span->end; i++) {
641 lambda[i] += bias;
642 }
643 }
644
645 if (curObj->Sampler.MinLod != -1000.0 ||
646 curObj->Sampler.MaxLod != 1000.0) {
647 /* apply LOD clamping to lambda */
648 const GLfloat min = curObj->Sampler.MinLod;
649 const GLfloat max = curObj->Sampler.MaxLod;
650 GLuint i;
651 for (i = 0; i < span->end; i++) {
652 GLfloat l = lambda[i];
653 lambda[i] = CLAMP(l, min, max);
654 }
655 }
656 }
657
658 /* Sample the texture (span->end = number of fragments) */
659 swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end,
660 texcoords, lambda, texels );
661
662 /* manipulate the span values of the bump target
663 not sure this can work correctly even ignoring
664 the problem that channel is unsigned */
665 for (i = 0; i < span->end; i++) {
666 targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] *
667 rotMatrix01) / targetcoords[i][3];
668 targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] *
669 rotMatrix11) / targetcoords[i][3];
670 }
671 }
672 }
673
674 /*
675 * Must do all texture sampling before combining in order to
676 * accomodate GL_ARB_texture_env_crossbar.
677 */
678 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
679 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
680 if (texUnit->_ReallyEnabled &&
681 texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) {
682 const GLfloat (*texcoords)[4] = (const GLfloat (*)[4])
683 span->array->attribs[FRAG_ATTRIB_TEX0 + unit];
684 const struct gl_texture_object *curObj = texUnit->_Current;
685 GLfloat *lambda = span->array->lambda[unit];
686 float4_array texels = get_texel_array(swrast, unit);
687
688 /* adjust texture lod (lambda) */
689 if (span->arrayMask & SPAN_LAMBDA) {
690 if (texUnit->LodBias + curObj->Sampler.LodBias != 0.0F) {
691 /* apply LOD bias, but don't clamp yet */
692 const GLfloat bias = CLAMP(texUnit->LodBias + curObj->Sampler.LodBias,
693 -ctx->Const.MaxTextureLodBias,
694 ctx->Const.MaxTextureLodBias);
695 GLuint i;
696 for (i = 0; i < span->end; i++) {
697 lambda[i] += bias;
698 }
699 }
700
701 if (curObj->Sampler.MinLod != -1000.0 ||
702 curObj->Sampler.MaxLod != 1000.0) {
703 /* apply LOD clamping to lambda */
704 const GLfloat min = curObj->Sampler.MinLod;
705 const GLfloat max = curObj->Sampler.MaxLod;
706 GLuint i;
707 for (i = 0; i < span->end; i++) {
708 GLfloat l = lambda[i];
709 lambda[i] = CLAMP(l, min, max);
710 }
711 }
712 }
713 else if (curObj->Sampler.MaxAnisotropy > 1.0 &&
714 curObj->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
715 /* sample_lambda_2d_aniso is beeing used as texture_sample_func,
716 * it requires the current SWspan *span as an additional parameter.
717 * In order to keep the same function signature, the unused lambda
718 * parameter will be modified to actually contain the SWspan pointer.
719 * This is a Hack. To make it right, the texture_sample_func
720 * signature and all implementing functions need to be modified.
721 */
722 /* "hide" SWspan struct; cast to (GLfloat *) to suppress warning */
723 lambda = (GLfloat *)span;
724 }
725
726 /* Sample the texture (span->end = number of fragments) */
727 swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end,
728 texcoords, lambda, texels );
729
730 /* GL_EXT_texture_swizzle */
731 if (curObj->_Swizzle != SWIZZLE_NOOP) {
732 swizzle_texels(curObj->_Swizzle, span->end, texels);
733 }
734 }
735 }
736
737 /*
738 * OK, now apply the texture (aka texture combine/blend).
739 * We modify the span->color.rgba values.
740 */
741 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
742 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
743 texture_combine( ctx, unit, span->end,
744 primary_rgba,
745 swrast->TexelBuffer,
746 span->array->rgba );
747 }
748 }
749
750 free(primary_rgba);
751 }