Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ShieldRep.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: ShieldRep.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  ShieldRep Solid class
13 */
14 
15 #include "MemDebug.h"
16 #include "ShieldRep.h"
17 #include "Random.h"
18 
19 #include "Game.h"
20 #include "Light.h"
21 #include "Solid.h"
22 #include "Bitmap.h"
23 #include "Color.h"
24 #include "DataLoader.h"
25 
26 // +--------------------------------------------------------------------+
27 
28 const int MAX_SHIELD_HITS = 16;
29 
30 // +--------------------------------------------------------------------+
31 
32 struct ShieldHit
33 {
35  double damage;
36  double age;
38 
39  ShieldHit() : damage(0), age(0), shot(0) { }
40 };
41 
42 // +--------------------------------------------------------------------+
43 
45 {
46  bubble = false;
47  luminous = true;
48  trans = true;
49  nhits = 0;
50 
51  hits = new(__FILE__,__LINE__) ShieldHit[MAX_SHIELD_HITS];
52 }
53 
55 {
56  delete [] hits;
57 }
58 
59 // +--------------------------------------------------------------------+
60 
61 void
62 ShieldRep::Hit(Vec3 impact, Shot* shot, double damage)
63 {
64  if (!model || model->GetSurfaces().size() < 1)
65  return;
66 
67  // transform impact into object space:
68  Matrix xform(Orientation());
69 
70  Vec3 tmp = impact - loc;
71 
72  impact.x = tmp * Vec3(xform(0,0), xform(0,1), xform(0,2));
73  impact.y = tmp * Vec3(xform(1,0), xform(1,1), xform(1,2));
74  impact.z = tmp * Vec3(xform(2,0), xform(2,1), xform(2,2));
75 
76  // find slot to store the hit:
77  int i;
78  int slot = -1;
79  double age = -1;
80 
81  for (i = 0; i < MAX_SHIELD_HITS; i++) {
82  if (hits[i].shot == shot) {
83  slot = i;
84  break;
85  }
86  }
87 
88  if (slot < 0) {
89  for (i = 0; i < MAX_SHIELD_HITS; i++) {
90  if (hits[i].damage <= 0) {
91  slot = i;
92  break;
93  }
94 
95  if (hits[i].age > age) {
96  slot = i;
97  age = hits[i].age;
98  }
99  }
100  }
101 
102  if (slot >= 0 && slot < MAX_SHIELD_HITS) {
103  // record the hit in the slot:
104  hits[slot].hitloc = impact;
105  hits[slot].damage = damage;
106  hits[slot].age = 1;
107  hits[slot].shot = shot;
108 
109  if (nhits < MAX_SHIELD_HITS)
110  nhits++;
111  }
112 }
113 
114 // +--------------------------------------------------------------------+
115 
116 void
117 ShieldRep::Energize(double seconds, bool b)
118 {
119  bubble = b;
120 
121  if (nhits < 1) return;
122 
123  nhits = 0;
124 
125  for (int i = 0; i < MAX_SHIELD_HITS; i++) {
126  if (hits[i].damage > 0) {
127  // age the hit:
128  hits[i].age += seconds;
129  hits[i].damage -= (hits[i].damage * 4 * seconds);
130 
131  // collect garbage:
132  if (hits[i].damage < 10) {
133  hits[i].age = 0;
134  hits[i].damage = 0;
135  hits[i].shot = 0;
136  }
137  else {
138  nhits++;
139  }
140  }
141  }
142 }
143 
144 // +--------------------------------------------------------------------+
145 
146 void
148 {
149  true_eye_point = ref;
150  Solid::TranslateBy(ref);
151 }
152 
153 // +--------------------------------------------------------------------+
154 
155 void
157 {
158  if (!model) return;
159 
160  Surface* surf = model->GetSurfaces().first();
161  VertexSet* vset = surf->GetVertexSet();
162  int nverts = vset->nverts;
163 
164  for (int i = 0; i < nverts; i++) {
165  vset->diffuse[i] = 0;
166  vset->specular[i] = 0;
167  }
168 
169  double all_damage = 0;
170 
171  if (nhits < 1) return;
172 
173  for (int i = 0; i < MAX_SHIELD_HITS; i++) {
174  if (hits[i].damage > 0) {
175  // add the hit's contribution to the shield verts:
176  Vec3 hitloc = hits[i].hitloc;
177  double hitdam = hits[i].damage * 2000;
178 
179  all_damage += hits[i].damage;
180 
181  if (!bubble) {
182 
183  double limit = radius * radius;
184  if (hitdam > limit)
185  hitdam = limit;
186 
187  for (int v = 0; v < nverts; v++) {
188  double dist = (vset->loc[v] - hitloc).length();
189 
190  if (dist < 1)
191  dist = 1; // can't divide by zero!
192 
193  else
194  dist = pow(dist, 2.7);
195 
196  double pert = Random(0.1, 1.5);
197  double intensity = pert*hitdam/dist;
198 
199  if (intensity > 0.003)
200  vset->diffuse[v] = ((Color::White * intensity) + vset->diffuse[v]).Value();
201  }
202 
203  }
204  }
205  }
206 
207  if (bubble) {
208  double shield_gain = 1;
209 
210  if (all_damage < 1000) {
211  shield_gain = all_damage / 1000;
212  }
213 
214  for (int i = 0; i < nverts; i++) {
215  Vec3 vloc = (vset->loc[i] * orientation) + loc;
216  Vec3 vnrm = (vset->nrm[i] * orientation);
217 
218  Vec3 V = vloc * -1.0f;
219  V.Normalize();
220 
221  double intensity = 1 - V*vnrm;
222 
223  if (intensity > 0) {
224  intensity *= intensity;
225 
226  if (intensity > 1) intensity = 1;
227 
228  intensity *= (shield_gain * Random(0.75, 1.0));
229 
230  Color vs = Color::White * intensity;
231  vset->diffuse[i] = vs.Value();
232  }
233  }
234  }
235 
237 }
238 
239 void
240 ShieldRep::Render(Video* video, DWORD flags)
241 {
242  if ((flags & RENDER_ADDITIVE) == 0)
243  return;
244 
245  if (nhits > 0) {
246  Illuminate();
247  Solid::Render(video, RENDER_ALPHA); // have to lie about the render flag
248  // or the engine will reject the solid
249  }
250 }