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