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