Results 1 to 10 of 10

Thread: BackGround Safe Color (QT 3.x)

  1. #1
    Registered User
    Join Date
    Sep 2003
    Posts
    105

    BackGround Safe Color (QT 3.x)

    I finally had a moment and enough knowledge/motivation to resolve the hated black lines on black background I complained about in years past. Unfortunately I am NOT skilled enough to make a diff that will produce a viable patch file so I'm going to just post the changed files in their entirety in code blocks here and let a much more proficent dev get it moved into the tree.

    I adjusted the MapCommon class by adding a function to do the comparison and adjust the color accordingly. This new function requires the background color from the MapParamaters Class to be passed into it so it can do it's compairsons.

    I then adjusted in the .cpp file where the p.setPen for painting of the lines so that they will use the new background safe color.

    I used showeq-5.13.3.0 as my starting point.

    note: gray lines on white backgrounds still draw properly, but are hard to see. If this is a major problem for folks I can look into putting some more conditions in on the comparison portion of the system. But my goal was to resolve black on black and other color on identical color background issues with SOE maps being used in SEQ.


    ~ TK


    Code:
    /*
     * mapcore.h
     *
     *  ShowEQ Distributed under GPL
     *  http://seq.sf.net/
     * 
     * Portions Copyright 2001-2003 Zaphod ([email protected]). 
     * 
     */
    
    // Author: Zaphod ([email protected])
    //    Many parts derived from existing ShowEQ/SINS map code
    
    //
    // NOTE: Trying to keep this file ShowEQ/Everquest independent to allow it
    // to be reused for other Show{} style projects.  Any existing ShowEQ/EQ
    // dependencies will be migrated out.
    //
    //
    
    // ZBTEMP: Note: Currently hardcoded to use int16_t type for point data, 
    // should migrate this to a compiler define/typedef based value that 
    // can be defined differently depending on the needs of other projects
    //
    #ifndef _MAPCORE_H
    #define _MAPCORE_H
    
    #include <stdlib.h>
    #include <stdio.h>
    
    #include <qstring.h>
    #include <qcolor.h>
    #include <qfont.h>
    #include <qpixmap.h>
    #include <qptrlist.h>
    #include <qpointarray.h>
    
    #include "point.h"
    #include "pointarray.h"
    #include "fixpt.h"
    
    ///////////////////////////////////////////
    // forward declarations
    class MapData;
    class MapLine;
    class MapLocation;
    class MapParameters;
    class MapImage;
    
    ///////////////////////////////////////////
    // type definitions
    typedef Point3D<int16_t> MapPoint;
    typedef Point3DArray<int16_t> MapPointArray;
    
    ///////////////////////////////////////////
    // enumerated types
    enum MapLineStyle
    {
      tMap_Normal,
      tMap_DepthFiltered,
      tMap_FadedFloors,
    };
    
    enum MapOptimizationMethod
    {
      tMap_MemoryOptim = 0,
      tMap_NormalOptim = 1,
      tMap_BestOptim = 2,
      tMap_DefaultOptim = 3,
      tMap_NoOptim = 4,
    };
    
    //----------------------------------------------------------------------
    // constants
    
    //----------------------------------------------------------------------
    // MapParameters
    class MapParameters
    {
     public:
      // q format used for map fixed point math
      enum { qFormat = 14 };
    
     public:
      MapParameters(const MapData& mapData);
      ~MapParameters();
    
      // get methods
      const MapPoint& player() const { return m_curPlayer; }
      const QPoint& playerOffset() const { return m_curPlayerOffset; }
      int playerXOffset() const { return m_curPlayerOffset.x(); }
      int playerYOffset() const { return m_curPlayerOffset.y(); }
      int16_t playerHeadRoom() const { return m_playerHeadRoom; }
      int16_t playerFloorRoom() const { return m_playerFloorRoom; }
      const QSize& screenLength() const { return m_screenLength; }
      int screenLengthX() const { return m_screenLength.width(); }
      int screenLengthY() const { return m_screenLength.height(); }
      const QRect& screenBounds() const { return m_screenBounds; }
      const QPoint& screenCenter() const { return m_screenCenter; }
      int screenCenterX() const { return m_screenCenter.x(); }
      int screenCenterY() const { return m_screenCenter.y(); }
      const QSize& zoomMapLength() const { return m_zoomMapLength; }
      int zoomMapLengthX() const { return m_zoomMapLength.width(); }
      int zoomMapLengthY() const { return m_zoomMapLength.height(); }
      int panOffsetX() const { return m_panOffsetX; }
      int panOffsetY() const { return m_panOffsetY; }
      int zoom() const { return m_zoom; }
      int zoomDefault() const { return m_zoomDefault; }
      double ratio() const { return m_ratio; }
      double ratioX() const { return m_ratio; }
      double ratioY() const { return m_ratio; } 
      int ratioIFixPt() const { return m_ratioIFixPt; }
    
      int gridResolution() const { return m_gridResolution; }
      const QColor& gridLineColor() const { return m_gridLineColor; }
      const QColor& gridTickColor() const { return m_gridTickColor; }
      const QColor& backgroundColor() const { return m_backgroundColor; }
      const QFont& font() const { return m_font; }
      int16_t headRoom() const { return m_headRoom; }
      int16_t floorRoom() const { return m_floorRoom; }
      MapOptimizationMethod mapOptimizationMethod() { return m_optimization; }
      QPixmap::Optimization pixmapOptimizationMethod();
      MapLineStyle mapLineStyle() { return m_mapLineStyle; }
      bool fadeFloors() const { return (m_mapLineStyle == tMap_FadedFloors); }
      bool depthFiltering() const { return (m_mapLineStyle == tMap_DepthFiltered); }
      bool showBackgroundImage() const { return m_showBackgroundImage; }
      bool showLocations() const { return m_showLocations; }
      bool showLines() const { return m_showLines; }
      bool showGridLines() const { return m_showGridLines; }
      bool showGridTicks() const { return m_showGridTicks; }
    
      // utility methods
      int calcXOffset (int mapCoordinate) const;
      int invertXOffset (int worldX) const;
      int calcYOffset (int mapCoordinate) const;
      int invertYOffset (int worldY) const;
    
      int calcXOffsetI(int mapCoordinate) const;
      int calcYOffsetI(int mapCoordinate) const;
    
      // set/adjust methods
      void setPlayer(const MapPoint& pos);
    
      void setGridResolution(int res);
      void increaseGridResolution(void);
      void decreaseGridResolution(void);
      void setZoomDefault(int zoom);
      bool setZoom(int zoom);
      bool zoomIn();
      bool zoomOut();
      void panX(int xPan);
      void panY(int yPan);
      void panXY(int xPan, int yPan);
      void clearPan();
      void setPan(int xPan, int yPan);
      void setPanX(int xPan);
      void setPanY(int yPan);
      void setScreenSize(const QSize& size);
      void setBackgroundColor(const QColor& color) { m_backgroundColor = color; }
      void setFont(const QFont& font) { m_font = font; }
      void setMapOptimizationMethod(MapOptimizationMethod method) 
        { m_optimization = method; }  
      void setMapLineStyle(MapLineStyle style) { m_mapLineStyle = style; }
      void setShowBackgroundImage(bool val) { m_showBackgroundImage = val; }
      void setShowLocations(bool val) { m_showLocations = val; }
      void setShowLines(bool val) { m_showLines = val; }
      void setShowGridLines(bool val) { m_showGridLines = val; }
      void setShowGridTicks(bool val) { m_showGridTicks = val; }
      void setGridLineColor(const QColor& color) { m_gridLineColor = color; }
      void setGridTickColor(const QColor& color) { m_gridTickColor = color; }
      void setHeadRoom(int16_t headRoom);
      void setFloorRoom(int16_t floorRoom);
      
      void reAdjust(MapPoint* targetPoint);
      void reAdjust();
      
      void reset();
     private:
      const MapData* m_mapData;
      MapPoint m_curPlayer;
      QPoint m_curPlayerOffset;
      int16_t m_playerHeadRoom; 
      int16_t m_playerFloorRoom;
      QSize m_screenLength;
      QRect m_screenBounds;
      QPoint m_screenCenter;
      QSize m_zoomMapLength;
      uint32_t m_zoom;
      uint32_t m_zoomDefault;
      int m_panOffsetX;
      int m_panOffsetY;
      double m_ratio;
      int m_ratioIFixPt;
    
      // configuration parameters
      int m_gridResolution;
      QColor m_gridLineColor;
      QColor m_gridTickColor;
      QColor m_backgroundColor;
      QFont m_font;
      int16_t m_headRoom;
      int16_t m_floorRoom;
    
      MapPoint m_targetPoint;
      bool m_targetPointSet;
    
      MapOptimizationMethod m_optimization;
      MapLineStyle m_mapLineStyle;
      bool m_showBackgroundImage; 
      bool m_showLocations;
      bool m_showLines;
      bool m_showGridLines;
      bool m_showGridTicks;
    };
    
    inline 
    int MapParameters::calcXOffset (int mapCoordinate) const
    { 
      return screenCenterX() - (int)(mapCoordinate / m_ratio); 
    }
    
    inline 
    int MapParameters::invertXOffset (int worldX) const
    {
      return (int)rint((screenCenterX() - worldX) * m_ratio); 
    }
    
    inline 
    int MapParameters::calcYOffset (int mapCoordinate) const
    { 
      return screenCenterY() - (int)(mapCoordinate / m_ratio); 
    }
    
    inline 
    int MapParameters::invertYOffset (int worldY) const
    { 
      return (int)rint((screenCenterY() - worldY) * m_ratio); 
    }
    
    inline 
    int MapParameters::calcXOffsetI(int mapCoordinate) const
    { 
      return screenCenterX() - 
        fixPtMulII(m_ratioIFixPt, qFormat, mapCoordinate);
    }
    
    inline 
    int MapParameters::calcYOffsetI(int mapCoordinate) const
    { 
      return screenCenterY() - 
        fixPtMulII(m_ratioIFixPt, qFormat, mapCoordinate);
    }
    
    inline 
    void MapParameters::setGridResolution(int res) 
    {
      if ((res >= 50) && (res <= 1500))
        m_gridResolution = res; 
    }
    
    inline 
    void MapParameters::increaseGridResolution(void)
    {
      if (m_gridResolution <= 100)
        m_gridResolution = 50;
      else
        m_gridResolution -= 100;
      reAdjust();
    }
    
    inline 
    void MapParameters::decreaseGridResolution(void)
    {
      if (m_gridResolution >= 1500)
        return;
      
      m_gridResolution += 100;
      reAdjust();
    }
    
    inline 
    bool MapParameters::setZoom(int zoom)
    {
      if ((zoom <= 32) &&
          (zoom >= 1))
      {
        m_zoom = zoom;
        reAdjust();
        return true;
      }
      
      return false;
    }
    
    inline 
    void MapParameters::setZoomDefault(int zoom)
    {
      if ((zoom <= 32) &&
          (zoom >= 1))
        m_zoomDefault = zoom;
    }
    
    inline 
    bool MapParameters::zoomIn() 
    { 
      if (m_zoom < 32) 
      {
        m_zoom *= 2; 
        reAdjust();
        return true;
      }
      return false;
    }
    
    inline 
    bool MapParameters::zoomOut() 
    { 
      if (m_zoom > 1) 
      {
        m_zoom /= 2; 
        if (m_zoom == 1) 
          clearPan();
        
        reAdjust();
        
        return true;
      }
      return false;
    }
    
    inline 
    void MapParameters::panX(int xPan) 
    { 
      m_panOffsetX += m_zoomMapLength.width() / xPan;
      reAdjust();
    }
    
    inline 
    void MapParameters::panY(int yPan) 
    { 
      m_panOffsetY += m_zoomMapLength.height() / yPan; 
      reAdjust();
    }
    
    inline 
    void MapParameters::panXY(int xPan, int yPan)
    {
      m_panOffsetX += m_zoomMapLength.width() / xPan;
      m_panOffsetY += m_zoomMapLength.height() / yPan;
      reAdjust();
    }
    
    inline 
    void MapParameters::clearPan() 
    { 
      m_panOffsetX = 0; 
      m_panOffsetY = 0; 
      reAdjust();
    }
    
    inline 
    void MapParameters::setPan(int xPan, int yPan) 
    { 
      m_panOffsetX = xPan; 
      m_panOffsetY = yPan; 
      reAdjust();
    }
    
    inline 
    void MapParameters::setPanX(int xPan)
    {
      m_panOffsetX = xPan;
      reAdjust();
    }
    
    inline 
    void MapParameters::setPanY(int yPan)
    {
      m_panOffsetY = yPan;
      reAdjust();
    }
    
    inline 
    void MapParameters::setScreenSize(const QSize& size) 
    { 
      m_screenLength = size; 
      reAdjust();
    }
    
    //----------------------------------------------------------------------
    // MapCommon
    class MapCommon
    {
     public:
      MapCommon() {}
      MapCommon(const QString& name, const QString& color)
        : m_name(name), m_colorName(color), m_color(color) {}
      MapCommon(const QString& name, const QColor& color)
        : m_name(name), m_color(color) {}
      virtual ~MapCommon();
    
      const QString& name() const { return m_name; }
      const QColor& color() const { return m_color; }
      QString colorName() const;
    
      void setName(const QString& name) { m_name = name; }
      void setColor(const QString& color) { m_color = color; }
    
      // Returns a QColor object for a color that will contrast the background better
      QColor bgSafeColor(const QColor& bgColor);
    
     private:
      QString m_name;
      QString m_colorName;
      QColor m_color;
      QColor m_bgSafeColor;
    };
    
    inline QString MapCommon::colorName() const
    {
      // if a color name was specified, return it
      if (!m_colorName.isEmpty())
        return m_colorName;
    
      // otherwise return the string form of a QColor
      return m_color.name();
    }
    
    inline QColor MapCommon::bgSafeColor(const QColor& bgColor)
    {
      QColor bgSafeColor = color();
      // Compairing the draw color with the backround and adjusting if they are too similar
      if ((abs(color().red() - bgColor.red()) <= 55) && 
              (abs(color().green() - bgColor.green()) <= 55) && 
              (abs(color().blue() - bgColor.blue()) <= 55))
      {
      	// black on black fails to XOR
      	// if the color is too black, and we assume the background is black as well
      	// because we passed the previous if statement we set the color to gray
      	if (color().red() <= 55 && color().green() <= 55 && color().blue() <= 55)
      	{
      	  bgSafeColor.setNamedColor("gray");
      	} else { 
      	  // the carrot symbol performs an XOR
      	  // If the colors are identical the line will be drawn black
          bgSafeColor.setRgb(color().red() ^ bgColor.red(), 
                             color().green() ^ bgColor.green(), 
                             color().blue() ^ bgColor.blue());
      	}
      } else {
        bgSafeColor = color();
      }
    
      return bgSafeColor;
    }
    
    //----------------------------------------------------------------------
    // MapLineL
    class MapLineL : public MapCommon, public QPointArray
    {
     public:
      MapLineL();
      MapLineL(const QString& name, const QString& color, uint32_t size);
      MapLineL(const QString& name, const QString& color, uint32_t size, int16_t z);
      virtual ~MapLineL();
      
      int16_t z() const { return m_z; }
      bool heightSet() const { return m_heightSet; }
      const QRect& boundingRect() const { return m_bounds; }
    
      void setZPos(uint16_t z)
        {  m_z = z; m_heightSet = true; }
      void calcBounds() { m_bounds = QPointArray::boundingRect(); }
    
     private:
      int16_t m_z;
      bool m_heightSet;
      QRect m_bounds;
    };
    
    //----------------------------------------------------------------------
    // MapLineM
    class MapLineM : public MapCommon, public MapPointArray
    {
     public:
      MapLineM();
      MapLineM(const QString& name, const QString& color, uint32_t size);
      MapLineM(const QString& name, const QColor& color, uint32_t size);
      MapLineM(const QString& name, const QString& color, const MapPoint& point);
      virtual ~MapLineM();
    
      const QRect& boundingRect() const { return m_bounds; }
      void calcBounds() { m_bounds = MapPointArray::boundingRect(); }
    
     private:
      QRect m_bounds;
    };
    
    //----------------------------------------------------------------------
    // MapLocation
    class MapLocation : public MapCommon, public MapPoint
    {
     public:
      MapLocation();
      MapLocation(const QString& name, const QString& color, const QPoint& point);
      MapLocation(const QString& name, const QString& color, const MapPoint& point);
      MapLocation(const QString& name, const QString& color, 
    	      int16_t x, int16_t y);
      MapLocation(const QString& name, const QString& color, 
    	      int16_t x, int16_t y, int16_t z);
      MapLocation(const QString& name, const QColor& color, 
    	      int16_t x, int16_t y, int16_t z);
      virtual ~MapLocation();
      bool heightSet() const { return m_heightSet; }
    
     private:
      bool m_heightSet;
    };
    
    //----------------------------------------------------------------------
    // MapAggro
    class MapAggro
    {
     public:
      MapAggro();
      MapAggro(const QString& name, uint16_t range) : m_name(name), m_range(range) {}
      virtual ~MapAggro();
    
      const QString& name() { return m_name; }
      uint16_t range() { return m_range; }
    
      void setName(const QString& name) { m_name = name; }
      void setRange(uint16_t range);
     private:
      QString m_name;
      uint16_t m_range;
    };
    
    //----------------------------------------------------------------------
    // MapData
    class MapData
    {
     public:
      // constructor/destructor
      MapData();
      ~MapData();
    
      // map loading/clearing/saving
      void clear();
      void loadMap(const QString& fileName, bool import = false);
      void loadSOEMap(const QString& fileName, bool import = false);
      void saveMap(const QString& fileName) const;
      void saveSOEMap(const QString& fileName) const;
    
      // accessors
      const QString& fileName() const { return m_fileName; }
      const QString& zoneShortName() const { return m_zoneShortName; }
      const QString& zoneLongName() const { return m_zoneLongName; }
      const QRect& boundingRect() const { return m_boundingRect; }
      const QSize& size() const { return m_size; }
      uint8_t zoneZEM() const { return m_zoneZEM; }
      int16_t minX() const { return m_minX; }
      int16_t minY() const { return m_minY; }
      int16_t maxX() const { return m_maxX; }
      int16_t maxY() const { return m_maxY; }
      QPtrList<MapLineL>& lLines() { return m_lLines; }
      QPtrList<MapLineM>& mLines() { return m_mLines; }
      QPtrList<MapLocation>& locations() { return m_locations; }
      QPtrList<MapAggro>& aggros() { return m_aggros; }
      const QPixmap& image() const { return m_image; }
      bool imageLoaded() const { return m_imageLoaded; }
      bool mapLoaded() const { return m_mapLoaded; }
      bool isAggro(const QString& name, uint16_t* range) const;
    
      // make sure map is big enough, returns true if size modified
      bool checkPos(int16_t x, int16_t y);
      void quickCheckPos(int16_t x, int16_t y);
      void updateBounds();
    
      // map editing
      void addLocation(const QString& name, const QString& color, const QPoint& point);
      void setLocationName(const QString& name);
      void setLocationColor(const QString& color);
      void startLine(const QString& name, const QString& color, const MapPoint& point);
      void addLinePoint(const MapPoint& point);
      void delLinePoint(void);
      void setLineName(const QString& name);
      void setLineColor(const QString& color);
      void setFileName(const QString& name) { m_fileName = name; }
      void setZoneLongName(const QString& name) { m_zoneShortName = name; }
      void setZoneShortName(const QString& name) { m_zoneLongName = name; }
      void setZoneZEM(uint8_t zem) { m_zoneZEM = zem; }
      void scaleDownZ(int16_t factor);
      void scaleUpZ(int16_t factor);
    
      // map painting
      void paintGrid(MapParameters& param, QPainter& p) const;
      void paintLines(MapParameters& param, QPainter& p) const;
      void paintDepthFilteredLines(MapParameters& param, QPainter& p) const;
      void paintFadedFloorsLines(MapParameters& param, QPainter& p) const;
      void paintLocations(MapParameters& param, QPainter& p) const;
      bool paintMapImage(MapParameters& param, QPainter& p) const;
    
     private:
      int16_t m_minX;
      int16_t m_minY;
      int16_t m_maxX;
      int16_t m_maxY;
      QRect m_boundingRect;
      QSize m_size;
      QString m_fileName;
      QString m_zoneLongName;
      QString m_zoneShortName;
      QPtrList<MapLineL> m_lLines;
      QPtrList<MapLineM> m_mLines;
      MapLineM* m_editLineM;
      QPtrList<MapLocation> m_locations;
      MapLocation* m_editLocation;
      QPtrList<MapAggro> m_aggros;
      uint8_t m_zoneZEM;
      QPixmap m_image;
      bool m_imageLoaded;
      bool m_mapLoaded;
    };
    
    inline
    bool MapData::checkPos(int16_t x, int16_t y)
    {
      bool flag = false;
    
    #if defined(MAP_DEBUG)
      printf("in x: %i, in y: %i, max(%i,%i) Min(%i,%i)\n", x, y, m_maxX, m_maxY, m_minX, m_minY);
    #endif /* MAP_DEBUG */
    
      if (x > m_maxX)
      {
        m_maxX = x;
        flag = true;
      }
      if (y > m_maxY)
      {
        m_maxY = y;
        flag = true;
      }
      if (x < m_minX)
      {
        m_minX = x;
        flag = true;
      }
      if (y < m_minY)
      {
        m_minY = y;
        flag = true;
      }
    
      // update the boundary information if bounds changed
      if (flag)
        updateBounds();
    
      return flag;
    }
    
    inline
    void MapData::quickCheckPos(int16_t x, int16_t y)
    {
      // quick, no-nonsense checking of the bounds, for batch use.
      // call updateBounds() after finished with the batch
      if (x > m_maxX)
        m_maxX = x;
      if (y > m_maxY)
        m_maxY = y;
      if (x < m_minX)
          m_minX = x;
      if (y < m_minY)
        m_minY = y;
    }
    
    inline
    void MapData::updateBounds()
    {
      // update the boundary information
      m_boundingRect =  QRect(QPoint(m_minX, m_minY), QPoint(m_maxX, m_maxY));
      m_size.setWidth(m_boundingRect.width());
      m_size.setHeight(m_boundingRect.height());
    }
    
    //----------------------------------------------------------------------
    // MapCache
    class MapCache 
    {
     public:
      MapCache(const MapData& data);
      ~MapCache();
    
      const QPixmap& getMapImage(MapParameters& param);
    
      // get methods
      bool needRepaint(MapParameters& param);
      bool alwaysRepaint() const { return m_alwaysRepaint; }
    #ifdef DEBUG
      uint32_t paintCount() const { return m_paintCount; }
    #endif
    
      // set methods
      void setAlwaysRepaint(bool val) { m_alwaysRepaint = val; }
      void forceRepaint() { m_painted = false; }
      
     private:
      const MapData& m_mapData;
      QPixmap m_mapImage;
      MapParameters m_lastParam;
    #ifdef DEBUG
      uint32_t m_paintCount;
    #endif
      bool m_painted;
      bool m_alwaysRepaint;
    };
    
    //----------------------------------------------------------------------
    // assorted utility functions
    inline bool inRect(const QRect& rect, 
    		   const int16_t& x, 
    		   const int16_t& y)
    {
      return ((rect.left() <= x) && (rect.right() >= x) &&
    	  (rect.top() <= y) && (rect.bottom() >= y));
    }
    
    inline bool inRoom(const int16_t& headRoom, 
    		   const int16_t& floorRoom, 
    		   const int16_t& z)
    {
      return ((z <= headRoom) &&
    	  (z >= floorRoom));
    }
    
    #endif // _MAPCORE_H
    Code:
    /*
     * mapcore.cpp
     *
     *  ShowEQ Distributed under GPL
     *  http://seq.sf.net/
     * 
     * Portions Copyright 2001-2007 Zaphod ([email protected]). 
     * 
     */
    
    // Author: Zaphod ([email protected])
    //    Many parts derived from existing ShowEQ/SINS map code
    
    //
    // NOTE: Trying to keep this file ShowEQ/Everquest independent to allow it
    // to be reused for other Show{} style projects.  Any existing ShowEQ/EQ
    // dependencies will be migrated out.
    //
    
    //#define DEBUGMAPLOAD
    
    #include "mapcore.h"
    #include "diagnosticmessages.h"
    
    #include <errno.h>
    
    #include <qpainter.h>
    #include <qstring.h>
    #include <qstringlist.h>
    #include <qfileinfo.h>
    #include <qfile.h>
    #include <qregexp.h>
    
    //----------------------------------------------------------------------
    // MapParameters
    MapParameters::MapParameters(const MapData& mapData)
      : m_mapData(&mapData),
        m_curPlayer(0, 0, 0),
        m_screenLength(600, 600)
    {
      m_zoomDefault = 1;
      m_screenCenter = QPoint(300, 300);
      m_zoomMapLength = QSize(100, 100);
      m_panOffsetX = 0;
      m_panOffsetY = 0;
      m_ratio = 1.0;
    
      // calculate fixed point inverse ratio using the defiend qFormat 
      // for calculate speed purposes (* is faster than /)
      m_ratioIFixPt = fixPtToFixed<int, double>((1.0 / m_ratio), qFormat);
    
      m_targetPoint = MapPoint(0, 0, 0);
      m_targetPointSet = false;
    
      m_gridResolution = 500;
      m_gridTickColor.setRgb(225, 200, 75);
      m_gridLineColor.setRgb(75, 200, 75);
      m_backgroundColor = Qt::black;
    
      m_headRoom = 75;
      m_floorRoom = 75;
    
      m_mapLineStyle = tMap_Normal;
      m_showBackgroundImage = true;
      m_showLocations = true;
      m_showLines = true;
      m_showGridLines = true;
      m_showGridTicks = true;
      m_optimization = tMap_NormalOptim;
    
      reset();
    }
    
    MapParameters::~MapParameters()
    {
    }
    
    void MapParameters::reset()
    {
      m_zoom = m_zoomDefault;
      m_panOffsetX = 0;
      m_panOffsetY = 0;
    }
    
    void MapParameters::reAdjust(MapPoint* targetPoint)
    {
      if (targetPoint)
      {
        m_targetPoint = *targetPoint;
        m_targetPointSet = true;
      }
      else
      {
        m_targetPoint.setPoint(0, 0, 0);
        m_targetPointSet = false;
      }
    
      reAdjust();
    }
    
    void MapParameters::reAdjust()
    {
      // get the map length
      const QSize& mapSize = m_mapData->size();
    
      if (m_zoom > 32)
        m_zoom = 32;
    
      // calculate zoomed map size
      int pxrat = ((mapSize.width()) / (m_zoom));
      int pyrat = ((mapSize.height()) / (m_zoom));
    
      // if it's a bit small, zoom out
      if ((pxrat <= 2) || (pyrat <= 2))
      {
         if (m_zoom > 1) 
         {
           m_zoom /= 2; 
           if (m_zoom == 1) 
    	 clearPan();
    
           // recalculate zoomed map size
           pxrat = ((mapSize.width()) / (m_zoom));
           pyrat = ((mapSize.height()) / (m_zoom));
         }
      }
    
      // save zoomed map size
      m_zoomMapLength.setWidth(pxrat);
      m_zoomMapLength.setHeight(pyrat);
    
      double xrat = (double)m_screenLength.width() / m_zoomMapLength.width();
      double yrat = (double)m_screenLength.height() / m_zoomMapLength.height();
    
      int xoff = 0;
      int yoff = 0;
    
      if (xrat < yrat) 
      {
        m_zoomMapLength.setHeight((int)(m_screenLength.height() / xrat));
        if (m_zoom <= 1)
          yoff = (m_zoomMapLength.height() - pyrat) >> 1;
      } 
      else if (yrat) 
      {
        m_zoomMapLength.setWidth((int)(m_screenLength.width() / yrat));
        if (m_zoom <= 1)
          xoff = (m_zoomMapLength.width() - pxrat) >> 1;
      }
    
      // calculate the scaling ratio to use
      m_ratio = (double)m_zoomMapLength.width() / (double)m_screenLength.width();
    
      // calculate fixed point inverse ratio using the defined qFormat 
      // for calculate speed purposes (* is faster than /)
      m_ratioIFixPt = fixPtToFixed<int, double>((1.0 / m_ratio), qFormat);
    
      int iZMaxX, iZMinX, iZMaxY, iZMinY;
    
      // center on the target based on target
      if (m_targetPointSet)
      {
        iZMaxX = m_targetPoint.x() + m_panOffsetX +( m_zoomMapLength.width() >> 1);
        iZMinX = m_targetPoint.x() + m_panOffsetX - (m_zoomMapLength.width() >> 1);
        
        iZMaxY = m_targetPoint.y() + m_panOffsetY + (m_zoomMapLength.height() >> 1);
        iZMinY = m_targetPoint.y() + m_panOffsetY - (m_zoomMapLength.height() >> 1);
      }
      else
      {
        iZMaxX = m_panOffsetX + (m_zoomMapLength.width() >> 1);
        iZMinX = m_panOffsetX - (m_zoomMapLength.width() >> 1);
        
        iZMaxY = m_panOffsetY + (m_zoomMapLength.height() >> 1);
        iZMinY = m_panOffsetY - (m_zoomMapLength.height() >> 1);
      }
    
      // try not to have blank space on the sides
      if (iZMinX < m_mapData->minX())
      {
        iZMaxX -= (iZMinX - m_mapData->minX());
        iZMinX -= (iZMinX - m_mapData->minX());
      }
      if (iZMinY < m_mapData->minY())
      {
        iZMaxY -= (iZMinY - m_mapData->minY());
        iZMinY -= (iZMinY - m_mapData->minY());
      }
    
      if (iZMaxX > m_mapData->maxX())
      {
        iZMinX -= iZMaxX - m_mapData->maxX();
        iZMaxX -= iZMaxX - m_mapData->maxX();
      }
      if (iZMaxY > m_mapData->maxY())
      {
        iZMinY -= (iZMaxY - m_mapData->maxY());
        iZMaxY -= (iZMaxY - m_mapData->maxY());
      }
    
      // calculate the new screen center
      m_screenCenter.setX((((iZMaxX + xoff) * m_screenLength.width()) / 
    		       m_zoomMapLength.width()));
      m_screenCenter.setY((((iZMaxY + yoff) * m_screenLength.height()) / 
    		       m_zoomMapLength.height()));
    
      // calculate screen bounds
      m_screenBounds = QRect(int((m_screenCenter.x() - m_screenLength.width()) * 
    			     m_ratio),
    			 int((m_screenCenter.y() - m_screenLength.height()) * 
    			     m_ratio),
    			 int(m_screenLength.width() * m_ratio),
    			 int(m_screenLength.height() * m_ratio));
    
    
      // adjust pre-calculate player offsets
      m_curPlayerOffset.setX(calcXOffset(m_curPlayer.x()));
      m_curPlayerOffset.setY(calcYOffset(m_curPlayer.y()));
    }
    
    QPixmap::Optimization MapParameters::pixmapOptimizationMethod()
    {
      switch (m_optimization)
      {
      case tMap_MemoryOptim:  
        return QPixmap::MemoryOptim; 
      case tMap_NoOptim:
        return QPixmap::NoOptim; 
      case tMap_NormalOptim:  
        return QPixmap::NormalOptim;
      case tMap_BestOptim:  
        return QPixmap::BestOptim;
      case tMap_DefaultOptim:
      default: 
        return QPixmap::DefaultOptim;
      }
       /* Optimization Methods:
            DefaultOptim - A pixmap with this optimization mode set always has the default optimization type
                   - default optimization type for qPixMap is NormalOptim
            NoOptim      - no optimization (currently the same as MemoryOptim).
            MemoryOptim  - optimize for minimal memory use. 
            NormalOptim  - optimize for typical usage. Often uses more memory than MemoryOptim, and often faster. 
            BestOptim    - optimize for pixmaps that are drawn very often and where performance is critical.
                           Generally uses more memory than NormalOptim and may provide a little better speed
       */
    }
    
    void MapParameters::setPlayer(const MapPoint& pos)
    { 
      m_curPlayer = pos; 
    
      // re-calculate precomputed player head/floor room
      m_playerHeadRoom = m_curPlayer.z() + m_headRoom;
      m_playerFloorRoom = m_curPlayer.z() - m_floorRoom;
    
      m_curPlayerOffset.setX(calcXOffset(m_curPlayer.x()));
      m_curPlayerOffset.setY(calcYOffset(m_curPlayer.y()));
    }
    
    void MapParameters::setHeadRoom(int16_t headRoom)
    { 
      m_headRoom = headRoom; 
    
      // re-calculate precomputed player head/floor room
      m_playerHeadRoom = m_curPlayer.z() + m_headRoom;
    }
    
    void MapParameters::setFloorRoom(int16_t floorRoom) 
    { 
      m_floorRoom = floorRoom; 
    
      // re-calculate precomputed player head/floor room
      m_playerFloorRoom = m_curPlayer.z() - m_floorRoom;
    }
    
    //----------------------------------------------------------------------
    // MapCommon
    MapCommon::~MapCommon()
    {
    }
    
    //----------------------------------------------------------------------
    // MapLineL
    MapLineL::MapLineL()
      : MapCommon(), m_z(0), m_heightSet(false)
    {
    }
    
    MapLineL::MapLineL(const QString& name, 
    		   const QString& color, 
    		   uint32_t size)
      : MapCommon(name, color),
        QPointArray(size), 
        m_z(0),
        m_heightSet(false)
    {
    }
    
    MapLineL::MapLineL(const QString& name, 
    		   const QString& color, 
    		   uint32_t size, 
    		   int16_t z)
      : MapCommon(name, color),
        QPointArray(size), 
        m_z(z),
        m_heightSet(true)
    {
    }
    
    MapLineL::~MapLineL()
    {
    }
    
    //----------------------------------------------------------------------
    // MapLineM
    MapLineM::MapLineM()
      : MapCommon()
    {
    }
    
    MapLineM::MapLineM(const QString& name, const QString& color, uint32_t size)
      : MapCommon(name, color),
        MapPointArray(size)
    {
    }
    
    MapLineM::MapLineM(const QString& name, const QColor& color, uint32_t size)
      : MapCommon(name, color),
        MapPointArray(size)
    {
    }
    
    MapLineM::MapLineM(const QString& name, const QString& color, const MapPoint& point)
      : MapCommon(name, color),
        MapPointArray(1)
    {
      // set the first point
      setPoint(0, point);
    }
    
    MapLineM::~MapLineM()
    {
    }
    
    //----------------------------------------------------------------------
    // MapLocation
    MapLocation::MapLocation()
    {
    }
    
    MapLocation::MapLocation(const QString& name, 
    			 const QString& color, 
    			 const QPoint& point)
      : MapCommon(name, color),
        MapPoint(point),
        m_heightSet(false)
    {
    }
    
    MapLocation::MapLocation(const QString& name, 
    			 const QString& color, 
    			 const MapPoint& point)
      : MapCommon(name, color),
        MapPoint(point),
        m_heightSet(true)
    {
    }
    
    MapLocation::MapLocation(const QString& name, 
    			 const QString& color, 
    			 int16_t x, 
    			 int16_t y)
      : MapCommon(name, color),
        MapPoint(x, y, 0),
        m_heightSet(false)
    {
    }
    
    MapLocation::MapLocation(const QString& name, 
    			 const QString& color, 
    			 int16_t x, 
    			 int16_t y, 
    			 int16_t z)
      : MapCommon(name, color),
        MapPoint(x, y, z),
        m_heightSet(true)
    {
    }
    
    MapLocation::MapLocation(const QString& name, 
    			 const QColor& color, 
    			 int16_t x, 
    			 int16_t y,
    			 int16_t z)
      : MapCommon(name, color),
        MapPoint(x, y, z),
        m_heightSet(true)
    {
    }
    
    MapLocation::~MapLocation()
    {
    }
    
    //----------------------------------------------------------------------
    // MapAggro
    MapAggro::~MapAggro()
    {
    }
    
    
    //----------------------------------------------------------------------
    // MapData
    MapData::MapData()
    {
      // make all lists auto delete
      m_lLines.setAutoDelete(true);
      m_mLines.setAutoDelete(true);
      m_locations.setAutoDelete(true);
      m_aggros.setAutoDelete(true);
    
      // clear the structure
      clear();
    }
    
    MapData::~MapData()
    {
    }
    
    void MapData::clear()
    {
      m_fileName = "";
      m_zoneLongName = "";
      m_zoneShortName = "";
      m_minX = -50;
      m_maxX = 50;
      m_minY = -50;
      m_maxY = 50;
      updateBounds();
      m_lLines.clear();
      m_mLines.clear();
      m_locations.clear();
      m_aggros.clear();
    
      m_mapLoaded = false;
      m_imageLoaded = false;
      
      m_editLineM = NULL;
      m_editLocation = NULL;
      m_zoneZEM = 75;
    }
    
    void MapData::loadMap(const QString& fileName, bool import)
    {
      int16_t mx, my, mz;
      uint numPoints;
      int16_t globHeight=0;
      bool globHeightSet = false;
      int filelines = 1;  // number of lines in map file
      QString name;
      QString color;
      uint16_t rangeVal;
      uint32_t linePoints;
      uint32_t specifiedLinePoints;
      MapLineL* currentLineL = NULL;
      MapLineM* currentLineM = NULL;
    
      // set the map filename
      setFileName(fileName);
    
      // clear any existing map data (if not importing)
      if (!import)
        clear();
    
      /* Kind of stupid to try a non-existant map, don't you think? */
      if (fileName.contains("/.map") != 0)
        return;
    
      
      const char* filename = (const char*)fileName;
    
      QFile mapFile(fileName);
    
      if (!mapFile.open(IO_ReadOnly))
      {
        seqWarn("Error opening map file '%s'!", filename);
    
        return;
      }
    
      // note the file name 
      m_fileName = filename;
        
      // allocate memory in a QCString to hold the entire file contents
      QCString textData(mapFile.size() + 1);
      
      // read the file as one big chunk
      mapFile.readBlock(textData.data(), textData.size());
      
      // construct a regex to deal with either style line termination
      QRegExp lineTerm("[\r\n]{1,2}");
    
      // split the data into lines at the line termination
      QStringList lines = QStringList::split(lineTerm, 
    					 QString::fromUtf8(textData), false);
    
    
      // start iterating over the lines
      QStringList::Iterator lit = lines.begin();
    
      filelines = 1;
    
    #ifdef DEBUGMAPLOAD
      seqDebug("Zone info line: %s", (const char*)(*lit));
    #endif
    
      QString fieldSep = ",";
    
      // split the line into fields
      QStringList fields = QStringList::split(fieldSep, *lit);
    
      size_t count = fields.count();
      if (!count)
      {
        seqWarn("Error, no fields in first line of map file '%s'",
    	    filename);
        return;
      }
      
      if (count < 2)
      {
        seqWarn("Error, too few fields in first line of map file '%s'",
    	    filename);
        return;
      }
    
      // start iterator over the fields
      QStringList::Iterator fit = fields.begin();
    
      m_zoneLongName = (*fit++);
      m_zoneShortName = (*fit++);
    
      if (count > 2)
      {
        m_size.setWidth((*fit++).toInt());
        m_size.setHeight((*fit++).toInt());
      }
    
      // start looping at the next map line
      for (++lit; lit != lines.end(); ++lit)
      {
        // increment line count
        filelines++;
         
    #ifdef DEBUGMAPLOAD
        seqWarn("Map line %d: %s", filelines, (const char*)*lit);
    #endif
    
        // split the line into fields
        fields = QStringList::split(fieldSep, *lit);
    
        // skip empty lines
        if (fields.isEmpty())
          continue;
    
        // entry type is the first character of the line
        QChar entryType = fields.first().at(0);
    
        // pop the entry type off the front of the fields list
        fields.pop_front();
    
        // start at the first argument to the entry
        fit = fields.begin();
    
        // get the field count
        count = fields.count();
    
        bool ok;
    
        switch (entryType) 
        {
        case 'M':
          {
    #ifdef DEBUGMAPLOAD
    	seqDebug("M record  [%d] [%d fields]: %s", 
    		 filelines, count, (const char*)*lit);
    #endif
    	
    	if (count < 3)
    	{
    	  seqWarn("Error reading M line %d on map '%s'! %d is too few fields",
    		  filelines, filename, count);
    	  continue;
    	}
    	
    	// calculate the number of line points
    	linePoints = ((count - 3) / 3);
    	
    	// only bother going forward if there will be enough line points
            if (linePoints < 2)
    	{
    	  seqWarn("M Line %d in map '%s' only had %d points, not loading.",
    		  filelines, filename, linePoints );
    	  continue;
    	}
    	
    	// Line Name
    	name = (*fit++);
    	
    	// Line Color
    	color = (*fit++);
    	if (color.isEmpty()) 
    	  color = "#7F7F7F";
    	
    	// Number of points
    	specifiedLinePoints = (*fit++).toUInt(&ok);
    	if (!ok) 
    	{
    	  seqWarn("Error reading number of points on line %d in map '%s'!",
    		  filelines, filename);
    	  continue;
    	}
    	
    	if ((specifiedLinePoints != linePoints) && (specifiedLinePoints != 0))
    	{
    	  seqWarn("M Line %d in map '%s' has %d points as opposed to the %d points it specified!", 
    		  filelines, filename, linePoints, specifiedLinePoints);
    	}
    	
    	// create an M line
    	currentLineM = new MapLineM(name, color, linePoints);
    
    	numPoints = 0;
    	while ((fit != fields.end()) && (numPoints < linePoints))
            {
    	  // X coord
    	  mx = (*fit++).toShort();
    	  my = (*fit++).toShort();
    	  mz = (*fit++).toShort();
    
    	  // set the point data
    	  currentLineM->setPoint(numPoints, mx, my, mz);
    	  
    	  // increment point count
    	  numPoints++;
    	}
    	
    	// calculate the XY bounds of the line
    	currentLineM->calcBounds();
    	
    	// get the bounding rect
    	const QRect& bounds = currentLineM->boundingRect();
    	
    	// adjust map boundaries based on the bounding rect
    	quickCheckPos(bounds.left(), bounds.top());
    	quickCheckPos(bounds.right(), bounds.bottom());
    	
    	// add it to the list of L lines
    	m_mLines.append(currentLineM);
          }
          break;
    	
        case 'L':
          {
    #ifdef DEBUGMAPLOAD
    	seqDebug("L record  [%d] [%d fields] %s", 
    		filelines, count, (const char*)*lit);
    #endif
    	
    	if (count < 3)
            {
    	  seqWarn("Error reading L line %d on map '%s'! %d is too few fields",
    		  filelines, filename, count);
    	  continue;
    	}
    
    	// calculate the number of line points
    	linePoints = ((count - 3) >> 1);
    	
    	// only bother going forward if there will be enough line points
    	if (linePoints < 2)
    	{
    	  seqWarn("L Line %d in map '%s' only had %d points, not loading.",
    		  filelines, filename, linePoints);
    	  continue;
    	}
    	
    	// Line Name
    	name = (*fit++);
    	
    	// Line Color
    	color = (*fit++);
    	if (color.isEmpty()) 
    	  color = "#7F7F7F";
    	
    	// Number of points
    	specifiedLinePoints = (*fit++).toUInt(&ok);
    	if (!ok) 
    	{
    	  seqWarn("Error reading number of points on line %d in map '%s'!",
    		  filelines, filename);
    	  continue;
    	}
    	
    	if ((specifiedLinePoints != linePoints) && (specifiedLinePoints != 0))
    	{
    	   seqWarn("L Line %d in map '%s' has %d points as opposed to the %d points it specified!", 
    		  filelines, filename, linePoints, specifiedLinePoints);
    	}
    	
    	// create the appropriate style L line depending on if the global 
    	// height has been set
    	if (globHeightSet)
    	  currentLineL = new MapLineL(name, color, linePoints, globHeight);
    	else
    	  currentLineL = new MapLineL(name, color, linePoints);
    
    	numPoints = 0;
    	
    	// keep going until we run out of fields... 
    	while ((fit != fields.end()) && (numPoints < linePoints))
            {
    	  // X coord
    	  mx = (*fit++).toShort();
    	  
    	  // Y coord
    	  my = (*fit++).toShort();
    	  
    	  // store the point
    	  currentLineL->setPoint(numPoints, mx, my);
    	  
    	  // increment point count
    	  numPoints++;
    	}
    	
    	// calculate the XY bounds of the line
    	currentLineL->calcBounds();
    	
    	// get the bounding rect
    	const QRect& bounds = currentLineL->boundingRect();
    	
    	// adjust map boundaries based on the bounding rect
    	quickCheckPos(bounds.left(), bounds.top());
    	quickCheckPos(bounds.right(), bounds.bottom());
    	
    	// add it to the list of L lines
    	m_lLines.append(currentLineL);
          }
          break;
    
        case 'P':
          {
    #ifdef DEBUGMAPLOAD
    	seqWarn("P record [%d] [%d fields]: %s", 
    		filelines, count, (const char*)*lit);
    #endif
    
    	if (count < 4)
            {
    	  seqWarn("Error reading P line %d on map '%s'! %d is too few fields",
    		  filelines, filename, count);
    	  continue;
    	}
    
    	name = (*fit++); // Location name
    	color = (*fit++); // Location color
    	mx = (*fit++).toShort();
    	my = (*fit++).toShort();
    
    	if (count == 5)
    	{
    	  mz = (*fit++).toShort();
    	  
    	  // add the appropriate style Location depending on if the global height is set
    	  m_locations.append(new MapLocation(name, color, mx, my, mz));
    	}
    	  
    	// add the appropriate style Location depending on if the global 
    	// height has been set
    	if (globHeightSet)
    	  m_locations.append(new MapLocation(name, color, mx, my, globHeight));
    	else
    	  m_locations.append(new MapLocation(name, color, mx, my));
    	
    	// adjust map boundaries
    	quickCheckPos(mx, my);
          }
          break;
    
        case 'A':  //Creates aggro ranges.
          {
    #ifdef DEBUGMAPLOAD
    	seqWarn("A record  [%d] [%d fields]: %s",
    		filelines, count, (const char*)*lit);
    #endif
    	
    	if (count < 2)
            {
    	  seqWarn("Line %d in map '%s' has an A record with too few fields (%d)!",
    		  filelines, filename, count);
    	  break;
    	}
    	
    	name = (*fit++);
    	if (name.isEmpty()) 
            {
    	  seqWarn("Line %d in map '%s' has an A marker with no Name expression!", 
    		  filelines, filename);
    	  break;
    	}
    	rangeVal = (*fit++).toUShort();
    	if (!rangeVal) 
            {
    	  seqWarn("Line %d in map '%s' has an A marker with no or 0 Range radius!", 
    		  filelines, filename);
    	  break;
    	}
    	
    	// create and add a new aggro object
    	m_aggros.append(new MapAggro(name, rangeVal));
    	
    	break;
          case 'H':  //Sets global height for L lines.
    #ifdef DEBUGMAPLOAD
    	seqDebug("H record [%d] [%d fields]: %s", 
    		filelines, count, (const char*)*lit);
    #endif
    	
    	if (count < 1)
            {
    	  seqWarn("Line %d in map '%s' has an H record with too few fields (%d)!", 
    		  filelines, filename, count);
    	  break;
    	}
    	
    	// get global height
    	globHeight = (*fit++).toShort(&ok);
    	if (!ok) 
            {
    	  seqWarn("Line %d in map '%s' has an H marker with invalid Z!", 
    		  filelines, filename);
    	  break;
    	}
    	globHeightSet = true;
          }
          break;
    
        case 'Z':  // Quick and dirty ZEM implementation
          {
    #ifdef DEBUGMAPLOAD
    	seqWarn("Z record [%d] [%d fields]: %s", 
    		filelines, count, (const char*)*lit);
    #endif
    	
    	if (count < 1)
            {
    	  seqWarn("Line %d in map '%s' has a Z record with too few fields (%d)!", 
    		  filelines, filename, count);
    	  break;
    	}
    	
    	m_zoneZEM = (*fit++).toUShort(&ok);
    	if (!ok) 
            {
    	  seqWarn("Line %d in map '%s' has an Z marker with invalid ZEM!", 
    		  filelines, filename);
    	  break;
    	}
    #ifdef DEBUGMAPLOAD
    	seqDebug("ZEM set to %d", m_zoneZEM);
    #endif
          }
          break;
    
        }
      }
    
      // calculate the bounding rect
      updateBounds();
    
      m_mapLoaded = true;
      
      m_imageLoaded = false;
      QString imageFileName = filename;
      imageFileName.truncate(imageFileName.findRev('.'));
      imageFileName += ".pgm";
    
      if (m_image.load(imageFileName))
      {
        m_imageLoaded = true;
        seqInfo("Loaded map image: '%s'", (const char*)imageFileName);
      }
    
      seqInfo("Loaded map: '%s'", filename);
    }
    
    void MapData::loadSOEMap(const QString& fileName, bool import)
    {
      int16_t x1, y1, z1;
      int16_t x2, y2, z2;
      MapPoint src, dest, oldSrc;
      uint8_t r, g, b;
      uint32_t numPoints = 0;
      uint32_t checkPoint = 0;
      int filelines = 1;  // number of lines in map file
      QString name;
      MapLineM* currentLineM = 0;
      size_t count;
    
      // if the same map is already loaded, don't reload it.
      if (m_mapLoaded && (m_fileName.lower() == fileName.lower()))
        return;
    
      // set the map filename
      setFileName(fileName);
    
      // clear any existing map data if not importing
      if (!import)
        clear();
    
      /* Kind of stupid to try a non-existant map, don't you think? */
      if (fileName.contains("/.txt") != 0)
        return;
      
      const char* filename = (const char*)fileName;
    
      QFile mapFile(fileName);
    
      if (!mapFile.open(IO_ReadOnly))
      {
        seqWarn("Error opening map file '%s'!", filename);
    
        return;
      }
    
      // note the file name 
      m_fileName = filename;
        
      // allocate memory in a QCString to hold the entire file contents
      QCString textData(mapFile.size() + 1);
      
      // read the file as one big chunk
      mapFile.readBlock(textData.data(), textData.size());
      
      // construct a regex to deal with either style line termination
      QRegExp lineTerm("[\r\n]{1,2}");
    
      // split the data into lines at the line termination
      QStringList lines = QStringList::split(lineTerm, 
    					 QString::fromUtf8(textData), false);
    
    
      // start iterating over the lines
      QStringList::Iterator lit = lines.begin();
    
      filelines = 1;
    
      QRegExp fieldSep(",\\s*");
    
      // split the line into fields
      QStringList fields;
      QStringList::Iterator fit;
    
      // use the file base name as the zone long/short name, it isn't perfect,
      // but neither is this file format
      QFileInfo fileInfo(m_fileName);
      QRegExp reStripTrailer("_[1-3]");
      
      m_zoneLongName = fileInfo.baseName().remove(reStripTrailer);
      m_zoneShortName = m_zoneLongName;
    
      // start looping at the next map line
      for (; lit != lines.end(); ++lit)
      {
        // increment line count
        filelines++;
         
    #ifdef DEBUGMAPLOAD
        seqDebug("Map line %d: %s", filelines, (const char*)*lit);
    #endif
    
        // entry type is the first character of the line
        QChar entryType = (*lit).at(0);
    
        // remove the entryType and the leading space
        (*lit).remove(0, 2);
    
        // split the line into fields
        fields = QStringList::split(fieldSep, *lit);
    
        // skip empty lines
        if (fields.isEmpty())
          continue;
    
        // start at the first argument to the entry
        fit = fields.begin();
    
        // get the field count
        count = fields.count();
    
        switch (entryType) 
        {
        case 'L':
          {
    #ifdef DEBUGMAPLOAD
    	seqDebug("L record  [%d] [%d fields]: %s", 
    		filelines, count, (const char*)*lit);
    #endif
    	
    	if (count != 9)
    	{
    	  seqWarn("Error reading L line %d on map '%s'! %d is an incorrect field count!",
    		  filelines, filename, count);
    	  continue;
    	}
    
    	x1 = -int16_t((*fit++).toFloat());
    	y1 = -int16_t((*fit++).toFloat());
    	z1 = int16_t((*fit++).toFloat());
    	x2 = -int16_t((*fit++).toFloat());
    	y2 = -int16_t((*fit++).toFloat());
    	z2 = int16_t((*fit++).toFloat());
    	r = (*fit++).toUShort();
    	g = (*fit++).toUShort();
    	b = (*fit).toUShort();
    	
    	if (!currentLineM || 
    	    !currentLineM->point(checkPoint).isEqual(x2, y2, z2) ||
    	    (currentLineM->color().red() != r) ||
    	    (currentLineM->color().green() != g) ||
    	    (currentLineM->color().blue() != b))
    	{
    	  numPoints = 0;
    
    	  // create an M line (start with 2 points because of SOE's lame
    	  // format).
    	  currentLineM = new MapLineM("soe", QColor(r, g, b), 2);
    
    	  // set the first point
    	  currentLineM->setPoint(numPoints++, x2, y2, z2);
    	  
    	  // set the second point
    	  currentLineM->setPoint(checkPoint = numPoints++, x1, y1, z1);
    	
    	  // add it to the list of M lines
    	  m_mLines.append(currentLineM);
    	}
    	else 
    	{
    	  // if necessary, add room for a point
    	  if (currentLineM->size() < (numPoints+1))
    	    currentLineM->resize(numPoints+1);
    
    	  // add the point
    	  currentLineM->setPoint(checkPoint = numPoints++, x1, y1, z1);
    	}
    
    	// calculate the XY bounds of the line
    	currentLineM->calcBounds();
    	
    	// get the bounding rect
    	const QRect& bounds = currentLineM->boundingRect();
    	
    	// adjust map boundaries based on the bounding rect
    	quickCheckPos(bounds.left(), bounds.top());
    	quickCheckPos(bounds.right(), bounds.bottom());
          }
          break;
    
        case 'P':
          {
    #ifdef DEBUGMAPLOAD
    	seqDebug("P record [%d] [%d fields]: %s", 
    		filelines, count, (const char*)*lit);
    #endif
    	
    	if (count != 8)
    	{
    	  seqWarn("Error reading L line %d on map '%s'! %d is an incorrect field count!",
    		  filelines, filename, count);
    	  continue;
    	}
    
    	// get all the fields
    	x1 = -int16_t((*fit++).toFloat());
    	y1 = -int16_t((*fit++).toFloat());
    	z1 = int16_t((*fit++).toFloat());
    	r = (*fit++).toUShort();
    	g = (*fit++).toUShort();
    	b = (*fit++).toUShort();
    	fit++; // skip unknown
    	name = (*fit); // Location name, conver
    	
    	// convert underscores to spaces.
    	name.replace("_", " ");
    
    	// add it to the list of locations
    	m_locations.append(new MapLocation(name, QColor(r, g, b), 
    					   x1, y1, z1));
    	
    	// adjust map boundaries
    	quickCheckPos(x1, y1);
          }
          break;
    
        }
      }
    
      // calculate the bounding rect
      updateBounds();
    
      m_mapLoaded = true;
      
      m_imageLoaded = false;
      QString imageFileName = filename;
      imageFileName.truncate(imageFileName.findRev('.'));
      imageFileName += ".pgm";
    
      if (m_image.load(imageFileName))
      {
        m_imageLoaded = true;
        seqInfo("Loaded map image: '%s'", (const char*)imageFileName);
      }
    
      seqInfo("Loaded SOE map: '%s'", filename);
    }
    
    void MapData::saveMap(const QString& fileName) const
    {
    #ifdef DEBUG
      debug ("saveMap()");
    #endif /* DEBUG */
      FILE * fh;
      uint32_t i;
    
      const char* filename;
      if (!fileName.isEmpty())
        filename = (const char*)fileName;
      else 
        filename = (const char*)m_fileName;
    
      if ((fh = fopen(filename, "w")) == NULL) 
      {
        seqWarn("Error saving map '%s'!", filename);
        return;
      }
      
      // write out header info
      fprintf(fh, "%s,%s,%d,%d\n", 
    	  (const char*)m_zoneLongName, (const char*)m_zoneShortName,
    	  m_size.width(), m_size.height());
    
      // write out ZEM info if non-default
      if (m_zoneZEM != 75)
        fprintf(fh, "Z,%i\n", m_zoneZEM);
    
      // write out the L (2D) lines with possible fixed Z
      bool heightSet = false;
      int16_t lastHeightSet = 0;
      MapLineL* currentLineL;
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
      {
        // was the global height set?
        if (currentLineL->heightSet())
        {
          // if no height was set previously, or this one doesn't match the previously
          // set height, write out an H record
          if ((!heightSet) || (lastHeightSet != currentLineL->z()))
          {
    	// write out an H record.
    	fprintf(fh, "H,%i\n", currentLineL->z());
    
    	// note the last height set, and that it was set
    	lastHeightSet = currentLineL->z();
    	heightSet = true;
          }
        }
    
        // write out the start of the line info
        fprintf (fh, "L,%s,%s,%d", 
    	     (const char*)currentLineL->name(), 
    	     (const char*)currentLineL->colorName(), 
    	     currentLineL->size());
    
        // write out all the 2D points in the line
        for(i = 0; i < currentLineL->size(); i++)
        {
          QPoint curQPoint = currentLineL->point(i);
          fprintf (fh, ",%d,%d", curQPoint.x(), curQPoint.y());
        }
    
        // terminate the line
        fprintf (fh, "\n");
      }
    
      // write out the M (3D) lines
      MapLineM* currentLineM;
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        // write out the start of the line info
        fprintf (fh, "M,%s,%s,%d", 
    	     (const char*)currentLineM->name(), 
    	     (const char*)currentLineM->colorName(), 
    	     currentLineM->size());
    
        // write out all the 3D points in the line
        for(i = 0; i < currentLineM->size(); i++)
        {
          MapPoint curMPoint = currentLineM->point(i);
    
          fprintf (fh, ",%d,%d,%d", 
    	       curMPoint.x(), curMPoint.y(), curMPoint.z());
        }
        // terminate the line
        fprintf (fh, "\n");
      }
    
      // write out location information
      QPtrListIterator<MapLocation> lit(m_locations);
      for(; lit.current(); ++lit)
      {
        MapLocation* currentLoc = lit.current();
    
        if (!currentLoc->heightSet())
          fprintf (fh, "P,%s,%s,%d,%d\n", 
    	       (const char*)currentLoc->name(), 
    	       (const char*)currentLoc->colorName(), 
    	       currentLoc->x(),
    	       currentLoc->y());
        else
          fprintf (fh, "P,%s,%s,%d,%d,%d\n", 
    	       (const char*)currentLoc->name(), 
    	       (const char*)currentLoc->colorName(), 
    	       currentLoc->x(),
    	       currentLoc->y(),
    	       currentLoc->z());
      }
    
      // write out aggro information
      QPtrListIterator<MapAggro> ait(m_aggros);
      for (; ait.current(); ++ait)
      {
        MapAggro* currentAggro = ait.current();
        
        fprintf (fh, "A,%s,%d\n", 
    	     (const char*)currentAggro->name(), currentAggro->range());
      }
    
    #ifdef DEBUGMAP
      seqDebug("saveMap() - map '%s' saved with %d L lines, %d M lines, %d locations", filename,
    	 m_lLines.count(), m_mLines.count(), m_locations.count());
    #endif
      
      fclose (fh);
    
      seqInfo("Saved map: '%s'", filename);
    }
    
    void MapData::saveSOEMap(const QString& fileName) const
    {
    #ifdef DEBUG
      debug ("saveMap()");
    #endif /* DEBUG */
      FILE * fh;
      uint i;
    
      const char* filename;
      if (!fileName.isEmpty())
        filename = (const char*)fileName;
      else 
        filename = (const char*)m_fileName;
    
      if ((fh = fopen(filename, "w")) == NULL) 
      {
        seqWarn("Error saving map '%s'!", filename);
        return;
      }
      
      // write out the L (2D) lines with possible fixed Z
      uint8_t r, g, b;
      float z1;
      QString name;
      MapLineL* currentLineL;
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
      {
        z1 = float(currentLineL->z());
    
        const QColor& color = currentLineL->color();
        r = color.red();
        g = color.green();
        b = color.blue();
    
        QPoint lastQPoint = currentLineL->point(0);
        
        // write out all the 2D points in the line
        for(i = 1; i < currentLineL->size(); ++i)
        {
          const QPoint& curQPoint = currentLineL->point(i);
    
          // write out the line info
          fprintf (fh, "L %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %d, %d, %d\n", 
    	       -float(curQPoint.x()), -float(curQPoint.y()), z1,
    	       -float(lastQPoint.x()), -float(lastQPoint.y()), z1, 
    	       r, g, b);
          
          lastQPoint = curQPoint;
        }
    
        // terminate the line
        fprintf (fh, "\n");
      }
    
      // write out the M (3D) lines
      MapLineM* currentLineM;
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        const QColor& color = currentLineM->color();
        r = color.red();
        g = color.green();
        b = color.blue();
    
        MapPoint lastMPoint = currentLineM->point(0);
    
        // write out all the 3D points in the line
        for(i = 1; i < currentLineM->size() ; ++i)
        {
          const MapPoint& curMPoint = currentLineM->point(i);
    
          // write out the line info
          fprintf (fh, "L %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %d, %d, %d\n", 
    	       -float(curMPoint.x()), -float(curMPoint.y()), float(curMPoint.z()),
    	       -float(lastMPoint.x()), -float(lastMPoint.y()), float(lastMPoint.z()), 
    	       r, g, b);
          
          lastMPoint = curMPoint;
        }
      }
    
      // write out location information
      QPtrListIterator<MapLocation> lit(m_locations);
      MapLocation* currentLoc;
      for(currentLoc = lit.toFirst(); 
          currentLoc; 
          currentLoc = ++lit)
      {
        const QColor& color = currentLoc->color();
    
        // convert spaces to underscores
        name = currentLoc->name();
        name.replace(" ", "_");
    
        fprintf(fh, "P %.1f, %.1f, %.1f, %d, %d, %d, 3,  %s\n",
    	    -float(currentLoc->x()), -float(currentLoc->y()), 
    	    float(currentLoc->z()),
    	    color.red(), color.green(), color.blue(),
    	    (const char*)name);
      }
    #ifdef DEBUGMAP
      seqDebug("saveMap() - map '%s' saved with %d L lines, %d M lines, %d locations", filename,
    	 m_lLines.count(), m_mLines.count(), m_locations.count());
    #endif
      
      fclose (fh);
    
      seqInfo("Saved SOE map: '%s'", filename);
    }
    
    bool MapData::isAggro(const QString& name, uint16_t* range) const
    {
      MapAggro* aggro;
      QPtrListIterator<MapAggro> ait(m_aggros);
      for (aggro = ait.toFirst();
           aggro != NULL;
           aggro = ++ait)
      {
        // does the name match this aggro?
        if (name.find(aggro->name(), 0, false) != -1)
        {
          if (range != NULL)
    	*range = aggro->range();
    
          return true;
        }
      }
    
      return false;
    }
    
    void MapData::addLocation(const QString& name, 
    			  const QString& color, 
    			  const QPoint& point)
    {
      // create the new location
      m_editLocation = new MapLocation(name, color, point);
      
      // add it to the list of locations
      m_locations.append(m_editLocation);
    }
    
    void MapData::setLocationName(const QString& name)
    {
      // make sure there is a location to edit
      if (m_editLocation == NULL)
        return;
    
      // set the location name
      m_editLocation->setName(name);
    }
    
    void MapData::setLocationColor(const QString& color)
    {
      // make sure there is a location to edit
      if (m_editLocation == NULL)
        return;
    
      // set the location color
      m_editLocation->setColor(color);
    }
    
    void MapData::startLine(const QString& name, 
    			const QString& color, 
    			const MapPoint& point)
    {
      // create the new line, with just the first point
      m_editLineM = new MapLineM(name, color, point); 
    
      // calculate the XY bounds of the line
      m_editLineM->calcBounds();
    
      // add line to the line list
      m_mLines.append(m_editLineM);
    }
    
    void MapData::addLinePoint(const MapPoint& point)
    {
      // make sure there is a line to add to
      if (m_editLineM == NULL)
        return;
    
      uint32_t pos = m_editLineM->size();
    
      // increase the size of the line by one point
      m_editLineM->resize(pos + 1);
      
      // set the point data
      m_editLineM->setPoint(pos, point);
    
      // calculate the XY bounds of the line
      m_editLineM->calcBounds();
    }
    
    void MapData::delLinePoint(void)
    {
      // make sure there is a line to add to
      if (m_editLineM == NULL)
        return;
    
      // remove the last entry from the line
      m_editLineM->resize(m_editLineM->size() - 1);
    
      // if the user has deleted that last point in the line, delete the line
      if (m_editLineM->size() == 0)
      {
        // remove the line
        m_mLines.remove(m_editLineM);
    
        // clear the currently edited line entry
        m_editLineM = NULL;
      }
      else
      {
        // calculate the XY bounds of the line
        m_editLineM->calcBounds();
      }
    }
    
    void MapData::setLineName(const QString& name)
    {
      // make sure there is a line to add to
      if (m_editLineM == NULL)
        return;
    
      // set the line name
      m_editLineM->setName(name);
    }
    
    void MapData::setLineColor(const QString& color)
    {
      // make sure there is a line to add to
      if (m_editLineM == NULL)
        return;
    
      // set the line color
      m_editLineM->setColor(color);
    }
    
    void MapData::scaleDownZ(int16_t factor)
    {
      // first scale down the L lines
      MapLineL* currentLineL;
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
        currentLineL->setZPos(currentLineL->z() / factor);
    
      // finish off by scaling down the M lines
      MapLineM* currentLineM;
      MapPoint* mData;
      size_t numPoints;
      size_t i;
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        // get the number of points in the line
        numPoints = currentLineM->size();
        
        // get the underlying array
        mData = currentLineM->data();
    
        for (i = 0; i < numPoints; i++)
          mData[i].setZPos(mData[i].z() / factor);
      }
    }
    
    void MapData::scaleUpZ(int16_t factor)
    {
      // first scale down the L lines
      MapLineL* currentLineL;
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
        currentLineL->setZPos(currentLineL->z() * factor);
    
      // finish off by scaling down the M lines
      MapLineM* currentLineM;
      MapPoint* mData;
      size_t numPoints;
      size_t i;
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        // get the number of points in the line
        numPoints = currentLineM->size();
        
        // get the underlying array
        mData = currentLineM->data();
    
        for (i = 0; i < numPoints; i++)
          mData[i].setZPos(mData[i].z() * factor);
      }
    }
    
    void MapData::paintGrid(MapParameters& param, QPainter& p) const
    {
      // if nothing will be drawn, don't go through the motions
      if (!param.showGridLines() && !param.showGridTicks())
        return;
    
      /* Paint the grid */
    
      // set the brush
      p.setBrush(QColor (80, 80, 80));
    
      // Need to put in some stuff to auto resize the gridres
      // based on the screenLength and map size
      int gridres = param.gridResolution();
      int offsetPos;
      int pos;
      const QRect& screenBounds = param.screenBounds();
      int lastGrid = (maxX() / gridres) + 1;
    
      // start from the minimum position and increment to the last grid position
      for (int gx = (minX() / gridres) - 1; 
           gx <= lastGrid; 
           gx++)
      {
        // calculate position
        pos = gx * gridres;
        
        // haven't reached visible portion yet, continue
        if (screenBounds.left() > pos)
          continue;
    
        // past the visible portion, stop
        if (screenBounds.right() < pos)
          break;
    
        // calculate offset
        offsetPos = param.calcXOffsetI(pos);
    
        // if grid lines are show, draw them
        if (param.showGridLines())
        {
          p.setPen(param.gridLineColor());
          p.drawLine(offsetPos, 0,
    		   offsetPos, param.screenLengthY());
        }
        
        // if grid ticks are shown, draw them
        if (param.showGridTicks())
        {
          p.setPen(param.gridTickColor());
          p.drawText(offsetPos, param.screenLengthY(), QString::number(pos));
        }
      }
    
      lastGrid = (maxY() / gridres) + 1;
    
      // start from the minimum position and increment to the last grid position
      for (int gy = (minY() / gridres) - 1; 
           gy <= lastGrid; 
           gy++)
      {
        // calculate position
        pos = gy * gridres;
    
        // haven't reached visible portion yet, continue
        if (screenBounds.top() > pos)
          continue;
    
        if (screenBounds.bottom() < pos)
          break;
    
        // calculate the offset position
        offsetPos = param.calcYOffsetI(pos);
    
        // if grid lines are shown, draw them
        if (param.showGridLines())
        {
          p.setPen(param.gridLineColor());
          p.drawLine(0, offsetPos,
    		   param.screenLengthX(), offsetPos);
        }
        
        // if grid ticks are shown, draw thm
        if (param.showGridTicks())
        {
          p.setPen(param.gridTickColor());
          p.drawText(0, offsetPos, QString::number(pos));
        }
    
      }  
    }
    
    void MapData::paintLines(MapParameters& param, QPainter& p) const
    {
      //----------------------------------------------------------------------
      /* Paint the lines */
    #ifdef DEBUGMAP
      seqDebug("Paint the lines");
    #endif
      // Note: none of the map loops below check for zero length lines,
      // because all line manipulation code makes sure that they don't occur
    
      // stuff used no matter how the map is drawn
      MapLineL* currentLineL;
      MapLineM* currentLineM;
    
      // set the brush
      p.setBrush(QColor (80, 80, 80));
    
      const QRect& screenBounds = param.screenBounds();
    
      // determine which painting method is to be used.
      // no depth filtering, cool, let's make this quick and easy
      bool lastInBounds;
      bool curInBounds;
      int16_t curX, curY;
      int cur2DX, cur2DY;
      uint numPoints;
      QPoint* lData;
      MapPoint* mData;
      
      // first paint the L lines
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
      {
        // if line is outside the currently visible region, skip it.
        if (!currentLineL->boundingRect().intersects(screenBounds))
          continue;
        
        // get the number of points in the line
        numPoints = currentLineL->size();
        
        // get the underlying array
        lData = currentLineL->data();
        
        // set pen color
    #ifdef DEBUGMAP
        seqDebug("lineColor = '%s'", (char *) currentLineL->colorName());
    #endif
        p.setPen(currentLineL->bgSafeColor( param.backgroundColor()));
        
        cur2DX = lData[0].x();
        cur2DY = lData[0].y();
        
        // see if the starting position is in bounds
        lastInBounds = inRect(screenBounds, cur2DX, cur2DY);
        
        // move to the starting position
        p.moveTo(param.calcXOffsetI(cur2DX), 
    	     param.calcYOffsetI(cur2DY));
        
        // iterate over all the points in the line
        for (uint32_t i = 1; i < numPoints; i++)
        {
          cur2DX = lData[i].x();
          cur2DY = lData[i].y();
          
          // determine if the current position is in bounds
          curInBounds = inRect(screenBounds, cur2DX, cur2DY);
          
          // draw the line segment if either end is in bounds
          if (lastInBounds || curInBounds)
    	p.lineTo(param.calcXOffsetI(cur2DX),
    		 param.calcYOffsetI(cur2DY));
          else
    	p.moveTo(param.calcXOffsetI(cur2DX),
    		 param.calcYOffsetI(cur2DY));
          
          // current becomes the last
          lastInBounds = curInBounds;
        }
      }
      
      // then paint the M lines
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        // if line is outside the currently visible region, skip it.
        if (!currentLineM->boundingRect().intersects(screenBounds))
          continue;
        
        // get the number of points in the line
        numPoints = currentLineM->size();
        
        // get the underlying array
        mData = currentLineM->data();
        
        // set pen color
    #ifdef DEBUGMAP
        seqDebug("lineColor = '%s'", (char *) currentLineM->colorName());
    #endif
        p.setPen(currentLineM->bgSafeColor( param.backgroundColor()));
        
        curX = mData[0].x();
        curY = mData[0].y();
        
        // see if the starting position is in bounds
        lastInBounds = inRect(screenBounds, curX, curY);
        
        // move to the starting position
        p.moveTo(param.calcXOffsetI(curX), 
    	     param.calcYOffsetI(curY));
        
        // iterate over all the points in the line
        for (uint32_t i = 1; i < numPoints; i++)
        {
          curX = mData[i].x();
          curY = mData[i].y();
          
          // determine if the current position is in bounds
          curInBounds = inRect(screenBounds, curX, curY);
          
          // draw the line segment if either end is in bounds
          if (lastInBounds || curInBounds)
    	p.lineTo(param.calcXOffsetI(curX),
    		 param.calcYOffsetI(curY));
          else
    	p.moveTo(param.calcXOffsetI(curX),
    		 param.calcYOffsetI(curY));
          
          // current becomes the last
          lastInBounds = curInBounds;
        }
      }
    }
    
    void MapData::paintDepthFilteredLines(MapParameters& param, QPainter& p) const
    {
      //----------------------------------------------------------------------
      /* Paint the lines */
    #ifdef DEBUGMAP
      seqDebug("Paint Depth Filtered lines");
    #endif
      // Note: none of the map loops below check for zero length lines,
      // because all line manipulation code makes sure that they don't occur
    
      // stuff used no matter how the map is drawn
      MapLineL* currentLineL;
      MapLineM* currentLineM;
    
      // set the brush
      p.setBrush(QColor (80, 80, 80));
    
      const QRect& screenBounds = param.screenBounds();
    
      // map depth filtering, without faded floors
      bool lastInBounds;
      bool curInBounds;
      int16_t curX, curY, curZ;
      int cur2DX, cur2DY;
      uint32_t numPoints;
      QPoint* lData;
      MapPoint* mData;
      
      // get the players position for it's Z information
      MapPoint playerPos = param.player();
    
      // first paint the L lines
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
      {
        // if line is outside the currently visible region, skip it.
        if (!currentLineL->boundingRect().intersects(screenBounds))
          continue;
        
        // since it's an L type line, check for the depth is easy
        // just check if height is set, and if so, check if it's within range
        if (currentLineL->heightSet() && 
    	!inRoom(param.playerHeadRoom(), param.playerFloorRoom(), 
    		currentLineL->z()))
          continue;  // outside of range, continue to the next line
        
        // get the number of points in the line
        numPoints = currentLineL->size();
        
        // get the underlying array
        lData = currentLineL->data();
        
        // set the line color
    #ifdef DEBUGMAP
        seqDebug("lineColor = '%s'", (char *) currentLineL->color());
    #endif
        p.setPen(currentLineL->bgSafeColor( param.backgroundColor()));
        
        cur2DX = lData[0].x();
        cur2DY = lData[0].y();
        
        // see if the starting position is in bounds
        lastInBounds = inRect(screenBounds, cur2DX, cur2DY);
        
        // move to the starting position
        p.moveTo(param.calcXOffsetI(cur2DX), 
    	     param.calcYOffsetI(cur2DY));
        
        // iterate over all the points in the line
        for (uint32_t i = 1; i < numPoints; i++)
        {
          cur2DX = lData[i].x();
          cur2DY = lData[i].y();
          
          // determine if the current position is in bounds
          curInBounds = inRect(screenBounds, cur2DX, cur2DY);
          
          // draw the line segment if either end is in bounds
          if (lastInBounds || curInBounds)
    	p.lineTo(param.calcXOffsetI(cur2DX),
    		 param.calcYOffsetI(cur2DY));
          else
    	p.moveTo(param.calcXOffsetI(cur2DX),
    		 param.calcYOffsetI(cur2DY));
          
          // current becomes the last
          lastInBounds = curInBounds;
        }
      }
      
      // then paint the M lines
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        // if line is outside the currently visible region, skip it.
        if (!currentLineM->boundingRect().intersects(screenBounds))
          continue;
        
        // get the number of points in the line
        numPoints = currentLineM->size();
        
        // get the underlying array
        mData = currentLineM->data();
        
        // set the line color
    #ifdef DEBUGMAP
        seqDebug("lineColor = '%s'", (char *) currentLineM->color());
    #endif
        p.setPen(currentLineM->bgSafeColor( param.backgroundColor()));
        
        // get current coordinates
        curX = mData[0].x();
        curY = mData[0].y();
        curZ = mData[0].z();
    
        // see if the starting position is in bounds
        lastInBounds = (inRect(screenBounds, curX, curY) &&
    		    inRoom(param.playerHeadRoom(), param.playerFloorRoom(),
    			   curZ));
        
    #ifdef DEBUGMAP
        seqDebug("Line has %i points:", currentLineM->size());
    #endif
        
        // move to the starting position
        p.moveTo(param.calcXOffsetI(curX), 
    	     param.calcYOffsetI(curY));
        
        // iterate over all the points in the line
        for (uint32_t i = 1; i < numPoints; i++)
        {
          // get current coordinates
          curX = mData[i].x();
          curY = mData[i].y();
          curZ = mData[i].z();
          
          // determine if the current position is in bounds
          curInBounds = (inRect(screenBounds, curX, curY) &&
    		     inRoom(param.playerHeadRoom(), param.playerFloorRoom(),
    			    curZ));
          
          // draw the line segment if either end is in bounds
          if (lastInBounds || curInBounds)
    	p.lineTo(param.calcXOffsetI(curX),
    		 param.calcYOffsetI(curY));
          else
    	p.moveTo(param.calcXOffsetI(curX),
    		 param.calcYOffsetI(curY));
          
          // current becomes the last
          lastInBounds = curInBounds;
        }
      }
    }
    
    void MapData::paintFadedFloorsLines(MapParameters& param, QPainter& p) const
    {
      //----------------------------------------------------------------------
      /* Paint the lines */
    #ifdef DEBUGMAP
      seqDebug("Paint Faded Floor lines");
    #endif
      // Note: none of the map loops below check for zero length lines,
      // because all line manipulation code makes sure that they don't occur
    
      // stuff used no matter how the map is drawn
      MapLineL* currentLineL;
      MapLineM* currentLineM;
    
      // set the brush
      p.setBrush(QColor (80, 80, 80));
    
      const QRect& screenBounds = param.screenBounds();
    
      // depth filtering with faded floors
      int oldColor, newColor, useColor;
      bool lastInBounds;
      bool curInBounds;
      int16_t curX, curY, curZ;
      int cur2DX, cur2DY, cur2DZ;
      uint32_t numPoints;
      QPoint* lData;
      MapPoint* mData;
      
      // get the players position for it's Z information
      MapPoint playerPos = param.player();
      
      double topm = 0 - 255.0 / (double)param.headRoom();
      double botm = 255.0 / (double)param.floorRoom();
      double topb = 255 - (topm * playerPos.z());
      double botb = 255 - (botm * playerPos.z());
      
      // first paint the L lines
      QPtrListIterator<MapLineL> mlit(m_lLines);
      for (currentLineL = mlit.toFirst(); 
           currentLineL != NULL; 
           currentLineL = ++mlit)
      {
        // if line is outside the currently visible region, skip it.
        if (!currentLineL->boundingRect().intersects(screenBounds))
          continue;
        
        // get the number of points in the line
        numPoints = currentLineL->size();
        
        // get the underlying array
        lData = currentLineL->data();
        
        // get first point coordinates
        cur2DX = lData[0].x();
        cur2DY = lData[0].y();
        cur2DZ = currentLineL->z();
        
        // color determination is different depending on if a height was set
        if (!currentLineL->heightSet())
        {
          // set the line color
    #ifdef DEBUGMAP
          seqDebug("lineColor = '%s'", (char *) currentLineL->color());
    #endif
          p.setPen(currentLineL->bgSafeColor( param.backgroundColor()));
        }
        else
        {
          // calculate color to use for the line (since L type, only do this once)
          if (currentLineL->z() > playerPos.z())
    	useColor = (int)((cur2DZ * topm) + topb);
          else 
    	useColor = (int)((cur2DZ * botm) + botb);
          
          if (useColor > 255) useColor = 255;
          if (useColor < 0) useColor = 0;
          
          // set the line color
    #ifdef DEBUGMAP
          seqDebug("lineColor = '#%2x%2x%2x'", useColor, useColor, useColor);
    #endif
          p.setPen(QColor(useColor, useColor, useColor));
        }
        
        // see if the starting position is in bounds
        lastInBounds = inRect(screenBounds, cur2DX, cur2DY);
        
        // move to the starting position
        p.moveTo(param.calcXOffsetI(cur2DX), 
    	     param.calcYOffsetI(cur2DY));
        
        // iterate over all the points in the line
        for (uint32_t i = 1; i < numPoints; i++)
        {
          // get coordinates
          cur2DX = lData[i].x();
          cur2DY = lData[i].y();
          
          // determine if the current position is in bounds
          curInBounds = inRect(screenBounds, cur2DX, cur2DY);
          
          // draw the line segment if either end is in bounds
          if (lastInBounds || curInBounds)
    	p.lineTo(param.calcXOffsetI(cur2DX),
    		 param.calcYOffsetI(cur2DY));
          else
    	p.moveTo(param.calcXOffsetI(cur2DX),
    		 param.calcYOffsetI(cur2DY));
          
          // current becomes the last
          lastInBounds = curInBounds;
        }
      }
      
      // then paint the M lines
      QPtrListIterator<MapLineM> mmit(m_mLines);
      for (currentLineM = mmit.toFirst(); 
           currentLineM; 
           currentLineM = ++mmit)
      {
        // if line is outside the currently visible region, skip it.
        if (!currentLineM->boundingRect().intersects(screenBounds))
          continue;
        
        // get the number of points in the line
        numPoints = currentLineM->size();
        
        // get the underlying array
        mData = currentLineM->data();
        
        // set the line color
    #ifdef DEBUGMAP
        seqDebug("lineColor = '%s'", (char *) currentLineM->color());
    #endif
        p.setPen(currentLineM->bgSafeColor( param.backgroundColor()));
        
        // get starting point coordinates
        curX = mData[0].x();
        curY = mData[0].y();
        curZ = mData[0].z();
        
        // see if the starting position is in bounds
        lastInBounds = inRect(screenBounds, curX, curY);
        
    #ifdef DEBUGMAP
        seqDebug("Line has %i points:", currentLineM->size());
    #endif
        
        // calculate starting color info for the line
        if (curZ > playerPos.z()) 
          oldColor = (int)((curZ * topm) + topb);
        else 
          oldColor = (int)((curZ * botm) + botb);
        
        if (oldColor > 255) oldColor = 255;
        if (oldColor < 0) oldColor = 0;
        
        // move to the starting position
        p.moveTo(param.calcXOffsetI(curX), 
    	     param.calcYOffsetI(curY));
        
        // iterate over all the points in the line
        for (uint i = 1; i < numPoints; i++)
        {
          curX = mData[i].x();
          curY = mData[i].y();
          curZ = mData[i].z();
          
          // calculate the new color
          if (curZ > playerPos.z()) 
    	newColor = (int)((curZ * topm) + topb);
          else 
    	newColor = (int)((curZ * botm) + botb);
          if (newColor > 255) newColor = 255;
          if (newColor < 0) newColor = 0;
          
          // determine if the current position is in bounds
          curInBounds = inRect(screenBounds, curX, curY);
          
          // the use color is the average of the two colors
          useColor = (newColor + oldColor) >> 1;
          
          // draw the line segment if either end is in bounds
          if ((lastInBounds || curInBounds) && (useColor != 0))
          {
    	p.setPen(QColor(useColor, useColor, useColor));
    	p.lineTo(param.calcXOffsetI(curX),
    		 param.calcYOffsetI(curY));
          }
          else
    	p.moveTo(param.calcXOffsetI(curX),
    		 param.calcYOffsetI(curY));
          
          // current becomes the last/old
          lastInBounds = curInBounds;
          oldColor = newColor;
        }
      }
    }
    
    void MapData::paintLocations(MapParameters& param, QPainter& p) const
    {
      //----------------------------------------------------------------------
      /* Paint the locations */
    #ifdef DEBUGMAP
      seqDebug("Paint the locations");
    #endif
      // set the brush
      p.setBrush(QColor (80, 80, 80));
    
      // set the font
      p.setFont(param.font());
    
      // iterate over all the map locations
      QPtrListIterator<MapLocation> lit(m_locations);
      for(; lit.current(); ++lit)
      {
        MapLocation* currentLoc = lit.current();
    
        // set the color
        QColor color(currentLoc->color());
    
        // make sure the color isn't the same as the background color
        if (color == param.backgroundColor())
          color = QColor( ~ param.backgroundColor().rgb());
    
        // set the pen color
        p.setPen(color);
    
        // draw the text
        p.drawText(param.calcXOffsetI(currentLoc->x()) - 2,
    	       param.calcYOffsetI(currentLoc->y()) - 2, 
    	       currentLoc->name());
      }
    }
    
    bool MapData::paintMapImage(MapParameters& param, QPainter& p) const
    {
      p.save();
    
      double scaleX = (double(param.screenLength().width()) / 
    		   double(m_image.width())) * double(param.zoom());
      double scaleY = (double(param.screenLength().height()) / 
    		   double(m_image.height())) * double(param.zoom());
    
      if (scaleX > 3.0 || scaleY > 3.0)
        return false;
    
      p.scale(scaleX, scaleY);
    
      int x = param.calcXOffset(m_maxX);
      int y = param.calcYOffset(m_maxY);
    
      p.drawPixmap(x, y, m_image);
      p.restore();
    
      return true;
    }
    
    //----------------------------------------------------------------------
    // MapCache
    MapCache::MapCache(const MapData& mapData)
      : m_mapData(mapData),
        m_lastParam(mapData)
    {
    #ifdef DEBUG
      m_paintCount = 0;
    #endif
      m_painted = false;
      m_alwaysRepaint = false;
    }
    
    MapCache::~MapCache()
    {
    }
    
    bool MapCache::needRepaint(MapParameters& param)
    {
      // if any of these conditions are true, then a repaint is needed
      // NOTE: May need to add more conditions
      if (!m_painted || m_alwaysRepaint ||
          (m_lastParam.screenCenter() != param.screenCenter()) ||
          (m_lastParam.screenLength() != param.screenLength()) ||
          (m_lastParam.ratio() != param.ratio()) ||
          (m_lastParam.zoomMapLength() != param.zoomMapLength()) ||
          (m_lastParam.screenBounds() != param.screenBounds() ) ||
          ((param.mapLineStyle() == tMap_FadedFloors) && 
           (m_lastParam.player().z() != param.player().z())) ||
          ((param.mapLineStyle() == tMap_DepthFiltered) &&
           ((m_lastParam.playerHeadRoom() != param.playerHeadRoom()) ||
    	(m_lastParam.playerFloorRoom() != param.playerFloorRoom()))) ||
          (m_lastParam.mapLineStyle() != param.mapLineStyle()) ||
          (m_lastParam.showLocations() != param.showLocations()) ||
          (m_lastParam.showLines() != param.showLines()) ||
          (m_lastParam.showGridLines() != param.showGridLines()) ||
          (m_lastParam.showGridTicks() != param.showGridTicks()) || 
          (m_lastParam.showBackgroundImage() != param.showBackgroundImage()) ||
          (m_lastParam.gridTickColor() != param.gridTickColor()) || 
          (m_lastParam.backgroundColor() != param.backgroundColor()) || 
          (m_lastParam.font() != param.font()))
        return true;
    
      // if none of the above conditions is true, no need to repaint.
      return false;
    }
    
    const QPixmap& MapCache::getMapImage(MapParameters& param)
    {
      // only repaint the map if absolutely necessary.
      if (!needRepaint(param))
        return m_mapImage;
    
    #ifdef DEBUG
      // increment paint count
      m_paintCount++;
    #endif
      // set pixmap optimization if it's changed
      if (m_lastParam.mapOptimizationMethod() !=
          param.mapOptimizationMethod())
        m_mapImage.setOptimization(param.pixmapOptimizationMethod());
    
      // make sure the map is the correct size
      m_mapImage.resize(param.screenLength());
    
      QPainter tmp;
    
      // Begin Painting
      tmp.begin (&m_mapImage);
      tmp.setPen (QPen::NoPen);
      tmp.setFont (param.font());
    
      // load the background image or paint the background
      if (!m_mapData.imageLoaded() || 
          !param.showBackgroundImage() ||
          !m_mapData.paintMapImage(param, tmp))
      {
        // paint the map backdrop with the users background color for all 
        // map line styles except faded floor, which only really works with
        // a black background
        if (param.mapLineStyle() != tMap_FadedFloors)
          tmp.fillRect(m_mapImage.rect(), param.backgroundColor());
        else 
          tmp.fillRect(m_mapImage.rect(), Qt::black);
      }
    
      tmp.setPen (QColor (80, 80, 80));
      tmp.setBrush (QColor (80, 80, 80));
    
      //----------------------------------------------------------------------
      /* Paint the grid */
      if (param.showGridLines() || param.showGridTicks())
        m_mapData.paintGrid(param, tmp);
    
      //----------------------------------------------------------------------
      /* Paint the lines */
      if (param.showLines())
      {
        switch (param.mapLineStyle())
        {
        case tMap_Normal:
          m_mapData.paintLines(param, tmp);
          break;
        case tMap_DepthFiltered:
          m_mapData.paintDepthFilteredLines(param, tmp);
          break;
        case tMap_FadedFloors:
          m_mapData.paintFadedFloorsLines(param, tmp);
          break;
    #ifdef DEBUGMAP
        default:
          seqWarn("Unknown Map Line Style: %d!", param.mapLineStyle());
          break;
    #endif
        }
      }
    
      //----------------------------------------------------------------------
      /* Paint the locations */
      if (param.showLocations())
        m_mapData.paintLocations(param, tmp);
    
      // finished painting
      tmp.end();
    
      // note that painting has been done
      m_painted = true;
    
      // note parameters used to paint, for later comparison
      m_lastParam = param;
    
      // return the map image
      return m_mapImage;
    }
    Last edited by Tor K'tal; 04-20-2009 at 03:43 PM. Reason: grammatical issues

  2. #2
    Developer
    Join Date
    Nov 2007
    Posts
    539

    Re: BackGround Safe Color (QT 3.x)

    Try this change and see how it works. I didn't test it. But is should make lines distinct no matter what, by inverting color if too close to background. If it and background are close to grey, it sets to black.

    Code:
     
    inline QColor MapCommon::bgSafeColor(const QColor& bgColor)
    {
      QColor bgSafeColor = color();
      // Compairing the draw color with the backround and adjusting if they are too similar
      if ((abs(color().red() - bgColor.red()) <= 75) && 
              (abs(color().green() - bgColor.green()) <= 75) && 
              (abs(color().blue() - bgColor.blue()) <= 75))
      {
       // We are too close to the background color, so inverse the color
     bgSafeColor.setRgb(255 - color().red(),255 - color().green(), 255 - color().blue());
            // perform another check to see if color inverted is too close to background still
            // if it is too close, then the color and background are both close to grey
            if ((abs(bgSafeColor.red() - bgColor.red()) <= 75) && 
                  (abs(bgSafeColor.green() - bgColor.green()) <= 75) && 
                  (abs(bgSafeColor.blue() - bgColor.blue()) <= 75))
            {
            // We are too close still, so both are almost grey, so set to black
                  bgSafeColor.setNamedColor("black");
            }
      } else {
            bgSafeColor = color();
      }
      return bgSafeColor;
    }
    Razzle
    Last edited by Razzle; 04-20-2009 at 08:56 PM. Reason: I tpye lkie I ma dyslexci somteimes

  3. #3
    Developer
    Join Date
    Jul 2004
    Posts
    920

    Re: BackGround Safe Color (QT 3.x)

    Does everyone think this is a good idea? Can someone take some screen shots of what it does? Also can someone make me a unified diff?

  4. #4
    Developer
    Join Date
    Jun 2003
    Posts
    446

    Re: BackGround Safe Color (QT 3.x)

    I haven't tried it but I think it's great if it works. Not having to convert maps anymore would be wonderful.

  5. #5
    Registered User
    Join Date
    Sep 2003
    Posts
    105

    Re: BackGround Safe Color (QT 3.x)

    I thought about inverting the colors as you did Razzle. The issue was that I didn't want that harsh white on the map (issues with my monitor not the principle), since I prefer the "gray" color as the default line color I chose not to. I'm sure what you made works fantastically and is more elegant than my solution.

    I would love to make a unified diff but when I run the patch command to try and apply it to the standard 5.13.3.0 it just hangs up, making me think I'm not making the diff correctly. I've tried making a 5.13.3.1 directory and then running the following command, where the 5.13.3.1 has the new mapcore.cpp and .h files:
    "diff -rdu ./showeq-5.13.3.0 ./showeq-5.13.3.1"

    I'll see if I can post a screen shot of the version I made. My test map was the SOE file format version of thedeep_1.txt since the majority of it's lines are black.

    ~ TK
    Last edited by Tor K'tal; 04-23-2009 at 06:46 PM. Reason: spell errors

  6. #6
    Developer
    Join Date
    Nov 2007
    Posts
    539

    Re: BackGround Safe Color (QT 3.x)

    Let me think about it for a little bit. I know I like the grey better than that bright white on a black background. I am sure there is a way to get it to work a little better. I will try to put something together later tonight.

    Razzle

  7. #7
    Developer
    Join Date
    Jun 2003
    Posts
    446

    Re: BackGround Safe Color (QT 3.x)

    Code:
    diff -wurd ./old ./new >> test.diff
    is what I use.

  8. #8
    Registered User
    Join Date
    Sep 2003
    Posts
    105

    Re: BackGround Safe Color (QT 3.x)

    Here is a diff, and when you do a "patch -i diff-FileName" from the showeq-5.13.3.0/src directory it appears to apply it correctly.

    There are some changes in the #ifdef when I was trying to test it and couldn't get the color names to pump out to the console window as I expected those #ifdef's to do. I don't think they work but they shouldn't hurt either.

    Code:
    diff -wurd ./showeq-5.13.3.0/src/mapcore.cpp ./showeq-5.13.3.1/src/mapcore.cpp
    --- ./showeq-5.13.3.0/src/mapcore.cpp   2009-01-05 11:06:39.000000000 -0700
    +++ ./showeq-5.13.3.1/src/mapcore.cpp   2009-04-20 14:46:23.000000000 -0600
    @@ -1,5 +1,5 @@
     /*
    - * mapcore.h
    + * mapcore.cpp
      *
      *  ShowEQ Distributed under GPL
      *  http://seq.sf.net/
    @@ -1707,9 +1707,9 @@
    
         // set pen color
     #ifdef DEBUGMAP
    -    seqDebug("lineColor = '%s'", (char *) currentLineL->color());
    +    seqDebug("lineColor = '%s'", (char *) currentLineL->colorName());
     #endif
    -    p.setPen(currentLineL->color());
    +    p.setPen(currentLineL->bgSafeColor(param.backgroundColor()));
    
         cur2DX = lData[0].x();
         cur2DY = lData[0].y();
    @@ -1761,9 +1761,9 @@
    
         // set pen color
     #ifdef DEBUGMAP
    -    seqDebug("lineColor = '%s'", (char *) currentLineM->color());
    +    seqDebug("lineColor = '%s'", (char *) currentLineM->colorName());
     #endif
    -    p.setPen(currentLineM->color());
    +    p.setPen(currentLineM->bgSafeColor(param.backgroundColor()));
    
         curX = mData[0].x();
         curY = mData[0].y();
    @@ -1856,7 +1856,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineL->color());
     #endif
    -    p.setPen(currentLineL->color());
    +    p.setPen(currentLineL->bgSafeColor(param.backgroundColor()));
    
         cur2DX = lData[0].x();
         cur2DY = lData[0].y();
    @@ -1910,7 +1910,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineM->color());
     #endif
    -    p.setPen(currentLineM->color());
    +    p.setPen(currentLineM->bgSafeColor(param.backgroundColor()));
    
         // get current coordinates
         curX = mData[0].x();
    @@ -2022,7 +2022,7 @@
     #ifdef DEBUGMAP
           seqDebug("lineColor = '%s'", (char *) currentLineL->color());
     #endif
    -      p.setPen(currentLineL->color());
    +      p.setPen(currentLineL->bgSafeColor(param.backgroundColor()));
         }
         else
         {
    @@ -2092,7 +2092,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineM->color());
     #endif
    -    p.setPen(currentLineM->color());
    +    p.setPen(currentLineM->bgSafeColor(param.backgroundColor()));
    
         // get starting point coordinates
         curX = mData[0].x();
    diff -wurd ./showeq-5.13.3.0/src/mapcore.h ./showeq-5.13.3.1/src/mapcore.h
    --- ./showeq-5.13.3.0/src/mapcore.h     2009-01-05 11:06:39.000000000 -0700
    +++ ./showeq-5.13.3.1/src/mapcore.h     2009-04-20 14:37:45.000000000 -0600
    @@ -406,10 +406,14 @@
       void setName(const QString& name) { m_name = name; }
       void setColor(const QString& color) { m_color = color; }
    
    +  // Returns a QColor object for a color that will contrast the background better
    +  QColor bgSafeColor(const QColor& bgColor);
    +
      private:
       QString m_name;
       QString m_colorName;
       QColor m_color;
    +  QColor m_bgSafeColor;
     };
    
     inline QString MapCommon::colorName() const
    @@ -422,6 +426,34 @@
       return m_color.name();
     }
    
    +inline QColor MapCommon::bgSafeColor(const QColor& bgColor)
    +{
    +  QColor bgSafeColor = color();
    +  // Compairing the draw color with the backround and adjusts if they are too similar
    +  if ((abs(color().red() - bgColor.red()) <= 55) &&
    +          (abs(color().green() - bgColor.green()) <= 55) &&
    +          (abs(color().blue() - bgColor.blue()) <= 55))
    +  {
    +       // black on black fails to XOR
    +       // if the color is too black, and we assume the background is black as well
    +       // because we passed the previous if statement we set the color to gray
    +       if (color().red() <= 55 && color().green() <= 55 && color().blue() <= 55)
    +       {
    +         bgSafeColor.setNamedColor("gray");
    +       } else {
    +         // the carrot symbol performs an XOR
    +         // If the colors are identical the line will be drawn black
    +        bgSafeColor.setRgb(color().red() ^ bgColor.red(),
    +                         color().green() ^ bgColor.green(),
    +                         color().blue() ^ bgColor.blue());
    +       }
    +  } else {
    +    bgSafeColor = color();
    +  }
    +
    +  return bgSafeColor;
    +}
    +
     //----------------------------------------------------------------------
     // MapLineL
     class MapLineL : public MapCommon, public QPointArray
    For some reason I'm not allowed to attach a screen shot and haven't figured out another way to get it onto the web that I'm comfortable with.

    ~ TK
    Last edited by Tor K'tal; 04-23-2009 at 10:25 PM. Reason: Corrected patch command

  9. #9
    Did you SEQ today? BlueAdept's Avatar
    Join Date
    Dec 2001
    Posts
    2,008

    Re: BackGround Safe Color (QT 3.x)

    Sorry I havent been able to test this. Actually I havent been able to play EQ in several weeks.

    To attach an image, you have to upload it to an online image place. Like photobucket or image shack.

    http://photobucket.com/
    http://imageshack.us/
    Filters for ShowEQ can now be found here. filters-5xx-06-20-05.tar.gz

    ShowEQ file section is here. https://sourceforge.net/project/show...roup_id=10131#

    Famous Quotes:

    Ratt: WTF you talkin' about BA? (Ok.. that sounds like a bad combo of Diffrent Strokes and A-Team)

    Razzle: I showeq my wife

  10. #10
    Developer
    Join Date
    Nov 2007
    Posts
    539

    Re: BackGround Safe Color (QT 3.x)

    Here is a diff based on Tor's, expanded to cover different combinations of fore and backgrounds. I also tweaked it so it wont be the bright white on black, but a shade darker.

    Code:
    diff -wurd ./old/src/mapcore.cpp ./new/src/mapcore.cpp
    --- ./old/src/mapcore.cpp    2009-01-05 19:06:39.000000000 +0100
    +++ ./new/src/mapcore.cpp    2009-04-25 00:19:55.000000000 +0200
    @@ -1709,7 +1709,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineL->color());
     #endif
    -    p.setPen(currentLineL->color());
    +    p.setPen(currentLineL->safeColor(param.backgroundColor()));
         
         cur2DX = lData[0].x();
         cur2DY = lData[0].y();
    @@ -1763,7 +1763,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineM->color());
     #endif
    -    p.setPen(currentLineM->color());
    +    p.setPen(currentLineM->safeColor(param.backgroundColor()));
         
         curX = mData[0].x();
         curY = mData[0].y();
    @@ -1856,7 +1856,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineL->color());
     #endif
    -    p.setPen(currentLineL->color());
    +    p.setPen(currentLineL->safeColor(param.backgroundColor()));
         
         cur2DX = lData[0].x();
         cur2DY = lData[0].y();
    @@ -1910,7 +1910,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineM->color());
     #endif
    -    p.setPen(currentLineM->color());
    +    p.setPen(currentLineM->safeColor(param.backgroundColor()));
         
         // get current coordinates
         curX = mData[0].x();
    @@ -2022,7 +2022,7 @@
     #ifdef DEBUGMAP
           seqDebug("lineColor = '%s'", (char *) currentLineL->color());
     #endif
    -      p.setPen(currentLineL->color());
    +      p.setPen(currentLineL->safeColor(param.backgroundColor()));
         }
         else
         {
    @@ -2092,7 +2092,7 @@
     #ifdef DEBUGMAP
         seqDebug("lineColor = '%s'", (char *) currentLineM->color());
     #endif
    -    p.setPen(currentLineM->color());
    +    p.setPen(currentLineM->safeColor(param.backgroundColor()));
         
         // get starting point coordinates
         curX = mData[0].x();
    Only in ./new/src: mapcore.cpp~
    diff -wurd ./old/src/mapcore.h ./new/src/mapcore.h
    --- ./old/src/mapcore.h    2009-01-05 19:06:39.000000000 +0100
    +++ ./new/src/mapcore.h    2009-04-25 00:58:14.000000000 +0200
    @@ -402,6 +402,7 @@
       const QString& name() const { return m_name; }
       const QColor& color() const { return m_color; }
       QString colorName() const;
    +  QColor safeColor(const QColor& bgColor);
     
       void setName(const QString& name) { m_name = name; }
       void setColor(const QString& color) { m_color = color; }
    @@ -422,6 +423,19 @@
       return m_color.name();
     }
     
    +inline QColor MapCommon::safeColor(const QColor& bgColor)
    +{
    +  if ((abs(color().red() - bgColor.red()) < 55) &&
    +    (abs(color().green() - bgColor.green()) < 55) &&
    +    (abs(color().blue() - bgColor.blue()) < 55))
    +      m_color.setRgb(192 - 0.75 * color().red(), 192 - 0.75 * color().green(), 192 - 0.75 * color().blue());
    +  if ((abs(color().red() - bgColor.red()) < 55) &&
    +    (abs(color().green() - bgColor.green()) < 55) &&
    +    (abs(color().blue() - bgColor.blue()) < 55))
    +      m_color.setNamedColor("black");
    +  return m_color;
    +}
    +
     //----------------------------------------------------------------------
     // MapLineL
     class MapLineL : public MapCommon, public QPointArray
    Razzle

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

You may post new threads
You may post replies
You may post attachments
You may edit your posts
HTML code is Off
vB code is On
Smilies are On
[IMG] code is On