<commit_before>#ifndef SequenceVerificationExpectation_hpp_
#define SequenceVerificationExpectation_hpp_

#include "fakeit/FakeitExceptions.hpp"
#include "mockutils/smart_ptr.hpp"

namespace fakeit {

struct SequenceVerificationExpectation {

	friend class SequenceVerificationProgress;

	~SequenceVerificationExpectation() THROWS{
		if (std::uncaught_exception()) {
			return;
		}
		VerifyExpectation();
	}

	template<typename ... list>
	void setExpectedPattern(const Sequence& sequence, const list&... tail) {
		collectSequences(_expectedPattern, sequence, tail...);
	}

	void setExpectedCount(const int count) {
		_expectedCount = count;
	}

	void setFileInfo(std::string file, int line, std::string callingMethod) {
		_file = file;
		_line = line;
		_testMethod = callingMethod;
	}

private:

	std::set<const ActualInvocationsSource*> _involvedMocks;
	std::vector<Sequence*> _expectedPattern;
	int _expectedCount;

	std::string _file;
	int _line;
	std::string _testMethod;

	SequenceVerificationExpectation(std::set<const ActualInvocationsSource*>& mocks) : //
		_involvedMocks{ mocks }, //
		_expectedPattern{}, //
		_expectedCount(-1), //
		_line(0) {
	}

	void VerifyExpectation()
	{
		std::unordered_set<Invocation*> actualIvocations;
		collectActualInvocations(_expectedPattern, actualIvocations);

		std::vector<Invocation*> actualSequence;
		sortByInvocationOrder(actualIvocations, actualSequence);

		std::vector<Invocation*> matchedInvocations;
		int count = countMatches(_expectedPattern, actualSequence, matchedInvocations);

		if (isAtLeastVerification() && atLeastLimitNotReached(count)) {
			throwAtLeastVerificationException(actualSequence, count);
		}

		if (isExactVerification() && exactLimitNotMatched(count)) {
			throwExactVerificationException(actualSequence, count);
		}

		markAsVerified(matchedInvocations);
	}

	static inline int AT_LEAST_ONCE() {
		return -1;
	}

	std::vector<Sequence*>& collectSequences(std::vector<Sequence*>& vec) {
		return vec;
	}

	template<typename ... list>
	std::vector<Sequence*>& collectSequences(std::vector<Sequence*>& vec, const Sequence& sequence, const list&... tail) {
		vec.push_back(&const_cast<Sequence&>(sequence));
		return collectSequences(vec, tail...);
	}

	void collectActualInvocations(std::vector<Sequence*>& expectedPattern, std::unordered_set<Invocation*>& actualIvocations) {
		for (auto mock : _involvedMocks) {
			mock->getActualInvocations(actualIvocations);
		}
	}

	void markAsVerified(std::vector<Invocation*>& matchedInvocations) {
		for (auto i : matchedInvocations)
			i->markAsVerified();
	}

	int countMatches(std::vector<Sequence*> &pattern, std::vector<Invocation*>& actualSequence,
		std::vector<Invocation*>& matchedInvocations) {
		int end = -1;
		int count = 0;
		int startSearchIndex = 0;
		while (findNextMatch(pattern, actualSequence, startSearchIndex, end, matchedInvocations)) {
			count++;
			startSearchIndex = end;
		}
		return count;
	}

	void collectMatchedInvocations(std::vector<Invocation*>& actualSequence, std::vector<Invocation*>& matchedInvocations, int start,
		int length) {
		int indexAfterMatchedPattern = start + length;
		for (; start < indexAfterMatchedPattern; start++) {
			matchedInvocations.push_back(actualSequence[start]);
		}
	}

	bool findNextMatch(std::vector<Sequence*> &pattern, std::vector<Invocation*>& actualSequence, int startSearchIndex, int& end,
		std::vector<Invocation*>& matchedInvocations) {
		for (auto sequence : pattern) {
			int index = findNextMatch(sequence, actualSequence, startSearchIndex);
			if (index == -1) {
				return false;
			}
			collectMatchedInvocations(actualSequence, matchedInvocations, index, sequence->size());
			startSearchIndex = index + sequence->size();
		}
		end = startSearchIndex;
		return true;
	}

	bool isMatch(std::vector<Invocation*>& actualSequence, std::vector<Invocation::Matcher*>& expectedSequence, int start) {
		bool found = true;
		for (unsigned int j = 0; found && j < expectedSequence.size(); j++) {
			Invocation* actual = actualSequence[start + j];
			Invocation::Matcher* expected = expectedSequence[j];
			found = found && expected->matches(*actual);
		}
		return found;
	}

	int findNextMatch(Sequence* &pattern, std::vector<Invocation*>& actualSequence, int startSearchIndex) {
		std::vector<Invocation::Matcher*> expectedSequence;
		pattern->getExpectedSequence(expectedSequence);
		for (int i = startSearchIndex; i < ((int) actualSequence.size() - (int) expectedSequence.size() + 1); i++) {
			if (isMatch(actualSequence, expectedSequence, i)) {
				return i;
			}
		}
		return -1;
	}

	bool isAtLeastVerification() {
		// negative number represents an "AtLeast" search;
		return _expectedCount < 0;
	}

	bool isExactVerification() {
		return !isAtLeastVerification();
	}

	bool atLeastLimitNotReached(int count) {
		return count < -_expectedCount;
	}

	bool exactLimitNotMatched(int count) {
		return count != _expectedCount;
	}

	void throwExactVerificationException(std::vector<Invocation*> actualSequence, int count) {
		struct ExactVerificationException : public SequenceVerificationException {

			ExactVerificationException(std::vector<Sequence*>& expectedPattern, std::vector<Invocation*>& actualSequence,
			int expectedCount, int actualCount) :
			SequenceVerificationException(expectedPattern, actualSequence, expectedCount, actualCount) {
			}

			virtual VerificationType verificationType()const override {
				return VerificationType::Exact;
			}
		};

		ExactVerificationException e(_expectedPattern, actualSequence, _expectedCount, count);
		e.setFileInfo(_file, _line, _testMethod);
		fakeit::FakeIt::handle(e);
		throw e;
	}

	void throwAtLeastVerificationException(std::vector<Invocation*> actualSequence, int count) {
		struct AtLeastVerificationException : public SequenceVerificationException {
			AtLeastVerificationException(std::vector<Sequence*>& expectedPattern, std::vector<Invocation*>& actualSequence,
			int expectedCount, int actualCount) :
			SequenceVerificationException(expectedPattern, actualSequence, expectedCount, actualCount) {
			}

			virtual VerificationType verificationType()const override {
				return VerificationType::AtLeast;
			}
		};

		AtLeastVerificationException e(_expectedPattern, actualSequence, -_expectedCount, count);
		e.setFileInfo(_file, _line, _testMethod);
		FakeIt::handle(e);
		throw e;
	}

};

}

#endif
<commit_msg>yet another try<commit_after>#ifndef SequenceVerificationExpectation_hpp_
#define SequenceVerificationExpectation_hpp_

#include "fakeit/FakeitExceptions.hpp"
#include "mockutils/smart_ptr.hpp"

namespace fakeit {

struct SequenceVerificationExpectation {

	friend class SequenceVerificationProgress;

	~SequenceVerificationExpectation() THROWS{
		if (std::uncaught_exception()) {
			return;
		}
		VerifyExpectation();
	}

	template<typename ... list>
	void setExpectedPattern(const Sequence& sequence, const list&... tail) {
		collectSequences(_expectedPattern, sequence, tail...);
	}

	void setExpectedCount(const int count) {
		_expectedCount = count;
	}

	void setFileInfo(std::string file, int line, std::string callingMethod) {
		_file = file;
		_line = line;
		_testMethod = callingMethod;
	}

private:

	std::set<const ActualInvocationsSource*> _involvedMocks;
	std::vector<Sequence*> _expectedPattern;
	int _expectedCount;

	std::string _file;
	int _line;
	std::string _testMethod;

	SequenceVerificationExpectation(std::set<const ActualInvocationsSource*>& mocks) : //
		_involvedMocks( mocks ), //
		_expectedPattern(), //
		_expectedCount(-1), //
		_line(0) {
	}

	void VerifyExpectation()
	{
		std::unordered_set<Invocation*> actualIvocations;
		collectActualInvocations(_expectedPattern, actualIvocations);

		std::vector<Invocation*> actualSequence;
		sortByInvocationOrder(actualIvocations, actualSequence);

		std::vector<Invocation*> matchedInvocations;
		int count = countMatches(_expectedPattern, actualSequence, matchedInvocations);

		if (isAtLeastVerification() && atLeastLimitNotReached(count)) {
			throwAtLeastVerificationException(actualSequence, count);
		}

		if (isExactVerification() && exactLimitNotMatched(count)) {
			throwExactVerificationException(actualSequence, count);
		}

		markAsVerified(matchedInvocations);
	}

	static inline int AT_LEAST_ONCE() {
		return -1;
	}

	std::vector<Sequence*>& collectSequences(std::vector<Sequence*>& vec) {
		return vec;
	}

	template<typename ... list>
	std::vector<Sequence*>& collectSequences(std::vector<Sequence*>& vec, const Sequence& sequence, const list&... tail) {
		vec.push_back(&const_cast<Sequence&>(sequence));
		return collectSequences(vec, tail...);
	}

	void collectActualInvocations(std::vector<Sequence*>& expectedPattern, std::unordered_set<Invocation*>& actualIvocations) {
		for (auto mock : _involvedMocks) {
			mock->getActualInvocations(actualIvocations);
		}
	}

	void markAsVerified(std::vector<Invocation*>& matchedInvocations) {
		for (auto i : matchedInvocations)
			i->markAsVerified();
	}

	int countMatches(std::vector<Sequence*> &pattern, std::vector<Invocation*>& actualSequence,
		std::vector<Invocation*>& matchedInvocations) {
		int end = -1;
		int count = 0;
		int startSearchIndex = 0;
		while (findNextMatch(pattern, actualSequence, startSearchIndex, end, matchedInvocations)) {
			count++;
			startSearchIndex = end;
		}
		return count;
	}

	void collectMatchedInvocations(std::vector<Invocation*>& actualSequence, std::vector<Invocation*>& matchedInvocations, int start,
		int length) {
		int indexAfterMatchedPattern = start + length;
		for (; start < indexAfterMatchedPattern; start++) {
			matchedInvocations.push_back(actualSequence[start]);
		}
	}

	bool findNextMatch(std::vector<Sequence*> &pattern, std::vector<Invocation*>& actualSequence, int startSearchIndex, int& end,
		std::vector<Invocation*>& matchedInvocations) {
		for (auto sequence : pattern) {
			int index = findNextMatch(sequence, actualSequence, startSearchIndex);
			if (index == -1) {
				return false;
			}
			collectMatchedInvocations(actualSequence, matchedInvocations, index, sequence->size());
			startSearchIndex = index + sequence->size();
		}
		end = startSearchIndex;
		return true;
	}

	bool isMatch(std::vector<Invocation*>& actualSequence, std::vector<Invocation::Matcher*>& expectedSequence, int start) {
		bool found = true;
		for (unsigned int j = 0; found && j < expectedSequence.size(); j++) {
			Invocation* actual = actualSequence[start + j];
			Invocation::Matcher* expected = expectedSequence[j];
			found = found && expected->matches(*actual);
		}
		return found;
	}

	int findNextMatch(Sequence* &pattern, std::vector<Invocation*>& actualSequence, int startSearchIndex) {
		std::vector<Invocation::Matcher*> expectedSequence;
		pattern->getExpectedSequence(expectedSequence);
		for (int i = startSearchIndex; i < ((int) actualSequence.size() - (int) expectedSequence.size() + 1); i++) {
			if (isMatch(actualSequence, expectedSequence, i)) {
				return i;
			}
		}
		return -1;
	}

