From 3992cc547b723518abf01ed6a9a38a7773032d59 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Sun, 30 Nov 2014 02:29:29 +0100 Subject: [PATCH] Update drawing logic (fixes #1035). - Draw negative part of the axis with stippled lines - Calculate contrast color for axis based on background color - Disable lighting for axis / crosshair --- src/GLView.cc | 58 ++++++++++++++++++++++++++++-------------------- src/GLView.h | 8 +++---- src/colormap.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ src/colormap.h | 2 ++ 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/GLView.cc b/src/GLView.cc index 7ca5a480..fdc668b8 100644 --- a/src/GLView.cc +++ b/src/GLView.cc @@ -150,18 +150,20 @@ void GLView::setupCamera() void GLView::paintGL() { - glEnable(GL_LIGHTING); + glDisable(GL_LIGHTING); - setupCamera(); + setupCamera(); Color4f bgcol = ColorMap::getColor(*this->colorscheme, BACKGROUND_COLOR); + Color4f bgcontrast = ColorMap::getContrastColor(bgcol); glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // Only for GIMBAL cam + // Only for GIMBAL cam if (showcrosshairs) GLView::showCrosshairs(); - if (showaxes) GLView::showAxes(); + if (showaxes) GLView::showAxes(bgcontrast); + glEnable(GL_LIGHTING); glDepthFunc(GL_LESS); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); @@ -174,10 +176,11 @@ void GLView::paintGL() OpenCSG::setContext(this->opencsg_id); #endif this->renderer->draw(showfaces, showedges); - } + } // Only for GIMBAL - if (showaxes) GLView::showSmallaxes(); + glDisable(GL_LIGHTING); + if (showaxes) GLView::showSmallaxes(bgcontrast); } #ifdef ENABLE_OPENCSG @@ -348,6 +351,7 @@ void GLView::initializeGL() glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); glEnable(GL_NORMALIZE); + glEnable(GL_LINE_STIPPLE); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); // The following line is reported to fix issue #71 @@ -358,7 +362,7 @@ void GLView::initializeGL() #endif } -void GLView::showSmallaxes() +void GLView::showSmallaxes(const Color4f &col) { // Fixme - this doesnt work in Vector Camera mode @@ -423,14 +427,9 @@ void GLView::showSmallaxes() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - // FIXME: This was an attempt to keep contrast with background, but is suboptimal - // (e.g. nearly invisible against a gray background). - // int r,g,b; - // r=g=b=0; - // bgcol.getRgb(&r, &g, &b); - // glColor3f((255.0f-r)/255.0f, (255.0f-g)/255.0f, (255.0f-b)/255.0f); - float d = 3*dpi; - glColor3f(0.0f, 0.0f, 0.0f); + glColor3f(col[0], col[1], col[2]); + + float d = 3*dpi; glBegin(GL_LINES); // X Label glVertex3d(xlabel_x-d, xlabel_y-d, 0); glVertex3d(xlabel_x+d, xlabel_y+d, 0); @@ -447,29 +446,40 @@ void GLView::showSmallaxes() glEnd(); } -void GLView::showAxes() +void GLView::showAxes(const Color4f &col) { + double l = cam.projection == Camera::PERSPECTIVE ? cam.viewer_distance : cam.height; + // FIXME: doesn't work under Vector Camera // Large gray axis cross inline with the model - // FIXME: This is always gray - adjust color to keep contrast with background glLineWidth(this->getDPI()); - glColor3d(0.5, 0.5, 0.5); + glColor3f(col[0], col[1], col[2]); + glBegin(GL_LINES); - double l = cam.projection == Camera::PERSPECTIVE ? cam.viewer_distance : cam.height; - glVertex3d(-l, 0, 0); + glVertex3d(0, 0, 0); glVertex3d(+l, 0, 0); - glVertex3d(0, -l, 0); + glVertex3d(0, 0, 0); glVertex3d(0, +l, 0); - glVertex3d(0, 0, -l); + glVertex3d(0, 0, 0); glVertex3d(0, 0, +l); glEnd(); + + glPushAttrib(GL_LINE_BIT); + glLineStipple(3, 0xAAAA); + glBegin(GL_LINES); + glVertex3d(0, 0, 0); + glVertex3d(-l, 0, 0); + glVertex3d(0, 0, 0); + glVertex3d(0, -l, 0); + glVertex3d(0, 0, 0); + glVertex3d(0, 0, -l); + glEnd(); + glPopAttrib(); } void GLView::showCrosshairs() { // FIXME: this might not work with Vector camera - // FIXME: Crosshairs and axes are lighted, this doesn't make sense and causes them - // to change color based on view orientation. glLineWidth(3); Color4f col = ColorMap::getColor(*this->colorscheme, CROSSHAIR_COLOR); glColor3f(col[0], col[1], col[2]); diff --git a/src/GLView.h b/src/GLView.h index f3f98ae2..5e3e4c53 100644 --- a/src/GLView.h +++ b/src/GLView.h @@ -42,10 +42,6 @@ public: void setCamera(const Camera &cam); void setupCamera(); - void showCrosshairs(); - void showAxes(); - void showSmallaxes(); - void setColorScheme(const ColorScheme &cs); void setColorScheme(const std::string &cs); void updateColorScheme(); @@ -76,4 +72,8 @@ public: bool opencsg_support; int opencsg_id; #endif +private: + void showCrosshairs(); + void showAxes(const Color4f &col); + void showSmallaxes(const Color4f &col); }; diff --git a/src/colormap.cc b/src/colormap.cc index e4ccda14..026c21fe 100644 --- a/src/colormap.cc +++ b/src/colormap.cc @@ -5,6 +5,29 @@ static const char *DEFAULT_COLOR_SCHEME_NAME = "Cornfield"; +// See http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +static void rgbtohsv(float r, float g, float b, float &h, float &s, float &v) +{ + float K = 0.f; + + if (g < b) + { + std::swap(g, b); + K = -1.f; + } + + if (r < g) + { + std::swap(r, g); + K = -2.f / 6.f - K; + } + + float chroma = r - std::min(g, b); + h = fabs(K + (g - b) / (6.f * chroma + 1e-20f)); + s = chroma / (r + 1e-20f); + v = r; +} + RenderColorScheme::RenderColorScheme() : _path("") { _name = DEFAULT_COLOR_SCHEME_NAME; @@ -196,6 +219,42 @@ Color4f ColorMap::getColor(const ColorScheme &cs, const RenderColor rc) return Color4f(0, 0, 0, 127); } +Color4f ColorMap::getColorHSV(const Color4f &col) +{ + float h, s, v; + rgbtohsv(col[0], col[1], col[2], h, s, v); + return Color4f(h, s, v, col[3]); +} + +/** + * Calculate contrast color. Based on the article + * http://gamedev.stackexchange.com/questions/38536/given-a-rgb-color-x-how-to-find-the-most-contrasting-color-y + * + * @param col the input color + * @return a color with high contrast to the input color + */ +Color4f ColorMap::getContrastColor(const Color4f &col) +{ + Color4f hsv = ColorMap::getColorHSV(col); + float Y = 0.2126 * col[0] + 0.7152 * col[1] + 0.0722 * col[2]; + float S = hsv[1]; + + if (S < 0.5) { + // low saturation, choose between black / white based on luminance Y + float val = Y > 0.5 ? 0.0f : 1.0f; + return Color4f(val, val, val, 1.0f); + } else { + float H = 360 * hsv[0]; + if ((H < 60) || (H > 300)) { + return Color4f(0.0f, 1.0f, 1.0f, 1.0f); // red -> cyan + } else if (H < 180) { + return Color4f(1.0f, 0.0f, 1.0f, 1.0f); // green -> magenta + } else { + return Color4f(1.0f, 1.0f, 0.0f, 1.0f); // blue -> yellow + } + } +} + void ColorMap::enumerateColorSchemesInPath(colorscheme_set_t &result_set, const fs::path basePath) { const fs::path color_schemes = basePath / "color-schemes" / "render"; diff --git a/src/colormap.h b/src/colormap.h index 883932fc..0f8bc545 100644 --- a/src/colormap.h +++ b/src/colormap.h @@ -79,6 +79,8 @@ public: std::list colorSchemeNames(bool guiOnly = false) const; static Color4f getColor(const ColorScheme &cs, const RenderColor rc); + static Color4f getContrastColor(const Color4f &col); + static Color4f getColorHSV(const Color4f &col); private: ColorMap();