private static int LoadBlocks()
        {
            string dir = $"{SharpCraft.Instance.GameFolderDir}\\SharpCraft_Data\\assets\\models\\block";

            if (!Directory.Exists(dir))
            {
                return(0);
            }

            var listOfBlocks = BlockRegistry.AllBlocks();

            List <string> nonDuplicateTextures = new List <string>();

            var blockModels = new ConcurrentDictionary <string, JsonBlockModel>();

            foreach (var block in listOfBlocks)
            {
                string file = $"{dir}\\{block.UnlocalizedName}.json";

                if (!File.Exists(file))
                {
                    continue;
                }

                JsonBlockModel bjm = FixBlockJson(file);

                string blockName = Path.GetFileNameWithoutExtension(file);

                blockModels.TryAdd(blockName, bjm); //save what block is using what model

                foreach (var pair in bjm.textures)  //iterating over the textureMap in the Json model
                {
                    if (!nonDuplicateTextures.Contains(pair.Value))
                    {
                        nonDuplicateTextures.Add(pair.Value); //add the current texture name to a list of all textureMap if isn't already there
                    }
                }
            }

            var textureMapElements = new Dictionary <string, TextureMapElement>();   //each texture name has it's UV values TODO - maybe make a TextureMap class where this could be used

            var id = Stitch(nonDuplicateTextures.ToArray(), 16, textureMapElements); // stitch all textureMap, return the texture ID of the registered texture in VRAM

            //TODO - if json doesn't contain cube model, assume it's a full cube
            foreach (var pair in blockModels) //one model per registered block
            {
                string         name  = pair.Key;
                JsonBlockModel model = pair.Value;

                float[] vertexes = new float[72 * model.cubes.Length];
                float[] normals  = new float[72 * model.cubes.Length];
                float[] uvs      = new float[48 * model.cubes.Length];

                for (var index = 0; index < model.cubes.Length; index++)
                {
                    var cube = model.cubes[index];

                    CubeModelBuilder.AppendCubeModel(cube, model.textures, textureMapElements, ref vertexes,
                                                     ref normals, ref uvs, index);
                }

                string particleTextureName;

                if (!model.textures.TryGetValue("particle", out particleTextureName))
                {
                    particleTextureName = model.textures.Values.ToArray()[SharpCraft.Instance.Random.Next(0, model.textures.Count)];
                }

                var tme = textureMapElements[particleTextureName];

                ModelBlock mb = new ModelBlock(tme, _blockShader, ModelManager.LoadBlockModelToVao(vertexes, normals, uvs));

                _blockModels.TryAdd(name, mb);
            }

            return(id);
        }