Search in sources :

Example 1 with AssetHierarchy

use of io.xol.chunkstories.api.content.mods.AssetHierarchy in project chunkstories by Hugobros3.

the class VoxelModelsStore method resetAndLoadModels.

public void resetAndLoadModels() {
    models.clear();
    Iterator<AssetHierarchy> allFiles = voxels.parent().modsManager().getAllUniqueEntries();
    while (allFiles.hasNext()) {
        AssetHierarchy entry = allFiles.next();
        if (entry.getName().startsWith("./voxels/blockmodels/") && entry.getName().endsWith(".model")) {
            Asset f = entry.topInstance();
            readBlockModel(f);
        }
    }
}
Also used : Asset(io.xol.chunkstories.api.content.Asset) AssetHierarchy(io.xol.chunkstories.api.content.mods.AssetHierarchy)

Example 2 with AssetHierarchy

use of io.xol.chunkstories.api.content.mods.AssetHierarchy in project chunkstories by Hugobros3.

the class ModsManagerImplementation method getAllAssetsByPrefix.

@Override
public Iterator<Asset> getAllAssetsByPrefix(String prefix) {
    return new Iterator<Asset>() {

        Iterator<ModsAssetHierarchy> base = avaibleAssets.values().iterator();

        Asset next = null;

        @Override
        public boolean hasNext() {
            if (next != null)
                return true;
            // If next == null, try to set it
            while (base.hasNext()) {
                AssetHierarchy entry = base.next();
                if (entry.getName().startsWith(prefix)) {
                    next = entry.topInstance();
                    break;
                }
            }
            // Did we suceed etc
            return next != null;
        }

        @Override
        public Asset next() {
            // Try loading
            if (next == null)
                hasNext();
            // Null out reference and return it
            Asset ret = next;
            next = null;
            return ret;
        }
    };
}
Also used : Iterator(java.util.Iterator) IterableIterator(io.xol.chunkstories.api.util.IterableIterator) Asset(io.xol.chunkstories.api.content.Asset) AssetHierarchy(io.xol.chunkstories.api.content.mods.AssetHierarchy)

Example 3 with AssetHierarchy

use of io.xol.chunkstories.api.content.mods.AssetHierarchy in project chunkstories by Hugobros3.

the class ModsManagerImplementation method getAllAssetsByExtension.

@Override
public Iterator<Asset> getAllAssetsByExtension(String extension) {
    return new Iterator<Asset>() {

        Iterator<ModsAssetHierarchy> base = avaibleAssets.values().iterator();

        Asset next = null;

        @Override
        public boolean hasNext() {
            if (next != null)
                return true;
            // If next == null, try to set it
            while (base.hasNext()) {
                AssetHierarchy entry = base.next();
                if (entry.getName().endsWith(extension)) {
                    next = entry.topInstance();
                    break;
                }
            }
            // Did we suceed etc
            return next != null;
        }

        @Override
        public Asset next() {
            // Try loading
            if (next == null)
                hasNext();
            // Null out reference and return it
            Asset ret = next;
            next = null;
            return ret;
        }
    };
}
Also used : Iterator(java.util.Iterator) IterableIterator(io.xol.chunkstories.api.util.IterableIterator) Asset(io.xol.chunkstories.api.content.Asset) AssetHierarchy(io.xol.chunkstories.api.content.mods.AssetHierarchy)

Example 4 with AssetHierarchy

use of io.xol.chunkstories.api.content.mods.AssetHierarchy in project chunkstories by Hugobros3.

the class VoxelTexturesArrays method buildTextureAtlas.

