基于D3D技术实现的九宫格算法绘制图片

九宫格示意图:


下面是代码实现:

#include <Windows.h>
#include <D3D9.h>
#include <cstdio>
#include <D3dx9tex.h>
#pragma comment(lib, "D3D9.lib")
#pragma  comment(lib, "D3dx9.lib")

#define D3D_FVF_VECTOR (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)

HINSTANCE kInstance = nullptr;
const TCHAR *kClassName = L"NineSquared_D3D";
D3DPRESENT_PARAMETERS params;
IDirect3D9 *d3d9 = nullptr;
IDirect3DDevice9 *device9 = nullptr;
IDirect3DVertexBuffer9 *vectex_buffer9 = nullptr; 
IDirect3DTexture9 *picture_texture = nullptr;
IDirect3DSurface9 *picture_surface = nullptr;
int kVertexCount = 0; //顶点个数
int kVertexMaxCount = 2000;//顶点最大数
int kWndWidth = 1024;
int kWndHeight = 800;
bool window_mode = true;

extern "C" {
    extern unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp);
    extern void stbi_image_free(void *retval_from_stbi_load);
};

bool InitD3D(HWND hwnd);//初始化
bool Done();//完成
bool Paint();
IDirect3DSurface9 *LoadImage(char const *filename);
RECT GetTexturePicturePos(IDirect3DSurface9 *surface);
void DrawImage(const RECT &src, const RECT &dest, const RECT &nine_squared);

LRESULT CALLBACK WindowProc(
    _In_ HWND   hwnd,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    );


struct Vertex {
    Vertex(float v_x, float v_y, float v_z, DWORD c, float u, float v)
        : x(v_x),
        y(v_y),
        z(v_z),
        color(c),
        picture_u(u),
        picture_v(v) {
            rhw = 1.0f;
            z = 0.0f;
    }

    Vertex() {
        rhw = 1.0f;
        z = 0.0f;
    }

    float x, y, z, rhw;
    DWORD color;
    float picture_u, picture_v;//图片纹理
};

Vertex *vector_buffer = nullptr;

int CALLBACK WinMain(
    _In_ HINSTANCE hInstance,
    _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR     lpCmdLine,
    _In_ int       nCmdShow
    ) {

        kInstance = hInstance;
        //init app
        WNDCLASSEX wndclassex;
        wndclassex.cbSize = sizeof(WNDCLASSEX);
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;
        wndclassex.lpfnWndProc = WindowProc;
        wndclassex.cbClsExtra = 0;
        wndclassex.cbWndExtra = 0;
        wndclassex.hInstance = hInstance;
        wndclassex.hIcon = nullptr;
        wndclassex.hCursor = LoadCursor(hInstance, IDC_ARROW);
        wndclassex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wndclassex.lpszMenuName = nullptr;
        wndclassex.lpszClassName = kClassName;
        wndclassex.hIconSm = nullptr;
        RegisterClassEx(&wndclassex);

        //WS_OVERLAPPEDWINDOW
        HWND  hwnd = CreateWindowEx(0, kClassName, L"图片九宫格", WS_OVERLAPPEDWINDOW, 100, 100, kWndWidth, kWndHeight, nullptr, nullptr, hInstance, nullptr);

        ShowWindow(hwnd, nCmdShow);

        InitD3D(hwnd);
        UpdateWindow(hwnd);
        MSG msg;
        BOOL ret;
        while((ret = GetMessage(&msg, nullptr, 0, 0)) != 0) {
            if (ret == -1) {
                //出现了错误
            } else {
                ::TranslateMessage(&msg);
                ::DispatchMessage(&msg);
            }
        } 

        Done();
        return 0;
}

LRESULT CALLBACK WindowProc(
    _In_ HWND   hwnd,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    ) {

        PAINTSTRUCT ps;
        HDC hdc;
        if (uMsg == WM_PAINT) {
            hdc = BeginPaint(hwnd, &ps);
                Paint();
            EndPaint(hwnd, &ps);
        }else if (uMsg == WM_DESTROY) {
            PostMessage(hwnd, WM_QUIT, 0, 0);
        }

        return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

bool Paint() {
    if (nullptr == device9) {
        return false;
    }
    BYTE	*vertices = NULL;
    INT		length = kVertexCount * sizeof(Vertex);
    // 拷贝顶点数据
    if (SUCCEEDED(vectex_buffer9->Lock(0, length, (LPVOID*)&vertices, 0))){
        memcpy_s(vertices, length,vector_buffer, length);
        vectex_buffer9->Unlock();
    }
    device9->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 255, 255, 255), 0.0f, 0);
    device9->SetStreamSource(0, vectex_buffer9, 0, sizeof(Vertex));
    device9->SetFVF(D3D_FVF_VECTOR);
    device9->BeginScene();
    device9->DrawPrimitive(D3DPT_TRIANGLELIST, 0, kVertexCount / 3);
    device9->EndScene();
    device9->Present(0, 0, 0, 0);

    return true;
}

