<commit_before>/// @file
/// @author uentity
/// @date 18.10.2016
/// @brief Test BS type factory
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#define BOOST_TEST_DYN_LINK
#include <bs/objbase.h>
#include <bs/type_macro.h>
#include <bs/kernel.h>
#include <bs/log.h>

#include <boost/test/unit_test.hpp>
#include <iostream>

BLUE_SKY_PLUGIN_DESCRIPTOR("test_type_descriptor", "1.0", "Types factory unit test");

namespace blue_sky {

/*-----------------------------------------------------------------------------
 * test simple class
 *-----------------------------------------------------------------------------*/
class bs_person : public objbase {
public:
	bs_person() : name_("[NONAME]"), age_(0) {}

	bs_person(const char* name) : name_(name), age_(0) {}

	bs_person(double age) : name_("[NONAME]"), age_(age) {}

	bs_person(const std::string& name, double age = 0) : name_(name), age_(age) {}

	template< class Ostream >
	friend Ostream& operator<<(Ostream& os, const bs_person& p) {
		return os << "Person name = " << p.name_ << ", age = " << p.age_;
	}

	std::string name_;
	double age_;

	BS_TYPE_DECL
};
using sp_person = std::shared_ptr< bs_person >;

// define free function that returns bs_person singleton
sp_obj create_single_person() {
	static bs_person P("[SINGLE]");
	auto noop_del = [](const bs_person*) {};
	return std::shared_ptr< bs_person >(&P, noop_del);
}

BS_TYPE_IMPL(bs_person, objbase, "bs_person", "BS Person", false, false)
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (const char*))
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (double))
// add free function constructor
//BS_TYPE_ADD_DEF_CONSTRUCTOR(bs_person)
BS_TYPE_ADD_CONSTRUCTOR_F(bs_person, create_single_person)

// these two should coincide
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (const std::string&))
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (std::string))

BS_TYPE_ADD_CONSTRUCTOR(bs_person, (const std::string&, double))
BS_TYPE_ADD_COPY_CONSTRUCTOR(bs_person)

BS_REGISTER_TYPE(bs_person)

/*-----------------------------------------------------------------------------
 * test templated class
 *-----------------------------------------------------------------------------*/
template< class T >
struct my_strategy : public objbase {
	using cont_type = std::vector< T >;

	my_strategy() : name_("[NONAME]") {}
	my_strategy(const my_strategy&) = default;
	my_strategy(my_strategy&&) = default;
	my_strategy(const std::string& name) : name_(name) {}

	std::string name_;

	//template< class Ostream >
	friend std::ostream& operator<<(std::ostream& os, const my_strategy& s) {
		return os << "Strategy type : " << bs_type().type_name() << "; strategy name = " << s.name_;
	}

	// expect that only one strategy can exist
	BS_TYPE_DECL_INL(my_strategy, objbase, "", "Strategy", true, true)
};
template< class T >
using sp_strat = std::shared_ptr< my_strategy< T > >;

// register strategy
BS_TYPE_IMPL_INL_T1(my_strategy, int)
BS_TYPE_IMPL_INL_T1(my_strategy, double)
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< int >, (const char*))
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< double >, (const char*))
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< int >, (const std::string&))
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< double >, (const std::string&))

BS_REGISTER_TYPE(my_strategy< int >)
BS_REGISTER_TYPE(my_strategy< double >)

/*-----------------------------------------------------------------------------
 * test complex templated class
 *-----------------------------------------------------------------------------*/
// Strategy is passed with tuple argument just for testing
template< class T, class Strategy >
class uber_type : public objbase {
public:
	using uber_T = T;
	using cont_T = typename Strategy::cont_type;

	uber_type() : name_("[NONAME]") {};
	uber_type(const uber_type&) = default;
	uber_type(const char* name) : name_(name) {}
	uber_type(const std::string& name) : name_(name) {}

	void add_value(uber_T val) { storage_.emplace_back(std::move(val)); }

	//template< class Ostream >
	friend std::ostream& operator<<(std::ostream& os, const uber_type& s) {
		os << "Uber type: " << bs_type().type_name() << "; Uber name = " << s.name_ <<
			" has elements [" << s.storage_.size() << "]: ";
		for(auto& v : s.storage_) {
			os << v << ' ';
		}
		return os;
	}

	T value_;
	cont_T storage_;
	std::string name_;

	BS_TYPE_DECL_INL_BEGIN(uber_type, objbase, "", "Uber complex type", true, false)
		td.add_constructor< uber_type, const char* >();
		td.add_copy_constructor< uber_type >();
	BS_TYPE_DECL_INL_END
};
template< class T >
using uber_t = uber_type< T, my_strategy< T > >;
template< class T >
using sp_uber = std::shared_ptr< uber_t< T > >;

// define free function that returns bs_person singleton
template< class T >
sp_obj create_single_uber(T val) {
	using uber_t = uber_type< T, my_strategy< T > >;
	static uber_t P("[SINGLE]");
	P.add_value(val);

	auto noop_del = [](const uber_t*) {};
	return std::shared_ptr< uber_t >(&P, noop_del);
}

BS_TYPE_IMPL_INL_T(uber_type, (int, my_strategy< int >))
BS_TYPE_IMPL_INL_T(uber_type, (double, my_strategy< double >))
BS_TYPE_ADD_CONSTRUCTOR_T(uber_type, (int, my_strategy< int >), (std::string))
BS_TYPE_ADD_CONSTRUCTOR_T(uber_type, (double, my_strategy< double >), (std::string))

// add free function constructors
BS_TYPE_ADD_CONSTRUCTOR_T_F(uber_type, (int, my_strategy< int >), create_single_uber, (int))
BS_TYPE_ADD_CONSTRUCTOR_T_F(uber_type, (double, my_strategy< double >), create_single_uber, (double))

BS_REGISTER_TYPE_T(uber_type, (int, my_strategy< int >))
BS_REGISTER_TYPE_T(uber_type, (double, my_strategy< double >))

} // eof blue_sky namespace

using namespace blue_sky;

BOOST_AUTO_TEST_CASE(test_type_descriptor) {
	std::cout << "*** testing bs_type_descriptor..." << std::endl;
	// register type first
	//BS_KERNEL.register_type(bs_person::bs_type());

	sp_person p = BS_KERNEL.create_object("bs_person");
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// fill name
	p = BS_KERNEL.create_object("bs_person", "John");
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// fill age with int - should fail
	p = BS_KERNEL.create_object("bs_person", 28);
	BOOST_TEST((p == nullptr));
	// fill age with double - should work
	p = BS_KERNEL.create_object("bs_person", 28.);
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// fill both age and name
	p = BS_KERNEL.create_object("bs_person", std::string("Sarah"), 33.);
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// make copy
	sp_person p1 = BS_KERNEL.create_object_copy(p);
	BOOST_TEST(p1);
	if(p1)
		std::cout << "Copy is: " << *p1 << std::endl;

	// create strategy
	sp_strat< int > si = BS_KERNEL.create_object(my_strategy< int >::bs_type(), "integer strategy");
	BOOST_TEST(si);
	if(si) {
		std::cout << *si << std::endl;
	}
	sp_strat< double > sd = BS_KERNEL.create_object("my_strategy double", "double strategy");
	BOOST_TEST(sd);
	if(sd) std::cout << *sd << std::endl;

	// create uber_type
	sp_uber< int > ui = BS_KERNEL.create_object(uber_type< int, my_strategy< int > >::bs_type());
	BOOST_TEST(ui);
	if(ui) std::cout << *ui << std::endl;

	sp_uber< double > ud = BS_KERNEL.create_object("uber_type double my_strategy< double >", "I'm double");
	ud->add_value(42.);
	BOOST_TEST(ud);
	if(ud) std::cout << *ud << std::endl;

	// test using free function
	ud = BS_KERNEL.create_object("uber_type double my_strategy< double >", 27.5);
	BOOST_TEST(ud);
	ud = BS_KERNEL.create_object("uber_type double my_strategy< double >", 42.);
	BOOST_TEST(ud);
	if(ud) std::cout << *ud << std::endl;
}

<commit_msg>test: update type_descriptor test, fix macro name according to kernel changes<commit_after>/// @file
/// @author uentity
/// @date 18.10.2016
/// @brief Test BS type factory
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#define BOOST_TEST_DYN_LINK
#include <bs/objbase.h>
#include <bs/type_macro.h>
#include <bs/kernel.h>
#include <bs/log.h>

#include <boost/test/unit_test.hpp>
#include <iostream>

BS_PLUGIN_DESCRIPTOR("test_type_descriptor", "1.0", "Types factory unit test");

namespace blue_sky {

/*-----------------------------------------------------------------------------
 * test simple class
 *-----------------------------------------------------------------------------*/
class bs_person : public objbase {
public:
	bs_person() : name_("[NONAME]"), age_(0) {}

	bs_person(const char* name) : name_(name), age_(0) {}

	bs_person(double age) : name_("[NONAME]"), age_(age) {}

	bs_person(const std::string& name, double age = 0) : name_(name), age_(age) {}

	template< class Ostream >
	friend Ostream& operator<<(Ostream& os, const bs_person& p) {
		return os << "Person name = " << p.name_ << ", age = " << p.age_;
	}

	std::string name_;
	double age_;

	BS_TYPE_DECL
};
using sp_person = std::shared_ptr< bs_person >;

// define free function that returns bs_person singleton
sp_obj create_single_person() {
	static bs_person P("[SINGLE]");
	auto noop_del = [](const bs_person*) {};
	return std::shared_ptr< bs_person >(&P, noop_del);
}

BS_TYPE_IMPL(bs_person, objbase, "bs_person", "BS Person", false, false)
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (const char*))
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (double))
// add free function constructor
//BS_TYPE_ADD_DEF_CONSTRUCTOR(bs_person)
BS_TYPE_ADD_CONSTRUCTOR_F(bs_person, create_single_person)

// these two should coincide
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (const std::string&))
BS_TYPE_ADD_CONSTRUCTOR(bs_person, (std::string))

BS_TYPE_ADD_CONSTRUCTOR(bs_person, (const std::string&, double))
BS_TYPE_ADD_COPY_CONSTRUCTOR(bs_person)

BS_REGISTER_TYPE(bs_person)

/*-----------------------------------------------------------------------------
 * test templated class
 *-----------------------------------------------------------------------------*/
template< class T >
struct my_strategy : public objbase {
	using cont_type = std::vector< T >;

	my_strategy() : name_("[NONAME]") {}
	my_strategy(const my_strategy&) = default;
	my_strategy(my_strategy&&) = default;
	my_strategy(const std::string& name) : name_(name) {}

	std::string name_;

	//template< class Ostream >
	friend std::ostream& operator<<(std::ostream& os, const my_strategy& s) {
		return os << "Strategy type : " << bs_type().type_name() << "; strategy name = " << s.name_;
	}

	// expect that only one strategy can exist
	BS_TYPE_DECL_INL(my_strategy, objbase, "", "Strategy", true, true)
};
template< class T >
using sp_strat = std::shared_ptr< my_strategy< T > >;

// register strategy
BS_TYPE_IMPL_INL_T1(my_strategy, int)
BS_TYPE_IMPL_INL_T1(my_strategy, double)
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< int >, (const char*))
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< double >, (const char*))
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< int >, (const std::string&))
BS_TYPE_ADD_CONSTRUCTOR(my_strategy< double >, (const std::string&))

BS_REGISTER_TYPE(my_strategy< int >)
BS_REGISTER_TYPE(my_strategy< double >)

/*-----------------------------------------------------------------------------
 * test complex templated class
 *-----------------------------------------------------------------------------*/
// Strategy is passed with tuple argument just for testing
template< class T, class Strategy >
class uber_type : public objbase {
public:
	using uber_T = T;
	using cont_T = typename Strategy::cont_type;