public void buildTextureAtlas() {
    defaultAlbedo = null;
    defaultNormal = null;
    defaultMaterial = null;
    textures.clear();
    try {
        int gl_MaxTextureUnits = glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS);
        int gl_MaxTextureArraySize = glGetInteger(GL_MAX_ARRAY_TEXTURE_LAYERS);
        if (gl_MaxTextureArraySize < 2048) {
            logger().warn("Max texture array size < 2048. For ideal results please use a GPU from this geological era.");
        }
        if (gl_MaxTextureUnits < 32) {
            logger().warn("Max texture units < 32. This means your GPU is ancient and you'll run into a lot of issues!");
        }
        // We'll reserve 8 texture units for all the other fluff
        int maxTextureArrays = (gl_MaxTextureUnits - 8);
        List<AtlasElement> elements = new ArrayList<AtlasElement>();
        // Map<Integer, AtlasElement> sizeBuckets = new HashMap<Integer, AtlasElement>();
        // First we want to iterate over every file to get an idea of how many textures (and of how many sizes) we are dealing
        Iterator<AssetHierarchy> allFiles = content.modsManager().getAllUniqueEntries();
        AssetHierarchy entry;
        Asset f;
        while (allFiles.hasNext()) {
            entry = allFiles.next();
            if (entry.getName().startsWith("./voxels/textures/")) {
                String name = entry.getName().replace("./voxels/textures/", "");
                Type type = Type.ALBEDO;
                if (name.startsWith("normal/")) {
                    name = name.substring("normal/".length());
                    type = Type.NORMAL;
                } else if (name.startsWith("material/")) {
                    name = name.substring("material/".length());
                    type = Type.MATERIAL;
                }
                // We are only interested in top-level textures.
                if (name.contains("/"))
                    continue;
                f = entry.topInstance();
                if (f.getName().endsWith(".png")) {
                    String textureName = name.replace(".png", "");
                    // VoxelTextureAtlased voxelTexture = new VoxelTextureAtlased(textureName, uniquesIds);
                    int width, height;
                    try {
                        ImageReader reader = ImageIO.getImageReadersBySuffix("png").next();
                        ImageInputStream stream = ImageIO.createImageInputStream(f.read());
                        reader.setInput(stream);
                        width = reader.getWidth(reader.getMinIndex());
                        height = reader.getHeight(reader.getMinIndex());
                    } catch (Exception e) {
                        logger().warn("Could not obtain the size of the asset: " + f.getName());
                        // e.printStackTrace();
                        continue;
                    }
                    // We want nice powers of two
                    if ((width & (width - 1)) != 0 || (height & (height - 1)) != 0) {
                        logger().warn("Non pow2 texture size (" + width + ":" + height + ") for: " + f.getName() + ", skipping.");
                        continue;
                    }
                    // Width >= 16
                    if (width < 16 || height < 16) {
                        logger().warn("Too small (<16px) texture (" + width + ":" + height + ") for: " + f.getName() + ", skipping.");
                        continue;
                    }
                    int frames = height / width;
                    AtlasElement texture = new AtlasElement(f, type, textureName, width, frames);
                    elements.add(texture);
                    if (textureName.equals("notex")) {
                        switch(type) {
                            case ALBEDO:
                                defaultAlbedo = texture;
                                break;
                            case NORMAL:
                                defaultNormal = texture;
                                break;
                            case MATERIAL:
                                defaultMaterial = texture;
                                break;
                        }
                    }
                // System.out.println(textureName + " : " + frames);
                // sizeBuckets.put(width, texture);
                // System.out.println("Added: "+texture);
                } else if (f.getName().endsWith(".jpg") || f.getName().endsWith(".tiff") || f.getName().endsWith(".bmp") || f.getName().endsWith(".gif")) {
                    logger().warn("Found image file of unsupported format in voxels folder: " + f.getName() + ", ignoring.");
                    continue;
                }
            }
        }
        // Check we DID obtain default textures
        if (defaultAlbedo == null || defaultNormal == null || defaultMaterial == null) {
            logger().error("Missing 'notex.png' for one of the 3 texture types (albedo, normal, material), exiting !");
            System.exit(-602);
        }
        // Once that's done, try to fit all everything in the texture units constraints
        int[] sizes = new int[maxTextureArrays];
        int[] counts = new int[maxTextureArrays];
        AtlasElement[][] stuff = new AtlasElement[maxTextureArrays][gl_MaxTextureArraySize];
        int maxSize = 0;
        int maxDownscaled = 0;
        int downscaleTimes = 0;
        while (true) {
            // Check if everything could fit in N - 8 texture units
            for (int i = 0; i < maxTextureArrays; i++) {
                sizes[i] = 0;
                counts[i] = 0;
            }
            boolean ko = false;
            for (AtlasElement e : elements) {
                if (e.downscaleTo > maxSize)
                    maxSize = e.downscaleTo;
                boolean foundSpace = false;
                for (int i = 0; i < maxTextureArrays; i++) {
                    // Can create a new size
                    if (sizes[i] == 0) {
                        sizes[i] = e.downscaleTo;
                        stuff[i][counts[i]] = e;
                        counts[i] += e.animationFrames;
                        foundSpace = true;
                        break;
                    } else // Size already exist
                    if (sizes[i] == e.downscaleTo) {
                        // Has enough remaining space
                        if (gl_MaxTextureArraySize - counts[i] >= e.animationFrames) {
                            stuff[i][counts[i]] = e;
                            counts[i] += e.animationFrames;
                            foundSpace = true;
                            break;
                        }
                    }
                }
                if (foundSpace) {
                    continue;
                } else {
                    // We're out of space, cancel already
                    ko = true;
                    break;
                }
            }
            if (!ko) {
                // Everyone found a place! Go ahead it's cool
                break;
            } else {
                if (maxSize == 16) {
                    JOptionPane.showMessageDialog(null, "Exceeded vram constraints :(");
                }
                // Shrink the biggest texture size and try again
                for (AtlasElement e : elements) {
                    if (e.downscaleTo >= maxSize) {
                        e.downscaleTo = e.downscaleTo / 2;
                    }
                }
                downscaleTimes++;
                maxDownscaled = maxSize / 2;
                maxSize = 0;
            }
        }
        System.out.println("Found space OK for every " + elements.size() + " voxel texture, had to downscale " + downscaleTimes + " resolutions down to " + maxDownscaled);
        // Once we secured all the needed textures, let's assemble them in a big map
        for (int i = 0; i < maxTextureArrays; i++) {
            System.out.println("Array " + i + ": Size:" + sizes[i] + " Count:" + counts[i]);
            sizes[i] = 0;
            counts[i] = 0;
            for (int j = 0; j < counts[i]; j++) {
                AtlasElement element = stuff[i][j];
                VoxelTextureArrayed completedTexture = textures.get(element.name);
                if (completedTexture == null) {
                    completedTexture = new VoxelTextureArrayed(element.name);
                    textures.put(element.name, completedTexture);
                }
                switch(element.type) {
                    case ALBEDO:
                        completedTexture.albedo = element;
                        break;
                    case NORMAL:
                        completedTexture.normal = element;
                        break;
                    case MATERIAL:
                        completedTexture.material = element;
                        break;
                }
            }
        }
    } catch (Exception e) {
        logger().error("Exception during loading of voxel textures: " + e.getMessage());
        // e.printStackTrace(logger().getPrintWriter());
        e.printStackTrace();
    }
    System.exit(0);
}
Also used : ImageInputStream(javax.imageio.stream.ImageInputStream) ArrayList(java.util.ArrayList) Asset(io.xol.chunkstories.api.content.Asset) AssetHierarchy(io.xol.chunkstories.api.content.mods.AssetHierarchy) ImageReader(javax.imageio.ImageReader)

