<commit_before>#include <cstddef>
#include <algorithm>
#include <deque>
#include <limits>
#include <utility>
#include <vector>
#include <insertionfinder/algorithm.hpp>
#include <insertionfinder/insertion.hpp>
#include <insertionfinder/termcolor.hpp>
#include <insertionfinder/twist.hpp>
using std::size_t;
using Algorithm = InsertionFinder::Algorithm;
using Insertion = InsertionFinder::Insertion;
using MergedInsertion = InsertionFinder::MergedInsertion;
using Rotation = InsertionFinder::Rotation;
using Solution = InsertionFinder::Solution;

namespace {
    constexpr size_t invalid = std::numeric_limits<size_t>::max() >> 1;

    class MultiInsertion {
    private:
        Algorithm skeleton;
        Algorithm current_skeleton;
        std::vector<std::vector<std::size_t>> insert_places_before;
        std::vector<std::vector<std::size_t>> insert_places_after;
        std::vector<const Algorithm*> insertions;
        std::vector<std::size_t> positions;
    public:
        MultiInsertion(const Algorithm& skeleton);
    public:
        const Algorithm& get_skeleton() const noexcept {
            return this->skeleton;
        }
        const Algorithm& get_current_skeleton() const noexcept {
            return this->current_skeleton;
        }
        std::vector<std::pair<std::size_t, std::vector<std::size_t>>> get_insert_places() const;
        const std::vector<const Algorithm*>& get_insertions() const noexcept {
            return this->insertions;
        }
    public:
        bool try_insert(const Insertion& insertion);
    };
};

MultiInsertion::MultiInsertion(const Algorithm& skeleton):
    skeleton(skeleton), current_skeleton(skeleton),
    insert_places_before(skeleton.length() + 1),
    insert_places_after(skeleton.length() + 1) {
    this->positions.reserve(skeleton.length());
    for (size_t i = 0; i < skeleton.length(); ++i) {
        this->positions.push_back(i);
    }
}

std::vector<std::pair<size_t, std::vector<size_t>>> MultiInsertion::get_insert_places() const {
    std::vector<std::pair<size_t, std::vector<size_t>>> result;
    for (size_t i = 0; i <= this->skeleton.length(); ++i) {
        const auto& before = this->insert_places_before[i];
        const auto& after = this->insert_places_after[i];
        if (!before.empty() || !after.empty()) {
            result.emplace_back(i, std::vector<size_t>(before.crbegin(), before.crend()));
            result.back().second.insert(result.back().second.cend(), after.cbegin(), after.cend());
        }
    }
    return result;
}

bool MultiInsertion::try_insert(const Insertion& insertion) {
    size_t length = this->current_skeleton.length();
    if (insertion.skeleton.length() != length) {
        return false;
    }
    for (size_t i = 0; i < length; ++i) {
        if (this->current_skeleton[i] == insertion.skeleton[i]) {
        } else if (
            this->current_skeleton.swappable(i + 1)
            && this->current_skeleton[i] == insertion.skeleton[i + 1]
            && this->current_skeleton[i + 1] == insertion.skeleton[i]
        ) {
            if (insertion.insert_place == i + 1) {
                if (this->positions[i + 1] - this->positions[i] == 1) {
                    this->skeleton.swap_adjacent(this->positions[i] + 1);
                    this->current_skeleton.swap_adjacent(i + 1);
                } else {
                    return false;
                }
            }
            ++i;
        } else {
            return false;
        }
    }
    if (insertion.insert_place == 0) {
        this->insert_places_before.front().push_back(this->insertions.size());
    } else if (insertion.insert_place == length) {
        this->insert_places_after.back().push_back(this->insertions.size());
    } else if (this->positions[insertion.insert_place] != invalid) {
        this->insert_places_after[this->positions[insertion.insert_place]].push_back(this->insertions.size());
    } else if (this->positions[insertion.insert_place - 1] != invalid) {
        this->insert_places_before[this->positions[insertion.insert_place - 1] + 1].push_back(this->insertions.size());
    } else {
        return false;
    }
    this->insertions.push_back(insertion.insertion);
    auto [
        insertion_result, skeleton_marks, insertion_marks
    ] = this->current_skeleton.insert_return_marks(*insertion.insertion, insertion.insert_place);
    for (size_t i = 1; i < insertion.insert_place; ++i) {
        if (skeleton_marks[i - 1] != 0 && skeleton_marks[i] == 0 && this->positions[i] - this->positions[i - 1] == 1) {
            this->skeleton.swap_adjacent(this->positions[i]);
            this->current_skeleton.swap_adjacent(i);
            std::swap(skeleton_marks[i - 1], skeleton_marks[i]);
            if (skeleton_marks[i - 1] == 1) {
                insertion_result.swap_adjacent(i);
            }
            break;
        }
    }
    for (size_t i = insertion.insert_place + 1; i < length; ++i) {
        if (skeleton_marks[i - 1] == 0 && skeleton_marks[i] != 0 && this->positions[i] - this->positions[i - 1] == 1) {
            this->skeleton.swap_adjacent(this->positions[i]);
            this->current_skeleton.swap_adjacent(i);
            std::swap(skeleton_marks[i - 1], skeleton_marks[i]);
            if (skeleton_marks[i] == 1) {
                insertion_result.swap_adjacent(i);
            }
            break;
        }
    }
    std::vector<std::size_t> new_positions(insertion_result.length(), invalid);
    for (size_t i = 0; i < insertion.insert_place; ++i) {
        if (skeleton_marks[i] == 0) {
            new_positions[i] = this->positions[i];
        }
    }
    for (size_t i = insertion.insert_place; i < length; ++i) {
        if (skeleton_marks[i] == 0) {
            new_positions[insertion_result.length() + i - this->current_skeleton.length()] = this->positions[i];
        }
    }
    this->current_skeleton = std::move(insertion_result);
    this->positions = std::move(new_positions);
    return true;
}

std::vector<std::pair<size_t, std::vector<MergedInsertion::SubInsertion>>> MergedInsertion::get_insertions() const {
    std::vector<std::pair<size_t, std::vector<SubInsertion>>> result;
    result.reserve(this->insert_places.size());
    for (const auto& [insert_place, orders]: this->insert_places) {
        std::vector<SubInsertion> insertions;
        insertions.reserve(orders.size());
        for (size_t order: orders) {
            insertions.push_back(SubInsertion{&this->insertions[order], order});
        }
        result.emplace_back(insert_place, std::move(insertions));
    }
    return result;
}

void MergedInsertion::print(std::ostream& out, std::size_t initial_order, const Solution& solution) const {
    auto [
        result, skeleton_marks, insertion_masks
    ] = this->skeleton.multi_insert_return_marks(this->insertions, this->insert_places);
    bool skeleton_has_space = this->insert_places.front().first > 0;
    this->skeleton.print(out, skeleton_marks, 0, this->insert_places.front().first);
    for (size_t order: this->insert_places.front().second) {
        if (skeleton_has_space) {
            out << ' ';
        }
        skeleton_has_space = true;
        out << termcolor::bold << "[@" << initial_order + order + 1 << ']' << termcolor::reset;
    }
    for (size_t i = 1; i < this->insert_places.size(); ++i) {
        out << ' ';
        this->skeleton.print(out, skeleton_marks, this->insert_places[i - 1].first, this->insert_places[i].first);
        for (size_t order: this->insert_places[i].second) {
            out << termcolor::bold << " [@" << initial_order + order + 1 << ']' << termcolor::reset;
        }
    }
    if (this->insert_places.back().first < this->skeleton.length()) {
        out << ' ';
        this->skeleton.print(out, skeleton_marks, this->insert_places.back().first, this->skeleton.length());
    }
    for (const auto& [_, orders]: this->insert_places) {
        for (size_t order: orders) {
            const Algorithm& insertion = this->insertions[order];
            out << std::endl
                << termcolor::bold << "Insert at @" << initial_order + order + 1 << ": " << termcolor::reset;
            insertion.print(out, insertion_masks[order]);
            size_t length_before = solution.insertions[initial_order + order].skeleton.length();
            size_t length_after = initial_order + order + 1 >= solution.insertions.size()
                ? solution.final_solution.length()
                : solution.insertions[initial_order + order + 1].skeleton.length();
            out << termcolor::dark << termcolor::italic << " (+" << insertion.length()
                << " -" << length_before + insertion.length() - length_after << ')' << termcolor::reset;
        }
    }
}

std::vector<MergedInsertion> Solution::merge_insertions(const Algorithm& skeleton) const {
    std::vector<MultiInsertion> multi_insertion_list;
    multi_insertion_list.emplace_back(skeleton);
    auto multi_insertion = multi_insertion_list.rbegin();
    for (const Insertion& insertion: this->insertions) {
        if (bool success = multi_insertion->try_insert(insertion); !success) {
            multi_insertion_list.emplace_back(multi_insertion->get_current_skeleton());
            multi_insertion = multi_insertion_list.rbegin();
            multi_insertion->try_insert(insertion);
        }
    }
    std::vector<MergedInsertion> merged_insertion_list;
    merged_insertion_list.reserve(multi_insertion_list.size());
    for (const MultiInsertion& multi_insertion: multi_insertion_list) {
        MergedInsertion merged_insertion;
        merged_insertion.skeleton = multi_insertion.get_skeleton();
        merged_insertion.final_solution = multi_insertion.get_current_skeleton();
        merged_insertion.insert_places = multi_insertion.get_insert_places();
        auto insertions = multi_insertion.get_insertions();
        size_t insertion_count = insertions.size();
        merged_insertion.insertions.reserve(insertion_count);
        for (size_t i = insertion_count; i-- > 0;) {
            Algorithm insertion = *insertions[i];
            Rotation rotation = 0;
            for (const auto& [_, orders]: merged_insertion.insert_places) {
                bool found = false;
                for (size_t order: orders) {
                    if (order == i) {
                        found = true;
                        break;
                    } else if (order < i) {
                        rotation *= insertions[order]->cube_rotation();
                    }
                }
                if (found) {
                    break;
                }
            }
            insertion.rotate(rotation);
            insertion.normalize();
            merged_insertion.insertions.emplace_back(std::move(insertion));
        }
        std::reverse(merged_insertion.insertions.begin(), merged_insertion.insertions.end());
        merged_insertion_list.emplace_back(std::move(merged_insertion));
    }
    return merged_insertion_list;
}
<commit_msg>fix bug when insert place is larger than algorithm length after insertion<commit_after>#include <cstddef>
#include <algorithm>
#include <deque>
#include <limits>
#include <utility>
#include <vector>
#include <insertionfinder/algorithm.hpp>
#include <insertionfinder/insertion.hpp>
#include <insertionfinder/termcolor.hpp>
#include <insertionfinder/twist.hpp>
using std::size_t;
using Algorithm = InsertionFinder::Algorithm;
using Insertion = InsertionFinder::Insertion;
using MergedInsertion = InsertionFinder::MergedInsertion;
using Rotation = InsertionFinder::Rotation;
using Solution = InsertionFinder::Solution;

namespace {
    constexpr size_t invalid = std::numeric_limits<size_t>::max() >> 1;

