public RawImage GetMip(TgvFile file, uint mip) { RawImage ret; uint width = file.ImageWidth; uint height = file.ImageHeight; // Compute width and height. for (uint m = 0; m < mip; m++) { width = Math.Max(1, width / 2); height = Math.Max(1, height / 2); } ret = new RawImage(width, height); using (var ms = new MemoryStream(file.MipMaps[(int)mip].Content)) { if (DDS.DDS.IsCompressedFormat(file.Format)) { ReadBlockFormat(ret, ms); } } return ret; }
private static void ReadBlockFormat(RawImage ret, Stream ms) { ret.ColFormat = RawImage.Format.Format_ARGB; uint w = ret.Width; uint h = ret.Height; uint bw = (w + 3) / 4; uint bh = (h + 3) / 4; for (uint by = 0; by < bh; by++) for (uint bx = 0; bx < bw; bx++) { var block = new ColorBlock(); // Read color block. ReadBlock(block, ms); // Write color block. for (uint y = 0; y < Math.Min(4, h - 4 * by); y++) for (uint x = 0; x < Math.Min(4, w - 4 * bx); x++) ret.Data[(4 * by + y) * ret.Width + (4 * bx + x)] = block.Color(x, y); } }
/// Initialize this color block. public ColorBlock(RawImage img, uint x, uint y) : this() { init(img, x, y); }
void init(RawImage img, uint x, uint y) { if (img == null) throw new ArgumentNullException("img"); uint bw = Math.Min(img.Width - x, 4U); uint bh = Math.Min(img.Height - y, 4U); if (bw == 0 || bh == 0) throw new InvalidOperationException("bw and bh have to be > 0)"); uint[] remainder = { 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 2, 0, 0, 1, 2, 3 }; // Blocks that are smaller than 4x4 are handled by repeating the pixels. // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( for (uint i = 0; i < 4; i++) { //const int by = i % bh; uint by = remainder[(bh - 1) * 4 + i]; for (uint e = 0; e < 4; e++) { //const int bx = e % bw; uint bx = remainder[(bw - 1) * 4 + e]; Data[i * 4 + e] = img.Pixel(x + bx, y + by); } } }