public void updateTexImageData(Image img, Texture.Type type, int unit, boolean scaleToPot) {
        int texId = img.getId();
        if (texId == -1) {
            // create texture
            gl.glGenTextures(intBuf1);
            texId = intBuf1.get(0);
            img.setId(texId);
            objManager.registerObject(img);

            statistics.onNewTexture();
        }

        // bind texture
        int target = convertTextureType(type, img.getMultiSamples(), -1);
        bindTextureAndUnit(target, img, unit);

        int imageSamples = img.getMultiSamples();
        if (imageSamples <= 1) {
            if (!img.hasMipmaps() && img.isGeneratedMipmapsRequired()) {
                // Image does not have mipmaps, but they are required.
                // Generate from base level.

                if (!caps.contains(Caps.FrameBuffer) && gl2 != null) {
                    gl2.glTexParameteri(target, GL2.GL_GENERATE_MIPMAP, GL.GL_TRUE);
                    img.setMipmapsGenerated(true);
                } else {
                    // For OpenGL3 and up.
                    // We'll generate mipmaps via glGenerateMipmapEXT (see below)
                }
            } else if (caps.contains(Caps.OpenGL20) || caps.contains(Caps.OpenGLES30)) {
                if (img.hasMipmaps()) {
                    // Image already has mipmaps, set the max level based on the
                    // number of mipmaps we have.
                    gl.glTexParameteri(target, GL2.GL_TEXTURE_MAX_LEVEL, img.getMipMapSizes().length - 1);
                } else {
                    // Image does not have mipmaps, and they are not required.
                    // Specify that the texture has no mipmaps.
                    gl.glTexParameteri(target, GL2.GL_TEXTURE_MAX_LEVEL, 0);
                }
            }
        } else {
            // Check if graphics card doesn't support multisample textures
            if (!caps.contains(Caps.TextureMultisample)) {
                throw new RendererException("Multisample textures are not supported by the video hardware");
            }

            if (img.isGeneratedMipmapsRequired() || img.hasMipmaps()) {
                throw new RendererException("Multisample textures do not support mipmaps");
            }

            if (img.getFormat().isDepthFormat()) {
                img.setMultiSamples(Math.min(limits.get(Limits.DepthTextureSamples), imageSamples));
            } else {
                img.setMultiSamples(Math.min(limits.get(Limits.ColorTextureSamples), imageSamples));
            }

            scaleToPot = false;
        }

        // Check if graphics card doesn't support depth textures
        if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) {
            throw new RendererException("Depth textures are not supported by the video hardware");
        }

        if (target == GL.GL_TEXTURE_CUBE_MAP) {
            // Check max texture size before upload
            int cubeSize = limits.get(Limits.CubemapSize);
            if (img.getWidth() > cubeSize || img.getHeight() > cubeSize) {
                throw new RendererException("Cannot upload cubemap " + img + ". The maximum supported cubemap resolution is " + cubeSize);
            }
            if (img.getWidth() != img.getHeight()) {
                throw new RendererException("Cubemaps must have square dimensions");
            }
        } else {
            int texSize = limits.get(Limits.TextureSize);
            if (img.getWidth() > texSize || img.getHeight() > texSize) {
                throw new RendererException("Cannot upload texture " + img + ". The maximum supported texture resolution is " + texSize);
            }
        }

        Image imageForUpload;
        if (scaleToPot) {
            imageForUpload = MipMapGenerator.resizeToPowerOf2(img);
        } else {
            imageForUpload = img;
        }
        if (target == GL.GL_TEXTURE_CUBE_MAP) {
            List<ByteBuffer> data = imageForUpload.getData();
            if (data.size() != 6) {
                logger.log(Level.WARNING, "Invalid texture: {0}\n"
                        + "Cubemap textures must contain 6 data units.", img);
                return;
            }
            for (int i = 0; i < 6; i++) {
                texUtil.uploadTexture(imageForUpload, GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, linearizeSrgbImages);
            }
        } else if (target == GLExt.GL_TEXTURE_2D_ARRAY_EXT) {
            if (!caps.contains(Caps.TextureArray)) {
                throw new RendererException("Texture arrays not supported by graphics hardware");
            }

            List<ByteBuffer> data = imageForUpload.getData();

            // -1 index specifies prepare data for 2D Array
            texUtil.uploadTexture(imageForUpload, target, -1, linearizeSrgbImages);

            for (int i = 0; i < data.size(); i++) {
                // upload each slice of 2D array in turn
                // this time with the appropriate index
                texUtil.uploadTexture(imageForUpload, target, i, linearizeSrgbImages);
            }
        } else {
            texUtil.uploadTexture(imageForUpload, target, 0, linearizeSrgbImages);
        }

        if (img.getMultiSamples() != imageSamples) {
            img.setMultiSamples(imageSamples);
        }

        if (caps.contains(Caps.FrameBuffer) || gl2 == null) {
            if (!img.hasMipmaps() && img.isGeneratedMipmapsRequired() && img.getData(0) != null) {
                glfbo.glGenerateMipmapEXT(target);
                img.setMipmapsGenerated(true);
            }
        }

        img.clearUpdateNeeded();
    }
Uploads the given image to the GL driver.

@param img The image to upload
@param type How the data in the image argument should be interpreted.
@param unit The texture slot to be used to upload the image, not important
@param scaleToPot If true, the image will be scaled to power-of-2 dimensions
before being uploaded.
jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java