    class MultiInsertion {
    private:
        Algorithm skeleton;
        Algorithm current_skeleton;
        std::vector<std::vector<std::size_t>> insert_places_before;
        std::vector<std::vector<std::size_t>> insert_places_after;
        std::vector<const Algorithm*> insertions;
        std::vector<std::size_t> positions;
    public:
        MultiInsertion(const Algorithm& skeleton);
    public:
        const Algorithm& get_skeleton() const noexcept {
            return this->skeleton;
        }
        const Algorithm& get_current_skeleton() const noexcept {
            return this->current_skeleton;
        }
        std::vector<std::pair<std::size_t, std::vector<std::size_t>>> get_insert_places() const;
        const std::vector<const Algorithm*>& get_insertions() const noexcept {
            return this->insertions;
        }
    public:
        bool try_insert(const Insertion& insertion);
    };
};

MultiInsertion::MultiInsertion(const Algorithm& skeleton):
    skeleton(skeleton), current_skeleton(skeleton),
    insert_places_before(skeleton.length() + 1),
    insert_places_after(skeleton.length() + 1) {
    this->positions.reserve(skeleton.length());
    for (size_t i = 0; i < skeleton.length(); ++i) {
        this->positions.push_back(i);
    }
}

std::vector<std::pair<size_t, std::vector<size_t>>> MultiInsertion::get_insert_places() const {
    std::vector<std::pair<size_t, std::vector<size_t>>> result;
    for (size_t i = 0; i <= this->skeleton.length(); ++i) {
        const auto& before = this->insert_places_before[i];
        const auto& after = this->insert_places_after[i];
        if (!before.empty() || !after.empty()) {
            result.emplace_back(i, std::vector<size_t>(before.crbegin(), before.crend()));
            result.back().second.insert(result.back().second.cend(), after.cbegin(), after.cend());
        }
    }
    return result;
}

bool MultiInsertion::try_insert(const Insertion& insertion) {
    size_t length = this->current_skeleton.length();
    if (insertion.skeleton.length() != length) {
        return false;
    }
    for (size_t i = 0; i < length; ++i) {
        if (this->current_skeleton[i] == insertion.skeleton[i]) {
        } else if (
            this->current_skeleton.swappable(i + 1)
            && this->current_skeleton[i] == insertion.skeleton[i + 1]
            && this->current_skeleton[i + 1] == insertion.skeleton[i]
        ) {
            if (insertion.insert_place == i + 1) {
                if (this->positions[i + 1] - this->positions[i] == 1) {
                    this->skeleton.swap_adjacent(this->positions[i] + 1);
                    this->current_skeleton.swap_adjacent(i + 1);
                } else {
                    return false;
                }
            }
            ++i;
        } else {
            return false;
        }
    }
    if (insertion.insert_place == 0) {
        this->insert_places_before.front().push_back(this->insertions.size());
    } else if (insertion.insert_place == length) {
        this->insert_places_after.back().push_back(this->insertions.size());
    } else if (this->positions[insertion.insert_place] != invalid) {
        this->insert_places_after[this->positions[insertion.insert_place]].push_back(this->insertions.size());
    } else if (this->positions[insertion.insert_place - 1] != invalid) {
        this->insert_places_before[this->positions[insertion.insert_place - 1] + 1].push_back(this->insertions.size());
    } else {
        return false;
    }
    this->insertions.push_back(insertion.insertion);
    auto [
        insertion_result, skeleton_marks, insertion_marks
    ] = this->current_skeleton.insert_return_marks(*insertion.insertion, insertion.insert_place);
    for (size_t i = 1; i < insertion.insert_place; ++i) {
        if (skeleton_marks[i - 1] != 0 && skeleton_marks[i] == 0 && this->positions[i] - this->positions[i - 1] == 1) {
            this->skeleton.swap_adjacent(this->positions[i]);
            this->current_skeleton.swap_adjacent(i);
            std::swap(skeleton_marks[i - 1], skeleton_marks[i]);
            if (skeleton_marks[i - 1] == 1) {
                insertion_result.swap_adjacent(i);
            }
            break;
        }
    }
    for (size_t i = insertion.insert_place + 1; i < length; ++i) {
        if (skeleton_marks[i - 1] == 0 && skeleton_marks[i] != 0 && this->positions[i] - this->positions[i - 1] == 1) {
            this->skeleton.swap_adjacent(this->positions[i]);
            this->current_skeleton.swap_adjacent(i);
            std::swap(skeleton_marks[i - 1], skeleton_marks[i]);
            if (skeleton_marks[i] == 1) {
                insertion_result.swap_adjacent(i);
            }
            break;
        }
    }
    std::vector<std::size_t> new_positions(insertion_result.length(), invalid);
    for (size_t i = 0; i < std::min(insertion.insert_place, insertion_result.length()); ++i) {
        if (skeleton_marks[i] == 0) {
            new_positions[i] = this->positions[i];
        }
    }
    for (size_t i = insertion.insert_place; i < length; ++i) {
        if (skeleton_marks[i] == 0) {
            new_positions[insertion_result.length() + i - length] = this->positions[i];
        }
    }
    this->current_skeleton = std::move(insertion_result);
    this->positions = std::move(new_positions);
    return true;
}

std::vector<std::pair<size_t, std::vector<MergedInsertion::SubInsertion>>> MergedInsertion::get_insertions() const {
    std::vector<std::pair<size_t, std::vector<SubInsertion>>> result;
    result.reserve(this->insert_places.size());
    for (const auto& [insert_place, orders]: this->insert_places) {
        std::vector<SubInsertion> insertions;
        insertions.reserve(orders.size());
        for (size_t order: orders) {
            insertions.push_back(SubInsertion{&this->insertions[order], order});
        }
        result.emplace_back(insert_place, std::move(insertions));
    }
    return result;
}

void MergedInsertion::print(std::ostream& out, std::size_t initial_order, const Solution& solution) const {
    auto [
        result, skeleton_marks, insertion_masks
    ] = this->skeleton.multi_insert_return_marks(this->insertions, this->insert_places);
    bool skeleton_has_space = this->insert_places.front().first > 0;
    this->skeleton.print(out, skeleton_marks, 0, this->insert_places.front().first);
    for (size_t order: this->insert_places.front().second) {
        if (skeleton_has_space) {
            out << ' ';
        }
        skeleton_has_space = true;
        out << termcolor::bold << "[@" << initial_order + order + 1 << ']' << termcolor::reset;
    }
    for (size_t i = 1; i < this->insert_places.size(); ++i) {
        out << ' ';
        this->skeleton.print(out, skeleton_marks, this->insert_places[i - 1].first, this->insert_places[i].first);
        for (size_t order: this->insert_places[i].second) {
            out << termcolor::bold << " [@" << initial_order + order + 1 << ']' << termcolor::reset;
        }
    }
    if (this->insert_places.back().first < this->skeleton.length()) {
        out << ' ';
        this->skeleton.print(out, skeleton_marks, this->insert_places.back().first, this->skeleton.length());
    }
    for (const auto& [_, orders]: this->insert_places) {
        for (size_t order: orders) {
            const Algorithm& insertion = this->insertions[order];
            out << std::endl
                << termcolor::bold << "Insert at @" << initial_order + order + 1 << ": " << termcolor::reset;
            insertion.print(out, insertion_masks[order]);
            size_t length_before = solution.insertions[initial_order + order].skeleton.length();
            size_t length_after = initial_order + order + 1 >= solution.insertions.size()
                ? solution.final_solution.length()
                : solution.insertions[initial_order + order + 1].skeleton.length();
            out << termcolor::dark << termcolor::italic << " (+" << insertion.length()
                << " -" << length_before + insertion.length() - length_after << ')' << termcolor::reset;
        }
    }
}

std::vector<MergedInsertion> Solution::merge_insertions(const Algorithm& skeleton) const {
    std::vector<MultiInsertion> multi_insertion_list;
    multi_insertion_list.emplace_back(skeleton);
    auto multi_insertion = multi_insertion_list.rbegin();
    for (const Insertion& insertion: this->insertions) {
        if (bool success = multi_insertion->try_insert(insertion); !success) {
            multi_insertion_list.emplace_back(multi_insertion->get_current_skeleton());
            multi_insertion = multi_insertion_list.rbegin();
            multi_insertion->try_insert(insertion);
        }
    }
    std::vector<MergedInsertion> merged_insertion_list;
    merged_insertion_list.reserve(multi_insertion_list.size());
    for (const MultiInsertion& multi_insertion: multi_insertion_list) {
        MergedInsertion merged_insertion;
        merged_insertion.skeleton = multi_insertion.get_skeleton();
        merged_insertion.final_solution = multi_insertion.get_current_skeleton();
        merged_insertion.insert_places = multi_insertion.get_insert_places();
        auto insertions = multi_insertion.get_insertions();
        size_t insertion_count = insertions.size();
        merged_insertion.insertions.reserve(insertion_count);
        for (size_t i = insertion_count; i-- > 0;) {
            Algorithm insertion = *insertions[i];
            Rotation rotation = 0;
            for (const auto& [_, orders]: merged_insertion.insert_places) {
                bool found = false;
                for (size_t order: orders) {
                    if (order == i) {
                        found = true;
                        break;
                    } else if (order < i) {
                        rotation *= insertions[order]->cube_rotation();
                    }
                }
                if (found) {
                    break;
                }
            }
            insertion.rotate(rotation);
            insertion.normalize();
            merged_insertion.insertions.emplace_back(std::move(insertion));
        }
        std::reverse(merged_insertion.insertions.begin(), merged_insertion.insertions.end());
        merged_insertion_list.emplace_back(std::move(merged_insertion));
    }
    return merged_insertion_list;
}
<|endoftext|>


<commit_before>#include "SceneManager.h"
#include "Light.h"
#include "proto_camera.h"

#include "Spacejet.h"
#include "Cube.h"
#include "CubeSphere.h"
#include "BARTMesh.h"

#include "../Render/Passes/Final/Final_Pass.h"
#include "../Render/Passes/GBuffer/GBuffer_Pass.h"
#include "../Render/Passes/Bloom/Bloom_Pass.h"
#include "../Render/Passes/Raytrace/Raytrace_Pass.h"
#include "../Render/DebugOutput.h"

#include "../Parser/INIParser.h"

using namespace Scene;

SceneManager::SceneManager(const File::ShaderLoaderPtr &shader_loader, unsigned int width, unsigned int height, const std::string &resource_dir)
	: shader_loader(shader_loader), width(width), height(height), resource_dir(resource_dir)
{
	debug_output = std::make_shared<Render::DebugOutput>();

	//////////////////////////////////////////
	// DEFERRED RENDERER INITIALIZING
	//////////////////////////////////////////
	g_buffer_pass = std::make_shared<Render::GBuffer_Pass>(shader_loader, width, height);
	raytrace_pass = std::make_shared<Render::Raytrace_Pass>(g_buffer_pass, width, height, resource_dir);
	//bloom_pass = std::make_shared<Render::Bloom_Pass>(final_pass, shader_loader, width, height);
	final_pass = std::make_shared<Render::Final_Pass>(g_buffer_pass, raytrace_pass, shader_loader, width, height);
}

