HD files versions automatic loading

Hi everyone,

I’m actually porting one of my IOS game to android using cocos2Dx, and i see that there is no “HD suffix” support in android version ?

so i add one version, it seems to work well… so if someone need, i will see how to put it somewhere :smiley:

JC

Do you mean that, you packed resources in different DPI together in your APK, and the game can adjust the DPI automatically then load different images?

Yes,

i mean doing exactly what is done for IOS with retina suffix.

i’m using view->Create(…) method to setup my “base resolution” (i put the same as iphone, but can be whatever you want, depending on resources), and computing “contentscalefactor” depending on the “screenscalefactor”.

so if my base resolution is 480x320, in create it compute ScreenScale Factor, if the screenscale factor > XX (i put 1.5, but can be changed… or take a config value ?) i set the director content scale facor to 2.

i will probably add later a test for screen scale factor > 2.5 to use “ipad retina” graphics by putting content scale factor to 4, or something like that.

after doing that, the file utils methods getfullpathfromrelative take content scale factor and if it’s 2 (or later 4), try to add hd suffix file exist.

if there is a “simpler” and more “portable” way to do that…. ?
i need something to reduce amount of work when maintaining code for IOS and Android (and probably later in other devices).

This looks useful. I appreciate it if you could share this to the community :slight_smile:

Ok, so, that version is for android, but it’s probably easy to generalize it for all devices.

first, in main.cpp in your android project, setup the view with the “base resolution” using create :

here, i took the iphone non retina resolution.

        view->setFrameWidthAndHeight(w, h);
        // if you want to run in WVGA with HVGA resource, set it
        view->create(480, 320);

next, in CCEGLView_android.cpp :

void CCEGLView::create(int width, int height)
{
    if (width == 0 || height == 0)
    {
        return;
    }

    m_sSizeInPoint.width = width;
    m_sSizeInPoint.height = height;

    // calculate the factor and the rect of viewport    
    m_fScreenScaleFactor =  MIN((float)m_sSizeInPixel.width / m_sSizeInPoint.width, (float)m_sSizeInPixel.height / m_sSizeInPoint.height);
    CCLOG("CCEGLView::Create / Screen Scale Factor = %f", m_fScreenScaleFactor);
    if (m_fScreenScaleFactor >= 1.5f)
    {
        CCLOG("CCEGLView::Create / HD Scale Factor => Increase Content Scale Factor");
        cocos2d::CCDirector::sharedDirector()->setContentScaleFactor(2.0f);
    }
    int viewPortW = (int)(m_sSizeInPoint.width * m_fScreenScaleFactor);
    int viewPortH = (int)(m_sSizeInPoint.height * m_fScreenScaleFactor);
    m_rcViewPort.origin.x = (m_sSizeInPixel.width - viewPortW) / 2;
    m_rcViewPort.origin.y = (m_sSizeInPixel.height - viewPortH) / 2;
    m_rcViewPort.size.width = viewPortW;
    m_rcViewPort.size.height = viewPortH;

    m_bNotHVGA = true;  
}

next in CCFileUtils_android.cpp :

const char* CCFileUtils::fullPathFromRelativePath(const char *pszRelativePath)
{
    if (CC_CONTENT_SCALE_FACTOR() == 2.0f)
    {
    //CC_RETINA_DISPLAY_FILENAME_SUFFIX
    // verifier si suffix deja present
        std::string path = pszRelativePath;
        std::string::size_type pos = path.rfind("/") + 1; // the begin index of last part of path

        std::string::size_type suffixPos = path.rfind(CC_RETINA_DISPLAY_FILENAME_SUFFIX);
        if ((std::string::npos != suffixPos) && (suffixPos > pos))
        {
            // => if yes, return path directly
        }
        else
        {
            // => if no, add "retina"/hd suffix and test if file exist
            CCString *pRet = new CCString();
            pRet->autorelease();
            pRet->m_sString = path.substr(0, path.rfind(".")) + CC_RETINA_DISPLAY_FILENAME_SUFFIX + path.substr(path.rfind("."), path.length());

            if (existFileData(pRet->m_sString.c_str()))
            {
                //    => if yes, return path with suffix
                CCLog("cocos2d: FilePath(%s) with suffix(%s) exist, use it.", pRet->m_sString.c_str(), CC_RETINA_DISPLAY_FILENAME_SUFFIX);

                return pRet->m_sString.c_str();
            }
            else
            {
                //    => if no, return path without suffix
            }
        }
    }
    return pszRelativePath;
}

const char* CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const char *pszRelativeFile)
{
    std::string relativeFile = pszRelativeFile;
    CCString *pRet = new CCString();
    pRet->autorelease();
    pRet->m_sString = relativeFile.substr(0, relativeFile.rfind('/')+1);
    pRet->m_sString += pszFilename;
    return pRet->m_sString.c_str();
}
bool CCFileUtils::existFileData(const char* pszFileName)
{
    string fullPath(pszFileName);

    if ((! pszFileName))
    {
        return false;
    }

    if (pszFileName[0] != '/')
    {
        // read from apk
        fullPath.insert(0, "assets/");
        return CCFileUtils::existFileDataFromZip(s_strResourcePath.c_str(), fullPath.c_str());
    }
    else
    {
        do
        {
            // read rrom other path than user set it
            FILE *fp = fopen(pszFileName, "rb");
            if (fp != NULL)
            {
                fclose(fp);
                return true;
            }
        }
        while (0);
    }
    return false;
}

ok, it’s done, (i hope i don’t forget something…). you have to update some headers like for CCFileUtils.h add the existFileData method…

with all that, you get the same behavior as IOS in android. i think we can generalize it for all device to get a global HD/SD assets loading system :slight_smile: