1 #include <GL/glew.h>
2 #include <SFML/OpenGL.hpp>
3 
4 #include "main.h"
5 #include "nebula.h"
6 #include "playerInfo.h"
7 
8 #include "scriptInterface.h"
9 
10 #include "glObjects.h"
11 #include "shaderRegistry.h"
12 
13 #if FEATURE_3D_RENDERING
14 struct VertexAndTexCoords
15 {
16     sf::Vector3f vertex;
17     sf::Vector2f texcoords;
18 };
19 #endif
20 
21 
22 /// Nebulae block long-range radar in a 5U range.
REGISTER_SCRIPT_SUBCLASS(Nebula,SpaceObject)23 REGISTER_SCRIPT_SUBCLASS(Nebula, SpaceObject)
24 {
25 }
26 
27 PVector<Nebula> Nebula::nebula_list;
28 
29 REGISTER_MULTIPLAYER_CLASS(Nebula, "Nebula")
Nebula()30 Nebula::Nebula()
31 : SpaceObject(5000, "Nebula")
32 {
33     // Nebulae need a large radius to render properly from a distance, but
34     // collision isn't important, so set the collision radius to a tiny range.
35     setCollisionRadius(1);
36     setRotation(random(0, 360));
37     radar_visual = irandom(1, 3);
38     setRadarSignatureInfo(0.0, 0.8, -1.0);
39 
40     registerMemberReplication(&radar_visual);
41 
42     for(int n=0; n<cloud_count; n++)
43     {
44         clouds[n].size = random(512, 1024 * 2);
45         clouds[n].texture = irandom(1, 3);
46         float dist_min = clouds[n].size / 2.0f;
47         float dist_max = getRadius() - clouds[n].size;
48         clouds[n].offset = sf::vector2FromAngle(float(n * 360 / cloud_count)) * random(dist_min, dist_max);
49     }
50 
51     nebula_list.push_back(this);
52 }
53 
54 #if FEATURE_3D_RENDERING
draw3DTransparent()55 void Nebula::draw3DTransparent()
56 {
57     ShaderRegistry::ScopedShader shader(ShaderRegistry::Shaders::Billboard);
58     glTranslatef(-getPosition().x, -getPosition().y, 0);
59 
60     std::array<VertexAndTexCoords, 4> quad{
61         sf::Vector3f(), {0.f, 1.f},
62         sf::Vector3f(), {1.f, 1.f},
63         sf::Vector3f(), {1.f, 0.f},
64         sf::Vector3f(), {0.f, 0.f}
65     };
66 
67     gl::ScopedVertexAttribArray positions(shader.get().attribute(ShaderRegistry::Attributes::Position));
68     gl::ScopedVertexAttribArray texcoords(shader.get().attribute(ShaderRegistry::Attributes::Texcoords));
69 
70     for(int n=0; n<cloud_count; n++)
71     {
72         NebulaCloud& cloud = clouds[n];
73 
74         sf::Vector3f position = sf::Vector3f(getPosition().x, getPosition().y, 0) + sf::Vector3f(cloud.offset.x, cloud.offset.y, 0);
75         float size = cloud.size;
76 
77         float distance = sf::length(camera_position - position);
78         float alpha = 1.0 - (distance / 10000.0f);
79         if (alpha < 0.0)
80             continue;
81 
82         // setup our quad.
83         for (auto& point : quad)
84         {
85             point.vertex = position;
86         }
87 
88         glBindTexture(GL_TEXTURE_2D, textureManager.getTexture("Nebula" + string(cloud.texture) + ".png")->getNativeHandle());
89         glUniform4f(shader.get().uniform(ShaderRegistry::Uniforms::Color), alpha * 0.8f, alpha * 0.8f, alpha * 0.8f, size);
90 
91         glVertexAttribPointer(positions.get(), 3, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)quad.data());
92         glVertexAttribPointer(texcoords.get(), 2, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)((char*)quad.data() + sizeof(sf::Vector3f)));
93         std::initializer_list<uint8_t> indices = { 0, 3, 2, 0, 2, 1 };
94         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, std::begin(indices));
95     }
96 }
97 #endif//FEATURE_3D_RENDERING
98 
drawOnRadar(sf::RenderTarget & window,sf::Vector2f position,float scale,float rotation,bool long_range)99 void Nebula::drawOnRadar(sf::RenderTarget& window, sf::Vector2f position, float scale, float rotation, bool long_range)
100 {
101     sf::Sprite object_sprite;
102     textureManager.setTexture(object_sprite, "Nebula" + string(radar_visual) + ".png");
103     object_sprite.setRotation(getRotation()-rotation);
104     object_sprite.setPosition(position);
105     float size = getRadius() * scale / object_sprite.getTextureRect().width * 3.0;
106     object_sprite.setScale(size, size);
107     object_sprite.setColor(sf::Color(255, 255, 255));
108     window.draw(object_sprite, sf::BlendAdd);
109 }
110 
drawOnGMRadar(sf::RenderTarget & window,sf::Vector2f position,float scale,float rotation,bool long_range)111 void Nebula::drawOnGMRadar(sf::RenderTarget& window, sf::Vector2f position, float scale, float rotation, bool long_range)
112 {
113     sf::CircleShape range_circle(getRadius() * scale);
114     range_circle.setOrigin(getRadius() * scale, getRadius() * scale);
115     range_circle.setPosition(position);
116     range_circle.setFillColor(sf::Color::Transparent);
117     range_circle.setOutlineColor(sf::Color(255, 255, 255, 64));
118     range_circle.setOutlineThickness(2.0);
119     window.draw(range_circle);
120 }
121 
inNebula(sf::Vector2f position)122 bool Nebula::inNebula(sf::Vector2f position)
123 {
124     foreach(Nebula, n, nebula_list)
125     {
126         if ((n->getPosition() - position) < n->getRadius())
127             return true;
128     }
129     return false;
130 }
131 
blockedByNebula(sf::Vector2f start,sf::Vector2f end,float radar_short_range)132 bool Nebula::blockedByNebula(sf::Vector2f start, sf::Vector2f end, float radar_short_range)
133 {
134     sf::Vector2f startEndDiff = end - start;
135     float startEndLength = sf::length(startEndDiff);
136     if (startEndLength < radar_short_range)
137         return false;
138 
139     foreach(Nebula, n, nebula_list)
140     {
141         //Calculate point q, which is a point on the line start-end that is closest to n->getPosition
142         float f = sf::dot(startEndDiff, n->getPosition() - start) / startEndLength;
143         if (f < 0.0f)
144             f = 0.0f;
145         if (f > startEndLength)
146             f = startEndLength;
147         sf::Vector2f q = start + startEndDiff / startEndLength * f;
148         if ((q - n->getPosition()) < n->getRadius())
149         {
150             return true;
151         }
152     }
153     return false;
154 }
155 
getFirstBlockedPosition(sf::Vector2f start,sf::Vector2f end)156 sf::Vector2f Nebula::getFirstBlockedPosition(sf::Vector2f start, sf::Vector2f end)
157 {
158     sf::Vector2f startEndDiff = end - start;
159     float startEndLength = sf::length(startEndDiff);
160     P<Nebula> first_nebula;
161     float first_nebula_f = startEndLength;
162     sf::Vector2f first_nebula_q;
163     foreach(Nebula, n, nebula_list)
164     {
165         float f = sf::dot(startEndDiff, n->getPosition() - start) / startEndLength;
166         if (f < 0.0)
167             f = 0;
168         sf::Vector2f q = start + startEndDiff / startEndLength * f;
169         if ((q - n->getPosition()) < n->getRadius())
170         {
171             if (!first_nebula || f < first_nebula_f)
172             {
173                 first_nebula = n;
174                 first_nebula_f = f;
175                 first_nebula_q = q;
176             }
177         }
178     }
179     if (!first_nebula)
180         return end;
181 
182     float d = sf::length(first_nebula_q - first_nebula->getPosition());
183     return first_nebula_q + sf::normalize(start - end) * sqrtf(first_nebula->getRadius() * first_nebula->getRadius() - d * d);
184 }
185 
getNebulas()186 PVector<Nebula> Nebula::getNebulas()
187 {
188     return nebula_list;
189 }
190