Index: celengine/location.cpp =================================================================== --- celengine/location.cpp (revision 4328) +++ celengine/location.cpp (working copy) @@ -183,6 +183,9 @@ } +/*! Get the position of the location relative to its body in + * the J2000 ecliptic coordinate system. + */ Point3d Location::getPlanetocentricPosition(double t) const { if (parent == NULL) Index: celengine/marker.h =================================================================== --- celengine/marker.h (revision 4328) +++ celengine/marker.h (working copy) @@ -1,6 +1,6 @@ // marker.h // -// Copyright (C) 2003, Chris Laurel +// Copyright (C) 2003-2008, Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -17,25 +17,9 @@ #include - -class Marker +class MarkerRepresentation { - public: - Marker(const Selection&); - ~Marker(); - - UniversalCoord getPosition(double jd) const; - Selection getObject() const; - - Color getColor() const; - void setColor(Color); - float getSize() const; - void setSize(float); - int getPriority() const; - void setPriority(int); - bool isOccludable() const; - void setOccludable(bool); - +public: enum Symbol { Diamond = 0, @@ -49,25 +33,66 @@ UpArrow = 8, DownArrow = 9, Circle = 10, - Disk = 11 - }; + Disk = 11 + }; + + MarkerRepresentation(Symbol symbol = MarkerRepresentation::Diamond, + float size = 10.0f, + Color color = Color::White, + const std::string& label = "") : + m_symbol(symbol), + m_size(size), + m_color(color), + m_label(label) + { + } + + MarkerRepresentation(const MarkerRepresentation& rep); + + MarkerRepresentation& operator=(const MarkerRepresentation& rep); + + Color color() const { return m_color; } + void setColor(Color); + float size() const { return m_size; } + void setSize(float size); + string label() const { return m_label; } + void setLabel(const std::string&); + + void render(float size) const; + +private: + Symbol m_symbol; + float m_size; + Color m_color; + string m_label; +}; - Symbol getSymbol() const; - void setSymbol(Symbol); - string getLabel() const; - void setLabel(string); +class Marker +{ + public: + Marker(const Selection&); + ~Marker(); + UniversalCoord position(double jd) const; + Selection object() const; + + int priority() const; + void setPriority(int); + bool occludable() const; + void setOccludable(bool); + + const MarkerRepresentation& representation() const { return m_representation; } + MarkerRepresentation& representation() { return m_representation; } + void setRepresentation(const MarkerRepresentation& rep); + void render() const; private: - Selection obj; - float size; - Color color; - int priority; - Symbol symbol; - string label; - bool occludable; + Selection m_object; + int m_priority; + MarkerRepresentation m_representation; + bool m_occludable; }; typedef std::vector MarkerList; Index: celengine/universe.h =================================================================== --- celengine/universe.h (revision 4328) +++ celengine/universe.h (working copy) @@ -99,11 +99,8 @@ std::vector& stars) const; void markObject(const Selection&, - float size, - Color color, - Marker::Symbol symbol, + const MarkerRepresentation& rep, int priority, - string label, bool occludable = true); void unmarkObject(const Selection&, int priority); void unmarkAll(); Index: celengine/simulation.cpp =================================================================== --- celengine/simulation.cpp (revision 4328) +++ celengine/simulation.cpp (working copy) @@ -149,12 +149,12 @@ { universe->unmarkObject(selection, 0); selection = sel; - universe->markObject(selection, - 10.0f, - Color(1.0f, 0.0f, 0.0f, 0.9f), - Marker::Diamond, - 0, - ""); + + MarkerRepresentation markerRep(MarkerRepresentation::Diamond); + markerRep.setSize(10.0f); + markerRep.setColor(Color(1.0f, 0.0f, 0.0f, 0.9f)); + + universe->markObject(selection, markerRep, 0); } } Index: celengine/render.h =================================================================== --- celengine/render.h (revision 4328) +++ celengine/render.h (working copy) @@ -228,22 +228,22 @@ struct Annotation { char labelText[MaxLabelLength]; - const Marker* marker; + const MarkerRepresentation* markerRep; Color color; Point3f position; bool operator<(const Annotation&) const; }; - void addForegroundAnnotation(const Marker*, const std::string& labelText, Color, const Point3f&, float depth = -1); - void addBackgroundAnnotation(const Marker*, const std::string& labelText, Color, const Point3f&, float depth = -1); + void addForegroundAnnotation(const MarkerRepresentation* markerRep, const std::string& labelText, Color, const Point3f&, float depth = -1); + void addBackgroundAnnotation(const MarkerRepresentation* markerRep, const std::string& labelText, Color, const Point3f&, float depth = -1); void addBackgroundAnnotation(const std::string& labelText, Color, const Point3f&, float depth = -1); - void addSortedAnnotation(const Marker* marker, const std::string& labelText, Color, const Point3f&); + void addSortedAnnotation(const MarkerRepresentation* markerRep, const std::string& labelText, Color, const Point3f&); // Callbacks for renderables; these belong in a special renderer interface // only visible in object's render methods. void beginObjectAnnotations(); - void addObjectAnnotation(const Marker*, const std::string& labelText, Color, const Point3f&); + void addObjectAnnotation(const MarkerRepresentation* markerRep, const std::string& labelText, Color, const Point3f&); void endObjectAnnotations(); Quatf getCameraOrientation() const; float getNearPlaneDistance() const; @@ -303,8 +303,7 @@ radius(1.0f), semiAxes(1.0f, 1.0f, 1.0f), model(InvalidResource), - orientation(1.0f), - locations(NULL) + orientation(1.0f) {}; Surface* surface; @@ -315,7 +314,6 @@ ResourceHandle model; Quatf orientation; std::vector* eclipseShadows; - std::vector* locations; }; class StarVertexBuffer @@ -526,11 +524,9 @@ float fade, bool lit); - void renderLocations(const vector& locations, - const Quatf& cameraOrientation, - const Point3d& bodyPosition, - const Quatd& bodyOrientation, - float scale); + void renderLocations(const Body& body, + const Vec3d& bodyPosition, + const Quatd& bodyOrientation); // Render an item from the render list void renderItem(const RenderListEntry& rle, @@ -552,7 +548,7 @@ void addAnnotation(std::vector&, - const Marker*, + const MarkerRepresentation*, const std::string& labelText, Color, const Point3f&, @@ -572,7 +568,7 @@ void renderMarkers(const MarkerList&, const UniversalCoord& cameraPosition, - const Quatd& cameraOrientation, + const Quatd& cameraOrientation, double jd); void renderOrbit(const OrbitPathListEntry&, @@ -729,6 +725,13 @@ // True if we're in between a begin/endObjectAnnotations bool objectAnnotationSetOpen; + + // Location markers + MarkerRepresentation mountainRep; + MarkerRepresentation craterRep; + MarkerRepresentation observatoryRep; + MarkerRepresentation cityRep; + MarkerRepresentation genericLocationRep; std::list watchers; Index: celengine/render.cpp =================================================================== --- celengine/render.cpp (revision 4328) +++ celengine/render.cpp (working copy) @@ -234,6 +234,7 @@ Color Renderer::PlanetographicGridColor (0.8f, 0.8f, 0.8f); Color Renderer::PlanetEquatorColor (0.5f, 1.0f, 1.0f); + // Some useful unit conversions inline float mmToInches(float mm) { @@ -1230,7 +1231,7 @@ void Renderer::addAnnotation(vector& annotations, - const Marker* marker, + const MarkerRepresentation* markerRep, const string& labelText, Color color, const Point3f& pos, @@ -1253,14 +1254,15 @@ { Annotation a; - if (marker == NULL) + a.labelText[0] = '\0'; + if (markerRep == NULL) { ReplaceGreekLetterAbbr(a.labelText, MaxLabelLength, labelText.c_str(), labelText.length()); // Might be nice to use abbreviations instead of Greek letters // strncpy(l.text, text, MaxLabelLength); a.labelText[MaxLabelLength - 1] = '\0'; } - a.marker = marker; + a.markerRep = markerRep; a.color = color; a.position = Point3f((float) winX, (float) winY, -depth); annotations.push_back(a); @@ -1268,23 +1270,23 @@ } -void Renderer::addForegroundAnnotation(const Marker* marker, +void Renderer::addForegroundAnnotation(const MarkerRepresentation* markerRep, const string& labelText, Color color, const Point3f& pos, float depth) { - addAnnotation(foregroundAnnotations, marker, labelText, color, pos, depth); + addAnnotation(foregroundAnnotations, markerRep, labelText, color, pos, depth); } -void Renderer::addBackgroundAnnotation(const Marker* marker, +void Renderer::addBackgroundAnnotation(const MarkerRepresentation* markerRep, const string& labelText, Color color, const Point3f& pos, float depth) { - addAnnotation(backgroundAnnotations, marker, labelText, color, pos, depth); + addAnnotation(backgroundAnnotations, markerRep, labelText, color, pos, depth); } @@ -1297,7 +1299,7 @@ } -void Renderer::addSortedAnnotation(const Marker* marker, const string& labelText, Color color, const Point3f& pos) +void Renderer::addSortedAnnotation(const MarkerRepresentation* markerRep, const string& labelText, Color color, const Point3f& pos) { double winX, winY, winZ; int view[4] = { 0, 0, 0, 0 }; @@ -1316,13 +1318,14 @@ { Annotation a; - if (marker == NULL) + a.labelText[0] = '\0'; + if (markerRep == NULL) { //l.text = ReplaceGreekLetterAbbr(_(text.c_str())); strncpy(a.labelText, labelText.c_str(), MaxLabelLength); a.labelText[MaxLabelLength - 1] = '\0'; } - a.marker = marker; + a.markerRep = markerRep; a.color = color; a.position = Point3f((float) winX, (float) winY, -depth); depthSortedAnnotations.push_back(a); @@ -1385,7 +1388,7 @@ } -void Renderer::addObjectAnnotation(const Marker* marker, +void Renderer::addObjectAnnotation(const MarkerRepresentation* markerRep, const string& labelText, Color color, const Point3f& pos) @@ -1411,12 +1414,13 @@ Annotation a; - if (marker == NULL) + a.labelText[0] = '\0'; + if (!labelText.empty()) { strncpy(a.labelText, labelText.c_str(), MaxLabelLength); a.labelText[MaxLabelLength - 1] = '\0'; } - a.marker = marker; + a.markerRep = markerRep; a.color = color; a.position = Point3f((float) winX, (float) winY, -depth); @@ -6772,164 +6776,115 @@ } -void Renderer::renderLocations(const vector& locations, - const Quatf& cameraOrientation, - const Point3d& bodyPosition, - const Quatd& bodyOrientation, - float scale) +void Renderer::renderLocations(const Body& body, + const Vec3d& bodyPosition, + const Quatd& bodyOrientation) { - if (font[FontNormal] == NULL) + const vector* locations = body.getLocations(); + if (locations == NULL) return; + + Vec3f semiAxes = body.getSemiAxes(); + + float nearDist = getNearPlaneDistance(); + double boundingRadius = max(semiAxes.x, max(semiAxes.y, semiAxes.z)); - double winX, winY, winZ; - int view[4] = { 0, 0, 0, 0 }; - view[0] = -windowWidth / 2; - view[1] = -windowHeight / 2; - view[2] = windowWidth; - view[3] = windowHeight; + Vec3d bodyCenter(bodyPosition.x, bodyPosition.y, bodyPosition.z); + Vec3d viewRayOrigin = -bodyCenter * (~bodyOrientation).toMatrix3(); + double labelOffset = 0.0001; - Vec3f viewNormal = Vec3f(0.0f, 0.0f, -1.0f) * - cameraOrientation.toMatrix3(); - Vec3d viewNormald = Vec3d(viewNormal.x, viewNormal.y, viewNormal.z); - - double modelview[16]; - double projection[16]; - glGetDoublev(GL_PROJECTION_MATRIX, projection); - - // Get the camera matrix GL-style for gluProject + Vec3f vn = Vec3f(0.0f, 0.0f, -1.0f) * getCameraOrientation().toMatrix3(); + Vec3d viewNormal(vn.x, vn.y, vn.z); + + Ellipsoidd bodyEllipsoid(Vec3d(semiAxes.x, semiAxes.y, semiAxes.z)); + + Mat3d bodyMatrix = bodyOrientation.toMatrix3(); + + for (vector::const_iterator iter = locations->begin(); + iter != locations->end(); iter++) { - Mat3f cameraMatrix = cameraOrientation.toMatrix3(); - modelview[0] = cameraMatrix[0][0]; - modelview[1] = cameraMatrix[1][0]; - modelview[2] = cameraMatrix[2][0]; - modelview[3] = 0.0f; - modelview[4] = cameraMatrix[0][1]; - modelview[5] = cameraMatrix[1][1]; - modelview[6] = cameraMatrix[2][1]; - modelview[7] = 0.0f; - modelview[8] = cameraMatrix[0][2]; - modelview[9] = cameraMatrix[1][2]; - modelview[10] = cameraMatrix[2][2]; - modelview[11] = 0.0; - modelview[12] = 0.0; - modelview[13] = 0.0; - modelview[14] = 0.0; - modelview[15] = 1.0; - } - -#ifdef USE_HDR - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); -#endif - glEnable(GL_DEPTH_TEST); - glEnable(GL_TEXTURE_2D); - font[FontNormal]->bind(); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_LIGHTING); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0, windowWidth, 0, windowHeight, 1.0f, -1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - // Render the labels very close to the near plane with z=-0.999f. In fact, - // z=-1.0f should work, but I'm concerned that some OpenGL implementations - // might clip things placed right on the near plane. - glTranslatef(GLfloat((int) (windowWidth / 2)), - GLfloat((int) (windowHeight / 2)), -0.999f); - - Point3d origin(0.0, 0.0, 0.0); - - Ellipsoidd ellipsoid(bodyPosition, Vec3d(scale, scale, scale)); - - //float iScale = 1.0f / scale; - Mat3d mat = bodyOrientation.toMatrix3(); - - for (vector::const_iterator iter = locations.begin(); - iter != locations.end(); iter++) - { - if ((*iter)->getFeatureType() & locationFilter) + const Location& location = **iter; + + if (location.getFeatureType() & locationFilter) { - // Get the position of the annotation with respect to the planet center - Vec3f ppos = (*iter)->getPosition(); - - // Compute the body-centric position of the location - Vec3d locPos = Vec3d(ppos.x, ppos.y, ppos.z) * mat; - - // Get the position in camera space. Add a slight scale factor + // Get the position of the location with respect to the planet center + Vec3f ppos = location.getPosition(); + + // Compute the bodycentric position of the location + Vec3d locPos = Vec3d(ppos.x, ppos.y, ppos.z); + + // Get the planetocentric position of the label. Add a slight scale factor // to keep the point from being exactly on the surface. - Point3d cpos(bodyPosition + locPos * 1.0000001); - - float effSize = (*iter)->getImportance(); + Vec3d pcLabelPos = locPos * (1.0 + labelOffset); + + // Get the camera space label position + Vec3d labelPos = bodyCenter + locPos * bodyMatrix; + + float effSize = location.getImportance(); if (effSize < 0.0f) - effSize = (*iter)->getSize(); - - float pixSize = effSize / (float) (cpos.distanceFromOrigin() * pixelSize); - - if (pixSize > minFeatureSize && (cpos - origin) * viewNormald > 0.0) + effSize = location.getSize(); + + float pixSize = effSize / (float) (labelPos.length() * pixelSize); + + if (pixSize > minFeatureSize && labelPos * viewNormal > 0.0) { - double r = locPos.length(); - if (r < scale * 0.99) - cpos = bodyPosition + locPos * (scale * 1.01 / r); - - double t = 0.0f; - + // Labels on non-ellipsoidal bodies need special handling; the + // ellipsoid visibility test will always fail for them, since they + // will lie on the surface of the mesh, which is inside the + // the bounding ellipsoid. The following code projects location positions + // onto the bounding sphere. + if (!body.isEllipsoid()) + { + double r = locPos.length(); + if (r < boundingRadius) + pcLabelPos = locPos * (boundingRadius * 1.01 / r); + } + + double t = 0.0; + // Test for an intersection of the eye-to-location ray with // the planet ellipsoid. If we hit the planet first, then // the label is obscured by the planet. An exact calculation // for irregular objects would be too expensive, and the // ellipsoid approximation works reasonably well for them. - bool hit = testIntersection(Ray3d(origin, cpos - origin), - ellipsoid, t); - if (!hit || t >= 1.0) - { - if (gluProject(bodyPosition.x + locPos.x, - bodyPosition.y + locPos.y, - bodyPosition.z + locPos.z, - modelview, - projection, - (const GLint*) view, - &winX, &winY, &winZ) != GL_FALSE) - { - glColor(LocationLabelColor); - glPushMatrix(); - glTranslatef((int) winX + PixelOffset, - (int) winY + PixelOffset, - 0.0f); -#ifdef USE_HDR - glPushMatrix(); -#endif - font[FontNormal]->render((*iter)->getName(true)); -#ifdef USE_HDR - glPopMatrix(); - // Write black alpha for glyphs to prevent inclusion in - // post processing steps (bloom, etc) - // TODO: This should be done when loading the font - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - font[FontNormal]->render((*iter)->getName(true)); -#endif -#ifdef USE_HDR - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -#endif - glPopMatrix(); - } + Ray3d testRay(Point3d(viewRayOrigin.x, viewRayOrigin.y, viewRayOrigin.z), + pcLabelPos - viewRayOrigin); + bool hit = testIntersection(testRay, bodyEllipsoid, t); + Vec3d blah = labelPos - viewRayOrigin; + + if (hit) + clog << "hit: " << location.getName(true) << ", t=" << t << endl; + if (hit && t >= 1.0) + { + // Calculate the intersection of the eye-to-label ray with the plane perpendicular to + // the view normal that touches the front of the object's bounding sphere + double planetZ = viewNormal * bodyCenter - boundingRadius; + if (planetZ < -nearDist * 1.001) + planetZ = -nearDist * 1.001; + double z = viewNormal * labelPos; + labelPos *= planetZ / z; + + uint32 featureType = location.getFeatureType(); + MarkerRepresentation* locationMarker = NULL; + if (featureType & Location::City) + locationMarker = &cityRep; + else if (featureType & (Location::LandingSite | Location::Observatory)) + locationMarker = &observatoryRep; + else if (featureType & Location::Crater) + locationMarker = &craterRep; + else if (featureType & (Location::Mons)) + locationMarker = &mountainRep; + else if (featureType & (Location::Patera | Location::Mensa | Location::Other)) + locationMarker = &genericLocationRep; + + addObjectAnnotation(locationMarker, + location.getName(true), + LocationLabelColor, + Point3f((float) labelPos.x, (float) labelPos.y, (float) labelPos.z)); } } } - } - - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); -#ifdef USE_HDR - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -#endif + } } @@ -7884,8 +7839,7 @@ rp.orientation = body.getOrientation() * Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z); - rp.locations = body.getLocations(); - if (rp.locations != NULL && (labelMode & LocationLabels) != 0) + if (body.getLocations() != NULL && (labelMode & LocationLabels) != 0) body.computeLocations(); LightingState lights; @@ -7989,19 +7943,22 @@ if (body.getLocations() != NULL && (labelMode & LocationLabels) != 0) { + // Set up location markers for this body + mountainRep = MarkerRepresentation(MarkerRepresentation::Triangle, 8.0f, LocationLabelColor); + craterRep = MarkerRepresentation(MarkerRepresentation::Circle, 8.0f, LocationLabelColor); + observatoryRep = MarkerRepresentation(MarkerRepresentation::Plus, 8.0f, LocationLabelColor); + cityRep = MarkerRepresentation(MarkerRepresentation::X, 3.0f, LocationLabelColor); + genericLocationRep = MarkerRepresentation(MarkerRepresentation::Square, 8.0f, LocationLabelColor); + glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glDisable(GL_BLEND); // We need a double precision body-relative position of the // observer, otherwise location labels will tend to jitter. - Vec3d posd = (Selection(&body).getPosition(observer.getTime()) - + Vec3d posd = (body.getPosition(observer.getTime()) - observer.getPosition()) * astro::microLightYearsToKilometers(1.0); - renderLocations(*body.getLocations(), - cameraOrientation, - Point3d(posd.x, posd.y, posd.z), - q, - rp.radius); + renderLocations(body, posd, q); glDisable(GL_DEPTH_TEST); } @@ -10271,29 +10228,31 @@ for (int i = 0; i < (int) annotations.size(); i++) { - glPushMatrix(); - - if (annotations[i].marker != NULL) + if (annotations[i].markerRep != NULL) { - const Marker& marker = *annotations[i].marker; + glPushMatrix(); + const MarkerRepresentation& markerRep = *annotations[i].markerRep; - glColor(marker.getColor()); + glColor(markerRep.color()); glTranslatef((GLfloat) (int) annotations[i].position.x, (GLfloat) (int) annotations[i].position.y, 0.0f); glDisable(GL_TEXTURE_2D); - marker.render(); + markerRep.render(markerRep.size()); glEnable(GL_TEXTURE_2D); - if (!marker.getLabel().empty()) + if (!markerRep.label().empty()) { - int labelOffset = (int) marker.getSize() / 2; + int labelOffset = (int) markerRep.size() / 2; glTranslatef(labelOffset + PixelOffset, -labelOffset - font[fs]->getHeight() + PixelOffset, 0.0f); - font[fs]->render(marker.getLabel()); - } + font[fs]->render(markerRep.label()); + } + glPopMatrix(); } - else + + if (annotations[i].labelText[0] != '\0') { + glPushMatrix(); int labelOffset = 2; if (la == AlignCenter) { @@ -10306,13 +10265,16 @@ labelOffset = (int) -(labelwidth + 2); } + if (annotations[i].markerRep != NULL) + labelOffset += (int) annotations[i].markerRep->size() / 2; + glColor(annotations[i].color); glTranslatef((int) annotations[i].position.x + GLfloat((int) labelOffset) + PixelOffset, (int) annotations[i].position.y + PixelOffset, 0.0f); // EK TODO: Check where to replace (see '_(' above) font[fs]->render(annotations[i].labelText); + glPopMatrix(); } - glPopMatrix(); } glPopMatrix(); @@ -10392,22 +10354,22 @@ int labelVOffset = 0; glPushMatrix(); - if (iter->marker != NULL) + if (iter->markerRep != NULL) { - const Marker& marker = *iter->marker; + const MarkerRepresentation& markerRep = *iter->markerRep; glTranslatef((GLfloat) (int) iter->position.x, (GLfloat) (int) iter->position.y, ndc_z); - glColor(marker.getColor()); + glColor(markerRep.color()); glDisable(GL_TEXTURE_2D); - marker.render(); + markerRep.render(markerRep.size()); glEnable(GL_TEXTURE_2D); - if (!marker.getLabel().empty()) + if (!markerRep.label().empty()) { - int labelOffset = (int) marker.getSize() / 2; + int labelOffset = (int) markerRep.size() / 2; glTranslatef(labelOffset + PixelOffset, -labelOffset - font[fs]->getHeight() + PixelOffset, 0.0f); - font[fs]->render(marker.getLabel()); + font[fs]->render(markerRep.label()); } } else @@ -10475,34 +10437,40 @@ int labelHOffset = 0; int labelVOffset = 0; - glPushMatrix(); - if (iter->marker != NULL) + if (iter->markerRep != NULL) { - const Marker& marker = *iter->marker; + glPushMatrix(); + const MarkerRepresentation& markerRep = *iter->markerRep; glTranslatef((GLfloat) (int) iter->position.x, (GLfloat) (int) iter->position.y, ndc_z); - glColor(marker.getColor()); + glColor(markerRep.color()); glDisable(GL_TEXTURE_2D); - marker.render(); + markerRep.render(markerRep.size()); glEnable(GL_TEXTURE_2D); - if (!marker.getLabel().empty()) + if (!markerRep.label().empty()) { - int labelOffset = (int) marker.getSize() / 2; + int labelOffset = (int) markerRep.size() / 2; glTranslatef(labelOffset + PixelOffset, -labelOffset - font[fs]->getHeight() + PixelOffset, 0.0f); - font[fs]->render(marker.getLabel()); + font[fs]->render(markerRep.label()); } + glPopMatrix(); } - else + + if (iter->labelText[0] != '\0') { + if (iter->markerRep != NULL) + labelHOffset += (int) iter->markerRep->size() / 2 + 3; + + glPushMatrix(); glTranslatef((int) iter->position.x + PixelOffset + labelHOffset, (int) iter->position.y + PixelOffset + labelVOffset, ndc_z); glColor(iter->color); font[fs]->render(iter->labelText); + glPopMatrix(); } - glPopMatrix(); } glPopMatrix(); @@ -10532,13 +10500,13 @@ for (MarkerList::const_iterator iter = markers.begin(); iter != markers.end(); iter++) { - UniversalCoord uc = iter->getPosition(jd); + UniversalCoord uc = iter->position(jd); Vec3d offset = (uc - cameraPosition) * astro::microLightYearsToKilometers(1.0); // Only render those markers that lie withing the field of view. if ((offset * viewVector) > cosFOV * offset.length()) { - if (iter->isOccludable()) + if (iter->occludable()) { // If the marker is occludable, add it to the sorted annotation list if it's relatively // nearby, and to the background list if it's very distant. @@ -10546,26 +10514,26 @@ { // Modify the marker position so that it is always in front of the marked object. double boundingRadius; - if (iter->getObject().body() != NULL) - boundingRadius = iter->getObject().body()->getBoundingRadius(); + if (iter->object().body() != NULL) + boundingRadius = iter->object().body()->getBoundingRadius(); else - boundingRadius = iter->getObject().radius(); + boundingRadius = iter->object().radius(); offset *= (1.0 - boundingRadius * 1.01 / offset.length()); - addSortedAnnotation(&(*iter), EMPTY_STRING, iter->getColor(), + addSortedAnnotation(&(iter->representation()), EMPTY_STRING, iter->representation().color(), Point3f((float) offset.x, (float) offset.y, (float) offset.z)); } else { addAnnotation(backgroundAnnotations, - &(*iter), EMPTY_STRING, iter->getColor(), + &(iter->representation()), EMPTY_STRING, iter->representation().color(), Point3f((float) offset.x, (float) offset.y, (float) offset.z)); } } else { addAnnotation(foregroundAnnotations, - &(*iter), EMPTY_STRING, iter->getColor(), + &(iter->representation()), EMPTY_STRING, iter->representation().color(), Point3f((float) offset.x, (float) offset.y, (float) offset.z)); } } Index: celengine/universe.cpp =================================================================== --- celengine/universe.cpp (revision 4328) +++ celengine/universe.cpp (working copy) @@ -168,22 +168,19 @@ void Universe::markObject(const Selection& sel, - float size, - Color color, - Marker::Symbol symbol, + const MarkerRepresentation& rep, int priority, - string label, bool occludable) { for (MarkerList::iterator iter = markers->begin(); iter != markers->end(); iter++) { - if (iter->getObject() == sel) + if (iter->object() == sel) { // Handle the case when the object is already marked. If the // priority is higher than the existing marker, replace it. // Otherwise, do nothing. - if (priority > iter->getPriority()) + if (priority > iter->priority()) { markers->erase(iter); break; @@ -196,11 +193,8 @@ } Marker marker(sel); - marker.setColor(color); - marker.setSymbol(symbol); - marker.setSize(size); + marker.setRepresentation(rep); marker.setPriority(priority); - marker.setLabel(label); marker.setOccludable(occludable); markers->insert(markers->end(), marker); } @@ -211,9 +205,9 @@ for (MarkerList::iterator iter = markers->begin(); iter != markers->end(); iter++) { - if (iter->getObject() == sel) + if (iter->object() == sel) { - if (priority >= iter->getPriority()) + if (priority >= iter->priority()) markers->erase(iter); break; } @@ -232,8 +226,8 @@ for (MarkerList::iterator iter = markers->begin(); iter != markers->end(); iter++) { - if (iter->getObject() == sel) - return iter->getPriority() >= priority; + if (iter->object() == sel) + return iter->priority() >= priority; } return false; Index: celengine/cmdparser.cpp =================================================================== --- celengine/cmdparser.cpp (revision 4328) +++ celengine/cmdparser.cpp (working copy) @@ -613,40 +613,43 @@ paramList->getNumber("alpha", alpha); Color color((float) colorv.x, (float) colorv.y, (float) colorv.z, (float) alpha); - Marker::Symbol symbol = Marker::Diamond; + MarkerRepresentation rep(MarkerRepresentation::Diamond); string symbolString; if (paramList->getString("symbol", symbolString)) { if (compareIgnoringCase(symbolString, "diamond") == 0) - symbol = Marker::Diamond; + rep = MarkerRepresentation(MarkerRepresentation::Diamond); else if (compareIgnoringCase(symbolString, "triangle") == 0) - symbol = Marker::Triangle; + rep = MarkerRepresentation(MarkerRepresentation::Triangle); else if (compareIgnoringCase(symbolString, "square") == 0) - symbol = Marker::Square; + rep = MarkerRepresentation(MarkerRepresentation::Square); else if (compareIgnoringCase(symbolString, "filledsquare") == 0) - symbol = Marker::FilledSquare; + rep = MarkerRepresentation(MarkerRepresentation::FilledSquare); else if (compareIgnoringCase(symbolString, "plus") == 0) - symbol = Marker::Plus; + rep = MarkerRepresentation(MarkerRepresentation::Plus); else if (compareIgnoringCase(symbolString, "x") == 0) - symbol = Marker::X; + rep = MarkerRepresentation(MarkerRepresentation::X); else if (compareIgnoringCase(symbolString, "leftarrow") == 0) - symbol = Marker::LeftArrow; + rep = MarkerRepresentation(MarkerRepresentation::LeftArrow); else if (compareIgnoringCase(symbolString, "rightarrow") == 0) - symbol = Marker::RightArrow; + rep = MarkerRepresentation(MarkerRepresentation::RightArrow); else if (compareIgnoringCase(symbolString, "uparrow") == 0) - symbol = Marker::UpArrow; + rep = MarkerRepresentation(MarkerRepresentation::UpArrow); else if (compareIgnoringCase(symbolString, "downarrow") == 0) - symbol = Marker::DownArrow; + rep = MarkerRepresentation(MarkerRepresentation::DownArrow); else if (compareIgnoringCase(symbolString, "circle") == 0) - symbol = Marker::Circle; + rep = MarkerRepresentation(MarkerRepresentation::Circle); else if (compareIgnoringCase(symbolString, "disk") == 0) - symbol = Marker::Disk; + rep = MarkerRepresentation(MarkerRepresentation::Disk); } - + string label; paramList->getString("label", label); + rep.setSize((float) size); + rep.setColor(color); + rep.setLabel(label); - cmd = new CommandMark(object, color, (float) size, symbol, label); + cmd = new CommandMark(object, rep); } else if (commandName == "unmark") { Index: celengine/marker.cpp =================================================================== --- celengine/marker.cpp (revision 4328) +++ celengine/marker.cpp (working copy) @@ -15,13 +15,10 @@ Marker::Marker(const Selection& s) : - obj(s), - size(10.0f), - color(Color::White), - priority(0), - symbol(Diamond), - label(""), - occludable(true) + m_object(s), + m_priority(0), + m_representation(MarkerRepresentation::Diamond), + m_occludable(true) { } @@ -30,93 +27,115 @@ } -UniversalCoord Marker::getPosition(double jd) const +UniversalCoord Marker::position(double jd) const { - return obj.getPosition(jd); + return m_object.getPosition(jd); } -Selection Marker::getObject() const +Selection Marker::object() const { - return obj; + return m_object; } -Color Marker::getColor() const +int Marker::priority() const { - return color; + return m_priority; } -void Marker::setColor(Color _color) +void Marker::setPriority(int priority) { - color = _color; + m_priority = priority; } -float Marker::getSize() const +void Marker::setRepresentation(const MarkerRepresentation& rep) { - return size; + m_representation = rep; } -void Marker::setSize(float _size) +bool Marker::occludable() const { - size = _size; + return m_occludable; } -int Marker::getPriority() const +void Marker::setOccludable(bool occludable) { - return priority; + m_occludable = occludable; } -void Marker::setPriority(int _priority) +void Marker::render() const { - priority = _priority; + m_representation.render(m_representation.size()); } -Marker::Symbol Marker::getSymbol() const + +static void DrawCircle(float s) { - return symbol; -} + if (s < 1.0f) + s = 1.0f; // 0 and negative values are not allowed in the case of circle markers. + else if (s > 1024.0f) + s = 1024.0f; // Bigger values would give a too high number of segments in the circle markers. -void Marker::setSymbol(Marker::Symbol _symbol) -{ - symbol = _symbol; + int step = (int) (60 / sqrt(s)); + for (int i = 0; i < 360; i += step) + { + float degInRad = (float) (i * PI / 180); + glVertex3f((float) cos(degInRad) * s, (float) sin(degInRad) * s, 0.0f); + } } -string Marker::getLabel() const +MarkerRepresentation::MarkerRepresentation(const MarkerRepresentation& rep) : + m_symbol(rep.m_symbol), + m_size(rep.m_size), + m_color(rep.m_color), + m_label(rep.m_label) { - return label; } -void Marker::setLabel(string _label) +MarkerRepresentation& +MarkerRepresentation::operator=(const MarkerRepresentation& rep) { - label = _label; + m_symbol = rep.m_symbol; + m_size = rep.m_size; + m_color = rep.m_color; + m_label = rep.m_label; + + return *this; } + + +void MarkerRepresentation::setColor(Color color) +{ + m_color = color; +} -bool Marker::isOccludable() const +void MarkerRepresentation::setSize(float size) { - return occludable; + m_size = size; } -void Marker::setOccludable(bool _occludable) +void MarkerRepresentation::setLabel(const std::string& label) { - occludable = _occludable; + m_label = label; } -void Marker::render() const + +void MarkerRepresentation::render(float size) const { - float s = getSize() / 2.0f; + float s = size / 2.0f; - switch (symbol) + switch (m_symbol) { case Diamond: glBegin(GL_LINE_LOOP); @@ -224,22 +243,13 @@ case Circle: glBegin(GL_LINE_LOOP); - + DrawCircle(s); + glEnd(); + break; + case Disk: glBegin(GL_POLYGON); - - if (s < 1.0f) - s = 1.0f; // 0 and negative values are not allowed in the case of circle markers. - else if (s > 1024.0f) - s = 1024.0f; // Bigger values would give a too high number of segments in the circle markers. - - int step = (int) (60 / sqrt(s)); - for (int i=0; i < 360; i=i+step) - { - float degInRad = (float) (i * PI / 180); - glVertex3f((float) cos(degInRad) * s, (float) sin(degInRad) * s, 0.0f); - } - + DrawCircle(s); glEnd(); break; } Index: celengine/command.cpp =================================================================== --- celengine/command.cpp (revision 4328) +++ celengine/command.cpp (working copy) @@ -598,13 +598,10 @@ //////////////// // Mark object command -CommandMark::CommandMark(const string& _target, Color _color, float _size, - Marker::Symbol _symbol, const string& _label) : +CommandMark::CommandMark(const string& _target, + MarkerRepresentation _rep) : target(_target), - color(_color), - size(_size), - symbol(_symbol), - label(_label) + rep(_rep) { } @@ -615,7 +612,10 @@ return; if (env.getSimulation()->getUniverse() != NULL) - env.getSimulation()->getUniverse()->markObject(sel, size, color, symbol, 1, label); + { + + env.getSimulation()->getUniverse()->markObject(sel, rep, 1); + } } Index: celengine/command.h =================================================================== --- celengine/command.h (revision 4328) +++ celengine/command.h (working copy) @@ -502,15 +502,12 @@ class CommandMark : public InstantaneousCommand { public: - CommandMark(const std::string&, Color, float, Marker::Symbol, const std::string&); + CommandMark(const std::string&, MarkerRepresentation); void process(ExecutionEnvironment&); private: std::string target; - Color color; - float size; - Marker::Symbol symbol; - std::string label; + MarkerRepresentation rep; }; Index: celestia/winmain.cpp =================================================================== --- celestia/winmain.cpp (revision 4328) +++ celestia/winmain.cpp (working copy) @@ -4246,12 +4246,13 @@ Simulation* sim = appCore->getSimulation(); if (sim->getUniverse() != NULL) { + MarkerRepresentation markerRep(MarkerRepresentation::Diamond, + 10.0f, + Color(0.0f, 1.0f, 0.0f, 0.9f)); + sim->getUniverse()->markObject(sim->getSelection(), - 10.0f, - Color(0.0f, 1.0f, 0.0f, 0.9f), - Marker::Diamond, - 1, - ""); + markerRep, + 1); appCore->getRenderer()->setRenderFlags(appCore->getRenderer()->getRenderFlags() | Renderer::ShowMarkers); } Index: celestia/qt/qtdeepskybrowser.cpp =================================================================== --- celestia/qt/qtdeepskybrowser.cpp (revision 4333) +++ celestia/qt/qtdeepskybrowser.cpp (working copy) @@ -470,12 +470,12 @@ markerSymbolBox = new QComboBox(); markerSymbolBox->setEditable(false); markerSymbolBox->addItem(tr("None")); - markerSymbolBox->addItem(tr("Diamond"), (int) Marker::Diamond); - markerSymbolBox->addItem(tr("Triangle"), (int) Marker::Triangle); - markerSymbolBox->addItem(tr("Square"), (int) Marker::Square); - markerSymbolBox->addItem(tr("Plus"), (int) Marker::Plus); - markerSymbolBox->addItem(tr("X"), (int) Marker::X); - markerSymbolBox->addItem(tr("Circle"), (int) Marker::Circle); + markerSymbolBox->addItem(tr("Diamond"), (int) MarkerRepresentation::Diamond); + markerSymbolBox->addItem(tr("Triangle"), (int) MarkerRepresentation::Triangle); + markerSymbolBox->addItem(tr("Square"), (int) MarkerRepresentation::Square); + markerSymbolBox->addItem(tr("Plus"), (int) MarkerRepresentation::Plus); + markerSymbolBox->addItem(tr("X"), (int) MarkerRepresentation::X); + markerSymbolBox->addItem(tr("Circle"), (int) MarkerRepresentation::Circle); markerSymbolBox->setCurrentIndex(1); markerSymbolBox->setToolTip(tr("Select marker symbol")); markGroupLayout->addWidget(markerSymbolBox, 1, 0); @@ -562,7 +562,7 @@ bool labelMarker = labelMarkerBox->checkState() == Qt::Checked; bool convertOK = false; QVariant markerData = markerSymbolBox->itemData(markerSymbolBox->currentIndex()); - Marker::Symbol markerSymbol = (Marker::Symbol) markerData.toInt(&convertOK); + MarkerRepresentation::Symbol markerSymbol = (MarkerRepresentation::Symbol) markerData.toInt(&convertOK); QColor markerColor = colorSwatch->color(); Color color((float) markerColor.redF(), (float) markerColor.greenF(), @@ -587,9 +587,9 @@ label = ReplaceGreekLetterAbbr(label); } - universe->markObject(Selection(dso), 10.0f, - color, - markerSymbol, 1, label); + universe->markObject(Selection(dso), + MarkerRepresentation(markerSymbol, 10.0f, color, label), + 1); } else { Index: celestia/qt/qtselectionpopup.cpp =================================================================== --- celestia/qt/qtselectionpopup.cpp (revision 4333) +++ celestia/qt/qtselectionpopup.cpp (working copy) @@ -216,19 +216,19 @@ QMenu* SelectionPopup::createMarkMenu() { - const Marker::Symbol MARKER_SYMBOLS[] = { - Marker::Diamond, - Marker::Triangle, - Marker::Square, - Marker::FilledSquare, - Marker::Plus, - Marker::X, - Marker::LeftArrow, - Marker::RightArrow, - Marker::UpArrow, - Marker::DownArrow, - Marker::Circle, - Marker::Disk, + const MarkerRepresentation::Symbol MARKER_SYMBOLS[] = { + MarkerRepresentation::Diamond, + MarkerRepresentation::Triangle, + MarkerRepresentation::Square, + MarkerRepresentation::FilledSquare, + MarkerRepresentation::Plus, + MarkerRepresentation::X, + MarkerRepresentation::LeftArrow, + MarkerRepresentation::RightArrow, + MarkerRepresentation::UpArrow, + MarkerRepresentation::DownArrow, + MarkerRepresentation::Circle, + MarkerRepresentation::Disk, }; const char* MARKER_NAMES[] = { @@ -543,11 +543,8 @@ { Simulation* sim = appCore->getSimulation(); sim->getUniverse()->markObject(selection, - 10.0f, - Color(0.0f, 1.0f, 0.0f, 0.9f), - (Marker::Symbol) symbol, - 1, - ""); + MarkerRepresentation(MarkerRepresentation::Symbol(symbol), 10.0f, Color(0.0f, 1.0f, 0.0f, 0.9f)), + 1); // Automatically enable markers appCore->getRenderer()->setRenderFlags(appCore->getRenderer()->getRenderFlags() | Renderer::ShowMarkers); Index: celestia/qt/qtcelestialbrowser.cpp =================================================================== --- celestia/qt/qtcelestialbrowser.cpp (revision 4333) +++ celestia/qt/qtcelestialbrowser.cpp (working copy) @@ -550,12 +550,12 @@ markerSymbolBox = new QComboBox(); markerSymbolBox->setEditable(false); markerSymbolBox->addItem(tr("None")); - markerSymbolBox->addItem(tr("Diamond"), (int) Marker::Diamond); - markerSymbolBox->addItem(tr("Triangle"), (int) Marker::Triangle); - markerSymbolBox->addItem(tr("Square"), (int) Marker::Square); - markerSymbolBox->addItem(tr("Plus"), (int) Marker::Plus); - markerSymbolBox->addItem(tr("X"), (int) Marker::X); - markerSymbolBox->addItem(tr("Circle"), (int) Marker::Circle); + markerSymbolBox->addItem(tr("Diamond"), (int) MarkerRepresentation::Diamond); + markerSymbolBox->addItem(tr("Triangle"), (int) MarkerRepresentation::Triangle); + markerSymbolBox->addItem(tr("Square"), (int) MarkerRepresentation::Square); + markerSymbolBox->addItem(tr("Plus"), (int) MarkerRepresentation::Plus); + markerSymbolBox->addItem(tr("X"), (int) MarkerRepresentation::X); + markerSymbolBox->addItem(tr("Circle"), (int) MarkerRepresentation::Circle); markerSymbolBox->setCurrentIndex(1); markerSymbolBox->setToolTip(tr("Select marker symbol")); markGroupLayout->addWidget(markerSymbolBox, 1, 0); @@ -642,7 +642,7 @@ bool labelMarker = labelMarkerBox->checkState() == Qt::Checked; bool convertOK = false; QVariant markerData = markerSymbolBox->itemData(markerSymbolBox->currentIndex()); - Marker::Symbol markerSymbol = (Marker::Symbol) markerData.toInt(&convertOK); + MarkerRepresentation::Symbol markerSymbol = (MarkerRepresentation::Symbol) markerData.toInt(&convertOK); QColor markerColor = colorSwatch->color(); Color color((float) markerColor.redF(), (float) markerColor.greenF(), @@ -667,9 +667,9 @@ label = ReplaceGreekLetterAbbr(label); } - universe->markObject(sel, 10.0f, - color, - markerSymbol, 1, label); + universe->markObject(sel, + MarkerRepresentation(markerSymbol, 10.0f, color, label), + 1); } else { Index: celestia/celestiacore.cpp =================================================================== --- celestia/celestiacore.cpp (revision 4328) +++ celestia/celestiacore.cpp (working copy) @@ -1440,12 +1440,11 @@ } else { - sim->getUniverse()->markObject(sel, - 10.0f, - Color(0.0f, 1.0f, 0.0f, 0.9f), - Marker::Diamond, - 1, - ""); + MarkerRepresentation markerRep(MarkerRepresentation::Diamond); + markerRep.setSize(10.0f); + markerRep.setColor(Color(0.0f, 1.0f, 0.0f, 0.9f)); + + sim->getUniverse()->markObject(sel, markerRep, 1); } } break; Index: celestia/celx_object.cpp =================================================================== --- celestia/celx_object.cpp (revision 4328) +++ celestia/celx_object.cpp (working copy) @@ -23,34 +23,34 @@ using namespace std; -static Marker::Symbol parseMarkerSymbol(const string& name) +static MarkerRepresentation::Symbol parseMarkerSymbol(const string& name) { if (compareIgnoringCase(name, "diamond") == 0) - return Marker::Diamond; + return MarkerRepresentation::Diamond; else if (compareIgnoringCase(name, "triangle") == 0) - return Marker::Triangle; + return MarkerRepresentation::Triangle; else if (compareIgnoringCase(name, "square") == 0) - return Marker::Square; + return MarkerRepresentation::Square; else if (compareIgnoringCase(name, "filledsquare") == 0) - return Marker::FilledSquare; + return MarkerRepresentation::FilledSquare; else if (compareIgnoringCase(name, "plus") == 0) - return Marker::Plus; + return MarkerRepresentation::Plus; else if (compareIgnoringCase(name, "x") == 0) - return Marker::X; + return MarkerRepresentation::X; else if (compareIgnoringCase(name, "leftarrow") == 0) - return Marker::LeftArrow; + return MarkerRepresentation::LeftArrow; else if (compareIgnoringCase(name, "rightarrow") == 0) - return Marker::RightArrow; + return MarkerRepresentation::RightArrow; else if (compareIgnoringCase(name, "uparrow") == 0) - return Marker::UpArrow; + return MarkerRepresentation::UpArrow; else if (compareIgnoringCase(name, "downarrow") == 0) - return Marker::DownArrow; + return MarkerRepresentation::DownArrow; else if (compareIgnoringCase(name, "circle") == 0) - return Marker::Circle; + return MarkerRepresentation::Circle; else if (compareIgnoringCase(name, "disk") == 0) - return Marker::Disk; + return MarkerRepresentation::Disk; else - return Marker::Diamond; + return MarkerRepresentation::Diamond; } @@ -734,7 +734,7 @@ if (colorString != NULL) Color::parse(colorString, markColor); - Marker::Symbol markSymbol = Marker::Diamond; + MarkerRepresentation::Symbol markSymbol = MarkerRepresentation::Diamond; const char* markerString = celx.safeGetString(3, WrongType, "Second argument to object:mark must be a string"); if (markerString != NULL) markSymbol = parseMarkerSymbol(markerString); @@ -761,9 +761,13 @@ bool occludable = celx.safeGetBoolean(7, WrongType, "Sixth argument to object:mark must be a boolean", true); Simulation* sim = appCore->getSimulation(); - sim->getUniverse()->markObject(*sel, markSize, - markColorAlpha, markSymbol, 1, markLabel, occludable); + MarkerRepresentation markerRep(markSymbol); + markerRep.setSize(markSize); + markerRep.setColor(markColorAlpha); + markerRep.setLabel(markLabel); + sim->getUniverse()->markObject(*sel, markerRep, 1, occludable); + return 0; } Index: celestia/celx.cpp =================================================================== --- celestia/celx.cpp (revision 4328) +++ celestia/celx.cpp (working copy) @@ -2235,8 +2235,11 @@ if (sel != NULL) { - sim->getUniverse()->markObject(*sel, 10.0f, - Color(0.0f, 1.0f, 0.0f), Marker::Diamond, 1, ""); + MarkerRepresentation markerRep(MarkerRepresentation::Diamond); + markerRep.setColor(Color(0.0f, 1.0f, 0.0f)); + markerRep.setSize(10.0f); + + sim->getUniverse()->markObject(*sel, markerRep, 1); } else {