找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 7005|回复: 3

【C】真·抖动算法(GPU加速)Dithering with GPU

[复制链接]

1110

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24225 个
贡献
46222 次
宅之契约
0 份
在线时间
2296 小时
注册时间
2014-1-26
发表于 2015-3-9 21:53:37 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
我真是醉了,一直以为抖动算法都是要靠将颜色当成向量然后在空间中进行几何运算,曾经写的抖动算法都是这样的,效果却很不好。
这次从维基百科找到了算法= =果然是被自己坑死了
http://en.wikipedia.org/wiki/Ordered_dithering
其实算法很简单。看下面的伪指令:
  1. For Y = 1 To 高度
  2.     For X = 1 To 宽度
  3.         最近距离 = 取得距离(找到最接近的调色板颜色(原始颜色(x, y)), 原始颜色(x, y)) / 最大距离
  4.         旧像素 = 原始颜色(x, y) + 抖动矩阵(x Mod 16, Y Mod 16) * 最近距离
  5.         新像素 = 找到最接近的调色板颜色(旧像素)
  6.     Next
  7. Next
复制代码
这样的处理是完全可以进行并行处理的,所以不能浪费GPU资源。当然如果没有找到OpenGL 2.0支持的时候,我写的这个库,也能自动进行软件抖动。
20150309204339.png
20150309210135.png

测试用图:
图像来源:http://www.pixiv.net/member_illu ... ;illust_id=45035418
画师:木葵ひなた
槚本贵音 (Ene)
电视动画:目隐都市的演绎者

