Jump to content

[C++] GF __LoadAtlasMarkInfo WhiteMark pixel shift fix


Recommended Posts

  • Active+ Member

While working with the GF-based atlas mark system, I noticed a 1-pixel north-west offset on the 2×2 WhiteMark dots of NPCs that have an active quest on the minimap.
This offset was visible only on quest-marked NPCs; normal NPC dots looked correct at first glance.

.png

Why Was This Not Noticed Before?
With the old atlas data and previous loading functions, atlas mark positions were processed using low-resolution / coarse coordinates, which effectively masked the issue in practice.
In the newer GF __LoadAtlasMarkInfo implementation, atlas coordinates are used more accurately and directly, which made this previously unnoticed alignment issue visible.

For example, this is an entry from the old
Server\Binary\share\locale\xx\map\metin2_map_c1\npc.txt,
where the coordinates are written roughly:

m    732    390    0    0    0    0    1m    100    1    9009

And this is the corresponding entry from the new
Client\Binary\pack\locale\locale\xx\map\metin2_map_c1_point.txt,
where the coordinates are written precisely (×100):

#index    x    y    npc_vnum    enable_helper    icon
0    73200    39000    9009    0    0

This higher-precision data likely exposed floating-point alignment differences.
In other words, this is not a bug introduced by the new function, but rather a previously existing logical issue that was hidden and has now surfaced.

 

Cause
During the atlas mark loading stage:

  • Half of the sprite width/height was subtracted, applying early centering
  • During rendering, the sprite was already assumed to be centered

This resulted in:

  • Atlas mark positions being centered twice
  • A visible 1-pixel north-west shift, especially in the quest highlight pixel inside the WhiteMark

 

Solution
The responsibility between logic layers was clearly separated:

  • Atlas mark positions are now stored as center coordinates
  • Sprite size–dependent half-width / half-height offsets are applied only during rendering

As a result:

  • NPC dots
  • Quest highlight pixels
  • Waypoint and target markers

are all aligned using the same reference point.

 

Result

  • The quest pixel offset on WhiteMark is completely fixed
  • Atlas and minimap rendering logic is now more consistent
  • Future refactors or visual changes are less likely to reintroduce similar issues

 

Client\Source\UserInterface\PythonMiniMap.cpp:

// Search @@ void CPythonMiniMap::__LoadAtlasMarkInfo()

        aAtlasMarkInfo.m_fScreenX = aAtlasMarkInfo.m_fX / m_fAtlasMaxX * m_fAtlasImageSizeX - (float)m_WhiteMark.GetWidth() / 2.0f;
        aAtlasMarkInfo.m_fScreenY = aAtlasMarkInfo.m_fY / m_fAtlasMaxY * m_fAtlasImageSizeY - (float)m_WhiteMark.GetHeight() / 2.0f;

// Change

        /* - ATLAS_MARK_INFO [REFACTOR] ------------------------
         * [KaptanYosun Dev Note]
         * Atlas mark positions must be stored as CENTER coordinates.
         *
         * The previous implementation subtracted half of the mark size
         * here, effectively converting the position to top-left space
         * too early. This caused double-centering during rendering and
         * resulted in a 1px north-west offset in quest-highlight pixels.
         *
         * Centering (subtracting half width/height) is now applied ONLY
         * at render time, ensuring consistent alignment between:
         *  - NPC dots
         *  - Quest highlight pixels
         *  - Waypoints and target marks
         *
         * Rule: store logical positions as center, apply sprite offsets
         * only in the rendering layer.
         */
        aAtlasMarkInfo.m_fScreenX = aAtlasMarkInfo.m_fX / m_fAtlasMaxX * m_fAtlasImageSizeX;
        aAtlasMarkInfo.m_fScreenY = aAtlasMarkInfo.m_fY / m_fAtlasMaxY * m_fAtlasImageSizeY;
        /* ----------------------------------------------------- */

 

