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