116    glDisable( GL_CULL_FACE );
 
  120    glClear( GL_DEPTH_BUFFER_BIT );
 
  122    glMatrixMode( GL_PROJECTION );
 
  127    glMatrixMode( GL_MODELVIEW );
 
  130    glm::mat4 TranslationMatrix = glm::translate( glm::mat4( 1.0f ), 
SFVEC3F( 0.0f, 0.0f, -( 
m_arrowSize * 2.75f ) ) );
 
  131    glm::mat4 ViewMatrix = TranslationMatrix * aCameraRotationMatrix;
 
  132    glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
 
  137    glm::mat4 proj = glm::perspective( glm::radians( fov ), 1.0f, 0.001f, 2.0f * 
RANGE_SCALE_3D );
 
  138    glm::mat4 invVP = glm::inverse( proj * ViewMatrix );
 
  143    glm::vec4 rayStartWorld = invVP * rayStartNDC;
 
  144    rayStartWorld /= rayStartWorld.w;
 
  146    glm::vec4 rayEndWorld = invVP * rayEndNDC;
 
  147    rayEndWorld /= rayEndWorld.w;
 
  149    glm::vec3 rayOrigin = glm::vec3( rayStartWorld );
 
  150    glm::vec3 rayDirection = glm::normalize( glm::vec3( rayEndWorld - rayStartWorld ) );
 
  153            []( 
const glm::vec3& aRayOrigin, 
const glm::vec3& aRayDir, 
const glm::vec3& aSphereCenter, 
float aRadius )
 
  155        glm::vec3 
L = aSphereCenter - aRayOrigin;
 
  156        float     tca = glm::dot( 
L, aRayDir );
 
  157        float     d2 = glm::dot( 
L, 
L ) - tca * tca;
 
  158        return d2 <= aRadius * aRadius;
 
  161    int clickedIndex = -1;
 
  163    for( 
size_t i = 0; i < 
m_spheres.size(); ++i )
 
  166        if( intersects( rayOrigin, rayDirection, sphere.m_position, sphere.m_radius ) )
 
  168            clickedIndex = 