// Search @@ void CPythonMiniMap::RenderAtlas(float fScreenX, float fScreenY)

    STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, CInstanceBase::GetIndexedNameColor(CInstanceBase::NAMECOLOR_NPC));
    m_AtlasMarkInfoVectorIterator = m_AtlasNPCInfoVector.begin();

// Add below

    /* - ATLAS_MARK_INFO [REFACTOR] ------------------------ */
    const float halfWidth = static_cast<float>(m_WhiteMark.GetWidth()) * 0.5f;
    const float halfHeight = static_cast<float>(m_WhiteMark.GetHeight()) * 0.5f;
    /* ----------------------------------------------------- */

 

// Search (2x) @@ void CPythonMiniMap::RenderAtlas(float fScreenX, float fScreenY)

        m_WhiteMark.SetPosition(rAtlasMarkInfo.m_fScreenX, rAtlasMarkInfo.m_fScreenY);

// Change (2x)

        /* - ATLAS_MARK_INFO [REFACTOR] ------------------------ */
        m_WhiteMark.SetPosition(
            rAtlasMarkInfo.m_fScreenX - halfWidth,
            rAtlasMarkInfo.m_fScreenY - halfHeight
        );
        /* ----------------------------------------------------- */

 

This fix applies to all clients using the GF Atlas Mark system.

  • Metin2 Dev 1
  • muscle 1
  • Love 3
  • 3 weeks later...
  • Premium

Hello and thanks a lot it was driving me crazy, thinking i've done something wrong deleting the packet to send NPC pos !

I still have a slight issue : it works fine on the big map as shown in your topic, but I still have an offset on the minimap , I've tried to solved it but couldn't !

 

Thanks again !

 

EDIT : 
I've find something to correct the offset in the minimpa too but i don't know if it's good
 

Spoiler
//in  void CPythonMiniMap::Update(float fCenterX, float fCenterY):

//Search for : 
				rAtlasMarkInfo.m_fMiniMapX = ( m_fWidth - (float)m_WhiteMark.GetWidth() ) / 2.0f + fDistanceFromCenterX + m_fScreenX + 2.0f;
				rAtlasMarkInfo.m_fMiniMapY = ( m_fHeight - (float)m_WhiteMark.GetHeight() ) / 2.0f + fDistanceFromCenterY + m_fScreenY + 2.0f;

//replace with : 
				rAtlasMarkInfo.m_fMiniMapX = m_fWidth / 2.0f + fDistanceFromCenterX + m_fScreenX + 2.0f;
				rAtlasMarkInfo.m_fMiniMapY = m_fHeight / 2.0f + fDistanceFromCenterY + m_fScreenY + 2.0f;


//Search for : 
				rAtlasMarkInfo.m_fMiniMapX = ( m_fWidth - (float)m_WhiteMark.GetWidth() ) / 2.0f + fDistanceFromCenterX + m_fScreenX;
				rAtlasMarkInfo.m_fMiniMapY = ( m_fHeight - (float)m_WhiteMark.GetHeight() ) / 2.0f + fDistanceFromCenterY + m_fScreenY;

//replace with : 
				rAtlasMarkInfo.m_fMiniMapX = m_fWidth / 2.0f + fDistanceFromCenterX + m_fScreenX;
				rAtlasMarkInfo.m_fMiniMapY = m_fHeight / 2.0f + fDistanceFromCenterY + m_fScreenY;

 

 

Edited by ARiver
Minimap offset fix ?
  • 4 months later...

You have inconsistencies there, because void CPythonMiniMap::RegisterAtlasMark must be too ->

	aAtlasMarkInfo.m_fScreenX = aAtlasMarkInfo.m_fX / m_fAtlasMaxX * m_fAtlasImageSizeX;
	aAtlasMarkInfo.m_fScreenY = aAtlasMarkInfo.m_fY / m_fAtlasMaxY * m_fAtlasImageSizeY;

+ as a bonus, the .sub has wrong position with marks, which is mostly the main problem with all of this..
spacer.png

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.