1 #include "rc1.0_general.h"
2 #include "nvparse_errors.h"
3 #include "nvparse_externs.h"
4 #include <stdio.h>
5 
Validate(int numConsts,ConstColorStruct * pcc)6 void GeneralCombinersStruct::Validate(int numConsts, ConstColorStruct *pcc)
7 {
8 	GLint maxGCs;
9 	glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &maxGCs);
10 	if (num > maxGCs) {
11 		char buffer[256];
12 		sprintf(buffer, "%d general combiners specified, only %d supported", num, (int)maxGCs);
13 		errors.set(buffer);
14 		num = maxGCs;
15 	}
16 
17 	if (0 == num) {
18 		// Setup a "fake" general combiner 0
19 		general[0].ZeroOut();
20 		num = 1;
21 	}
22 
23 	localConsts = 0;
24 	int i;
25 	for (i = 0; i < num; i++)
26 		localConsts += general[i].numConsts;
27 
28 	if (localConsts > 0)
29     {
30 		if (NULL == glCombinerStageParameterfvNV)
31 			errors.set("local constant(s) specified, but not supported -- ignored");
32 		else
33 			for (i = 0; i < num; i++)
34 				general[i].SetUnusedLocalConsts(numConsts, pcc);
35     }
36 
37 	for (i = 0; i < num; i++)
38 		general[i].Validate(i);
39 
40 
41 	for (; i < maxGCs; i++)
42 		general[i].ZeroOut();
43 }
44 
Invoke()45 void GeneralCombinersStruct::Invoke()
46 {
47 	glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, num);
48 	int i;
49 	for (i = 0; i < num; i++)
50 		general[i].Invoke(i);
51 
52 	if (NULL != glCombinerStageParameterfvNV) {
53 		if (localConsts > 0)
54 			glEnable(GL_PER_STAGE_CONSTANTS_NV);
55 		else
56 			glDisable(GL_PER_STAGE_CONSTANTS_NV);
57 	}
58 
59 }
60 
ZeroOut()61 void GeneralCombinerStruct::ZeroOut()
62 {
63 		numPortions = 2;
64 		numConsts = 0;
65 
66 		portion[0].ZeroOut();
67 		portion[0].designator = RCP_RGB;
68 		portion[1].ZeroOut();
69 		portion[1].designator = RCP_ALPHA;
70 }
71 
72 
SetUnusedLocalConsts(int numGlobalConsts,ConstColorStruct * globalCCs)73 void GeneralCombinerStruct::SetUnusedLocalConsts(int numGlobalConsts, ConstColorStruct *globalCCs)
74 {
75         int i;
76 	for (i = 0; i < numGlobalConsts; i++) {
77 		bool constUsed = false;
78 		int j;
79 		for (j = 0; j < numConsts; j++)
80 			constUsed |= (cc[j].reg.bits.name == globalCCs[i].reg.bits.name);
81 		if (!constUsed)
82 			cc[numConsts++] = globalCCs[i];
83 	}
84 }
85 
86 
Validate(int stage)87 void GeneralCombinerStruct::Validate(int stage)
88 {
89 	if (2 == numConsts &&
90 		cc[0].reg.bits.name == cc[1].reg.bits.name)
91 		errors.set("local constant set twice");
92 
93 	switch (numPortions)
94 	{
95 	case 0:
96 		portion[0].designator = RCP_RGB;
97 		// Fallthru
98 	case 1:
99 		portion[1].designator = ((RCP_RGB == portion[0].designator) ? RCP_ALPHA : RCP_RGB);
100 		// Fallthru
101 	case 2:
102 		if (portion[0].designator == portion[1].designator)
103 			errors.set("portion declared twice");
104 		break;
105 	}
106 	int i;
107 	for (i = 0; i < numPortions; i++)
108 		portion[i].Validate(stage);
109 
110 	for (; i < 2; i++)
111 		portion[i].ZeroOut();
112 
113 }
114 
Invoke(int stage)115 void GeneralCombinerStruct::Invoke(int stage)
116 {
117 	int i;
118 
119 	if (NULL != glCombinerStageParameterfvNV)
120 		for (i = 0; i < numConsts; i++)
121 			glCombinerStageParameterfvNV(GL_COMBINER0_NV + stage, cc[i].reg.bits.name, &(cc[i].v[0]));
122 
123 	for (i = 0; i < 2; i++)
124 		portion[i].Invoke(stage);
125 }
126 
Validate(int stage)127 void GeneralPortionStruct::Validate(int stage)
128 {
129 	gf.Validate(stage, designator);
130 }
131 
Invoke(int stage)132 void GeneralPortionStruct::Invoke(int stage)
133 {
134 	gf.Invoke(stage, designator, bs);
135 }
136 
ZeroOut()137 void GeneralPortionStruct::ZeroOut()
138 {
139 	gf.ZeroOut();
140 	bs.word = RCP_SCALE_BY_ONE;
141 }
142 
ZeroOut()143 void GeneralFunctionStruct::ZeroOut()
144 {
145 	// Create mapped registers for zero and discard
146 	MappedRegisterStruct unsignedZero;
147 	RegisterEnum zero;
148 	zero.word = RCP_ZERO;
149 	unsignedZero.Init(zero);
150 
151 	MappedRegisterStruct unsignedDiscard;
152 	RegisterEnum discard;
153 	discard.word = RCP_DISCARD;
154 	unsignedDiscard.Init(discard);
155 
156 	numOps = 3;
157 
158 	op[0].op = RCP_MUL;
159 	op[0].reg[0] = unsignedDiscard;
160 	op[0].reg[1] = unsignedZero;
161 	op[0].reg[2] = unsignedZero;
162 
163 	op[1].op = RCP_MUL;
164 	op[1].reg[0] = unsignedDiscard;
165 	op[1].reg[1] = unsignedZero;
166 	op[1].reg[2] = unsignedZero;
167 
168 	op[2].op = RCP_SUM;
169 	op[2].reg[0] = unsignedDiscard;
170 
171 }
172 
Validate(int stage,int portion)173 void GeneralFunctionStruct::Validate(int stage, int portion)
174 {
175         int i;
176 	for (i = 0; i < numOps; i++)
177 		op[i].Validate(stage, portion);
178 	// Check if multiple ops are writing to same register (and it's not DISCARD)
179 	if (numOps > 1 &&
180 		op[0].reg[0].reg.bits.name == op[1].reg[0].reg.bits.name &&
181 		GL_DISCARD_NV != op[0].reg[0].reg.bits.name)
182 		errors.set("writing to same register twice");
183 	if (numOps > 2 &&
184 		(op[0].reg[0].reg.bits.name == op[2].reg[0].reg.bits.name ||
185 		 op[1].reg[0].reg.bits.name == op[2].reg[0].reg.bits.name) &&
186 		GL_DISCARD_NV != op[2].reg[0].reg.bits.name)
187 		errors.set("writing to same register twice");
188 
189 	// Set unused outputs to discard, unused inputs to zero/unsigned_identity
190 	if (numOps < 2) {
191 		// Set C input to zero
192 		op[1].reg[1].reg.bits.name = GL_ZERO;
193 		op[1].reg[1].map = GL_UNSIGNED_IDENTITY_NV;
194 		op[1].reg[1].reg.bits.channel = portion;
195 
196 		// Set D input to zero
197 		op[1].reg[2].reg.bits.name = GL_ZERO;
198 		op[1].reg[2].map = GL_UNSIGNED_IDENTITY_NV;
199 		op[1].reg[2].reg.bits.channel = portion;
200 
201 		// Discard CD output
202 		op[1].op = false;
203 		op[1].reg[0].reg.bits.name = GL_DISCARD_NV;
204 	}
205 
206 	if (numOps < 3) {
207 		// Discard muxSum output
208 		op[2].reg[0].reg.bits.name = GL_DISCARD_NV;
209 		op[2].op = RCP_SUM;
210 	}
211 }
212 
213 
Invoke(int stage,int portion,BiasScaleEnum bs)214 void GeneralFunctionStruct::Invoke(int stage, int portion, BiasScaleEnum bs)
215 {
216 	GLenum portionEnum = (RCP_RGB == portion) ? GL_RGB : GL_ALPHA;
217 
218 	glCombinerInputNV(GL_COMBINER0_NV + stage,
219 		portionEnum,
220 		GL_VARIABLE_A_NV,
221 		op[0].reg[1].reg.bits.name,
222 		op[0].reg[1].map,
223 		MAP_CHANNEL(op[0].reg[1].reg.bits.channel));
224 
225 	glCombinerInputNV(GL_COMBINER0_NV + stage,
226 		portionEnum,
227 		GL_VARIABLE_B_NV,
228 		op[0].reg[2].reg.bits.name,
229 		op[0].reg[2].map,
230 		MAP_CHANNEL(op[0].reg[2].reg.bits.channel));
231 
232 	glCombinerInputNV(GL_COMBINER0_NV + stage,
233 		portionEnum,
234 		GL_VARIABLE_C_NV,
235 		op[1].reg[1].reg.bits.name,
236 		op[1].reg[1].map,
237 		MAP_CHANNEL(op[1].reg[1].reg.bits.channel));
238 
239 	glCombinerInputNV(GL_COMBINER0_NV + stage,
240 		portionEnum,
241 		GL_VARIABLE_D_NV,
242 		op[1].reg[2].reg.bits.name,
243 		op[1].reg[2].map,
244 		MAP_CHANNEL(op[1].reg[2].reg.bits.channel));
245 
246 	glCombinerOutputNV(GL_COMBINER0_NV + stage,
247 		portionEnum,
248 		op[0].reg[0].reg.bits.name,
249 		op[1].reg[0].reg.bits.name,
250 		op[2].reg[0].reg.bits.name,
251 		bs.bits.scale,
252 		bs.bits.bias,
253 		op[0].op,
254 		op[1].op,
255 		(op[2].op == RCP_MUX) ? true : false);
256 }
257 
258 // This helper function assigns a channel to an undesignated input register
ConvertRegister(RegisterEnum & reg,int portion)259 static void ConvertRegister(RegisterEnum& reg, int portion)
260 {
261 	if (RCP_NONE == reg.bits.channel) {
262 		reg.bits.channel = portion;
263 		if (GL_FOG == reg.bits.name && RCP_ALPHA == portion)
264 			// Special case where fog alpha is final only, but RGB is not
265 			reg.bits.finalOnly = true;
266 	}
267 }
268 
269 
Validate(int stage,int portion)270 void OpStruct::Validate(int stage, int portion)
271 {
272 	int args = 1;
273 
274 	if (RCP_DOT == op || RCP_MUL == op)
275 		args = 3;
276 	else
277 		args = 1;
278 
279 	if (reg[0].reg.bits.readOnly)
280 		errors.set("writing to a read-only register");
281 
282 	if (RCP_ALPHA == portion &&
283 		RCP_DOT == op)
284 		errors.set("dot used in alpha portion");
285 	int i;
286 	for (i = 0; i < args; i++) {
287 		ConvertRegister(reg[i].reg, portion);
288 		if (reg[i].reg.bits.finalOnly)
289 			errors.set("final register used in general combiner");
290 		if (RCP_RGB == portion &&
291 			RCP_BLUE == reg[i].reg.bits.channel)
292 			errors.set("blue register used in rgb portion");
293 		if (RCP_ALPHA == portion &&
294 			RCP_RGB == reg[i].reg.bits.channel)
295 			errors.set("rgb register used in alpha portion");
296 		if (i > 0 &&
297 			GL_DISCARD_NV == reg[i].reg.bits.name)
298 			errors.set("reading from discard");
299 	}
300 }
301