cocos2dx 高性能高斯模糊(包含lua接口)

前端之家收集整理的这篇文章主要介绍了cocos2dx 高性能高斯模糊(包含lua接口)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

根据官方的帖子实现的高斯模糊当前屏幕内容 点击打开链接


1.截屏缩小压缩,减小像素采样的优化算法。默认截屏后缩小到原来的1/4。

2.C++代码进行一次性高斯模糊。避免使用shader造成的渲染掉帧


以下是C++部分代码

  1. /*
  2. * 高斯模糊接口 缩放因子:iScale,截图会把全屏压缩为1/iScale大
  3. */
  4. static void gaussianBlur(const std::function<void(bool,cocos2d::Image*)>& afterCaptured,int iScale = 4);

  1. // The Stack Blur Algorithm was invented by Mario Klingemann,// mario@quasimondo.com and described here:
  2. // http://incubator.quasimondo.com/processing/fast_blur_deluxe.PHP
  3.  
  4. // This is C++ RGBA (32 bit color) multi-threaded version
  5. // by Victor Laskin (victor.laskin@gmail.com)
  6. // More details: http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp
  7.  
  8. // This code is using MVThread class from my cross-platform framework
  9. // You can exchange it with any thread implementation you like
  10. // -------------------------------------- stackblur ----------------------------------------->
  11.  
  12. static unsigned short const stackblur_mul[255] =
  13. {
  14. 512,512,456,328,335,405,271,388,292,454,364,298,496,420,360,312,273,482,428,383,345,284,259,475,437,404,374,347,323,302,282,265,497,468,441,417,394,373,354,337,320,305,291,278,507,485,465,446,412,396,381,367,341,329,318,307,297,287,269,261,505,489,461,447,435,422,411,399,389,378,368,359,350,332,324,316,309,301,294,281,274,268,262,257,501,491,480,470,460,451,442,433,424,416,408,400,392,385,377,370,363,357,344,338,326,315,310,304,299,289,285,280,275,267,263,259
  15. };
  16.  
  17. static unsigned char const stackblur_shr[255] =
  18. {
  19. 9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24
  20. };
  21.  
  22. /// Stackblur algorithm body
  23. void stackblurJob(unsigned char* src,///< input image data
  24. unsigned int w,///< image width
  25. unsigned int h,///< image height
  26. unsigned int radius,///< blur intensity (should be in 2..254 range)
  27. int cores,///< total number of working threads
  28. int core,///< current thread number
  29. int step,///< step of processing (1,2)
  30. unsigned char* stack ///< stack buffer
  31. )
  32. {
  33. unsigned int x,y,xp,yp,i;
  34. unsigned int sp;
  35. unsigned int stack_start;
  36. unsigned char* stack_ptr;
  37.  
  38. unsigned char* src_ptr;
  39. unsigned char* dst_ptr;
  40.  
  41. unsigned long sum_r;
  42. unsigned long sum_g;
  43. unsigned long sum_b;
  44. unsigned long sum_a;
  45. unsigned long sum_in_r;
  46. unsigned long sum_in_g;
  47. unsigned long sum_in_b;
  48. unsigned long sum_in_a;
  49. unsigned long sum_out_r;
  50. unsigned long sum_out_g;
  51. unsigned long sum_out_b;
  52. unsigned long sum_out_a;
  53.  
  54. unsigned int wm = w - 1;
  55. unsigned int hm = h - 1;
  56. unsigned int w4 = w * 4;
  57. unsigned int div = (radius * 2) + 1;
  58. unsigned int mul_sum = stackblur_mul[radius];
  59. unsigned char shr_sum = stackblur_shr[radius];
  60.  
  61.  
  62. if (step == 1)
  63. {
  64. int minY = core * h / cores;
  65. int maxY = (core + 1) * h / cores;
  66.  
  67. for (y = minY; y < maxY; y++)
  68. {
  69. sum_r = sum_g = sum_b = sum_a =
  70. sum_in_r = sum_in_g = sum_in_b = sum_in_a =
  71. sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0;
  72.  
  73. src_ptr = src + w4 * y; // start of line (0,y)
  74.  
  75. for (i = 0; i <= radius; i++)
  76. {
  77. stack_ptr = &stack[4 * i];
  78. stack_ptr[0] = src_ptr[0];
  79. stack_ptr[1] = src_ptr[1];
  80. stack_ptr[2] = src_ptr[2];
  81. stack_ptr[3] = src_ptr[3];
  82. sum_r += src_ptr[0] * (i + 1);
  83. sum_g += src_ptr[1] * (i + 1);
  84. sum_b += src_ptr[2] * (i + 1);
  85. sum_a += src_ptr[3] * (i + 1);
  86. sum_out_r += src_ptr[0];
  87. sum_out_g += src_ptr[1];
  88. sum_out_b += src_ptr[2];
  89. sum_out_a += src_ptr[3];
  90. }
  91.  
  92.  
  93. for (i = 1; i <= radius; i++)
  94. {
  95. if (i <= wm) src_ptr += 4;
  96. stack_ptr = &stack[4 * (i + radius)];
  97. stack_ptr[0] = src_ptr[0];
  98. stack_ptr[1] = src_ptr[1];
  99. stack_ptr[2] = src_ptr[2];
  100. stack_ptr[3] = src_ptr[3];
  101. sum_r += src_ptr[0] * (radius + 1 - i);
  102. sum_g += src_ptr[1] * (radius + 1 - i);
  103. sum_b += src_ptr[2] * (radius + 1 - i);
  104. sum_a += src_ptr[3] * (radius + 1 - i);
  105. sum_in_r += src_ptr[0];
  106. sum_in_g += src_ptr[1];
  107. sum_in_b += src_ptr[2];
  108. sum_in_a += src_ptr[3];
  109. }
  110.  
  111.  
  112. sp = radius;
  113. xp = radius;
  114. if (xp > wm) xp = wm;
  115. src_ptr = src + 4 * (xp + y * w); // img.pix_ptr(xp,y);
  116. dst_ptr = src + y * w4; // img.pix_ptr(0,y);
  117. for (x = 0; x < w; x++)
  118. {
  119. dst_ptr[0] = (sum_r * mul_sum) >> shr_sum;
  120. dst_ptr[1] = (sum_g * mul_sum) >> shr_sum;
  121. dst_ptr[2] = (sum_b * mul_sum) >> shr_sum;
  122. dst_ptr[3] = (sum_a * mul_sum) >> shr_sum;
  123. dst_ptr += 4;
  124.  
  125. sum_r -= sum_out_r;
  126. sum_g -= sum_out_g;
  127. sum_b -= sum_out_b;
  128. sum_a -= sum_out_a;
  129.  
  130. stack_start = sp + div - radius;
  131. if (stack_start >= div) stack_start -= div;
  132. stack_ptr = &stack[4 * stack_start];
  133.  
  134. sum_out_r -= stack_ptr[0];
  135. sum_out_g -= stack_ptr[1];
  136. sum_out_b -= stack_ptr[2];
  137. sum_out_a -= stack_ptr[3];
  138.  
  139. if (xp < wm)
  140. {
  141. src_ptr += 4;
  142. ++xp;
  143. }
  144.  
  145. stack_ptr[0] = src_ptr[0];
  146. stack_ptr[1] = src_ptr[1];
  147. stack_ptr[2] = src_ptr[2];
  148. stack_ptr[3] = src_ptr[3];
  149.  
  150. sum_in_r += src_ptr[0];
  151. sum_in_g += src_ptr[1];
  152. sum_in_b += src_ptr[2];
  153. sum_in_a += src_ptr[3];
  154. sum_r += sum_in_r;
  155. sum_g += sum_in_g;
  156. sum_b += sum_in_b;
  157. sum_a += sum_in_a;
  158.  
  159. ++sp;
  160. if (sp >= div) sp = 0;
  161. stack_ptr = &stack[sp * 4];
  162.  
  163. sum_out_r += stack_ptr[0];
  164. sum_out_g += stack_ptr[1];
  165. sum_out_b += stack_ptr[2];
  166. sum_out_a += stack_ptr[3];
  167. sum_in_r -= stack_ptr[0];
  168. sum_in_g -= stack_ptr[1];
  169. sum_in_b -= stack_ptr[2];
  170. sum_in_a -= stack_ptr[3];
  171.  
  172.  
  173. }
  174.  
  175. }
  176. }
  177.  
  178. // step 2
  179. if (step == 2)
  180. {
  181. int minX = core * w / cores;
  182. int maxX = (core + 1) * w / cores;
  183.  
  184. for (x = minX; x < maxX; x++)
  185. {
  186. sum_r = sum_g = sum_b = sum_a =
  187. sum_in_r = sum_in_g = sum_in_b = sum_in_a =
  188. sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0;
  189.  
  190. src_ptr = src + 4 * x; // x,0
  191. for (i = 0; i <= radius; i++)
  192. {
  193. stack_ptr = &stack[i * 4];
  194. stack_ptr[0] = src_ptr[0];
  195. stack_ptr[1] = src_ptr[1];
  196. stack_ptr[2] = src_ptr[2];
  197. stack_ptr[3] = src_ptr[3];
  198. sum_r += src_ptr[0] * (i + 1);
  199. sum_g += src_ptr[1] * (i + 1);
  200. sum_b += src_ptr[2] * (i + 1);
  201. sum_a += src_ptr[3] * (i + 1);
  202. sum_out_r += src_ptr[0];
  203. sum_out_g += src_ptr[1];
  204. sum_out_b += src_ptr[2];
  205. sum_out_a += src_ptr[3];
  206. }
  207. for (i = 1; i <= radius; i++)
  208. {
  209. if (i <= hm) src_ptr += w4; // +stride
  210.  
  211. stack_ptr = &stack[4 * (i + radius)];
  212. stack_ptr[0] = src_ptr[0];
  213. stack_ptr[1] = src_ptr[1];
  214. stack_ptr[2] = src_ptr[2];
  215. stack_ptr[3] = src_ptr[3];
  216. sum_r += src_ptr[0] * (radius + 1 - i);
  217. sum_g += src_ptr[1] * (radius + 1 - i);
  218. sum_b += src_ptr[2] * (radius + 1 - i);
  219. sum_a += src_ptr[3] * (radius + 1 - i);
  220. sum_in_r += src_ptr[0];
  221. sum_in_g += src_ptr[1];
  222. sum_in_b += src_ptr[2];
  223. sum_in_a += src_ptr[3];
  224. }
  225.  
  226. sp = radius;
  227. yp = radius;
  228. if (yp > hm) yp = hm;
  229. src_ptr = src + 4 * (x + yp * w); // img.pix_ptr(x,yp);
  230. dst_ptr = src + 4 * x; // img.pix_ptr(x,0);
  231. for (y = 0; y < h; y++)
  232. {
  233. dst_ptr[0] = (sum_r * mul_sum) >> shr_sum;
  234. dst_ptr[1] = (sum_g * mul_sum) >> shr_sum;
  235. dst_ptr[2] = (sum_b * mul_sum) >> shr_sum;
  236. dst_ptr[3] = (sum_a * mul_sum) >> shr_sum;
  237. dst_ptr += w4;
  238.  
  239. sum_r -= sum_out_r;
  240. sum_g -= sum_out_g;
  241. sum_b -= sum_out_b;
  242. sum_a -= sum_out_a;
  243.  
  244. stack_start = sp + div - radius;
  245. if (stack_start >= div) stack_start -= div;
  246. stack_ptr = &stack[4 * stack_start];
  247.  
  248. sum_out_r -= stack_ptr[0];
  249. sum_out_g -= stack_ptr[1];
  250. sum_out_b -= stack_ptr[2];
  251. sum_out_a -= stack_ptr[3];
  252.  
  253. if (yp < hm)
  254. {
  255. src_ptr += w4; // stride
  256. ++yp;
  257. }
  258.  
  259. stack_ptr[0] = src_ptr[0];
  260. stack_ptr[1] = src_ptr[1];
  261. stack_ptr[2] = src_ptr[2];
  262. stack_ptr[3] = src_ptr[3];
  263.  
  264. sum_in_r += src_ptr[0];
  265. sum_in_g += src_ptr[1];
  266. sum_in_b += src_ptr[2];
  267. sum_in_a += src_ptr[3];
  268. sum_r += sum_in_r;
  269. sum_g += sum_in_g;
  270. sum_b += sum_in_b;
  271. sum_a += sum_in_a;
  272.  
  273. ++sp;
  274. if (sp >= div) sp = 0;
  275. stack_ptr = &stack[sp * 4];
  276.  
  277. sum_out_r += stack_ptr[0];
  278. sum_out_g += stack_ptr[1];
  279. sum_out_b += stack_ptr[2];
  280. sum_out_a += stack_ptr[3];
  281. sum_in_r -= stack_ptr[0];
  282. sum_in_g -= stack_ptr[1];
  283. sum_in_b -= stack_ptr[2];
  284. sum_in_a -= stack_ptr[3];
  285. }
  286. }
  287. }
  288.  
  289. }
  290.  
  291.  
  292. class MVImageUtilsStackBlurTask
  293. {
  294. public:
  295. unsigned char* src;
  296. unsigned int w;
  297. unsigned int h;
  298. unsigned int radius;
  299. int cores;
  300. int core;
  301. int step;
  302. unsigned char* stack;
  303.  
  304. inline MVImageUtilsStackBlurTask(unsigned char* src,unsigned int w,unsigned int h,unsigned int radius,int cores,int core,int step,unsigned char* stack)
  305. {
  306. this->src = src;
  307. this->w = w;
  308. this->h = h;
  309. this->radius = radius;
  310. this->cores = cores;
  311. this->core = core;
  312. this->step = step;
  313. this->stack = stack;
  314. }
  315.  
  316. inline void run()
  317. {
  318. stackblurJob(src,w,h,radius,cores,core,step,stack);
  319. }
  320.  
  321. };
  322.  
  323.  
  324. /// Stackblur algorithm by Mario Klingemann
  325. /// Details here:
  326. /// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
  327. /// C++ implemenation base from:
  328. /// https://gist.github.com/benjamin9999/3809142
  329. /// http://www.antigrain.com/__code/include/agg_blur.h.html
  330. /// This version works only with RGBA color
  331. void stackblur(unsigned char* src,///< blur intensity (should be in 2..254 range)
  332. int cores = 1 ///< number of threads (1 - normal single thread)
  333. )
  334. {
  335. if (radius > 254) return;
  336. if (radius < 2) return;
  337.  
  338. unsigned int div = (radius * 2) + 1;
  339. unsigned char* stack = new unsigned char[div * 4 * cores];
  340.  
  341. if (cores == 1)
  342. {
  343. // no multithreading
  344. stackblurJob(src,1,stack);
  345. stackblurJob(src,2,stack);
  346. }
  347.  
  348.  
  349. delete[] stack;
  350. }
  351.  
  352.  
  353. /**
  354. * Capture screen implementation,don't use it directly.
  355. */
  356. void onCaptureScreen(const std::function<void(bool,Image*)>& afterCaptured,int iScale)
  357. {
  358. static bool startedCapture = false;
  359.  
  360. if (startedCapture)
  361. {
  362. CCLOG("Screen capture is already working");
  363. if (afterCaptured)
  364. {
  365. afterCaptured(false,nullptr);
  366. }
  367. return;
  368. }
  369. else
  370. {
  371. startedCapture = true;
  372. }
  373.  
  374.  
  375. auto glView = Director::getInstance()->getOpenGLView();
  376. auto frameSize = glView->getFrameSize();
  377. #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
  378. frameSize = frameSize * glView->getFrameZoomFactor() * glView->getRetinaFactor();
  379. #endif
  380.  
  381. int width = static_cast<int>(frameSize.width);
  382. int height = static_cast<int>(frameSize.height);
  383.  
  384. do
  385. {
  386. std::shared_ptr<GLubyte> buffer(new GLubyte[width * height * 4],[](GLubyte* p){ CC_SAFE_DELETE_ARRAY(p); });
  387. if (!buffer)
  388. {
  389. break;
  390. }
  391.  
  392. glPixelStorei(GL_PACK_ALIGNMENT,1);
  393. glReadPixels(0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,buffer.get());
  394.  
  395. std::shared_ptr<GLubyte> flippedBuffer(new GLubyte[width * height * 4],[](GLubyte* p) { CC_SAFE_DELETE_ARRAY(p); });
  396. if (!flippedBuffer)
  397. {
  398. break;
  399. }
  400.  
  401. for (int row = 0; row < height; ++row)
  402. {
  403. memcpy(flippedBuffer.get() + (height - row - 1) * width * 4,buffer.get() + row * width * 4,width * 4);
  404. }
  405.  
  406. /*-------------压缩start------------*/
  407. unsigned long dst_width = width / iScale;
  408. unsigned long dst_height = height / iScale;
  409.  
  410. std::shared_ptr<GLubyte> zipFlippedBuffer(new GLubyte[dst_width * dst_height * 4],[](GLubyte* p) { CC_SAFE_DELETE_ARRAY(p); });
  411. if (!zipFlippedBuffer)
  412. {
  413. break;
  414. }
  415. unsigned long xrIntFloat_16 = (width << 16) / dst_width + 1;
  416. unsigned long yrIntFloat_16 = (height << 16) / dst_height + 1;
  417. unsigned long srcy_16 = 0;
  418.  
  419. unsigned long byte_width = 4;//单个数据的物理宽度 4字节
  420. unsigned long byte_shift = 2;//单个数据的物理移位
  421.  
  422. auto beginPos = zipFlippedBuffer.get();
  423.  
  424. for (unsigned long y = 0; y < dst_height; ++y)
  425. {
  426. //auto pSrcLine = flippedBuffer.get() + width * byte_width * (srcy_16 >> 16);
  427. auto pSrcLine = flippedBuffer.get() + (width<<2)*(srcy_16>>16);
  428.  
  429. unsigned long srcx_16 = 0;
  430. for (unsigned long x = 0; x < dst_width; ++x)
  431. {
  432. //memcpy(beginPos + x * byte_width,pSrcLine + (srcx_16 >> 16)*byte_width,byte_width);
  433. memcpy(beginPos + (x<<2),pSrcLine + ((srcx_16 >> 16)<<2),byte_width);
  434. srcx_16 += xrIntFloat_16;
  435. }
  436. srcy_16 += yrIntFloat_16;
  437. beginPos += (dst_width << byte_shift);
  438. }
  439. /*-------------压缩end------------*/
  440.  
  441. //使用算法一次性对图片进行高斯模糊
  442. stackblur(zipFlippedBuffer.get(),dst_width,dst_height,5);
  443.  
  444. Image* image = new (std::nothrow) Image;
  445. if (image)
  446. {
  447. image->initWithRawData(zipFlippedBuffer.get(),dst_width * dst_height * 4,8);
  448. image->autorelease();
  449. if (afterCaptured)
  450. {
  451. afterCaptured(true,image);
  452. }
  453. }
  454. else
  455. {
  456. CCLOG("Malloc Image memory Failed!");
  457. if (afterCaptured)
  458. {
  459. afterCaptured(false,nullptr);
  460. }
  461. delete image;
  462. image = nullptr;
  463. }
  464. startedCapture = false;
  465. } while (0);
  466. }
  467.  
  468.  
  469. /*
  470. * 高斯模糊接口 缩放因子:iScale,截图会把全屏压缩为1/iScale大
  471. */
  472. static EventListenerCustom* s_captureScreenListener;
  473. static CustomCommand s_captureScreenCommand;
  474. void Util::gaussianBlur(const std::function<void(bool,int iScale /*= 4*/)
  475. {
  476. if (s_captureScreenListener)
  477. {
  478. CCLOG("Warning: CaptureScreen has been called already,don't call more than once in one frame.");
  479. return;
  480. }
  481. s_captureScreenCommand.init(std::numeric_limits<float>::max());
  482. s_captureScreenCommand.func = std::bind(onCaptureScreen,afterCaptured,iScale);
  483. s_captureScreenListener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(Director::EVENT_AFTER_DRAW,[](EventCustom *event) {
  484. auto director = Director::getInstance();
  485. director->getEventDispatcher()->removeEventListener((EventListener*)(s_captureScreenListener));
  486. s_captureScreenListener = nullptr;
  487. director->getRenderer()->addCommand(&s_captureScreenCommand);
  488. director->getRenderer()->render();
  489. });
  490. }


以下是导出的lua接口:

  1. #include "base/ccConfig.h"
  2. #ifndef __game_custom_h__
  3. #define __game_custom_h__
  4.  
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. #include "tolua++.h"
  9. #ifdef __cplusplus
  10. }
  11. #endif
  12.  
  13. int register_all_game_custom(lua_State* tolua_S);
  14.  
  15. #endif // __game_custom_h__

  1. static int tolua_pf_common_gaussianBlur(lua_State* tolua_S)
  2. {
  3. LUA_FUNCTION callbackHander = toluafix_ref_function(tolua_S,0);
  4. if (callbackHander == 0)
  5. {
  6. CCLOG("tolua_pf_common_gaussianBlur : toluafix_ref_function,error");
  7. return 0;
  8. }
  9.  
  10. auto capture_callback = [=](bool succeed,Image* img){
  11. auto luastack = LuaEngine::getInstance()->getLuaStack();
  12.  
  13. luastack->pushBoolean(succeed);
  14. if (succeed){
  15. luastack->pushObject(img,"cc.Image");
  16. }
  17. else{
  18. luastack->pushNil();
  19. }
  20. luastack->executeFunctionByHandler(callbackHander,2);
  21. };
  22.  
  23.  
  24. int argc = lua_gettop(tolua_S) - 1;
  25. if (argc == 2)
  26. {
  27. int q = 4;
  28. if (!luaval_to_int32(tolua_S,3,&q))
  29. {
  30. CCLOG("tolua_pf_common_gaussianBlur : luaval_to_number,error");
  31. return 0;
  32. }
  33. Util::gaussianBlur(capture_callback,q);
  34. }
  35. else
  36. {
  37. Util::gaussianBlur(capture_callback);
  38. }
  39. return 0;
  40. }
  41.  
  42. TOLUA_API int register_all_game_custom(lua_State* tolua_S)
  43. {
  44. tolua_open(tolua_S);
  45.  
  46. tolua_module(tolua_S,"pf",0);
  47. tolua_beginmodule(tolua_S,"pf");
  48.  
  49. tolua_module(tolua_S,"Common",0);
  50. tolua_beginmodule(tolua_S,"Common");
  51. {
  52. tolua_function(tolua_S,"GaussianBlur",tolua_pf_common_gaussianBlur);
  53. }
  54. tolua_endmodule(tolua_S);
  55.  
  56. tolua_endmodule(tolua_S);
  57. return 1;
  58. }


使用方法:

  1. local function onFinishCapture(ret,img)
  2. if ret then
  3. local texture = cc.Director:getInstance():getTextureCache():addImage(img,"capriteadu")
  4. local spriteBlur = cc.Sprite:createWithTexture(texture)
  5. local wSize = cc.Director:getInstance():getWinSize()
  6. spriteBlur:setPosition(cc.p(wSize.width/2,wSize.height/2))
  7. self:addChild(spriteBlur)
  8. PF.UIEx.nodeToScaleForFixedSize(spriteBlur,wSize)
  9. end
  10. end
  11. pf.Common:GaussianBlur(onFinishCapture,4)

猜你在找的Cocos2d-x相关文章