package tk.captainsplexx.Resource.ITEXTURE; import tk.captainsplexx.Resource.FileHandler; import tk.captainsplexx.Resource.CAS.CasManager; import tk.captainsplexx.Resource.DDS.DDS_HEADER; import tk.captainsplexx.Resource.DDS.DDS_PIXELFORMAT; public class ITextureConverter { public static DDS_HEADER getDDSHeader(ITexture itexture){ DDS_HEADER header = new DDS_HEADER(); header.setDwSize(124); header.setDwFlags(659471); header.setDwHeight(itexture.getHeight()); header.setDwWidth(itexture.getWidth()); header.setDwPitchOrLinearSize(itexture.getMipSizes()[0]); header.setDwDepth(itexture.getDepth()); header.setDwMipMapCount(itexture.getNumSizes()); header.setDwReserved1(new int[11]); for (int i=0; i<header.getDwReserved1().length;i++){ header.getDwReserved1()[i] = 0; } header.setDwCaps(4096); header.setDwCaps2(0); /*PixelFormat*/ DDS_PIXELFORMAT pixelformat = new DDS_PIXELFORMAT( /*dwSize*/ 32, /*dwFlags*/ 4, /*dwFourCC*/ 827611204, /*dwRGBBitCount*/ 0, /*dwRBitMask*/ 0, /*dwGBitMask*/ 0, /*dwBBitMask*/ 0, /*dwABitMask)*/ 0 ); if (itexture.getTextureType()==ITexture.TT_Cube){ header.setDwCaps2(65024); header.setDwCaps(header.getDwCaps() | 8); } if (!ITexture.PixelFormatTypes.containsKey(itexture.getPixelFormat())){ switch (itexture.getPixelFormat()){ case ITexture.TF_ABGR32F: pixelformat.setDwFourCC(0); pixelformat.setDwRGBBitCount((itexture.getPixelFormat() == ITexture.TF_ABGR32F) ? 128 : 32); pixelformat.setDwGBitMask(16711680); pixelformat.setDwGBitMask(65280); pixelformat.setDwBBitMask(-16777216); pixelformat.setDwFlags(65); header.setDwFlags(-524289); header.setDwFlags(header.getDwFlags() | 8); break; case ITexture.TF_L8: pixelformat.setDwFourCC(0); pixelformat.setDwRGBBitCount(8); pixelformat.setDwABitMask(255); pixelformat.setDwFlags(2); header.setDwFlags(-524289); header.setDwFlags(header.getDwFlags() | 8); break; case ITexture.TF_L16: pixelformat.setDwFourCC(0); pixelformat.setDwRGBBitCount(16); pixelformat.setDwRBitMask(65535); pixelformat.setDwFlags(131072); header.setDwFlags(-524289); header.setDwFlags(header.getDwFlags() | 8); break; case ITexture.TF_ARGB8888: //Loading Screens pixelformat.setDwFourCC(0); pixelformat.setDwABitMask(0xff000000); pixelformat.setDwBBitMask(0xff); pixelformat.setDwGBitMask(0xff00); pixelformat.setDwRBitMask(0xff0000); pixelformat.setDwRGBBitCount(32); pixelformat.setDwFlags(0x41); header.setDwFlags(0x81007); break; case ITexture.TF_ABGR16: break; case ITexture.TF_ABGR16F: break; } }else{ pixelformat.setDwFourCC(ITexture.PixelFormatTypes.get(itexture.getPixelFormat())); if (itexture.getPixelFormat() == ITexture.TF_DXT1A){ pixelformat.setDwFlags(pixelformat.getDwFlags() | 1); } } header.setPixelformat(pixelformat); return header; } public static ITexture getITextureHeader(byte[] ddsFile, ITexture originalITextureHeader, String newGUID){ DDS_HEADER ddsHeader = new DDS_HEADER(ddsFile, null); ITexture itexture = new ITexture(); //itexture.setFirstMip(originalITextureHeader.getFirstMip()); //We don't want to calculate range args so, we start at the first mip. itexture.setFirstMip((byte) 0x1); //itexture.setFirstMip(originalITextureHeader.getFirstMip()); itexture.setUnknown(originalITextureHeader.getUnknown()); if (originalITextureHeader.getTextureType() == ITexture.TF_NormalDXT1 && ddsHeader.getPixelformat().getDwFourCC() != ITexture.DDS_DXT1) { System.err.println("DDS does NOT MATCH DXT1 normalmap.\n" + "Make sure to use the original Format.\n" + "--Canceling process!--"); return null; } switch (ddsHeader.getPixelformat().getDwFourCC()){ case 0: switch (ddsHeader.getPixelformat().getDwRGBBitCount()){ case 8: itexture.setPixelFormat(ITexture.TF_L8); break; case 16: itexture.setPixelFormat(ITexture.TF_L16); break; case 128: itexture.setPixelFormat(ITexture.TF_ABGR32F); break; case 32: itexture.setPixelFormat(ITexture.TF_ARGB8888); break; default: System.err.println("The RGBBitCount of " + ddsHeader.getPixelformat().getDwRGBBitCount() + " is not assigned to any valid formats.\n" + "You could try to use a DXT1(no alpha) or DXT5(Alpha) Texture instead.\n" + "Please submit your texture and format details to @CaptainSpleXx on GitHub!"); return null; } break; case ITexture.DDS_ABGR32F: itexture.setPixelFormat(ITexture.TF_ABGR32F); break; case ITexture.DDS_DXT1: itexture.setPixelFormat(ITexture.TF_DXT1); break; case ITexture.DDS_NormalDXN: itexture.setPixelFormat(ITexture.TF_NormalDXN); break; case ITexture.DDS_DXT5: itexture.setPixelFormat(ITexture.TF_DXT5); break; default: itexture.setPixelFormat(ITexture.TF_Unknown); System.err.println("DDS File has an unknown format. Make sure to use a supported one!"); return null; } itexture.setTextureType(((ddsHeader.getDwCaps2() == 65024) ? ITexture.TT_Cube : ITexture.TT_2d)); if (originalITextureHeader.getTextureType() == ITexture.TT_Cube && ddsHeader.getDwCaps2() != 65024) { System.err.println("Original texture type is a cubemap! - Can't convert to DDS!"); return null; } if (itexture.getTextureType()!=originalITextureHeader.getTextureType()||itexture.getPixelFormat()!=originalITextureHeader.getPixelFormat()){ System.err.println("Can't continue. New file has a diffrent TextureType or PixelFormat!"); return null; } itexture.setNameHash(originalITextureHeader.getNameHash()); itexture.setWidth((short) ddsHeader.getDwWidth()); itexture.setHeight((short) ddsHeader.getDwHeight()); itexture.setDepth((byte) 0x1); itexture.setSliceCount((short) 1); itexture.setNumSizes((byte) ddsHeader.getDwMipMapCount()); itexture.setChunkSize(ddsFile.length-128/*Substract Header with FourCC*/); itexture.setName(originalITextureHeader.getName()); itexture.setMipSizes(new int[15]); int width = ddsHeader.getDwWidth(); int height = ddsHeader.getDwHeight(); if (ddsHeader.getPixelformat().getDwFourCC() == 0) { int num3 = 0; switch (itexture.getPixelFormat()) { case ITexture.TF_ABGR16F: for (int i = 0; i < ddsHeader.getDwMipMapCount(); i++) { /* Alpha Blue Green Red, each is using a single float. * So we get a total of 16 Bytes � pixel. */ itexture.getMipSizes()[i] = width * height * 16; width >>= 1; height >>= 1; } break; default: System.err.println(itexture.getPixelFormat()+" is currently not supported!"); break; } } else { /* * DXT: * When compressing a 4 colour palette is determined for these 16 pixels. * Afterwards each pixel will get an index into this palette, which only requires 2 bit per pixel. * For the palette only two colours are stored, the two extremes, and the other two colours are interpolated between these extremes. * The colour information is also stored with a compression so that only 16 bits are used per colour. * This means that these 16 pixels of the texture only take 64 bits to store (32 for the palette and 32 for the indexing). * * Besides that the palette only stores two colour, let's call them colour1 and colour2. * The other two colours that can be indexed are linearly interpolated. * So that means that colour3 is 2/3 of colour1 plus 1/3 of colour2 and for colour4 the reverse is true (1/3 if colour1 plus 2/3 of colour2). * This means that if the 4 most common colours used in your 16 pixels are not on a one linear line in the colour space, you will loose some colours. * * * * DXT1 + Alpha: * A 1 bit alpha channel means that the transparency is either on or off. * To store this one of the colours of the colour palette will get the meaning completely transparent. * The other three colours are left to store the colour information of your pixels. * So for the two colours stored in this case only one has to be interpolated, * colour3 is 1/2 colour1 plus 1/2 colour2. * This means even less resolution is left for different shades of colours. * * * * DXT5 + Alpha: * For the alpha information it uses a palette, similar to the way the colour information is also stored. * This palette contains a minimum and maximum alpha value. * Then 6 other alpha values are interpolated between this minimum and maximum. * This thus allows more gradual changes of the alpha value. * A second variant does interpolate only 4 other alpha values between the minimum and maximum, * but also adds an alpha value of 0 and 1 (for fully transparent and not transparent). * For some textures this might give better results. * * */ int bits = 8; int pixelFormat = itexture.getPixelFormat(); if (pixelFormat == ITexture.TF_DXT5 || pixelFormat == ITexture.TF_NormalDXN) { bits = 16; } for (int j = 0; j < ddsHeader.getDwMipMapCount(); j++) { int tWidth = width / 4; int tHeight = height / 4; /*num7 = ((num7 < 1) ? 1 : num7); num8 = ((num8 < 1) ? 1 : num8);*/ itexture.getMipSizes()[j] = tWidth * bits * tHeight; width >>= 1; height >>= 1; } } itexture.setMipSizes(originalITextureHeader.getMipSizes()); itexture.setMipOneEndOffset(itexture.getMipSizes()[0] + (CasManager.calculateNumberOfBlocks(itexture.getMipSizes()[0]) * CasManager.blockHeaderNumBytes)); if (itexture.getNumSizes()>=2){ itexture.setMipTwoEndOffset(itexture.getMipOneEndOffset() + itexture.getMipSizes()[1] + (CasManager.calculateNumberOfBlocks(itexture.getMipSizes()[1]) * CasManager.blockHeaderNumBytes)); } itexture.setChunkID(FileHandler.hexStringToByteArray(newGUID)); System.out.println("ITexture Header created for Chunk "+newGUID); return itexture; } public static byte[] getBlockData(byte[] ddsFileBytes){ if (ddsFileBytes!=null){ //DDS Header has a size of 0x80! byte[] blockData = new byte[ddsFileBytes.length-0x80]; for (int i=0; i<blockData.length; i++){ blockData[i] = ddsFileBytes[i+0x80]; } return blockData; }else{ System.err.println("DDS File can not be null. (ITextureConverter.getBlockData)!"); return null; } } }