	bool isAtLeastVerification() {
		// negative number represents an "AtLeast" search;
		return _expectedCount < 0;
	}

	bool isExactVerification() {
		return !isAtLeastVerification();
	}

	bool atLeastLimitNotReached(int count) {
		return count < -_expectedCount;
	}

	bool exactLimitNotMatched(int count) {
		return count != _expectedCount;
	}

	void throwExactVerificationException(std::vector<Invocation*> actualSequence, int count) {
		struct ExactVerificationException : public SequenceVerificationException {

			ExactVerificationException(std::vector<Sequence*>& expectedPattern, std::vector<Invocation*>& actualSequence,
			int expectedCount, int actualCount) :
			SequenceVerificationException(expectedPattern, actualSequence, expectedCount, actualCount) {
			}

			virtual VerificationType verificationType()const override {
				return VerificationType::Exact;
			}
		};

		ExactVerificationException e(_expectedPattern, actualSequence, _expectedCount, count);
		e.setFileInfo(_file, _line, _testMethod);
		fakeit::FakeIt::handle(e);
		throw e;
	}

	void throwAtLeastVerificationException(std::vector<Invocation*> actualSequence, int count) {
		struct AtLeastVerificationException : public SequenceVerificationException {
			AtLeastVerificationException(std::vector<Sequence*>& expectedPattern, std::vector<Invocation*>& actualSequence,
			int expectedCount, int actualCount) :
			SequenceVerificationException(expectedPattern, actualSequence, expectedCount, actualCount) {
			}

			virtual VerificationType verificationType()const override {
				return VerificationType::AtLeast;
			}
		};

		AtLeastVerificationException e(_expectedPattern, actualSequence, -_expectedCount, count);
		e.setFileInfo(_file, _line, _testMethod);
		FakeIt::handle(e);
		throw e;
	}

};

}

#endif
<|endoftext|>


<commit_before>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "skin.h"
#include "utils/polygonUtils.h"

#define MIN_AREA_SIZE (0.4 * 0.4)

namespace cura
{

void generateSkins(int layerNr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount, int innermost_wall_extrusion_width, int insetCount, bool no_small_gaps_heuristic, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    generateSkinAreas(layerNr, storage, innermost_wall_extrusion_width, downSkinCount, upSkinCount, no_small_gaps_heuristic);

    SliceLayer* layer = &storage.layers[layerNr];
    for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
    {
        SliceLayerPart* part = &layer->parts[partNr];
        generateSkinInsets(part, extrusionWidth, insetCount, avoidOverlappingPerimeters_0, avoidOverlappingPerimeters);
    }
}

void generateSkinAreas(int layer_nr, SliceMeshStorage& storage, int innermost_wall_extrusion_width, int downSkinCount, int upSkinCount, bool no_small_gaps_heuristic)
{
    SliceLayer& layer = storage.layers[layer_nr];

    if (downSkinCount == 0 && upSkinCount == 0)
    {
        return;
    }

    for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
    {
        SliceLayerPart& part = layer.parts[partNr];

        Polygons upskin = part.insets.back().offset(-innermost_wall_extrusion_width/2);
        Polygons downskin = (downSkinCount == 0)? Polygons() : upskin;
        if (upSkinCount == 0) upskin = Polygons();

        auto getInsidePolygons = [&part](SliceLayer& layer2)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2.parts)
                {
                    if (part.boundaryBox.hit(part2.boundaryBox))
                        result.add(part2.insets.back());
                }
                return result;
            };

        if (no_small_gaps_heuristic)
        {
            if (static_cast<int>(layer_nr - downSkinCount) >= 0)
            {
                downskin = downskin.difference(getInsidePolygons(storage.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
            }

            if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(storage.layers.size()))
            {
                upskin = upskin.difference(getInsidePolygons(storage.layers[layer_nr + upSkinCount])); // skin overlaps with the walls
            }
        }
        else
        {
            if (layer_nr > 0 && downSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr - 1]);
                for (int downskin_layer_nr = std::max(0, layer_nr - downSkinCount); downskin_layer_nr < layer_nr - 1; downskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[downskin_layer_nr]));
                }
                downskin = downskin.difference(not_air); // skin overlaps with the walls
            }

            if (layer_nr < static_cast<int>(storage.layers.size()) - 1 && upSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr + 1]);
                for (int upskin_layer_nr = layer_nr + 2; upskin_layer_nr < std::min(static_cast<int>(storage.layers.size()) - 1, layer_nr + upSkinCount); upskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[upskin_layer_nr]));
                }
                upskin = upskin.difference(not_air); // skin overlaps with the walls
            }
        }

        Polygons skin = upskin.unionPolygons(downskin);

        skin.removeSmallAreas(MIN_AREA_SIZE);

        for (PolygonsPart& skin_area_part : skin.splitIntoParts())
        {
            part.skin_parts.emplace_back();
            part.skin_parts.back().outline = skin_area_part;
        }
    }
}

void generateSkinInsets(SliceLayerPart* part, int extrusionWidth, int insetCount, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    if (insetCount == 0)
    {
        return;
    }

    for (SkinPart& skin_part : part->skin_parts)
    {
        for(int i=0; i<insetCount; i++)
        {
            skin_part.insets.push_back(Polygons());
            if (i == 0)
            {
                PolygonUtils::offsetSafe(skin_part.outline, - extrusionWidth/2, extrusionWidth, skin_part.insets[0], avoidOverlappingPerimeters_0);
                Polygons in_between = skin_part.outline.difference(skin_part.insets[0].offset(extrusionWidth/2));
                skin_part.perimeterGaps.add(in_between);
            } else
            {
                PolygonUtils::offsetExtrusionWidth(skin_part.insets[i-1], true, extrusionWidth, skin_part.insets[i], &skin_part.perimeterGaps, avoidOverlappingPerimeters);
            }

            // optimize polygons: remove unnnecesary verts
            skin_part.insets[i].simplify();
            if (skin_part.insets[i].size() < 1)
            {
                skin_part.insets.pop_back();
                break;
            }
        }
    }
}

void generateInfill(int layerNr, SliceMeshStorage& storage, int extrusionWidth, int infill_skin_overlap)
{
    SliceLayer& layer = storage.layers[layerNr];

    for(SliceLayerPart& part : layer.parts)
    {
        Polygons infill = part.insets.back().offset(-extrusionWidth / 2 - infill_skin_overlap);

        for(SliceLayerPart& part2 : layer.parts)
        {
            if (part.boundaryBox.hit(part2.boundaryBox))
            {
                for(SkinPart& skin_part : part2.skin_parts)
                {
                    infill = infill.difference(skin_part.outline);
                }
            }
        }
        infill.removeSmallAreas(MIN_AREA_SIZE);

        part.infill_area.push_back(infill.offset(infill_skin_overlap));
    }
}

void combineInfillLayers(SliceMeshStorage& storage,unsigned int amount)
{
    amount = std::max(amount,1u);
    if(storage.layers.empty() || storage.layers.size() - 1 < (size_t)storage.getSettingAsCount("top_layers") || storage.getSettingAsCount("infill_line_distance") <= 0) //No infill is even generated.
    {
        return;
    }
    /* We need to round down the layer index we start at to the nearest
    divisible index. Otherwise we get some parts that have infill at divisible
    layers and some at non-divisible layers. Those layers would then miss each
    other. */
    size_t min_layer = storage.getSettingAsCount("bottom_layers") + amount - 1;
    min_layer -= min_layer % amount; //Round upwards to the nearest layer divisible by infill_sparse_combine.
    size_t max_layer = storage.layers.size() - 1 - storage.getSettingAsCount("top_layers");
    max_layer -= max_layer % amount; //Round downwards to the nearest layer divisible by infill_sparse_combine.
    for(size_t layer_idx = min_layer;layer_idx <= max_layer;layer_idx += amount) //Skip every few layers, but extrude more.
    {
        SliceLayer* layer = &storage.layers[layer_idx];

        for(unsigned int n = 1;n < amount;n++)
        {
            if(layer_idx < n)
            {
                break;
            }

            SliceLayer* layer2 = &storage.layers[layer_idx - n];
            for(SliceLayerPart& part : layer->parts)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2->parts)
                {
                    if(part.boundaryBox.hit(part2.boundaryBox))
                    {
                        Polygons intersection = part.infill_area[n - 1].intersection(part2.infill_area[0]).offset(-200).offset(200);
                        result.add(intersection);
                        part.infill_area[n - 1] = part.infill_area[n - 1].difference(intersection);
                        part2.infill_area[0] = part2.infill_area[0].difference(intersection);
                    }
                }

                part.infill_area.push_back(result);
            }
        }
    }
}

void generatePerimeterGaps(int layer_nr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount)
{
    SliceLayer& layer = storage.layers[layer_nr];

    for (SliceLayerPart& part : layer.parts)
    { // handle gaps between perimeters etc.
        if (downSkinCount > 0 && upSkinCount > 0 && // note: if both are zero or less, then all gaps will be used
            layer_nr >= downSkinCount && layer_nr < static_cast<int>(storage.layers.size() - upSkinCount)) // remove gaps which appear within print, i.e. not on the bottom most or top most skin
        {
            Polygons outlines_above;
            for (SliceLayerPart& part_above : storage.layers[layer_nr + upSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_above.boundaryBox))
                {
                    outlines_above.add(part_above.outline);
                }
            }
            Polygons outlines_below;
            for (SliceLayerPart& part_below : storage.layers[layer_nr - downSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_below.boundaryBox))
                {
                    outlines_below.add(part_below.outline);
                }
            }
            part.perimeterGaps = part.perimeterGaps.intersection(outlines_above.xorPolygons(outlines_below));
        }
        part.perimeterGaps.removeSmallAreas(MIN_AREA_SIZE);
    }
}

}//namespace cura
<commit_msg>combineInfillLayers to stop if combining 1 or 0 layers<commit_after>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "skin.h"
#include "utils/polygonUtils.h"

#define MIN_AREA_SIZE (0.4 * 0.4)

namespace cura
{

void generateSkins(int layerNr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount, int innermost_wall_extrusion_width, int insetCount, bool no_small_gaps_heuristic, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    generateSkinAreas(layerNr, storage, innermost_wall_extrusion_width, downSkinCount, upSkinCount, no_small_gaps_heuristic);

    SliceLayer* layer = &storage.layers[layerNr];
    for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
    {
        SliceLayerPart* part = &layer->parts[partNr];
        generateSkinInsets(part, extrusionWidth, insetCount, avoidOverlappingPerimeters_0, avoidOverlappingPerimeters);
    }
}

void generateSkinAreas(int layer_nr, SliceMeshStorage& storage, int innermost_wall_extrusion_width, int downSkinCount, int upSkinCount, bool no_small_gaps_heuristic)
{
    SliceLayer& layer = storage.layers[layer_nr];

    if (downSkinCount == 0 && upSkinCount == 0)
    {
        return;
    }

    for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
    {
        SliceLayerPart& part = layer.parts[partNr];

        Polygons upskin = part.insets.back().offset(-innermost_wall_extrusion_width/2);
        Polygons downskin = (downSkinCount == 0)? Polygons() : upskin;
        if (upSkinCount == 0) upskin = Polygons();

        auto getInsidePolygons = [&part](SliceLayer& layer2)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2.parts)
                {
                    if (part.boundaryBox.hit(part2.boundaryBox))
                        result.add(part2.insets.back());
                }
                return result;
            };

