private static bool LoadFromBinaryV2(string path, ThermalDataT <PipelineV2.ThermalCell> thermalData, ref Header header)
    {
        using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)))
        {
            header.resolution = reader.ReadUInt32();
            header.minValue   = reader.ReadSingle();
            header.maxValue   = reader.ReadSingle();
            header.sizeX      = reader.ReadSingle();
            header.sizeY      = reader.ReadSingle();
            header.sizeZ      = reader.ReadSingle();
            uint count = reader.ReadUInt32();

            thermalData.frames                     = new ThermalFrame[2];
            thermalData.frames[1].offset           = count;
            thermalData.frames[1].minTemperature   = header.minValue;
            thermalData.frames[1].temperatureRange = header.maxValue - header.minValue;

            thermalData.CreateCells(count);
            for (uint i = 0; i < count; i++)
            {
                thermalData.cells[i].index       = reader.ReadUInt32();
                thermalData.cells[i].temperature = reader.ReadSingle();
            }

            Debug.Log("Loaded " + count + " cells");
        }

        return(true);
    }
    public static unsafe bool LoadFromBinary <C>(string path, uint level, int startTime, int endTime, uint interval, ThermalDataT <C> thermalData)
        where C : struct
    {
        Stopwatch sw = new Stopwatch();

        sw.Start();

        string filename = path + "LOD" + level + "_" + startTime + "_" + endTime + ".heat";

        if (!File.Exists(filename))
        {
            UnityDebug.LogError("Couldn't find file " + filename);
            return(false);
        }

        IntPtr fileHandle = IntPtr.Zero;

        if (!Open(filename, ref fileHandle))
        {
            UnityDebug.LogError("Couldn't open file " + filename);
            return(false);
        }

        int size;
        int bytesRead = 0;

        // Read header
        ThermalDataHeader  header  = new ThermalDataHeader();
        ThermalDataHeader *pHeader = &header;

        ReadFile(fileHandle, pHeader, sizeof(ThermalDataHeader), &bytesRead, 0);

#if ENABLE_SAFETY_CHECKS
        if (level != header.level)
        {
            UnityDebug.LogError("File " + filename + "contains invalid header LOD: " + header.level);
            CloseHandle(fileHandle);
            return(false);
        }
        if (startTime != header.startTime)
        {
            UnityDebug.LogError("File " + filename + "contains invalid header start time: " + header.startTime);
            CloseHandle(fileHandle);
            return(false);
        }
        if (endTime != header.endTime)
        {
            UnityDebug.LogError("File " + filename + "contains invalid header end time: " + header.endTime);
            CloseHandle(fileHandle);
            return(false);
        }
#endif
        thermalData.startTime = header.startTime;
        thermalData.endTime   = header.endTime;

        // UnityDebug.Log("Loading level " + header.level + " from " + header.startTime + " to " + header.endTime + " with " + header.count + " elements.");

        // Note: add 1 element at the beginning of the keyframes buffer with value 0
        // for easier computation and reduce if statements
        uint framesCount = (uint)(endTime - startTime) / interval + 1;
        if (thermalData.frames == null || thermalData.frames.Length != framesCount)
        {
            thermalData.frames = new ThermalFrame[framesCount];
        }

        // Read keyframes
        bytesRead = 0;
        size      = (int)((framesCount - 1) * sizeof(ThermalFrame));
        fixed(ThermalFrame *pFirst = &thermalData.frames[1])
        {
            if (!ReadFile(fileHandle, pFirst, size, &bytesRead, 0))
            {
                UnityDebug.LogError("Couldn't read keyframes!");
                CloseHandle(fileHandle);
                return(false);
            }
        }

#if ENABLE_SAFETY_CHECKS
        if (bytesRead != size)
        {
            UnityDebug.LogError("Keyframes: only read " + bytesRead + " bytes out of " + size);
        }
        if (thermalData.frames[framesCount - 1].offset != header.count)
        {
            UnityDebug.LogError("Keyframes: last offset is " + thermalData.frames[framesCount - 1].offset + ", expected " + header.count);
        }
#endif

        if (header.count > 0)
        {
            // Create thermal cells buffer
            if (thermalData.cells == null || thermalData.cells.Length < header.count)
            {
                thermalData.CreateCells(header.count);
            }

            // Read thermal cells
            size = (int)header.count * GetCellSize(thermalData.cells);
            if (!ReadFile(fileHandle, thermalData.GetCellsPointer(), size, &bytesRead, 0))
            {
                UnityDebug.LogError("Couldn't read thermal cells!");
                CloseHandle(fileHandle);
                return(false);
            }
#if ENABLE_SAFETY_CHECKS
            if (bytesRead != size)
            {
                UnityDebug.LogError("Heat cells: only read " + bytesRead + " bytes out of " + size);
            }
#endif
        }

        CloseHandle(fileHandle);

        sw.Stop();
        if (sw.Elapsed.TotalMilliseconds > 120)
        {
            UnityDebug.LogWarning("Parsing " + filename + " took " + sw.Elapsed.TotalMilliseconds + "ms.");
        }
        return(true);
    }