OSDN Git Service

Add TortoiseProc
[tortoisegit/TortoiseGitJp.git] / Utils / MiscUI / WaterEffect.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2006 - Stefan Kueng\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "WaterEffect.h"\r
21 \r
22 #include <math.h>\r
23 \r
24 \r
25 CWaterEffect::CWaterEffect()\r
26 {\r
27         m_iBuffer1 = NULL;\r
28         m_iBuffer2 = NULL;\r
29 \r
30         m_iWidth = 0;\r
31         m_iHeight = 0;\r
32 \r
33         m_iLightModifier = 10;\r
34         m_iHpage = 0;\r
35         m_iDensity = 2;\r
36 }\r
37 \r
38 CWaterEffect::~CWaterEffect()\r
39 {\r
40         // free memory\r
41         if (m_iBuffer1 != NULL)\r
42                 delete [] m_iBuffer1;\r
43         if (m_iBuffer2 != NULL)\r
44                 delete [] m_iBuffer2;\r
45 \r
46         m_iBuffer1 = NULL;\r
47         m_iBuffer2 = NULL;\r
48 }\r
49 \r
50 void CWaterEffect::Create(int iWidth, int iHeight)\r
51 {\r
52         if (m_iBuffer1 != NULL)\r
53                 delete [] m_iBuffer1;\r
54         if (m_iBuffer2 != NULL)\r
55                 delete [] m_iBuffer2;\r
56 \r
57         m_iBuffer1 = new int[(iWidth*iHeight)];\r
58         m_iBuffer2 = new int[(iWidth*iHeight)];\r
59 \r
60         m_iWidth = iWidth;\r
61         m_iHeight = iHeight;\r
62 \r
63         ClearWater();\r
64 \r
65         m_iHpage = 0;\r
66 \r
67 }\r
68 \r
69 void CWaterEffect::Blob(int x, int y, int radius, int height, int page)\r
70 {\r
71         int rquad;\r
72         int cx, cy, cyq;\r
73         int left, top, right, bottom;\r
74         \r
75         int *pNew;\r
76         int *pOld;\r
77         \r
78         if (page == 0)\r
79         {\r
80                 pNew = &m_iBuffer1[0];\r
81                 pOld = &m_iBuffer2[0];\r
82         }\r
83         else\r
84         {\r
85                 pNew = &m_iBuffer2[0];\r
86                 pOld = &m_iBuffer1[0];\r
87         }\r
88         \r
89         rquad = radius * radius;\r
90         \r
91         if (x<0) \r
92                 x = 1 + radius + rand() % (m_iWidth - 2 * radius - 1);\r
93         if (y<0)\r
94                 y = 1 + radius + rand() % (m_iHeight - 2 * radius - 1);\r
95         \r
96         left = -radius;\r
97         right = radius;\r
98         top = -radius;\r
99         bottom = radius;\r
100         \r
101         // clip edges\r
102         if (x - radius < 1)\r
103                 left -= (x-radius-1);\r
104         if (y - radius < 1) \r
105                 top  -= (y-radius-1);\r
106         if (x + radius > m_iWidth-1) \r
107                 right -= (x+radius-m_iWidth+1);\r
108         if (y + radius > m_iHeight-1) \r
109                 bottom-= (y+radius-m_iHeight+1);\r
110         \r
111         for(cy = top; cy < bottom; cy++)\r
112         {\r
113                 cyq = cy*cy;\r
114                 for(cx = left; cx < right; cx++)\r
115                 {\r
116                         if (cx*cx + cyq < rquad)\r
117                         {\r
118                                 pNew[m_iWidth*(cy+y) + (cx+x)] += height;\r
119                         }\r
120                 }\r
121         }\r
122 }\r
123 \r
124 void CWaterEffect::ClearWater()\r
125 {\r
126         // clear height fields\r
127         memset(m_iBuffer1,0, (m_iWidth*m_iHeight)*sizeof(int));\r
128         memset(m_iBuffer2,0, (m_iWidth*m_iHeight)*sizeof(int));\r
129 }\r
130 \r
131 void CWaterEffect::Render(DWORD* pSrcImage, DWORD* pTargetImage)\r
132 {\r
133         DrawWater(m_iHpage, m_iLightModifier, pSrcImage, pTargetImage);\r
134 \r
135         CalcWater(m_iHpage, m_iDensity);\r
136 \r
137         //change the field from 0 to 1 and vice versa\r
138         m_iHpage ^= 1;\r
139 \r
140 }\r
141 \r
142 void CWaterEffect::CalcWater(int npage, int density)\r
143 {\r
144         int newh;\r
145         int count = m_iWidth + 1;\r
146         int *pNew;\r
147         int *pOld;\r
148         \r
149         if (npage == 0)\r
150         {\r
151                 pNew = &m_iBuffer1[0];\r
152                 pOld = &m_iBuffer2[0];\r
153         }\r
154         else\r
155         {\r
156                 pNew = &m_iBuffer2[0];\r
157                 pOld = &m_iBuffer1[0];\r
158         }\r
159         \r
160         int x, y;\r
161         \r
162         // a description of the algorithm and an implementation\r
163         // in 'pseudocode' can be found here:\r
164         // http://freespace.virgin.net/hugo.elias/graphics/x_water.htm\r
165         for (y = (m_iHeight-1)*m_iWidth; count < y; count += 2)\r
166         {\r
167                 for (x = count+m_iWidth-2; count < x; count++)\r
168                 {\r
169                         // use eight pixels\r
170                         newh = ((pOld[count + m_iWidth]\r
171                                         + pOld[count - m_iWidth]\r
172                                         + pOld[count + 1]\r
173                                         + pOld[count - 1]\r
174                                         + pOld[count - m_iWidth - 1]\r
175                                         + pOld[count - m_iWidth + 1]\r
176                                         + pOld[count + m_iWidth - 1]\r
177                                         + pOld[count + m_iWidth + 1]\r
178                                         ) >> 2 )\r
179                                         - pNew[count];\r
180 \r
181                         pNew[count] = newh - (newh >> density);\r
182                 }\r
183         }\r
184 }\r
185 \r
186 void CWaterEffect::SmoothWater(int npage)\r
187 {\r
188         //flatten and spread the waves\r
189         int newh;\r
190         int count = m_iWidth + 1;\r
191         \r
192         int *pNew;\r
193         int *pOld;\r
194         \r
195         if (npage == 0)\r
196         {\r
197                 pNew = &m_iBuffer1[0];\r
198                 pOld = &m_iBuffer2[0];\r
199         }\r
200         else\r
201         {\r
202                 pNew = &m_iBuffer2[0];\r
203                 pOld = &m_iBuffer1[0];\r
204         }\r
205         \r
206         int x, y;\r
207         \r
208         // a description of the algorithm and an implementation\r
209         // in 'pseudocode' can be found here:\r
210         // http://freespace.virgin.net/hugo.elias/graphics/x_water.htm\r
211         for(y=1; y<m_iHeight-1; y++)\r
212         {\r
213                 for(x=1; x<m_iWidth-1; x++)\r
214                 {\r
215                   newh = ((pOld[count + m_iWidth]\r
216                                         + pOld[count - m_iWidth]\r
217                                         + pOld[count + 1]\r
218                                         + pOld[count - 1]\r
219                                         + pOld[count - m_iWidth - 1]\r
220                                         + pOld[count - m_iWidth + 1]\r
221                                         + pOld[count + m_iWidth - 1]\r
222                                         + pOld[count + m_iWidth + 1]\r
223                                         ) >> 3 )\r
224                                         + pNew[count];\r
225 \r
226                   pNew[count] = newh>>1;\r
227                   count++;\r
228                 }\r
229                 count += 2;\r
230         }\r
231 }\r
232 \r
233 void CWaterEffect::DrawWater(int /*page*/, int /*LightModifier*/, DWORD* pSrcImage, DWORD* pTargetImage)\r
234 {\r
235         int dx, dy;\r
236         int x, y;\r
237         DWORD c;\r
238         \r
239         int offset = m_iWidth + 1;\r
240         long lIndex;\r
241         long lBreak = m_iWidth*m_iHeight;\r
242         \r
243         int *ptr = &m_iBuffer1[0];\r
244         \r
245         \r
246         for (y = (m_iHeight-1)*m_iWidth; offset < y; offset += 2)\r
247         {\r
248                 for (x = offset + m_iWidth - 2; offset < x; offset++)\r
249                 {\r
250                         dx = ptr[offset] - ptr[offset+1];\r
251                         dy = ptr[offset] - ptr[offset+m_iWidth];\r
252                         \r
253                         lIndex = offset + m_iWidth*(dy>>3) + (dx>>3);\r
254                         if (lIndex < lBreak && lIndex > 0)\r
255                         {\r
256                                 c = pSrcImage[lIndex];\r
257                                 c = GetShiftedColor(c,dx);\r
258                                 pTargetImage[offset] = c;\r
259                         }\r
260                         \r
261                         offset++;\r
262                         dx = ptr[offset] - ptr[offset+1];\r
263                         dy = ptr[offset] - ptr[offset+m_iWidth];\r
264                         \r
265                         lIndex = offset + m_iWidth*(dy>>3) + (dx>>3);\r
266                         if (lIndex < lBreak && lIndex > 0)\r
267                         {\r
268                                 c = pSrcImage[lIndex];\r
269                                 c = GetShiftedColor(c,dx);\r
270                                 pTargetImage[offset] = c;\r
271                         }\r
272                 }\r
273         }\r
274 }\r
275 \r
276 COLORREF CWaterEffect::GetShiftedColor(COLORREF color, int shift)\r
277 {\r
278         long R;\r
279         long G;\r
280         long B;\r
281         int ir;\r
282         int ig;\r
283         int ib;\r
284 \r
285         R = GetRValue(color)-shift;\r
286         G = GetGValue(color)-shift;\r
287         B = GetBValue(color)-shift;\r
288 \r
289         ir = (R < 0) ? 0 : (R > 255) ? 255 : R;\r
290         ig = (G < 0) ? 0 : (G > 255) ? 255 : G;\r
291         ib = (B < 0) ? 0 : (B > 255) ? 255 : B;\r
292 \r
293         return RGB(ir,ig,ib);\r
294 }\r