/// <summary> /// </summary> /// <param name="gl"> /// </param> /// <param name="ext"> /// </param> /// <param name="arrayBuffer"> /// </param> /// <param name="info"> /// </param> /// <param name="loadMipmaps"> /// </param> /// <param name="faces"> /// </param> public static void UploadDDSLevels( WebGLRenderingContext gl, WEBGL_compressed_texture_s3tc ext, byte[] arrayBuffer, DDSInfo info, bool loadMipmaps, int faces) { var header = ArrayConvert.AsInt(arrayBuffer, 0, headerLengthInt); int fourCC; var blockBytes = 0; var internalFormat = 0; int width; int height; int dataLength; int dataOffset; byte[] byteArray; int mipmapCount; int i; if (header[off_magic] != DDS_MAGIC) { Tools.Error("Invalid magic number in DDS header"); return; } if (!info.isFourCC && !info.isRGB && !info.isLuminance) { Tools.Error("Unsupported format, must contain a FourCC, RGB or LUMINANCE code"); return; } if (info.isFourCC) { fourCC = header[off_pfFourCC]; switch (fourCC) { case FOURCC_DXT1: blockBytes = 8; internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case FOURCC_DXT3: blockBytes = 16; internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT5: blockBytes = 16; internalFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: Tools.Error(string.Format("Unsupported FourCC code: {0}", fourCC)); return; } } mipmapCount = 1; if ((header[off_flags] & DDSD_MIPMAPCOUNT) > 0 && loadMipmaps) { mipmapCount = Math.Max(1, header[off_mipmapCount]); } var bpp = header[off_RGBbpp]; for (var face = 0; face < faces; face++) { var sampler = (faces == 1) ? Gl.TEXTURE_2D : (Gl.TEXTURE_CUBE_MAP_POSITIVE_X + face); width = header[off_width]; height = header[off_height]; dataOffset = header[off_size] + 4; for (i = 0; i < mipmapCount; ++i) { if (info.isRGB) { if (bpp == 24) { dataLength = width * height * 3; byteArray = GetRGBArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer); gl.texImage2D(sampler, i, Gl.RGB, width, height, 0, Gl.RGB, Gl.UNSIGNED_BYTE, byteArray); } else { dataLength = width * height * 4; byteArray = GetRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer); gl.texImage2D(sampler, i, Gl.RGBA, width, height, 0, Gl.RGBA, Gl.UNSIGNED_BYTE, byteArray); } } else if (info.isLuminance) { var unpackAlignment = (int)gl.getParameter(Gl.UNPACK_ALIGNMENT); var unpaddedRowSize = width; var paddedRowSize = (int)Math.Floor((double)(width + unpackAlignment - 1) / unpackAlignment) * unpackAlignment; dataLength = paddedRowSize * (height - 1) + unpaddedRowSize; byteArray = GetLuminanceArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer); gl.texImage2D(sampler, i, Gl.LUMINANCE, width, height, 0, Gl.LUMINANCE, Gl.UNSIGNED_BYTE, byteArray); } else { dataLength = Math.Max(4, width) / 4 * Math.Max(4, height) / 4 * blockBytes; byteArray = ArrayConvert.AsByte(arrayBuffer, dataOffset, dataLength); gl.compressedTexImage2D(sampler, i, internalFormat, width, height, 0, byteArray); } dataOffset += dataLength; width /= 2; height /= 2; width = Math.Max(1, width); height = Math.Max(1, height); } } }
/// <summary> /// </summary> /// <param name="gl"> /// </param> /// <param name="data"> /// </param> public static void UploadContent(WebGLRenderingContext gl, byte[] data) { if (data.Length < 19) { Tools.Error("Unable to load TGA file - Not enough data to contain header"); return; } var offset = 18; var header = GetTGAHeader(data); if (header.id_length + offset > data.Length) { Tools.Error("Unable to load TGA file - Not enough data"); return; } offset += header.id_length; var use_rle = false; var use_pal = false; var use_rgb = false; var use_grey = false; switch (header.image_type) { case _TYPE_RLE_INDEXED: use_rle = true; use_pal = true; break; case _TYPE_INDEXED: use_pal = true; break; case _TYPE_RLE_RGB: use_rle = true; use_rgb = true; break; case _TYPE_RGB: use_rgb = true; break; case _TYPE_RLE_GREY: use_rle = true; use_grey = true; break; case _TYPE_GREY: use_grey = true; break; } byte[] pixel_data; var numAlphaBits = header.flags & 0xf; var pixel_size = header.pixel_size << 3; var pixel_total = header.width * header.height * pixel_size; byte[] palettes = null; if (use_pal) { palettes = ArrayConvert.AsByte(data, offset, header.colormap_length * (header.colormap_size << 3)); } if (use_rle) { pixel_data = new byte[pixel_total]; byte c; int count; int i; var localOffset = 0; var pixels = new byte[pixel_size]; while (offset < pixel_total) { c = data[offset++]; count = (c & 0x7f) + 1; if ((c & 0x80) > 0) { for (i = 0; i < pixel_size; ++i) { pixels[i] = data[offset++]; } for (i = 0; i < count; ++i) { pixel_data = ArrayConvert.AsByte(pixels, localOffset, i * pixel_size); } localOffset += pixel_size * count; } else { count *= pixel_size; for (i = 0; i < count; ++i) { pixel_data[localOffset + i] = data[offset++]; } localOffset += count; } } } else { pixel_data = ArrayConvert.AsByte(data, offset, (use_pal) ? header.width * header.height : pixel_total); } int x_start; int y_start; int x_step; int y_step; int y_end; int x_end; switch ((header.flags & _ORIGIN_MASK) << _ORIGIN_SHIFT) { default: case _ORIGIN_UL: x_start = 0; x_step = 1; x_end = header.width; y_start = 0; y_step = 1; y_end = header.height; break; case _ORIGIN_BL: x_start = 0; x_step = 1; x_end = header.width; y_start = header.height - 1; y_step = -1; y_end = -1; break; case _ORIGIN_UR: x_start = header.width - 1; x_step = -1; x_end = -1; y_start = 0; y_step = 1; y_end = header.height; break; case _ORIGIN_BR: x_start = header.width - 1; x_step = -1; x_end = -1; y_start = header.height - 1; y_step = -1; y_end = -1; break; } byte[] imageData = null; if (use_grey) { switch (header.pixel_size) { case 8: imageData = _getImageDataGrey8bits(header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end); break; case 16: imageData = _getImageDataGrey16bits(header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end); break; } } else { switch (header.pixel_size) { case 8: imageData = _getImageData8bits(header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end); break; case 16: imageData = _getImageData16bits(header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end); break; case 24: imageData = _getImageData24bits(header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end); break; case 32: imageData = _getImageData32bits(header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end); break; } } gl.texImage2D(Gl.TEXTURE_2D, 0, Gl.RGBA, header.width, header.height, 0, Gl.RGBA, Gl.UNSIGNED_BYTE, imageData); }