diff --git a/ContextHelp.h b/ContextHelp.h index d6249343e..0be41e5b5 100644 --- a/ContextHelp.h +++ b/ContextHelp.h @@ -8,11 +8,16 @@ #define HIDC_ALWAYS_BLACK 0x808903f5 // IDD_GEOMETRY_PREFS #define HIDC_ANISO_LEVEL 0x860b03fb // IDD_PRIMITIVES_PREFS #define HIDC_ANISO_LEVEL_LABEL 0x860b04d0 // IDD_PRIMITIVES_PREFS +#define HIDC_AUTOMATE_EDGE_COLOR_CHECK 0x8089053a // IDD_GEOMETRY_PREFS +#define HIDC_AUTOMATE_EDGE_COLOR 0x808903f6 // IDD_GEOMETRY_PREFS #define HIDC_AUTO_CROP 0x808d04bd // IDD_SAVE_OPTIONS #define HIDC_BACKGROUND_COLOR 0x808b03fd // IDD_GENERAL_PREFS #define HIDC_BACKGROUND_COLOR_LABEL 0x808b0439 // IDD_GENERAL_PREFS #define HIDC_BFC 0x80890412 // IDD_GEOMETRY_PREFS #define HIDC_BFC_BOX 0x808904a0 // IDD_GEOMETRY_PREFS +#define HIDC_BLACK_EDGE_COLOR 0x8224053d // IDD_STUD_STYLE_COLORS +#define HIDC_BLACK_EDGE_COLOR_CHECK 0x8224053c // IDD_STUD_STYLE_COLORS +#define HIDC_BLACK_EDGE_COLOR_RESET 0x8224053e // IDD_STUD_STYLE_COLORS #define HIDC_BLUE_NEUTRAL_FACES 0x80890415 // IDD_GEOMETRY_PREFS #define HIDC_BROWSE_CUSTOM_CONFIG 0x808b052c // IDD_GENERAL_PREFS #define HIDC_BROWSE_EXPORT_DIR 0x808b04f6 // IDD_GENERAL_PREFS @@ -27,6 +32,10 @@ #define HIDC_LDRAW_RESET 0x808e0467 // IDD_LDRAW_PREFS #define HIDC_CONDITIONAL_CONTROLS 0x80890410 // IDD_GEOMETRY_PREFS #define HIDC_CONDITIONAL_HIGHLIGHTS 0x8089050a // IDD_GEOMETRY_PREFS +#define HIDC_CONTRAST_NAME 0x82240544 // IDD_STUD_STYLE_COLORS +#define HIDC_CONTRAST_RESET 0x82240546 // IDD_STUD_STYLE_COLORS +#define HIDC_CONTRAST_SLIDER 0x82240543 // IDD_STUD_STYLE_COLORS +#define HIDC_CONTRAST_VALUE 0x82240545 // IDD_STUD_STYLE_COLORS #define HIDC_CROSS_EYED_STEREO 0x808a03f6 // IDD_EFFECTS_PREFS #define HIDC_CURVE_QUALITY 0x860b03fa // IDD_PRIMITIVES_PREFS #define HIDC_CURVE_QUALITY_LABEL 0x860b03fc // IDD_PRIMITIVES_PREFS @@ -40,6 +49,9 @@ #define HIDC_CUTAWAY_OPACITY_LABEL 0x808a0464 // IDD_EFFECTS_PREFS #define HIDC_CUTAWAY_THICKNESS 0x808a0466 // IDD_EFFECTS_PREFS #define HIDC_CUTAWAY_THICKNESS_LABEL 0x808a0465 // IDD_EFFECTS_PREFS +#define HIDC_DARK_EDGE_COLOR 0x82240540 // IDD_STUD_STYLE_COLORS +#define HIDC_DARK_EDGE_COLOR_CHECK 0x8224053f // IDD_STUD_STYLE_COLORS +#define HIDC_DARK_EDGE_COLOR_RESET 0x82240541 // IDD_STUD_STYLE_COLORS #define HIDC_DEFAULT_COLOR 0x808b03ff // IDD_GENERAL_PREFS #define HIDC_DEFAULT_COLOR_LABEL 0x808b043a // IDD_GENERAL_PREFS #define HIDC_DELETE_PREF_SET 0x860c0477 // IDD_PREFSETS_PREFS @@ -67,6 +79,7 @@ #define HIDC_GREEN_FRONT_FACES 0x80890414 // IDD_GEOMETRY_PREFS #define HIDC_HIDE_LIGHT_DAT 0x808a03f3 // IDD_EFFECTS_PREFS #define HIDC_HIGHLIGHTS 0x808903eb // IDD_GEOMETRY_PREFS +#define HIDC_HIGH_CONTRAST_COLOR 0x860b052f // IDD_PRIMITIVES_PREFS #define HIDC_HI_RES 0x860b050b // IDD_PRIMITIVES_PREFS #define HIDC_IGNORE_FBO 0x808d04ab // IDD_SAVE_OPTIONS #define HIDC_IGNORE_PBUFFER 0x808d04a6 // IDD_SAVE_OPTIONS @@ -75,6 +88,10 @@ #define HIDC_LIGHTING_BOX 0x808a045d // IDD_EFFECTS_PREFS #define HIDC_LIGHTING_QUALITY 0x808a03e9 // IDD_EFFECTS_PREFS #define HIDC_LIGHTING_SUBDUED 0x808a040d // IDD_EFFECTS_PREFS +#define HIDC_LIGHT_DARK_NAME 0x82240532 // IDD_STUD_STYLE_COLORS +#define HIDC_LIGHT_DARK_RESET 0x82240534 // IDD_STUD_STYLE_COLORS +#define HIDC_LIGHT_DARK_SLIDER 0x82240531 // IDD_STUD_STYLE_COLORS +#define HIDC_LIGHT_DARK_VALUE 0x82240533 // IDD_STUD_STYLE_COLORS #define HIDC_LIGHT_DIR 0x808a04ca // IDD_EFFECTS_PREFS #define HIDC_LINE_AA 0x808b0471 // IDD_GENERAL_PREFS #define HIDC_MEMORY_COMBO 0x808b04aa // IDD_GENERAL_PREFS @@ -90,6 +107,9 @@ #define HIDC_PARTS_LIST_DIR 0x808b04f1 // IDD_GENERAL_PREFS #define HIDC_PARTS_LIST_DIR_COMBO 0x808b04ee // IDD_GENERAL_PREFS #define HIDC_PART_BOUNDING_BOXES 0x808904f9 // IDD_GEOMETRY_PREFS +#define HIDC_PART_EDGE_COLOR 0x8224053a // IDD_STUD_STYLE_COLORS +#define HIDC_PART_EDGE_COLOR_CHECK 0x82240539 // IDD_STUD_STYLE_COLORS +#define HIDC_PART_EDGE_COLOR_RESET 0x8224053b // IDD_STUD_STYLE_COLORS #define HIDC_PREFSETS_LABEL 0x860c047d // IDD_PREFSETS_PREFS #define HIDC_PREFSETS_LIST 0x860c0478 // IDD_PREFSETS_PREFS #define HIDC_PREF_SET_HOT_KEY 0x860c0479 // IDD_PREFSETS_PREFS @@ -112,6 +132,10 @@ #define HIDC_REMOVE_HIDDEN_LINES 0x80890411 // IDD_GEOMETRY_PREFS #define HIDC_RESET_TIMES 0x80a70518 // IDD_UPDATES_PREFS #define HIDC_SAME_SCALE 0x808d04c2 // IDD_SAVE_OPTIONS +#define HIDC_SATURATION_NAME 0x82240548 // IDD_STUD_STYLE_COLORS +#define HIDC_SATURATION_RESET 0x8224054a // IDD_STUD_STYLE_COLORS +#define HIDC_SATURATION_SLIDER 0x82240547 // IDD_STUD_STYLE_COLORS +#define HIDC_SATURATION_VALUE 0x82240549 // IDD_STUD_STYLE_COLORS #define HIDC_SAVE_ACTUAL_SIZE 0x808d043e // IDD_SAVE_OPTIONS #define HIDC_SAVE_ACTUAL_SIZE_BOX 0x808d04a9 // IDD_SAVE_OPTIONS #define HIDC_SAVE_DIGITS 0x808d0443 // IDD_SAVE_OPTIONS @@ -157,13 +181,18 @@ #define HIDC_STEREO_SPACING 0x808a0431 // IDD_EFFECTS_PREFS #define HIDC_STEREO_SPACING_LABEL 0x808a0432 // IDD_EFFECTS_PREFS #define HIDC_STIPPLE 0x808a03f0 // IDD_EFFECTS_PREFS -#define HIDC_STUD_QUALITY 0x860b0512 // IDD_PRIMITIVES_PREFS +#define HIDC_STUD_CYLINDER_COLOR 0x82240537 // IDD_STUD_STYLE_COLORS +#define HIDC_STUD_CYLINDER_COLOR_CHECK 0x82240536 // IDD_STUD_STYLE_COLORS +#define HIDC_STUD_CYLINDER_COLOR_RESET 0x82240538 // IDD_STUD_STYLE_COLORS +#define HIDC_STUD_QUALITY 0x860b0514 // IDD_PRIMITIVES_PREFS +#define HIDC_STUD_STYLE_COMBO 0x860b0513 // IDD_PRIMITIVES_PREFS +#define HIDC_STUD_STYLE_USE 0x860b0512 // IDD_PRIMITIVES_PREFS #define HIDC_TEXMAPS 0x860b0509 // IDD_PRIMITIVES_PREFS -#define HIDC_TEXTURE_ANISO 0x860b0513 // IDD_PRIMITIVES_PREFS -#define HIDC_TEXTURE_OFFSET 0x860b0516 // IDD_PRIMITIVES_PREFS +#define HIDC_TEXTURE_ANISO 0x860b0515 // IDD_PRIMITIVES_PREFS #define HIDC_TEXTURE_BILINEAR 0x860b0456 // IDD_PRIMITIVES_PREFS #define HIDC_TEXTURE_NEAREST 0x860b0455 // IDD_PRIMITIVES_PREFS -#define HIDC_TEXTURE_STUDS 0x860b0514 // IDD_PRIMITIVES_PREFS +#define HIDC_TEXTURE_OFFSET 0x860b0517 // IDD_PRIMITIVES_PREFS +#define HIDC_TEXTURE_STUDS 0x860b0516 // IDD_PRIMITIVES_PREFS #define HIDC_TEXTURE_TRILINEAR 0x860b0457 // IDD_PRIMITIVES_PREFS #define HIDC_TRANSPARENCY_BOX 0x808a043c // IDD_EFFECTS_PREFS #define HIDC_TRANS_DEFAULT_COLOR 0x808b03ec // IDD_GENERAL_PREFS diff --git a/LDExporter/LDPovExporter.cpp b/LDExporter/LDPovExporter.cpp index e4b20631d..d499fe89f 100644 --- a/LDExporter/LDPovExporter.cpp +++ b/LDExporter/LDPovExporter.cpp @@ -3481,7 +3481,7 @@ void LDPovExporter::writeColorDeclaration(int colorNumber) colorInfo = pPalette->getAnyColorInfo(colorNumber); if (colorInfo.name[0]) { - fprintf(m_pPovFile, " // %s", colorInfo.name); + fprintf(m_pPovFile, " // %s", colorInfo.name.c_str()); } writeInnerColorDeclaration(colorNumber, false); if (it != m_xmlColors.end()) diff --git a/LDLib/LDHtmlInventory.cpp b/LDLib/LDHtmlInventory.cpp index e0c3cd3ff..d91af4604 100644 --- a/LDLib/LDHtmlInventory.cpp +++ b/LDLib/LDHtmlInventory.cpp @@ -549,7 +549,7 @@ void LDHtmlInventory::writeColorCell( int r, g, b, a; palette->getRGBA(colorInfo, r, g, b, a); - if (strlen(colorInfo.name)) + if (!colorInfo.name.empty()) { fprintf(file, " %d:\n", colorNumber); @@ -571,7 +571,7 @@ void LDHtmlInventory::writeColorCell( fprintf(file, " \n"); fprintf(file, " \n"); fprintf(file, " \n", r, g, b); diff --git a/LDLib/LDPreferences.cpp b/LDLib/LDPreferences.cpp index 4b905fd46..e02ff48ac 100644 --- a/LDLib/LDPreferences.cpp +++ b/LDLib/LDPreferences.cpp @@ -78,6 +78,20 @@ LDPreferences::LDPreferences(LDrawModelViewer* modelViewer) , m_texmaps(false) , m_textureOffsetFactor(0.0) , m_useStrips(false) + , m_automateEdgeColor(true) + , m_useStudStyle(false) + , m_studStyle(0) + , m_studCylinderColorEnabled(true) + , m_partEdgeColorEnabled(true) + , m_blackEdgeColorEnabled(true) + , m_darkEdgeColorEnabled(true) + , m_partColorLDIndex(0.5f) + , m_studCylinderColor(0x1B2A34) // 27,42,52,255 + , m_partEdgeColor(0) // 0,0,0,255 + , m_blackEdgeColor(0xFFFFFF) // 255,255,255,255 + , m_darkEdgeColor(0x1B2A34) // 27,42,52,255 + , m_partEdgeContrast(0.5f) + , m_partEdgeSaturation(0.5f) , m_proxyType(0) , m_proxyPort(0) , m_checkPartTracker(false) @@ -196,6 +210,28 @@ void LDPreferences::getRGB(int color, int &r, int &g, int &b) b = color & 0xFF; } +TCULong LDPreferences::getRGBAColor(int r, int g, int b, int a) +{ + return ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF); +} + +void LDPreferences::getRGBA(int color, int& r, int& g, int& b, int& a) +{ + // Colors are stored in ARGB format. + a = (color >> 24) & 0xFF; + r = (color >> 16) & 0xFF; + g = (color >> 8) & 0xFF; + b = color & 0xFF; +} + +void LDPreferences::getRGBAColorSetting(const char* key, int& r, int& g, int& b, + int& a, TCULong defaultColor) +{ + int value = (int)getRGBAFromStringSetting(key, defaultColor); + + getRGBA(value, r, g, b, a); +} + void LDPreferences::getColorSetting(const char *key, int &r, int &g, int &b, TCULong defaultColor) { @@ -362,6 +398,9 @@ void LDPreferences::applyGeometrySettings(void) m_modelViewer->setUsePolygonOffset(m_usePolygonOffset); m_modelViewer->setBlackHighlights(m_blackHighlights); m_modelViewer->setHighlightLineWidth((GLfloat)m_edgeThickness); + m_modelViewer->setAutomateEdgeColor(m_automateEdgeColor); + m_modelViewer->setPartEdgeContrast(m_partEdgeContrast); + m_modelViewer->setPartEdgeSaturation(m_partEdgeSaturation); } } @@ -407,7 +446,44 @@ void LDPreferences::applyPrimitivesSettings(void) m_modelViewer->setTexturesAfterTransparent(true); m_modelViewer->setTextureOffsetFactor(m_textureOffsetFactor); m_modelViewer->setUseStrips(m_useStrips); - } + m_modelViewer->setUseStudStyle(m_useStudStyle); + m_modelViewer->setStudStyle(m_studStyle); + m_modelViewer->setStudCylinderColorEnabled(m_studCylinderColorEnabled); + m_modelViewer->setPartEdgeColorEnabled(m_partEdgeColorEnabled); + m_modelViewer->setBlackEdgeColorEnabled(m_blackEdgeColorEnabled); + m_modelViewer->setDarkEdgeColorEnabled(m_darkEdgeColorEnabled); + m_modelViewer->setStudCylinderColor(m_studCylinderColor); + m_modelViewer->setPartEdgeColor(m_partEdgeColor); + m_modelViewer->setBlackEdgeColor(m_blackEdgeColor); + m_modelViewer->setDarkEdgeColor(m_darkEdgeColor); + m_modelViewer->setPartColorLDIndex(m_partColorLDIndex); + } + LDLModel::setStudStyle(m_studStyle); + LDLModel::setUseStudStyle(m_useStudStyle); + LDLModel::setStudCylinderColorEnabled(m_studCylinderColorEnabled); + LDLPalette::setAutomateEdgeColor(m_automateEdgeColor); + LDLPalette::setPartEdgeColorEnabled(m_partEdgeColorEnabled); + LDLPalette::setBlackEdgeColorEnabled(m_blackEdgeColorEnabled); + LDLPalette::setDarkEdgeColorEnabled(m_darkEdgeColorEnabled); + LDLPalette::setStudCylinderColor(getLDLColor(m_studCylinderColor)); + LDLPalette::setPartEdgeColor(getLDLColor(m_partEdgeColor)); + LDLPalette::setBlackEdgeColor(getLDLColor(m_blackEdgeColor)); + LDLPalette::setDarkEdgeColor(getLDLColor(m_darkEdgeColor)); + LDLPalette::setPartColorLDIndex(m_partColorLDIndex); + LDLPalette::setPartEdgeContrast(m_partEdgeContrast); + LDLPalette::setPartEdgeSaturation(m_partEdgeSaturation); +} + +LDLColor LDPreferences::getLDLColor(TCULong color) +{ + int r, g, b, a; + getRGBA(color, r, g, b, a); + LDLColor ldlColor; + ldlColor.r = (TCByte)r; + ldlColor.g = (TCByte)g; + ldlColor.b = (TCByte)b; + ldlColor.a = (TCByte)a; + return ldlColor; } void LDPreferences::applyUpdatesSettings(void) @@ -558,7 +634,11 @@ void LDPreferences::loadDefaultGeometrySettings(bool initializing /*= true*/) setUsePolygonOffset(true); setBlackHighlights(false); setEdgeThickness(1); + setAutomateEdgeColor(false); + setPartEdgeContrast(0.5f); + setPartEdgeSaturation(0.5f); m_initializing = false; + } void LDPreferences::loadDefaultEffectsSettings(bool initializing /*= true*/) @@ -605,6 +685,17 @@ void LDPreferences::loadDefaultPrimitivesSettings(bool initializing /*= true*/) setTexmaps(true); setTextureOffsetFactor(5.0); setUseStrips(true); + setUseStudStyle(false); + setStudStyle(0/*Plain*/); + setStudCylinderColorEnabled(true); + setPartEdgeColorEnabled(true); + setBlackEdgeColorEnabled(true); + setDarkEdgeColorEnabled(true); + setStudCylinderColor(27, 42, 52, 255); + setPartEdgeColor(0, 0, 0, 255); + setBlackEdgeColor(255, 255, 255, 255); + setDarkEdgeColor(27, 42, 52, 255); + setPartColorLDIndex(0.5f); m_initializing = false; } @@ -762,6 +853,10 @@ void LDPreferences::loadGeometrySettings(void) m_usePolygonOffset = getBoolSetting(POLYGON_OFFSET_KEY, m_usePolygonOffset); m_blackHighlights = getBoolSetting(BLACK_HIGHLIGHTS_KEY, m_blackHighlights); m_edgeThickness = getIntSetting(EDGE_THICKNESS_KEY, m_edgeThickness); + + m_automateEdgeColor = getBoolSetting(AUTOMATE_EDGE_COLOR_KEY, m_automateEdgeColor); + m_partEdgeContrast = getFloatSetting(PART_EDGE_CONTRAST_KEY, m_partEdgeContrast); + m_partEdgeSaturation = getFloatSetting(PART_EDGE_SATURATION_KEY, m_partEdgeSaturation); } void LDPreferences::loadEffectsSettings(void) @@ -810,6 +905,21 @@ void LDPreferences::loadPrimitivesSettings(void) m_textureOffsetFactor = getFloatSetting(TEXTURE_OFFSET_FACTOR_KEY, m_textureOffsetFactor); m_useStrips = getBoolSetting(STRIPS_KEY, m_useStrips); + + m_useStudStyle = getBoolSetting(USE_STUD_STYLE_KEY, m_useStudStyle); + m_studStyle = getIntSetting(STUD_STYLE_KEY, m_studStyle); + + m_studCylinderColorEnabled = getBoolSetting(STUD_CYLINDER_COLOR_ENABLED_KEY, m_studCylinderColorEnabled); + m_partEdgeColorEnabled = getBoolSetting(PART_EDGE_COLOR_ENABLED_KEY, m_partEdgeColorEnabled); + m_blackEdgeColorEnabled = getBoolSetting(BLACK_EDGE_COLOR_ENABLED_KEY, m_blackEdgeColorEnabled); + m_darkEdgeColorEnabled = getBoolSetting(DARK_EDGE_COLOR_ENABLED_KEY, m_darkEdgeColorEnabled); + + m_studCylinderColor = (TCULong)getRGBAFromStringSetting(STUD_CYLINDER_COLOR_KEY, m_studCylinderColor); + m_partEdgeColor = (TCULong)getRGBAFromStringSetting(PART_EDGE_COLOR_KEY, m_partEdgeColor); + m_blackEdgeColor = (TCULong)getRGBAFromStringSetting(BLACK_EDGE_COLOR_KEY, m_blackEdgeColor); + m_darkEdgeColor = (TCULong)getRGBAFromStringSetting(DARK_EDGE_COLOR_KEY, m_darkEdgeColor); + + m_partColorLDIndex = getFloatSetting(PART_COLOR_LD_INDEX_KEY, m_partColorLDIndex); } void LDPreferences::loadUpdatesSettings(void) @@ -937,6 +1047,9 @@ void LDPreferences::commitGeometrySettings(bool flush /*= true*/) setBlackHighlights(m_blackHighlights, true); } setEdgeThickness(m_edgeThickness, true); + setAutomateEdgeColor(m_automateEdgeColor, true); + setPartEdgeContrast(m_partEdgeContrast, true); + setPartEdgeSaturation(m_partEdgeSaturation, true); if (flush) { TCUserDefaults::flush(); @@ -989,6 +1102,32 @@ void LDPreferences::commitPrimitivesSettings(bool flush /*= true*/) setTexmaps(m_texmaps, true); setTextureOffsetFactor(m_textureOffsetFactor, true); setUseStrips(m_useStrips, true); + + setUseStudStyle(m_useStudStyle, true); + if (m_useStudStyle) + { + setStudStyle(m_studStyle, true); + } + int r, g, b, a; + getRGBA(m_studCylinderColor, r, g, b, a); + setStudCylinderColor(r, g, b, a, true); + + getRGBA(m_partEdgeColor, r, g, b, a); + setPartEdgeColor(r, g, b, a, true); + + getRGBA(m_blackEdgeColor, r, g, b, a); + setBlackEdgeColor(r, g, b, a, true); + + getRGBA(m_darkEdgeColor, r, g, b, a); + setDarkEdgeColor(r, g, b, a, true); + + setStudCylinderColorEnabled(m_studCylinderColorEnabled, true); + setPartEdgeColorEnabled(m_partEdgeColorEnabled, true); + setBlackEdgeColorEnabled(m_blackEdgeColorEnabled, true); + setDarkEdgeColorEnabled(m_darkEdgeColorEnabled, true); + + setPartColorLDIndex(m_partColorLDIndex, true); + if (flush) { TCUserDefaults::flush(); @@ -1142,6 +1281,29 @@ void LDPreferences::setupModelSize(void) } } +void LDPreferences::setRGBAColorSetting(TCULong& setting, int r, int g, int b, int a, + const char* key, bool commit) +{ + TCULong value = getRGBAColor(r, g, b, a); + if (setting != value || (m_changedSettings[key] && commit)) + { + setting = value; + if (commit) + { + char stringValue[128]; + + sprintf(stringValue, "%d,%d,%d,%d", r, g, b, a); + TCUserDefaults::setStringForKey(stringValue, key, + !m_globalSettings[key]); + m_changedSettings.erase(key); + } + else + { + m_changedSettings[key] = true; + } + } +} + void LDPreferences::setColorSetting(TCULong &setting, int r, int g, int b, const char *key, bool commit) { @@ -1395,6 +1557,25 @@ float LDPreferences::getFloatSetting(const char *key, float defaultValue) return TCUserDefaults::floatForKey(key, defaultValue, !m_globalSettings[key]); } +long LDPreferences::getRGBAFromStringSetting(const char* key, + TCULong defaultValue) +{ + std::string rgbaString; + + rgbaString = getStringSetting(key); + if (!rgbaString.empty()) + { + int n, r, g, b, a; + + n = sscanf(rgbaString.c_str(), "%d,%d,%d,%d", &r, &g, &b, &a); + if (n == 3 || n == 4) + { + return getRGBAColor(r, g, b, (n == 3 ? 255 : a)); + } + } + return defaultValue; +} + std::string LDPreferences::getStringSetting( const char *key, const char *defaultValue /*= NULL*/, @@ -2013,6 +2194,116 @@ void LDPreferences::setCurveQuality(int value, bool commit) setSetting(m_curveQuality, value, CURVE_QUALITY_KEY, commit); } +void LDPreferences::setAutomateEdgeColor(bool value, bool commit, bool apply) +{ + setSetting(m_automateEdgeColor, value, AUTOMATE_EDGE_COLOR_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setAutomateEdgeColor(m_automateEdgeColor); + } +} + +void LDPreferences::setUseStudStyle(bool value, bool commit, bool apply) +{ + setSetting(m_useStudStyle, value, USE_STUD_STYLE_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setUseStudStyle(m_useStudStyle); + } +} + +void LDPreferences::setStudStyle(int value, bool commit, bool apply) +{ + setSetting(m_studStyle, value, STUD_STYLE_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setStudStyle(m_studStyle); + } +} + +void LDPreferences::setStudCylinderColorEnabled(bool value, bool commit, bool apply) +{ + setSetting(m_studCylinderColorEnabled, value, STUD_CYLINDER_COLOR_ENABLED_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setStudCylinderColorEnabled(m_studCylinderColorEnabled); + } +} + +void LDPreferences::setPartEdgeColorEnabled(bool value, bool commit, bool apply) +{ + setSetting(m_partEdgeColorEnabled, value, PART_EDGE_COLOR_ENABLED_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setPartEdgeColorEnabled(m_partEdgeColorEnabled); + } +} + +void LDPreferences::setBlackEdgeColorEnabled(bool value, bool commit, bool apply) +{ + setSetting(m_blackEdgeColorEnabled, value, BLACK_EDGE_COLOR_ENABLED_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setBlackEdgeColorEnabled(m_blackEdgeColorEnabled); + } +} + +void LDPreferences::setDarkEdgeColorEnabled(bool value, bool commit, bool apply) +{ + setSetting(m_darkEdgeColorEnabled, value, DARK_EDGE_COLOR_ENABLED_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setDarkEdgeColorEnabled(m_darkEdgeColorEnabled); + } +} + +void LDPreferences::setStudCylinderColor(int r, int g, int b, int a, bool commit) +{ + setRGBAColorSetting(m_studCylinderColor, r, g, b, a, STUD_CYLINDER_COLOR_KEY, commit); +} + +void LDPreferences::setPartEdgeColor(int r, int g, int b, int a, bool commit) +{ + setRGBAColorSetting(m_partEdgeColor, r, g, b, a, PART_EDGE_COLOR_KEY, commit); +} + +void LDPreferences::setBlackEdgeColor(int r, int g, int b, int a, bool commit) +{ + setRGBAColorSetting(m_blackEdgeColor, r, g, b, a, BLACK_EDGE_COLOR_KEY, commit); +} + +void LDPreferences::setDarkEdgeColor(int r, int g, int b, int a, bool commit) +{ + setRGBAColorSetting(m_darkEdgeColor, r, g, b, a, DARK_EDGE_COLOR_KEY, commit); +} + +void LDPreferences::setPartColorLDIndex(TCFloat value, bool commit, bool apply) +{ + setSetting(m_partColorLDIndex, value, PART_COLOR_LD_INDEX_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setPartColorLDIndex(m_partColorLDIndex); + } +} + +void LDPreferences::setPartEdgeContrast(TCFloat value, bool commit, bool apply) +{ + setSetting(m_partEdgeContrast, value, PART_EDGE_CONTRAST_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setPartEdgeContrast(m_partEdgeContrast); + } +} + +void LDPreferences::setPartEdgeSaturation(TCFloat value, bool commit, bool apply) +{ + setSetting(m_partEdgeSaturation, value, PART_EDGE_SATURATION_KEY, commit); + if (apply && m_modelViewer != NULL) + { + m_modelViewer->setPartEdgeSaturation(m_partEdgeSaturation); + } +} + void LDPreferences::setQualityStuds(bool value, bool commit, bool apply) { setSetting(m_qualityStuds, value, QUALITY_STUDS_KEY, commit); @@ -2191,6 +2482,26 @@ void LDPreferences::getCustomColor(int index, int &r, int &g, int &b) getRGB(m_customColors[index], r, g, b); } +void LDPreferences::getStudCylinderColor(int& r, int& g, int& b, int& a) +{ + getRGBA(m_studCylinderColor, r, g, b, a); +} + +void LDPreferences::getPartEdgeColor(int& r, int& g, int& b, int& a) +{ + getRGBA(m_partEdgeColor, r, g, b, a); +} + +void LDPreferences::getBlackEdgeColor(int& r, int& g, int& b, int& a) +{ + getRGBA(m_blackEdgeColor, r, g, b, a); +} + +void LDPreferences::getDarkEdgeColor(int& r, int& g, int& b, int& a) +{ + getRGBA(m_darkEdgeColor, r, g, b, a); +} + LDPreferences::LightDirection LDPreferences::getLightDirection(void) { if (m_lightVector == TCVector(-1.0f, 1.0f, 1.0f)) diff --git a/LDLib/LDPreferences.h b/LDLib/LDPreferences.h index c26268ba3..20d9fc83e 100644 --- a/LDLib/LDPreferences.h +++ b/LDLib/LDPreferences.h @@ -5,7 +5,7 @@ #include #include #include - +#include class LDPreferences : public TCAlertSender { @@ -199,6 +199,24 @@ class LDPreferences : public TCAlertSender bool getTexturesAfterTransparent(void) { return true; } TCFloat getTextureOffsetFactor(void) { return m_textureOffsetFactor; } + bool getAutomateEdgeColor(void) { return m_automateEdgeColor; }; + bool getUseStudStyle(void) { return m_useStudStyle; } + int getStudStyle(void) { return m_studStyle; } + + bool getStudCylinderColorEnabled(void) { return m_studCylinderColorEnabled; } + bool getPartEdgeColorEnabled(void) { return m_partEdgeColorEnabled; } + bool getBlackEdgeColorEnabled(void) { return m_blackEdgeColorEnabled; } + bool getDarkEdgeColorEnabled(void) { return m_darkEdgeColorEnabled; } + + void getStudCylinderColor(int& r, int& g, int& b, int& a); + void getPartEdgeColor(int& r, int& g, int& b, int& a); + void getBlackEdgeColor(int& r, int& g, int& b, int& a); + void getDarkEdgeColor(int& r, int& g, int& b, int& a); + + TCFloat getPartColorLDIndex(void) { return m_partColorLDIndex; }; + TCFloat getPartEdgeContrast(void) { return m_partEdgeContrast; }; + TCFloat getPartEdgeSaturation(void) { return m_partEdgeContrast; }; + // Update settings int getProxyType(void) { return m_proxyType; } const char *getProxyServer(void) { return m_proxyServer.c_str(); } @@ -338,6 +356,24 @@ class LDPreferences : public TCAlertSender void setTextureOffsetFactor(TCFloat value, bool commit = false, bool apply = false); void setUseStrips(bool value, bool commit = false, bool apply = false); + void setAutomateEdgeColor(bool value, bool commit = false, bool apply = false); + void setUseStudStyle(bool value, bool commit = false, bool apply = false); + void setStudStyle(int value, bool commit = false, bool apply = false); + + void setStudCylinderColorEnabled(bool value, bool commit = false, bool apply = false); + void setPartEdgeColorEnabled(bool value, bool commit = false, bool apply = false); + void setBlackEdgeColorEnabled(bool value, bool commit = false, bool apply = false); + void setDarkEdgeColorEnabled(bool value, bool commit = false, bool apply = false); + + void setPartColorLDIndex(TCFloat value, bool commit = false, bool apply = false); + void setStudCylinderColor(int r, int g, int b, int a, bool commit = false); + void setPartEdgeColor(int r, int g, int b, int a, bool commit = false); + void setBlackEdgeColor(int r, int g, int b, int a, bool commit = false); + void setDarkEdgeColor(int r, int g, int b, int a, bool commit = false); + + void setPartEdgeContrast(TCFloat value, bool commit = false, bool apply = false); + void setPartEdgeSaturation(TCFloat value, bool commit = false, bool apply = false); + // Update settings void setProxyType(int value, bool commit = false); void setProxyServer(const char *value, bool commit = false); @@ -381,6 +417,8 @@ class LDPreferences : public TCAlertSender const char *key, bool commit); void setColorSetting(TCULong &setting, int r, int g, int b, const char *key, bool commit); + void setRGBAColorSetting(TCULong& setting, int r, int g, int b, int a, + const char* key, bool commit); bool getBoolSetting(const char *key, bool defaultValue = false); LongVector getLongVectorSetting(const char *key, const LongVector &defaultValue = LongVector()); @@ -396,10 +434,16 @@ class LDPreferences : public TCAlertSender const char *defaultValue = NULL, bool isPath = false); void getColorSetting(const char *key, int &r, int &g, int &b, TCULong defaultColor = 0); + void getRGBAColorSetting(const char* key, int& r, int& g, int& b, + int& a, TCULong defaultColor); + long getRGBAFromStringSetting(const char* key, TCULong defaultValue = 0); + virtual void getRGBA(int color, int& r, int& g, int& b, int& a); + virtual TCULong getRGBAColor(int r, int g, int b, int a); virtual void getRGB(int color, int &r, int &g, int &b); virtual int getColor(int r, int g, int b); virtual void commitSaveDir(SaveOp op); + LDLColor getLDLColor(TCULong color); // These are called from the constructor, and cannot be properly made into // virtual functions. @@ -504,6 +548,21 @@ class LDPreferences : public TCAlertSender TCFloat m_textureOffsetFactor; bool m_useStrips; + bool m_automateEdgeColor; + bool m_useStudStyle; + int m_studStyle; + bool m_studCylinderColorEnabled; + bool m_partEdgeColorEnabled; + bool m_blackEdgeColorEnabled; + bool m_darkEdgeColorEnabled; + TCFloat m_partColorLDIndex; + TCULong m_studCylinderColor; + TCULong m_partEdgeColor; + TCULong m_blackEdgeColor; + TCULong m_darkEdgeColor; + TCFloat m_partEdgeContrast; + TCFloat m_partEdgeSaturation; + // Update settings int m_proxyType; std::string m_proxyServer; diff --git a/LDLib/LDUserDefaultsKeys.h b/LDLib/LDUserDefaultsKeys.h index 74329cd50..d60a8d163 100644 --- a/LDLib/LDUserDefaultsKeys.h +++ b/LDLib/LDUserDefaultsKeys.h @@ -157,6 +157,20 @@ #define WIREFRAME_FOG_KEY "WireframeFog" #define WIREFRAME_THICKNESS_KEY "WireframeThickness" #define ZOOM_MAX_KEY "ZoomMax" // NO UI +#define AUTOMATE_EDGE_COLOR_KEY "AutomateEdgeColor" +#define USE_STUD_STYLE_KEY "UseStudStyle" +#define STUD_STYLE_KEY "StudStyle" +#define STUD_CYLINDER_COLOR_ENABLED_KEY "StudCylinderColorEnabled" +#define PART_EDGE_COLOR_ENABLED_KEY "PartEdgeColorEnabled" +#define BLACK_EDGE_COLOR_ENABLED_KEY "BlackEdgeColorEnabled" +#define DARK_EDGE_COLOR_ENABLED_KEY "DarkEdgeColorEnabled" +#define STUD_CYLINDER_COLOR_KEY "StudCylinderColor" +#define PART_EDGE_COLOR_KEY "PartEdgeColor" +#define BLACK_EDGE_COLOR_KEY "BlackEdgeColor" +#define DARK_EDGE_COLOR_KEY "DarkEdgeColor" +#define PART_COLOR_LD_INDEX_KEY "PartColorLDIndex" +#define PART_EDGE_CONTRAST_KEY "PartEdgeContrast" +#define PART_EDGE_SATURATION_KEY "PartEdgeSaturation" // The following are undocumented, and should stay that way. #define DEBUG_LEVEL_KEY "DebugLevel" diff --git a/LDLib/LDrawModelViewer.cpp b/LDLib/LDrawModelViewer.cpp index a85cd363e..95ce8c0c6 100644 --- a/LDLib/LDrawModelViewer.cpp +++ b/LDLib/LDrawModelViewer.cpp @@ -155,6 +155,18 @@ LDrawModelViewer::LDrawModelViewer(TCFloat width, TCFloat height) highlightR(160), highlightG(224), highlightB(255), + studStyle(0), + studCylinderColorEnabled(true), + partEdgeColorEnabled(true), + blackEdgeColorEnabled(true), + darkEdgeColorEnabled(true), + studCylinderColor(1780276), // 27,42,52,255 + partEdgeColor(0), // 0,0,0,255 + blackEdgeColor(16777215), // 255,255,255,255 + darkEdgeColor(1780276), // 27,42,52,255 + partColorLDIndex(0.5f), + partEdgeContrast(0.5f), + partEdgeSaturation(0.5f), cameraData(NULL) { #ifdef _LEAK_DEBUG @@ -234,6 +246,8 @@ LDrawModelViewer::LDrawModelViewer(TCFloat width, TCFloat height) flags.keepRightSideUp = false; flags.texmaps = true; flags.useStrips = true; + flags.useStudStyle = false; + flags.automateEdgeColor = false; TCAlertManager::registerHandler(LDLFindFileAlert::alertClass(), this, (TCAlertCallback)&LDrawModelViewer::findFileAlertCallback); // Set 4:4:4 as the default sub-sample pattern for JPEG images. @@ -2335,6 +2349,154 @@ void LDrawModelViewer::setCurveQuality(int value) } } +void LDrawModelViewer::setAutomateEdgeColor(bool value) +{ + if (value != flags.automateEdgeColor) + { + flags.automateEdgeColor = value; + flags.needsReparse = true; + } + +} + +void LDrawModelViewer::setUseStudStyle(bool value) +{ + if (value != flags.useStudStyle) + { + flags.useStudStyle = value; + flags.needsReload = true; + } +} + +void LDrawModelViewer::setStudStyle(int value) +{ + if (value != studStyle) + { + studStyle = value; + if (flags.useStudStyle) + { + flags.needsReload = true; + } + } +} + +void LDrawModelViewer::setStudCylinderColorEnabled(bool value) +{ + if (value != studCylinderColorEnabled) + { + studCylinderColorEnabled = value; + if (flags.useStudStyle) + { + flags.needsReload = true; + } + } +} + +void LDrawModelViewer::setPartEdgeColorEnabled(bool value) +{ + if (value != partEdgeColorEnabled) + { + partEdgeColorEnabled = value; + if (flags.useStudStyle) + { + flags.needsReload = true; + } + } +} + +void LDrawModelViewer::setBlackEdgeColorEnabled(bool value) +{ + if (value != blackEdgeColorEnabled) + { + blackEdgeColorEnabled = value; + if (flags.useStudStyle) + { + flags.needsReload = true; + } + } +} + +void LDrawModelViewer::setDarkEdgeColorEnabled(bool value) +{ + if (value != darkEdgeColorEnabled) + { + darkEdgeColorEnabled = value; + if (flags.useStudStyle) + { + flags.needsReload = true; + } + } +} + +void LDrawModelViewer::setStudCylinderColor(TCULong value) +{ + if (value != studCylinderColor) + { + studCylinderColor = value; + flags.needsReload = true; + } +} + +void LDrawModelViewer::setPartEdgeColor(TCULong value) +{ + if (value != partEdgeColor) + { + partEdgeColor = value; + flags.needsReload = true; + } +} + +void LDrawModelViewer::setBlackEdgeColor(TCULong value) +{ + if (value != blackEdgeColor) + { + blackEdgeColor = value; + flags.needsReload = true; + } +} + +void LDrawModelViewer::setDarkEdgeColor(TCULong value) +{ + if (value != darkEdgeColor) + { + darkEdgeColor = value; + flags.needsReload = true; + } +} + +void LDrawModelViewer::setPartColorLDIndex(TCFloat value) +{ + if (value != partColorLDIndex) + { + partColorLDIndex = value; + flags.needsReload = true; + } +} + +void LDrawModelViewer::setPartEdgeContrast(TCFloat value) +{ + if (value != partEdgeContrast) + { + partEdgeContrast = value; + if (flags.automateEdgeColor) + { + flags.needsReload = true; + } + } +} + +void LDrawModelViewer::setPartEdgeSaturation(TCFloat value) +{ + if (value != partEdgeSaturation) + { + partEdgeSaturation = value; + if (flags.automateEdgeColor) + { + flags.needsReload = true; + } + } +} + void LDrawModelViewer::setRandomColors(bool value) { if (value != flags.randomColors) diff --git a/LDLib/LDrawModelViewer.h b/LDLib/LDrawModelViewer.h index 0a0207213..0c6493b19 100644 --- a/LDLib/LDrawModelViewer.h +++ b/LDLib/LDrawModelViewer.h @@ -635,6 +635,41 @@ class LDrawModelViewer: public TCAlertSender static void resetUnofficialDownloadTimes(void); static std::string libraryUrl(const std::string& path); // static bool doCommandLineExport(void); + void setAutomateEdgeColor(bool value); + void setUseStudStyle(bool value); + void setStudStyle(int value); + + void setStudCylinderColorEnabled(bool value); + void setPartEdgeColorEnabled(bool value); + void setBlackEdgeColorEnabled(bool value); + void setDarkEdgeColorEnabled(bool value); + + void setStudCylinderColor(TCULong value); + void setPartEdgeColor(TCULong value); + void setBlackEdgeColor(TCULong value); + void setDarkEdgeColor(TCULong value); + + void setPartColorLDIndex(TCFloat value); + void setPartEdgeContrast(TCFloat value); + void setPartEdgeSaturation(TCFloat value); + + bool getAutomateEdgeColor(void) { return flags.automateEdgeColor ? true : false; }; + bool getUseStudStyle(void) const { return flags.useStudStyle ? true : false; } + int getStudStyle(void) const { return studStyle; } + + bool getStudCylinderColorEnabled(void) { return studCylinderColorEnabled != false; } + bool getPartEdgeColorEnabled(void) { return partEdgeColorEnabled != false; } + bool getBlackEdgeColorEnabled(void) { return blackEdgeColorEnabled != false; } + bool getDarkEdgeColorEnabled(void) { return darkEdgeColorEnabled != false; } + + TCULong getStudCylinderColor(void) const { return studCylinderColor; }; + TCULong getPartEdgeColor(void) const { return partEdgeColor; }; + TCULong getBlackEdgeColor(void) const { return blackEdgeColor; }; + TCULong getDarkEdgeColor(void) const { return darkEdgeColor; }; + + TCFloat getPartColorLDIndex(void) { return partColorLDIndex; }; + TCFloat getPartEdgeContrast(void) { return partEdgeContrast; }; + TCFloat getPartEdgeSaturation(void) { return partEdgeSaturation; }; protected: ~LDrawModelViewer(void); void dealloc(void); @@ -831,6 +866,18 @@ class LDrawModelViewer: public TCAlertSender int highlightR; int highlightG; int highlightB; + int studStyle; + bool studCylinderColorEnabled; + bool partEdgeColorEnabled; + bool blackEdgeColorEnabled; + bool darkEdgeColorEnabled; + TCULong studCylinderColor; + TCULong partEdgeColor; + TCULong blackEdgeColor; + TCULong darkEdgeColor; + TCFloat partColorLDIndex; + TCFloat partEdgeContrast; + TCFloat partEdgeSaturation; #ifdef USE_STD_CHRONO std::chrono::time_point frameTime; #else @@ -927,6 +974,8 @@ class LDrawModelViewer: public TCAlertSender bool texmaps:1; bool texturesAfterTransparent:1; bool useStrips:1; + bool useStudStyle:1; + bool automateEdgeColor:1; } flags; struct CameraData { diff --git a/LDLoader/LDLMainModel.cpp b/LDLoader/LDLMainModel.cpp index 56d90df85..9a017d2a3 100644 --- a/LDLoader/LDLMainModel.cpp +++ b/LDLoader/LDLMainModel.cpp @@ -92,6 +92,7 @@ bool LDLMainModel::load(const char *filename) ldrawDirNotFound(); return false; } + LDLModel::clearStudStylePrimitives(); m_mainModel = this; if (openStream(filename, stream)) { diff --git a/LDLoader/LDLModel.cpp b/LDLoader/LDLModel.cpp index f0964d77e..317c274d3 100644 --- a/LDLoader/LDLModel.cpp +++ b/LDLoader/LDLModel.cpp @@ -41,9 +41,13 @@ std::string LDLModel::sm_systemLDrawDirSlashes; char *LDLModel::sm_defaultLDrawDir = NULL; LDrawIniS *LDLModel::sm_lDrawIni = NULL; int LDLModel::sm_modelCount = 0; +int LDLModel::sm_studStyle = 0; +bool LDLModel::sm_useStudStyle = false; +bool LDLModel::sm_studCylinderColorEnabled = true; LDLFileCaseCallback LDLModel::fileCaseCallback = NULL; LDLModel::LDLModelCleanup LDLModel::sm_cleanup; StringList LDLModel::sm_checkDirs; +std::map, less_no_case> LDLModel::sm_studStylePrimitives; std::string LDLModel::sm_ldrawZipPath; std::string LDLModel::sm_unoffZipPath; bool LDLModel::sm_verifyLDrawSubDirs = false; @@ -187,6 +191,154 @@ TCObject *LDLModel::copy(void) const return new LDLModel(*this); } +void LDLModel::clearStudStylePrimitives(void) +{ + // Every time the main model loads we want to reload these so that the + // processed version matches our current settings. + sm_studStylePrimitives.clear(); + sm_studStylePrimitives["stud.dat"] = std::make_pair(0, ""); + sm_studStylePrimitives["8/stud.dat"] = std::make_pair(1, ""); + sm_studStylePrimitives["stud2.dat"] = std::make_pair(2, ""); + sm_studStylePrimitives["8/stud2.dat"] = std::make_pair(3, ""); + sm_studStylePrimitives["stud2a.dat"] = std::make_pair(4, ""); + sm_studStylePrimitives["8stud2a.dat"] = std::make_pair(5, ""); + sm_studStylePrimitives["stud3.dat"] = std::make_pair(6, ""); + sm_studStylePrimitives["8/stud3.dat"] = std::make_pair(7, ""); + sm_studStylePrimitives["stud4.dat"] = std::make_pair(8, ""); + sm_studStylePrimitives["8/stud4.dat"] = std::make_pair(9, ""); + sm_studStylePrimitives["stud4a.dat"] = std::make_pair(10, ""); + sm_studStylePrimitives["8/stud4a.dat"] = std::make_pair(11, ""); + sm_studStylePrimitives["stud4h.dat"] = std::make_pair(12, ""); + sm_studStylePrimitives["8/stud4h.dat"] = std::make_pair(13, ""); + sm_studStylePrimitives["2-4stud4.dat"] = std::make_pair(14, ""); + sm_studStylePrimitives["stud-logo.dat"] = std::make_pair(15, ""); + sm_studStylePrimitives["8/stud-logo.dat"] = std::make_pair(16, ""); + sm_studStylePrimitives["stud2-logo.dat"] = std::make_pair(17, ""); + sm_studStylePrimitives["8/stud2-logo.dat"] = std::make_pair(18, ""); +} + +const std::string& LDLModel::getStudStylePrimitive(const std::string& filename) +{ + static std::string empty; + auto it = sm_studStylePrimitives.find(filename); + if (it == sm_studStylePrimitives.end()) + { + return empty; + } + std::string& result = it->second.second; + if (result.empty() && !loadStudStylePrimitive(filename, it->second.first, result)) + { + return empty; + } + return result; +} + +void LDLModel::streamPart(std::ostringstream &oss, const TCFloat* matrix, const std::string& name) +{ + oss << "1 16 " << matrix[12] << " " << matrix[13] << " " << matrix[14] << " "; + oss << matrix[0] << " " << matrix[1] << " " << matrix[2] << " "; + oss << matrix[4] << " " << matrix[5] << " " << matrix[6] << " "; + oss << matrix[8] << " " << matrix[9] << " " << matrix[10] << " "; + oss << name; +} + +void LDLModel::updateStudStyleLine(std::string& line, bool isStud4) +{ + if (!sm_studCylinderColorEnabled || sm_studStyle == 0) + { + return; + } + const std::string studColor = "4242"; + size_t spot = line.find("-4cyli.dat"); + if (spot != line.npos && stringHasPrefix(line, "1 16 ")) + { + bool update = true; + if (isStud4) + { + std::string cyli = line.substr(spot - 1, 7); + std::string pattern1 = " 0 0 0 8 " + cyli; + std::string pattern2 = " 0 0 0 8 8\\" + cyli; + if (line.find(pattern1) != line.npos || line.find(pattern2) != line.npos) + { + // For some reason, the 8LDU-diameter cylinders on the stud4* + // files don't have their colors updated. + update = false; + } + } + if (update) + { + line = "1 " + studColor + line.substr(4); + } + } + if (spot == line.npos) + { + spot = line.find("4-4cylc.dat"); + if (spot != line.npos) + { + // 4-4cylc needs for its cylinder to be recolored, but not the rest + // of the part, so replace that one line with the 4 individual + // parts, making the 4-4cyli have the new color. + LDLModelLine *modelLine = (LDLModelLine*)LDLFileLine::initFileLine(this, line.c_str(), 1); + if (modelLine->parse()) + { + const TCFloat* matrix = modelLine->getMatrix(); + + if (matrix != NULL) + { + TCFloat matrix2i[16]; + TCFloat matrix2[16]; + TCVector::initIdentityMatrix(matrix2i); + matrix2i[13] = 1; + TCVector::multMatrix(matrix, matrix2i, matrix2); + std::ostringstream oss; + streamPart(oss, matrix, "4-4edge.dat\n"); + streamPart(oss, matrix2, "4-4edge.dat\n"); + streamPart(oss, matrix, "4-4disc.dat\n"); + std::string others = oss.str(); + oss.clear(); + oss.str(""); + streamPart(oss, matrix, "4-4cyli.dat"); + line = oss.str(); + // Recursive call on the 4-4cyli line to update its color. + updateStudStyleLine(line, isStud4); + line = others + line; + } + } + TCObject::release(modelLine); + } + } +} + +bool LDLModel::loadStudStylePrimitive(const std::string& filename, int index, std::string& value) +{ + LDLModel* model = new LDLModel(); + std::ifstream subModelStream; + TCUnzipStream zipStream; + std::string subModelPath; + bool loop = false; + + model->setMainModel(m_mainModel); + if (!model->openSubModelNamed(filename.c_str(), subModelPath, subModelStream, &zipStream, false, &loop) || + !model->load(subModelStream, &zipStream)) + { + TCObject::release(model); + return false; + } + LDLFileLineArray* fileLines = model->m_fileLines; + size_t lineCount = model->m_fileLines->getCount(); + bool isStud4 = index >= 8 && index <= 14; + for (unsigned int i = 0; i < lineCount; ++i) + { + LDLFileLine *fileLine = (*fileLines)[i]; + std::string line(*fileLine); + updateStudStyleLine(line, isStud4); + line += "\n"; + value += line; + } + TCObject::release(model); + return true; +} + void LDLModel::setFilename(const char *filename) { delete[] m_filename; @@ -287,7 +439,7 @@ LDLModel *LDLModel::subModelNamed(const char *subModelName, bool lowRes, { ancestorCheck = true; } - if (strcasecmp(subModelName, "stud.dat") == 0) + if (studStylePrimitiveType(subModelName, sm_studStyle)) { m_flags.hasStuds = true; } @@ -867,6 +1019,87 @@ bool LDLModel::openSubModelNamed( return false; } +void LDLModel::buildStudLogo(std::ostringstream& oss, const std::string& dictName, bool isOpen, const std::string& style) +{ + oss << "0 Stud"; + if (!style.empty()) + { + oss << " "; + } + oss << (isOpen ? "Open" : style); + oss << "\n0 Name: "; + oss << dictName; + oss << "\n0 Author: LDView\n0 !LDRAW_ORG Primitive\n0 BFC CERTIFY CCW\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 stud"; + oss << (isOpen ? "2" : ""); + oss << "-logo"; + oss << style; + oss << ".dat\n"; +} + +bool LDLModel::getStudStyleFile(LDLModel* subModel, const char* dictName, bool openStud) +{ + std::ostringstream oss; + + if (sm_studStyle > 0 && sm_studStyle < 6) + { + std::string style; + if (sm_studStyle > 1) + { + style = ltostr(sm_studStyle); + } + buildStudLogo(oss, dictName, openStud, style); + } + else + { + bool isOpen = studStylePrimitiveType(dictName, sm_studStyle) == 2; + if (sm_studStyle == 7 && (strcasecmp(dictName, "stud.dat") == 0 || isOpen)) + { + buildStudLogo(oss, dictName, isOpen, ""); + } + else + { + oss << getStudStylePrimitive(dictName); + } + } + + std::istringstream iss(oss.str()); + std::ifstream dummy; + return subModel->load(dummy, NULL, &iss); +} + +// Return: +// 0: Note stud style primitive +// 1: Closed stud style primitive +// 2: Open stud style primitive +int LDLModel::studStylePrimitiveType(const char* filename, int studStyle) +{ + // for styles 0-5, return if file has '-logo' suffix + if (studStyle < 6 && strstr(filename, "-logo") != NULL) + { + return 0; + } + + auto it = sm_studStylePrimitives.find(filename); + if (it == sm_studStylePrimitives.end()) + { + return 0; + } + // for styles 0-5, only check for stud, stud2 and stud2a + if (studStyle < 6 && it->second.first > 5) + { + return 0; + } + + if (strcasecmp(filename, "stud2.dat") == 0 || strcasecmp(filename, "stud2a.dat") == 0) + { + return 2; // open stud + } + else + { + return 1; + } +} + bool LDLModel::initializeNewSubModel(LDLModel *subModel, const char *dictName) { std::ifstream closedStream; @@ -904,7 +1137,18 @@ bool LDLModel::initializeNewSubModel( subModel->m_flags.unofficial = true; } bool zipValid = zipStream != NULL && zipStream->is_valid(); - if ((subModelStream.is_open() || zipValid) && + bool studStylePrimitive = false; + if (sm_useStudStyle && m_flags.loadingPrimitive && m_flags.hasStuds) + { + unsigned int studStyleType = studStylePrimitiveType(dictName, sm_studStyle); + if (studStyleType > 0) + { + bool openStud = studStyleType == 2; + studStylePrimitive = getStudStyleFile(subModel, dictName, + openStud); + } + } + if (!studStylePrimitive && (subModelStream.is_open() || zipValid) && !subModel->load(subModelStream, zipStream)) { subModelDict->removeObjectForKey(dictName); @@ -1441,16 +1685,24 @@ void LDLModel::processLine(std::string& line, size_t& lineNumber) } } -std::basic_istream>& LDLModel::getLine(std::ifstream &stream, TCUnzipStream *zipStream, std::string& line) +std::basic_istream>& LDLModel::getLine( + std::ifstream &stream, + TCUnzipStream *zipStream, + std::istringstream *ss, + std::string& line) { if (zipStream != NULL && zipStream->is_valid()) { return std::getline(*zipStream, line); } + else if (ss != NULL) + { + return std::getline(*ss, line); + } return std::getline(stream, line); } -bool LDLModel::read(std::ifstream &stream, TCUnzipStream *zipStream) +bool LDLModel::read(std::ifstream &stream, TCUnzipStream *zipStream, std::istringstream *ss) { std::string line; size_t lineNumber = 1; @@ -1467,7 +1719,7 @@ bool LDLModel::read(std::ifstream &stream, TCUnzipStream *zipStream) } while (!done && !getLoadCanceled()) { - if (getLine(stream, zipStream, line)) + if (getLine(stream, zipStream, ss, line)) { processLine(line, lineNumber); } @@ -1523,6 +1775,7 @@ void LDLModel::reportProgress(const wchar_t *message, float progress, bool LDLModel::load( std::ifstream &stream, TCUnzipStream *zipStream, + std::istringstream *ss, bool trackProgress) { bool retValue; @@ -1531,7 +1784,7 @@ bool LDLModel::load( { reportProgress(LOAD_MESSAGE, 0.0f); } - if (!read(stream, zipStream)) + if (!read(stream, zipStream, ss)) { if (trackProgress) { diff --git a/LDLoader/LDLModel.h b/LDLoader/LDLModel.h index 159cfd04d..49b821a29 100644 --- a/LDLoader/LDLModel.h +++ b/LDLoader/LDLModel.h @@ -8,6 +8,7 @@ #include #include #include +#include class TCDictionary; class LDLMainModel; @@ -57,7 +58,7 @@ class LDLModel : public TCAlertSender virtual const char *getCategory(void) const { return m_category; } virtual void setName(const char *name); bool load(std::ifstream &stream, TCUnzipStream *zipStream = NULL, - bool trackProgress = true); + std::istringstream *ss = NULL, bool trackProgress = true); void print(int indent) const; virtual bool parse(void); virtual TCDictionary* getLoadedModels(void); @@ -133,6 +134,12 @@ class LDLModel : public TCAlertSender static bool checkLDrawZipPath(const std::string& value); static void setVerifyLDrawSubDirs(bool value) { sm_verifyLDrawSubDirs = value; } static void setFileCaseCallback(LDLFileCaseCallback value); + static void setStudStyle(int value) { sm_studStyle = value; } + static int getStudStyle(void) { return sm_studStyle; } + static void setUseStudStyle(int value) { sm_useStudStyle = value; } + static bool getUseStudStyle(void) { return sm_useStudStyle; } + static void setStudCylinderColorEnabled(bool value) { sm_studCylinderColorEnabled = value; } + static bool getStudCylinderColorEnabled(void) { return sm_studCylinderColorEnabled; } static LDLFileCaseCallback getFileCaseCallback(void) { return fileCaseCallback; @@ -146,6 +153,7 @@ class LDLModel : public TCAlertSender static void closeZips(void); static void ldrawZipUpdated(void); static bool fileExists(const std::string &filename); + static void clearStudStylePrimitives(void); StringVector getKeywords(void); protected: static std::string getLastModifiedKey(const std::string& lfilename); @@ -164,7 +172,8 @@ class LDLModel : public TCAlertSender TCUnzipStream *zipStream); virtual bool initializeNewSubModel(LDLModel* subModel, const char *dictName); - virtual bool read(std::ifstream &stream, TCUnzipStream *zipStream); + virtual bool read(std::ifstream &stream, TCUnzipStream *zipStream, + std::istringstream *ss); virtual void processLine(std::string& line, size_t& lineNumber); virtual ptrdiff_t parseComment(size_t index, LDLCommentLine *commentLine); virtual ptrdiff_t parseMPDMeta(size_t index, const char *filename); @@ -202,11 +211,24 @@ class LDLModel : public TCAlertSender void endTexmap(void); void extractData(); std::basic_istream>& getLine( - std::ifstream &stream, TCUnzipStream *zipStream, std::string& line); + std::ifstream &stream, TCUnzipStream *zipStream, std::istringstream *ss, + std::string& line); static time_t getFileTimestamp(const std::string& path); + const std::string& getStudStylePrimitive(const std::string& filename); + bool loadStudStylePrimitive(const std::string& filename, int index, + std::string& value); + void updateStudStyleLine(std::string& line, bool isStud4); + void streamPart(std::ostringstream &oss, const TCFloat* matrix, const std::string& name); + void buildStudLogo(std::ostringstream& oss, const std::string& dictName, + bool isOpen, const std::string& style); + static void initCheckDirs(); + static int studStylePrimitiveType(const char* filename, int studStyle); + bool getStudStyleFile(LDLModel* subModel, const char* dictName, + bool openStud); + char *m_filename; char *m_name; char *m_author; @@ -274,6 +296,7 @@ class LDLModel : public TCAlertSender } m_flags; static StringList sm_checkDirs; + static std::map, less_no_case> sm_studStylePrimitives; static char *sm_systemLDrawDir; #ifdef WIN32 static std::string sm_systemLDrawDirSlashes; @@ -281,6 +304,9 @@ class LDLModel : public TCAlertSender static char *sm_defaultLDrawDir; static LDrawIniS *sm_lDrawIni; static int sm_modelCount; + static int sm_studStyle; + static bool sm_useStudStyle; + static bool sm_studCylinderColorEnabled; static LDLFileCaseCallback fileCaseCallback; static std::string sm_ldrawZipPath; static std::string sm_unoffZipPath; diff --git a/LDLoader/LDLPalette.cpp b/LDLoader/LDLPalette.cpp index f3dafafcd..983a8b234 100644 --- a/LDLoader/LDLPalette.cpp +++ b/LDLoader/LDLPalette.cpp @@ -1,6 +1,9 @@ #include "LDLPalette.h" +#include "LDLModel.h" #include #include +#include +#include #include #ifdef WIN32 @@ -13,10 +16,155 @@ static const TCByte transA = 110; +#define TC_SRGB_TO_LINEAR(v) (powf(v, 2.2f)) +#define TC_LINEAR_TO_SRGB(v) (powf(v, 1.0f / 2.2f)) +#define TC_LUM_FROM_SRGB(r,g,b) ((0.2126f * TC_SRGB_TO_LINEAR(r)) + (0.7152f * TC_SRGB_TO_LINEAR(g)) + (0.0722f * TC_SRGB_TO_LINEAR(b))) +#define TC_LUM_FROM_RGB(r,g,b) ((0.2126f * r) + (0.7152f * g) + (0.0722f * b)) +#define TC_RGB_EPSILON (0.5f / 255.0f) +#define TC_RGB_TO_DEC(v) ((TCFloat)(v) / 255.0f) + +bool LDLPalette::sm_automateEdgeColor = false; +bool LDLPalette::sm_useStudStyle = false; +int LDLPalette::sm_studStyle = 0; +bool LDLPalette::sm_partEdgeColorEnabled = true; +bool LDLPalette::sm_blackEdgeColorEnabled = true; +bool LDLPalette::sm_darkEdgeColorEnabled = true; +LDLColor LDLPalette::sm_studCylinderColor{ 27,42,52,255 }; +LDLColor LDLPalette::sm_partEdgeColor{ 0,0,0,255 }; +LDLColor LDLPalette::sm_blackEdgeColor{ 255,255,255,255 }; +LDLColor LDLPalette::sm_darkEdgeColor{ 27,42,52,255 }; +TCFloat LDLPalette::sm_partColorLDIndex = 0.5f; +TCFloat LDLPalette::sm_partEdgeContrast = 0.5f; +TCFloat LDLPalette::sm_partEdgeSaturation = 0.5f; + LDLPalette *LDLPalette::sm_defaultPalette = NULL; TCByte LDLPalette::sm_transA = transA; LDLPalette::LDLPaletteCleanup LDLPalette::sm_cleanup; +static TCVector rgb2hsl(const TCVector& rgb) +{ + int Mi; + TCFloat M, m, C, h, S, L; // h is H/60 + + Mi = (rgb[0] >= rgb[1]) ? 0 : 1; + Mi = (rgb[Mi] >= rgb[2]) ? Mi : 2; + M = rgb[Mi]; + + m = (rgb[0] < rgb[1]) ? rgb[0] : rgb[1]; + m = (m < rgb[2]) ? m : rgb[2]; + + C = M - m; + L = (M + m) / 2.0f; + + if (C < TC_RGB_EPSILON) // C == 0.0 + h = 0.0f; + else if (Mi == 0) // M == R + h = 0.0f + (rgb[1] - rgb[2]) / C; + else if (Mi == 1) // M == G + h = 2.0f + (rgb[2] - rgb[0]) / C; + else // M = B + h = 4.0f + (rgb[0] - rgb[1]) / C; + + h = (h < 0.0) ? h + 6.0f : h; + h = (h >= 6.0) ? h - 6.0f : h; + + S = ((L < (TC_RGB_EPSILON / 2.0f)) || (L > (1.0f - (TC_RGB_EPSILON / 2.0f)))) + ? 0.0f : (2.0f * (M - L)) / (1.0f - fabs((2.0f * L) - 1.0f)); + + return TCVector(h, S, L); +} + +static TCVector hsl2rgb(const TCVector& hSL) +{ + TCVector rgb; + float h, S, L, C, X, m; + + h = hSL[0]; + S = hSL[1]; + L = hSL[2]; + + C = (1.0f - fabs(2.0f * L - 1.0f)) * S; + X = C * (1.0f - fabs(fmodf(h, 2.0f) - 1.0f)); + + if (h < 1.0f) + rgb = TCVector(C, X, 0.0f); + else if (h < 2.0f) + rgb = TCVector(X, C, 0.0f); + else if (h < 3.0f) + rgb = TCVector(0.0f, C, X); + else if (h < 4.0f) + rgb = TCVector(0.0f, X, C); + else if (h < 5.0f) + rgb = TCVector(X, 0.0f, C); + else + rgb = TCVector(C, 0.0f, X); + + m = L - C / 2.0f; + + rgb[0] += m; + rgb[1] += m; + rgb[2] += m; + + return rgb; +} + +static LDLColor getAlgorithmicEdgeColor(const TCVector& value, const float valueLum, + const float edgeLum, const float contrast, const float saturation) +{ + float y1, yt; + float y0 = valueLum; + float ye = edgeLum; + float cont = contrast; + float sat = saturation; + TCVector hSL, rgb1, rgbf; + + // Determine luma target + if (ye < y0) + { + // Light base color + yt = y0 - cont * y0; + } + else + { + // Dark base color + yt = y0 + cont * (1.0f - y0); + } + + // Get base color in hSL + hSL = rgb2hsl(value); + + // Desaturate + hSL[1] *= sat; + + // Adjusted color to RGB + rgb1 = hsl2rgb(TCVector(hSL[0], hSL[1], 0.5f)); + + // Fix adjusted color luma to target value + y1 = TC_LUM_FROM_RGB(rgb1[0], rgb1[1], rgb1[2]); + if (yt < y1) + { + // Make darker via scaling + rgbf = (yt / y1) * rgb1; + } + else + { + // Make lighter via scaling anti-color + rgbf = TCVector(1.0f, 1.0f, 1.0f) - rgb1; + rgbf *= (1.0f - yt) / (1.0f - y1); + rgbf = TCVector(1.0f, 1.0f, 1.0f) - rgbf; + } + + TCVector rgb = TCVector(TC_LINEAR_TO_SRGB(rgbf[0]), TC_LINEAR_TO_SRGB(rgbf[1]), + TC_LINEAR_TO_SRGB(rgbf[2])) *= 255; + +#ifdef USE_CPP11 + return LDLColor{ (TCByte)rgb[0], (TCByte)rgb[1], (TCByte)rgb[2], 255 }; +#else // USE_CPP11 + LDLColor result = { (TCByte)rgb[0], (TCByte)rgb[1], (TCByte)rgb[2], 255 }; + return result; +#endif // !USE_CPP11 +} + LDLPalette::LDLPaletteCleanup::~LDLPaletteCleanup(void) { TCObject::release(LDLPalette::sm_defaultPalette); @@ -25,7 +173,7 @@ LDLPalette::LDLPaletteCleanup::~LDLPaletteCleanup(void) static const int standardColorSize = 5; -static const char standardColorNames[][64] = +static const std::string standardColorNames[] = { "Black", "Blue", @@ -195,6 +343,7 @@ void LDLPalette::init(void) initStandardColors(); initDitherColors(); initOtherColors(); + initStudStyleSettings(); } void LDLPalette::reset(void) @@ -213,7 +362,7 @@ void LDLPalette::initStandardColors(void) { int ofs = i * standardColorSize; - strcpy(m_colors[i].name, standardColorNames[i]); + m_colors[i].name = standardColorNames[i]; m_namesMap[m_colors[i].name] = i; m_colors[i].color.r = (TCByte)standardColors[ofs]; m_colors[i].color.g = (TCByte)standardColors[ofs + 1]; @@ -334,9 +483,91 @@ void LDLPalette::initOtherColors(void) initSpecular(494, 0.9f, 0.9f, 1.5f, 1.0f, 5.0f); } +void LDLPalette::initStudStyleSettings() +{ + sm_useStudStyle = LDLModel::getUseStudStyle(); + sm_studStyle = LDLModel::getStudStyle(); + if (!sm_useStudStyle || (sm_studStyle < 6 && !sm_automateEdgeColor)) + return; + + int edgeColorNumber = getEdgeColorNumberFromRGB(sm_partEdgeColor); + LDLColorInfo* colorInfo = updateColor(4242, sm_studCylinderColor, sm_studCylinderColor, + edgeColorNumber, (-25500.0f / 255.0f)); + if (colorInfo) + { + std::string name("Stud Cylinder Color"); + colorInfo->name = name; + m_namesMap[name] = 4242; + colorInfo->rubber = false; + colorInfo->chrome = false; + } + else + { + debugPrintf("Error creating Stud Cylinder Color (%d)\n", 4242); + } +} + +int LDLPalette::getEdgeColorNumberFromRGB(const LDLColor& color) +{ + // colorForRGBA returns 0xRRGGBBAA, so shift right 8 bits, mask, then use + // bitwise or to put it into the opaque direct color range. + return ((colorForRGBA(color.r, color.g, color.b, 255) >> 8) & 0xFFFFFF) | 0x2000000; +} + +int LDLPalette::getStudStyleOrAutoEdgeColor(int colorNumber) +{ + LDLColorInfo colorInfo = getAnyColorInfo(colorNumber); + TCVector value(TC_RGB_TO_DEC(colorInfo.color.r), TC_RGB_TO_DEC(colorInfo.color.g), TC_RGB_TO_DEC(colorInfo.color.b)); + const TCFloat valueLuminescence = TC_LUM_FROM_SRGB(value[0], value[1], value[2]); + + if (sm_automateEdgeColor) + { + if (colorInfo.automated) + { + // The edge color for this color has already been calculated. + return colorInfo.edgeColorNumber; + } + else + { + int r, g, b, a; + getRGBA(colorInfo.edgeColorNumber, r, g, b, a); + const TCFloat edgeLuminescence = TC_LUM_FROM_SRGB(TC_RGB_TO_DEC(r), TC_RGB_TO_DEC(g), TC_RGB_TO_DEC(b)); + + LDLColor algEdgeColor = getAlgorithmicEdgeColor(value, valueLuminescence, edgeLuminescence, sm_partEdgeContrast, sm_partEdgeSaturation); + int edgeColorNumber = getEdgeColorNumberFromRGB(algEdgeColor); + + LDLColorInfo* adjustColorInfo; + adjustColorInfo = updateColor(colorNumber, colorInfo.color, colorInfo.ditherColor, edgeColorNumber); + // Mark the color as having had its edge color calculated + adjustColorInfo->automated = true; + return edgeColorNumber; + } + } + else + { + TCFloat lightDarkControl = TC_SRGB_TO_LINEAR(sm_partColorLDIndex); + if (sm_blackEdgeColorEnabled && colorNumber == 0) + return getEdgeColorNumberFromRGB(sm_blackEdgeColor); + else if (sm_darkEdgeColorEnabled && colorNumber != 4242 && + valueLuminescence < lightDarkControl) + return getEdgeColorNumberFromRGB(sm_darkEdgeColor); + else if (sm_partEdgeColorEnabled) + return getEdgeColorNumberFromRGB(sm_partEdgeColor); + } + + debugPrintf("Error creating edge color number for color: %d\n", + colorNumber); + + return 0; +} + int LDLPalette::getEdgeColorNumber(int colorNumber) { - if (colorNumber < 512 && colorNumber >= 0) + if (sm_studStyle > 5 || sm_automateEdgeColor) + { + return getStudStyleOrAutoEdgeColor(colorNumber); + } + else if (colorNumber < 512 && colorNumber >= 0) { return m_colors[colorNumber].edgeColorNumber; } @@ -423,7 +654,7 @@ void LDLPalette::getRGBA(const LDLColorInfo &colorInfo, int &r, int &g, int &b, void LDLPalette::initColorInfo(LDLColorInfo &colorInfo, int r, int g, int b, int a) { - colorInfo.name[0] = 0; + colorInfo.name.clear(); colorInfo.color.r = (TCByte)r; colorInfo.color.g = (TCByte)g; colorInfo.color.b = (TCByte)b; @@ -436,6 +667,7 @@ void LDLPalette::initColorInfo(LDLColorInfo &colorInfo, int r, int g, int b, colorInfo.luminance = -100.0f; colorInfo.chrome = false; colorInfo.rubber = false; + colorInfo.automated = false; initSpecularAndShininess(colorInfo); } @@ -591,18 +823,19 @@ bool LDLPalette::parseLDrawOrgColorComment(const char *comment) bool chrome = false; bool rubber = false; bool metal = false; - char name[1024]; + std::string name; - strncpy(name, &comment[10], sizeof(name)); - name[sizeof(name) - 1] = 0; + name = &comment[10]; stripLeadingWhitespace(name); - if (strchr(name, ' ')) + size_t spot = name.find(' '); + if (spot != name.npos) { - *strchr(name, ' ') = 0; + name.erase(spot); } - if (strchr(name, '\t')) + spot = name.find('\t'); + if (spot != name.npos) { - *strchr(name, '\t') = 0; + name.erase(spot); } replaceStringCharacter(name, '_', ' '); if (!itemSpot) @@ -631,7 +864,7 @@ bool LDLPalette::parseLDrawOrgColorComment(const char *comment) comment); return false; } - itemSpot = strcasestr(&comment[10 + strlen(name)], "EDGE "); + itemSpot = strcasestr(&comment[10 + name.size()], "EDGE "); if (!itemSpot) { debugPrintf("Couldn't find color EDGE in color meta-comment:\n%s\n", @@ -713,8 +946,7 @@ bool LDLPalette::parseLDrawOrgColorComment(const char *comment) (float)luminance / 255.0f); if (colorInfo) { - strncpy(colorInfo->name, name, sizeof(colorInfo->name)); - colorInfo->name[sizeof(colorInfo->name) - 1] = 0; + colorInfo->name = name; m_namesMap[name] = colorNumber; if (rubber) { diff --git a/LDLoader/LDLPalette.h b/LDLoader/LDLPalette.h index 615dcf849..d643f8b7f 100644 --- a/LDLoader/LDLPalette.h +++ b/LDLoader/LDLPalette.h @@ -14,7 +14,7 @@ typedef struct typedef struct { - char name[64]; + std::string name; LDLColor color; LDLColor ditherColor; int edgeColorNumber; @@ -23,6 +23,7 @@ typedef struct float luminance; bool chrome; bool rubber; + bool automated; // Has the edge color already been calculated? } LDLColorInfo; class LDLPalette : public TCObject @@ -51,6 +52,17 @@ class LDLPalette : public TCObject static int colorNumberForRGBA(int r, int g, int b, int a); static int colorNumberForPackedRGBA(TCULong color); static TCByte getTransA(void) { return sm_transA; } + static void setAutomateEdgeColor(bool value) { sm_automateEdgeColor = value; } + static void setPartEdgeColorEnabled(bool value) { sm_partEdgeColorEnabled = value; } + static void setBlackEdgeColorEnabled(bool value) { sm_blackEdgeColorEnabled = value; } + static void setDarkEdgeColorEnabled(bool value) { sm_darkEdgeColorEnabled = value; } + static void setStudCylinderColor(const LDLColor& value) { sm_studCylinderColor = value; } + static void setPartEdgeColor(const LDLColor& value) { sm_partEdgeColor = value; } + static void setBlackEdgeColor(const LDLColor& value) { sm_blackEdgeColor = value; } + static void setDarkEdgeColor(const LDLColor& value) { sm_darkEdgeColor = value; } + static void setPartColorLDIndex(TCFloat value) { sm_partColorLDIndex = value; } + static void setPartEdgeContrast(TCFloat value) { sm_partEdgeContrast = value; } + static void setPartEdgeSaturation(TCFloat value) { sm_partEdgeSaturation = value; } protected: virtual ~LDLPalette(void); virtual void dealloc(void); @@ -86,7 +98,15 @@ class LDLPalette : public TCObject LDLColorInfo colorInfo; CustomColor() : colorNumber(0) { - memset(&colorInfo, 0, sizeof(colorInfo)); + clearValue(colorInfo.color); + clearValue(colorInfo.ditherColor); + clearValue(colorInfo.edgeColorNumber); + clearValue(colorInfo.specular); + clearValue(colorInfo.shininess); + clearValue(colorInfo.luminance); + clearValue(colorInfo.chrome); + clearValue(colorInfo.rubber); + clearValue(colorInfo.automated); } }; @@ -94,6 +114,24 @@ class LDLPalette : public TCObject TCTypedObjectArray *m_customColors; CIStringIntMap m_namesMap; + void initStudStyleSettings(void); + int getStudStyleOrAutoEdgeColor(int colorNumber); + int getEdgeColorNumberFromRGB(const LDLColor& color); + + static bool sm_automateEdgeColor; + static bool sm_useStudStyle; + static int sm_studStyle; + static bool sm_partEdgeColorEnabled; + static bool sm_blackEdgeColorEnabled; + static bool sm_darkEdgeColorEnabled; + static LDLColor sm_studCylinderColor; + static LDLColor sm_partEdgeColor; + static LDLColor sm_blackEdgeColor; + static LDLColor sm_darkEdgeColor; + static TCFloat sm_partColorLDIndex; + static TCFloat sm_partEdgeContrast; + static TCFloat sm_partEdgeSaturation; + static LDLPalette *sm_defaultPalette; static TCByte sm_transA; static class LDLPaletteCleanup diff --git a/LDLoader/LDLPrimitiveCheck.cpp b/LDLoader/LDLPrimitiveCheck.cpp index a4fae6757..ac91296b9 100644 --- a/LDLoader/LDLPrimitiveCheck.cpp +++ b/LDLoader/LDLPrimitiveCheck.cpp @@ -635,6 +635,8 @@ bool LDLPrimitiveCheck::performPrimitiveSubstitution( } else if (strcasecmp(m_modelName, "stud.dat") == 0) { + if (LDLModel::getUseStudStyle()) + return false; return substituteStud(); } else if (strcasecmp(m_modelName, "1-8sphe.dat") == 0) diff --git a/LDView.rc b/LDView.rc index 7f6efa145..efa80f99f 100644 --- a/LDView.rc +++ b/LDView.rc @@ -282,8 +282,11 @@ BEGIN CONTROL "Show control points",IDC_CONDITIONAL_CONTROLS,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,178,87,74,10,0,HIDC_CONDITIONAL_CONTROLS CONTROL "High quality",IDC_QUALITY_LINES,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,169,98,51,10,0,HIDC_QUALITY_LINES CONTROL "Always black",IDC_ALWAYS_BLACK,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,169,109,61,10,0,HIDC_ALWAYS_BLACK - LTEXT "Thickness:",IDC_EDGE_THICKNESS_LABEL,166,125,36,8,0,WS_EX_TRANSPARENT,HIDC_EDGE_THICKNESS_LABEL - CONTROL "Slider1",IDC_EDGE_THICKNESS,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,204,120,68,18,0,HIDC_EDGE_THICKNESS + CONTROL "Automate edge line color",IDC_AUTOMATE_EDGE_COLOR_CHECK, + "Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,169,120,97,10,0,HIDC_AUTOMATE_EDGE_COLOR_CHECK + PUSHBUTTON "...",IDC_AUTOMATE_EDGE_COLOR,270,118,13,14,0,0,HIDC_AUTOMATE_EDGE_COLOR + LTEXT "Thickness:",IDC_EDGE_THICKNESS_LABEL,166,136,36,8,0,WS_EX_TRANSPARENT,HIDC_EDGE_THICKNESS_LABEL + CONTROL "Slider1",IDC_EDGE_THICKNESS,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,204,131,68,18,0,HIDC_EDGE_THICKNESS PUSHBUTTON "&Reset",IDC_GEOMETRY_RESET,253,231,50,14,WS_GROUP,0,HIDC_GEOMETRY_RESET END @@ -498,9 +501,12 @@ BEGIN CONTROL "Anisotropic filtering:",IDC_TEXTURE_ANISO,"Button",BS_AUTORADIOBUTTON,23,132,75,10,0,HIDC_TEXTURE_ANISO CONTROL "Slider1",IDC_ANISO_LEVEL,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,100,130,80,18,0,HIDC_ANISO_LEVEL LTEXT "nx",IDC_ANISO_LEVEL_LABEL,185,134,26,8,0,0,HIDC_ANISO_LEVEL_LABEL - GROUPBOX "&Misc",IDC_PRIMITIVES_MISC_BOX,7,157,296,40,WS_GROUP,WS_EX_TRANSPARENT,HIDC_PRIMITIVES_MISC_BOX - CONTROL "Low quality studs (faster)",IDC_STUD_QUALITY,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,15,170,93,10,0,HIDC_STUD_QUALITY - CONTROL "Use hi-res primitives when available",IDC_HI_RES,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,15,181,127,10,0,HIDC_HI_RES + GROUPBOX "&Misc",IDC_PRIMITIVES_MISC_BOX,7,157,296,52,WS_GROUP,WS_EX_TRANSPARENT,HIDC_PRIMITIVES_MISC_BOX + CONTROL "Use stud style geometry",IDC_STUD_STYLE_USE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,168,94,10,0,HIDC_STUD_STYLE_USE + COMBOBOX IDC_STUD_STYLE_COMBO,115,166,106,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP,0,HIDC_STUD_STYLE_COMBO + PUSHBUTTON "...",IDC_HIGH_CONTRAST_COLOR,227,165,13,14,0,0,HIDC_HIGH_CONTRAST_COLOR + CONTROL "Low quality studs (faster)",IDC_STUD_QUALITY,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,15,181,93,10,0,HIDC_STUD_QUALITY + CONTROL "Use hi-res primitives when available",IDC_HI_RES,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,15,194,127,10,0,HIDC_HI_RES PUSHBUTTON "&Reset",IDC_PRIMITIVES_RESET,253,231,50,14,WS_GROUP,0,HIDC_PRIMITIVES_RESET END @@ -818,6 +824,53 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,98,24,50,14 END +IDD_HIGH_CONTRAST_STUD_COLOR DIALOGEX 0, 0, 247, 167 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "High Contrast Studs" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Edge Line Color",IDC_EDGE_LINE_COLOR_GROUP,13,9,216,32 + CONTROL "",IDC_LIGHT_DARK_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,75,19,64,15,0,HIDC_LIGHT_DARK_SLIDER + LTEXT "Light/Dark Value",IDC_LIGHT_DARK_NAME,17,22,53,8,0,0,HIDC_LIGHT_DARK_NAME + LTEXT "0.00",IDC_LIGHT_DARK_VALUE,145,22,16,8,0,0,HIDC_LIGHT_DARK_VALUE + PUSHBUTTON "Reset",IDC_LIGHT_DARK_RESET,172,19,49,14,WS_GROUP,0,HIDC_LIGHT_DARK_RESET + GROUPBOX "High Contrast",IDC_HIGH_CONTRAST_COLOR_GROUP,13,43,216,92 + CONTROL "Stud cylinder color",IDC_STUD_CYLINDER_COLOR_CHECK, + "Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,17,55,75,10,0,HIDC_STUD_CYLINDER_COLOR_CHECK + CONTROL "",IDC_STUD_CYLINDER_COLOR,"Button",BS_OWNERDRAW | BS_BITMAP | BS_NOTIFY | WS_GROUP | WS_TABSTOP,134,52,29,16,0,HIDC_STUD_CYLINDER_COLOR + PUSHBUTTON "Reset",IDC_STUD_CYLINDER_COLOR_RESET,172,53,49,14,WS_GROUP,0,HIDC_STUD_CYLINDER_COLOR_RESET + CONTROL "Parts edge color",IDC_PART_EDGE_COLOR_CHECK,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,17,75,68,10,0,HIDC_PART_EDGE_COLOR_CHECK + CONTROL "",IDC_PART_EDGE_COLOR,"Button",BS_OWNERDRAW | BS_BITMAP | BS_NOTIFY | WS_GROUP | WS_TABSTOP,134,72,29,16,0,HIDC_PART_EDGE_COLOR + PUSHBUTTON "Reset",IDC_PART_EDGE_COLOR_RESET,172,73,49,14,WS_GROUP,0,HIDC_PART_EDGE_COLOR_RESET + CONTROL "Black parts edge color",IDC_BLACK_EDGE_COLOR_CHECK, + "Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,18,96,86,10,0,HIDC_BLACK_EDGE_COLOR_CHECK + CONTROL "",IDC_BLACK_EDGE_COLOR,"Button",BS_OWNERDRAW | BS_BITMAP | BS_NOTIFY | WS_GROUP | WS_TABSTOP,134,92,29,16,0,HIDC_BLACK_EDGE_COLOR + PUSHBUTTON "Reset",IDC_BLACK_EDGE_COLOR_RESET,172,93,50,14,WS_GROUP,0,HIDC_BLACK_EDGE_COLOR_RESET + CONTROL "Dark parts edge color",IDC_DARK_EDGE_COLOR_CHECK,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,17,116,85,10,0,HIDC_DARK_EDGE_COLOR_CHECK + CONTROL "",IDC_DARK_EDGE_COLOR,"Button",BS_OWNERDRAW | BS_BITMAP | BS_NOTIFY | WS_GROUP | WS_TABSTOP,134,113,29,16,0,HIDC_DARK_EDGE_COLOR + PUSHBUTTON "Reset",IDC_DARK_EDGE_COLOR_RESET,172,114,50,14,WS_GROUP,0,HIDC_DARK_EDGE_COLOR_RESET + DEFPUSHBUTTON "OK",IDC_HIGH_CONTRAST_STUD_COLOR_OK,116,140,50,14 + PUSHBUTTON "Cancel",IDCANCEL,172,140,50,14 +END + +IDD_AUTOMATE_EDGE_LINE_COLOR DIALOGEX 0, 0, 245, 92 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Automate Edge Line Color" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Edge Line Color",IDC_AUTO_EDGE_LINE_COLOR_GROUP,13,10,219,51 + CONTROL "",IDC_CONTRAST_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,79,20,64,15,0,HIDC_CONTRAST_SLIDER + LTEXT "Contrast",IDC_CONTRAST_NAME,23,23,29,8,0,0,HIDC_CONTRAST_NAME + LTEXT "0.00",IDC_CONTRAST_VALUE,150,23,16,8,0,0,HIDC_CONTRAST_VALUE + PUSHBUTTON "Reset",IDC_CONTRAST_RESET,176,20,49,14,WS_GROUP,0,HIDC_CONTRAST_RESET + CONTROL "",IDC_SATURATION_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,79,40,64,15,0,HIDC_SATURATION_SLIDER + LTEXT "Saturation",IDC_SATURATION_NAME,23,43,34,8,0,0,HIDC_SATURATION_NAME + LTEXT "0.00",IDC_SATURATION_VALUE,150,43,16,8,0,0,HIDC_SATURATION_VALUE + PUSHBUTTON "Reset",IDC_SATURATION_RESET,176,41,49,14,WS_GROUP,0,HIDC_SATURATION_RESET + DEFPUSHBUTTON "OK",IDC_AUTOMATE_EDGE_LINE_COLOR_OK,122,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,176,66,50,14 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -1078,6 +1131,22 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 39 END + + IDD_HIGH_CONTRAST_STUD_COLOR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 239 + TOPMARGIN, 7 + BOTTOMMARGIN, 160 + END + + IDD_AUTOMATE_EDGE_LINE_COLOR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 238 + TOPMARGIN, 7 + BOTTOMMARGIN, 86 + END END #endif // APSTUDIO_INVOKED @@ -1669,6 +1738,9 @@ BEGIN HIDC_BACKGROUND_COLOR_LABEL "This allows you to set the color used to draw the background behind the model." HIDC_BFC "Enabling this option turns on back-face culling (BFC). BFC is a technique that can improve rendering performance by not drawing the back faces of polygons. (Only BFC-certified parts have their back faces removed.)\r\n\r\nNote that while this can improve rendering performance, it can also slow things down, so don't assume that enabling this will always result in the best performance." HIDC_BFC_BOX "BFC-related settings." + HIDC_BLACK_EDGE_COLOR "Set the edge color for black parts. For example, a common edge color for black parts is white." + HIDC_BLACK_EDGE_COLOR_CHECK "Use this to enable the black parts edge color preference." + HIDC_BLACK_EDGE_COLOR_RESET "This resets the black parts edge color to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." HIDC_BLUE_NEUTRAL_FACES "This option is only available while BFC is enabled. Enabling it causes the faces of non-BFC-certified polygons to be drawn in blue. This is mainly useful for part authors to allow them to correctly specify which direction faces should face in order to BFC certify their part files." HIDC_BROWSE_CUSTOM_CONFIG "Set the path of the file used for custom config." HIDC_BROWSE_EXPORT_DIR "Set the default directory to use for Exports.\r\n\r\nModel: The default directory is the same directory as the currently loaded model.\r\n\r\nLast Saved Export: The default directory is whatever directory was used last. (The first time you save an export, the default directory is the model's directory.)\r\n\r\nSpecified: The default directory is specified in the field to the right of the drop-down box. Use the Browse... button to browse for a directory, or enter it in the field directly." @@ -1680,6 +1752,10 @@ BEGIN HIDC_COLORS_BOX "Color-related settings." HIDC_CONDITIONAL_CONTROLS "This option is only available if edge lines and conditional lines are enabled. Enabling it causes lines to be drawn from the first point of each conditional line to each of its two control points. This option is primarily designed for part authors, so they can verify that the control points are in the correct location." HIDC_CONDITIONAL_HIGHLIGHTS "This option is only available if edge lines are enabled. Enabling it causes conditional edge lines to be computed and drawn. Conditional edge lines show up as a silhouette of curved surfaces; they are only drawn when they are visually at the edge of the surface from the current viewing angle." + HIDC_CONTRAST_NAME "Set the contrast preference for automated part edge color calculation." + HIDC_CONTRAST_RESET "This resets the contrast preference to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." + HIDC_CONTRAST_SLIDER "Set the contrast preference for automated part edge color calculation." + HIDC_CONTRAST_VALUE "Diaplay the contrast value." HIDC_CROSS_EYED_STEREO "This option is only available if stereo is enabled. Selecting this sets the stereo mode to cross-eyed stereo. The two images are drawn side by side, with the image for the right eye on the left and the image for the left eye on the right. By crossing your eyes and then focusing, you can see a stereoscopic image. Many people find it difficult or even impossible to focus with their eyes crossed." HIDC_CURVE_QUALITY "This option is only available if primitive substitution is enabled. It adjusts the quality of substituted primitives by changing the number of facets used to draw curved primitives. Changing this from its default value can lead to holes in the model between the substitute primitives and other geometry. Be very careful with this setting. Setting it too high can lead to huge slow-downs. The default setting of 2 (9%) is fine for most models." HIDC_CURVE_QUALITY_LABEL "This option is only available if primitive substitution is enabled. It adjusts the quality of substituted primitives by changing the number of facets used to draw curved primitives. Changing this from its default value can lead to holes in the model between the substitute primitives and other geometry. Be very careful with this setting. Setting it too high can lead to huge slow-downs. The default setting of 2 (9%) is fine for most models." @@ -1693,6 +1769,9 @@ BEGIN HIDC_CUTAWAY_OPACITY_LABEL "This option is only available if wireframe cutaway is enabled. The slider controls the opacity of the wireframe cutaway. When Color is selected as the type of wireframe cutaway to draw this may be fixed at 100% on some graphics cards. Also, when color is selected and sort is not selected in the transparency box, transparent pieces will ignore the opacity setting and be drawn with the standard opacity setting for transparent pieces." HIDC_CUTAWAY_THICKNESS "This option is only available if wireframe cutaway is enabled. The slider controls the thickness of the lines in the wireframe cutaway." HIDC_CUTAWAY_THICKNESS_LABEL "This option is only available if wireframe cutaway is enabled. The slider controls the thickness of the lines in the wireframe cutaway." + HIDC_DARK_EDGE_COLOR "Set the edge color for dark parts. For example, a common edge color for dark parts is light grey." + HIDC_DARK_EDGE_COLOR_CHECK "Use this to enable the dark edge color preference." + HIDC_DARK_EDGE_COLOR_RESET "This resets the dark edge color to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." HIDC_DEFAULT_COLOR "This allows you to set the default color. Normally this is only visible when you load a part directly. Most models don't ever use this color.\r\n\r\nNote that edge lines on default-colored objects will be black unless you choose the exact RGB value used by one of the standard LDraw colors. The default custom colors in the color panel correspond to the first 16 standard LDraw colors. Resetting the General preferences also resets these colors." HIDC_DEFAULT_COLOR_LABEL "This allows you to set the default color. Normally this is only visible when you load a part directly. Most models don't ever use this color.\r\n\r\nNote that edge lines on default-colored objects will be black unless you choose the exact RGB value used by one of the standard LDraw colors. The default custom colors in the color panel correspond to the first 16 standard LDraw colors. Resetting the General preferences also resets these colors." HIDC_DELETE_PREF_SET "This deletes the currently selected preference set." @@ -1719,6 +1798,7 @@ BEGIN HIDC_GEOMETRY_RESET "This resets all the Geometry preferences to their default values. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." HIDC_GREEN_FRONT_FACES "This option is only available while BFC is enabled. Enabling it causes the front faces of polygons to be drawn in green. This is mainly useful for part authors to allow them to correctly specify which direction faces should face in order to BFC certify their part files." HIDC_HIDE_LIGHT_DAT "Selecting this causes LDView to not display the geometry from LIGHT.DAT parts. Since the geometry is a small set of 3D coordinate axes, you often don't want to see it." + HIDC_HIGH_CONTRAST_COLOR "Display the High Contrast Stud Color settings dialog." HIDC_HIGHLIGHTS "Enabling this option causes the edge lines that outline all the pieces to be drawn. It is recommended that you disable the seam width option if you enable this option." HIDC_HI_RES "Enabling this option causes LDView to attempt to load hi-res versions of primitives before loading the standard ones. The hi-res primitives are otherwise known as 48-sided primitives, because they approximate circular features with 48-sided features." HIDC_IGNORE_FBO "Enabling this option disables the use of a framebuffer object for snapshot rendering. Use of a framebuffer object can result in a corrupt image on certain video cards with certain video drivers. If your snapshots are corrupted, enable this. Otherwise, leave it disabled." @@ -1727,6 +1807,10 @@ BEGIN HIDC_LDRAW_DIR "This contains the full path to the LDraw directory.\r\n\r\nNote: Even if the LDraw Zip is set, this still must be set, and will be used to download unofficial parts from ldraw.org." HIDC_LDRAW_RESET "This resets all the LDraw preferences to their default values. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." HIDC_LDRAW_ZIP "This contains the full path to the LDraw Parts Library Zip.\r\n\r\nNote: If a file named ldrawunf.zip exists in the same directory as this file, it will automatically be searched for unofficial parts." + HIDC_LIGHT_DARK_NAME "Set the light dark factor preference for high contrast part color calculation." + HIDC_LIGHT_DARK_RESET "This resets the light dark factor to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." + HIDC_LIGHT_DARK_SLIDER "Set the light dark factor preference for high contrast part color calculation." + HIDC_LIGHT_DARK_VALUE "Diaplay the light dark factor value." HIDC_LIGHTING "Enabling this option enables lighting. If you disable lighting, it is strongly recommended that you enable edge lines, unless you are in wireframe mode. (Both edge lines and wireframe mode are on the Geometry tab.)" HIDC_LIGHTING_BOX "Lighting-related settings." HIDC_LIGHTING_QUALITY "This option is only available if lighting is enabled. Selecting this enables high quality lighting. The easiest way to see the difference between having this option on and off is with a baseplate. If you angle a baseplate until the specular highlight becomes visible (it gets shiny), and then switch back and forth, you will see that the highlight is located in a specific location when high quality lighting is enabled, and covers the entire surface when it is disabled. Enabling this can significantly decrease performance, especially with large models." @@ -1746,6 +1830,9 @@ BEGIN HIDC_PARTS_LIST_DIR "Set the default directory to use for Parts Lists.\r\n\r\nModel: The default directory is the same directory as the currently loaded model.\r\n\r\nLast Saved Parts List: The default directory is whatever directory was used last. (The first time you save a parts list, the default directory is the model's directory.)\r\n\r\nSpecified: The default directory is specified in the field to the right of the drop-down box. Use the Browse... button to browse for a directory, or enter it in the field directly." HIDC_PARTS_LIST_DIR_COMBO "Set the default directory to use for Parts Lists.\r\n\r\nModel: The default directory is the same directory as the currently loaded model.\r\n\r\nLast Saved Parts List: The default directory is whatever directory was used last. (The first time you save a parts list, the default directory is the model's directory.)\r\n\r\nSpecified: The default directory is specified in the field to the right of the drop-down box. Use the Browse... button to browse for a directory, or enter it in the field directly." HIDC_PART_BOUNDING_BOXES "Enabling this option makes it so that all parts in the model are drawn as just bounding boxes. A bounding box is the minimum axis-aligned box that can completely contain the part. Geometry that isn't detected as being inside a part is drawn normally." + HIDC_PART_EDGE_COLOR "Set the part edge color. For example, a common edge color is dark grey." + HIDC_PART_EDGE_COLOR_CHECK "Use this to enable the part edge color preference." + HIDC_PART_EDGE_COLOR_RESET "This resets the part edge color to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." HIDC_PREFSETS_LABEL "This list shows all of the available preference sets. Until you create new ones, there is only one item in this list, named . Selecting an item from this list will cause LDView to use the preferences stored in that set after you hit Apply. If you have made any changes to preferences on other tabs and select a new preference set, it will prompt you whether you want to apply those changes, abandon them, or cancel your selection." HIDC_PREFSETS_LIST "This list shows all of the available preference sets. Until you create new ones, there is only one item in this list, named . Selecting an item from this list will cause LDView to use the preferences stored in that set after you hit Apply. If you have made any changes to preferences on other tabs and select a new preference set, it will prompt you whether you want to apply those changes, abandon them, or cancel your selection." HIDC_PREF_SET_HOT_KEY "This allows you to assign a hot key to the currently selected preference set." @@ -1768,6 +1855,10 @@ BEGIN HIDC_REMOVE_HIDDEN_LINES "This option is only available if wireframe drawing is enabled. Enabling it causes the solid (non-transparent) portions of the model to hide lines that are behind them, even though these portions themselves aren't actually drawn." HIDC_RESET_TIMES "Clears the recorded time for last download of unofficial parts. This forces LDView to check the LDraw parts tracker for all unofficial parts, instead of waiting the specified number of days.\r\n\r\nPlease note: Unlike other settings, hitting this happens immediately; you do not have to hit Apply or OK." HIDC_SAME_SCALE "This option is only available if all steps are enabled. Enabling it causes all step snapshots to be generated using the same scale." + HIDC_SATURATION_NAME "Set the saturation preference for automated part edge color calculation." + HIDC_SATURATION_RESET "This resets the saturation preference to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." + HIDC_SATURATION_SLIDER "Set the saturation preference for automated part edge color calculation." + HIDC_SATURATION_VALUE "Diaplay the saturation value." HIDC_SAVE_ACTUAL_SIZE "Enabling this option allows you to specify a width and height for the snapshot image. Otherwise, the snapshot created will have the same dimensions as the LDView window." HIDC_SAVE_ACTUAL_SIZE_BOX "Settings related to the image size." HIDC_SAVE_DIGITS "This option is only available when save snapshot series is enabled. It controls the number of digits in the number that is appended to the filename. Zeroes are added before the number to make up the number of digits you select here. For example, if you select 3 here, and the number is 5, then 005 will be used in the filename instead of just 5." @@ -1812,6 +1903,11 @@ BEGIN HIDC_STEREO_SPACING "This option is only available if stereo is enabled. The slider controls the stereo spacing. A small value will result in a very subtle stereoscopic effect, as if you were looking at a very large object from a very long distance. (The minimum value results in no stereoscopic effect at all.) A large value will result in a pronounced stereoscopic effect, as if you were looking at a small object from a very short distance." HIDC_STEREO_SPACING_LABEL "This option is only available if stereo is enabled. The slider controls the stereo spacing. A small value will result in a very subtle stereoscopic effect, as if you were looking at a very large object from a very long distance. (The minimum value results in no stereoscopic effect at all.) A large value will result in a pronounced stereoscopic effect, as if you were looking at a small object from a very short distance." HIDC_STIPPLE "Enabling this option causes transparent shapes to be drawn using a stipple (checkerboard) pattern. This may be significantly faster on some video hardware, but with potentially reduced quality. Using the stipple pattern totally eliminates the errors that may occur where far transparent objects are drawn in front of closer ones. This option is mutually exclusive with the sort option." + HIDC_STUD_STYLE_USE "Enabling this option gives the user the ability to select the displayed stud style geometry. When unchecked, Texture studs settings will be respected." + HIDC_STUD_STYLE_COMBO "This allows you to select the stud style display when Use stud style geometry preference is checked." + HIDC_STUD_CYLINDER_COLOR "Set the stud cylinder high contrast color. For example, a common high contrast stud cylinder color is black." + HIDC_STUD_CYLINDER_COLOR_CHECK "Use this to enable the stud cylinder color preference." + HIDC_STUD_CYLINDER_COLOR_RESET "This resets the stud cylinder color to its default value. As with all other preference changes, you must hit OK or Apply for the reset values to go into effect." HIDC_STUD_QUALITY "Enabling this option switches to using the low-resolution stud files instead of the normal-resolution stud files. This can produce significantly faster rendering." HIDC_TEXMAPS "Enabling this option turns on support for the LDraw TEXMAP extension. Disabling it will cause LDView to use any fallback geometry included in the LDraw file." HIDC_TEXTURE_ANISO "This option is only available if primitive substitution and texture studs are both enabled, and your video card supports it. Selecting it causes anisotropic texture filtering to be used. When anisotropic filtering is selected, you can pick the filtering level on the slider to the right of the radio button. This is the highest quality texture filtering." diff --git a/LDViewMessages.ini b/LDViewMessages.ini index 130e3b89c..3490a900b 100644 --- a/LDViewMessages.ini +++ b/LDViewMessages.ini @@ -98,6 +98,15 @@ BrowseForSnapshotDir =Please select the directory to save snapshots into. BrowseForPartsListDir =Please select the directory to save parts lists into. BrowseForExportDir =Please select the directory to save exports into. +; Stud style geometry +Plain =0 Plain +SingleWire =1 Single Wire +DoubleWire =2 Double Wire +RaisedFlat =3 Raised Flat +RaisedRounded =4 Raised Rounded +SubtleRounded =5 Subtle Rounded +HighContrast =6 High Contrast Plain +HighContrastSingleWire =7 High Contrast Single Wire ; ** LDViewWindow ** diff --git a/LDViewPreferences.cpp b/LDViewPreferences.cpp index 99e786ba2..a0ad6ed59 100644 --- a/LDViewPreferences.cpp +++ b/LDViewPreferences.cpp @@ -64,7 +64,7 @@ ucstring LDViewPreferences::ldviewPath; LDViewPreferences::LDViewPreferences( HINSTANCE hInstance, - LDViewWindow *ldviewWindow, + LDViewWindow* ldviewWindow, LDrawModelViewer* modelViewer) : CUIPropertySheet(ls(_UC("LDViewPreferences")), hInstance) , modelViewer(modelViewer != NULL ? ((LDrawModelViewer*)modelViewer->retain()) : NULL) @@ -82,6 +82,18 @@ LDViewPreferences::LDViewPreferences( , hBackgroundColorButton(NULL) , hDefaultColorBitmap(NULL) , hDefaultColorButton(NULL) + , hStudCylinderColorBitmap(NULL) + , hStudCylinderColorButton(NULL) + , hStudCylinderColorReset(NULL) + , hPartEdgeColorBitmap(NULL) + , hPartEdgeColorButton(NULL) + , hPartEdgeColorReset(NULL) + , hBlackEdgeColorBitmap(NULL) + , hBlackEdgeColorButton(NULL) + , hBlackEdgeColorReset(NULL) + , hDarkEdgeColorBitmap(NULL) + , hDarkEdgeColorButton(NULL) + , hDarkEdgeColorReset(NULL) , hMouseOverButton(NULL) , origButtonWindowProc(NULL) , hButtonColorDC(NULL) @@ -96,6 +108,17 @@ LDViewPreferences::LDViewPreferences( , setActiveWarned(false) , checkAbandon(true) , hButtonTheme(NULL) + , hAutomateEdgeColorButton(NULL) + , hHighContrastColorButton(NULL) + , hHighContrastStudColor(NULL) + , hAutomateEdgeLineColor(NULL) + , partEdgeLightDarkValue(0.0f) + , partEdgeContrastValue(0.0f) + , partEdgeSaturationValue(0.0f) + , studCylinderColorEnabled(false) + , partEdgeColorEnabled(false) + , blackEdgeColorEnabled(false) + , darkEdgeColorEnabled(false) // hTabTheme(NULL) { WillyMessage("\n\n\n"); @@ -487,6 +510,42 @@ COLORREF LDViewPreferences::getDefaultColor(void) return RGB((BYTE)r, (BYTE)g, (BYTE)b); } +void LDViewPreferences::getStudCylinderColor(void) +{ + int r, g, b, a; + + ldPrefs->getStudCylinderColor(r, g, b, a); + crStudCylinderColor = RGB((BYTE)r, (BYTE)g, (BYTE)b); + studCylinderColorEnabled = ldPrefs->getStudCylinderColorEnabled(); +} + +void LDViewPreferences::getPartEdgeColor(void) +{ + int r, g, b, a; + + ldPrefs->getPartEdgeColor(r, g, b, a); + crPartEdgeColor = RGB((BYTE)r, (BYTE)g, (BYTE)b); + partEdgeColorEnabled = ldPrefs->getPartEdgeColorEnabled(); +} + +void LDViewPreferences::getBlackEdgeColor(void) +{ + int r, g, b, a; + + ldPrefs->getBlackEdgeColor(r, g, b, a); + crBlackEdgeColor = RGB((BYTE)r, (BYTE)g, (BYTE)b); + blackEdgeColorEnabled = ldPrefs->getBlackEdgeColorEnabled(); +} + +void LDViewPreferences::getDarkEdgeColor(void) +{ + int r, g, b, a; + + ldPrefs->getDarkEdgeColor(r, g, b, a); + crDarkEdgeColor = RGB((BYTE)r, (BYTE)g, (BYTE)b); + darkEdgeColorEnabled = ldPrefs->getDarkEdgeColorEnabled(); +} + void LDViewPreferences::setDrawConditionalHighlights(bool value) { if (value != ldPrefs->getDrawConditionalHighlights()) @@ -1020,6 +1079,23 @@ BOOL LDViewPreferences::doDialogNotify(HWND hDlg, int controlId, return FALSE; } } + else if (hDlg == hHighContrastStudColor) + { + if (controlId == IDC_LIGHT_DARK_SLIDER) + { + enableApply(hPrimitivesPage); + setStudStyleSliderValue(hDlg, controlId); + } + } + else if (hDlg == hAutomateEdgeLineColor) + { + if (controlId == IDC_CONTRAST_SLIDER || + controlId == IDC_SATURATION_SLIDER) + { + enableApply(hGeometryPage); + setStudStyleSliderValue(hDlg, controlId); + } + } } else if (notification->code == CBN_SELCHANGE) { @@ -1339,6 +1415,37 @@ void LDViewPreferences::setupDefaultColorButton(void) getDefaultColor()); } +BOOL LDViewPreferences::highContrastStudColorInit(HWND hDlg) +{ + UCCHAR label[16]; + hHighContrastStudColor = hDlg; + + CUIDialog::trackBarSetup(hDlg, IDC_LIGHT_DARK_SLIDER, 0, 10, 1, + sliderPosFromStudStyleVal(partEdgeLightDarkValue)); + setStudStyleSliderValue(hDlg, IDC_LIGHT_DARK_SLIDER); + + setupStudStyleColorButton(hDlg, IDC_STUD_CYLINDER_COLOR); + setupStudStyleColorButton(hDlg, IDC_PART_EDGE_COLOR); + setupStudStyleColorButton(hDlg, IDC_BLACK_EDGE_COLOR); + setupStudStyleColorButton(hDlg, IDC_DARK_EDGE_COLOR); + return TRUE; +} + +BOOL LDViewPreferences::automateEdgeLineColorInit(HWND hDlg) +{ + UCCHAR label[16]; + hAutomateEdgeLineColor = hDlg; + + CUIDialog::trackBarSetup(hDlg, IDC_CONTRAST_SLIDER, 0, 10, 1, + sliderPosFromStudStyleVal(partEdgeContrastValue)); + setStudStyleSliderValue(hDlg, IDC_CONTRAST_SLIDER); + + CUIDialog::trackBarSetup(hDlg, IDC_SATURATION_SLIDER, 0, 10, 1, + sliderPosFromStudStyleVal(partEdgeSaturationValue)); + setStudStyleSliderValue(hDlg, IDC_SATURATION_SLIDER); + return TRUE; +} + LRESULT CALLBACK LDViewPreferences::staticIconButtonProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1992,6 +2099,10 @@ void LDViewPreferences::applyGeometryChanges(void) IDC_QUALITY_LINES)); ldPrefs->setBlackHighlights(getCheck(hGeometryPage, IDC_ALWAYS_BLACK)); + ldPrefs->setAutomateEdgeColor(getCheck(hGeometryPage, + IDC_AUTOMATE_EDGE_COLOR_CHECK)); + ldPrefs->setPartEdgeContrast(partEdgeContrastValue); + ldPrefs->setPartEdgeSaturation(partEdgeSaturationValue); } ldPrefs->setEdgeThickness(CUIDialog::trackBarGetPos(hGeometryPage, IDC_EDGE_THICKNESS)); @@ -2084,6 +2195,43 @@ void LDViewPreferences::applyPrimitivesChanges(void) ldPrefs->setTextureOffsetFactor(textureOffsetFromSliderValue( trackBarGetPos(hTextureOffsetSlider))); } + ldPrefs->setUseStudStyle(getCheck(hPrimitivesPage, IDC_STUD_STYLE_USE)); + ldPrefs->setStudStyle(CUIDialog::comboGetCurSel(hPrimitivesPage, + IDC_STUD_STYLE_COMBO)); + ldPrefs->setPartColorLDIndex(partEdgeLightDarkValue); + ldPrefs->setStudCylinderColorEnabled(studCylinderColorEnabled); + ldPrefs->setPartEdgeColorEnabled(partEdgeColorEnabled); + ldPrefs->setBlackEdgeColorEnabled(blackEdgeColorEnabled); + ldPrefs->setDarkEdgeColorEnabled(darkEdgeColorEnabled); + int r, g, b; + if (studCylinderColorEnabled) + { + r = GetRValue(crStudCylinderColor); + g = GetGValue(crStudCylinderColor); + b = GetBValue(crStudCylinderColor); + ldPrefs->setStudCylinderColor(r, g, b, 255); + } + if (partEdgeColorEnabled) + { + r = GetRValue(crPartEdgeColor); + g = GetGValue(crPartEdgeColor); + b = GetBValue(crPartEdgeColor); + ldPrefs->setPartEdgeColor(r, g, b, 255); + } + if (blackEdgeColorEnabled) + { + r = GetRValue(crBlackEdgeColor); + g = GetGValue(crBlackEdgeColor); + b = GetBValue(crBlackEdgeColor); + ldPrefs->setBlackEdgeColor(r, g, b, 255); + } + if (darkEdgeColorEnabled) + { + r = GetRValue(crDarkEdgeColor); + g = GetGValue(crDarkEdgeColor); + b = GetBValue(crDarkEdgeColor); + ldPrefs->setDarkEdgeColor(r, g, b, 255); + } ldPrefs->setQualityStuds(!getCheck(hPrimitivesPage, IDC_STUD_QUALITY)); ldPrefs->setHiResPrimitives(getCheck(hPrimitivesPage, IDC_HI_RES)); ldPrefs->applyPrimitivesSettings(); @@ -2197,6 +2345,26 @@ void LDViewPreferences::chooseDefaultColor(void) ldPrefs->setDefaultColor(r, g, b); } +void LDViewPreferences::chooseStudCylinderColor(void) +{ + chooseColor(hStudCylinderColorButton, hStudCylinderColorBitmap, crStudCylinderColor); +} + +void LDViewPreferences::choosePartEdgeColor(void) +{ + chooseColor(hPartEdgeColorButton, hPartEdgeColorBitmap, crPartEdgeColor); +} + +void LDViewPreferences::chooseBlackEdgeColor(void) +{ + chooseColor(hBlackEdgeColorButton, hBlackEdgeColorBitmap, crBlackEdgeColor); +} + +void LDViewPreferences::chooseDarkEdgeColor(void) +{ + chooseColor(hDarkEdgeColorButton, hDarkEdgeColorBitmap, crDarkEdgeColor); +} + void LDViewPreferences::chooseColor(HWND hColorButton, HBITMAP hColorBitmap, COLORREF &color) { @@ -2359,6 +2527,15 @@ void LDViewPreferences::doGeometryClick(int controlId, HWND /*controlHWnd*/) case IDC_SEAMS: doSeams(); break; + case IDC_ALWAYS_BLACK: + doAlwaysBlack(); + break; + case IDC_AUTOMATE_EDGE_COLOR_CHECK: + doAutomateEdgeColorCheck(); + break; + case IDC_AUTOMATE_EDGE_COLOR: + doAutomateEdgeColor(); + break; case IDC_GEOMETRY_RESET: ldPrefs->loadDefaultGeometrySettings(false); setupGeometryPage(); @@ -2484,6 +2661,22 @@ void LDViewPreferences::doNewPrefSet(void) } } +void LDViewPreferences::doHighContrastColor(void) +{ + if (DialogBoxParam(getLanguageModule(), MAKEINTRESOURCE(IDD_HIGH_CONTRAST_STUD_COLOR), + hPropSheet, staticDialogProc, (LPARAM)this) == IDOK) + { + } +} + +void LDViewPreferences::doAutomateEdgeColor(void) +{ + if (DialogBoxParam(getLanguageModule(), MAKEINTRESOURCE(IDD_AUTOMATE_EDGE_LINE_COLOR), + hPropSheet, staticDialogProc, (LPARAM)this) == IDOK) + { + } +} + ucstring LDViewPreferences::getHotKey(int index) { char key[128]; @@ -2703,6 +2896,180 @@ void LDViewPreferences::doOtherClick(HWND hDlg, int controlId, { EndDialog(hDlg, controlId); } + else if (hDlg == hHighContrastStudColor) + { + if (controlId == IDC_HIGH_CONTRAST_STUD_COLOR_OK) + { + EndDialog(hDlg, IDOK); + } + else if (controlId == IDC_STUD_CYLINDER_COLOR_CHECK) + { + enableApply(hPrimitivesPage); + studCylinderColorEnabled = getCheck(hDlg, controlId); + EnableWindow(hStudCylinderColorButton, studCylinderColorEnabled); + EnableWindow(hStudCylinderColorReset, studCylinderColorEnabled); + } + else if (controlId == IDC_STUD_CYLINDER_COLOR) + { + chooseStudCylinderColor(); + } + else if (controlId == IDC_PART_EDGE_COLOR_CHECK) + { + enableApply(hPrimitivesPage); + partEdgeColorEnabled = getCheck(hDlg, controlId); + EnableWindow(hPartEdgeColorButton, partEdgeColorEnabled); + EnableWindow(hPartEdgeColorReset, partEdgeColorEnabled); + } + else if (controlId == IDC_PART_EDGE_COLOR) + { + choosePartEdgeColor(); + } + else if (controlId == IDC_BLACK_EDGE_COLOR_CHECK) + { + enableApply(hPrimitivesPage); + blackEdgeColorEnabled = getCheck(hDlg, controlId); + EnableWindow(hBlackEdgeColorButton, blackEdgeColorEnabled); + EnableWindow(hBlackEdgeColorReset, blackEdgeColorEnabled); + } + else if (controlId == IDC_BLACK_EDGE_COLOR) + { + chooseBlackEdgeColor(); + } + else if (controlId == IDC_DARK_EDGE_COLOR_CHECK) + { + enableApply(hPrimitivesPage); + darkEdgeColorEnabled = getCheck(hDlg, controlId); + EnableWindow(hDarkEdgeColorButton, darkEdgeColorEnabled); + EnableWindow(hDarkEdgeColorReset, darkEdgeColorEnabled); + } + else if (controlId == IDC_DARK_EDGE_COLOR) + { + chooseDarkEdgeColor(); + } + else if (controlId == IDC_LIGHT_DARK_RESET) + { + CUIDialog::trackBarSetup(hDlg, IDC_LIGHT_DARK_SLIDER, 0, 10, 1, + sliderPosFromStudStyleVal(ldPrefs->getPartColorLDIndex())); + setStudStyleSliderValue(hDlg, IDC_LIGHT_DARK_SLIDER); + } + else if (controlId == IDC_STUD_CYLINDER_COLOR_RESET) + { + setupStudStyleColorButton(hDlg, IDC_STUD_CYLINDER_COLOR); + } + else if (controlId == IDC_PART_EDGE_COLOR_RESET) + { + setupStudStyleColorButton(hDlg, IDC_PART_EDGE_COLOR); + } + else if (controlId == IDC_BLACK_EDGE_COLOR_RESET) + { + setupStudStyleColorButton(hDlg, IDC_BLACK_EDGE_COLOR); + } + else if (controlId == IDC_DARK_EDGE_COLOR_RESET) + { + setupStudStyleColorButton(hDlg, IDC_DARK_EDGE_COLOR); + } + } + else if (hDlg == hAutomateEdgeLineColor) + { + if (controlId == IDC_AUTOMATE_EDGE_LINE_COLOR_OK) + { + EndDialog(hDlg, IDOK); + } + else if (controlId == IDC_CONTRAST_RESET) + { + CUIDialog::trackBarSetup(hDlg, IDC_CONTRAST_SLIDER, 0, 10, 1, + sliderPosFromStudStyleVal(ldPrefs->getPartEdgeContrast())); + setStudStyleSliderValue(hDlg, IDC_CONTRAST_SLIDER); + } + else if (controlId == IDC_SATURATION_RESET) + { + CUIDialog::trackBarSetup(hDlg, IDC_SATURATION_SLIDER, 0, 10, 1, + sliderPosFromStudStyleVal(ldPrefs->getPartEdgeSaturation())); + setStudStyleSliderValue(hDlg, IDC_SATURATION_SLIDER); + } + } +} + +void LDViewPreferences::setStudStyleSliderValue(HWND hDlg, int controlId) +{ + UCCHAR label[16]; + HWND hSliderValue = NULL; + HWND hSliderControl = GetDlgItem(hDlg, controlId); + float value = studStyleValFromSliderPos(trackBarGetPos(hSliderControl)); + if (controlId == IDC_LIGHT_DARK_SLIDER) + { + partEdgeLightDarkValue = value; + hSliderValue = GetDlgItem(hDlg, IDC_LIGHT_DARK_VALUE); + } + else if (controlId == IDC_CONTRAST_SLIDER) + { + partEdgeContrastValue = value; + hSliderValue = GetDlgItem(hDlg, IDC_CONTRAST_VALUE); + } + else if (controlId == IDC_SATURATION_SLIDER) + { + partEdgeSaturationValue = value; + hSliderValue = GetDlgItem(hDlg, IDC_SATURATION_VALUE); + } + if (hSliderValue) + { + if (value > 0) + { + sucprintf(label, COUNT_OF(label), _UC("%.2f"), value); + } + else + { + label[0] = 0; + } + CUIDialog::windowSetText(hSliderValue, label); + } +} + +void LDViewPreferences::setupStudStyleColorButton(HWND hDlg, int controlId) +{ + switch (controlId) + { + case IDC_STUD_CYLINDER_COLOR: + setupColorButton(hDlg, hStudCylinderColorButton, controlId, hStudCylinderColorBitmap, + crStudCylinderColor); + hStudCylinderColorReset = GetDlgItem(hDlg, IDC_STUD_CYLINDER_COLOR_RESET); + studCylinderColorEnabled = ldPrefs->getStudCylinderColorEnabled(); + if (getCheck(hDlg, IDC_STUD_CYLINDER_COLOR_CHECK) != studCylinderColorEnabled) + setCheck(hDlg, IDC_STUD_CYLINDER_COLOR_CHECK, studCylinderColorEnabled); + EnableWindow(hStudCylinderColorButton, studCylinderColorEnabled); + EnableWindow(hStudCylinderColorReset, studCylinderColorEnabled); + break; + case IDC_PART_EDGE_COLOR: + setupColorButton(hDlg, hPartEdgeColorButton, controlId, hPartEdgeColorBitmap, + crPartEdgeColor); + hPartEdgeColorReset = GetDlgItem(hDlg, IDC_PART_EDGE_COLOR_RESET); + partEdgeColorEnabled = ldPrefs->getPartEdgeColorEnabled(); + if (getCheck(hDlg, IDC_PART_EDGE_COLOR_CHECK) != partEdgeColorEnabled) + setCheck(hDlg, IDC_PART_EDGE_COLOR_CHECK, partEdgeColorEnabled); + EnableWindow(hPartEdgeColorButton, partEdgeColorEnabled); + EnableWindow(hPartEdgeColorReset, partEdgeColorEnabled); + break; + case IDC_BLACK_EDGE_COLOR: + setupColorButton(hDlg, hBlackEdgeColorButton, controlId, hBlackEdgeColorBitmap, + crBlackEdgeColor); + hBlackEdgeColorReset = GetDlgItem(hDlg, IDC_BLACK_EDGE_COLOR_RESET); + blackEdgeColorEnabled = ldPrefs->getBlackEdgeColorEnabled(); + if (getCheck(hDlg, IDC_BLACK_EDGE_COLOR_CHECK) != blackEdgeColorEnabled) + setCheck(hDlg, IDC_BLACK_EDGE_COLOR_CHECK, blackEdgeColorEnabled); + EnableWindow(hBlackEdgeColorButton, blackEdgeColorEnabled); + EnableWindow(hBlackEdgeColorReset, blackEdgeColorEnabled); + break; + case IDC_DARK_EDGE_COLOR: + setupColorButton(hDlg, hDarkEdgeColorButton, controlId, hDarkEdgeColorBitmap, + crDarkEdgeColor); + hDarkEdgeColorReset = GetDlgItem(hDlg, IDC_DARK_EDGE_COLOR_RESET); + darkEdgeColorEnabled = ldPrefs->getDarkEdgeColorEnabled(); + if (getCheck(hDlg, IDC_DARK_EDGE_COLOR_CHECK) != darkEdgeColorEnabled) + setCheck(hDlg, IDC_DARK_EDGE_COLOR_CHECK, darkEdgeColorEnabled); + EnableWindow(hDarkEdgeColorButton, darkEdgeColorEnabled); + EnableWindow(hDarkEdgeColorReset, darkEdgeColorEnabled); + break; + } } void LDViewPreferences::setAniso(int value) @@ -2757,6 +3124,12 @@ void LDViewPreferences::doPrimitivesClick(int controlId, HWND /*controlHWnd*/) EnableWindow(hAnisoLevelSlider, TRUE); } break; + case IDC_STUD_STYLE_USE: + doStudStyle(); + break; + case IDC_HIGH_CONTRAST_COLOR: + doHighContrastColor(); + break; case IDC_PRIMITIVES_RESET: ldPrefs->loadDefaultPrimitivesSettings(false); setupPrimitivesPage(); @@ -2859,6 +3232,12 @@ DWORD LDViewPreferences::doComboSelChange(HWND hPage, int controlId, enableApply(hPage); break; case IDC_MEMORY_COMBO: + enableApply(hPage); + break; + case IDC_STUD_STYLE_COMBO: + ldPrefs->setStudStyle(CUIDialog::comboGetCurSel(hPrimitivesPage, + IDC_STUD_STYLE_COMBO)); + doStudStyle(); enableApply(hPage); break; case IDC_SNAPSHOTS_DIR_COMBO: @@ -3006,6 +3385,20 @@ void LDViewPreferences::doConditionals(void) } } +void LDViewPreferences::doAlwaysBlack(void) +{ + EnableWindow(hAutomateEdgeColorCheck, !getCheck(hGeometryPage, + IDC_ALWAYS_BLACK)); +} + +void LDViewPreferences::doAutomateEdgeColorCheck(void) +{ + EnableWindow(hAutomateEdgeColorButton, getCheck(hGeometryPage, + IDC_AUTOMATE_EDGE_COLOR_CHECK)); + EnableWindow(hAlwaysBlackButton, !getCheck(hGeometryPage, + IDC_AUTOMATE_EDGE_COLOR_CHECK)); +} + void LDViewPreferences::setCheck(HWND hPage, int buttonId, bool value) { CUIDialog::buttonSetChecked(hPage, buttonId, value); @@ -3165,6 +3558,15 @@ void LDViewPreferences::updateTexmapsEnabled(void) void LDViewPreferences::doTextureStuds(void) { updateTextureFilteringEnabled(); + if (getCheck(hPrimitivesPage, IDC_TEXTURE_STUDS)) + { + setCheck(hPrimitivesPage, IDC_STUD_STYLE_USE, FALSE); + disableStudStyle(); + } + else + { + enableStudStyle(); + } } void LDViewPreferences::doTexmaps(void) @@ -3261,6 +3663,63 @@ void LDViewPreferences::setupMemoryUsage(void) CUIDialog::comboSetCurSel(hGeneralPage, IDC_MEMORY_COMBO, ldPrefs->getMemoryUsage()); } +void LDViewPreferences::enableStudStyle(void) +{ + hHighContrastColorButton = GetDlgItem(hPrimitivesPage, IDC_HIGH_CONTRAST_COLOR); + EnableWindow(GetDlgItem(hPrimitivesPage, IDC_STUD_STYLE_USE), TRUE); + EnableWindow(GetDlgItem(hPrimitivesPage, IDC_STUD_STYLE_COMBO), TRUE); + EnableWindow(hHighContrastColorButton, ldPrefs->getStudStyle() > 5); +} + +void LDViewPreferences::disableStudStyle(void) +{ + EnableWindow(GetDlgItem(hPrimitivesPage, IDC_STUD_STYLE_USE), FALSE); + EnableWindow(GetDlgItem(hPrimitivesPage, IDC_STUD_STYLE_COMBO), FALSE); + EnableWindow(GetDlgItem(hPrimitivesPage, IDC_HIGH_CONTRAST_COLOR), FALSE); +} + +void LDViewPreferences::doStudStyle(void) +{ + if (getCheck(hPrimitivesPage, IDC_STUD_STYLE_USE)) + { + setCheck(hPrimitivesPage, IDC_TEXTURE_STUDS, false); + EnableWindow(hTextureStudsButton, FALSE); + disableTextureFiltering(); + } + else + { + setCheck(hPrimitivesPage, IDC_TEXTURE_STUDS, ldPrefs->getTextureStuds()); + EnableWindow(hTextureStudsButton, TRUE); + updateTextureFilteringEnabled(); + } + if (!getCheck(hPrimitivesPage, IDC_TEXTURE_STUDS)) + { + enableStudStyle(); + } + partEdgeLightDarkValue = ldPrefs->getPartColorLDIndex(); + getStudCylinderColor(); + getPartEdgeColor(); + getBlackEdgeColor(); + getDarkEdgeColor(); +} + +void LDViewPreferences::setupStudStyle(void) +{ + CUIDialog::comboResetContent(hPrimitivesPage, IDC_STUD_STYLE_COMBO); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("Plain"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("SingleWire"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("DoubleWire"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("RaisedFlat"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("RaisedRounded"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("SubtleRounded"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("HighContrast"))); + CUIDialog::comboAddString(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ls(_UC("HighContrastSingleWire"))); + CUIDialog::comboSetCurSel(hPrimitivesPage, IDC_STUD_STYLE_COMBO, ldPrefs->getStudStyle()); + + setCheck(hPrimitivesPage, IDC_STUD_STYLE_USE, ldPrefs->getUseStudStyle()); + doStudStyle(); +} + void LDViewPreferences::updateSaveDir( HWND hTextField, HWND hBrowseButton, @@ -3903,9 +4362,11 @@ void LDViewPreferences::enableEdges(void) EnableWindow(hConditionalHighlightsButton, TRUE); EnableWindow(hEdgesOnlyButton, TRUE); EnableWindow(hQualityLinesButton, TRUE); - EnableWindow(hAlwaysBlackButton, TRUE); + EnableWindow(hAlwaysBlackButton, !ldPrefs->getAutomateEdgeColor()); EnableWindow(hEdgeThicknessLabel, TRUE); EnableWindow(hEdgeThicknessSlider, TRUE); + EnableWindow(hAutomateEdgeColorCheck, !ldPrefs->getBlackHighlights()); + EnableWindow(hAutomateEdgeColorButton, ldPrefs->getAutomateEdgeColor()); if (ldPrefs->getDrawConditionalHighlights()) { enableConditionals(); @@ -3914,11 +4375,14 @@ void LDViewPreferences::enableEdges(void) { disableConditionals(); } + setCheck(hGeometryPage, IDC_AUTOMATE_EDGE_COLOR_CHECK, ldPrefs->getAutomateEdgeColor() && + !ldPrefs->getBlackHighlights()); setCheck(hGeometryPage, IDC_EDGES_ONLY, ldPrefs->getEdgesOnly()); setCheck(hGeometryPage, IDC_CONDITIONAL_HIGHLIGHTS, ldPrefs->getDrawConditionalHighlights()); setCheck(hGeometryPage, IDC_QUALITY_LINES, ldPrefs->getUsePolygonOffset()); - setCheck(hGeometryPage, IDC_ALWAYS_BLACK, ldPrefs->getBlackHighlights()); + setCheck(hGeometryPage, IDC_ALWAYS_BLACK, ldPrefs->getBlackHighlights() && + !ldPrefs->getAutomateEdgeColor()); } void LDViewPreferences::disableEdges(void) @@ -3929,6 +4393,8 @@ void LDViewPreferences::disableEdges(void) EnableWindow(hAlwaysBlackButton, FALSE); EnableWindow(hEdgeThicknessLabel, FALSE); EnableWindow(hEdgeThicknessSlider, FALSE); + EnableWindow(hAutomateEdgeColorCheck, FALSE); + EnableWindow(hAutomateEdgeColorButton, FALSE); disableConditionals(); setCheck(hGeometryPage, IDC_EDGES_ONLY, false); setCheck(hGeometryPage, IDC_CONDITIONAL_HIGHLIGHTS, false); @@ -3945,6 +4411,12 @@ void LDViewPreferences::setupEdgeLines(void) hShowAllConditionalButton = GetDlgItem(hGeometryPage, IDC_ALL_CONDITIONAL); hShowConditionalControlsButton = GetDlgItem(hGeometryPage, IDC_CONDITIONAL_CONTROLS); + hAutomateEdgeColorCheck = GetDlgItem(hGeometryPage, + IDC_AUTOMATE_EDGE_COLOR_CHECK); + hAutomateEdgeColorButton = GetDlgItem(hGeometryPage, + IDC_AUTOMATE_EDGE_COLOR); + partEdgeContrastValue = ldPrefs->getPartEdgeContrast(); + partEdgeSaturationValue = ldPrefs->getPartEdgeSaturation(); hEdgesOnlyButton = GetDlgItem(hGeometryPage, IDC_EDGES_ONLY); hQualityLinesButton = GetDlgItem(hGeometryPage, IDC_QUALITY_LINES); hAlwaysBlackButton = GetDlgItem(hGeometryPage, IDC_ALWAYS_BLACK); @@ -4314,6 +4786,16 @@ TCFloat32 LDViewPreferences::anisoFromSliderValue(int value) return (TCFloat32)(1 << value); } +int LDViewPreferences::sliderPosFromStudStyleVal(double value) +{ + return (int)(value * 10); +} + +TCFloat32 LDViewPreferences::studStyleValFromSliderPos(int position) +{ + return (TCFloat32)(position / 10.0f); +} + void LDViewPreferences::setupSubstitution(void) { setupGroupCheckButton(hPrimitivesPage, IDC_PRIMITIVE_SUBSTITUTION, @@ -4372,6 +4854,7 @@ void LDViewPreferences::setupPrimitivesPage(void) hPrimitivesPage = hwndArray->pointerAtIndex(primitivesPageNumber); setupTextures(); setupSubstitution(); + setupStudStyle(); setCheck(hPrimitivesPage, IDC_STUD_QUALITY, !ldPrefs->getQualityStuds()); setCheck(hPrimitivesPage, IDC_HI_RES, ldPrefs->getHiResPrimitives()); } @@ -4687,7 +5170,19 @@ BOOL LDViewPreferences::doDialogInit( CUIPropertySheet::doDialogInit(hDlg, hFocusWindow, lParam); HWND hNewPrefSetField = NULL; HWND hHotKeyCombo = NULL; + HWND hHighContrastStudControl = NULL; + HWND hAutomateEdgeLineControl = NULL; + hHighContrastStudControl = GetDlgItem(hDlg, IDC_LIGHT_DARK_SLIDER); + if (hHighContrastStudControl) + { + return highContrastStudColorInit(hDlg); + } + hAutomateEdgeLineControl = GetDlgItem(hDlg, IDC_CONTRAST_SLIDER); + if (hAutomateEdgeLineControl) + { + return automateEdgeLineColorInit(hDlg); + } hNewPrefSetField = GetDlgItem(hDlg, IDC_NEW_PREF_SET_FIELD); if (hNewPrefSetField) { @@ -5195,7 +5690,9 @@ BOOL LDViewPreferences::doDrawItem(HWND hDlg, int itemId, { HWND hWnd = GetDlgItem(hDlg, itemId); - if (itemId == IDC_DEFAULT_COLOR || itemId == IDC_BACKGROUND_COLOR) + if (itemId == IDC_DEFAULT_COLOR || itemId == IDC_BACKGROUND_COLOR || + itemId == IDC_STUD_CYLINDER_COLOR || itemId == IDC_PART_EDGE_COLOR || + itemId == IDC_BLACK_EDGE_COLOR || itemId == IDC_DARK_EDGE_COLOR) { return doDrawColorButton(hDlg, hWnd, hButtonTheme, drawItemStruct); } diff --git a/LDViewPreferences.h b/LDViewPreferences.h index 18f895134..e94be28ec 100644 --- a/LDViewPreferences.h +++ b/LDViewPreferences.h @@ -71,6 +71,10 @@ class LDViewPreferences: public CUIPropertySheet void setOptionalStandardLight(bool value); COLORREF getBackgroundColor(void); COLORREF getDefaultColor(void); + void getStudCylinderColor(void); + void getPartEdgeColor(void); + void getBlackEdgeColor(void); + void getDarkEdgeColor(void); bool getUseSeams(void); void setUseSeams(bool value); int getSeamWidth(void); @@ -149,12 +153,15 @@ class LDViewPreferences: public CUIPropertySheet virtual void setupColorButton(HWND hPage, HWND &hColorButton, int controlID, HBITMAP &hButtonBitmap, COLORREF color); virtual void setupMemoryUsage(void); + virtual void setupStudStyle(void); virtual void setupFov(bool warn = false); virtual void setupBackgroundColorButton(void); virtual void setupDefaultColorButton(void); virtual void setupSeamWidth(void); virtual void setupFullScreenRefresh(void); virtual void setupSaveDirs(void); + virtual BOOL highContrastStudColorInit(HWND hDlg); + virtual BOOL automateEdgeLineColorInit(HWND hDlg); virtual void updateSaveDir(HWND hTextField, HWND hBrowseButton, LDPreferences::DefaultDirMode dirMode, const ucstring &filename); virtual void setupSaveDir(HWND hComboBox, HWND hTextField, @@ -170,6 +177,15 @@ class LDViewPreferences: public CUIPropertySheet virtual void browseForDir(CUCSTR prompt, HWND hTextField, ucstring &dir); virtual void chooseDefaultColor(void); + virtual void chooseStudCylinderColor(void); + virtual void choosePartEdgeColor(void); + virtual void chooseBlackEdgeColor(void); + virtual void chooseDarkEdgeColor(void); + virtual void doHighContrastColor(void); + virtual void doAutomateEdgeColorCheck(void); + virtual void doAutomateEdgeColor(void); + virtual void doStudStyle(void); + virtual void doAlwaysBlack(void); virtual void doFSRefresh(void); virtual void doStipple(void); virtual void doSort(void); @@ -275,7 +291,11 @@ class LDViewPreferences: public CUIPropertySheet virtual void disableTextureFiltering(void); virtual void enableTexmaps(void); virtual void disableTexmaps(void); + virtual void enableStudStyle(void); + virtual void disableStudStyle(void); virtual void setupOpacitySlider(void); + virtual void setupStudStyleColorButton(HWND hDlg, int controlId); + virtual void setStudStyleSliderValue(HWND hDlg, int controlId); virtual ucstring getPrefSet(int index); virtual ucstring getSelectedPrefSet(void); virtual void selectPrefSet(const ucstring& prefSet = ucstring(), bool force = false); @@ -342,6 +362,8 @@ class LDViewPreferences: public CUIPropertySheet static TCFloat32 textureOffsetFromSliderValue(int value); static int sliderValueFromAniso(double value); static TCFloat32 anisoFromSliderValue(int value); + static int sliderPosFromStudStyleVal(double value); + static TCFloat32 studStyleValFromSliderPos(int position); LDrawModelViewer* modelViewer; LDViewWindow* ldviewWindow; @@ -365,6 +387,25 @@ class LDViewPreferences: public CUIPropertySheet HWND hBackgroundColorButton; HBITMAP hDefaultColorBitmap; HWND hDefaultColorButton; + + // Stud Style and Edge Lines Color Controls + HBITMAP hStudCylinderColorBitmap; + COLORREF crStudCylinderColor; + HWND hStudCylinderColorButton; + HWND hStudCylinderColorReset; + HBITMAP hPartEdgeColorBitmap; + COLORREF crPartEdgeColor; + HWND hPartEdgeColorButton; + HWND hPartEdgeColorReset; + HBITMAP hBlackEdgeColorBitmap; + COLORREF crBlackEdgeColor; + HWND hBlackEdgeColorButton; + HWND hBlackEdgeColorReset; + HBITMAP hDarkEdgeColorBitmap; + COLORREF crDarkEdgeColor; + HWND hDarkEdgeColorButton; + HWND hDarkEdgeColorReset; + HWND hSnapshotDirCombo; HWND hSnapshotDirField; HWND hSnapshotBrowseButton; @@ -458,6 +499,26 @@ class LDViewPreferences: public CUIPropertySheet HWND hNewPrefSetButton; HWND hPrefSetHotKeyButton; + // Stud Style and Edge Lines Controls + HWND hAutomateEdgeColorCheck; + HWND hAutomateEdgeColorButton; + HWND hHighContrastColorButton; + + // Stud Style and Edge Lines Dialogs + HWND hHighContrastStudColor; + HWND hAutomateEdgeLineColor; + + // Stud Style and Edge Lines Color Values + TCFloat partEdgeLightDarkValue; + TCFloat partEdgeContrastValue; + TCFloat partEdgeSaturationValue; + + // Stud Style Color Enabled Checks + bool studCylinderColorEnabled; + bool partEdgeColorEnabled; + bool blackEdgeColorEnabled; + bool darkEdgeColorEnabled; + bool setActiveWarned; bool checkAbandon; diff --git a/MacOSX/LDView/LDView.xcodeproj/xcshareddata/xcschemes/LDView.xcscheme b/MacOSX/LDView/LDView.xcodeproj/xcshareddata/xcschemes/LDView.xcscheme index 1b34d1ec7..96f3bbfbe 100644 --- a/MacOSX/LDView/LDView.xcodeproj/xcshareddata/xcschemes/LDView.xcscheme +++ b/MacOSX/LDView/LDView.xcodeproj/xcshareddata/xcschemes/LDView.xcscheme @@ -50,6 +50,16 @@ ReferencedContainer = "container:LDView.xcodeproj"> + + + + + + #endif // _QT +#include class TCAutoreleasePool; @@ -65,6 +66,10 @@ class TCExport TCObject //#endif static const wchar_t *ls(const wchar_t *key); static const char *lsUtf8(const char *key); + template static void clearValue(T& value) + { + memset(&value, 0, sizeof(value)); + } protected: virtual ~TCObject(void); diff --git a/TCFoundation/mystring.cpp b/TCFoundation/mystring.cpp index 5eb8fab6e..b0289c650 100644 --- a/TCFoundation/mystring.cpp +++ b/TCFoundation/mystring.cpp @@ -1182,6 +1182,25 @@ void stripCRLF(wchar_t* line) } } +void stripLeadingWhitespace(std::string& string) +{ + size_t spot; + + for (spot = 0; string[spot] == ' ' || string[spot] == '\t'; ++spot) + ; + if (string[spot]) + { + if (spot != 0) + { + string.erase(0, spot); + } + } + else + { + string.clear(); + } +} + void stripLeadingWhitespace(char* string) { char *spot; diff --git a/TCFoundation/mystring.h b/TCFoundation/mystring.h index 0ff2bca93..5a8671e36 100644 --- a/TCFoundation/mystring.h +++ b/TCFoundation/mystring.h @@ -156,6 +156,7 @@ TCExport void stripTrailingWhitespace(char*); TCExport void stripTrailingWhitespace(wchar_t*); TCExport void stripLeadingWhitespace(char*); TCExport void stripLeadingWhitespace(wchar_t*); +TCExport void stripLeadingWhitespace(std::string&); TCExport void stripTrailingPathSeparators(char*); TCExport void stripTrailingPathSeparators(wchar_t*); TCExport void replaceStringCharacter(char*, char, char, int = 1);
" - "%s\n", colorInfo.name); + "%s\n", colorInfo.name.c_str()); fprintf(file, "
" "