Example 5 with AssetHierarchy

use of io.xol.chunkstories.api.content.mods.AssetHierarchy in project chunkstories by Hugobros3.

the class VoxelTexturesStoreAndAtlaser method buildTextureAtlas.

public void buildTextureAtlas() {
    try {
        // Clear previous values
        texMap.clear();
        // colors.clear();
        // Compute all sizes first.
        int totalSurfacedNeeded = 0;
        // File folder = new File("./res/voxels/textures/");
        // Get all sizes :
        List<VoxelTextureAtlased> voxelTexturesSortedBySize = new ArrayList<VoxelTextureAtlased>();
        // First we want to iterate over every file to get an idea of how many textures (and of how many sizes) we are dealing
        Iterator<AssetHierarchy> allFiles = content.modsManager().getAllUniqueEntries();
        AssetHierarchy entry;
        Asset f;
        while (allFiles.hasNext()) {
            entry = allFiles.next();
            if (entry.getName().startsWith("./voxels/textures/")) {
                String name = entry.getName().replace("./voxels/textures/", "");
                if (name.contains("/"))
                    continue;
                f = entry.topInstance();
                if (f.getName().endsWith(".png")) {
                    String textureName = name.replace(".png", "");
                    // System.out.println("texName:"+textureName+" "+entry.getKey());
                    if (!texMap.containsKey(textureName)) {
                        VoxelTextureAtlased voxelTexture = new VoxelTextureAtlased(textureName, uniquesIds);
                        uniquesIds++;
                        voxelTexture.imageFileDimensions = getImageSize(f);
                        voxelTexturesSortedBySize.add(voxelTexture);
                        totalSurfacedNeeded += voxelTexture.imageFileDimensions * voxelTexture.imageFileDimensions;
                    }
                }
            }
        }
        // Sort them by size
        Collections.sort(voxelTexturesSortedBySize, new Comparator<VoxelTextureAtlased>() {

            @Override
            public int compare(VoxelTextureAtlased a, VoxelTextureAtlased b) {
                return Integer.compare(b.imageFileDimensions, a.imageFileDimensions);
            }
        });
        for (VoxelTextureAtlased voxelTexture : voxelTexturesSortedBySize) {
            // System.out.println(vt.imageFileDimensions);
            texMap.put(voxelTexture.getName(), voxelTexture);
        }
        // Estimates the required texture atlas size by surface
        int sizeRequired = 16;
        for (int i = 4; i < 14; i++) {
            int iSize = (int) Math.pow(2, i);
            if (iSize * iSize >= totalSurfacedNeeded) {
                sizeRequired = iSize;
                break;
            }
        }
        // ChunkStoriesLogger.getInstance().info("At least " + sizeRequired + " by " + sizeRequired + " for TextureAtlas (surfacedNeeded : " + totalSurfacedNeeded + ")");
        // Delete previous atlases
        File diffuseTextureFile = new File(GameDirectory.getGameFolderPath() + "/cache/tiles_merged_albedo.png");
        if (diffuseTextureFile.exists())
            diffuseTextureFile.delete();
        File normalTextureFile = new File(GameDirectory.getGameFolderPath() + "/cache/tiles_merged_normal.png");
        if (normalTextureFile.exists())
            normalTextureFile.delete();
        File materialTextureFile = new File(GameDirectory.getGameFolderPath() + "/cache/tiles_merged_material.png");
        if (materialTextureFile.exists())
            materialTextureFile.delete();
        // Build the new one
        boolean loadedOK = false;
        while (// Security to prevend
        !loadedOK && sizeRequired <= 8192) // HUGE-ASS textures
        {
            // We need this
            BLOCK_ATLAS_SIZE = sizeRequired;
            BLOCK_ATLAS_FACTOR = 32768 / BLOCK_ATLAS_SIZE;
            loadedOK = true;
            // Create boolean bitfield
            boolean[][] used = new boolean[sizeRequired / 16][sizeRequired / 16];
            diffuseTextureImage = null;
            normalTextureImage = null;
            materialTextureImage = null;
            if (content.getContext() instanceof ClientInterface) {
                diffuseTextureImage = new BufferedImage(sizeRequired, sizeRequired, Transparency.TRANSLUCENT);
                normalTextureImage = new BufferedImage(sizeRequired, sizeRequired, Transparency.TRANSLUCENT);
                materialTextureImage = new BufferedImage(sizeRequired, sizeRequired, Transparency.TRANSLUCENT);
                logger.debug("This is a client so we'll make the texture atlas");
            }
            BufferedImage imageBuffer;
            for (VoxelTextureAtlased vt : voxelTexturesSortedBySize) {
                // Find a free spot on the atlas
                boolean foundSpot = false;
                int spotX = 0, spotY = 0;
                for (int a = 0; (a < sizeRequired / 16 && !foundSpot); a++) for (int b = 0; (b < sizeRequired / 16 && !foundSpot); b++) {
                    if (// Unused
                    used[a][b] == false && a + vt.imageFileDimensions / 16 <= sizeRequired / 16 && b + vt.imageFileDimensions / 16 <= sizeRequired / 16) {
                        boolean usedAlready = false;
                        // Not pretty loops that do clamped space checks
                        for (int i = 0; (i < vt.imageFileDimensions / 16 && a + i < sizeRequired / 16); i++) for (int j = 0; (j < vt.imageFileDimensions / 16 && b + j < sizeRequired / 16); j++) if (// Well
                        used[a + i][b + j] == true)
                            // fuck
                            // it
                            usedAlready = true;
                        if (!usedAlready) {
                            spotX = a * 16;
                            spotY = b * 16;
                            vt.setAtlasS(spotX * BLOCK_ATLAS_FACTOR);
                            vt.setAtlasT(spotY * BLOCK_ATLAS_FACTOR);
                            vt.setAtlasOffset(vt.imageFileDimensions * BLOCK_ATLAS_FACTOR);
                            foundSpot = true;
                            for (int i = 0; (i < vt.imageFileDimensions / 16 && a + i < sizeRequired / 16); i++) for (int j = 0; (j < vt.imageFileDimensions / 16 && b + j < sizeRequired / 16); j++) used[a + i][b + j] = true;
                        }
                    }
                }
                if (!foundSpot) {
                    System.out.println("Failed to find a space to place the texture in. Retrying with a larger atlas.");
                    loadedOK = false;
                    break;
                }
                imageBuffer = ImageIO.read(content.modsManager().getAsset("./voxels/textures/" + vt.getName() + ".png").read());
                // imageBuffer = ImageIO.read(GameContent.getTextureFileLocation());
                float alphaTotal = 0;
                int nonNullPixels = 0;
                Vector3f color = new Vector3f();
                for (int x = 0; x < vt.imageFileDimensions; x++) {
                    for (int y = 0; y < vt.imageFileDimensions; y++) {
                        int rgb = imageBuffer.getRGB(x, y);
                        if (diffuseTextureImage != null)
                            diffuseTextureImage.setRGB(spotX + x, spotY + y, rgb);
                        float alpha = ((rgb & 0xFF000000) >>> 24) / 255f;
                        // System.out.println("a:"+alpha);
                        alphaTotal += alpha;
                        if (alpha > 0)
                            nonNullPixels++;
                        float red = ((rgb & 0xFF0000) >> 16) / 255f * alpha;
                        float green = ((rgb & 0x00FF00) >> 8) / 255f * alpha;
                        float blue = (rgb & 0x0000FF) / 255f * alpha;
                        color.add(new Vector3f(red, green, blue));
                    // Vector3f.add(color, new Vector3f(red, green, blue), color);
                    }
                }
                color.mul(1f / alphaTotal);
                if (nonNullPixels > 0)
                    alphaTotal /= nonNullPixels;
                vt.setColor(new Vector4f(color.x(), color.y(), color.z(), alphaTotal));
                // Don't bother if it's not a Client context
                if (diffuseTextureImage == null)
                    continue;
                // Do also the normal maps !
                Asset normalMap = content.modsManager().getAsset("./voxels/textures/normal/" + vt.getName() + ".png");
                if (normalMap == null)
                    normalMap = content.modsManager().getAsset("./voxels/textures/normal/notex.png");
                imageBuffer = ImageIO.read(normalMap.read());
                for (int x = 0; x < vt.imageFileDimensions; x++) {
                    for (int y = 0; y < vt.imageFileDimensions; y++) {
                        int rgb = imageBuffer.getRGB(x % imageBuffer.getWidth(), y % imageBuffer.getHeight());
                        normalTextureImage.setRGB(spotX + x, spotY + y, rgb);
                    }
                }
                // And the materials !
                Asset materialMap = content.modsManager().getAsset("./voxels/textures/material/" + vt.getName() + ".png");
                if (materialMap == null)
                    materialMap = content.modsManager().getAsset("./voxels/textures/material/notex.png");
                imageBuffer = ImageIO.read(materialMap.read());
                for (int x = 0; x < vt.imageFileDimensions; x++) {
                    for (int y = 0; y < vt.imageFileDimensions; y++) {
                        int rgb = imageBuffer.getRGB(x % imageBuffer.getWidth(), y % imageBuffer.getHeight());
                        materialTextureImage.setRGB(spotX + x, spotY + y, rgb);
                    }
                }
            }
            if (loadedOK && diffuseTextureImage != null) {
                // save it son
                ImageIO.write(diffuseTextureImage, "PNG", diffuseTextureFile);
                ImageIO.write(normalTextureImage, "PNG", normalTextureFile);
                ImageIO.write(materialTextureImage, "PNG", materialTextureFile);
                diffuseTexture = null;
                normalTexture = null;
                materialTexture = null;
            } else
                // It's too small, initial estimation was wrong !
                sizeRequired *= 2;
        }
        // Read textures metadata
        // TODO read all overrides in priority
        readTexturesMeta(content.modsManager().getAsset("./voxels/textures/meta.txt"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Also used : ArrayList(java.util.ArrayList) ClientInterface(io.xol.chunkstories.api.client.ClientInterface) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException) Vector4f(org.joml.Vector4f) Vector3f(org.joml.Vector3f) Asset(io.xol.chunkstories.api.content.Asset) AssetHierarchy(io.xol.chunkstories.api.content.mods.AssetHierarchy) File(java.io.File)

Aggregations

Asset (io.xol.chunkstories.api.content.Asset)5 AssetHierarchy (io.xol.chunkstories.api.content.mods.AssetHierarchy)5 IterableIterator (io.xol.chunkstories.api.util.IterableIterator)2 ArrayList (java.util.ArrayList)2 Iterator (java.util.Iterator)2 ClientInterface (io.xol.chunkstories.api.client.ClientInterface)1 BufferedImage (java.awt.image.BufferedImage)1 File (java.io.File)1 IOException (java.io.IOException)1 ImageReader (javax.imageio.ImageReader)1 ImageInputStream (javax.imageio.stream.ImageInputStream)1 Vector3f (org.joml.Vector3f)1 Vector4f (org.joml.Vector4f)1