	uber_type() : name_("[NONAME]") {};
	uber_type(const uber_type&) = default;
	uber_type(const char* name) : name_(name) {}
	uber_type(const std::string& name) : name_(name) {}

	void add_value(uber_T val) { storage_.emplace_back(std::move(val)); }

	//template< class Ostream >
	friend std::ostream& operator<<(std::ostream& os, const uber_type& s) {
		os << "Uber type: " << bs_type().type_name() << "; Uber name = " << s.name_ <<
			" has elements [" << s.storage_.size() << "]: ";
		for(auto& v : s.storage_) {
			os << v << ' ';
		}
		return os;
	}

	T value_;
	cont_T storage_;
	std::string name_;

	BS_TYPE_DECL_INL_BEGIN(uber_type, objbase, "", "Uber complex type", true, false)
		td.add_constructor< uber_type, const char* >();
		td.add_copy_constructor< uber_type >();
	BS_TYPE_DECL_INL_END
};
template< class T >
using uber_t = uber_type< T, my_strategy< T > >;
template< class T >
using sp_uber = std::shared_ptr< uber_t< T > >;

// define free function that returns bs_person singleton
template< class T >
sp_obj create_single_uber(T val) {
	using uber_t = uber_type< T, my_strategy< T > >;
	static uber_t P("[SINGLE]");
	P.add_value(val);

	auto noop_del = [](const uber_t*) {};
	return std::shared_ptr< uber_t >(&P, noop_del);
}

BS_TYPE_IMPL_INL_T(uber_type, (int, my_strategy< int >))
BS_TYPE_IMPL_INL_T(uber_type, (double, my_strategy< double >))
BS_TYPE_ADD_CONSTRUCTOR_T(uber_type, (int, my_strategy< int >), (std::string))
BS_TYPE_ADD_CONSTRUCTOR_T(uber_type, (double, my_strategy< double >), (std::string))

// add free function constructors
BS_TYPE_ADD_CONSTRUCTOR_T_F(uber_type, (int, my_strategy< int >), create_single_uber, (int))
BS_TYPE_ADD_CONSTRUCTOR_T_F(uber_type, (double, my_strategy< double >), create_single_uber, (double))

BS_REGISTER_TYPE_T(uber_type, (int, my_strategy< int >))
BS_REGISTER_TYPE_T(uber_type, (double, my_strategy< double >))

} // eof blue_sky namespace

using namespace blue_sky;

BOOST_AUTO_TEST_CASE(test_type_descriptor) {
	std::cout << "*** testing bs_type_descriptor..." << std::endl;
	// register type first
	//BS_KERNEL.register_type(bs_person::bs_type());

	sp_person p = BS_KERNEL.create_object("bs_person");
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// fill name
	p = BS_KERNEL.create_object("bs_person", "John");
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// fill age with int - should fail
	p = BS_KERNEL.create_object("bs_person", 28);
	BOOST_TEST((p == nullptr));
	// fill age with double - should work
	p = BS_KERNEL.create_object("bs_person", 28.);
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// fill both age and name
	p = BS_KERNEL.create_object("bs_person", std::string("Sarah"), 33.);
	BOOST_TEST(p);
	if(p)
		std::cout << *p << std::endl;
	// make copy
	sp_person p1 = BS_KERNEL.create_object_copy(p);
	BOOST_TEST(p1);
	if(p1)
		std::cout << "Copy is: " << *p1 << std::endl;

	// create strategy
	sp_strat< int > si = BS_KERNEL.create_object(my_strategy< int >::bs_type(), "integer strategy");
	BOOST_TEST(si);
	if(si) {
		std::cout << *si << std::endl;
	}
	sp_strat< double > sd = BS_KERNEL.create_object("my_strategy double", "double strategy");
	BOOST_TEST(sd);
	if(sd) std::cout << *sd << std::endl;

	// create uber_type
	sp_uber< int > ui = BS_KERNEL.create_object(uber_type< int, my_strategy< int > >::bs_type());
	BOOST_TEST(ui);
	if(ui) std::cout << *ui << std::endl;

	sp_uber< double > ud = BS_KERNEL.create_object("uber_type double my_strategy< double >", "I'm double");
	ud->add_value(42.);
	BOOST_TEST(ud);
	if(ud) std::cout << *ud << std::endl;

	// test using free function
	ud = BS_KERNEL.create_object("uber_type double my_strategy< double >", 27.5);
	BOOST_TEST(ud);
	ud = BS_KERNEL.create_object("uber_type double my_strategy< double >", 42.);
	BOOST_TEST(ud);
	if(ud) std::cout << *ud << std::endl;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <filagui/ImGuiHelper.h>

#include <vector>
#include <unordered_map>

#include <imgui.h>

#include <filament/Camera.h>
#include <filament/Fence.h>
#include <filament/IndexBuffer.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Scene.h>
#include <filament/Texture.h>
#include <filament/TextureSampler.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <utils/EntityManager.h>

using namespace filament::math;
using namespace filament;
using namespace utils;

using MinFilter = TextureSampler::MinFilter;
using MagFilter = TextureSampler::MagFilter;

namespace filagui {

#include "generated/resources/filagui_resources.h"

ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontPath,
        ImGuiContext *imGuiContext)
        : mEngine(engine), mView(view), mScene(engine->createScene()),
        mImGuiContext(imGuiContext ? imGuiContext : ImGui::CreateContext()) {
    ImGuiIO& io = ImGui::GetIO();

    // Create a simple alpha-blended 2D blitting material.
    mMaterial = Material::Builder()
            .package(FILAGUI_RESOURCES_UIBLIT_DATA, FILAGUI_RESOURCES_UIBLIT_SIZE)
            .build(*engine);

    // If the given font path is invalid, ImGui will silently fall back to proggy, which is a
    // tiny "pixel art" texture that is compiled into the library.
    if (!fontPath.isEmpty()) {
        io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 16.0f);
    }
    createAtlasTexture(engine);

    // For proggy, switch to NEAREST for pixel-perfect text.
    if (fontPath.isEmpty() && !imGuiContext) {
        mSampler = TextureSampler(MinFilter::NEAREST, MagFilter::NEAREST);
        mMaterial->setDefaultParameter("albedo", mTexture, mSampler);
    }

    utils::EntityManager& em = utils::EntityManager::get();
    mCameraEntity = em.create();
    mCamera = mEngine->createCamera(mCameraEntity);

    view->setCamera(mCamera);

    view->setPostProcessingEnabled(false);
    view->setBlendMode(View::BlendMode::TRANSLUCENT);
    view->setShadowingEnabled(false);

    // Attach a scene for our one and only Renderable.
    view->setScene(mScene);

    mRenderable = em.create();
    mScene->addEntity(mRenderable);

    ImGui::StyleColorsDark();
}

void ImGuiHelper::createAtlasTexture(Engine* engine) {
    engine->destroy(mTexture);
    ImGuiIO& io = ImGui::GetIO();
    // Create the grayscale texture that ImGui uses for its glyph atlas.
    static unsigned char* pixels;
    int width, height;
    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
    size_t size = (size_t) (width * height * 4);
    Texture::PixelBufferDescriptor pb(
            pixels, size,
            Texture::Format::RGBA, Texture::Type::UBYTE);
    mTexture = Texture::Builder()
            .width((uint32_t) width)
            .height((uint32_t) height)
            .levels((uint8_t) 1)
            .format(Texture::InternalFormat::RGBA8)
            .sampler(Texture::Sampler::SAMPLER_2D)
            .build(*engine);
    mTexture->setImage(*engine, 0, std::move(pb));

    mSampler = TextureSampler(MinFilter::LINEAR, MagFilter::LINEAR);
    mMaterial->setDefaultParameter("albedo", mTexture, mSampler);
}

ImGuiHelper::~ImGuiHelper() {
    mEngine->destroy(mScene);
    mEngine->destroy(mRenderable);
    mEngine->destroyCameraComponent(mCameraEntity);

    for (auto& mi : mMaterialInstances) {
        mEngine->destroy(mi);
    }
    mEngine->destroy(mMaterial);
    mEngine->destroy(mTexture);
    for (auto& vb : mVertexBuffers) {
        mEngine->destroy(vb);
    }
    for (auto& ib : mIndexBuffers) {
        mEngine->destroy(ib);
    }

    EntityManager& em = utils::EntityManager::get();
    em.destroy(mRenderable);
    em.destroy(mCameraEntity);

    ImGui::DestroyContext(mImGuiContext);
    mImGuiContext = nullptr;
}

void ImGuiHelper::setDisplaySize(int width, int height, float scaleX, float scaleY) {
    ImGuiIO& io = ImGui::GetIO();
    io.DisplaySize = ImVec2(width, height);
    io.DisplayFramebufferScale.x = scaleX;
    io.DisplayFramebufferScale.y = scaleY;
    mCamera->setProjection(Camera::Projection::ORTHO,
            0.0, double(width),
            double(height), 0.0,
            0.0, 1.0);
}

void ImGuiHelper::render(float timeStepInSeconds, Callback imguiCommands) {
    ImGui::SetCurrentContext(mImGuiContext);
    ImGuiIO& io = ImGui::GetIO();
    io.DeltaTime = timeStepInSeconds;
    // First, let ImGui process events and increment its internal frame count.
    // This call will also update the io.WantCaptureMouse, io.WantCaptureKeyboard flag
    // that tells us whether to dispatch inputs (or not) to the app.
    ImGui::NewFrame();
    // Allow the client app to create widgets.
    imguiCommands(mEngine, mView);
    // Let ImGui build up its draw data.
    ImGui::Render();
    // Finally, translate the draw data into Filament objects.
    processImGuiCommands(ImGui::GetDrawData(), ImGui::GetIO());
}

void ImGuiHelper::processImGuiCommands(ImDrawData* commands, const ImGuiIO& io) {
    ImGui::SetCurrentContext(mImGuiContext);

    mHasSynced = false;
    auto& rcm = mEngine->getRenderableManager();

    // Avoid rendering when minimized and scale coordinates for retina displays.
    int fbwidth = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
    int fbheight = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
    if (fbwidth == 0 || fbheight == 0)
        return;
    commands->ScaleClipRects(io.DisplayFramebufferScale);

    // Ensure that we have enough vertex buffers and index buffers.
    createBuffers(commands->CmdListsCount);

    // Count how many primitives we'll need, then create a Renderable builder.
    size_t nPrims = 0;
    std::unordered_map<uint64_t, filament::MaterialInstance*> scissorRects;
    for (int cmdListIndex = 0; cmdListIndex < commands->CmdListsCount; cmdListIndex++) {
        const ImDrawList* cmds = commands->CmdLists[cmdListIndex];
        nPrims += cmds->CmdBuffer.size();
    }
    auto rbuilder = RenderableManager::Builder(nPrims);
    rbuilder.boundingBox({{ 0, 0, 0 }, { 10000, 10000, 10000 }}).culling(false);

    // Ensure that we have a material instance for each primitive.
    size_t previousSize = mMaterialInstances.size();
    if (nPrims > mMaterialInstances.size()) {
        mMaterialInstances.resize(nPrims);
        for (size_t i = previousSize; i < mMaterialInstances.size(); i++) {
            mMaterialInstances[i] = mMaterial->createInstance();
        }
    }

    // Recreate the Renderable component and point it to the vertex buffers.
    rcm.destroy(mRenderable);
    int bufferIndex = 0;
    int primIndex = 0;
    for (int cmdListIndex = 0; cmdListIndex < commands->CmdListsCount; cmdListIndex++) {
        const ImDrawList* cmds = commands->CmdLists[cmdListIndex];
        populateVertexData(bufferIndex,
                cmds->VtxBuffer.Size * sizeof(ImDrawVert), cmds->VtxBuffer.Data,
                cmds->IdxBuffer.Size * sizeof(ImDrawIdx), cmds->IdxBuffer.Data);
        for (const auto& pcmd : cmds->CmdBuffer) {
            if (pcmd.UserCallback) {
                pcmd.UserCallback(cmds, &pcmd);
            } else {
                MaterialInstance* materialInstance = mMaterialInstances[primIndex];
                materialInstance->setScissor( pcmd.ClipRect.x, fbheight - pcmd.ClipRect.w,
                        (uint16_t) (pcmd.ClipRect.z - pcmd.ClipRect.x),
                        (uint16_t) (pcmd.ClipRect.w - pcmd.ClipRect.y));
                if (pcmd.TextureId) {
                    TextureSampler sampler(MinFilter::LINEAR, MagFilter::LINEAR);
                    materialInstance->setParameter("albedo", (Texture const*)pcmd.TextureId, sampler);
                } else {
                    materialInstance->setParameter("albedo", mTexture, mSampler);
                }
                rbuilder
                        .geometry(primIndex, RenderableManager::PrimitiveType::TRIANGLES,
                                mVertexBuffers[bufferIndex], mIndexBuffers[bufferIndex],
                                pcmd.IdxOffset, pcmd.ElemCount)
                        .blendOrder(primIndex, primIndex)
                        .material(primIndex, materialInstance);
                primIndex++;
            }
        }
        bufferIndex++;
    }
    if (commands->CmdListsCount > 0) {
        rbuilder.build(*mEngine, mRenderable);
    }
}