经过抖动算法之后,图像在被降级至256色的时候,仍然能表现出不错的画质。这就是抖动算法的作用了。当然刚才给的示例中我只是用的平均抖动算法,所以效果不太好。要配合八叉树算法才能将图像的损失降到最低。
相关资料:八叉树算法http://www.0xaa55.com/thread-1214-1-1.html
  1. //=============================================================================
  2. //作者:0xAA55
  3. //网站:[url]http://www.0xaa55.com/[/url]
  4. //请保留原作者信息,否则视为侵权。
  5. //-----------------------------------------------------------------------------
  6. //必须在包含gl.h之前包含glew.h
  7. #include<gl\glew.h>
  8. #include<stdio.h>
  9. #include<stdint.h>
  10. #include<malloc.h>
  11. #include<math.h>

  12. #define        D_Source
  13. #include"Dither.h"

  14. #define MaxWaitTime 1000
  15. //#define Software_Only

  16. //着色器代码
  17. extern char                g_szDitherVSCode[];
  18. extern char                g_szDitherFSCode[];

  19. #ifdef _DEBUG
  20. static void DbgInfo(char*szFormat,...)
  21. {
  22.         char szBuf[0x1000];//4K缓冲区
  23.         va_list ap;
  24.         va_start(ap,szFormat);
  25.         vsprintf(szBuf,szFormat,ap);
  26.         MessageBoxA(NULL,szBuf,"Dither",MB_ICONINFORMATION);
  27.         va_end(ap);
  28. }
  29. static void ShowShaderOutput(GLuint uProgram)
  30. {
  31.         GLsizei Length;
  32.         glGetProgramiv(uProgram,GL_INFO_LOG_LENGTH,&Length);
  33.         if(Length)
  34.         {
  35.                 GLsizei BytesRet;
  36.                 char*pBuffer=(char*)malloc(Length);
  37.                 if(!pBuffer)
  38.                         return;
  39.                 glGetProgramInfoLog(uProgram,Length,&BytesRet,pBuffer);
  40.                 if(strlen(pBuffer))
  41.                         MessageBoxA(NULL,pBuffer,NULL,MB_OK);
  42.                 free(pBuffer);
  43.         }
  44. }
  45. #else
  46. #define DbgInfo(fmt,...)
  47. #define ShowShaderOutput(u)
  48. #endif // _DEBUG

  49. const uint8_t g_DitherMatrix[]=
  50. {
  51.         0x00,0xEB,0x3B,0xDB,0x0F,0xE7,0x37,0xD7,0x02,0xE8,0x38,0xD9,0x0C,0xE5,0x34,0xD5,
  52.         0x80,0x40,0xBB,0x7B,0x8F,0x4F,0xB7,0x77,0x82,0x42,0xB8,0x78,0x8C,0x4C,0xB4,0x74,
  53.         0x21,0xC0,0x10,0xFB,0x2F,0xCF,0x1F,0xF7,0x22,0xC2,0x12,0xF8,0x2C,0xCC,0x1C,0xF4,
  54.         0xA1,0x61,0x90,0x50,0xAF,0x6F,0x9F,0x5F,0xA2,0x62,0x92,0x52,0xAC,0x6C,0x9C,0x5C,
  55.         0x08,0xE1,0x30,0xD0,0x05,0xEF,0x3F,0xDF,0x0A,0xE2,0x32,0xD2,0x06,0xEC,0x3C,0xDC,
  56.         0x88,0x48,0xB0,0x70,0x85,0x45,0xBF,0x7F,0x8A,0x4A,0xB2,0x72,0x86,0x46,0xBC,0x7C,
  57.         0x29,0xC8,0x18,0xF0,0x24,0xC5,0x14,0xFF,0x2A,0xCA,0x1A,0xF2,0x26,0xC6,0x16,0xFC,
  58.         0xA9,0x69,0x98,0x58,0xA4,0x64,0x94,0x54,0xAA,0x6A,0x9A,0x5A,0xA6,0x66,0x96,0x56,
  59.         0x03,0xE9,0x39,0xD8,0x0D,0xE4,0x35,0xD4,0x01,0xEA,0x3A,0xDA,0x0E,0xE6,0x36,0xD6,
  60.         0x83,0x43,0xB9,0x79,0x8D,0x4D,0xB5,0x75,0x81,0x41,0xBA,0x7A,0x8E,0x4E,0xB6,0x76,
  61.         0x23,0xC3,0x13,0xF9,0x2D,0xCD,0x1D,0xF5,0x20,0xC1,0x11,0xFA,0x2E,0xCE,0x1E,0xF6,
  62.         0xA3,0x63,0x93,0x53,0xAD,0x6D,0x9D,0x5D,0xA0,0x60,0x91,0x51,0xAE,0x6E,0x9E,0x5E,
  63.         0x0B,0xE3,0x33,0xD3,0x07,0xED,0x3D,0xDD,0x09,0xE0,0x31,0xD1,0x04,0xEE,0x3E,0xDE,
  64.         0x8B,0x4B,0xB3,0x73,0x87,0x47,0xBD,0x7D,0x89,0x49,0xB1,0x71,0x84,0x44,0xBE,0x7E,
  65.         0x2B,0xCB,0x1B,0xF3,0x27,0xC7,0x17,0xFD,0x28,0xC9,0x19,0xF1,0x25,0xC4,0x15,0xFE,
  66.         0xAB,0x6B,0x9B,0x5B,0xA7,0x67,0x97,0x57,0xA8,0x68,0x99,0x59,0xA5,0x65,0x95,0x55,
  67. };

  68. #ifdef _WIN32

  69. //=============================================================================
  70. //函数:WndProcForHiddenWindow
  71. //描述:隐藏窗口的消息处理程序
  72. //-----------------------------------------------------------------------------
  73. static LRESULT CALLBACK WndProcForHiddenWindow
  74. (
  75.         HWND hWnd,
  76.         UINT Msg,
  77.         WPARAM wp,
  78.         LPARAM lp
  79. )
  80. {
  81.         switch(Msg)
  82.         {
  83.         default:
  84.                 return DefWindowProc(hWnd,Msg,wp,lp);
  85.         case WM_DESTROY:
  86.                 PostQuitMessage(0);
  87.                 return 0;
  88.         }
  89. }

  90. //=============================================================================
  91. //函数:HiddenWindowThreadProc
  92. //描述:创建一个线程用于处理窗口消息循环。
  93. //平台相关。参数为堆上的D_GLContext结构体
  94. //-----------------------------------------------------------------------------
  95. static DWORD WINAPI HiddenWindowThreadProc(D_GLContextP pContext)
  96. {
  97.         MSG msg;
  98.         WNDCLASSEX WCEx=
  99.         {
  100.                 sizeof(WNDCLASSEX),
  101.                 0,
  102.                 (WNDPROC)WndProcForHiddenWindow,
  103.                 0,
  104.                 0,
  105.                 GetModuleHandle(NULL),
  106.                 NULL,
  107.                 NULL,
  108.                 (HBRUSH)(COLOR_WINDOW+1),
  109.                 NULL,
  110.                 TEXT("Dither_HiddenWindow"),
  111.                 NULL
  112.         };
  113.         pContext->aHiddenWindow=RegisterClassEx(&WCEx);
  114.         if(pContext->aHiddenWindow && !pContext->hWnd)
  115.                 pContext->hWnd=CreateWindowEx(0,MAKEINTATOM(pContext->aHiddenWindow),
  116.                 TEXT(""),WS_POPUP|WS_SYSMENU,0,0,1,1,NULL,NULL,WCEx.hInstance,NULL);
  117.        
  118.         while(GetMessage(&msg,pContext->hWnd,0,0))
  119.         {
  120.                 if(msg.message==WM_CLOSE)
  121.                         break;
  122.                 TranslateMessage(&msg);
  123.                 DispatchMessage(&msg);
  124.         }
  125.         return msg.wParam;
  126. }

  127. //=============================================================================
  128. //函数:CreateHiddenWindow
  129. //描述:创建一个隐藏的窗口,用于初始化OpenGL
  130. //平台相关。
  131. //-----------------------------------------------------------------------------
  132. static void CreateHiddenWindow(D_GLContextP pContext)
  133. {
  134.         DWORD dwTimer;
  135.         pContext->hThread=CreateThread(NULL,0,
  136.                 (LPTHREAD_START_ROUTINE)HiddenWindowThreadProc,pContext,0,
  137.                 &(pContext->dwThreadID));
  138.         if(!pContext->hThread)
  139.         {
  140.                 //创建线程失败。
  141.                 return;
  142.         }
  143.         dwTimer=GetTickCount();
  144.         while(!pContext->hWnd)
  145.         {
  146.                 DWORD dwExitCode;
  147.                 GetExitCodeThread(pContext->hThread,&dwExitCode);
  148.                 if(dwExitCode!=STILL_ACTIVE)//如果线程已经退出
  149.                 {
  150.                         CloseHandle(pContext->hThread);
  151.                         pContext->hThread=NULL;
  152.                         //线程失败
  153.                         return;
  154.                 }
  155.                 else//线程仍在运行
  156.                 {
  157.                         //超出能等待的时间
  158.                         if(GetTickCount()-dwTimer>MaxWaitTime)
  159.                         {
  160.                                 TerminateThread(pContext->hThread,1);
  161.                                 CloseHandle(pContext->hThread);
  162.                                 pContext->hThread=NULL;
  163.                                 //线程失败
  164.                                 return;
  165.                         }
  166.                         //切换到线程
  167. #                        if(_WIN32_WINNT >= 0x0600)
  168.                         SwitchToThread();
  169. #                        else
  170.                         Sleep(1);
  171. #                        endif
  172.                 }
  173.         }
  174. }

  175. //=============================================================================
  176. //函数:DestroyHiddenWindow
  177. //描述:销毁隐藏的窗口
  178. //-----------------------------------------------------------------------------
  179. static void DestroyHiddenWindow(D_GLContextP pContext)
  180. {
  181.         if(pContext->hWnd)
  182.         {
  183.                 //发送关闭窗口的命令
  184.                 PostMessage(pContext->hWnd,WM_CLOSE,0,0);
  185.         }
  186.         if(pContext->hThread)
  187.         {
  188.                 DWORD dwExitCode=0;
  189.                 //判断线程是否仍在运行
  190.                 GetExitCodeThread(pContext->hThread,&dwExitCode);
  191.                 if(dwExitCode==STILL_ACTIVE)
  192.                         WaitForSingleObject(pContext->hThread,MaxWaitTime);
  193.                 //判断线程是否仍在运行
  194.                 GetExitCodeThread(pContext->hThread,&dwExitCode);
  195.                 if(dwExitCode==STILL_ACTIVE)
  196.                         TerminateThread(pContext->hThread,0);
  197.                 CloseHandle(pContext->hThread);
  198.         }
  199. }

  200. //=============================================================================
  201. //函数:InitGL
  202. //描述:定义初始化OpenGL的操作
  203. //平台相关。
  204. //-----------------------------------------------------------------------------
  205. static HGLRC InitGL(HDC hDC)
  206. {
  207.         HGLRC hRC;
  208.         PIXELFORMATDESCRIPTOR PFD={0};
  209.         int nPixelFormat;

  210.         PFD.nSize                =sizeof(PFD);
  211.         PFD.nVersion        =1;
  212.         PFD.dwFlags                =PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
  213.         PFD.iPixelType        =PFD_TYPE_RGBA;
  214.         PFD.cDepthBits        =0;
  215.         PFD.cBlueBits        =8;        PFD.cBlueShift        =0;
  216.         PFD.iLayerType        =PFD_MAIN_PLANE;

  217.         nPixelFormat=ChoosePixelFormat(hDC,&PFD);
  218.         SetPixelFormat(hDC,nPixelFormat,&PFD);

  219.         hRC=wglCreateContext(hDC);
  220.         if(hRC)
  221.         {
  222.                 wglMakeCurrent(hDC,hRC);
  223.                 glewInit();
  224.                 wglMakeCurrent(NULL,NULL);
  225.                 return hRC;
  226.         }
  227.         else
  228.                 return NULL;
  229. }

  230. //=============================================================================
  231. //函数:SetDitherGLContext
  232. //描述:设置OpenGL上下文,进行OpenGL渲染前必须调用此函数。
  233. //-----------------------------------------------------------------------------
  234. static void SetDitherGLContext
  235. (
  236.         D_GLContextP pContext
  237. )
  238. {
  239.         if(pContext)
  240.                 wglMakeCurrent(pContext->hDC,pContext->hRC);
  241.         else
  242.                 wglMakeCurrent(NULL,NULL);
  243. }

  244. //=============================================================================
  245. //函数:UnsetDitherGLContextt
  246. //描述:取消设置OpenGL上下文,完成OpenGL渲染后必须调用此函数。
  247. //和SetDitherGLContext匹配使用
  248. //-----------------------------------------------------------------------------
  249. static void UnsetDitherGLContext()
  250. {
  251.         wglMakeCurrent(NULL,NULL);
  252. }

  253. //=============================================================================
  254. //函数:GetDitherGLContext
  255. //描述:创建GLContext结构,并且初始化OpenGL
  256. //代码平台相关
  257. //-----------------------------------------------------------------------------
  258. D_Func(D_GLContextP,CreateDitherGLContext)()
  259. {
  260.         D_GLContextP pRet=NULL;
  261.         GLint iUniform;//着色器参数
  262.         GLuint uDitherVS;//顶点着色器
  263.         GLuint uDitherFS;//像素着色器
  264.         GLchar*pszDitherVSCode=g_szDitherVSCode;//顶点着色器代码
  265.         GLchar*pszDitherFSCode=g_szDitherFSCode;//像素着色器代码

  266.         //分配内存
  267.         pRet=(D_GLContextP)malloc(sizeof(D_GLContext));
  268.         if(!pRet)
  269.         {
  270.                 //内存不足
  271.                 return NULL;
  272.         }
  273.         memset(pRet,0,sizeof(D_GLContext));

  274.         CreateHiddenWindow(pRet);
  275.         if(!pRet->aHiddenWindow||!pRet->hWnd)
  276.         {
  277.                 //创建隐藏的窗口失败
  278.                 goto ErrorHandler;
  279.         }

  280.         //初始化OpenGL
  281.         pRet->hDC=GetWindowDC(pRet->hWnd);
  282.         pRet->hRC=InitGL(pRet->hDC);
  283.         if(pRet->hRC)
  284.         {
  285.                 //如果功能没有支持到OpenGL 2.0
  286. #                ifndef Software_Only
  287.                 if(!GLEW_VERSION_2_0)
  288.                 {
  289. #                endif
  290.                         wglDeleteContext(pRet->hRC);
  291.                         pRet->hRC=NULL;
  292.                         ReleaseDC(pRet->hWnd,pRet->hDC);
  293.                         pRet->hDC=NULL;
  294.                         DestroyHiddenWindow(pRet);
  295.                         pRet->hWnd=NULL;
  296. #                ifndef Software_Only
  297.                 }
  298. #                endif
  299.         }
  300.         else
  301.         {
  302.                 //初始化OpenGL失败
  303.                 //使用软件加速
  304.                 ReleaseDC(pRet->hWnd,pRet->hDC);
  305.                 pRet->hDC=NULL;
  306.                 DestroyHiddenWindow(pRet);
  307.                 pRet->hWnd=NULL;
  308.         }

  309.         if(pRet->hRC)
  310.         {
  311.                 SetDitherGLContext(pRet);

  312.                 //编译着色器代码
  313.                 uDitherVS=glCreateShader(GL_VERTEX_SHADER);
  314.                 uDitherFS=glCreateShader(GL_FRAGMENT_SHADER);
  315.                 if(!uDitherVS || !uDitherFS)
  316.                 {
  317.                         //创建着色器失败
  318.                         goto ErrorHandler;
  319.                 }
  320.                 glShaderSource(uDitherVS,1,&pszDitherVSCode,NULL);
  321.                 glShaderSource(uDitherFS,1,&pszDitherFSCode,NULL);
  322.                 glCompileShader(uDitherVS);
  323.                 glCompileShader(uDitherFS);
  324.                 pRet->uDitherProgram=glCreateProgram();
  325.                 if(!pRet->uDitherProgram)
  326.                 {
  327.                         //创建着色器失败
  328.                         goto ErrorHandler;
  329.                 }
  330.                 glAttachShader(pRet->uDitherProgram,uDitherVS);
  331.                 glAttachShader(pRet->uDitherProgram,uDitherFS);
  332.                 glLinkProgram(pRet->uDitherProgram);
  333.                 ShowShaderOutput(pRet->uDitherProgram);
  334.        
  335.                 //设置着色器常数参数
  336.                 glUseProgram(pRet->uDitherProgram);
  337.                 iUniform=glGetUniformLocation(pRet->uDitherProgram,"Pal");
  338.                 glUniform1i(iUniform,0);
  339.                 iUniform=glGetUniformLocation(pRet->uDitherProgram,"Tex");
  340.                 glUniform1i(iUniform,1);
  341.                 iUniform=glGetUniformLocation(pRet->uDitherProgram,"DitherMat");
  342.                 glUniform1i(iUniform,2);
  343.                 glUseProgram(0);

  344.                 //创建纹理缓冲区
  345.                 glGenTextures(3,pRet->uTextures);

  346.                 //抖动矩阵的纹理
  347.                 glBindTexture(GL_TEXTURE_2D,pRet->uTextures[2]);
  348.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  349.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  350.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  351.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  352.                 glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,16,16,0,
  353.                         GL_BLUE,GL_UNSIGNED_BYTE,g_DitherMatrix);       
  354.                 glBindTexture(GL_TEXTURE_2D,0);

  355.                 UnsetDitherGLContext();
  356.         }

  357.         //返回创建的结构体
  358.         return pRet;
  359. ErrorHandler:
  360.         DestroyDitherGLContext(&pRet);
  361.         return NULL;
  362. }

  363. //=============================================================================
  364. //函数:DestroyDitherGLContext
  365. //描述:销毁创建的GLContext结构,结束OpenGL
  366. //-----------------------------------------------------------------------------
  367. D_Func(void,DestroyDitherGLContext)
  368. (
  369.         D_GLContextP*ppContext
  370. )
  371. {
  372.         if(ppContext && *ppContext)
  373.         {
  374.                 if((*ppContext)->hRC)
  375.                         wglDeleteContext((*ppContext)->hRC);
  376.                 if((*ppContext)->hDC && (*ppContext)->hWnd)
  377.                 {
  378.                         ReleaseDC((*ppContext)->hWnd,(*ppContext)->hDC);
  379.                         DestroyHiddenWindow(*ppContext);
  380.                 }
  381.                 free(*ppContext);
  382.                 *ppContext=NULL;
  383.         }
  384. }

  385. //=============================================================================
  386. //函数:Get24BitBits
  387. //描述:从一个HDC取得24位的Bits。缓冲区需要用户自己分配
  388. //-----------------------------------------------------------------------------
  389. D_Func(BOOL,Get24BitBits)
  390. (
  391.         HDC                hDC,
  392.         LONG        lOrgWidth,
  393.         LONG        lOrgHeight,
  394.         void        *pBits24
  395. )
  396. {
  397.         HDC                hDIBDC=NULL;
  398.         HBITMAP        hDIBitmap=NULL;
  399.         BITMAPINFOHEADER BMIF24={0};
  400.         void        *pBits;

  401.         BMIF24.biSize=sizeof(BMIF24);
  402.         BMIF24.biWidth=lOrgWidth;
  403.         BMIF24.biHeight=lOrgHeight;
  404.         BMIF24.biPlanes=1;
  405.         BMIF24.biBitCount=24;
  406.         BMIF24.biClrImportant=BI_RGB;
  407.         BMIF24.biSizeImage=CalcSize(24,lOrgWidth,lOrgHeight);

  408.         //先创建一个HDC
  409.         hDIBDC=CreateCompatibleDC(hDC);
  410.         if(!hDIBDC)
  411.                 goto ErrorHandler;

  412.         //创建位图
  413.         hDIBitmap=CreateDIBSection(hDIBDC,(BITMAPINFO*)&BMIF24,DIB_PAL_COLORS,
  414.                 &pBits,NULL,0);
  415.         if(!hDIBitmap)
  416.                 goto ErrorHandler;

  417.         //选入位图
  418.         SelectObject(hDIBDC,hDIBitmap);

  419.         //绘制位图到我们创建的24位DIB位图缓冲区
  420.         BitBlt(hDIBDC,0,0,lOrgWidth,lOrgHeight,hDC,0,0,SRCCOPY);

  421.         //将Bits拷贝出去
  422.         memcpy(pBits24,pBits,(size_t)CalcSize(24,lOrgWidth,lOrgHeight));

  423.         //删除已经创建的缓冲区和设备上下文
  424.         DeleteObject(hDIBitmap);
  425.         DeleteDC(hDIBDC);
  426.         return TRUE;
  427. ErrorHandler:
  428.         if(hDIBitmap)
  429.                 DeleteObject(hDIBitmap);
  430.         if(hDIBDC)
  431.                 DeleteDC(hDIBDC);
  432.         return FALSE;
  433. }
  434. #else
  435. #error TODO:添加其它平台代码
  436. #endif // _WIN32

  437. //=============================================================================
  438. //函数:CalcPitch
  439. //描述:根据像素位数和图像宽度计算每行字节数(32位对齐)
  440. //-----------------------------------------------------------------------------
  441. D_Func(GLsizei,CalcPitch)
  442. (
  443.         GLsizei BitCount,
  444.         GLsizei Width
  445. )
  446. {
  447.         return _CalcPitch(BitCount,Width);
  448. }
  449. #define CalcPitch _CalcPitch

  450. //=============================================================================
  451. //函数:CalcSize
  452. //描述:根据像素位数和图像高度计算整个位图的字节数(32位对齐)
  453. //-----------------------------------------------------------------------------
  454. D_Func(GLsizei,CalcSize)
  455. (
  456.         GLsizei BitCount,
  457.         GLsizei Width,
  458.         GLsizei Height
  459. )
  460. {
  461.         return _CalcSize(BitCount,Width,Height);
  462. }
  463. #define CalcSize _CalcSize

  464. //=============================================================================
  465. //函数:ConvToP2Image
  466. //描述:将位图转换为尺寸是2的N次方的位图。返回错误代码。ppDstBits用于接收新创建
  467. //的位图。
  468. //-----------------------------------------------------------------------------
  469. static int        ConvToP2Image
  470. (
  471.         void        *pSrcBits,                //原位图指针
  472.         GLuint        uBitCount,                //原位图位数
  473.         GLsizei        BMPWidth,                //位图宽度
  474.         GLsizei        BMPHeight,                //位图高度
  475.         GLsizei        *NewWidth,                //返回的新位图宽度
  476.         GLsizei        *NewHeight,                //返回的新位图高度
  477.         void        **ppDstBits                //新位图指针
  478. )
  479. {
  480.         GLsizei        TexWidth=1,TexHeight=1;//数值扩展到2的N次方的位图的新尺寸
  481.         void        *pNewBits=NULL;
  482.         size_t        cbSrcPitch,cbDstPitch;
  483.         size_t        cbDstBits;
  484.         void        *pSrcLine;
  485.         void        *pDstLine;
  486.         GLsizei y;
  487.         int                iErrCode=DErr_Unknown;

  488.         //计算新的位图尺寸
  489.         while(TexWidth && TexWidth<BMPWidth)TexWidth<<=1;
  490.         if(!TexWidth)return DErr_BitmapTooLarge;
  491.         while(TexHeight && TexHeight<BMPHeight)TexHeight<<=1;
  492.         if(!TexHeight)return DErr_BitmapTooLarge;

  493.         //计算每行字节数
  494.         cbSrcPitch=CalcPitch(uBitCount,BMPWidth);
  495.         cbDstPitch=CalcPitch(uBitCount,TexWidth);

  496.         //给新的位图分配缓冲区
  497.         pNewBits=malloc(cbDstBits=cbDstPitch*TexHeight);
  498.         if(!pNewBits)
  499.         {
  500.                 iErrCode=DErr_NoEnoughMemory;
  501.                 goto ErrorHandler;
  502.         }
  503.         memset(pNewBits,0,cbDstBits);

  504.         //一行一行拷贝内容
  505.         pSrcLine=pSrcBits;
  506.         pDstLine=pNewBits;
  507.         for(y=0;y<BMPHeight;y++)
  508.         {
  509.                 memcpy(pDstLine,pSrcLine,cbSrcPitch);
  510.                 (uint8_t*)pSrcLine+=cbSrcPitch;
  511.                 (uint8_t*)pDstLine+=cbDstPitch;
  512.         }

  513.         *NewWidth=TexWidth;
  514.         *NewHeight=TexHeight;
  515.         *ppDstBits=pNewBits;
  516.         return DErr_OK;
  517. ErrorHandler:
  518.         free(pNewBits);
  519.         return iErrCode;
  520. }

  521. //=============================================================================
  522. //函数:GetColorIndex
  523. //描述:从调色板中找到最接近的颜色
  524. //-----------------------------------------------------------------------------
  525. static uint8_t GetColorIndex
  526. (
  527.         uint8_t R,uint8_t G,uint8_t B,        //颜色值
  528.         D_PaletteItemP        pPaletteItems,        //调色板项
  529.         GLsizei                        NbPaletteItems        //调色板项数
  530. )
  531. {
  532.         uint32_t uLastDist=255*255*3;
  533.         GLsizei i,ColorIndex;
  534.         for(i=0;i<NbPaletteItems;i++)
  535.         {
  536.                 int32_t RDiff,GDiff,BDiff;
  537.                 uint32_t uDist;
  538.                 RDiff=(int32_t)R-(int32_t)pPaletteItems[i].R;
  539.                 GDiff=(int32_t)G-(int32_t)pPaletteItems[i].G;
  540.                 BDiff=(int32_t)B-(int32_t)pPaletteItems[i].B;
  541.                 uDist=RDiff*RDiff+GDiff*GDiff+BDiff*BDiff;
  542.                 if(uDist<uLastDist)
  543.                 {
  544.                         ColorIndex=i;
  545.                         uLastDist=uDist;
  546.                 }
  547.         }
  548.         return (uint8_t)ColorIndex;
  549. }

  550. //=============================================================================
  551. //函数:DitherPixel
  552. //描述:进行单个像素的抖动运算
  553. //-----------------------------------------------------------------------------
  554. D_Func(uint8_t,DitherPixel)
  555. (
  556.         GLsizei                        x,
  557.         GLsizei                        y,
  558.         uint8_t R,uint8_t G,uint8_t B,        //颜色值
  559.         D_PaletteItemP        pPaletteItems,        //调色板项
  560.         GLsizei                        NbPaletteItems        //调色板项数
  561. )
  562. {
  563.         float fDitherVal=(float)g_DitherMatrix[x%16+(y%16)*16]/255.0f;
  564.         uint8_t uNear=GetColorIndex(R,G,B,pPaletteItems,NbPaletteItems);
  565.         float fOrgR,fOrgG,fOrgB;
  566.         float fNearR,fNearG,fNearB;
  567.         float fDistR,fDistG,fDistB;
  568.         fOrgR=(float)R/255.0f;
  569.         fOrgG=(float)G/255.0f;
  570.         fOrgB=(float)B/255.0f;
  571.         fNearR=(float)pPaletteItems[uNear].R/255.0f;
  572.         fNearG=(float)pPaletteItems[uNear].G/255.0f;
  573.         fNearB=(float)pPaletteItems[uNear].B/255.0f;
  574.         fDistR=fNearR-fOrgR;
  575.         fDistG=fNearG-fOrgG;
  576.         fDistB=fNearB-fOrgB;
  577.         fDitherVal=(fDitherVal*2-1)*(float)(sqrt(fDistR*fDistR
  578.                                                                                         +fDistG*fDistG
  579.                                                                                         +fDistB*fDistB))/1.73205080756887f;
  580.         fNearR=fOrgR+fDitherVal;if(fNearR>1)fNearR=1;if(fNearR<0)fNearR=0;
  581.         fNearG=fOrgG+fDitherVal;if(fNearG>1)fNearG=1;if(fNearG<0)fNearG=0;
  582.         fNearB=fOrgB+fDitherVal;if(fNearB>1)fNearB=1;if(fNearB<0)fNearB=0;
  583.         return GetColorIndex((uint8_t)(fNearR*255.0f),
  584.                                                  (uint8_t)(fNearG*255.0f),
  585.                                                  (uint8_t)(fNearB*255.0f),
  586.                                                  pPaletteItems,NbPaletteItems);
  587. }

  588. //=============================================================================
  589. //函数:Dither
  590. //描述:进行抖动算法
  591. //-----------------------------------------------------------------------------
  592. D_Func(int,Dither)
  593. (
  594.         D_GLContextP        pContext,                //OpenGL上下文
  595.         GLuint                        BitCount,                //位图颜色位数,必须为24或32
  596.         GLsizei                        BMPWidth,                //位图宽度
  597.         GLsizei                        BMPHeight,                //位图高度
  598.         void                        *PixelBits,                //位图
  599.         D_PaletteItemP        pPaletteItems,        //调色板项
  600.         GLsizei                        NbPaletteItems,        //调色板项数
  601.         void                        *pPixelBitsOut        //输出的位图的缓冲区(8-bit位图)
  602. )
  603. {
  604.         GLint        iUniform;//着色器参数

  605.         GLuint        uTexBits=BitCount;//新位图的位数
  606.         GLsizei        TexWidth=1,TexHeight=1;//数值扩展到2的N次方的位图的新尺寸
  607.         void        *pTexImageBits=NULL;//新位图的存储位置

  608.         uint8_t        SourceNot2P=0;//判断是否创建了新位图
  609.         int                iErrCode=DErr_Unknown;
  610.         float        fTU,fTV;
  611.        
  612.         if//检查参数的正确性
  613.         (
  614.                 (BitCount!=24 && BitCount!=32) ||
  615.                 (BMPWidth<=0 || BMPHeight<=0) ||
  616.                 (!PixelBits) ||
  617.                 (!pPaletteItems) ||
  618.                 (!NbPaletteItems)
  619.         )
  620.                 //参数错误
  621.                 return DErr_InvalidParam;

  622.         if(pContext->hRC)
  623.         {
  624.                 SetDitherGLContext(pContext);

  625. #                ifdef _WIN32
  626.                 MoveWindow(pContext->hWnd,0,0,BMPWidth,BMPHeight,FALSE);
  627. #                endif
  628.                 glViewport(0,0,BMPWidth,BMPHeight);
  629.        
  630.                 //创建一个宽高为2的N次方的新位图,鉴于显卡的兼容性
  631.                 while(TexWidth && TexWidth<BMPWidth)TexWidth<<=1;
  632.                 if(!TexWidth)return DErr_BitmapTooLarge;
  633.                 while(TexHeight && TexHeight<BMPHeight)TexHeight<<=1;
  634.                 if(!TexHeight)return DErr_BitmapTooLarge;

  635.                 //如果原始的位图并不是宽高为2的N次方的位图,则创建新的位图并拷贝内容
  636.                 if(TexWidth!=BMPWidth || TexHeight!=BMPHeight)
  637.                 {
  638.                         iErrCode=ConvToP2Image(PixelBits,BitCount,BMPWidth,BMPHeight,
  639.                                 &TexWidth,&TexHeight,&pTexImageBits);
  640.                         if(iErrCode!=DErr_OK)
  641.                                 goto ErrorHandler;
  642.                 }
  643.                 else
  644.                 {
  645.                         //如果源数据就是2的N次方尺寸的则不必重新分配内存
  646.                         uTexBits=BitCount;
  647.                         pTexImageBits=PixelBits;
  648.                 }

  649.                 //创建一个调色板位图
  650.                 glBindTexture(GL_TEXTURE_2D,pContext->uTextures[0]);
  651.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  652.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  653.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  654.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  655.                 glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,NbPaletteItems,1,0,
  656.                         GL_RGBA,GL_UNSIGNED_BYTE,pPaletteItems);       
  657.                 glBindTexture(GL_TEXTURE_2D,0);

  658.                 //原图的纹理
  659.                 glBindTexture(GL_TEXTURE_2D,pContext->uTextures[1]);
  660.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  661.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  662.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
  663.                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
  664.                 glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,TexWidth,TexHeight,0,
  665.                         uTexBits==24?GL_RGB:GL_RGBA,GL_UNSIGNED_BYTE,pTexImageBits);       
  666.                 glBindTexture(GL_TEXTURE_2D,0);
  667.        
  668.                 //清空缓冲区
  669.                 glClearColor(0,0,0,0);
  670.                 glClear(GL_COLOR_BUFFER_BIT);

  671.                 //矩阵变换
  672.                 glMatrixMode(GL_PROJECTION);
  673.                 glLoadIdentity();
  674.                 glMatrixMode(GL_MODELVIEW);
  675.                 glLoadIdentity();

  676.                 //设置着色器参数
  677.                 glUseProgram(pContext->uDitherProgram);
  678.                 iUniform=glGetUniformLocation(pContext->uDitherProgram,"TexWidth");
  679.                 glUniform1i(iUniform,TexWidth);
  680.                 iUniform=glGetUniformLocation(pContext->uDitherProgram,"TexHeight");
  681.                 glUniform1i(iUniform,TexHeight);
  682.                 iUniform=glGetUniformLocation(pContext->uDitherProgram,"BMPWidth");
  683.                 glUniform1i(iUniform,BMPWidth);
  684.                 iUniform=glGetUniformLocation(pContext->uDitherProgram,"BMPHeight");
  685.                 glUniform1i(iUniform,BMPHeight);
  686.        
  687.                 //三层纹理
  688.                 glActiveTexture(GL_TEXTURE0);
  689.                 glBindTexture(GL_TEXTURE_2D,pContext->uTextures[0]);
  690.                 glActiveTexture(GL_TEXTURE1);
  691.                 glBindTexture(GL_TEXTURE_2D,pContext->uTextures[1]);
  692.                 glActiveTexture(GL_TEXTURE2);
  693.                 glBindTexture(GL_TEXTURE_2D,pContext->uTextures[2]);
  694.        
  695.                 //计算原始位图相对于新位图的尺寸
  696.                 fTU=(float)BMPWidth/(float)TexWidth;
  697.                 fTV=(float)BMPHeight/(float)TexHeight;

  698.                 //画一个全屏BillBoard,使用着色器程序进行抖动算法处理
  699.                 glBegin(GL_TRIANGLE_STRIP);
  700.                 glTexCoord2f(0,0);                glVertex2f(-1,-1);
  701.                 glTexCoord2f(fTU,0);        glVertex2f(1,-1);
  702.                 glTexCoord2f(0,fTV);        glVertex2f(-1,1);
  703.                 glTexCoord2f(fTU,fTV);        glVertex2f(1,1);
  704.                 glEnd();
  705.                 glFlush();

  706.                 glActiveTexture(GL_TEXTURE0);
  707.                 glBindTexture(GL_TEXTURE_2D,0);
  708.                 glActiveTexture(GL_TEXTURE1);
  709.                 glBindTexture(GL_TEXTURE_2D,0);
  710.                 glActiveTexture(GL_TEXTURE2);
  711.                 glBindTexture(GL_TEXTURE_2D,0);

  712.                 //如果不提供输出数据的指针的话,直接显示到屏幕
  713.                 if(pPixelBitsOut)
  714.                         glReadPixels(0,0,BMPWidth,BMPHeight,GL_BLUE,GL_UNSIGNED_BYTE,pPixelBitsOut);
  715.         }
  716.         else//如果硬件不支持则使用软件抖动
  717.         {
  718.                 if(BitCount==24)
  719.                 {
  720.                         D_RGB24P        pInLinePtr;//输入位图的行指针
  721.                         uint8_t                *pOutLinePtr;//输出位图的行指针
  722.                         size_t                cbInPitch,cbOutPitch;//每行字节数
  723.                         GLsizei                x,y;

  724.                         pInLinePtr=(D_RGB24P)PixelBits;
  725.                         pOutLinePtr=(uint8_t*)pPixelBitsOut;
  726.                         cbInPitch=CalcPitch(BitCount,BMPWidth);
  727.                         cbOutPitch=CalcPitch(8,BMPWidth);

  728.                         for(y=0;y<BMPHeight;y++)
  729.                         {
  730.                                 //处理当前行
  731.                                 D_RGB24P pInPtr=pInLinePtr;
  732.                                 uint8_t*pOutPtr=pOutLinePtr;
  733.                                 for(x=0;x<BMPWidth;x++)
  734.                                 {
  735.                                         *pOutPtr++=DitherPixel(x,y,pInPtr->R,pInPtr->G,pInPtr->B,
  736.                                                 pPaletteItems,NbPaletteItems);
  737.                                         pInPtr++;
  738.                                 }
  739.                                 //移至下一行
  740.                                 (uint8_t*)pInLinePtr+=cbInPitch;
  741.                                 (uint8_t*)pOutLinePtr+=cbOutPitch;
  742.                         }
  743.                 }
  744.                 else if(BitCount==32)
  745.                 {
  746.                         D_RGB32P        pInLinePtr;//输入位图的行指针
  747.                         uint8_t                *pOutLinePtr;//输出位图的行指针
  748.                         size_t                cbInPitch,cbOutPitch;//每行字节数
  749.                         GLsizei                x,y;

  750.                         pInLinePtr=(D_RGB32P)PixelBits;
  751.                         pOutLinePtr=(uint8_t*)pPixelBitsOut;
  752.                         cbInPitch=CalcPitch(BitCount,BMPWidth);
  753.                         cbOutPitch=CalcPitch(8,BMPWidth);

  754.                         for(y=0;y<BMPHeight;y++)
  755.                         {
  756.                                 //处理当前行
  757.                                 D_RGB32P pInPtr=pInLinePtr;
  758.                                 uint8_t*pOutPtr=pOutLinePtr;
  759.                                 for(x=0;x<BMPWidth;x++)
  760.                                 {
  761.                                         *pOutPtr++=DitherPixel(x,y,pInPtr->R,pInPtr->G,pInPtr->B,
  762.                                                 pPaletteItems,NbPaletteItems);
  763.                                         pInPtr++;
  764.                                 }
  765.                                 //移至下一行
  766.                                 (uint8_t*)pInLinePtr+=cbInPitch;
  767.                                 (uint8_t*)pOutLinePtr+=cbOutPitch;
  768.                         }
  769.                 }
  770.         }

  771.         if(SourceNot2P)
  772.                 free(pTexImageBits);
  773.         return DErr_OK;
  774. ErrorHandler:
  775.         if(SourceNot2P)
  776.                 free(pTexImageBits);
  777.         return iErrCode;
  778. }
