Arachnoid GLESv1.1 plugin. Compile and run (a bit glitchy and no frameskip) on the...
[mupen64plus-pandora.git] / source / mupen64plus-video-arachnoid / src / Combiner / AdvancedTexEnvCombiner.cpp
1 /******************************************************************************
2  * Arachnoid Graphics Plugin for Mupen64Plus
3  * http://bitbucket.org/wahrhaft/mupen64plus-video-arachnoid/
4  *
5  * Copyright (C) 2007 Kristofer Karlsson, Rickard Niklasson
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *****************************************************************************/
21
22 #include <algorithm>
23 using std::max;
24 #include "AdvancedTexEnvCombiner.h"
25 #include "CombinerStructs.h"
26 #include "MultiTexturingExt.h"    //glActiveTextureARB
27 #include "ExtensionChecker.h"
28
29 #ifndef GL_ATI_texture_env_combine3
30 #define GL_ATI_texture_env_combine3
31     #define GL_ATI_texture_env_combine3
32     #define GL_MODULATE_ADD_ATI                             0x8744
33     #define GL_MODULATE_SIGNED_ADD_ATI                      0x8745
34     #define GL_MODULATE_SUBTRACT_ATI                        0x8746
35 #endif //GL_ATI_texture_env_combine3 
36
37 #ifndef GL_ATIX_texture_env_route
38 #define GL_ATIX_texture_env_route 1
39     #define GL_SECONDARY_COLOR_ATIX                 0x8747
40     #define GL_TEXTURE_OUTPUT_RGB_ATIX              0x8748
41     #define GL_TEXTURE_OUTPUT_ALPHA_ATIX            0x8749
42 #endif // GL_ATIX_texture_env_route 
43
44 static TexEnvCombinerArg TexEnvArgs[] =
45 {
46     // CMB
47     { GL_PREVIOUS_ARB,       GL_SRC_COLOR },
48     // T0
49     { GL_TEXTURE,            GL_SRC_COLOR },
50     // T1
51     { GL_TEXTURE,            GL_SRC_COLOR },
52     // PRIM
53     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
54     // SHADE
55     { GL_PRIMARY_COLOR_ARB,  GL_SRC_COLOR },
56     // ENV
57     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
58     // CENTER
59     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
60     // SCALE
61     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
62     // CMBALPHA
63     { GL_PREVIOUS_ARB,       GL_SRC_ALPHA },
64     // T0ALPHA
65     { GL_TEXTURE,            GL_SRC_ALPHA },
66     // T1ALPHA
67     { GL_TEXTURE,            GL_SRC_ALPHA },
68     // PRIMALPHA
69     { GL_CONSTANT_ARB,       GL_SRC_ALPHA },
70     // SHADEALPHA
71     { GL_PRIMARY_COLOR_ARB,  GL_SRC_ALPHA },
72     // ENVALPHA
73     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
74     // LODFRAC
75     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
76     // PRIMLODFRAC
77     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
78     // NOISE
79     { GL_TEXTURE,            GL_SRC_COLOR },
80     // K4
81     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
82     // K5
83     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
84     // ONE
85     { GL_CONSTANT_ARB,       GL_SRC_COLOR },
86     // ZERO
87     { GL_CONSTANT_ARB,       GL_SRC_COLOR }
88 };
89
90 //-----------------------------------------------------------------------------
91 //! Constructor
92 //-----------------------------------------------------------------------------
93 AdvancedTexEnvCombiner::AdvancedTexEnvCombiner()
94 {
95 }
96
97 //-----------------------------------------------------------------------------
98 //! Destructor
99 //-----------------------------------------------------------------------------
100 AdvancedTexEnvCombiner::~AdvancedTexEnvCombiner()
101 {
102 }
103
104 //-----------------------------------------------------------------------------
105 //* Initialize
106 //! Checks if extensions are supported
107 //-----------------------------------------------------------------------------
108 void AdvancedTexEnvCombiner::initialize()
109 {
110 #ifdef HAVE_GLES
111     ARB_texture_env_combine  = true;
112     ARB_texture_env_crossbar = true;
113 #else
114     ARB_texture_env_combine  = isExtensionSupported( "GL_ARB_texture_env_combine" );
115     ARB_texture_env_crossbar = isExtensionSupported( "GL_ARB_texture_env_crossbar" );
116 #endif
117     ATI_texture_env_combine3 = isExtensionSupported( "GL_ATI_texture_env_combine3" );
118     ATIX_texture_env_route   = isExtensionSupported( "GL_ATIX_texture_env_route" );
119     NV_texture_env_combine4  = isExtensionSupported( "GL_NV_texture_env_combine4" );;
120
121     if ( ARB_texture_env_crossbar || NV_texture_env_combine4 || ATIX_texture_env_route )
122     {
123         TexEnvArgs[TEXEL0].source       = GL_TEXTURE0_ARB;
124         TexEnvArgs[TEXEL0_ALPHA].source = GL_TEXTURE0_ARB;
125         TexEnvArgs[TEXEL1].source       = GL_TEXTURE1_ARB;
126         TexEnvArgs[TEXEL1_ALPHA].source = GL_TEXTURE1_ARB;
127     }
128
129     if ( ATI_texture_env_combine3 )
130     {
131         TexEnvArgs[ONE].source  = GL_ONE;
132         TexEnvArgs[ZERO].source = GL_ZERO;
133     }
134 }
135
136 //-----------------------------------------------------------------------------
137 //* Begin Texture Update
138 //! Disables all textures
139 //-----------------------------------------------------------------------------
140 void AdvancedTexEnvCombiner::beginTextureUpdate()
141 {
142     const int openGLMaxTextureUnits = 8;
143
144     //Disable all texture channels
145     for (int i = 0; i <openGLMaxTextureUnits; i++)
146     {
147         glActiveTextureARB(GL_TEXTURE0_ARB + i);
148         glDisable(GL_TEXTURE_2D );
149     }
150 }
151
152
153 //-----------------------------------------------------------------------------
154 //* End Texture Update
155 //! Enables selected textures in a texture environment
156 //! @param texEnv Texture environment with textures to be enabled
157 //-----------------------------------------------------------------------------
158 void AdvancedTexEnvCombiner::endTextureUpdate(TexEnvCombiner* texEnv)
159 {  
160     //Enable texturing
161     for (int i = 0; i <texEnv->usedUnits; i++)
162     {
163         glActiveTextureARB( GL_TEXTURE0_ARB + i );
164         glEnable( GL_TEXTURE_2D );
165     }
166 }
167
168 //-----------------------------------------------------------------------------
169 //* Set Texture Enviroment Colors
170 //! Sets texture enviorment colors for all active textures
171 //! @param texEnv Texture environment with textures that will be assigned colors
172 //-----------------------------------------------------------------------------
173 void AdvancedTexEnvCombiner::setTextureEnviromentColors(TexEnvCombiner* texEnv)
174 {
175     float color[4];
176
177     int openGLMaxTextureUnits = 8;
178
179     for (int i = 0; i < openGLMaxTextureUnits; i++)
180     {
181         this->getCombinerColor( color, texEnv->color[i].constant, texEnv->alpha[i].constant );
182
183         glActiveTextureARB(GL_TEXTURE0_ARB + i);
184         glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &color[0]);
185     }
186 }
187
188 //-----------------------------------------------------------------------------
189 //* Set Texture Enviroment
190 //! Sets texture environment for all active textures
191 //! @param texEnv Texture environment with input data which will be 
192 //!               sent to OpenGL using function "glTexEnvi" using ARB extensions
193 //-----------------------------------------------------------------------------
194 void AdvancedTexEnvCombiner::setTextureEnviroment(TexEnvCombiner* texEnv)
195 {
196     const int openGLMaxTextureUnits = 8;
197
198     for (int i=0; i<openGLMaxTextureUnits; ++i)
199     {
200         glActiveTextureARB(GL_TEXTURE0_ARB + i);
201
202         if ( (i < texEnv->usedUnits ) || (i < 2 && texEnv->usesT1) )
203         {
204             glEnable( GL_TEXTURE_2D );
205             glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,   GL_COMBINE_ARB );
206             glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB,    texEnv->color[i].combine );
207             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB,    texEnv->color[i].arg0.source );
208             glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB,   texEnv->color[i].arg0.operand );
209             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB,    texEnv->color[i].arg1.source );
210             glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB,   texEnv->color[i].arg1.operand );
211             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB,    texEnv->color[i].arg2.source );
212             glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB,   texEnv->color[i].arg2.operand );
213             glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB,  texEnv->alpha[i].combine );
214             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB,  texEnv->alpha[i].arg0.source );
215             glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, texEnv->alpha[i].arg0.operand );
216             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB,  texEnv->alpha[i].arg1.source );
217             glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, texEnv->alpha[i].arg1.operand );
218             glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB,  texEnv->alpha[i].arg2.source );
219             glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, texEnv->alpha[i].arg2.operand );
220         }
221         else
222         {
223             glDisable(GL_TEXTURE_2D);
224         }            
225     }
226 }
227
228 //-----------------------------------------------------------------------------
229 //* Create New Texture Enviornment
230 //! Allocates a new texture enviroment
231 //! @param[in] colorCombiner How to combine and get a color
232 //! @param[in] alphaCombiner How to combine and get an alpha value
233 //! @return The texture enviroment that was created
234 //-----------------------------------------------------------------------------
235 TexEnvCombiner* AdvancedTexEnvCombiner::createNewTextureEnviroment(Combiner* colorCombiner, Combiner *alphaCombiner)
236 {
237     TexEnvCombiner* envCombiner = new TexEnvCombiner();
238
239     int curUnit;
240
241     const int openGLMaxTextureUnits = 8;
242
243     //For each texture unit
244     for (int i = 0; i < openGLMaxTextureUnits; i++)
245     {
246         envCombiner->color[i].combine = GL_REPLACE;
247         envCombiner->alpha[i].combine = GL_REPLACE;
248
249         SetColorCombinerValues( i, arg0, GL_PREVIOUS_ARB, GL_SRC_COLOR );
250         SetColorCombinerValues( i, arg1, GL_PREVIOUS_ARB, GL_SRC_COLOR );
251         SetColorCombinerValues( i, arg2, GL_PREVIOUS_ARB, GL_SRC_COLOR );
252         envCombiner->color[i].constant = COMBINED;
253         envCombiner->color[i].outputTexture = GL_TEXTURE0_ARB + i;
254
255         SetAlphaCombinerValues( i, arg0, GL_PREVIOUS_ARB, GL_SRC_ALPHA );
256         SetAlphaCombinerValues( i, arg1, GL_PREVIOUS_ARB, GL_SRC_ALPHA );
257         SetAlphaCombinerValues( i, arg2, GL_PREVIOUS_ARB, GL_SRC_ALPHA );
258         envCombiner->alpha[i].constant = COMBINED;
259         envCombiner->alpha[i].outputTexture = GL_TEXTURE0_ARB + i;
260     }
261
262     envCombiner->usesT0 = false;
263     envCombiner->usesT1 = false;
264
265     envCombiner->vertex.color = COMBINED;
266     envCombiner->vertex.secondaryColor = COMBINED;
267     envCombiner->vertex.alpha = COMBINED;
268
269     curUnit = 0;
270
271     for (int i=0; i<alphaCombiner->numStages; i++)
272     {
273         for (int j = 0; j < alphaCombiner->stage[i].numOps; j++)
274         {
275             float sb = 0.0f;
276
277             if (alphaCombiner->stage[i].op[j].param1 == PRIMITIVE_ALPHA)
278                 sb = m_primColor[3];
279             else if (alphaCombiner->stage[i].op[j].param1 == ENV_ALPHA)
280                 sb = m_envColor[3];
281             else if (alphaCombiner->stage[i].op[j].param1 == ONE)
282                 sb = 1.0f;
283
284             if (((alphaCombiner->stage[i].numOps - j) >= 3) &&
285                 (alphaCombiner->stage[i].op[j].op == SUB) &&
286                 (alphaCombiner->stage[i].op[j+1].op == MUL) &&
287                 (alphaCombiner->stage[i].op[j+2].op == ADD) &&
288                 (sb > 0.5f) && 
289                 (ARB_texture_env_combine))
290             {
291                 envCombiner->usesT0 |= alphaCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA;
292                 envCombiner->usesT1 |= alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA;
293
294                 if (alphaCombiner->stage[i].op[j].param1 == ONE)
295                 {
296                     SetAlphaCombinerValues( curUnit, arg0, envCombiner->alpha[curUnit].arg0.source, GL_ONE_MINUS_SRC_ALPHA );
297                 }
298                 else
299                 {
300                     envCombiner->alpha[curUnit].combine = GL_SUBTRACT_ARB;
301                     SetAlphaCombinerValues( curUnit, arg1, envCombiner->alpha[curUnit].arg0.source, GL_SRC_ALPHA );
302                     SetAlphaCombinerArg( curUnit, arg0, alphaCombiner->stage[i].op[j].param1 );
303
304                     curUnit++;
305                 }
306
307                 j++;
308
309                 envCombiner->usesT0 |= alphaCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA;
310                 envCombiner->usesT1 |= alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA;
311
312                 envCombiner->alpha[curUnit].combine = GL_MODULATE;
313                 SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param1 );
314
315                 curUnit++;
316                 j++;
317
318                 envCombiner->usesT0 |= alphaCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA;
319                 envCombiner->usesT1 |= alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA;
320
321                 envCombiner->alpha[curUnit].combine = GL_SUBTRACT_ARB;
322                 SetAlphaCombinerArg( curUnit, arg0, alphaCombiner->stage[i].op[j].param1 );
323
324                 curUnit++;
325             }
326             else
327             {
328                 envCombiner->usesT0 |= alphaCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA;
329                 envCombiner->usesT1 |= alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA;
330
331                 switch (alphaCombiner->stage[i].op[j].op)
332                 {
333                     case LOAD:
334                         if (!(ARB_texture_env_crossbar || NV_texture_env_combine4) &&
335                             (alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA) && (curUnit == 0))
336                             curUnit++;
337
338                         envCombiner->alpha[curUnit].combine = GL_REPLACE;
339
340                         SetAlphaCombinerArg( curUnit, arg0, alphaCombiner->stage[i].op[j].param1 );
341                         break;
342                     case SUB:
343                         if (!ARB_texture_env_combine)
344                             break;
345
346                         if (!(ARB_texture_env_crossbar || NV_texture_env_combine4) &&
347                             (alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA) && (curUnit == 0))
348                             curUnit++;
349
350                         if ((j > 0) && (alphaCombiner->stage[i].op[j-1].op == LOAD) && (alphaCombiner->stage[i].op[j-1].param1 == ONE))
351                         {
352                             SetAlphaCombinerArg( curUnit, arg0, alphaCombiner->stage[i].op[j].param1 );
353                             envCombiner->alpha[curUnit].arg0.operand = GL_ONE_MINUS_SRC_ALPHA;
354                         }
355                         else if ((ATI_texture_env_combine3) && (curUnit > 0) && (envCombiner->alpha[curUnit - 1].combine == GL_MODULATE))
356                         {
357                             curUnit--;
358                             SetAlphaCombinerValues( curUnit, arg2, envCombiner->alpha[curUnit].arg1.source, envCombiner->alpha[curUnit].arg1.operand );
359                             envCombiner->alpha[curUnit].combine = GL_MODULATE_SUBTRACT_ATI;
360                             SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param1 );
361                             curUnit++;
362                         }
363                         else
364                         {
365                             envCombiner->alpha[curUnit].combine = GL_SUBTRACT_ARB;
366                             SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param1 );
367                             curUnit++;
368                         }
369                         break;
370                     case MUL:
371                         if (!( ARB_texture_env_crossbar ||  NV_texture_env_combine4) &&
372                             (alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA) && (curUnit == 0))
373                             curUnit++;
374
375                         envCombiner->alpha[curUnit].combine = GL_MODULATE;
376
377                         SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param1 );
378                         curUnit++;
379                         break;
380                     case ADD:
381                         if (!(ARB_texture_env_crossbar || NV_texture_env_combine4) &&
382                             (alphaCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA) && (curUnit == 0))
383                             curUnit++;
384
385                         if ((ATI_texture_env_combine3) && (curUnit > 0) && (envCombiner->alpha[curUnit - 1].combine == GL_MODULATE))
386                         {
387                             curUnit--;
388                             SetAlphaCombinerValues( curUnit, arg2, envCombiner->alpha[curUnit].arg1.source, envCombiner->alpha[curUnit].arg1.operand );
389                             envCombiner->alpha[curUnit].combine = GL_MODULATE_ADD_ATI;
390                             SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param1 );
391                         }
392                         else
393                         {
394                             envCombiner->alpha[curUnit].combine = GL_ADD;
395                             SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param1 );
396                         }
397                         curUnit++;
398                         break;
399                     case INTERPOLATE:
400                         envCombiner->usesT0 |= (alphaCombiner->stage[i].op[j].param2 == TEXEL0_ALPHA) || (alphaCombiner->stage[i].op[j].param3 == TEXEL0_ALPHA);
401                         envCombiner->usesT1 |= (alphaCombiner->stage[i].op[j].param2 == TEXEL1_ALPHA) || (alphaCombiner->stage[i].op[j].param3 == TEXEL1_ALPHA);
402
403                         envCombiner->alpha[curUnit].combine = GL_INTERPOLATE_ARB;
404
405                         SetAlphaCombinerArg( curUnit, arg0, alphaCombiner->stage[i].op[j].param1 );
406                         SetAlphaCombinerArg( curUnit, arg1, alphaCombiner->stage[i].op[j].param2 );
407                         SetAlphaCombinerArg( curUnit, arg2, alphaCombiner->stage[i].op[j].param3 );
408
409                         curUnit++;
410                         break;
411                 }
412             }
413         }
414     }
415
416     envCombiner->usedUnits = max( curUnit, 1 );
417
418     curUnit = 0;
419     for (int i = 0; i < colorCombiner->numStages; i++)
420     {
421         for (int j = 0; j < colorCombiner->stage[i].numOps; j++)
422         {
423             float sb = 0.0f;
424
425             if (colorCombiner->stage[i].op[j].param1 == PRIMITIVE)
426                 sb = (m_primColor[0] + m_primColor[2] + m_primColor[1]) / 3.0f;
427             else if (colorCombiner->stage[i].op[j].param1 == ENVIRONMENT)
428                 sb = (m_envColor[0] + m_envColor[2] + m_envColor[1]) / 3.0f;
429
430             // This helps with problems caused by not using signed values between texture units
431             if (((colorCombiner->stage[i].numOps - j) >= 3) &&
432                 (colorCombiner->stage[i].op[j].op == SUB) &&
433                 (colorCombiner->stage[i].op[j+1].op == MUL) &&
434                 (colorCombiner->stage[i].op[j+2].op == ADD) &&
435                 (sb > 0.5f) && 
436                 (ARB_texture_env_combine))
437             {
438                 envCombiner->usesT0 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL0) || (colorCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA));
439                 envCombiner->usesT1 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA));
440
441                 envCombiner->color[curUnit].combine = GL_SUBTRACT_ARB;
442                 SetColorCombinerValues( curUnit, arg1, envCombiner->color[curUnit].arg0.source, envCombiner->color[curUnit].arg0.operand );
443                 SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param1 );
444
445                 curUnit++;
446                 j++;
447
448                 envCombiner->usesT0 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL0) || (colorCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA));
449                 envCombiner->usesT1 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA));
450
451                 envCombiner->color[curUnit].combine = GL_MODULATE;
452                 SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param1 );
453
454                 curUnit++;
455                 j++;
456
457                 envCombiner->usesT0 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL0) || (colorCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA));
458                 envCombiner->usesT1 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA));
459
460                 envCombiner->color[curUnit].combine = GL_SUBTRACT_ARB;
461                 SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param1 );
462
463                 curUnit++;
464             }
465             else
466             {
467                 envCombiner->usesT0 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL0) || (colorCombiner->stage[i].op[j].param1 == TEXEL0_ALPHA));
468                 envCombiner->usesT1 |= ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA));
469
470                 switch (colorCombiner->stage[i].op[j].op)
471                 {
472                     case LOAD:
473                         if (!( ARB_texture_env_crossbar ||  NV_texture_env_combine4) &&
474                             ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA)) && (curUnit == 0))
475                             curUnit++;
476
477                         envCombiner->color[curUnit].combine = GL_REPLACE;
478
479                         SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param1 );
480                         break;
481                     case SUB:
482                         if (!ARB_texture_env_combine)
483                             break;
484
485                         if (!(ARB_texture_env_crossbar ||  NV_texture_env_combine4) &&
486                             ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA)) && (curUnit == 0))
487                             curUnit++;
488
489                         if ((j > 0) && (colorCombiner->stage[i].op[j-1].op == LOAD) && (colorCombiner->stage[i].op[j-1].param1 == ONE))
490                         {
491                             SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param1 );
492                             envCombiner->color[curUnit].arg0.operand = GL_ONE_MINUS_SRC_COLOR;
493                         }
494                         else if (( ATI_texture_env_combine3) && (curUnit > 0) && (envCombiner->color[curUnit - 1].combine == GL_MODULATE))
495                         {
496                             curUnit--;
497                             SetColorCombinerValues( curUnit, arg2, envCombiner->color[curUnit].arg1.source, envCombiner->color[curUnit].arg1.operand );
498                             envCombiner->color[curUnit].combine = GL_MODULATE_SUBTRACT_ATI;
499                             SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param1 );
500                             curUnit++;
501                         }
502                         else
503                         {
504                             envCombiner->color[curUnit].combine = GL_SUBTRACT_ARB;
505                             SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param1 );
506                             curUnit++;
507                         }
508                         break;
509                     case MUL:
510                         if (!( ARB_texture_env_crossbar ||  NV_texture_env_combine4) &&
511                             ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA)) && (curUnit == 0))
512                             curUnit++;
513
514                         envCombiner->color[curUnit].combine = GL_MODULATE;
515
516                         SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param1 );
517                         curUnit++;
518                         break;
519                     case ADD:
520                         if (!( ARB_texture_env_crossbar ||  NV_texture_env_combine4) &&
521                             ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param1 == TEXEL1_ALPHA)) && (curUnit == 0))
522                             curUnit++;
523
524                         // ATI_texture_env_combine3 adds GL_MODULATE_ADD_ATI; saves texture units
525                         if (( ATI_texture_env_combine3) && (curUnit > 0) && (envCombiner->color[curUnit - 1].combine == GL_MODULATE))
526                         {
527                             curUnit--;
528                             SetColorCombinerValues( curUnit, arg2, envCombiner->color[curUnit].arg1.source, envCombiner->color[curUnit].arg1.operand );
529                             envCombiner->color[curUnit].combine = GL_MODULATE_ADD_ATI;
530                             SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param1 );
531                         }
532                         else
533                         {
534                             envCombiner->color[curUnit].combine = GL_ADD;
535                             SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param1 );
536                         }
537                         curUnit++;
538                         break;
539                     case INTERPOLATE:
540                         envCombiner->usesT0 |= (colorCombiner->stage[i].op[j].param2 == TEXEL0) || (colorCombiner->stage[i].op[j].param3 == TEXEL0) || (colorCombiner->stage[i].op[j].param3 == TEXEL0_ALPHA);
541                         envCombiner->usesT1 |= (colorCombiner->stage[i].op[j].param2 == TEXEL1) || (colorCombiner->stage[i].op[j].param3 == TEXEL1) || (colorCombiner->stage[i].op[j].param3 == TEXEL1_ALPHA);
542
543                         if (!( ARB_texture_env_crossbar ||  NV_texture_env_combine4) &&
544                             ((colorCombiner->stage[i].op[j].param1 == TEXEL1) || (colorCombiner->stage[i].op[j].param2 == TEXEL1) || (colorCombiner->stage[i].op[j].param3 == TEXEL1) || (colorCombiner->stage[i].op[j].param3 == TEXEL1_ALPHA)) && (curUnit == 0))
545                         {
546                             if (colorCombiner->stage[i].op[j].param1 == TEXEL0)
547                             {
548                                 envCombiner->color[curUnit].combine = GL_REPLACE;
549                                 SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param1 );
550                                 colorCombiner->stage[i].op[j].param1 = COMBINED;
551                             }
552                             if (colorCombiner->stage[i].op[j].param2 == TEXEL0)
553                             {
554                                 envCombiner->color[curUnit].combine = GL_REPLACE;
555                                 SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param2 )
556
557                                 colorCombiner->stage[i].op[j].param2 = COMBINED;
558                             }
559                             if (colorCombiner->stage[i].op[j].param3 == TEXEL0)
560                             {
561                                 envCombiner->color[curUnit].combine = GL_REPLACE;
562                                 SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param3 );
563                                 colorCombiner->stage[i].op[j].param3 = COMBINED;
564                             }
565                             if (colorCombiner->stage[i].op[j].param3 == TEXEL0_ALPHA)
566                             {
567                                 envCombiner->color[curUnit].combine = GL_REPLACE;
568                                 SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param3 );
569                                 colorCombiner->stage[i].op[j].param3 = COMBINED_ALPHA;
570                             }
571
572                             curUnit++;
573                         }
574
575                         envCombiner->color[curUnit].combine = GL_INTERPOLATE_ARB;
576
577                         SetColorCombinerArg( curUnit, arg0, colorCombiner->stage[i].op[j].param1 );
578                         SetColorCombinerArg( curUnit, arg1, colorCombiner->stage[i].op[j].param2 );
579                         SetColorCombinerArg( curUnit, arg2, colorCombiner->stage[i].op[j].param3 );
580
581                         curUnit++;
582                         break;
583                 }
584             }
585         }
586     }
587
588     envCombiner->usedUnits = max( (unsigned short)curUnit, envCombiner->usedUnits );
589     return envCombiner;
590 }