#include "lc_global.h" #include "lc_colors.h" #include "lc_file.h" #include "lc_library.h" #include "lc_application.h" #include std::vector gColorList; lcColorGroup gColorGroups[LC_NUM_COLORGROUPS]; int gEdgeColor; int gDefaultColor; static void GetToken(char*& Ptr, char* Token) { while (*Ptr && *Ptr <= 32) Ptr++; while (*Ptr > 32) *Token++ = *Ptr++; *Token = 0; } static void lcAdjustStudStyleColors(std::vector& Colors, lcStudStyle StudStyle) { const lcPreferences& Preferences = lcGetPreferences(); if (!Preferences.mAutomateEdgeColor && !lcIsHighContrast(StudStyle)) return; const lcVector4 Edge = lcVector4FromColor(Preferences.mPartEdgeColor); const lcVector4 DarkEdge = lcVector4FromColor(Preferences.mDarkEdgeColor); const lcVector4 BlackEdge = lcVector4FromColor(Preferences.mBlackEdgeColor); const float ContrastControl = Preferences.mPartEdgeContrast; const float LightDarkControl = Preferences.mAutomateEdgeColor ? Preferences.mPartColorValueLDIndex : LC_SRGB_TO_LINEAR(Preferences.mPartColorValueLDIndex); for (lcColor& Color : Colors) { const lcVector3 LinearColor = lcSRGBToLinear(lcVector3(Color.Value)); const float ValueLuminescence = lcLuminescence(LinearColor); if (Preferences.mAutomateEdgeColor) { if (Color.Adjusted) continue; const float EdgeLuminescence = lcLuminescence(lcSRGBToLinear(lcVector3(Color.Edge))); Color.Edge = lcAlgorithmicEdgeColor(LinearColor, ValueLuminescence, EdgeLuminescence, ContrastControl, LightDarkControl); Color.Adjusted = true; } else { if (Color.Code == LC_STUD_CYLINDER_COLOR_CODE) continue; else if (Preferences.mBlackEdgeColorEnabled && Color.Code == 0) Color.Edge = BlackEdge; else if (Preferences.mDarkEdgeColorEnabled && ValueLuminescence < LightDarkControl) Color.Edge = DarkEdge; else if (Preferences.mPartEdgeColorEnabled) Color.Edge = Edge; } } } static std::vector lcParseColorFile(lcFile& File) { char Line[1024], Token[1024]; std::vector Colors; lcColor Color; while (File.ReadLine(Line, sizeof(Line))) { char* Ptr = Line; GetToken(Ptr, Token); if (strcmp(Token, "0")) continue; GetToken(Ptr, Token); strupr(Token); if (strcmp(Token, "!COLOUR")) continue; Color.Code = ~0U; Color.Translucent = false; Color.Chrome = false; Color.Rubber = false; Color.Group = LC_COLORGROUP_SOLID; Color.Value[0] = FLT_MAX; Color.Value[1] = FLT_MAX; Color.Value[2] = FLT_MAX; Color.Value[3] = 1.0f; Color.Edge[0] = FLT_MAX; Color.Edge[1] = FLT_MAX; Color.Edge[2] = FLT_MAX; Color.Edge[3] = 1.0f; GetToken(Ptr, Token); strncpy(Color.Name, Token, sizeof(Color.Name)); Color.Name[LC_MAX_COLOR_NAME - 1] = 0; strncpy(Color.SafeName, Color.Name, sizeof(Color.SafeName)); for (char* Underscore = strchr((char*)Color.Name, '_'); Underscore; Underscore = strchr(Underscore, '_')) *Underscore = ' '; for (GetToken(Ptr, Token); Token[0]; GetToken(Ptr, Token)) { strupr(Token); if (!strcmp(Token, "CODE")) { GetToken(Ptr, Token); Color.Code = atoi(Token); } else if (!strcmp(Token, "VALUE")) { GetToken(Ptr, Token); if (Token[0] == '#') Token[0] = ' '; int Value; if (sscanf(Token, "%x", &Value) != 1) Value = 0; Color.Value[2] = (float)(Value & 0xff) / 255.0f; Value >>= 8; Color.Value[1] = (float)(Value & 0xff) / 255.0f; Value >>= 8; Color.Value[0] = (float)(Value & 0xff) / 255.0f; } else if (!strcmp(Token, "EDGE")) { GetToken(Ptr, Token); if (Token[0] == '#') Token[0] = ' '; int Value; if (sscanf(Token, "%x", &Value) != 1) Value = 0; Color.Edge[2] = (float)(Value & 0xff) / 255.0f; Value >>= 8; Color.Edge[1] = (float)(Value & 0xff) / 255.0f; Value >>= 8; Color.Edge[0] = (float)(Value & 0xff) / 255.0f; } else if (!strcmp(Token, "ALPHA")) { GetToken(Ptr, Token); int Value = atoi(Token); Color.Value[3] = (float)(Value & 0xff) / 255.0f; if (Value != 255) Color.Translucent = true; if (Value == 128) Color.Group = LC_COLORGROUP_TRANSLUCENT; else if (Value != 0) Color.Group = LC_COLORGROUP_SPECIAL; } else if (!strcmp(Token, "CHROME")) { Color.Chrome = true; Color.Group = LC_COLORGROUP_SPECIAL; } else if (!strcmp(Token, "RUBBER")) { Color.Rubber = true; Color.Group = LC_COLORGROUP_SPECIAL; } else if (!strcmp(Token, "PEARLESCENT") || !strcmp(Token, "MATTE_METALIC") || !strcmp(Token, "METAL") || !strcmp(Token, "LUMINANCE")) { Color.Group = LC_COLORGROUP_SPECIAL; } else if (!strcmp(Token, "MATERIAL")) { Color.Group = LC_COLORGROUP_SPECIAL; break; // Material is always last so ignore it and the rest of the line. } } if (Color.Code == ~0U || Color.Value[0] == FLT_MAX) continue; if (Color.Edge[0] == FLT_MAX) { Color.Edge[0] = 33.0f / 255.0f; Color.Edge[1] = 33.0f / 255.0f; Color.Edge[2] = 33.0f / 255.0f; } bool Duplicate = false; for (lcColor& ExistingColor : Colors) { if (ExistingColor.Code == Color.Code) { ExistingColor = Color; Duplicate = true; break; } } if (!Duplicate) Colors.push_back(Color); } return Colors; } bool lcLoadColorFile(lcFile& File, lcStudStyle StudStyle) { std::vector Colors = lcParseColorFile(File); const bool Valid = !Colors.empty(); if (Valid) lcAdjustStudStyleColors(Colors, StudStyle); bool FoundMain = false, FoundEdge = false, FoundStudCylinder = false, FoundNoColor = false; for (const lcColor& Color : Colors) { switch (Color.Code) { case 16: FoundMain = true; break; case 24: FoundEdge = true; break; case LC_STUD_CYLINDER_COLOR_CODE: FoundStudCylinder = true; break; case LC_COLOR_NOCOLOR: FoundNoColor = true; break; } } if (!FoundMain) { lcColor MainColor; MainColor.Code = 16; MainColor.Translucent = false; MainColor.Chrome = false; MainColor.Rubber = false; MainColor.Group = LC_COLORGROUP_SOLID; MainColor.Value[0] = 1.0f; MainColor.Value[1] = 1.0f; MainColor.Value[2] = 0.5f; MainColor.Value[3] = 1.0f; MainColor.Edge[0] = 0.2f; MainColor.Edge[1] = 0.2f; MainColor.Edge[2] = 0.2f; MainColor.Edge[3] = 1.0f; strcpy(MainColor.Name, "Main Color"); strcpy(MainColor.SafeName, "Main_Color"); Colors.push_back(MainColor); } if (!FoundEdge) { lcColor EdgeColor; EdgeColor.Code = 24; EdgeColor.Translucent = false; EdgeColor.Chrome = false; EdgeColor.Rubber = false; EdgeColor.Group = LC_NUM_COLORGROUPS; EdgeColor.Value[0] = 0.5f; EdgeColor.Value[1] = 0.5f; EdgeColor.Value[2] = 0.5f; EdgeColor.Value[3] = 1.0f; EdgeColor.Edge[0] = 0.2f; EdgeColor.Edge[1] = 0.2f; EdgeColor.Edge[2] = 0.2f; EdgeColor.Edge[3] = 1.0f; strcpy(EdgeColor.Name, "Edge Color"); strcpy(EdgeColor.SafeName, "Edge_Color"); Colors.push_back(EdgeColor); } if (!FoundStudCylinder) { const lcPreferences& Preferences = lcGetPreferences(); lcColor StudCylinderColor; StudCylinderColor.Code = LC_STUD_CYLINDER_COLOR_CODE; StudCylinderColor.Translucent = false; StudCylinderColor.Chrome = false; StudCylinderColor.Rubber = false; StudCylinderColor.Group = LC_NUM_COLORGROUPS; StudCylinderColor.Value = lcVector4FromColor(Preferences.mStudCylinderColor); StudCylinderColor.Edge = lcVector4FromColor(Preferences.mPartEdgeColor); strcpy(StudCylinderColor.Name, "Stud Cylinder Color"); strcpy(StudCylinderColor.SafeName, "Stud_Cylinder_Color"); Colors.push_back(StudCylinderColor); } if (!FoundNoColor) { lcColor NoColor; NoColor.Code = LC_COLOR_NOCOLOR; NoColor.Translucent = false; NoColor.Chrome = false; NoColor.Rubber = false; NoColor.Group = LC_NUM_COLORGROUPS; NoColor.Value[0] = 0.5f; NoColor.Value[1] = 0.5f; NoColor.Value[2] = 0.5f; NoColor.Value[3] = 1.0f; NoColor.Edge[0] = 0.2f; NoColor.Edge[1] = 0.2f; NoColor.Edge[2] = 0.2f; NoColor.Edge[3] = 1.0f; strcpy(NoColor.Name, "No Color"); strcpy(NoColor.SafeName, "No_Color"); Colors.push_back(NoColor); } for (lcColor& Color : gColorList) Color.Group = LC_NUM_COLORGROUPS; for (int GroupIdx = 0; GroupIdx < LC_NUM_COLORGROUPS; GroupIdx++) gColorGroups[GroupIdx].Colors.clear(); gColorGroups[0].Name = QApplication::tr("Solid", "Colors"); gColorGroups[1].Name = QApplication::tr("Translucent", "Colors"); gColorGroups[2].Name = QApplication::tr("Special", "Colors"); for (lcColor& Color : Colors) { int ColorIndex; for (ColorIndex = 0; ColorIndex < static_cast(gColorList.size()); ColorIndex++) if (gColorList[ColorIndex].Code == Color.Code) break; if (ColorIndex == static_cast(gColorList.size())) gColorList.push_back(Color); else gColorList[ColorIndex] = Color; if (Color.Group != LC_NUM_COLORGROUPS) gColorGroups[Color.Group].Colors.push_back(ColorIndex); if (Color.Code == 16) gDefaultColor = ColorIndex; else if (Color.Code == 24) gEdgeColor = ColorIndex; } return Valid; } void lcLoadDefaultColors(lcStudStyle StudStyle) { lcDiskFile ConfigFile(":/resources/ldconfig.ldr"); if (ConfigFile.Open(QIODevice::ReadOnly)) lcLoadColorFile(ConfigFile, StudStyle); } int lcGetColorIndex(quint32 ColorCode) { for (size_t ColorIdx = 0; ColorIdx < gColorList.size(); ColorIdx++) if (gColorList[ColorIdx].Code == ColorCode) return (int)ColorIdx; lcColor Color; Color.Code = ColorCode; Color.Translucent = false; Color.Chrome = false; Color.Rubber = false; Color.Edge[0] = 0.2f; Color.Edge[1] = 0.2f; Color.Edge[2] = 0.2f; Color.Edge[3] = 1.0f; if (ColorCode & LC_COLOR_DIRECT) { Color.Value[0] = (float)((ColorCode & 0xff0000) >> 16) / 255.0f; Color.Value[1] = (float)((ColorCode & 0x00ff00) >> 8) / 255.0f; Color.Value[2] = (float)((ColorCode & 0x0000ff) >> 0) / 255.0f; Color.Value[3] = 1.0f; sprintf(Color.Name, "Color %06X", ColorCode & 0xffffff); sprintf(Color.SafeName, "Color_%06X", ColorCode & 0xffffff); } else { Color.Value[0] = 0.5f; Color.Value[1] = 0.5f; Color.Value[2] = 0.5f; Color.Value[3] = 1.0f; sprintf(Color.Name, "Color %03d", ColorCode); sprintf(Color.SafeName, "Color_%03d", ColorCode); } gColorList.push_back(Color); return (int)gColorList.size() - 1; }