1 // Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details 2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt 3 4 #include "Thruster.h" 5 #include "BaseLoader.h" 6 #include "Easing.h" 7 #include "NodeVisitor.h" 8 #include "Serializer.h" 9 #include "graphics/Material.h" 10 #include "graphics/RenderState.h" 11 #include "graphics/Renderer.h" 12 #include "graphics/TextureBuilder.h" 13 #include "graphics/VertexArray.h" 14 15 namespace SceneGraph { 16 17 static const std::string thrusterTextureFilename("textures/thruster.dds"); 18 static const std::string thrusterGlowTextureFilename("textures/halo.dds"); 19 static Color baseColor(178, 153, 255, 255); 20 Thruster(Graphics::Renderer * r,bool _linear,const vector3f & _pos,const vector3f & _dir)21 Thruster::Thruster(Graphics::Renderer *r, bool _linear, const vector3f &_pos, const vector3f &_dir) : 22 Node(r, NODE_TRANSPARENT), 23 linearOnly(_linear), 24 dir(_dir), 25 pos(_pos), 26 currentColor(baseColor) 27 { 28 //set up materials 29 Graphics::MaterialDescriptor desc; 30 desc.textures = 1; 31 32 m_tMat.Reset(r->CreateMaterial(desc)); 33 m_tMat->texture0 = Graphics::TextureBuilder::Billboard(thrusterTextureFilename).GetOrCreateTexture(r, "billboard"); 34 m_tMat->diffuse = baseColor; 35 36 m_glowMat.Reset(r->CreateMaterial(desc)); 37 m_glowMat->texture0 = Graphics::TextureBuilder::Billboard(thrusterGlowTextureFilename).GetOrCreateTexture(r, "billboard"); 38 m_glowMat->diffuse = baseColor; 39 40 Graphics::RenderStateDesc rsd; 41 rsd.blendMode = Graphics::BLEND_ALPHA_ONE; 42 rsd.depthWrite = false; 43 rsd.cullMode = Graphics::CULL_NONE; 44 m_renderState = r->CreateRenderState(rsd); 45 } 46 Thruster(const Thruster & thruster,NodeCopyCache * cache)47 Thruster::Thruster(const Thruster &thruster, NodeCopyCache *cache) : 48 Node(thruster, cache), 49 m_tMat(thruster.m_tMat), 50 m_renderState(thruster.m_renderState), 51 linearOnly(thruster.linearOnly), 52 dir(thruster.dir), 53 pos(thruster.pos), 54 currentColor(thruster.currentColor) 55 { 56 } 57 Clone(NodeCopyCache * cache)58 Node *Thruster::Clone(NodeCopyCache *cache) 59 { 60 return this; //thrusters are shared 61 } 62 Accept(NodeVisitor & nv)63 void Thruster::Accept(NodeVisitor &nv) 64 { 65 nv.ApplyThruster(*this); 66 } 67 Render(const matrix4x4f & trans,const RenderData * rd)68 void Thruster::Render(const matrix4x4f &trans, const RenderData *rd) 69 { 70 PROFILE_SCOPED() 71 float power = -dir.Dot(vector3f(rd->linthrust)); 72 73 if (!linearOnly) { 74 // pitch X 75 // yaw Y 76 // roll Z 77 //model center is at 0,0,0, no need for invSubModelMat stuff 78 const vector3f at = vector3f(rd->angthrust); 79 const vector3f angdir = pos.Cross(dir); 80 81 const float xp = angdir.x * at.x; 82 const float yp = angdir.y * at.y; 83 const float zp = angdir.z * at.z; 84 85 if (xp + yp + zp > 0) { 86 if (xp > yp && xp > zp && fabs(at.x) > power) 87 power = fabs(at.x); 88 else if (yp > xp && yp > zp && fabs(at.y) > power) 89 power = fabs(at.y); 90 else if (zp > xp && zp > yp && fabs(at.z) > power) 91 power = fabs(at.z); 92 } 93 } 94 if (power < 0.001f) return; 95 96 m_tMat->diffuse = m_glowMat->diffuse = currentColor * power; 97 98 //directional fade 99 vector3f cdir = vector3f(trans * -dir).Normalized(); 100 vector3f vdir = vector3f(trans[2], trans[6], -trans[10]).Normalized(); 101 // XXX check this for transition to new colors. 102 m_glowMat->diffuse.a = Easing::Circ::EaseIn(Clamp(vdir.Dot(cdir), 0.f, 1.f), 0.f, 1.f, 1.f) * 255; 103 m_tMat->diffuse.a = 255 - m_glowMat->diffuse.a; 104 105 Graphics::Renderer *r = GetRenderer(); 106 if (!m_tBuffer.Valid()) { 107 m_tBuffer.Reset(CreateThrusterGeometry(r, m_tMat.Get())); 108 m_glowBuffer.Reset(CreateGlowGeometry(r, m_glowMat.Get())); 109 } 110 111 r->SetTransform(trans); 112 r->DrawBuffer(m_tBuffer.Get(), m_renderState, m_tMat.Get()); 113 r->DrawBuffer(m_glowBuffer.Get(), m_renderState, m_glowMat.Get()); 114 } 115 Save(NodeDatabase & db)116 void Thruster::Save(NodeDatabase &db) 117 { 118 Node::Save(db); 119 db.wr->Bool(linearOnly); 120 db.wr->Vector3f(dir); 121 db.wr->Vector3f(pos); 122 } 123 Load(NodeDatabase & db)124 Thruster *Thruster::Load(NodeDatabase &db) 125 { 126 const bool linear = db.rd->Bool(); 127 const vector3f dir = db.rd->Vector3f(); 128 const vector3f pos = db.rd->Vector3f(); 129 Thruster *t = new Thruster(db.loader->GetRenderer(), linear, pos, dir); 130 return t; 131 } 132 CreateThrusterGeometry(Graphics::Renderer * r,Graphics::Material * mat)133 Graphics::VertexBuffer *Thruster::CreateThrusterGeometry(Graphics::Renderer *r, Graphics::Material *mat) 134 { 135 Graphics::VertexArray verts(Graphics::ATTRIB_POSITION | Graphics::ATTRIB_UV0); 136 137 //zero at thruster center 138 //+x down 139 //+y right 140 //+z backwards (or thrust direction) 141 const float w = 0.5f; 142 143 vector3f one(0.f, -w, 0.f); //top left 144 vector3f two(0.f, w, 0.f); //top right 145 vector3f three(0.f, w, 1.f); //bottom right 146 vector3f four(0.f, -w, 1.f); //bottom left 147 148 //uv coords 149 const vector2f topLeft(0.f, 1.f); 150 const vector2f topRight(1.f, 1.f); 151 const vector2f botLeft(0.f, 0.f); 152 const vector2f botRight(1.f, 0.f); 153 154 //add four intersecting planes to create a volumetric effect 155 for (int i = 0; i < 4; i++) { 156 verts.Add(one, topLeft); 157 verts.Add(two, topRight); 158 verts.Add(three, botRight); 159 160 verts.Add(three, botRight); 161 verts.Add(four, botLeft); 162 verts.Add(one, topLeft); 163 164 one.ArbRotate(vector3f(0.f, 0.f, 1.f), DEG2RAD(45.f)); 165 two.ArbRotate(vector3f(0.f, 0.f, 1.f), DEG2RAD(45.f)); 166 three.ArbRotate(vector3f(0.f, 0.f, 1.f), DEG2RAD(45.f)); 167 four.ArbRotate(vector3f(0.f, 0.f, 1.f), DEG2RAD(45.f)); 168 } 169 170 //create buffer and upload data 171 Graphics::VertexBufferDesc vbd; 172 vbd.attrib[0].semantic = Graphics::ATTRIB_POSITION; 173 vbd.attrib[0].format = Graphics::ATTRIB_FORMAT_FLOAT3; 174 vbd.attrib[1].semantic = Graphics::ATTRIB_UV0; 175 vbd.attrib[1].format = Graphics::ATTRIB_FORMAT_FLOAT2; 176 vbd.numVertices = verts.GetNumVerts(); 177 vbd.usage = Graphics::BUFFER_USAGE_STATIC; 178 Graphics::VertexBuffer *vb = r->CreateVertexBuffer(vbd); 179 vb->Populate(verts); 180 181 return vb; 182 } 183 CreateGlowGeometry(Graphics::Renderer * r,Graphics::Material * mat)184 Graphics::VertexBuffer *Thruster::CreateGlowGeometry(Graphics::Renderer *r, Graphics::Material *mat) 185 { 186 Graphics::VertexArray verts(Graphics::ATTRIB_POSITION | Graphics::ATTRIB_UV0); 187 188 //create glow billboard for linear thrusters 189 const float w = 0.2; 190 191 vector3f one(-w, -w, 0.f); //top left 192 vector3f two(-w, w, 0.f); //top right 193 vector3f three(w, w, 0.f); //bottom right 194 vector3f four(w, -w, 0.f); //bottom left 195 196 //uv coords 197 const vector2f topLeft(0.f, 1.f); 198 const vector2f topRight(1.f, 1.f); 199 const vector2f botLeft(0.f, 0.f); 200 const vector2f botRight(1.f, 0.f); 201 202 for (int i = 0; i < 5; i++) { 203 verts.Add(one, topLeft); 204 verts.Add(two, topRight); 205 verts.Add(three, botRight); 206 207 verts.Add(three, botRight); 208 verts.Add(four, botLeft); 209 verts.Add(one, topLeft); 210 211 one.z += .1f; 212 two.z = three.z = four.z = one.z; 213 } 214 215 //create buffer and upload data 216 Graphics::VertexBufferDesc vbd; 217 vbd.attrib[0].semantic = Graphics::ATTRIB_POSITION; 218 vbd.attrib[0].format = Graphics::ATTRIB_FORMAT_FLOAT3; 219 vbd.attrib[1].semantic = Graphics::ATTRIB_UV0; 220 vbd.attrib[1].format = Graphics::ATTRIB_FORMAT_FLOAT2; 221 vbd.numVertices = verts.GetNumVerts(); 222 vbd.usage = Graphics::BUFFER_USAGE_STATIC; 223 Graphics::VertexBuffer *vb = r->CreateVertexBuffer(vbd); 224 vb->Populate(verts); 225 226 return vb; 227 } 228 229 } // namespace SceneGraph 230