匯東網


图像渐变切换动画效果(像素点位移)

[編輯] [转简体]
|
作者:huidong | 分類:【編程】EasyX
[ 23 瀏覽 0 評論 6 贊 7 踩 ]

概要

正文

/////////////////////////////////////
//
//    图像切换动画效果(像素点位移)
//
//    Visual Studio 2022 | EasyX 20220610
//    
//    by huidong <mailhuid@163.com>
//    2022.7.16
//

#include <easyx.h>
#include <stdio.h>
#include <time.h>
#include <vector>
using std::vector;

#define SQR(x)    ((x)*(x))
#define DISTANCE(x1, y1, x2, y2)    sqrt(SQR(x2-x1)+SQR(y2-y1))

struct FloatPoint
{
    double x = 0, y = 0;
};

struct MovePoint
{
    FloatPoint pt = {};            // 原位置
    double vx = 0, vy = 0;        // 毫秒速度
    bool isRedundant = false;    // 该点是否多余(Src)
    bool isUsed = false;        // 是否已被作为目标点(Dst)
};

IMAGE imgSrc, imgDst;
vector<MovePoint> vecSrc, vecDst;
int nAnimateDuration = 2;    // 动画时长(秒)
int nFPS = 24;                // 帧率

int nDelayMS = (int)((1.0 / nFPS) * 1000);    // 每帧的延时(毫秒)

void Load()
{
    WCHAR lpszSrcFile[128] = {};
    WCHAR lpszDstFile[128] = {};
    printf("Source file:");
    _getws_s(lpszSrcFile);
    printf("Destination file:");
    _getws_s(lpszDstFile);

    loadimage(&imgSrc, lpszSrcFile);
    loadimage(&imgDst, lpszDstFile);
}

void Record()
{
    IMAGE* pImg[] = { &imgSrc,&imgDst };
    vector<MovePoint>* pVec[] = { &vecSrc,&vecDst };
    for (int i = 0; i < 2; i++)
    {
        SetWorkingImage(pImg[i]);
        for (int x = 0; x < getwidth(); x++)
        {
            for (int y = 0; y < getheight(); y++)
            {
                if (getpixel(x, y) == BLACK)
                {
                    MovePoint pt = { (double)x,(double)y };
                    pVec[i]->push_back(pt);
                }
            }
        }
    }
}

void Calc()
{
    // 平衡源点和目标点数量
    size_t sizeSrc = vecSrc.size();
    size_t sizeDst = vecDst.size();
    if (sizeSrc < sizeDst)
    {
        for (size_t i = 0; i < sizeDst - sizeSrc; i++)
        {
            vecSrc.push_back(vecSrc[rand() % sizeSrc]);
        }
    }
    else if (sizeSrc > sizeDst)
    {
        size_t sizeDiff = sizeSrc - sizeDst;
        for (size_t i = 0; i < sizeDiff; i++)
        {
            vecSrc[sizeSrc / sizeDiff * i].isRedundant = true;
        }
    }

    // 分配目标点,计算速度
    size_t sizeSrcNew = vecSrc.size();
    for (size_t i = 0; i < sizeSrcNew; i++)
    {
        FloatPoint ptBest = { -1,-1 };
        double dDistance = -1;
        int nBestIndex = -1;
        for (size_t j = 0; j < sizeDst; j++)
        {
            // 多余的点选哪个做目标都可以,但是其他点只能选择没用过的
            if (vecSrc[i].isRedundant || !vecDst[j].isUsed)
            {
                double dThis = DISTANCE(
                    vecSrc[i].pt.x, vecSrc[i].pt.y,
                    vecDst[j].pt.x, vecDst[j].pt.y);
                if (dThis < dDistance || dDistance == -1)
                {
                    ptBest = vecDst[j].pt;
                    dDistance = dThis;
                    nBestIndex = j;
                }
            }
        }

        if (nBestIndex == -1)
        {
            printf("\nError.\n");
            exit(-1);
        }

        if (!vecSrc[i].isRedundant)
        {
            vecDst[nBestIndex].isUsed = true;
        }
        vecSrc[i].vx = (ptBest.x - vecSrc[i].pt.x) / (double)nAnimateDuration / 1000;
        vecSrc[i].vy = (ptBest.y - vecSrc[i].pt.y) / (double)nAnimateDuration / 1000;
    }
}

// 精确延时函数(可以精确到 1ms,精度 ±1ms)
// by yangw80<yw80@qq.com>, 2011-5-4
void HpSleep(int ms)
{
    static clock_t oldclock = clock();        // 静态变量,记录上一次 tick

    oldclock += ms * CLOCKS_PER_SEC / 1000;    // 更新 tick

    if (clock() > oldclock)                    // 如果已经超时,无需延时
        oldclock = clock();
    else
        while (clock() < oldclock)            // 延时
            Sleep (1);                        // 释放 CPU 控制权,降低 CPU 占用率
//            Sleep (0);                        // 更高精度、更高 CPU 占用率
}

void Animate(bool reverse = false)
{
    int nDelayFrequency = nAnimateDuration * 1000 / nDelayMS;
    vector<MovePoint> vecPt = vecSrc;
    if (reverse)
    {
        for (size_t j = 0; j < vecSrc.size(); j++)
        {
            vecPt[j].pt.x += vecPt[j].vx * nAnimateDuration * 1000;
            vecPt[j].pt.y += vecPt[j].vy * nAnimateDuration * 1000;
            vecPt[j].vx = -vecPt[j].vx;
            vecPt[j].vy = -vecPt[j].vy;
        }
    }
    for (int i = 0; i < nDelayFrequency; i++)
    {
        cleardevice();
        for (size_t j = 0; j < vecSrc.size(); j++)
        {
            vecPt[j].pt.x += vecPt[j].vx * nDelayMS;
            vecPt[j].pt.y += vecPt[j].vy * nDelayMS;
            putpixel((int)vecPt[j].pt.x, (int)vecPt[j].pt.y, BLACK);
        }
        FlushBatchDraw();
        HpSleep(nDelayMS);
    }
}

int main()
{
    Load();
    printf("\nLoading...");
    Record();
    Calc();

    initgraph(640, 480);
    BeginBatchDraw();
    setbkcolor(WHITE);
    settextcolor(BLACK);

    while (true)
    {
        cleardevice();
        putimage(0, 0, &imgSrc);
        outtextxy(0, 0, L"Any key to start.");
        FlushBatchDraw();
        flushmessage();
        getmessage(EM_KEY);
        Animate();
        outtextxy(0, 0, L"Any key to replay.");
        FlushBatchDraw();
        flushmessage();
        getmessage(EM_KEY);
        Animate(true);
    }

    EndBatchDraw();
    closegraph();
    return 0;
}


[ 6] [ 7]


 評論區  0 條評論

+ 添加評論