1 #include "lc_global.h"
2 #include "lc_synth.h"
3 #include "lc_library.h"
4 #include "lc_application.h"
5 #include "lc_file.h"
6 #include "lc_meshloader.h"
7 #include "pieceinf.h"
8 #include <locale.h>
9 
10 class lcSynthInfoCurved : public lcSynthInfo
11 {
12 public:
13 	lcSynthInfoCurved(float Length, float DefaultScale, int NumSections, bool RigidEdges);
14 
15 	void GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
16 	void VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
17 
18 protected:
19 	float GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const;
20 	void CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const override;
21 	static void AddTubeParts(lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections, float Radius, bool IsInner);
22 
23 	struct lcSynthComponent
24 	{
25 		lcMatrix44 Transform;
26 		float Length;
27 	};
28 
29 	lcSynthComponent mStart;
30 	lcSynthComponent mMiddle;
31 	lcSynthComponent mEnd;
32 	float mCenterLength = 0.0f;
33 	int mNumSections;
34 	float mDefaultScale;
35 	bool mRigidEdges;
36 };
37 
38 class lcSynthInfoFlexibleHose : public lcSynthInfoCurved
39 {
40 public:
41 	lcSynthInfoFlexibleHose(float Length, int NumSections, const char* EdgePart2);
42 
43 protected:
44 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
45 
46 	const char* mEdgePart2;
47 };
48 
49 class lcSynthInfoFlexSystemHose : public lcSynthInfoCurved
50 {
51 public:
52 	lcSynthInfoFlexSystemHose(float Length, int NumSections);
53 
54 	void GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
55 
56 protected:
57 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
58 };
59 
60 class lcSynthInfoPneumaticTube : public lcSynthInfoCurved
61 {
62 public:
63 	lcSynthInfoPneumaticTube(float Length, int NumSections, const char* EndPart);
64 
65 protected:
66 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
67 
68 	const char* mEndPart;
69 };
70 
71 class lcSynthInfoRibbedHose : public lcSynthInfoCurved
72 {
73 public:
74 	lcSynthInfoRibbedHose(float Length, int NumSections);
75 
76 protected:
77 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
78 };
79 
80 class lcSynthInfoFlexibleAxle : public lcSynthInfoCurved
81 {
82 public:
83 	lcSynthInfoFlexibleAxle(float Length, int NumSections);
84 
85 protected:
86 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
87 };
88 
89 class lcSynthInfoBraidedString : public lcSynthInfoCurved
90 {
91 public:
92 	lcSynthInfoBraidedString(float Length, int NumSections);
93 
94 protected:
95 	void CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const override;
96 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
97 };
98 
99 class lcSynthInfoStraight : public lcSynthInfo
100 {
101 public:
102 	explicit lcSynthInfoStraight(float Length);
103 
104 	void VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
105 
106 protected:
107 	void CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const override;
108 };
109 
110 class lcSynthInfoShockAbsorber : public lcSynthInfoStraight
111 {
112 public:
113 	explicit lcSynthInfoShockAbsorber(const char* SpringPart);
114 
115 	void GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
116 
117 protected:
118 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
119 
120 	const char* mSpringPart;
121 };
122 
123 class lcSynthInfoActuator : public lcSynthInfoStraight
124 {
125 public:
126 	explicit lcSynthInfoActuator(const char* BodyPart, const char* PistonPart, const char* AxlePart, float Length, float AxleOffset);
127 
128 	void GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
129 
130 protected:
131 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
132 
133 	const char* mBodyPart;
134 	const char* mPistonPart;
135 	const char* mAxlePart;
136 	float mAxleOffset;
137 };
138 
139 class lcSynthInfoUniversalJoint : public lcSynthInfo
140 {
141 public:
142 	lcSynthInfoUniversalJoint(float Length, float EndOffset, const char* EndPart, const char* CenterPart);
143 
144 	void GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
145 	void VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const override;
146 
147 protected:
148 	void CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const override;
149 	void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const override;
150 
151 	float mEndOffset;
152 	const char* mEndPart;
153 	const char* mCenterPart;
154 };
155 
lcSynthInit()156 void lcSynthInit()
157 {
158 	lcPiecesLibrary* Library = lcGetPiecesLibrary();
159 
160 	static const struct
161 	{
162 		char PartID[16];
163 		float Length;
164 		int NumSections;
165 		char EdgePart2[8];
166 	}
167 	FlexibleHoses[] =
168 	{
169 		{ "73590a.dat", 140.0f, 51, "752.dat" }, // Hose Flexible  8.5L without Tabs
170 		{ "73590b.dat", 140.0f, 51, "750.dat" }, // Hose Flexible  8.5L with Tabs
171 	};
172 
173 	for (const auto& HoseInfo: FlexibleHoses)
174 	{
175 		PieceInfo* Info = Library->FindPiece(HoseInfo.PartID, nullptr, false, false);
176 
177 		if (Info)
178 			Info->SetSynthInfo(new lcSynthInfoFlexibleHose(HoseInfo.Length, HoseInfo.NumSections, HoseInfo.EdgePart2));
179 	}
180 
181 	static const struct
182 	{
183 		char PartID[16];
184 		float Length;
185 		int NumSections;
186 	}
187 	FlexSystemHoses[] =
188 	{
189 		{ "76263.dat",      60.0f,  29 }, // Technic Flex-System Hose  3L (60LDU)
190 		{ "76250.dat",      80.0f,  39 }, // Technic Flex-System Hose  4L (80LDU)
191 		{ "76307.dat",     100.0f,  49 }, // Technic Flex-System Hose  5L (100LDU)
192 		{ "76279.dat",     120.0f,  59 }, // Technic Flex-System Hose  6L (120LDU)
193 		{ "76289.dat",     140.0f,  69 }, // Technic Flex-System Hose  7L (140LDU)
194 		{ "76260.dat",     160.0f,  79 }, // Technic Flex-System Hose  8L (160LDU)
195 		{ "76324.dat",     180.0f,  89 }, // Technic Flex-System Hose  9L (180LDU)
196 		{ "76348.dat",     200.0f,  99 }, // Technic Flex-System Hose 10L (200LDU)
197 		{ "71505.dat",     220.0f, 109 }, // Technic Flex-System Hose 11L (220LDU)
198 		{ "71175.dat",     240.0f, 119 }, // Technic Flex-System Hose 12L (240LDU)
199 		{ "71551.dat",     260.0f, 129 }, // Technic Flex-System Hose 13L (260LDU)
200 		{ "71177.dat",     280.0f, 139 }, // Technic Flex-System Hose 14L (280LDU)
201 		{ "71194.dat",     300.0f, 149 }, // Technic Flex-System Hose 15L (300LDU)
202 		{ "71192.dat",     320.0f, 159 }, // Technic Flex-System Hose 16L (320LDU)
203 		{ "76270.dat",     340.0f, 169 }, // Technic Flex-System Hose 17L (340LDU)
204 		{ "71582.dat",     360.0f, 179 }, // Technic Flex-System Hose 18L (360LDU)
205 		{ "22463.dat",     380.0f, 189 }, // Technic Flex-System Hose 19L (380LDU)
206 		{ "76276.dat",     400.0f, 199 }, // Technic Flex-System Hose 20L (400LDU)
207 		{ "70978.dat",     420.0f, 209 }, // Technic Flex-System Hose 21L (420LDU)
208 		{ "76252.dat",     440.0f, 219 }, // Technic Flex-System Hose 22L (440LDU)
209 		{ "76254.dat",     460.0f, 229 }, // Technic Flex-System Hose 23L (460LDU)
210 		{ "76277.dat",     480.0f, 239 }, // Technic Flex-System Hose 24L (480LDU)
211 		{ "53475.dat",     520.0f, 259 }, // Technic Flex-System Hose 26L (520LDU)
212 		{ "76280.dat",     560.0f, 279 }, // Technic Flex-System Hose 28L (560LDU)
213 		{ "76389.dat",     580.0f, 289 }, // Technic Flex-System Hose 29L (580LDU)
214 		{ "76282.dat",     600.0f, 299 }, // Technic Flex-System Hose 30L (600LDU)
215 		{ "76283.dat",     620.0f, 309 }, // Technic Flex-System Hose 31L (620LDU)
216 		{ "57274.dat",     640.0f, 319 }, // Technic Flex-System Hose 32L (640LDU)
217 		{ "42688.dat",     660.0f, 329 }, // Technic Flex-System Hose 33L (660LDU)
218 		{ "22461.dat",     680.0f, 339 }, // Technic Flex-System Hose 34L (680LDU)
219 		{ "46305.dat",     800.0f, 399 }, // Technic Flex-System Hose 40L (800LDU)
220 		{ "76281.dat",     900.0f, 449 }, // Technic Flex-System Hose 45L (900LDU)
221 		{ "22296.dat",    1060.0f, 529 }, // Technic Flex-System Hose 53L (1060LDU)
222 	};
223 
224 	for (const auto& HoseInfo: FlexSystemHoses)
225 	{
226 		PieceInfo* Info = Library->FindPiece(HoseInfo.PartID, nullptr, false, false);
227 
228 		if (Info)
229 			Info->SetSynthInfo(new lcSynthInfoFlexSystemHose(HoseInfo.Length, HoseInfo.NumSections));
230 	}
231 
232 	static const struct
233 	{
234 		char PartID[16];
235 		float Length;
236 		int NumSections;
237 	}
238 	PneumaticTubes[] =
239 	{
240 		{ "21761-f1.dat",   60.0f,  10 }, // Technic Pneumatic Tube  3L
241 		{ "26445-f1.dat",   80.0f,  20 }, // Technic Pneumatic Tube  4L
242 		{ "14653-f1.dat",  100.0f,  20 }, // Technic Pneumatic Tube  5L
243 		{ "21766-f1.dat",  120.0f,  40 }, // Technic Pneumatic Tube  6L
244 		{ "14657-f1.dat",  140.0f,  40 }, // Technic Pneumatic Tube  7L
245 		{ "21837-f1.dat",  160.0f,  40 }, // Technic Pneumatic Tube  8L
246 		{ "21826-f1.dat",  180.0f,  40 }, // Technic Pneumatic Tube  9L
247 		{ "21767-f1.dat",  200.0f,  80 }, // Technic Pneumatic Tube 10L
248 		{ "63539-f1.dat",  240.0f,  80 }, // Technic Pneumatic Tube 12L
249 		{ "37467-f1.dat",  260.0f,  80 }, // Technic Pneumatic Tube 13L
250 		{ "37461-f1.dat",  280.0f,  80 }, // Technic Pneumatic Tube 14L
251 		{ "87948-f1.dat",  320.0f,  80 }, // Technic Pneumatic Tube 16L
252 		{ "53168-f1.dat",  340.0f,  80 }, // Technic Pneumatic Tube 17L
253 		{ "21839-f1.dat",  380.0f, 160 }, // Technic Pneumatic Tube 19L
254 		{ "87950-f1.dat",  400.0f, 160 }, // Technic Pneumatic Tube 20L
255 		{ "53184-f1.dat",  420.0f, 160 }, // Technic Pneumatic Tube 21L
256 		{ "26436-f1.dat",  460.0f, 160 }, // Technic Pneumatic Tube 23L
257 		{ "21830-f1.dat",  540.0f, 160 }, // Technic Pneumatic Tube 27L
258 		{ "21825-f1.dat",  560.0f, 160 }, // Technic Pneumatic Tube 28L
259 		{ "21833-f1.dat",  600.0f, 160 }, // Technic Pneumatic Tube 30L
260 		{ "26440-f1.dat",  640.0f, 160 }, // Technic Pneumatic Tube 32L
261 		{ "96889-f1.dat",  660.0f, 160 }, // Technic Pneumatic Tube 33L
262 		{ "87949-f1.dat",  720.0f, 320 }, // Technic Pneumatic Tube 36L
263 		{ "21835-f1.dat",  740.0f, 320 }, // Technic Pneumatic Tube 37L
264 		{ "14661-f1.dat",  780.0f, 320 }, // Technic Pneumatic Tube 39L
265 		{ "26438-f1.dat",  800.0f, 320 }, // Technic Pneumatic Tube 40L
266 		{ "44079-f1.dat",  840.0f, 320 }, // Technic Pneumatic Tube 42L
267 		{ "26439-f1.dat",  960.0f, 320 }, // Technic Pneumatic Tube 48L
268 		{ "96890-f1.dat", 1080.0f, 320 }, // Technic Pneumatic Tube 54L
269 		{ "96891-f1.dat", 1600.0f, 320 }, // Technic Pneumatic Tube 80L
270 	};
271 
272 	for (const auto& TubeInfo: PneumaticTubes)
273 	{
274 		PieceInfo* Info = Library->FindPiece(TubeInfo.PartID, nullptr, false, false);
275 
276 		if (Info)
277 			Info->SetSynthInfo(new lcSynthInfoPneumaticTube(TubeInfo.Length, TubeInfo.NumSections, "71533k02.dat"));
278 
279 		auto RegularInfo = TubeInfo;
280 		RegularInfo.PartID[7] = '2';
281 		RegularInfo.Length -= 40.0f;
282 
283 		Info = Library->FindPiece(RegularInfo.PartID, nullptr, false, false);
284 
285 		if (Info)
286 			Info->SetSynthInfo(new lcSynthInfoPneumaticTube(RegularInfo.Length, RegularInfo.NumSections, "71533k01.dat"));
287 	}
288 
289 	static const struct
290 	{
291 		char PartID[16];
292 		float Length;
293 		int NumSections;
294 	}
295 	RibbedHoses[] =
296 	{
297 		{ "72504.dat",     31.25f,   4 }, // Technic Ribbed Hose  2L
298 		{ "72706.dat",     50.00f,   7 }, // Technic Ribbed Hose  3L
299 		{ "71952.dat",     75.00f,  11 }, // Technic Ribbed Hose  4L
300 		{ "72853.dat",     93.75f,  14 }, // Technic Ribbed Hose  5L
301 		{ "71944.dat",    112.50f,  17 }, // Technic Ribbed Hose  6L
302 		{ "57719.dat",    131.25f,  20 }, // Technic Ribbed Hose  7L
303 		{ "71951.dat",    150.00f,  23 }, // Technic Ribbed Hose  8L
304 		{ "71917.dat",    175.00f,  27 }, // Technic Ribbed Hose  9L
305 		{ "71949.dat",    193.75f,  30 }, // Technic Ribbed Hose 10L
306 		{ "71986.dat",    212.50f,  33 }, // Technic Ribbed Hose 11L
307 		{ "71819.dat",    231.25f,  36 }, // Technic Ribbed Hose 12L
308 		{ "71923.dat",    275.00f,  43 }, // Technic Ribbed Hose 14L
309 		{ "71946.dat",    293.75f,  46 }, // Technic Ribbed Hose 15L
310 		{ "71947.dat",    312.50f,  49 }, // Technic Ribbed Hose 16L
311 		{ "22900.dat",    331.25f,  52 }, // Technic Ribbed Hose 17L
312 		{ "72039.dat",    350.00f,  55 }, // Technic Ribbed Hose 18L
313 		{ "43675.dat",    375.00f,  58 }, // Technic Ribbed Hose 19L
314 		{ "23397.dat",    468.75f,  74 }, // Technic Ribbed Hose 24L
315 		{ "33763.dat",    512.50f,  81 }, // Technic Ribbed Hose 26L
316 	};
317 
318 	for (const auto& HoseInfo: RibbedHoses)
319 	{
320 		PieceInfo* Info = Library->FindPiece(HoseInfo.PartID, nullptr, false, false);
321 
322 		if (Info)
323 			Info->SetSynthInfo(new lcSynthInfoRibbedHose(HoseInfo.Length, HoseInfo.NumSections));
324 	}
325 
326 	static const struct
327 	{
328 		char PartID[16];
329 		float Length;
330 		int NumSections;
331 	}
332 	FlexibleAxles[] =
333 	{
334 		{ "32580.dat",    120.00f,  15 }, // Technic Axle Flexible  7
335 		{ "32199.dat",    200.00f,  35 }, // Technic Axle Flexible 11
336 		{ "55709.dat",    200.00f,  35 }, // Technic Axle Flexible 11
337 		{ "32200.dat",    220.00f,  40 }, // Technic Axle Flexible 12
338 		{ "32201.dat",    260.00f,  50 }, // Technic Axle Flexible 14
339 		{ "32202.dat",    300.00f,  60 }, // Technic Axle Flexible 16
340 		{ "32235.dat",    360.00f,  75 }, // Technic Axle Flexible 19
341 	};
342 
343 	for (const auto& AxleInfo: FlexibleAxles)
344 	{
345 		PieceInfo* Info = Library->FindPiece(AxleInfo.PartID, nullptr, false, false);
346 
347 		if (Info)
348 			Info->SetSynthInfo(new lcSynthInfoFlexibleAxle(AxleInfo.Length, AxleInfo.NumSections));
349 	}
350 
351 	static const struct
352 	{
353 		char PartID[16];
354 		float Length;
355 		int NumSections;
356 	}
357 	BraidedStrings[] =
358 	{
359 		{ "76384.dat",    200.00f,  46 }, // String Braided 11L with End Studs
360 		{ "75924.dat",    400.00f,  96 }, // String Braided 21L with End Studs
361 		{ "572C02.dat",   800.00f, 196 }, // String Braided 41L with End Studs
362 	};
363 
364 	for (const auto& StringInfo: BraidedStrings)
365 	{
366 		PieceInfo* Info = Library->FindPiece(StringInfo.PartID, nullptr, false, false);
367 
368 		if (Info)
369 			Info->SetSynthInfo(new lcSynthInfoBraidedString(StringInfo.Length, StringInfo.NumSections));
370 	}
371 
372 	static const struct
373 	{
374 		char PartID[16];
375 		char SpringPart[16];
376 	}
377 	ShockAbsorbers[] =
378 	{
379 		{ "73129.dat", "70038.dat" }, // Technic Shock Absorber 6.5L
380 		{ "41838.dat", "41837.dat" }, // Technic Shock Absorber 6.5L Soft
381 		{ "76138.dat", "71953.dat" }, // Technic Shock Absorber 6.5L Stiff
382 		{ "76537.dat", "22977.dat" }, // Technic Shock Absorber 6.5L Extra Stiff
383 	};
384 
385 	for (const auto& AbsorberInfo: ShockAbsorbers)
386 	{
387 		PieceInfo* Info = Library->FindPiece(AbsorberInfo.PartID, nullptr, false, false);
388 
389 		if (Info)
390 			Info->SetSynthInfo(new lcSynthInfoShockAbsorber(AbsorberInfo.SpringPart));
391 	}
392 
393 	static const struct
394 	{
395 		char PartID[16];
396 		char BodyPart[16];
397 		char PistonPart[16];
398 		char AxlePart[16];
399 		float Length;
400 		float AxleOffset;
401 	}
402 	Actuators[] =
403 	{
404 		{ "61927-F1.dat",    "62271c01.dat", "62274c01.dat", "47157.dat", 170.00f,  0.0f }, // Technic Linear Actuator 8 x 2 x 2 (Contracted)
405 		{ "61927-F2.dat",    "62271c01.dat", "62274c01.dat", "47157.dat", 270.00f,  0.0f }, // Technic Linear Actuator 8 x 2 x 2 (Extended)
406 		{ "61927C01.dat",    "62271c01.dat", "62274c01.dat", "47157.dat", 270.00f,  0.0f }, // Moved to 61927-f2 (was Technic Power Functions Linear Actuator (Extended))
407 		{ "61927.dat",       "62271c01.dat", "62274c01.dat", "47157.dat", 170.00f,  0.0f }, // Moved to 61927-f1 (was Technic Power Functions Linear Actuator (Contracted))
408 		{ "92693C01-F1.dat", "92693c01.dat", "92696.dat",    "92695.dat", 120.00f, 30.0f }, // Technic Linear Actuator 4 x 1 x 1 (Contracted)
409 		{ "92693C01-F2.dat", "92693c01.dat", "92696.dat",    "92695.dat", 180.00f, 30.0f }, // Technic Linear Actuator 4 x 1 x 1 (Extended)
410 		{ "92693C02.dat",    "92693c01.dat", "92696.dat",    "92695.dat", 120.00f, 30.0f }, // Moved to 92693c01-f1 (was Technic Linear Actuator Small (Contracted))
411 		{ "92693C03.dat",    "92693c01.dat", "92696.dat",    "92695.dat", 180.00f, 30.0f }, // Moved to 92693c01-f2 (was Technic Linear Actuator Small (Extended))
412 	};
413 
414 	for (const auto& ActuatorInfo: Actuators)
415 	{
416 		PieceInfo* Info = Library->FindPiece(ActuatorInfo.PartID, nullptr, false, false);
417 
418 		if (Info)
419 			Info->SetSynthInfo(new lcSynthInfoActuator(ActuatorInfo.BodyPart, ActuatorInfo.PistonPart,
420 					ActuatorInfo.AxlePart, ActuatorInfo.Length, ActuatorInfo.AxleOffset));
421 	}
422 
423 	static const struct
424 	{
425 		char PartID[16];
426 		float Length;
427 		float EndOffset;
428 		char EndPart[16];
429 		char CenterPart[16];
430 	}
431 	UniversalJoints[] =
432 	{
433 		{ "61903.dat",   60.00f,  0.0f, "62520.dat", "62519.dat" }, // Technic Universal Joint 3L (Complete)
434 		{ "3712C01.dat", 60.00f, 30.0f, "3712.dat",  "3326.dat"  }, // Technic Universal Joint 4L with Bush Ends with Centre Type 2 (Complete)
435 		{ "3712C03.dat", 60.00f, 30.0f, "3712.dat",  "3326a.dat" }, // Technic Universal Joint 4L with Bush Ends with Centre Type 1 (Complete)
436 		{ "575C01.dat",  60.00f, 30.0f, "575.dat",   "3326a.dat" }  // Technic Universal Joint Type 1 (Complete)
437 	};
438 
439 	for (const auto& JointInfo: UniversalJoints)
440 	{
441 		PieceInfo* Info = Library->FindPiece(JointInfo.PartID, nullptr, false, false);
442 
443 		if (Info)
444 			Info->SetSynthInfo(new lcSynthInfoUniversalJoint(JointInfo.Length, JointInfo.EndOffset, JointInfo.EndPart, JointInfo.CenterPart));
445 	}
446 
447 //	"758C01" // Hose Flexible  12L
448 }
449 
lcSynthInfo(float Length)450 lcSynthInfo::lcSynthInfo(float Length)
451 	: mLength(Length)
452 {
453 }
454 
lcSynthInfoCurved(float Length,float DefaultScale,int NumSections,bool RigidEdges)455 lcSynthInfoCurved::lcSynthInfoCurved(float Length, float DefaultScale, int NumSections, bool RigidEdges)
456 	: lcSynthInfo(Length), mNumSections(NumSections), mDefaultScale(DefaultScale), mRigidEdges(RigidEdges)
457 {
458 	mCurve = true;
459 
460 	mStart.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f));
461 	mEnd.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f));
462 }
463 
lcSynthInfoFlexibleHose(float Length,int NumSections,const char * EdgePart2)464 lcSynthInfoFlexibleHose::lcSynthInfoFlexibleHose(float Length, int NumSections, const char* EdgePart2)
465 	: lcSynthInfoCurved(Length, 12.f, NumSections, true),
466 	mEdgePart2(EdgePart2)
467 {
468 	mStart.Length = 5.0f;
469 	mMiddle.Length = 2.56f;
470 	mEnd.Length = 5.0f;
471 	mCenterLength = 4.56f;
472 }
473 
lcSynthInfoFlexSystemHose(float Length,int NumSections)474 lcSynthInfoFlexSystemHose::lcSynthInfoFlexSystemHose(float Length, int NumSections)
475 	: lcSynthInfoCurved(Length, 12.f, NumSections, true)
476 {
477 	mStart.Transform = lcMatrix44Identity();
478 	mEnd.Transform = lcMatrix44Identity();
479 	mStart.Length = 1.0f;
480 	mMiddle.Length = 2.0f;
481 	mEnd.Length = 1.0f;
482 }
483 
lcSynthInfoPneumaticTube(float Length,int NumSections,const char * EndPart)484 lcSynthInfoPneumaticTube::lcSynthInfoPneumaticTube(float Length, int NumSections, const char* EndPart)
485 	: lcSynthInfoCurved(Length, 12.f, NumSections, true),
486 	mEndPart(EndPart)
487 {
488 	mStart.Length = 0.0f;
489 	mMiddle.Length = mLength / NumSections;
490 	mEnd.Length = 0.0f;
491 }
492 
lcSynthInfoRibbedHose(float Length,int NumSections)493 lcSynthInfoRibbedHose::lcSynthInfoRibbedHose(float Length, int NumSections)
494 	: lcSynthInfoCurved(Length, 80.0f, NumSections, false)
495 {
496 	mStart.Length = 6.25f;
497 	mMiddle.Length = 6.25f;
498 	mEnd.Length = 6.25f;
499 }
500 
lcSynthInfoFlexibleAxle(float Length,int NumSections)501 lcSynthInfoFlexibleAxle::lcSynthInfoFlexibleAxle(float Length, int NumSections)
502 	: lcSynthInfoCurved(Length, 12.0f, NumSections, true)
503 {
504 	mStart.Length = 30.0f;
505 	mMiddle.Length = 4.0f;
506 	mEnd.Length = 30.0f;
507 }
508 
lcSynthInfoBraidedString(float Length,int NumSections)509 lcSynthInfoBraidedString::lcSynthInfoBraidedString(float Length, int NumSections)
510 	: lcSynthInfoCurved(Length, 12.0f, NumSections, true)
511 {
512 	mStart.Transform = lcMatrix44Identity();
513 	mEnd.Transform = lcMatrix44Identity();
514 	mStart.Length = 8.0f;
515 	mMiddle.Length = 4.0f;
516 	mEnd.Length = 8.0f;
517 }
518 
lcSynthInfoStraight(float Length)519 lcSynthInfoStraight::lcSynthInfoStraight(float Length)
520 	: lcSynthInfo(Length)
521 {
522 	mUnidirectional = true;
523 }
524 
lcSynthInfoShockAbsorber(const char * SpringPart)525 lcSynthInfoShockAbsorber::lcSynthInfoShockAbsorber(const char* SpringPart)
526 	: lcSynthInfoStraight(110.00f), mSpringPart(SpringPart)
527 {
528 }
529 
lcSynthInfoActuator(const char * BodyPart,const char * PistonPart,const char * AxlePart,float Length,float AxleOffset)530 lcSynthInfoActuator::lcSynthInfoActuator(const char* BodyPart, const char* PistonPart, const char* AxlePart, float Length, float AxleOffset)
531 	: lcSynthInfoStraight(Length), mBodyPart(BodyPart), mPistonPart(PistonPart), mAxlePart(AxlePart), mAxleOffset(AxleOffset)
532 {
533 }
534 
lcSynthInfoUniversalJoint(float Length,float EndOffset,const char * EndPart,const char * CenterPart)535 lcSynthInfoUniversalJoint::lcSynthInfoUniversalJoint(float Length, float EndOffset, const char* EndPart, const char* CenterPart)
536 	: lcSynthInfo(Length), mEndOffset(EndOffset), mEndPart(EndPart), mCenterPart(CenterPart)
537 {
538 	mNondirectional = true;
539 }
540 
GetDefaultControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const541 void lcSynthInfoCurved::GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
542 {
543 	ControlPoints.SetSize(2);
544 
545 	float HalfLength = mLength / 2.0f;
546 	float Scale = lcMin(mDefaultScale, HalfLength);
547 
548 	ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(-HalfLength, 0.0f, 0.0f));
549 	ControlPoints[1].Transform = lcMatrix44Translation(lcVector3( HalfLength, 0.0f, 0.0f));
550 
551 	ControlPoints[0].Scale = Scale;
552 	ControlPoints[1].Scale = Scale;
553 }
554 
VerifyControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const555 void lcSynthInfoCurved::VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
556 {
557 	if (ControlPoints.GetSize() < 2)
558 		GetDefaultControlPoints(ControlPoints);
559 }
560 
GetDefaultControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const561 void lcSynthInfoFlexSystemHose::GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
562 {
563 	lcSynthInfoCurved::GetDefaultControlPoints(ControlPoints);
564 
565 	ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength));
566 	ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f));
567 }
568 
VerifyControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const569 void lcSynthInfoStraight::VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
570 {
571 	if (ControlPoints.GetSize() < 2)
572 		GetDefaultControlPoints(ControlPoints);
573 	else
574 		ControlPoints.SetSize(2);
575 }
576 
GetDefaultControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const577 void lcSynthInfoShockAbsorber::GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
578 {
579 	ControlPoints.SetSize(2);
580 
581 	ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength));
582 	ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f));
583 
584 	ControlPoints[0].Scale = 1.0f;
585 	ControlPoints[1].Scale = 1.0f;
586 }
587 
GetDefaultControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const588 void lcSynthInfoActuator::GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
589 {
590 	ControlPoints.SetSize(2);
591 
592 	ControlPoints[0].Transform = lcMatrix44(lcMatrix33(lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f));
593 	ControlPoints[1].Transform = lcMatrix44(lcMatrix33(lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, mLength, 0.0f));
594 
595 	ControlPoints[0].Scale = 1.0f;
596 	ControlPoints[1].Scale = 1.0f;
597 }
598 
GetDefaultControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const599 void lcSynthInfoUniversalJoint::GetDefaultControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
600 {
601 	ControlPoints.SetSize(1);
602 	float HalfLength = mLength / 2;
603 
604 	ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, HalfLength, 0.0f));
605 	ControlPoints[0].Scale = 1.0f;
606 }
607 
VerifyControlPoints(lcArray<lcPieceControlPoint> & ControlPoints) const608 void lcSynthInfoUniversalJoint::VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const
609 {
610 	if (ControlPoints.IsEmpty())
611 		GetDefaultControlPoints(ControlPoints);
612 	else
613 		ControlPoints.SetSize(1);
614 }
615 
GetSectionTwist(const lcMatrix44 & StartTransform,const lcMatrix44 & EndTransform) const616 float lcSynthInfoCurved::GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const
617 {
618 	lcVector3 StartTangent(StartTransform[1].x, StartTransform[1].y, StartTransform[1].z);
619 	lcVector3 EndTangent(EndTransform[1].x, EndTransform[1].y, EndTransform[1].z);
620 	lcVector3 StartUp(StartTransform[2].x, StartTransform[2].y, StartTransform[2].z);
621 	lcVector3 EndUp(EndTransform[2].x, EndTransform[2].y, EndTransform[2].z);
622 
623 	float TangentDot = lcDot(StartTangent, EndTangent);
624 	float UpDot = lcDot(StartUp, EndUp);
625 
626 	if (TangentDot > 0.99f && UpDot > 0.99f)
627 		return 0.0f;
628 
629 	if (fabs(TangentDot) > 0.99f)
630 	{
631 		return acosf(lcClamp(lcDot(EndUp, StartUp), -1.0f, 1.0f));
632 	}
633 	else if (TangentDot > -0.99f)
634 	{
635 		lcVector3 Axis = lcCross(StartTangent, EndTangent);
636 		float Angle = acosf(lcClamp(TangentDot, -1.0f, 1.0f));
637 
638 		lcMatrix33 Rotation = lcMatrix33FromAxisAngle(Axis, Angle);
639 		lcVector3 AdjustedStartUp = lcMul(StartUp, Rotation);
640 		return acosf(lcClamp(lcDot(EndUp, AdjustedStartUp), -1.0f, 1.0f));
641 	}
642 
643 	lcVector3 StartSide(StartTransform[0].x, StartTransform[0].y, StartTransform[0].z);
644 	lcVector3 EndSide(EndTransform[0].x, EndTransform[0].y, EndTransform[0].z);
645 
646 	float SideDot = lcDot(StartSide, EndSide);
647 
648 	if (fabs(SideDot) < 0.99f)
649 	{
650 		lcVector3 Axis = lcCross(StartSide, EndSide);
651 		float Angle = acosf(SideDot);
652 
653 		lcMatrix33 Rotation = lcMatrix33FromAxisAngle(Axis, Angle);
654 		lcVector3 AdjustedStartUp = lcMul(StartUp, Rotation);
655 		return acosf(lcClamp(lcDot(EndUp, AdjustedStartUp), -1.0f, 1.0f));
656 	}
657 
658 	return 0.0f;
659 }
660 
CalculateSections(const lcArray<lcPieceControlPoint> & ControlPoints,lcArray<lcMatrix44> & Sections,SectionCallbackFunc SectionCallback) const661 void lcSynthInfoCurved::CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const
662 {
663 	float SectionLength = 0.0f;
664 
665 	for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize() - 1 && Sections.GetSize() < mNumSections + 2; ControlPointIdx++)
666 	{
667 		lcVector3 SegmentControlPoints[4];
668 
669 		lcMatrix44 StartTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform);
670 		lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx + 1].Transform);
671 		StartTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mStart.Transform), lcMatrix33(StartTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), StartTransform.GetTranslation());
672 
673 		if (ControlPointIdx == 0)
674 		{
675 			if (mRigidEdges)
676 			{
677 				StartTransform.SetTranslation(lcMul30(lcVector3(0.0f, mStart.Length, 0.0f), StartTransform) + StartTransform.GetTranslation());
678 				SectionLength = 0.0f;
679 			}
680 			else
681 				SectionLength = mStart.Length;
682 
683 			Sections.Add(StartTransform);
684 		}
685 
686 		EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation());
687 
688 		SegmentControlPoints[0] = StartTransform.GetTranslation();
689 		SegmentControlPoints[1] = lcMul31(lcVector3(0.0f, ControlPoints[ControlPointIdx].Scale, 0.0f), StartTransform);
690 		SegmentControlPoints[2] = lcMul31(lcVector3(0.0f, -ControlPoints[ControlPointIdx + 1].Scale, 0.0f), EndTransform);
691 		SegmentControlPoints[3] = EndTransform.GetTranslation();
692 
693 		const int NumCurvePoints = 8192;
694 		lcArray<lcVector3> CurvePoints;
695 		CurvePoints.AllocGrow(NumCurvePoints);
696 
697 		for (int PointIdx = 0; PointIdx < NumCurvePoints; PointIdx++)
698 		{
699 			float t = (float)PointIdx / (float)(NumCurvePoints - 1);
700 			float it = 1.0f - t;
701 
702 			lcVector3 Position = it * it * it * SegmentControlPoints[0] + it * it * 3.0f * t * SegmentControlPoints[1] + it * 3.0 * t * t * SegmentControlPoints[2] + t * t * t * SegmentControlPoints[3];
703 			CurvePoints.Add(Position);
704 		}
705 
706 		float CurrentSegmentLength = 0.0f;
707 		float TotalSegmentLength = 0.0f;
708 
709 		for (int PointIdx = 0; PointIdx < CurvePoints.GetSize() - 1; PointIdx++)
710 			TotalSegmentLength += lcLength(CurvePoints[PointIdx] - CurvePoints[PointIdx + 1]);
711 
712 		lcVector3 StartUp = lcMul30(lcVector3(1.0f, 0.0f, 0.0f), StartTransform);
713 		float Twist = GetSectionTwist(StartTransform, EndTransform);
714 		int CurrentPointIndex = 0;
715 
716 		while (CurrentPointIndex < CurvePoints.GetSize() - 1)
717 		{
718 			float Length = lcLength(CurvePoints[CurrentPointIndex + 1] - CurvePoints[CurrentPointIndex]);
719 			CurrentSegmentLength += Length;
720 			SectionLength -= Length;
721 			CurrentPointIndex++;
722 
723 			if (SectionLength > 0.0f)
724 				continue;
725 
726 			float t = (float)CurrentPointIndex / (float)(NumCurvePoints - 1);
727 			float it = 1.0f - t;
728 
729 			lcVector3 Tangent = lcNormalize(-3.0f * it * it * SegmentControlPoints[0] + (3.0f * it * it - 6.0f * t * it) * SegmentControlPoints[1] + (-3.0f * t * t + 6.0f * t * it) * SegmentControlPoints[2] + 3.0f * t * t * SegmentControlPoints[3]);
730 			lcVector3 Up;
731 
732 			if (Twist)
733 			{
734 				Up = lcMul(StartUp, lcMatrix33FromAxisAngle(Tangent, Twist * (CurrentSegmentLength / TotalSegmentLength)));
735 				CurrentSegmentLength = 0.0f;
736 			}
737 			else
738 				Up = StartUp;
739 
740 			lcVector3 Side = lcNormalize(lcCross(Tangent, Up));
741 			Up = lcNormalize(lcCross(Side, Tangent));
742 			StartUp = Up;
743 
744 			Sections.Add(lcMatrix44(lcMatrix33(Up, Tangent, Side), CurvePoints[CurrentPointIndex]));
745 
746 			if (SectionCallback)
747 				SectionCallback(CurvePoints[CurrentPointIndex], ControlPointIdx, t);
748 
749 			if (Sections.GetSize() == mNumSections + 2)
750 				break;
751 
752 			if (mCenterLength != 0.0f && (Sections.GetSize() == mNumSections / 2 + 1))
753 				SectionLength += mCenterLength;
754 			else
755 				SectionLength += mMiddle.Length;
756 
757 			if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges)
758 				SectionLength += mEnd.Length;
759 		}
760 	}
761 
762 	while (Sections.GetSize() < mNumSections + 2)
763 	{
764 		lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPoints.GetSize() - 1].Transform);
765 		EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation());
766 		lcVector3 Position = lcMul31(lcVector3(0.0f, SectionLength, 0.0f), EndTransform);
767 		EndTransform.SetTranslation(Position);
768 		Sections.Add(EndTransform);
769 
770 		if (SectionCallback)
771 			SectionCallback(Position, ControlPoints.GetSize() - 1, 1.0f);
772 
773 		if (mCenterLength != 0.0f && (Sections.GetSize() == mNumSections / 2 + 1))
774 			SectionLength += mCenterLength;
775 		else
776 			SectionLength += mMiddle.Length;
777 
778 		if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges)
779 			SectionLength += mEnd.Length;
780 	}
781 }
782 
CalculateSections(const lcArray<lcPieceControlPoint> & ControlPoints,lcArray<lcMatrix44> & Sections,SectionCallbackFunc SectionCallback) const783 void lcSynthInfoBraidedString::CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const
784 {
785 	float SectionLength = 0.0f;
786 
787 	for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize() - 1 && Sections.GetSize() < mNumSections + 2; ControlPointIdx++)
788 	{
789 		lcVector3 SegmentControlPoints[4];
790 
791 		lcMatrix44 StartTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform);
792 		lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx + 1].Transform);
793 		StartTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mStart.Transform), lcMatrix33(StartTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), StartTransform.GetTranslation());
794 
795 		if (ControlPointIdx == 0)
796 		{
797 			if (mRigidEdges)
798 			{
799 				StartTransform.SetTranslation(lcMul30(lcVector3(mStart.Length, 0.0f, 0.0f), StartTransform) + StartTransform.GetTranslation());
800 				SectionLength = 0.0f;
801 			}
802 			else
803 				SectionLength = mStart.Length;
804 
805 			Sections.Add(StartTransform);
806 		}
807 
808 		EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation());
809 
810 		SegmentControlPoints[0] = StartTransform.GetTranslation();
811 		SegmentControlPoints[1] = lcMul31(lcVector3(ControlPoints[ControlPointIdx].Scale, 0.0f, 0.0f), StartTransform);
812 		SegmentControlPoints[2] = lcMul31(lcVector3(-ControlPoints[ControlPointIdx + 1].Scale, 0.0f, 0.0f), EndTransform);
813 		SegmentControlPoints[3] = EndTransform.GetTranslation();
814 
815 		const int NumCurvePoints = 8192;
816 		lcArray<lcVector3> CurvePoints;
817 		CurvePoints.AllocGrow(NumCurvePoints);
818 
819 		for (int PointIdx = 0; PointIdx < NumCurvePoints; PointIdx++)
820 		{
821 			float t = (float)PointIdx / (float)(NumCurvePoints - 1);
822 			float it = 1.0f - t;
823 
824 			lcVector3 Position = it * it * it * SegmentControlPoints[0] + it * it * 3.0f * t * SegmentControlPoints[1] + it * 3.0 * t * t * SegmentControlPoints[2] + t * t * t * SegmentControlPoints[3];
825 			CurvePoints.Add(Position);
826 		}
827 
828 		float CurrentSegmentLength = 0.0f;
829 		float TotalSegmentLength = 0.0f;
830 
831 		for (int PointIdx = 0; PointIdx < CurvePoints.GetSize() - 1; PointIdx++)
832 			TotalSegmentLength += lcLength(CurvePoints[PointIdx] - CurvePoints[PointIdx + 1]);
833 
834 		lcVector3 StartUp = lcMul30(lcVector3(0.0f, 1.0f, 0.0f), StartTransform);
835 		float Twist = GetSectionTwist(StartTransform, EndTransform);
836 		int CurrentPointIndex = 0;
837 
838 		while (CurrentPointIndex < CurvePoints.GetSize() - 1)
839 		{
840 			float Length = lcLength(CurvePoints[CurrentPointIndex + 1] - CurvePoints[CurrentPointIndex]);
841 			CurrentSegmentLength += Length;
842 			SectionLength -= Length;
843 			CurrentPointIndex++;
844 
845 			if (SectionLength > 0.0f)
846 				continue;
847 
848 			float t = (float)CurrentPointIndex / (float)(NumCurvePoints - 1);
849 			float it = 1.0f - t;
850 
851 			lcVector3 Tangent = lcNormalize(-3.0f * it * it * SegmentControlPoints[0] + (3.0f * it * it - 6.0f * t * it) * SegmentControlPoints[1] + (-3.0f * t * t + 6.0f * t * it) * SegmentControlPoints[2] + 3.0f * t * t * SegmentControlPoints[3]);
852 			lcVector3 Up;
853 
854 			if (Twist)
855 			{
856 				Up = lcMul(StartUp, lcMatrix33FromAxisAngle(Tangent, Twist * (CurrentSegmentLength / TotalSegmentLength)));
857 				CurrentSegmentLength = 0.0f;
858 			}
859 			else
860 				Up = StartUp;
861 
862 			lcVector3 Side = lcNormalize(lcCross(Tangent, Up));
863 			Up = lcNormalize(lcCross(Side, Tangent));
864 			StartUp = Up;
865 
866 			Sections.Add(lcMatrix44(lcMatrix33(Tangent, Up, -Side), CurvePoints[CurrentPointIndex]));
867 
868 			if (SectionCallback)
869 				SectionCallback(CurvePoints[CurrentPointIndex], ControlPointIdx, t);
870 
871 			if (Sections.GetSize() == mNumSections + 2)
872 				break;
873 
874 			if (mCenterLength != 0.0f && (Sections.GetSize() == mNumSections / 2 + 1))
875 				SectionLength += mCenterLength;
876 			else
877 				SectionLength += mMiddle.Length;
878 
879 			if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges)
880 				SectionLength += mEnd.Length;
881 		}
882 	}
883 
884 	while (Sections.GetSize() < mNumSections + 2)
885 	{
886 		lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPoints.GetSize() - 1].Transform);
887 		EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation());
888 		lcVector3 Position = lcMul31(lcVector3(SectionLength, 0.0f, 0.0f), EndTransform);
889 		EndTransform.SetTranslation(Position);
890 		Sections.Add(EndTransform);
891 
892 		if (SectionCallback)
893 			SectionCallback(Position, ControlPoints.GetSize() - 1, 1.0f);
894 
895 		if (mCenterLength != 0.0f && (Sections.GetSize() == mNumSections / 2 + 1))
896 			SectionLength += mCenterLength;
897 		else
898 			SectionLength += mMiddle.Length;
899 
900 		if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges)
901 			SectionLength += mEnd.Length;
902 	}
903 }
904 
CalculateSections(const lcArray<lcPieceControlPoint> & ControlPoints,lcArray<lcMatrix44> & Sections,SectionCallbackFunc SectionCallback) const905 void lcSynthInfoStraight::CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const
906 {
907 	for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++)
908 	{
909 		lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform);
910 		Sections.Add(Transform);
911 
912 		if (SectionCallback)
913 			SectionCallback(Transform.GetTranslation(), ControlPointIdx, 1.0f);
914 	}
915 }
916 
CalculateSections(const lcArray<lcPieceControlPoint> & ControlPoints,lcArray<lcMatrix44> & Sections,SectionCallbackFunc SectionCallback) const917 void lcSynthInfoUniversalJoint::CalculateSections(const lcArray<lcPieceControlPoint>& ControlPoints, lcArray<lcMatrix44>& Sections, SectionCallbackFunc SectionCallback) const
918 {
919 	for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++)
920 	{
921 		lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform);
922 		Sections.Add(Transform);
923 
924 		if (SectionCallback)
925 			SectionCallback(Transform.GetTranslation(), ControlPointIdx, 1.0f);
926 	}
927 }
928 
AddParts(lcMemFile & File,lcLibraryMeshData &,const lcArray<lcMatrix44> & Sections) const929 void lcSynthInfoFlexibleHose::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray<lcMatrix44>& Sections) const
930 {
931 	char Line[256];
932 	const int NumEdgeParts = 2;
933 
934 	const lcMatrix33 EdgeTransforms[2] =
935 	{
936 		lcMatrix33(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, -1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f)),
937 		lcMatrix33(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f,  1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f))
938 	};
939 
940 	const char* EdgeParts[2] =
941 	{
942 		"755.dat", mEdgePart2
943 	};
944 
945 	for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++)
946 	{
947 		const int SectionIdx = 0;
948 		lcMatrix33 Transform(lcMul(lcMul(EdgeTransforms[PartIdx], lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), lcMatrix33(Sections[SectionIdx])));
949 		lcVector3 Offset = lcMul31(lcVector3(0.0f, -5.0f, 0.0f), Sections[SectionIdx]);
950 
951 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
952 		        Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]);
953 
954 		File.WriteBuffer(Line, strlen(Line));
955 	}
956 
957 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
958 	{
959 		lcMatrix33 Transform = lcMatrix33(Sections[SectionIdx]);
960 		lcVector3 Offset = Sections[SectionIdx].GetTranslation();
961 
962 		if (SectionIdx < Sections.GetSize() / 2)
963 			Transform = lcMul(lcMatrix33(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, -1.0f, 0.0f), lcVector3(-1.0f, 0.0f, 0.0f)), Transform);
964 		else if (SectionIdx != Sections.GetSize() / 2)
965 			Transform = lcMul(lcMatrix33(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f,  1.0f, 0.0f), lcVector3( 1.0f, 0.0f, 0.0f)), Transform);
966 		else
967 			Transform = lcMul(lcMatrix33(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f,  1.0f, 0.0f), lcVector3( 1.0f, 0.0f, 0.0f)), Transform);
968 
969 		const char* Part = SectionIdx != Sections.GetSize() / 2 ? "754.dat" : "756.dat";
970 
971 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
972 		        Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], Part);
973 
974 		File.WriteBuffer(Line, strlen(Line));
975 	}
976 
977 	for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++)
978 	{
979 		const int SectionIdx = Sections.GetSize() - 1;
980 		lcMatrix33 Transform(lcMul(EdgeTransforms[PartIdx], lcMatrix33(Sections[SectionIdx])));
981 		lcVector3 Offset = lcMul31(lcVector3(0.0f, 5.0f - 2.56f, 0.0f), Sections[SectionIdx]);
982 
983 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
984 		        Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]);
985 
986 		File.WriteBuffer(Line, strlen(Line));
987 	}
988 }
989 
AddTubeParts(lcLibraryMeshData & MeshData,const lcArray<lcMatrix44> & Sections,float Radius,bool IsInner)990 void lcSynthInfoCurved::AddTubeParts(lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections, float Radius, bool IsInner)
991 {
992 	// a unit circle
993 	static const lcVector3 Vertices[16] =
994 	{
995 		{  1.000000f, 0.0f,  0.000000f },
996 		{  0.923880f, 0.0f,  0.382683f },
997 		{  0.707107f, 0.0f,  0.707107f },
998 		{  0.382683f, 0.0f,  0.923880f },
999 		{  0.000000f, 0.0f,  1.000000f },
1000 		{ -0.382683f, 0.0f,  0.923880f },
1001 		{ -0.707107f, 0.0f,  0.707107f },
1002 		{ -0.923880f, 0.0f,  0.382683f },
1003 		{ -1.000000f, 0.0f,  0.000000f },
1004 		{ -0.923879f, 0.0f, -0.382684f },
1005 		{ -0.707107f, 0.0f, -0.707107f },
1006 		{ -0.382683f, 0.0f, -0.923880f },
1007 		{  0.000000f, 0.0f, -1.000000f },
1008 		{  0.382684f, 0.0f, -0.923879f },
1009 		{  0.707107f, 0.0f, -0.707107f },
1010 		{  0.923880f, 0.0f, -0.382683f },
1011 	};
1012 	const int NumSectionVertices = LC_ARRAY_COUNT(Vertices);
1013 
1014 	int BaseVertex;
1015 	lcMeshLoaderVertex* VertexBuffer;
1016 	quint32* IndexBuffer;
1017 	MeshData.AddVertices(LC_MESHDATA_SHARED, NumSectionVertices * (Sections.GetSize() - 1), &BaseVertex, &VertexBuffer);
1018 
1019 	float NormalDirection = IsInner ? -1.0f : 1.0f;
1020 
1021 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize(); SectionIdx++)
1022 	{
1023 		for (int VertexIdx = 0; VertexIdx < NumSectionVertices; VertexIdx++)
1024 		{
1025 			VertexBuffer->Position = lcMul31(Radius * Vertices[VertexIdx], Sections[SectionIdx]);
1026 			VertexBuffer->Normal = lcMul30(NormalDirection * Vertices[VertexIdx], Sections[SectionIdx]);
1027 			VertexBuffer->NormalWeight = 4.0f;
1028 			VertexBuffer++;
1029 		}
1030 	}
1031 
1032 	MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, 6 * NumSectionVertices * (Sections.GetSize() - 2), &IndexBuffer);
1033 
1034 	int Offset1, Offset2;
1035 	if (IsInner)
1036 	{
1037 		Offset1 = NumSectionVertices - 1;	// -1 mod NumVertices
1038 		Offset2 = 0;
1039 	}
1040 	else
1041 	{
1042 		Offset1 = 0;
1043 		Offset2 = 1;
1044 	}
1045 
1046 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
1047 	{
1048 		for (int VertexIdx = 0; VertexIdx < NumSectionVertices; VertexIdx++)
1049 		{
1050 			int Vertex1 = BaseVertex + (VertexIdx + Offset1) % NumSectionVertices;
1051 			int Vertex2 = BaseVertex + (VertexIdx + Offset2) % NumSectionVertices;
1052 
1053 			*IndexBuffer++ = Vertex1;
1054 			*IndexBuffer++ = Vertex2;
1055 			*IndexBuffer++ = Vertex1 + NumSectionVertices;
1056 			*IndexBuffer++ = Vertex2;
1057 			*IndexBuffer++ = Vertex2 + NumSectionVertices;
1058 			*IndexBuffer++ = Vertex1 + NumSectionVertices;
1059 		}
1060 		BaseVertex += NumSectionVertices;
1061 	}
1062 }
1063 
AddParts(lcMemFile & File,lcLibraryMeshData & MeshData,const lcArray<lcMatrix44> & Sections) const1064 void lcSynthInfoFlexSystemHose::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const
1065 {
1066 	char Line[256];
1067 
1068 	{
1069 		const int SectionIdx = 0;
1070 		lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(-1.0f, 1.0f, 1.0f)), lcMatrix33(Sections[SectionIdx])));
1071 		lcVector3 Offset = lcMul31(lcVector3(0.0f, -1.0f, 0.0f), Sections[SectionIdx]);
1072 
1073 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f u9053.dat\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1074 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1075 
1076 		File.WriteBuffer(Line, strlen(Line));
1077 	}
1078 
1079 	{
1080 		const int SectionIdx = Sections.GetSize() - 1;
1081 		lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(Sections[SectionIdx])));
1082 		lcVector3 Offset = lcMul31(lcVector3(0.0f, 1.0f, 0.0f), Sections[SectionIdx]);
1083 
1084 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f u9053.dat\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1085 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1086 
1087 		File.WriteBuffer(Line, strlen(Line));
1088 	}
1089 
1090 	AddTubeParts(MeshData, Sections, 4.0f, false);
1091 	AddTubeParts(MeshData, Sections, 2.0f, true);
1092 }
1093 
AddParts(lcMemFile & File,lcLibraryMeshData & MeshData,const lcArray<lcMatrix44> & Sections) const1094 void lcSynthInfoPneumaticTube::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const
1095 {
1096 	char Line[256];
1097 
1098 	{
1099 		const int SectionIdx = 0;
1100 		lcMatrix33 EdgeTransform(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, -1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f));
1101 		lcMatrix33 Transform(lcMul(lcMul(EdgeTransform, lcMatrix33Scale(lcVector3(1.0f, 1.0f, 1.0f))), lcMatrix33(Sections[SectionIdx])));
1102 		lcVector3 Offset = lcMul31(lcVector3(0.0f, 0.0f, 0.0f), Sections[SectionIdx]);
1103 
1104 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1105 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2],
1106 				mEndPart);
1107 
1108 		File.WriteBuffer(Line, strlen(Line));
1109 	}
1110 
1111 	{
1112 		const int SectionIdx = Sections.GetSize() - 1;
1113 		lcMatrix33 EdgeTransform(lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, -1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f));
1114 		lcMatrix33 Transform(lcMul(lcMul(EdgeTransform, lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), lcMatrix33(Sections[SectionIdx])));
1115 		lcVector3 Offset = lcMul31(lcVector3(0.0f, 0.0f, 0.0f), Sections[SectionIdx]);
1116 
1117 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1118 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2],
1119 				mEndPart);
1120 
1121 		File.WriteBuffer(Line, strlen(Line));
1122 	}
1123 
1124 	AddTubeParts(MeshData, Sections, 5.0f, false);
1125 	AddTubeParts(MeshData, Sections, 3.0f, true);
1126 }
1127 
AddParts(lcMemFile & File,lcLibraryMeshData &,const lcArray<lcMatrix44> & Sections) const1128 void lcSynthInfoRibbedHose::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray<lcMatrix44>& Sections) const
1129 {
1130 	char Line[256];
1131 
1132 	{
1133 		const int SectionIdx = 0;
1134 		lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(Sections[SectionIdx])));
1135 		lcVector3 Offset = Sections[SectionIdx].GetTranslation();
1136 
1137 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 79.dat\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1138 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1139 
1140 		File.WriteBuffer(Line, strlen(Line));
1141 	}
1142 
1143 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
1144 	{
1145 		const lcMatrix44& Transform = Sections[SectionIdx];
1146 
1147 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 80.dat\n", Transform[3][0], Transform[3][1], Transform[3][2], Transform[0][0], Transform[1][0], Transform[2][0],
1148 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1149 
1150 		File.WriteBuffer(Line, strlen(Line));
1151 	}
1152 
1153 	{
1154 		const int SectionIdx = Sections.GetSize() - 1;
1155 		lcMatrix33 Transform(Sections[SectionIdx]);
1156 		lcVector3 Offset = lcMul31(lcVector3(0.0f, -6.25f, 0.0f), Sections[SectionIdx]);
1157 
1158 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 79.dat\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1159 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1160 
1161 		File.WriteBuffer(Line, strlen(Line));
1162 	}
1163 }
1164 
AddParts(lcMemFile & File,lcLibraryMeshData & MeshData,const lcArray<lcMatrix44> & Sections) const1165 void lcSynthInfoFlexibleAxle::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& Sections) const
1166 {
1167 	char Line[256];
1168 	const int NumEdgeParts = 6;
1169 
1170 	lcMatrix33 EdgeTransforms[6] =
1171 	{
1172 		lcMatrix33(lcVector3(-1.0f, 0.0f, 0.0f), lcVector3(0.0f, -5.0f, 0.0f), lcVector3(0.0f, 0.0f,  1.0f)),
1173 		lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f,  0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)),
1174 		lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f,  0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)),
1175 		lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f,  0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)),
1176 		lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f,  0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)),
1177 		lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f,  0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)),
1178 	};
1179 
1180 	const char* EdgeParts[6] =
1181 	{
1182 		"stud3a.dat", "s/faxle1.dat", "s/faxle2.dat", "s/faxle3.dat", "s/faxle4.dat", "s/faxle5.dat"
1183 	};
1184 
1185 	for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++)
1186 	{
1187 		const int SectionIdx = 0;
1188 		lcMatrix33 Transform(lcMul(lcMul(EdgeTransforms[PartIdx], lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), lcMatrix33(Sections[SectionIdx])));
1189 		lcVector3 Offset = lcMul31(lcVector3(0.0f, -4.0f * (5 - PartIdx), 0.0f), Sections[SectionIdx]);
1190 
1191 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1192 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]);
1193 
1194 		File.WriteBuffer(Line, strlen(Line));
1195 	}
1196 
1197 	for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++)
1198 	{
1199 		const int SectionIdx = Sections.GetSize() - 1;
1200 		lcMatrix33 Transform(lcMul(EdgeTransforms[PartIdx], lcMatrix33(Sections[SectionIdx])));
1201 		lcVector3 Offset = lcMul31(lcVector3(0.0f, 4.0f * (5 - PartIdx), 0.0f), Sections[SectionIdx]);
1202 
1203 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1204 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]);
1205 
1206 		File.WriteBuffer(Line, strlen(Line));
1207 	}
1208 
1209 	const lcMeshLoaderVertex SectionVertices[28] =
1210 	{
1211 		{ lcVector3(-6.000f, 0.0f,  0.000f), lcVector3(-1.000f, 0.0f,  0.000f), 2.0f, lcVector2(0.0f, 0.0f), 0 },
1212 		{ lcVector3(-5.602f, 0.0f,  2.000f), lcVector3(-0.942f, 0.0f,  0.336f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1213 		{ lcVector3(-5.602f, 0.0f,  2.000f), lcVector3( 0.000f, 0.0f,  1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1214 		{ lcVector3(-2.000f, 0.0f,  2.000f), lcVector3( 0.000f, 0.0f,  1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1215 		{ lcVector3(-2.000f, 0.0f,  2.000f), lcVector3(-1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1216 		{ lcVector3(-2.000f, 0.0f,  5.602f), lcVector3(-1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1217 		{ lcVector3(-2.000f, 0.0f,  5.602f), lcVector3(-0.336f, 0.0f,  0.942f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1218 		{ lcVector3( 0.000f, 0.0f,  6.000f), lcVector3( 0.000f, 0.0f,  1.000f), 2.0f, lcVector2(0.0f, 0.0f), 0 },
1219 		{ lcVector3( 2.000f, 0.0f,  5.602f), lcVector3( 0.336f, 0.0f,  0.942f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1220 		{ lcVector3( 2.000f, 0.0f,  5.602f), lcVector3( 1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1221 		{ lcVector3( 2.000f, 0.0f,  2.000f), lcVector3( 1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1222 		{ lcVector3( 2.000f, 0.0f,  2.000f), lcVector3( 0.000f, 0.0f,  1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1223 		{ lcVector3( 5.602f, 0.0f,  2.000f), lcVector3( 0.000f, 0.0f,  1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1224 		{ lcVector3( 5.602f, 0.0f,  2.000f), lcVector3( 0.942f, 0.0f,  0.336f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1225 		{ lcVector3( 6.000f, 0.0f,  0.000f), lcVector3( 1.000f, 0.0f,  0.000f), 2.0f, lcVector2(0.0f, 0.0f), 0 },
1226 		{ lcVector3( 5.602f, 0.0f, -2.000f), lcVector3( 0.942f, 0.0f, -0.336f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1227 		{ lcVector3( 5.602f, 0.0f, -2.000f), lcVector3( 0.000f, 0.0f, -1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1228 		{ lcVector3( 2.000f, 0.0f, -2.000f), lcVector3( 0.000f, 0.0f, -1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1229 		{ lcVector3( 2.000f, 0.0f, -2.000f), lcVector3( 1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1230 		{ lcVector3( 2.000f, 0.0f, -5.602f), lcVector3( 1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1231 		{ lcVector3( 2.000f, 0.0f, -5.602f), lcVector3( 0.336f, 0.0f, -0.942f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1232 		{ lcVector3( 0.000f, 0.0f, -6.000f), lcVector3( 0.000f, 0.0f, -1.000f), 2.0f, lcVector2(0.0f, 0.0f), 0 },
1233 		{ lcVector3(-2.000f, 0.0f, -5.602f), lcVector3(-0.336f, 0.0f, -0.942f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1234 		{ lcVector3(-2.000f, 0.0f, -5.602f), lcVector3(-1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1235 		{ lcVector3(-2.000f, 0.0f, -2.000f), lcVector3(-1.000f, 0.0f,  0.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1236 		{ lcVector3(-2.000f, 0.0f, -2.000f), lcVector3( 0.000f, 0.0f, -1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1237 		{ lcVector3(-5.602f, 0.0f, -2.000f), lcVector3( 0.000f, 0.0f, -1.000f), 4.0f, lcVector2(0.0f, 0.0f), 0 },
1238 		{ lcVector3(-5.602f, 0.0f, -2.000f), lcVector3(-0.942f, 0.0f, -0.336f), 4.0f, lcVector2(0.0f, 0.0f), 0 }
1239 	};
1240 
1241 	const int NumSectionVertices = LC_ARRAY_COUNT(SectionVertices);
1242 
1243 	int BaseVertex;
1244 	lcMeshLoaderVertex* VertexBuffer;
1245 	quint32* IndexBuffer;
1246 	MeshData.AddVertices(LC_MESHDATA_SHARED, NumSectionVertices * (Sections.GetSize() - 1), &BaseVertex, &VertexBuffer);
1247 	MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_LINES, 24, 2 * 12 * (Sections.GetSize() - 2), &IndexBuffer);
1248 
1249 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize(); SectionIdx++)
1250 	{
1251 		for (int VertexIdx = 0; VertexIdx < NumSectionVertices; VertexIdx++)
1252 		{
1253 			VertexBuffer->Position = lcMul31(SectionVertices[VertexIdx].Position, Sections[SectionIdx]);
1254 			VertexBuffer->Normal = lcMul30(SectionVertices[VertexIdx].Normal, Sections[SectionIdx]);
1255 			VertexBuffer->NormalWeight = SectionVertices[VertexIdx].NormalWeight;
1256 			VertexBuffer++;
1257 		}
1258 	}
1259 
1260 	int BaseLinesVertex = BaseVertex;
1261 
1262 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
1263 	{
1264 		const int Indices[] = { 1, 3, 5, 8, 10, 12, 15, 17, 19, 22, 24, 26 };
1265 
1266 		for (int VertexIdx = 0; VertexIdx < 12; VertexIdx++)
1267 		{
1268 			*IndexBuffer++ = BaseLinesVertex + Indices[VertexIdx];
1269 			*IndexBuffer++ = BaseLinesVertex + Indices[VertexIdx] + NumSectionVertices;
1270 		}
1271 
1272 		BaseLinesVertex += NumSectionVertices;
1273 	}
1274 
1275 	MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, 6 * NumSectionVertices * (Sections.GetSize() - 2), &IndexBuffer);
1276 
1277 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
1278 	{
1279 		for (int VertexIdx = 0; VertexIdx < NumSectionVertices; VertexIdx++)
1280 		{
1281 			int Vertex1 = BaseVertex + VertexIdx;
1282 			int Vertex2 = BaseVertex + (VertexIdx + 1) % NumSectionVertices;
1283 
1284 			*IndexBuffer++ = Vertex1;
1285 			*IndexBuffer++ = Vertex2;
1286 			*IndexBuffer++ = Vertex1 + NumSectionVertices;
1287 			*IndexBuffer++ = Vertex2;
1288 			*IndexBuffer++ = Vertex2 + NumSectionVertices;
1289 			*IndexBuffer++ = Vertex1 + NumSectionVertices;
1290 		}
1291 		BaseVertex += NumSectionVertices;
1292 	}
1293 }
1294 
AddParts(lcMemFile & File,lcLibraryMeshData & MeshData,const lcArray<lcMatrix44> & SectionsIn) const1295 void lcSynthInfoBraidedString::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray<lcMatrix44>& SectionsIn) const
1296 {
1297 	lcArray<lcMatrix44> Sections;
1298 	Sections.SetSize(SectionsIn.GetSize());
1299 
1300 	for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++)
1301 	{
1302 		lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(SectionsIn[SectionIdx])));
1303 		lcVector3 Offset = SectionsIn[SectionIdx].GetTranslation();
1304 		Sections[SectionIdx] = lcMatrix44(Transform, Offset);
1305 	}
1306 
1307 	char Line[256];
1308 
1309 	{
1310 		const int SectionIdx = 0;
1311 		lcMatrix33 Transform(Sections[SectionIdx]);
1312 		lcVector3 Offset = lcMul31(lcVector3(-8.0f, 0.0f, 0.0f), Sections[SectionIdx]);
1313 
1314 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 572A.dat\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1315 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1316 
1317 		File.WriteBuffer(Line, strlen(Line));
1318 	}
1319 
1320 	const int NumSegments = 16;
1321 	const int NumBraids = 4;
1322 	const float PositionTable[16] =
1323 	{
1324 		-1.5f, -1.386f, -1.061f, -0.574f, 0.0f, 0.574f, 1.061f, 1.386f, 1.5f, 1.386f, 1.061f, 0.574f, 0.0f, -0.574f, -1.061f, -1.386f
1325 	};
1326 
1327 	int BaseVertex;
1328 	lcMeshLoaderVertex* VertexBuffer;
1329 	quint32* IndexBuffer;
1330 	MeshData.AddVertices(LC_MESHDATA_SHARED, NumBraids * ((Sections.GetSize() - 2) * NumSegments + 1), &BaseVertex, &VertexBuffer);
1331 	MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_LINES, 24, NumBraids * (Sections.GetSize() - 2) * NumSegments * 2, &IndexBuffer);
1332 
1333 	for (int BraidIdx = 0; BraidIdx < NumBraids; BraidIdx++)
1334 	{
1335 		int BaseX = (BraidIdx == 0 || BraidIdx == 2) ? 0 : 8;
1336 		int BaseY = (BraidIdx == 0 || BraidIdx == 3) ? 12 : 4;
1337 
1338 		for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
1339 		{
1340 			lcMatrix33 Transform1 = lcMatrix33(Sections[SectionIdx]);
1341 			lcMatrix33 Transform2 = lcMatrix33(Sections[SectionIdx + 1]);
1342 			lcVector3 Offset1 = Sections[SectionIdx].GetTranslation();
1343 			lcVector3 Offset2 = Sections[SectionIdx + 1].GetTranslation();
1344 
1345 			for (int SegmentIdx = 0; SegmentIdx < ((SectionIdx < Sections.GetSize() - 2) ? NumSegments : NumSegments + 1); SegmentIdx++)
1346 			{
1347 				float t = (float)SegmentIdx / (float)NumSegments;
1348 
1349 				lcVector3 Vertex1 = lcVector3(t * 4.0f, PositionTable[(BaseX + SegmentIdx) % NumSegments], PositionTable[(BaseY + SegmentIdx) % NumSegments]) + lcVector3(0.0f, 1.5f, 0.0f);
1350 				lcVector3 Vertex2 = lcVector3((1.0f - t) * -4.0f, PositionTable[(BaseX + SegmentIdx) % NumSegments], PositionTable[(BaseY + SegmentIdx) % NumSegments]) + lcVector3(0.0f, 1.5f, 0.0f);
1351 
1352 				lcVector3 Vertex = (lcMul(Vertex1, Transform1) + Offset1) * (1.0f - t) + (lcMul(Vertex2, Transform2) + Offset2) * t;
1353 
1354 				VertexBuffer->Position = Vertex;
1355 				VertexBuffer->Normal = lcVector3(0.0f, 0.0f, 0.0f);
1356 				VertexBuffer->NormalWeight = 0.0f;
1357 				VertexBuffer++;
1358 
1359 				if (SegmentIdx != NumSegments)
1360 				{
1361 					*IndexBuffer++ = BaseVertex;
1362 					*IndexBuffer++ = BaseVertex + 1;
1363 					BaseVertex++;
1364 				}
1365 			}
1366 		}
1367 
1368 		BaseVertex++;
1369 	}
1370 
1371 	int NumSlices = 16;
1372 	MeshData.AddVertices(LC_MESHDATA_SHARED, NumSlices * ((Sections.GetSize() - 2) * NumSegments + 1), &BaseVertex, &VertexBuffer);
1373 	MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, NumSlices * (Sections.GetSize() - 2) * NumSegments * 6, &IndexBuffer);
1374 
1375 	for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++)
1376 	{
1377 		lcMatrix33 Transform1 = lcMatrix33(Sections[SectionIdx]);
1378 		lcMatrix33 Transform2 = lcMatrix33(Sections[SectionIdx + 1]);
1379 		lcVector3 Offset1 = Sections[SectionIdx].GetTranslation();
1380 		lcVector3 Offset2 = Sections[SectionIdx + 1].GetTranslation();
1381 
1382 		for (int SegmentIdx = 0; SegmentIdx < ((SectionIdx < Sections.GetSize() - 2) ? NumSegments : NumSegments + 1); SegmentIdx++)
1383 		{
1384 			float t1 = (float)SegmentIdx / (float)NumSegments;
1385 			int BaseX = 8;
1386 			int BaseY = 4;
1387 
1388 			for (int SliceIdx = 0; SliceIdx < NumSlices; SliceIdx++)
1389 			{
1390 				lcVector3 Vertex11 = lcVector3(t1 * 4.0f, PositionTable[(BaseX + SliceIdx) % NumSlices], PositionTable[(BaseY + SliceIdx) % NumSlices]) + lcVector3(0.0f, 1.5f, 0.0f);
1391 				lcVector3 Vertex12 = lcVector3((1.0f - t1) * -4.0f, PositionTable[(BaseX + SliceIdx) % NumSlices], PositionTable[(BaseY + SliceIdx) % NumSlices]) + lcVector3(0.0f, 1.5f, 0.0f);
1392 				VertexBuffer->Position = (lcMul(Vertex11, Transform1) + Offset1) * (1.0f - t1) + (lcMul(Vertex12, Transform2) + Offset2) * t1;
1393 
1394 				lcVector3 Normal11 = lcVector3(0.0f, PositionTable[(BaseX + SliceIdx) % NumSlices] / 1.5f, PositionTable[(BaseY + SliceIdx) % NumSlices] / 1.5f);
1395 				lcVector3 Normal12 = lcVector3(0.0f, PositionTable[(BaseX + SliceIdx) % NumSlices] / 1.5f, PositionTable[(BaseY + SliceIdx) % NumSlices] / 1.5f);
1396 				VertexBuffer->Normal = lcMul(Normal11, Transform1) * (1.0f - t1) + lcMul(Normal12, Transform2) * t1;
1397 				VertexBuffer->NormalWeight = 1.0f;
1398 				VertexBuffer++;
1399 
1400 				if (SegmentIdx != NumSegments)
1401 				{
1402 					*IndexBuffer++ = BaseVertex + SliceIdx;
1403 					*IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices;
1404 					*IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices + NumSlices;
1405 
1406 					*IndexBuffer++ = BaseVertex + SliceIdx + NumSlices;
1407 					*IndexBuffer++ = BaseVertex + SliceIdx;
1408 					*IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices + NumSlices;
1409 				}
1410 			}
1411 
1412 			BaseVertex += NumSlices;
1413 		}
1414 	}
1415 
1416 	{
1417 		const int SectionIdx = Sections.GetSize() - 1;
1418 		lcMatrix33 Transform(Sections[SectionIdx]);
1419 		lcVector3 Offset = lcMul31(lcVector3(8.0f, 0.0f, 0.0f), Sections[SectionIdx]);
1420 
1421 		sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 572A.dat\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0],
1422 				Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]);
1423 
1424 		File.WriteBuffer(Line, strlen(Line));
1425 	}
1426 }
1427 
AddParts(lcMemFile & File,lcLibraryMeshData &,const lcArray<lcMatrix44> & Sections) const1428 void lcSynthInfoShockAbsorber::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray<lcMatrix44>& Sections) const
1429 {
1430 	char Line[256];
1431 	lcVector3 Offset;
1432 
1433 	Offset = Sections[0].GetTranslation();
1434 	sprintf(Line, "1 0 %f %f %f 1 0 0 0 1 0 0 0 1 4254.dat\n", Offset[0], Offset[1], Offset[2]);
1435 	File.WriteBuffer(Line, strlen(Line));
1436 
1437 	Offset = Sections[1].GetTranslation();
1438 	sprintf(Line, "1 16 %f %f %f 1 0 0 0 1 0 0 0 1 4255.dat\n", Offset[0], Offset[1], Offset[2]);
1439 	File.WriteBuffer(Line, strlen(Line));
1440 
1441 	float Distance = Sections[0].GetTranslation().y - Sections[1].GetTranslation().y;
1442 	float Scale = (Distance - 66.0f) / 44.0f;
1443 
1444 	Offset = Sections[0].GetTranslation();
1445 	sprintf(Line, "1 494 %f %f %f 1 0 0 0 %f 0 0 0 1 %s\n", Offset[0], Offset[1] - 10 - 44.0f * Scale, Offset[2], Scale, mSpringPart);
1446 	File.WriteBuffer(Line, strlen(Line));
1447 }
1448 
AddParts(lcMemFile & File,lcLibraryMeshData &,const lcArray<lcMatrix44> & Sections) const1449 void lcSynthInfoActuator::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray<lcMatrix44>& Sections) const
1450 {
1451 	char Line[256];
1452 	lcVector3 Offset;
1453 
1454 	Offset = Sections[0].GetTranslation();
1455 	sprintf(Line, "1 16 %f %f %f 1 0 0 0 1 0 0 0 1 %s\n", Offset[0], Offset[1], Offset[2], mBodyPart);
1456 	File.WriteBuffer(Line, strlen(Line));
1457 
1458 	Offset = lcMul(Sections[0], lcMatrix44Translation(lcVector3(0.0f, 0.0f, mAxleOffset))).GetTranslation();
1459 	sprintf(Line, "1 25 %f %f %f 0 1 0 -1 0 0 0 0 1 %s\n", Offset[0], Offset[1], Offset[2], mAxlePart);
1460 	File.WriteBuffer(Line, strlen(Line));
1461 
1462 	Offset = Sections[1].GetTranslation();
1463 	sprintf(Line, "1 72 %f %f %f 1 0 0 0 1 0 0 0 1 %s\n", Offset[0], Offset[1], Offset[2], mPistonPart);
1464 	File.WriteBuffer(Line, strlen(Line));
1465 }
1466 
AddParts(lcMemFile & File,lcLibraryMeshData &,const lcArray<lcMatrix44> & Sections) const1467 void lcSynthInfoUniversalJoint::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray<lcMatrix44>& Sections) const
1468 {
1469 	char Line[256];
1470 	lcVector3 Offset = Sections[0].GetTranslation();
1471 
1472 	float Angle = atan2f(Offset.x, Offset.z);
1473 	lcMatrix44 Rotation = lcMatrix44RotationZ(Angle);
1474 	lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(Rotation);
1475 
1476 	sprintf(Line, "1 16 0 0 0 %f %f %f %f %f %f %f %f %f %s\n", Transform[0][0], Transform[1][0], Transform[2][0],
1477 			Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], mCenterPart);
1478 	File.WriteBuffer(Line, strlen(Line));
1479 
1480 	Angle = atan2f(Offset.y, hypotf(Offset.x, Offset.z));
1481 	Rotation = lcMul(Rotation, lcMatrix44RotationX(Angle));
1482 	Transform = lcMul(
1483 			lcMatrix44Translation(lcVector3(0.0f, 0.0f, mEndOffset)),
1484 			lcMatrix44LeoCADToLDraw(Rotation)
1485 			);
1486 
1487 	sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Transform[3][0], Transform[3][1], Transform[3][2],
1488 			Transform[0][0], Transform[1][0], Transform[2][0],
1489 			Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], mEndPart);
1490 	File.WriteBuffer(Line, strlen(Line));
1491 
1492 	Rotation = lcMatrix44FromEulerAngles(lcVector3(0.0f, LC_PI/2, LC_PI));
1493 	Transform = lcMatrix44LeoCADToLDraw(lcMul(lcMatrix44Translation(lcVector3(0.0f, mEndOffset, 0.0f)), Rotation));
1494 	sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Transform[3][0], Transform[3][1], Transform[3][2],
1495 			Transform[0][0], Transform[1][0], Transform[2][0],
1496 			Transform[0][1], Transform[1][1], -Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], mEndPart);
1497 	File.WriteBuffer(Line, strlen(Line));
1498 }
1499 
CreateMesh(const lcArray<lcPieceControlPoint> & ControlPoints) const1500 lcMesh* lcSynthInfo::CreateMesh(const lcArray<lcPieceControlPoint>& ControlPoints) const
1501 {
1502 	lcArray<lcMatrix44> Sections;
1503 
1504 	CalculateSections(ControlPoints, Sections, nullptr);
1505 
1506 	lcLibraryMeshData MeshData;
1507 	lcMemFile File; // todo: rewrite this to pass the parts directly
1508 
1509 	AddParts(File, MeshData, Sections);
1510 
1511 	File.WriteU8(0);
1512 
1513 	lcArray<lcMeshLoaderTextureMap> TextureStack;
1514 	File.Seek(0, SEEK_SET);
1515 
1516 	lcMeshLoader MeshLoader(MeshData, false, nullptr, false);
1517 	if (MeshLoader.LoadMesh(File, LC_MESHDATA_SHARED))
1518 		return MeshData.CreateMesh();
1519 
1520 	return nullptr;
1521 }
1522 
InsertControlPoint(lcArray<lcPieceControlPoint> & ControlPoints,const lcVector3 & Start,const lcVector3 & End) const1523 int lcSynthInfo::InsertControlPoint(lcArray<lcPieceControlPoint>& ControlPoints, const lcVector3& Start, const lcVector3& End) const
1524 {
1525 	lcArray<lcMatrix44> Sections;
1526 
1527 	int BestSegment = -1;
1528 	float BestTime;
1529 	float BestDistance = FLT_MAX;
1530 	lcVector3 BestPosition;
1531 
1532 	CalculateSections(ControlPoints, Sections,
1533 		[&](const lcVector3& CurvePoint, int SegmentIndex, float t)
1534 		{
1535 			float Distance = lcRayPointDistance(CurvePoint, Start, End);
1536 			if (Distance < BestDistance)
1537 			{
1538 				BestSegment = SegmentIndex;
1539 				BestTime = t;
1540 				BestDistance = Distance;
1541 				BestPosition = lcVector3LDrawToLeoCAD(CurvePoint);
1542 			}
1543 		}
1544 	);
1545 
1546 	if (BestSegment != -1)
1547 	{
1548 		lcPieceControlPoint ControlPoint = ControlPoints[BestSegment];
1549 		ControlPoint.Transform.SetTranslation(BestPosition);
1550 
1551 		if (BestSegment != ControlPoints.GetSize() - 1)
1552 		{
1553 			lcPieceControlPoint NextControlPoint = ControlPoints[BestSegment + 1];
1554 			ControlPoint.Scale = ControlPoint.Scale * (1.0f - BestTime) + NextControlPoint.Scale * BestTime;
1555 		}
1556 
1557 		ControlPoints.InsertAt(BestSegment + 1, ControlPoint);
1558 	}
1559 
1560 	return BestSegment + 1;
1561 }
1562