        if (no_small_gaps_heuristic)
        {
            if (static_cast<int>(layer_nr - downSkinCount) >= 0)
            {
                downskin = downskin.difference(getInsidePolygons(storage.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
            }

            if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(storage.layers.size()))
            {
                upskin = upskin.difference(getInsidePolygons(storage.layers[layer_nr + upSkinCount])); // skin overlaps with the walls
            }
        }
        else
        {
            if (layer_nr > 0 && downSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr - 1]);
                for (int downskin_layer_nr = std::max(0, layer_nr - downSkinCount); downskin_layer_nr < layer_nr - 1; downskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[downskin_layer_nr]));
                }
                downskin = downskin.difference(not_air); // skin overlaps with the walls
            }

            if (layer_nr < static_cast<int>(storage.layers.size()) - 1 && upSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr + 1]);
                for (int upskin_layer_nr = layer_nr + 2; upskin_layer_nr < std::min(static_cast<int>(storage.layers.size()) - 1, layer_nr + upSkinCount); upskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[upskin_layer_nr]));
                }
                upskin = upskin.difference(not_air); // skin overlaps with the walls
            }
        }

        Polygons skin = upskin.unionPolygons(downskin);

        skin.removeSmallAreas(MIN_AREA_SIZE);

        for (PolygonsPart& skin_area_part : skin.splitIntoParts())
        {
            part.skin_parts.emplace_back();
            part.skin_parts.back().outline = skin_area_part;
        }
    }
}

void generateSkinInsets(SliceLayerPart* part, int extrusionWidth, int insetCount, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    if (insetCount == 0)
    {
        return;
    }

    for (SkinPart& skin_part : part->skin_parts)
    {
        for(int i=0; i<insetCount; i++)
        {
            skin_part.insets.push_back(Polygons());
            if (i == 0)
            {
                PolygonUtils::offsetSafe(skin_part.outline, - extrusionWidth/2, extrusionWidth, skin_part.insets[0], avoidOverlappingPerimeters_0);
                Polygons in_between = skin_part.outline.difference(skin_part.insets[0].offset(extrusionWidth/2));
                skin_part.perimeterGaps.add(in_between);
            } else
            {
                PolygonUtils::offsetExtrusionWidth(skin_part.insets[i-1], true, extrusionWidth, skin_part.insets[i], &skin_part.perimeterGaps, avoidOverlappingPerimeters);
            }

            // optimize polygons: remove unnnecesary verts
            skin_part.insets[i].simplify();
            if (skin_part.insets[i].size() < 1)
            {
                skin_part.insets.pop_back();
                break;
            }
        }
    }
}

void generateInfill(int layerNr, SliceMeshStorage& storage, int extrusionWidth, int infill_skin_overlap)
{
    SliceLayer& layer = storage.layers[layerNr];

    for(SliceLayerPart& part : layer.parts)
    {
        Polygons infill = part.insets.back().offset(-extrusionWidth / 2 - infill_skin_overlap);

        for(SliceLayerPart& part2 : layer.parts)
        {
            if (part.boundaryBox.hit(part2.boundaryBox))
            {
                for(SkinPart& skin_part : part2.skin_parts)
                {
                    infill = infill.difference(skin_part.outline);
                }
            }
        }
        infill.removeSmallAreas(MIN_AREA_SIZE);

        part.infill_area.push_back(infill.offset(infill_skin_overlap));
    }
}

void combineInfillLayers(SliceMeshStorage& storage,unsigned int amount)
{
    if(amount <= 1) //If we must combine 1 layer, nothing needs to be combined. Combining 0 layers is invalid.
    {
        return;
    }
    if(storage.layers.empty() || storage.layers.size() - 1 < (size_t)storage.getSettingAsCount("top_layers") || storage.getSettingAsCount("infill_line_distance") <= 0) //No infill is even generated.
    {
        return;
    }
    /* We need to round down the layer index we start at to the nearest
    divisible index. Otherwise we get some parts that have infill at divisible
    layers and some at non-divisible layers. Those layers would then miss each
    other. */
    size_t min_layer = storage.getSettingAsCount("bottom_layers") + amount - 1;
    min_layer -= min_layer % amount; //Round upwards to the nearest layer divisible by infill_sparse_combine.
    size_t max_layer = storage.layers.size() - 1 - storage.getSettingAsCount("top_layers");
    max_layer -= max_layer % amount; //Round downwards to the nearest layer divisible by infill_sparse_combine.
    for(size_t layer_idx = min_layer;layer_idx <= max_layer;layer_idx += amount) //Skip every few layers, but extrude more.
    {
        SliceLayer* layer = &storage.layers[layer_idx];

        for(unsigned int n = 1;n < amount;n++)
        {
            if(layer_idx < n)
            {
                break;
            }

            SliceLayer* layer2 = &storage.layers[layer_idx - n];
            for(SliceLayerPart& part : layer->parts)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2->parts)
                {
                    if(part.boundaryBox.hit(part2.boundaryBox))
                    {
                        Polygons intersection = part.infill_area[n - 1].intersection(part2.infill_area[0]).offset(-200).offset(200);
                        result.add(intersection);
                        part.infill_area[n - 1] = part.infill_area[n - 1].difference(intersection);
                        part2.infill_area[0] = part2.infill_area[0].difference(intersection);
                    }
                }

                part.infill_area.push_back(result);
            }
        }
    }
}

void generatePerimeterGaps(int layer_nr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount)
{
    SliceLayer& layer = storage.layers[layer_nr];

    for (SliceLayerPart& part : layer.parts)
    { // handle gaps between perimeters etc.
        if (downSkinCount > 0 && upSkinCount > 0 && // note: if both are zero or less, then all gaps will be used
            layer_nr >= downSkinCount && layer_nr < static_cast<int>(storage.layers.size() - upSkinCount)) // remove gaps which appear within print, i.e. not on the bottom most or top most skin
        {
            Polygons outlines_above;
            for (SliceLayerPart& part_above : storage.layers[layer_nr + upSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_above.boundaryBox))
                {
                    outlines_above.add(part_above.outline);
                }
            }
            Polygons outlines_below;
            for (SliceLayerPart& part_below : storage.layers[layer_nr - downSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_below.boundaryBox))
                {
                    outlines_below.add(part_below.outline);
                }
            }
            part.perimeterGaps = part.perimeterGaps.intersection(outlines_above.xorPolygons(outlines_below));
        }
        part.perimeterGaps.removeSmallAreas(MIN_AREA_SIZE);
    }
}

}//namespace cura
<|endoftext|>


<commit_before>#include <iostream>
#include "constants.hpp"
#include "parameters.hpp"
#include "matprops.hpp"
#include "utils.hpp"
#include "fields.hpp"

void allocate_variables(const Param &param, Variables& var)
{
    const int n = var.nnode;
    const int e = var.nelem;

    var.volume = new double_vec(e);
    var.temperature = new double_vec(n);

    var.shpdx = new shapefn(e);
    var.shpdz = new shapefn(e);

    var.mat = new MatProps(param, var);
}

void update_temperature(const Param &param, const Variables &var,
                        double_vec &temperature, double_vec &tdot)
{

    // To be completed

}<commit_msg>implemented a test solver.<commit_after>#include <iostream>
#include "constants.hpp"
#include "parameters.hpp"
#include "matprops.hpp"
#include "utils.hpp"
#include "fields.hpp"

void allocate_variables(const Param &param, Variables& var)
{
    const int n = var.nnode;
    const int e = var.nelem;

    var.volume = new double_vec(e);
    var.temperature = new double_vec(n);

    var.shpdx = new shapefn(e);
    var.shpdz = new shapefn(e);

    var.mat = new MatProps(param, var);
}

void update_temperature(const Param &param, const Variables &var,
                        double_vec &temperature, double_vec &tdot)
{

    // To be completed
	double *A, *b, *x;
	A = (double *)(malloc(N*N*(sizeof(double))));
	b = (double *)(malloc(N*(sizeof(double))));
	x = (double *)(malloc(N*(sizeof(double))));

	solver_cg(A, b, x);

	// store x
}<|endoftext|>


<commit_before>#ifndef ITER_FILTER_H_
#define ITER_FILTER_H_

#include "internal/iterator_wrapper.hpp"
#include "internal/iterbase.hpp"

#include <initializer_list>
#include <iterator>
#include <utility>

namespace iter {
  namespace impl {
    template <typename FilterFunc, typename Container>
    class Filtered;

    struct BoolTester {
      template <typename T>
      constexpr bool operator()(const T& item) const {
        return bool(item);
      }
    };

    using FilterFn = IterToolFnOptionalBindFirst<Filtered, BoolTester>;
  }

  constexpr impl::FilterFn filter{};
}

template <typename FilterFunc, typename Container>
class iter::impl::Filtered {
 private:
  Container container;
  FilterFunc filter_func;

  friend FilterFn;

 protected:
  // Value constructor for use only in the filter function
  Filtered(FilterFunc in_filter_func, Container&& in_container)
      : container(std::forward<Container>(in_container)),
        filter_func(in_filter_func) {}

 public:
  Filtered(Filtered&&) = default;

  class Iterator : public std::iterator<std::input_iterator_tag,
                       iterator_traits_deref<Container>> {
   protected:
    using Holder = DerefHolder<iterator_deref<Container>>;
    IteratorWrapper<Container> sub_iter;
    IteratorWrapper<Container> sub_end;
    Holder item;
    FilterFunc* filter_func;

    void inc_sub_iter() {
      ++this->sub_iter;
      if (this->sub_iter != this->sub_end) {
        this->item.reset(*this->sub_iter);
      }
    }

    // increment until the iterator points to is true on the
    // predicate.  Called by constructor and operator++
    void skip_failures() {
      while (this->sub_iter != this->sub_end
             && !(*this->filter_func)(this->item.get())) {
        this->inc_sub_iter();
      }
    }

   public:
    Iterator(IteratorWrapper<Container>&& iter,
        IteratorWrapper<Container>&& end, FilterFunc& in_filter_func)
        : sub_iter{std::move(iter)},
          sub_end{std::move(end)},
          filter_func(&in_filter_func) {
      if (this->sub_iter != this->sub_end) {
        this->item.reset(*this->sub_iter);
      }
      this->skip_failures();
    }

    typename Holder::reference operator*() {
      return this->item.get();
    }

    typename Holder::pointer operator->() {
      return this->item.get_ptr();
    }

    Iterator& operator++() {
      this->inc_sub_iter();
      this->skip_failures();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container),
        this->filter_func};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container),
        this->filter_func};
  }
};

#endif
<commit_msg>trailing _ on data members<commit_after>#ifndef ITER_FILTER_H_
#define ITER_FILTER_H_

#include "internal/iterator_wrapper.hpp"
#include "internal/iterbase.hpp"

#include <initializer_list>
#include <iterator>
#include <utility>

namespace iter {
  namespace impl {
    template <typename FilterFunc, typename Container>
    class Filtered;

    struct BoolTester {
      template <typename T>
      constexpr bool operator()(const T& item_) const {
        return bool(item_);
      }
    };

    using FilterFn = IterToolFnOptionalBindFirst<Filtered, BoolTester>;
  }

  constexpr impl::FilterFn filter{};
}

template <typename FilterFunc, typename Container>
class iter::impl::Filtered {
 private:
  Container container_;
  FilterFunc filter_func_;

  friend FilterFn;

 protected:
  // Value constructor for use only in the filter function
  Filtered(FilterFunc filter_func, Container&& container)
      : container_(std::forward<Container>(container)),
        filter_func_(filter_func) {}

 public:
  Filtered(Filtered&&) = default;