SceneManager::~SceneManager()
{
	long final_pass_count = final_pass.use_count();
	final_pass.reset();

	/*long bloom_pass_count = bloom_pass.use_count();
	bloom_pass.reset();*/

	long raytrace_pass_count = raytrace_pass.use_count();
	raytrace_pass.reset();

	long g_buffer_pass_count = g_buffer_pass.use_count();
	g_buffer_pass.reset();
}

void SceneManager::render()
{
	g_buffer_pass->begin();
	{
		glEnable(GL_DEPTH_TEST);
		for(auto it = begin(scene); it!=end(scene); ++it )
			(*it)->render(g_buffer_pass->getShader());
		glDisable(GL_DEPTH_TEST);
	} g_buffer_pass->end();

	raytrace_pass->begin();
	{
		//raytrace_pass->update(g_buffer_pass->getRenderTextures(), scene, lights);
		raytrace_pass->render();
	} raytrace_pass->end();

	/*light_pass->begin();
	{
		light_pass->update(lights, g_buffer_pass->getRenderTextures(), raytrace_pass->getRenderTextures());
		light_pass->render();
	} light_pass->end();*/

	/*bloom_pass->begin();
	{
		bloom_pass->update(light_pass->getFinalColorTexture());
		bloom_pass->render_extraction_step();
		bloom_pass->render_blur_steps();
		bloom_pass->render_final_step();
	} bloom_pass->end();*/

	final_pass->begin();
	{
		//final_pass->update(light_pass->getFinalColorTexture(), bloom_pass->getFilterTexture());
		bindLights(final_pass->getShader());
		final_pass->render();
	} final_pass->end();
}

void SceneManager::bindLights(const Render::ShaderPtr &active_program)
{
	for(auto it = begin(lights); it!=end(lights); ++it )
		(*it)->bind(active_program);
}

void SceneManager::reshape(int width, int height)
{
	g_buffer_pass->reshape(width,height);
	raytrace_pass->reshape(width,height);
	final_pass->reshape(width,height);
}

void SceneManager::add(const SceneNodePtr &node)
{
	scene.push_back(node);
}

void SceneManager::addList(const std::vector<SceneNodePtr> &nodeList)
{
	scene.insert( scene.end(), nodeList.begin(), nodeList.end() );
}

void SceneManager::add(const LightPtr &light)
{
	lights.push_back(light);
}

void SceneManager::initScene(	const File::AssetManagerPtr &asset_manager,
								const File::MaterialLoaderPtr &mat_loader,
								const File::MeshLoaderPtr &mesh_loader,
								const File::BARTLoader2Ptr &bart_loader)
{
	auto camera = Scene::FirstPersonCamera::getSingleton();
	camera->updateProjection(width, height, 40.0f, 0.1f, 1000.0f);
    //camera->init(width, height, 60.0f, 1.0f, 1000.0f);
	//camera->setTarget(glm::vec3(10,-8,20));

	Scene::LightPtr light = std::make_shared<Scene::Light>(0);
	light->setPosition(glm::vec3(0,0,0));

	auto spacejet_tex = asset_manager->getTex2DRelativePath("FEROX_DI.tga", false);
	auto spacejet_normal_tex = asset_manager->getTex2DRelativePath("FEROX_BU.tga", false);

	auto array_tex = asset_manager->getTex2DRelativePath("cube.jpg", false);
	auto array2_tex = asset_manager->getTex2DRelativePath("array.png", false);

	Render::UniformPtr tex_sampler = std::make_shared<Render::Uniform>(g_buffer_pass->getShader()->getFS(), "diffuse_tex");
	Render::UniformPtr norm_sampler = std::make_shared<Render::Uniform>(g_buffer_pass->getShader()->getFS(), "normal_tex");

	Render::SamplerPtr array_sampler;// = std::make_shared<Render::Sampler>();

    //final_pass->setRayTexture(raytracer->getRenderTexture(), tex_sampler);

	auto basic_cube_mat = final_pass->addMaterial(mat_loader->load("basic_cube.mat"));
	auto red_cube_mat = final_pass->addMaterial(mat_loader->load("red_cube.mat"));
	auto blue_cube_mat = final_pass->addMaterial(mat_loader->load("blue_cube.mat"));

	auto spacejet = mesh_loader->load<Scene::Spacejet>("Ferox.3DS");
	{
		spacejet->init(shader_loader);
		spacejet->setTexture(0,spacejet_tex, "diffuse_tex");
		spacejet->setTexture(1,spacejet_normal_tex, "normal_tex");
		spacejet->setMaterial(red_cube_mat);
		spacejet->setPosition(glm::vec3(0, 0, 20));
		spacejet->setScale(glm::vec3(0.01f,0.01f,0.01f));
		add(spacejet);
	}

	Scene::CubePtr cube = std::make_shared<Scene::Cube>(1.0f);
	{
		cube->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		cube->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		cube->setViewToClipUniform(		g_buffer_pass->getViewToClipUniform());
		cube->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		cube->setTexture(0, array_tex, tex_sampler, array_sampler);
		cube->setMaterial(basic_cube_mat);
		add(cube);
		cube->setPosition( glm::vec3(5,5,-20) );
	}

	Scene::CubePtr cube2 = std::make_shared<Scene::Cube>(.5f);
	{
		cube2->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		cube2->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		cube2->setViewToClipUniform(	g_buffer_pass->getViewToClipUniform());
		cube2->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		cube2->setTexture(0,array2_tex, tex_sampler, array_sampler);
		cube2->setMaterial(red_cube_mat);
		add(cube2);
		cube2->setPosition( glm::vec3(5,3,-20) );
	}

    const int sideBySide = 25;
    const float fSideBySide = float(sideBySide);
	for ( int i=0; i<sideBySide; i++ ) {
		for ( int j=0; j<sideBySide; j++ ) {
            const float u = -.5f + i/fSideBySide;
            const float v = -.5f + j/fSideBySide;
            float freq = 2.f * 6.28f;
            float distOrigin = sqrt(u*u + v*v);
            const float x = fSideBySide*u;
            const float y = 1.5f * cos(distOrigin * freq) - 10.f;
			const float z = fSideBySide*v;

			Scene::CubePtr cube3 = std::make_shared<Scene::Cube>(0.5f);
			{
				cube3->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
				cube3->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
				cube3->setViewToClipUniform(	g_buffer_pass->getViewToClipUniform());
				cube3->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
				cube3->setTexture(0, array_tex, tex_sampler, array_sampler);
				cube3->setMaterial(blue_cube_mat);
				add(cube3);
				cube3->setPosition( glm::vec3(x,y,z) );
			}
		}
	}

	Scene::CubeSpherePtr sphere = std::make_shared<Scene::CubeSphere>();
	{
		sphere->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		sphere->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		sphere->setViewToClipUniform(	g_buffer_pass->getViewToClipUniform());
		sphere->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		sphere->setTexture(0,array_tex, tex_sampler, array_sampler);
		sphere->setMaterial(blue_cube_mat);
		add(sphere);
		sphere->setPosition( glm::vec3(1,-1,6) );
	}

	ini::Parser config(resource_dir + "ini\\scene.ini");
	auto scene_dir = config.getString("load", "dir", "procedural\\");
	auto scene_file = config.getString("load", "scene", "balls.nff");

	std::vector<Scene::SceneNodePtr> nodes = bart_loader->load(scene_dir, scene_file);
	for(auto it=begin(nodes); it!=end(nodes); ++it)
	{
		Scene::SceneNodePtr &node = *it;
		node->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		node->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		node->setViewToClipUniform(		g_buffer_pass->getViewToClipUniform());
		node->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		//node->setTexture(array_tex, tex_sampler, array_sampler);
	}
	addList( nodes );
}
<commit_msg>Fixed the SceneManager issue in HybridMethods.<commit_after>#include "SceneManager.h"
#include "Light.h"
#include "proto_camera.h"

#include "Spacejet.h"
#include "Cube.h"
#include "CubeSphere.h"
#include "BARTMesh.h"

#include "../Render/Passes/Final/Final_Pass.h"
#include "../Render/Passes/GBuffer/GBuffer_Pass.h"
#include "../Render/Passes/Bloom/Bloom_Pass.h"
#include "../Render/Passes/Raytrace/Raytrace_Pass.h"
#include "../Render/DebugOutput.h"

#include "../Parser/INIParser.h"

using namespace Scene;

SceneManager::SceneManager(const File::ShaderLoaderPtr &shader_loader, unsigned int width, unsigned int height, const std::string &resource_dir)
	: shader_loader(shader_loader), width(width), height(height), resource_dir(resource_dir)
{
	debug_output = std::make_shared<Render::DebugOutput>();

	//////////////////////////////////////////
	// DEFERRED RENDERER INITIALIZING
	//////////////////////////////////////////
	g_buffer_pass = std::make_shared<Render::GBuffer_Pass>(shader_loader, width, height);
	raytrace_pass = std::make_shared<Render::Raytrace_Pass>(g_buffer_pass, width, height, resource_dir);
	//bloom_pass = std::make_shared<Render::Bloom_Pass>(final_pass, shader_loader, width, height);
	final_pass = std::make_shared<Render::Final_Pass>(g_buffer_pass, raytrace_pass, shader_loader, width, height);
}

SceneManager::~SceneManager()
{
	long final_pass_count = final_pass.use_count();
	final_pass.reset();

	/*long bloom_pass_count = bloom_pass.use_count();
	bloom_pass.reset();*/

	long raytrace_pass_count = raytrace_pass.use_count();
	raytrace_pass.reset();

	long g_buffer_pass_count = g_buffer_pass.use_count();
	g_buffer_pass.reset();
}

void SceneManager::render()
{
	g_buffer_pass->begin();
	{
		glEnable(GL_DEPTH_TEST);
		for(auto it = begin(scene); it!=end(scene); ++it )
			(*it)->render(g_buffer_pass->getShader());
		glDisable(GL_DEPTH_TEST);
	} g_buffer_pass->end();

	raytrace_pass->begin();
	{
		//raytrace_pass->update(g_buffer_pass->getRenderTextures(), scene, lights);
		raytrace_pass->render();
	} raytrace_pass->end();

	/*light_pass->begin();
	{
		light_pass->update(lights, g_buffer_pass->getRenderTextures(), raytrace_pass->getRenderTextures());
		light_pass->render();
	} light_pass->end();*/

	/*bloom_pass->begin();
	{
		bloom_pass->update(light_pass->getFinalColorTexture());
		bloom_pass->render_extraction_step();
		bloom_pass->render_blur_steps();
		bloom_pass->render_final_step();
	} bloom_pass->end();*/

	final_pass->begin();
	{
		//final_pass->update(light_pass->getFinalColorTexture(), bloom_pass->getFilterTexture());
		bindLights(final_pass->getShader());
		final_pass->render();
	} final_pass->end();
}

void SceneManager::bindLights(const Render::ShaderPtr &active_program)
{
	for(auto it = begin(lights); it!=end(lights); ++it )
		(*it)->bind(active_program);
}

