Added support for multilayered images.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9336 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
		
							parent
							
								
									96cfd22510
								
							
						
					
					
						commit
						b09e37c9d9
					
				| @ -236,26 +236,74 @@ public class TextureHelper extends AbstractBlenderHelper { | |||||||
| 	 * @return the decompressed image | 	 * @return the decompressed image | ||||||
| 	 */ | 	 */ | ||||||
| 	public Image decompress(Image image) { | 	public Image decompress(Image image) { | ||||||
| 		byte[] bytes = null; |  | ||||||
| 		TexturePixel[] colors = null; |  | ||||||
| 		ByteBuffer data = image.getData(0);// TODO: support decompression of all data 'layers' |  | ||||||
| 		data.rewind(); |  | ||||||
| 		Format format = image.getFormat(); | 		Format format = image.getFormat(); | ||||||
|  | 		int depth = image.getDepth(); | ||||||
|  | 		if(depth == 0) { | ||||||
|  | 			depth = 1; | ||||||
|  | 		} | ||||||
|  | 		ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(depth); | ||||||
|  | 		TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() }; | ||||||
| 		 | 		 | ||||||
| 		DDSTexelData texelData = new DDSTexelData(data.remaining() / (format.getBitsPerPixel() * 2), image.getWidth(), image.getHeight(), format != Format.DXT1); | 		for (int dataLayerIndex = 0; dataLayerIndex < depth; ++dataLayerIndex) { | ||||||
| 		switch (format) {// TODO: DXT1A | 			ByteBuffer data = image.getData(dataLayerIndex); | ||||||
| 			case DXT1:// BC1 | 			data.rewind(); | ||||||
| 				bytes = new byte[image.getWidth() * image.getHeight() * 4]; | 			 | ||||||
| 				colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() }; | 			byte[] bytes = new byte[image.getWidth() * image.getHeight() << 2]; | ||||||
| 				while (data.hasRemaining()) { | 			DDSTexelData texelData = new DDSTexelData(data.remaining() * 8/format.getBitsPerPixel()/16/*data.remaining() / (format.getBitsPerPixel() << 1)*/,  | ||||||
| 					short c0 = data.getShort(); | 					image.getWidth(), image.getHeight(), format != Format.DXT1); | ||||||
| 					short c1 = data.getShort(); | 			switch (format) { | ||||||
| 					int col0 = RGB565.RGB565_to_ARGB8(c0); | 				case DXT1:// BC1 | ||||||
| 					int col1 = RGB565.RGB565_to_ARGB8(c1); | 				case DXT1A: | ||||||
| 					colors[0].fromARGB8(col0); | 					while (data.hasRemaining()) { | ||||||
| 					colors[1].fromARGB8(col1); | 						short c0 = data.getShort(); | ||||||
|  | 						short c1 = data.getShort(); | ||||||
|  | 						int col0 = RGB565.RGB565_to_ARGB8(c0); | ||||||
|  | 						int col1 = RGB565.RGB565_to_ARGB8(c1); | ||||||
|  | 						colors[0].fromARGB8(col0); | ||||||
|  | 						colors[1].fromARGB8(col1); | ||||||
|  | 
 | ||||||
|  | 						if (col0 > col1) { | ||||||
|  | 							// creating color2 = 2/3color0 + 1/3color1 | ||||||
|  | 							colors[2].fromPixel(colors[0]); | ||||||
|  | 							colors[2].mult(2); | ||||||
|  | 							colors[2].add(colors[1]); | ||||||
|  | 							colors[2].divide(3); | ||||||
|  | 
 | ||||||
|  | 							// creating color3 = 1/3color0 + 2/3color1; | ||||||
|  | 							colors[3].fromPixel(colors[1]); | ||||||
|  | 							colors[3].mult(2); | ||||||
|  | 							colors[3].add(colors[0]); | ||||||
|  | 							colors[3].divide(3); | ||||||
|  | 						} else { | ||||||
|  | 							// creating color2 = 1/2color0 + 1/2color1 | ||||||
|  | 							colors[2].fromPixel(colors[0]); | ||||||
|  | 							colors[2].add(colors[1]); | ||||||
|  | 							colors[2].mult(0.5f); | ||||||
|  | 
 | ||||||
|  | 							colors[3].fromARGB8(0); | ||||||
|  | 						} | ||||||
|  | 						int indexes = data.getInt();// 4-byte table with color indexes in decompressed table | ||||||
|  | 						texelData.add(colors, indexes); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case DXT3:// BC2 | ||||||
|  | 					while (data.hasRemaining()) { | ||||||
|  | 						long alpha = data.getLong(); | ||||||
|  | 						float[] alphas = new float[16]; | ||||||
|  | 						long alphasIndex = 0; | ||||||
|  | 						for (int i = 0; i < 16; ++i) { | ||||||
|  | 							alphasIndex |= i << i * 4; | ||||||
|  | 							byte a = (byte) ((alpha >> i * 4 & 0x0F) << 4); | ||||||
|  | 							alphas[i] = a >= 0 ? a / 255.0f : 1.0f - ~a / 255.0f; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						short c0 = data.getShort(); | ||||||
|  | 						short c1 = data.getShort(); | ||||||
|  | 						int col0 = RGB565.RGB565_to_ARGB8(c0); | ||||||
|  | 						int col1 = RGB565.RGB565_to_ARGB8(c1); | ||||||
|  | 						colors[0].fromARGB8(col0); | ||||||
|  | 						colors[1].fromARGB8(col1); | ||||||
| 
 | 
 | ||||||
| 					if (col0 > col1) { |  | ||||||
| 						// creating color2 = 2/3color0 + 1/3color1 | 						// creating color2 = 2/3color0 + 1/3color1 | ||||||
| 						colors[2].fromPixel(colors[0]); | 						colors[2].fromPixel(colors[0]); | ||||||
| 						colors[2].mult(2); | 						colors[2].mult(2); | ||||||
| @ -267,106 +315,60 @@ public class TextureHelper extends AbstractBlenderHelper { | |||||||
| 						colors[3].mult(2); | 						colors[3].mult(2); | ||||||
| 						colors[3].add(colors[0]); | 						colors[3].add(colors[0]); | ||||||
| 						colors[3].divide(3); | 						colors[3].divide(3); | ||||||
| 					} else { | 
 | ||||||
| 						// creating color2 = 1/2color0 + 1/2color1 | 						int indexes = data.getInt();// 4-byte table with color indexes in decompressed table | ||||||
|  | 						texelData.add(colors, indexes, alphas, alphasIndex); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case DXT5:// BC3 | ||||||
|  | 					float[] alphas = new float[8]; | ||||||
|  | 					while (data.hasRemaining()) { | ||||||
|  | 						alphas[0] = data.get() * 255.0f; | ||||||
|  | 						alphas[1] = data.get() * 255.0f; | ||||||
|  | 						long alphaIndices = data.get() | data.get() << 8 | data.get() << 16 | data.get() << 24 | data.get() << 32 | data.get() << 40; | ||||||
|  | 						if (alphas[0] > alphas[1]) {// 6 interpolated alpha values. | ||||||
|  | 							alphas[2] = (6 * alphas[0] + alphas[1]) / 7; | ||||||
|  | 							alphas[3] = (5 * alphas[0] + 2 * alphas[1]) / 7; | ||||||
|  | 							alphas[4] = (4 * alphas[0] + 3 * alphas[1]) / 7; | ||||||
|  | 							alphas[5] = (3 * alphas[0] + 4 * alphas[1]) / 7; | ||||||
|  | 							alphas[6] = (2 * alphas[0] + 5 * alphas[1]) / 7; | ||||||
|  | 							alphas[7] = (alphas[0] + 6 * alphas[1]) / 7; | ||||||
|  | 						} else { | ||||||
|  | 							alphas[2] = (4 * alphas[0] + alphas[1]) * 0.2f; | ||||||
|  | 							alphas[3] = (3 * alphas[0] + 2 * alphas[1]) * 0.2f; | ||||||
|  | 							alphas[4] = (2 * alphas[0] + 3 * alphas[1]) * 0.2f; | ||||||
|  | 							alphas[5] = (alphas[0] + 4 * alphas[1]) * 0.2f; | ||||||
|  | 							alphas[6] = 0; | ||||||
|  | 							alphas[7] = 1; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						short c0 = data.getShort(); | ||||||
|  | 						short c1 = data.getShort(); | ||||||
|  | 						int col0 = RGB565.RGB565_to_ARGB8(c0); | ||||||
|  | 						int col1 = RGB565.RGB565_to_ARGB8(c1); | ||||||
|  | 						colors[0].fromARGB8(col0); | ||||||
|  | 						colors[1].fromARGB8(col1); | ||||||
|  | 
 | ||||||
|  | 						// creating color2 = 2/3color0 + 1/3color1 | ||||||
| 						colors[2].fromPixel(colors[0]); | 						colors[2].fromPixel(colors[0]); | ||||||
|  | 						colors[2].mult(2); | ||||||
| 						colors[2].add(colors[1]); | 						colors[2].add(colors[1]); | ||||||
| 						colors[2].mult(0.5f); | 						colors[2].divide(3); | ||||||
| 
 | 
 | ||||||
| 						colors[3].fromARGB8(0); | 						// creating color3 = 1/3color0 + 2/3color1; | ||||||
| 					} | 						colors[3].fromPixel(colors[1]); | ||||||
| 					int indexes = data.getInt();// 4-byte table with color indexes in decompressed table | 						colors[3].mult(2); | ||||||
| 					texelData.add(colors, indexes); | 						colors[3].add(colors[0]); | ||||||
| 				} | 						colors[3].divide(3); | ||||||
| 				break; | 
 | ||||||
| 			case DXT3:// BC2 | 						int indexes = data.getInt();// 4-byte table with color indexes in decompressed table | ||||||
| 				bytes = new byte[image.getWidth() * image.getHeight() * 4]; | 						texelData.add(colors, indexes, alphas, alphaIndices); | ||||||
| 				colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() }; |  | ||||||
| 				while (data.hasRemaining()) { |  | ||||||
| 					long alpha = data.getLong(); |  | ||||||
| 					float[] alphas = new float[16]; |  | ||||||
| 					long alphasIndex = 0; |  | ||||||
| 					for (int i = 0; i < 16; ++i) { |  | ||||||
| 						alphasIndex |= i << i * 4; |  | ||||||
| 						byte a = (byte) ((alpha >> i * 4 & 0x0F) << 4); |  | ||||||
| 						alphas[i] = a >= 0 ? a / 255.0f : 1.0f - ~a / 255.0f; |  | ||||||
| 					} | 					} | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					throw new IllegalStateException("Unknown compressed format: " + format); | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 					short c0 = data.getShort(); |  | ||||||
| 					short c1 = data.getShort(); |  | ||||||
| 					int col0 = RGB565.RGB565_to_ARGB8(c0); |  | ||||||
| 					int col1 = RGB565.RGB565_to_ARGB8(c1); |  | ||||||
| 					colors[0].fromARGB8(col0); |  | ||||||
| 					colors[1].fromARGB8(col1); |  | ||||||
| 
 |  | ||||||
| 					// creating color2 = 2/3color0 + 1/3color1 |  | ||||||
| 					colors[2].fromPixel(colors[0]); |  | ||||||
| 					colors[2].mult(2); |  | ||||||
| 					colors[2].add(colors[1]); |  | ||||||
| 					colors[2].divide(3); |  | ||||||
| 
 |  | ||||||
| 					// creating color3 = 1/3color0 + 2/3color1; |  | ||||||
| 					colors[3].fromPixel(colors[1]); |  | ||||||
| 					colors[3].mult(2); |  | ||||||
| 					colors[3].add(colors[0]); |  | ||||||
| 					colors[3].divide(3); |  | ||||||
| 
 |  | ||||||
| 					int indexes = data.getInt();// 4-byte table with color indexes in decompressed table |  | ||||||
| 					texelData.add(colors, indexes, alphas, alphasIndex); |  | ||||||
| 				} |  | ||||||
| 				break; |  | ||||||
| 			case DXT5:// BC3 |  | ||||||
| 				bytes = new byte[image.getWidth() * image.getHeight() * 4]; |  | ||||||
| 				colors = new TexturePixel[] { new TexturePixel(), new TexturePixel(), new TexturePixel(), new TexturePixel() }; |  | ||||||
| 				float[] alphas = new float[8]; |  | ||||||
| 				while (data.hasRemaining()) { |  | ||||||
| 					alphas[0] = data.get() * 255.0f; |  | ||||||
| 					alphas[1] = data.get() * 255.0f; |  | ||||||
| 					long alphaIndices = data.get() | data.get() << 8 | data.get() << 16 | data.get() << 24 | data.get() << 32 | data.get() << 40; |  | ||||||
| 					if (alphas[0] > alphas[1]) {// 6 interpolated alpha values. |  | ||||||
| 						alphas[2] = (6 * alphas[0] + alphas[1]) / 7; |  | ||||||
| 						alphas[3] = (5 * alphas[0] + 2 * alphas[1]) / 7; |  | ||||||
| 						alphas[4] = (4 * alphas[0] + 3 * alphas[1]) / 7; |  | ||||||
| 						alphas[5] = (3 * alphas[0] + 4 * alphas[1]) / 7; |  | ||||||
| 						alphas[6] = (2 * alphas[0] + 5 * alphas[1]) / 7; |  | ||||||
| 						alphas[7] = (alphas[0] + 6 * alphas[1]) / 7; |  | ||||||
| 					} else { |  | ||||||
| 						alphas[2] = (4 * alphas[0] + alphas[1]) * 0.2f; |  | ||||||
| 						alphas[3] = (3 * alphas[0] + 2 * alphas[1]) * 0.2f; |  | ||||||
| 						alphas[4] = (2 * alphas[0] + 3 * alphas[1]) * 0.2f; |  | ||||||
| 						alphas[5] = (alphas[0] + 4 * alphas[1]) * 0.2f; |  | ||||||
| 						alphas[6] = 0; |  | ||||||
| 						alphas[7] = 1; |  | ||||||
| 					} |  | ||||||
| 
 |  | ||||||
| 					short c0 = data.getShort(); |  | ||||||
| 					short c1 = data.getShort(); |  | ||||||
| 					int col0 = RGB565.RGB565_to_ARGB8(c0); |  | ||||||
| 					int col1 = RGB565.RGB565_to_ARGB8(c1); |  | ||||||
| 					colors[0].fromARGB8(col0); |  | ||||||
| 					colors[1].fromARGB8(col1); |  | ||||||
| 
 |  | ||||||
| 					// creating color2 = 2/3color0 + 1/3color1 |  | ||||||
| 					colors[2].fromPixel(colors[0]); |  | ||||||
| 					colors[2].mult(2); |  | ||||||
| 					colors[2].add(colors[1]); |  | ||||||
| 					colors[2].divide(3); |  | ||||||
| 
 |  | ||||||
| 					// creating color3 = 1/3color0 + 2/3color1; |  | ||||||
| 					colors[3].fromPixel(colors[1]); |  | ||||||
| 					colors[3].mult(2); |  | ||||||
| 					colors[3].add(colors[0]); |  | ||||||
| 					colors[3].divide(3); |  | ||||||
| 
 |  | ||||||
| 					int indexes = data.getInt();// 4-byte table with color indexes in decompressed table |  | ||||||
| 					texelData.add(colors, indexes, alphas, alphaIndices); |  | ||||||
| 				} |  | ||||||
| 				break; |  | ||||||
| 			default: |  | ||||||
| 				LOGGER.fine("Unsupported decompression format."); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (bytes != null) {// writing the data to the result table |  | ||||||
| 			byte[] pixelBytes = new byte[4]; | 			byte[] pixelBytes = new byte[4]; | ||||||
| 			for (int i = 0; i < image.getWidth(); ++i) { | 			for (int i = 0; i < image.getWidth(); ++i) { | ||||||
| 				for (int j = 0; j < image.getHeight(); ++j) { | 				for (int j = 0; j < image.getHeight(); ++j) { | ||||||
| @ -377,11 +379,15 @@ public class TextureHelper extends AbstractBlenderHelper { | |||||||
| 					bytes[(j * image.getWidth() + i) * 4 + 3] = pixelBytes[3]; | 					bytes[(j * image.getWidth() + i) * 4 + 3] = pixelBytes[3]; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			// TODO: think of other image formats (ie. RGB if the texture has no | 			dataArray.add(BufferUtils.createByteBuffer(bytes)); | ||||||
| 			// alpha values) |  | ||||||
| 			return new Image(Format.RGBA8, image.getWidth(), image.getHeight(), BufferUtils.createByteBuffer(bytes)); |  | ||||||
| 		} | 		} | ||||||
| 		return image; | 		 | ||||||
|  | 		Image result = depth > 1 ? new Image(Format.RGBA8, image.getWidth(), image.getHeight(), depth, dataArray) :  | ||||||
|  | 								   new Image(Format.RGBA8, image.getWidth(), image.getHeight(), dataArray.get(0)); | ||||||
|  | 		if(image.getMipMapSizes() != null) { | ||||||
|  | 			result.setMipMapSizes(image.getMipMapSizes().clone()); | ||||||
|  | 		} | ||||||
|  | 		return result; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | |||||||
| @ -42,7 +42,6 @@ public class TextureBlenderAWT extends AbstractTextureBlender { | |||||||
| 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) { | 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) { | ||||||
| 		float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f }; | 		float[] pixelColor = new float[] { color[0], color[1], color[2], 1.0f }; | ||||||
| 		Format format = image.getFormat(); | 		Format format = image.getFormat(); | ||||||
| 		ByteBuffer data = image.getData(0); |  | ||||||
| 		 | 		 | ||||||
| 		PixelInputOutput basePixelIO = null, pixelReader = PixelIOFactory.getPixelIO(format); | 		PixelInputOutput basePixelIO = null, pixelReader = PixelIOFactory.getPixelIO(format); | ||||||
| 		TexturePixel basePixel = null, pixel = new TexturePixel(); | 		TexturePixel basePixel = null, pixel = new TexturePixel(); | ||||||
| @ -59,44 +58,50 @@ public class TextureBlenderAWT extends AbstractTextureBlender { | |||||||
| 		if (depth == 0) { | 		if (depth == 0) { | ||||||
| 			depth = 1; | 			depth = 1; | ||||||
| 		} | 		} | ||||||
| 		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4); | 		ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(depth); | ||||||
| 		 | 		 | ||||||
| 		float[] resultPixel = new float[4]; | 		float[] resultPixel = new float[4]; | ||||||
| 		int dataIndex = 0, x = 0, y = 0, index = 0; | 		for (int dataLayerIndex = 0; dataLayerIndex < depth; ++dataLayerIndex) { | ||||||
| 		while (index < data.limit()) { | 			ByteBuffer data = image.getData(dataLayerIndex); | ||||||
| 			//getting the proper material color if the base texture is applied | 			data.rewind(); | ||||||
| 			if(basePixelIO != null) { | 			ByteBuffer newData = BufferUtils.createByteBuffer(width * height * 4); | ||||||
| 				basePixelIO.read(baseImage, basePixel, x, y); |  | ||||||
| 				basePixel.toRGBA(materialColor); |  | ||||||
| 			}			 |  | ||||||
| 			 | 			 | ||||||
| 			//reading the current texture's pixel | 			int dataIndex = 0, x = 0, y = 0, index = 0; | ||||||
| 			pixelReader.read(image, pixel, index); | 			while (index < data.limit()) { | ||||||
| 			index += image.getFormat().getBitsPerPixel() >> 3; | 				//getting the proper material color if the base texture is applied | ||||||
| 			pixel.toRGBA(pixelColor); | 				if(basePixelIO != null) { | ||||||
| 			if (negateTexture) { | 					basePixelIO.read(baseImage, basePixel, x, y); | ||||||
| 				pixel.negate(); | 					basePixel.toRGBA(materialColor); | ||||||
| 			} | 				}			 | ||||||
| 				 | 				 | ||||||
| 			this.blendPixel(resultPixel, materialColor, pixelColor, blenderContext); | 				//reading the current texture's pixel | ||||||
| 			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f)); | 				pixelReader.read(image, pixel, index); | ||||||
| 			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f)); | 				index += image.getFormat().getBitsPerPixel() >> 3; | ||||||
| 			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f)); | 				pixel.toRGBA(pixelColor); | ||||||
| 			newData.put(dataIndex++, (byte) (pixelColor[3] * 255.0f)); | 				if (negateTexture) { | ||||||
|  | 					pixel.negate(); | ||||||
|  | 				} | ||||||
| 				 | 				 | ||||||
| 			++x; | 				this.blendPixel(resultPixel, materialColor, pixelColor, blenderContext); | ||||||
| 			if(x >= width) { | 				newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f)); | ||||||
| 				x = 0; | 				newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f)); | ||||||
| 				++y; | 				newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f)); | ||||||
|  | 				newData.put(dataIndex++, (byte) (pixelColor[3] * 255.0f)); | ||||||
|  | 				 | ||||||
|  | 				++x; | ||||||
|  | 				if(x >= width) { | ||||||
|  | 					x = 0; | ||||||
|  | 					++y; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} |  | ||||||
| 		if(depth > 1) { |  | ||||||
| 			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1); |  | ||||||
| 			dataArray.add(newData); | 			dataArray.add(newData); | ||||||
| 			return new Image(Format.RGBA8, width, height, depth, dataArray); |  | ||||||
| 		} else { |  | ||||||
| 			return new Image(Format.RGBA8, width, height, newData); |  | ||||||
| 		} | 		} | ||||||
|  | 		 | ||||||
|  | 		Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray) : new Image(Format.RGBA8, width, height, dataArray.get(0)); | ||||||
|  | 		if(image.getMipMapSizes() != null) { | ||||||
|  | 			result.setMipMapSizes(image.getMipMapSizes().clone()); | ||||||
|  | 		} | ||||||
|  | 		return result; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | |||||||
| @ -2,8 +2,6 @@ package com.jme3.scene.plugins.blender.textures.blending; | |||||||
| 
 | 
 | ||||||
| import java.nio.ByteBuffer; | import java.nio.ByteBuffer; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.logging.Level; |  | ||||||
| import java.util.logging.Logger; |  | ||||||
| 
 | 
 | ||||||
| import jme3tools.converters.RGB565; | import jme3tools.converters.RGB565; | ||||||
| 
 | 
 | ||||||
| @ -18,15 +16,12 @@ import com.jme3.util.BufferUtils; | |||||||
| /** | /** | ||||||
|  * The class that is responsible for blending the following texture types: |  * The class that is responsible for blending the following texture types: | ||||||
|  * <li> DXT1 |  * <li> DXT1 | ||||||
|  |  * <li> DXT1A | ||||||
|  * <li> DXT3 |  * <li> DXT3 | ||||||
|  * <li> DXT5 |  * <li> DXT5 | ||||||
|  * Not yet supported (but will be): |  | ||||||
|  * <li> DXT1A: |  | ||||||
|  * @author Marcin Roguski (Kaelthas) |  * @author Marcin Roguski (Kaelthas) | ||||||
|  */ |  */ | ||||||
| public class TextureBlenderDDS extends TextureBlenderAWT { | public class TextureBlenderDDS extends TextureBlenderAWT { | ||||||
| 	private static final Logger	LOGGER	= Logger.getLogger(TextureBlenderDDS.class.getName()); |  | ||||||
| 
 |  | ||||||
| 	public TextureBlenderDDS(int flag, boolean negateTexture, int blendType, float[] materialColor, float[] color, float blendFactor) { | 	public TextureBlenderDDS(int flag, boolean negateTexture, int blendType, float[] materialColor, float[] color, float blendFactor) { | ||||||
| 		super(flag, negateTexture, blendType, materialColor, color, blendFactor); | 		super(flag, negateTexture, blendType, materialColor, color, blendFactor); | ||||||
| 	} | 	} | ||||||
| @ -34,16 +29,13 @@ public class TextureBlenderDDS extends TextureBlenderAWT { | |||||||
| 	@Override | 	@Override | ||||||
| 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) { | 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) { | ||||||
| 		Format format = image.getFormat(); | 		Format format = image.getFormat(); | ||||||
| 		ByteBuffer data = image.getData(0); |  | ||||||
| 		data.rewind(); |  | ||||||
| 
 |  | ||||||
| 		int width = image.getWidth(); | 		int width = image.getWidth(); | ||||||
| 		int height = image.getHeight(); | 		int height = image.getHeight(); | ||||||
| 		int depth = image.getDepth(); | 		int depth = image.getDepth(); | ||||||
| 		if (depth == 0) { | 		if (depth == 0) { | ||||||
| 			depth = 1; | 			depth = 1; | ||||||
| 		} | 		} | ||||||
| 		ByteBuffer newData = BufferUtils.createByteBuffer(data.remaining()); | 		ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(depth); | ||||||
| 		 | 		 | ||||||
| 		PixelInputOutput basePixelIO = null; | 		PixelInputOutput basePixelIO = null; | ||||||
| 		float[][] compressedMaterialColor = null; | 		float[][] compressedMaterialColor = null; | ||||||
| @ -57,77 +49,77 @@ public class TextureBlenderDDS extends TextureBlenderAWT { | |||||||
| 		float[] resultPixel = new float[4]; | 		float[] resultPixel = new float[4]; | ||||||
| 		float[] pixelColor = new float[4]; | 		float[] pixelColor = new float[4]; | ||||||
| 		TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel() }; | 		TexturePixel[] colors = new TexturePixel[] { new TexturePixel(), new TexturePixel() }; | ||||||
| 		int dataIndex = 0, baseXTexelIndex = 0, baseYTexelIndex = 0; | 		int baseXTexelIndex = 0, baseYTexelIndex = 0; | ||||||
| 		float[] alphas = new float[] {1, 1}; | 		float[] alphas = new float[] {1, 1}; | ||||||
| 		while (data.hasRemaining()) { | 		for (int dataLayerIndex = 0; dataLayerIndex < depth; ++dataLayerIndex) { | ||||||
| 			if(format == Format.DXT1A) { | 			ByteBuffer data = image.getData(dataLayerIndex); | ||||||
| 				LOGGER.log(Level.WARNING, "Image type not yet supported for blending: {0}", format); | 			data.rewind(); | ||||||
| 				break; | 			ByteBuffer newData = BufferUtils.createByteBuffer(data.remaining()); | ||||||
| 			} | 			System.out.println(dataLayerIndex); | ||||||
| 			if(format == Format.DXT3) { | 			while (data.hasRemaining()) { | ||||||
| 				long alpha = data.getLong(); | 				if(format == Format.DXT3) { | ||||||
| 				//get alpha for first and last pixel that is compressed in the texel | 					long alpha = data.getLong(); | ||||||
| 				byte alpha0 = (byte)(alpha << 4 & 0xFF); | 					//get alpha for first and last pixel that is compressed in the texel | ||||||
| 				byte alpha1 = (byte)(alpha >> 60 & 0xFF); | 					byte alpha0 = (byte)(alpha << 4 & 0xFF); | ||||||
| 				alphas[0] = alpha0 >= 0 ? alpha0 / 255.0f : 1.0f - ~alpha0 / 255.0f; | 					byte alpha1 = (byte)(alpha >> 60 & 0xFF); | ||||||
| 				alphas[1] = alpha1 >= 0 ? alpha1 / 255.0f : 1.0f - ~alpha1 / 255.0f; | 					alphas[0] = alpha0 >= 0 ? alpha0 / 255.0f : 1.0f - ~alpha0 / 255.0f; | ||||||
| 				dataIndex += 8; | 					alphas[1] = alpha1 >= 0 ? alpha1 / 255.0f : 1.0f - ~alpha1 / 255.0f; | ||||||
| 			} else if(format == Format.DXT5) { | 					newData.putLong(alpha); | ||||||
| 				byte alpha0 = data.get(); | 				} else if(format == Format.DXT5) { | ||||||
| 				byte alpha1 = data.get(); | 					byte alpha0 = data.get(); | ||||||
| 				alphas[0] = alpha0 >= 0 ? alpha0 / 255.0f : 1.0f - ~alpha0 / 255.0f; | 					byte alpha1 = data.get(); | ||||||
| 				alphas[1] = alpha1 >= 0 ? alpha0 / 255.0f : 1.0f - ~alpha0 / 255.0f; | 					alphas[0] = alpha0 >= 0 ? alpha0 / 255.0f : 1.0f - ~alpha0 / 255.0f; | ||||||
| 				//only read the next 6 bytes (these are alpha indexes) | 					alphas[1] = alpha1 >= 0 ? alpha0 / 255.0f : 1.0f - ~alpha0 / 255.0f; | ||||||
| 				data.getInt(); | 					newData.put(alpha0); | ||||||
| 				data.getShort(); | 					newData.put(alpha1); | ||||||
| 				dataIndex += 8; | 					//only read the next 6 bytes (these are alpha indexes) | ||||||
| 			} | 					newData.putInt(data.getInt()); | ||||||
| 			int col0 = RGB565.RGB565_to_ARGB8(data.getShort()); | 					newData.putShort(data.getShort()); | ||||||
| 			int col1 = RGB565.RGB565_to_ARGB8(data.getShort()); | 				} | ||||||
| 			colors[0].fromARGB8(col0); | 				int col0 = RGB565.RGB565_to_ARGB8(data.getShort()); | ||||||
| 			colors[1].fromARGB8(col1); | 				int col1 = RGB565.RGB565_to_ARGB8(data.getShort()); | ||||||
| 			 | 				colors[0].fromARGB8(col0); | ||||||
| 			//compressing 16 pixels from the base texture as if they belonged to a texel | 				colors[1].fromARGB8(col1); | ||||||
| 			if(baseImage != null) { | 				 | ||||||
| 				//reading pixels (first and last of the 16 colors array) | 				//compressing 16 pixels from the base texture as if they belonged to a texel | ||||||
| 				basePixelIO.read(baseImage, baseTextureColors[0], baseXTexelIndex << 2, baseYTexelIndex << 2);//first pixel | 				if(baseImage != null) { | ||||||
| 				basePixelIO.read(baseImage, baseTextureColors[1], baseXTexelIndex << 2 + 4, baseYTexelIndex << 2 + 4);//last pixel | 					//reading pixels (first and last of the 16 colors array) | ||||||
| 				baseTextureColors[0].toRGBA(compressedMaterialColor[0]); | 					basePixelIO.read(baseImage, baseTextureColors[0], baseXTexelIndex << 2, baseYTexelIndex << 2);//first pixel | ||||||
| 				baseTextureColors[1].toRGBA(compressedMaterialColor[1]); | 					basePixelIO.read(baseImage, baseTextureColors[1], baseXTexelIndex << 2 + 4, baseYTexelIndex << 2 + 4);//last pixel | ||||||
| 			} | 					baseTextureColors[0].toRGBA(compressedMaterialColor[0]); | ||||||
| 
 | 					baseTextureColors[1].toRGBA(compressedMaterialColor[1]); | ||||||
| 			// blending colors | 				} | ||||||
| 			for (int i = 0; i < colors.length; ++i) { | 
 | ||||||
| 				if (negateTexture) { | 				// blending colors | ||||||
| 					colors[i].negate(); | 				for (int i = 0; i < colors.length; ++i) { | ||||||
|  | 					if (negateTexture) { | ||||||
|  | 						colors[i].negate(); | ||||||
|  | 					} | ||||||
|  | 					colors[i].toRGBA(pixelColor); | ||||||
|  | 					pixelColor[3] = alphas[i]; | ||||||
|  | 					this.blendPixel(resultPixel, compressedMaterialColor != null ? compressedMaterialColor[i] : materialColor, pixelColor, blenderContext); | ||||||
|  | 					colors[i].fromARGB8(1, resultPixel[0], resultPixel[1], resultPixel[2]); | ||||||
|  | 					int argb8 = colors[i].toARGB8(); | ||||||
|  | 					short rgb565 = RGB565.ARGB8_to_RGB565(argb8); | ||||||
|  | 					newData.putShort(rgb565); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				// just copy the remaining 4 bytes of the current texel | ||||||
|  | 				newData.putInt(data.getInt()); | ||||||
|  | 				 | ||||||
|  | 				++baseXTexelIndex; | ||||||
|  | 				if(baseXTexelIndex > image.getWidth() >> 2) { | ||||||
|  | 					baseXTexelIndex = 0; | ||||||
|  | 					++baseYTexelIndex; | ||||||
| 				} | 				} | ||||||
| 				colors[i].toRGBA(pixelColor); |  | ||||||
| 				pixelColor[3] = alphas[i]; |  | ||||||
| 				this.blendPixel(resultPixel, compressedMaterialColor != null ? compressedMaterialColor[i] : materialColor, pixelColor, blenderContext); |  | ||||||
| 				colors[i].fromARGB8(1, resultPixel[0], resultPixel[1], resultPixel[2]); |  | ||||||
| 				int argb8 = colors[i].toARGB8(); |  | ||||||
| 				short rgb565 = RGB565.ARGB8_to_RGB565(argb8); |  | ||||||
| 				newData.putShort(dataIndex, rgb565); |  | ||||||
| 				dataIndex += 2; |  | ||||||
| 			} | 			} | ||||||
| 
 |  | ||||||
| 			// just copy the remaining 4 bytes of the current texel |  | ||||||
| 			newData.putInt(dataIndex, data.getInt()); |  | ||||||
| 			dataIndex += 4; |  | ||||||
| 			 |  | ||||||
| 			++baseXTexelIndex; |  | ||||||
| 			if(baseXTexelIndex > image.getWidth() >> 2) { |  | ||||||
| 				baseXTexelIndex = 0; |  | ||||||
| 				++baseYTexelIndex; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		if(depth > 1) { |  | ||||||
| 			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1); |  | ||||||
| 			dataArray.add(newData); | 			dataArray.add(newData); | ||||||
| 			return new Image(format, width, height, depth, dataArray); |  | ||||||
| 		} else { |  | ||||||
| 			return new Image(format, width, height, newData); |  | ||||||
| 		} | 		} | ||||||
|  | 		 | ||||||
|  | 		Image result = dataArray.size() > 1 ? new Image(format, width, height, depth, dataArray) : new Image(format, width, height, dataArray.get(0)); | ||||||
|  | 		if(image.getMipMapSizes() != null) { | ||||||
|  | 			result.setMipMapSizes(image.getMipMapSizes().clone()); | ||||||
|  | 		} | ||||||
|  | 		return result; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -35,8 +35,6 @@ public class TextureBlenderLuminance extends AbstractTextureBlender { | |||||||
| 	 | 	 | ||||||
| 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) { | 	public Image blend(Image image, Image baseImage, BlenderContext blenderContext) { | ||||||
| 		Format format = image.getFormat(); | 		Format format = image.getFormat(); | ||||||
| 		ByteBuffer data = image.getData(0); |  | ||||||
| 		data.rewind(); |  | ||||||
| 
 | 
 | ||||||
| 		PixelInputOutput basePixelIO = null; | 		PixelInputOutput basePixelIO = null; | ||||||
| 		TexturePixel basePixel = null; | 		TexturePixel basePixel = null; | ||||||
| @ -53,39 +51,44 @@ public class TextureBlenderLuminance extends AbstractTextureBlender { | |||||||
| 		if (depth == 0) { | 		if (depth == 0) { | ||||||
| 			depth = 1; | 			depth = 1; | ||||||
| 		} | 		} | ||||||
| 		ByteBuffer newData = BufferUtils.createByteBuffer(width * height * depth * 4); | 		ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(depth); | ||||||
| 
 | 
 | ||||||
| 		float[] resultPixel = new float[4]; | 		float[] resultPixel = new float[4]; | ||||||
| 		float[] tinAndAlpha = new float[2]; | 		float[] tinAndAlpha = new float[2]; | ||||||
| 		int dataIndex = 0, x = 0, y = 0; | 		for (int dataLayerIndex = 0; dataLayerIndex < depth; ++dataLayerIndex) { | ||||||
| 		while (data.hasRemaining()) { | 			ByteBuffer data = image.getData(dataLayerIndex); | ||||||
| 			//getting the proper material color if the base texture is applied | 			data.rewind(); | ||||||
| 			if(basePixelIO != null) { | 			ByteBuffer newData = BufferUtils.createByteBuffer(width * height * 4); | ||||||
| 				basePixelIO.read(baseImage, basePixel, x, y); | 			 | ||||||
| 				basePixel.toRGBA(materialColor); | 			int dataIndex = 0, x = 0, y = 0; | ||||||
|  | 			while (data.hasRemaining()) { | ||||||
|  | 				//getting the proper material color if the base texture is applied | ||||||
|  | 				if(basePixelIO != null) { | ||||||
|  | 					basePixelIO.read(baseImage, basePixel, x, y); | ||||||
|  | 					basePixel.toRGBA(materialColor); | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
|  | 				this.getTinAndAlpha(data, format, negateTexture, tinAndAlpha); | ||||||
|  | 				this.blendPixel(resultPixel, materialColor, color, tinAndAlpha[0], blendFactor, blendType, blenderContext); | ||||||
|  | 				newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f)); | ||||||
|  | 				newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f)); | ||||||
|  | 				newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f)); | ||||||
|  | 				newData.put(dataIndex++, (byte) (tinAndAlpha[1] * 255.0f)); | ||||||
|  | 				 | ||||||
|  | 				++x; | ||||||
|  | 				if(x >= width) { | ||||||
|  | 					x = 0; | ||||||
|  | 					++y; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			 |  | ||||||
| 			this.getTinAndAlpha(data, format, negateTexture, tinAndAlpha); |  | ||||||
| 			this.blendPixel(resultPixel, materialColor, color, tinAndAlpha[0], blendFactor, blendType, blenderContext); |  | ||||||
| 			newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f)); |  | ||||||
| 			newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f)); |  | ||||||
| 			newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f)); |  | ||||||
| 			newData.put(dataIndex++, (byte) (tinAndAlpha[1] * 255.0f)); |  | ||||||
| 			 |  | ||||||
| 			++x; |  | ||||||
| 			if(x >= width) { |  | ||||||
| 				x = 0; |  | ||||||
| 				++y; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		if(depth > 1) { |  | ||||||
| 			ArrayList<ByteBuffer> dataArray = new ArrayList<ByteBuffer>(1); |  | ||||||
| 			dataArray.add(newData); | 			dataArray.add(newData); | ||||||
| 			return new Image(Format.RGBA8, width, height, depth, dataArray); |  | ||||||
| 		} else { |  | ||||||
| 			return new Image(Format.RGBA8, width, height, newData); |  | ||||||
| 		} | 		} | ||||||
|  | 		 | ||||||
|  | 		Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray) : new Image(Format.RGBA8, width, height, dataArray.get(0)); | ||||||
|  | 		if(image.getMipMapSizes() != null) { | ||||||
|  | 			result.setMipMapSizes(image.getMipMapSizes().clone()); | ||||||
|  | 		} | ||||||
|  | 		return result; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | |||||||
| @ -34,7 +34,8 @@ import com.jme3.texture.Image; | |||||||
| 		ByteBuffer data = image.getData().get(0); | 		ByteBuffer data = image.getData().get(0); | ||||||
| 		 | 		 | ||||||
| 		switch (image.getFormat()) { | 		switch (image.getFormat()) { | ||||||
| 			case DXT1: {// BC1 | 			case DXT1: // BC1 | ||||||
|  | 			case DXT1A:{ | ||||||
| 				data.position(texelIndex * 8); | 				data.position(texelIndex * 8); | ||||||
| 				short c0 = data.getShort(); | 				short c0 = data.getShort(); | ||||||
| 				short c1 = data.getShort(); | 				short c1 = data.getShort(); | ||||||
| @ -142,8 +143,6 @@ import com.jme3.texture.Image; | |||||||
| 				indexes = data.getInt();// 4-byte table with color indexes in decompressed table | 				indexes = data.getInt();// 4-byte table with color indexes in decompressed table | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			case DXT1A://TODO: implement |  | ||||||
| 				break; |  | ||||||
| 			default: | 			default: | ||||||
| 				throw new IllegalStateException("Unsupported decompression format."); | 				throw new IllegalStateException("Unsupported decompression format."); | ||||||
| 		} | 		} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user