  class Iterator : public std::iterator<std::input_iterator_tag,
                       iterator_traits_deref<Container>> {
   protected:
    using Holder = DerefHolder<iterator_deref<Container>>;
    IteratorWrapper<Container> sub_iter_;
    IteratorWrapper<Container> sub_end_;
    Holder item_;
    FilterFunc* filter_func_;

    void inc_sub_iter() {
      ++sub_iter_;
      if (sub_iter_ != sub_end_) {
        item_.reset(*sub_iter_);
      }
    }

    // increment until the iterator points to is true on the
    // predicate.  Called by constructor and operator++
    void skip_failures() {
      while (sub_iter_ != sub_end_ && !(*filter_func_)(item_.get())) {
        inc_sub_iter();
      }
    }

   public:
    Iterator(IteratorWrapper<Container>&& sub_iter,
        IteratorWrapper<Container>&& sub_end, FilterFunc& filter_func)
        : sub_iter_{std::move(sub_iter)},
          sub_end_{std::move(sub_end)},
          filter_func_(&filter_func) {
      if (sub_iter_ != sub_end_) {
        item_.reset(*sub_iter_);
      }
      skip_failures();
    }

    typename Holder::reference operator*() {
      return item_.get();
    }

    typename Holder::pointer operator->() {
      return item_.get_ptr();
    }

    Iterator& operator++() {
      inc_sub_iter();
      skip_failures();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return sub_iter_ != other.sub_iter_;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(container_), std::end(container_), filter_func_};
  }

  Iterator end() {
    return {std::end(container_), std::end(container_), filter_func_};
  }
};

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "eventReceiver.h"
#include "java_id.h"
#include "variant.h"

JClassID com4jEventProxy("com4j/EventProxy");
JMethodID<jintArray> com4jEventProxy_getDISPIDs(com4jEventProxy,"getDISPIDs","([Ljava/lang/String;)[I");
JMethodID<jobject> com4jEventProxy_invoke(com4jEventProxy,"invoke","(II[Lcom4j/Variant;)Ljava/lang/Object;");
JStaticMethodID<jstring> com4jEventProxy_getErrorSource(com4jEventProxy,"getErrorSource","(Ljava/lang/Throwable;)Ljava/lang/String;");
JStaticMethodID<jstring> com4jEventProxy_getErrorDetail(com4jEventProxy,"getErrorDetail","(Ljava/lang/Throwable;)Ljava/lang/String;");

STDMETHODIMP CEventReceiver::GetIDsOfNames( REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId ) {
	AttachThread jniScope(jniModule);
	JNIEnv* pEnv = jniScope;

	bool unknown = false;

	LockedArray<jint> r(pEnv, com4jEventProxy_getDISPIDs( pEnv, eventProxy ));
	for(unsigned int i=0; i<cNames; i++ ) {
		*rgDispId++ = r[i];
		if(r[i]==DISPID_UNKNOWN)
			unknown = true;
	}

	return unknown? DISP_E_UNKNOWNNAME : S_OK;
}

STDMETHODIMP CEventReceiver::Invoke( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pResult, EXCEPINFO* pExcepInfo, UINT* puArgErr ) {
	AttachThread jniScope(jniModule);
	JNIEnv* pEnv = jniScope;

	jobjectArray ar = pEnv->NewObjectArray(pDispParams->cArgs,com4j_Variant,NULL);

	{// copy arguments into com4j Variant types, since we may later change their types
		LockedArray<jobject> data(pEnv,ar);
		int len = pDispParams->cArgs;
		for( int i=0; i<len; i++ ) {
			data[len-i-1] = com4j_Variant_new(pEnv);
			::VariantCopy(com4jVariantToVARIANT(pEnv,data[len-i-1]), &pDispParams->rgvarg[i]);
		}
	}

	jobject r = com4jEventProxy_invoke(pEnv,eventProxy, (jint)dispid,(jint)wFlags,ar);

	// check if there was any exception
	jthrowable t = pEnv->ExceptionOccurred();
	if(t!=NULL) {
		pEnv->ExceptionClear();
		if(pExcepInfo!=NULL) {
			pExcepInfo->wCode = 1000;	// Java doesn't have any notion of 'error code'
			pExcepInfo->wReserved = 0;
			pExcepInfo->bstrSource		= SysAllocString(JString(pEnv,com4jEventProxy_getErrorSource(pEnv,t)));
			pExcepInfo->bstrDescription = SysAllocString(JString(pEnv,com4jEventProxy_getErrorDetail(pEnv,t)));
			pExcepInfo->bstrHelpFile = NULL;
			pExcepInfo->dwHelpContext = 0;
			pExcepInfo->pvReserved = NULL;
			pExcepInfo->pfnDeferredFillIn = NULL;
			pExcepInfo->scode = 0;
		}

		return DISP_E_EXCEPTION;
	}

	if(r!=NULL && pResult!=NULL) {
		VARIANT* pSrc = convertToVariant(pEnv,r);
		::VariantCopy(pResult,pSrc);
		::VariantClear(pSrc);
	}

	return S_OK;
}
<commit_msg>Send the message name array to java to prevent access violations<commit_after>#include "stdafx.h"
#include "eventReceiver.h"
#include "java_id.h"
#include "variant.h"

JClassID com4jEventProxy("com4j/EventProxy");
JMethodID<jintArray> com4jEventProxy_getDISPIDs(com4jEventProxy,"getDISPIDs","([Ljava/lang/String;)[I");
JMethodID<jobject> com4jEventProxy_invoke(com4jEventProxy,"invoke","(II[Lcom4j/Variant;)Ljava/lang/Object;");
JStaticMethodID<jstring> com4jEventProxy_getErrorSource(com4jEventProxy,"getErrorSource","(Ljava/lang/Throwable;)Ljava/lang/String;");
JStaticMethodID<jstring> com4jEventProxy_getErrorDetail(com4jEventProxy,"getErrorDetail","(Ljava/lang/Throwable;)Ljava/lang/String;");

STDMETHODIMP CEventReceiver::GetIDsOfNames( REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId ) {
	AttachThread jniScope(jniModule);
	JNIEnv* pEnv = jniScope;

	bool unknown = false;

	// Convert names to string array
	jobjectArray ar = pEnv->NewObjectArray(cNames,javaLangString, NULL);
	int len = cNames;
	for( int i=0; i < len; i++) {
		pEnv->SetObjectArrayElement( ar, i, pEnv->NewString( (jchar*)rgszNames[i], wcslen( rgszNames[i])));
	}

	LockedArray<jint> r(pEnv, com4jEventProxy_getDISPIDs( pEnv, eventProxy, ar));
	for(unsigned int i=0; i<cNames; i++ ) {
		*rgDispId++ = r[i];
		if(r[i]==DISPID_UNKNOWN)
			unknown = true;
	}

	return unknown? DISP_E_UNKNOWNNAME : S_OK;
}

STDMETHODIMP CEventReceiver::Invoke( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pResult, EXCEPINFO* pExcepInfo, UINT* puArgErr ) {
	AttachThread jniScope(jniModule);
	JNIEnv* pEnv = jniScope;

	jobjectArray ar = pEnv->NewObjectArray(pDispParams->cArgs,com4j_Variant,NULL);

	{// copy arguments into com4j Variant types, since we may later change their types
		LockedArray<jobject> data(pEnv,ar);
		int len = pDispParams->cArgs;
		for( int i=0; i<len; i++ ) {
			data[len-i-1] = com4j_Variant_new(pEnv);
			::VariantCopy(com4jVariantToVARIANT(pEnv,data[len-i-1]), &pDispParams->rgvarg[i]);
		}
	}

	jobject r = com4jEventProxy_invoke(pEnv,eventProxy, (jint)dispid,(jint)wFlags,ar);

	// check if there was any exception
	jthrowable t = pEnv->ExceptionOccurred();
	if(t!=NULL) {
		pEnv->ExceptionClear();
		if(pExcepInfo!=NULL) {
			pExcepInfo->wCode = 1000;	// Java doesn't have any notion of 'error code'
			pExcepInfo->wReserved = 0;
			pExcepInfo->bstrSource		= SysAllocString(JString(pEnv,com4jEventProxy_getErrorSource(pEnv,t)));
			pExcepInfo->bstrDescription = SysAllocString(JString(pEnv,com4jEventProxy_getErrorDetail(pEnv,t)));
			pExcepInfo->bstrHelpFile = NULL;
			pExcepInfo->dwHelpContext = 0;
			pExcepInfo->pvReserved = NULL;
			pExcepInfo->pfnDeferredFillIn = NULL;
			pExcepInfo->scode = 0;
		}

		return DISP_E_EXCEPTION;
	}

	if(r!=NULL && pResult!=NULL) {
		VARIANT* pSrc = convertToVariant(pEnv,r);
		::VariantCopy(pResult,pSrc);
		::VariantClear(pSrc);
	}

	return S_OK;
}
<|endoftext|>


<commit_before>// NO CLANG FORMAT (concepts not yet supported)
#include <iostream>

template <typename T>
concept bool Incrementable()
{
	return requires (T t)
	{
		++t;
	};
}

class MyClass
{
};

class MyIncrementableClass
{
public:
  MyIncrementableClass& operator++()
  {
    return *this;
  }
};

void foo(Incrementable& i)
{
	std::cout << "foo" << std::endl;
}

int main(int argc, char* argv[])
{
	MyClass m;
	//foo(m); // will not compile

	MyIncrementableClass im;
	foo(im);
}

<commit_msg>minor neatenings<commit_after>// NO CLANG FORMAT (concepts not yet supported)
#include <iostream>
#include <type_traits>

template <typename T>
concept bool Incrementable()
{
	return requires (T t)
	{
		++t;
	};
}

struct MyClass {};

struct MyIncrementableClass
{
  MyIncrementableClass& operator++() { return *this; }
};

void foo(Incrementable& i)
{
	std::cout << "foo" << std::endl;
}

int main(int argc, char* argv[])
{
	MyClass m;
	foo(m); // will not compile

	MyIncrementableClass im;
	foo(im);
}

<|endoftext|>


<commit_before>/// @file
/// @author  Boris Mikic
/// @version 3.1
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#ifdef _OPENKODE_WINDOW
#ifdef __APPLE__
	#include <TargetConditionals.h>
	#if TARGET_OS_IPHONE
		#import <UIKit/UIWindow.h>
	#endif
#endif

#include <KD/kd.h>

#include <hltypes/hltypesUtil.h>
#include <hltypes/hlog.h>
#include <hltypes/hthread.h>

#include "april.h"
#include "RenderSystem.h"
#include "SystemDelegate.h"
#include "Timer.h"

#ifdef _EGL
#include "egl.h"
#endif
#include "OpenGL_RenderSystem.h"
#include "OpenKODE_Window.h"
#include "OpenKODE_Keys.h"

#if TARGET_OS_IPHONE
#import <AVFoundation/AVFoundation.h>

bool (*iOShandleUrlCallback)(chstr url) = NULL; // KD-TODO
#endif

namespace april
{
#if TARGET_OS_IPHONE
	static void iosSetupAudioSession()
	{
		// kspes: copied this from iOS app delegate code, it's needed for OpenKODE and OpenAL to play along on iOS
		if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0" options:NSNumericSearch] == NSOrderedAscending)
		{
			// less then iOS 5.0 - workarround for an apple bug where the audio sesion get's interrupted while using AVAssetReader and similar
			AVAudioSession *audioSession = [AVAudioSession sharedInstance];
			[audioSession setActive: NO error: nil];
			[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];

			// Modifying Playback Mixing Behavior, allow playing music in other apps
			UInt32 allowMixing = true;
			AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);
			[audioSession setActive: YES error: nil];
		}
		else
		{
			[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:NULL];
		}
	}