void SceneManager::reshape(int width, int height)
{
	g_buffer_pass->reshape(width,height);
	raytrace_pass->reshape(width,height);
	final_pass->reshape(width,height);
}

void SceneManager::add(const SceneNodePtr &node)
{
	scene.push_back(node);
}

void SceneManager::addList(const std::vector<SceneNodePtr> &nodeList)
{
	scene.insert( scene.end(), nodeList.begin(), nodeList.end() );
}

void SceneManager::add(const LightPtr &light)
{
	lights.push_back(light);
}

void SceneManager::initScene(	const File::AssetManagerPtr &asset_manager,
								const File::MaterialLoaderPtr &mat_loader,
								const File::MeshLoaderPtr &mesh_loader,
								const File::BARTLoader2Ptr &bart_loader)
{
	auto camera = Scene::FirstPersonCamera::getSingleton();
	camera->updateProjection(width, height, 40.0f, 0.1f, 1000.0f);
    //camera->init(width, height, 60.0f, 1.0f, 1000.0f);
	//camera->setTarget(glm::vec3(10,-8,20));

	Scene::LightPtr light = std::make_shared<Scene::Light>(0);
	light->setPosition(glm::vec3(0,0,0));

	auto spacejet_tex = asset_manager->getTex2DRelativePath("FEROX_DI.tga", false);
	auto spacejet_normal_tex = asset_manager->getTex2DRelativePath("FEROX_BU.tga", false);

	auto array_tex = asset_manager->getTex2DRelativePath("cube.jpg", false);
	auto array2_tex = asset_manager->getTex2DRelativePath("array.png", false);

	Render::UniformPtr tex_sampler = std::make_shared<Render::Uniform>(g_buffer_pass->getShader()->getFS(), "diffuse_tex");
	Render::UniformPtr norm_sampler = std::make_shared<Render::Uniform>(g_buffer_pass->getShader()->getFS(), "normal_tex");

	Render::SamplerPtr array_sampler;// = std::make_shared<Render::Sampler>();

    //final_pass->setRayTexture(raytracer->getRenderTexture(), tex_sampler);

	auto basic_cube_mat = final_pass->addMaterial(mat_loader->load("basic_cube.mat"));
	auto red_cube_mat = final_pass->addMaterial(mat_loader->load("red_cube.mat"));
	auto blue_cube_mat = final_pass->addMaterial(mat_loader->load("blue_cube.mat"));

	auto spacejet = mesh_loader->load<Scene::Spacejet>("Ferox.3DS");
	{
		spacejet->init(shader_loader);
		spacejet->setTexture(0,spacejet_tex, "diffuse_tex");
		spacejet->setTexture(1,spacejet_normal_tex, "normal_tex");
		spacejet->setMaterial(red_cube_mat);
		spacejet->setPosition(glm::vec3(0, 0, 20));
		spacejet->setScale(glm::vec3(0.01f,0.01f,0.01f));
		add(spacejet);
	}

	Scene::CubePtr cube = std::make_shared<Scene::Cube>(1.0f);
	{
		cube->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		cube->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		cube->setViewToClipUniform(		g_buffer_pass->getViewToClipUniform());
		cube->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		cube->setTexture(0, array_tex, tex_sampler, array_sampler);
		cube->setMaterial(basic_cube_mat);
		add(cube);
		cube->setPosition( glm::vec3(5,5,-20) );
	}

	Scene::CubePtr cube2 = std::make_shared<Scene::Cube>(.5f);
	{
		cube2->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		cube2->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		cube2->setViewToClipUniform(	g_buffer_pass->getViewToClipUniform());
		cube2->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		cube2->setTexture(0,array2_tex, tex_sampler, array_sampler);
		cube2->setMaterial(red_cube_mat);
		add(cube2);
		cube2->setPosition( glm::vec3(5,3,-20) );
	}

    const int sideBySide = 25;
    const float fSideBySide = float(sideBySide);
	for ( int i=0; i<sideBySide; i++ ) {
		for ( int j=0; j<sideBySide; j++ ) {
            const float u = -.5f + i/fSideBySide;
            const float v = -.5f + j/fSideBySide;
            float freq = 2.f * 6.28f;
            float distOrigin = sqrt(u*u + v*v);
            const float x = fSideBySide*u;
            const float y = 1.5f * cos(distOrigin * freq) - 10.f;
			const float z = fSideBySide*v;

			Scene::CubePtr cube3 = std::make_shared<Scene::Cube>(0.5f);
			{
				cube3->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
				cube3->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
				cube3->setViewToClipUniform(	g_buffer_pass->getViewToClipUniform());
				cube3->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
				cube3->setTexture(0, array_tex, tex_sampler, array_sampler);
				cube3->setMaterial(blue_cube_mat);
				add(cube3);
				cube3->setPosition( glm::vec3(x,y,z) );
			}
		}
	}

	Scene::CubeSpherePtr sphere = std::make_shared<Scene::CubeSphere>();
	{
		sphere->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		sphere->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		sphere->setViewToClipUniform(	g_buffer_pass->getViewToClipUniform());
		sphere->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		sphere->setTexture(0,array_tex, tex_sampler, array_sampler);
		sphere->setMaterial(blue_cube_mat);
		add(sphere);
		sphere->setPosition( glm::vec3(1,-1,6) );
	}

	ini::Parser config(resource_dir + "ini\\scene.ini");
	auto scene_dir = config.getString("load", "dir", "procedural\\");
	auto scene_file = config.getString("load", "scene", "balls.nff");

	auto nodes = bart_loader->load(scene_dir, scene_file);
	for(auto it=begin(nodes); it!=end(nodes); ++it)
	{
		auto &node = *it;
		node->setObjectToWorldUniform(	g_buffer_pass->getObjectToWorldUniform());
		node->setWorldToViewUniform(	g_buffer_pass->getWorldToViewUniform());
		node->setViewToClipUniform(		g_buffer_pass->getViewToClipUniform());
		node->setNormalToViewUniform(	g_buffer_pass->getNormalToViewUniform());
		//node->setTexture(array_tex, tex_sampler, array_sampler);
	}
	for(unsigned int i = 0; i < nodes.size(); i++)
		add(nodes[i]);
}
<|endoftext|>


<commit_before>// Sh: A GPU metaprogramming language.
//
// Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
// Project administrator: Michael D. McCool
// Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
//          Michael D. McCool
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//////////////////////////////////////////////////////////////////////////////

#include <sstream>
#include "ShDebug.hpp"
#include "ShVariableNode.hpp"
#include "ShError.hpp"
#include "ShAlgebra.hpp"
#include "ShFixedManipulator.hpp"

namespace SH {

ShFixedManipulatorNode::ShFixedManipulatorNode() {
}

ShFixedManipulatorNode::~ShFixedManipulatorNode() {
}

ShVariable makeVariable(const ShVariableNodePtr &v, ShVariableKind kind) {
  ShVariable result(new ShVariableNode(kind, v->size(), v->specialType()));
  result.name(v->name());
  return result;
}

ShKeepNode::ShKeepNode(int numChannels)
  : m_numChannels(numChannels) {
}

ShProgram ShKeepNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    for(int i = 0; i < m_numChannels; ++i, ++finger) {
      std::cout << "Keep apply to channel: " << (*finger)->nameOfType() << (*finger)->name() << std::endl;
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram channels for manipulator"));
      }
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
      ShVariable input = makeVariable((*finger), SH_VAR_INPUT);
      ShStatement stmt(output, SH_OP_ASN, input);
      ShEnvironment::shader->tokenizer.blockList()->addStatement(stmt);
    }
  } SH_END;
  return result;
}

ShProgram ShKeepNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  return applyToInputs(finger, end);
}

ShFixedManipulator shKeep(int numChannels) {
  return new ShKeepNode(numChannels);
}

ShLoseNode::ShLoseNode(int numChannels)
  : m_numChannels(numChannels) {
}

ShProgram ShLoseNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    for(int i = 0; i < m_numChannels; ++i, ++finger) {
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram channels for manipulator"));
      }
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
    }
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShProgram ShLoseNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    for(int i = 0; i < m_numChannels; ++i, ++finger) {
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram channels for manipulator"));
      }
      ShVariable input = makeVariable((*finger), SH_VAR_INPUT);
    }
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShFixedManipulator shLose(int numChannels) {
  return new ShLoseNode(numChannels);
}

ShDupNode::ShDupNode(int numDups)
  : m_numDups(numDups) {
}

ShProgram ShDupNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    ShVariable input;
    for(int i = 0; i < m_numDups; ++i, ++finger) {
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram channels for manipulator"));
      }
      if(i == 0) {
        input = makeVariable((*finger), SH_VAR_INPUT);
      }
      if((*finger)->size() != input.size()) {
        ShError(ShAlgebraException("Duplicating type " + input.node()->nameOfType()
              + " to incompatible type " + (*finger)->nameOfType()));
      }
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
      ShStatement stmt(output, SH_OP_ASN, input);
      ShEnvironment::shader->tokenizer.blockList()->addStatement(stmt);
    }
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShProgram ShDupNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  return applyToInputs(finger, end);
}

ShFixedManipulator shDup(int numDups) {
  return new ShDupNode(numDups);
}

ShProgramManipNode::ShProgramManipNode(const ShProgram &p)
  : p(p) {
}

ShProgram ShProgramManipNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  int i;
  for(i = 0; i < p->outputs.size() && finger != end; ++i, ++finger);
  // allow extra outputs from p
  return p;
}

ShProgram ShProgramManipNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  int i;
  for(i = 0; i < p->inputs.size() && finger != end; ++i, ++finger);
  // allow extra inputs from p
  return p;
}

ShTreeManipNode::ShTreeManipNode(const ShFixedManipulator &a, const ShFixedManipulator &b)
  : a(a), b(b) {
  SH_DEBUG_ASSERT(a);
  SH_DEBUG_ASSERT(b);
}

ShProgram ShTreeManipNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram aProgram = a->applyToInputs(finger, end);
  ShProgram bProgram = b->applyToInputs(finger, end);
  return aProgram & bProgram;
}

ShProgram ShTreeManipNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram aProgram = a->applyToOutputs(finger, end);
  ShProgram bProgram = b->applyToOutputs(finger, end);
  return aProgram & bProgram;
}

ShProgram operator<<(const ShProgram &p, const ShFixedManipulator &m) {
  ShManipVarIterator finger = p->inputs.begin();
  ShProgram manipulator = m->applyToInputs(finger, p->inputs.end());
  return p << manipulator;
}

ShProgram operator<<(const ShFixedManipulator &m, const ShProgram &p) {
  ShManipVarIterator finger = p->outputs.begin();
  ShProgram manipulator = m->applyToOutputs(finger, p->outputs.end());
  return p << manipulator;
}

ShFixedManipulator operator&(const ShFixedManipulator &m, const ShFixedManipulator &n) {
  return new ShTreeManipNode(m, n);
}

ShFixedManipulator operator&(const ShFixedManipulator &m, const ShProgram &p) {
  return m & new ShProgramManipNode(p);
}
ShFixedManipulator operator&(const ShProgram &p, const ShFixedManipulator &m) {
  return new ShProgramManipNode(p) & m;
}

}

