2 |
2 |
3 #include "common.h" |
3 #include "common.h" |
4 #include "io.h" |
4 #include "io.h" |
5 #include "misc.h" |
5 #include "misc.h" |
6 #include "bbox.h" |
6 #include "bbox.h" |
|
7 #include "gui.h" |
7 |
8 |
8 vector<str> g_zaFileLoadPaths; |
9 vector<str> g_zaFileLoadPaths; |
9 |
10 |
10 // ============================================================================= |
11 // ============================================================================= |
11 // IO_FindLoadedFile (str) |
12 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
12 // |
13 // ============================================================================= |
13 // Returns a pointer to the first found open file with the given name. |
14 OpenFile* findLoadedFile (str name) { |
14 // ============================================================================= |
|
15 OpenFile* IO_FindLoadedFile (str name) { |
|
16 for (ulong i = 0; i < g_LoadedFiles.size(); i++) { |
15 for (ulong i = 0; i < g_LoadedFiles.size(); i++) { |
17 OpenFile* const file = g_LoadedFiles[i]; |
16 OpenFile* const file = g_LoadedFiles[i]; |
18 if (file->zFileName == name) |
17 if (file->zFileName == name) |
19 return file; |
18 return file; |
20 } |
19 } |
21 |
20 |
22 return nullptr; |
21 return nullptr; |
23 } |
22 } |
24 |
23 |
25 // ============================================================================= |
24 // ============================================================================= |
26 // IO_OpenLDrawFile (str) |
25 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
27 // |
26 // ============================================================================= |
28 // Opens the given file and parses the LDraw code within. |
27 OpenFile* openDATFile (str path) { |
29 // ============================================================================= |
|
30 OpenFile* IO_OpenLDrawFile (str path) { |
|
31 logf ("Opening %s...\n", path.chars()); |
28 logf ("Opening %s...\n", path.chars()); |
32 |
29 |
33 FILE* fp = fopen (path.chars (), "r"); |
30 FILE* fp = fopen (path.chars (), "r"); |
34 |
31 |
35 if (!fp) { |
32 if (!fp) { |
67 } |
64 } |
68 |
65 |
69 fclose (fp); |
66 fclose (fp); |
70 |
67 |
71 for (ulong i = 0; i < lines.size(); ++i) { |
68 for (ulong i = 0; i < lines.size(); ++i) { |
72 LDObject* obj = ParseLine (lines[i]); |
69 LDObject* obj = parseLine (lines[i]); |
73 load->objects.push_back (obj); |
70 load->objects.push_back (obj); |
74 |
71 |
75 // Check for warnings |
72 // Check for parse errors and warn abotu tthem |
76 if (obj->getType() == OBJ_Gibberish) { |
73 if (obj->getType() == OBJ_Gibberish) { |
77 logf (LOG_Warning, "Couldn't parse line #%lu: %s\n", |
74 logf (LOG_Warning, "Couldn't parse line #%lu: %s\n", |
78 i, static_cast<LDGibberish*> (obj)->zReason.chars()); |
75 i, static_cast<LDGibberish*> (obj)->zReason.chars()); |
79 logf (LOG_Warning, "- Line was: %s\n", lines[i].chars()); |
76 logf (LOG_Warning, "- Line was: %s\n", lines[i].chars()); |
80 numWarnings++; |
77 numWarnings++; |
88 |
85 |
89 return load; |
86 return load; |
90 } |
87 } |
91 |
88 |
92 // ============================================================================= |
89 // ============================================================================= |
93 // isNumber (char*) [static] |
90 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
94 // |
91 // ============================================================================= |
95 // Returns whether a given string represents a floating point number |
92 // Clear everything from the model |
96 // TODO: Does LDraw support scientific notation? |
93 void OpenFile::close () { |
97 // ============================================================================= |
94 for (ulong j = 0; j < objects.size(); ++j) |
98 static bool isNumber (char* sToken) { |
95 delete objects[j]; |
99 char* sPointer = &sToken[0]; |
96 |
100 bool bGotDot = false; |
97 delete this; |
101 |
98 } |
102 // Allow leading hyphen for negatives |
99 |
103 if (*sPointer == '-') |
100 // ============================================================================= |
104 sPointer++; |
101 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
105 |
102 // ============================================================================= |
106 while (*sPointer != '\0') { |
103 void closeAll () { |
107 if (*sPointer == '.' && !bGotDot) { |
104 if (!g_LoadedFiles.size()) |
108 // Decimal point |
105 return; |
109 bGotDot = true; |
106 |
110 sPointer++; |
107 // Remove all loaded files and the objects they contain |
111 continue; |
108 for (ushort i = 0; i < g_LoadedFiles.size(); i++) { |
112 } |
109 OpenFile* f = g_LoadedFiles[i]; |
|
110 f->close (); |
|
111 } |
|
112 |
|
113 // Clear the array |
|
114 g_LoadedFiles.clear(); |
|
115 g_CurrentFile = NULL; |
|
116 |
|
117 g_qWindow->R->hardRefresh(); |
|
118 } |
|
119 |
|
120 // ============================================================================= |
|
121 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
122 // ============================================================================= |
|
123 void newFile () { |
|
124 // Create a new anonymous file and set it to our current |
|
125 closeAll (); |
|
126 |
|
127 OpenFile* f = new OpenFile; |
|
128 f->zFileName = ""; |
|
129 g_LoadedFiles.push_back (f); |
|
130 g_CurrentFile = f; |
|
131 |
|
132 g_BBox.calculate(); |
|
133 g_qWindow->buildObjList (); |
|
134 g_qWindow->R->hardRefresh(); |
|
135 } |
|
136 |
|
137 // ============================================================================= |
|
138 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
139 // ============================================================================= |
|
140 void openMainFile (str zPath) { |
|
141 closeAll (); |
|
142 |
|
143 OpenFile* pFile = openDATFile (zPath); |
|
144 g_CurrentFile = pFile; |
|
145 |
|
146 // Recalculate the bounding box |
|
147 g_BBox.calculate(); |
|
148 |
|
149 // Rebuild the object tree view now. |
|
150 g_qWindow->buildObjList (); |
|
151 g_qWindow->setTitle (); |
|
152 } |
|
153 |
|
154 // ============================================================================= |
|
155 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
156 // ============================================================================= |
|
157 void OpenFile::save (str zPath) { |
|
158 if (!~zPath) |
|
159 zPath = zFileName; |
|
160 |
|
161 FILE* fp = fopen (zPath, "w"); |
|
162 if (!fp) |
|
163 return; |
|
164 |
|
165 // Write all entries now |
|
166 for (ulong i = 0; i < objects.size(); ++i) { |
|
167 LDObject* obj = objects[i]; |
113 |
168 |
114 if (*sPointer >= '0' && *sPointer <= '9') { |
169 // LDraw requires lines to have DOS line endings |
115 sPointer++; |
170 str zLine = str::mkfmt ("%s\r\n",obj->getContents ().chars ()); |
116 continue; // Digit |
|
117 } |
|
118 |
171 |
119 // If the above cases didn't catch this character, it was |
172 fwrite (zLine.chars(), 1, ~zLine, fp); |
120 // illegal and this is therefore not a number. |
173 } |
121 return false; |
174 |
122 } |
175 fclose (fp); |
123 |
176 } |
124 return true; |
177 |
125 } |
178 // ============================================================================= |
126 |
179 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
127 // ============================================================================= |
|
128 // ParseLine (str) |
|
129 // |
|
130 // Parses a string line containing an LDraw object and returns the object parsed. |
|
131 // ============================================================================= |
180 // ============================================================================= |
132 #define CHECK_TOKEN_COUNT(N) \ |
181 #define CHECK_TOKEN_COUNT(N) \ |
133 if (tokens.size() != N) \ |
182 if (tokens.size() != N) \ |
134 return new LDGibberish (zLine, "Bad amount of tokens"); |
183 return new LDGibberish (zLine, "Bad amount of tokens"); |
135 |
184 |
137 for (ushort i = MIN; i <= MAX; ++i) \ |
186 for (ushort i = MIN; i <= MAX; ++i) \ |
138 if (!isNumber (tokens[i])) \ |
187 if (!isNumber (tokens[i])) \ |
139 return new LDGibberish (zLine, str::mkfmt ("Token #%u was `%s`, expected a number", \ |
188 return new LDGibberish (zLine, str::mkfmt ("Token #%u was `%s`, expected a number", \ |
140 (i + 1), tokens[i].chars())); |
189 (i + 1), tokens[i].chars())); |
141 |
190 |
142 LDObject* ParseLine (str zLine) { |
191 LDObject* parseLine (str zLine) { |
143 str zNoWhitespace = zLine; |
192 str zNoWhitespace = zLine; |
144 StripWhitespace (zNoWhitespace); |
193 stripWhitespace (zNoWhitespace); |
145 if (!~zNoWhitespace) { |
194 if (!~zNoWhitespace) { |
146 // Line was empty, or only consisted of whitespace |
195 // Line was empty, or only consisted of whitespace |
147 return new LDEmpty; |
196 return new LDEmpty; |
148 } |
197 } |
149 |
198 |
175 #ifndef WIN32 |
224 #ifndef WIN32 |
176 tokens[14].replace ("\\", "/"); |
225 tokens[14].replace ("\\", "/"); |
177 #endif // WIN32 |
226 #endif // WIN32 |
178 |
227 |
179 // Try open the file |
228 // Try open the file |
180 OpenFile* pFile = IO_FindLoadedFile (tokens[14]); |
229 OpenFile* pFile = findLoadedFile (tokens[14]); |
181 if (!pFile) |
230 if (!pFile) |
182 pFile = IO_OpenLDrawFile (tokens[14]); |
231 pFile = openDATFile (tokens[14]); |
183 |
232 |
184 // If we cannot open the file, mark it an error |
233 // If we cannot open the file, mark it an error |
185 if (!pFile) |
234 if (!pFile) |
186 return new LDGibberish (zLine, "Could not open referred file"); |
235 return new LDGibberish (zLine, "Could not open referred file"); |
187 |
236 |
188 LDSubfile* obj = new LDSubfile; |
237 LDSubfile* obj = new LDSubfile; |
189 obj->dColor = atoi (tokens[1]); |
238 obj->dColor = atoi (tokens[1]); |
190 obj->vPosition = ParseVertex (zLine, 2); // 2 - 4 |
239 obj->vPosition = parseVertex (zLine, 2); // 2 - 4 |
191 |
240 |
192 for (short i = 0; i < 9; ++i) |
241 for (short i = 0; i < 9; ++i) |
193 obj->faMatrix[i] = atof (tokens[i + 5]); // 5 - 13 |
242 obj->faMatrix[i] = atof (tokens[i + 5]); // 5 - 13 |
194 |
243 |
195 obj->zFileName = tokens[14]; |
244 obj->zFileName = tokens[14]; |
202 CHECK_TOKEN_COUNT (8) |
251 CHECK_TOKEN_COUNT (8) |
203 CHECK_TOKEN_NUMBERS (1, 7) |
252 CHECK_TOKEN_NUMBERS (1, 7) |
204 |
253 |
205 // Line |
254 // Line |
206 LDLine* obj = new LDLine; |
255 LDLine* obj = new LDLine; |
207 obj->dColor = GetWordInt (zLine, 1); |
256 obj->dColor = getWordInt (zLine, 1); |
208 for (short i = 0; i < 2; ++i) |
257 for (short i = 0; i < 2; ++i) |
209 obj->vaCoords[i] = ParseVertex (zLine, 2 + (i * 3)); // 2 - 7 |
258 obj->vaCoords[i] = parseVertex (zLine, 2 + (i * 3)); // 2 - 7 |
210 return obj; |
259 return obj; |
211 } |
260 } |
212 |
261 |
213 case 3: |
262 case 3: |
214 { |
263 { |
215 CHECK_TOKEN_COUNT (11) |
264 CHECK_TOKEN_COUNT (11) |
216 CHECK_TOKEN_NUMBERS (1, 10) |
265 CHECK_TOKEN_NUMBERS (1, 10) |
217 |
266 |
218 // Triangle |
267 // Triangle |
219 LDTriangle* obj = new LDTriangle; |
268 LDTriangle* obj = new LDTriangle; |
220 obj->dColor = GetWordInt (zLine, 1); |
269 obj->dColor = getWordInt (zLine, 1); |
221 |
270 |
222 for (short i = 0; i < 3; ++i) |
271 for (short i = 0; i < 3; ++i) |
223 obj->vaCoords[i] = ParseVertex (zLine, 2 + (i * 3)); // 2 - 10 |
272 obj->vaCoords[i] = parseVertex (zLine, 2 + (i * 3)); // 2 - 10 |
224 |
273 |
225 return obj; |
274 return obj; |
226 } |
275 } |
227 |
276 |
228 case 4: |
277 case 4: |
245 CHECK_TOKEN_COUNT (14) |
294 CHECK_TOKEN_COUNT (14) |
246 CHECK_TOKEN_NUMBERS (1, 13) |
295 CHECK_TOKEN_NUMBERS (1, 13) |
247 |
296 |
248 // Conditional line |
297 // Conditional line |
249 LDCondLine* obj = new LDCondLine; |
298 LDCondLine* obj = new LDCondLine; |
250 obj->dColor = GetWordInt (zLine, 1); |
299 obj->dColor = getWordInt (zLine, 1); |
251 |
300 |
252 for (short i = 0; i < 2; ++i) |
301 for (short i = 0; i < 2; ++i) |
253 obj->vaCoords[i] = ParseVertex (zLine, 2 + (i * 3)); // 2 - 7 |
302 obj->vaCoords[i] = parseVertex (zLine, 2 + (i * 3)); // 2 - 7 |
254 |
303 |
255 for (short i = 0; i < 2; ++i) |
304 for (short i = 0; i < 2; ++i) |
256 obj->vaControl[i] = ParseVertex (zLine, 8 + (i * 3)); // 8 - 13 |
305 obj->vaControl[i] = parseVertex (zLine, 8 + (i * 3)); // 8 - 13 |
257 return obj; |
306 return obj; |
258 } |
307 } |
259 |
308 |
260 default: // Strange line we couldn't parse |
309 default: // Strange line we couldn't parse |
261 return new LDGibberish (zLine, "Unknown line code number"); |
310 return new LDGibberish (zLine, "Unknown line code number"); |