1 #include <GL/glew.h>
2 #include "planet.h"
3 #include <SFML/OpenGL.hpp>
4 #include "main.h"
5 #include "pathPlanner.h"
6
7 #include "scriptInterface.h"
8 #include "glObjects.h"
9 #include "shaderRegistry.h"
10
11 #include <glm/vec4.hpp>
12 #include <glm/gtc/type_ptr.hpp>
13
14 #if FEATURE_3D_RENDERING
15 struct VertexAndTexCoords
16 {
17 sf::Vector3f vertex;
18 sf::Vector2f texcoords;
19 };
20 #endif
21
22 static Mesh* planet_mesh[16];
23
24 class PlanetMeshGenerator
25 {
26 public:
27 std::vector<MeshVertex> vertices;
28 int max_iterations;
29
PlanetMeshGenerator(int iterations)30 PlanetMeshGenerator(int iterations)
31 {
32 max_iterations = iterations;
33
34 createFace(0, sf::Vector3f(0, 0, 1), sf::Vector3f(0, 1, 0), sf::Vector3f(1, 0, 0), sf::Vector2f(0, 0), sf::Vector2f(0, 0.5), sf::Vector2f(0.25, 0.5));
35 createFace(0, sf::Vector3f(0, 0, 1), sf::Vector3f(1, 0, 0), sf::Vector3f(0,-1, 0), sf::Vector2f(0.25, 0), sf::Vector2f(0.25, 0.5), sf::Vector2f(0.5, 0.5));
36 createFace(0, sf::Vector3f(0, 0, 1), sf::Vector3f(0,-1, 0), sf::Vector3f(-1, 0, 0), sf::Vector2f(0.5, 0), sf::Vector2f(0.5, 0.5), sf::Vector2f(0.75, 0.5));
37 createFace(0, sf::Vector3f(0, 0, 1), sf::Vector3f(-1, 0, 0), sf::Vector3f(0, 1, 0), sf::Vector2f(0.75, 0), sf::Vector2f(0.75, 0.5), sf::Vector2f(1.0, 0.5));
38
39 createFace(0, sf::Vector3f(0, 0,-1), sf::Vector3f(1, 0, 0), sf::Vector3f(0, 1, 0), sf::Vector2f(0, 1.0), sf::Vector2f(0.25, 0.5), sf::Vector2f(0.0, 0.5));
40 createFace(0, sf::Vector3f(0, 0,-1), sf::Vector3f(0,-1, 0), sf::Vector3f(1, 0, 0), sf::Vector2f(0.25, 1.0), sf::Vector2f(0.5, 0.5), sf::Vector2f(0.25, 0.5));
41 createFace(0, sf::Vector3f(0, 0,-1), sf::Vector3f(-1, 0, 0), sf::Vector3f(0,-1, 0), sf::Vector2f(0.5, 1.0), sf::Vector2f(0.75, 0.5), sf::Vector2f(0.5, 0.5));
42 createFace(0, sf::Vector3f(0, 0,-1), sf::Vector3f(0,1, 0), sf::Vector3f(-1, 0, 0), sf::Vector2f(0.75, 1.0), sf::Vector2f(1.0, 0.5), sf::Vector2f(0.75, 0.5));
43
44 for(unsigned int n=0; n<vertices.size(); n++)
45 {
46 float u = sf::vector2ToAngle(sf::Vector2f(vertices[n].position[1], vertices[n].position[0])) / 360.0f;
47 if (u < 0.0f)
48 u = 1.0 + u;
49 if (std::abs(u - vertices[n].uv[0]) > 0.5)
50 u += 1.0f;
51 vertices[n].uv[0] = u;
52 vertices[n].uv[1] = 0.5 + sf::vector2ToAngle(sf::Vector2f(sf::length(sf::Vector2f(vertices[n].position[0], vertices[n].position[1])), vertices[n].position[2])) / 180.0f;
53 }
54 }
55
createFace(int iteration,sf::Vector3f v0,sf::Vector3f v1,sf::Vector3f v2,sf::Vector2f uv0,sf::Vector2f uv1,sf::Vector2f uv2)56 void createFace(int iteration, sf::Vector3f v0, sf::Vector3f v1, sf::Vector3f v2, sf::Vector2f uv0, sf::Vector2f uv1, sf::Vector2f uv2)
57 {
58 if (iteration < max_iterations)
59 {
60 sf::Vector3f v01 = v0 + v1;
61 sf::Vector3f v12 = v1 + v2;
62 sf::Vector3f v02 = v0 + v2;
63 sf::Vector2f uv01 = (uv0 + uv1) / 2.0f;
64 sf::Vector2f uv12 = (uv1 + uv2) / 2.0f;
65 sf::Vector2f uv02 = (uv0 + uv2) / 2.0f;
66 v01 /= sf::length(v01);
67 v12 /= sf::length(v12);
68 v02 /= sf::length(v02);
69 createFace(iteration + 1, v0, v01, v02, uv0, uv01, uv02);
70 createFace(iteration + 1, v01, v1, v12, uv01, uv1, uv12);
71 createFace(iteration + 1, v01, v12, v02, uv01, uv12, uv02);
72 createFace(iteration + 1, v2, v02, v12, uv2, uv02, uv12);
73 }else{
74 vertices.emplace_back();
75 vertices.back().position[0] = v0.x;
76 vertices.back().position[1] = v0.y;
77 vertices.back().position[2] = v0.z;
78 vertices.back().normal[0] = v0.x;
79 vertices.back().normal[1] = v0.y;
80 vertices.back().normal[2] = v0.z;
81 vertices.back().uv[0] = uv0.x;
82 vertices.back().uv[1] = uv0.y;
83
84 vertices.emplace_back();
85 vertices.back().position[0] = v1.x;
86 vertices.back().position[1] = v1.y;
87 vertices.back().position[2] = v1.z;
88 vertices.back().normal[0] = v1.x;
89 vertices.back().normal[1] = v1.y;
90 vertices.back().normal[2] = v1.z;
91 vertices.back().uv[0] = uv1.x;
92 vertices.back().uv[1] = uv1.y;
93
94 vertices.emplace_back();
95 vertices.back().position[0] = v2.x;
96 vertices.back().position[1] = v2.y;
97 vertices.back().position[2] = v2.z;
98 vertices.back().normal[0] = v2.x;
99 vertices.back().normal[1] = v2.y;
100 vertices.back().normal[2] = v2.z;
101 vertices.back().uv[0] = uv2.x;
102 vertices.back().uv[1] = uv2.y;
103 }
104 }
105 };
106
107 /// A planet.
REGISTER_SCRIPT_SUBCLASS(Planet,SpaceObject)108 REGISTER_SCRIPT_SUBCLASS(Planet, SpaceObject)
109 {
110 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setPlanetAtmosphereColor);
111 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setPlanetAtmosphereTexture);
112 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setPlanetSurfaceTexture);
113 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setPlanetCloudTexture);
114 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, getPlanetRadius);
115 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setPlanetRadius);
116 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, getCollisionSize);
117 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setPlanetCloudRadius);
118 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setDistanceFromMovementPlane);
119 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setAxialRotationTime);
120 REGISTER_SCRIPT_CLASS_FUNCTION(Planet, setOrbit);
121 }
122
123 REGISTER_MULTIPLAYER_CLASS(Planet, "Planet");
Planet()124 Planet::Planet()
125 : SpaceObject(5000, "Planet")
126 {
127 planet_size = 5000;
128 cloud_size = 5200;
129 planet_texture = "";
130 cloud_texture = "";
131 atmosphere_texture = "";
132 atmosphere_color = sf::Color(0, 0, 0);
133 atmosphere_size = 0;
134 distance_from_movement_plane = 0;
135 axial_rotation_time = 0.0;
136 orbit_target_id = -1;
137 orbit_time = 0.0f;
138 orbit_distance = 0.0f;
139
140 collision_size = -2.0f;
141
142 setRadarSignatureInfo(0.5, 0, 0.3);
143
144 registerMemberReplication(&planet_size);
145 registerMemberReplication(&cloud_size);
146 registerMemberReplication(&atmosphere_size);
147 registerMemberReplication(&planet_texture);
148 registerMemberReplication(&cloud_texture);
149 registerMemberReplication(&atmosphere_texture);
150 registerMemberReplication(&atmosphere_color);
151 registerMemberReplication(&distance_from_movement_plane);
152 registerMemberReplication(&axial_rotation_time);
153 registerMemberReplication(&orbit_target_id);
154 registerMemberReplication(&orbit_time);
155 registerMemberReplication(&orbit_distance);
156 }
157
setPlanetAtmosphereColor(float r,float g,float b)158 void Planet::setPlanetAtmosphereColor(float r, float g, float b)
159 {
160 atmosphere_color.r = r * 255;
161 atmosphere_color.g = g * 255;
162 atmosphere_color.b = b * 255;
163 }
164
setPlanetAtmosphereTexture(string texture_name)165 void Planet::setPlanetAtmosphereTexture(string texture_name)
166 {
167 atmosphere_texture = texture_name;
168 }
169
setPlanetSurfaceTexture(string texture_name)170 void Planet::setPlanetSurfaceTexture(string texture_name)
171 {
172 planet_texture = texture_name;
173 }
174
setPlanetCloudTexture(string texture_name)175 void Planet::setPlanetCloudTexture(string texture_name)
176 {
177 cloud_texture = texture_name;
178 }
179
getPlanetRadius()180 float Planet::getPlanetRadius()
181 {
182 return planet_size;
183 }
184
getCollisionSize()185 float Planet::getCollisionSize()
186 {
187 return collision_size;
188 }
189
setPlanetRadius(float size)190 void Planet::setPlanetRadius(float size)
191 {
192 this->planet_size = size;
193 this->cloud_size = size * 1.05;
194 this->atmosphere_size = size * 1.2;
195 }
196
setPlanetCloudRadius(float size)197 void Planet::setPlanetCloudRadius(float size)
198 {
199 cloud_size = size;
200 }
201
setDistanceFromMovementPlane(float distance_from_movement_plane)202 void Planet::setDistanceFromMovementPlane(float distance_from_movement_plane)
203 {
204 this->distance_from_movement_plane = distance_from_movement_plane;
205 }
206
setAxialRotationTime(float time)207 void Planet::setAxialRotationTime(float time)
208 {
209 axial_rotation_time = time;
210 }
211
setOrbit(P<SpaceObject> target,float orbit_time)212 void Planet::setOrbit(P<SpaceObject> target, float orbit_time)
213 {
214 if (!target)
215 return;
216 this->orbit_target_id = target->getMultiplayerId();
217 this->orbit_distance = sf::length(getPosition() - target->getPosition());
218 this->orbit_time = orbit_time;
219 }
220
update(float delta)221 void Planet::update(float delta)
222 {
223 if (collision_size == -2.0f)
224 {
225 updateCollisionSize();
226 if (collision_size > 0.0)
227 PathPlannerManager::getInstance()->addAvoidObject(this, collision_size);
228 }
229
230 if (orbit_distance > 0.0f)
231 {
232 P<SpaceObject> orbit_target;
233 if (game_server)
234 orbit_target = game_server->getObjectById(orbit_target_id);
235 else
236 orbit_target = game_client->getObjectById(orbit_target_id);
237 if (orbit_target)
238 {
239 float angle = sf::vector2ToAngle(getPosition() - orbit_target->getPosition());
240 angle += delta / orbit_time * 360.0f;
241 setPosition(orbit_target->getPosition() + sf::vector2FromAngle(angle) * orbit_distance);
242 }
243 }
244
245 if (axial_rotation_time != 0.0f)
246 setRotation(getRotation() + delta / axial_rotation_time * 360.0f);
247 }
248
249 #if FEATURE_3D_RENDERING
draw3D()250 void Planet::draw3D()
251 {
252 float distance = sf::length(camera_position - sf::Vector3f(getPosition().x, getPosition().y, distance_from_movement_plane));
253
254 //view_scale ~= about the size the planet is on the screen.
255 float view_scale = planet_size / distance;
256 int level_of_detail = 4;
257 if (view_scale < 0.01)
258 level_of_detail = 2;
259 if (view_scale < 0.1)
260 level_of_detail = 3;
261
262 if (planet_texture != "" && planet_size > 0)
263 {
264 glTranslatef(0, 0, distance_from_movement_plane);
265 glScalef(planet_size, planet_size, planet_size);
266
267 if (!planet_mesh[level_of_detail])
268 {
269 PlanetMeshGenerator planet_mesh_generator(level_of_detail);
270 planet_mesh[level_of_detail] = new Mesh(std::move(planet_mesh_generator.vertices));
271 }
272
273 ShaderRegistry::ScopedShader shader(ShaderRegistry::Shaders::Planet);
274
275 glUniform4f(shader.get().uniform(ShaderRegistry::Uniforms::Color), 1.f, 1.f, 1.f, 1.f);
276 glUniform4fv(shader.get().uniform(ShaderRegistry::Uniforms::AtmosphereColor), 1, glm::value_ptr(glm::vec4(atmosphere_color.r, atmosphere_color.g, atmosphere_color.b, atmosphere_color.a) / 255.f));
277 glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(planet_texture)->getNativeHandle());
278 {
279 gl::ScopedVertexAttribArray positions(shader.get().attribute(ShaderRegistry::Attributes::Position));
280 gl::ScopedVertexAttribArray texcoords(shader.get().attribute(ShaderRegistry::Attributes::Texcoords));
281 gl::ScopedVertexAttribArray normals(shader.get().attribute(ShaderRegistry::Attributes::Normal));
282
283 planet_mesh[level_of_detail]->render(positions.get(), texcoords.get(), normals.get());
284 }
285 }
286 }
287
draw3DTransparent()288 void Planet::draw3DTransparent()
289 {
290 float distance = sf::length(camera_position - sf::Vector3f(getPosition().x, getPosition().y, distance_from_movement_plane));
291
292 //view_scale ~= about the size the planet is on the screen.
293 float view_scale = planet_size / distance;
294 int level_of_detail = 4;
295 if (view_scale < 0.01)
296 level_of_detail = 2;
297 if (view_scale < 0.1)
298 level_of_detail = 3;
299
300 glTranslatef(0, 0, distance_from_movement_plane);
301 if (cloud_texture != "" && cloud_size > 0)
302 {
303 glPushMatrix();
304 glScalef(cloud_size, cloud_size, cloud_size);
305 glRotatef(engine->getElapsedTime() * 1.0f, 0, 0, 1);
306
307 if (!planet_mesh[level_of_detail])
308 {
309 PlanetMeshGenerator planet_mesh_generator(level_of_detail);
310 planet_mesh[level_of_detail] = new Mesh(std::move(planet_mesh_generator.vertices));
311 }
312
313 ShaderRegistry::ScopedShader shader(ShaderRegistry::Shaders::Planet);
314
315 glUniform4f(shader.get().uniform(ShaderRegistry::Uniforms::Color), 1.f, 1.f, 1.f, 1.f);
316 glUniform4fv(shader.get().uniform(ShaderRegistry::Uniforms::AtmosphereColor), 1, glm::value_ptr(glm::vec4(0.f)));
317
318 glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(cloud_texture)->getNativeHandle());
319 {
320 gl::ScopedVertexAttribArray positions(shader.get().attribute(ShaderRegistry::Attributes::Position));
321 gl::ScopedVertexAttribArray texcoords(shader.get().attribute(ShaderRegistry::Attributes::Texcoords));
322 gl::ScopedVertexAttribArray normals(shader.get().attribute(ShaderRegistry::Attributes::Normal));
323
324 planet_mesh[level_of_detail]->render(positions.get(), texcoords.get(), normals.get());
325 }
326 glPopMatrix();
327 }
328 if (atmosphere_texture != "" && atmosphere_size > 0)
329 {
330 static std::array<VertexAndTexCoords, 4> quad{
331 sf::Vector3f(), {0.f, 1.f},
332 sf::Vector3f(), {1.f, 1.f},
333 sf::Vector3f(), {1.f, 0.f},
334 sf::Vector3f(), {0.f, 0.f}
335 };
336
337 ShaderRegistry::ScopedShader shader(ShaderRegistry::Shaders::Billboard);
338
339 glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(atmosphere_texture)->getNativeHandle());
340 glm::vec4 color(glm::vec3(atmosphere_color.r, atmosphere_color.g, atmosphere_color.b) / 255.f, atmosphere_size * 2.0f);
341 glUniform4fv(shader.get().uniform(ShaderRegistry::Uniforms::Color), 1, glm::value_ptr(color));
342 gl::ScopedVertexAttribArray positions(shader.get().attribute(ShaderRegistry::Attributes::Position));
343 gl::ScopedVertexAttribArray texcoords(shader.get().attribute(ShaderRegistry::Attributes::Texcoords));
344
345 glVertexAttribPointer(positions.get(), 3, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)quad.data());
346 glVertexAttribPointer(texcoords.get(), 2, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)((char*)quad.data() + sizeof(sf::Vector3f)));
347
348 std::initializer_list<uint8_t> indices = { 0, 2, 1, 0, 3, 2 };
349 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, std::begin(indices));
350 }
351 }
352 #endif
353
drawOnRadar(sf::RenderTarget & window,sf::Vector2f position,float scale,float rotation,bool long_range)354 void Planet::drawOnRadar(sf::RenderTarget& window, sf::Vector2f position, float scale, float rotation, bool long_range)
355 {
356 if (collision_size > 0)
357 {
358 sf::CircleShape radar_radius(collision_size * scale);
359 radar_radius.setOrigin(collision_size * scale, collision_size * scale);
360 radar_radius.setPosition(position);
361 radar_radius.setFillColor(sf::Color(atmosphere_color.r, atmosphere_color.g, atmosphere_color.b, 128));
362 window.draw(radar_radius);
363 }
364 }
365
drawOnGMRadar(sf::RenderTarget & window,sf::Vector2f position,float scale,float rotation,bool long_range)366 void Planet::drawOnGMRadar(sf::RenderTarget& window, sf::Vector2f position, float scale, float rotation, bool long_range)
367 {
368 sf::CircleShape radar_radius(planet_size * scale);
369 radar_radius.setOrigin(planet_size * scale, planet_size * scale);
370 radar_radius.setPosition(position);
371 radar_radius.setFillColor(sf::Color::Transparent);
372 radar_radius.setOutlineColor(sf::Color(255, 255, 255, 128));
373 radar_radius.setOutlineThickness(3);
374 window.draw(radar_radius);
375 }
376
collide(Collisionable * target,float collision_force)377 void Planet::collide(Collisionable* target, float collision_force)
378 {
379 if (collision_size > 0)
380 {
381 //Something hit this planet...
382 }
383 }
384
updateCollisionSize()385 void Planet::updateCollisionSize()
386 {
387 setRadius(planet_size);
388 if (std::abs(distance_from_movement_plane) >= planet_size)
389 {
390 collision_size = -1.0;
391 }else{
392 collision_size = sqrt((planet_size * planet_size) - (distance_from_movement_plane * distance_from_movement_plane)) * 1.1f;
393 setCollisionRadius(collision_size);
394 setCollisionPhysics(true, true);
395 }
396 }
397
getExportLine()398 string Planet::getExportLine()
399 {
400 string ret="Planet():setPosition(" + string(getPosition().x, 0) + ", " + string(getPosition().y, 0) + "):setPlanetRadius(" + string(getPlanetRadius(), 0) + ")";
401 if (atmosphere_color.r != 0 || atmosphere_color.g != 0 || atmosphere_color.b != 0)
402 {
403 ret += ":setPlanetAtmosphereColor(" + string(atmosphere_color.r/255.0f) + "," + string(atmosphere_color.g/255.0f) + "," + string(atmosphere_color.b/255.0f) + ")";
404 }
405 if (distance_from_movement_plane!=0)
406 {
407 ret += ":setDistanceFromMovementPlane(" + string(distance_from_movement_plane) + ")";
408 }
409 //TODO setPlanetAtmosphereTexture
410 //TODO setPlanetSurfaceTexture
411 //TODO setPlanetCloudTexture
412 //TODO setPlanetCloudRadius
413 //TODO setAxialRotationTime
414 //TODO setOrbit
415 return ret;
416 }
417