bool Done() {
#if _DEBUG
    D3DXSaveTextureToFileW(L"PicTexture.png", D3DXIFF_PNG, picture_texture, NULL);
#endif
    if (nullptr != picture_surface) {
        picture_surface->Release();
        picture_surface = nullptr;
    }
    if (nullptr != picture_texture) {
        picture_texture->Release();
        picture_texture = nullptr;
    }
    if (nullptr != vectex_buffer9) {
        vectex_buffer9->Release();
        vectex_buffer9 = nullptr;
    }
    if (nullptr != device9) {
        device9->Release();
        device9 = nullptr;
    }
    if (nullptr != d3d9) {
        d3d9->Release();
        d3d9 = nullptr;
    }
    if (nullptr != vector_buffer) {
        delete []vector_buffer;
        vector_buffer = nullptr;
    }
    return true;
}

bool InitD3D(HWND hwnd) {
    d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
    if (nullptr == d3d9) {
        return false;
    }
    params.BackBufferWidth = kWndWidth;
    params.BackBufferHeight = kWndHeight;
    params.BackBufferFormat = D3DFMT_A8R8G8B8;
    params.BackBufferCount = 1;
    params.MultiSampleType = D3DMULTISAMPLE_NONE;
    params.MultiSampleQuality = 0;
    params.SwapEffect = D3DSWAPEFFECT_COPY;
    params.hDeviceWindow = hwnd;
    params.Windowed = window_mode ? TRUE : FALSE;
    params.EnableAutoDepthStencil = FALSE;
    params.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
    params.Flags = 0;
    params.FullScreen_RefreshRateInHz = 0;
    params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶ms, &device9);
    if (FAILED(hr)) {
        return false;
    }
    device9->SetRenderState(D3DRS_LIGHTING, false);
    // 开启AlphaBlend
    device9->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    device9->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    device9->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

    hr = device9->CreateVertexBuffer(kVertexMaxCount * sizeof(Vertex), 0, D3D_FVF_VECTOR, D3DPOOL_SYSTEMMEM, &vectex_buffer9, nullptr);
    if (FAILED(hr)) {
        return false;
    }

    //创建图片纹理
    hr = device9->CreateTexture(1024, 1024, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &picture_texture, 0);
    if (FAILED(hr)) {
        return false;
    }
    picture_texture->GetSurfaceLevel(0, &picture_surface);
    device9->SetTexture(0, picture_texture);
    if (nullptr == vector_buffer) {
        vector_buffer = new Vertex[kVertexMaxCount];
    }
    kVertexCount = 0;

    IDirect3DSurface9 *surface = LoadImage("widi_bg.png");
    RECT src = GetTexturePicturePos(surface);
    RECT dest;
    ::SetRect(&dest, 100,100, 500, 500);
    RECT corner;
    ::SetRect(&corner, 180, 60, 15, 15);
    DrawImage(src, dest, corner);

    surface->Release();

    return true;
}

IDirect3DSurface9 *LoadImage(char const *filename) {
    LPBYTE image_buffer = nullptr;
    int x,y,n;
    image_buffer = stbi_load(filename, &x, &y, &n, 4);
    if (nullptr == image_buffer) {
        return nullptr;
    }
    BITMAPINFO bitmap_info;
    ::ZeroMemory(&bitmap_info, sizeof(BITMAPINFO));
    bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmap_info.bmiHeader.biWidth = x;
    bitmap_info.bmiHeader.biHeight = -y;
    bitmap_info.bmiHeader.biPlanes = 1;
    bitmap_info.bmiHeader.biBitCount = 32;
    bitmap_info.bmiHeader.biCompression = BI_RGB;
    bitmap_info.bmiHeader.biSizeImage = x * y * 4;
    LPBYTE buffer = nullptr;
    HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmap_info,DIB_RGB_COLORS,(void**)&buffer, NULL, 0);
    for (int i = 0; i< x * y; ++i) {
        buffer[i*4 + 3] = image_buffer[i*4 + 3];
        if (buffer[i*4 + 3] < 255) {
            buffer[i*4] = (BYTE)(DWORD(image_buffer[i*4 + 2])*image_buffer[i*4 + 3]/255);
            buffer[i*4 + 1] = (BYTE)(DWORD(image_buffer[i*4 + 1])*image_buffer[i*4 + 3]/255);
            buffer[i*4 + 2] = (BYTE)(DWORD(image_buffer[i*4])*image_buffer[i*4 + 3]/255); 
        } else {
            buffer[i*4] = image_buffer[i*4 + 2];
            buffer[i*4 + 1] = image_buffer[i*4 + 1];
            buffer[i*4 + 2] = image_buffer[i*4]; 
        }
    }
    stbi_image_free((void*)image_buffer);

    IDirect3DSurface9 *surface = nullptr;
    HRESULT hr = device9->CreateOffscreenPlainSurface(x, y, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, nullptr);
    if (FAILED(hr)) {
        nullptr;
    }
    D3DLOCKED_RECT lock_rect;
    surface->LockRect(&lock_rect, nullptr, 0);
    BYTE* surface_buffer = static_cast<BYTE*>(lock_rect.pBits);
    for(int h = 0; h < y; ++h) {
        memcpy((BYTE*)surface_buffer + h * lock_rect.Pitch, buffer + h*x*4, x * 4);
    }
    surface->UnlockRect();
    DeleteObject(bitmap);

    return surface;
}

