1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package jme3tools.converters;
34
35import com.jme3.math.FastMath;
36import com.jme3.texture.Image;
37import com.jme3.texture.Image.Format;
38import com.jme3.texture.plugins.AWTLoader;
39import com.jme3.util.BufferUtils;
40import java.awt.Graphics2D;
41import java.awt.RenderingHints;
42import java.awt.image.BufferedImage;
43import java.nio.ByteBuffer;
44import java.util.ArrayList;
45
46public class MipMapGenerator {
47
48    private static BufferedImage scaleDown(BufferedImage sourceImage, int targetWidth, int targetHeight) {
49        int sourceWidth  = sourceImage.getWidth();
50        int sourceHeight = sourceImage.getHeight();
51
52        BufferedImage targetImage = new BufferedImage(targetWidth, targetHeight, sourceImage.getType());
53
54        Graphics2D g = targetImage.createGraphics();
55        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
56        g.drawImage(sourceImage, 0, 0, targetWidth, targetHeight, 0, 0, sourceWidth, sourceHeight, null);
57        g.dispose();
58
59        return targetImage;
60    }
61
62    public static void resizeToPowerOf2(Image image){
63        BufferedImage original = ImageToAwt.convert(image, false, true, 0);
64        int potWidth = FastMath.nearestPowerOfTwo(image.getWidth());
65        int potHeight = FastMath.nearestPowerOfTwo(image.getHeight());
66        int potSize = Math.max(potWidth, potHeight);
67
68        BufferedImage scaled = scaleDown(original, potSize, potSize);
69
70        AWTLoader loader = new AWTLoader();
71        Image output = loader.load(scaled, false);
72
73        image.setWidth(potSize);
74        image.setHeight(potSize);
75        image.setDepth(0);
76        image.setData(output.getData(0));
77        image.setFormat(output.getFormat());
78        image.setMipMapSizes(null);
79    }
80
81    public static void generateMipMaps(Image image){
82        BufferedImage original = ImageToAwt.convert(image, false, true, 0);
83        int width = original.getWidth();
84        int height = original.getHeight();
85        int level = 0;
86
87        BufferedImage current = original;
88        AWTLoader loader = new AWTLoader();
89        ArrayList<ByteBuffer> output = new ArrayList<ByteBuffer>();
90        int totalSize = 0;
91        Format format = null;
92
93        while (height >= 1 || width >= 1){
94            Image converted = loader.load(current, false);
95            format = converted.getFormat();
96            output.add(converted.getData(0));
97            totalSize += converted.getData(0).capacity();
98
99            if(height == 1 || width == 1) {
100              break;
101            }
102
103            level++;
104
105            height /= 2;
106            width /= 2;
107
108            current = scaleDown(current, width, height);
109        }
110
111        ByteBuffer combinedData = BufferUtils.createByteBuffer(totalSize);
112        int[] mipSizes = new int[output.size()];
113        for (int i = 0; i < output.size(); i++){
114            ByteBuffer data = output.get(i);
115            data.clear();
116            combinedData.put(data);
117            mipSizes[i] = data.capacity();
118        }
119        combinedData.flip();
120
121        // insert mip data into image
122        image.setData(0, combinedData);
123        image.setMipMapSizes(mipSizes);
124        image.setFormat(format);
125    }
126
127}
128