1using System;
2using System.Drawing;
3using System.Drawing.Imaging;
4using System.Collections;
5using System.ComponentModel;
6using System.Windows.Forms;
7using System.Reflection;
8using System.IO;
9using System.Runtime.InteropServices;
10
11namespace TerraNova.PocketShArc
12{
13 /// <summary>
14 /// Summary description for SplashForm.
15 /// </summary>
16 public class SplashForm : System.Windows.Forms.Form
17 {
18 public static System.Drawing.Image GetImage(string name)
19 {
20 System.Reflection.Assembly ea = System.Reflection.Assembly.GetExecutingAssembly();
21 string resourceName = "TerraNova.Resources.Images." + name;
22 Stream stream = ea.GetManifestResourceStream(resourceName);
23 return new System.Drawing.Bitmap(stream);
24 }
25
26 /// <summary>
27 /// A hack constant specifying how many cells the animation has
28 /// </summary>
29 const int kNumAnimationCells = 8;
30
31 /// <summary>
32 /// Splash screen background bitmap
33 /// </summary>
34 Bitmap bmpSplash = null;
35
36 /// <summary>
37 /// Splash screen animation bitmap
38 /// </summary>
39 Bitmap bmpAnim = null;
40
41 /// <summary>
42 /// Current screen position of the animation
43 /// </summary>
44 Rectangle animPos = new Rectangle(0,0,0,0);
45
46 /// <summary>
47 /// Graphics object used to render splash screen.
48 /// Cached for performance.
49 /// </summary>
50 Graphics g = null;
51
52 /// <summary>
53 /// The region of the screen filled by the background.
54 /// Cached for performance.
55 /// </summary>
56 Rectangle splashRegion = new Rectangle(0,0,0,0);
57
58 /// <summary>
59 /// The source region of the background draw.
60 /// Cached for performance.
61 /// </summary>
62 Rectangle splashSrc = new Rectangle(0,0,0,0);
63
64 /// <summary>
65 /// Image attributes specifying transperancy color.
66 /// Cached for performance.
67 /// </summary>
68 ImageAttributes attr = new ImageAttributes();
69
70 /// <summary>
71 /// Timer used to update the screen at regular intervals.
72 /// </summary>
73 System.Threading.Timer splashTimer = null;
74
75 /// <summary>
76 /// Source region for redrawing the background.
77 /// Cached for performance.
78 /// </summary>
79 Rectangle redrawSrc = new Rectangle(0,0,0,0);
80
81 /// <summary>
82 /// Current cell being displayed in the animation.
83 /// </summary>
84 int curAnimCell = 0;
85
86 /// <summary>
87 /// The number of updates that the splash screen timer triggered.
88 /// </summary>
89 int numUpdates = 0;
90
91 /// <summary>
92 /// Time between screen updates (ms)
93 /// </summary>
94 int timerInterval_ms = 0;
95
96 /// <summary>
97 /// Constructor for the splash screen form. Creates the background
98 /// and animation Bitmap objects
99 /// </summary>
100 /// <param name="timerInterval">Length of time between screen updates (ms)</param>
101 public SplashForm(int timerInterval)
102 {
103 // Store the timer interval
104 timerInterval_ms = timerInterval;
105
106 // Load the embedded splash image resources
107 bmpSplash = new Bitmap(GetImage("ShArc.bmp"));
108 bmpAnim = new Bitmap(GetImage("anim.bmp"));
109
110 //
111 // Required for Windows Form Designer support
112 //
113 InitializeComponent();
114
115 }
116
117 /// <summary>
118 /// Clean up any resources being used.
119 /// </summary>
120 protected override void Dispose(bool disposing)
121 {
122 base.Dispose(disposing);
123 }
124 #region Windows Form Designer generated code ...
125
126 /// <summary>
127 /// Required method for Designer support - do not modify
128 /// the contents of this method with the code editor.
129 /// </summary>
130 private void InitializeComponent()
131 {
132 //
133 // SplashForm
134 //
135 this.Load += new System.EventHandler(this.SplashForm_Load);
136
137 }
138 #endregion
139
140 /// <summary>
141 /// Return the amount of time the splash screen has been displayed in
142 /// milliseconds. This is based on the number of times the timer has
143 /// triggered and the interval of the timer. This is not completely
144 /// accurate but good enough for the purposes of this function.
145 /// </summary>
146 /// <returns></returns>
147 public int GetUpMilliseconds()
148 {
149 return numUpdates * timerInterval_ms;
150 }
151
152 /// <summary>
153 /// The form is ready to be displayed so initialize all of the
154 /// splash screen data and draw the first frame.
155 /// </summary>
156 /// <param name="sender">Sending object</param>
157 /// <param name="e">Event arguments</param>
158 private void SplashForm_Load(object sender, System.EventArgs e)
159 {
160 // Make the form full screen
161 this.Text = "";
162 this.MaximizeBox = false;
163 this.MinimizeBox = false;
164 this.ControlBox = false;
165 this.FormBorderStyle = FormBorderStyle.None;
166 this.WindowState = FormWindowState.Maximized;
167 this.Menu = null;
168
169 // Center the splash screen background
170 splashRegion.X = (Screen.PrimaryScreen.Bounds.Width - bmpSplash.Width) / 2;
171 splashRegion.Y = (Screen.PrimaryScreen.Bounds.Height - bmpSplash.Height) / 2;
172 splashRegion.Width = bmpSplash.Width;
173 splashRegion.Height = bmpSplash.Height;
174
175 // Set up the rectangle from which the background will be drawn
176 splashSrc.X = 0;
177 splashSrc.Y = 0;
178 splashSrc.Width = bmpSplash.Width;
179 splashSrc.Height = bmpSplash.Height;
180
181 // Set up the destination region of the animatino draw
182 animPos.X = splashRegion.X - bmpAnim.Width / kNumAnimationCells;
183 animPos.Y = splashRegion.Y + splashRegion.Height - bmpAnim.Height;
184 animPos.Width = bmpAnim.Width / kNumAnimationCells;
185 animPos.Height = bmpAnim.Height;
186
187
188 // Initialize the draw region used to optimize animation updates
189 redrawSrc.Width = bmpAnim.Width / kNumAnimationCells;
190 redrawSrc.Height = bmpAnim.Height;
191
192 // Cache the transparent color
193 attr.SetColorKey(bmpAnim.GetPixel(0,0), bmpAnim.GetPixel(0,0));
194
195 // Create the graphics object and set its clipping region
196 g = CreateGraphics();
197 g.Clip = new Region(splashRegion);
198
199 // Draw the screen once with the full background update
200 // No need to use Application.DoEvents to force OnPaint.
201 Draw(true, false);
202
203 // Start a timer that will call Draw every 200 ms
204 System.Threading.TimerCallback splashDelegate = new System.Threading.TimerCallback(this.Draw);
205 this.splashTimer = new System.Threading.Timer(splashDelegate, null, timerInterval_ms, timerInterval_ms);
206 }
207
208 /// <summary>
209 /// If a paint event is generated then redraw the splash screen
210 /// </summary>
211 /// <param name="e"></param>
212 protected override void OnPaint(PaintEventArgs e)
213 {
214 Draw(true, false);
215 }
216
217 /// <summary>
218 /// Do not respond to paint background events
219 /// </summary>
220 /// <param name="e"></param>
221 protected override void OnPaintBackground(PaintEventArgs e){}
222
223 /// <summary>
224 /// Kill this form
225 /// </summary>
226 /// <param name="o">Not used</param>
227 /// <param name="e">Not used</param>
228 public void KillMe(object o, EventArgs e)
229 {
230 // Stop the timer first so there are no racing issues
231 splashTimer.Dispose();
232
233 // Shut down the form
234 this.Close();
235 }
236
237 /// <summary>
238 /// Draw the screen. This is the callback for the timer
239 /// </summary>
240 /// <param name="state">Not used - timer data</param>
241 protected void Draw(Object state)
242 {
243 numUpdates++;
244
245 Draw(false, true);
246 }
247
248 /// <summary>
249 /// Draw the screen
250 /// </summary>
251 /// <param name="bFullImage">true if the entire background should be updated</param>
252 /// <param name="bUpdateAnim">true if the animation position and cell should be updated</param>
253 protected void Draw(bool bFullImage, bool bUpdateAnim)
254 {
255 if (g == null)
256 return;
257
258 // Make sure it is safe to access the form
259 lock (this)
260 {
261 // Draw the background
262 if (bFullImage)
263 {
264 g.DrawImage(bmpSplash, splashRegion, splashSrc, GraphicsUnit.Pixel);
265 }
266 else if (bUpdateAnim)
267 {
268 // If not drawing the full background then only upate the
269 // location of the animation
270 redrawSrc.X = animPos.X - splashRegion.X;
271 redrawSrc.Y = animPos.Y - splashRegion.Y;
272 g.DrawImage(bmpSplash, animPos, redrawSrc, GraphicsUnit.Pixel);
273 }
274
275 if (bUpdateAnim)
276 {
277 // Update the current animation cell
278 curAnimCell++;
279 if (curAnimCell >= kNumAnimationCells)
280 curAnimCell = 0;
281
282 // Move the animation (yes hard-coded for the example)
283 animPos.X += 5;
284 if (animPos.X > splashRegion.X + splashRegion.Width)
285 animPos.X = splashRegion.X - bmpAnim.Width / kNumAnimationCells;
286 }
287
288 // Draw the animation
289 g.DrawImage(bmpAnim, animPos, curAnimCell * bmpAnim.Width / kNumAnimationCells, 0, bmpAnim.Width / kNumAnimationCells, bmpAnim.Height, GraphicsUnit.Pixel, attr);
290 }
291 }
292 }
293}
294