source: OGRE/trunk/ogrenew/Samples/Water/src/WaterMesh.cpp @ 657

Revision 657, 10.8 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10You may use this sample code for anything you like, it is not covered by the
11LGPL like the rest of the engine.
12-----------------------------------------------------------------------------
13*/
14
15
16#include "WaterMesh.h"
17
18#define ANIMATIONS_PER_SECOND 100.0f
19
20WaterMesh::WaterMesh(const String& meshName, Real planeSize, int complexity)
21{
22        int x,y,b; // I prefer to initialize for() variables inside it, but VC doesn't like it ;(
23       
24        this->meshName = meshName ;
25        this->complexity =  complexity ;
26        numFaces = 2 * complexity * complexity;
27        numVertices = (complexity + 1) * (complexity + 1) ;
28        lastTimeStamp = 0 ;
29        lastAnimationTimeStamp = 0;
30        lastFrameTime = 0 ;
31       
32        // initialize algorithm parameters
33        PARAM_C = 0.3f ; // ripple speed
34        PARAM_D = 0.4f ; // distance
35        PARAM_U = 0.05f ; // viscosity
36        PARAM_T = 0.13f ; // time
37        useFakeNormals = false ;
38       
39        // allocate space for normal calculation
40        vNormals = new Vector3[numVertices];
41       
42        // create mesh and submesh
43        mesh = MeshManager::getSingleton().createManual(meshName,
44        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
45        subMesh = mesh->createSubMesh();
46        subMesh->useSharedVertices=false;
47       
48        // Vertex buffers
49        subMesh->vertexData = new VertexData();
50        subMesh->vertexData->vertexStart = 0;
51        subMesh->vertexData->vertexCount = numVertices;
52
53        VertexDeclaration* vdecl = subMesh->vertexData->vertexDeclaration;
54        VertexBufferBinding* vbind = subMesh->vertexData->vertexBufferBinding;
55       
56
57        vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
58        vdecl->addElement(1, 0, VET_FLOAT3, VES_NORMAL);
59        vdecl->addElement(2, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);
60       
61        // Prepare buffer for positions - todo: first attempt, slow
62        posVertexBuffer =
63         HardwareBufferManager::getSingleton().createVertexBuffer(
64            3*sizeof(float),
65                        numVertices,
66                        HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
67        vbind->setBinding(0, posVertexBuffer);
68
69        // Prepare buffer for normals - write only
70        normVertexBuffer =
71         HardwareBufferManager::getSingleton().createVertexBuffer(
72            3*sizeof(float),
73                        numVertices,
74                        HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
75        vbind->setBinding(1, normVertexBuffer);
76       
77        // Prepare texture coords buffer - static one
78        // todo: optimize to write directly into buffer
79        float *texcoordsBufData = new float[numVertices*2];
80        for(y=0;y<=complexity;y++) {
81                for(x=0;x<=complexity;x++) {
82                        texcoordsBufData[2*(y*(complexity+1)+x)+0] = (float)x / complexity ;
83                        texcoordsBufData[2*(y*(complexity+1)+x)+1] = 1.0f - ((float)y / (complexity)) ;
84                }
85        }
86        texcoordsVertexBuffer =
87         HardwareBufferManager::getSingleton().createVertexBuffer(
88            2*sizeof(float),
89                        numVertices,
90                        HardwareBuffer::HBU_STATIC_WRITE_ONLY);
91        texcoordsVertexBuffer->writeData(0,
92                texcoordsVertexBuffer->getSizeInBytes(),
93                texcoordsBufData,
94                true); // true?
95        delete [] texcoordsBufData;
96    vbind->setBinding(2, texcoordsVertexBuffer);
97       
98        // Prepare buffer for indices
99        indexBuffer =
100                HardwareBufferManager::getSingleton().createIndexBuffer(
101                        HardwareIndexBuffer::IT_16BIT,
102                        3*numFaces,
103                        HardwareBuffer::HBU_STATIC, true);
104        unsigned short *faceVertexIndices = (unsigned short*)
105                indexBuffer->lock(0, numFaces*3*2, HardwareBuffer::HBL_DISCARD);
106        for(y=0 ; y<complexity ; y++) {
107                for(int x=0 ; x<complexity ; x++) {
108                        unsigned short *twoface = faceVertexIndices + (y*complexity+x)*2*3;
109                        int p0 = y*(complexity+1) + x ;
110                        int p1 = y*(complexity+1) + x + 1 ;
111                        int p2 = (y+1)*(complexity+1) + x ;
112                        int p3 = (y+1)*(complexity+1) + x + 1 ;
113                        twoface[0]=p2; //first tri
114                        twoface[1]=p1;
115                        twoface[2]=p0;
116                        twoface[3]=p2; //second tri
117                        twoface[4]=p3;
118                        twoface[5]=p1;
119                }
120        }
121        indexBuffer->unlock();
122        // Set index buffer for this submesh
123        subMesh->indexData->indexBuffer = indexBuffer;
124        subMesh->indexData->indexStart = 0;
125        subMesh->indexData->indexCount = 3*numFaces;
126       
127        /*      prepare vertex positions
128         *      note - we use 3 vertex buffers, since algorighm uses two last phases
129         *      to calculate the next one
130         */
131        for(b=0;b<3;b++) {
132                vertexBuffers[b] = new float[numVertices * 3] ;
133                for(y=0;y<=complexity;y++) {
134                        for(x=0;x<=complexity;x++) {
135                                int numPoint = y*(complexity+1) + x ;
136                                float* vertex = vertexBuffers[b] + 3*numPoint ;
137                                vertex[0]=(float)(x) / (float)(complexity) * (float) planeSize ;
138                                vertex[1]= 0 ; // rand() % 30 ;
139                                vertex[2]=(float)(y) / (float)(complexity) * (float) planeSize ;
140                        }
141                }
142        }
143       
144        AxisAlignedBox meshBounds(0,0,0,
145                planeSize,0, planeSize);
146        mesh->_setBounds(meshBounds);
147       
148        currentBuffNumber = 0 ;
149        posVertexBuffer->writeData(0,
150                posVertexBuffer->getSizeInBytes(), // size
151                vertexBuffers[currentBuffNumber], // source
152                true); // discard?
153
154    mesh->load();
155    mesh->touch();
156}
157/* ========================================================================= */
158WaterMesh::~WaterMesh ()
159{
160        delete[] vertexBuffers[0];
161        delete[] vertexBuffers[1];
162        delete[] vertexBuffers[2];
163
164        delete[] vNormals;
165}
166/* ========================================================================= */
167void WaterMesh::push(Real x, Real y, Real depth, bool absolute)
168{
169        float *buf = vertexBuffers[currentBuffNumber]+1 ;
170        // scale pressure according to time passed
171        depth = depth * lastFrameTime * ANIMATIONS_PER_SECOND ;
172#define _PREP(addx,addy) { \
173        float *vertex=buf+3*((int)(y+addy)*(complexity+1)+(int)(x+addx)) ; \
174        float diffy = y - floor(y+addy); \
175        float diffx = x - floor(x+addx); \
176        float dist=sqrt(diffy*diffy + diffx*diffx) ; \
177        float power = 1 - dist ; \
178        if (power<0)  \
179                power = 0; \
180        if (absolute) \
181                *vertex = depth*power ;  \
182        else \
183                *vertex += depth*power ;  \
184} /* #define */
185        _PREP(0,0);
186        _PREP(0,1);
187        _PREP(1,0);
188        _PREP(1,1);
189#undef _PREP   
190}
191/* ========================================================================= */
192Real WaterMesh::getHeight(Real x, Real y)
193{
194#define hat(_x,_y) buf[3*((int)_y*(complexity+1)+(int)(_x))]
195        float *buf = vertexBuffers[currentBuffNumber] ;
196        Real xa = floor(x);
197        Real xb = xa + 1 ;
198        Real ya = floor(y);
199        Real yb = ya + 1 ;
200        float *vertex = buf + 3*((int)(ya)*(complexity+1)+(int)(xa));
201        Real yaxavg = hat(xa,ya) * (1.0f-fabs(xa-x)) + hat(xb,ya) * (1.0f-fabs(xb-x));
202        Real ybxavg = hat(xa,yb) * (1.0f-fabs(xa-x)) + hat(xb,yb) * (1.0f-fabs(xb-x));
203        Real yavg = yaxavg * (1.0f-fabs(ya-y)) + ybxavg * (1.0f-fabs(yb-y)) ;
204        return yavg ;
205}
206/* ========================================================================= */
207void WaterMesh::calculateFakeNormals()
208{
209        int x,y;
210        float *buf = vertexBuffers[currentBuffNumber] + 1;
211        float *pNormals = (float*) normVertexBuffer->lock(
212                0,normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
213        for(y=1;y<complexity;y++) {
214                float *nrow = pNormals + 3*y*(complexity+1);
215                float *row = buf + 3*y*(complexity+1) ;
216                float *rowup = buf + 3*(y-1)*(complexity+1) ;
217                float *rowdown = buf + 3*(y+1)*(complexity+1) ;
218                for(x=1;x<complexity;x++) {
219                        Real xdiff = row[3*x+3] - row[3*x-3] ;
220                        Real ydiff = rowup[3*x] - rowdown[3*x-3] ;
221                        Vector3 norm(xdiff,30,ydiff);
222                        norm.normalise();
223                        nrow[3*x+0] = norm.x;
224                        nrow[3*x+1] = norm.y;
225                        nrow[3*x+2] = norm.z;
226                }
227        }
228        normVertexBuffer->unlock();
229}
230/* ========================================================================= */
231void WaterMesh::calculateNormals()
232{
233        int i,x,y;
234        float *buf = vertexBuffers[currentBuffNumber] + 1;
235        // zero normals
236        for(i=0;i<numVertices;i++) {
237                vNormals[i] = Vector3::ZERO;
238        }
239        // first, calculate normals for faces, add them to proper vertices
240        buf = vertexBuffers[currentBuffNumber] ;
241        unsigned short* vinds = (unsigned short*) indexBuffer->lock(
242                0, indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_READ_ONLY);
243        float *pNormals = (float*) normVertexBuffer->lock(
244                0, normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
245        for(i=0;i<numFaces;i++) {
246                int p0 = vinds[3*i] ;
247                int p1 = vinds[3*i+1] ;
248                int p2 = vinds[3*i+2] ;
249                Vector3 v0(buf[3*p0], buf[3*p0+1], buf[3*p0+2]);
250                Vector3 v1(buf[3*p1], buf[3*p1+1], buf[3*p1+2]);
251                Vector3 v2(buf[3*p2], buf[3*p2+1], buf[3*p2+2]);
252                Vector3 diff1 = v2 - v1 ;
253                Vector3 diff2 = v0 - v1 ;
254                Vector3 fn = diff1.crossProduct(diff2);
255                vNormals[p0] += fn ;
256                vNormals[p1] += fn ;
257                vNormals[p2] += fn ;
258        }
259        // now normalize vertex normals
260        for(y=0;y<=complexity;y++) {
261                for(x=0;x<=complexity;x++) {
262                        int numPoint = y*(complexity+1) + x ;
263                        Vector3 n = vNormals[numPoint] ;
264                        n.normalise() ;
265                        float* normal = pNormals + 3*numPoint ;
266                        normal[0]=n.x;
267                        normal[1]=n.y;
268                        normal[2]=n.z;
269                }
270        }
271        indexBuffer->unlock();
272        normVertexBuffer->unlock();
273}
274/* ========================================================================= */
275void WaterMesh::updateMesh(Real timeSinceLastFrame)
276{
277        int x, y ;
278       
279        lastFrameTime = timeSinceLastFrame ;
280        lastTimeStamp += timeSinceLastFrame ;
281       
282        // do rendering to get ANIMATIONS_PER_SECOND
283        while(lastAnimationTimeStamp <= lastTimeStamp) {
284       
285                // switch buffer numbers
286                currentBuffNumber = (currentBuffNumber + 1) % 3 ;
287                float *buf = vertexBuffers[currentBuffNumber] + 1 ; // +1 for Y coordinate
288                float *buf1 = vertexBuffers[(currentBuffNumber+2)%3] + 1 ;
289                float *buf2 = vertexBuffers[(currentBuffNumber+1)%3] + 1;       
290       
291                /* we use an algorithm from
292                 * http://collective.valve-erc.com/index.php?go=water_simulation
293                 * The params could be dynamically changed every frame ofcourse
294                 */
295                double C = PARAM_C; // ripple speed
296                double D = PARAM_D; // distance
297                double U = PARAM_U; // viscosity
298                double T = PARAM_T; // time
299                Real TERM1 = ( 4.0f - 8.0f*C*C*T*T/(D*D) ) / (U*T+2) ;
300                Real TERM2 = ( U*T-2.0f ) / (U*T+2.0f) ;
301                Real TERM3 = ( 2.0f * C*C*T*T/(D*D) ) / (U*T+2) ;
302                for(y=1;y<complexity;y++) { // don't do anything with border values
303                        float *row = buf + 3*y*(complexity+1) ;
304                        float *row1 = buf1 + 3*y*(complexity+1) ;
305                        float *row1up = buf1 + 3*(y-1)*(complexity+1) ;
306                        float *row1down = buf1 + 3*(y+1)*(complexity+1) ;
307                        float *row2 = buf2 + 3*y*(complexity+1) ;
308                        for(x=1;x<complexity;x++) {
309                                row[3*x] = TERM1 * row1[3*x]
310                                        + TERM2 * row2[3*x]
311                                        + TERM3 * ( row1[3*x-3] + row1[3*x+3] + row1up[3*x]+row1down[3*x] ) ;
312                        }
313                }
314               
315                lastAnimationTimeStamp += (1.0f / ANIMATIONS_PER_SECOND);
316        }
317
318        if (useFakeNormals) {
319                calculateFakeNormals();
320        } else {
321                calculateNormals();
322        }
323
324        // set vertex buffer
325        posVertexBuffer->writeData(0,
326                posVertexBuffer->getSizeInBytes(), // size
327                vertexBuffers[currentBuffNumber], // source
328                true); // discard?
329}
Note: See TracBrowser for help on using the repository browser.