<commit_msg>Fixed bugs with several fixed manips.<commit_after>// Sh: A GPU metaprogramming language.
//
// Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
// Project administrator: Michael D. McCool
// Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
//          Michael D. McCool
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//////////////////////////////////////////////////////////////////////////////

#include <sstream>
#include "ShDebug.hpp"
#include "ShVariableNode.hpp"
#include "ShError.hpp"
#include "ShAlgebra.hpp"
#include "ShFixedManipulator.hpp"

namespace SH {

ShFixedManipulatorNode::ShFixedManipulatorNode() {
}

ShFixedManipulatorNode::~ShFixedManipulatorNode() {
}

ShVariable makeVariable(const ShVariableNodePtr &v, ShVariableKind kind) {
  ShVariable result(new ShVariableNode(kind, v->size(), v->specialType()));
  result.name(v->name());
  return result;
}

ShKeepNode::ShKeepNode(int numChannels)
  : m_numChannels(numChannels) {
}

ShProgram ShKeepNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  SH_DEBUG_PRINT( "Applying keep " << m_numChannels  );
  ShProgram result = SH_BEGIN_PROGRAM() {
    for(int i = 0; i < m_numChannels; ++i, ++finger) {
      std::cout << "Keep apply to channel: " << (*finger)->nameOfType() << (*finger)->name() << std::endl;
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram channels for shKeep manipulator"));
      }
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
      ShVariable input = makeVariable((*finger), SH_VAR_INPUT);
      ShStatement stmt(output, SH_OP_ASN, input);
      ShEnvironment::shader->tokenizer.blockList()->addStatement(stmt);
    }
  } SH_END;
  return result;
}

ShProgram ShKeepNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  return applyToInputs(finger, end);
}

ShFixedManipulator shKeep(int numChannels) {
  return new ShKeepNode(numChannels);
}

ShLoseNode::ShLoseNode(int numChannels)
  : m_numChannels(numChannels) {
}

ShProgram ShLoseNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  SH_DEBUG_PRINT( "Applying lose " << m_numChannels  );
  ShProgram result = SH_BEGIN_PROGRAM() {
    for(int i = 0; i < m_numChannels; ++i, ++finger) {
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram input channels for shLose manipulator"));
      }
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
    }
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShProgram ShLoseNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    for(int i = 0; i < m_numChannels; ++i, ++finger) {
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram output channels for shLose manipulator"));
      }
      ShVariable input = makeVariable((*finger), SH_VAR_INPUT);
    }
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShFixedManipulator shLose(int numChannels) {
  return new ShLoseNode(numChannels);
}

ShDupNode::ShDupNode(int numDups)
  : m_numDups(numDups) {
}

ShProgram ShDupNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    ShVariable input;
    for(int i = 0; i < m_numDups; ++i, ++finger) {
      if(finger == end) {
        ShError(ShAlgebraException("Not enough ShProgram input channels for shDup manipulator"));
      }
      if(i == 0) {
        input = makeVariable((*finger), SH_VAR_INPUT);
      }
      if((*finger)->size() != input.size()) {
        ShError(ShAlgebraException("Duplicating type " + input.node()->nameOfType()
              + " to incompatible type " + (*finger)->nameOfType()));
      }
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
      ShStatement stmt(output, SH_OP_ASN, input);
      ShEnvironment::shader->tokenizer.blockList()->addStatement(stmt);
    }
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShProgram ShDupNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram result = SH_BEGIN_PROGRAM() {
    if(finger == end) {
      ShError(ShAlgebraException("Not enough ShProgram output channels for shDup manipulator"));
    }
    ShVariable input = makeVariable((*finger), SH_VAR_INPUT);

    for(int i = 0; i < m_numDups; ++i) {
      ShVariable output = makeVariable((*finger), SH_VAR_OUTPUT);
      ShStatement stmt(output, SH_OP_ASN, input);
      ShEnvironment::shader->tokenizer.blockList()->addStatement(stmt);
    }
    ++finger;
    // TODO  remove this when empty connect/combine bugs fixed
    ShAttrib4f dummy = dummy;
  } SH_END;
  return result;
}

ShFixedManipulator shDup(int numDups) {
  return new ShDupNode(numDups);
}

ShProgramManipNode::ShProgramManipNode(const ShProgram &p)
  : p(p) {
}

ShProgram ShProgramManipNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  int i;
  for(i = 0; i < p->outputs.size() && finger != end; ++i, ++finger);
  // allow extra outputs from p
  return p;
}

ShProgram ShProgramManipNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  int i;
  for(i = 0; i < p->inputs.size() && finger != end; ++i, ++finger);
  // allow extra inputs from p
  return p;
}

ShTreeManipNode::ShTreeManipNode(const ShFixedManipulator &a, const ShFixedManipulator &b)
  : a(a), b(b) {
  SH_DEBUG_ASSERT(a);
  SH_DEBUG_ASSERT(b);
}

ShProgram ShTreeManipNode::applyToInputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram aProgram = a->applyToInputs(finger, end);
  ShProgram bProgram = b->applyToInputs(finger, end);
  return aProgram & bProgram;
}

ShProgram ShTreeManipNode::applyToOutputs(ShManipVarIterator &finger, ShManipVarIterator end) const {
  ShProgram aProgram = a->applyToOutputs(finger, end);
  ShProgram bProgram = b->applyToOutputs(finger, end);
  return aProgram & bProgram;
}

ShProgram operator<<(const ShProgram &p, const ShFixedManipulator &m) {
  ShManipVarIterator finger = p->inputs.begin();
  ShProgram manipulator = m->applyToInputs(finger, p->inputs.end());
  return p << manipulator;
}

ShProgram operator<<(const ShFixedManipulator &m, const ShProgram &p) {
  ShManipVarIterator finger = p->outputs.begin();
  ShProgram manipulator = m->applyToOutputs(finger, p->outputs.end());
  return manipulator << p;
}

ShFixedManipulator operator&(const ShFixedManipulator &m, const ShFixedManipulator &n) {
  return new ShTreeManipNode(m, n);
}

ShFixedManipulator operator&(const ShFixedManipulator &m, const ShProgram &p) {
  return m & new ShProgramManipNode(p);
}
ShFixedManipulator operator&(const ShProgram &p, const ShFixedManipulator &m) {
  return new ShProgramManipNode(p) & m;
}

}

<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt/DBusTubeChannel>

#include "TelepathyQt/_gen/dbus-tube-channel.moc.hpp"

#include "TelepathyQt/debug-internal.h"
#include "TelepathyQt/outgoing-stream-tube-channel-internal.h"

#include <TelepathyQt/Connection>
#include <TelepathyQt/ContactManager>

namespace Tp
{

struct TP_QT_NO_EXPORT DBusTubeChannel::Private
{
    Private(DBusTubeChannel *parent);
    virtual ~Private();

    void extractProperties(const QVariantMap &props);
    void extractParticipants(const Tp::DBusTubeParticipants &participants);

    static void introspectDBusTube(Private *self);
    static void introspectBusNamesMonitoring(Private *self);

    ReadinessHelper *readinessHelper;

    // Public object
    DBusTubeChannel *parent;

    // Properties
    UIntList accessControls;
    QString serviceName;
    QHash<ContactPtr, QString> busNames;
    QString address;

    QHash<QUuid, QString> pendingNewBusNamesToAdd;
    QList<QUuid> pendingNewBusNamesToRemove;

    QueuedContactFactory *queuedContactFactory;
};

DBusTubeChannel::Private::Private(DBusTubeChannel *parent)
        : parent(parent),
          queuedContactFactory(new QueuedContactFactory(parent->connection()->contactManager(), parent))
{
    // Initialize readinessHelper + introspectables here
    readinessHelper = parent->readinessHelper();

    ReadinessHelper::Introspectables introspectables;

    ReadinessHelper::Introspectable introspectableDBusTube(
        QSet<uint>() << 0,                                                      // makesSenseForStatuses
        Features() << TubeChannel::FeatureCore,                                 // dependsOnFeatures (core)
        QStringList(),                                                          // dependsOnInterfaces
        (ReadinessHelper::IntrospectFunc) &Private::introspectDBusTube,
        this);
    introspectables[DBusTubeChannel::FeatureDBusTube] = introspectableDBusTube;

    ReadinessHelper::Introspectable introspectableBusNamesMonitoring(
        QSet<uint>() << 0,                                                      // makesSenseForStatuses
        Features() << DBusTubeChannel::FeatureDBusTube,                         // dependsOnFeatures (core)
        QStringList(),                                                          // dependsOnInterfaces
        (ReadinessHelper::IntrospectFunc) &Private::introspectBusNamesMonitoring,
        this);
    introspectables[DBusTubeChannel::FeatureBusNameMonitoring] = introspectableBusNamesMonitoring;

    readinessHelper->addIntrospectables(introspectables);
}

DBusTubeChannel::Private::~Private()
{
}

void DBusTubeChannel::Private::extractProperties(const QVariantMap &props)
{
    serviceName = qdbus_cast<QString>(props[QLatin1String("Service")]);
    accessControls = qdbus_cast<UIntList>(props[QLatin1String("SupportedAccessControls")]);
    extractParticipants(qdbus_cast<DBusTubeParticipants>(props[QLatin1String("DBusNames")]));
}

void DBusTubeChannel::Private::extractParticipants(const Tp::DBusTubeParticipants &participants)
{
    busNames.clear();
    for (DBusTubeParticipants::const_iterator i = participants.constBegin();
         i != participants.constEnd();
         ++i) {
        QUuid uuid = queuedContactFactory->appendNewRequest(UIntList() << i.key());
        pendingNewBusNamesToAdd.insert(uuid, i.value());
    }
}

void DBusTubeChannel::Private::introspectBusNamesMonitoring(DBusTubeChannel::Private *self)
{
    DBusTubeChannel *parent = self->parent;

    Client::ChannelTypeDBusTubeInterface *dbusTubeInterface =
            parent->interface<Client::ChannelTypeDBusTubeInterface>();

    // It must be present
    Q_ASSERT(dbusTubeInterface);

    // It makes sense only if this is a room, if that's not the case just spit a warning
    if (parent->targetHandleType() == static_cast<uint>(Tp::HandleTypeRoom)) {
        parent->connect(dbusTubeInterface, SIGNAL(DBusNamesChanged(Tp::DBusTubeParticipants,Tp::UIntList)),
                        parent, SLOT(onDBusNamesChanged(Tp::DBusTubeParticipants,Tp::UIntList)));
    } else {
        debug() << "FeatureBusNameMonitoring does not make sense in a P2P context";
    }

    self->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureBusNameMonitoring, true);
}

void DBusTubeChannel::Private::introspectDBusTube(DBusTubeChannel::Private *self)
{
    DBusTubeChannel *parent = self->parent;

    debug() << "Introspect dbus tube properties";

    Client::DBus::PropertiesInterface *properties =
            parent->interface<Client::DBus::PropertiesInterface>();

    QDBusPendingCallWatcher *watcher =
        new QDBusPendingCallWatcher(
                properties->GetAll(
                    QLatin1String(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE)),
                parent);
    parent->connect(watcher,
            SIGNAL(finished(QDBusPendingCallWatcher*)),
            parent,
            SLOT(gotDBusTubeProperties(QDBusPendingCallWatcher*)));
}