void ImGuiHelper::createVertexBuffer(size_t bufferIndex, size_t capacity) {
    syncThreads();
    mEngine->destroy(mVertexBuffers[bufferIndex]);
    mVertexBuffers[bufferIndex] = VertexBuffer::Builder()
            .vertexCount(capacity)
            .bufferCount(1)
            .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0,
                    sizeof(ImDrawVert))
            .attribute(VertexAttribute::UV0, 0, VertexBuffer::AttributeType::FLOAT2,
                    sizeof(filament::math::float2), sizeof(ImDrawVert))
            .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4,
                    2 * sizeof(filament::math::float2), sizeof(ImDrawVert))
            .normalized(VertexAttribute::COLOR)
            .build(*mEngine);
}

void ImGuiHelper::createIndexBuffer(size_t bufferIndex, size_t capacity) {
    syncThreads();
    mEngine->destroy(mIndexBuffers[bufferIndex]);
    mIndexBuffers[bufferIndex] = IndexBuffer::Builder()
            .indexCount(capacity)
            .bufferType(IndexBuffer::IndexType::USHORT)
            .build(*mEngine);
}

void ImGuiHelper::createBuffers(int numRequiredBuffers) {
    if (numRequiredBuffers > mVertexBuffers.size()) {
        size_t previousSize = mVertexBuffers.size();
        mVertexBuffers.resize(numRequiredBuffers, nullptr);
        for (size_t i = previousSize; i < mVertexBuffers.size(); i++) {
            // Pick a reasonable starting capacity; it will grow if needed.
            createVertexBuffer(i, 1000);
        }
    }
    if (numRequiredBuffers > mIndexBuffers.size()) {
        size_t previousSize = mIndexBuffers.size();
        mIndexBuffers.resize(numRequiredBuffers, nullptr);
        for (size_t i = previousSize; i < mIndexBuffers.size(); i++) {
            // Pick a reasonable starting capacity; it will grow if needed.
            createIndexBuffer(i, 5000);
        }
    }
}

void ImGuiHelper::populateVertexData(size_t bufferIndex, size_t vbSizeInBytes, void* vbImguiData,
        size_t ibSizeInBytes, void* ibImguiData)
{
    // Create a new vertex buffer if the size isn't large enough, then copy the ImGui data into
    // a staging area since Filament's render thread might consume the data at any time.
    size_t requiredVertCount = vbSizeInBytes / sizeof(ImDrawVert);
    size_t capacityVertCount = mVertexBuffers[bufferIndex]->getVertexCount();
    if (requiredVertCount > capacityVertCount) {
        createVertexBuffer(bufferIndex, requiredVertCount);
    }
    size_t nVbBytes = requiredVertCount * sizeof(ImDrawVert);
    void* vbFilamentData = malloc(nVbBytes);
    memcpy(vbFilamentData, vbImguiData, nVbBytes);
    mVertexBuffers[bufferIndex]->setBufferAt(*mEngine, 0,
            VertexBuffer::BufferDescriptor(vbFilamentData, nVbBytes,
                [](void* buffer, size_t size, void* user) {
                    free(buffer);
                }, /* user = */ nullptr));

    // Create a new index buffer if the size isn't large enough, then copy the ImGui data into
    // a staging area since Filament's render thread might consume the data at any time.
    size_t requiredIndexCount = ibSizeInBytes / 2;
    size_t capacityIndexCount = mIndexBuffers[bufferIndex]->getIndexCount();
    if (requiredIndexCount > capacityIndexCount) {
        createIndexBuffer(bufferIndex, requiredIndexCount);
    }
    size_t nIbBytes = requiredIndexCount * 2;
    void* ibFilamentData = malloc(nIbBytes);
    memcpy(ibFilamentData, ibImguiData, nIbBytes);
    mIndexBuffers[bufferIndex]->setBuffer(*mEngine,
            IndexBuffer::BufferDescriptor(ibFilamentData, nIbBytes,
                [](void* buffer, size_t size, void* user) {
                    free(buffer);
                }, /* user = */ nullptr));
}

void ImGuiHelper::syncThreads() {
#if UTILS_HAS_THREADING
    if (!mHasSynced) {
        // This is called only when ImGui needs to grow a vertex buffer, which occurs a few times
        // after launching and rarely (if ever) after that.
        Fence::waitAndDestroy(mEngine->createFence());
        mHasSynced = true;
    }
#endif
}

} // namespace filagui
<commit_msg>Check the font path is the file (#5734)<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <filagui/ImGuiHelper.h>

#include <vector>
#include <unordered_map>

#include <imgui.h>

#include <filament/Camera.h>
#include <filament/Fence.h>
#include <filament/IndexBuffer.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Scene.h>
#include <filament/Texture.h>
#include <filament/TextureSampler.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <utils/EntityManager.h>

using namespace filament::math;
using namespace filament;
using namespace utils;

using MinFilter = TextureSampler::MinFilter;
using MagFilter = TextureSampler::MagFilter;

namespace filagui {

#include "generated/resources/filagui_resources.h"

ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontPath,
        ImGuiContext *imGuiContext)
        : mEngine(engine), mView(view), mScene(engine->createScene()),
        mImGuiContext(imGuiContext ? imGuiContext : ImGui::CreateContext()) {
    ImGuiIO& io = ImGui::GetIO();

    // Create a simple alpha-blended 2D blitting material.
    mMaterial = Material::Builder()
            .package(FILAGUI_RESOURCES_UIBLIT_DATA, FILAGUI_RESOURCES_UIBLIT_SIZE)
            .build(*engine);

    // If the given font path is invalid, ImGui will silently fall back to proggy, which is a
    // tiny "pixel art" texture that is compiled into the library.
    if (fontPath.isFile()) {
        io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 16.0f);
    }
    createAtlasTexture(engine);

    // For proggy, switch to NEAREST for pixel-perfect text.
    if (!fontPath.isFile() && !imGuiContext) {
        mSampler = TextureSampler(MinFilter::NEAREST, MagFilter::NEAREST);
        mMaterial->setDefaultParameter("albedo", mTexture, mSampler);
    }

    utils::EntityManager& em = utils::EntityManager::get();
    mCameraEntity = em.create();
    mCamera = mEngine->createCamera(mCameraEntity);

    view->setCamera(mCamera);

    view->setPostProcessingEnabled(false);
    view->setBlendMode(View::BlendMode::TRANSLUCENT);
    view->setShadowingEnabled(false);

    // Attach a scene for our one and only Renderable.
    view->setScene(mScene);

    mRenderable = em.create();
    mScene->addEntity(mRenderable);

    ImGui::StyleColorsDark();
}

void ImGuiHelper::createAtlasTexture(Engine* engine) {
    engine->destroy(mTexture);
    ImGuiIO& io = ImGui::GetIO();
    // Create the grayscale texture that ImGui uses for its glyph atlas.
    static unsigned char* pixels;
    int width, height;
    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
    size_t size = (size_t) (width * height * 4);
    Texture::PixelBufferDescriptor pb(
            pixels, size,
            Texture::Format::RGBA, Texture::Type::UBYTE);
    mTexture = Texture::Builder()
            .width((uint32_t) width)
            .height((uint32_t) height)
            .levels((uint8_t) 1)
            .format(Texture::InternalFormat::RGBA8)
            .sampler(Texture::Sampler::SAMPLER_2D)
            .build(*engine);
    mTexture->setImage(*engine, 0, std::move(pb));

    mSampler = TextureSampler(MinFilter::LINEAR, MagFilter::LINEAR);
    mMaterial->setDefaultParameter("albedo", mTexture, mSampler);
}

ImGuiHelper::~ImGuiHelper() {
    mEngine->destroy(mScene);
    mEngine->destroy(mRenderable);
    mEngine->destroyCameraComponent(mCameraEntity);

    for (auto& mi : mMaterialInstances) {
        mEngine->destroy(mi);
    }
    mEngine->destroy(mMaterial);
    mEngine->destroy(mTexture);
    for (auto& vb : mVertexBuffers) {
        mEngine->destroy(vb);
    }
    for (auto& ib : mIndexBuffers) {
        mEngine->destroy(ib);
    }

    EntityManager& em = utils::EntityManager::get();
    em.destroy(mRenderable);
    em.destroy(mCameraEntity);

    ImGui::DestroyContext(mImGuiContext);
    mImGuiContext = nullptr;
}

void ImGuiHelper::setDisplaySize(int width, int height, float scaleX, float scaleY) {
    ImGuiIO& io = ImGui::GetIO();
    io.DisplaySize = ImVec2(width, height);
    io.DisplayFramebufferScale.x = scaleX;
    io.DisplayFramebufferScale.y = scaleY;
    mCamera->setProjection(Camera::Projection::ORTHO,
            0.0, double(width),
            double(height), 0.0,
            0.0, 1.0);
}

void ImGuiHelper::render(float timeStepInSeconds, Callback imguiCommands) {
    ImGui::SetCurrentContext(mImGuiContext);
    ImGuiIO& io = ImGui::GetIO();
    io.DeltaTime = timeStepInSeconds;
    // First, let ImGui process events and increment its internal frame count.
    // This call will also update the io.WantCaptureMouse, io.WantCaptureKeyboard flag
    // that tells us whether to dispatch inputs (or not) to the app.
    ImGui::NewFrame();
    // Allow the client app to create widgets.
    imguiCommands(mEngine, mView);
    // Let ImGui build up its draw data.
    ImGui::Render();
    // Finally, translate the draw data into Filament objects.
    processImGuiCommands(ImGui::GetDrawData(), ImGui::GetIO());
}