#endif

	void KD_APIENTRY lowMemoryEventCallback(const KDEvent * _event)
	{
		switch (_event->type)
		{
			case KD_EVENT_LOWMEM:
			{
				hlog::write(logTag, "Received libKD memory warning!");
				if (april::window) april::window->handleLowMemoryWarning();
				break;
			}
		}
	}

	OpenKODE_Window::OpenKODE_Window() : Window()
	{
#if TARGET_OS_IPHONE
		iosSetupAudioSession();
#endif
		this->name = APRIL_WS_OPENKODE;
		this->kdWindow = NULL;
		this->virtualKeyboardVisible = false;
		memset(this->kdTouches, 0, 16 * sizeof(bool));
#if defined(_WIN32) && !defined(_EGL)
		hlog::warn(april::logTag, "OpenKODE Window requires EGL to be present!");
#endif
		initOpenKODEKeyMap();
	}

	OpenKODE_Window::~OpenKODE_Window()
	{
		this->destroy();
	}

	bool OpenKODE_Window::create(int w, int h, bool fullscreen, chstr title, Window::Options options)
	{
		if (!Window::create(w, h, fullscreen, title, options))
		{
			return false;
		}
		this->virtualKeyboardVisible = false;
		if (w <= 0 || h <= 0)
		{
			hlog::errorf(april::logTag, "Cannot create window with size: %d x %d", w, h);
			this->destroy();
			return false;
		}
#ifdef _EGL
		this->kdWindow = kdCreateWindow(april::egl->display, april::egl->config, NULL);
#endif
		if (this->kdWindow == NULL)
		{
			hlog::error(april::logTag, "Can't create KD Window!");
			this->destroy();
			return false;
		}
		if (fullscreen) // KD only supports fullscreen in the screen's resolution
		{
			kdQueryAttribi(KD_ATTRIB_WIDTH, &w);
			kdQueryAttribi(KD_ATTRIB_HEIGHT, &h);
		}
		KDint32 size[] = {w, h};
		kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);
		kdSetWindowPropertycv(this->kdWindow, KD_WINDOWPROPERTY_CAPTION, title.c_str());
#ifdef _EGL // KD doesn't actually work without EGL
		if (kdRealizeWindow(this->kdWindow, &april::egl->hWnd) != 0)
#endif
		{
			hlog::error(april::logTag, "Can't realize KD Window!");
			this->destroy();
			return false;
		}
#ifdef _EGL
		april::egl->create();
#endif

		kdInstallCallback(&lowMemoryEventCallback, KD_EVENT_LOWMEM, NULL);
		return true;
	}

	bool OpenKODE_Window::destroy()
	{
		kdInstallCallback(NULL, KD_EVENT_LOWMEM, NULL);

		if (!Window::destroy())
		{
			return false;
		}
		this->virtualKeyboardVisible = false;
#ifdef _EGL
		april::egl->destroy();
#endif
		if (this->kdWindow != NULL)
		{
			kdDestroyWindow(this->kdWindow);
			this->kdWindow = NULL;
		}
		return true;
	}

	int OpenKODE_Window::getWidth()
	{
		KDint32 size[] = {0, 0};
		kdGetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);
		return size[0];
	}

	int OpenKODE_Window::getHeight()
	{
		KDint32 size[] = {0, 0};
		kdGetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);
		return size[1];
	}

	void OpenKODE_Window::setTitle(chstr title)
	{
		this->title = title;
		kdSetWindowPropertycv(this->kdWindow, KD_WINDOWPROPERTY_CAPTION, this->title.c_str());
	}

	bool OpenKODE_Window::isCursorVisible()
	{
		return (Window::isCursorVisible() || !this->isCursorInside());
	}

	void OpenKODE_Window::setCursorVisible(bool value)
	{
		Window::setCursorVisible(value);
		if (this->kdWindow)
		{
			KDint param = value ? KD_CURSOR_ARROW : KD_CURSOR_NONE;
			kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_CURSOR, &param);
		}
	}

	void* OpenKODE_Window::getBackendId()
	{
#if TARGET_OS_IPHONE
		UIWindow* window = [UIApplication sharedApplication].keyWindow;
		if (!window)
			window = [[UIApplication sharedApplication].windows objectAtIndex:0];

		UIViewController* controller = [window rootViewController];

		return controller;
#elif defined(_EGL)
		return april::egl->hWnd;
#else
		return 0;
#endif
	}

	void OpenKODE_Window::setResolution(int w, int h, bool fullscreen)
	{
		if (fullscreen) // KD only supports fullscreen in the screen's resolution
		{
			kdQueryAttribi(KD_ATTRIB_WIDTH, &w);
			kdQueryAttribi(KD_ATTRIB_HEIGHT, &h);
		}
		this->fullscreen = fullscreen;
		KDint32 size[] = {w, h};
		kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);

		april::SystemDelegate* delegate = this->getSystemDelegate();
		april::rendersys->setViewport(grect(0, 0, w, h));

		if (delegate)
		{
			delegate->onWindowSizeChanged(w, h, fullscreen);
		}

	}

	void OpenKODE_Window::handleActivityChangeEvent(bool active)
	{
		if (active != this->focused)
		{
			this->handleFocusChangeEvent(active);
		}
	}

	bool OpenKODE_Window::updateOneFrame()
	{
		static bool result;
		this->checkEvents();
		// rendering
		result = Window::updateOneFrame();
		this->setTitle(this->title); // has to come after Window::updateOneFrame(), otherwise FPS value in title would be late one frame
		return result;
	}

	void OpenKODE_Window::presentFrame()
	{
#ifdef _EGL
		april::egl->swapBuffers();
#endif
	}

	int OpenKODE_Window::getAprilTouchIndex(int kdIndex)
	{
		int index = 0;
		for (int i = 0; i <= kdIndex; i++)
		{
			if (this->kdTouches[i])
			{
				index++;
			}
		}

		return index -1;
	}

	bool OpenKODE_Window::_processEvent(const KDEvent* evt)
	{
		switch (evt->type)
		{
		case KD_EVENT_QUIT:
			this->handleQuitRequest(false);
			this->terminateMainLoop();
			return true;
		case KD_EVENT_WINDOW_CLOSE:
			this->handleQuitRequest(true);
			return true;
		case KD_EVENT_PAUSE:
			hlog::write(logTag, "OpenKODE pause event received.");
			this->handleActivityChangeEvent(false);
			april::rendersys->unloadTextures();
#ifdef _EGL
			april::egl->destroy();
#endif
			return true;
		case KD_EVENT_RESUME:
#ifdef _EGL
			april::egl->create();
#endif
			hlog::write(logTag, "OpenKODE resume event received.");
			this->handleActivityChangeEvent(true);
			return true;
		case KD_EVENT_WINDOW_FOCUS:
			{
				bool active = evt->data.windowfocus.focusstate != 0;
				if (this->focused != active)
					this->handleFocusChangeEvent(active);
			}
			return true;
		case KD_EVENT_INPUT:
			if (evt->data.input.value.i != 0)
			{
				if (evt->data.input.index < KD_IOGROUP_CHARS) // because key and char events are separate
				{
					this->queueKeyEvent(april::Window::AKEYEVT_DOWN, kd2april(evt->data.input.index), 0);
				}
				else
				{
					this->queueKeyEvent(april::Window::AKEYEVT_DOWN, april::AK_NONE, evt->data.input.index - KD_IOGROUP_CHARS);
				}
			}
			else
			{
				this->queueKeyEvent(april::Window::AKEYEVT_UP, kd2april(evt->data.input.index), 0);
			}
			return true;
		case KD_EVENT_INPUT_POINTER:
			{
#ifdef _PC_INPUT
				int index = evt->data.inputpointer.index;
				gvec2 pos((float)evt->data.inputpointer.x, (float)evt->data.inputpointer.y);

				if (index == KD_INPUT_POINTER_X || index == KD_INPUT_POINTER_Y)
				{
					this->queueMouseEvent(Window::AMOUSEEVT_MOVE, pos, AK_NONE);
					this->cursorPosition = pos;
				}
				else if (index == KD_INPUT_POINTER_SELECT)
				{
					int s = evt->data.inputpointer.select;
					bool state[3];
					state[0] = s & 1;
					state[1] = s & 2;
					state[2] = s & 4;

					for (int i = 0; i < 3; i++)
					{
						if (state[i] != this->kdTouches[i])
						{
							this->queueMouseEvent(state[i] ? Window::AMOUSEEVT_DOWN : Window::AMOUSEEVT_UP, pos, (i == 0 ? AK_LBUTTON : (i == 1 ? AK_RBUTTON : AK_MBUTTON)));
						}
					}
					memcpy(this->kdTouches, state, 3 * sizeof(bool));
					this->cursorPosition = pos;
				}
				else if (index == KD_INPUT_POINTER_WHEEL)
				{
					int deltaV = -short(evt->data.inputpointer.select >> 16);
					int deltaH = -short(evt->data.inputpointer.select & 0xFFFF);
					this->queueMouseEvent(Window::AMOUSEEVT_SCROLL, gvec2(deltaH * 0.2f, deltaV * 0.2f), AK_NONE);
				}
#else
				int i, j, index = evt->data.inputpointer.index;
				gvec2 pos((float)evt->data.inputpointer.x, (float)evt->data.inputpointer.y);
				for (i = 0, j = 0; i < 4; i++, j += KD_IO_POINTER_STRIDE)
				{
					if (index == KD_INPUT_POINTER_X + j || index == KD_INPUT_POINTER_Y + j)
					{
						this->queueTouchEvent(Window::AMOUSEEVT_MOVE, pos, this->getAprilTouchIndex(i));
					}
					else if (index == KD_INPUT_POINTER_SELECT + j)
					{
						if (evt->data.inputpointer.select != 0)
						{
							this->kdTouches[i] = true;
							this->queueTouchEvent(Window::AMOUSEEVT_DOWN, pos, this->getAprilTouchIndex(i));
						}
						else
						{
							this->queueTouchEvent(Window::AMOUSEEVT_UP, pos, this->getAprilTouchIndex(i));
							this->kdTouches[i] = false;
						}
					}
					else
						continue;
					break;
				}
				if (i == 0)
				{
					this->cursorPosition = pos;
				}
#endif
			}
			return true;
		case KD_EVENT_WINDOWPROPERTY_CHANGE:
			if (evt->data.windowproperty.pname == KD_WINDOWPROPERTY_SIZE)
			{
				this->_setRenderSystemResolution();
			}
			return true;
		}
		return false;
	}

	void OpenKODE_Window::checkEvents()
	{
		kdPumpEvents();
		const KDEvent* evt;
		// 1 milisecond as timeout
		while (this->running && (evt = kdWaitEvent(1000000L)) != NULL)
		{
			if (!this->_processEvent(evt))
			{
				kdDefaultEvent(evt);
			}
		}
		Window::checkEvents();
	}

	void OpenKODE_Window::beginKeyboardHandling()
	{
		kdKeyboardShow(this->kdWindow, 1);
		this->virtualKeyboardVisible = true;
		if (this->systemDelegate != NULL)
		{
			this->systemDelegate->onVirtualKeyboardVisibilityChanged(true);
		}
	}

	void OpenKODE_Window::terminateKeyboardHandling()
	{
		kdKeyboardShow(this->kdWindow, 0);
		this->virtualKeyboardVisible = false;
		if (this->systemDelegate != NULL)
		{
			this->systemDelegate->onVirtualKeyboardVisibilityChanged(false);
		}
	}

}
#endif<commit_msg>workaround for macosx cursor bug in OpenKODE<commit_after>/// @file
/// @author  Boris Mikic
/// @version 3.1
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#ifdef _OPENKODE_WINDOW
#ifdef __APPLE__
	#include <TargetConditionals.h>
	#if TARGET_OS_IPHONE
		#import <UIKit/UIWindow.h>
    #else
        #define MAC_OS
	#endif