/**
 * \class DBusTubeChannel
 * \headerfile TelepathyQt/stream-tube-channel.h <TelepathyQt/DBusTubeChannel>
 *
 * A class representing a DBus Tube
 *
 * \c DBusTubeChannel is an high level wrapper for managing Telepathy interface
 * #TELEPATHY_INTERFACE_CHANNEL_TYPE_DBUS_TUBE.
 * It provides a private DBus connection, either peer-to-peer or between a group of contacts, which
 * can be used just like a standard DBus connection. As such, services exposed MUST adhere to the
 * DBus specification.
 *
 * This class provides high level methods for managing both incoming and outgoing tubes - however,
 * you probably want to use one of its subclasses, #OutgoingDBusTubeChannel or
 * #IncomingDBusTubeChannel, which both provide higher level methods for accepting
 * or offering tubes.
 *
 * For more details, please refer to Telepathy spec.
 */

// Features declaration and documentation
/**
 * Feature representing the core that needs to become ready to make the
 * DBusTubeChannel object usable.
 *
 * Note that this feature must be enabled in order to use most
 * DBusTubeChannel methods.
 * See specific methods documentation for more details.
 */
const Feature DBusTubeChannel::FeatureDBusTube = Feature(QLatin1String(DBusTubeChannel::staticMetaObject.className()), 0);
/**
 * Feature used in order to monitor connections to this tube.
 * Please note that this feature makes sense only in Group tubes.
 *
 * %busNamesChanged will be emitted when the participants of this tube change
 */
const Feature DBusTubeChannel::FeatureBusNameMonitoring = Feature(QLatin1String(DBusTubeChannel::staticMetaObject.className()), 1);

/**
 * Create a new DBusTubeChannel channel.
 *
 * \param connection Connection owning this channel, and specifying the
 *                   service.
 * \param objectPath The object path of this channel.
 * \param immutableProperties The immutable properties of this channel.
 * \return A DBusTubeChannelPtr object pointing to the newly created
 *         DBusTubeChannel object.
 */
DBusTubeChannelPtr DBusTubeChannel::create(const ConnectionPtr &connection,
        const QString &objectPath, const QVariantMap &immutableProperties)
{
    return DBusTubeChannelPtr(new DBusTubeChannel(connection, objectPath,
                immutableProperties));
}

/**
 * Construct a new DBusTubeChannel object.
 *
 * \param connection Connection owning this channel, and specifying the
 *                   service.
 * \param objectPath The object path of this channel.
 * \param immutableProperties The immutable properties of this channel.
 */
DBusTubeChannel::DBusTubeChannel(const ConnectionPtr &connection,
        const QString &objectPath,
        const QVariantMap &immutableProperties)
    : TubeChannel(connection, objectPath, immutableProperties),
      mPriv(new Private(this))
{
    connect(mPriv->queuedContactFactory,
            SIGNAL(contactsRetrieved(QUuid,QList<Tp::ContactPtr>)),
            this,
            SLOT(onContactsRetrieved(QUuid,QList<Tp::ContactPtr>)));
}

/**
 * Class destructor.
 */
DBusTubeChannel::~DBusTubeChannel()
{
    delete mPriv;
}

/**
 * Returns the service name which will be used over the tube.
 *
 * This method requires DBusTubeChannel::FeatureDBusTube to be enabled.
 *
 * \return the service name that will be used over the tube
 */
QString DBusTubeChannel::serviceName() const
{
    if (!isReady(FeatureDBusTube)) {
        warning() << "DBusTubeChannel::service() used with "
            "FeatureDBusTube not ready";
        return QString();
    }

    return mPriv->serviceName;
}

/**
 * Checks if this tube is capable to accept or offer a private bus which
 * will require credentials upon connection.
 *
 * When this capability is available and enabled, the connecting process must send a byte when
 * it first connects, which is not considered to be part of the data stream.
 * If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass
 * credentials over sockets, the connecting process must do so if possible;
 * if not, it must still send the byte.
 *
 * The listening process will disconnect the connection unless it can determine
 * by OS-specific means that the connecting process has the same user ID as the listening process.
 *
 * This method requires DBusTubeChannel::FeatureDBusTube to be enabled.
 *
 * \note It is strongly advised to call this method before attempting to call
 *       #IncomingDBusTubeChannel::acceptTube or
 *       #OutgoingDBusTubeChannel::offerTube requiring
 *       credentials to prevent failures, as the spec implies
 *       this feature is not compulsory for connection managers.
 *
 * \return Whether this DBus tube is capable to accept or offer a private bus
 *         requiring credentials for connecting to it.
 *
 * \sa IncomingDBusTubeChannel::acceptTube
 * \sa OutgoingDBusTubeChannel::offerTube
 */
bool DBusTubeChannel::supportsCredentials() const
{
    if (!isReady(FeatureDBusTube)) {
        warning() << "DBusTubeChannel::supportsCredentials() used with "
            "FeatureDBusTube not ready";
        return false;
    }

    return mPriv->accessControls.contains(static_cast<uint>(Tp::SocketAccessControlCredentials));
}

/**
 * If the tube has been opened, this function returns the private bus address you should be connecting
 * to for using this tube.
 *
 * Please note this function will return a meaningful value only if the tube has already
 * been opened successfully: in case of failure or the tube being still pending, an empty QString will be
 * returned.
 *
 * \returns The address of the private bus opened by this tube
 */
QString DBusTubeChannel::address() const
{
    if (state() != TubeChannelStateOpen) {
        warning() << "DBusTubeChannel::address() can be called only if "
            "the tube has already been opened";
        return QString();
    }

    return mPriv->address;
}

/**
 * This function returns all the known active connections since FeatureBusNameMonitoring has
 * been enabled. For this method to return all known connections, you need to make
 * FeatureBusNameMonitoring ready before accepting or offering the tube.
 *
 * This function will always return an empty hash in case the tube is p2p, even if
 * FeatureBusNameMonitoring has been activated.
 *
 * \returns A list of active connection ids known to this tube
 */
QHash<ContactPtr, QString> DBusTubeChannel::busNames() const
{
    if (!isReady(FeatureBusNameMonitoring)) {
        warning() << "DBusTubeChannel::busNames() used with "
            "FeatureBusNameMonitoring not ready";
        return QHash<ContactPtr, QString>();
    }

    return mPriv->busNames;
}

void DBusTubeChannel::gotDBusTubeProperties(QDBusPendingCallWatcher *watcher)
{
    QDBusPendingReply<QVariantMap> reply = *watcher;

    if (!reply.isError()) {
        QVariantMap props = reply.value();
        debug() << "Got reply to Properties::GetAll(DBusTubeChannel)";
        mPriv->extractProperties(props);
        mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureDBusTube, true);
    } else {
        warning().nospace() << "Properties::GetAll(DBusTubeChannel) failed "
            "with " << reply.error().name() << ": " << reply.error().message();
        mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureDBusTube, false,
                reply.error());
    }
}

void DBusTubeChannel::onDBusNamesChanged(const Tp::DBusTubeParticipants &added,
        const Tp::UIntList &removed)
{
    for (DBusTubeParticipants::const_iterator i = added.constBegin();
         i != added.constEnd();
         ++i) {
        QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << i.key());
        // Add it to our hash as well
        mPriv->pendingNewBusNamesToAdd.insert(uuid, i.value());
    }

    foreach (uint handle, removed) {
        QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << handle);
        // Add it to pending removed as well
        mPriv->pendingNewBusNamesToRemove << uuid;
    }
}

void DBusTubeChannel::onContactsRetrieved(const QUuid &uuid, const QList<ContactPtr> &contacts)
{
    // Retrieve our hash
    if (mPriv->pendingNewBusNamesToAdd.contains(uuid)) {
        QString busName = mPriv->pendingNewBusNamesToAdd.take(uuid);
        QHash<ContactPtr, QString> added;

        // Add it to our connections hash
        foreach (const Tp::ContactPtr &contact, contacts) {
            mPriv->busNames.insertMulti(contact, busName);
            added.insert(contact, busName);
        }

        // Time for us to emit the signal
        emit busNamesChanged(added, QList<ContactPtr>());
    } else if (mPriv->pendingNewBusNamesToRemove.contains(uuid)) {
        mPriv->pendingNewBusNamesToRemove.removeOne(uuid);
        QList<ContactPtr> removed;

        // Remove it from our connections hash
        foreach (const Tp::ContactPtr &contact, contacts) {
            mPriv->busNames.remove(contact);
            removed << contact;
        }

        // Time for us to emit the signal
        emit busNamesChanged(QHash<ContactPtr, QString>(), removed);
    } else {
        warning() << "Contacts retrieved but no pending bus names were found";
        return;
    }
}

void DBusTubeChannel::setAddress(const QString& address)
{
    mPriv->address = address;
}

// Signals documentation
/**
 * \fn void DBusTubeChannel::busNamesChanged(const QHash< ContactPtr, QString > &added, const QList< ContactPtr > &removed)
 *
 * Emitted when the participants of this tube change.
 *
 * This signal will be emitted only if the tube is a group tube (not p2p), and if the
 * FeatureBusNameMonitoring feature has been enabled. You usually want to wait until the
 * aforementioned feature is ready before connecting to this signal.
 *
 * \param added An hash containing the contacts who joined this tube, with their respective bus name.
 * \param removed A list containing the contacts who left this tube.
 */

}
<commit_msg>dbus-tubes: Don't use insertMulti<commit_after>/*
 * This file is part of TelepathyQt
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt/DBusTubeChannel>

#include "TelepathyQt/_gen/dbus-tube-channel.moc.hpp"

#include "TelepathyQt/debug-internal.h"
#include "TelepathyQt/outgoing-stream-tube-channel-internal.h"

#include <TelepathyQt/Connection>
#include <TelepathyQt/ContactManager>

namespace Tp
{

struct TP_QT_NO_EXPORT DBusTubeChannel::Private
{
    Private(DBusTubeChannel *parent);
    virtual ~Private();

    void extractProperties(const QVariantMap &props);
    void extractParticipants(const Tp::DBusTubeParticipants &participants);

    static void introspectDBusTube(Private *self);
    static void introspectBusNamesMonitoring(Private *self);

    ReadinessHelper *readinessHelper;

    // Public object
    DBusTubeChannel *parent;

    // Properties
    UIntList accessControls;
    QString serviceName;
    QHash<ContactPtr, QString> busNames;
    QString address;

    QHash<QUuid, QString> pendingNewBusNamesToAdd;
    QList<QUuid> pendingNewBusNamesToRemove;

