1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <water/Water2Patch.h>
22 #include <water/Water2Constants.h>
23 #include <common/Logger.h>
24 #include <graph/OptionsDisplay.h>
25 #include <GLEXT/GLState.h>
26 #include <GLEXT/GLStateExtension.h>
27 #include <GLEXT/GLInfo.h>
28
Water2Patch()29 Water2Patch::Water2Patch() :
30 data_(0), dataSize_(0), size_(0), bufferOffSet_(-1)
31 {
32 }
33
~Water2Patch()34 Water2Patch::~Water2Patch()
35 {
36 delete [] data_;
37 }
38
getPosition(Water2Points & heights,int x,int y,int startX,int startY,int totalSize)39 static Vector getPosition(Water2Points &heights,
40 int x, int y, int startX, int startY, int totalSize)
41 {
42 int currentX = startX + x;
43 int currentY = startY + y;
44 int currentXNormalized = currentX % totalSize;
45 int currentYNormalized = currentY % totalSize;
46 if (currentXNormalized < 0) currentXNormalized += totalSize;
47 if (currentYNormalized < 0) currentYNormalized += totalSize;
48
49 int position = currentXNormalized + currentYNormalized * totalSize;
50 DIALOG_ASSERT(position >= 0 && position < totalSize * totalSize);
51
52 Vector &height = heights.getPoint(currentXNormalized, currentYNormalized);
53
54 Vector result(
55 height[0] + float(x) * 2.0f,
56 height[1] + float(y) * 2.0f,
57 height[2]);
58 return result;
59 }
60
generate(Water2Points & heights,int size,int totalSize,int posX,int posY,float waterHeight)61 void Water2Patch::generate(Water2Points &heights,
62 int size, int totalSize,
63 int posX, int posY,
64 float waterHeight)
65 {
66 size_ = size;
67 dataSize_ = (size + 1) * (size + 1);
68 if (!data_) data_ = new Data[dataSize_];
69
70 int startX = posX * size;
71 int startY = posY * size;
72
73 {
74 Data *data = data_;
75 for (int y=0; y<=size; y++)
76 {
77 for (int x=0; x<=size; x++, data++)
78 {
79 // Calculate the position
80 Vector position = getPosition(heights, x, y, startX, startY, totalSize);
81
82 // Set the position
83 data->x = position[0];
84 data->y = position[1];
85 data->z = position[2];
86 }
87 }
88
89 data = data_;
90 for (int y=0; y<=size; y++)
91 {
92 for (int x=0; x<=size; x++, data++)
93 {
94 // Calculate the normal
95 Vector current(data->x, data->y, data->z);
96 Vector other1, other2, other3, other4;
97
98 if (x<size) other1 = Vector((data+1)->x, (data+1)->y, (data+1)->z);
99 else other1 = getPosition(heights, x + 1, y, startX, startY, totalSize);
100
101 if (y<size) other2 = Vector((data+size+1)->x, (data+size+1)->y, (data+size+1)->z);
102 else other2 = getPosition(heights, x, y + 1, startX, startY, totalSize);
103
104 if (x>0) other3 = Vector((data-1)->x, (data-1)->y, (data-1)->z);
105 else other3 = getPosition(heights, x - 1, y, startX, startY, totalSize);
106
107 if (y>0) other4 = Vector((data-size-1)->x, (data-size-1)->y, (data-size-1)->z);
108 else other4 = getPosition(heights, x, y - 1, startX, startY, totalSize);
109
110 Vector dir1 = other1 - current;
111 Vector dir2 = other2 - current;
112 Vector dir3 = other3 - current;
113 Vector dir4 = other4 - current;
114
115 Vector normal1 = dir1 * dir2;
116 Vector normal3 = dir3 * dir4;
117
118 Vector normal = (normal1 + normal3).Normalize();
119
120 // Set the normal
121 data->nx = normal[0];
122 data->ny = normal[1];
123 data->nz = normal[2];
124 }
125 }
126 }
127 }
128
draw(MipMapPatchIndex & index)129 void Water2Patch::draw(MipMapPatchIndex &index)
130 {
131 // Number triangles
132 GLInfo::addNoTriangles(index.getSize());
133
134 if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
135 GLStateExtension::hasDrawRangeElements())
136 {
137 // Map indices to draw
138 unsigned short *indices = 0;
139 if (index.getBufferOffSet() != -1)
140 {
141 indices = (unsigned short *) NULL + (index.getBufferOffSet() / sizeof(unsigned short));
142 }
143 else
144 {
145 indices = index.getIndices();
146 }
147
148 // Draw elements
149 glDrawRangeElements(GL_TRIANGLE_STRIP,
150 index.getMinIndex(),
151 index.getMaxIndex(),
152 index.getSize(),
153 GL_UNSIGNED_SHORT,
154 indices);
155 DIALOG_ASSERT((index.getMaxIndex()-index.getMinIndex()+1) <
156 GLStateExtension::getMaxElementVertices());
157 DIALOG_ASSERT(index.getSize() <
158 GLStateExtension::getMaxElementIndices());
159 }
160 else
161 {
162 glBegin(GL_TRIANGLE_STRIP);
163 for (int i=0; i<index.getSize(); i++)
164 {
165 float *data = &data_[0].x +
166 (sizeof(Data) / 4 * index.getIndices()[i]);
167
168 glNormal3fv(data + 3);
169 glVertex3fv(data);
170 }
171 glEnd();
172 }
173 }
174
getData(int x,int y)175 Water2Patch::Data *Water2Patch::getData(int x, int y)
176 {
177 DIALOG_ASSERT(x >= 0 && y >= 0 &&
178 x <= size_ && y <= size_);
179 return &data_[x + y * (size_ + 1)];
180 }
181