#endif

#include <KD/kd.h>

#include <hltypes/hltypesUtil.h>
#include <hltypes/hlog.h>
#include <hltypes/hthread.h>

#include "april.h"
#include "RenderSystem.h"
#include "SystemDelegate.h"
#include "Timer.h"

#ifdef _EGL
#include "egl.h"
#endif
#include "OpenGL_RenderSystem.h"
#include "OpenKODE_Window.h"
#include "OpenKODE_Keys.h"

#if TARGET_OS_IPHONE
#import <AVFoundation/AVFoundation.h>

bool (*iOShandleUrlCallback)(chstr url) = NULL; // KD-TODO
#endif

namespace april
{
#if TARGET_OS_IPHONE
	static void iosSetupAudioSession()
	{
		// kspes: copied this from iOS app delegate code, it's needed for OpenKODE and OpenAL to play along on iOS
		if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0" options:NSNumericSearch] == NSOrderedAscending)
		{
			// less then iOS 5.0 - workarround for an apple bug where the audio sesion get's interrupted while using AVAssetReader and similar
			AVAudioSession *audioSession = [AVAudioSession sharedInstance];
			[audioSession setActive: NO error: nil];
			[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];

			// Modifying Playback Mixing Behavior, allow playing music in other apps
			UInt32 allowMixing = true;
			AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);
			[audioSession setActive: YES error: nil];
		}
		else
		{
			[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:NULL];
		}
	}
#endif

	void KD_APIENTRY lowMemoryEventCallback(const KDEvent * _event)
	{
		switch (_event->type)
		{
			case KD_EVENT_LOWMEM:
			{
				hlog::write(logTag, "Received libKD memory warning!");
				if (april::window) april::window->handleLowMemoryWarning();
				break;
			}
		}
	}

	OpenKODE_Window::OpenKODE_Window() : Window()
	{
#if TARGET_OS_IPHONE
		iosSetupAudioSession();
#endif
		this->name = APRIL_WS_OPENKODE;
		this->kdWindow = NULL;
		this->virtualKeyboardVisible = false;
		memset(this->kdTouches, 0, 16 * sizeof(bool));
#if defined(_WIN32) && !defined(_EGL)
		hlog::warn(april::logTag, "OpenKODE Window requires EGL to be present!");
#endif
		initOpenKODEKeyMap();
	}

	OpenKODE_Window::~OpenKODE_Window()
	{
		this->destroy();
	}

	bool OpenKODE_Window::create(int w, int h, bool fullscreen, chstr title, Window::Options options)
	{
		if (!Window::create(w, h, fullscreen, title, options))
		{
			return false;
		}
		this->virtualKeyboardVisible = false;
		if (w <= 0 || h <= 0)
		{
			hlog::errorf(april::logTag, "Cannot create window with size: %d x %d", w, h);
			this->destroy();
			return false;
		}
#ifdef _EGL
		this->kdWindow = kdCreateWindow(april::egl->display, april::egl->config, NULL);
#endif
		if (this->kdWindow == NULL)
		{
			hlog::error(april::logTag, "Can't create KD Window!");
			this->destroy();
			return false;
		}
		if (fullscreen) // KD only supports fullscreen in the screen's resolution
		{
			kdQueryAttribi(KD_ATTRIB_WIDTH, &w);
			kdQueryAttribi(KD_ATTRIB_HEIGHT, &h);
		}
		KDint32 size[] = {w, h};
		kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);
		kdSetWindowPropertycv(this->kdWindow, KD_WINDOWPROPERTY_CAPTION, title.c_str());
#ifdef _EGL // KD doesn't actually work without EGL
		if (kdRealizeWindow(this->kdWindow, &april::egl->hWnd) != 0)
#endif
		{
			hlog::error(april::logTag, "Can't realize KD Window!");
			this->destroy();
			return false;
		}
#ifdef _EGL
		april::egl->create();
#endif

		kdInstallCallback(&lowMemoryEventCallback, KD_EVENT_LOWMEM, NULL);
		return true;
	}

	bool OpenKODE_Window::destroy()
	{
		kdInstallCallback(NULL, KD_EVENT_LOWMEM, NULL);

		if (!Window::destroy())
		{
			return false;
		}
		this->virtualKeyboardVisible = false;
#ifdef _EGL
		april::egl->destroy();
#endif
		if (this->kdWindow != NULL)
		{
			kdDestroyWindow(this->kdWindow);
			this->kdWindow = NULL;
		}
		return true;
	}

	int OpenKODE_Window::getWidth()
	{
		KDint32 size[] = {0, 0};
		kdGetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);
		return size[0];
	}

	int OpenKODE_Window::getHeight()
	{
		KDint32 size[] = {0, 0};
		kdGetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);
		return size[1];
	}

	void OpenKODE_Window::setTitle(chstr title)
	{
		this->title = title;
		kdSetWindowPropertycv(this->kdWindow, KD_WINDOWPROPERTY_CAPTION, this->title.c_str());
	}

	bool OpenKODE_Window::isCursorVisible()
	{
		return (Window::isCursorVisible() || !this->isCursorInside());
	}

	void OpenKODE_Window::setCursorVisible(bool value)
	{
		Window::setCursorVisible(value);
		if (this->kdWindow)
		{
			KDint param = value ? KD_CURSOR_ARROW : KD_CURSOR_NONE;
			kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_CURSOR, &param);
		}
	}

	void* OpenKODE_Window::getBackendId()
	{
#if TARGET_OS_IPHONE
		UIWindow* window = [UIApplication sharedApplication].keyWindow;
		if (!window)
			window = [[UIApplication sharedApplication].windows objectAtIndex:0];

		UIViewController* controller = [window rootViewController];

		return controller;
#elif defined(_EGL)
		return april::egl->hWnd;
#else
		return 0;
#endif
	}

	void OpenKODE_Window::setResolution(int w, int h, bool fullscreen)
	{
		if (fullscreen) // KD only supports fullscreen in the screen's resolution
		{
			kdQueryAttribi(KD_ATTRIB_WIDTH, &w);
			kdQueryAttribi(KD_ATTRIB_HEIGHT, &h);
		}
		this->fullscreen = fullscreen;
		KDint32 size[] = {w, h};
		kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_SIZE, size);

		april::SystemDelegate* delegate = this->getSystemDelegate();
		april::rendersys->setViewport(grect(0, 0, w, h));

		if (delegate)
		{
			delegate->onWindowSizeChanged(w, h, fullscreen);
		}
	}

	void OpenKODE_Window::handleActivityChangeEvent(bool active)
	{
		if (active != this->focused)
		{
			this->handleFocusChangeEvent(active);
		}
	}

	bool OpenKODE_Window::updateOneFrame()
	{
#ifdef MAC_OS
        // MacOS has a bug where if you move the cursor to the dock area and back, it resets to the arrow cursor
        // in Mac window we implemented a workarround, but in OpenKODE, depending on implementation, it may not work
        // so the simplest solution would be to just reset the cursor every 60 frames and problem solved.
        static int timer = 0;
        if (!this->cursorVisible)
        {
            timer++;
            if (timer > 60)
            {
                timer = 0;
                KDint param = KD_CURSOR_NONE;
                kdSetWindowPropertyiv(this->kdWindow, KD_WINDOWPROPERTY_CURSOR, &param);
            }
        }
#endif
		static bool result;
		this->checkEvents();
		// rendering
		result = Window::updateOneFrame();
		this->setTitle(this->title); // has to come after Window::updateOneFrame(), otherwise FPS value in title would be late one frame
		return result;
	}

	void OpenKODE_Window::presentFrame()
	{
#ifdef _EGL
		april::egl->swapBuffers();
#endif
	}

	int OpenKODE_Window::getAprilTouchIndex(int kdIndex)
	{
		int index = 0;
		for (int i = 0; i <= kdIndex; i++)
		{
			if (this->kdTouches[i])
			{
				index++;
			}
		}

		return index -1;
	}

	bool OpenKODE_Window::_processEvent(const KDEvent* evt)
	{
		switch (evt->type)
		{
        case KD_EVENT_QUIT:
			this->handleQuitRequest(false);
			this->terminateMainLoop();
			return true;
		case KD_EVENT_WINDOW_CLOSE:
			this->handleQuitRequest(true);
			return true;
		case KD_EVENT_PAUSE:
			hlog::write(logTag, "OpenKODE pause event received.");
			this->handleActivityChangeEvent(false);
			april::rendersys->unloadTextures();
#ifdef _EGL
			april::egl->destroy();
#endif
			return true;
		case KD_EVENT_RESUME:
#ifdef _EGL
			april::egl->create();
#endif
			hlog::write(logTag, "OpenKODE resume event received.");
			this->handleActivityChangeEvent(true);
			return true;
		case KD_EVENT_WINDOW_FOCUS:
			{
				bool active = evt->data.windowfocus.focusstate != 0;
				if (this->focused != active)
					this->handleFocusChangeEvent(active);
			}
			return true;
		case KD_EVENT_INPUT:
			if (evt->data.input.value.i != 0)
			{
				if (evt->data.input.index < KD_IOGROUP_CHARS) // because key and char events are separate
				{
					this->queueKeyEvent(april::Window::AKEYEVT_DOWN, kd2april(evt->data.input.index), 0);
				}
				else
				{
					this->queueKeyEvent(april::Window::AKEYEVT_DOWN, april::AK_NONE, evt->data.input.index - KD_IOGROUP_CHARS);
				}
			}
			else
			{
				this->queueKeyEvent(april::Window::AKEYEVT_UP, kd2april(evt->data.input.index), 0);
			}
			return true;
		case KD_EVENT_INPUT_POINTER:
			{
#ifdef _PC_INPUT
				int index = evt->data.inputpointer.index;
				gvec2 pos((float)evt->data.inputpointer.x, (float)evt->data.inputpointer.y);

				if (index == KD_INPUT_POINTER_X || index == KD_INPUT_POINTER_Y)
				{
					this->queueMouseEvent(Window::AMOUSEEVT_MOVE, pos, AK_NONE);
					this->cursorPosition = pos;
				}
				else if (index == KD_INPUT_POINTER_SELECT)
				{
					int s = evt->data.inputpointer.select;
					bool state[3];
					state[0] = s & 1;
					state[1] = s & 2;
					state[2] = s & 4;

					for (int i = 0; i < 3; i++)
					{
						if (state[i] != this->kdTouches[i])
						{
							this->queueMouseEvent(state[i] ? Window::AMOUSEEVT_DOWN : Window::AMOUSEEVT_UP, pos, (i == 0 ? AK_LBUTTON : (i == 1 ? AK_RBUTTON : AK_MBUTTON)));
						}
					}
					memcpy(this->kdTouches, state, 3 * sizeof(bool));
					this->cursorPosition = pos;
				}
				else if (index == KD_INPUT_POINTER_WHEEL)
				{
					int deltaV = -short(evt->data.inputpointer.select >> 16);
					int deltaH = -short(evt->data.inputpointer.select & 0xFFFF);
					this->queueMouseEvent(Window::AMOUSEEVT_SCROLL, gvec2(deltaH * 0.2f, deltaV * 0.2f), AK_NONE);
				}
#else
				int i, j, index = evt->data.inputpointer.index;
				gvec2 pos((float)evt->data.inputpointer.x, (float)evt->data.inputpointer.y);
				for (i = 0, j = 0; i < 4; i++, j += KD_IO_POINTER_STRIDE)
				{
					if (index == KD_INPUT_POINTER_X + j || index == KD_INPUT_POINTER_Y + j)
					{
						this->queueTouchEvent(Window::AMOUSEEVT_MOVE, pos, this->getAprilTouchIndex(i));
					}
					else if (index == KD_INPUT_POINTER_SELECT + j)
					{
						if (evt->data.inputpointer.select != 0)
						{
							this->kdTouches[i] = true;
							this->queueTouchEvent(Window::AMOUSEEVT_DOWN, pos, this->getAprilTouchIndex(i));
						}
						else
						{
							this->queueTouchEvent(Window::AMOUSEEVT_UP, pos, this->getAprilTouchIndex(i));
							this->kdTouches[i] = false;
						}
					}
					else
						continue;
					break;
				}
				if (i == 0)
				{
					this->cursorPosition = pos;
				}
#endif
			}
			return true;
		case KD_EVENT_WINDOWPROPERTY_CHANGE:
			if (evt->data.windowproperty.pname == KD_WINDOWPROPERTY_SIZE)
			{
				this->_setRenderSystemResolution();
			}
			return true;
		}
		return false;
	}

	void OpenKODE_Window::checkEvents()
	{
		kdPumpEvents();
		const KDEvent* evt;
		// 1 milisecond as timeout
		while (this->running && (evt = kdWaitEvent(1000000L)) != NULL)
		{
			if (!this->_processEvent(evt))
			{
				kdDefaultEvent(evt);
			}
		}
		Window::checkEvents();
	}

	void OpenKODE_Window::beginKeyboardHandling()
	{
		kdKeyboardShow(this->kdWindow, 1);
		this->virtualKeyboardVisible = true;
		if (this->systemDelegate != NULL)
		{
			this->systemDelegate->onVirtualKeyboardVisibilityChanged(true);
		}
	}

	void OpenKODE_Window::terminateKeyboardHandling()
	{
		kdKeyboardShow(this->kdWindow, 0);
		this->virtualKeyboardVisible = false;
		if (this->systemDelegate != NULL)
		{
			this->systemDelegate->onVirtualKeyboardVisibilityChanged(false);
		}
	}

}
#endif<|endoftext|>