    QueuedContactFactory *queuedContactFactory;
};

DBusTubeChannel::Private::Private(DBusTubeChannel *parent)
        : parent(parent),
          queuedContactFactory(new QueuedContactFactory(parent->connection()->contactManager(), parent))
{
    // Initialize readinessHelper + introspectables here
    readinessHelper = parent->readinessHelper();

    ReadinessHelper::Introspectables introspectables;

    ReadinessHelper::Introspectable introspectableDBusTube(
        QSet<uint>() << 0,                                                      // makesSenseForStatuses
        Features() << TubeChannel::FeatureCore,                                 // dependsOnFeatures (core)
        QStringList(),                                                          // dependsOnInterfaces
        (ReadinessHelper::IntrospectFunc) &Private::introspectDBusTube,
        this);
    introspectables[DBusTubeChannel::FeatureDBusTube] = introspectableDBusTube;

    ReadinessHelper::Introspectable introspectableBusNamesMonitoring(
        QSet<uint>() << 0,                                                      // makesSenseForStatuses
        Features() << DBusTubeChannel::FeatureDBusTube,                         // dependsOnFeatures (core)
        QStringList(),                                                          // dependsOnInterfaces
        (ReadinessHelper::IntrospectFunc) &Private::introspectBusNamesMonitoring,
        this);
    introspectables[DBusTubeChannel::FeatureBusNameMonitoring] = introspectableBusNamesMonitoring;

    readinessHelper->addIntrospectables(introspectables);
}

DBusTubeChannel::Private::~Private()
{
}

void DBusTubeChannel::Private::extractProperties(const QVariantMap &props)
{
    serviceName = qdbus_cast<QString>(props[QLatin1String("Service")]);
    accessControls = qdbus_cast<UIntList>(props[QLatin1String("SupportedAccessControls")]);
    extractParticipants(qdbus_cast<DBusTubeParticipants>(props[QLatin1String("DBusNames")]));
}

void DBusTubeChannel::Private::extractParticipants(const Tp::DBusTubeParticipants &participants)
{
    busNames.clear();
    for (DBusTubeParticipants::const_iterator i = participants.constBegin();
         i != participants.constEnd();
         ++i) {
        QUuid uuid = queuedContactFactory->appendNewRequest(UIntList() << i.key());
        pendingNewBusNamesToAdd.insert(uuid, i.value());
    }
}

void DBusTubeChannel::Private::introspectBusNamesMonitoring(DBusTubeChannel::Private *self)
{
    DBusTubeChannel *parent = self->parent;

    Client::ChannelTypeDBusTubeInterface *dbusTubeInterface =
            parent->interface<Client::ChannelTypeDBusTubeInterface>();

    // It must be present
    Q_ASSERT(dbusTubeInterface);

    // It makes sense only if this is a room, if that's not the case just spit a warning
    if (parent->targetHandleType() == static_cast<uint>(Tp::HandleTypeRoom)) {
        parent->connect(dbusTubeInterface, SIGNAL(DBusNamesChanged(Tp::DBusTubeParticipants,Tp::UIntList)),
                        parent, SLOT(onDBusNamesChanged(Tp::DBusTubeParticipants,Tp::UIntList)));
    } else {
        debug() << "FeatureBusNameMonitoring does not make sense in a P2P context";
    }

    self->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureBusNameMonitoring, true);
}

void DBusTubeChannel::Private::introspectDBusTube(DBusTubeChannel::Private *self)
{
    DBusTubeChannel *parent = self->parent;

    debug() << "Introspect dbus tube properties";

    Client::DBus::PropertiesInterface *properties =
            parent->interface<Client::DBus::PropertiesInterface>();

    QDBusPendingCallWatcher *watcher =
        new QDBusPendingCallWatcher(
                properties->GetAll(
                    QLatin1String(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE)),
                parent);
    parent->connect(watcher,
            SIGNAL(finished(QDBusPendingCallWatcher*)),
            parent,
            SLOT(gotDBusTubeProperties(QDBusPendingCallWatcher*)));
}

/**
 * \class DBusTubeChannel
 * \headerfile TelepathyQt/stream-tube-channel.h <TelepathyQt/DBusTubeChannel>
 *
 * A class representing a DBus Tube
 *
 * \c DBusTubeChannel is an high level wrapper for managing Telepathy interface
 * #TELEPATHY_INTERFACE_CHANNEL_TYPE_DBUS_TUBE.
 * It provides a private DBus connection, either peer-to-peer or between a group of contacts, which
 * can be used just like a standard DBus connection. As such, services exposed MUST adhere to the
 * DBus specification.
 *
 * This class provides high level methods for managing both incoming and outgoing tubes - however,
 * you probably want to use one of its subclasses, #OutgoingDBusTubeChannel or
 * #IncomingDBusTubeChannel, which both provide higher level methods for accepting
 * or offering tubes.
 *
 * For more details, please refer to Telepathy spec.
 */

// Features declaration and documentation
/**
 * Feature representing the core that needs to become ready to make the
 * DBusTubeChannel object usable.
 *
 * Note that this feature must be enabled in order to use most
 * DBusTubeChannel methods.
 * See specific methods documentation for more details.
 */
const Feature DBusTubeChannel::FeatureDBusTube = Feature(QLatin1String(DBusTubeChannel::staticMetaObject.className()), 0);
/**
 * Feature used in order to monitor connections to this tube.
 * Please note that this feature makes sense only in Group tubes.
 *
 * %busNamesChanged will be emitted when the participants of this tube change
 */
const Feature DBusTubeChannel::FeatureBusNameMonitoring = Feature(QLatin1String(DBusTubeChannel::staticMetaObject.className()), 1);

/**
 * Create a new DBusTubeChannel channel.
 *
 * \param connection Connection owning this channel, and specifying the
 *                   service.
 * \param objectPath The object path of this channel.
 * \param immutableProperties The immutable properties of this channel.
 * \return A DBusTubeChannelPtr object pointing to the newly created
 *         DBusTubeChannel object.
 */
DBusTubeChannelPtr DBusTubeChannel::create(const ConnectionPtr &connection,
        const QString &objectPath, const QVariantMap &immutableProperties)
{
    return DBusTubeChannelPtr(new DBusTubeChannel(connection, objectPath,
                immutableProperties));
}

/**
 * Construct a new DBusTubeChannel object.
 *
 * \param connection Connection owning this channel, and specifying the
 *                   service.
 * \param objectPath The object path of this channel.
 * \param immutableProperties The immutable properties of this channel.
 */
DBusTubeChannel::DBusTubeChannel(const ConnectionPtr &connection,
        const QString &objectPath,
        const QVariantMap &immutableProperties)
    : TubeChannel(connection, objectPath, immutableProperties),
      mPriv(new Private(this))
{
    connect(mPriv->queuedContactFactory,
            SIGNAL(contactsRetrieved(QUuid,QList<Tp::ContactPtr>)),
            this,
            SLOT(onContactsRetrieved(QUuid,QList<Tp::ContactPtr>)));
}

/**
 * Class destructor.
 */
DBusTubeChannel::~DBusTubeChannel()
{
    delete mPriv;
}

/**
 * Returns the service name which will be used over the tube.
 *
 * This method requires DBusTubeChannel::FeatureDBusTube to be enabled.
 *
 * \return the service name that will be used over the tube
 */
QString DBusTubeChannel::serviceName() const
{
    if (!isReady(FeatureDBusTube)) {
        warning() << "DBusTubeChannel::service() used with "
            "FeatureDBusTube not ready";
        return QString();
    }

    return mPriv->serviceName;
}

/**
 * Checks if this tube is capable to accept or offer a private bus which
 * will require credentials upon connection.
 *
 * When this capability is available and enabled, the connecting process must send a byte when
 * it first connects, which is not considered to be part of the data stream.
 * If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass
 * credentials over sockets, the connecting process must do so if possible;
 * if not, it must still send the byte.
 *
 * The listening process will disconnect the connection unless it can determine
 * by OS-specific means that the connecting process has the same user ID as the listening process.
 *
 * This method requires DBusTubeChannel::FeatureDBusTube to be enabled.
 *
 * \note It is strongly advised to call this method before attempting to call
 *       #IncomingDBusTubeChannel::acceptTube or
 *       #OutgoingDBusTubeChannel::offerTube requiring
 *       credentials to prevent failures, as the spec implies
 *       this feature is not compulsory for connection managers.
 *
 * \return Whether this DBus tube is capable to accept or offer a private bus
 *         requiring credentials for connecting to it.
 *
 * \sa IncomingDBusTubeChannel::acceptTube
 * \sa OutgoingDBusTubeChannel::offerTube
 */
bool DBusTubeChannel::supportsCredentials() const
{
    if (!isReady(FeatureDBusTube)) {
        warning() << "DBusTubeChannel::supportsCredentials() used with "
            "FeatureDBusTube not ready";
        return false;
    }

    return mPriv->accessControls.contains(static_cast<uint>(Tp::SocketAccessControlCredentials));
}

/**
 * If the tube has been opened, this function returns the private bus address you should be connecting
 * to for using this tube.
 *
 * Please note this function will return a meaningful value only if the tube has already
 * been opened successfully: in case of failure or the tube being still pending, an empty QString will be
 * returned.
 *
 * \returns The address of the private bus opened by this tube
 */
QString DBusTubeChannel::address() const
{
    if (state() != TubeChannelStateOpen) {
        warning() << "DBusTubeChannel::address() can be called only if "
            "the tube has already been opened";
        return QString();
    }

    return mPriv->address;
}

/**
 * This function returns all the known active connections since FeatureBusNameMonitoring has
 * been enabled. For this method to return all known connections, you need to make
 * FeatureBusNameMonitoring ready before accepting or offering the tube.
 *
 * This function will always return an empty hash in case the tube is p2p, even if
 * FeatureBusNameMonitoring has been activated.
 *
 * \returns A list of active connection ids known to this tube
 */
QHash<ContactPtr, QString> DBusTubeChannel::busNames() const
{
    if (!isReady(FeatureBusNameMonitoring)) {
        warning() << "DBusTubeChannel::busNames() used with "
            "FeatureBusNameMonitoring not ready";
        return QHash<ContactPtr, QString>();
    }

    return mPriv->busNames;
}

void DBusTubeChannel::gotDBusTubeProperties(QDBusPendingCallWatcher *watcher)
{
    QDBusPendingReply<QVariantMap> reply = *watcher;

    if (!reply.isError()) {
        QVariantMap props = reply.value();
        debug() << "Got reply to Properties::GetAll(DBusTubeChannel)";
        mPriv->extractProperties(props);
        mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureDBusTube, true);
    } else {
        warning().nospace() << "Properties::GetAll(DBusTubeChannel) failed "
            "with " << reply.error().name() << ": " << reply.error().message();
        mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureDBusTube, false,
                reply.error());
    }
}

void DBusTubeChannel::onDBusNamesChanged(const Tp::DBusTubeParticipants &added,
        const Tp::UIntList &removed)
{
    for (DBusTubeParticipants::const_iterator i = added.constBegin();
         i != added.constEnd();
         ++i) {
        QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << i.key());
        // Add it to our hash as well
        mPriv->pendingNewBusNamesToAdd.insert(uuid, i.value());
    }

    foreach (uint handle, removed) {
        QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << handle);
        // Add it to pending removed as well
        mPriv->pendingNewBusNamesToRemove << uuid;
    }
}

