Search in sources :

Example 21 with Asset

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

the class ShaderGL method load.

private void load() {
    this.samplers.clear();
    shaderProgramId = glCreateProgram();
    StringBuilder vertexSource = new StringBuilder();
    StringBuilder fragSource = new StringBuilder();
    StringBuilder geometrySource = null;
    try {
        Asset vertexShader = modsManager.getAsset("./shaders/" + shaderName + "/" + shaderName + ".vs");
        Asset fragmentShader = modsManager.getAsset("./shaders/" + shaderName + "/" + shaderName + ".fs");
        // This might not exist !
        Asset geometryShader = modsManager.getAsset("./shaders/" + shaderName + "/" + shaderName + ".gs");
        GLSLPreprocessor.loadRecursivly(modsManager, vertexShader, vertexSource, false, null);
        GLSLPreprocessor.loadRecursivly(modsManager, fragmentShader, fragSource, true, null);
        // If a geometry shader asset was found
        if (geometryShader != null) {
            geometrySource = new StringBuilder();
            GLSLPreprocessor.loadRecursivly(modsManager, geometryShader, geometrySource, true, null);
        }
    } catch (IOException e) {
        logger().error("Failed to load shader program " + shaderName);
        logger().error("Exception: {}", e);
        return;
    }
    vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
    fragShaderId = glCreateShader(GL_FRAGMENT_SHADER);
    if (geometrySource != null)
        geometryShaderId = glCreateShader(GL_GEOMETRY_SHADER);
    // Anti-AMD bullshit : AMD drivers have this stupid design decision of attributing vertex attributes by lexicographical order instead of
    // order of apparition, leading to these annoying issues where an optional attribute is in index zero and disabling it screws the drawcalls
    // To counter this, this piece of code forces the attributes locations to be declared in proper order
    int i = 0;
    for (String line : vertexSource.toString().split("\n")) {
        if (line.startsWith("in ")) {
            String attributeName = line.split(" ")[2].replace(";", "");
            glBindAttribLocation(shaderProgramId, i, attributeName);
            i++;
        }
    }
    glShaderSource(vertexShaderId, vertexSource);
    glCompileShader(vertexShaderId);
    // Parse the fragment shader to look for outputs and assign them locations based on their order of appearance
    // Also look for samplers
    int j = 0;
    for (String line : fragSource.toString().split("\n")) {
        if (line.startsWith("out ")) {
            String outputName = line.split(" ")[2].replace(";", "");
            if (outputName.equals("gl_FragDepth")) {
                logger.info("Writing to depth in frag enabled");
                continue;
            }
            glBindFragDataLocation(shaderProgramId, j, outputName);
            j++;
        } else if (line.startsWith("uniform ")) {
            String[] tokens = line.split(" ");
            if (tokens.length >= 3) {
                if (tokens[1].startsWith("sampler") || tokens[1].startsWith("usampler") || tokens[1].startsWith("isampler")) {
                    SamplerType type = null;
                    if (tokens[1].endsWith("Shadow"))
                        tokens[1] = tokens[1].substring(0, tokens[1].length() - 6);
                    if (tokens[1].endsWith("1D"))
                        type = SamplerType.TEXTURE_1D;
                    else if (tokens[1].endsWith("2D"))
                        type = SamplerType.TEXTURE_2D;
                    else if (tokens[1].endsWith("3D"))
                        type = SamplerType.TEXTURE_3D;
                    else if (tokens[1].endsWith("Cube"))
                        type = SamplerType.CUBEMAP;
                    else if (tokens[1].endsWith("2DArray"))
                        type = SamplerType.ARRAY_TEXTURE_2D;
                    else {
                        logger.error("Could not recognize the sampler type: " + tokens[1]);
                    }
                    tokens[2] = tokens[2].substring(0, tokens[2].length() - 1);
                    if (type != null) {
                        samplers.put(tokens[2], type);
                    }
                }
            }
        }
    }
    glShaderSource(fragShaderId, fragSource);
    glCompileShader(fragShaderId);
    if (geometrySource != null) {
        glShaderSource(geometryShaderId, geometrySource);
        glCompileShader(geometryShaderId);
    }
    if (glGetShaderi(fragShaderId, GL_COMPILE_STATUS) == GL_FALSE) {
        logger().error("Failed to compile shader program " + shaderName + " (fragment)");
        String errorsSource = glGetShaderInfoLog(fragShaderId, 5000);
        String[] errorsLines = errorsSource.split("\n");
        String[] sourceLines = fragSource.toString().split("\n");
        for (String line : errorsLines) {
            logger().debug(line);
            if (line.toLowerCase().startsWith("error: ")) {
                String[] parsed = line.split(":");
                if (parsed.length >= 3) {
                    try {
                        int lineNumber = Integer.parseInt(parsed[2]);
                        if (sourceLines.length > lineNumber) {
                            logger.debug("@line: " + lineNumber + ": " + sourceLines[lineNumber]);
                        }
                    } catch (Exception e) {
                        logger.debug(line);
                    }
                }
            }
        }
        return;
    }
    if (glGetShaderi(vertexShaderId, GL_COMPILE_STATUS) == GL_FALSE) {
        logger().error("Failed to compile shader program " + shaderName + " (vertex)");
        String errorsSource = glGetShaderInfoLog(vertexShaderId, 5000);
        String[] errorsLines = errorsSource.split("\n");
        String[] sourceLines = vertexSource.toString().split("\n");
        for (String line : errorsLines) {
            logger().debug(line);
            if (line.toLowerCase().startsWith("error: ")) {
                String[] parsed = line.split(":");
                if (parsed.length >= 3) {
                    try {
                        int lineNumber = Integer.parseInt(parsed[2]);
                        if (sourceLines.length > lineNumber) {
                            logger.debug("@line: " + lineNumber + ": " + sourceLines[lineNumber]);
                        }
                    } catch (Exception e) {
                        logger.debug(line);
                    }
                }
            }
        }
        return;
    }
    if (geometrySource != null && glGetShaderi(geometryShaderId, GL_COMPILE_STATUS) == GL_FALSE) {
        logger().error("Failed to compile shader program " + shaderName + " (geometry)");
        String errorsSource = glGetShaderInfoLog(geometryShaderId, 5000);
        String[] errorsLines = errorsSource.split("\n");
        String[] sourceLines = geometrySource.toString().split("\n");
        for (String line : errorsLines) {
            logger().debug(line);
            if (line.toLowerCase().startsWith("error: ")) {
                String[] parsed = line.split(":");
                if (parsed.length >= 3) {
                    try {
                        int lineNumber = Integer.parseInt(parsed[2]);
                        if (sourceLines.length > lineNumber) {
                            logger.debug("@line: " + lineNumber + ": " + sourceLines[lineNumber]);
                        }
                    } catch (Exception e) {
                        logger.debug(line);
                    }
                }
            }
        }
        return;
    }
    glAttachShader(shaderProgramId, vertexShaderId);
    glAttachShader(shaderProgramId, fragShaderId);
    if (geometrySource != null)
        glAttachShader(shaderProgramId, geometryShaderId);
    glLinkProgram(shaderProgramId);
    if (glGetProgrami(shaderProgramId, GL_LINK_STATUS) == GL_FALSE) {
        logger().error("Failed to link program " + shaderName + "");
        String errorsSource = glGetProgramInfoLog(shaderProgramId, 5000);
        String[] errorsLines = errorsSource.split("\n");
        for (String line : errorsLines) {
            logger().debug(line);
        }
        return;
    }
    needValidation = true;
    loadedCorrectly = true;
}
Also used : Asset(io.xol.chunkstories.api.content.Asset) IOException(java.io.IOException) IOException(java.io.IOException)