<commit_before>#include <chrono>
#include <thread>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>

#ifdef EMSCRIPTEN
#include <emscripten/emscripten.h>
#endif

#include <wonder_rabbit_project/wonderland.renderer.hxx>
#include <wonder_rabbit_project/wonderland.subsystem.hxx>

auto main()
  -> int
try
{
  std::cout
    << "[Home]/[End] key or mouse [Wheel]: camera distance forward/backward.\n"
    << "[up]/[left]/[right]/[bottom]: control camera phi and theta.\n"
    << "[shift] + [Home]/[End] key or mouse [Wheel]: light distance forward/backward.\n"
    << "[shift] + [up]/[left]/[right]/[bottom]: control light phi and theta.\n"
    << "[q]/[e]: camera eye auto orbitation on/off."
    << "[1]: shader program change to Wonderland.Renderer embedded <constant> shader program.\n"
    << "[2]: shader program change to Wonderland.Renderer embedded <phong> shader program.\n"
    << "[3]: shader program change to Wonderland.Renderer embedded <cartoon> shader program.\n"
    << "\n"
    ;

  using namespace wonder_rabbit_project::wonderland::subsystem;
  using namespace wonder_rabbit_project::wonderland::renderer;
  using wonder_rabbit_project::wonderland::renderer::model::animation_state_t;

  constexpr auto screen_width  = 1920 >> 1;
  constexpr auto screen_height = 1080 >> 1;

  auto subsystem = std::make_shared< subsystem_t >();

  auto ips = subsystem -> default_initialize_params();
  ips.put( "width"  , screen_width  );
  ips.put( "height" , screen_height );
  ips.put( "title"  , "Wonderland.Renderer example-1" );
  ips.put( "samples", 4 ); // FSAA
  subsystem -> initialize( std::move(ips) );

  auto renderer = std::make_shared< renderer_t >();

  // wonderland.renderer has the standard shader program
  //   effects:
  //     1. create shader program from embedded sources as < shader::constant >.
  //     2. set default program automatically ( you can set `renderer -> default_program( p )` after manually )
  // or you can manually create your shader from source string and link program if you need.
  //   auto my_shader0 = renderer -> create_shader< vertex_shader >( "your source string" );
  //   auto my_program = renderer -> create_program( my_shader0, my_shader1, my_shader2, ... );
  auto program_constant = renderer -> create_program_from_embedded< shader::constant >();
  auto program_phong    = renderer -> create_program_from_embedded< shader::phong    >();
  auto program_cartoon  = renderer -> create_program_from_embedded< shader::cartoon  >();

  // create light with effect:
  //  set default lights automatically
  //  ( you can add/remove default light `{add|remove}_lights( light0, light1, light2, ... )` )
  //  ( and `lights( light0, light1, light2, ... )` to set lights or remove all. )
  auto light0 = renderer -> create_light<point_light_t>();

  // load models with assimp currently
  auto model0 = renderer -> create_model( "assets/like_a_cornell_box.x" );
  auto model1 = renderer -> create_model( "assets/vertex-colored-cube.x" );
  auto model2 = renderer -> create_model( "assets/n175Anim.x" );

  struct model_instance_state_t
  {
    decltype(model0)  model;
    animation_state_t animation_state;
    glm::mat4         world_transformation;
  };

  std::array< model_instance_state_t, 9 > model_instance_states;

  {
    model_instance_states[0].model = model1;
    model_instance_states[0].world_transformation
      = glm::translate( glm::mat4(), glm::vec3( 0.0f, 80.0f, 0.0f ) );

    auto animation_names = model2 -> animation_names();

    for ( const auto& animation_name : animation_names )
      std::cout << "has animation: " << animation_name << std::endl;

    for ( auto n = 1; n < model_instance_states.size(); ++n )
    {
      auto& s = model_instance_states[ n ];

      s.model = model2;

      if ( ! animation_names.empty() )
      {
        s.animation_state.name = animation_names[ n % animation_names.size() ];
        s.animation_state.time = animation_state_t::fseconds( float(n) * 19937 );
      }

      s.world_transformation = glm::scale( glm::mat4(), glm::vec3( 25.f ) );
      switch ( n )
      { case 1: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  5.0f, 1.0f,  0.0f ) ); break;
        case 2: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3( -5.0f, 1.0f,  0.0f ) ); break;
        case 3: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  5.0f, 0.0f,  5.0f ) ); break;
        case 4: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  0.0f, 1.0f,  5.0f ) ); break;
        case 5: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3( -5.0f, 1.0f,  5.0f ) ); break;
        case 6: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  5.0f, 1.0f, -5.0f ) ); break;
        case 7: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  0.0f, 0.0f, -5.0f ) ); break;
        case 8: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3( -5.0f, 1.0f, -5.0f ) );
      }
    }
  }

  // clear color
  {
    const auto color = glm::vec4( 0.8f, 0.8f, 1.0f, 1.0f );
    renderer -> clear_color( color );
  }

  // projection transformation
  {
    const auto fov_y = glm::pi<float>() / 4.0f;
    constexpr auto screen_aspect_ratio = float( screen_width ) / float( screen_height );
    constexpr auto near_clip = 1.0e-1f;
    constexpr auto far_clip  = 1.0e+3f;
    renderer -> projection_transformation( glm::perspective( fov_y, screen_aspect_ratio, near_clip, far_clip ) );
  }

  subsystem -> update_functors.emplace_front
  ( [ subsystem, renderer
    , &model_instance_states
    , light0
    , program_constant
    , program_phong
    , program_cartoon
    ]
  {
    static auto camera_theta           = glm::half_pi< float >();
    static auto camera_phi             = glm::half_pi< float >() * -0.5f;
    static auto camera_distance        = 300.0f;
    static auto camera_auto_orbitation = false;

    static auto light_theta           = glm::half_pi< float >();
    static auto light_phi             = glm::half_pi< float >() * -0.5f;
    static auto light_distance        = 1000.0f;
    static auto light_auto_orbitation = false;

    for ( auto& model_instance_state : model_instance_states )
      model_instance_state.animation_state += animation_state_t::fseconds( 1.0f / 30.0f );

    const auto wheel    = subsystem -> pointing_states_wheel();
    const auto key_home = subsystem -> keyboard_state< key::home >();
    const auto key_end  = subsystem -> keyboard_state< key::end  >();
    const auto shift    = subsystem -> keyboard_state< key::left_shift >()
                       || subsystem -> keyboard_state< key::right_shift >()
                       ;

    // camera change
    if      ( wheel.y > 0 or key_home )
      ( shift ? light_distance : camera_distance ) -= 10.0f;
    else if ( wheel.y < 0 or key_end  )
      ( shift ? light_distance : camera_distance ) += 10.0f;

    if ( subsystem -> keyboard_state< key::left_arrow >() )
      ( shift ? light_theta : camera_theta ) -= 0.05f;
    if ( subsystem -> keyboard_state< key::right_arrow >() )
      ( shift ? light_theta : camera_theta ) += 0.05f;
    if ( subsystem -> keyboard_state< key::up_arrow >() )
      ( shift ? light_phi : camera_phi ) -= 0.05f;
    if ( subsystem -> keyboard_state< key::down_arrow >() )
      ( shift ? light_phi : camera_phi ) += 0.05f;

    renderer -> camera()
      -> target( { 0.0f, 25.0f, 0.0f } )
      -> eye_from_orbit_of_target( camera_theta, camera_phi, camera_distance )
      -> up    ( { 0.0f,  1.0f, 0.0f } )
      ;

    // light change
    light0 -> position = ( glm::mat4_cast( glm::quat( glm::vec3( light_phi, light_theta, 0.0f ) ) ) * glm::vec4( 0.0f, 0.0f, light_distance, 1.0f ) ).xyz();

    // program change
    const auto program_change =
    [ renderer, subsystem ]
    ( program_t::const_shared_t program, const key_code_t key, const std::string& name )
      -> bool
    {
      if ( ( renderer -> default_program() != program ) and subsystem -> keyboard_state( key ) )
      {
        renderer -> default_program( program );
        std::cout << "change to Wonderland.Renderer embedded < " << name << " > shader program.\n";
        return true;
      }
      return false;
    };

    program_change( program_constant, key::_1, "constant" ) ? 0 :
    program_change( program_phong   , key::_2, "phong"    ) ? 0 :
    program_change( program_cartoon , key::_3, "cartoon"  )
    ;

    if ( ( not camera_auto_orbitation ) and subsystem -> keyboard_state< key::q >() )
    {
      camera_auto_orbitation = true;
      std::cout << "camera auto orbitation on.\n";
    }
    else if ( ( camera_auto_orbitation ) and subsystem -> keyboard_state< key::e >() )
    {
      camera_auto_orbitation = false;
      std::cout << "camera auto orbitation off.\n";
    }

    if ( camera_auto_orbitation )
      camera_theta += 0.01f;
    if ( light_auto_orbitation )
      light_theta += 0.01f;
  }
  );

  subsystem -> update_functors.emplace_front
  ( [ subsystem ]
  {
    if ( subsystem -> keyboard_state< key::escape >() )
      subsystem -> to_continue( false );
  }
  );

  subsystem -> render_functors.emplace_front
  ( [ renderer
    , model0
    , &model_instance_states
    ]
  {
    // invoker effects:
    //  1. clear
    //  2. return { flusher(), use_program( p ) }
    //    use default program if call with no parameter.
    auto rendering_invoker = renderer -> invoker();

    // draw model with world transformation
    //  automatic set
    //   1. uniform(world_view_projection_transformation) if shader program has uniform world_view_projection_transformation
    //   2. uniform(world_transformation) if shader program has uniform world_transformation

    renderer -> draw( model0 , glm::mat4(), { } );

    for ( const auto& model_instance_state : model_instance_states )
      renderer -> draw( model_instance_state.model , model_instance_state.world_transformation, { model_instance_state.animation_state } );
  }
  );

  subsystem -> render_functors.emplace_front
  ( [ ]
  {
    static auto before = std::chrono::high_resolution_clock::now();
    const auto elapsed = std::chrono::high_resolution_clock::now() - before;
    const auto wait = std::chrono::duration<float>( 1.0f / 30.0f ) - elapsed;
    std::this_thread::sleep_for(wait);
    before = std::chrono::high_resolution_clock::now();
  }
  );

  subsystem -> invoke();
}
catch( const std::exception& e )
{ std::cerr << e.what(); return 1; }
catch( ... )
{ std::cerr << "unknown exception"; return 2; }<commit_msg>reformat<commit_after>#include <chrono>
#include <thread>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>

