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