I'm trying to use the ColladaImporter to load a model of a building from Google's 3D Warehouse, which unfortunately uses satellite imagery to provide the roof of the building. An example of the dimensions of one of the texture images is 4800 x 3183. I'd like to scale these images before using the model. I know that I can walk the nodes to find the offending textures, but I was wondering if there was a better way. I'm imagining that at some point, I'll find models that sure these large images and it would be useful to correct them before they are cached.
You might be able to use a custom resource locator for this. You could basically load up the image in your locator and test the size, maybe even rewrite and send on the url to a new image instead.
Using a customized ResourceLocator would allow for the loaded/cached image to be controlled. Since the ResourceLocator only returns a URL to the resource based upon the path, the scaled image would have to be URL addressable.
- The customized ResourceLocator could actually scale the file and then return a URL to a temporary file. This would work, but the use of a temporary file would mean that the returned URL would have an indeterminate shelf-life.
- References within the Collada file currently cause the ColladaImporter to clone the Texture. This is achieved by using the BinaryExporter to persist the instance and then reading the result using the BinaryImporter. This sends the path parts of the URL (which could be quite different from the original path) back through the ResourceLocators.
I think that all of this points to flaws in the current resource location process.
- The ResourceLocator has no contextual information. In the example of the Collada file, the images are relative to the location of the model DAE file (i.e. "../images/roof.jpg"). However, I could very easily be loading several independent models, each of which happened to use the same path (all of the building models have a relative reference to "../images/roof.jpg"). Since the paths are non-unique, I'm not sure how to handle this case.
- The BinaryExport process is writing the location of the resource, which is a URL, but is still using the ResourceLocators. If the ResourceLocator is intended to be used to convert a path into an addressable URL, then once the URL has been determined then the ResourceLocator should not be needed.
- Building a caching mechanism for the located resources would be difficult since parts of the originally located URL are not passed into the ResourceLocator mechanism.
- Using the combination of BinaryExport and BinaryImport between runs of the application would be dependent upon non-persisted aspects of the running instance of the application (e.g. the ResourceLocation list). This would be fine for cases where the model and textures are locally controlled, but would be problematic in cases where the models are dynamically loaded from multiple web site.
The complete resource picture would handle the following cases:
- Textures and other resources could be relatively referenced from the owning model. This is a obviously a common practice for exported models, and would apply to both local file system cases as well as web addressable models.
- Textures and other resources could use absolute references. This would be commonly used for shard resources.
- Support for a default set of resource locations. This would apply to simple games where all resources are locally controlled.
- Load a shared resource only once.
- Handle independent resources with the same relative path.
- Optionally allow for local caching of web addressable resources.
I was able to use an ImageLoader with TextureManager to handle scaling the image before it is cached by the TextureManager.
TextureManager.registerHandler(".jpg", new ImageLoader() {
public Image load(InputStream is) throws IOException {
BufferedImage image = ImageIO.read(is);
if (image.getWidth() < 3900) {
return TextureManager.loadImage(image, true);
} else {
return TextureManager.loadImage(image.getScaledInstance(
512, 512, BufferedImage.SCALE_DEFAULT), true);
}
}
});
I still believe that the BinaryExport/BinaryImport combination used to clone the texture should not need to call the ResourceLocator.