复制代码
Fragment Shader着色器代码:
  1. varying vec2 vTexCoord;//纹理坐标
  2. varying vec2 vDitherCoord;//抖动矩阵的纹理坐标

  3. uniform sampler2D Pal;//调色板采样器
  4. uniform sampler2D Tex;//纹理采样器
  5. uniform sampler2D DitherMat;//抖动矩阵

  6. #define InitDistSq 999.0
  7. #define        MaxDist 0.25
  8. #define        MaxDistSq (MaxDist*MaxDist)

  9. void main()
  10. {
  11.         int i,iNearestColor=0;
  12.         vec4 vOrgColor;//原颜色
  13.         vec3 vCurPos;//当前位置
  14.         vec3 vCurVec;//当前向量
  15.         float fDitherVal;//抖动亮度值
  16.         float fLastDistSq;

  17.         //初始值
  18.         gl_FragColor=texture2D(Pal,vec2(0,0));
  19.         vCurPos=gl_FragColor.xyz;
  20.         vCurVec=vCurPos-vOrgColor.rgb;
  21.        
  22.         //原始颜色
  23.         vOrgColor=texture2D(Tex,vTexCoord);

  24.         //找出最接近的颜色
  25.         fLastDistSq=InitDistSq;
  26.         for(i=0;i<256;i++)
  27.         {
  28.                 vec4 vPalColor=texture2D(Pal,vec2(float(i)/256.0,0));
  29.                 vec3 vDiff=vPalColor.rgb-vOrgColor.rgb;
  30.                 float fDistanceSq=dot(vDiff,vDiff);
  31.                 if(fDistanceSq<fLastDistSq)
  32.                 {
  33.                         fLastDistSq=fDistanceSq;
  34.                         gl_FragColor=vPalColor;
  35.                         iNearestColor=i;
  36.                 }
  37.         }

  38.         //抖动亮度值
  39.         fDitherVal=(texture2D(DitherMat,vDitherCoord).b*2.0-1.0)*sqrt(fLastDistSq)/1.7320508075688772935274463415059;
  40.        
  41.         //抖动原始颜色
  42.         vOrgColor+=vec4(fDitherVal,fDitherVal,fDitherVal,0);
  43.        
  44.         //找出抖动后的最接近颜色
  45.         fLastDistSq=InitDistSq;
  46.         for(i=0;i<256;i++)
  47.         {
  48.                 vec4 vPalColor=texture2D(Pal,vec2(float(i)/256.0,0));
  49.                 vec3 vDiff=vPalColor.rgb-vOrgColor.rgb;
  50.                 float fDistanceSq=dot(vDiff,vDiff);
  51.                 if(fDistanceSq<fLastDistSq)
  52.                 {
  53.                         fLastDistSq=fDistanceSq;
  54.                         gl_FragColor=vPalColor;
  55.                         iNearestColor=i;
  56.                 }
  57.         }
  58.        
  59.         //输出颜色表索引
  60.         gl_FragColor=vec4(vec3(iNearestColor,iNearestColor,iNearestColor)/255.0,1);
  61. }
