Rasterizer.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:22k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "stdafx.h"
  22. #include <string.h>
  23. #include <math.h>
  24. #include <vector>
  25. #include <algorithm>
  26. #include "Rasterizer.h"
  27. Rasterizer::Rasterizer() : mpPathTypes(NULL), mpPathPoints(NULL), mPathPoints(0), mpOverlayBuffer(NULL)
  28. {
  29. mOverlayWidth = mOverlayHeight = 0;
  30. mPathOffsetX = mPathOffsetY = 0;
  31. mOffsetX = mOffsetY = 0;
  32. }
  33. Rasterizer::~Rasterizer()
  34. {
  35. _TrashPath();
  36. _TrashOverlay();
  37. }
  38. void Rasterizer::_TrashPath()
  39. {
  40. delete [] mpPathTypes;
  41. delete [] mpPathPoints;
  42. mpPathTypes = NULL;
  43. mpPathPoints = NULL;
  44. mPathPoints = 0;
  45. }
  46. void Rasterizer::_TrashOverlay()
  47. {
  48. delete [] mpOverlayBuffer;
  49. mpOverlayBuffer = NULL;
  50. }
  51. void Rasterizer::_ReallocEdgeBuffer(int edges)
  52. {
  53. mEdgeHeapSize = edges;
  54. mpEdgeBuffer = (Edge*)realloc(mpEdgeBuffer, sizeof(Edge)*edges);
  55. }
  56. void Rasterizer::_EvaluateBezier(int ptbase, bool fBSpline)
  57. {
  58. const POINT* pt0 = mpPathPoints + ptbase;
  59. const POINT* pt1 = mpPathPoints + ptbase + 1;
  60. const POINT* pt2 = mpPathPoints + ptbase + 2;
  61. const POINT* pt3 = mpPathPoints + ptbase + 3;
  62. double x0 = pt0->x;
  63. double x1 = pt1->x;
  64. double x2 = pt2->x;
  65. double x3 = pt3->x;
  66. double y0 = pt0->y;
  67. double y1 = pt1->y;
  68. double y2 = pt2->y;
  69. double y3 = pt3->y;
  70. double cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
  71. if(fBSpline)
  72. {
  73. // 1   [-1 +3 -3 +1]
  74. // - * [+3 -6 +3  0]
  75. // 6   [-3  0 +3  0]
  76. //    [+1 +4 +1  0]
  77. double _1div6 = 1.0/6.0;
  78. cx3 = _1div6*(-  x0+3*x1-3*x2+x3);
  79. cx2 = _1div6*( 3*x0-6*x1+3*x2);
  80. cx1 = _1div6*(-3*x0    +3*x2);
  81. cx0 = _1div6*(   x0+4*x1+1*x2);
  82. cy3 = _1div6*(-  y0+3*y1-3*y2+y3);
  83. cy2 = _1div6*( 3*y0-6*y1+3*y2);
  84. cy1 = _1div6*(-3*y0     +3*y2);
  85. cy0 = _1div6*(   y0+4*y1+1*y2);
  86. }
  87. else // bezier
  88. {
  89. // [-1 +3 -3 +1]
  90. // [+3 -6 +3  0]
  91. // [-3 +3  0  0]
  92. // [+1  0  0  0]
  93. cx3 = -  x0+3*x1-3*x2+x3;
  94. cx2 =  3*x0-6*x1+3*x2;
  95. cx1 = -3*x0+3*x1;
  96. cx0 =    x0;
  97. cy3 = -  y0+3*y1-3*y2+y3;
  98. cy2 =  3*y0-6*y1+3*y2;
  99. cy1 = -3*y0+3*y1;
  100. cy0 =    y0;
  101. }
  102. //
  103. // This equation is from Graphics Gems I.
  104. //
  105. // The idea is that since we're approximating a cubic curve with lines,
  106. // any error we incur is due to the curvature of the line, which we can
  107. // estimate by calculating the maximum acceleration of the curve.  For
  108. // a cubic, the acceleration (second derivative) is a line, meaning that
  109. // the absolute maximum acceleration must occur at either the beginning
  110. // (|c2|) or the end (|c2+c3|).  Our bounds here are a little more
  111. // conservative than that, but that's okay.
  112. //
  113. // If the acceleration of the parametric formula is zero (c2 = c3 = 0),
  114. // that component of the curve is linear and does not incur any error.
  115. // If a=0 for both X and Y, the curve is a line segment and we can
  116. // use a step size of 1.
  117. double maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
  118. double maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
  119. double maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
  120. double h = 1.0;
  121. if(maxaccel > 8.0) h = sqrt(8.0 / maxaccel);
  122. if(!fFirstSet) {firstp.x = (LONG)cx0; firstp.y = (LONG)cy0; lastp = firstp; fFirstSet = true;}
  123. for(double t = 0; t < 1.0; t += h)
  124. {
  125. double x = cx0 + t*(cx1 + t*(cx2 + t*cx3));
  126. double y = cy0 + t*(cy1 + t*(cy2 + t*cy3));
  127. _EvaluateLine(lastp.x, lastp.y, (int)x, (int)y);
  128. }
  129. double x = cx0 + cx1 + cx2 + cx3;
  130. double y = cy0 + cy1 + cy2 + cy3;
  131. _EvaluateLine(lastp.x, lastp.y, (int)x, (int)y);
  132. }
  133. void Rasterizer::_EvaluateLine(int pt1idx, int pt2idx)
  134. {
  135. const POINT* pt1 = mpPathPoints + pt1idx;
  136. const POINT* pt2 = mpPathPoints + pt2idx;
  137. _EvaluateLine(pt1->x, pt1->y, pt2->x, pt2->y);
  138. }
  139. void Rasterizer::_EvaluateLine(int x0, int y0, int x1, int y1)
  140. {
  141. if(lastp.x != x0 || lastp.y != y0)
  142. {
  143. _EvaluateLine(lastp.x, lastp.y, x0, y0);
  144. }
  145. if(!fFirstSet) {firstp.x = x0; firstp.y = y0; fFirstSet = true;}
  146. lastp.x = x1; lastp.y = y1;
  147. if(y1 > y0) // down
  148. {
  149. __int64 xacc = (__int64)x0 << 13;
  150. // prestep y0 down
  151. int dy = y1 - y0;
  152. int y = ((y0 + 3)&~7) + 4;
  153. int iy = y >> 3;
  154. y1 = (y1 - 5) >> 3;
  155. if(iy <= y1)
  156. {
  157. __int64 invslope = (__int64(x1 - x0) << 16) / dy;
  158. while(mEdgeNext + y1 + 1 - iy > mEdgeHeapSize)
  159. _ReallocEdgeBuffer(mEdgeHeapSize*2);
  160. xacc += (invslope * (y - y0)) >> 3;
  161. while(iy <= y1)
  162. {
  163. int ix = (int)((xacc + 32768) >> 16);
  164. mpEdgeBuffer[mEdgeNext].next = mpScanBuffer[iy];
  165. mpEdgeBuffer[mEdgeNext].posandflag = ix*2 + 1;
  166. mpScanBuffer[iy] = mEdgeNext++;
  167. ++iy;
  168. xacc += invslope;
  169. }
  170. }
  171. }
  172. else if(y1 < y0) // up
  173. {
  174. __int64 xacc = (__int64)x1 << 13;
  175. // prestep y1 down
  176. int dy = y0 - y1;
  177. int y = ((y1 + 3)&~7) + 4;
  178. int iy = y >> 3;
  179. y0 = (y0 - 5) >> 3;
  180. if(iy <= y0)
  181. {
  182. __int64 invslope = (__int64(x0 - x1) << 16) / dy;
  183. while(mEdgeNext + y0 + 1 - iy > mEdgeHeapSize)
  184. _ReallocEdgeBuffer(mEdgeHeapSize*2);
  185. xacc += (invslope * (y - y1)) >> 3;
  186. while(iy <= y0)
  187. {
  188. int ix = (int)((xacc + 32768) >> 16);
  189. mpEdgeBuffer[mEdgeNext].next = mpScanBuffer[iy];
  190. mpEdgeBuffer[mEdgeNext].posandflag = ix*2;
  191. mpScanBuffer[iy] = mEdgeNext++;
  192. ++iy;
  193. xacc += invslope;
  194. }
  195. }
  196. }
  197. }
  198. bool Rasterizer::BeginPath(HDC hdc)
  199. {
  200. _TrashPath();
  201. return !!::BeginPath(hdc);
  202. }
  203. bool Rasterizer::EndPath(HDC hdc)
  204. {
  205. ::CloseFigure(hdc);
  206. if(::EndPath(hdc))
  207. {
  208. mPathPoints = GetPath(hdc, NULL, NULL, 0);
  209. if(!mPathPoints)
  210. return true;
  211. mpPathTypes = (BYTE*)malloc(sizeof(BYTE) * mPathPoints);
  212. mpPathPoints = (POINT*)malloc(sizeof(POINT) * mPathPoints);
  213. if(mPathPoints == GetPath(hdc, mpPathPoints, mpPathTypes, mPathPoints))
  214. return true;
  215. }
  216. ::AbortPath(hdc);
  217. return false;
  218. }
  219. bool Rasterizer::PartialBeginPath(HDC hdc, bool bClearPath)
  220. {
  221. if(bClearPath)
  222. _TrashPath();
  223. return !!::BeginPath(hdc);
  224. }
  225. bool Rasterizer::PartialEndPath(HDC hdc, long dx, long dy)
  226. {
  227. ::CloseFigure(hdc);
  228. if(::EndPath(hdc))
  229. {
  230. int nPoints;
  231. BYTE* pNewTypes;
  232. POINT* pNewPoints;
  233. nPoints = GetPath(hdc, NULL, NULL, 0);
  234. if(!nPoints)
  235. return true;
  236. pNewTypes = (BYTE*)realloc(mpPathTypes, (mPathPoints + nPoints) * sizeof(BYTE));
  237. pNewPoints = (POINT*)realloc(mpPathPoints, (mPathPoints + nPoints) * sizeof(POINT));
  238. if(pNewTypes)
  239. mpPathTypes = pNewTypes;
  240. if(pNewPoints)
  241. mpPathPoints = pNewPoints;
  242. BYTE* pTypes = new BYTE[nPoints];
  243. POINT* pPoints = new POINT[nPoints];
  244. if(pNewTypes && pNewPoints && nPoints == GetPath(hdc, pPoints, pTypes, nPoints))
  245. {
  246. for(int i = 0; i < nPoints; ++i)
  247. {
  248. mpPathPoints[mPathPoints + i].x = pPoints[i].x + dx;
  249. mpPathPoints[mPathPoints + i].y = pPoints[i].y + dy;
  250. mpPathTypes[mPathPoints + i] = pTypes[i];
  251. }
  252. mPathPoints += nPoints;
  253. delete[] pTypes;
  254. delete[] pPoints;
  255. return true;
  256. }
  257. else
  258. DebugBreak();
  259. delete[] pTypes;
  260. delete[] pPoints;
  261. }
  262. ::AbortPath(hdc);
  263. return false;
  264. }
  265. bool Rasterizer::ScanConvert()
  266. {
  267. int lastmoveto = -1;
  268. int i;
  269. // Drop any outlines we may have.
  270. mOutline.clear();
  271. mWideOutline.clear();
  272. // Determine bounding box
  273. if(!mPathPoints)
  274. {
  275. mPathOffsetX = mPathOffsetY = 0;
  276. mWidth = mHeight = 0;
  277. return 0;
  278. }
  279. int minx = INT_MAX;
  280. int miny = INT_MAX;
  281. int maxx = INT_MIN;
  282. int maxy = INT_MIN;
  283. for(i=0; i<mPathPoints; ++i)
  284. {
  285. int ix = mpPathPoints[i].x;
  286. int iy = mpPathPoints[i].y;
  287. if(ix < minx) minx = ix;
  288. if(ix > maxx) maxx = ix;
  289. if(iy < miny) miny = iy;
  290. if(iy > maxy) maxy = iy;
  291. }
  292. minx = (minx >> 3) & ~7;
  293. miny = (miny >> 3) & ~7;
  294. maxx = (maxx + 7) >> 3;
  295. maxy = (maxy + 7) >> 3;
  296. for(i=0; i<mPathPoints; ++i)
  297. {
  298. mpPathPoints[i].x -= minx*8;
  299. mpPathPoints[i].y -= miny*8;
  300. }
  301. if(minx > maxx || miny > maxy)
  302. {
  303. mWidth = mHeight = 0;
  304. mPathOffsetX = mPathOffsetY = 0;
  305. _TrashPath();
  306. return true;
  307. }
  308. mWidth = maxx + 1 - minx;
  309. mHeight = maxy + 1 - miny;
  310. mPathOffsetX = minx;
  311. mPathOffsetY = miny;
  312. // Initialize edge buffer.  We use edge 0 as a sentinel.
  313. mEdgeNext = 1;
  314. mEdgeHeapSize = 2048;
  315. mpEdgeBuffer = (Edge*)malloc(sizeof(Edge)*mEdgeHeapSize);
  316. // Initialize scanline list.
  317. mpScanBuffer = new unsigned int[mHeight];
  318. memset(mpScanBuffer, 0, mHeight*sizeof(unsigned int));
  319. // Scan convert the outline.  Yuck, Bezier curves....
  320. // Unfortunately, Windows 95/98 GDI has a bad habit of giving us text
  321. // paths with all but the first figure left open, so we can't rely
  322. // on the PT_CLOSEFIGURE flag being used appropriately.
  323. fFirstSet = false;
  324. firstp.x = firstp.y = 0;
  325. lastp.x = lastp.y = 0;
  326. for(i=0; i<mPathPoints; ++i)
  327. {
  328. BYTE t = mpPathTypes[i] & ~PT_CLOSEFIGURE;
  329. switch(t)
  330. {
  331. case PT_MOVETO:
  332. if(lastmoveto >= 0 && firstp != lastp)
  333. _EvaluateLine(lastp.x, lastp.y, firstp.x, firstp.y);
  334. lastmoveto = i;
  335. fFirstSet = false;
  336. lastp = mpPathPoints[i];
  337. break;
  338. case PT_MOVETONC:
  339. break;
  340. case PT_LINETO:
  341. if(mPathPoints - (i-1) >= 2) _EvaluateLine(i-1, i);
  342. break;
  343. case PT_BEZIERTO:
  344. if(mPathPoints - (i-1) >= 4) _EvaluateBezier(i-1, false);
  345. i += 2;
  346. break;
  347. case PT_BSPLINETO:
  348. if(mPathPoints - (i-1) >= 4) _EvaluateBezier(i-1, true);
  349. i += 2;
  350. break;
  351. case PT_BSPLINEPATCHTO:
  352. if(mPathPoints - (i-3) >= 4) _EvaluateBezier(i-3, true);
  353. break;
  354. }
  355. }
  356. if(lastmoveto >= 0 && firstp != lastp)
  357. _EvaluateLine(lastp.x, lastp.y, firstp.x, firstp.y);
  358. // Free the path since we don't need it anymore.
  359. _TrashPath();
  360. // Convert the edges to spans.  We couldn't do this before because some of
  361. // the regions may have winding numbers >+1 and it would have been a pain
  362. // to try to adjust the spans on the fly.  We use one heap to detangle
  363. // a scanline's worth of edges from the singly-linked lists, and another
  364. // to collect the actual scans.
  365. std::vector<int> heap;
  366. mOutline.reserve(mEdgeNext / 2);
  367. __int64 y = 0;
  368. for(y=0; y<mHeight; ++y)
  369. {
  370. int count = 0;
  371. // Detangle scanline into edge heap.
  372. for(unsigned ptr = (unsigned)(mpScanBuffer[y]&0xffffffff); ptr; ptr = mpEdgeBuffer[ptr].next)
  373. {
  374. heap.push_back(mpEdgeBuffer[ptr].posandflag);
  375. }
  376. // Sort edge heap.  Note that we conveniently made the opening edges
  377. // one more than closing edges at the same spot, so we won't have any
  378. // problems with abutting spans.
  379. std::sort(heap.begin(), heap.end()/*begin() + heap.size()*/);
  380. // Process edges and add spans.  Since we only check for a non-zero
  381. // winding number, it doesn't matter which way the outlines go!
  382. std::vector<int>::iterator itX1 = heap.begin();
  383. std::vector<int>::iterator itX2 = heap.end(); // begin() + heap.size();
  384. int x1, x2;
  385. for(; itX1 != itX2; ++itX1)
  386. {
  387. int x = *itX1;
  388. if(!count) 
  389. x1 = (x>>1);
  390. if(x&1) 
  391. ++count;
  392. else 
  393. --count;
  394. if(!count)
  395. {
  396. x2 = (x>>1);
  397. if(x2>x1)
  398. mOutline.push_back(std::pair<__int64,__int64>((y<<32)+x1+0x4000000040000000i64, (y<<32)+x2+0x4000000040000000i64)); // G: damn Avery, this is evil! :)
  399. }
  400. }
  401. heap.clear();
  402. }
  403. // Dump the edge and scan buffers, since we no longer need them.
  404. free(mpEdgeBuffer);
  405. delete [] mpScanBuffer;
  406. // All done!
  407. return true;
  408. }
  409. using namespace std;
  410. void Rasterizer::_OverlapRegion(tSpanBuffer& dst, tSpanBuffer& src, int dx, int dy)
  411. {
  412. tSpanBuffer temp;
  413. temp.reserve(dst.size() + src.size());
  414. dst.swap(temp);
  415. tSpanBuffer::iterator itA = temp.begin();
  416. tSpanBuffer::iterator itAE = temp.end();
  417. tSpanBuffer::iterator itB = src.begin();
  418. tSpanBuffer::iterator itBE = src.end();
  419. // Don't worry -- even if dy<0 this will still work! // G: hehe, the evil twin :)
  420. unsigned __int64 offset1 = (((__int64)dy)<<32) - dx;
  421. unsigned __int64 offset2 = (((__int64)dy)<<32) + dx;
  422. while(itA != itAE && itB != itBE)
  423. {
  424. if((*itB).first + offset1 < (*itA).first)
  425. {
  426. // B span is earlier.  Use it.
  427. unsigned __int64 x1 = (*itB).first + offset1;
  428. unsigned __int64 x2 = (*itB).second + offset2;
  429. ++itB;
  430. // B spans don't overlap, so begin merge loop with A first.
  431. for(;;)
  432. {
  433. // If we run out of A spans or the A span doesn't overlap,
  434. // then the next B span can't either (because B spans don't
  435. // overlap) and we exit.
  436. if(itA == itAE || (*itA).first > x2)
  437. break;
  438. do {x2 = _MAX(x2, (*itA++).second);}
  439. while(itA != itAE && (*itA).first <= x2);
  440. // If we run out of B spans or the B span doesn't overlap,
  441. // then the next A span can't either (because A spans don't
  442. // overlap) and we exit.
  443. if(itB == itBE || (*itB).first + offset1 > x2)
  444. break;
  445. do {x2 = _MAX(x2, (*itB++).second + offset2);}
  446. while(itB != itBE && (*itB).first + offset1 <= x2);
  447. }
  448. // Flush span.
  449. dst.push_back(tSpan(x1, x2));
  450. }
  451. else
  452. {
  453. // A span is earlier.  Use it.
  454. unsigned __int64 x1 = (*itA).first;
  455. unsigned __int64 x2 = (*itA).second;
  456. ++itA;
  457. // A spans don't overlap, so begin merge loop with B first.
  458. for(;;)
  459. {
  460. // If we run out of B spans or the B span doesn't overlap,
  461. // then the next A span can't either (because A spans don't
  462. // overlap) and we exit.
  463. if(itB == itBE || (*itB).first + offset1 > x2)
  464. break;
  465. do {x2 = _MAX(x2, (*itB++).second + offset2);}
  466. while(itB != itBE && (*itB).first + offset1 <= x2);
  467. // If we run out of A spans or the A span doesn't overlap,
  468. // then the next B span can't either (because B spans don't
  469. // overlap) and we exit.
  470. if(itA == itAE || (*itA).first > x2)
  471. break;
  472. do {x2 = _MAX(x2, (*itA++).second);}
  473. while(itA != itAE && (*itA).first <= x2);
  474. }
  475. // Flush span.
  476. dst.push_back(tSpan(x1, x2));
  477. }
  478. }
  479. // Copy over leftover spans.
  480. while(itA != itAE)
  481. dst.push_back(*itA++);
  482. while(itB != itBE)
  483. {
  484. dst.push_back(tSpan((*itB).first + offset1, (*itB).second + offset2));
  485. ++itB;
  486. }
  487. }
  488. bool Rasterizer::CreateWidenedRegion(int r)
  489. {
  490. if(r < 0) r = 0;
  491. for(int y = -r; y <= r; ++y)
  492. {
  493. int x = (int)(0.5 + sqrt(float(r*r - y*y)));
  494. _OverlapRegion(mWideOutline, mOutline, x, y);
  495. }
  496. mWideBorder = r;
  497. return true;
  498. }
  499. void Rasterizer::DeleteOutlines()
  500. {
  501. mWideOutline.clear();
  502. mOutline.clear();
  503. }
  504. bool Rasterizer::Rasterize(int xsub, int ysub, bool fBlur)
  505. {
  506. _TrashOverlay();
  507. if(!mWidth || !mHeight)
  508. {
  509. mOverlayWidth = mOverlayHeight = 0;
  510. return true;
  511. }
  512. xsub &= 7;
  513. ysub &= 7;
  514. int width = mWidth + xsub;
  515. int height = mHeight + ysub;
  516. mOffsetX = mPathOffsetX - xsub;
  517. mOffsetY = mPathOffsetY - ysub;
  518. mWideBorder = (mWideBorder+7)&~7;
  519. if(!mWideOutline.empty())
  520. {
  521. width += 2*mWideBorder;
  522. height += 2*mWideBorder;
  523. xsub += mWideBorder;
  524. ysub += mWideBorder;
  525. mOffsetX -= mWideBorder;
  526. mOffsetY -= mWideBorder;
  527. }
  528. mOverlayWidth = ((width+7)>>3) + 1;
  529. mOverlayHeight = ((height+7)>>3) + 1;
  530. mpOverlayBuffer = new byte[2 * mOverlayWidth * mOverlayHeight];
  531. memset(mpOverlayBuffer, 0, 2 * mOverlayWidth * mOverlayHeight);
  532. // Are we doing a border?
  533. tSpanBuffer* pOutline[2] = {&mOutline, &mWideOutline};
  534. for(int i = countof(pOutline)-1; i >= 0; i--)
  535. {
  536. tSpanBuffer::iterator it = pOutline[i]->begin();
  537. tSpanBuffer::iterator itEnd = pOutline[i]->end();
  538. for(; it!=itEnd; ++it)
  539. {
  540. int y = (int)(((*it).first >> 32) - 0x40000000 + ysub);
  541. int x1 = (int)(((*it).first & 0xffffffff) - 0x40000000 + xsub);
  542. int x2 = (int)(((*it).second & 0xffffffff) - 0x40000000 + xsub);
  543. if(x2 > x1)
  544. {
  545. int first = x1>>3;
  546. int last = (x2-1)>>3;
  547. byte* dst = mpOverlayBuffer + 2*(mOverlayWidth*(y>>3) + first) + i;
  548. if(first == last)
  549. *dst += x2-x1;
  550. else
  551. {
  552. *dst += ((first+1)<<3) - x1;
  553. dst += 2;
  554. while(++first < last)
  555. {
  556. *dst += 0x08;
  557. dst += 2;
  558. }
  559. *dst += x2 - (last<<3);
  560. }
  561. }
  562. }
  563. }
  564. if(fBlur && mOverlayWidth >= 3 && mOverlayHeight >= 3)
  565. {
  566. int pitch = mOverlayWidth*2;
  567. byte* tmp = new byte[pitch*mOverlayHeight];
  568. if(!tmp) return(false);
  569. memcpy(tmp, mpOverlayBuffer, pitch*mOverlayHeight);
  570. int border = !mWideOutline.empty() ? 1 : 0;
  571. for(int j = 1; j < mOverlayHeight-1; j++)
  572. {
  573. byte* src = tmp + pitch*j + 2 + border;
  574. byte* dst = mpOverlayBuffer + pitch*j + 2 + border;
  575. for(int i = 1; i < mOverlayWidth-1; i++, src+=2, dst+=2)
  576. {
  577. *dst = (src[-2-pitch] + (src[-pitch]<<1) + src[+2-pitch]
  578. + (src[-2]<<1) + (src[0]<<2) + (src[+2]<<1)
  579. + src[-2+pitch] + (src[+pitch]<<1) + src[+2+pitch]) >> 4;
  580. }
  581. }
  582. delete [] tmp;
  583. }
  584. return true;
  585. }
  586. ///////////////////////////////////////////////////////////////////////////
  587. #define pixmix(s) {  
  588. int a = (((s)*(color>>24))>>6)&0xff;  
  589. int ia = 256-a;  
  590.  
  591. dst[wt] = ((((dst[wt]&0x00ff00ff)*ia + (color&0x00ff00ff)*a)&0xff00ff00)>>8) 
  592. | ((((dst[wt]&0x0000ff00)*ia + (color&0x0000ff00)*a)&0x00ff0000)>>8) 
  593. | ((((dst[wt]>>8)&0x00ff0000)*ia)&0xff000000);  
  594. #include <xmmintrin.h>
  595. #include <emmintrin.h>
  596. __forceinline void pixmix_sse2(DWORD* dst, DWORD color, DWORD alpha)
  597. {
  598. alpha = ((alpha * (color>>24)) >> 6) & 0xff;
  599. color &= 0xffffff;
  600. __m128i zero = _mm_setzero_si128();
  601. __m128i a = _mm_set1_epi32((alpha << 16) | (0x100 - alpha));
  602. __m128i d = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*dst), zero);
  603. __m128i s = _mm_unpacklo_epi8(_mm_cvtsi32_si128(color), zero);
  604. __m128i r = _mm_unpacklo_epi16(d, s);
  605. r = _mm_madd_epi16(r, a);
  606. r = _mm_srli_epi32(r, 8);
  607. r = _mm_packs_epi32(r, r);
  608. r = _mm_packus_epi16(r, r);
  609. *dst = (DWORD)_mm_cvtsi128_si32(r);
  610. }
  611. #include "../dsutil/vd.h"
  612. CRect Rasterizer::Draw(SubPicDesc& spd, CRect& clipRect, byte* pAlphaMask, int xsub, int ysub, const long* switchpts, bool fBody, bool fBorder)
  613. {
  614. CRect bbox(0, 0, 0, 0);
  615. if(!switchpts || !fBody && !fBorder) return(bbox);
  616. // clip
  617. CRect r(0, 0, spd.w, spd.h);
  618. r &= clipRect;
  619. int x = (xsub + mOffsetX + 4)>>3;
  620. int y = (ysub + mOffsetY + 4)>>3;
  621. int w = mOverlayWidth;
  622. int h = mOverlayHeight;
  623. int xo = 0, yo = 0;
  624. if(x < r.left) {xo = r.left-x; w -= r.left-x; x = r.left;}
  625. if(y < r.top) {yo = r.top-y; h -= r.top-y; y = r.top;}
  626. if(x+w > r.right) w = r.right-x;
  627. if(y+h > r.bottom) h = r.bottom-y;
  628. if(w <= 0 || h <= 0) return(bbox);
  629. bbox.SetRect(x, y, x+w, y+h);
  630. bbox &= CRect(0, 0, spd.w, spd.h);
  631. // draw
  632. const byte* src = mpOverlayBuffer + 2*(mOverlayWidth * yo + xo);
  633. const byte* s = fBorder ? (src+1) : src;
  634. const byte* am = pAlphaMask + spd.w * y + x;
  635. unsigned long* dst = (unsigned long *)((char *)spd.bits + spd.pitch * y) + x;
  636. unsigned long color = switchpts[0];
  637. bool fSSE2 = !!(g_cpuid.m_flags & CCpuID::sse2);
  638. while(h--)
  639. {
  640. if(!pAlphaMask)
  641. {
  642. if(switchpts[1] == 0xffffffff)
  643. {
  644. if(fBody)
  645. {
  646. if(fSSE2) for(int wt=0; wt<w; ++wt) pixmix_sse2(&dst[wt], color, s[wt*2]);
  647. else for(int wt=0; wt<w; ++wt) pixmix(s[wt*2]);
  648. }
  649. else
  650. {
  651. if(fSSE2) for(int wt=0; wt<w; ++wt) pixmix_sse2(&dst[wt], color, src[wt*2+1] - src[wt*2]);
  652. else for(int wt=0; wt<w; ++wt) pixmix(src[wt*2+1] - src[wt*2]);
  653. }
  654. }
  655. else
  656. {
  657. const long *sw = switchpts;
  658. if(fBody)
  659. {
  660. if(fSSE2) 
  661. for(int wt=0; wt<w; ++wt)
  662. {
  663. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];}
  664. pixmix_sse2(&dst[wt], color, s[wt*2]);
  665. }
  666. else
  667. for(int wt=0; wt<w; ++wt)
  668. {
  669. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];}
  670. pixmix(s[wt*2]);
  671. }
  672. }
  673. else
  674. {
  675. if(fSSE2) 
  676. for(int wt=0; wt<w; ++wt)
  677. {
  678. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];} 
  679. pixmix_sse2(&dst[wt], color, src[wt*2+1] - src[wt*2]);
  680. }
  681. else
  682. for(int wt=0; wt<w; ++wt)
  683. {
  684. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];} 
  685. pixmix(src[wt*2+1] - src[wt*2]);
  686. }
  687. }
  688. }
  689. }
  690. else
  691. {
  692. if(switchpts[1] == 0xffffffff)
  693. {
  694. if(fBody)
  695. {
  696. if(fSSE2) for(int wt=0; wt<w; ++wt) pixmix_sse2(&dst[wt], color, s[wt*2] * am[wt]);
  697. else for(int wt=0; wt<w; ++wt) pixmix(s[wt*2] * am[wt]);
  698. }
  699. else
  700. {
  701. if(fSSE2) for(int wt=0; wt<w; ++wt) pixmix_sse2(&dst[wt], color, (src[wt*2+1] - src[wt*2]) * am[wt]);
  702. else for(int wt=0; wt<w; ++wt) pixmix((src[wt*2+1] - src[wt*2]) * am[wt]);
  703. }
  704. }
  705. else
  706. {
  707. const long *sw = switchpts;
  708. if(fBody)
  709. {
  710. if(fSSE2) 
  711. for(int wt=0; wt<w; ++wt)
  712. {
  713. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];}
  714. pixmix_sse2(&dst[wt], color, s[wt*2] * am[wt]);
  715. }
  716. else
  717. for(int wt=0; wt<w; ++wt)
  718. {
  719. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];}
  720. pixmix(s[wt*2] * am[wt]);
  721. }
  722. }
  723. else
  724. {
  725. if(fSSE2) 
  726. for(int wt=0; wt<w; ++wt)
  727. {
  728. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];} 
  729. pixmix_sse2(&dst[wt], color, (src[wt*2+1] - src[wt*2]) * am[wt]);
  730. }
  731. else
  732. for(int wt=0; wt<w; ++wt)
  733. {
  734. if(wt+xo >= sw[1]) {while(wt+xo >= sw[1]) sw += 2; color = sw[-2];} 
  735. pixmix((src[wt*2+1] - src[wt*2]) * am[wt]);
  736. }
  737. }
  738. }
  739. }
  740. src += 2*mOverlayWidth;
  741. s += 2*mOverlayWidth;
  742. am += spd.w;
  743. dst = (unsigned long *)((char *)dst + spd.pitch);
  744. }
  745. return bbox;
  746. }