source: OniSplit/Imaging/Surface.cs@ 1148

Last change on this file since 1148 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 13.3 KB
Line 
1using System;
2
3namespace Oni.Imaging
4{
5 internal class Surface
6 {
7 private int width;
8 private int height;
9 private int stride;
10 private int pixelSize;
11 private SurfaceFormat format;
12 private byte[] data;
13
14 public Surface(int width, int height)
15 : this(width, height, SurfaceFormat.RGBA)
16 {
17 }
18
19 public Surface(int width, int height, SurfaceFormat format)
20 {
21 if (format == SurfaceFormat.DXT1)
22 {
23 width = Math.Max(width, 4);
24 height = Math.Max(height, 4);
25 }
26
27 this.width = width;
28 this.height = height;
29 this.format = format;
30
31 pixelSize = GetPixelSize(format);
32 stride = pixelSize * width;
33 data = new byte[GetDataSize(width, height, format)];
34 }
35
36 public Surface(int width, int height, SurfaceFormat format, byte[] data)
37 {
38 if (format == SurfaceFormat.DXT1)
39 {
40 width = Math.Max(width, 4);
41 height = Math.Max(height, 4);
42 }
43
44 this.width = width;
45 this.height = height;
46 this.format = format;
47 this.data = data;
48
49 pixelSize = GetPixelSize(format);
50 stride = pixelSize * width;
51 }
52
53 private static int GetDataSize(int width, int height, SurfaceFormat format)
54 {
55 switch (format)
56 {
57 case SurfaceFormat.BGRA4444:
58 case SurfaceFormat.BGRX5551:
59 case SurfaceFormat.BGRA5551:
60 return width * height * 2;
61
62 case SurfaceFormat.BGRX:
63 case SurfaceFormat.BGRA:
64 case SurfaceFormat.RGBX:
65 case SurfaceFormat.RGBA:
66 return width * height * 4;
67
68 case SurfaceFormat.DXT1:
69 return width * height / 2;
70
71 default:
72 throw new NotSupportedException(string.Format("Unsupported texture format {0}", format));
73 }
74 }
75
76 private static int GetPixelSize(SurfaceFormat format)
77 {
78 switch (format)
79 {
80 case SurfaceFormat.BGRA4444:
81 case SurfaceFormat.BGRX5551:
82 case SurfaceFormat.BGRA5551:
83 return 2;
84
85 case SurfaceFormat.BGRX:
86 case SurfaceFormat.BGRA:
87 case SurfaceFormat.RGBX:
88 case SurfaceFormat.RGBA:
89 return 4;
90
91 case SurfaceFormat.DXT1:
92 return 2;
93
94 default:
95 throw new NotSupportedException(string.Format("Unsupported texture format {0}", format));
96 }
97 }
98
99 public int Width => width;
100 public int Height => height;
101 public SurfaceFormat Format => format;
102 public byte[] Data => data;
103
104 public bool HasAlpha
105 {
106 get
107 {
108 switch (format)
109 {
110 case SurfaceFormat.BGRA:
111 case SurfaceFormat.RGBA:
112 case SurfaceFormat.BGRA4444:
113 case SurfaceFormat.BGRA5551:
114 return true;
115
116 default:
117 return false;
118 }
119 }
120 }
121
122 public void CleanupAlpha()
123 {
124 if (format != SurfaceFormat.BGRA5551 && format != SurfaceFormat.RGBA && format != SurfaceFormat.BGRA)
125 return;
126
127 if (!HasTransparentPixels())
128 {
129 switch (format)
130 {
131 case SurfaceFormat.BGRA5551:
132 format = SurfaceFormat.BGRX5551;
133 break;
134 case SurfaceFormat.BGRA:
135 format = SurfaceFormat.BGRX;
136 break;
137 case SurfaceFormat.RGBA:
138 format = SurfaceFormat.RGBX;
139 break;
140 }
141 }
142 }
143
144 public bool HasTransparentPixels()
145 {
146 for (int y = 0; y < height; y++)
147 {
148 for (int x = 0; x < width; x++)
149 {
150 Color c = GetPixel(x, y);
151
152 if (c.A != 255)
153 return true;
154 }
155 }
156
157 return false;
158 }
159
160 public Color this[int x, int y]
161 {
162 get
163 {
164 if (x < 0 || width <= x || y < 0 || height <= y)
165 return Color.Black;
166
167 return GetPixel(x, y);
168 }
169 set
170 {
171 if (x < 0 || width <= x || y < 0 || height <= y)
172 return;
173
174 SetPixel(x, y, value);
175 }
176 }
177
178 public void FlipVertical()
179 {
180 var temp = new byte[stride];
181
182 for (int y = 0; y < height / 2; y++)
183 {
184 int ry = height - y - 1;
185
186 Array.Copy(data, y * stride, temp, 0, stride);
187 Array.Copy(data, ry * stride, data, y * stride, stride);
188 Array.Copy(temp, 0, data, ry * stride, stride);
189 }
190 }
191
192 public void FlipHorizontal()
193 {
194 for (int y = 0; y < height; y++)
195 {
196 for (int x = 0; x < width / 2; x++)
197 {
198 int rx = width - x - 1;
199
200 Color c1 = GetPixel(x, y);
201 Color c2 = GetPixel(rx, y);
202 SetPixel(x, y, c2);
203 SetPixel(rx, y, c1);
204 }
205 }
206 }
207
208 public void Rotate90()
209 {
210 for (int x = 0; x < width; x++)
211 {
212 for (int y = 0; y < height; y++)
213 {
214 if (x <= y)
215 continue;
216
217 var c1 = GetPixel(x, y);
218 var c2 = GetPixel(y, x);
219 SetPixel(x, y, c2);
220 SetPixel(y, x, c1);
221 }
222 }
223 }
224
225 public Surface Convert(SurfaceFormat dstFormat)
226 {
227 Surface dst;
228
229 if (format == dstFormat)
230 {
231 dst = new Surface(width, height, dstFormat, (byte[])data.Clone());
232 }
233 else if (dstFormat == SurfaceFormat.DXT1)
234 {
235 dst = Dxt1.Compress(this);
236 }
237 else if (format == SurfaceFormat.DXT1)
238 {
239 dst = Dxt1.Decompress(this, dstFormat);
240 }
241 else
242 {
243 dst = new Surface(width, height, dstFormat);
244
245 for (int y = 0; y < height; y++)
246 {
247 for (int x = 0; x < width; x++)
248 dst.SetPixel(x, y, GetPixel(x, y));
249 }
250 }
251
252 return dst;
253 }
254
255 public Surface Resize(int newWidth, int newHeight)
256 {
257 if (newWidth > width || newHeight > height)
258 throw new NotImplementedException();
259
260 var dst = new Surface(newWidth, newHeight, format);
261
262 if (newWidth * 2 == width && newHeight * 2 == height)
263 {
264 Halfsize(dst);
265 return dst;
266 }
267
268 float sx = (float)width / dst.width;
269 float sy = (float)height / dst.height;
270
271 for (int dstY = 0; dstY < dst.height; dstY++)
272 {
273 float top = dstY * sy;
274 float bottom = top + sy;
275
276 int yTop = (int)top;
277 int yBottom = (int)(bottom - 0.001f);
278
279 float topWeight = 1.0f - (top - yTop);
280 float bottomWeight = bottom - yBottom;
281
282 for (int dstX = 0; dstX < dst.width; dstX++)
283 {
284 float left = dstX * sx;
285 float right = left + sx;
286
287 int xLeft = (int)left;
288 int xRight = (int)(right - 0.001f);
289
290 float leftWeight = 1.0f - (left - xLeft);
291 float rightWeight = right - xRight;
292
293 var sum = GetVector4(xLeft, yTop) * (leftWeight * topWeight);
294 sum += GetVector4(xRight, yTop) * (rightWeight * topWeight);
295 sum += GetVector4(xLeft, yBottom) * (leftWeight * bottomWeight);
296 sum += GetVector4(xRight, yBottom) * (rightWeight * bottomWeight);
297
298 for (int y = yTop + 1; y < yBottom; y++)
299 {
300 sum += GetVector4(xLeft, y) * leftWeight;
301 sum += GetVector4(xRight, y) * rightWeight;
302 }
303
304 for (int x = xLeft + 1; x < xRight; x++)
305 {
306 sum += GetVector4(x, yTop) * topWeight;
307 sum += GetVector4(x, yBottom) * bottomWeight;
308 }
309
310 for (int y = yTop + 1; y < yBottom; y++)
311 {
312 for (int x = xLeft + 1; x < xRight; x++)
313 sum += GetVector4(x, y);
314 }
315
316 float area = (right - left) * (bottom - top);
317
318 dst.SetPixel(dstX, dstY, new Color(sum / area));
319 }
320 }
321
322 return dst;
323 }
324
325 private void Halfsize(Surface dst)
326 {
327 int halfWidth = dst.width;
328 int halfHeight = dst.height;
329
330 for (int dstY = 0; dstY < halfHeight; dstY++)
331 {
332 int yTop = dstY * 2;
333 int yBottom = yTop + 1;
334
335 for (int dstX = 0; dstX < halfWidth; dstX++)
336 {
337 int xLeft = dstX * 2;
338 int xRight = xLeft + 1;
339
340 var sum = GetVector4(xLeft, yTop);
341 sum += GetVector4(xRight, yTop);
342 sum += GetVector4(xLeft, yBottom);
343 sum += GetVector4(xRight, yBottom);
344
345 dst.SetPixel(dstX, dstY, new Color(sum / 4.0f));
346 }
347 }
348 }
349
350 private Vector4 GetVector4(int x, int y)
351 {
352 return GetPixel(x, y).ToVector4();
353 }
354
355 private Color GetPixel(int x, int y)
356 {
357 int i = x * pixelSize + y * stride;
358
359 switch (format)
360 {
361 case SurfaceFormat.BGRA4444:
362 return Color.ReadBgra4444(data, i);
363 case SurfaceFormat.BGRX5551:
364 return Color.ReadBgrx5551(data, i);
365 case SurfaceFormat.BGRA5551:
366 return Color.ReadBgra5551(data, i);
367 case SurfaceFormat.BGR565:
368 return Color.ReadBgr565(data, i);
369 case SurfaceFormat.BGRX:
370 return Color.ReadBgrx(data, i);
371 case SurfaceFormat.BGRA:
372 return Color.ReadBgra(data, i);
373 case SurfaceFormat.RGBX:
374 return Color.ReadRgbx(data, i);
375 case SurfaceFormat.RGBA:
376 return Color.ReadRgba(data, i);
377 default:
378 throw new NotSupportedException(string.Format("Unsupported texture format {0}", format));
379 }
380 }
381
382 private void SetPixel(int x, int y, Color color)
383 {
384 int i = x * pixelSize + y * stride;
385
386 switch (format)
387 {
388 case SurfaceFormat.BGRA4444:
389 Color.WriteBgra4444(color, data, i);
390 return;
391 case SurfaceFormat.BGRX5551:
392 Color.WriteBgrx5551(color, data, i);
393 return;
394 case SurfaceFormat.BGRA5551:
395 Color.WriteBgra5551(color, data, i);
396 return;
397 case SurfaceFormat.BGR565:
398 Color.WriteBgr565(color, data, i);
399 return;
400 case SurfaceFormat.BGRX:
401 Color.WriteBgrx(color, data, i);
402 return;
403 case SurfaceFormat.BGRA:
404 Color.WriteBgra(color, data, i);
405 return;
406 case SurfaceFormat.RGBX:
407 Color.WriteRgbx(color, data, i);
408 return;
409 case SurfaceFormat.RGBA:
410 Color.WriteRgba(color, data, i);
411 return;
412 default:
413 throw new NotSupportedException(string.Format("Unsupported texture format {0}", format));
414 }
415 }
416
417 public void Fill(int x, int y, int width, int height, Color color)
418 {
419 for (int px = x; px < x + width; px++)
420 {
421 for (int py = y; py < y + height; py++)
422 SetPixel(px, py, color);
423 }
424 }
425 }
426}
Note: See TracBrowser for help on using the repository browser.