#ifdef EMSCRIPTEN
#include <emscripten/emscripten.h>
#endif

#include <wonder_rabbit_project/wonderland.renderer.hxx>
#include <wonder_rabbit_project/wonderland.subsystem.hxx>

auto main()
  -> int
try
{
  std::cout
    << "[Home]/[End] key or mouse [Wheel]: camera distance forward/backward.\n"
    << "[up]/[left]/[right]/[bottom]: control camera phi and theta.\n"
    << "[shift] + [Home]/[End] key or mouse [Wheel]: light distance forward/backward.\n"
    << "[shift] + [up]/[left]/[right]/[bottom]: control light phi and theta.\n"
    << "[q]/[e]: camera eye auto orbitation on/off."
    << "[1]: shader program change to Wonderland.Renderer embedded <constant> shader program.\n"
    << "[2]: shader program change to Wonderland.Renderer embedded <phong> shader program.\n"
    << "[3]: shader program change to Wonderland.Renderer embedded <cartoon> shader program.\n"
    << "\n"
    ;

  using namespace wonder_rabbit_project::wonderland::subsystem;
  using namespace wonder_rabbit_project::wonderland::renderer;
  using wonder_rabbit_project::wonderland::renderer::model::animation_state_t;

  constexpr auto screen_width  = 1920 >> 1;
  constexpr auto screen_height = 1080 >> 1;

  auto subsystem = std::make_shared< subsystem_t >();

  auto ips = subsystem -> default_initialize_params();
  ips.put( "width"  , screen_width  );
  ips.put( "height" , screen_height );
  ips.put( "title"  , "Wonderland.Renderer example-1" );
  ips.put( "samples", 4 ); // FSAA
  subsystem -> initialize( std::move(ips) );

  auto renderer = std::make_shared< renderer_t >();

  // wonderland.renderer has the standard shader program
  //   effects:
  //     1. create shader program from embedded sources as < shader::constant >.
  //     2. set default program automatically ( you can set `renderer -> default_program( p )` after manually )
  // or you can manually create your shader from source string and link program if you need.
  //   auto my_shader0 = renderer -> create_shader< vertex_shader >( "your source string" );
  //   auto my_program = renderer -> create_program( my_shader0, my_shader1, my_shader2, ... );
  auto program_constant = renderer -> create_program_from_embedded< shader::constant >();
  auto program_phong    = renderer -> create_program_from_embedded< shader::phong    >();
  auto program_cartoon  = renderer -> create_program_from_embedded< shader::cartoon  >();

  // create light with effect:
  //  set default lights automatically
  //  ( you can add/remove default light `{add|remove}_lights( light0, light1, light2, ... )` )
  //  ( and `lights( light0, light1, light2, ... )` to set lights or remove all. )
  auto light0 = renderer -> create_light<point_light_t>();

  // load models with assimp currently
  auto model0 = renderer -> create_model( "assets/like_a_cornell_box.x" );
  auto model1 = renderer -> create_model( "assets/vertex-colored-cube.x" );
  auto model2 = renderer -> create_model( "assets/n175Anim.x" );

  struct model_instance_state_t
  {
    decltype(model0)  model;
    animation_state_t animation_state;
    glm::mat4         world_transformation;
  };

  std::array< model_instance_state_t, 9 > model_instance_states;

  {
    model_instance_states[0].model = model1;
    model_instance_states[0].world_transformation
      = glm::translate( glm::mat4(), glm::vec3( 0.0f, 80.0f, 0.0f ) );

    auto animation_names = model2 -> animation_names();

    for ( const auto& animation_name : animation_names )
      std::cout << "has animation: " << animation_name << std::endl;

    for ( auto n = 1; n < model_instance_states.size(); ++n )
    {
      auto& s = model_instance_states[ n ];

      s.model = model2;

      if ( ! animation_names.empty() )
      {
        s.animation_state.name = animation_names[ n % animation_names.size() ];
        s.animation_state.time = animation_state_t::fseconds( float(n) * 19937 );
      }

      s.world_transformation = glm::scale( glm::mat4(), glm::vec3( 25.f ) );
      switch ( n )
      { case 1: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  5.0f, 1.0f,  0.0f ) ); break;
        case 2: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3( -5.0f, 1.0f,  0.0f ) ); break;
        case 3: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  5.0f, 0.0f,  5.0f ) ); break;
        case 4: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  0.0f, 1.0f,  5.0f ) ); break;
        case 5: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3( -5.0f, 1.0f,  5.0f ) ); break;
        case 6: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  5.0f, 1.0f, -5.0f ) ); break;
        case 7: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3(  0.0f, 0.0f, -5.0f ) ); break;
        case 8: s.world_transformation *= glm::translate( glm::mat4(), glm::vec3( -5.0f, 1.0f, -5.0f ) );
      }
    }
  }

  // clear color
  {
    const auto color = glm::vec4( 0.8f, 0.8f, 1.0f, 1.0f );
    renderer -> clear_color( color );
  }

  // projection transformation
  {
    const auto fov_y = glm::pi<float>() / 4.0f;
    constexpr auto screen_aspect_ratio = float( screen_width ) / float( screen_height );
    constexpr auto near_clip = 1.0e-1f;
    constexpr auto far_clip  = 1.0e+3f;
    renderer -> projection_transformation( glm::perspective( fov_y, screen_aspect_ratio, near_clip, far_clip ) );
  }

  subsystem -> update_functors.emplace_front
  ( [ subsystem, renderer
    , &model_instance_states
    , light0
    , program_constant
    , program_phong
    , program_cartoon
    ]
  {
    static auto camera_theta           = glm::half_pi< float >();
    static auto camera_phi             = glm::half_pi< float >() * -0.5f;
    static auto camera_distance        = 300.0f;
    static auto camera_auto_orbitation = false;

    static auto light_theta           = glm::half_pi< float >();
    static auto light_phi             = glm::half_pi< float >() * -0.5f;
    static auto light_distance        = 1000.0f;
    static auto light_auto_orbitation = false;

    for ( auto& model_instance_state : model_instance_states )
      model_instance_state.animation_state += animation_state_t::fseconds( 1.0f / 30.0f );

    const auto wheel    = subsystem -> pointing_states_wheel();
    const auto key_home = subsystem -> keyboard_state< key::home >();
    const auto key_end  = subsystem -> keyboard_state< key::end  >();
    const auto shift    = subsystem -> keyboard_state< key::left_shift >()
                       || subsystem -> keyboard_state< key::right_shift >()
                       ;

    // camera change
    if      ( wheel.y > 0 or key_home )
      ( shift ? light_distance : camera_distance ) -= 10.0f;
    else if ( wheel.y < 0 or key_end  )
      ( shift ? light_distance : camera_distance ) += 10.0f;

    if ( subsystem -> keyboard_state< key::left_arrow >() )
      ( shift ? light_theta : camera_theta ) -= 0.05f;
    if ( subsystem -> keyboard_state< key::right_arrow >() )
      ( shift ? light_theta : camera_theta ) += 0.05f;
    if ( subsystem -> keyboard_state< key::up_arrow >() )
      ( shift ? light_phi : camera_phi ) -= 0.05f;
    if ( subsystem -> keyboard_state< key::down_arrow >() )
      ( shift ? light_phi : camera_phi ) += 0.05f;

    renderer -> camera()
      -> target( { 0.0f, 25.0f, 0.0f } )
      -> eye_from_orbit_of_target( camera_theta, camera_phi, camera_distance )
      -> up    ( { 0.0f,  1.0f, 0.0f } )
      ;

    // light change
    light0 -> position = ( glm::mat4_cast( glm::quat( glm::vec3( light_phi, light_theta, 0.0f ) ) ) * glm::vec4( 0.0f, 0.0f, light_distance, 1.0f ) ).xyz();

    // program change
    const auto program_change =
    [ renderer, subsystem ]
    ( program_t::const_shared_t program, const key_code_t key, const std::string& name )
      -> bool
    {
      if ( ( renderer -> default_program() != program ) and subsystem -> keyboard_state( key ) )
      {
        renderer -> default_program( program );
        std::cout << "change to Wonderland.Renderer embedded < " << name << " > shader program.\n";
        return true;
      }
      return false;
    };

    program_change( program_constant, key::_1, "constant" ) ? 0 :
    program_change( program_phong   , key::_2, "phong"    ) ? 0 :
    program_change( program_cartoon , key::_3, "cartoon"  )
    ;

    if ( ( not camera_auto_orbitation ) and subsystem -> keyboard_state< key::q >() )
    {
      camera_auto_orbitation = true;
      std::cout << "camera auto orbitation on.\n";
    }
    else if ( ( camera_auto_orbitation ) and subsystem -> keyboard_state< key::e >() )
    {
      camera_auto_orbitation = false;
      std::cout << "camera auto orbitation off.\n";
    }

    if ( camera_auto_orbitation )
      camera_theta += 0.01f;
    if ( light_auto_orbitation )
      light_theta += 0.01f;
  }
  );

  subsystem -> update_functors.emplace_front
  ( [ subsystem ]
  {
    if ( subsystem -> keyboard_state< key::escape >() )
      subsystem -> to_continue( false );
  }
  );

  subsystem -> render_functors.emplace_front
  ( [ renderer
    , model0
    , &model_instance_states
    ]
  {
    // invoker effects:
    //  1. clear
    //  2. return { flusher(), use_program( p ) }
    //    use default program if call with no parameter.
    auto rendering_invoker = renderer -> invoker();

    // draw model with world transformation
    //  automatic set
    //   1. uniform(world_view_projection_transformation) if shader program has uniform world_view_projection_transformation
    //   2. uniform(world_transformation) if shader program has uniform world_transformation

    renderer -> draw( model0 , glm::mat4(), { } );

    for ( const auto& model_instance_state : model_instance_states )
      renderer -> draw( model_instance_state.model , model_instance_state.world_transformation, { model_instance_state.animation_state } );
  }
  );

  subsystem -> render_functors.emplace_front
  ( [ ]
  {
    static auto before = std::chrono::high_resolution_clock::now();
    const auto elapsed = std::chrono::high_resolution_clock::now() - before;
    const auto wait = std::chrono::duration<float>( 1.0f / 30.0f ) - elapsed;
    std::this_thread::sleep_for(wait);
    before = std::chrono::high_resolution_clock::now();
  }
  );

  subsystem -> invoke();

}
catch( const std::exception& e )
{ std::cerr << e.what(); return 1; }
catch( ... )
{ std::cerr << "unknown exception"; return 2; }<|endoftext|>