1 #include <GL/glew.h>
2 #include <SFML/OpenGL.hpp>
3 #include "beamEffect.h"
4 #include "spaceship.h"
5 #include "mesh.h"
6 #include "main.h"
7 
8 #include "shaderRegistry.h"
9 
10 #if FEATURE_3D_RENDERING
11 struct VertexAndTexCoords
12 {
13     sf::Vector3f vertex;
14     sf::Vector2f texcoords;
15 };
16 #endif
17 
18 /// BeamEffect is a beam weapon fire effect that will fade after 1 seond
19 /// Example: BeamEffect():setSource(player):setTarget(enemy_ship)
REGISTER_SCRIPT_SUBCLASS(BeamEffect,SpaceObject)20 REGISTER_SCRIPT_SUBCLASS(BeamEffect, SpaceObject)
21 {
22     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setSource);
23     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setTarget);
24     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setTexture);
25     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setBeamFireSound);
26     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setBeamFireSoundPower);
27     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setDuration);
28     REGISTER_SCRIPT_CLASS_FUNCTION(BeamEffect, setRing);
29 }
30 
31 REGISTER_MULTIPLAYER_CLASS(BeamEffect, "BeamEffect");
BeamEffect()32 BeamEffect::BeamEffect()
33 : SpaceObject(1000, "BeamEffect")
34 {
35     has_weight = false;
36     setRadarSignatureInfo(0.0, 0.3, 0.0);
37     setCollisionRadius(1.0);
38     lifetime = 1.0;
39     sourceId = -1;
40     target_id = -1;
41     beam_texture = "beam_orange.png";
42     beam_fire_sound = "sfx/laser_fire.wav";
43     beam_fire_sound_power = 1;
44     beam_sound_played = false;
45     fire_ring = true;
46     registerMemberReplication(&lifetime, 0.1);
47     registerMemberReplication(&sourceId);
48     registerMemberReplication(&target_id);
49     registerMemberReplication(&sourceOffset);
50     registerMemberReplication(&targetOffset);
51     registerMemberReplication(&targetLocation, 1.0);
52     registerMemberReplication(&hitNormal);
53     registerMemberReplication(&beam_texture);
54     registerMemberReplication(&beam_fire_sound);
55     registerMemberReplication(&beam_fire_sound_power);
56     registerMemberReplication(&fire_ring);
57 }
58 
59 //due to a suspected compiler bug this deconstructor needs to be explicitly defined
~BeamEffect()60 BeamEffect::~BeamEffect()
61 {
62 }
63 
64 #if FEATURE_3D_RENDERING
draw3DTransparent()65 void BeamEffect::draw3DTransparent()
66 {
67     glTranslatef(-getPosition().x, -getPosition().y, 0);
68     sf::Vector3f startPoint(getPosition().x, getPosition().y, sourceOffset.z);
69     sf::Vector3f endPoint(targetLocation.x, targetLocation.y, targetOffset.z);
70     sf::Vector3f eyeNormal = sf::normalize(sf::cross(camera_position - startPoint, endPoint - startPoint));
71 
72     glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(beam_texture)->getNativeHandle());
73 
74     ShaderRegistry::ScopedShader beamShader(ShaderRegistry::Shaders::Basic);
75 
76     glUniform4f(beamShader.get().uniform(ShaderRegistry::Uniforms::Color), lifetime, lifetime, lifetime, 1.f);
77 
78     gl::ScopedVertexAttribArray positions(beamShader.get().attribute(ShaderRegistry::Attributes::Position));
79     gl::ScopedVertexAttribArray texcoords(beamShader.get().attribute(ShaderRegistry::Attributes::Texcoords));
80 
81     std::array<VertexAndTexCoords, 4> quad;
82     // Beam
83     {
84         sf::Vector3f v0 = startPoint + eyeNormal * 4.0f;
85         sf::Vector3f v1 = endPoint + eyeNormal * 4.0f;
86         sf::Vector3f v2 = endPoint - eyeNormal * 4.0f;
87         sf::Vector3f v3 = startPoint - eyeNormal * 4.0f;
88         quad[0].vertex = v0;
89         quad[0].texcoords = { 0.f, 0.f };
90         quad[1].vertex = v1;
91         quad[1].texcoords = { 0.f, 1.f };
92         quad[2].vertex = v2;
93         quad[2].texcoords = { 1.f, 1.f };
94         quad[3].vertex = v3;
95         quad[3].texcoords = { 1.f, 0.f };
96 
97         glVertexAttribPointer(positions.get(), 3, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)quad.data());
98         glVertexAttribPointer(texcoords.get(), 2, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)((char*)quad.data() + sizeof(sf::Vector3f)));
99         // Draw the beam
100         std::initializer_list<uint8_t> indices = { 0, 1, 2, 2, 3, 0 };
101         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, std::begin(indices));
102 
103     }
104 
105     // Fire ring
106     if (fire_ring)
107     {
108         sf::Vector3f side = sf::cross(hitNormal, sf::Vector3f(0, 0, 1));
109         sf::Vector3f up = sf::cross(side, hitNormal);
110 
111         sf::Vector3f v0(targetLocation.x, targetLocation.y, targetOffset.z);
112 
113         float ring_size = Tween<float>::easeOutCubic(lifetime, 1.0, 0.0, 10.0f, 80.0f);
114         sf::Vector3f v1 = v0 + side * ring_size + up * ring_size;
115         sf::Vector3f v2 = v0 - side * ring_size + up * ring_size;
116         sf::Vector3f v3 = v0 - side * ring_size - up * ring_size;
117         sf::Vector3f v4 = v0 + side * ring_size - up * ring_size;
118 
119         quad[0].vertex = v1;
120         quad[0].texcoords = { 0.f, 0.f };
121         quad[1].vertex = v2;
122         quad[1].texcoords = { 1.f, 0.f };
123         quad[2].vertex = v3;
124         quad[2].texcoords = { 1.f, 1.f };
125         quad[3].vertex = v4;
126         quad[3].texcoords = { 0.f, 1.f };
127 
128         glBindTexture(GL_TEXTURE_2D, textureManager.getTexture("fire_ring.png")->getNativeHandle());
129         glVertexAttribPointer(positions.get(), 3, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)quad.data());
130         glVertexAttribPointer(texcoords.get(), 2, GL_FLOAT, GL_FALSE, sizeof(VertexAndTexCoords), (GLvoid*)((char*)quad.data() + sizeof(sf::Vector3f)));
131         std::initializer_list<uint8_t> indices = { 0, 1, 2, 2, 3, 0 };
132         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, std::begin(indices));
133     }
134 }
135 #endif//FEATURE_3D_RENDERING
136 
update(float delta)137 void BeamEffect::update(float delta)
138 {
139     P<SpaceObject> source, target;
140     if (game_server)
141     {
142         source = game_server->getObjectById(sourceId);
143         target = game_server->getObjectById(target_id);
144     }else{
145         source = game_client->getObjectById(sourceId);
146         target = game_client->getObjectById(target_id);
147     }
148     if (source)
149         setPosition(source->getPosition() + rotateVector(sf::Vector2f(sourceOffset.x, sourceOffset.y), source->getRotation()));
150     if (target)
151         targetLocation = target->getPosition() + sf::Vector2f(targetOffset.x, targetOffset.y);
152 
153     if (source && delta > 0 && !beam_sound_played)
154     {
155         float volume = 50.0f + (beam_fire_sound_power * 75.0f);
156         float pitch = (1.0f / beam_fire_sound_power) + random(-0.1f, 0.1f);
157         soundManager->playSound(beam_fire_sound, source->getPosition(), 400.0, 60.0, pitch, volume);
158         beam_sound_played = true;
159     }
160 
161     lifetime -= delta;
162     if (lifetime < 0)
163         destroy();
164 }
165 
setSource(P<SpaceObject> source,sf::Vector3f offset)166 void BeamEffect::setSource(P<SpaceObject> source, sf::Vector3f offset)
167 {
168     sourceId = source->getMultiplayerId();
169     sourceOffset = offset;
170     update(0);
171 }
172 
setTarget(P<SpaceObject> target,sf::Vector2f hitLocation)173 void BeamEffect::setTarget(P<SpaceObject> target, sf::Vector2f hitLocation)
174 {
175     target_id = target->getMultiplayerId();
176     float r = target->getRadius();
177     hitLocation -= target->getPosition();
178     targetOffset = sf::Vector3f(hitLocation.x + random(-r/2.0, r/2.0), hitLocation.y + random(-r/2.0, r/2.0), random(-r/4.0, r/4.0));
179 
180     if (target->hasShield())
181         targetOffset = sf::normalize(targetOffset) * r;
182     else
183         targetOffset = sf::normalize(targetOffset) * random(0, r / 2.0);
184     update(0);
185 
186     sf::Vector3f hitPos(targetLocation.x, targetLocation.y, targetOffset.z);
187     sf::Vector3f targetPos(target->getPosition().x, target->getPosition().y, 0);
188     hitNormal = sf::normalize(targetPos - hitPos);
189 }
190