void DBusTubeChannel::onContactsRetrieved(const QUuid &uuid, const QList<ContactPtr> &contacts)
{
    // Retrieve our hash
    if (mPriv->pendingNewBusNamesToAdd.contains(uuid)) {
        QString busName = mPriv->pendingNewBusNamesToAdd.take(uuid);
        QHash<ContactPtr, QString> added;

        // Add it to our connections hash
        foreach (const Tp::ContactPtr &contact, contacts) {
            mPriv->busNames.insert(contact, busName);
            added.insert(contact, busName);
        }

        // Time for us to emit the signal
        emit busNamesChanged(added, QList<ContactPtr>());
    } else if (mPriv->pendingNewBusNamesToRemove.contains(uuid)) {
        mPriv->pendingNewBusNamesToRemove.removeOne(uuid);
        QList<ContactPtr> removed;

        // Remove it from our connections hash
        foreach (const Tp::ContactPtr &contact, contacts) {
            mPriv->busNames.remove(contact);
            removed << contact;
        }

        // Time for us to emit the signal
        emit busNamesChanged(QHash<ContactPtr, QString>(), removed);
    } else {
        warning() << "Contacts retrieved but no pending bus names were found";
        return;
    }
}

void DBusTubeChannel::setAddress(const QString& address)
{
    mPriv->address = address;
}

// Signals documentation
/**
 * \fn void DBusTubeChannel::busNamesChanged(const QHash< ContactPtr, QString > &added, const QList< ContactPtr > &removed)
 *
 * Emitted when the participants of this tube change.
 *
 * This signal will be emitted only if the tube is a group tube (not p2p), and if the
 * FeatureBusNameMonitoring feature has been enabled. You usually want to wait until the
 * aforementioned feature is ready before connecting to this signal.
 *
 * \param added An hash containing the contacts who joined this tube, with their respective bus name.
 * \param removed A list containing the contacts who left this tube.
 */

}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.

#include <osgManipulator/AntiSquish>

using namespace osgManipulator;

namespace
{
    class AntiSquishCallback: public osg::NodeCallback
    {
        public:
            AntiSquishCallback(AntiSquish* asq) : osg::NodeCallback(), _antiSquish(asq) {}
            virtual ~AntiSquishCallback() {};

            virtual void operator() (osg::Node*, osg::NodeVisitor* nv)
            {
                // Get the node path.
                osg::NodePath np = nv->getNodePath();

                // Remove the last node which is the anti squish node itself.
                np.pop_back();

                // Get the accumulated modeling matrix.
                osg::Matrix localToWorld = osg::computeLocalToWorld(np);

                // compute the unsquished matrix.
                bool flag = false;
                osg::Matrix _unsquishedMatrix = _antiSquish->computeUnSquishedMatrix(localToWorld, flag);
                if (flag)
                    _antiSquish->setMatrix(_unsquishedMatrix);
            }

        protected:
            AntiSquish* _antiSquish;
    };

}

AntiSquish::AntiSquish() : _usePivot(true), _usePosition(false)
{
    _asqCallback = new AntiSquishCallback(this);
    setUpdateCallback(_asqCallback);
}

AntiSquish::AntiSquish(const osg::Vec3d& pivot) : _pivot(pivot), _usePivot(true), _usePosition(false)
{
    _asqCallback = new AntiSquishCallback(this);
    setUpdateCallback(_asqCallback);
}

AntiSquish::AntiSquish(const osg::Vec3d& pivot, const osg::Vec3d& pos)
    : _pivot(pivot), _usePivot(true), _position(pos), _usePosition(true)
{
    _asqCallback = new AntiSquishCallback(this);
    setUpdateCallback(_asqCallback);
}

AntiSquish::AntiSquish(const AntiSquish& pat,const osg::CopyOp& copyop) :
    MatrixTransform(pat,copyop),
    _asqCallback(pat._asqCallback),
    _pivot(pat._pivot),
    _usePivot(pat._usePivot),
    _position(pat._position),
    _usePosition(pat._usePosition),
    _cachedLocalToWorld(pat._cachedLocalToWorld)
{
}

AntiSquish::~AntiSquish()
{
}

osg::Matrix AntiSquish::computeUnSquishedMatrix(const osg::Matrix& LTW, bool& flag)
{
    osg::Vec3d t, s;
    osg::Quat r, so;

    if (LTW == _cachedLocalToWorld && _dirty == false)
    {
        flag = false;
        return osg::Matrix::identity();
    }

    _cachedLocalToWorld = LTW;

    LTW.decompose(t, r, s, so);

    // Let's take an average of the scale.
    double av = (s[0] + s[1] + s[2])/3.0;
    s[0] = av; s[1] = av; s[2]=av;

    if (av == 0)
    {
        flag = false;
        return osg::Matrix::identity();
    }

    osg::Matrix unsquished;

    //
    // Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position]
    // OR [SO]^[S][SO][R][T][LOCALTOWORLD]^
    //
    if (_usePivot)
    {
        unsquished.postMultTranslate(-_pivot);

        osg::Matrix tmps, invtmps;
        so.get(tmps);
        if (!invtmps.invert(tmps))
        {
            flag = false;
            return osg::Matrix::identity();
        }

        //SO^
        unsquished.postMult(invtmps);
        //S
        unsquished.postMultScale(s);
        //SO
        unsquished.postMult(tmps);
        //R
        unsquished.postMultRotate(r);
        //T
        unsquished.postMultTranslate(t);

        osg::Matrix invltw;
        if (!invltw.invert(LTW))
        {
            flag = false;
            return osg::Matrix::identity();
        }
        // LTW^
        unsquished.postMult( invltw );

        // Position
        if (_usePosition)
            unsquished.postMult(_position);
        else
            unsquished.postMult(_pivot);
    }
    else
    {
        osg::Matrix tmps, invtmps;
        so.get(tmps);
        if (!invtmps.invert(tmps))
        {
            flag = false;
            return osg::Matrix::identity();
        }
        unsquished.postMult(invtmps);
        unsquished.postMultScale(s);
        unsquished.postMult(tmps);
        unsquished.postMultRotate(r);
        unsquished.postMultTranslate(t);
        osg::Matrix invltw;
        if (!invltw.invert(LTW))
        {
            flag = false;
            return osg::Matrix::identity();
        }
        unsquished.postMult( invltw );
    }

    if (unsquished.isNaN())
    {
        flag = false;
        return  osg::Matrix::identity();
    }

    flag = true;
    _dirty = false;
    return unsquished;
}

<commit_msg>From Rene Molenaar, "The bug is as described above:<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.

#include <osgManipulator/AntiSquish>

using namespace osgManipulator;

namespace
{
    class AntiSquishCallback: public osg::NodeCallback
    {
        public:
            AntiSquishCallback(AntiSquish* asq) : osg::NodeCallback(), _antiSquish(asq) {}
            virtual ~AntiSquishCallback() {};

            virtual void operator() (osg::Node*, osg::NodeVisitor* nv)
            {
                // Get the node path.
                osg::NodePath np = nv->getNodePath();

                // Remove the last node which is the anti squish node itself.
                np.pop_back();

                // Get the accumulated modeling matrix.
                osg::Matrix localToWorld = osg::computeLocalToWorld(np);

                // compute the unsquished matrix.
                bool flag = false;
                osg::Matrix _unsquishedMatrix = _antiSquish->computeUnSquishedMatrix(localToWorld, flag);
                if (flag)
                    _antiSquish->setMatrix(_unsquishedMatrix);
            }

        protected:
            AntiSquish* _antiSquish;
    };

}

AntiSquish::AntiSquish() : _usePivot(true), _usePosition(false)
{
    _asqCallback = new AntiSquishCallback(this);
    setUpdateCallback(_asqCallback);
}

AntiSquish::AntiSquish(const osg::Vec3d& pivot) : _pivot(pivot), _usePivot(true), _usePosition(false)
{
    _asqCallback = new AntiSquishCallback(this);
    setUpdateCallback(_asqCallback);
}

AntiSquish::AntiSquish(const osg::Vec3d& pivot, const osg::Vec3d& pos)
    : _pivot(pivot), _usePivot(true), _position(pos), _usePosition(true)
{
    _asqCallback = new AntiSquishCallback(this);
    setUpdateCallback(_asqCallback);
}

AntiSquish::AntiSquish(const AntiSquish& pat,const osg::CopyOp& copyop) :
    MatrixTransform(pat,copyop),
    _asqCallback(pat._asqCallback),
    _pivot(pat._pivot),
    _usePivot(pat._usePivot),
    _position(pat._position),
    _usePosition(pat._usePosition),
    _cachedLocalToWorld(pat._cachedLocalToWorld)
{
}

AntiSquish::~AntiSquish()
{
}

osg::Matrix AntiSquish::computeUnSquishedMatrix(const osg::Matrix& LTW, bool& flag)
{
    osg::Vec3d t, s;
    osg::Quat r, so;

    if (LTW == _cachedLocalToWorld && _dirty == false)
    {
        flag = false;
        return osg::Matrix::identity();
    }

    _cachedLocalToWorld = LTW;

    LTW.decompose(t, r, s, so);

    // Let's take an average of the scale.
    double av = (s[0] + s[1] + s[2])/3.0;
    s[0] = av; s[1] = av; s[2]=av;

    if (av == 0)
    {
        flag = false;
        return osg::Matrix::identity();
    }

    osg::Matrix unsquished;

    //
    // Final Matrix: [-Pivot][SO]^[S][SO][R][T][Pivot][LOCALTOWORLD]^[position]
    // OR [SO]^[S][SO][R][T][LOCALTOWORLD]^
    //
    if (_usePivot)
    {
        unsquished.postMultTranslate(-_pivot);

        osg::Matrix tmps, invtmps;
        so.get(tmps);
        if (!invtmps.invert(tmps))
        {
            flag = false;
            return osg::Matrix::identity();
        }

        //SO^
        unsquished.postMult(invtmps);
        //S
        unsquished.postMultScale(s);
        //SO
        unsquished.postMult(tmps);
        //R
        unsquished.postMultRotate(r);
        //T
        unsquished.postMultTranslate(t);

        osg::Matrix invltw;
        if (!invltw.invert(LTW))
        {
            flag = false;
            return osg::Matrix::identity();
        }
        // LTW^
        unsquished.postMult( invltw );

        // Position
        if (_usePosition)
            unsquished.postMultTranslate(_position);
        else
            unsquished.postMultTranslate(_pivot);
    }
    else
    {
        osg::Matrix tmps, invtmps;
        so.get(tmps);
        if (!invtmps.invert(tmps))
        {
            flag = false;
            return osg::Matrix::identity();
        }
        unsquished.postMult(invtmps);
        unsquished.postMultScale(s);
        unsquished.postMult(tmps);
        unsquished.postMultRotate(r);
        unsquished.postMultTranslate(t);
        osg::Matrix invltw;
        if (!invltw.invert(LTW))
        {
            flag = false;
            return osg::Matrix::identity();
        }
        unsquished.postMult( invltw );
    }

    if (unsquished.isNaN())
    {
        flag = false;
        return  osg::Matrix::identity();
    }

    flag = true;
    _dirty = false;
    return unsquished;
}

<|endoftext|>