static_cast<int>( i );
 
  176    for( 
size_t i = 0; i < 
m_spheres.size(); ++i )
 
  178        if( 
static_cast<int>( i ) == clickedIndex )
 
  180            m_spheres[i].m_color = { 1.0f, 1.0f, 1.0f }; 
 
  190    auto drawBillboardCircle =
 
  191            []( 
const glm::vec3& aCenter, 
float aRadius, 
const glm::vec3& aColor,
 
  192                const glm::vec3& aCamRight, 
const glm::vec3& aCamUp, 
int aSegments = 64 )
 
  194                float thickness = aRadius * 0.4f;
 
  195                glColor3f( aColor.r, aColor.g, aColor.b );
 
  197                glBegin( GL_TRIANGLE_STRIP );
 
  198                for( 
int i = 0; i <= aSegments; ++i )
 
  200                    float     angle = 2.0f * glm::pi<float>() * i / aSegments;
 
  201                    glm::vec3 dir = cos( angle ) * aCamRight + sin( angle ) * aCamUp;
 
  203                    glm::vec3 outer = aCenter + dir * ( aRadius + thickness * 0.5f );
 
  204                    glm::vec3 inner = aCenter + dir * ( aRadius - thickness * 0.5f );
 
  206                    glVertex3f( outer.x, outer.y, outer.z );
 
  207                    glVertex3f( inner.x, inner.y, inner.z );
 
  212    glm::vec3 camRight( aCameraRotationMatrix[0][0], aCameraRotationMatrix[1][0], aCameraRotationMatrix[2][0] );
 
  213    glm::vec3 camUp( aCameraRotationMatrix[0][1], aCameraRotationMatrix[1][1], aCameraRotationMatrix[2][1] );
 
  215    glEnable( GL_BLEND );
 
  216    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 
  220        glColor4f( sphere.m_color.r, sphere.m_color.g, sphere.m_color.b, 0.3f );
 
  222        glTranslatef( sphere.m_position.x, sphere.m_position.y, sphere.m_position.z );
 
  225            gluSphere( 
m_quadric, sphere.m_radius, 32, 32 );
 
  229        drawBillboardCircle( sphere.m_position, sphere.m_radius, sphere.m_color, camRight, camUp );
 
  234    glDisable( GL_DEPTH_TEST );
 
  235    glDisable( GL_LIGHTING );
 
  237    std::array<std::string, 6> labels = { 
"X", 
"", 
"Y", 
"", 
"Z", 
"" };
 
  241    glm::vec3 offset = glm::normalize( -rayDirection ) * 0.02f;
 
  243    glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
 
  246            []( 
const glm::vec3& aPos, 
float aSize, 
const glm::vec3& aColor, 
const glm::vec3& aCamRight,
 
  247                const glm::vec3& aCamUp )
 
  249                glColor3f( aColor.r, aColor.g, aColor.b );
 
  252                float h = aSize * 0.5f;
 
  255                glm::vec3 dir1 = ( -aCamRight + aCamUp ) * h; 
 
  256                glm::vec3 dir2 = ( -aCamRight - aCamUp ) * h; 
 
  259                glVertex3f( ( aPos - dir1 ).x, ( aPos - dir1 ).y, ( aPos - dir1 ).z );
 
  260                glVertex3f( ( aPos + dir1 ).x, ( aPos + dir1 ).y, ( aPos + dir1 ).z );
 
  262                glVertex3f( ( aPos - dir2 ).x, ( aPos - dir2 ).y, ( aPos - dir2 ).z );
 
  263                glVertex3f( ( aPos + dir2 ).x, ( aPos + dir2 ).y, ( aPos + dir2 ).z );
 
  268            []( 
const glm::vec3& aPos, 
float aSize, 
const glm::vec3& aColor, 
const glm::vec3& aCamRight,
 
  269                const glm::vec3& aCamUp )
 
  271                glColor3f( aColor.r, aColor.g, aColor.b );
 
  274                float h = aSize * 0.5f;
 
  277                glm::vec3 topLeft = aPos + aCamUp * h - aCamRight * h;
 
  278                glm::vec3 topRight = aPos + aCamUp * h + aCamRight * h;
 
  279                glm::vec3 bottom = aPos - aCamUp * h;
 
  282                glVertex3f( topLeft.x, topLeft.y, topLeft.z );
 
  283                glVertex3f( aPos.x, aPos.y, aPos.z );
 
  285                glVertex3f( topRight.x, topRight.y, topRight.z );
 
  286                glVertex3f( aPos.x, aPos.y, aPos.z );
 
  288                glVertex3f( aPos.x, aPos.y, aPos.z );
 
  289                glVertex3f( bottom.x, bottom.y, bottom.z );
 
  294            []( 
const glm::vec3& aPos, 
float aSize, 
const glm::vec3& aColor, 
const glm::vec3& aCamRight,
 
  295                const glm::vec3& aCamUp )
 
  297                glColor3f( aColor.r, aColor.g, aColor.b );
 
  300                float h = aSize * 0.5f;
 
  303                glm::vec3 topLeft = aPos + aCamUp * h - aCamRight * h;
 
  304                glm::vec3 topRight = aPos + aCamUp * h + aCamRight * h;
 
  305                glm::vec3 bottomLeft = aPos - aCamUp * h - aCamRight * h;
 
  306                glm::vec3 bottomRight = aPos - aCamUp * h + aCamRight * h;
 
  308                glBegin( GL_LINE_STRIP );
 
  309                glVertex3f( topLeft.x, topLeft.y, topLeft.z );
 
  310                glVertex3f( topRight.x, topRight.y, topRight.z );
 
  311                glVertex3f( bottomLeft.x, bottomLeft.y, bottomLeft.z );
 
  312                glVertex3f( bottomRight.x, bottomRight.y, bottomRight.z );
 
  316    for( 
size_t i = 0; i < 
m_spheres.size(); ++i )
 
  318        if( labels[i].
empty() )
 
  321        glm::vec3          textPos = 
m_spheres[i].m_position + offset;
 
  322        const std::string& label = labels[i];
 
  326            drawX( textPos, 0.30f, glm::vec3( 0.0f ), camRight, camUp );
 
  328        else if( label == 
"Y" )
 
  330            drawY( textPos, 0.30f, glm::vec3( 0.0f ), camRight, camUp );
 
  332        else if( label == 
"Z" )
 
  334            drawZ( textPos, 0.30f, glm::vec3( 0.0f ), camRight, camUp );
 
  338    glEnable( GL_LIGHTING );
 
  339    glEnable( GL_DEPTH_TEST );
 
  345    glColor3f( 0.9f, 0.0f, 0.0f ); 
 
  346    glVertex3f( 0.0f, 0.0f, 0.0f );
 
  349    glColor3f( 0.0f, 0.9f, 0.0f ); 
 
  350    glVertex3f( 0.0f, 0.0f, 0.0f );
 
  353    glColor3f( 0.0f, 0.0f, 0.9f ); 
 
  354    glVertex3f( 0.0f, 0.0f, 0.0f );
 
  359    glEnable( GL_CULL_FACE );