corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28  
29 namespace OpenMetaverse.Imaging
30 {
31 public class ManagedImage
32 {
33 [Flags]
34 public enum ImageChannels
35 {
36 Gray = 1,
37 Color = 2,
38 Alpha = 4,
39 Bump = 8
40 };
41  
42 public enum ImageResizeAlgorithm
43 {
44 NearestNeighbor
45 }
46  
47 /// <summary>
48 /// Image width
49 /// </summary>
50 public int Width;
51  
52 /// <summary>
53 /// Image height
54 /// </summary>
55 public int Height;
56  
57 /// <summary>
58 /// Image channel flags
59 /// </summary>
60 public ImageChannels Channels;
61  
62 /// <summary>
63 /// Red channel data
64 /// </summary>
65 public byte[] Red;
66  
67 /// <summary>
68 /// Green channel data
69 /// </summary>
70 public byte[] Green;
71  
72 /// <summary>
73 /// Blue channel data
74 /// </summary>
75 public byte[] Blue;
76  
77 /// <summary>
78 /// Alpha channel data
79 /// </summary>
80 public byte[] Alpha;
81  
82 /// <summary>
83 /// Bump channel data
84 /// </summary>
85 public byte[] Bump;
86  
87 /// <summary>
88 /// Create a new blank image
89 /// </summary>
90 /// <param name="width">width</param>
91 /// <param name="height">height</param>
92 /// <param name="channels">channel flags</param>
93 public ManagedImage(int width, int height, ImageChannels channels)
94 {
95 Width = width;
96 Height = height;
97 Channels = channels;
98  
99 int n = width * height;
100  
101 if ((channels & ImageChannels.Gray) != 0)
102 {
103 Red = new byte[n];
104 }
105 else if ((channels & ImageChannels.Color) != 0)
106 {
107 Red = new byte[n];
108 Green = new byte[n];
109 Blue = new byte[n];
110 }
111  
112 if ((channels & ImageChannels.Alpha) != 0)
113 Alpha = new byte[n];
114  
115 if ((channels & ImageChannels.Bump) != 0)
116 Bump = new byte[n];
117 }
118  
119 #if !NO_UNSAFE
120 /// <summary>
121 ///
122 /// </summary>
123 /// <param name="bitmap"></param>
124 public ManagedImage(System.Drawing.Bitmap bitmap)
125 {
126 Width = bitmap.Width;
127 Height = bitmap.Height;
128  
129 int pixelCount = Width * Height;
130  
131 if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb)
132 {
133 Channels = ImageChannels.Alpha | ImageChannels.Color;
134 Red = new byte[pixelCount];
135 Green = new byte[pixelCount];
136 Blue = new byte[pixelCount];
137 Alpha = new byte[pixelCount];
138  
139 System.Drawing.Imaging.BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height),
140 System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
141  
142 unsafe
143 {
144 byte* pixel = (byte*)bd.Scan0;
145  
146 for (int i = 0; i < pixelCount; i++)
147 {
148 // GDI+ gives us BGRA and we need to turn that in to RGBA
149 Blue[i] = *(pixel++);
150 Green[i] = *(pixel++);
151 Red[i] = *(pixel++);
152 Alpha[i] = *(pixel++);
153 }
154 }
155  
156 bitmap.UnlockBits(bd);
157 }
158 else if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format16bppGrayScale)
159 {
160 Channels = ImageChannels.Gray;
161 Red = new byte[pixelCount];
162  
163 throw new NotImplementedException("16bpp grayscale image support is incomplete");
164 }
165 else if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb)
166 {
167 Channels = ImageChannels.Color;
168 Red = new byte[pixelCount];
169 Green = new byte[pixelCount];
170 Blue = new byte[pixelCount];
171  
172 System.Drawing.Imaging.BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height),
173 System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
174  
175 unsafe
176 {
177 byte* pixel = (byte*)bd.Scan0;
178  
179 for (int i = 0; i < pixelCount; i++)
180 {
181 // GDI+ gives us BGR and we need to turn that in to RGB
182 Blue[i] = *(pixel++);
183 Green[i] = *(pixel++);
184 Red[i] = *(pixel++);
185 }
186 }
187  
188 bitmap.UnlockBits(bd);
189 }
190 else if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppRgb)
191 {
192 Channels = ImageChannels.Color;
193 Red = new byte[pixelCount];
194 Green = new byte[pixelCount];
195 Blue = new byte[pixelCount];
196  
197 System.Drawing.Imaging.BitmapData bd = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height),
198 System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
199  
200 unsafe
201 {
202 byte* pixel = (byte*)bd.Scan0;
203  
204 for (int i = 0; i < pixelCount; i++)
205 {
206 // GDI+ gives us BGR and we need to turn that in to RGB
207 Blue[i] = *(pixel++);
208 Green[i] = *(pixel++);
209 Red[i] = *(pixel++);
210 pixel++; // Skip over the empty byte where the Alpha info would normally be
211 }
212 }
213  
214 bitmap.UnlockBits(bd);
215 }
216 else
217 {
218 throw new NotSupportedException("Unrecognized pixel format: " + bitmap.PixelFormat.ToString());
219 }
220 }
221 #endif
222  
223 /// <summary>
224 /// Convert the channels in the image. Channels are created or destroyed as required.
225 /// </summary>
226 /// <param name="channels">new channel flags</param>
227 public void ConvertChannels(ImageChannels channels)
228 {
229 if (Channels == channels)
230 return;
231  
232 int n = Width * Height;
233 ImageChannels add = Channels ^ channels & channels;
234 ImageChannels del = Channels ^ channels & Channels;
235  
236 if ((add & ImageChannels.Color) != 0)
237 {
238 Red = new byte[n];
239 Green = new byte[n];
240 Blue = new byte[n];
241 }
242 else if ((del & ImageChannels.Color) != 0)
243 {
244 Red = null;
245 Green = null;
246 Blue = null;
247 }
248  
249 if ((add & ImageChannels.Alpha) != 0)
250 {
251 Alpha = new byte[n];
252 FillArray(Alpha, 255);
253 }
254 else if ((del & ImageChannels.Alpha) != 0)
255 Alpha = null;
256  
257 if ((add & ImageChannels.Bump) != 0)
258 Bump = new byte[n];
259 else if ((del & ImageChannels.Bump) != 0)
260 Bump = null;
261  
262 Channels = channels;
263 }
264  
265 /// <summary>
266 /// Resize or stretch the image using nearest neighbor (ugly) resampling
267 /// </summary>
268 /// <param name="width">new width</param>
269 /// <param name="height">new height</param>
270 public void ResizeNearestNeighbor(int width, int height)
271 {
272 if (width == Width && height == Height)
273 return;
274  
275 byte[]
276 red = null,
277 green = null,
278 blue = null,
279 alpha = null,
280 bump = null;
281 int n = width * height;
282 int di = 0, si;
283  
284 if (Red != null) red = new byte[n];
285 if (Green != null) green = new byte[n];
286 if (Blue != null) blue = new byte[n];
287 if (Alpha != null) alpha = new byte[n];
288 if (Bump != null) bump = new byte[n];
289  
290 for (int y = 0; y < height; y++)
291 {
292 for (int x = 0; x < width; x++)
293 {
294 si = (y * Height / height) * Width + (x * Width / width);
295 if (Red != null) red[di] = Red[si];
296 if (Green != null) green[di] = Green[si];
297 if (Blue != null) blue[di] = Blue[si];
298 if (Alpha != null) alpha[di] = Alpha[si];
299 if (Bump != null) bump[di] = Bump[si];
300 di++;
301 }
302 }
303  
304 Width = width;
305 Height = height;
306 Red = red;
307 Green = green;
308 Blue = blue;
309 Alpha = alpha;
310 Bump = bump;
311 }
312  
313 /// <summary>
314 /// Create a byte array containing 32-bit RGBA data with a bottom-left
315 /// origin, suitable for feeding directly into OpenGL
316 /// </summary>
317 /// <returns>A byte array containing raw texture data</returns>
318 public byte[] ExportRaw()
319 {
320 byte[] raw = new byte[Width * Height * 4];
321  
322 if ((Channels & ImageChannels.Alpha) != 0)
323 {
324 if ((Channels & ImageChannels.Color) != 0)
325 {
326 // RGBA
327 for (int h = 0; h < Height; h++)
328 {
329 for (int w = 0; w < Width; w++)
330 {
331 int pos = (Height - 1 - h) * Width + w;
332 int srcPos = h * Width + w;
333  
334 raw[pos * 4 + 0] = Red[srcPos];
335 raw[pos * 4 + 1] = Green[srcPos];
336 raw[pos * 4 + 2] = Blue[srcPos];
337 raw[pos * 4 + 3] = Alpha[srcPos];
338 }
339 }
340 }
341 else
342 {
343 // Alpha only
344 for (int h = 0; h < Height; h++)
345 {
346 for (int w = 0; w < Width; w++)
347 {
348 int pos = (Height - 1 - h) * Width + w;
349 int srcPos = h * Width + w;
350  
351 raw[pos * 4 + 0] = Alpha[srcPos];
352 raw[pos * 4 + 1] = Alpha[srcPos];
353 raw[pos * 4 + 2] = Alpha[srcPos];
354 raw[pos * 4 + 3] = Byte.MaxValue;
355 }
356 }
357 }
358 }
359 else
360 {
361 // RGB
362 for (int h = 0; h < Height; h++)
363 {
364 for (int w = 0; w < Width; w++)
365 {
366 int pos = (Height - 1 - h) * Width + w;
367 int srcPos = h * Width + w;
368  
369 raw[pos * 4 + 0] = Red[srcPos];
370 raw[pos * 4 + 1] = Green[srcPos];
371 raw[pos * 4 + 2] = Blue[srcPos];
372 raw[pos * 4 + 3] = Byte.MaxValue;
373 }
374 }
375 }
376  
377 return raw;
378 }
379  
380 /// <summary>
381 /// Create a byte array containing 32-bit RGBA data with a bottom-left
382 /// origin, suitable for feeding directly into OpenGL
383 /// </summary>
384 /// <returns>A byte array containing raw texture data</returns>
385 public System.Drawing.Bitmap ExportBitmap()
386 {
387 byte[] raw = new byte[Width * Height * 4];
388  
389 if ((Channels & ImageChannels.Alpha) != 0)
390 {
391 if ((Channels & ImageChannels.Color) != 0)
392 {
393 // RGBA
394 for (int pos = 0; pos < Height * Width; pos++)
395 {
396 raw[pos * 4 + 0] = Blue[pos];
397 raw[pos * 4 + 1] = Green[pos];
398 raw[pos * 4 + 2] = Red[pos];
399 raw[pos * 4 + 3] = Alpha[pos];
400 }
401 }
402 else
403 {
404 // Alpha only
405 for (int pos = 0; pos < Height * Width; pos++)
406 {
407 raw[pos * 4 + 0] = Alpha[pos];
408 raw[pos * 4 + 1] = Alpha[pos];
409 raw[pos * 4 + 2] = Alpha[pos];
410 raw[pos * 4 + 3] = Byte.MaxValue;
411 }
412 }
413 }
414 else
415 {
416 // RGB
417 for (int pos = 0; pos < Height * Width; pos++)
418 {
419 raw[pos * 4 + 0] = Blue[pos];
420 raw[pos * 4 + 1] = Green[pos];
421 raw[pos * 4 + 2] = Red[pos];
422 raw[pos * 4 + 3] = Byte.MaxValue;
423 }
424 }
425  
426 System.Drawing.Bitmap b = new System.Drawing.Bitmap(
427 Width,
428 Height,
429 System.Drawing.Imaging.PixelFormat.Format32bppArgb);
430  
431 System.Drawing.Imaging.BitmapData bd = b.LockBits(new System.Drawing.Rectangle(0, 0, b.Width, b.Height),
432 System.Drawing.Imaging.ImageLockMode.WriteOnly,
433 System.Drawing.Imaging.PixelFormat.Format32bppArgb);
434  
435 System.Runtime.InteropServices.Marshal.Copy(raw, 0, bd.Scan0, Width * Height * 4);
436  
437 b.UnlockBits(bd);
438  
439 return b;
440 }
441  
442 public byte[] ExportTGA()
443 {
444 byte[] tga = new byte[Width * Height * ((Channels & ImageChannels.Alpha) == 0 ? 3 : 4) + 32];
445 int di = 0;
446 tga[di++] = 0; // idlength
447 tga[di++] = 0; // colormaptype = 0: no colormap
448 tga[di++] = 2; // image type = 2: uncompressed RGB
449 tga[di++] = 0; // color map spec is five zeroes for no color map
450 tga[di++] = 0; // color map spec is five zeroes for no color map
451 tga[di++] = 0; // color map spec is five zeroes for no color map
452 tga[di++] = 0; // color map spec is five zeroes for no color map
453 tga[di++] = 0; // color map spec is five zeroes for no color map
454 tga[di++] = 0; // x origin = two bytes
455 tga[di++] = 0; // x origin = two bytes
456 tga[di++] = 0; // y origin = two bytes
457 tga[di++] = 0; // y origin = two bytes
458 tga[di++] = (byte)(Width & 0xFF); // width - low byte
459 tga[di++] = (byte)(Width >> 8); // width - hi byte
460 tga[di++] = (byte)(Height & 0xFF); // height - low byte
461 tga[di++] = (byte)(Height >> 8); // height - hi byte
462 tga[di++] = (byte)((Channels & ImageChannels.Alpha) == 0 ? 24 : 32); // 24/32 bits per pixel
463 tga[di++] = (byte)((Channels & ImageChannels.Alpha) == 0 ? 32 : 40); // image descriptor byte
464  
465 int n = Width * Height;
466  
467 if ((Channels & ImageChannels.Alpha) != 0)
468 {
469 if ((Channels & ImageChannels.Color) != 0)
470 {
471 // RGBA
472 for (int i = 0; i < n; i++)
473 {
474 tga[di++] = Blue[i];
475 tga[di++] = Green[i];
476 tga[di++] = Red[i];
477 tga[di++] = Alpha[i];
478 }
479 }
480 else
481 {
482 // Alpha only
483 for (int i = 0; i < n; i++)
484 {
485 tga[di++] = Alpha[i];
486 tga[di++] = Alpha[i];
487 tga[di++] = Alpha[i];
488 tga[di++] = Byte.MaxValue;
489 }
490 }
491 }
492 else
493 {
494 // RGB
495 for (int i = 0; i < n; i++)
496 {
497 tga[di++] = Blue[i];
498 tga[di++] = Green[i];
499 tga[di++] = Red[i];
500 }
501 }
502  
503 return tga;
504 }
505  
506 private static void FillArray(byte[] array, byte value)
507 {
508 if (array != null)
509 {
510 for (int i = 0; i < array.Length; i++)
511 array[i] = value;
512 }
513 }
514  
515 public void Clear()
516 {
517 FillArray(Red, 0);
518 FillArray(Green, 0);
519 FillArray(Blue, 0);
520 FillArray(Alpha, 0);
521 FillArray(Bump, 0);
522 }
523  
524 public ManagedImage Clone()
525 {
526 ManagedImage image = new ManagedImage(Width, Height, Channels);
527 if (Red != null) image.Red = (byte[])Red.Clone();
528 if (Green != null) image.Green = (byte[])Green.Clone();
529 if (Blue != null) image.Blue = (byte[])Blue.Clone();
530 if (Alpha != null) image.Alpha = (byte[])Alpha.Clone();
531 if (Bump != null) image.Bump = (byte[])Bump.Clone();
532 return image;
533 }
534 }
535 }