46 static void populateCategories(); |
46 static void populateCategories(); |
47 static void loadPrimitiveCatgories(); |
47 static void loadPrimitiveCatgories(); |
48 |
48 |
49 // ============================================================================= |
49 // ============================================================================= |
50 // ----------------------------------------------------------------------------- |
50 // ----------------------------------------------------------------------------- |
51 void loadPrimitives() { |
51 void loadPrimitives() |
52 print ("Loading primitives...\n"); |
52 { print ("Loading primitives...\n"); |
53 loadPrimitiveCatgories(); |
53 loadPrimitiveCatgories(); |
54 |
54 |
55 // Try to load prims.cfg |
55 // Try to load prims.cfg |
56 File conf (Config::filepath ("prims.cfg"), File::Read); |
56 File conf (Config::filepath ("prims.cfg"), File::Read); |
57 |
57 |
58 if (!conf) { |
58 if (!conf) |
59 // No prims.cfg, build it |
59 { // No prims.cfg, build it |
60 PrimitiveLister::start(); |
60 PrimitiveLister::start(); |
61 } else { |
61 } |
62 // Read primitives from prims.cfg |
62 else |
63 for (str line : conf) { |
63 { // Read primitives from prims.cfg |
64 int space = line.indexOf (" "); |
64 for (str line : conf) |
65 |
65 { int space = line.indexOf (" "); |
|
66 |
66 if (space == -1) |
67 if (space == -1) |
67 continue; |
68 continue; |
68 |
69 |
69 Primitive info; |
70 Primitive info; |
70 info.name = line.left (space); |
71 info.name = line.left (space); |
71 info.title = line.mid (space + 1); |
72 info.title = line.mid (space + 1); |
72 g_primitives << info; |
73 g_primitives << info; |
73 } |
74 } |
74 |
75 |
75 populateCategories(); |
76 populateCategories(); |
76 } |
77 } |
77 } |
78 } |
78 |
79 |
79 // ============================================================================= |
80 // ============================================================================= |
80 // ----------------------------------------------------------------------------- |
81 // ----------------------------------------------------------------------------- |
81 static void recursiveGetFilenames (QDir dir, List<str>& fnames) { |
82 static void recursiveGetFilenames (QDir dir, List<str>& fnames) |
82 QFileInfoList flist = dir.entryInfoList(); |
83 { QFileInfoList flist = dir.entryInfoList(); |
83 |
84 |
84 for (const QFileInfo & info : flist) { |
85 for (const QFileInfo & info : flist) |
85 if (info.fileName() == "." || info.fileName() == "..") |
86 { if (info.fileName() == "." || info.fileName() == "..") |
86 continue; // skip . and .. |
87 continue; // skip . and .. |
87 |
88 |
88 if (info.isDir()) |
89 if (info.isDir()) |
89 recursiveGetFilenames (QDir (info.absoluteFilePath()), fnames); |
90 recursiveGetFilenames (QDir (info.absoluteFilePath()), fnames); |
90 else |
91 else |
91 fnames << info.absoluteFilePath(); |
92 fnames << info.absoluteFilePath(); |
92 } |
93 } |
93 } |
94 } |
94 |
95 |
95 // ============================================================================= |
96 // ============================================================================= |
96 // ----------------------------------------------------------------------------- |
97 // ----------------------------------------------------------------------------- |
97 void PrimitiveLister::work() { |
98 void PrimitiveLister::work() |
98 g_activePrimLister = this; |
99 { g_activePrimLister = this; |
99 m_prims.clear(); |
100 m_prims.clear(); |
100 |
101 |
101 QDir dir (LDPaths::prims()); |
102 QDir dir (LDPaths::prims()); |
102 ulong baselen = dir.absolutePath().length(); |
103 ulong baselen = dir.absolutePath().length(); |
103 ulong i = 0; |
104 ulong i = 0; |
104 List<str> fnames; |
105 List<str> fnames; |
105 |
106 |
106 assert (dir.exists()); |
107 assert (dir.exists()); |
107 recursiveGetFilenames (dir, fnames); |
108 recursiveGetFilenames (dir, fnames); |
108 emit starting (fnames.size()); |
109 emit starting (fnames.size()); |
109 |
110 |
110 for (str fname : fnames) { |
111 for (str fname : fnames) |
111 File f (fname, File::Read); |
112 { File f (fname, File::Read); |
112 |
113 |
113 Primitive info; |
114 Primitive info; |
114 info.name = fname.mid (baselen + 1); // make full path relative |
115 info.name = fname.mid (baselen + 1); // make full path relative |
115 info.name.replace ('/', '\\'); // use DOS backslashes, they're expected |
116 info.name.replace ('/', '\\'); // use DOS backslashes, they're expected |
116 info.cat = null; |
117 info.cat = null; |
117 |
118 |
118 if (!f.readLine (info.title)) |
119 if (!f.readLine (info.title)) |
119 info.title = ""; |
120 info.title = ""; |
120 |
121 |
121 info.title = info.title.simplified(); |
122 info.title = info.title.simplified(); |
122 |
123 |
123 if (info.title[0] == '0') { |
124 if (info.title[0] == '0') |
124 info.title.remove (0, 1); // remove 0 |
125 { info.title.remove (0, 1); // remove 0 |
125 info.title = info.title.simplified(); |
126 info.title = info.title.simplified(); |
126 } |
127 } |
127 |
128 |
128 m_prims << info; |
129 m_prims << info; |
129 emit update (++i); |
130 emit update (++i); |
130 } |
131 } |
131 |
132 |
132 // Save to a config file |
133 // Save to a config file |
133 File conf (Config::filepath ("prims.cfg"), File::Write); |
134 File conf (Config::filepath ("prims.cfg"), File::Write); |
134 |
135 |
135 for (Primitive & info : m_prims) |
136 for (Primitive & info : m_prims) |
136 fprint (conf, "%1 %2\n", info.name, info.title); |
137 fprint (conf, "%1 %2\n", info.name, info.title); |
137 |
138 |
138 conf.close(); |
139 conf.close(); |
139 |
140 |
140 g_primListerMutex = true; |
141 g_primListerMutex = true; |
141 g_primitives = m_prims; |
142 g_primitives = m_prims; |
142 populateCategories(); |
143 populateCategories(); |
143 g_primListerMutex = false; |
144 g_primListerMutex = false; |
144 g_activePrimLister = null; |
145 g_activePrimLister = null; |
145 emit workDone(); |
146 emit workDone(); |
146 } |
147 } |
147 |
148 |
148 // ============================================================================= |
149 // ============================================================================= |
149 // ----------------------------------------------------------------------------- |
150 // ----------------------------------------------------------------------------- |
150 void PrimitiveLister::start() { |
151 void PrimitiveLister::start() |
151 if (g_activePrimLister) |
152 { if (g_activePrimLister) |
152 return; |
153 return; |
153 |
154 |
154 PrimitiveLister* lister = new PrimitiveLister; |
155 PrimitiveLister* lister = new PrimitiveLister; |
155 QThread* listerThread = new QThread; |
156 QThread* listerThread = new QThread; |
156 lister->moveToThread (listerThread); |
157 lister->moveToThread (listerThread); |
157 connect (lister, SIGNAL (starting (ulong)), g_win, SLOT (primitiveLoaderStart (ulong))); |
158 connect (lister, SIGNAL (starting (ulong)), g_win, SLOT (primitiveLoaderStart (ulong))); |
158 connect (lister, SIGNAL (update (ulong)), g_win, SLOT (primitiveLoaderUpdate (ulong))); |
159 connect (lister, SIGNAL (update (ulong)), g_win, SLOT (primitiveLoaderUpdate (ulong))); |
227 } |
228 } |
228 } |
229 } |
229 |
230 |
230 // ============================================================================= |
231 // ============================================================================= |
231 // ----------------------------------------------------------------------------- |
232 // ----------------------------------------------------------------------------- |
232 static void loadPrimitiveCatgories() { |
233 static void loadPrimitiveCatgories() |
233 g_PrimitiveCategories.clear(); |
234 { g_PrimitiveCategories.clear(); |
234 File f (Config::dirpath() + "primregexps.cfg", File::Read); |
235 File f (Config::dirpath() + "primregexps.cfg", File::Read); |
235 |
236 |
236 if (!f) |
237 if (!f) |
237 f.open (":/data/primitive-categories.cfg", File::Read); |
238 f.open (":/data/primitive-categories.cfg", File::Read); |
238 |
239 |
239 if (!f) |
240 if (!f) |
240 critical (QObject::tr ("Failed to open primitive categories!")); |
241 critical (QObject::tr ("Failed to open primitive categories!")); |
241 |
242 |
242 if (f) { |
243 if (f) |
243 PrimitiveCategory cat; |
244 { PrimitiveCategory cat; |
244 |
245 |
245 for (str line : f) { |
246 for (str line : f) |
246 int colon; |
247 { int colon; |
247 |
248 |
248 if (line.length() == 0 || line[0] == '#') |
249 if (line.length() == 0 || line[0] == '#') |
249 continue; |
250 continue; |
250 |
251 |
251 if ((colon = line.indexOf (":")) == -1) { |
252 if ( (colon = line.indexOf (":")) == -1) |
252 if (cat.regexes.size() > 0) |
253 { if (cat.regexes.size() > 0) |
253 g_PrimitiveCategories << cat; |
254 g_PrimitiveCategories << cat; |
254 |
255 |
255 cat.regexes.clear(); |
256 cat.regexes.clear(); |
256 cat.prims.clear(); |
257 cat.prims.clear(); |
257 cat.setName (line); |
258 cat.setName (line); |
258 } else { |
259 } |
259 str cmd = line.left (colon); |
260 else |
|
261 { str cmd = line.left (colon); |
260 PrimitiveCategory::Type type = PrimitiveCategory::Filename; |
262 PrimitiveCategory::Type type = PrimitiveCategory::Filename; |
261 |
263 |
262 if (cmd == "f") |
264 if (cmd == "f") |
263 type = PrimitiveCategory::Filename; |
265 type = PrimitiveCategory::Filename; |
264 elif (cmd == "t") |
266 elif (cmd == "t") |
265 type = PrimitiveCategory::Title; |
267 type = PrimitiveCategory::Title; |
266 else |
268 else |
267 continue; |
269 continue; |
268 |
270 |
269 QRegExp regex (line.mid (colon + 1)); |
271 QRegExp regex (line.mid (colon + 1)); |
270 PrimitiveCategory::RegexEntry entry = { regex, type }; |
272 PrimitiveCategory::RegexEntry entry = { regex, type }; |
271 cat.regexes << entry; |
273 cat.regexes << entry; |
272 } |
274 } |
273 } |
275 } |
274 |
276 |
275 if (cat.regexes.size() > 0) |
277 if (cat.regexes.size() > 0) |
276 g_PrimitiveCategories << cat; |
278 g_PrimitiveCategories << cat; |
277 } |
279 } |
278 |
280 |
279 // Add a category for unmatched primitives |
281 // Add a category for unmatched primitives |
280 PrimitiveCategory cat; |
282 PrimitiveCategory cat; |
281 cat.setName (g_Other); |
283 cat.setName (g_Other); |
282 g_PrimitiveCategories << cat; |
284 g_PrimitiveCategories << cat; |
283 } |
285 } |
284 |
286 |
285 // ============================================================================= |
287 // ============================================================================= |
286 // ----------------------------------------------------------------------------- |
288 // ----------------------------------------------------------------------------- |
287 bool primitiveLoaderBusy() { |
289 bool primitiveLoaderBusy() |
288 return g_primListerMutex; |
290 { return g_primListerMutex; |
289 } |
291 } |
290 |
292 |
291 // ============================================================================= |
293 // ============================================================================= |
292 // ----------------------------------------------------------------------------- |
294 // ----------------------------------------------------------------------------- |
293 static double radialPoint (int i, int divs, double (*func) (double)) { |
295 static double radialPoint (int i, int divs, double (*func) (double)) |
294 return (*func) ((i * 2 * pi) / divs); |
296 { return (*func) ((i * 2 * pi) / divs); |
295 } |
297 } |
296 |
298 |
297 // ============================================================================= |
299 // ============================================================================= |
298 // ----------------------------------------------------------------------------- |
300 // ----------------------------------------------------------------------------- |
299 List<LDObject*> makePrimitive (PrimitiveType type, int segs, int divs, int num) { |
301 List<LDObject*> makePrimitive (PrimitiveType type, int segs, int divs, int num) |
300 List<LDObject*> objs; |
302 { List<LDObject*> objs; |
301 List<int> condLineSegs; |
303 List<int> condLineSegs; |
302 |
304 |
303 for (int i = 0; i < segs; ++i) { |
305 for (int i = 0; i < segs; ++i) |
304 double x0 = radialPoint (i, divs, cos), |
306 { double x0 = radialPoint (i, divs, cos), |
305 x1 = radialPoint (i + 1, divs, cos), |
307 x1 = radialPoint (i + 1, divs, cos), |
306 z0 = radialPoint (i, divs, sin), |
308 z0 = radialPoint (i, divs, sin), |
307 z1 = radialPoint (i + 1, divs, sin); |
309 z1 = radialPoint (i + 1, divs, sin); |
308 |
310 |
309 switch (type) { |
311 switch (type) |
310 case Circle: { |
312 { case Circle: |
311 vertex v0 (x0, 0.0f, z0), |
313 { vertex v0 (x0, 0.0f, z0), |
312 v1 (x1, 0.0f, z1); |
314 v1 (x1, 0.0f, z1); |
313 |
315 |
314 LDLine* line = new LDLine; |
316 LDLine* line = new LDLine; |
315 line->setVertex (0, v0); |
317 line->setVertex (0, v0); |
316 line->setVertex (1, v1); |
318 line->setVertex (1, v1); |
317 line->setColor (edgecolor); |
319 line->setColor (edgecolor); |
318 objs << line; |
320 objs << line; |
319 } |
321 } |
320 break; |
322 break; |
321 |
323 |
322 case Cylinder: |
324 case Cylinder: |
323 case Ring: |
325 case Ring: |
324 case Cone: |
326 case Cone: |
325 { |
327 { double x2, x3, z2, z3; |
326 double x2, x3, z2, z3; |
|
327 double y0, y1, y2, y3; |
328 double y0, y1, y2, y3; |
328 |
329 |
329 if (type == Cylinder) { |
330 if (type == Cylinder) |
330 x2 = x1; |
331 { x2 = x1; |
331 x3 = x0; |
332 x3 = x0; |
332 z2 = z1; |
333 z2 = z1; |
333 z3 = z0; |
334 z3 = z0; |
334 |
335 |
335 y0 = y1 = 0.0f; |
336 y0 = y1 = 0.0f; |
336 y2 = y3 = 1.0f; |
337 y2 = y3 = 1.0f; |
337 } else { |
338 } |
338 x2 = x1 * (num + 1); |
339 else |
|
340 { x2 = x1 * (num + 1); |
339 x3 = x0 * (num + 1); |
341 x3 = x0 * (num + 1); |
340 z2 = z1 * (num + 1); |
342 z2 = z1 * (num + 1); |
341 z3 = z0 * (num + 1); |
343 z3 = z0 * (num + 1); |
342 |
344 |
343 x0 *= num; |
345 x0 *= num; |
344 x1 *= num; |
346 x1 *= num; |
345 z0 *= num; |
347 z0 *= num; |
346 z1 *= num; |
348 z1 *= num; |
347 |
349 |
348 if (type == Ring) |
350 if (type == Ring) |
349 y0 = y1 = y2 = y3 = 0.0f; |
351 y0 = y1 = y2 = y3 = 0.0f; |
350 else { |
352 else |
351 y0 = y1 = 1.0f; |
353 { y0 = y1 = 1.0f; |
352 y2 = y3 = 0.0f; |
354 y2 = y3 = 0.0f; |
353 } |
355 } |
354 } |
356 } |
355 |
357 |
356 vertex v0 (x0, y0, z0), |
358 vertex v0 (x0, y0, z0), |
357 v1 (x1, y1, z1), |
359 v1 (x1, y1, z1), |
358 v2 (x2, y2, z2), |
360 v2 (x2, y2, z2), |
359 v3 (x3, y3, z3); |
361 v3 (x3, y3, z3); |
360 |
362 |
361 LDQuad* quad = new LDQuad; |
363 LDQuad* quad = new LDQuad; |
362 quad->setColor (maincolor); |
364 quad->setColor (maincolor); |
363 quad->setVertex (0, v0); |
365 quad->setVertex (0, v0); |
364 quad->setVertex (1, v1); |
366 quad->setVertex (1, v1); |
365 quad->setVertex (2, v2); |
367 quad->setVertex (2, v2); |
366 quad->setVertex (3, v3); |
368 quad->setVertex (3, v3); |
367 |
369 |
368 if (type == Cylinder) |
370 if (type == Cylinder) |
369 quad->invert(); |
371 quad->invert(); |
370 |
372 |
371 objs << quad; |
373 objs << quad; |
372 |
374 |
373 if (type == Cylinder || type == Cone) |
375 if (type == Cylinder || type == Cone) |
374 condLineSegs << i; |
376 condLineSegs << i; |
375 } |
377 } |
376 break; |
378 break; |
377 |
379 |
378 case Disc: |
380 case Disc: |
379 case DiscNeg: |
381 case DiscNeg: |
380 { |
382 { double x2, z2; |
381 double x2, z2; |
383 |
382 |
|
383 if (type == Disc) |
384 if (type == Disc) |
384 x2 = z2 = 0.0f; |
385 x2 = z2 = 0.0f; |
385 else { |
386 else |
386 x2 = (x0 >= 0.0f) ? 1.0f : -1.0f; |
387 { x2 = (x0 >= 0.0f) ? 1.0f : -1.0f; |
387 z2 = (z0 >= 0.0f) ? 1.0f : -1.0f; |
388 z2 = (z0 >= 0.0f) ? 1.0f : -1.0f; |
388 } |
389 } |
389 |
390 |
390 vertex v0 (x0, 0.0f, z0), |
391 vertex v0 (x0, 0.0f, z0), |
391 v1 (x1, 0.0f, z1), |
392 v1 (x1, 0.0f, z1), |
392 v2 (x2, 0.0f, z2); |
393 v2 (x2, 0.0f, z2); |
393 |
394 |
394 // Disc negatives need to go the other way around, otherwise |
395 // Disc negatives need to go the other way around, otherwise |
395 // they'll end up upside-down. |
396 // they'll end up upside-down. |
396 LDTriangle* seg = new LDTriangle; |
397 LDTriangle* seg = new LDTriangle; |
397 seg->setColor (maincolor); |
398 seg->setColor (maincolor); |
398 seg->setVertex (type == Disc ? 0 : 2, v0); |
399 seg->setVertex (type == Disc ? 0 : 2, v0); |
399 seg->setVertex (1, v1); |
400 seg->setVertex (1, v1); |
400 seg->setVertex (type == Disc ? 2 : 0, v2); |
401 seg->setVertex (type == Disc ? 2 : 0, v2); |
401 objs << seg; |
402 objs << seg; |
402 } |
403 } |
403 break; |
404 break; |
404 |
405 |
405 default: |
406 default: |
406 break; |
407 break; |
407 } |
408 } |
408 } |
409 } |
409 |
410 |
410 // If this is not a full circle, we need a conditional line at the other |
411 // If this is not a full circle, we need a conditional line at the other |
411 // end, too. |
412 // end, too. |
412 if (segs < divs && condLineSegs.size() != 0) |
413 if (segs < divs && condLineSegs.size() != 0) |
413 condLineSegs << segs; |
414 condLineSegs << segs; |
414 |
415 |
415 for (int i : condLineSegs) { |
416 for (int i : condLineSegs) |
416 vertex v0 (radialPoint (i, divs, cos), 0.0f, radialPoint (i, divs, sin)), |
417 { vertex v0 (radialPoint (i, divs, cos), 0.0f, radialPoint (i, divs, sin)), |
417 v1, |
418 v1, |
418 v2 (radialPoint (i + 1, divs, cos), 0.0f, radialPoint (i + 1, divs, sin)), |
419 v2 (radialPoint (i + 1, divs, cos), 0.0f, radialPoint (i + 1, divs, sin)), |
419 v3 (radialPoint (i - 1, divs, cos), 0.0f, radialPoint (i - 1, divs, sin)); |
420 v3 (radialPoint (i - 1, divs, cos), 0.0f, radialPoint (i - 1, divs, sin)); |
420 |
421 |
421 if (type == Cylinder) |
422 if (type == Cylinder) |
422 v1 = vertex (v0[X], 1.0f, v0[Z]); |
423 v1 = vertex (v0[X], 1.0f, v0[Z]); |
423 elif (type == Cone) { |
424 elif (type == Cone) |
424 v1 = vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1)); |
425 { v1 = vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1)); |
425 v0[X] *= num; |
426 v0[X] *= num; |
426 v0[Y] = 1.0f; |
427 v0[Y] = 1.0f; |
427 v0[Z] *= num; |
428 v0[Z] *= num; |
428 } |
429 } |
429 |
430 |
430 LDCndLine* line = new LDCndLine; |
431 LDCndLine* line = new LDCndLine; |
431 line->setColor (edgecolor); |
432 line->setColor (edgecolor); |
432 line->setVertex (0, v0); |
433 line->setVertex (0, v0); |
433 line->setVertex (1, v1); |
434 line->setVertex (1, v1); |
434 line->setVertex (2, v2); |
435 line->setVertex (2, v2); |
435 line->setVertex (3, v3); |
436 line->setVertex (3, v3); |
436 objs << line; |
437 objs << line; |
437 } |
438 } |
438 |
439 |
439 return objs; |
440 return objs; |
440 } |
441 } |
441 |
442 |
442 // ============================================================================= |
443 // ============================================================================= |
443 // ----------------------------------------------------------------------------- |
444 // ----------------------------------------------------------------------------- |
444 static str primitiveTypeName (PrimitiveType type) { |
445 static str primitiveTypeName (PrimitiveType type) |
445 // Not translated as primitives are in English. |
446 { // Not translated as primitives are in English. |
446 return type == Circle ? "Circle" : |
447 return type == Circle ? "Circle" : |
447 type == Cylinder ? "Cylinder" : |
448 type == Cylinder ? "Cylinder" : |
448 type == Disc ? "Disc" : |
449 type == Disc ? "Disc" : |
449 type == DiscNeg ? "Disc Negative" : |
450 type == DiscNeg ? "Disc Negative" : |
450 type == Ring ? "Ring" : "Cone"; |
451 type == Ring ? "Ring" : "Cone"; |
451 } |
452 } |
452 |
453 |
453 // ============================================================================= |
454 // ============================================================================= |
454 // ----------------------------------------------------------------------------- |
455 // ----------------------------------------------------------------------------- |
455 str radialFileName (PrimitiveType type, int segs, int divs, int num) { |
456 str radialFileName (PrimitiveType type, int segs, int divs, int num) |
456 short numer = segs, |
457 { short numer = segs, |
457 denom = divs; |
458 denom = divs; |
458 |
459 |
459 // Simplify the fractional part, but the denominator must be at least 4. |
460 // Simplify the fractional part, but the denominator must be at least 4. |
460 simplify (numer, denom); |
461 simplify (numer, denom); |
461 |
462 |
462 if (denom < 4) { |
463 if (denom < 4) |
463 const short factor = 4 / denom; |
464 { const short factor = 4 / denom; |
464 |
465 |
465 numer *= factor; |
466 numer *= factor; |
466 denom *= factor; |
467 denom *= factor; |
467 } |
468 } |
468 |
469 |
469 // Compose some general information: prefix, fraction, root, ring number |
470 // Compose some general information: prefix, fraction, root, ring number |
470 str prefix = (divs == lores) ? "" : fmt ("%1/", divs); |
471 str prefix = (divs == lores) ? "" : fmt ("%1/", divs); |
471 str frac = fmt ("%1-%2", numer, denom); |
472 str frac = fmt ("%1-%2", numer, denom); |
472 str root = g_radialNameRoots[type]; |
473 str root = g_radialNameRoots[type]; |
473 str numstr = (type == Ring || type == Cone) ? fmt ("%1", num) : ""; |
474 str numstr = (type == Ring || type == Cone) ? fmt ("%1", num) : ""; |
474 |
475 |
475 // Truncate the root if necessary (7-16rin4.dat for instance). |
476 // Truncate the root if necessary (7-16rin4.dat for instance). |
476 // However, always keep the root at least 2 characters. |
477 // However, always keep the root at least 2 characters. |
477 int extra = (frac.length() + numstr.length() + root.length()) - 8; |
478 int extra = (frac.length() + numstr.length() + root.length()) - 8; |
478 root.chop (min<short> (max<short> (extra, 0), 2)); |
479 root.chop (min<short> (max<short> (extra, 0), 2)); |
479 |
480 |
480 // Stick them all together and return the result. |
481 // Stick them all together and return the result. |
481 return prefix + frac + root + numstr + ".dat"; |
482 return prefix + frac + root + numstr + ".dat"; |
482 } |
483 } |
483 |
484 |
484 // ============================================================================= |
485 // ============================================================================= |
485 // ----------------------------------------------------------------------------- |
486 // ----------------------------------------------------------------------------- |
486 void generatePrimitive() { |
487 void generatePrimitive() |
487 PrimitivePrompt* dlg = new PrimitivePrompt (g_win); |
488 { PrimitivePrompt* dlg = new PrimitivePrompt (g_win); |
488 |
489 |
489 if (!dlg->exec()) |
490 if (!dlg->exec()) |
490 return; |
491 return; |
491 |
492 |
492 int segs = dlg->ui->sb_segs->value(); |
493 int segs = dlg->ui->sb_segs->value(); |
493 int divs = dlg->ui->cb_hires->isChecked() ? hires : lores; |
494 int divs = dlg->ui->cb_hires->isChecked() ? hires : lores; |
494 int num = dlg->ui->sb_ringnum->value(); |
495 int num = dlg->ui->sb_ringnum->value(); |
495 PrimitiveType type = |
496 PrimitiveType type = |
496 dlg->ui->rb_circle->isChecked() ? Circle : |
497 dlg->ui->rb_circle->isChecked() ? Circle : |
497 dlg->ui->rb_cylinder->isChecked() ? Cylinder : |
498 dlg->ui->rb_cylinder->isChecked() ? Cylinder : |
498 dlg->ui->rb_disc->isChecked() ? Disc : |
499 dlg->ui->rb_disc->isChecked() ? Disc : |
499 dlg->ui->rb_ndisc->isChecked() ? DiscNeg : |
500 dlg->ui->rb_ndisc->isChecked() ? DiscNeg : |
500 dlg->ui->rb_ring->isChecked() ? Ring : Cone; |
501 dlg->ui->rb_ring->isChecked() ? Ring : Cone; |
501 |
502 |
502 // Make the description |
503 // Make the description |
503 str frac = ftoa (((float) segs) / divs); |
504 str frac = ftoa ( ( (float) segs) / divs); |
504 str name = radialFileName (type, segs, divs, num); |
505 str name = radialFileName (type, segs, divs, num); |
505 str descr; |
506 str descr; |
506 |
507 |
507 // Ensure that there's decimals, even if they're 0. |
508 // Ensure that there's decimals, even if they're 0. |
508 if (frac.indexOf (".") == -1) |
509 if (frac.indexOf (".") == -1) |
509 frac += ".0"; |
510 frac += ".0"; |
510 |
511 |
511 if (type == Ring || type == Cone) { |
512 if (type == Ring || type == Cone) |
512 str spacing = |
513 { str spacing = |
513 (num < 10 ) ? " " : |
514 (num < 10) ? " " : |
514 (num < 100) ? " " : ""; |
515 (num < 100) ? " " : ""; |
515 |
516 |
516 descr = fmt ("%1 %2%3 x %4", primitiveTypeName (type), spacing, num, frac); |
517 descr = fmt ("%1 %2%3 x %4", primitiveTypeName (type), spacing, num, frac); |
517 } else |
518 } |
|
519 else |
518 descr = fmt ("%1 %2", primitiveTypeName (type), frac); |
520 descr = fmt ("%1 %2", primitiveTypeName (type), frac); |
519 |
521 |
520 // Prepend "Hi-Res" if 48/ primitive. |
522 // Prepend "Hi-Res" if 48/ primitive. |
521 if (divs == hires) |
523 if (divs == hires) |
522 descr.insert (0, "Hi-Res "); |
524 descr.insert (0, "Hi-Res "); |
523 |
525 |
524 LDFile* f = new LDFile; |
526 LDFile* f = new LDFile; |
525 f->setName (QFileDialog::getSaveFileName (null, QObject::tr ("Save Primitive"), name)); |
527 f->setName (QFileDialog::getSaveFileName (null, QObject::tr ("Save Primitive"), name)); |
526 |
528 |
527 f->addObjects ({ |
529 f->addObjects ( |
528 new LDComment (descr), |
530 { new LDComment (descr), |
529 new LDComment (fmt ("Name: %1", name)), |
531 new LDComment (fmt ("Name: %1", name)), |
530 new LDComment (fmt ("Author: LDForge")), |
532 new LDComment (fmt ("Author: LDForge")), |
531 new LDComment (fmt ("!LDRAW_ORG Unofficial_%1Primitive", divs == hires ? "48_" : "")), |
533 new LDComment (fmt ("!LDRAW_ORG Unofficial_%1Primitive", divs == hires ? "48_" : "")), |
532 new LDComment (CALicense), |
534 new LDComment (CALicense), |
533 new LDEmpty, |
535 new LDEmpty, |
534 new LDBFC (LDBFC::CertifyCCW), |
536 new LDBFC (LDBFC::CertifyCCW), |
535 new LDEmpty, |
537 new LDEmpty, |
536 }); |
538 }); |
537 |
539 |
538 f->addObjects (makePrimitive (type, segs, divs, num)); |
540 f->addObjects (makePrimitive (type, segs, divs, num)); |
539 |
541 |
540 g_win->save (f, false); |
542 g_win->save (f, false); |
541 delete f; |
543 delete f; |
542 } |
544 } |
543 |
545 |
544 // ============================================================================= |
546 // ============================================================================= |
545 // ----------------------------------------------------------------------------- |
547 // ----------------------------------------------------------------------------- |
546 PrimitivePrompt::PrimitivePrompt (QWidget* parent, Qt::WindowFlags f) : |
548 PrimitivePrompt::PrimitivePrompt (QWidget* parent, Qt::WindowFlags f) : |
547 QDialog (parent, f) { |
549 QDialog (parent, f) |
548 |
550 { |
|
551 |
549 ui = new Ui_MakePrimUI; |
552 ui = new Ui_MakePrimUI; |
550 ui->setupUi (this); |
553 ui->setupUi (this); |
551 connect (ui->cb_hires, SIGNAL (toggled(bool)), this, SLOT (hiResToggled (bool))); |
554 connect (ui->cb_hires, SIGNAL (toggled (bool)), this, SLOT (hiResToggled (bool))); |
552 } |
555 } |
553 |
556 |
554 // ============================================================================= |
557 // ============================================================================= |
555 // ----------------------------------------------------------------------------- |
558 // ----------------------------------------------------------------------------- |
556 PrimitivePrompt::~PrimitivePrompt() { |
559 PrimitivePrompt::~PrimitivePrompt() |
557 delete ui; |
560 { delete ui; |
558 } |
561 } |
559 |
562 |
560 // ============================================================================= |
563 // ============================================================================= |
561 // ----------------------------------------------------------------------------- |
564 // ----------------------------------------------------------------------------- |
562 void PrimitivePrompt::hiResToggled (bool on) { |
565 void PrimitivePrompt::hiResToggled (bool on) |
563 ui->sb_segs->setMaximum (on ? hires : lores); |
566 { ui->sb_segs->setMaximum (on ? hires : lores); |
564 |
567 |
565 // If the current value is 16 and we switch to hi-res, default the |
568 // If the current value is 16 and we switch to hi-res, default the |
566 // spinbox to 48. |
569 // spinbox to 48. |
567 if (on && ui->sb_segs->value() == lores) |
570 if (on && ui->sb_segs->value() == lores) |
568 ui->sb_segs->setValue (hires); |
571 ui->sb_segs->setValue (hires); |
569 } |
572 } |
570 #include "moc_primitives.cpp" |
|