1 /* weather.h
2 Adds purely decorative snow and rain
3
4 Copyright (C) 2003-2004 Mathias Broxvall
5
6 This program 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 This program 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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "weather.h"
22
23 #include "game.h"
24 #include "player.h"
25 #include "settings.h"
26
27 #include <cstring>
28
Weather()29 Weather::Weather() {
30 if (Settings::settings->gfx_details <= 2) max_weather_particles = 500;
31 if (Settings::settings->gfx_details == 3) max_weather_particles = 1000;
32 if (Settings::settings->gfx_details == 4) max_weather_particles = 2000;
33 if (Settings::settings->gfx_details >= 5) max_weather_particles = 3000;
34 kind = WEATHER_SNOW;
35 clear();
36
37 bufs[0] = 0;
38 bufs[1] = 0;
39 vao = 0;
40 }
~Weather()41 Weather::~Weather() {
42 if (bufs[0] == bufs[1]) {
43 glDeleteBuffers(2, bufs);
44 glDeleteVertexArrays(1, &vao);
45 }
46 }
47
tick(Real td,Player * player)48 void Weather::tick(Real td, Player *player) {
49 static double count = 0.0;
50 static double snowDrift = 0.0;
51
52 if (Settings::settings->gfx_details <= 1) return;
53 if (strength < 0.0) return;
54
55 if (kind == WEATHER_SNOW) {
56 for (count += td * 300.0 * strength; count > 0.0; count -= 1.0) {
57 Particle *p = &particles[next];
58 next = (next + 1) % max_weather_particles;
59 p->size = frandom() * (0.5 + 0.5 * strength);
60 p->position[0] = player->position[0] + (frandom() - 0.5) * 20.0;
61 p->position[1] = player->position[1] + (frandom() - 0.5) * 20.0;
62 p->position[2] = player->position[2] + 4.0;
63 p->velocity[0] = (frandom() - 0.5) * 1.0;
64 p->velocity[1] = (frandom() - 0.5) * 1.0;
65 p->velocity[2] = -1.0 - frandom();
66 for (int j = 0; j < 3; j++)
67 for (int k = 0; k < 3; k++) p->corners[j][k] = frandom() * 0.06;
68 }
69 /* Make it look like the snow particles is drifting in the wind by changing
70 their velocities randomly once every 2 seconds. */
71 for (snowDrift += (max_weather_particles * td) / 2.0; snowDrift > 0.0; snowDrift -= 1.0) {
72 Particle *p = &particles[nextSnowDrift];
73 nextSnowDrift = (nextSnowDrift + 1) % max_weather_particles;
74 p->velocity[0] += (frandom() - 0.5) * 0.5;
75 p->velocity[1] += (frandom() - 0.5) * 0.5;
76 }
77
78 } else if (kind == WEATHER_RAIN) {
79 for (count += td * 500.0 * strength; count > 0.0; count -= 1.0) {
80 Particle *p = &particles[next];
81 next = (next + 1) % max_weather_particles;
82 p->size = frandom() * (0.5 + 0.5 * strength);
83 p->position[0] = player->position[0] + (frandom() - 0.5) * 15.0;
84 p->position[1] = player->position[1] + (frandom() - 0.5) * 15.0;
85 p->position[2] = player->position[2] + 5.0;
86 p->velocity[0] = 0.0;
87 p->velocity[1] = 0.0;
88 p->velocity[2] = -4.0 - p->size * 4.0;
89 }
90 }
91
92 for (int i = 0; i < max_weather_particles; i++) {
93 Particle *p = &particles[i];
94 p->position[0] += p->velocity[0] * td;
95 p->position[1] += p->velocity[1] * td;
96 p->position[2] += p->velocity[2] * td;
97 }
98 }
99
draw2(Player * player)100 void Weather::draw2(Player *player) {
101 if (Settings::settings->gfx_details <= 1) return;
102 if (strength == -1.0) return;
103 if (activeView.calculating_shadows) return;
104
105 if (bufs[0] == bufs[1]) {
106 glGenBuffers(2, bufs);
107 glGenVertexArrays(1, &vao);
108 /* Create a fixed linear index */
109 ushort *idxs = new ushort[3 * 3000];
110 for (int i = 0; i < 3 * 3000; i++) { idxs[i] = i; }
111 glBindVertexArray(0);
112 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufs[1]);
113 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * 3000 * sizeof(ushort), idxs, GL_STATIC_DRAW);
114 delete[] idxs;
115 }
116
117 if (kind == WEATHER_RAIN) {
118 /** Draw RAIN particles **/
119 glEnable(GL_BLEND);
120 glLineWidth(1.5);
121 glEnable(GL_LINE_SMOOTH);
122 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
123
124 GLfloat h = player->position[2] - 6.0;
125 int nactive = 0;
126 for (int i = 0; i < max_weather_particles; i++) {
127 if (particles[i].position[2] < h) continue;
128 nactive++;
129 }
130 if (nactive <= 0) { return; }
131
132 GLfloat *data = new GLfloat[2 * 3 * nactive];
133 int j = 0;
134 for (int i = 0; i < max_weather_particles; i++) {
135 const Particle &p = particles[i];
136 if (p.position[2] < h) continue;
137 data[6 * j + 0] = p.position[0];
138 data[6 * j + 1] = p.position[1];
139 data[6 * j + 2] = p.position[2] + 0.2 * p.size;
140 data[6 * j + 3] = p.position[0];
141 data[6 * j + 4] = p.position[1];
142 data[6 * j + 5] = p.position[2];
143 j++;
144 }
145
146 glBindVertexArray(vao);
147 glBindBuffer(GL_ARRAY_BUFFER, bufs[0]);
148 glBufferData(GL_ARRAY_BUFFER, 2 * 3 * nactive * sizeof(GLfloat), data, GL_STATIC_DRAW);
149 delete[] data;
150
151 // Transfer data
152 setActiveProgramAndUniforms(Shader_Line);
153 glUniform4f(uniformLocations.line_color, 0.3, 0.3, 0.4, 0.7);
154
155 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufs[1]);
156 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
157 glEnableVertexAttribArray(0);
158 glDrawElements(GL_LINES, (2 * nactive), GL_UNSIGNED_SHORT, (void *)0);
159 } else if (kind == WEATHER_SNOW) {
160 /** Draw SNOW particles **/
161 glDisable(GL_CULL_FACE);
162 glEnable(GL_BLEND);
163
164 int nactive = 0;
165 GLfloat h = player->position[2] - 5.0;
166 for (int i = 0; i < max_weather_particles; i++) {
167 // Note that < and >= or not opposite for nan
168 if (particles[i].position[2] < h) continue;
169 nactive++;
170 }
171 if (nactive <= 0) { return; }
172
173 GLfloat *data = new GLfloat[3 * 8 * nactive];
174
175 Color color(0.8, 0.8, 0.85, 1.);
176 GLfloat flat[3] = {0.f, 0.f, 0.f};
177 GLfloat txc[3][2] = {{0.5f, 0.f}, {0.f, 1.f}, {1.f, 1.f}};
178 GLfloat size = 1.3f;
179
180 char *pos = (char *)data;
181 for (int i = 0; i < max_weather_particles; i++) {
182 const Particle &p = particles[i];
183 if (p.position[2] < h) continue;
184 for (int k = 0; k < 3; k++) {
185 pos += packObjectVertex(pos, p.position[0] + p.corners[k][0] * size,
186 p.position[1] + p.corners[k][1] * size,
187 p.position[2] + p.corners[k][2] * size, txc[k][0], txc[k][1],
188 color, flat);
189 }
190 }
191
192 // Transfer data
193 glBindVertexArray(vao);
194 glBindBuffer(GL_ARRAY_BUFFER, bufs[0]);
195 glBufferData(GL_ARRAY_BUFFER, 3 * 8 * nactive * sizeof(GLfloat), data, GL_STATIC_DRAW);
196 delete[] data;
197
198 setActiveProgramAndUniforms(Shader_Object);
199 setObjectUniforms(Color(0., 0., 0., 1.), 1., Lighting_None);
200 glBindTexture(GL_TEXTURE_2D, textureGlitter);
201
202 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufs[1]);
203
204 configureObjectAttributes();
205 glDrawElements(GL_TRIANGLES, 3 * nactive, GL_UNSIGNED_SHORT, (void *)0);
206 }
207 }
208
clear()209 void Weather::clear() {
210 // Zero in case of changes
211 memset(particles, 0, sizeof(particles));
212 for (int i = 0; i < max_weather_particles; i++) { particles[i].position[2] = -10.0; }
213 next = 0;
214 nextSnowDrift = 0;
215 strength = -1.0;
216 }
217
snow(double s)218 void Weather::snow(double s) {
219 kind = WEATHER_SNOW;
220 strength = s;
221 if (strength < 0.0) strength = 0.0;
222 if (strength > 1.0) strength = 1.0;
223 }
rain(double s)224 void Weather::rain(double s) {
225 kind = WEATHER_RAIN;
226 strength = s;
227 if (strength < 0.0) strength = 0.0;
228 if (strength > 1.0) strength = 1.0;
229 }
230