复制代码
BIN: Dither_Bin.7z (78.65 KB, 下载次数: 12)
SRC: Dither_Src.7z (537.21 KB, 下载次数: 23)

本帖被以下淘专辑推荐:

回复

使用道具 举报

307

主题

228

回帖

7335

积分

用户组: 真·技术宅

UID
2
精华
76
威望
291 点
宅币
5585 个
贡献
253 次
宅之契约
0 份
在线时间
947 小时
注册时间
2014-1-25
发表于 2015-3-9 21:56:43 | 显示全部楼层
哇,代码快上千了
回复 赞! 靠!

使用道具 举报

4

主题

14

回帖

100

积分

用户组: 小·技术宅

UID
565
精华
1
威望
3 点
宅币
71 个
贡献
0 次
宅之契约
0 份
在线时间
6 小时
注册时间
2014-11-24
发表于 2015-3-25 17:02:43 | 显示全部楼层
牛的一逼
回复

使用道具 举报

1

主题

60

回帖

201

积分

用户组: 中·技术宅

UID
4683
精华
0
威望
0 点
宅币
140 个
贡献
0 次
宅之契约
0 份
在线时间
31 小时
注册时间
2019-2-11
发表于 2019-5-10 20:42:50 | 显示全部楼层
代码有点长,我先收下,慢慢看。
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-19 12:32 , Processed in 0.049098 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表