CWaterRoutine.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. // WaterRoutine.cpp: implementation of the CWaterRoutine class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "CWaterRoutine.h"
  6. #include <math.h>
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #endif
  10. //////////////////////////////////////////////////////////////////////
  11. // Construction/Destruction
  12. //////////////////////////////////////////////////////////////////////
  13. #define random( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))
  14. CWaterRoutine::CWaterRoutine()
  15. {
  16. m_iHeightField1 = NULL;
  17. m_iHeightField2 = NULL;
  18. m_iWidth = 0;
  19. m_iHeight = 0;
  20. m_bDrawWithLight = TRUE;
  21. m_iLightModifier = 1;
  22. m_iHpage = 0;
  23. m_density = 5;
  24. }
  25. CWaterRoutine::~CWaterRoutine()
  26. {
  27. // Cleanup
  28. if(m_iHeightField1 != NULL)
  29. {
  30. delete [] m_iHeightField1;
  31. m_iHeightField1 = NULL;
  32. }
  33. if(m_iHeightField2 != NULL)
  34. {
  35. delete [] m_iHeightField2;
  36. m_iHeightField2 = NULL;
  37. }
  38. }
  39. void CWaterRoutine::Create(int iWidth,int iHeight)
  40. {
  41. if(m_iHeightField1 != NULL)
  42. delete [] m_iHeightField1;
  43. if(m_iHeightField2 != NULL)
  44. delete [] m_iHeightField2;
  45. // Create our height fields
  46. m_iHeightField1 = new int[(iWidth*iHeight)];
  47. m_iHeightField2 = new int[(iWidth*iHeight)];
  48. // Clear our height fields
  49. memset(m_iHeightField1,0,(iWidth*iHeight)*sizeof(int));
  50. memset(m_iHeightField2,0,(iWidth*iHeight)*sizeof(int));
  51. m_iWidth = iWidth;
  52. m_iHeight = iHeight;
  53. // Set our page to 0
  54. m_iHpage = 0;
  55. }
  56. void CWaterRoutine::FlattenWater()
  57. {
  58. // Clear our height fields
  59. memset(m_iHeightField1,0,(m_iWidth*m_iHeight)*sizeof(int));
  60. memset(m_iHeightField2,0,(m_iWidth*m_iHeight)*sizeof(int));
  61. }
  62. void CWaterRoutine::Render(DWORD* pSrcImage,DWORD* pTargetImage)
  63. {
  64. // Yes they have to be the same size...(for now)
  65. if(m_bDrawWithLight == FALSE)
  66. {
  67. DrawWaterNoLight(m_iHpage,pSrcImage,pTargetImage);
  68. }
  69. else
  70. {
  71. DrawWaterWithLight(m_iHpage,m_iLightModifier,pSrcImage,pTargetImage);
  72. }
  73. CalcWater(m_iHpage,m_density);
  74. m_iHpage ^= 1;
  75. }
  76. void CWaterRoutine::CalcWater(int npage, int density)
  77. {
  78. int newh;
  79. int count = m_iWidth + 1;
  80. int *newptr;
  81. int *oldptr;
  82. // Set up the pointers
  83. if(npage == 0)
  84. {
  85. newptr = &m_iHeightField1[0];
  86. oldptr = &m_iHeightField2[0];
  87. }
  88. else
  89. {
  90. newptr = &m_iHeightField2[0];
  91. oldptr = &m_iHeightField1[0];
  92. }
  93. int x, y;
  94. // Sorry, this function might not be as readable as I'd like, because
  95. // I optimized it somewhat. (enough to make me feel satisfied with it)
  96. for (y = (m_iHeight-1)*m_iWidth; count < y; count += 2)
  97. {
  98. for (x = count+m_iWidth-2; count < x; count++)
  99. {
  100. // This does the eight-pixel method. It looks much better.
  101. newh = ((oldptr[count + m_iWidth]
  102. + oldptr[count - m_iWidth]
  103. + oldptr[count + 1]
  104. + oldptr[count - 1]
  105. + oldptr[count - m_iWidth - 1]
  106. + oldptr[count - m_iWidth + 1]
  107. + oldptr[count + m_iWidth - 1]
  108. + oldptr[count + m_iWidth + 1]
  109. ) >> 2 )
  110. - newptr[count];
  111. newptr[count] = newh - (newh >> density);
  112. /*
  113. // This is the "sludge" method...
  114. newh = (oldptr[count]<<2)
  115. + oldptr[count-1-m_iWidth]
  116. + oldptr[count+1-m_iWidth]
  117. + oldptr[count-1+m_iWidth]
  118. + oldptr[count+1+m_iWidth]
  119. + ((oldptr[count-1]
  120. + oldptr[count+1]
  121. + oldptr[count-m_iWidth]
  122. + oldptr[count+m_iWidth])<<1);
  123. newptr[count] = (newh-(newh>>6)) >> density;
  124. */
  125. }
  126. }
  127. }
  128. void CWaterRoutine::SmoothWater(int npage)
  129. {
  130. int newh;
  131. int count = m_iWidth + 1;
  132. int *newptr;
  133. int *oldptr;
  134. // Set up the pointers
  135. if(npage == 0)
  136. {
  137. newptr = &m_iHeightField1[0];
  138. oldptr = &m_iHeightField2[0];
  139. }
  140. else
  141. {
  142. newptr = &m_iHeightField2[0];
  143. oldptr = &m_iHeightField1[0];
  144. }
  145. int x, y;
  146. // Sorry, this function might not be as readable as I'd like, because
  147. // I optimized it somewhat. (enough to make me feel satisfied with it)
  148. for(y=1; y<m_iHeight-1; y++)
  149. {
  150. for(x=1; x<m_iWidth-1; x++)
  151. {
  152. // This does the eight-pixel method. It looks much better.
  153. newh = ((oldptr[count + m_iWidth]
  154. + oldptr[count - m_iWidth]
  155. + oldptr[count + 1]
  156. + oldptr[count - 1]
  157. + oldptr[count - m_iWidth - 1]
  158. + oldptr[count - m_iWidth + 1]
  159. + oldptr[count + m_iWidth - 1]
  160. + oldptr[count + m_iWidth + 1]
  161. ) >> 3 )
  162. + newptr[count];
  163. newptr[count] = newh>>1;
  164. count++;
  165. }
  166. count += 2;
  167. }
  168. }
  169. void CWaterRoutine::CalcWaterBigFilter(int npage, int density)
  170. {
  171. int newh;
  172. int count = (2*m_iWidth) + 2;
  173. int *newptr;
  174. int *oldptr;
  175. // Set up the pointers
  176. if(npage == 0)
  177. {
  178. newptr = &m_iHeightField1[0];
  179. oldptr = &m_iHeightField2[0];
  180. }
  181. else
  182. {
  183. newptr = &m_iHeightField2[0];
  184. oldptr = &m_iHeightField1[0];
  185. }
  186. int x, y;
  187. // Sorry, this function might not be as readable as I'd like, because
  188. // I optimized it somewhat. (enough to make me feel satisfied with it)
  189. for(y=2; y<m_iHeight-2; y++)
  190. {
  191. for(x=2; x<m_iWidth-2; x++)
  192. {
  193. // This does the 25-pixel method. It looks much okay.
  194. newh = (
  195. (
  196. (
  197. (oldptr[count + m_iWidth]
  198. + oldptr[count - m_iWidth]
  199. + oldptr[count + 1]
  200. + oldptr[count - 1]
  201. )<<1)
  202. + ((oldptr[count - m_iWidth - 1]
  203. + oldptr[count - m_iWidth + 1]
  204. + oldptr[count + m_iWidth - 1]
  205. + oldptr[count + m_iWidth + 1]))
  206. + ( (
  207. oldptr[count - (m_iWidth*2)]
  208. + oldptr[count + (m_iWidth*2)]
  209. + oldptr[count - 2]
  210. + oldptr[count + 2]
  211. ) >> 1 )
  212. + ( (
  213. oldptr[count - (m_iWidth*2) - 1]
  214. + oldptr[count - (m_iWidth*2) + 1]
  215. + oldptr[count + (m_iWidth*2) - 1]
  216. + oldptr[count + (m_iWidth*2) + 1]
  217. + oldptr[count - 2 - m_iWidth]
  218. + oldptr[count - 2 + m_iWidth]
  219. + oldptr[count + 2 - m_iWidth]
  220. + oldptr[count + 2 + m_iWidth]
  221. ) >> 2 )
  222. )
  223. >> 3)
  224. - (newptr[count]);
  225. newptr[count] = newh - (newh >> density);
  226. count++;
  227. }
  228. count += 4;
  229. }
  230. }
  231. void CWaterRoutine::HeightBlob(int x, int y, int radius, int height, int page)
  232. {
  233. int rquad;
  234. int cx, cy, cyq;
  235. int left, top, right, bottom;
  236. int *newptr;
  237. int *oldptr;
  238. // Set up the pointers
  239. if(page == 0)
  240. {
  241. newptr = &m_iHeightField1[0];
  242. oldptr = &m_iHeightField2[0];
  243. }
  244. else
  245. {
  246. newptr = &m_iHeightField2[0];
  247. oldptr = &m_iHeightField1[0];
  248. }
  249. rquad = radius * radius;
  250. // Make a randomly-placed blob...
  251. if( x<0 )
  252. x = 1+radius + rand()%(m_iWidth-2*radius-1);
  253. if( y<0 )
  254. y = 1+radius + rand()%(m_iHeight-2*radius-1);
  255. left = -radius;
  256. right = radius;
  257. top = -radius;
  258. bottom = radius;
  259. // Perform edge clipping...
  260. if(x - radius < 1)
  261. left -= (x-radius-1);
  262. if(y - radius < 1)
  263. top -= (y-radius-1);
  264. if(x + radius > m_iWidth-1)
  265. right -= (x+radius-m_iWidth+1);
  266. if(y + radius > m_iHeight-1)
  267. bottom-= (y+radius-m_iHeight+1);
  268. for(cy = top; cy < bottom; cy++)
  269. {
  270. cyq = cy*cy;
  271. for( cx = left; cx < right; cx++ )
  272. {
  273. if( cx*cx + cyq < rquad )
  274. newptr[m_iWidth*(cy+y) + (cx+x)] += height;
  275. }
  276. }
  277. }
  278. void CWaterRoutine::HeightBox (int x, int y, int radius, int height, int page)
  279. {
  280. int cx, cy;
  281. int left, top, right, bottom;
  282. int *newptr;
  283. int *oldptr;
  284. // Set up the pointers
  285. if(page == 0)
  286. {
  287. newptr = &m_iHeightField1[0];
  288. oldptr = &m_iHeightField2[0];
  289. }
  290. else
  291. {
  292. newptr = &m_iHeightField2[0];
  293. oldptr = &m_iHeightField1[0];
  294. }
  295. if(x<0)
  296. x = 1+radius+ rand()%(m_iWidth-2*radius-1);
  297. if(y<0)
  298. y = 1+radius+ rand()%(m_iHeight-2*radius-1);
  299. left=-radius;
  300. right = radius;
  301. top=-radius;
  302. bottom = radius;
  303. // Perform edge clipping...
  304. if(x - radius < 1)
  305. left -= (x-radius-1);
  306. if(y - radius < 1)
  307. top -= (y-radius-1);
  308. if(x + radius > m_iWidth-1)
  309. right -= (x+radius-m_iWidth+1);
  310. if(y + radius > m_iHeight-1)
  311. bottom-= (y+radius-m_iHeight+1);
  312. for(cy = top; cy < bottom; cy++)
  313. {
  314. for(cx = left; cx < right; cx++)
  315. {
  316. newptr[m_iWidth*(cy+y) + (cx+x)] = height;
  317. }
  318. }
  319. }
  320. void CWaterRoutine::WarpBlob(int x, int y, int radius, int height, int page)
  321. {
  322. int cx, cy;
  323. int left,top,right,bottom;
  324. int square;
  325. int radsquare = radius * radius;
  326. int *newptr;
  327. int *oldptr;
  328. // Set up the pointers
  329. if(page == 0)
  330. {
  331. newptr = &m_iHeightField1[0];
  332. oldptr = &m_iHeightField2[0];
  333. }
  334. else
  335. {
  336. newptr = &m_iHeightField2[0];
  337. oldptr = &m_iHeightField1[0];
  338. }
  339. // radsquare = (radius*radius) << 8;
  340. radsquare = (radius*radius);
  341. height /= 64;
  342. left=-radius; right = radius;
  343. top=-radius; bottom = radius;
  344. // Perform edge clipping...
  345. if(x - radius < 1) left -= (x-radius-1);
  346. if(y - radius < 1) top -= (y-radius-1);
  347. if(x + radius > m_iWidth-1) right -= (x+radius-m_iWidth+1);
  348. if(y + radius > m_iHeight-1) bottom-= (y+radius-m_iHeight+1);
  349. for(cy = top; cy < bottom; cy++)
  350. {
  351. for(cx = left; cx < right; cx++)
  352. {
  353. square = cy*cy + cx*cx;
  354. // square <<= 8;
  355. if(square < radsquare)
  356. {
  357. // Height[page][WATERWID*(cy+y) + cx+x]
  358. // += (sqrt(radsquare)-sqrt(square))*height;
  359. newptr[m_iWidth*(cy+y) + cx+x] += int( ( radius - sqrt((float)square) ) * (float)(height) );
  360. }
  361. }
  362. }
  363. }
  364. void CWaterRoutine::SineBlob(int x, int y, int radius, int height, int page)
  365. {
  366. int cx, cy;
  367. int left,top,right,bottom;
  368. int square, dist;
  369. int radsquare = radius * radius;
  370. float length = float((1024.0/(float)radius)*(1024.0/(float)radius));
  371. int *newptr;
  372. int *oldptr;
  373. // Set up the pointers
  374. if(page == 0)
  375. {
  376. newptr = &m_iHeightField1[0];
  377. oldptr = &m_iHeightField2[0];
  378. }
  379. else
  380. {
  381. newptr = &m_iHeightField2[0];
  382. oldptr = &m_iHeightField1[0];
  383. }
  384. if(x<0) x = 1+radius+ rand()%(m_iWidth-2*radius-1);
  385. if(y<0) y = 1+radius+ rand()%(m_iHeight-2*radius-1);
  386. // radsquare = (radius*radius) << 8;
  387. radsquare = (radius*radius);
  388. // height /= 8;
  389. left=-radius; right = radius;
  390. top=-radius; bottom = radius;
  391. // Perform edge clipping...
  392. if(x - radius < 1) left -= (x-radius-1);
  393. if(y - radius < 1) top -= (y-radius-1);
  394. if(x + radius > m_iWidth-1) right -= (x+radius-m_iWidth+1);
  395. if(y + radius > m_iHeight-1) bottom-= (y+radius-m_iHeight+1);
  396. for(cy = top; cy < bottom; cy++)
  397. {
  398. for(cx = left; cx < right; cx++)
  399. {
  400. square = cy*cy + cx*cx;
  401. if(square < radsquare)
  402. {
  403. dist = int(sqrt(square*length));
  404. newptr[m_iWidth*(cy+y) + cx+x] += (int)( ( cos((float)dist) + 0xffff )*(height) ) >> 19;
  405. }
  406. }
  407. }
  408. }
  409. void CWaterRoutine::DrawWaterNoLight(int page,DWORD* pSrcImage,DWORD* pTargetImage)
  410. {
  411. // int ox, oy;
  412. int dx, dy;
  413. int x, y;
  414. DWORD c;
  415. int offset=m_iWidth + 1;
  416. int *ptr = &m_iHeightField1[0];
  417. for (y = (m_iHeight-1)*m_iWidth; offset < y; offset += 2)
  418. {
  419. for (x = offset+m_iWidth-2; offset < x; offset++)
  420. {
  421. dx = ptr[offset] - ptr[offset+1];
  422. dy = ptr[offset] - ptr[offset+m_iWidth];
  423. //Shading = dx;?
  424. // Water draw method?
  425. // c = BkGdImage[offset + WATERWID*(dy>>3) + (dx>>3)];
  426. c = pSrcImage[offset + m_iWidth*(dy>>3) + (dx>>3)];
  427. // If anyone knows a better/faster way to do this, please tell me...
  428. // temp[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
  429. pTargetImage[offset] = c;
  430. offset++;
  431. dx = ptr[offset] - ptr[offset+1];
  432. dy = ptr[offset] - ptr[offset+m_iWidth];
  433. // c = BkGdImage[offset + m_iWidth*(dy>>3) + (dx>>3)];
  434. c = pSrcImage[offset + m_iWidth*(dy>>3) + (dx>>3)];
  435. pTargetImage[offset] = c;
  436. // temp[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
  437. }
  438. }
  439. }
  440. void CWaterRoutine::DrawWaterWithLight(int page, int LightModifier,DWORD* pSrcImage,DWORD* pTargetImage)
  441. {
  442. // int ox, oy;
  443. int dx, dy;
  444. int x, y;
  445. DWORD c;
  446. int offset=m_iWidth + 1;
  447. long lIndex;
  448. long lBreak = m_iWidth*m_iHeight;
  449. int *ptr = &m_iHeightField1[0];
  450. for (y = (m_iHeight-1)*m_iWidth; offset < y; offset += 2)
  451. {
  452. for (x = offset+m_iWidth-2; offset < x; offset++)
  453. {
  454. dx = ptr[offset] - ptr[offset+1];
  455. dy = ptr[offset] - ptr[offset+m_iWidth];
  456. lIndex = offset + m_iWidth*(dy>>3) + (dx>>3);
  457. if(lIndex < lBreak && lIndex > 0)
  458. {
  459. c = pSrcImage[lIndex];// - (dx>>LightModifier);
  460. // Now we shift it by the dx component...
  461. //
  462. c = GetShiftedColor(c,dx);
  463. pTargetImage[offset] = c;
  464. }
  465. offset++;
  466. dx = ptr[offset] - ptr[offset+1];
  467. dy = ptr[offset] - ptr[offset+m_iWidth];
  468. lIndex = offset + m_iWidth*(dy>>3) + (dx>>3);
  469. if(lIndex < lBreak && lIndex > 0)
  470. {
  471. c = pSrcImage[lIndex];// - (dx>>LightModifier);
  472. c = GetShiftedColor(c,dx);
  473. // temp[offset] = (c < 0) ? 0 : (c > 255) ? 255 : c;
  474. pTargetImage[offset] = c;
  475. }
  476. }
  477. }
  478. }
  479. inline COLORREF CWaterRoutine::GetShiftedColor(COLORREF color,int shift)
  480. {
  481. long R;
  482. long G;
  483. long B;
  484. int ir;
  485. int ig;
  486. int ib;
  487. R = GetRValue(color)-shift;
  488. G = GetGValue(color)-shift;
  489. B = GetBValue(color)-shift;
  490. ir = (R < 0) ? 0 : (R > 255) ? 255 : R;
  491. ig = (G < 0) ? 0 : (G > 255) ? 255 : G;
  492. ib = (B < 0) ? 0 : (B > 255) ? 255 : B;
  493. return RGB(ir,ig,ib);
  494. }