<commit_before>#include "GHIElectronics_TinyCLR_Devices_Storage.h"
#include "../GHIElectronics_TinyCLR_InteropUtil.h"

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::get_Descriptor___GHIElectronicsTinyCLRDevicesStorageStorageDescriptor(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    const TinyCLR_Storage_Descriptor* descriptor;

    auto result = api->GetDescriptor(api, descriptor);

    TinyCLR_Interop_ClrValue obj, ret;
    TinyCLR_Interop_ClrTypeId type;

    md.InteropManager->FindType(md.InteropManager, "GHIElectronics.TinyCLR.Devices.Storage", "GHIElectronics.TinyCLR.Devices.Storage", "StorageDescriptor", type);

    md.InteropManager->CreateObject(md.InteropManager, md.Stack, type, obj);

    TinyCLR_Interop_ClrValue canReadDirectField, canWriteDirectField, canExecuteDirectField, eraseBeforeWriteField, removableField, regionsContiguousField, regionsEqualSizedField, regionCountField, regionAddressesField, regionSizesField;

    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___CanReadDirect__BackingField___BOOLEAN, canReadDirectField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___CanWriteDirect__BackingField___BOOLEAN, canWriteDirectField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___CanExecuteDirect__BackingField___BOOLEAN, canExecuteDirectField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___EraseBeforeWrite__BackingField___BOOLEAN, eraseBeforeWriteField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___Removable__BackingField___BOOLEAN, removableField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionsContiguous__BackingField___BOOLEAN, regionsContiguousField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionsEqualSized__BackingField___BOOLEAN, regionsEqualSizedField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionCount__BackingField___I4, regionCountField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionAddresses__BackingField___SZARRAY_I8, regionAddressesField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionSizes__BackingField___SZARRAY_I4, regionSizesField);

    if (descriptor != nullptr) {
        canReadDirectField.Data.Numeric->Boolean = descriptor->CanReadDirect;
        canWriteDirectField.Data.Numeric->Boolean = descriptor->CanWriteDirect;
        canExecuteDirectField.Data.Numeric->Boolean = descriptor->CanWriteDirect;
        eraseBeforeWriteField.Data.Numeric->Boolean = descriptor->EraseBeforeWrite;
        removableField.Data.Numeric->Boolean = descriptor->Removable;
        regionsContiguousField.Data.Numeric->Boolean = descriptor->RegionsContiguous;
        regionsEqualSizedField.Data.Numeric->Boolean = descriptor->RegionsEqualSized;
        regionCountField.Data.Numeric->I4 = descriptor->RegionCount;

        md.InteropManager->FindType(md.InteropManager, "mscorlib", "System", "Int64", type);
        md.InteropManager->CreateArray(md.InteropManager, descriptor->RegionCount, type, regionAddressesField);

        md.InteropManager->FindType(md.InteropManager, "mscorlib", "System", "Int32", type);
        md.InteropManager->CreateArray(md.InteropManager, descriptor->RegionCount, type, regionSizesField);

        auto regionAddresses = reinterpret_cast<int64_t*>(regionAddressesField.Data.SzArray.Data);
        auto regionSizes = reinterpret_cast<int32_t*>(regionSizesField.Data.SzArray.Data);

        for (auto i = 0; i < descriptor->RegionCount; i++) {
            regionAddresses[i] = descriptor->RegionAddresses[i];
            regionSizes[i] = descriptor->RegionSizes[i];
        }

        md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

        md.InteropManager->AssignObjectReference(md.InteropManager, ret, obj.Object);
    }

    return TinyCLR_Result::Success;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Open___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Open(api);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Close___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Close(api);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Read___I4__I8__I4__SZARRAY_U1__I4__mscorlibSystemTimeSpan(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    TinyCLR_Interop_ClrValue args[5];

    for (auto i = 0; i < sizeof(args) / sizeof(TinyCLR_Interop_ClrValue); i++) {
        md.InteropManager->GetArgument(md.InteropManager, md.Stack, i, args[i]);
    }

    auto sector = static_cast<uint64_t>(args[0].Data.Numeric->I8);
    auto count = static_cast<size_t>(args[1].Data.Numeric->I4);
    auto buffer = reinterpret_cast<uint8_t*>(args[2].Data.SzArray.Data);
    auto offset = args[3].Data.Numeric->I8;
    auto timeout = args[4].Data.Numeric->I4;

    buffer += offset;

    auto result = api->Read(api, sector, count, buffer, timeout);

    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    ret.Data.Numeric->I4 = count;

    return result;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Write___I4__I8__I4__SZARRAY_U1__I4__mscorlibSystemTimeSpan(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    TinyCLR_Interop_ClrValue args[5];

    for (auto i = 0; i < sizeof(args) / sizeof(TinyCLR_Interop_ClrValue); i++) {
        md.InteropManager->GetArgument(md.InteropManager, md.Stack, i, args[i]);
    }

    auto sector = static_cast<uint64_t>(args[0].Data.Numeric->I8);
    auto count = static_cast<size_t>(args[1].Data.Numeric->I4);
    auto buffer = reinterpret_cast<uint8_t*>(args[2].Data.SzArray.Data);
    auto offset = args[3].Data.Numeric->I4;
    auto timeout = args[4].Data.Numeric->I8;

    buffer += offset;

    auto result = api->Write(api, sector, count, buffer, timeout);

    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    ret.Data.Numeric->I4 = count;

    return result;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Erase___I4__I8__I4__mscorlibSystemTimeSpan(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    TinyCLR_Interop_ClrValue args[3];

    for (auto i = 0; i < sizeof(args) / sizeof(TinyCLR_Interop_ClrValue); i++) {
        md.InteropManager->GetArgument(md.InteropManager, md.Stack, i, args[i]);
    }

    auto sector = static_cast<uint64_t>(args[0].Data.Numeric->I8);
    auto count = static_cast<size_t>(args[1].Data.Numeric->I4);

    auto timeout = args[2].Data.Numeric->I8;

    auto result = api->Erase(api, sector, count, timeout);

    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    ret.Data.Numeric->I4 = count;

    return result;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::IsErased___BOOLEAN__I8__I4(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));
    TinyCLR_Interop_ClrValue arg0, arg1, ret;

    md.InteropManager->GetArgument(md.InteropManager, md.Stack, 0, arg0);
    md.InteropManager->GetArgument(md.InteropManager, md.Stack, 1, arg1);
    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    size_t count = arg1.Data.Numeric->I4;

    return api->IsErased(api, arg0.Data.Numeric->I8, count, ret.Data.Numeric->Boolean);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Acquire___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Acquire(api);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Release___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Release(api);
}
<commit_msg>Rename. Variable should be address, not sector.<commit_after>#include "GHIElectronics_TinyCLR_Devices_Storage.h"
#include "../GHIElectronics_TinyCLR_InteropUtil.h"

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::get_Descriptor___GHIElectronicsTinyCLRDevicesStorageStorageDescriptor(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    const TinyCLR_Storage_Descriptor* descriptor;

    auto result = api->GetDescriptor(api, descriptor);

    TinyCLR_Interop_ClrValue obj, ret;
    TinyCLR_Interop_ClrTypeId type;

    md.InteropManager->FindType(md.InteropManager, "GHIElectronics.TinyCLR.Devices.Storage", "GHIElectronics.TinyCLR.Devices.Storage", "StorageDescriptor", type);

    md.InteropManager->CreateObject(md.InteropManager, md.Stack, type, obj);

    TinyCLR_Interop_ClrValue canReadDirectField, canWriteDirectField, canExecuteDirectField, eraseBeforeWriteField, removableField, regionsContiguousField, regionsEqualSizedField, regionCountField, regionAddressesField, regionSizesField;

    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___CanReadDirect__BackingField___BOOLEAN, canReadDirectField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___CanWriteDirect__BackingField___BOOLEAN, canWriteDirectField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___CanExecuteDirect__BackingField___BOOLEAN, canExecuteDirectField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___EraseBeforeWrite__BackingField___BOOLEAN, eraseBeforeWriteField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___Removable__BackingField___BOOLEAN, removableField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionsContiguous__BackingField___BOOLEAN, regionsContiguousField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionsEqualSized__BackingField___BOOLEAN, regionsEqualSizedField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionCount__BackingField___I4, regionCountField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionAddresses__BackingField___SZARRAY_I8, regionAddressesField);
    md.InteropManager->GetField(md.InteropManager, obj.Object, Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_StorageDescriptor::FIELD___RegionSizes__BackingField___SZARRAY_I4, regionSizesField);

    if (descriptor != nullptr) {
        canReadDirectField.Data.Numeric->Boolean = descriptor->CanReadDirect;
        canWriteDirectField.Data.Numeric->Boolean = descriptor->CanWriteDirect;
        canExecuteDirectField.Data.Numeric->Boolean = descriptor->CanWriteDirect;
        eraseBeforeWriteField.Data.Numeric->Boolean = descriptor->EraseBeforeWrite;
        removableField.Data.Numeric->Boolean = descriptor->Removable;
        regionsContiguousField.Data.Numeric->Boolean = descriptor->RegionsContiguous;
        regionsEqualSizedField.Data.Numeric->Boolean = descriptor->RegionsEqualSized;
        regionCountField.Data.Numeric->I4 = descriptor->RegionCount;

        md.InteropManager->FindType(md.InteropManager, "mscorlib", "System", "Int64", type);
        md.InteropManager->CreateArray(md.InteropManager, descriptor->RegionCount, type, regionAddressesField);

        md.InteropManager->FindType(md.InteropManager, "mscorlib", "System", "Int32", type);
        md.InteropManager->CreateArray(md.InteropManager, descriptor->RegionCount, type, regionSizesField);

        auto regionAddresses = reinterpret_cast<int64_t*>(regionAddressesField.Data.SzArray.Data);
        auto regionSizes = reinterpret_cast<int32_t*>(regionSizesField.Data.SzArray.Data);

        for (auto i = 0; i < descriptor->RegionCount; i++) {
            regionAddresses[i] = descriptor->RegionAddresses[i];
            regionSizes[i] = descriptor->RegionSizes[i];
        }

        md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

        md.InteropManager->AssignObjectReference(md.InteropManager, ret, obj.Object);
    }

    return TinyCLR_Result::Success;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Open___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Open(api);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Close___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Close(api);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Read___I4__I8__I4__SZARRAY_U1__I4__mscorlibSystemTimeSpan(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    TinyCLR_Interop_ClrValue args[5];

    for (auto i = 0; i < sizeof(args) / sizeof(TinyCLR_Interop_ClrValue); i++) {
        md.InteropManager->GetArgument(md.InteropManager, md.Stack, i, args[i]);
    }

    auto address = static_cast<uint64_t>(args[0].Data.Numeric->I8);
    auto count = static_cast<size_t>(args[1].Data.Numeric->I4);
    auto buffer = reinterpret_cast<uint8_t*>(args[2].Data.SzArray.Data);
    auto offset = args[3].Data.Numeric->I8;
    auto timeout = args[4].Data.Numeric->I4;

    buffer += offset;

    auto result = api->Read(api, address, count, buffer, timeout);

    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    ret.Data.Numeric->I4 = count;

    return result;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Write___I4__I8__I4__SZARRAY_U1__I4__mscorlibSystemTimeSpan(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    TinyCLR_Interop_ClrValue args[5];

    for (auto i = 0; i < sizeof(args) / sizeof(TinyCLR_Interop_ClrValue); i++) {
        md.InteropManager->GetArgument(md.InteropManager, md.Stack, i, args[i]);
    }

    auto address = static_cast<uint64_t>(args[0].Data.Numeric->I8);
    auto count = static_cast<size_t>(args[1].Data.Numeric->I4);
    auto buffer = reinterpret_cast<uint8_t*>(args[2].Data.SzArray.Data);
    auto offset = args[3].Data.Numeric->I4;
    auto timeout = args[4].Data.Numeric->I8;

    buffer += offset;

    auto result = api->Write(api, address, count, buffer, timeout);

    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    ret.Data.Numeric->I4 = count;

    return result;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Erase___I4__I8__I4__mscorlibSystemTimeSpan(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    TinyCLR_Interop_ClrValue args[3];

    for (auto i = 0; i < sizeof(args) / sizeof(TinyCLR_Interop_ClrValue); i++) {
        md.InteropManager->GetArgument(md.InteropManager, md.Stack, i, args[i]);
    }

    auto address = static_cast<uint64_t>(args[0].Data.Numeric->I8);
    auto count = static_cast<size_t>(args[1].Data.Numeric->I4);

    auto timeout = args[2].Data.Numeric->I8;

    auto result = api->Erase(api, address, count, timeout);

    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    ret.Data.Numeric->I4 = count;

    return result;
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::IsErased___BOOLEAN__I8__I4(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));
    TinyCLR_Interop_ClrValue arg0, arg1, ret;

    md.InteropManager->GetArgument(md.InteropManager, md.Stack, 0, arg0);
    md.InteropManager->GetArgument(md.InteropManager, md.Stack, 1, arg1);
    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    size_t count = arg1.Data.Numeric->I4;

    return api->IsErased(api, arg0.Data.Numeric->I8, count, ret.Data.Numeric->Boolean);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Acquire___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Acquire(api);
}

TinyCLR_Result Interop_GHIElectronics_TinyCLR_Devices_Storage_GHIElectronics_TinyCLR_Devices_Storage_Provider_StorageControllerApiWrapper::Release___VOID(const TinyCLR_Interop_MethodData md) {
    auto api = reinterpret_cast<const TinyCLR_Storage_Controller*>(TinyCLR_Interop_GetApi(md, FIELD___impl___I));

    return api->Release(api);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014 Kajetan Swierk <k0zmo@outlook.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#include "Logic/NodeType.h"
#include "Logic/NodeFactory.h"
#include "Kommon/Utils.h"
#include "Kommon/StringUtils.h"

#include <opencv2/features2d/features2d.hpp>

using std::vector;

static vector<cv::DMatch> distanceRatioTest(const vector<vector<cv::DMatch>>& knMatches,
                                            float distanceRatioThreshold)
{
    vector<cv::DMatch> positiveMatches;
    positiveMatches.reserve(knMatches.size());

    for(const auto& knMatch : knMatches)
    {
        if(knMatch.size() != 2)
            continue;

        const auto& best = knMatch[0];
        const auto& good = knMatch[1];

        if(best.distance <= distanceRatioThreshold * good.distance)
            positiveMatches.push_back(best);
    }

    return positiveMatches;
}

static vector<cv::DMatch> symmetryTest(const vector<cv::DMatch>& matches1to2,
                                       const vector<cv::DMatch>& matches2to1)
{
    vector<cv::DMatch> bothMatches;

    for(const auto& match1to2 : matches1to2)
    {
        for(const auto& match2to1 : matches2to1)
        {
            if(match1to2.queryIdx == match2to1.trainIdx
            && match2to1.queryIdx == match1to2.trainIdx)
            {
                bothMatches.push_back(match1to2);
                break;
            }
        }
    }

    return bothMatches;
}

class MatcherNodeType : public NodeType
{
public:
    MatcherNodeType()
        : _distanceRatio(0.8f)
        , _symmetryTest(false)
    {
    }

    bool setProperty(PropertyID propId, const NodeProperty& newValue) override
    {
        switch(static_cast<pid>(propId))
        {
        case pid::DistanceRatio:
            _distanceRatio = newValue.toFloat();
            return true;
        case pid::SymmetryTest:
            _symmetryTest = newValue.toBool();
            return true;
        }

        return false;
    }

    NodeProperty property(PropertyID propId) const override
    {
        switch(static_cast<pid>(propId))
        {
        case pid::DistanceRatio: return _distanceRatio;
        case pid::SymmetryTest: return _symmetryTest;
        }

        return NodeProperty();
    }

    void configuration(NodeConfig& nodeConfig) const override
    {
        static const InputSocketConfig in_config[] = {
            { ENodeFlowDataType::Keypoints, "keypoints1", "Query keypoints", "" },
            { ENodeFlowDataType::Array, "descriptors1", "Query descriptors", "" },
            { ENodeFlowDataType::Keypoints, "keypoints2", "Train keypoints", "" },
            { ENodeFlowDataType::Array, "descriptors2", "Train descriptors", "" },
            { ENodeFlowDataType::Invalid, "", "", "" }
        };
        static const OutputSocketConfig out_config[] = {
            { ENodeFlowDataType::Matches, "matches", "Matches", "" },
            { ENodeFlowDataType::Invalid, "", "", "" }
        };
        static const PropertyConfig prop_config[] = {
            { EPropertyType::Double, "Distance ratio", "min:0.0, max:1.0, step:0.1, decimals:2" },
            { EPropertyType::Boolean, "Symmetry test", "" },
            { EPropertyType::Unknown, "", "" }
        };

        nodeConfig.description = "Finds best matches between query and train descriptors using nearest neighbour distance ratio and/or symmetry test.";
        nodeConfig.pInputSockets = in_config;
        nodeConfig.pOutputSockets = out_config;
        nodeConfig.pProperties = prop_config;
    }

protected:
    enum class pid
    {
        DistanceRatio,
        SymmetryTest,
    };

    float _distanceRatio;
    bool _symmetryTest;
};

class BruteForceMatcherNodeType : public MatcherNodeType
{
public:
    ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
    {
        // Read input sockets
        const KeyPoints& queryKp = reader.readSocket(0).getKeypoints();
        const cv::Mat& query = reader.readSocket(1).getArray();
        const KeyPoints& trainKp = reader.readSocket(2).getKeypoints();
        const cv::Mat& train = reader.readSocket(3).getArray();
        // Acquire output sockets
        Matches& mt = writer.acquireSocket(0).getMatches();

        // Validate inputs
        if(train.empty() || query.empty())
            return ExecutionStatus(EStatus::Ok);

        if(query.cols != train.cols
        || query.type() != train.type())
            return ExecutionStatus(EStatus::Error, "Query and train descriptors are different types");

        if(query.type() != CV_32F && query.type() != CV_8U)
        {
            return ExecutionStatus(EStatus::Error,
                "Unsupported descriptor data type "
                "(must be float for L2 norm or Uint8 for Hamming norm");
        }

        // Do stuff
        vector<cv::DMatch> matches;

        if(_symmetryTest)
        {
            vector<cv::DMatch> matches1to2 = nndrMatch(query, train);
            vector<cv::DMatch> matches2to1 = nndrMatch(train, query);
            matches = symmetryTest(matches1to2, matches2to1);
        }
        else
        {
            matches = nndrMatch(query, train);
        }

        // Convert to 'Matches' data type
        mt.queryPoints.clear();
        mt.trainPoints.clear();

        mt.queryImage = queryKp.image;
        mt.trainImage = trainKp.image;

        for(const auto& match : matches)
        {
            mt.queryPoints.push_back(queryKp.kpoints[match.queryIdx].pt);
            mt.trainPoints.push_back(trainKp.kpoints[match.trainIdx].pt);
        }

        return ExecutionStatus(EStatus::Ok,
            string_format("Matches found: %d", (int) mt.queryPoints.size()));
    }

private:
    vector<cv::DMatch> nndrMatch(const cv::Mat& query, const cv::Mat& train)
    {
        vector<cv::DMatch> nndrMatches;

        if(query.type() == CV_32F)
        {
            // for each descriptors in query array
            for(int queryIdx = 0; queryIdx < query.rows; ++queryIdx)
            {
                const float* query_row = query.ptr<float>(queryIdx);

                float bestDistance1 = std::numeric_limits<float>::max();
                float bestDistance2 = std::numeric_limits<float>::max();
                int bestTrainIdx1 = -1;

                // for each descriptors in train array
                for(int trainIdx = 0; trainIdx < train.rows; ++trainIdx)
                {
                    const float* train_row = train.ptr<float>(trainIdx);

                    cv::L2<float> op;
                    cv::L2<float>::ResultType dist = op(train_row, query_row, train.cols);

                    if(dist < bestDistance1)
                    {
                        bestDistance2 = bestDistance1;
                        bestDistance1 = dist;
                        bestTrainIdx1 = trainIdx;
                    }
                    else if(dist < bestDistance2)
                    {
                        bestDistance2 = dist;
                    }
                }

                if(bestDistance1 <= _distanceRatio * bestDistance2)
                {
                    nndrMatches.push_back(cv::DMatch(queryIdx, bestTrainIdx1, bestDistance1));
                }
            }
        }
        else if(query.type() == CV_8U)
        {
            // for each descriptors in query array
            for(int queryIdx = 0; queryIdx < query.rows; ++queryIdx)
            {
                const uchar* query_row = query.ptr<uchar>(queryIdx);

                int bestDistance1 = std::numeric_limits<int>::max();
                int bestDistance2 = std::numeric_limits<int>::max();
                int bestTrainIdx1 = -1;

                // for each descriptors in train array
                for(int trainIdx = 0; trainIdx < train.rows; ++trainIdx)
                {
                    const uchar* train_row = train.ptr<uchar>(trainIdx);

                    cv::Hamming op;
                    cv::Hamming::ResultType dist = op(train_row, query_row, train.cols);

                    if(dist < bestDistance1)
                    {
                        bestDistance2 = bestDistance1;
                        bestDistance1 = dist;
                        bestTrainIdx1 = trainIdx;
                    }
                    else if(dist < bestDistance2)
                    {
                        bestDistance2 = dist;
                    }
                }

                if(bestDistance1 <= _distanceRatio * bestDistance2)
                {
                    nndrMatches.emplace_back(cv::DMatch(queryIdx, bestTrainIdx1, (float)bestDistance1));
                }
            }
        }

        return nndrMatches;
    }
};

class AproximateNearestNeighborMatcherNodeType : public MatcherNodeType
{
public:
    ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
    {
        // Read input sockets
        const KeyPoints& queryKp = reader.readSocket(0).getKeypoints();
        const cv::Mat& queryDesc = reader.readSocket(1).getArray();
        const KeyPoints& trainKp = reader.readSocket(2).getKeypoints();
        const cv::Mat& trainDesc = reader.readSocket(3).getArray();
        // Acquire output sockets
        Matches& mt = writer.acquireSocket(0).getMatches();

        // Validate inputs
        if(trainDesc.empty() || queryDesc.empty())
            return ExecutionStatus(EStatus::Ok);

        if((size_t) trainDesc.rows != trainKp.kpoints.size()
        || (size_t) queryDesc.rows != queryKp.kpoints.size())
        {
            return ExecutionStatus(EStatus::Error, "Keypoints and descriptors mismatched");
        }

        // Do stuff
        cv::Ptr<cv::flann::IndexParams> indexParams;

        if(trainDesc.depth() == CV_8U)
        {
            indexParams = new cv::flann::LshIndexParams(12, 20, 2);
            // For now doesn't work for binary descriptors :(
            //cv::flann::HierarchicalClusteringIndexParams();
        }
        else if(trainDesc.depth() == CV_32F
             || trainDesc.depth() == CV_64F)
        {
            indexParams = new cv::flann::HierarchicalClusteringIndexParams();
        }

        cv::FlannBasedMatcher matcher(indexParams);
        vector<cv::DMatch> matches;

        if(_symmetryTest)
        {
            vector<vector<cv::DMatch>> knMatches1to2, knMatches2to1;

            matcher.knnMatch(queryDesc, trainDesc, knMatches1to2, 2);
            matcher.knnMatch(trainDesc, queryDesc, knMatches2to1, 2);

            auto matches1to2 = distanceRatioTest(knMatches1to2, _distanceRatio);
            auto matches2to1 = distanceRatioTest(knMatches2to1, _distanceRatio);
            matches = symmetryTest(matches1to2, matches2to1);
        }
        else
        {
            vector<vector<cv::DMatch>> knMatches;
            matcher.knnMatch(queryDesc, trainDesc, knMatches, 2);

            matches = distanceRatioTest(knMatches, _distanceRatio);
        }

        // Convert to 'Matches' data type
        mt.queryPoints.clear();
        mt.trainPoints.clear();

        for(const auto& match : matches)
        {
            mt.queryPoints.push_back(queryKp.kpoints[match.queryIdx].pt);
            mt.trainPoints.push_back(trainKp.kpoints[match.trainIdx].pt);
        }

        mt.queryImage = queryKp.image;
        mt.trainImage = trainKp.image;

        return ExecutionStatus(EStatus::Ok,
            string_format("Matches found: %d", (int) mt.queryPoints.size()));
    }
};

/// Only BFMatcher as LSH (FLANN) for 1-bit descriptor isn't supported
class RadiusBruteForceMatcherNodeType : public NodeType
{
public:
    RadiusBruteForceMatcherNodeType()
        : _maxDistance(100.0)
    {
    }

    bool setProperty(PropertyID propId, const NodeProperty& newValue) override
    {
        switch(static_cast<pid>(propId))
        {
        case pid::MaxDistance:
            _maxDistance = newValue.toFloat();
            return true;
        }

        return false;
    }

    NodeProperty property(PropertyID propId) const override
    {
        switch(static_cast<pid>(propId))
        {
        case pid::MaxDistance: return _maxDistance;
        }

        return NodeProperty();
    }

    ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
    {
        // Read input sockets
        const KeyPoints& queryKp = reader.readSocket(0).getKeypoints();
        const cv::Mat& queryDesc = reader.readSocket(1).getArray();
        const KeyPoints& trainKp = reader.readSocket(2).getKeypoints();
        const cv::Mat& trainDesc = reader.readSocket(3).getArray();
        // Acquire output sockets
        Matches& mt = writer.acquireSocket(0).getMatches();

        // Validate inputs
        if(trainDesc.empty() || queryDesc.empty())
            return ExecutionStatus(EStatus::Ok);

        if((size_t) trainDesc.rows != trainKp.kpoints.size()
        || (size_t) queryDesc.rows != queryKp.kpoints.size())
        {
            return ExecutionStatus(EStatus::Error, "Keypoints and descriptors mismatched");
        }

        int normType = cv::NORM_L2;
        // If BRISK, ORB or FREAK was used as a descriptor
        if(queryDesc.depth() == CV_8U && trainDesc.depth() == CV_8U)
            normType = cv::NORM_HAMMING;

        mt.queryPoints.clear();
        mt.trainPoints.clear();

        cv::BFMatcher matcher(normType);
        vector<vector<cv::DMatch>> radiusMatches;

        matcher.radiusMatch(queryDesc, trainDesc, radiusMatches, _maxDistance);

        // remove unmatched ones and pick only first matches
        vector<cv::DMatch> matches;

        for(const auto& rmatches : radiusMatches)
        {
            if(!rmatches.empty())
            {
                matches.push_back(rmatches[0]);
            }
        }

        // Convert to 'Matches' data type
        mt.queryPoints.clear();
        mt.trainPoints.clear();

        for(const auto& match : matches)
        {
            mt.queryPoints.push_back(queryKp.kpoints[match.queryIdx].pt);
            mt.trainPoints.push_back(trainKp.kpoints[match.trainIdx].pt);
        }

        mt.queryImage = queryKp.image;
        mt.trainImage = trainKp.image;

        return ExecutionStatus(EStatus::Ok,
            string_format("Matches found: %d", (int) mt.queryPoints.size()));
    }

    void configuration(NodeConfig& nodeConfig) const override
    {
        static const InputSocketConfig in_config[] = {
            { ENodeFlowDataType::Keypoints, "keypoints1", "Query keypoints", "" },
            { ENodeFlowDataType::Array, "descriptors1", "Query descriptors", "" },
            { ENodeFlowDataType::Keypoints, "keypoints2", "Train keypoints", "" },
            { ENodeFlowDataType::Array, "descriptors2", "Train descriptors", "" },
            { ENodeFlowDataType::Invalid, "", "", "" }
        };
        static const OutputSocketConfig out_config[] = {
            { ENodeFlowDataType::Matches, "matches", "Matches", "" },
            { ENodeFlowDataType::Invalid, "", "", "" }
        };
        static const PropertyConfig prop_config[] = {
            { EPropertyType::Double, "Max distance", "min:0.0, decimals:2" },
            { EPropertyType::Unknown, "", "" }
        };

        nodeConfig.description = "Finds the training descriptors not farther than the specified distance.";
        nodeConfig.pInputSockets = in_config;
        nodeConfig.pOutputSockets = out_config;
        nodeConfig.pProperties = prop_config;
    }
private:
    enum class pid
    {
        MaxDistance
    };

    float _maxDistance;
};

REGISTER_NODE("Features/Radius BForce Matcher", RadiusBruteForceMatcherNodeType);
REGISTER_NODE("Features/BForce Matcher", BruteForceMatcherNodeType);
REGISTER_NODE("Features/ANN Matcher", AproximateNearestNeighborMatcherNodeType)
<commit_msg>updated matcher nodes for new node conf. interface [WIP]<commit_after>/*
 * Copyright (c) 2013-2014 Kajetan Swierk <k0zmo@outlook.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#include "Logic/NodeType.h"
#include "Logic/NodeFactory.h"
#include "Kommon/Utils.h"
#include "Kommon/StringUtils.h"

#include <opencv2/features2d/features2d.hpp>

using std::vector;

static vector<cv::DMatch> distanceRatioTest(const vector<vector<cv::DMatch>>& knMatches,
                                            float distanceRatioThreshold)
{
    vector<cv::DMatch> positiveMatches;
    positiveMatches.reserve(knMatches.size());

    for(const auto& knMatch : knMatches)
    {
        if(knMatch.size() != 2)
            continue;

        const auto& best = knMatch[0];
        const auto& good = knMatch[1];

        if(best.distance <= distanceRatioThreshold * good.distance)
            positiveMatches.push_back(best);
    }

    return positiveMatches;
}

static vector<cv::DMatch> symmetryTest(const vector<cv::DMatch>& matches1to2,
                                       const vector<cv::DMatch>& matches2to1)
{
    vector<cv::DMatch> bothMatches;

    for(const auto& match1to2 : matches1to2)
    {
        for(const auto& match2to1 : matches2to1)
        {
            if(match1to2.queryIdx == match2to1.trainIdx
            && match2to1.queryIdx == match1to2.trainIdx)
            {
                bothMatches.push_back(match1to2);
                break;
            }
        }
    }

    return bothMatches;
}

class MatcherNodeType : public NodeType
{
public:
    MatcherNodeType()
        : _distanceRatio(0.8f)
        , _symmetryTest(false)
    {
        addInput("Query keypoints", ENodeFlowDataType::Keypoints);
        addInput("Query descriptors", ENodeFlowDataType::Array);
        addInput("Train keypoints", ENodeFlowDataType::Keypoints);
        addInput("Train descriptors", ENodeFlowDataType::Array);
        addOutput("Matches", ENodeFlowDataType::Matches);
        addProperty("Distance ratio", _distanceRatio)
            .setValidator(make_validator<InclRangePropertyValidator<double>>(0.0, 1.0))
            .setUiHints("min:0.0, max:1.0, step:0.1, decimals:2");
        addProperty("Symmetry test", _symmetryTest);
        setDescription("Finds best matches between query and train descriptors "
            "using nearest neighbour distance ratio and/or symmetry test.");
    }

protected:
    TypedNodeProperty<float> _distanceRatio;
    TypedNodeProperty<bool> _symmetryTest;
};

class BruteForceMatcherNodeType : public MatcherNodeType
{
public:
    ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
    {
        // Read input sockets
        const KeyPoints& queryKp = reader.readSocket(0).getKeypoints();
        const cv::Mat& query = reader.readSocket(1).getArray();
        const KeyPoints& trainKp = reader.readSocket(2).getKeypoints();
        const cv::Mat& train = reader.readSocket(3).getArray();
        // Acquire output sockets
        Matches& mt = writer.acquireSocket(0).getMatches();

        // Validate inputs
        if(train.empty() || query.empty())
            return ExecutionStatus(EStatus::Ok);

        if(query.cols != train.cols
        || query.type() != train.type())
            return ExecutionStatus(EStatus::Error, "Query and train descriptors are different types");

        if(query.type() != CV_32F && query.type() != CV_8U)
        {
            return ExecutionStatus(EStatus::Error,
                "Unsupported descriptor data type "
                "(must be float for L2 norm or Uint8 for Hamming norm");
        }

        // Do stuff
        vector<cv::DMatch> matches;

        if(_symmetryTest)
        {
            vector<cv::DMatch> matches1to2 = nndrMatch(query, train);
            vector<cv::DMatch> matches2to1 = nndrMatch(train, query);
            matches = symmetryTest(matches1to2, matches2to1);
        }
        else
        {
            matches = nndrMatch(query, train);
        }

        // Convert to 'Matches' data type
        mt.queryPoints.clear();
        mt.trainPoints.clear();

        mt.queryImage = queryKp.image;
        mt.trainImage = trainKp.image;

        for(const auto& match : matches)
        {
            mt.queryPoints.push_back(queryKp.kpoints[match.queryIdx].pt);
            mt.trainPoints.push_back(trainKp.kpoints[match.trainIdx].pt);
        }

        return ExecutionStatus(EStatus::Ok,
            string_format("Matches found: %d", (int) mt.queryPoints.size()));
    }

private:
    vector<cv::DMatch> nndrMatch(const cv::Mat& query, const cv::Mat& train)
    {
        vector<cv::DMatch> nndrMatches;

        if(query.type() == CV_32F)
        {
            // for each descriptors in query array
            for(int queryIdx = 0; queryIdx < query.rows; ++queryIdx)
            {
                const float* query_row = query.ptr<float>(queryIdx);

                float bestDistance1 = std::numeric_limits<float>::max();
                float bestDistance2 = std::numeric_limits<float>::max();
                int bestTrainIdx1 = -1;

                // for each descriptors in train array
                for(int trainIdx = 0; trainIdx < train.rows; ++trainIdx)
                {
                    const float* train_row = train.ptr<float>(trainIdx);

                    cv::L2<float> op;
                    cv::L2<float>::ResultType dist = op(train_row, query_row, train.cols);

                    if(dist < bestDistance1)
                    {
                        bestDistance2 = bestDistance1;
                        bestDistance1 = dist;
                        bestTrainIdx1 = trainIdx;
                    }
                    else if(dist < bestDistance2)
                    {
                        bestDistance2 = dist;
                    }
                }

                if(bestDistance1 <= _distanceRatio * bestDistance2)
                {
                    nndrMatches.push_back(cv::DMatch(queryIdx, bestTrainIdx1, bestDistance1));
                }
            }
        }
        else if(query.type() == CV_8U)
        {
            // for each descriptors in query array
            for(int queryIdx = 0; queryIdx < query.rows; ++queryIdx)
            {
                const uchar* query_row = query.ptr<uchar>(queryIdx);

                int bestDistance1 = std::numeric_limits<int>::max();
                int bestDistance2 = std::numeric_limits<int>::max();
                int bestTrainIdx1 = -1;

                // for each descriptors in train array
                for(int trainIdx = 0; trainIdx < train.rows; ++trainIdx)
                {
                    const uchar* train_row = train.ptr<uchar>(trainIdx);

                    cv::Hamming op;
                    cv::Hamming::ResultType dist = op(train_row, query_row, train.cols);

                    if(dist < bestDistance1)
                    {
                        bestDistance2 = bestDistance1;
                        bestDistance1 = dist;
                        bestTrainIdx1 = trainIdx;
                    }
                    else if(dist < bestDistance2)
                    {
                        bestDistance2 = dist;
                    }
                }

                if(bestDistance1 <= _distanceRatio * bestDistance2)
                {
                    nndrMatches.emplace_back(cv::DMatch(queryIdx, bestTrainIdx1, (float)bestDistance1));
                }
            }
        }

        return nndrMatches;
    }
};

class AproximateNearestNeighborMatcherNodeType : public MatcherNodeType
{
public:
    ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
    {
        // Read input sockets
        const KeyPoints& queryKp = reader.readSocket(0).getKeypoints();
        const cv::Mat& queryDesc = reader.readSocket(1).getArray();
        const KeyPoints& trainKp = reader.readSocket(2).getKeypoints();
        const cv::Mat& trainDesc = reader.readSocket(3).getArray();
        // Acquire output sockets
        Matches& mt = writer.acquireSocket(0).getMatches();

        // Validate inputs
        if(trainDesc.empty() || queryDesc.empty())
            return ExecutionStatus(EStatus::Ok);

        if((size_t) trainDesc.rows != trainKp.kpoints.size()
        || (size_t) queryDesc.rows != queryKp.kpoints.size())
        {
            return ExecutionStatus(EStatus::Error, "Keypoints and descriptors mismatched");
        }

        // Do stuff
        cv::Ptr<cv::flann::IndexParams> indexParams;

        if(trainDesc.depth() == CV_8U)
        {
            indexParams = new cv::flann::LshIndexParams(12, 20, 2);
            // For now doesn't work for binary descriptors :(
            //cv::flann::HierarchicalClusteringIndexParams();
        }
        else if(trainDesc.depth() == CV_32F
             || trainDesc.depth() == CV_64F)
        {
            indexParams = new cv::flann::HierarchicalClusteringIndexParams();
        }

        cv::FlannBasedMatcher matcher(indexParams);
        vector<cv::DMatch> matches;

        if(_symmetryTest)
        {
            vector<vector<cv::DMatch>> knMatches1to2, knMatches2to1;

            matcher.knnMatch(queryDesc, trainDesc, knMatches1to2, 2);
            matcher.knnMatch(trainDesc, queryDesc, knMatches2to1, 2);

            auto matches1to2 = distanceRatioTest(knMatches1to2, _distanceRatio);
            auto matches2to1 = distanceRatioTest(knMatches2to1, _distanceRatio);
            matches = symmetryTest(matches1to2, matches2to1);
        }
        else
        {
            vector<vector<cv::DMatch>> knMatches;
            matcher.knnMatch(queryDesc, trainDesc, knMatches, 2);

            matches = distanceRatioTest(knMatches, _distanceRatio);
        }

        // Convert to 'Matches' data type
        mt.queryPoints.clear();
        mt.trainPoints.clear();

        for(const auto& match : matches)
        {
            mt.queryPoints.push_back(queryKp.kpoints[match.queryIdx].pt);
            mt.trainPoints.push_back(trainKp.kpoints[match.trainIdx].pt);
        }

        mt.queryImage = queryKp.image;
        mt.trainImage = trainKp.image;

        return ExecutionStatus(EStatus::Ok,
            string_format("Matches found: %d", (int) mt.queryPoints.size()));
    }
};

/// Only BFMatcher as LSH (FLANN) for 1-bit descriptor isn't supported
class RadiusBruteForceMatcherNodeType : public NodeType
{
public:
    RadiusBruteForceMatcherNodeType()
        : _maxDistance(100.0)
    {
        addInput("Query keypoints", ENodeFlowDataType::Keypoints);
        addInput("Query descriptors", ENodeFlowDataType::Array);
        addInput("Train keypoints", ENodeFlowDataType::Keypoints);
        addInput("Train descriptors", ENodeFlowDataType::Array);
        addOutput("Matches", ENodeFlowDataType::Matches);
        addProperty("Max distance", _maxDistance)
            .setValidator(make_validator<MinPropertyValidator<double>>(0.0))
            .setUiHints("min:0.0, decimals:2");
        setDescription("Finds the training descriptors not farther than the specified distance.");
    }

    ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
    {
        // Read input sockets
        const KeyPoints& queryKp = reader.readSocket(0).getKeypoints();
        const cv::Mat& queryDesc = reader.readSocket(1).getArray();
        const KeyPoints& trainKp = reader.readSocket(2).getKeypoints();
        const cv::Mat& trainDesc = reader.readSocket(3).getArray();
        // Acquire output sockets
        Matches& mt = writer.acquireSocket(0).getMatches();

        // Validate inputs
        if(trainDesc.empty() || queryDesc.empty())
            return ExecutionStatus(EStatus::Ok);

        if((size_t) trainDesc.rows != trainKp.kpoints.size()
        || (size_t) queryDesc.rows != queryKp.kpoints.size())
        {
            return ExecutionStatus(EStatus::Error, "Keypoints and descriptors mismatched");
        }

        int normType = cv::NORM_L2;
        // If BRISK, ORB or FREAK was used as a descriptor
        if(queryDesc.depth() == CV_8U && trainDesc.depth() == CV_8U)
            normType = cv::NORM_HAMMING;

        mt.queryPoints.clear();
        mt.trainPoints.clear();

        cv::BFMatcher matcher(normType);
        vector<vector<cv::DMatch>> radiusMatches;

        matcher.radiusMatch(queryDesc, trainDesc, radiusMatches, _maxDistance);

        // remove unmatched ones and pick only first matches
        vector<cv::DMatch> matches;

        for(const auto& rmatches : radiusMatches)
        {
            if(!rmatches.empty())
            {
                matches.push_back(rmatches[0]);
            }
        }

        // Convert to 'Matches' data type
        mt.queryPoints.clear();
        mt.trainPoints.clear();

        for(const auto& match : matches)
        {
            mt.queryPoints.push_back(queryKp.kpoints[match.queryIdx].pt);
            mt.trainPoints.push_back(trainKp.kpoints[match.trainIdx].pt);
        }

        mt.queryImage = queryKp.image;
        mt.trainImage = trainKp.image;

        return ExecutionStatus(EStatus::Ok,
            string_format("Matches found: %d", (int) mt.queryPoints.size()));
    }

private:
    TypedNodeProperty<float> _maxDistance;
};

REGISTER_NODE("Features/Radius BForce Matcher", RadiusBruteForceMatcherNodeType);
REGISTER_NODE("Features/BForce Matcher", BruteForceMatcherNodeType);
REGISTER_NODE("Features/ANN Matcher", AproximateNearestNeighborMatcherNodeType)
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_IterableFromIterator_inl_
#define _Stroika_Foundation_Traversal_IterableFromIterator_inl_

#include "../Debug/Assertions.h"
#include "DelegatedIterator.h"

namespace Stroika::Foundation::Traversal {

#if qDebug
    /*
     ********************************************************************************
     * IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_IteratorTracker *
     ********************************************************************************
     */
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    inline IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_IteratorTracker::~_IteratorTracker ()
    {
        Assert (*fCountRunning == 0);
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    inline Iterator<T> IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_IteratorTracker::MakeDelegatedIterator (const Iterator<T>& sourceIterator)
    {
        return DelegatedIterator<T, shared_ptr<unsigned int>> (sourceIterator, fCountRunning);
    }
#endif

    /*
     ********************************************************************************
     * IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep *
     ********************************************************************************
     */
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    template <typename K1, enable_if_t<not is_same_v<K1, void>>*>
    inline IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_Rep (const _ContextObjectType& contextForEachIterator)
        : _fContextForEachIterator{contextForEachIterator}
    {
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    template <typename K1, enable_if_t<is_same_v<K1, void>>*>
    inline IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_Rep ()
    {
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    Iterator<T> IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::MakeIterator () const
    {
        if constexpr (is_same_v<NEW_ITERATOR_REP_TYPE, void>) {
            return nullptr;
        }
        else {
#if qDebug
            return fIteratorTracker_.MakeDelegatedIterator (Iterator<T>{Iterator<T>::template MakeSmartPtr<NEW_ITERATOR_REP_TYPE> (_fContextForEachIterator)});
#else
            return Iterator<T>{Iterator<T>::template MakeSmartPtr<NEW_ITERATOR_REP_TYPE> (_fContextForEachIterator)};
#endif
        }
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    size_t IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::GetLength () const
    {
        size_t n = 0;
        for (auto i = this->MakeIterator (); not i.Done (); ++i) {
            n++;
        }
        return n;
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    bool IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::IsEmpty () const
    {
        for (auto i = this->MakeIterator (); not i.Done (); ++i) {
            return false;
        }
        return true;
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    void IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::Apply (const function<void (ArgByValueType<value_type> item)>& doToElement) const
    {
        this->_Apply (doToElement);
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    Iterator<T> IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::FindFirstThat (const function<bool (ArgByValueType<value_type> item)>& doToElement) const
    {
        return this->_FindFirstThat (doToElement);
    }

    /*
     ********************************************************************************
     **************************** MakeIterableFromIterator **************************
     ********************************************************************************
     */
    template <typename T>
    Iterable<T> MakeIterableFromIterator (const Iterator<T>& iterator)
    {
        struct MyIterable_ : public Iterable<T> {
            struct Rep : public IterableFromIterator<T>::_Rep, public Memory::UseBlockAllocationIfAppropriate<Rep> {
                using inherited             = typename IterableFromIterator<T>::_Rep;
                using _IteratorTracker      = typename inherited::_IteratorTracker;
                using _IterableRepSharedPtr = typename Iterable<T>::_IterableRepSharedPtr;
                Iterator<T> fOriginalIterator;
#if qDebug
                mutable _IteratorTracker fIteratorTracker_{};
#endif
                Rep (const Iterator<T>& originalIterator)
                    : fOriginalIterator{originalIterator}
                {
                }
                virtual Iterator<T> MakeIterator () const override
                {
#if qDebug
                    return fIteratorTracker_.MakeDelegatedIterator (fOriginalIterator);
#else
                    return fOriginalIterator;
#endif
                }
                virtual _IterableRepSharedPtr Clone () const override
                {
                    return Iterable<T>::template MakeSmartPtr<Rep> (*this);
                }
            };
            MyIterable_ (const Iterator<T>& originalIterator)
                : Iterable<T>{Iterable<T>::template MakeSmartPtr<Rep> (originalIterator)}
            {
            }
        };
        return MyIterable_{iterator};
    }

}

#endif /* _Stroika_Foundation_Traversal_IterableFromIterator_inl_ */
<commit_msg>Silecne warning<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_IterableFromIterator_inl_
#define _Stroika_Foundation_Traversal_IterableFromIterator_inl_

#include "../Debug/Assertions.h"
#include "DelegatedIterator.h"

namespace Stroika::Foundation::Traversal {

#if qDebug
    /*
     ********************************************************************************
     * IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_IteratorTracker *
     ********************************************************************************
     */
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    inline IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_IteratorTracker::~_IteratorTracker ()
    {
        Assert (*fCountRunning == 0);
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    inline Iterator<T> IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_IteratorTracker::MakeDelegatedIterator (const Iterator<T>& sourceIterator)
    {
        return DelegatedIterator<T, shared_ptr<unsigned int>> (sourceIterator, fCountRunning);
    }
#endif

    /*
     ********************************************************************************
     * IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep *
     ********************************************************************************
     */
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    template <typename K1, enable_if_t<not is_same_v<K1, void>>*>
    inline IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_Rep (const _ContextObjectType& contextForEachIterator)
        : _fContextForEachIterator{contextForEachIterator}
    {
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    template <typename K1, enable_if_t<is_same_v<K1, void>>*>
    inline IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_Rep ()
    {
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    Iterator<T> IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::MakeIterator () const
    {
        if constexpr (is_same_v<NEW_ITERATOR_REP_TYPE, void>) {
            return nullptr;
        }
        else {
#if qDebug
            return fIteratorTracker_.MakeDelegatedIterator (Iterator<T>{Iterator<T>::template MakeSmartPtr<NEW_ITERATOR_REP_TYPE> (_fContextForEachIterator)});
#else
            return Iterator<T>{Iterator<T>::template MakeSmartPtr<NEW_ITERATOR_REP_TYPE> (_fContextForEachIterator)};
#endif
        }
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    size_t IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::GetLength () const
    {
        size_t n = 0;
        for (auto i = this->MakeIterator (); not i.Done (); ++i) {
            n++;
        }
        return n;
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    bool IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::IsEmpty () const
    {
        for (auto i = this->MakeIterator (); not i.Done (); ++i) {
            return false;
        }
        return true;
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    void IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::Apply (const function<void (ArgByValueType<value_type> item)>& doToElement) const
    {
        this->_Apply (doToElement);
    }
    template <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
    Iterator<T> IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::FindFirstThat (const function<bool (ArgByValueType<value_type> item)>& doToElement) const
    {
        return this->_FindFirstThat (doToElement);
    }

    /*
     ********************************************************************************
     **************************** MakeIterableFromIterator **************************
     ********************************************************************************
     */
    template <typename T>
    Iterable<T> MakeIterableFromIterator (const Iterator<T>& iterator)
    {
        struct MyIterable_ : public Iterable<T> {
            struct Rep : public IterableFromIterator<T>::_Rep, public Memory::UseBlockAllocationIfAppropriate<Rep> {
                using inherited             = typename IterableFromIterator<T>::_Rep;
#if qDebug
                using _IteratorTracker      = typename inherited::_IteratorTracker;
#endif
                using _IterableRepSharedPtr = typename Iterable<T>::_IterableRepSharedPtr;
                Iterator<T> fOriginalIterator;
#if qDebug
                mutable _IteratorTracker fIteratorTracker_{};
#endif
                Rep (const Iterator<T>& originalIterator)
                    : fOriginalIterator{originalIterator}
                {
                }
                virtual Iterator<T> MakeIterator () const override
                {
#if qDebug
                    return fIteratorTracker_.MakeDelegatedIterator (fOriginalIterator);
#else
                    return fOriginalIterator;
#endif
                }
                virtual _IterableRepSharedPtr Clone () const override
                {
                    return Iterable<T>::template MakeSmartPtr<Rep> (*this);
                }
            };
            MyIterable_ (const Iterator<T>& originalIterator)
                : Iterable<T>{Iterable<T>::template MakeSmartPtr<Rep> (originalIterator)}
            {
            }
        };
        return MyIterable_{iterator};
    }

}

#endif /* _Stroika_Foundation_Traversal_IterableFromIterator_inl_ */
<|endoftext|>


<commit_before>#include "EntityEditor.hpp"

#include <Engine/Component/Animation.hpp>
#include <Engine/Component/Physics.hpp>
#include <Engine/Component/Mesh.hpp>
#include <Engine/Component/Lens.hpp>
#include <Engine/Component/Material.hpp>
#include <Engine/Component/DirectionalLight.hpp>
#include <Engine/Component/PointLight.hpp>
#include <Engine/Component/SpotLight.hpp>
#include <Engine/Component/Listener.hpp>
#include <Engine/Component/Script.hpp>
#include <Engine/Component/SoundSource.hpp>
#include <Engine/Component/ParticleEmitter.hpp>
#include <Engine/Geometry/Model.hpp>
#include <Engine/Texture/TextureAsset.hpp>
#include <Video/Texture/Texture2D.hpp>
#include <Engine/Audio/SoundBuffer.hpp>
#include <Engine/Script/ScriptFile.hpp>
#include <Engine/Util/FileSystem.hpp>
#include <Engine/Manager/Managers.hpp>
#include <Engine/Manager/ScriptManager.hpp>
#include <Engine/Manager/ParticleManager.hpp>
#include <Engine/Hymn.hpp>

#include "../../Util/EditorSettings.hpp"
#include "../FileSelector.hpp"
#include "../../ImGui/GuiHelpers.hpp"
#include "../../Resources.hpp"

using namespace GUI;

EntityEditor::EntityEditor() {
    name[0] = '\0';
    AddEditor<Component::Animation>("Animation", std::bind(&EntityEditor::AnimationEditor, this, std::placeholders::_1));
    AddEditor<Component::Physics>("Physics", std::bind(&EntityEditor::PhysicsEditor, this, std::placeholders::_1));
    AddEditor<Component::Mesh>("Mesh", std::bind(&EntityEditor::MeshEditor, this, std::placeholders::_1));
    AddEditor<Component::Lens>("Lens", std::bind(&EntityEditor::LensEditor, this, std::placeholders::_1));
    AddEditor<Component::Material>("Material", std::bind(&EntityEditor::MaterialEditor, this, std::placeholders::_1));
    AddEditor<Component::DirectionalLight>("Directional light", std::bind(&EntityEditor::DirectionalLightEditor, this, std::placeholders::_1));
    AddEditor<Component::PointLight>("Point light", std::bind(&EntityEditor::PointLightEditor, this, std::placeholders::_1));
    AddEditor<Component::SpotLight>("Spot light", std::bind(&EntityEditor::SpotLightEditor, this, std::placeholders::_1));
    AddEditor<Component::Listener>("Listener", std::bind(&EntityEditor::ListenerEditor, this, std::placeholders::_1));
    AddEditor<Component::Script>("Script", std::bind(&EntityEditor::ScriptEditor, this, std::placeholders::_1));
    AddEditor<Component::SoundSource>("Sound source", std::bind(&EntityEditor::SoundSourceEditor, this, std::placeholders::_1));
    AddEditor<Component::ParticleEmitter>("Particle emitter", std::bind(&EntityEditor::ParticleEmitterEditor, this, std::placeholders::_1));
}

EntityEditor::~EntityEditor() {

}

void EntityEditor::Show() {
    if (ImGui::Begin(("Entity: " + entity->name + "###" + std::to_string(reinterpret_cast<uintptr_t>(entity))).c_str(), &visible, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ShowBorders)) {
        ImGui::InputText("Name", name, 128);
        entity->name = name;
        ImGui::Text("Transform");
        ImGui::ShowHelpMarker("The entity's position, rotation and scale.", 75.f);
        ImGui::Indent();
        ImGui::DraggableVec3("Position", entity->position);
        ImGui::DraggableVec3("Rotation", entity->rotation);
        ImGui::DraggableVec3("Scale", entity->scale);
        ImGui::Unindent();
        if (!entity->IsScene()) {
            if (ImGui::Button("Add component"))
                ImGui::OpenPopup("Add component");

            if (ImGui::BeginPopup("Add component")) {
                ImGui::Text("Components");
                ImGui::Separator();

                for (Editor& editor : editors) {
                    editor.addFunction();
                }

                ImGui::EndPopup();
            }

            for (Editor& editor : editors) {
                editor.editFunction();
            }
        }
    }

    ImGui::End();
}

void EntityEditor::SetEntity(Entity* entity) {
    this->entity = entity;
    strcpy(name, entity->name.c_str());
}

Entity* EntityEditor::GetEntity() {
    return entity;
}

bool EntityEditor::ShowsEntity(Entity* entity) {
    return this->entity == entity;
}

bool EntityEditor::IsVisible() const {
    return visible;
}

void EntityEditor::SetVisible(bool visible) {
    this->visible = visible;
}

void EntityEditor::AnimationEditor(Component::Animation* animation) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Animation"))
        ImGui::OpenPopup("Select model##Animation");

    if (ImGui::BeginPopup("Select model##Animation")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Resources().models) {
            if (ImGui::Selectable(model->name.c_str()))
                animation->riggedModel = dynamic_cast<Geometry::Model*>(model);
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::PhysicsEditor(Component::Physics* physics) {
    ImGui::Text("Positional");
    ImGui::Indent();
    ImGui::DraggableVec3("Velocity", physics->velocity);
    ImGui::DraggableFloat("Max velocity", physics->maxVelocity, 0.0f);
    ImGui::DraggableVec3("Acceleration", physics->acceleration);
    ImGui::DraggableFloat("Velocity drag factor", physics->velocityDragFactor);
    ImGui::DraggableFloat("Gravity factor", physics->gravityFactor);
    ImGui::Unindent();
    ImGui::Text("Angular");
    ImGui::Indent();
    ImGui::DraggableVec3("Angular velocity", physics->angularVelocity);
    ImGui::DraggableFloat("Max angular velocity", physics->maxAngularVelocity, 0.0f);
    ImGui::DraggableVec3("Angular acceleration", physics->angularAcceleration);
    ImGui::DraggableFloat("Angular drag factor", physics->angularDragFactor);
    ImGui::DraggableVec3("Moment of inertia", physics->momentOfInertia);
    ImGui::Unindent();

}

void EntityEditor::MeshEditor(Component::Mesh* mesh) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Mesh"))
        ImGui::OpenPopup("Select model##Mesh");

    if (ImGui::BeginPopup("Select model##Mesh")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Resources().models) {
            if (ImGui::Selectable(model->name.c_str()))
                mesh->geometry = model;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::LensEditor(Component::Lens* lens) {
    ImGui::Indent();
    ImGui::DraggableFloat("Field of view", lens->fieldOfView, 0.0f, 180.f);
    ImGui::DraggableFloat("Z near", lens->zNear, 0.0f);
    ImGui::DraggableFloat("Z far", lens->zFar, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::MaterialEditor(Component::Material* material) {
    // Diffuse
    ImGui::Text("Diffuse");
    ImGui::Indent();
    if (material->diffuse->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->diffuse->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select diffuse texture"))
        ImGui::OpenPopup("Select diffuse texture");

    if (ImGui::BeginPopup("Select diffuse texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->diffuse = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Normal
    ImGui::Text("Normal");
    ImGui::Indent();
    if (material->normal->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->normal->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select normal texture"))
        ImGui::OpenPopup("Select normal texture");

    if (ImGui::BeginPopup("Select normal texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->normal = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Specular
    ImGui::Text("Specular");
    ImGui::Indent();
    if (material->specular->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->specular->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select specular texture"))
        ImGui::OpenPopup("Select specular texture");

    if (ImGui::BeginPopup("Select specular texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->specular = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Glow
    ImGui::Text("Glow");
    ImGui::Indent();
    if (material->glow->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->glow->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select glow texture"))
        ImGui::OpenPopup("Select glow texture");

    if (ImGui::BeginPopup("Select glow texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->glow = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::DirectionalLightEditor(Component::DirectionalLight* directionalLight) {
    ImGui::Indent();
    ImGui::ColorEdit3("Color", &directionalLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", directionalLight->ambientCoefficient, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::PointLightEditor(Component::PointLight* pointLight) {
    ImGui::Indent();
    ImGui::ColorEdit3("Color", &pointLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", pointLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", pointLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", pointLight->intensity, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::SpotLightEditor(Component::SpotLight* spotLight) {
    ImGui::Indent();
    ImGui::ColorEdit3("Color", &spotLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", spotLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", spotLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", spotLight->intensity, 0.0f);
    ImGui::DraggableFloat("Cone angle", spotLight->coneAngle, 0.0f, 180.f);
    ImGui::Unindent();
}

void EntityEditor::ListenerEditor(Component::Listener* listener) {

}

void EntityEditor::ScriptEditor(Component::Script* script) {
    ImGui::Indent();
    if(script->scriptFile != nullptr)
        ImGui::Text(script->scriptFile->name.c_str());
    else
        ImGui::Text("No script loaded");

    if (ImGui::Button("Select script"))
        ImGui::OpenPopup("Select script");

    if (ImGui::BeginPopup("Select script")) {
        ImGui::Text("Scripts");
        ImGui::Separator();

        for (ScriptFile* scriptFile : Hymn().scripts) {
            if (ImGui::Selectable(scriptFile->name.c_str()))
                script->scriptFile = scriptFile;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::SoundSourceEditor(Component::SoundSource* soundSource) {
    ImGui::Text("Sound");
    ImGui::Indent();
    if (ImGui::Button("Select sound"))
        ImGui::OpenPopup("Select sound");

    if (ImGui::BeginPopup("Select sound")) {
        ImGui::Text("Sounds");
        ImGui::Separator();

        for (Audio::SoundBuffer* sound : Resources().sounds) {
            if (ImGui::Selectable(sound->name.c_str()))
                soundSource->soundBuffer = sound;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
    ImGui::Text("Sound properties");
    ImGui::Indent();
    ImGui::DraggableFloat("Pitch", soundSource->pitch, 0.0f);
    ImGui::DraggableFloat("Gain", soundSource->gain, 0.0f);
    ImGui::Checkbox("Loop", &soundSource->loop);
    ImGui::Unindent();
}

void EntityEditor::ParticleEmitterEditor(Component::ParticleEmitter* particleEmitter) {
    ImGui::Text("Particle");
    ImGui::Indent();
    int rows = Managers().particleManager->GetTextureAtlasRows();
    float column = static_cast<float>(particleEmitter->particleType.textureIndex % rows);
    float row = static_cast<float>(particleEmitter->particleType.textureIndex / rows);
    ImGui::Image((void*) Managers().particleManager->GetTextureAtlas()->GetTextureID(), ImVec2(128, 128), ImVec2(column / rows, row / rows), ImVec2((column + 1.f) / rows, (row + 1.f) / rows));
    ImGui::InputInt("Texture index", &particleEmitter->particleType.textureIndex);
    ImGui::ColorEdit3("Color", &particleEmitter->particleType.color[0]);
    ImGui::DraggableVec3("Min velocity", particleEmitter->particleType.minVelocity);
    ImGui::DraggableVec3("Max velocity", particleEmitter->particleType.maxVelocity);
    ImGui::DraggableFloat("Average lifetime", particleEmitter->particleType.averageLifetime, 0.0f);
    ImGui::DraggableFloat("Lifetime variance", particleEmitter->particleType.lifetimeVariance, 0.0f);
    ImGui::DraggableVec2("Average size", particleEmitter->particleType.averageSize, 0.0f);
    ImGui::DraggableVec2("Size variance", particleEmitter->particleType.sizeVariance, 0.0f);
    ImGui::Checkbox("Uniform scaling", &particleEmitter->particleType.uniformScaling);
    ImGui::DraggableFloat("Start alpha", particleEmitter->particleType.startAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("Mid alpha", particleEmitter->particleType.midAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("End alpha", particleEmitter->particleType.endAlpha, 0.0f, 1.0f);
    ImGui::Unindent();

    ImGui::Text("Emitter");
    ImGui::Indent();
    ImGui::DraggableFloat("Average emit time", particleEmitter->averageEmitTime, 0.0f);
    ImGui::DraggableFloat("Emit time variance", particleEmitter->emitTimeVariance, 0.0f);

    const char* items[] = { "Point", "Cuboid" };
    int item = static_cast<int>(particleEmitter->emitterType);
    if (ImGui::Combo("Emitter type", &item, items, 2))
        particleEmitter->emitterType = static_cast<Component::ParticleEmitter::EmitterType>(item);

    if (particleEmitter->emitterType == Component::ParticleEmitter::CUBOID)
        ImGui::DraggableVec3("Size", particleEmitter->size);

    ImGui::Unindent();

    ImGui::Text("Preview");
    ImGui::Indent();
    ImGui::Checkbox("Simulate", &particleEmitter->preview);
    ImGui::Unindent();
}
<commit_msg>Fix reference counting when selecting textures<commit_after>#include "EntityEditor.hpp"

#include <Engine/Component/Animation.hpp>
#include <Engine/Component/Physics.hpp>
#include <Engine/Component/Mesh.hpp>
#include <Engine/Component/Lens.hpp>
#include <Engine/Component/Material.hpp>
#include <Engine/Component/DirectionalLight.hpp>
#include <Engine/Component/PointLight.hpp>
#include <Engine/Component/SpotLight.hpp>
#include <Engine/Component/Listener.hpp>
#include <Engine/Component/Script.hpp>
#include <Engine/Component/SoundSource.hpp>
#include <Engine/Component/ParticleEmitter.hpp>
#include <Engine/Geometry/Model.hpp>
#include <Engine/Texture/TextureAsset.hpp>
#include <Video/Texture/Texture2D.hpp>
#include <Engine/Audio/SoundBuffer.hpp>
#include <Engine/Script/ScriptFile.hpp>
#include <Engine/Util/FileSystem.hpp>
#include <Engine/Manager/Managers.hpp>
#include <Engine/Manager/ScriptManager.hpp>
#include <Engine/Manager/ParticleManager.hpp>
#include <Engine/Manager/ResourceManager.hpp>
#include <Engine/Hymn.hpp>

#include "../../Util/EditorSettings.hpp"
#include "../FileSelector.hpp"
#include "../../ImGui/GuiHelpers.hpp"
#include "../../Resources.hpp"

using namespace GUI;

EntityEditor::EntityEditor() {
    name[0] = '\0';
    AddEditor<Component::Animation>("Animation", std::bind(&EntityEditor::AnimationEditor, this, std::placeholders::_1));
    AddEditor<Component::Physics>("Physics", std::bind(&EntityEditor::PhysicsEditor, this, std::placeholders::_1));
    AddEditor<Component::Mesh>("Mesh", std::bind(&EntityEditor::MeshEditor, this, std::placeholders::_1));
    AddEditor<Component::Lens>("Lens", std::bind(&EntityEditor::LensEditor, this, std::placeholders::_1));
    AddEditor<Component::Material>("Material", std::bind(&EntityEditor::MaterialEditor, this, std::placeholders::_1));
    AddEditor<Component::DirectionalLight>("Directional light", std::bind(&EntityEditor::DirectionalLightEditor, this, std::placeholders::_1));
    AddEditor<Component::PointLight>("Point light", std::bind(&EntityEditor::PointLightEditor, this, std::placeholders::_1));
    AddEditor<Component::SpotLight>("Spot light", std::bind(&EntityEditor::SpotLightEditor, this, std::placeholders::_1));
    AddEditor<Component::Listener>("Listener", std::bind(&EntityEditor::ListenerEditor, this, std::placeholders::_1));
    AddEditor<Component::Script>("Script", std::bind(&EntityEditor::ScriptEditor, this, std::placeholders::_1));
    AddEditor<Component::SoundSource>("Sound source", std::bind(&EntityEditor::SoundSourceEditor, this, std::placeholders::_1));
    AddEditor<Component::ParticleEmitter>("Particle emitter", std::bind(&EntityEditor::ParticleEmitterEditor, this, std::placeholders::_1));
}

EntityEditor::~EntityEditor() {

}

void EntityEditor::Show() {
    if (ImGui::Begin(("Entity: " + entity->name + "###" + std::to_string(reinterpret_cast<uintptr_t>(entity))).c_str(), &visible, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ShowBorders)) {
        ImGui::InputText("Name", name, 128);
        entity->name = name;
        ImGui::Text("Transform");
        ImGui::ShowHelpMarker("The entity's position, rotation and scale.", 75.f);
        ImGui::Indent();
        ImGui::DraggableVec3("Position", entity->position);
        ImGui::DraggableVec3("Rotation", entity->rotation);
        ImGui::DraggableVec3("Scale", entity->scale);
        ImGui::Unindent();
        if (!entity->IsScene()) {
            if (ImGui::Button("Add component"))
                ImGui::OpenPopup("Add component");

            if (ImGui::BeginPopup("Add component")) {
                ImGui::Text("Components");
                ImGui::Separator();

                for (Editor& editor : editors) {
                    editor.addFunction();
                }

                ImGui::EndPopup();
            }

            for (Editor& editor : editors) {
                editor.editFunction();
            }
        }
    }

    ImGui::End();
}

void EntityEditor::SetEntity(Entity* entity) {
    this->entity = entity;
    strcpy(name, entity->name.c_str());
}

Entity* EntityEditor::GetEntity() {
    return entity;
}

bool EntityEditor::ShowsEntity(Entity* entity) {
    return this->entity == entity;
}

bool EntityEditor::IsVisible() const {
    return visible;
}

void EntityEditor::SetVisible(bool visible) {
    this->visible = visible;
}

void EntityEditor::AnimationEditor(Component::Animation* animation) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Animation"))
        ImGui::OpenPopup("Select model##Animation");

    if (ImGui::BeginPopup("Select model##Animation")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Resources().models) {
            if (ImGui::Selectable(model->name.c_str()))
                animation->riggedModel = dynamic_cast<Geometry::Model*>(model);
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::PhysicsEditor(Component::Physics* physics) {
    ImGui::Text("Positional");
    ImGui::Indent();
    ImGui::DraggableVec3("Velocity", physics->velocity);
    ImGui::DraggableFloat("Max velocity", physics->maxVelocity, 0.0f);
    ImGui::DraggableVec3("Acceleration", physics->acceleration);
    ImGui::DraggableFloat("Velocity drag factor", physics->velocityDragFactor);
    ImGui::DraggableFloat("Gravity factor", physics->gravityFactor);
    ImGui::Unindent();
    ImGui::Text("Angular");
    ImGui::Indent();
    ImGui::DraggableVec3("Angular velocity", physics->angularVelocity);
    ImGui::DraggableFloat("Max angular velocity", physics->maxAngularVelocity, 0.0f);
    ImGui::DraggableVec3("Angular acceleration", physics->angularAcceleration);
    ImGui::DraggableFloat("Angular drag factor", physics->angularDragFactor);
    ImGui::DraggableVec3("Moment of inertia", physics->momentOfInertia);
    ImGui::Unindent();

}

void EntityEditor::MeshEditor(Component::Mesh* mesh) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Mesh"))
        ImGui::OpenPopup("Select model##Mesh");

    if (ImGui::BeginPopup("Select model##Mesh")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Resources().models) {
            if (ImGui::Selectable(model->name.c_str()))
                mesh->geometry = model;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::LensEditor(Component::Lens* lens) {
    ImGui::Indent();
    ImGui::DraggableFloat("Field of view", lens->fieldOfView, 0.0f, 180.f);
    ImGui::DraggableFloat("Z near", lens->zNear, 0.0f);
    ImGui::DraggableFloat("Z far", lens->zFar, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::MaterialEditor(Component::Material* material) {
    // Diffuse
    ImGui::Text("Diffuse");
    ImGui::Indent();
    if (material->diffuse->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->diffuse->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select diffuse texture"))
        ImGui::OpenPopup("Select diffuse texture");

    if (ImGui::BeginPopup("Select diffuse texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str())) {
                if (material->diffuse != Hymn().defaultDiffuse)
                    Managers().resourceManager->FreeTextureAsset(material->diffuse);

                material->diffuse = Managers().resourceManager->CreateTextureAsset(texture->name);
            }
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Normal
    ImGui::Text("Normal");
    ImGui::Indent();
    if (material->normal->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->normal->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select normal texture"))
        ImGui::OpenPopup("Select normal texture");

    if (ImGui::BeginPopup("Select normal texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str())) {
                if (material->normal != Hymn().defaultNormal)
                    Managers().resourceManager->FreeTextureAsset(material->normal);

                material->normal = Managers().resourceManager->CreateTextureAsset(texture->name);
            }
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Specular
    ImGui::Text("Specular");
    ImGui::Indent();
    if (material->specular->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->specular->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select specular texture"))
        ImGui::OpenPopup("Select specular texture");

    if (ImGui::BeginPopup("Select specular texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str())) {
                if (material->specular != Hymn().defaultSpecular)
                    Managers().resourceManager->FreeTextureAsset(material->specular);

                material->specular = Managers().resourceManager->CreateTextureAsset(texture->name);
            }
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Glow
    ImGui::Text("Glow");
    ImGui::Indent();
    if (material->glow->GetTexture()->IsLoaded())
        ImGui::Image((void*) material->glow->GetTexture()->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select glow texture"))
        ImGui::OpenPopup("Select glow texture");

    if (ImGui::BeginPopup("Select glow texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (TextureAsset* texture : Resources().textures) {
            if (ImGui::Selectable(texture->name.c_str())) {
                if (material->glow != Hymn().defaultGlow)
                    Managers().resourceManager->FreeTextureAsset(material->glow);

                material->glow = Managers().resourceManager->CreateTextureAsset(texture->name);
            }
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::DirectionalLightEditor(Component::DirectionalLight* directionalLight) {
    ImGui::Indent();
    ImGui::ColorEdit3("Color", &directionalLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", directionalLight->ambientCoefficient, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::PointLightEditor(Component::PointLight* pointLight) {
    ImGui::Indent();
    ImGui::ColorEdit3("Color", &pointLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", pointLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", pointLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", pointLight->intensity, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::SpotLightEditor(Component::SpotLight* spotLight) {
    ImGui::Indent();
    ImGui::ColorEdit3("Color", &spotLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", spotLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", spotLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", spotLight->intensity, 0.0f);
    ImGui::DraggableFloat("Cone angle", spotLight->coneAngle, 0.0f, 180.f);
    ImGui::Unindent();
}

void EntityEditor::ListenerEditor(Component::Listener* listener) {

}

void EntityEditor::ScriptEditor(Component::Script* script) {
    ImGui::Indent();
    if(script->scriptFile != nullptr)
        ImGui::Text(script->scriptFile->name.c_str());
    else
        ImGui::Text("No script loaded");

    if (ImGui::Button("Select script"))
        ImGui::OpenPopup("Select script");

    if (ImGui::BeginPopup("Select script")) {
        ImGui::Text("Scripts");
        ImGui::Separator();

        for (ScriptFile* scriptFile : Hymn().scripts) {
            if (ImGui::Selectable(scriptFile->name.c_str()))
                script->scriptFile = scriptFile;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::SoundSourceEditor(Component::SoundSource* soundSource) {
    ImGui::Text("Sound");
    ImGui::Indent();
    if (ImGui::Button("Select sound"))
        ImGui::OpenPopup("Select sound");

    if (ImGui::BeginPopup("Select sound")) {
        ImGui::Text("Sounds");
        ImGui::Separator();

        for (Audio::SoundBuffer* sound : Resources().sounds) {
            if (ImGui::Selectable(sound->name.c_str()))
                soundSource->soundBuffer = sound;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
    ImGui::Text("Sound properties");
    ImGui::Indent();
    ImGui::DraggableFloat("Pitch", soundSource->pitch, 0.0f);
    ImGui::DraggableFloat("Gain", soundSource->gain, 0.0f);
    ImGui::Checkbox("Loop", &soundSource->loop);
    ImGui::Unindent();
}

void EntityEditor::ParticleEmitterEditor(Component::ParticleEmitter* particleEmitter) {
    ImGui::Text("Particle");
    ImGui::Indent();
    int rows = Managers().particleManager->GetTextureAtlasRows();
    float column = static_cast<float>(particleEmitter->particleType.textureIndex % rows);
    float row = static_cast<float>(particleEmitter->particleType.textureIndex / rows);
    ImGui::Image((void*) Managers().particleManager->GetTextureAtlas()->GetTextureID(), ImVec2(128, 128), ImVec2(column / rows, row / rows), ImVec2((column + 1.f) / rows, (row + 1.f) / rows));
    ImGui::InputInt("Texture index", &particleEmitter->particleType.textureIndex);
    ImGui::ColorEdit3("Color", &particleEmitter->particleType.color[0]);
    ImGui::DraggableVec3("Min velocity", particleEmitter->particleType.minVelocity);
    ImGui::DraggableVec3("Max velocity", particleEmitter->particleType.maxVelocity);
    ImGui::DraggableFloat("Average lifetime", particleEmitter->particleType.averageLifetime, 0.0f);
    ImGui::DraggableFloat("Lifetime variance", particleEmitter->particleType.lifetimeVariance, 0.0f);
    ImGui::DraggableVec2("Average size", particleEmitter->particleType.averageSize, 0.0f);
    ImGui::DraggableVec2("Size variance", particleEmitter->particleType.sizeVariance, 0.0f);
    ImGui::Checkbox("Uniform scaling", &particleEmitter->particleType.uniformScaling);
    ImGui::DraggableFloat("Start alpha", particleEmitter->particleType.startAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("Mid alpha", particleEmitter->particleType.midAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("End alpha", particleEmitter->particleType.endAlpha, 0.0f, 1.0f);
    ImGui::Unindent();

    ImGui::Text("Emitter");
    ImGui::Indent();
    ImGui::DraggableFloat("Average emit time", particleEmitter->averageEmitTime, 0.0f);
    ImGui::DraggableFloat("Emit time variance", particleEmitter->emitTimeVariance, 0.0f);

    const char* items[] = { "Point", "Cuboid" };
    int item = static_cast<int>(particleEmitter->emitterType);
    if (ImGui::Combo("Emitter type", &item, items, 2))
        particleEmitter->emitterType = static_cast<Component::ParticleEmitter::EmitterType>(item);

    if (particleEmitter->emitterType == Component::ParticleEmitter::CUBOID)
        ImGui::DraggableVec3("Size", particleEmitter->size);

    ImGui::Unindent();

    ImGui::Text("Preview");
    ImGui::Indent();
    ImGui::Checkbox("Simulate", &particleEmitter->preview);
    ImGui::Unindent();
}
<|endoftext|>


<commit_before><?hh

/*
 *
 *  ____            _        _   __  __ _                  __  __ ____
 * |  _ \ ___   ___| | _____| |_|  \/  (_)_ __   ___      |  \/  |  _ \
 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
 * |  __/ (_) | (__|   <  __/ |_| |  | | | | | |  __/_____| |  | |  __/
 * |_|   \___/ \___|_|\_\___|\__|_|  |_|_|_| |_|\___|     |_|  |_|_|
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * @author PocketMine Team
 * @link http://www.pocketmine.net/
 *
 *
*/

namespace pocketmine;

abstract class Collectable extends \Threaded implements \Collectable{

    private $isGarbage = false;

    public function isGarbage() : bool{
        return $this->isGarbage;
    }

    public function setGarbage(){
        $this->isGarbage = true;
    }
}
<commit_msg>Delete Collectable.hh<commit_after><|endoftext|>