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