Example 22 with Asset

use of io.xol.chunkstories.api.content.Asset 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)22 IOException (java.io.IOException)6 AssetHierarchy (io.xol.chunkstories.api.content.mods.AssetHierarchy)5 File (java.io.File)3 ArrayList (java.util.ArrayList)3 IterableIterator (io.xol.chunkstories.api.util.IterableIterator)2 BufferedReader (java.io.BufferedReader)2 Iterator (java.util.Iterator)2 PNGDecoder (de.matthiasmann.twl.utils.PNGDecoder)1 ClientInterface (io.xol.chunkstories.api.client.ClientInterface)1 IllegalVoxelDeclarationException (io.xol.chunkstories.api.exceptions.content.IllegalVoxelDeclarationException)1 MeshLoadException (io.xol.chunkstories.api.exceptions.content.MeshLoadException)1 PluginLoadException (io.xol.chunkstories.api.exceptions.plugins.PluginLoadException)1 AnimatableMesh (io.xol.chunkstories.api.mesh.AnimatableMesh)1 Mesh (io.xol.chunkstories.api.mesh.Mesh)1 VoxelRenderer (io.xol.chunkstories.api.rendering.voxel.VoxelRenderer)1 ForeignCodeClassLoader (io.xol.chunkstories.content.sandbox.ForeignCodeClassLoader)1 NotAPluginException (io.xol.chunkstories.plugin.NotAPluginException)1 PluginInformationImplementation (io.xol.chunkstories.plugin.PluginInformationImplementation)1 BufferedImage (java.awt.image.BufferedImage)1