void DrawImage(const RECT &src, const RECT &dest, const RECT &nine_squared) {
    if (nullptr == picture_surface) {
        return;
    }
    
    //九宫格绘制
    RECT texture_rect;
    RECT paint_rect;
    bool is_draw = false;
    Vertex vectors[6];

    for (int grid = 0; grid < 9; ++grid) {
        vectors[0] = Vertex(0, 0, 0, 0xffFFFFFF, 0, 1);
        vectors[1] = Vertex(0, 0, 0, 0xffFFFFFF, 0, 0);
        vectors[2] = Vertex(0, 0, 0, 0xffFFFFFF, 1, 0);
        vectors[3] = Vertex(0, 0, 0, 0xffFFFFFF, 0, 1);
        vectors[4] = Vertex(0, 0, 0, 0xffFFFFFF, 1, 0);
        vectors[5] = Vertex(0, 0, 0, 0xffFFFFFF, 1, 1);
        is_draw = false;
        if (grid == 0) {
            //middle
            paint_rect.left = dest.left + nine_squared.left;
            paint_rect.top = dest.top + nine_squared.top;
            paint_rect.right = dest.right - nine_squared.right;
            paint_rect.bottom = dest.bottom - nine_squared.bottom;

            texture_rect.left = src.left + nine_squared.left;
            texture_rect.top = src.top + nine_squared.top;
            texture_rect.right = src.right - nine_squared.right;
            texture_rect.bottom = src.bottom - nine_squared.bottom;
            is_draw = true;
        } else if (grid == 1 && nine_squared.left > 0 && nine_squared.top > 0) {
            //left-top
            paint_rect.left = dest.left;
            paint_rect.top = dest.top;
            paint_rect.right = dest.left + nine_squared.left;
            paint_rect.bottom = dest.top + nine_squared.top;

            texture_rect.left = src.left;
            texture_rect.top = src.top;
            texture_rect.right = src.left + nine_squared.left;
            texture_rect.bottom = src.top + nine_squared.top;
            is_draw = true;
        } else if (grid == 2 && nine_squared.top > 0) {
            //top
            paint_rect.left = dest.left + nine_squared.left;
            paint_rect.top = dest.top;
            paint_rect.right = dest.right - nine_squared.right;
            paint_rect.bottom = dest.top + nine_squared.top;

            texture_rect.left = src.left + nine_squared.left;
            texture_rect.top = src.top;
            texture_rect.right = src.right - nine_squared.right;
            texture_rect.bottom = src.top + nine_squared.top;
            is_draw = true;
        } else if (grid == 3 && nine_squared.right > 0 && nine_squared.top > 0) {
            //right-top
            paint_rect.left = dest.right - nine_squared.right;
            paint_rect.top = dest.top;
            paint_rect.right = dest.right;
            paint_rect.bottom = dest.top + nine_squared.top;

            texture_rect.left = src.right - nine_squared.right;
            texture_rect.top = src.top;
            texture_rect.right = src.right;
            texture_rect.bottom = src.top + nine_squared.top;
            is_draw = true;
        } else if (grid == 4 && nine_squared.left > 0) {
            //left
            paint_rect.left = dest.left;
            paint_rect.top = dest.top + nine_squared.top;
            paint_rect.right = dest.left + nine_squared.left;
            paint_rect.bottom = dest.bottom - nine_squared.bottom;

            texture_rect.left = src.left;
            texture_rect.top = src.top + nine_squared.top;
            texture_rect.right = src.left + nine_squared.left;
            texture_rect.bottom = src.bottom - nine_squared.bottom;
            is_draw = true;
        } else if (grid == 5 && nine_squared.right > 0) {
            //right
            paint_rect.left = dest.right - nine_squared.right;
            paint_rect.top = dest.top + nine_squared.top;
            paint_rect.right = dest.right;
            paint_rect.bottom = dest.bottom - nine_squared.bottom;

            texture_rect.left = src.right - nine_squared.right;
            texture_rect.top = src.top + nine_squared.top;
            texture_rect.right = src.right;
            texture_rect.bottom = src.bottom - nine_squared.bottom;
            is_draw = true;
        } else if (grid == 6 && nine_squared.left > 0 && nine_squared.bottom > 0) {
            //left-bottom
            paint_rect.left = dest.left;
            paint_rect.top = dest.bottom - nine_squared.bottom;
            paint_rect.right = dest.left + nine_squared.left;
            paint_rect.bottom = dest.bottom;

            texture_rect.left = src.left;
            texture_rect.top = src.bottom - nine_squared.bottom;
            texture_rect.right = src.left + nine_squared.left;
            texture_rect.bottom = src.bottom;
            is_draw = true;
        } else if (grid == 7 && nine_squared.bottom > 0) {
            //bottom
            paint_rect.left = dest.left + nine_squared.left;
            paint_rect.top = dest.bottom - nine_squared.bottom;
            paint_rect.right = dest.right - nine_squared.right;
            paint_rect.bottom = dest.bottom;

            texture_rect.left = src.left + nine_squared.left;
            texture_rect.top = src.bottom - nine_squared.bottom;
            texture_rect.right = src.right - nine_squared.right;
            texture_rect.bottom = src.bottom;
            is_draw = true;
        } else if (grid == 8 && nine_squared.right > 0 && nine_squared.bottom > 0) {
            //right-bottom
            paint_rect.left = dest.right - nine_squared.right;
            paint_rect.top = dest.bottom - nine_squared.bottom;
            paint_rect.right = dest.right;
            paint_rect.bottom = dest.bottom;

            texture_rect.left = src.right - nine_squared.right;
            texture_rect.top = src.bottom - nine_squared.bottom;
            texture_rect.right = src.right;
            texture_rect.bottom = src.bottom;
            is_draw = true;
        }
        if (is_draw) {
            D3DSURFACE_DESC pic_desc;
            picture_surface->GetDesc(&pic_desc);

            Vertex *vertex = vector_buffer + kVertexCount;
            memcpy_s(vertex, 6*sizeof(Vertex), vectors, 6*sizeof(Vertex));
            vertex[0].x = static_cast<float>(paint_rect.left);
            vertex[0].y = static_cast<float>(paint_rect.bottom);
            vertex[0].picture_u = static_cast<float>(texture_rect.left) / pic_desc.Width;
            vertex[0].picture_v = static_cast<float>(texture_rect.bottom) / pic_desc.Height;

            vertex[1].x = static_cast<float>(paint_rect.left);
            vertex[1].y = static_cast<float>(paint_rect.top);
            vertex[1].picture_u = static_cast<float>(texture_rect.left) / pic_desc.Width;
            vertex[1].picture_v = static_cast<float>(texture_rect.top) / pic_desc.Height;

            vertex[2].x = static_cast<float>(paint_rect.right);
            vertex[2].y = static_cast<float>(paint_rect.top);
            vertex[2].picture_u = static_cast<float>(texture_rect.right) / pic_desc.Width;
            vertex[2].picture_v = static_cast<float>(texture_rect.top) / pic_desc.Height;

            vertex[3].x = static_cast<float>(paint_rect.left);
            vertex[3].y = static_cast<float>(paint_rect.bottom);
            vertex[3].picture_u = static_cast<float>(texture_rect.left) / pic_desc.Width;
            vertex[3].picture_v = static_cast<float>(texture_rect.bottom) / pic_desc.Height;

            vertex[4].x = static_cast<float>(paint_rect.right);
            vertex[4].y = static_cast<float>(paint_rect.top);
            vertex[4].picture_u = static_cast<float>(texture_rect.right) / pic_desc.Width;
            vertex[4].picture_v = static_cast<float>(texture_rect.top) / pic_desc.Height;

            vertex[5].x = static_cast<float>(paint_rect.right);
            vertex[5].y = static_cast<float>(paint_rect.bottom);
            vertex[5].picture_u = static_cast<float>(texture_rect.right) / pic_desc.Width;
            vertex[5].picture_v = static_cast<float>(texture_rect.bottom) / pic_desc.Height;
            kVertexCount += 6;
        }

    }
    
}

RECT GetTexturePicturePos(IDirect3DSurface9 *surface) {
    //这个函数应该写个纹理管理算法,这里只是简单的放到上面去
    RECT dest = {0};
    if (nullptr == surface) {
        return dest;
    }
    D3DSURFACE_DESC desc;
    surface->GetDesc(&desc);
    RECT src;
    ::SetRect(&src, 0, 0, desc.Width, desc.Height);

    HRESULT hr = device9->StretchRect(surface, &src, picture_surface, &src, D3DTEXF_NONE);
    return src;
}
需要下载一个stb_image.c文件,这个文件是开源的。

然后就是效果图:



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值