void ImGuiHelper::processImGuiCommands(ImDrawData* commands, const ImGuiIO& io) {
    ImGui::SetCurrentContext(mImGuiContext);

    mHasSynced = false;
    auto& rcm = mEngine->getRenderableManager();

    // Avoid rendering when minimized and scale coordinates for retina displays.
    int fbwidth = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
    int fbheight = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
    if (fbwidth == 0 || fbheight == 0)
        return;
    commands->ScaleClipRects(io.DisplayFramebufferScale);

    // Ensure that we have enough vertex buffers and index buffers.
    createBuffers(commands->CmdListsCount);

    // Count how many primitives we'll need, then create a Renderable builder.
    size_t nPrims = 0;
    std::unordered_map<uint64_t, filament::MaterialInstance*> scissorRects;
    for (int cmdListIndex = 0; cmdListIndex < commands->CmdListsCount; cmdListIndex++) {
        const ImDrawList* cmds = commands->CmdLists[cmdListIndex];
        nPrims += cmds->CmdBuffer.size();
    }
    auto rbuilder = RenderableManager::Builder(nPrims);
    rbuilder.boundingBox({{ 0, 0, 0 }, { 10000, 10000, 10000 }}).culling(false);

    // Ensure that we have a material instance for each primitive.
    size_t previousSize = mMaterialInstances.size();
    if (nPrims > mMaterialInstances.size()) {
        mMaterialInstances.resize(nPrims);
        for (size_t i = previousSize; i < mMaterialInstances.size(); i++) {
            mMaterialInstances[i] = mMaterial->createInstance();
        }
    }

    // Recreate the Renderable component and point it to the vertex buffers.
    rcm.destroy(mRenderable);
    int bufferIndex = 0;
    int primIndex = 0;
    for (int cmdListIndex = 0; cmdListIndex < commands->CmdListsCount; cmdListIndex++) {
        const ImDrawList* cmds = commands->CmdLists[cmdListIndex];
        populateVertexData(bufferIndex,
                cmds->VtxBuffer.Size * sizeof(ImDrawVert), cmds->VtxBuffer.Data,
                cmds->IdxBuffer.Size * sizeof(ImDrawIdx), cmds->IdxBuffer.Data);
        for (const auto& pcmd : cmds->CmdBuffer) {
            if (pcmd.UserCallback) {
                pcmd.UserCallback(cmds, &pcmd);
            } else {
                MaterialInstance* materialInstance = mMaterialInstances[primIndex];
                materialInstance->setScissor( pcmd.ClipRect.x, fbheight - pcmd.ClipRect.w,
                        (uint16_t) (pcmd.ClipRect.z - pcmd.ClipRect.x),
                        (uint16_t) (pcmd.ClipRect.w - pcmd.ClipRect.y));
                if (pcmd.TextureId) {
                    TextureSampler sampler(MinFilter::LINEAR, MagFilter::LINEAR);
                    materialInstance->setParameter("albedo", (Texture const*)pcmd.TextureId, sampler);
                } else {
                    materialInstance->setParameter("albedo", mTexture, mSampler);
                }
                rbuilder
                        .geometry(primIndex, RenderableManager::PrimitiveType::TRIANGLES,
                                mVertexBuffers[bufferIndex], mIndexBuffers[bufferIndex],
                                pcmd.IdxOffset, pcmd.ElemCount)
                        .blendOrder(primIndex, primIndex)
                        .material(primIndex, materialInstance);
                primIndex++;
            }
        }
        bufferIndex++;
    }
    if (commands->CmdListsCount > 0) {
        rbuilder.build(*mEngine, mRenderable);
    }
}

void ImGuiHelper::createVertexBuffer(size_t bufferIndex, size_t capacity) {
    syncThreads();
    mEngine->destroy(mVertexBuffers[bufferIndex]);
    mVertexBuffers[bufferIndex] = VertexBuffer::Builder()
            .vertexCount(capacity)
            .bufferCount(1)
            .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0,
                    sizeof(ImDrawVert))
            .attribute(VertexAttribute::UV0, 0, VertexBuffer::AttributeType::FLOAT2,
                    sizeof(filament::math::float2), sizeof(ImDrawVert))
            .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4,
                    2 * sizeof(filament::math::float2), sizeof(ImDrawVert))
            .normalized(VertexAttribute::COLOR)
            .build(*mEngine);
}

void ImGuiHelper::createIndexBuffer(size_t bufferIndex, size_t capacity) {
    syncThreads();
    mEngine->destroy(mIndexBuffers[bufferIndex]);
    mIndexBuffers[bufferIndex] = IndexBuffer::Builder()
            .indexCount(capacity)
            .bufferType(IndexBuffer::IndexType::USHORT)
            .build(*mEngine);
}

void ImGuiHelper::createBuffers(int numRequiredBuffers) {
    if (numRequiredBuffers > mVertexBuffers.size()) {
        size_t previousSize = mVertexBuffers.size();
        mVertexBuffers.resize(numRequiredBuffers, nullptr);
        for (size_t i = previousSize; i < mVertexBuffers.size(); i++) {
            // Pick a reasonable starting capacity; it will grow if needed.
            createVertexBuffer(i, 1000);
        }
    }
    if (numRequiredBuffers > mIndexBuffers.size()) {
        size_t previousSize = mIndexBuffers.size();
        mIndexBuffers.resize(numRequiredBuffers, nullptr);
        for (size_t i = previousSize; i < mIndexBuffers.size(); i++) {
            // Pick a reasonable starting capacity; it will grow if needed.
            createIndexBuffer(i, 5000);
        }
    }
}

void ImGuiHelper::populateVertexData(size_t bufferIndex, size_t vbSizeInBytes, void* vbImguiData,
        size_t ibSizeInBytes, void* ibImguiData)
{
    // Create a new vertex buffer if the size isn't large enough, then copy the ImGui data into
    // a staging area since Filament's render thread might consume the data at any time.
    size_t requiredVertCount = vbSizeInBytes / sizeof(ImDrawVert);
    size_t capacityVertCount = mVertexBuffers[bufferIndex]->getVertexCount();
    if (requiredVertCount > capacityVertCount) {
        createVertexBuffer(bufferIndex, requiredVertCount);
    }
    size_t nVbBytes = requiredVertCount * sizeof(ImDrawVert);
    void* vbFilamentData = malloc(nVbBytes);
    memcpy(vbFilamentData, vbImguiData, nVbBytes);
    mVertexBuffers[bufferIndex]->setBufferAt(*mEngine, 0,
            VertexBuffer::BufferDescriptor(vbFilamentData, nVbBytes,
                [](void* buffer, size_t size, void* user) {
                    free(buffer);
                }, /* user = */ nullptr));

    // Create a new index buffer if the size isn't large enough, then copy the ImGui data into
    // a staging area since Filament's render thread might consume the data at any time.
    size_t requiredIndexCount = ibSizeInBytes / 2;
    size_t capacityIndexCount = mIndexBuffers[bufferIndex]->getIndexCount();
    if (requiredIndexCount > capacityIndexCount) {
        createIndexBuffer(bufferIndex, requiredIndexCount);
    }
    size_t nIbBytes = requiredIndexCount * 2;
    void* ibFilamentData = malloc(nIbBytes);
    memcpy(ibFilamentData, ibImguiData, nIbBytes);
    mIndexBuffers[bufferIndex]->setBuffer(*mEngine,
            IndexBuffer::BufferDescriptor(ibFilamentData, nIbBytes,
                [](void* buffer, size_t size, void* user) {
                    free(buffer);
                }, /* user = */ nullptr));
}

void ImGuiHelper::syncThreads() {
#if UTILS_HAS_THREADING
    if (!mHasSynced) {
        // This is called only when ImGui needs to grow a vertex buffer, which occurs a few times
        // after launching and rarely (if ever) after that.
        Fence::waitAndDestroy(mEngine->createFence());
        mHasSynced = true;
    }
#endif
}

} // namespace filagui
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/config.hpp"

#define CAF_SUITE io_dynamic_remote_actor_udp
#include "caf/test/unit_test.hpp"

#include <vector>
#include <sstream>
#include <utility>
#include <algorithm>

#include "caf/all.hpp"
#include "caf/io/all.hpp"

using namespace caf;

namespace {

constexpr char local_host[] = "127.0.0.1";

class config : public actor_system_config {
public:
  config() {
    load<io::middleman>();
    set("middleman.enable-udp", true);
    add_message_type<std::vector<int>>("std::vector<int>");
  }
};

struct fixture {
  // State for the server.
  config server_side_config;
  actor_system server_side;
  io::middleman& server_side_mm;

  // State for the client.
  config client_side_config;
  actor_system client_side;
  io::middleman& client_side_mm;

  fixture()
      : server_side(server_side_config.parse(test::engine::argc(),
                                             test::engine::argv())),
        server_side_mm(server_side.middleman()),
        client_side(client_side_config.parse(test::engine::argc(),
                                             test::engine::argv())),
        client_side_mm(client_side.middleman()) {
    // nop
  }
};

behavior make_pong_behavior() {
  return {
    [](int val) -> int {
      ++val;
      CAF_MESSAGE("pong with " << val);
      return val;
    }
  };
}

behavior make_ping_behavior(event_based_actor* self, const actor& pong) {
  CAF_MESSAGE("ping with " << 0);
  self->send(pong, 0);
  return {
    [=](int val) -> int {
      if (val == 3) {
        CAF_MESSAGE("ping with exit");
        self->send_exit(self->current_sender(),
                        exit_reason::user_shutdown);
        CAF_MESSAGE("ping quits");
        self->quit();
      }
      CAF_MESSAGE("ping with " << val);
      return val;
    }
  };
}

behavior make_sort_behavior() {
  return {
    [](std::vector<int>& vec) -> std::vector<int> {
      CAF_MESSAGE("sorter received: " << deep_to_string(vec));
      std::sort(vec.begin(), vec.end());
      CAF_MESSAGE("sorter sent: " << deep_to_string(vec));
      return std::move(vec);
    }
  };
}

behavior make_sort_requester_behavior(event_based_actor* self,
                                      const actor& sorter) {
  self->send(sorter, std::vector<int>{5, 4, 3, 2, 1});
  return {
    [=](const std::vector<int>& vec) {
      CAF_MESSAGE("sort requester received: " << deep_to_string(vec));
      std::vector<int> expected_vec{1, 2, 3, 4, 5};
      CAF_CHECK_EQUAL(vec, expected_vec);
      self->send_exit(sorter, exit_reason::user_shutdown);
      self->quit();
    }
  };
}

behavior fragile_mirror(event_based_actor* self) {
  return {
    [=](int i) {
      self->quit(exit_reason::user_shutdown);
      return i;
    }
  };
}

behavior linking_actor(event_based_actor* self, const actor& buddy) {
  CAF_MESSAGE("link to mirror and send dummy message");
  self->link_to(buddy);
  self->send(buddy, 42);
  return {
    [](int i) {
      CAF_CHECK_EQUAL(i, 42);
    }
  };
}

} // namespace <anonymous>

CAF_TEST_FIXTURE_SCOPE(dynamic_remote_actor_tests_udp, fixture)

CAF_TEST(identity_semantics_udp) {
  // server side
  auto server = server_side.spawn(make_pong_behavior);
  CAF_EXP_THROW(port1, server_side_mm.publish_udp(server, 0, local_host));
  CAF_EXP_THROW(port2, server_side_mm.publish_udp(server, 0, local_host));
  CAF_REQUIRE_NOT_EQUAL(port1, port2);
  CAF_EXP_THROW(same_server, server_side_mm.remote_actor_udp(local_host, port2));
  CAF_REQUIRE_EQUAL(same_server, server);
  CAF_CHECK_EQUAL(same_server->node(), server_side.node());
  CAF_EXP_THROW(server1, client_side_mm.remote_actor_udp(local_host, port1));
  CAF_EXP_THROW(server2, client_side_mm.remote_actor_udp(local_host, port2));
  CAF_CHECK_EQUAL(server1, client_side_mm.remote_actor_udp(local_host, port1));
  CAF_CHECK_EQUAL(server2, client_side_mm.remote_actor_udp(local_host, port2));
  anon_send_exit(server, exit_reason::user_shutdown);
}

