@ -2,10 +2,9 @@ package com.jme3.scene.plugins.blender.textures;
import java.awt.Graphics2D ;
import java.awt.RenderingHints ;
import java.awt.geom.AffineTransform ;
import java.awt.image.BufferedImage ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.LinkedHashMap ;
import java.util.List ;
import java.util.logging.Logger ;
@ -46,8 +45,6 @@ public class CombinedTexture {
private final int mappingType ;
/** The data for each of the textures. */
private List < TextureData > textureDatas = new ArrayList < TextureData > ( ) ;
/** The variable indicates if the texture was already triangulated or not. */
private boolean wasTriangulated ;
/** The result texture. */
private Texture resultTexture ;
/** The UV values for the result texture. */
@ -77,10 +74,12 @@ public class CombinedTexture {
* the type of UV coordinates projection ( for flat textures )
* @param textureStructure
* the texture sructure
* @param uvCoordinatesName
* the name of the used user ' s UV coordinates for this texture
* @param blenderContext
* the blender context
* /
public void add ( Texture texture , TextureBlender textureBlender , int uvCoordinatesType , int projectionType , Structure textureStructure , BlenderContext blenderContext ) {
public void add ( Texture texture , TextureBlender textureBlender , int uvCoordinatesType , int projectionType , Structure textureStructure , String uvCoordinatesName , BlenderContext blenderContext ) {
if ( ! ( texture instanceof GeneratedTexture ) & & ! ( texture instanceof Texture2D ) ) {
throw new IllegalArgumentException ( "Unsupported texture type: " + ( texture = = null ? "null" : texture . getClass ( ) ) ) ;
}
@ -92,6 +91,7 @@ public class CombinedTexture {
textureData . uvCoordinatesType = UVCoordinatesType . valueOf ( uvCoordinatesType ) ;
textureData . projectionType = UVProjectionType . valueOf ( projectionType ) ;
textureData . textureStructure = textureStructure ;
textureData . uvCoordinatesName = uvCoordinatesName ;
if ( textureDatas . size ( ) > 0 & & this . isWithoutAlpha ( textureData , blenderContext ) ) {
textureDatas . clear ( ) ; // clear previous textures, they will be covered anyway
@ -119,11 +119,12 @@ public class CombinedTexture {
* the blender context
* /
@SuppressWarnings ( "unchecked" )
public void flatten ( Geometry geometry , Long geometriesOMA , List < Vector2f > userDefinedUVCoordinates , BlenderContext blenderContext ) {
public void flatten ( Geometry geometry , Long geometriesOMA , LinkedHashMap < String , Li st < Vector2f > > userDefinedUVCoordinates , BlenderContext blenderContext ) {
TextureHelper textureHelper = blenderContext . getHelper ( TextureHelper . class ) ;
Mesh mesh = geometry . getMesh ( ) ;
Texture previousTexture = null ;
UVCoordinatesType masterUVCoordinatesType = null ;
String masterUserUVSetName = null ;
for ( TextureData textureData : textureDatas ) {
// decompress compressed textures (all will be merged into one texture anyway)
if ( textureDatas . size ( ) > 1 & & textureData . texture . getImage ( ) . getFormat ( ) . isCompressed ( ) ) {
@ -138,7 +139,12 @@ public class CombinedTexture {
resultTexture = textureData . texture ;
if ( textureData . uvCoordinatesType = = UVCoordinatesType . TEXCO_UV & & userDefinedUVCoordinates ! = null & & userDefinedUVCoordinates . size ( ) > 0 ) {
resultUVS = userDefinedUVCoordinates ;
if ( textureData . uvCoordinatesName = = null ) {
resultUVS = userDefinedUVCoordinates . values ( ) . iterator ( ) . next ( ) ; //get the first UV available
} else {
resultUVS = userDefinedUVCoordinates . get ( textureData . uvCoordinatesName ) ;
}
masterUserUVSetName = textureData . uvCoordinatesName ;
} else {
List < Geometry > geometries = ( List < Geometry > ) blenderContext . getLoadedFeature ( geometriesOMA , LoadedFeatureDataType . LOADED_FEATURE ) ;
resultUVS = UVCoordinatesGenerator . generateUVCoordinatesFor2DTexture ( mesh , textureData . uvCoordinatesType , textureData . projectionType , geometries ) ;
@ -161,7 +167,9 @@ public class CombinedTexture {
triangulatedTexture . blend ( textureData . textureBlender , ( TriangulatedTexture ) resultTexture , blenderContext ) ;
resultTexture = previousTexture = triangulatedTexture ;
} else if ( textureData . texture instanceof Texture2D ) {
if ( masterUVCoordinatesType = = textureData . uvCoordinatesType & & resultTexture instanceof Texture2D ) {
if ( this . isUVTypesMatch ( masterUVCoordinatesType , masterUserUVSetName ,
textureData . uvCoordinatesType , textureData . uvCoordinatesName ) & &
resultTexture instanceof Texture2D ) {
this . scale ( ( Texture2D ) textureData . texture , resultTexture . getImage ( ) . getWidth ( ) , resultTexture . getImage ( ) . getHeight ( ) ) ;
this . merge ( ( Texture2D ) resultTexture , ( Texture2D ) textureData . texture ) ;
previousTexture = resultTexture ;
@ -173,7 +181,11 @@ public class CombinedTexture {
// first triangulate the current texture
List < Vector2f > textureUVS = null ;
if ( textureData . uvCoordinatesType = = UVCoordinatesType . TEXCO_UV & & userDefinedUVCoordinates ! = null & & userDefinedUVCoordinates . size ( ) > 0 ) {
textureUVS = userDefinedUVCoordinates ;
if ( textureData . uvCoordinatesName = = null ) {
textureUVS = userDefinedUVCoordinates . values ( ) . iterator ( ) . next ( ) ; //get the first UV available
} else {
textureUVS = userDefinedUVCoordinates . get ( textureData . uvCoordinatesName ) ;
}
} else {
List < Geometry > geometries = ( List < Geometry > ) blenderContext . getLoadedFeature ( geometriesOMA , LoadedFeatureDataType . LOADED_FEATURE ) ;
textureUVS = UVCoordinatesGenerator . generateUVCoordinatesFor2DTexture ( mesh , textureData . uvCoordinatesType , textureData . projectionType , geometries ) ;
@ -196,7 +208,6 @@ public class CombinedTexture {
}
resultUVS = ( ( TriangulatedTexture ) resultTexture ) . getResultUVS ( ) ;
resultTexture = ( ( TriangulatedTexture ) resultTexture ) . getResultTexture ( ) ;
wasTriangulated = true ;
}
// setting additional data
@ -207,6 +218,31 @@ public class CombinedTexture {
resultTexture . setMinFilter ( MinFilter . NearestNoMipMaps ) ;
}
/ * *
* The method checks if the texture UV coordinates match .
* It the types are equal and different then UVCoordinatesType . TEXCO_UV then we consider them a match .
* If they are both UVCoordinatesType . TEXCO_UV then they match only when their UV sets names are equal .
* In other cases they are considered NOT a match .
* @param type1 the UV coord type
* @param uvSetName1 the user ' s UV coords set name ( considered only for UVCoordinatesType . TEXCO_UV )
* @param type2 the UV coord type
* @param uvSetName2 the user ' s UV coords set name ( considered only for UVCoordinatesType . TEXCO_UV )
* @return < b > true < / b > if the types match and < b > false < / b > otherwise
* /
private boolean isUVTypesMatch ( UVCoordinatesType type1 , String uvSetName1 ,
UVCoordinatesType type2 , String uvSetName2 ) {
if ( type1 = = type2 ) {
if ( type1 = = UVCoordinatesType . TEXCO_UV ) {
if ( uvSetName1 ! = null & & uvSetName2 ! = null & & uvSetName1 . equals ( uvSetName2 ) ) {
return true ;
}
} else {
return true ;
}
}
return false ;
}
/ * *
* This method blends the texture .
*
@ -228,129 +264,6 @@ public class CombinedTexture {
}
}
/ * *
* This method casts the current image to the basic UV ' s owner UV ' s
* coordinates .
*
* @param basicUVSOwner
* the owner of the UV ' s we cast to
* @param blenderContext
* the blender context
* /
public void castToUVS ( CombinedTexture basicUVSOwner , BlenderContext blenderContext ) {
if ( resultUVS . size ( ) ! = basicUVSOwner . resultUVS . size ( ) ) {
throw new IllegalStateException ( "The amount of UV coordinates must be equal in order to cast one UV's onto another!" ) ;
}
if ( ! resultUVS . equals ( basicUVSOwner . resultUVS ) ) {
if ( ! basicUVSOwner . wasTriangulated ) {
throw new IllegalStateException ( "The given texture must be triangulated!" ) ;
}
if ( ! this . wasTriangulated ) {
resultTexture = new TriangulatedTexture ( ( Texture2D ) resultTexture , resultUVS , blenderContext ) ;
resultUVS = ( ( TriangulatedTexture ) resultTexture ) . getResultUVS ( ) ;
resultTexture = ( ( TriangulatedTexture ) resultTexture ) . getResultTexture ( ) ;
}
// casting algorithm
TextureHelper textureHelper = blenderContext . getHelper ( TextureHelper . class ) ;
ImageLoader imageLoader = new ImageLoader ( ) ;
List < TriangleTextureElement > faceTextures = new ArrayList < TriangleTextureElement > ( ) ;
List < Vector2f > basicUVS = basicUVSOwner . getResultUVS ( ) ;
int [ ] imageRectangle = new int [ 4 ] ; // minX, minY, maxX, maxY
int [ ] sourceSize = new int [ 2 ] , targetSize = new int [ 2 ] ; // width,
// height
Vector2f [ ] destinationUVS = new Vector2f [ 3 ] ;
Vector2f [ ] sourceUVS = new Vector2f [ 3 ] ;
List < Vector2f > partImageUVS = Arrays . asList ( new Vector2f ( ) , new Vector2f ( ) , new Vector2f ( ) ) ;
int faceIndex = 0 ;
for ( int i = 0 ; i < basicUVS . size ( ) ; i + = 3 ) {
// destination size nad UVS
destinationUVS [ 0 ] = basicUVS . get ( i ) ;
destinationUVS [ 1 ] = basicUVS . get ( i + 1 ) ;
destinationUVS [ 2 ] = basicUVS . get ( i + 2 ) ;
this . computeImageRectangle ( destinationUVS , imageRectangle , basicUVSOwner . resultTexture . getImage ( ) . getWidth ( ) , basicUVSOwner . resultTexture . getImage ( ) . getHeight ( ) , blenderContext ) ;
targetSize [ 0 ] = imageRectangle [ 2 ] - imageRectangle [ 0 ] ;
targetSize [ 1 ] = imageRectangle [ 3 ] - imageRectangle [ 1 ] ;
for ( int j = 0 ; j < 3 ; + + j ) {
partImageUVS . get ( j ) . set ( ( basicUVSOwner . resultTexture . getImage ( ) . getWidth ( ) * destinationUVS [ j ] . x - imageRectangle [ 0 ] ) / targetSize [ 0 ] , ( basicUVSOwner . resultTexture . getImage ( ) . getHeight ( ) * destinationUVS [ j ] . y - imageRectangle [ 1 ] ) / targetSize [ 1 ] ) ;
}
// source size and UVS (translate UVS to (0,0) and stretch it to
// the borders of the image)
sourceUVS [ 0 ] = resultUVS . get ( i ) ;
sourceUVS [ 1 ] = resultUVS . get ( i + 1 ) ;
sourceUVS [ 2 ] = resultUVS . get ( i + 2 ) ;
this . computeImageRectangle ( sourceUVS , imageRectangle , resultTexture . getImage ( ) . getWidth ( ) , resultTexture . getImage ( ) . getHeight ( ) , blenderContext ) ;
sourceSize [ 0 ] = imageRectangle [ 2 ] - imageRectangle [ 0 ] ;
sourceSize [ 1 ] = imageRectangle [ 3 ] - imageRectangle [ 1 ] ;
float xTranslateFactor = imageRectangle [ 0 ] / ( float ) resultTexture . getImage ( ) . getWidth ( ) ;
float xStreachFactor = resultTexture . getImage ( ) . getWidth ( ) / ( float ) sourceSize [ 0 ] ;
float yTranslateFactor = imageRectangle [ 1 ] / ( float ) resultTexture . getImage ( ) . getHeight ( ) ;
float yStreachFactor = resultTexture . getImage ( ) . getHeight ( ) / ( float ) sourceSize [ 1 ] ;
for ( int j = 0 ; j < 3 ; + + j ) {
sourceUVS [ j ] . x = ( sourceUVS [ j ] . x - xTranslateFactor ) * xStreachFactor ;
sourceUVS [ j ] . y = ( sourceUVS [ j ] . y - yTranslateFactor ) * yStreachFactor ;
}
AffineTransform affineTransform = textureHelper . createAffineTransform ( sourceUVS , partImageUVS . toArray ( new Vector2f [ 3 ] ) , sourceSize , targetSize ) ;
Image image = textureHelper . getSubimage ( resultTexture . getImage ( ) , imageRectangle [ 0 ] , imageRectangle [ 1 ] , imageRectangle [ 2 ] , imageRectangle [ 3 ] ) ;
// compute the result texture
BufferedImage sourceImage = ImageToAwt . convert ( image , false , true , 0 ) ;
BufferedImage targetImage = new BufferedImage ( targetSize [ 0 ] , targetSize [ 1 ] , sourceImage . getType ( ) ) ;
Graphics2D g = targetImage . createGraphics ( ) ;
g . setRenderingHint ( RenderingHints . KEY_INTERPOLATION , RenderingHints . VALUE_INTERPOLATION_BILINEAR ) ;
g . drawImage ( sourceImage , affineTransform , null ) ;
g . dispose ( ) ;
Image output = imageLoader . load ( targetImage , false ) ;
faceTextures . add ( new TriangleTextureElement ( faceIndex + + , output , partImageUVS , false , blenderContext ) ) ;
}
TriangulatedTexture triangulatedTexture = new TriangulatedTexture ( faceTextures , blenderContext ) ;
triangulatedTexture . setKeepIdenticalTextures ( false ) ;
resultTexture = triangulatedTexture . getResultTexture ( ) ;
resultUVS = basicUVS ;
}
}
/ * *
* This method computes the rectangle of an image constrained by the
* triangle UV coordinates .
*
* @param triangleVertices
* the triangle UV coordinates
* @param result
* the array where the result is stored
* @param totalImageWidth
* the total image width
* @param totalImageHeight
* the total image height
* @param blenderContext
* the blender context
* /
private void computeImageRectangle ( Vector2f [ ] triangleVertices , int [ ] result , int totalImageWidth , int totalImageHeight , BlenderContext blenderContext ) {
TextureHelper textureHelper = blenderContext . getHelper ( TextureHelper . class ) ;
float minX = Math . min ( triangleVertices [ 0 ] . x , triangleVertices [ 1 ] . x ) ;
minX = Math . min ( minX , triangleVertices [ 2 ] . x ) ;
float maxX = Math . max ( triangleVertices [ 0 ] . x , triangleVertices [ 1 ] . x ) ;
maxX = Math . max ( maxX , triangleVertices [ 2 ] . x ) ;
float minY = Math . min ( triangleVertices [ 0 ] . y , triangleVertices [ 1 ] . y ) ;
minY = Math . min ( minY , triangleVertices [ 2 ] . y ) ;
float maxY = Math . max ( triangleVertices [ 0 ] . y , triangleVertices [ 1 ] . y ) ;
maxY = Math . max ( maxY , triangleVertices [ 2 ] . y ) ;
result [ 0 ] = textureHelper . getPixelPosition ( minX , totalImageWidth ) ;
result [ 1 ] = textureHelper . getPixelPosition ( minY , totalImageHeight ) ;
result [ 2 ] = textureHelper . getPixelPosition ( maxX , totalImageWidth ) ;
result [ 3 ] = textureHelper . getPixelPosition ( maxY , totalImageHeight ) ;
}
/ * *
* @return the result texture
* /
@ -546,5 +459,7 @@ public class CombinedTexture {
public UVProjectionType projectionType ;
/** The texture sructure. */
public Structure textureStructure ;
/** The name of the user's UV coordinates that are used for this texture. */
public String uvCoordinatesName ;
}
}