本帖最后由 VisualEleven 于 2012-09-26 13:40:14 编辑

解决方案 »

  1.   

    csdn资源上传了,还没给我地址= =
      

  2.   

    源码:#include "StdAfx.h"
    #include <windows.h>
    #include <crtdbg.h>#include "WYImgHelper.h"#define WND_WIDTH 800
    #define WND_HEIGHT 600
    #define WND_CLASSNAME "MainWnd"
    #define WND_TITLENAME "Test"
    #define FULLSCREEN 0
    struct SBmpInfo
    {
    BITMAPINFO m_BitmapInfo;
    RGBQUAD m_bmiColors[2]; // 为BITMAPINFO的m_bmiColors补充两个元素空间
    };struct SGDI
    {
    HWND m_hWnd;
    HDC m_hMainDC;
    HDC m_hMemoryDC;
    HBITMAP m_hMainSurface;
    HBITMAP m_hOldBitmap;
    int m_Width;
    int m_Height;
    UINT* m_pBackBuffer;
    SBmpInfo m_BmpInfo;
    };SGDI g_GDI;UINT* g_pBmp = NULL;
    int g_bmpWidth = 0;
    int g_bmpHeight = 0;
    void AlphaBlend32(UINT* pDstBmp, int dst_width, UINT* pSrcBmp, int src_width, int blend_width, int blend_height)
    {
    const int nextLineOffset_src = (src_width - blend_width) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
    const int nextLineOffset_dst = (dst_width - blend_width) * 4; __asm
    {
    mov edi, pDstBmp ; 目的像素
    mov esi, pSrcBmp ; 源像素
    xor ebx, ebx ; 已混合的高度
    mov ecx, blend_width ; 要混合的宽度BLEND_BEGIN:
    cmp dword ptr[esi], 0x00FFFFFF ; 如果alpha为0,则跳过混合部分
    jna BLEND_END movd mm0, [edi] ; 把目的像素值移入mm0寄存器的低32位
    movd mm1, [esi] ; 把源像素值移入mm1寄存器的低32位 ; Core Begin
    pxor mm2, mm2 ; 把MM2清0
    punpcklbw mm0, mm2 ; src:8 bit到16 bit以容纳结果,32bit expand to 64 bit
    punpcklbw mm1, mm2 ; dst:8 bit到16 bit以容纳结果.32bit expand to 64 bit
    movq mm3, mm1 ; 因为要用dst的Alpha值
    punpckhwd mm3, mm3 ; 高字移动到双字
    punpckhdq mm3, mm3 ; 双字移动到四字,现在有八个像素的Alpha了!
    movq mm4, mm0 ; mm4 = dst
    movq mm5, mm1 ; mm5 = src
    psubusw mm4, mm1 ; dst-src,饱和减,小于0为0
    psubusw mm5, mm0 ; src-dst,饱和减,小于0为0
    pmullw mm4, mm3 ; Alpha * (src-dst)
    pmullw mm5, mm3 ; Alpha * (dst-src)
    psrlw mm4, 8 ; 除以256,now mm4 get the result,(src-dst)<0 部分
    psrlw mm5, 8 ; 除以256,now mm5 get the result,(dst-src)>0 部分
    paddusw mm0, mm5 ; 饱和加到原图象:D=Alpha*(O-S)+S,(src-dst)<0 部分
    psubusw mm0, mm4 ; 饱和加到原图象D=S-Alpha*(S-O),(dst-src)>0 部分
    packuswb mm0, mm0 ; 紧缩到低32bit
    ; Core End movd [edi], mm0 ; 混合结果写进目的像素BLEND_END:
    add edi, 4
    add esi, 4
    loop BLEND_BEGIN ; 循环 add esi, nextLineOffset_src ; 加上偏移量,使定位到下行起始处
    add edi, nextLineOffset_dst inc ebx
    mov ecx, blend_width cmp ebx, blend_height ; 若ebx小于blend_height,则转移到上面继续混合
    jb BLEND_BEGIN EMMS ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
    }
    }void DrawBmp(UINT* pBmp, int width, int height, int x, int y)
    {
    RECT srcRect = { 0, 0, width-1, height-1 };
    RECT dstRect = { x, y, 0, 0 }; float scale_x = 0;
    float scale_y = 0;
    float tscale_x = 1.0f;
    float tscale_y = 1.0f;
    float sumW = 0;
    float sumH = 0; int visibleW = 0;
    int visibleH = 0; // 边界校正
    {
    if (srcRect.right >= width)
    srcRect.right = width - 1;
    if (srcRect.bottom >= height)
    srcRect.bottom = height - 1; // 超出左边界
    if (dstRect.left < 0)
    {
    srcRect.left += -dstRect.left;
    dstRect.left = 0;
    }
    // 超出上边界
    if (dstRect.top < 0)
    {
    srcRect.top += -dstRect.top;
    dstRect.top = 0;
    } visibleW = srcRect.right - srcRect.left + 1;
    visibleH = srcRect.bottom - srcRect.top + 1; // 超出右边界
    if (dstRect.left+visibleW > g_GDI.m_Width)
    {
    visibleW = g_GDI.m_Width - dstRect.left;
    srcRect.right = srcRect.left + visibleW-1;
    }
    // 超出下边界
    if (dstRect.top+visibleH > g_GDI.m_Height)
    {
    visibleH = g_GDI.m_Height - dstRect.top;
    srcRect.bottom = srcRect.top + visibleH-1;
    }
    dstRect.right = dstRect.left + (srcRect.right-srcRect.left);
    dstRect.bottom = dstRect.top + (srcRect.bottom-srcRect.top); if (visibleW<=0 || visibleH<=0) return;
    } UINT* pSrc = pBmp + srcRect.top*width+srcRect.left;
    UINT* pDst = g_GDI.m_pBackBuffer + dstRect.top*g_GDI.m_Width+dstRect.left;
    AlphaBlend32(pDst, g_GDI.m_Width, pSrc, width, srcRect.right-srcRect.left+1, srcRect.bottom-srcRect.top+1);
    //  for (int h=0; h<visibleH; h++)
    //  {
    //  memcpy(pDst, pSrc, visibleW*4);
    //  pSrc += width;
    //  pDst += g_GDI.m_Width;
    //  }
    }bool Init(HWND hWnd)
    {
    // 初始化g_GDI
    {
    memset(&g_GDI, 0, sizeof(g_GDI));
    g_GDI.m_hWnd = hWnd;
    g_GDI.m_Width = WND_WIDTH;
    g_GDI.m_Height = WND_HEIGHT;
    g_GDI.m_hMainDC = ::GetDC(hWnd);
    g_GDI.m_hMemoryDC = ::CreateCompatibleDC(NULL);
    g_GDI.m_hMainSurface = ::CreateCompatibleBitmap(g_GDI.m_hMainDC, g_GDI.m_Width, g_GDI.m_Height);
    g_GDI.m_pBackBuffer = new UINT[g_GDI.m_Width*g_GDI.m_Height]; BITMAPINFO& bmpInfo = g_GDI.m_BmpInfo.m_BitmapInfo;
    bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
    bmpInfo.bmiHeader.biWidth = g_GDI.m_Width;
    bmpInfo.bmiHeader.biHeight = -g_GDI.m_Height;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biBitCount = 32;
    bmpInfo.bmiHeader.biCompression = BI_BITFIELDS; *(UINT*)(bmpInfo.bmiColors+0) = 0xFF0000; // red分量
    *(UINT*)(bmpInfo.bmiColors+1) = 0x00FF00; // green分量
    *(UINT*)(bmpInfo.bmiColors+2) = 0x0000FF; // blue分量
    } {
    WuYuan::STGA_HEADER tgaHeader;
    FILE* pFile = WuYuan::TGA_OpenFile("test.tga", &tgaHeader);
    g_pBmp = new UINT[tgaHeader.ImageWidth*tgaHeader.ImageHeight];
    WuYuan::TGA_ReadPixel(pFile, &tgaHeader, g_pBmp, true);
    fclose(pFile); g_bmpWidth = tgaHeader.ImageWidth;
    g_bmpHeight = tgaHeader.ImageHeight;
    } DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
    if (!(dwExStyle & WS_EX_LAYERED))
    ::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle|WS_EX_LAYERED); return true;
    }void End()
    {
    if (g_pBmp != NULL)
    {
    delete [] g_pBmp;
    g_pBmp = NULL;
    } if (g_GDI.m_hMainSurface != NULL)
    {
    ::DeleteObject(g_GDI.m_hMainSurface);
    g_GDI.m_hMainSurface = NULL;
    }
    if (g_GDI.m_hMemoryDC != NULL)
    {
    ::DeleteDC(g_GDI.m_hMemoryDC);
    g_GDI.m_hMemoryDC = NULL;
    }
    if (g_GDI.m_hMainDC != NULL)
    {
    ReleaseDC(g_GDI.m_hWnd, g_GDI.m_hMainDC);
    g_GDI.m_hMainDC = NULL;
    }
    }void MainLoop()
    {
    // 将主表面选入内存DC
    g_GDI.m_hOldBitmap = (HBITMAP)::SelectObject(g_GDI.m_hMemoryDC, g_GDI.m_hMainSurface); // 清空后台像素
    memset(g_GDI.m_pBackBuffer, 0, g_GDI.m_Width*g_GDI.m_Height*4); DrawBmp(g_pBmp, g_bmpWidth, g_bmpHeight, 0, 0); // Flip
    {
    ::SetDIBitsToDevice(g_GDI.m_hMemoryDC,
    0, 0, g_GDI.m_Width, g_GDI.m_Height,
    0, 0, 0, g_GDI.m_Height,
    g_GDI.m_pBackBuffer, &g_GDI.m_BmpInfo.m_BitmapInfo, DIB_RGB_COLORS); {
    RECT rcWnd;
    ::GetWindowRect(g_GDI.m_hWnd, &rcWnd); POINT srcPos = { 0, 0 };
    POINT dstPos = { rcWnd.left, rcWnd.top };
    SIZE dstSize = { rcWnd.right-rcWnd.left, rcWnd.bottom-rcWnd.top }; BLENDFUNCTION blend;
    blend.BlendOp = 0;
    blend.BlendFlags = 0;
    blend.AlphaFormat = AC_SRC_ALPHA;
    blend.SourceConstantAlpha = 255;
    ::UpdateLayeredWindow(g_GDI.m_hWnd, g_GDI.m_hMainDC, &dstPos, &dstSize, g_GDI.m_hMemoryDC, &srcPos, 0, &blend, ULW_ALPHA);
    }
    } if (g_GDI.m_hOldBitmap != NULL)
    {
    ::SelectObject(g_GDI.m_hMemoryDC, g_GDI.m_hOldBitmap);
    g_GDI.m_hOldBitmap = NULL;
    }
    }LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    switch (uMsg)
    {
    case WM_LBUTTONDOWN:
    // 使鼠标单击窗口任何一个地方都能移动整个窗口
    ::SendMessageA(hWnd, WM_SYSCOMMAND, 0xF012, 0);
    break;
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps);
    return 0;
    }
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    } return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int nCmdShow)
    {
    // 内存泄漏检测
    #if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif WNDCLASSEXA wndClass;
    wndClass.cbSize = sizeof(wndClass);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NORMAL));
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;//MAKEINTRESOURCE(IDC_DAHUAXY2);
    wndClass.lpszClassName = WND_CLASSNAME;
    wndClass.hIconSm = NULL;//LoadIcon(wndClass.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    RegisterClassExA(&wndClass); DWORD wndStyle = WS_POPUP | WS_MINIMIZEBOX | WS_SYSMENU; // 无标题栏:WS_POPUP | WS_MINIMIZEBOX | WS_SYSMENU;
    if (FULLSCREEN)
    wndStyle = WS_POPUP; RECT rcWnd = { 0, 0, WND_WIDTH, WND_HEIGHT };
    AdjustWindowRect(&rcWnd, wndStyle, FALSE); HWND hWnd = CreateWindowExA(0,
    WND_CLASSNAME,
    WND_TITLENAME,
    wndStyle,
    (GetSystemMetrics(SM_CXSCREEN)-WND_WIDTH)/2, // SM_CXSCREEN:以像素为单位的屏幕的宽度
    (GetSystemMetrics(SM_CYSCREEN)-WND_HEIGHT)/2, // SM_CYSCREEN:以像素为单位的屏幕的高度
    (rcWnd.right-rcWnd.left), (rcWnd.bottom-rcWnd.top),
    NULL,
    NULL,
    hInstance,
    NULL); ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd); Init(hWnd); MSG msg;
    memset(&msg, 0, sizeof(msg)); while (TRUE)
    {
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
    if (msg.message == WM_QUIT)
    break; TranslateMessage(&msg);
    DispatchMessage(&msg);
    } // 帧开始
    const int constFps = 60;
    float timeInOneFps = 1000.0f/constFps; // 每秒60帧,则1帧就是约16毫秒
    DWORD timeBegin = GetTickCount(); MainLoop(); // 限帧
    DWORD timeTotal = GetTickCount() - timeBegin;
    if (timeTotal < timeInOneFps)
    {
    // Sleep(DWORD(timeInOneFps-timeTotal));
    }
    } End(); UnregisterClassA(WND_CLASSNAME, hInstance); return 0;
    }
      

  3.   

    完整下载地址:
    http://download.csdn.net/detail/weiwuyuan/4585498
      

  4.   

    用CreateDIBSection好点
    如果显示属性那里设置颜色质量为16位,CreateCompatibleBitmap创建的就不是32位位图了
      

  5.   

    可惜vc6上不能显示‘"test.tga"’
      

  6.   

    内存leak:
    // leak
    if (g_GDI.m_pBackBuffer != NULL)
    {
    delete [] g_GDI.m_pBackBuffer;
    g_GDI.m_pBackBuffer = NULL;
    }
      

  7.   


    代码写的有点匆忙,csdn的贴子又不让修改。还是人家GameRes比较开放和民主.
      

  8.   

    修改后的完整源码:(图像数据在代码里,但内容需要自己填充)#include <windows.h>
    #include <crtdbg.h>#define WND_WIDTH 100
    #define WND_HEIGHT 100
    #define WND_CLASSNAME "MainWnd"
    #define WND_TITLENAME "Test"
    struct SBmpInfo
    {
    BITMAPINFO m_BitmapInfo;
    RGBQUAD m_bmiColors[2]; // 为BITMAPINFO的m_bmiColors补充两个元素空间
    };struct SGDI
    {
    HWND m_hWnd;
    HDC m_hMainDC;
    HDC m_hMemoryDC;
    HBITMAP m_hMainSurface;
    HBITMAP m_hOldBitmap;
    int m_Width;
    int m_Height;
    UINT* m_pBackBuffer;
    SBmpInfo m_BmpInfo;
    };SGDI g_GDI;
    UINT g_Bmp32[40*39];  // 这个图像数据需要自己填充.
    int g_bmpWidth = 40;
    int g_bmpHeight = 39;
    void AlphaBlend32(UINT* pDstBmp, int dst_width, UINT* pSrcBmp, int src_width, int blend_width, int blend_height)
    {
    const int nextLineOffset_src = (src_width - blend_width) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
    const int nextLineOffset_dst = (dst_width - blend_width) * 4; __asm
    {
    mov edi, pDstBmp ; 目的像素
    mov esi, pSrcBmp ; 源像素
    xor ebx, ebx ; 已混合的高度
    mov ecx, blend_width ; 要混合的宽度BLEND_BEGIN:
    cmp dword ptr[esi], 0x00FFFFFF ; 如果alpha为0,则跳过混合部分
    jna BLEND_END movd mm0, [edi] ; 把目的像素值移入mm0寄存器的低32位
    movd mm1, [esi] ; 把源像素值移入mm1寄存器的低32位 ; Core Begin:result = b - (b-a)*a_alpha/255 (a为源像素分量,b为目的像素分量)
    pxor mm2, mm2 ; ① 把MM2清0
    punpcklbw mm0, mm2 ;    将mm0与mm2按字节交叉组合,存入mm0,mm0 = 0x00AA00BB00GG00RR
    punpcklbw mm1, mm2 ;    将mm1与mm2按字节交叉组合,存入mm1,mm1 = 0x00AA00BB00GG00RR
    movq mm3, mm1 ; ② mm3 = 0x00AA00BB00GG00RR
    punpckhwd mm3, mm3 ;    将高32位按16位交错排列,mm3 = 0x00AA00AA00BB00BB
    punpckhdq mm3, mm3 ;    将高32位按32位交错排列,mm3 = 0x00AA00AA00AA00AA
    movq mm4, mm0 ; ③ mm4 = 目的像素 = 0x00AA00BB00GG00RR
    movq mm5, mm1 ;    mm5 = 源像素   = 0x00AA00BB00GG00RR
    psubusw mm4, mm1 ; ④ dst-src,按字饱和减,小于0为0
    psubusw mm5, mm0 ;    src-dst,按字饱和减,小于0为0
    pmullw mm4, mm3 ;    (dst-src) * alpha,若dst-src为0,则mm4为0
    pmullw mm5, mm3 ;    (src-dst) * alpha,若src-dst为0,则mm5为0
    psrlw mm4, 8 ; 按字右移8位,即除以256
    psrlw mm5, 8 ; 按字右移8位,即除以256
    paddusw mm0, mm5 ; 饱和加到原图象:D=Alpha*(O-S)+S,(src-dst)<0 部分
    psubusw mm0, mm4 ; 饱和加到原图象D=S-Alpha*(S-O),(dst-src)>0 部分
    packuswb mm0, mm0 ; 按16位有符号数压缩为8位无符号数
    ; Core End movd [edi], mm0 ; 混合结果写进目的像素BLEND_END:
    add edi, 4
    add esi, 4
    loop BLEND_BEGIN ; 循环 add esi, nextLineOffset_src ; 加上偏移量,使定位到下行起始处
    add edi, nextLineOffset_dst inc ebx
    mov ecx, blend_width cmp ebx, blend_height ; 若ebx小于blend_height,则转移到上面继续混合
    jb BLEND_BEGIN EMMS ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
    }
    }void DrawBmp(UINT* pBmp, int width, int height, int x, int y)
    {
    RECT srcRect = { 0, 0, width-1, height-1 };
    RECT dstRect = { x, y, 0, 0 }; // 边界校正
    {
    if (srcRect.right >= width)
    srcRect.right = width - 1;
    if (srcRect.bottom >= height)
    srcRect.bottom = height - 1; // 超出左边界
    if (dstRect.left < 0)
    {
    srcRect.left += -dstRect.left;
    dstRect.left = 0;
    }
    // 超出上边界
    if (dstRect.top < 0)
    {
    srcRect.top += -dstRect.top;
    dstRect.top = 0;
    } int visibleW = srcRect.right - srcRect.left + 1;
    int visibleH = srcRect.bottom - srcRect.top + 1; // 超出右边界
    if (dstRect.left+visibleW > g_GDI.m_Width)
    {
    visibleW = g_GDI.m_Width - dstRect.left;
    srcRect.right = srcRect.left + visibleW-1;
    }
    // 超出下边界
    if (dstRect.top+visibleH > g_GDI.m_Height)
    {
    visibleH = g_GDI.m_Height - dstRect.top;
    srcRect.bottom = srcRect.top + visibleH-1;
    }
    dstRect.right = dstRect.left + (srcRect.right-srcRect.left);
    dstRect.bottom = dstRect.top + (srcRect.bottom-srcRect.top); if (visibleW<=0 || visibleH<=0) return;
    } UINT* pSrc = pBmp + srcRect.top*width+srcRect.left;
    UINT* pDst = g_GDI.m_pBackBuffer + dstRect.top*g_GDI.m_Width+dstRect.left;
    AlphaBlend32(pDst, g_GDI.m_Width, pSrc, width, srcRect.right-srcRect.left+1, srcRect.bottom-srcRect.top+1);
    }bool Init(HWND hWnd)
    {
    // 初始化g_GDI
    {
    memset(&g_GDI, 0, sizeof(g_GDI));
    g_GDI.m_hWnd = hWnd;
    g_GDI.m_Width = WND_WIDTH;
    g_GDI.m_Height = WND_HEIGHT;
    g_GDI.m_hMainDC = ::GetDC(hWnd);
    g_GDI.m_hMemoryDC = ::CreateCompatibleDC(NULL);
    g_GDI.m_hMainSurface = ::CreateCompatibleBitmap(g_GDI.m_hMainDC, g_GDI.m_Width, g_GDI.m_Height);
    g_GDI.m_pBackBuffer = (UINT*)malloc(g_GDI.m_Width*g_GDI.m_Height*4); BITMAPINFO& bmpInfo = g_GDI.m_BmpInfo.m_BitmapInfo;
    bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
    bmpInfo.bmiHeader.biWidth = g_GDI.m_Width;
    bmpInfo.bmiHeader.biHeight = -g_GDI.m_Height;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biBitCount = 32;
    bmpInfo.bmiHeader.biCompression = BI_BITFIELDS; *(UINT*)(bmpInfo.bmiColors+0) = 0xFF0000; // red分量
    *(UINT*)(bmpInfo.bmiColors+1) = 0x00FF00; // green分量
    *(UINT*)(bmpInfo.bmiColors+2) = 0x0000FF; // blue分量 // 将主表面选入内存DC
    g_GDI.m_hOldBitmap = (HBITMAP)::SelectObject(g_GDI.m_hMemoryDC, g_GDI.m_hMainSurface);
    } DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
    if (!(dwExStyle & WS_EX_LAYERED))
    ::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle|WS_EX_LAYERED); return true;
    }void End()
    {
    if (g_GDI.m_pBackBuffer != NULL)
    {
    free(g_GDI.m_pBackBuffer);
    g_GDI.m_pBackBuffer = NULL;
    }
    if (g_GDI.m_hMainSurface != NULL)
    {
    if (g_GDI.m_hOldBitmap != NULL)
    {
    ::SelectObject(g_GDI.m_hMemoryDC, g_GDI.m_hOldBitmap);
    g_GDI.m_hOldBitmap = NULL;
    } ::DeleteObject(g_GDI.m_hMainSurface);
    g_GDI.m_hMainSurface = NULL;
    }
    if (g_GDI.m_hMemoryDC != NULL)
    {
    ::DeleteDC(g_GDI.m_hMemoryDC);
    g_GDI.m_hMemoryDC = NULL;
    }
    if (g_GDI.m_hMainDC != NULL)
    {
    ReleaseDC(g_GDI.m_hWnd, g_GDI.m_hMainDC);
    g_GDI.m_hMainDC = NULL;
    }
    }void MainLoop()
    {
    // 清空后台像素
    memset(g_GDI.m_pBackBuffer, 0, g_GDI.m_Width*g_GDI.m_Height*4); DrawBmp(g_Bmp32, g_bmpWidth, g_bmpHeight, 0, 0); // Flip
    {
    ::SetDIBitsToDevice(g_GDI.m_hMemoryDC,
    0, 0, g_GDI.m_Width, g_GDI.m_Height,
    0, 0, 0, g_GDI.m_Height,
    g_GDI.m_pBackBuffer, &g_GDI.m_BmpInfo.m_BitmapInfo, DIB_RGB_COLORS); {
    RECT rcWnd;
    ::GetWindowRect(g_GDI.m_hWnd, &rcWnd); POINT srcPos = { 0, 0 };
    POINT dstPos = { rcWnd.left, rcWnd.top };
    SIZE dstSize = { rcWnd.right-rcWnd.left, rcWnd.bottom-rcWnd.top }; BLENDFUNCTION blend;
    blend.BlendOp = 0;
    blend.BlendFlags = 0;
    blend.AlphaFormat = AC_SRC_ALPHA;
    blend.SourceConstantAlpha = 255;
    ::UpdateLayeredWindow(g_GDI.m_hWnd, g_GDI.m_hMainDC, &dstPos, &dstSize, g_GDI.m_hMemoryDC, &srcPos, 0, &blend, ULW_ALPHA);
    }
    }
    }LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    switch (uMsg)
    {
    case WM_LBUTTONDOWN:
    // 使鼠标单击窗口任何一个地方都能移动整个窗口
    ::SendMessageA(hWnd, WM_SYSCOMMAND, 0xF012, 0);
    break;
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps);
    return 0;
    }
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    } return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int nCmdShow)
    {
    // 内存泄漏检测
    #if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif WNDCLASSEXA wndClass;
    wndClass.cbSize = sizeof(wndClass);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NORMAL));
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;//MAKEINTRESOURCE(IDC_DAHUAXY2);
    wndClass.lpszClassName = WND_CLASSNAME;
    wndClass.hIconSm = NULL;//LoadIcon(wndClass.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    RegisterClassExA(&wndClass); DWORD wndStyle = WS_POPUP | WS_MINIMIZEBOX | WS_SYSMENU; // 无标题栏:WS_POPUP | WS_MINIMIZEBOX | WS_SYSMENU; RECT rcWnd = { 0, 0, WND_WIDTH, WND_HEIGHT };
    AdjustWindowRect(&rcWnd, wndStyle, FALSE); HWND hWnd = CreateWindowExA(0,
    WND_CLASSNAME,
    WND_TITLENAME,
    wndStyle,
    (GetSystemMetrics(SM_CXSCREEN)-WND_WIDTH)/2, // SM_CXSCREEN:以像素为单位的屏幕的宽度
    (GetSystemMetrics(SM_CYSCREEN)-WND_HEIGHT)/2, // SM_CYSCREEN:以像素为单位的屏幕的高度
    (rcWnd.right-rcWnd.left), (rcWnd.bottom-rcWnd.top),
    NULL,
    NULL,
    hInstance,
    NULL); ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd); Init(hWnd); MSG msg;
    memset(&msg, 0, sizeof(msg)); while (TRUE)
    {
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
    if (msg.message == WM_QUIT)
    break; TranslateMessage(&msg);
    DispatchMessage(&msg);
    } // 帧开始
    const int constFps = 60;
    float timeInOneFps = 1000.0f/constFps; // 每秒60帧,则1帧就是约16毫秒
    DWORD timeBegin = GetTickCount(); MainLoop(); // 限帧
    DWORD timeTotal = GetTickCount() - timeBegin;
    if (timeTotal < timeInOneFps)
    {
    // Sleep(DWORD(timeInOneFps-timeTotal));
    }
    } End(); UnregisterClassA(WND_CLASSNAME, hInstance); return 0;
    }
      

  9.   

    我的vc6上可以显示tga了,但不知道为什么背景是 黑的 !
      

  10.   


    补充:
    我不敢保证vc6所使用的win32库能够很好的支持SetDIBitsToDevice()和UpdateLayeredWindow()函数
      

  11.   

    UpdateLayeredWindow() 这样得到:
    HINSTANCE hInstTmp = LoadLibrary("User32.DLL"); 
    if(hInstTmp) 
    { //取得 UpdateLayeredWindow 函数指针 
    g_fun=(MYFUNC)GetProcAddress(hInstTmp, "UpdateLayeredWindow");
    if(g_fun==0) MessageBox(hWnd,"UpdateLayeredWindow not found","Error",MB_OK);
    FreeLibrary(hInstTmp); 
    } SetDIBitsToDevice() 有变化?我的系统是 xp sp2。
      

  12.   


    void WuYuan::AlphaBlend32(UINT* pDstBmp, int dst_width, UINT* pSrcBmp, int src_width, int blend_width, int blend_height)
    {
    // C实现
    //  {
    //  const int nextLineOffset_src = (src_width - blend_width) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
    //  const int nextLineOffset_dst = (dst_width - blend_width) * 4;
    //  BYTE* pSrc = (BYTE*)pSrcBmp;
    //  BYTE* pDst = (BYTE*)pDstBmp;
    //  int below_A, below_R, below_G, below_B;
    //  int above_A, above_R, above_G, above_B;
    // 
    //  for (int h=0, w=0; h<blend_height; h++)
    //  {
    //  for (w=0; w<blend_width; w++)
    //  {
    //  above_B = *pSrc++;
    //  above_G = *pSrc++;
    //  above_R = *pSrc++;
    //  above_A = *pSrc++;
    // 
    //  if (above_A == 0)
    //  {
    //  pDst += 4;
    //  continue;
    //  }
    // 
    //  below_B = *pDst;
    //  below_G = *(pDst+1);
    //  below_R = *(pDst+2);
    //  below_A = *(pDst+3);
    // 
    //  *pDst++ = below_B - (below_B-above_B)*above_A/255;
    //  *pDst++ = below_G - (below_G-above_G)*above_A/255;
    //  *pDst++ = below_R - (below_R-above_R)*above_A/255;
    // 
    //  if (below_A == 255)
    //  *pDst++ = 255;
    //  else
    //  *pDst++ = below_A - (below_A-above_A)*above_A/255;
    //  }
    // 
    //  pSrc += nextLineOffset_src;
    //  pDst += nextLineOffset_dst;
    //  }
    //  return;
    //  } const int nextLineOffset_src = (src_width - blend_width) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
    const int nextLineOffset_dst = (dst_width - blend_width) * 4; __asm
    {
    mov edi, pDstBmp ; 目的像素
    mov esi, pSrcBmp ; 源像素
    xor ebx, ebx ; 已混合的高度
    mov ecx, blend_width ; 要混合的宽度BLEND_BEGIN:
    cmp dword ptr[esi], 0x00FFFFFF ; 如果alpha为0,则跳过混合部分
    jna BLEND_END movd mm0, [edi] ; 把目的像素值移入mm0寄存器的低32位
    movd mm1, [esi] ; 把源像素值移入mm1寄存器的低32位 ; Core Begin:result = b - (b-a)*a_alpha/255 (a为源像素分量,b为目的像素分量)
    pxor mm2, mm2 ; ① 把MM2清0
    punpcklbw mm0, mm2 ;    将mm0与mm2按字节交叉组合,存入mm0,mm0 = 0x00AA00BB00GG00RR
    punpcklbw mm1, mm2 ;    将mm1与mm2按字节交叉组合,存入mm1,mm1 = 0x00AA00BB00GG00RR
    movq mm3, mm1 ; ② mm3 = 0x00AA00BB00GG00RR
    punpckhwd mm3, mm3 ;    将高32位按16位交错排列,mm3 = 0x00AA00AA00BB00BB
    punpckhdq mm3, mm3 ;    将高32位按32位交错排列,mm3 = 0x00AA00AA00AA00AA
    movq mm4, mm0 ; ③ mm4 = 目的像素 = 0x00AA00BB00GG00RR
    movq mm5, mm1 ;    mm5 = 源像素   = 0x00AA00BB00GG00RR
    psubusw mm4, mm1 ; ④ dst-src,按字饱和减,小于0为0
    psubusw mm5, mm0 ;    src-dst,按字饱和减,小于0为0
    pmullw mm4, mm3 ;    (dst-src) * alpha,若dst-src为0,则mm4为0
    pmullw mm5, mm3 ;    (src-dst) * alpha,若src-dst为0,则mm5为0
    psrlw mm4, 8 ; 按字右移8位,即除以256
    psrlw mm5, 8 ; 按字右移8位,即除以256
    paddusw mm0, mm5 ; 饱和加到原图象:D=Alpha*(O-S)+S,(src-dst)<0 部分
    psubusw mm0, mm4 ; 饱和加到原图象D=S-Alpha*(S-O),(dst-src)>0 部分
    packuswb mm0, mm0 ; 按16位有符号数压缩为8位无符号数
    ; Core End movd [edi], mm0 ; 混合结果写进目的像素BLEND_END:
    add edi, 4
    add esi, 4
    loop BLEND_BEGIN ; 循环 add esi, nextLineOffset_src ; 加上偏移量,使定位到下行起始处
    add edi, nextLineOffset_dst inc ebx
    mov ecx, blend_width cmp ebx, blend_height ; 若ebx小于blend_height,则转移到上面继续混合
    jb BLEND_BEGIN EMMS ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
    }
    }
    这是我的原始代码,看到里面被注释掉的部分了吧?他是C实现,如果你觉得mmx看不懂,你可以换成这个,这上面发的代码,就是把这段给删了而已。