CAF_TEST(ping_pong_udp) {
  // server side
  CAF_EXP_THROW(port,
                server_side_mm.publish_udp(server_side.spawn(make_pong_behavior),
                                           0, local_host));
  // client side
  CAF_EXP_THROW(pong, client_side_mm.remote_actor_udp(local_host, port));
  client_side.spawn(make_ping_behavior, pong);
}

CAF_TEST(custom_message_type_udp) {
  // server side
  CAF_EXP_THROW(port,
                server_side_mm.publish_udp(server_side.spawn(make_sort_behavior),
                                           0, local_host));
  // client side
  CAF_EXP_THROW(sorter, client_side_mm.remote_actor_udp(local_host, port));
  client_side.spawn(make_sort_requester_behavior, sorter);
}

CAF_TEST(remote_link_udp) {
  // server side
  CAF_EXP_THROW(port,
                server_side_mm.publish_udp(server_side.spawn(fragile_mirror),
                                           0, local_host));
  // client side
  CAF_EXP_THROW(mirror, client_side_mm.remote_actor_udp(local_host, port));
  auto linker = client_side.spawn(linking_actor, mirror);
  scoped_actor self{client_side};
  self->wait_for(linker);
  CAF_MESSAGE("linker exited");
  self->wait_for(mirror);
  CAF_MESSAGE("mirror exited");
}

CAF_TEST(multiple_endpoints_udp) {
  config cfg;
  // setup server
  CAF_MESSAGE("creating server");
  actor_system server_sys{cfg};
  auto mirror = server_sys.spawn([]() -> behavior {
    return {
      [] (std::string str) {
        std::reverse(begin(str), end(str));
        return str;
      }
    };
  });
  server_sys.middleman().publish_udp(mirror, 12345);
  auto client_fun = [](event_based_actor* self) -> behavior {
    return {
      [=](actor s) {
        self->send(s, "hellow, world");
      },
      [=](const std::string& str) {
        CAF_CHECK_EQUAL(str, "dlrow ,wolleh");
        self->quit();
        CAF_MESSAGE("done");
      }
    };
  };
  // setup client a
  CAF_MESSAGE("creating first client");
  config client_cfg;
  actor_system client_sys{client_cfg};
  auto client = client_sys.spawn(client_fun);
  // acquire remote actor from the server
  auto client_srv = client_sys.middleman().remote_actor_udp("localhost", 12345);
  CAF_REQUIRE(client_srv);
  // setup other clients
  for (int i = 0; i < 5; ++i) {
    config other_cfg;
    actor_system other_sys{other_cfg};
    CAF_MESSAGE("creating new client");
    auto other = other_sys.spawn(client_fun);
    // acquire remote actor from the server
    auto other_srv = other_sys.middleman().remote_actor_udp("localhost", 12345);
    CAF_REQUIRE(other_srv);
    // establish communication and exit
    CAF_MESSAGE("client contacts server and exits");
    anon_send(other, *other_srv);
    other_sys.await_all_actors_done();
  }
  // establish communication and exit
  CAF_MESSAGE("first client contacts server and exits");
  anon_send(client, *client_srv);
  client_sys.await_all_actors_done();
  anon_send_exit(mirror, exit_reason::user_shutdown);
}

CAF_TEST_FIXTURE_SCOPE_END()
<commit_msg>Use dynamic port in UDP test case<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/config.hpp"

#define CAF_SUITE io_dynamic_remote_actor_udp
#include "caf/test/unit_test.hpp"

#include <vector>
#include <sstream>
#include <utility>
#include <algorithm>

#include "caf/all.hpp"
#include "caf/io/all.hpp"

using namespace caf;

namespace {

constexpr char local_host[] = "127.0.0.1";

class config : public actor_system_config {
public:
  config() {
    load<io::middleman>();
    set("middleman.enable-udp", true);
    add_message_type<std::vector<int>>("std::vector<int>");
  }
};

struct fixture {
  // State for the server.
  config server_side_config;
  actor_system server_side;
  io::middleman& server_side_mm;

  // State for the client.
  config client_side_config;
  actor_system client_side;
  io::middleman& client_side_mm;

  fixture()
      : server_side(server_side_config.parse(test::engine::argc(),
                                             test::engine::argv())),
        server_side_mm(server_side.middleman()),
        client_side(client_side_config.parse(test::engine::argc(),
                                             test::engine::argv())),
        client_side_mm(client_side.middleman()) {
    // nop
  }
};

behavior make_pong_behavior() {
  return {
    [](int val) -> int {
      ++val;
      CAF_MESSAGE("pong with " << val);
      return val;
    }
  };
}

behavior make_ping_behavior(event_based_actor* self, const actor& pong) {
  CAF_MESSAGE("ping with " << 0);
  self->send(pong, 0);
  return {
    [=](int val) -> int {
      if (val == 3) {
        CAF_MESSAGE("ping with exit");
        self->send_exit(self->current_sender(),
                        exit_reason::user_shutdown);
        CAF_MESSAGE("ping quits");
        self->quit();
      }
      CAF_MESSAGE("ping with " << val);
      return val;
    }
  };
}

behavior make_sort_behavior() {
  return {
    [](std::vector<int>& vec) -> std::vector<int> {
      CAF_MESSAGE("sorter received: " << deep_to_string(vec));
      std::sort(vec.begin(), vec.end());
      CAF_MESSAGE("sorter sent: " << deep_to_string(vec));
      return std::move(vec);
    }
  };
}

behavior make_sort_requester_behavior(event_based_actor* self,
                                      const actor& sorter) {
  self->send(sorter, std::vector<int>{5, 4, 3, 2, 1});
  return {
    [=](const std::vector<int>& vec) {
      CAF_MESSAGE("sort requester received: " << deep_to_string(vec));
      std::vector<int> expected_vec{1, 2, 3, 4, 5};
      CAF_CHECK_EQUAL(vec, expected_vec);
      self->send_exit(sorter, exit_reason::user_shutdown);
      self->quit();
    }
  };
}

behavior fragile_mirror(event_based_actor* self) {
  return {
    [=](int i) {
      self->quit(exit_reason::user_shutdown);
      return i;
    }
  };
}

behavior linking_actor(event_based_actor* self, const actor& buddy) {
  CAF_MESSAGE("link to mirror and send dummy message");
  self->link_to(buddy);
  self->send(buddy, 42);
  return {
    [](int i) {
      CAF_CHECK_EQUAL(i, 42);
    }
  };
}

} // namespace <anonymous>

CAF_TEST_FIXTURE_SCOPE(dynamic_remote_actor_tests_udp, fixture)

CAF_TEST(identity_semantics_udp) {
  // server side
  auto server = server_side.spawn(make_pong_behavior);
  CAF_EXP_THROW(port1, server_side_mm.publish_udp(server, 0, local_host));
  CAF_EXP_THROW(port2, server_side_mm.publish_udp(server, 0, local_host));
  CAF_REQUIRE_NOT_EQUAL(port1, port2);
  CAF_EXP_THROW(same_server, server_side_mm.remote_actor_udp(local_host, port2));
  CAF_REQUIRE_EQUAL(same_server, server);
  CAF_CHECK_EQUAL(same_server->node(), server_side.node());
  CAF_EXP_THROW(server1, client_side_mm.remote_actor_udp(local_host, port1));
  CAF_EXP_THROW(server2, client_side_mm.remote_actor_udp(local_host, port2));
  CAF_CHECK_EQUAL(server1, client_side_mm.remote_actor_udp(local_host, port1));
  CAF_CHECK_EQUAL(server2, client_side_mm.remote_actor_udp(local_host, port2));
  anon_send_exit(server, exit_reason::user_shutdown);
}

CAF_TEST(ping_pong_udp) {
  // server side
  CAF_EXP_THROW(port,
                server_side_mm.publish_udp(server_side.spawn(make_pong_behavior),
                                           0, local_host));
  // client side
  CAF_EXP_THROW(pong, client_side_mm.remote_actor_udp(local_host, port));
  client_side.spawn(make_ping_behavior, pong);
}

CAF_TEST(custom_message_type_udp) {
  // server side
  CAF_EXP_THROW(port,
                server_side_mm.publish_udp(server_side.spawn(make_sort_behavior),
                                           0, local_host));
  // client side
  CAF_EXP_THROW(sorter, client_side_mm.remote_actor_udp(local_host, port));
  client_side.spawn(make_sort_requester_behavior, sorter);
}

CAF_TEST(remote_link_udp) {
  // server side
  CAF_EXP_THROW(port,
                server_side_mm.publish_udp(server_side.spawn(fragile_mirror),
                                           0, local_host));
  // client side
  CAF_EXP_THROW(mirror, client_side_mm.remote_actor_udp(local_host, port));
  auto linker = client_side.spawn(linking_actor, mirror);
  scoped_actor self{client_side};
  self->wait_for(linker);
  CAF_MESSAGE("linker exited");
  self->wait_for(mirror);
  CAF_MESSAGE("mirror exited");
}

CAF_TEST(multiple_endpoints_udp) {
  config cfg;
  // Setup server.
  CAF_MESSAGE("creating server");
  actor_system server_sys{cfg};
  auto mirror = server_sys.spawn([]() -> behavior {
    return {
      [] (std::string str) {
        std::reverse(begin(str), end(str));
        return str;
      }
    };
  });
  auto port = server_sys.middleman().publish_udp(mirror, 0);
  CAF_REQUIRE(port);
  CAF_MESSAGE("server running on port " << port);
  auto client_fun = [](event_based_actor* self) -> behavior {
    return {
      [=](actor s) {
        self->send(s, "hellow, world");
      },
      [=](const std::string& str) {
        CAF_CHECK_EQUAL(str, "dlrow ,wolleh");
        self->quit();
        CAF_MESSAGE("done");
      }
    };
  };
  // Setup a client.
  CAF_MESSAGE("creating first client");
  config client_cfg;
  actor_system client_sys{client_cfg};
  auto client = client_sys.spawn(client_fun);
  // Acquire remote actor from the server.
  auto client_srv = client_sys.middleman().remote_actor_udp("localhost", *port);
  CAF_REQUIRE(client_srv);
  // Setup other clients.
  for (int i = 0; i < 5; ++i) {
    config other_cfg;
    actor_system other_sys{other_cfg};
    CAF_MESSAGE("creating new client");
    auto other = other_sys.spawn(client_fun);
    // Acquire remote actor from the new server.
    auto other_srv = other_sys.middleman().remote_actor_udp("localhost", *port);
    CAF_REQUIRE(other_srv);
    // Establish communication and exit.
    CAF_MESSAGE("client contacts server and exits");
    anon_send(other, *other_srv);
    other_sys.await_all_actors_done();
  }
  // Start communicate from the first actor.
  CAF_MESSAGE("first client contacts server and exits");
  anon_send(client, *client_srv);
  client_sys.await_all_actors_done();
  anon_send_exit(mirror, exit_reason::user_shutdown);
}

CAF_TEST_FIXTURE_SCOPE_END()
<|endoftext|>


<commit_before>#include "relative_weight_factor.hpp"
#include <iostream>
#include <stdio.h>
#include <vector>

/* Debug MACRO */
//#define MAIN_DEBUG
#ifdef MAIN_DEBUG
#define D(call) (call)
#else
#define D(call)
#endif

template <class T>
relative_weight_factor::rwf<T>::rwf (std::vector<T> vec, int head, int tail)
: _factors (vec), _steps (head - tail) {
    T sum_of_elements = 0;
    sum_of_elements   = _sum (_factors);
    D(std::cout << std::endl << "Total: " << sum_of_elements << std::endl);
}

template <class T> relative_weight_factor::rwf<T>::~rwf () {
}

