1 #include <GL/glew.h>
2 #include <SFML/OpenGL.hpp>
3
4 #include "main.h"
5 #include "wormHole.h"
6 #include "spaceship.h"
7 #include "scriptInterface.h"
8
9 #include "glObjects.h"
10 #include "shaderRegistry.h"
11
12 #define FORCE_MULTIPLIER 50.0
13 #define FORCE_MAX 10000.0
14 #define ALPHA_MULTIPLIER 10.0
15 #define DEFAULT_COLLISION_RADIUS 2500
16 #define AVOIDANCE_MULTIPLIER 1.2
17 #define TARGET_SPREAD 500
18
19 #if FEATURE_3D_RENDERING
20 struct VertexAndTexCoords
21 {
22 sf::Vector3f vertex;
23 sf::Vector2f texcoords;
24 };
25 #endif
26
27 /// A wormhole object that drags objects toward it like a black hole, and then
28 /// teleports them to another point when they reach its center.
REGISTER_SCRIPT_SUBCLASS(WormHole,SpaceObject)29 REGISTER_SCRIPT_SUBCLASS(WormHole, SpaceObject)
30 {
31 /// Set the target of this wormhole
32 REGISTER_SCRIPT_CLASS_FUNCTION(WormHole, setTargetPosition);
33 REGISTER_SCRIPT_CLASS_FUNCTION(WormHole, getTargetPosition);
34 /// Set a function that will be called if a SpaceObject is teleported.
35 /// First argument given to the function will be the WormHole, the second the SpaceObject that has been teleported.
36 REGISTER_SCRIPT_CLASS_FUNCTION(WormHole, onTeleportation);
37 }
38
39 REGISTER_MULTIPLAYER_CLASS(WormHole, "WormHole");
WormHole()40 WormHole::WormHole()
41 : SpaceObject(DEFAULT_COLLISION_RADIUS, "WormHole")
42 {
43 pathPlanner = PathPlannerManager::getInstance();
44 pathPlanner->addAvoidObject(this, (DEFAULT_COLLISION_RADIUS * AVOIDANCE_MULTIPLIER) );
45
46 setRadarSignatureInfo(0.9, 0.0, 0.0);
47
48 // Choose a texture to show on radar
49 radar_visual = irandom(1, 3);
50 registerMemberReplication(&radar_visual);
51
52 // Create some overlaying clouds
53 for(int n=0; n<cloud_count; n++)
54 {
55 clouds[n].size = random(1024, 1024 * 4);
56 clouds[n].texture = irandom(1, 3);
57 clouds[n].offset = sf::Vector2f(0, 0);
58 }
59 }
60
61 #if FEATURE_3D_RENDERING
draw3DTransparent()62 void WormHole::draw3DTransparent()
63 {
64 ShaderRegistry::ScopedShader shader(ShaderRegistry::Shaders::Billboard);
65 glTranslatef(-getPosition().x, -getPosition().y, 0);
66
67 std::array<VertexAndTexCoords, 4> quad{
68 sf::Vector3f(), {0.f, 1.f},
69 sf::Vector3f(), {1.f, 1.f},
70 sf::Vector3f(), {1.f, 0.f},
71 sf::Vector3f(), {0.f, 0.f}
72 };
73
74 gl::ScopedVertexAttribArray positions(shader.get().attribute(ShaderRegistry::Attributes::Position));
75 gl::ScopedVertexAttribArray texcoords(shader.get().attribute(ShaderRegistry::Attributes::Texcoords));
76
77 for(int n=0; n<cloud_count; n++)
78 {
79 NebulaCloud& cloud = clouds[n];
80
81 sf::Vector3f position = sf::Vector3f(getPosition().x, getPosition().y, 0) + sf::Vector3f(cloud.offset.x, cloud.offset.y, 0);
82 float size = cloud.size;
83
84 float distance = sf::length(camera_position - position);
85 float alpha = 1.0 - (distance / 10000.0f);
86 if (alpha < 0.0)
87 continue;
88
89 glBindTexture(GL_TEXTURE_2D, textureManager.getTexture("wormHole" + string(cloud.texture) + ".png")->getNativeHandle());
90 glUniform4f(shader.get().uniform(ShaderRegistry::Uniforms::Color), alpha * 0.8f, alpha * 0.8f, alpha * 0.8f, size);
91
92 glVertexAttribPointer(positions.get(), 3, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)quad.data());
93 glVertexAttribPointer(texcoords.get(), 2, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)((char*)quad.data() + sizeof(sf::Vector3f)));
94 std::initializer_list<uint8_t> indices = { 0, 2, 1, 0, 3, 2 };
95 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, std::begin(indices));
96 }
97 }
98 #endif//FEATURE_3D_RENDERING
99
100
drawOnRadar(sf::RenderTarget & window,sf::Vector2f position,float scale,float rotation,bool long_range)101 void WormHole::drawOnRadar(sf::RenderTarget& window, sf::Vector2f position, float scale, float rotation, bool long_range)
102 {
103 sf::Sprite object_sprite;
104 textureManager.setTexture(object_sprite, "wormHole" + string(radar_visual) + ".png");
105 object_sprite.setRotation(getRotation());
106 object_sprite.setPosition(position);
107 float size = getRadius() * scale / object_sprite.getTextureRect().width * 3.0;
108 object_sprite.setScale(size, size);
109 object_sprite.setColor(sf::Color(255, 255, 255));
110 window.draw(object_sprite, sf::RenderStates(sf::BlendAdd));
111 }
112
113 // Draw a line toward the target position
drawOnGMRadar(sf::RenderTarget & window,sf::Vector2f position,float scale,float rotation,bool long_range)114 void WormHole::drawOnGMRadar(sf::RenderTarget& window, sf::Vector2f position, float scale, float rotation, bool long_range)
115 {
116 sf::VertexArray a(sf::Lines, 2);
117 a[0].position = position;
118 a[1].position = position + (target_position - getPosition()) * scale;
119 a[0].color = sf::Color(255, 255, 255, 32);
120 window.draw(a);
121
122 sf::CircleShape range_circle(getRadius() * scale);
123 range_circle.setOrigin(getRadius() * scale, getRadius() * scale);
124 range_circle.setPosition(position);
125 range_circle.setFillColor(sf::Color::Transparent);
126 range_circle.setOutlineColor(sf::Color(255, 255, 255, 32));
127 range_circle.setOutlineThickness(2.0);
128 window.draw(range_circle);
129 }
130
131
update(float delta)132 void WormHole::update(float delta)
133 {
134 update_delta = delta;
135 }
136
collide(Collisionable * target,float collision_force)137 void WormHole::collide(Collisionable* target, float collision_force)
138 {
139 if (update_delta == 0.0)
140 return;
141
142 P<SpaceObject> obj = P<Collisionable>(target);
143 if (!obj) return;
144 if (!obj->hasWeight()) { return; } // the object is not affected by gravitation
145
146 sf::Vector2f diff = getPosition() - target->getPosition();
147 float distance = sf::length(diff);
148 float force = (getRadius() * getRadius() * FORCE_MULTIPLIER) / (distance * distance);
149
150 P<SpaceShip> spaceship = P<Collisionable>(target);
151
152 // Warp postprocessor-alpha is calculated using alpha = (1 - (delay/10))
153 if (spaceship)
154 spaceship->wormhole_alpha = ((distance / getRadius()) * ALPHA_MULTIPLIER);
155
156 if (force > FORCE_MAX)
157 {
158 force = FORCE_MAX;
159 if (isServer())
160 target->setPosition( (target_position +
161 sf::Vector2f(random(-TARGET_SPREAD, TARGET_SPREAD),
162 random(-TARGET_SPREAD, TARGET_SPREAD))));
163 if (on_teleportation.isSet())
164 {
165 on_teleportation.call<void>(P<WormHole>(this), obj);
166 }
167 if (spaceship)
168 {
169 spaceship->wormhole_alpha = 0.0;
170 }
171 }
172
173 // TODO: Escaping is impossible. Change setPosition to something Newtonianish.
174 target->setPosition(target->getPosition() + diff / distance * update_delta * force);
175 }
176
setTargetPosition(sf::Vector2f v)177 void WormHole::setTargetPosition(sf::Vector2f v)
178 {
179 target_position = v;
180 }
181
getTargetPosition()182 sf::Vector2f WormHole::getTargetPosition()
183 {
184 return target_position;
185 }
186
onTeleportation(ScriptSimpleCallback callback)187 void WormHole::onTeleportation(ScriptSimpleCallback callback)
188 {
189 this->on_teleportation = callback;
190 }
191