Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / vertex_program_parse.cpp
blobe8723c61feadd534499e50891081ebe66f91c985
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
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 Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
21 #include "nel/3d/vertex_program_parse.h"
23 #ifdef DEBUG_NEW
24 #define new DEBUG_NEW
25 #endif
27 enum TArguments
29 #ifdef NL_LITTLE_ENDIAN
30 ADD = 1094992928,
31 ARL = 1095912480,
32 BFC0 = 1111900976,
33 BFC1 = 1111900977,
34 COL0 = 1129270320,
35 COL1 = 1129270321,
36 DP3 = 1146106656,
37 DP4 = 1146106912,
38 DST = 1146311712,
39 END = 1162757152,
40 EXP = 1163415584,
41 EXPP = 1163415632,
42 FOGC = 1179600707,
43 HPOS = 1213222739,
44 LIT = 1279874080,
45 LOG = 1280263968,
46 MAD = 1296122912,
47 MAX = 1296128032,
48 MIN = 1296649760,
49 MOV = 1297045024,
50 MUL = 1297435680,
51 NRML = 1314016588,
52 OPOS = 1330663251,
53 PSIZ = 1347635546,
54 RCP = 1380143136,
55 RSQ = 1381191968,
56 SGE = 1397179680,
57 SLT = 1397511200,
58 TEX0 = 1413830704,
59 TEX1 = 1413830705,
60 TEX2 = 1413830706,
61 TEX3 = 1413830707,
62 TEX4 = 1413830708,
63 TEX5 = 1413830709,
64 TEX6 = 1413830710,
65 TEX7 = 1413830711,
66 WGHT = 1464289364,
67 #else
68 ADD = 541344833,
69 ARL = 541872705,
70 BFC0 = 809715266,
71 BFC1 = 826492482,
72 COL0 = 810307395,
73 COL1 = 827084611,
74 DP3 = 540233796,
75 DP4 = 540299332,
76 DST = 542397252,
77 END = 541347397,
78 EXP = 542136389,
79 EXPP = 1347442757,
80 FOGC = 1128746822,
81 HPOS = 1397706824,
82 LIT = 542394700,
83 LOG = 541544268,
84 MAD = 541344077,
85 MAX = 542654797,
86 MIN = 542001485,
87 MOV = 542527309,
88 MUL = 541873485,
89 NRML = 1280135758,
90 OPOS = 1397706831,
91 PSIZ = 1514754896,
92 RCP = 542131026,
93 RSQ = 542200658,
94 SGE = 541411155,
95 SLT = 542395475,
96 TEX0 = 811091284,
97 TEX1 = 827868500,
98 TEX2 = 844645716,
99 TEX3 = 861422932,
100 TEX4 = 878200148,
101 TEX5 = 894977364,
102 TEX6 = 911754580,
103 TEX7 = 928531796,
104 WGHT = 1414022999,
105 #endif
108 //=====================================
109 bool CVPParser::parseWriteMask(uint &mask, std::string &errorOutput)
111 // parse output mask
112 if (*_CurrChar != '.')
114 // no output masks
115 mask = 0xf; //output 4 coordinates
116 return true;
118 else
120 ++ _CurrChar;
121 mask = 0;
122 for(uint k = 0; k < 4; ++k)
124 uint maskIndex;
125 switch(*_CurrChar)
127 case 'x': maskIndex = 0; break;
128 case 'y': maskIndex = 1; break;
129 case 'z': maskIndex = 2; break;
130 case 'w': maskIndex = 3; break;
131 default:
132 if (k >= 1) return true;
133 else
135 errorOutput = "Can't parse output mask.";
136 return false;
138 break;
140 ++_CurrChar;
141 if (mask & (1 << maskIndex))
143 errorOutput = "Duplicated output mask component.";
144 return false;
146 mask |= 1 << maskIndex;
148 return true;
152 //=====================================
153 /** Skip tabulation and space in a source code
155 void CVPParser::skipSpacesAndComments()
157 bool stop = false;
160 switch(*_CurrChar)
162 case '\t':
163 case '\r':
164 case ' ' :
165 ++_CurrChar;
166 break;
168 case '\n':
169 ++_CurrChar;
170 ++_LineIndex;
171 _LineStart = _CurrChar;
172 break;
173 case '#': // comment go till end of line
174 while (*_CurrChar != '\n' && *_CurrChar != '\0') ++_CurrChar;
175 skipSpacesAndComments();
176 break;
177 default:
178 stop = true;
179 break;
182 while (!stop);
185 //=================================================================================================
186 uint CVPInstruction::getNumUsedSrc() const
188 switch(Opcode)
190 case CVPInstruction::ARL:
191 case CVPInstruction::RSQ:
192 case CVPInstruction::EXPP:
193 case CVPInstruction::LOG:
194 case CVPInstruction::RCP:
195 case CVPInstruction::MOV:
196 case CVPInstruction::LIT:
197 return 1;
199 case CVPInstruction::MAD:
200 return 3;
202 case CVPInstruction::MUL:
203 case CVPInstruction::ADD:
204 case CVPInstruction::DP3:
205 case CVPInstruction::DP4:
206 case CVPInstruction::DST:
207 case CVPInstruction::MIN:
208 case CVPInstruction::MAX:
209 case CVPInstruction::SLT:
210 case CVPInstruction::SGE:
211 return 2;
213 default:
214 nlstop;
216 return 0;
219 //=================================================================================================
220 bool CVPParser::parseOperand(CVPOperand &operand, bool outputOperand, std::string &errorOutput)
222 skipSpacesAndComments();
223 bool result;
224 if (outputOperand)
226 operand.Negate = false;
227 switch(*_CurrChar)
229 case 'o': result = parseOutputRegister(operand, errorOutput); break;
230 case 'R':
231 result = parseVariableRegister(operand, errorOutput);
232 break;
233 case 'A': result = parseAddressRegister(operand, errorOutput); break;
234 case '-':
235 errorOutput = "Negation not allowed on output register.";
236 return false;
237 default:
238 errorOutput = "Output, Address, or Temporary register expected as an output operand.";
239 return false;
241 if (!result) return false;
243 // parse the write mask
244 return parseWriteMask(operand.WriteMask, errorOutput);
246 else
248 operand.Negate = false;
249 switch(*_CurrChar)
251 case 'v': result = parseInputRegister(operand, errorOutput); break;
252 case 'R': result = parseVariableRegister(operand, errorOutput); break;
253 case 'c': result = parseConstantRegister(operand, errorOutput); break;
254 case 'a': result = parseAddressRegister(operand, errorOutput); break;
255 case '-':
257 operand.Negate = true;
258 // negation
259 ++ _CurrChar;
260 skipSpacesAndComments();
261 switch(*_CurrChar)
263 case 'v': result = parseInputRegister(operand, errorOutput); break;
264 case 'R': result = parseVariableRegister(operand, errorOutput); break;
265 case 'c': result = parseConstantRegister(operand, errorOutput); break;
266 default:
267 errorOutput = "Negation must be followed by an input register, a variable register, or a constant.";
268 return false;
269 break;
272 break;
273 default:
274 errorOutput = "Syntax error.";
275 return false;
276 break;
278 if (!result) return false;
279 if (operand.Type != CVPOperand::AddressRegister)
281 if (!parseSwizzle(operand.Swizzle, errorOutput)) return false;
282 if (operand.Type == CVPOperand::Variable)
284 for(uint k = 0; k < 4; ++k)
286 if (!(_RegisterMask[operand.Value.VariableValue] & (1 << operand.Swizzle.Comp[k])))
288 errorOutput = "Can't read a register component before writing to it.";
289 return false;
294 return true;
301 //=================================================================================================
302 bool CVPParser::parseInputRegister(CVPOperand &operand, std::string &errorOutput)
304 ++_CurrChar;
305 operand.Type = CVPOperand::InputRegister;
306 if (*_CurrChar != '[')
308 errorOutput = "'[' expected when parsing an input register.";
309 return false;
311 ++_CurrChar;
312 skipSpacesAndComments();
313 if (isdigit(*_CurrChar))
315 // The input register is expressed as an index
316 uint index = *_CurrChar - '0';
317 ++_CurrChar;
318 if (isdigit(*_CurrChar))
320 index = 10 * index + (*_CurrChar - '0');
321 ++_CurrChar;
323 if (index > 15)
325 errorOutput = "Invalid index for input register, must be in [0, 15].";
326 return false;
328 operand.Value.InputRegisterValue = (CVPOperand::EInputRegister) index;
330 else
332 // The input register is expressed as a string
333 uint32 strValue = 0;
334 // read the 4 letters
335 for(uint k = 0; k < 4; ++k)
337 if (!isalnum(*_CurrChar))
339 errorOutput = "Can't parse index for input register.";
340 return false;
342 strValue |= ((uint32) *_CurrChar) << (8 * (3 - k));
343 ++_CurrChar;
345 switch ((TArguments)strValue)
347 case OPOS: operand.Value.InputRegisterValue = CVPOperand::IPosition; break;
348 case WGHT: operand.Value.InputRegisterValue = CVPOperand::IWeight; break;
349 case NRML: operand.Value.InputRegisterValue = CVPOperand::INormal; break;
350 case COL0: operand.Value.InputRegisterValue = CVPOperand::IPrimaryColor; break;
351 case COL1: operand.Value.InputRegisterValue = CVPOperand::ISecondaryColor; break;
352 case FOGC: operand.Value.InputRegisterValue = CVPOperand::IFogCoord; break;
353 // texture argument
354 case TEX0:
355 case TEX1:
356 case TEX2:
357 case TEX3:
358 case TEX4:
359 case TEX5:
360 case TEX6:
361 case TEX7:
362 operand.Value.InputRegisterValue = (CVPOperand::EInputRegister) (((CVPOperand::ITex0 + strValue) & 0xff) - '0');
363 break;
364 default:
365 errorOutput = "Can't parse index for input register.";
366 return false;
369 skipSpacesAndComments();
370 if (*_CurrChar != ']')
372 errorOutput = "']' expected when parsing an input register.";
373 return false;
375 ++ _CurrChar;
376 return true;
379 //=================================================================================================
380 static inline bool letterToSwizzleComp(char letter, CVPSwizzle::EComp &comp)
382 switch (letter)
384 case 'x': comp = CVPSwizzle::X; return true;
385 case 'y': comp = CVPSwizzle::Y; return true;
386 case 'z': comp = CVPSwizzle::Z; return true;
387 case 'w': comp = CVPSwizzle::W; return true;
389 return false;
392 //=================================================================================================
393 bool CVPParser::parseSwizzle(CVPSwizzle &swizzle,std::string &errorOutput)
395 if (*_CurrChar != '.')
397 // no swizzle
398 swizzle.Comp[0] = CVPSwizzle::X;
399 swizzle.Comp[1] = CVPSwizzle::Y;
400 swizzle.Comp[2] = CVPSwizzle::Z;
401 swizzle.Comp[3] = CVPSwizzle::W;
402 return true;
404 ++_CurrChar;
405 // 4 letters case
406 for(uint k = 0; k < 4; ++k)
408 if (!isalpha(*_CurrChar))
410 if (k == 1) // 1 letter case
412 switch(*_CurrChar)
414 case ',':
415 case ';':
416 case ' ':
417 case '\t':
418 case '\r':
419 case '\n':
420 case '#':
421 swizzle.Comp[1] = swizzle.Comp[2] = swizzle.Comp[3] = swizzle.Comp[0];
422 return true;
423 break;
424 default:
425 errorOutput = "Can't parse swizzle.";
429 else
431 errorOutput = "Invalid swizzle value.";
432 return false;
436 if (!letterToSwizzleComp(*_CurrChar, swizzle.Comp[k]))
438 errorOutput = "Invalid swizzle value.";
439 return false;
441 ++ _CurrChar;
444 return true;
447 //=================================================================================================
448 bool CVPParser::parseOutputRegister(CVPOperand &operand, std::string &errorOutput)
450 ++_CurrChar;
451 operand.Type = CVPOperand::OutputRegister;
452 if (*_CurrChar != '[')
454 errorOutput = "'[' expected when parsing an output register.";
455 return false;
457 ++_CurrChar;
458 skipSpacesAndComments();
459 // The input register is expressed as a string
460 uint32 strValue = 0;
461 // read the 4 letters
462 for(uint k = 0; k < 4; ++k)
464 if (!isalnum(*_CurrChar))
466 errorOutput = "Can't parse index for output register.";
467 return false;
469 strValue |= ((uint32) *_CurrChar) << (8 * (3 - k));
470 ++_CurrChar;
472 // convert to enum
473 switch((TArguments)strValue)
475 case HPOS: operand.Value.OutputRegisterValue = CVPOperand::OHPosition; break;
476 case COL0: operand.Value.OutputRegisterValue = CVPOperand::OPrimaryColor; break;
477 case COL1: operand.Value.OutputRegisterValue = CVPOperand::OSecondaryColor; break;
478 case BFC0: operand.Value.OutputRegisterValue = CVPOperand::OBackFacePrimaryColor; break;
479 case BFC1: operand.Value.OutputRegisterValue = CVPOperand::OBackFaceSecondaryColor; break;
480 case FOGC: operand.Value.OutputRegisterValue = CVPOperand::OFogCoord; break;
481 case PSIZ: operand.Value.OutputRegisterValue = CVPOperand::OPointSize; break;
482 case TEX0: operand.Value.OutputRegisterValue = CVPOperand::OTex0; break;
483 case TEX1: operand.Value.OutputRegisterValue = CVPOperand::OTex1; break;
484 case TEX2: operand.Value.OutputRegisterValue = CVPOperand::OTex2; break;
485 case TEX3: operand.Value.OutputRegisterValue = CVPOperand::OTex3; break;
486 case TEX4: operand.Value.OutputRegisterValue = CVPOperand::OTex4; break;
487 case TEX5: operand.Value.OutputRegisterValue = CVPOperand::OTex5; break;
488 case TEX6: operand.Value.OutputRegisterValue = CVPOperand::OTex6; break;
489 case TEX7: operand.Value.OutputRegisterValue = CVPOperand::OTex7; break;
490 default:
491 errorOutput = "Can't read index for output register.";
492 return false;
493 break;
495 skipSpacesAndComments();
496 if (*_CurrChar != ']')
498 errorOutput = "']' expected when parsing an output register.";
499 return false;
501 ++_CurrChar;
502 return true;
505 //=================================================================================================
506 static inline const char *parseUInt(const char *src, uint &dest)
508 uint index = 0;
509 while (isdigit(*src))
511 index = 10 * index + *src - '0';
512 ++ src;
514 dest = index;
515 return src;
519 //=================================================================================================
520 bool CVPParser::parseConstantRegister(CVPOperand &operand, std::string &errorOutput)
522 ++_CurrChar;
523 operand.Type = CVPOperand::Constant;
524 if (*_CurrChar != '[')
526 errorOutput = "'[' expected when parsing a constant register.";
527 return false;
529 ++_CurrChar;
530 skipSpacesAndComments();
531 sint &index = operand.Value.ConstantValue;
532 if (isdigit(*_CurrChar))
534 // immediat case : c[0] to c[95]
535 uint uIndex;
536 _CurrChar = parseUInt(_CurrChar, uIndex);
537 if (uIndex > 95)
539 errorOutput = "Constant register index must range from 0 to 95.";
540 return false;
542 index = (sint) uIndex;
543 operand.Indexed = false;
545 else if (*_CurrChar == 'A')
547 // indexed case : c[A0.x - 64] to c[A0.x + 63]
548 operand.Indexed = true;
549 index = 0;
550 if (_CurrChar[1] == '0'
551 && _CurrChar[2] == '.'
552 && _CurrChar[3] == 'x')
554 _CurrChar += 4;
555 skipSpacesAndComments();
556 if (*_CurrChar == '+')
558 ++ _CurrChar;
559 skipSpacesAndComments();
560 if (isdigit(*_CurrChar))
562 uint uIndex;
563 _CurrChar = parseUInt(_CurrChar, uIndex);
564 if (uIndex > 63)
566 errorOutput = "Constant register index must range from -64 to +63.";
567 return false;
569 index = (sint) uIndex;
571 else
573 errorOutput = "Can't parse offset for constant register.";
574 return false;
577 else
578 if (*_CurrChar == '-')
580 ++ _CurrChar;
581 skipSpacesAndComments();
582 if (isdigit(*_CurrChar))
584 uint uIndex;
585 _CurrChar = parseUInt(_CurrChar, uIndex);
586 if (uIndex > 64)
588 errorOutput = "Constant register index must range from -64 to +63.";
589 return false;
591 index = - (sint) uIndex;
593 else
595 errorOutput = "Can't parse offset for constant register.";
596 return false;
600 else
602 errorOutput = "Can't parse constant register index.";
603 return false;
606 skipSpacesAndComments();
607 if (*_CurrChar != ']')
609 errorOutput = "']' expected when parsing an input register.";
610 return false;
612 ++_CurrChar;
613 return true;
616 //=================================================================================================
617 bool CVPParser::parseVariableRegister(CVPOperand &operand, std::string &errorOutput)
619 ++_CurrChar;
620 operand.Type = CVPOperand::Variable;
621 if (!isdigit(*_CurrChar))
623 errorOutput = "Can't parse variable register.";
624 return false;
626 uint &index = operand.Value.VariableValue;
627 _CurrChar = parseUInt(_CurrChar, index);
628 if (index > 11)
630 errorOutput = "Variable register index must range from 0 to 11.";
631 return false;
633 return true;
636 //=================================================================================================
637 bool CVPParser::parseAddressRegister(CVPOperand &operand, std::string &errorOutput)
639 ++_CurrChar;
640 operand.Type = CVPOperand::AddressRegister;
641 if (_CurrChar[0] != '0' || _CurrChar[1] != '.' || _CurrChar[2] != 'x')
643 errorOutput = "Can't parse address register.";
644 return false;
646 _CurrChar += 3;
647 return true;
650 //=================================================================================================
651 bool CVPParser::parseOp2(CVPInstruction &instr,std::string &errorOutput)
653 skipSpacesAndComments();
654 // parse output
655 if (!parseOperand(instr.Dest, true, errorOutput)) return false;
656 // Can't write in input or consant register
657 if (instr.Dest.Type == CVPOperand::Constant || instr.Dest.Type == CVPOperand::InputRegister)
659 errorOutput = "Can't write to a constant or input register";
660 return false;
663 skipSpacesAndComments();
664 if (*_CurrChar != ',')
666 errorOutput = "',' expected.";
667 return false;
669 ++_CurrChar;
670 skipSpacesAndComments();
671 // parse src1
672 if (!parseOperand(instr.Src1, false, errorOutput)) return false;
673 if (instr.Src1.Type == CVPOperand::AddressRegister
674 || instr.Src1.Type == CVPOperand::OutputRegister)
676 errorOutput = "Src1 must be constant, variable, or input register.";
677 return false;
679 return true;
682 //=================================================================================================
683 bool CVPParser::parseOp3(CVPInstruction &instr, std::string &errorOutput)
685 if (!parseOp2(instr, errorOutput)) return false;
686 skipSpacesAndComments();
687 if (*_CurrChar != ',')
689 errorOutput = "',' expected.";
690 return false;
692 ++_CurrChar;
693 skipSpacesAndComments();
694 // parse src2
695 if (!parseOperand(instr.Src2, false, errorOutput)) return false;
696 if (instr.Src2.Type == CVPOperand::AddressRegister
697 || instr.Src2.Type == CVPOperand::OutputRegister)
699 errorOutput = "Src2 must be constant, variable, or input register.";
700 return false;
702 // make sure we do not have 2 =/= contant register as src (or in put register)
704 // 2 constant registers ?
705 if (instr.Src1.Type == CVPOperand::Constant
706 && instr.Src2.Type == CVPOperand::Constant)
708 // the index must be the same
709 if (!
711 instr.Src1.Indexed == instr.Src2.Indexed
712 && instr.Src1.Value.ConstantValue == instr.Src2.Value.ConstantValue
716 errorOutput = "Can't read 2 different constant registers in a single instruction.";
717 return false;
721 // 2 input registers ?
722 if (instr.Src1.Type == CVPOperand::InputRegister
723 && instr.Src2.Type == CVPOperand::InputRegister)
725 // the index must be the same
726 if (instr.Src1.Value.InputRegisterValue != instr.Src2.Value.InputRegisterValue)
728 errorOutput = "Can't read 2 different input registers in a single instruction.";
729 return false;
732 return true;
735 //=================================================================================================
736 bool CVPParser::parseOp4(CVPInstruction &instr, std::string &errorOutput)
738 if (!parseOp3(instr, errorOutput)) return false;
739 // parse src 3
740 skipSpacesAndComments();
741 if (*_CurrChar != ',')
743 errorOutput = "',' expected.";
744 return false;
746 ++_CurrChar;
747 skipSpacesAndComments();
748 // parse src4
749 if (!parseOperand(instr.Src3, false, errorOutput)) return false;
750 if (instr.Src3.Type == CVPOperand::AddressRegister
751 || instr.Src3.Type == CVPOperand::OutputRegister)
753 errorOutput = "Src3 must be constant, variable, or input register.";
754 return false;
757 ///////////////////////////////////////////////////
758 // check for different contant / input registers //
759 ///////////////////////////////////////////////////
761 // Duplicated constant register
762 if (instr.Src3.Type == CVPOperand::Constant)
764 if (instr.Src1.Type == CVPOperand::Constant)
766 if (!
768 instr.Src1.Indexed == instr.Src3.Indexed
769 && instr.Src1.Value.ConstantValue == instr.Src3.Value.ConstantValue
773 errorOutput = "Can't read 2 different constant registers in a single instruction.";
774 return false;
777 if (instr.Src2.Type == CVPOperand::Constant)
779 if (!
781 instr.Src2.Indexed == instr.Src3.Indexed
782 && instr.Src2.Value.ConstantValue == instr.Src3.Value.ConstantValue
786 errorOutput = "Can't read 2 different constant registers in a single instruction.";
787 return false;
792 // Duplicated input register
793 if (instr.Src3.Type == CVPOperand::InputRegister)
795 if (instr.Src1.Type == CVPOperand::InputRegister)
797 if (instr.Src1.Value.InputRegisterValue != instr.Src3.Value.InputRegisterValue)
799 errorOutput = "Can't read 2 different input registers in a single instruction.";
800 return false;
803 if (instr.Src2.Type == CVPOperand::InputRegister)
805 if (instr.Src2.Value.InputRegisterValue != instr.Src3.Value.InputRegisterValue)
807 errorOutput = "Can't read 2 different input registers in a single instruction.";
808 return false;
814 return true;
817 //=================================================================================================
818 bool CVPParser::parseInstruction(CVPInstruction &instr, std::string &errorOutput, bool &endEncountered)
820 skipSpacesAndComments();
821 endEncountered = false;
822 uint32 instrStr = 0;
823 uint k;
824 for(k = 0; k < 4; ++k)
826 if (!isalnum(*_CurrChar))
828 if (k < 3) // at least 3 letter in an instruction
830 errorOutput = "Syntax error : can't read opcode.";
831 return false;
833 else break;
835 instrStr |= ((uint) *_CurrChar) << (8 * (3 - k));
836 ++ _CurrChar;
838 if (k != 4)
840 instrStr |= (uint32) ' ';
842 switch ((TArguments)instrStr)
844 case ARL:
845 instr.Opcode = CVPInstruction::ARL;
846 if (!parseOp2(instr, errorOutput)) return false;
847 if (!instr.Src1.Swizzle.isScalar())
849 errorOutput = "ARL need a scalar src value.";
850 return false;
852 break;
853 case RSQ:
854 instr.Opcode = CVPInstruction::RSQ;
855 if (!parseOp2(instr, errorOutput)) return false;
856 if (!instr.Src1.Swizzle.isScalar())
858 errorOutput = "RSQ need a scalar src value.";
859 return false;
861 break;
862 case EXP:
863 case EXPP:
864 instr.Opcode = CVPInstruction::EXPP;
865 if (!parseOp2(instr, errorOutput)) return false;
866 if (!instr.Src1.Swizzle.isScalar())
868 errorOutput = "EXP need a scalar src value.";
869 return false;
872 if (instr.Src1.Swizzle.Comp[0] != CVPSwizzle.W)
874 errorOutput = "EXPP input scalar must be w";
875 return false;
877 break;
878 case LOG:
879 instr.Opcode = CVPInstruction::LOG;
880 if (!parseOp2(instr, errorOutput)) return false;
881 if (!instr.Src1.Swizzle.isScalar())
883 errorOutput = "LOG need a scalar src value.";
884 return false;
887 if (instr.Src1.Swizzle.Comp[0] != CVPSwizzle.W)
889 errorOutput = "LOG input scalar must be w";
890 return false;
893 break;
894 case RCP:
895 instr.Opcode = CVPInstruction::RCP;
896 if (!parseOp2(instr, errorOutput)) return false;
897 if (!instr.Src1.Swizzle.isScalar())
899 errorOutput = "RCP need a scalar src value.";
900 return false;
902 break;
903 /////////////////
904 case MOV:
905 instr.Opcode = CVPInstruction::MOV;
906 if (!parseOp2(instr, errorOutput)) return false;
908 break;
909 case LIT:
910 instr.Opcode = CVPInstruction::LIT;
911 if (!parseOp2(instr, errorOutput)) return false;
912 break;
913 /////////////////
914 case MAD:
915 instr.Opcode = CVPInstruction::MAD;
916 if (!parseOp4(instr, errorOutput)) return false;
917 break;
918 /////////////////
919 case ADD:
920 instr.Opcode = CVPInstruction::ADD;
921 if (!parseOp3(instr, errorOutput)) return false;
922 break;
923 /////////////////
924 case MUL:
925 instr.Opcode = CVPInstruction::MUL;
926 if (!parseOp3(instr, errorOutput)) return false;
927 break;
928 case DP3:
929 instr.Opcode = CVPInstruction::DP3;
930 if (!parseOp3(instr, errorOutput)) return false;
931 break;
932 case DP4:
933 instr.Opcode = CVPInstruction::DP4;
934 if (!parseOp3(instr, errorOutput)) return false;
935 break;
936 case DST:
937 instr.Opcode = CVPInstruction::DST;
938 if (!parseOp3(instr, errorOutput)) return false;
939 break;
940 case MIN:
941 instr.Opcode = CVPInstruction::MIN;
942 if (!parseOp3(instr, errorOutput)) return false;
943 break;
944 case MAX:
945 instr.Opcode = CVPInstruction::MAX;
946 if (!parseOp3(instr, errorOutput)) return false;
947 break;
948 case SLT:
949 instr.Opcode = CVPInstruction::SLT;
950 if (!parseOp3(instr, errorOutput)) return false;
951 break;
952 case SGE:
953 instr.Opcode = CVPInstruction::SGE;
954 if (!parseOp3(instr, errorOutput)) return false;
955 break;
956 /////////////////
957 case END:
958 endEncountered = true;
959 return true;
960 break;
961 default:
962 errorOutput = "Syntax error : unknow opcode.";
963 return false;
964 break;
968 if (instr.Dest.Type == CVPOperand::Variable)
970 _RegisterMask[instr.Dest.Value.VariableValue] |= instr.Dest.WriteMask;
973 // it is not allowed to write to an adress register except for ARL
974 if (instrStr != NELID("ARL "))
976 if (instr.Dest.Type == CVPOperand::AddressRegister)
978 errorOutput = "Can't write to address register.";
979 return false;
983 // parse semi-colon
984 skipSpacesAndComments();
986 if (*_CurrChar != ';')
988 errorOutput = "';' expected.";
989 return false;
991 ++_CurrChar;
992 return true;
996 //=================================================================================================
997 bool CVPParser::isInputUsed(const TProgram &prg, CVPOperand::EInputRegister input)
999 for(uint k = 0; k < prg.size(); ++k)
1001 uint numSrc = prg[k].getNumUsedSrc();
1002 for(uint l = 0; l < numSrc; ++l)
1004 const CVPOperand &src = prg[k].getSrc(l);
1005 if (src.Type == CVPOperand::InputRegister && src.Value.InputRegisterValue == input) return true;
1008 return false;
1011 //=================================================================================================
1012 static std::string getStringUntilCR(const char *src)
1014 nlassert(src);
1015 std::string result;
1016 while (*src != '\n' && *src != '\r' && *src != '\0')
1018 result += *src;
1019 ++src;
1021 return result;
1024 //=================================================================================================
1025 bool CVPParser::parse(const char *src, CVPParser::TProgram &result, std::string &errorOutput)
1027 if (!src) return false;
1029 std::fill(_RegisterMask, _RegisterMask + 96, 0);
1032 _CurrChar = src;
1033 _LineStart = src;
1034 _LineIndex = 1;
1036 //skipSpacesAndComments(); // in fact space are not allowed at the start of the vertex program
1038 // parse version
1039 if ( _CurrChar[0] != '!'
1040 || _CurrChar[1] != '!'
1041 || _CurrChar[2] != 'V'
1042 || _CurrChar[3] != 'P'
1043 || _CurrChar[4] != '1'
1044 || _CurrChar[5] != '.'
1045 || (_CurrChar[6] != '0' && _CurrChar[6] != '1'))
1047 errorOutput = "Can't parse version.";
1048 return false;
1050 _CurrChar += 7;
1052 errorOutput.clear();
1053 // parse instructions
1054 bool endEncoutered = false;
1056 std::string errorMess;
1057 for(;;)
1059 CVPInstruction instr;
1060 if (!parseInstruction(instr, errorMess, endEncoutered))
1062 errorOutput = std::string("CVPParser::parse : Error encountered at line ") + NLMISC::toString(_LineIndex) + std::string(" : ") + errorMess + std::string(" Text : ") + getStringUntilCR(_LineStart);
1063 return false;
1065 if (endEncoutered) break;
1066 result.push_back(instr);
1068 return true;
1072 //=================================================================================================
1073 static const char *instrToName[] =
1075 "MOV ",
1076 "ARL ",
1077 "MUL ",
1078 "ADD ",
1079 "MAD ",
1080 "RSQ ",
1081 "DP3 ",
1082 "DP4 ",
1083 "DST ",
1084 "LIT ",
1085 "MIN ",
1086 "MAX ",
1087 "SLT ",
1088 "SGE ",
1089 "EXPP ",
1090 "LOG ",
1091 "RCP "
1094 //=================================================================================================
1095 static const char *outputRegisterToName[] =
1097 "HPOS",
1098 "COL0",
1099 "COL1",
1100 "BFC0",
1101 "BFC1",
1102 "FOGC",
1103 "PSIZ",
1104 "TEX0",
1105 "TEX1",
1106 "TEX2",
1107 "TEX3",
1108 "TEX4",
1109 "TEX5",
1110 "TEX6",
1111 "TEX7"
1115 //=================================================================================================
1116 static void dumpWriteMask(uint mask, std::string &out)
1118 if (mask == 0xf)
1120 out.clear();
1121 return;
1123 out = ".";
1124 if (mask & 1) out +="x";
1125 if (mask & 2) out +="y";
1126 if (mask & 4) out +="z";
1127 if (mask & 8) out +="w";
1130 //=================================================================================================
1131 static void dumpSwizzle(const CVPSwizzle &swz, std::string &out)
1133 if (swz.isIdentity())
1135 out.clear();
1136 return;
1138 out = ".";
1139 for(uint k = 0; k < 4; ++k)
1141 switch(swz.Comp[k])
1143 case CVPSwizzle::X: out += "x"; break;
1144 case CVPSwizzle::Y: out += "y"; break;
1145 case CVPSwizzle::Z: out += "z"; break;
1146 case CVPSwizzle::W: out += "w"; break;
1147 default:
1148 nlassert(0);
1149 break;
1151 if (swz.isScalar() && k == 0) break;
1156 //=================================================================================================
1157 static void dumpOperand(const CVPOperand &op, bool destOperand, std::string &out)
1159 out = op.Negate ? " -" : " ";
1160 switch(op.Type)
1162 case CVPOperand::Variable: out += "R" + NLMISC::toString(op.Value.VariableValue); break;
1163 case CVPOperand::Constant:
1164 out += "c[";
1165 if (op.Indexed)
1167 out += "A0.x + ";
1169 out += NLMISC::toString(op.Value.ConstantValue) + "]";
1170 break;
1171 case CVPOperand::InputRegister: out += "v[" + NLMISC::toString((uint) op.Value.InputRegisterValue) + "]"; break;
1172 case CVPOperand::OutputRegister:
1173 nlassert(op.Value.OutputRegisterValue < CVPOperand::OutputRegisterCount);
1174 out += "o[" + std::string(outputRegisterToName[op.Value.OutputRegisterValue]) + "]";
1175 break;
1176 case CVPOperand::AddressRegister:
1177 out += "A0.x";
1178 break;
1179 default:
1180 break;
1182 std::string suffix;
1183 if (destOperand)
1185 dumpWriteMask(op.WriteMask, suffix);
1187 else
1189 dumpSwizzle(op.Swizzle, suffix);
1191 out += suffix;
1194 //=================================================================================================
1195 /** Dump an instruction in a string
1197 static void dumpInstr(const CVPInstruction &instr, std::string &out)
1199 nlassert(instr.Opcode < CVPInstruction::OpcodeCount);
1200 out = instrToName[instr.Opcode];
1201 uint nbOp = instr.getNumUsedSrc();
1202 std::string destOperand;
1203 dumpOperand(instr.Dest, true, destOperand);
1204 out += destOperand;
1205 for(uint k = 0; k < nbOp; ++k)
1207 out += ", ";
1208 std::string srcOperand;
1209 dumpOperand(instr.getSrc(k), false, srcOperand);
1210 out += srcOperand;
1212 out +="; \n";
1215 //=================================================================================================
1216 void CVPParser::dump(const TProgram &prg, std::string &dest)
1218 dest = "!!VP1.0 \n";
1219 for(uint k = 0; k < prg.size(); ++k)
1221 std::string instr;
1222 dumpInstr(prg[k], instr);
1223 dest += instr;
1225 dest +="END";