template <class T>
std::vector<T> relative_weight_factor::rwf<T>::get_relative_weight_factor () {
    std::vector<T> vec;
    T sum          = _sum (_factors);
    T sum_inv      = _sum_inv (_factors);
    T step_per_fac = _steps / sum_inv;
    D (std::cout << "Sum: " << sum << "Sum inv: " << sum_inv
                 << "Steps/fac: " << step_per_fac << std::endl);
    for (auto i : _factors) {
        vec.push_back (
        (sum - i) * (step_per_fac)); // Add: (sum-val)*(step per factor)
        D (std::cout << "Fac: " << i << " InvFac: " << sum - i << std::endl);
    }
    return vec;
}

template <class T> T relative_weight_factor::rwf<T>::_sum (std::vector<T> vec) {
    T sum = 0;
    for (auto i : vec) {
        sum += i;
    }
    D (std::cout << "Sum: " << sum << std::endl);
    return sum;
}

template <class T>
T relative_weight_factor::rwf<T>::_sum_inv (std::vector<T> vec) {
    T sum     = _sum (vec);
    T sum_inv = 0;
    for (auto i : vec) {
        sum_inv += sum - i;
    }
    D (std::cout << "Sum inv: " << sum_inv << std::endl);
    return sum_inv;
}

template <class T>
void relative_weight_factor::rwf<T>::set_head_tail (int head, int tail) {
    _steps = head - tail;
}

template <class T>
void relative_weight_factor::rwf<T>::set_factors (std::vector<T> vec) {
    _factors = vec;
}
<commit_msg>remove useless debugging text in RWF lib<commit_after>#include "relative_weight_factor.hpp"
#include <iostream>
#include <stdio.h>
#include <vector>

/* Debug MACRO */
//#define MAIN_DEBUG
#ifdef MAIN_DEBUG
#define D(call) (call)
#else
#define D(call)
#endif

template <class T>
relative_weight_factor::rwf<T>::rwf (std::vector<T> vec, int head, int tail)
: _factors (vec), _steps (head - tail) {
}

template <class T> relative_weight_factor::rwf<T>::~rwf () {
}

template <class T>
std::vector<T> relative_weight_factor::rwf<T>::get_relative_weight_factor () {
    std::vector<T> vec;
    T sum          = _sum (_factors);
    T sum_inv      = _sum_inv (_factors);
    T step_per_fac = _steps / sum_inv;
    D (std::cout << "Sum: " << sum << "Sum inv: " << sum_inv
                 << "Steps/fac: " << step_per_fac << std::endl);
    for (auto i : _factors) {
        vec.push_back (
        (sum - i) * (step_per_fac)); // Add: (sum-val)*(step per factor)
        D (std::cout << "Fac: " << i << " InvFac: " << sum - i << std::endl);
    }
    return vec;
}

template <class T> T relative_weight_factor::rwf<T>::_sum (std::vector<T> vec) {
    T sum = 0;
    for (auto i : vec) {
        sum += i;
    }
    D (std::cout << "Sum: " << sum << std::endl);
    return sum;
}

template <class T>
T relative_weight_factor::rwf<T>::_sum_inv (std::vector<T> vec) {
    T sum     = _sum (vec);
    T sum_inv = 0;
    for (auto i : vec) {
        sum_inv += sum - i;
    }
    D (std::cout << "Sum inv: " << sum_inv << std::endl);
    return sum_inv;
}

template <class T>
void relative_weight_factor::rwf<T>::set_head_tail (int head, int tail) {
    _steps = head - tail;
}

