1 #include "lc_global.h"
2 #include "lc_colors.h"
3 #include "lc_file.h"
4 #include "lc_library.h"
5 #include "lc_application.h"
6 #include <float.h>
7
8 std::vector<lcColor> gColorList;
9 lcColorGroup gColorGroups[LC_NUM_COLORGROUPS];
10 int gEdgeColor;
11 int gDefaultColor;
12
13 lcVector4 gInterfaceColors[LC_NUM_INTERFACECOLORS] = // todo: make the colors configurable and include the grid and other hardcoded colors here as well.
14 {
15 lcVector4(0.898f, 0.298f, 0.400f, 1.000f), // LC_COLOR_SELECTED
16 lcVector4(0.400f, 0.298f, 0.898f, 1.000f), // LC_COLOR_FOCUSED
17 lcVector4(0.500f, 0.800f, 0.500f, 1.000f), // LC_COLOR_CAMERA
18 lcVector4(0.500f, 0.800f, 0.500f, 1.000f), // LC_COLOR_LIGHT
19 lcVector4(0.500f, 0.800f, 0.500f, 0.500f), // LC_COLOR_CONTROL_POINT
20 lcVector4(0.400f, 0.298f, 0.898f, 0.500f), // LC_COLOR_CONTROL_POINT_FOCUSED
21 };
22
GetToken(char * & Ptr,char * Token)23 static void GetToken(char*& Ptr, char* Token)
24 {
25 while (*Ptr && *Ptr <= 32)
26 Ptr++;
27
28 while (*Ptr > 32)
29 *Token++ = *Ptr++;
30
31 *Token = 0;
32 }
33
lcAdjustStudStyleColors(std::vector<lcColor> & Colors,lcStudStyle StudStyle)34 static void lcAdjustStudStyleColors(std::vector<lcColor>& Colors, lcStudStyle StudStyle)
35 {
36 const lcPreferences& Preferences = lcGetPreferences();
37
38 if (!Preferences.mAutomateEdgeColor && !lcIsHighContrast(StudStyle))
39 return;
40
41 const lcVector4 Edge = lcVector4FromColor(Preferences.mPartEdgeColor);
42 const lcVector4 DarkEdge = lcVector4FromColor(Preferences.mDarkEdgeColor);
43 const lcVector4 BlackEdge = lcVector4FromColor(Preferences.mBlackEdgeColor);
44
45 const float ContrastControl = Preferences.mPartEdgeContrast;
46 const float LightDarkControl = Preferences.mAutomateEdgeColor ? Preferences.mPartColorValueLDIndex : LC_SRGB_TO_LINEAR(Preferences.mPartColorValueLDIndex);
47
48 for (lcColor& Color : Colors)
49 {
50 lcVector3 LinearColor = lcSRGBToLinear(lcVector3(Color.Value));
51 const float ValueLuminescence = lcLuminescence(LinearColor);
52
53 if (Preferences.mAutomateEdgeColor)
54 {
55 if (Color.Adjusted)
56 continue;
57
58 const float EdgeLuminescence = lcLuminescence(lcSRGBToLinear(lcVector3(Color.Edge)));
59
60 Color.Edge = lcAlgorithmicEdgeColor(LinearColor, ValueLuminescence, EdgeLuminescence, ContrastControl, LightDarkControl);
61 Color.Adjusted = true;
62 }
63 else
64 {
65 if (Color.Code == 4242)
66 continue;
67 else if (Color.Code == 0)
68 Color.Edge = BlackEdge;
69 else if (ValueLuminescence < LightDarkControl)
70 Color.Edge = DarkEdge;
71 else
72 Color.Edge = Edge;
73 }
74 }
75 }
76
lcParseColorFile(lcFile & File)77 static std::vector<lcColor> lcParseColorFile(lcFile& File)
78 {
79 char Line[1024], Token[1024];
80 std::vector<lcColor> Colors;
81 lcColor Color;
82
83 while (File.ReadLine(Line, sizeof(Line)))
84 {
85 char* Ptr = Line;
86
87 GetToken(Ptr, Token);
88 if (strcmp(Token, "0"))
89 continue;
90
91 GetToken(Ptr, Token);
92 strupr(Token);
93 if (strcmp(Token, "!COLOUR"))
94 continue;
95
96 Color.Code = ~0U;
97 Color.Translucent = false;
98 Color.Group = LC_COLORGROUP_SOLID;
99 Color.Value[0] = FLT_MAX;
100 Color.Value[1] = FLT_MAX;
101 Color.Value[2] = FLT_MAX;
102 Color.Value[3] = 1.0f;
103 Color.Edge[0] = FLT_MAX;
104 Color.Edge[1] = FLT_MAX;
105 Color.Edge[2] = FLT_MAX;
106 Color.Edge[3] = 1.0f;
107
108 GetToken(Ptr, Token);
109 strncpy(Color.Name, Token, sizeof(Color.Name));
110 Color.Name[LC_MAX_COLOR_NAME - 1] = 0;
111 strncpy(Color.SafeName, Color.Name, sizeof(Color.SafeName));
112
113 for (char* Underscore = strchr((char*)Color.Name, '_'); Underscore; Underscore = strchr(Underscore, '_'))
114 *Underscore = ' ';
115
116 for (GetToken(Ptr, Token); Token[0]; GetToken(Ptr, Token))
117 {
118 strupr(Token);
119
120 if (!strcmp(Token, "CODE"))
121 {
122 GetToken(Ptr, Token);
123 Color.Code = atoi(Token);
124 }
125 else if (!strcmp(Token, "VALUE"))
126 {
127 GetToken(Ptr, Token);
128 if (Token[0] == '#')
129 Token[0] = ' ';
130
131 int Value;
132 if (sscanf(Token, "%x", &Value) != 1)
133 Value = 0;
134
135 Color.Value[2] = (float)(Value & 0xff) / 255.0f;
136 Value >>= 8;
137 Color.Value[1] = (float)(Value & 0xff) / 255.0f;
138 Value >>= 8;
139 Color.Value[0] = (float)(Value & 0xff) / 255.0f;
140 }
141 else if (!strcmp(Token, "EDGE"))
142 {
143 GetToken(Ptr, Token);
144 if (Token[0] == '#')
145 Token[0] = ' ';
146
147 int Value;
148 if (sscanf(Token, "%x", &Value) != 1)
149 Value = 0;
150
151 Color.Edge[2] = (float)(Value & 0xff) / 255.0f;
152 Value >>= 8;
153 Color.Edge[1] = (float)(Value & 0xff) / 255.0f;
154 Value >>= 8;
155 Color.Edge[0] = (float)(Value & 0xff) / 255.0f;
156 }
157 else if (!strcmp(Token, "ALPHA"))
158 {
159 GetToken(Ptr, Token);
160 int Value = atoi(Token);
161 Color.Value[3] = (float)(Value & 0xff) / 255.0f;
162 if (Value != 255)
163 Color.Translucent = true;
164
165 if (Value == 128)
166 Color.Group = LC_COLORGROUP_TRANSLUCENT;
167 else if (Value != 0)
168 Color.Group = LC_COLORGROUP_SPECIAL;
169 }
170 else if (!strcmp(Token, "CHROME") || !strcmp(Token, "PEARLESCENT") || !strcmp(Token, "RUBBER") ||
171 !strcmp(Token, "MATTE_METALIC") || !strcmp(Token, "METAL") || !strcmp(Token, "LUMINANCE"))
172 {
173 Color.Group = LC_COLORGROUP_SPECIAL;
174 }
175 else if (!strcmp(Token, "MATERIAL"))
176 {
177 Color.Group = LC_COLORGROUP_SPECIAL;
178 break; // Material is always last so ignore it and the rest of the line.
179 }
180 }
181
182 if (Color.Code == ~0U || Color.Value[0] == FLT_MAX)
183 continue;
184
185 if (Color.Edge[0] == FLT_MAX)
186 {
187 Color.Edge[0] = 33.0f / 255.0f;
188 Color.Edge[1] = 33.0f / 255.0f;
189 Color.Edge[2] = 33.0f / 255.0f;
190 }
191
192 bool Duplicate = false;
193
194 for (lcColor& ExistingColor : Colors)
195 {
196 if (ExistingColor.Code == Color.Code)
197 {
198 ExistingColor = Color;
199 Duplicate = true;
200 break;
201 }
202 }
203
204 if (!Duplicate)
205 Colors.push_back(Color);
206 }
207
208 return Colors;
209 }
210
lcLoadColorFile(lcFile & File,lcStudStyle StudStyle)211 bool lcLoadColorFile(lcFile& File, lcStudStyle StudStyle)
212 {
213 std::vector<lcColor> Colors = lcParseColorFile(File);
214 const bool Valid = !Colors.empty();
215
216 if (Valid)
217 lcAdjustStudStyleColors(Colors, StudStyle);
218
219 bool FoundMain = false, FoundEdge = false, FoundStud = false, FoundNoColor = false;
220
221 for (const lcColor& Color : Colors)
222 {
223 switch (Color.Code)
224 {
225 case 16:
226 FoundMain = true;
227 break;
228
229 case 24:
230 FoundEdge = true;
231 break;
232
233 case 4242:
234 FoundStud = true;
235 break;
236
237 case LC_COLOR_NOCOLOR:
238 FoundNoColor = true;
239 break;
240 }
241 }
242
243 if (!FoundMain)
244 {
245 lcColor MainColor;
246
247 MainColor.Code = 16;
248 MainColor.Translucent = false;
249 MainColor.Group = LC_COLORGROUP_SOLID;
250 MainColor.Value[0] = 1.0f;
251 MainColor.Value[1] = 1.0f;
252 MainColor.Value[2] = 0.5f;
253 MainColor.Value[3] = 1.0f;
254 MainColor.Edge[0] = 0.2f;
255 MainColor.Edge[1] = 0.2f;
256 MainColor.Edge[2] = 0.2f;
257 MainColor.Edge[3] = 1.0f;
258 strcpy(MainColor.Name, "Main Color");
259 strcpy(MainColor.SafeName, "Main_Color");
260
261 Colors.push_back(MainColor);
262 }
263
264 if (!FoundEdge)
265 {
266 lcColor EdgeColor;
267
268 EdgeColor.Code = 24;
269 EdgeColor.Translucent = false;
270 EdgeColor.Group = LC_NUM_COLORGROUPS;
271 EdgeColor.Value[0] = 0.5f;
272 EdgeColor.Value[1] = 0.5f;
273 EdgeColor.Value[2] = 0.5f;
274 EdgeColor.Value[3] = 1.0f;
275 EdgeColor.Edge[0] = 0.2f;
276 EdgeColor.Edge[1] = 0.2f;
277 EdgeColor.Edge[2] = 0.2f;
278 EdgeColor.Edge[3] = 1.0f;
279 strcpy(EdgeColor.Name, "Edge Color");
280 strcpy(EdgeColor.SafeName, "Edge_Color");
281
282 Colors.push_back(EdgeColor);
283 }
284
285 if (!FoundStud)
286 {
287 const lcPreferences& Preferences = lcGetPreferences();
288 lcColor StudCylinderColor;
289
290 StudCylinderColor.Code = 4242;
291 StudCylinderColor.Translucent = false;
292 StudCylinderColor.Group = LC_NUM_COLORGROUPS;
293 StudCylinderColor.Value = lcVector4FromColor(Preferences.mStudCylinderColor);
294 StudCylinderColor.Edge = lcVector4FromColor(Preferences.mPartEdgeColor);
295 strcpy(StudCylinderColor.Name, "Stud Cylinder Color");
296 strcpy(StudCylinderColor.SafeName, "Stud_Cylinder_Color");
297
298 Colors.push_back(StudCylinderColor);
299 }
300
301 if (!FoundNoColor)
302 {
303 lcColor NoColor;
304
305 NoColor.Code = LC_COLOR_NOCOLOR;
306 NoColor.Translucent = false;
307 NoColor.Group = LC_NUM_COLORGROUPS;
308 NoColor.Value[0] = 0.5f;
309 NoColor.Value[1] = 0.5f;
310 NoColor.Value[2] = 0.5f;
311 NoColor.Value[3] = 1.0f;
312 NoColor.Edge[0] = 0.2f;
313 NoColor.Edge[1] = 0.2f;
314 NoColor.Edge[2] = 0.2f;
315 NoColor.Edge[3] = 1.0f;
316 strcpy(NoColor.Name, "No Color");
317 strcpy(NoColor.SafeName, "No_Color");
318
319 Colors.push_back(NoColor);
320 }
321
322 for (lcColor& Color : gColorList)
323 Color.Group = LC_NUM_COLORGROUPS;
324
325 for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++)
326 gColorGroups[GroupIdx].Colors.clear();
327
328 gColorGroups[0].Name = QApplication::tr("Solid", "Colors");
329 gColorGroups[1].Name = QApplication::tr("Translucent", "Colors");
330 gColorGroups[2].Name = QApplication::tr("Special", "Colors");
331
332 for (lcColor& Color : Colors)
333 {
334 int ColorIndex;
335
336 for (ColorIndex = 0; ColorIndex < static_cast<int>(gColorList.size()); ColorIndex++)
337 if (gColorList[ColorIndex].Code == Color.Code)
338 break;
339
340 if (ColorIndex == static_cast<int>(gColorList.size()))
341 gColorList.push_back(Color);
342 else
343 gColorList[ColorIndex] = Color;
344
345 if (Color.Group != LC_NUM_COLORGROUPS)
346 gColorGroups[Color.Group].Colors.push_back(ColorIndex);
347
348 if (Color.Code == 16)
349 gDefaultColor = ColorIndex;
350 else if (Color.Code == 24)
351 gEdgeColor = ColorIndex;
352 }
353
354 return Valid;
355 }
356
lcLoadDefaultColors(lcStudStyle StudStyle)357 void lcLoadDefaultColors(lcStudStyle StudStyle)
358 {
359 lcDiskFile ConfigFile(":/resources/ldconfig.ldr");
360
361 if (ConfigFile.Open(QIODevice::ReadOnly))
362 lcLoadColorFile(ConfigFile, StudStyle);
363 }
364
lcGetColorIndex(quint32 ColorCode)365 int lcGetColorIndex(quint32 ColorCode)
366 {
367 for (size_t ColorIdx = 0; ColorIdx < gColorList.size(); ColorIdx++)
368 if (gColorList[ColorIdx].Code == ColorCode)
369 return (int)ColorIdx;
370
371 lcColor Color;
372
373 Color.Code = ColorCode;
374 Color.Translucent = false;
375 Color.Edge[0] = 0.2f;
376 Color.Edge[1] = 0.2f;
377 Color.Edge[2] = 0.2f;
378 Color.Edge[3] = 1.0f;
379
380 if (ColorCode & LC_COLOR_DIRECT)
381 {
382 Color.Value[0] = (float)((ColorCode & 0xff0000) >> 16) / 255.0f;
383 Color.Value[1] = (float)((ColorCode & 0x00ff00) >> 8) / 255.0f;
384 Color.Value[2] = (float)((ColorCode & 0x0000ff) >> 0) / 255.0f;
385 Color.Value[3] = 1.0f;
386 sprintf(Color.Name, "Color %06X", ColorCode & 0xffffff);
387 sprintf(Color.SafeName, "Color_%06X", ColorCode & 0xffffff);
388 }
389 else
390 {
391 Color.Value[0] = 0.5f;
392 Color.Value[1] = 0.5f;
393 Color.Value[2] = 0.5f;
394 Color.Value[3] = 1.0f;
395 sprintf(Color.Name, "Color %03d", ColorCode);
396 sprintf(Color.SafeName, "Color_%03d", ColorCode);
397 }
398
399 gColorList.push_back(Color);
400 return (int)gColorList.size() - 1;
401 }
402