template <class T>
void relative_weight_factor::rwf<T>::set_factors (std::vector<T> vec) {
    _factors = vec;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015, Nils Moehrle
 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
 */

#include <util/timer.h>
#include <util/tokenizer.h>
#include <mve/image_io.h>
#include <mve/image_tools.h>
#include <mve/bundle_io.h>
#include <mve/scene.h>

#include "progress_counter.h"
#include "texturing.h"

TEX_NAMESPACE_BEGIN

void
from_mve_scene(std::string const & scene_dir, std::string const & image_name,
    std::vector<TextureView> * texture_views) {

    mve::Scene::Ptr scene;
    try {
        scene = mve::Scene::create(scene_dir);
    } catch (std::exception& e) {
        std::cerr << "Could not open scene: " << e.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }
    std::size_t num_views = scene->get_views().size();
    texture_views->reserve(num_views);

    ProgressCounter view_counter("\tLoading", num_views);
    for (std::size_t i = 0; i < num_views; ++i) {
        view_counter.progress<SIMPLE>();

        mve::View::Ptr view = scene->get_view_by_id(i);
        if (view == NULL) {
            view_counter.inc();
            continue;
        }

        if (!view->has_image(image_name, mve::IMAGE_TYPE_UINT8)) {
            std::cout << "Warning: View " << view->get_name() << " has no byte image "
                << image_name << std::endl;
            continue;
        }

        mve::View::ImageProxy const * image_proxy = view->get_image_proxy(image_name);

        if (image_proxy->channels < 3) {
            std::cerr << "Image " << image_name << " of view " <<
                view->get_name() << " is not a color image!" << std::endl;
            exit(EXIT_FAILURE);
        }

        texture_views->push_back(
            TextureView(view->get_id(), view->get_camera(), util::fs::abspath(
            util::fs::join_path(view->get_directory(), image_proxy->filename))));
        view_counter.inc();
    }
}

void
from_images_and_camera_files(std::string const & path, std::vector<TextureView> * texture_views) {
    util::fs::Directory dir(path);
    std::sort(dir.begin(), dir.end());
    std::vector<std::string> files;
    for (std::size_t i = 0; i < dir.size(); ++i) {
        util::fs::File const & cam_file = dir[i];
        if (cam_file.is_dir) continue;

        std::string cam_file_ext = util::string::uppercase(util::string::right(cam_file.name, 4));
        if (cam_file_ext != ".CAM") continue;

        std::string prefix = util::string::left(cam_file.name, cam_file.name.size() - 4);
        if (prefix.empty()) continue;

        /* Find corresponding image file. */
        int step = 1;
        for (std::size_t j = i + 1; j < dir.size(); j += step) {
            util::fs::File const & img_file = dir[j];

            /* Since the files are sorted we can break - no more files with the same prefix exist. */
            if (util::string::left(img_file.name, prefix.size()) != prefix) {
                if (step == 1) {
                    j = i;
                    step = -1;
                    continue;
                } else {
                    break;
                }
            }

            /* Image file (based on extension)? */
            std::string img_file_ext = util::string::uppercase(util::string::right(img_file.name, 4));
            if (img_file_ext != ".PNG" && img_file_ext != ".JPG" &&
                img_file_ext != "TIFF" && img_file_ext != "JPEG") continue;

            files.push_back(cam_file.get_absolute_name());
            files.push_back(img_file.get_absolute_name());
            break;
        }
    }

    ProgressCounter view_counter("\tLoading", files.size() / 2);
    #pragma omp parallel for
    for (std::size_t i = 0; i < files.size(); i += 2) {
        view_counter.progress<SIMPLE>();
        std::string cam_file = files[i];
        std::string img_file = files[i + 1];

        /* Read CAM file. */
        std::ifstream infile(cam_file.c_str(), std::ios::binary);
        if (!infile.good())
            throw util::FileException(util::fs::basename(cam_file), std::strerror(errno));
        std::string cam_int_str, cam_ext_str;
        std::getline(infile, cam_ext_str);
        std::getline(infile, cam_int_str);
        util::Tokenizer tok_ext, tok_int;
        tok_ext.split(cam_ext_str);
        tok_int.split(cam_int_str);
        #pragma omp critical
        if (tok_ext.size() != 12 || tok_int.size() < 1) {
            std::cerr << "Invalid CAM file: " << util::fs::basename(cam_file) << std::endl;
            std::exit(EXIT_FAILURE);
        }

        /* Create cam_info and eventually undistort image. */
        mve::CameraInfo cam_info;
        cam_info.set_translation_from_string(tok_ext.concat(0, 3));
        cam_info.set_rotation_from_string(tok_ext.concat(3, 0));

        std::stringstream ss(cam_int_str);
        ss >> cam_info.flen;
        if (ss.peek() && !ss.eof())
            ss >> cam_info.dist[0];
        if (ss.peek() && !ss.eof())
            ss >> cam_info.dist[1];
        if (ss.peek() && !ss.eof())
            ss >> cam_info.paspect;
        if (ss.peek() && !ss.eof())
            ss >> cam_info.ppoint[0];
        if (ss.peek() && !ss.eof())
            ss >> cam_info.ppoint[1];

        std::string image_file = util::fs::abspath(util::fs::join_path(path, img_file));
        if (cam_info.dist[0] != 0.0f) {
            mve::ByteImage::Ptr image = mve::image::load_file(img_file);
            if (cam_info.dist[1] != 0.0f) {
                image = mve::image::image_undistort_bundler<uint8_t>(image,
                    cam_info.flen, cam_info.dist[0], cam_info.dist[1]);
            } else {
                image = mve::image::image_undistort_vsfm<uint8_t>(image,
                    cam_info.flen, cam_info.dist[0]);
            }

            image_file = std::string("/tmp/") + util::fs::basename(img_file);
            mve::image::save_png_file(image, image_file);
        }

        #pragma omp critical
        texture_views->push_back(TextureView(i / 2, cam_info, image_file));

        view_counter.inc();
    }
}

void
from_nvm_scene(std::string const & nvm_file, std::vector<TextureView> * texture_views) {
    std::vector<mve::NVMCameraInfo> nvm_cams;
    mve::Bundle::Ptr bundle = mve::load_nvm_bundle(nvm_file, &nvm_cams);
    mve::Bundle::Cameras& cameras = bundle->get_cameras();

    ProgressCounter view_counter("\tLoading", cameras.size());
    #pragma omp parallel for
    for (std::size_t i = 0; i < cameras.size(); ++i) {
        view_counter.progress<SIMPLE>();
        mve::CameraInfo& mve_cam = cameras[i];
        mve::NVMCameraInfo const& nvm_cam = nvm_cams[i];

        mve::ByteImage::Ptr image = mve::image::load_file(nvm_cam.filename);

        int const maxdim = std::max(image->width(), image->height());
        mve_cam.flen = mve_cam.flen / static_cast<float>(maxdim);

        image = mve::image::image_undistort_vsfm<uint8_t>
            (image, mve_cam.flen, nvm_cam.radial_distortion);

        std::string image_file = std::string("/tmp/") + util::fs::basename(nvm_cam.filename);
        mve::image::save_png_file(image, image_file);

        #pragma omp critical
        texture_views->push_back(TextureView(i, mve_cam, image_file));

        view_counter.inc();
    }
}

void
generate_texture_views(std::string const & in_scene, std::vector<TextureView> * texture_views) {
    util::Tokenizer tok;
    tok.split(in_scene, ':', true);

    /* Determine input format. */

    /* BUNDLEFILE */
    if (tok.size() == 1 && util::fs::file_exists(tok[0].c_str())) {
        std::string const & file = tok[0];
        std::string extension = util::string::uppercase(util::string::right(file, 3));
        if (extension == "NVM") from_nvm_scene(file, texture_views);
    }

    /* SCENE_FOLDER */
    if (tok.size() == 1 && util::fs::dir_exists(tok[0].c_str())) {
        from_images_and_camera_files(tok[0], texture_views);
    }

    /* MVE_SCENE::EMBEDDING */
    size_t pos = in_scene.rfind("::");
    if (pos != std::string::npos) {
        std::string scene_dir = in_scene.substr(0, pos);
        std::string image_name = in_scene.substr(pos + 2, in_scene.size());
        from_mve_scene(scene_dir, image_name, texture_views);
    }

    std::size_t num_views = texture_views->size();
    if (num_views == 0) {
        std::cerr << "No proper input scene descriptor given." << std::endl
            << "A input descriptor can be:" << std::endl
            << "BUNDLE_FILE - a bundle file (currently onle .nvm files are supported)" << std::endl
            << "SCENE_FOLDER - a folder containing images and .cam files" << std::endl
            << "MVE_SCENE::EMBEDDING - a mve scene and embedding" << std::endl;
        exit(EXIT_FAILURE);
    }
}

TEX_NAMESPACE_END
<commit_msg>Fix import of NVM bundle file or scene folder with .cam files on Windows<commit_after>/*
 * Copyright (C) 2015, Nils Moehrle
 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
 */

#include <util/timer.h>
#include <util/tokenizer.h>
#include <mve/image_io.h>
#include <mve/image_tools.h>
#include <mve/bundle_io.h>
#include <mve/scene.h>

#include "progress_counter.h"
#include "texturing.h"

TEX_NAMESPACE_BEGIN

void
from_mve_scene(std::string const & scene_dir, std::string const & image_name,
    std::vector<TextureView> * texture_views) {

    mve::Scene::Ptr scene;
    try {
        scene = mve::Scene::create(scene_dir);
    } catch (std::exception& e) {
        std::cerr << "Could not open scene: " << e.what() << std::endl;
        std::exit(EXIT_FAILURE);
    }
    std::size_t num_views = scene->get_views().size();
    texture_views->reserve(num_views);

    ProgressCounter view_counter("\tLoading", num_views);
    for (std::size_t i = 0; i < num_views; ++i) {
        view_counter.progress<SIMPLE>();

        mve::View::Ptr view = scene->get_view_by_id(i);
        if (view == NULL) {
            view_counter.inc();
            continue;
        }

        if (!view->has_image(image_name, mve::IMAGE_TYPE_UINT8)) {
            std::cout << "Warning: View " << view->get_name() << " has no byte image "
                << image_name << std::endl;
            continue;
        }

        mve::View::ImageProxy const * image_proxy = view->get_image_proxy(image_name);

        if (image_proxy->channels < 3) {
            std::cerr << "Image " << image_name << " of view " <<
                view->get_name() << " is not a color image!" << std::endl;
            exit(EXIT_FAILURE);
        }

        texture_views->push_back(
            TextureView(view->get_id(), view->get_camera(), util::fs::abspath(
            util::fs::join_path(view->get_directory(), image_proxy->filename))));
        view_counter.inc();
    }
}

void
from_images_and_camera_files(std::string const & path, std::vector<TextureView> * texture_views) {
    util::fs::Directory dir(path);
    std::sort(dir.begin(), dir.end());
    std::vector<std::string> files;
    for (std::size_t i = 0; i < dir.size(); ++i) {
        util::fs::File const & cam_file = dir[i];
        if (cam_file.is_dir) continue;

        std::string cam_file_ext = util::string::uppercase(util::string::right(cam_file.name, 4));
        if (cam_file_ext != ".CAM") continue;

        std::string prefix = util::string::left(cam_file.name, cam_file.name.size() - 4);
        if (prefix.empty()) continue;

        /* Find corresponding image file. */
        int step = 1;
        for (std::size_t j = i + 1; j < dir.size(); j += step) {
            util::fs::File const & img_file = dir[j];

            /* Since the files are sorted we can break - no more files with the same prefix exist. */
            if (util::string::left(img_file.name, prefix.size()) != prefix) {
                if (step == 1) {
                    j = i;
                    step = -1;
                    continue;
                } else {
                    break;
                }
            }

            /* Image file (based on extension)? */
            std::string img_file_ext = util::string::uppercase(util::string::right(img_file.name, 4));
            if (img_file_ext != ".PNG" && img_file_ext != ".JPG" &&
                img_file_ext != "TIFF" && img_file_ext != "JPEG") continue;

            files.push_back(cam_file.get_absolute_name());
            files.push_back(img_file.get_absolute_name());
            break;
        }
    }

    ProgressCounter view_counter("\tLoading", files.size() / 2);
    #pragma omp parallel for
    for (std::size_t i = 0; i < files.size(); i += 2) {
        view_counter.progress<SIMPLE>();
        std::string cam_file = files[i];
        std::string img_file = files[i + 1];

        /* Read CAM file. */
        std::ifstream infile(cam_file.c_str(), std::ios::binary);
        if (!infile.good())
            throw util::FileException(util::fs::basename(cam_file), std::strerror(errno));
        std::string cam_int_str, cam_ext_str;
        std::getline(infile, cam_ext_str);
        std::getline(infile, cam_int_str);
        util::Tokenizer tok_ext, tok_int;
        tok_ext.split(cam_ext_str);
        tok_int.split(cam_int_str);
        #pragma omp critical
        if (tok_ext.size() != 12 || tok_int.size() < 1) {
            std::cerr << "Invalid CAM file: " << util::fs::basename(cam_file) << std::endl;
            std::exit(EXIT_FAILURE);
        }

        /* Create cam_info and eventually undistort image. */
        mve::CameraInfo cam_info;
        cam_info.set_translation_from_string(tok_ext.concat(0, 3));
        cam_info.set_rotation_from_string(tok_ext.concat(3, 0));

        std::stringstream ss(cam_int_str);
        ss >> cam_info.flen;
        if (ss.peek() && !ss.eof())
            ss >> cam_info.dist[0];
        if (ss.peek() && !ss.eof())
            ss >> cam_info.dist[1];
        if (ss.peek() && !ss.eof())
            ss >> cam_info.paspect;
        if (ss.peek() && !ss.eof())
            ss >> cam_info.ppoint[0];
        if (ss.peek() && !ss.eof())
            ss >> cam_info.ppoint[1];

        std::string image_file = util::fs::abspath(util::fs::join_path(path, img_file));
        if (cam_info.dist[0] != 0.0f) {
            mve::ByteImage::Ptr image = mve::image::load_file(img_file);
            if (cam_info.dist[1] != 0.0f) {
                image = mve::image::image_undistort_bundler<uint8_t>(image,
                    cam_info.flen, cam_info.dist[0], cam_info.dist[1]);
            } else {
                image = mve::image::image_undistort_vsfm<uint8_t>(image,
                    cam_info.flen, cam_info.dist[0]);
            }

            image_file = std::string("/tmp/") + util::fs::basename(img_file);
            mve::image::save_png_file(image, image_file);
        }

        #pragma omp critical
        texture_views->push_back(TextureView(i / 2, cam_info, image_file));

        view_counter.inc();
    }
}

void
from_nvm_scene(std::string const & nvm_file, std::vector<TextureView> * texture_views) {
    std::vector<mve::NVMCameraInfo> nvm_cams;
    mve::Bundle::Ptr bundle = mve::load_nvm_bundle(nvm_file, &nvm_cams);
    mve::Bundle::Cameras& cameras = bundle->get_cameras();

    ProgressCounter view_counter("\tLoading", cameras.size());
    #pragma omp parallel for
    for (std::size_t i = 0; i < cameras.size(); ++i) {
        view_counter.progress<SIMPLE>();
        mve::CameraInfo& mve_cam = cameras[i];
        mve::NVMCameraInfo const& nvm_cam = nvm_cams[i];

        mve::ByteImage::Ptr image = mve::image::load_file(nvm_cam.filename);

        int const maxdim = std::max(image->width(), image->height());
        mve_cam.flen = mve_cam.flen / static_cast<float>(maxdim);

        image = mve::image::image_undistort_vsfm<uint8_t>
            (image, mve_cam.flen, nvm_cam.radial_distortion);

        std::string image_file = std::string("/tmp/") + util::fs::basename(nvm_cam.filename);
        mve::image::save_png_file(image, image_file);

        #pragma omp critical
        texture_views->push_back(TextureView(i, mve_cam, image_file));

        view_counter.inc();
    }
}

void
generate_texture_views(std::string const & in_scene, std::vector<TextureView> * texture_views) {
    /* Determine input format. */

    /* BUNDLEFILE */
    if (util::fs::file_exists(in_scene.c_str())) {
        std::string const & file = in_scene;
        std::string extension = util::string::uppercase(util::string::right(file, 3));
        if (extension == "NVM") from_nvm_scene(file, texture_views);
    }

    /* SCENE_FOLDER */
    if (util::fs::dir_exists(in_scene.c_str())) {
        from_images_and_camera_files(in_scene, texture_views);
    }

    /* MVE_SCENE::EMBEDDING */
    size_t pos = in_scene.rfind("::");
    if (pos != std::string::npos) {
        std::string scene_dir = in_scene.substr(0, pos);
        std::string image_name = in_scene.substr(pos + 2, in_scene.size());
        from_mve_scene(scene_dir, image_name, texture_views);
    }

    std::size_t num_views = texture_views->size();
    if (num_views == 0) {
        std::cerr << "No proper input scene descriptor given." << std::endl
            << "A input descriptor can be:" << std::endl
            << "BUNDLE_FILE - a bundle file (currently onle .nvm files are supported)" << std::endl
            << "SCENE_FOLDER - a folder containing images and .cam files" << std::endl
            << "MVE_SCENE::EMBEDDING - a mve scene and embedding" << std::endl;
        exit(EXIT_FAILURE);
    }
}

TEX_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * String, Union Find
 *
 */

// version 1 (reference):
class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        unordered_map<string,string> mapping;
        int n = A.size();
        for (int i = 0; i < n; i++) {
            /*
            Updated on Jun 6th, there is an invalid test case, in the problem description, it says "a list of unique strings", but there are test cases with duplicate strings.
            In this case, the following line is added.
            */
            if (mapping.find(A[i]) != mapping.end()) continue;
            mapping[A[i]] = A[i];
            for (int j = 0; j < i; j++) {
                if (isSimilar(A[i], A[j]) && mapping[A[j]] != A[i]) {
                    string x = getRoot(A[j], mapping);
                    mapping[x] = A[i];
                }
            }
        }

        int result = 0;
        for (auto it = mapping.begin(); it != mapping.end(); it++) {
            if (it->first == it->second) result++;
        }
        return result;
    }

private:
    bool isSimilar(string &a, string &b) {
        int n = a.length(), counter = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] != b[i]) counter++;
        }
        return counter == 2;
    }

    string getRoot(string s, unordered_map<string,string> &mapping) {
        string temp = mapping[s];
        if (temp != s) return getRoot(temp, mapping);
        else return temp;
    }
};

// version 2 (own):
class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        int n = A.size();
        for (int i = 0; i < n; i++) {
            if (father.find(A[i]) != father.end()) continue;
            father[A[i]] = A[i];
            for (int j = 0; j < i; j++) {
                if (isSimilar(A[i], A[j]) && father[A[j]] != A[i]) {
                    string x = find(A[j]);
                    father[x] = A[i];
                }
            }
        }

        int res = 0;
        for (auto it = father.begin(); it != father.end(); it++) {
            if (it->first == it->second) res++;
        }
        return res;
    }

private:
    unordered_map<string,string> father;

    bool isSimilar(string &a, string &b) {
        int n = a.length(), counter = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] != b[i]) counter++;
        }
        return counter == 2;
    }

    string find(string s) {
        if (father[s] == s) return s;
        return father[s] = find(father[s]);
    }
};

// Reference:
// Leetcode discuss: https://leetcode.com/problems/similar-string-groups/discuss/132375/C++-Union-Find-solution
// Leetcode article: https://leetcode.com/articles/similar-string-groups/

<commit_msg>Update 839.cpp<commit_after>/*
 * String, Union Find
 *
 */

// version 1 (reference):
class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        unordered_map<string,string> mapping;
        int n = A.size();
        for (int i = 0; i < n; i++) {
            /*
            Updated on Jun 6th, there is an invalid test case, in the problem description, it says "a list of unique strings", but there are test cases with duplicate strings.
            In this case, the following line is added.
            */
            if (mapping.find(A[i]) != mapping.end()) continue;
            mapping[A[i]] = A[i];
            for (int j = 0; j < i; j++) {
                if (isSimilar(A[i], A[j]) && mapping[A[j]] != A[i]) {
                    string x = getRoot(A[j], mapping);
                    mapping[x] = A[i];
                }
            }
        }

        int result = 0;
        for (auto it = mapping.begin(); it != mapping.end(); it++) {
            if (it->first == it->second) result++;
        }
        return result;
    }

private:
    bool isSimilar(string &a, string &b) {
        int n = a.length(), counter = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] != b[i]) counter++;
        }
        return counter == 2;
    }

    string getRoot(string s, unordered_map<string,string> &mapping) {
        string temp = mapping[s];
        if (temp != s) return getRoot(temp, mapping);
        else return temp;
    }
};

// version 2 (own):
class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        int n = A.size();
        for (int i = 0; i < n; i++) {
            if (father.find(A[i]) != father.end()) continue;
            father[A[i]] = A[i];
            for (int j = 0; j < i; j++) {
                if (isSimilar(A[i], A[j]) && father[A[j]] != A[i]) {
                    string x = find(A[j]);
                    father[x] = A[i];
                }
            }
        }

        int res = 0;
        for (auto it = father.begin(); it != father.end(); it++) {
            if (it->first == it->second) res++;
        }
        return res;
    }

private:
    unordered_map<string,string> father;

    bool isSimilar(string &a, string &b) {
        int n = a.length(), counter = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] != b[i]) counter++;
        }
        return counter == 2;
    }

    string find(string s) {
        if (father[s] == s) return s;
        return father[s] = find(father[s]);
    }
};

// version 3:
class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        for (int i = 0; i < A.size(); i++) {
            father[A[i]] = A[i];
            for (int j = 0; j < i; j++) {
                if (isSimilar(A[i], A[j]) && father[A[j]] != A[i]) {
                    string x = find(A[j]);
                    father[x] = A[i];
                }
            }
        }

        int res = 0;
        for(auto it = father.begin(); it != father.end(); it++) {
            if(it->first == it->second) res++;
        }
        return res;
    }

private:
    unordered_map<string, string> father;

    bool isSimilar(string &a, string &b) {
        int n = a.size(), diff = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] != b[i]) diff++;
        }
        return diff <= 2;
    }

    string find(string s) {
        if(father[s] == s) return s;
        return father[s] = find(father[s]);
    }
};

// Reference:
// Leetcode discuss: https://leetcode.com/problems/similar-string-groups/discuss/132375/C++-Union-Find-solution
// Leetcode article: https://leetcode.com/articles/similar-string-groups/

<|endoftext|>


<commit_before>#include "stdafx.h"

App app;

std::string g_type;

static float CalcRadius(const Mesh* m)
{
	const Block& b = m->GetRawDatas();
	float maxSq = 0;
	for (auto& it : b.vertices) {
		float sq = lengthSq(it.xyz);
		maxSq = std::max(maxSq, sq);
	}
	return sqrt(maxSq);
}

App::App()
{
	meshId = MeshMan::INVALID_MMID;
}

static void DrawSprites()
{
	SpriteCommands cmds;
	SpriteCommand cmd;
	cmd.quad = Vec4(0, 0, 256, 256);
	cmd.tex = texMan.Create("jiji.dds");

	Vec2 mouse = systemMetrics.GetMousePos();
	auto isHit = [&](const Mat& m) {
		Vec3 v = transform(Vec3(mouse.x, mouse.y, 0), inv(m));
		return v.x >= cmd.quad.x && v.y >= cmd.quad.y && v.x < cmd.quad.z && v.y < cmd.quad.w;
	};

	MatrixStack m;
	m.Mul(translate(64, 64, 0));
	for (int x = 0; x < 3; x++) {
		m.Push();
		for (int y = 0; y < 3; y++) {
			m.Push();
			m.Mul(q2m(Quat(Vec3(0, 0, 1), (x + y) * (float)M_PI / 3)));
			m.Mul(scale(0.5));
			m.Mul(translate(-128, -128, 0));
			cmd.matW = m.Get();
			cmd.color = isHit(m.Get()) ? 0xff0000ff : 0xffffffff;
			m.Pop();
			m.Mul(translate(0, 128, 0));
			cmds.push_back(cmd);
		}
		m.Pop();
		m.Mul(translate(128, 0, 0));
	}
	spriteRenderer.Draw(cmds);
}

void App::Draw()
{
	afDepthStencilMode(true);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	waterSurface.Draw();

	afDepthStencilMode(true);
	afBlendMode(BM_NONE);

	matrixMan.Set(MatrixMan::VIEW, devCamera.CalcViewMatrix());

	ivec2 scrSize = systemMetrics.GetScreenSize();

	float dist = devCamera.GetDistance();

	float f = dist * 1000;
	float n = dist / 1000;
	float aspect = (float)scrSize.x / scrSize.y;
	Mat proj = perspective(45, aspect, n, f);
	matrixMan.Set(MatrixMan::PROJ, proj);

	MeshXAnimResult r;
	MeshX* mesh = (MeshX*)meshMan.Get(meshId);
	if (mesh) {
		double now = GetTime();
		mesh->CalcAnimation(0, now, r);
		float wrappedTime = float(now - floor(now));
		auto normToRad = [](float n) { return n * float(M_PI * 2); };
		mesh->Draw(r, translate(0, radius * 1.5f, 0) * q2m(Quat(Vec3(0, 0, 1.0f), normToRad(wrappedTime))));
		mesh->Draw(r, translate(radius * 2.0f, 0, 0) * q2m(Quat(Vec3(0, 1.0f, 0), normToRad(wrappedTime))));
	}
	meshRenderer.Flush();
	DrawSprites();
	fontMan.Render();
}

void App::Init()
{
	ivec2 scrSize = systemMetrics.GetScreenSize();
    glViewport(0, 0, scrSize.x, scrSize.y);

	glClearColor(0.0f, 0.2f, 0.5f, 1.0f);
	afDepthStencilMode(true);

	meshRenderer.Create();
	waterSurface.Init();
	fontMan.Init();
	spriteRenderer.Init();
	luaMan.Create();

	LoadMesh("jiji.x");
}

void App::LoadMesh(const char* fileName)
{
	meshId = meshMan.Create(fileName);
	MeshX* mesh = (MeshX*)meshMan.Get(meshId);
	if (mesh) {
		radius = CalcRadius(mesh);
		float scale = std::max(0.00001f, radius);
		devCamera.SetDistance(scale * 3);
	}
	g_type = "mesh";
}

void App::OnTap(float x, float y)
{
	waterSurface.CreateRipple(Vec2(x, y));
}

void App::Destroy()
{
	luaMan.Destroy();
	spriteRenderer.Destroy();
	texMan.Destroy();
	shaderMan.Destroy();
	waterSurface.Destroy();
	fontMan.Destroy();
	meshRenderer.Destroy();
	meshMan.Destroy();
	meshId = MeshMan::INVALID_MMID;
}

void App::Update()
{
	luaMan.Update();
	waterSurface.Update();
	fps.Update();
	fontMan.DrawString(Vec2(20, 40), 20, SPrintf("FPS: %f", fps.Get()));
}
<commit_msg>snap to screen<commit_after>#include "stdafx.h"

App app;

std::string g_type;

static float CalcRadius(const Mesh* m)
{
	const Block& b = m->GetRawDatas();
	float maxSq = 0;
	for (auto& it : b.vertices) {
		float sq = lengthSq(it.xyz);
		maxSq = std::max(maxSq, sq);
	}
	return sqrt(maxSq);
}

App::App()
{
	meshId = MeshMan::INVALID_MMID;
}

static void DrawSprites()
{
	SpriteCommands cmds;
	SpriteCommand cmd;
	cmd.tex = texMan.Create("jiji.dds");

	const float pitch = 0.25f;
	const float sprW = 64;

	Vec2 mouse = systemMetrics.GetMousePos();
	auto isHit = [&](const Mat& m) {
		Vec3 v = transform(Vec3(mouse.x, mouse.y, 0), inv(m));
		return v.x >= 0 && v.y >= 0 && v.x < sprW && v.y < sprW;
	};
	Vec2 scrSize = systemMetrics.GetScreenSize();
	MatrixStack m;
	float mini = std::min(scrSize.x, scrSize.y);
	m.Mul(translate((scrSize.x - mini) / 2, (scrSize.y - mini) / 2, 0));
	m.Mul(scale(mini));
	for (int x = 0; x < 4; x++) {
		for (int y = 0; y < 4; y++) {
			cmd.quad = Vec4(x * sprW, y * sprW, x * sprW + sprW, y * sprW + sprW);
			m.Push();
			m.Mul(translate(pitch * x, pitch * y, 0));
			m.Mul(scale(0.25f / sprW));
			cmd.matW = m.Get();
			cmd.color = isHit(m.Get()) ? 0xff0000ff : 0xffffffff;
			m.Pop();
			cmds.push_back(cmd);
		}
	}
	spriteRenderer.Draw(cmds);
}

void App::Draw()
{
	afDepthStencilMode(true);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	waterSurface.Draw();

	afDepthStencilMode(true);
	afBlendMode(BM_NONE);

	matrixMan.Set(MatrixMan::VIEW, devCamera.CalcViewMatrix());

	ivec2 scrSize = systemMetrics.GetScreenSize();

	float dist = devCamera.GetDistance();

	float f = dist * 1000;
	float n = dist / 1000;
	float aspect = (float)scrSize.x / scrSize.y;
	Mat proj = perspective(45, aspect, n, f);
	matrixMan.Set(MatrixMan::PROJ, proj);

	MeshXAnimResult r;
	MeshX* mesh = (MeshX*)meshMan.Get(meshId);
	if (mesh) {
		double now = GetTime();
		mesh->CalcAnimation(0, now, r);
		float wrappedTime = float(now - floor(now));
		auto normToRad = [](float n) { return n * float(M_PI * 2); };
		mesh->Draw(r, translate(0, radius * 1.5f, 0) * q2m(Quat(Vec3(0, 0, 1.0f), normToRad(wrappedTime))));
		mesh->Draw(r, translate(radius * 2.0f, 0, 0) * q2m(Quat(Vec3(0, 1.0f, 0), normToRad(wrappedTime))));
	}
	meshRenderer.Flush();
	DrawSprites();
	fontMan.Render();
}

void App::Init()
{
	ivec2 scrSize = systemMetrics.GetScreenSize();
    glViewport(0, 0, scrSize.x, scrSize.y);

	glClearColor(0.0f, 0.2f, 0.5f, 1.0f);
	afDepthStencilMode(true);

	meshRenderer.Create();
	waterSurface.Init();
	fontMan.Init();
	spriteRenderer.Init();
	luaMan.Create();

	LoadMesh("jiji.x");
}

void App::LoadMesh(const char* fileName)
{
	meshId = meshMan.Create(fileName);
	MeshX* mesh = (MeshX*)meshMan.Get(meshId);
	if (mesh) {
		radius = CalcRadius(mesh);
		float scale = std::max(0.00001f, radius);
		devCamera.SetDistance(scale * 3);
	}
	g_type = "mesh";
}

void App::OnTap(float x, float y)
{
	waterSurface.CreateRipple(Vec2(x, y));
}

void App::Destroy()
{
	luaMan.Destroy();
	spriteRenderer.Destroy();
	texMan.Destroy();
	shaderMan.Destroy();
	waterSurface.Destroy();
	fontMan.Destroy();
	meshRenderer.Destroy();
	meshMan.Destroy();
	meshId = MeshMan::INVALID_MMID;
}

void App::Update()
{
	luaMan.Update();
	waterSurface.Update();
	fps.Update();
	fontMan.DrawString(Vec2(20, 40), 20, SPrintf("FPS: %f", fps.Get()));
}
<|endoftext|>