<commit_before>//----------------------------------------------------------------------------
// main.cpp
//
// main for pathed
//
// Copyright (C) 2011 Neil Butterworth
//----------------------------------------------------------------------------

#include <iostream>
#include <set>
#include "cmdline.h"
#include "error.h"
#include "registry.h"
#include "util.h"

using namespace std;

//----------------------------------------------------------------------------
// Flags controling behaviour in various ways.
//----------------------------------------------------------------------------

const char * const ADD_FLAG = "-a";			// add to path
const char * const REM_FLAG = "-r";			// remove from path
const char * const SYS_FLAG = "-s";			// use system instead of user path
const char * const EXIST_FLAG = "-f";		// check path exists on disk
const char * const LIST_FLAG = "-l";		// list current path
const char * const QUERY_FLAG = "-q";		// list current path
const char * const VERIFY_FLAG = "-v";		// verify path
const char * const EXPAND_FLAG = "-x";		// expand path
const char * const PRUNE_FLAG = "-p";		// prune path

static bool Remove = false,
			Add = false,
			UseSys = false,
			List = false,
			CheckExist = true,
			QueryPath = false,
			Verify = false,
			Expand = false,
			Prune = false;

//----------------------------------------------------------------------------
// Set flags from the command line, shifting them off as they are set.
//----------------------------------------------------------------------------

void SetFlags( CmdLine & cl ) {
	while( cl.Argc() > 1 ) {
		string s = cl.Argv(1);
		if ( s.size() && s[0] == '-' ) {
			if ( s == REM_FLAG ) {
				Remove = true;
			}
			else if ( s == PRUNE_FLAG ){
				Prune = true;
			}
			else if ( s == ADD_FLAG ) {
				Add = true;
			}
			else if ( s == SYS_FLAG ) {
				UseSys = true;
			}
			else if ( s == EXPAND_FLAG ) {
				Expand = true;
			}
			else if ( s == EXIST_FLAG ) {
				CheckExist = false;
			}
			else if ( s == LIST_FLAG ) {
				List = true;
			}
			else if ( s == QUERY_FLAG ) {
				QueryPath = true;
			}
			else if ( s == VERIFY_FLAG ) {
				Verify = true;
			}
			else {
				throw Error( "Invalid flag: " + s );
			}
			cl.Shift(1);
		}
		else {
			break;
		}
	}
}

//----------------------------------------------------------------------------
// List PATH to stdout, one directory per line
//----------------------------------------------------------------------------

void ListPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		cout << ( Expand ? ExpandPath( path.At(i) ) : path.At(i) ) << "\n";
	}
}

//----------------------------------------------------------------------------
// Add an entry to the path
//----------------------------------------------------------------------------

void AddPath( CmdLine & cl ) {
	if ( CheckExist ) {
		DWORD attr = GetFileAttributes( cl.Argv(1).c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES || ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			throw Error( "No such directory: " + cl.Argv(1));
		}
	}

	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( path.Find( cl.Argv(1), RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is already on the path" );
	}
	path.Add( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Remove entry from the path
//----------------------------------------------------------------------------

void RemovePath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( ! path.Find( cl.Argv(1) , RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is not on the path" );
	}
	path.Remove( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Prune duplicates and non-existent dirs from path
//----------------------------------------------------------------------------

void PrunePath( CmdLine &  ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );

	typedef std::set <string> DirSet;
	DirSet uniq;
	std::vector <string> ordered;

	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string dir = path.At( i );
		std::pair<DirSet::iterator, bool> ok = uniq.insert( dir );
		if ( ok.second ) {
			ordered.push_back( dir );
		}
		else {
			cout << "Pruned: " << dir << endl;
		}
	}

	string entry;

	for ( unsigned int i = 0; i < ordered.size(); i++ ) {
		string dir = ExpandPath( ordered[i] );
		DWORD attr = GetFileAttributes( dir.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ||
						! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Pruned: " << ordered[i] << endl;
		}
		else {
			if ( entry != "" ) {
				entry += ";";
			}
			entry += ordered[i];
		}

	}
	path.ReplaceAll( entry );
	std::cout << entry << std::endl;
}

//----------------------------------------------------------------------------
// See if directory is on the path, if so return success code (not boolean!)
//----------------------------------------------------------------------------

int FindPath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	return  path.Find( cl.Argv(1), Expand ? RegPath::Expand : RegPath::NoExpand ) ? 0 : 1;
}

//----------------------------------------------------------------------------
// Verify directories on path exist.
//----------------------------------------------------------------------------

int VerifyPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	int bad = 0;
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string epath = ExpandPath( path.At(i) );
		DWORD attr = GetFileAttributes( epath.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ) {
			cout << "No such directory: " << epath << "\n";
			bad++;
		}
		else if ( ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Not a directory: " << epath << "\n";
			bad++;
		}
	}
	return bad == 0 ? 0 : 1;
}

//----------------------------------------------------------------------------
// Display help
//----------------------------------------------------------------------------

void Help() {

	cout <<

	"pathed is a command-line tool for changing the Windows path in the registry\n"
	"Version 0.3\n"
	"Copyright (C) 2011 Neil Butterworth\n\n"
	"usage: pathed [-a | -r | -l  | -q | -v] [-s] [-f]  [-x] [dir]\n\n"
	"pathed -a dir    adds dir to the path in  the registry\n"
	"pathed -r dir    removes  dir from the path in the registry\n"
	"pathed -l        lists the entries on the current path\n"
	"pathed -q dir    queries registry, returns 0 if dir is on path, 1 otherwise\n"
	"pathed -v        verifies that all directories on the path exist\n"
	"pathed -p        prunes the path by removing duplicates and non-existent directories\n\n"
	"By default, pathed works on the path in HKEY_CURRENT_USER. You can make it use\n"
	"the system path in HKEY_LOCAL_MACHINE by using the -s flag.\n\n"
	"Normally, pathed will check a directory exists on disk before adding it to the\n"
	"path. To prevent this, use the -f flag.\n\n"
	"Paths containing environment variables such as %systemroot% will not normally have\n"
	"the variables expanded to their values. To expand them, use the -x flag\n\n"
	"AS WITH ALL COMMANDS THAT CHANGE THE REGISTRY, PATHED CAN CAUSE DAMAGE IF YOU\n"
	"DO NOT KNOW WHAT YOU ARE DOING. IF IN DOUBT, DO NOT USE IT!\n"

	<< endl;
}

//----------------------------------------------------------------------------
// Main for pathed
//----------------------------------------------------------------------------

int main( int argc, char *argv[] )
{
	try {
		CmdLine cl( argc, argv );

		SetFlags( cl );

		if ( cl.Argc() == 1 && ! ( List || Verify || Prune ) ) {
			Help();
			return 0;
		}
		else if ( ! (List || Add || QueryPath || Remove || Verify || Prune )  ) {
			throw Error( "Need one of -a, -r, -l, -q, -p or -v" );
		}

		if ( List ) {
			ListPath();
		}
		else if ( Verify ) {
			return VerifyPath();
		}
		else if ( QueryPath ) {
			return FindPath( cl );
		}
		else if ( Remove ) {
			RemovePath( cl );
		}
		else if ( Prune ) {
			PrunePath( cl );
		}
		else {
			AddPath( cl );
		}

		return 0;
	}
	catch( const Error & e ) {
		cerr << e.what() << endl;
		return 1;
	}
	catch( ... ) {
		cerr << "Unexpected exception" << endl;
		return 1;
	}
}
<commit_msg>bumped version<commit_after>//----------------------------------------------------------------------------
// main.cpp
//
// main for pathed
//
// Copyright (C) 2011 Neil Butterworth
//----------------------------------------------------------------------------

#include <iostream>
#include <set>
#include "cmdline.h"
#include "error.h"
#include "registry.h"
#include "util.h"

using namespace std;

//----------------------------------------------------------------------------
// Flags controling behaviour in various ways.
//----------------------------------------------------------------------------

const char * const ADD_FLAG = "-a";			// add to path
const char * const REM_FLAG = "-r";			// remove from path
const char * const SYS_FLAG = "-s";			// use system instead of user path
const char * const EXIST_FLAG = "-f";		// check path exists on disk
const char * const LIST_FLAG = "-l";		// list current path
const char * const QUERY_FLAG = "-q";		// list current path
const char * const VERIFY_FLAG = "-v";		// verify path
const char * const EXPAND_FLAG = "-x";		// expand path
const char * const PRUNE_FLAG = "-p";		// prune path

static bool Remove = false,
			Add = false,
			UseSys = false,
			List = false,
			CheckExist = true,
			QueryPath = false,
			Verify = false,
			Expand = false,
			Prune = false;

//----------------------------------------------------------------------------
// Set flags from the command line, shifting them off as they are set.
//----------------------------------------------------------------------------

void SetFlags( CmdLine & cl ) {
	while( cl.Argc() > 1 ) {
		string s = cl.Argv(1);
		if ( s.size() && s[0] == '-' ) {
			if ( s == REM_FLAG ) {
				Remove = true;
			}
			else if ( s == PRUNE_FLAG ){
				Prune = true;
			}
			else if ( s == ADD_FLAG ) {
				Add = true;
			}
			else if ( s == SYS_FLAG ) {
				UseSys = true;
			}
			else if ( s == EXPAND_FLAG ) {
				Expand = true;
			}
			else if ( s == EXIST_FLAG ) {
				CheckExist = false;
			}
			else if ( s == LIST_FLAG ) {
				List = true;
			}
			else if ( s == QUERY_FLAG ) {
				QueryPath = true;
			}
			else if ( s == VERIFY_FLAG ) {
				Verify = true;
			}
			else {
				throw Error( "Invalid flag: " + s );
			}
			cl.Shift(1);
		}
		else {
			break;
		}
	}
}

//----------------------------------------------------------------------------
// List PATH to stdout, one directory per line
//----------------------------------------------------------------------------

void ListPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		cout << ( Expand ? ExpandPath( path.At(i) ) : path.At(i) ) << "\n";
	}
}

//----------------------------------------------------------------------------
// Add an entry to the path
//----------------------------------------------------------------------------

void AddPath( CmdLine & cl ) {
	if ( CheckExist ) {
		DWORD attr = GetFileAttributes( cl.Argv(1).c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES || ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			throw Error( "No such directory: " + cl.Argv(1));
		}
	}

	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( path.Find( cl.Argv(1), RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is already on the path" );
	}
	path.Add( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Remove entry from the path
//----------------------------------------------------------------------------

void RemovePath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	if ( ! path.Find( cl.Argv(1) , RegPath::NoExpand ) ) {
		throw Error( cl.Argv(1) + " is not on the path" );
	}
	path.Remove( cl.Argv(1) );
}

//----------------------------------------------------------------------------
// Prune duplicates and non-existent dirs from path
//----------------------------------------------------------------------------

void PrunePath( CmdLine &  ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );

	typedef std::set <string> DirSet;
	DirSet uniq;
	std::vector <string> ordered;

	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string dir = path.At( i );
		std::pair<DirSet::iterator, bool> ok = uniq.insert( dir );
		if ( ok.second ) {
			ordered.push_back( dir );
		}
		else {
			cout << "Pruned: " << dir << endl;
		}
	}

	string entry;

	for ( unsigned int i = 0; i < ordered.size(); i++ ) {
		string dir = ExpandPath( ordered[i] );
		DWORD attr = GetFileAttributes( dir.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ||
						! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Pruned: " << ordered[i] << endl;
		}
		else {
			if ( entry != "" ) {
				entry += ";";
			}
			entry += ordered[i];
		}

	}
	path.ReplaceAll( entry );
	std::cout << entry << std::endl;
}

//----------------------------------------------------------------------------
// See if directory is on the path, if so return success code (not boolean!)
//----------------------------------------------------------------------------

int FindPath( CmdLine & cl ) {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	return  path.Find( cl.Argv(1), Expand ? RegPath::Expand : RegPath::NoExpand ) ? 0 : 1;
}

//----------------------------------------------------------------------------
// Verify directories on path exist.
//----------------------------------------------------------------------------

int VerifyPath() {
	RegPath path( UseSys ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER );
	int bad = 0;
	for ( unsigned int i = 0; i < path.Count(); i++ ) {
		string epath = ExpandPath( path.At(i) );
		DWORD attr = GetFileAttributes( epath.c_str() );
		if ( attr == INVALID_FILE_ATTRIBUTES ) {
			cout << "No such directory: " << epath << "\n";
			bad++;
		}
		else if ( ! (attr & FILE_ATTRIBUTE_DIRECTORY ) ) {
			cout << "Not a directory: " << epath << "\n";
			bad++;
		}
	}
	return bad == 0 ? 0 : 1;
}

//----------------------------------------------------------------------------
// Display help
//----------------------------------------------------------------------------

void Help() {

	cout <<

	"pathed is a command-line tool for changing the Windows path in the registry\n"
	"Version 0.4\n"
	"Copyright (C) 2011 Neil Butterworth\n\n"
	"usage: pathed [-a | -r | -l  | -q | -v] [-s] [-f]  [-x] [dir]\n\n"
	"pathed -a dir    adds dir to the path in  the registry\n"
	"pathed -r dir    removes  dir from the path in the registry\n"
	"pathed -l        lists the entries on the current path\n"
	"pathed -q dir    queries registry, returns 0 if dir is on path, 1 otherwise\n"
	"pathed -v        verifies that all directories on the path exist\n"
	"pathed -p        prunes the path by removing duplicates and non-existent directories\n\n"
	"By default, pathed works on the path in HKEY_CURRENT_USER. You can make it use\n"
	"the system path in HKEY_LOCAL_MACHINE by using the -s flag.\n\n"
	"Normally, pathed will check a directory exists on disk before adding it to the\n"
	"path. To prevent this, use the -f flag.\n\n"
	"Paths containing environment variables such as %systemroot% will not normally have\n"
	"the variables expanded to their values. To expand them, use the -x flag\n\n"
	"AS WITH ALL COMMANDS THAT CHANGE THE REGISTRY, PATHED CAN CAUSE DAMAGE IF YOU\n"
	"DO NOT KNOW WHAT YOU ARE DOING. IF IN DOUBT, DO NOT USE IT!\n"

	<< endl;
}

//----------------------------------------------------------------------------
// Main for pathed
//----------------------------------------------------------------------------

int main( int argc, char *argv[] )
{
	try {
		CmdLine cl( argc, argv );

		SetFlags( cl );

		if ( cl.Argc() == 1 && ! ( List || Verify || Prune ) ) {
			Help();
			return 0;
		}
		else if ( ! (List || Add || QueryPath || Remove || Verify || Prune )  ) {
			throw Error( "Need one of -a, -r, -l, -q, -p or -v" );
		}

		if ( List ) {
			ListPath();
		}
		else if ( Verify ) {
			return VerifyPath();
		}
		else if ( QueryPath ) {
			return FindPath( cl );
		}
		else if ( Remove ) {
			RemovePath( cl );
		}
		else if ( Prune ) {
			PrunePath( cl );
		}
		else {
			AddPath( cl );
		}

		return 0;
	}
	catch( const Error & e ) {
		cerr << e.what() << endl;
		return 1;
	}
	catch( ... ) {
		cerr << "Unexpected exception" << endl;
		return 1;
	}
}
<|endoftext|>


<commit_before>/*
The MIT License

Copyright (c) 2010-2017 Google, Inc. http://angularjs.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in-
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <v8.h>
#include <node.h>
#include "heap_metrics.h"

extern "C" {

void init (v8::Handle <v8::Object> exports, v8::Handle<v8::Object> module)
{
    // Instantiate the Singleton Heap Stats Object
    heap_metrics::InitHeapStats();

    // Map the client API's
    NODE_SET_METHOD(exports, "DumpHeapStats", heap_metrics::DumpHeapStats);
    NODE_SET_METHOD(exports, "ForceGC", heap_metrics::ForceGC);
}

// Associate the init() function (above) as the entry point to the Node module.
// The function will be invoked on execution of the JavaScript require():
//
//     const heapstats = require( 'heapstats.node' );

NODE_MODULE(heap_metrics, init);

}; //
<commit_msg>Missed adding init.cpp to previous commit<commit_after>/*
The MIT License

Copyright (c) 2010-2017 Google, Inc. http://angularjs.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in-
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <v8.h>
#include <node.h>
#include "heap_metrics.h"

extern "C" {

void init (v8::Handle <v8::Object> exports, v8::Handle<v8::Object> module)
{
    // Instantiate the Singleton Heap Metrics Object
    heap_metrics::InitHeapMetrics();

    // Map the client API's
    NODE_SET_METHOD(exports, "DumpHeapMetrics", heap_metrics::DumpHeapMetrics);
    NODE_SET_METHOD(exports, "ForceGC", heap_metrics::ForceGC);
}

// Associate the init() function (above) as the entry point to the Node module.
// The function will be invoked on execution of the JavaScript require():
//
//     const heap_metrics = require( 'metrics.node' );

NODE_MODULE(heap_metrics, init);

}; //
<|endoftext|>


<commit_before>#include <mapbox/geojsonvt/geojsonvt.hpp>
#include <mapbox/geojsonvt/geojsonvt_clip.hpp>
#include <mapbox/geojsonvt/geojsonvt_convert.hpp>
#include <mapbox/geojsonvt/geojsonvt_util.hpp>

#include <queue>

namespace mapbox {
namespace util {
namespace geojsonvt {

std::unordered_map<std::string, clock_t> Time::activities;

#pragma mark - GeoJSONVT

std::vector<ProjectedFeature> GeoJSONVT::convertFeatures(const std::string& data,
                                                         uint8_t baseZoom,
                                                         double tolerance,
                                                         bool debug) {

    if (debug) {
        Time::time("preprocess data");
    }

    uint32_t z2 = 1 << baseZoom;

    JSDocument deserializedData;
    deserializedData.Parse<0>(data.c_str());

    if (deserializedData.HasParseError()) {
        printf("invalid GeoJSON\n");
        return std::vector<ProjectedFeature>();
    }

    const uint16_t extent = 4096;

    std::vector<ProjectedFeature> features =
        Convert::convert(deserializedData, tolerance / (z2 * extent));

    if (debug) {
        Time::timeEnd("preprocess data");
    }

    return features;
}

GeoJSONVT::GeoJSONVT(const std::vector<ProjectedFeature>& features_,
                     uint8_t baseZoom_,
                     uint8_t maxZoom_,
                     uint32_t maxPoints_,
                     double tolerance_,
                     bool debug_)
    : baseZoom(baseZoom_),
      maxZoom(maxZoom_),
      maxPoints(maxPoints_),
      tolerance(tolerance_),
      debug(debug_) {

    if (this->debug) {
        Time::time("generate tiles up to z" + std::to_string(maxZoom));
    }

    splitTile(features_, 0, 0, 0);

    if (this->debug) {
        printf("features: %i, points: %i\n", this->tiles[0].numFeatures, this->tiles[0].numPoints);
        Time::timeEnd("generate tiles up to z" + std::to_string(maxZoom));
        printf("tiles generated: %i {\n", this->total);
        for (const auto& pair : this->stats) {
            printf("    z%i: %i\n", pair.first, pair.second);
        }
        printf("}\n");
    }
}

void GeoJSONVT::splitTile(std::vector<ProjectedFeature> features_,
                          uint8_t z_,
                          uint32_t x_,
                          uint32_t y_,
                          int8_t cz,
                          int32_t cx,
                          int32_t cy) {

    std::queue<FeatureStackItem> stack;
    stack.emplace(features_, z_, x_, y_);

    while (stack.size()) {
        FeatureStackItem set = stack.front();
        stack.pop();
        std::vector<ProjectedFeature> features = std::move(set.features);
        uint8_t z = set.z;
        uint32_t x = set.x;
        uint32_t y = set.y;

        uint32_t z2 = 1 << z;
        const uint64_t id = toID(z, x, y);
        Tile* tile;
        double tileTolerance = (z == this->baseZoom ? 0 : this->tolerance / (z2 * this->extent));

        if (this->tiles.count(id)) {
            tile = &this->tiles[id];
        } else {
            if (this->debug) {
                Time::time("creation");
            }

            this->tiles[id] = std::move(
                Tile::createTile(features, z2, x, y, tileTolerance, extent, (z == this->baseZoom)));
            tile = &this->tiles[id];

            if (this->debug) {
                printf("tile z%i-%i-%i (features: %i, points: %i, simplified: %i\n", z, x, y,
                       tile->numFeatures, tile->numPoints, tile->numSimplified);
                Time::timeEnd("creation");

                uint8_t key = z;
                this->stats[key] = (this->stats.count(key) ? this->stats[key] + 1 : 1);
                this->total++;
            }
        }

        if ((cz < 0 && (z == this->maxZoom || this->tiles[id].numPoints <= this->maxPoints ||
                        isClippedSquare(tile->features, this->extent, this->buffer))) ||
            z == this->baseZoom || z == cz) {
            tile->source = std::vector<ProjectedFeature>(features);
            continue;
        }

        if (cz >= 0) {
            tile->source = std::vector<ProjectedFeature>(features);
        } else {
            tile->source = {};
        }

        if (this->debug) {
            Time::time("clipping");
        }

        double k1 = 0.5 * this->buffer / this->extent;
        double k2 = 0.5 - k1;
        double k3 = 0.5 + k1;
        double k4 = 1 + k1;

        std::vector<ProjectedFeature> tl;
        std::vector<ProjectedFeature> bl;
        std::vector<ProjectedFeature> tr;
        std::vector<ProjectedFeature> br;
        std::vector<ProjectedFeature> left;
        std::vector<ProjectedFeature> right;
        uint32_t m = 0;
        bool goLeft = false;
        bool goTop = false;

        if (cz >= 0) {
            m = 1 << (cz - z);
            goLeft = double(cx) / double(m) - double(x) < 0.5;
            goTop = double(cy) / double(m) - double(y) < 0.5;
        }

        if (cz < 0 || goLeft) {
            left = Clip::clip(features, z2, x - k1, x + k3, 0, intersectX);
        }

        if (cz < 0 || !goLeft) {
            right = Clip::clip(features, z2, x + k2, x + k4, 0, intersectX);
        }

        if (left.size()) {
            if (cz < 0 || goTop) {
                tl = Clip::clip(left, z2, y - k1, y + k3, 1, intersectY);
            }

            if (cz < 0 || !goTop) {
                bl = Clip::clip(left, z2, y + k2, y + k4, 1, intersectY);
            }
        }

        if (right.size()) {
            if (cz < 0 || goTop) {
                tr = Clip::clip(right, z2, y - k1, y + k3, 1, intersectY);
            }

            if (cz < 0 || !goTop) {
                br = Clip::clip(right, z2, y + k2, y + k4, 1, intersectY);
            }
        }

        if (this->debug) {
            Time::timeEnd("clipping");
        }

        if (tl.size())
            stack.emplace(std::move(tl), z + 1, x * 2, y * 2);
        if (bl.size())
            stack.emplace(std::move(bl), z + 1, x * 2, y * 2 + 1);
        if (tr.size())
            stack.emplace(std::move(tr), z + 1, x * 2 + 1, y * 2);
        if (br.size())
            stack.emplace(std::move(br), z + 1, x * 2 + 1, y * 2 + 1);
    }
}

Tile& GeoJSONVT::getTile(uint8_t z, uint32_t x, uint32_t y) {

    std::lock_guard<std::mutex> lock(mtx);

    const uint64_t id = toID(z, x, y);
    if (this->tiles.count(id)) {
        return this->tiles[id];
    }

    if (this->debug) {
        printf("drilling down to z%i-%i-%i\n", z, x, y);
    }

    uint8_t z0 = z;
    uint32_t x0 = x;
    uint32_t y0 = y;
    Tile* parent = nullptr;

    while (!parent && z0) {
        z0--;
        x0 = x0 / 2;
        y0 = y0 / 2;
        const uint64_t checkID = toID(z0, x0, y0);
        if (this->tiles.count(checkID)) {
            parent = &this->tiles[checkID];
        }
    }

    if (this->debug) {
        printf("found parent tile z%i-%i-%i\n", z0, x0, y0);
    }

    if (parent->source.size()) {
        if (isClippedSquare(parent->features, this->extent, this->buffer)) {
            return *parent;
        }

        if (this->debug) {
            Time::time("drilling down");
        }

        splitTile(parent->source, z0, x0, y0, z, x, y);

        if (this->debug) {
            Time::timeEnd("drilling down");
        }
    }

    return this->tiles[id];
}

bool GeoJSONVT::isClippedSquare(const std::vector<TileFeature>& features,
                                uint16_t extent_,
                                uint8_t buffer_) const {

    if (features.size() != 1) {
        return false;
    }

    const TileFeature feature = features.front();

    if (feature.type != TileFeatureType::Polygon || feature.geometry.size() > 1) {
        return false;
    }

    const TileRing* ring = &(feature.geometry.front().get<TileRing>());

    for (size_t i = 0; i < ring->points.size(); ++i) {
        const TilePoint* p = &ring->points[i];
        if ((p->x != -buffer_ && p->x != extent_ + buffer_) ||
            (p->y != -buffer_ && p->y != extent_ + buffer_)) {
            return false;
        }
    }

    return true;
}

uint64_t GeoJSONVT::toID(uint8_t z, uint32_t x, uint32_t y) {

    return (((1 << z) * y + x) * 32) + z;
}

ProjectedPoint GeoJSONVT::intersectX(const ProjectedPoint& a, const ProjectedPoint& b, double x) {

    double r1 = x;
    double r2 = (x - a.x) * (b.y - a.y) / (b.x - a.x) + a.y;
    double r3 = 1;

    return ProjectedPoint(r1, r2, r3);
}

ProjectedPoint GeoJSONVT::intersectY(const ProjectedPoint& a, const ProjectedPoint& b, double y) {

    double r1 = (y - a.y) * (b.x - a.x) / (b.y - a.y) + a.x;
    double r2 = y;
    double r3 = 1;

    return ProjectedPoint(r1, r2, r3);
}

} // namespace geojsonvt
} // namespace util
} // namespace mapbox
<commit_msg>better tile drill-down strategy<commit_after>#include <mapbox/geojsonvt/geojsonvt.hpp>
#include <mapbox/geojsonvt/geojsonvt_clip.hpp>
#include <mapbox/geojsonvt/geojsonvt_convert.hpp>
#include <mapbox/geojsonvt/geojsonvt_util.hpp>

#include <queue>

namespace mapbox {
namespace util {
namespace geojsonvt {

std::unordered_map<std::string, clock_t> Time::activities;

#pragma mark - GeoJSONVT

std::vector<ProjectedFeature> GeoJSONVT::convertFeatures(const std::string& data,
                                                         uint8_t baseZoom,
                                                         double tolerance,
                                                         bool debug) {

    if (debug) {
        Time::time("preprocess data");
    }

    uint32_t z2 = 1 << baseZoom;

    JSDocument deserializedData;
    deserializedData.Parse<0>(data.c_str());

    if (deserializedData.HasParseError()) {
        printf("invalid GeoJSON\n");
        return std::vector<ProjectedFeature>();
    }

    const uint16_t extent = 4096;

    std::vector<ProjectedFeature> features =
        Convert::convert(deserializedData, tolerance / (z2 * extent));

    if (debug) {
        Time::timeEnd("preprocess data");
    }

    return features;
}

GeoJSONVT::GeoJSONVT(const std::vector<ProjectedFeature>& features_,
                     uint8_t baseZoom_,
                     uint8_t maxZoom_,
                     uint32_t maxPoints_,
                     double tolerance_,
                     bool debug_)
    : baseZoom(baseZoom_),
      maxZoom(maxZoom_),
      maxPoints(maxPoints_),
      tolerance(tolerance_),
      debug(debug_) {

    if (this->debug) {
        Time::time("generate tiles up to z" + std::to_string(maxZoom));
    }

    splitTile(features_, 0, 0, 0);

    if (this->debug) {
        printf("features: %i, points: %i\n", this->tiles[0].numFeatures, this->tiles[0].numPoints);
        Time::timeEnd("generate tiles up to z" + std::to_string(maxZoom));
        printf("tiles generated: %i {\n", this->total);
        for (const auto& pair : this->stats) {
            printf("    z%i: %i\n", pair.first, pair.second);
        }
        printf("}\n");
    }
}

void GeoJSONVT::splitTile(std::vector<ProjectedFeature> features_,
                          uint8_t z_,
                          uint32_t x_,
                          uint32_t y_,
                          int8_t cz,
                          int32_t cx,
                          int32_t cy) {

    std::queue<FeatureStackItem> stack;
    stack.emplace(features_, z_, x_, y_);

    while (stack.size()) {
        FeatureStackItem set = stack.front();
        stack.pop();
        std::vector<ProjectedFeature> features = std::move(set.features);
        uint8_t z = set.z;
        uint32_t x = set.x;
        uint32_t y = set.y;

        uint32_t z2 = 1 << z;
        const uint64_t id = toID(z, x, y);
        Tile* tile;
        double tileTolerance = (z == this->baseZoom ? 0 : this->tolerance / (z2 * this->extent));

        if (this->tiles.count(id)) {
            tile = &this->tiles[id];
        } else {
            if (this->debug) {
                Time::time("creation");
            }

            this->tiles[id] = std::move(
                Tile::createTile(features, z2, x, y, tileTolerance, extent, (z == this->baseZoom)));
            tile = &this->tiles[id];

            if (this->debug) {
                printf("tile z%i-%i-%i (features: %i, points: %i, simplified: %i\n", z, x, y,
                       tile->numFeatures, tile->numPoints, tile->numSimplified);
                Time::timeEnd("creation");

                uint8_t key = z;
                this->stats[key] = (this->stats.count(key) ? this->stats[key] + 1 : 1);
                this->total++;
            }
        }

        // save reference to original geometry in tile so that we can drill down later if we stop now
        tile->source = std::vector<ProjectedFeature>(features);

        // stop tiling if the tile is degenerate
        if (isClippedSquare(tile->features, extent, buffer)) continue;

        // if it's the first-pass tiling
        if (!cz) {
            // stop tiling if we reached max zoom, or if the tile is too simple
            if (z == maxZoom || tile->numPoints <= maxPoints) continue;

        // if a drilldown to a specific tile
        } else {
            // stop tiling if we reached base zoom or our target tile zoom
            if (z == baseZoom || z == cz) continue;

            // stop tiling if it's not an ancestor of the target tile
            const auto m = 1 << (cz - z);
            if (x != std::floor(cx / m) && y != std::floor(cy / m)) continue;
        }

        // if we slice further down, no need to keep source geometry
        tile->source = {};

        if (this->debug) {
            Time::time("clipping");
        }

        double k1 = 0.5 * this->buffer / this->extent;
        double k2 = 0.5 - k1;
        double k3 = 0.5 + k1;
        double k4 = 1 + k1;

        std::vector<ProjectedFeature> tl;
        std::vector<ProjectedFeature> bl;
        std::vector<ProjectedFeature> tr;
        std::vector<ProjectedFeature> br;
        std::vector<ProjectedFeature> left;
        std::vector<ProjectedFeature> right;

        left  = Clip::clip(features, z2, x - k1, x + k3, 0, intersectX);
        right = Clip::clip(features, z2, x + k2, x + k4, 0, intersectX);

        if (left.size()) {
            tl = Clip::clip(left, z2, y - k1, y + k3, 1, intersectY);
            bl = Clip::clip(left, z2, y + k2, y + k4, 1, intersectY);
        }

        if (right.size()) {
            tr = Clip::clip(right, z2, y - k1, y + k3, 1, intersectY);
            br = Clip::clip(right, z2, y + k2, y + k4, 1, intersectY);
        }

        if (this->debug) {
            Time::timeEnd("clipping");
        }

        if (tl.size())
            stack.emplace(std::move(tl), z + 1, x * 2, y * 2);
        if (bl.size())
            stack.emplace(std::move(bl), z + 1, x * 2, y * 2 + 1);
        if (tr.size())
            stack.emplace(std::move(tr), z + 1, x * 2 + 1, y * 2);
        if (br.size())
            stack.emplace(std::move(br), z + 1, x * 2 + 1, y * 2 + 1);
    }
}

Tile& GeoJSONVT::getTile(uint8_t z, uint32_t x, uint32_t y) {

    std::lock_guard<std::mutex> lock(mtx);

    const uint64_t id = toID(z, x, y);
    if (this->tiles.count(id)) {
        return this->tiles[id];
    }

    if (this->debug) {
        printf("drilling down to z%i-%i-%i\n", z, x, y);
    }

    uint8_t z0 = z;
    uint32_t x0 = x;
    uint32_t y0 = y;
    Tile* parent = nullptr;

    while (!parent && z0) {
        z0--;
        x0 = x0 / 2;
        y0 = y0 / 2;
        const uint64_t checkID = toID(z0, x0, y0);
        if (this->tiles.count(checkID)) {
            parent = &this->tiles[checkID];
        }
    }

    if (this->debug) {
        printf("found parent tile z%i-%i-%i\n", z0, x0, y0);
    }

    if (parent->source.size()) {
        if (isClippedSquare(parent->features, this->extent, this->buffer)) {
            return *parent;
        }

        if (this->debug) {
            Time::time("drilling down");
        }

        splitTile(parent->source, z0, x0, y0, z, x, y);

        if (this->debug) {
            Time::timeEnd("drilling down");
        }
    }

    return this->tiles[id];
}

bool GeoJSONVT::isClippedSquare(const std::vector<TileFeature>& features,
                                uint16_t extent_,
                                uint8_t buffer_) const {

    if (features.size() != 1) {
        return false;
    }

    const TileFeature feature = features.front();

    if (feature.type != TileFeatureType::Polygon || feature.geometry.size() > 1) {
        return false;
    }

    const TileRing* ring = &(feature.geometry.front().get<TileRing>());

    for (size_t i = 0; i < ring->points.size(); ++i) {
        const TilePoint* p = &ring->points[i];
        if ((p->x != -buffer_ && p->x != extent_ + buffer_) ||
            (p->y != -buffer_ && p->y != extent_ + buffer_)) {
            return false;
        }
    }

    return true;
}

uint64_t GeoJSONVT::toID(uint8_t z, uint32_t x, uint32_t y) {

    return (((1 << z) * y + x) * 32) + z;
}

ProjectedPoint GeoJSONVT::intersectX(const ProjectedPoint& a, const ProjectedPoint& b, double x) {

    double r1 = x;
    double r2 = (x - a.x) * (b.y - a.y) / (b.x - a.x) + a.y;
    double r3 = 1;

    return ProjectedPoint(r1, r2, r3);
}

ProjectedPoint GeoJSONVT::intersectY(const ProjectedPoint& a, const ProjectedPoint& b, double y) {

    double r1 = (y - a.y) * (b.x - a.x) / (b.y - a.y) + a.x;
    double r2 = y;
    double r3 = 1;

    return ProjectedPoint(r1, r2, r3);
}

} // namespace geojsonvt
} // namespace util
} // namespace mapbox
<|endoftext|>


<commit_before>#include "gl_core_4_5.h"
#include "GLFW/glfw3.h"
#include "assimp/Importer.hpp"
#include "assimp/postprocess.h"
#include "assimp/scene.h"
#include "Camera.hpp"
#include "glm/gtx/transform.hpp"
#include "Material.hpp"
#include "MeshManager.hpp"
#include "Model.hpp"
#include "RenderManager.hpp"
#include "SceneGraph.hpp"
#include "Shader.hpp"
#include "ShaderManager.hpp"
#include "ShadingProgram.hpp"
#include "Texture.hpp"
#include "TextureManager.hpp"
#include "Mesh.hpp"
#include <chrono>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

using namespace GlProj::Graphics;

inline void APIENTRY GLDbgCallback(GLenum source, GLenum type, GLuint id,
	GLenum severity, GLsizei length, const GLchar* message,
	const void*)
{
	thread_local static std::string output;
	output.clear();
	output += "GL error:\nSource: ";

	switch (source)
	{
	default:
		output += "GL_DEBUG_SOURCE_OTHER";
		break;
	case GL_DEBUG_SOURCE_API:
		output += "GL_DEBUG_SOURCE_API";
		break;
	case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
		output += "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
		break;
	case GL_DEBUG_SOURCE_SHADER_COMPILER:
		output += "GL_DEBUG_SOURCE_SHADER_COMPILER";
		break;
	case GL_DEBUG_SOURCE_THIRD_PARTY:
		output += "GL_DEBUG_SOURCE_THIRD_PARTY";
		break;
	case GL_DEBUG_SOURCE_APPLICATION:
		output += "GL_DEBUG_SOURCE_APPLICATION";
		break;
	}
	output += "\nType: ";

	switch (type)
	{
	default:
		output += "GL_DEBUG_TYPE_OTHER";
		break;
	case GL_DEBUG_TYPE_ERROR:
		output += "GL_DEBUG_TYPE_ERROR";
		break;
	case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
		output += "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR";
		break;
	case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
		output += "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR";
		break;
	case GL_DEBUG_TYPE_PORTABILITY:
		output += "GL_DEBUG_TYPE_PORTABILITY";
		break;
	case GL_DEBUG_TYPE_PERFORMANCE:
		output += "GL_DEBUG_TYPE_PERFORMANCE";
		break;
	case GL_DEBUG_TYPE_MARKER:
		output += "GL_DEBUG_TYPE_MARKER";
		break;
	case GL_DEBUG_TYPE_PUSH_GROUP:
		output += "GL_DEBUG_TYPE_PUSH_GROUP";
		break;
	case GL_DEBUG_TYPE_POP_GROUP:
		output += "GL_DEBUG_TYPE_POP_GROUP";
		break;
	}
	output += "\nID: ";
	output += std::to_string(id);
	output += "\nSeverity: ";

	switch (severity)
	{
	default:
		output += "GL_DEBUG_SEVERITY_NOTIFICATION";
		break;
	case GL_DEBUG_SEVERITY_HIGH:
		output += "GL_DEBUG_SEVERITY_HIGH";
		break;
	case GL_DEBUG_SEVERITY_MEDIUM:
		output += "GL_DEBUG_SEVERITY_MEDIUM";
		break;
	case GL_DEBUG_SEVERITY_LOW:
		output += "GL_DEBUG_SEVERITY_LOW";
		break;
	}
	output += "\nMessage:\n";
	output += message;

	std::cout << output << "\n\n";
}

inline glm::mat4 aiToGlm(const aiMatrix4x4& o)
{
	return{o.a1, o.a2, o.a3, o.a4,
		   o.b1, o.b2, o.b3, o.b4,
		   o.c1, o.c2, o.c3, o.c4,
		   o.d1, o.d2, o.d3, o.d4};
}

inline glm::mat4 ApplyHierarchy(const GlProj::Utilities::SceneNode<ModelData>& n)
{
	auto node = &n;

	auto t = glm::mat4(1);
	while (node != nullptr)
	{
		t *= node->data.transform;
		node = node->parent;
	}

	return t;
}

void PopulateGraph(SceneGraph<ModelData>& graph,
					GlProj::Utilities::SceneNode<ModelData>* parent,
					aiNode* node)
{
	parent = graph.emplace(parent, aiToGlm(node->mTransformation),
							std::vector<unsigned int>(node->mMeshes, node->mMeshes + node->mNumMeshes),
							node->mName.C_Str());

	auto children = node->mChildren;
	auto childCount = int(node->mNumChildren);

	for(int i = 0; i < childCount; ++i)
	{
		PopulateGraph(graph, parent, children[i]);
	}
}

void glfwExecErrorCallback(int, const char* msg)
{
	std::cerr << "glfw error: " << msg << std::endl;
}

LocalSharedPtr<Material> GetDefaultMaterial()
{
	static bool firstRun = true;
	static auto prog = GenerateProgram();
	static auto mat = GlProj::Utilities::make_localshared<Material>();
	if (!firstRun) return mat;

	auto vs = LoadShader(GetShaderManager(), GL_VERTEX_SHADER, "./data/shaders/BasicShader.vs");
	auto fs = LoadShader(GetShaderManager(), GL_FRAGMENT_SHADER, "./data/shaders/BasicShader.fs");

	AttachShader(prog.get(), vs.get());
	AttachShader(prog.get(), fs.get());
	LinkProgram(prog.get());
	prog->FetchProgramInfo();

	*mat = prog;
	firstRun = false;

	return mat;
}

void PrepareAndRunGame(GLFWwindow* window)
{
	Assimp::Importer importer{};
	auto bunny = importer.ReadFile("./data/models/bunny.obj", aiProcess_Triangulate | aiProcess_CalcTangentSpace | aiProcess_SortByPType | aiProcess_GenUVCoords | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_GenSmoothNormals);
	if (bunny == nullptr)
	{
		std::string err;
		err += importer.GetErrorString();
		throw std::runtime_error(err);
	}

	auto& initText = "System Init";

	glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, sizeof(initText), initText);
	std::vector<Renderable> submeshes;
	submeshes.reserve(bunny->mNumMeshes);
	auto material = GetDefaultMaterial();

	for (int i = 0; i < int(bunny->mNumMeshes); ++i)
	{
		submeshes.push_back({ RegisterMesh(GetMeshManager(), bunny->mMeshes[i], bunny->mMeshes[i]->mName.C_Str()),
							  nullptr });
	}

	SceneGraph<ModelData> bunnyGraph;
	PopulateGraph(bunnyGraph, nullptr, bunny->mRootNode);

	Model bunnyModel{ submeshes, std::move(bunnyGraph) };

	GlProj::Utilities::TestSceneGraph();

	glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
	auto renderer = GetRenderManager();
	auto batch = GenerateRenderBatch(renderer);

	std::vector<local_shared_ptr<RenderableHandle>> handles;
	for (int i = 0; i < int(submeshes.size()); ++i)
	{
		handles.push_back(SubmitRenderable(batch.get(), *(submeshes[i].mesh), submeshes[i].material.get()));
	}
	auto& hierarchy = bunnyModel.GetHierarchy();
	for (auto pos = hierarchy.begin(); pos != hierarchy.end(); ++pos)
	{
		if (pos->meshes.empty()) continue;

		auto transform = ApplyHierarchy(*pos.current);
		auto& dat = *pos;
		for (const auto& i : dat.meshes)
		{
			SetTransform(handles[i].get(), transform);
		}
	}
	SetOverrideMaterial(batch.get(), material.get());
	auto cam = Camera{ Camera::Orthographic{glm::vec2{8.0f, 4.5f}}, -5.0f, 5.0f};
	cam.transform = Transform{ {0.0f, -1.0f, 0.0f}, glm::quat(), {1.0f, 1.0f, 1.0f} };
	UpdateBatchCamera(batch.get(), cam);

	glPopDebugGroup();

	auto& renderingGroup = "Render loop";

	glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, sizeof(renderingGroup), renderingGroup);

	float angle = 0.0f;
	const float rotationSpeed = 0.2f;
	auto prevTime = glfwGetTime();

	while (!glfwWindowShouldClose(window))
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
				GL_STENCIL_BUFFER_BIT);

		auto newTime = glfwGetTime();
		auto delta = newTime - prevTime;
		prevTime = newTime;
		angle += float(delta) * rotationSpeed;

		hierarchy.begin()->transform = glm::rotate(angle, glm::vec3{0.0f, 1.0f, 0.0f});

		for (auto pos = hierarchy.begin(); pos != hierarchy.end(); ++pos)
		{
			if (pos->meshes.empty()) continue;

			auto transform = ApplyHierarchy(*pos.current);
			auto& dat = *pos;
			for (const auto& i : dat.meshes)
			{
				SetTransform(handles[i].get(), transform);
			}
		}

		Draw(renderer);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glPopDebugGroup();
}

int main()
try
{
	std::ios_base::sync_with_stdio(false);

	glfwSetErrorCallback(glfwExecErrorCallback);
	if (glfwInit() == GLFW_FALSE)
	{
		return EXIT_FAILURE;
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
#ifdef _DEBUG
	glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
#endif

	auto win = glfwCreateWindow(1280, 720, "Bad Window", nullptr, nullptr);

	if (win == nullptr)
	{
		return EXIT_FAILURE;
	}

	int contextMajorVersion = glfwGetWindowAttrib(win, GLFW_CONTEXT_VERSION_MAJOR);
	int contextMinorVersion = glfwGetWindowAttrib(win, GLFW_CONTEXT_VERSION_MINOR);

	std::cout << "Major version is " << contextMajorVersion << '\n';
	std::cout << "Minor version is " << contextMinorVersion << std::endl;

	glfwMakeContextCurrent(win);

	if (ogl_LoadFunctions() != ogl_LOAD_SUCCEEDED)
	{
		return EXIT_FAILURE;
	}

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_DEBUG_OUTPUT);

	glDebugMessageCallback(GLDbgCallback, nullptr);

	glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE);

	PrepareAndRunGame(win);

	glfwDestroyWindow(win);
	glfwTerminate();
}
catch(std::exception& e)
{
	std::cerr << e.what() << std::endl;
	throw;
}
<commit_msg>Added an algorithm for converting meshes with the same name into unique names. Working on post processing. UVs aren't being generated.<commit_after>#include "gl_core_4_5.h"
#include "GLFW/glfw3.h"
#include "assimp\DefaultLogger.hpp"
#include "assimp/Importer.hpp"
#include "assimp/postprocess.h"
#include "assimp/scene.h"
#include "Camera.hpp"
#include "glm/gtx/transform.hpp"
#include "Material.hpp"
#include "MeshManager.hpp"
#include "Model.hpp"
#include "RenderManager.hpp"
#include "SceneGraph.hpp"
#include "Shader.hpp"
#include "ShaderManager.hpp"
#include "ShadingProgram.hpp"
#include "Texture.hpp"
#include "TextureManager.hpp"
#include "Mesh.hpp"
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <string>
#include <vector>

using namespace GlProj::Graphics;

inline void APIENTRY GLDbgCallback(GLenum source, GLenum type, GLuint id,
	GLenum severity, GLsizei length, const GLchar* message,
	const void*)
{
	thread_local static std::string output;
	output.clear();
	output += "GL error:\nSource: ";

	switch (source)
	{
	default:
		output += "GL_DEBUG_SOURCE_OTHER";
		break;
	case GL_DEBUG_SOURCE_API:
		output += "GL_DEBUG_SOURCE_API";
		break;
	case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
		output += "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
		break;
	case GL_DEBUG_SOURCE_SHADER_COMPILER:
		output += "GL_DEBUG_SOURCE_SHADER_COMPILER";
		break;
	case GL_DEBUG_SOURCE_THIRD_PARTY:
		output += "GL_DEBUG_SOURCE_THIRD_PARTY";
		break;
	case GL_DEBUG_SOURCE_APPLICATION:
		output += "GL_DEBUG_SOURCE_APPLICATION";
		break;
	}
	output += "\nType: ";

	switch (type)
	{
	default:
		output += "GL_DEBUG_TYPE_OTHER";
		break;
	case GL_DEBUG_TYPE_ERROR:
		output += "GL_DEBUG_TYPE_ERROR";
		break;
	case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
		output += "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR";
		break;
	case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
		output += "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR";
		break;
	case GL_DEBUG_TYPE_PORTABILITY:
		output += "GL_DEBUG_TYPE_PORTABILITY";
		break;
	case GL_DEBUG_TYPE_PERFORMANCE:
		output += "GL_DEBUG_TYPE_PERFORMANCE";
		break;
	case GL_DEBUG_TYPE_MARKER:
		output += "GL_DEBUG_TYPE_MARKER";
		break;
	case GL_DEBUG_TYPE_PUSH_GROUP:
		output += "GL_DEBUG_TYPE_PUSH_GROUP";
		break;
	case GL_DEBUG_TYPE_POP_GROUP:
		output += "GL_DEBUG_TYPE_POP_GROUP";
		break;
	}
	output += "\nID: ";
	output += std::to_string(id);
	output += "\nSeverity: ";

	switch (severity)
	{
	default:
		output += "GL_DEBUG_SEVERITY_NOTIFICATION";
		break;
	case GL_DEBUG_SEVERITY_HIGH:
		output += "GL_DEBUG_SEVERITY_HIGH";
		break;
	case GL_DEBUG_SEVERITY_MEDIUM:
		output += "GL_DEBUG_SEVERITY_MEDIUM";
		break;
	case GL_DEBUG_SEVERITY_LOW:
		output += "GL_DEBUG_SEVERITY_LOW";
		break;
	}
	output += "\nMessage:\n";
	output += message;

	std::cout << output << "\n\n";
}

inline glm::mat4 aiToGlm(const aiMatrix4x4& o)
{
	return{o.a1, o.a2, o.a3, o.a4,
		   o.b1, o.b2, o.b3, o.b4,
		   o.c1, o.c2, o.c3, o.c4,
		   o.d1, o.d2, o.d3, o.d4};
}

template<typename I>
//requires value_type of iterator is std::string
inline void MakeNamesUnique(I first, I last)
{
	auto firstMesh = first;
	while (firstMesh != last)
	{
		auto pairStart = std::adjacent_find(firstMesh, last);
		if (pairStart == last)
		{
			break;
		}
		int i = 0;

		std::string prev = *pairStart;
		auto first = pairStart;
		//First duplicate will have a 0-suffix
		*first += std::to_string(i);
		++i;
		++pairStart;
		//Second duplicate will have a 1-suffix
		*pairStart += std::to_string(i);
		++pairStart;
		++i;
		//Subsequent duplicates will have
		while (pairStart != last && *pairStart == prev)
		{
			*pairStart += std::to_string(i);
			++pairStart;
			++i;
		}
		firstMesh = pairStart;
	}
}

inline glm::mat4 ApplyHierarchy(const GlProj::Utilities::SceneNode<ModelData>& n)
{
	auto node = &n;

	auto t = glm::mat4(1);
	while (node != nullptr)
	{
		t *= node->data.transform;
		node = node->parent;
	}

	return t;
}

void PopulateGraph(SceneGraph<ModelData>& graph,
					GlProj::Utilities::SceneNode<ModelData>* parent,
					aiNode* node)
{
	parent = graph.emplace(parent, aiToGlm(node->mTransformation),
							std::vector<unsigned int>(node->mMeshes, node->mMeshes + node->mNumMeshes),
							node->mName.C_Str());

	auto children = node->mChildren;
	auto childCount = int(node->mNumChildren);

	for(int i = 0; i < childCount; ++i)
	{
		PopulateGraph(graph, parent, children[i]);
	}
}

void glfwExecErrorCallback(int, const char* msg)
{
	std::cerr << "glfw error: " << msg << std::endl;
}

LocalSharedPtr<Material> GetDefaultMaterial()
{
	static bool firstRun = true;
	static auto prog = GenerateProgram();
	static auto mat = GlProj::Utilities::make_localshared<Material>();
	if (!firstRun) return mat;

	auto vs = LoadShader(GetShaderManager(), GL_VERTEX_SHADER, "./data/shaders/BasicShader.vs");
	auto fs = LoadShader(GetShaderManager(), GL_FRAGMENT_SHADER, "./data/shaders/BasicShader.fs");

	AttachShader(prog.get(), vs.get());
	AttachShader(prog.get(), fs.get());
	LinkProgram(prog.get());
	prog->FetchProgramInfo();

	*mat = prog;
	firstRun = false;

	return mat;
}

void PrepareAndRunGame(GLFWwindow* window)
{
	Assimp::Importer importer{};
	auto newLogger = Assimp::DefaultLogger::create("AssimpLog.txt", Assimp::Logger::NORMAL, aiDefaultLogStream_STDOUT);
	auto bunny = importer.ReadFile("./data/models/bunny.obj", aiProcess_Triangulate | aiProcess_SortByPType
															| aiProcess_GenUVCoords | aiProcess_OptimizeGraph
															| aiProcess_OptimizeMeshes | aiProcess_GenSmoothNormals);

	importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, 32767);
	bunny = importer.ApplyPostProcessing(aiProcess_SplitLargeMeshes | aiProcess_CalcTangentSpace | aiProcess_ValidateDataStructure);

	if (bunny == nullptr)
	{
		std::string err;
		err += importer.GetErrorString();
		throw std::runtime_error(err);
	}

	Assimp::DefaultLogger::kill();

	auto& initText = "System Init";

	glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, sizeof(initText), initText);
	std::vector<Renderable> submeshes;
	submeshes.reserve(bunny->mNumMeshes);
	auto material = GetDefaultMaterial();

	std::vector<std::string> meshNames;
	meshNames.reserve(bunny->mNumMeshes);
	std::transform(bunny->mMeshes, bunny->mMeshes + bunny->mNumMeshes, std::back_inserter(meshNames),
		[](const auto& x)
	{
		return x->mName.C_Str();
	});

	MakeNamesUnique(meshNames.begin(), meshNames.end());

	for (int i = 0; i < int(bunny->mNumMeshes); ++i)
	{
		submeshes.push_back({ RegisterMesh(GetMeshManager(), bunny->mMeshes[i], meshNames[i]),
							  nullptr });
	}

	SceneGraph<ModelData> bunnyGraph;
	PopulateGraph(bunnyGraph, nullptr, bunny->mRootNode);

	Model bunnyModel{ submeshes, std::move(bunnyGraph) };

	GlProj::Utilities::TestSceneGraph();

	glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
	auto renderer = GetRenderManager();
	auto batch = GenerateRenderBatch(renderer);

	std::vector<local_shared_ptr<RenderableHandle>> handles;
	for (int i = 0; i < int(submeshes.size()); ++i)
	{
		handles.push_back(SubmitRenderable(batch.get(), *(submeshes[i].mesh), submeshes[i].material.get()));
	}
	auto& hierarchy = bunnyModel.GetHierarchy();
	for (auto pos = hierarchy.begin(); pos != hierarchy.end(); ++pos)
	{
		if (pos->meshes.empty()) continue;

		auto transform = ApplyHierarchy(*pos.current);
		auto& dat = *pos;
		for (const auto& i : dat.meshes)
		{
			SetTransform(handles[i].get(), transform);
		}
	}
	SetOverrideMaterial(batch.get(), material.get());
	auto cam = Camera{ Camera::Orthographic{glm::vec2{8.0f, 4.5f}}, -5.0f, 5.0f};
	cam.transform = Transform{ {0.0f, -1.0f, 0.0f}, glm::quat(), {1.0f, 1.0f, 1.0f} };
	UpdateBatchCamera(batch.get(), cam);

	glPopDebugGroup();

	auto& renderingGroup = "Render loop";

	glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, sizeof(renderingGroup), renderingGroup);

	float angle = 0.0f;
	const float rotationSpeed = 0.2f;
	auto prevTime = glfwGetTime();

	while (!glfwWindowShouldClose(window))
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
				GL_STENCIL_BUFFER_BIT);

		auto newTime = glfwGetTime();
		auto delta = newTime - prevTime;
		prevTime = newTime;
		angle += float(delta) * rotationSpeed;

		hierarchy.begin()->transform = glm::rotate(angle, glm::vec3{0.0f, 1.0f, 0.0f});

		for (auto pos = hierarchy.begin(); pos != hierarchy.end(); ++pos)
		{
			if (pos->meshes.empty()) continue;

			auto transform = ApplyHierarchy(*pos.current);
			auto& dat = *pos;
			for (const auto& i : dat.meshes)
			{
				SetTransform(handles[i].get(), transform);
			}
		}

		Draw(renderer);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glPopDebugGroup();
}

int main()
try
{
	std::ios_base::sync_with_stdio(false);

	glfwSetErrorCallback(glfwExecErrorCallback);
	if (glfwInit() == GLFW_FALSE)
	{
		return EXIT_FAILURE;
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
#ifdef _DEBUG
	glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
#endif

	auto win = glfwCreateWindow(1280, 720, "Bad Window", nullptr, nullptr);

	if (win == nullptr)
	{
		return EXIT_FAILURE;
	}

	int contextMajorVersion = glfwGetWindowAttrib(win, GLFW_CONTEXT_VERSION_MAJOR);
	int contextMinorVersion = glfwGetWindowAttrib(win, GLFW_CONTEXT_VERSION_MINOR);

	std::cout << "Major version is " << contextMajorVersion << '\n';
	std::cout << "Minor version is " << contextMinorVersion << std::endl;

	glfwMakeContextCurrent(win);

	if (ogl_LoadFunctions() != ogl_LOAD_SUCCEEDED)
	{
		return EXIT_FAILURE;
	}

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_DEBUG_OUTPUT);

	glDebugMessageCallback(GLDbgCallback, nullptr);

	//glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE);

	PrepareAndRunGame(win);

	glfwDestroyWindow(win);
	glfwTerminate();
}
catch(std::exception& e)
{
	std::cerr << e.what() << std::endl;
	throw;
}
<|endoftext|>


<commit_before>//
//  main.cpp
//  PointPairFeatures
//
//  Created by Adrian Haarbach on 27.06.14.
//  Copyright (c) 2014 Adrian Haarbach. All rights reserved.
//
#include "Visualize.h"
#include "LoadingSaving.h"
#include "PointPairFeatures.h"
#include "PointCloudManipulation.h"

int main(int argc, char * argv[])
{

    //MatrixXd m = MatrixXd::Random(200,6);

    MatrixXd m=LoadingSaving::loadXYZ("bunny/model.xyz");//.block(0, 0, 1000, 6);

    MatrixXd mSmall=PointCloudManipulation::downSample(m,false);

    //double diamM=PointCloudManipulation::getPointCloudDiameter(mSmall);

    //LoadingSaving::saveXYZ("bunny/model_downSampled.xyz", mSmall);
    //MatrixXd mSmallVoxelCenter=PointPairFeatures::downSample(m,true);

    //Visualize::getInstance()->ms.push_back({m,RowVector3f(1,0,0)});
    //Visualize::getInstance()->ms.push_back({mSmall,RowVector3f(1,0.5,0)});
    //Visualize::getInstance()->ms.push_back({mSmallVoxelCenter,RowVector3f(1,0.9,0)});

    MatrixXd s=LoadingSaving::loadXYZ("bunny/scene.xyz");
    MatrixXd sSmall=PointCloudManipulation::downSample(s,false);
    //LoadingSaving::saveXYZ("bunny/scene_downSampled.xyz", sSmall);

    Projective3d P= Translation3d(0.1, 0, 0)*AngleAxisd(0.2, Vector3d(1,0,0));// * Scaling(s);
    sSmall=PointCloudManipulation::projectPointsAndNormals(P, sSmall);

    PointPairFeatures* ppfs=new PointPairFeatures();

    //Visualize::getInstance()->ms.push_back({sSmall,RowVector3f(0.5,1,0)});

    GlobalModelDescription map =  ppfs->buildGlobalModelDescription(mSmall);

    Matches matches = ppfs->matchSceneAgainstModel(sSmall, map);

    vector<MatrixXi> accVec=ppfs->voting(matches);

    //cout<<accVec[0]<<endl;

    Poses Pests = ppfs->computePoses(accVec, mSmall, sSmall);

    Projective3d Pest=ppfs->clusterPoses(Pests);

    cout<<"groundtruth:"<<endl;
    cout<<P.matrix()<<endl;

    //MatrixXd modelPoseEst=PointCloudManipulation::projectPointsAndNormals(Pest, m);

    //printMap(map);
    //KeyBucketPairList best10=PointPairFeatures::print10(map);

    //Visualize::getInstance()->b=best10;

    Visualize* inst=Visualize::getInstance();
    inst->model=mSmall;
    inst->scene=sSmall;
    //inst->modelT=modelPoseEst;
    inst->matches=matches;
    Visualize::visualize();

}<commit_msg>commented out clusterPoses to get nicer output for testing<commit_after>//
//  main.cpp
//  PointPairFeatures
//
//  Created by Adrian Haarbach on 27.06.14.
//  Copyright (c) 2014 Adrian Haarbach. All rights reserved.
//
#include "Visualize.h"
#include "LoadingSaving.h"
#include "PointPairFeatures.h"
#include "PointCloudManipulation.h"

int main(int argc, char * argv[])
{

    //MatrixXd m = MatrixXd::Random(200,6);

    MatrixXd m=LoadingSaving::loadXYZ("bunny/model.xyz");//.block(0, 0, 1000, 6);

    MatrixXd mSmall=PointCloudManipulation::downSample(m,false);

    //double diamM=PointCloudManipulation::getPointCloudDiameter(mSmall);

    //LoadingSaving::saveXYZ("bunny/model_downSampled.xyz", mSmall);
    //MatrixXd mSmallVoxelCenter=PointPairFeatures::downSample(m,true);

    //Visualize::getInstance()->ms.push_back({m,RowVector3f(1,0,0)});
    //Visualize::getInstance()->ms.push_back({mSmall,RowVector3f(1,0.5,0)});
    //Visualize::getInstance()->ms.push_back({mSmallVoxelCenter,RowVector3f(1,0.9,0)});

    MatrixXd s=LoadingSaving::loadXYZ("bunny/scene.xyz");
    MatrixXd sSmall=PointCloudManipulation::downSample(s,false);
    //LoadingSaving::saveXYZ("bunny/scene_downSampled.xyz", sSmall);

    Projective3d P= Translation3d(0.1, 0, 0)*AngleAxisd(0.2, Vector3d(1,0,0));// * Scaling(s);
    sSmall=PointCloudManipulation::projectPointsAndNormals(P, sSmall);

    PointPairFeatures* ppfs=new PointPairFeatures();

    //Visualize::getInstance()->ms.push_back({sSmall,RowVector3f(0.5,1,0)});

    GlobalModelDescription map =  ppfs->buildGlobalModelDescription(mSmall);

    Matches matches = ppfs->matchSceneAgainstModel(sSmall, map);

    vector<MatrixXi> accVec=ppfs->voting(matches);

    //cout<<accVec[0]<<endl;

    Poses Pests = ppfs->computePoses(accVec, mSmall, sSmall);

    //Projective3d Pest=ppfs->clusterPoses(Pests);

    cout<<"groundtruth:"<<endl;
    cout<<P.matrix()<<endl;

    //MatrixXd modelPoseEst=PointCloudManipulation::projectPointsAndNormals(Pest, m);

    //printMap(map);
    //KeyBucketPairList best10=PointPairFeatures::print10(map);

    //Visualize::getInstance()->b=best10;

    Visualize* inst=Visualize::getInstance();
    inst->model=mSmall;
    inst->scene=sSmall;
    //inst->modelT=modelPoseEst;
    inst->matches=matches;
    Visualize::visualize();

}<|endoftext|>


<commit_before>#include "resplunk/event/CancellableEvent.hpp"
#include "resplunk/event/CloneableEvent.hpp"

#include <iostream>

template<typename... Args>
using EventImplementor = resplunk::event::EventImplementor<Args...>;
using CancellableEvent = resplunk::event::CancellableEvent;
template<typename... Args>
using EventProcessor = resplunk::event::EventProcessor<Args...>;
template<typename... Args>
using EventReactor = resplunk::event::EventReactor<Args...>;
template<template<typename, typename...> typename Arg = std::unique_ptr, typename... Args>
using CloneableEvent = resplunk::event::CloneableEvent<Arg, Args...>;
template<typename... Args>
using LambdaEventProcessor = resplunk::event::LambdaEventProcessor<Args...>;
using Event = resplunk::event::Event;
using ListenerPriority = resplunk::event::ListenerPriority;

struct TestEvent
: EventImplementor<TestEvent, CancellableEvent>
{
	int x;
	TestEvent(int x) noexcept
	: x(x)
	{
	}
};

struct TestListener
: EventProcessor<TestEvent>
, EventReactor<TestEvent>
{
	TestListener() noexcept
	{
	}

	virtual void onEvent(TestEvent &e) const noexcept override
	{
		std::cout << "P x = " << e.x << std::endl;
		if(e.x > 10)
		{
			e.x = 10;
		}
		else if(e.x < 0)
		{
			e.cancelled(true);
		}
	}
	virtual void onEvent(TestEvent const &e) noexcept override
	{
		std::cout << "R x = " << e.x << std::endl;
	}
};

struct TestEventA
: EventImplementor<TestEventA, TestEvent>
{
	TestEventA() noexcept
	: TestEvent(1)
	{
	}
};
struct TestEventB
: EventImplementor<TestEventB, TestEvent>
{
	TestEventB() noexcept
	: TestEvent(2)
	{
	}
};

struct DerivedTestEvent
: EventImplementor<DerivedTestEvent, TestEventA, TestEventB>
{
	DerivedTestEvent() noexcept
	: TestEvent(4)
	{
	}
};

struct CloneableTestEvent
: EventImplementor<CloneableTestEvent, TestEvent, CloneableEvent<>>
{
	CloneableTestEvent(int x) noexcept
	: TestEvent(x)
	{
	}

private:
	virtual CloneableTestEvent *clone() const noexcept override
	{
		return new CloneableTestEvent(x);
	}
};

int main(int nargs, char **args) noexcept
{
	LambdaEventProcessor<Event> lep
	{
		[](Event &e)
		{
			std::cout << std::endl << "E @ " << &e
			<< " is \"" << typeid(e).name() << '"' << std::endl;
		},
		ListenerPriority::FIRST
	};
	TestListener l;
	TestEvent{7}.call();
	TestEvent{-1}.call();
	TestEvent{14}.call();
	DerivedTestEvent{}.call();
	CloneableTestEvent::Clone(CloneableTestEvent{9})->call();
}
<commit_msg>Small tweak to test code<commit_after>#include "resplunk/event/CancellableEvent.hpp"
#include "resplunk/event/CloneableEvent.hpp"

#include <iostream>

template<typename... Args>
using EventImplementor = resplunk::event::EventImplementor<Args...>;
using CancellableEvent = resplunk::event::CancellableEvent;
template<typename... Args>
using EventProcessor = resplunk::event::EventProcessor<Args...>;
template<typename... Args>
using EventReactor = resplunk::event::EventReactor<Args...>;
template<template<typename, typename...> typename Arg = std::unique_ptr, typename... Args>
using CloneableEvent = resplunk::event::CloneableEvent<Arg, Args...>;
template<typename... Args>
using LambdaEventProcessor = resplunk::event::LambdaEventProcessor<Args...>;
using Event = resplunk::event::Event;
using ListenerPriority = resplunk::event::ListenerPriority;

struct TestEvent
: EventImplementor<TestEvent, CancellableEvent>
{
	int x;
	TestEvent(int x) noexcept
	: x(x)
	{
	}
};

struct TestListener
: EventProcessor<TestEvent>
, EventReactor<TestEvent>
{
	TestListener() noexcept
	{
	}

	virtual void onEvent(TestEvent &e) const noexcept override
	{
		std::cout << "P x = " << e.x << std::endl;
		if(e.x > 10)
		{
			e.x = 10;
		}
		else if(e.x < 0)
		{
			e.cancelled(true);
		}
	}
	virtual void onEvent(TestEvent const &e) noexcept override
	{
		std::cout << "R x = " << e.x << std::endl;
	}
};

struct TestEventA
: EventImplementor<TestEventA, TestEvent>
{
	TestEventA() noexcept
	: TestEvent(1)
	{
	}
};
struct TestEventB
: EventImplementor<TestEventB, TestEvent>
{
	TestEventB() noexcept
	: TestEvent(2)
	{
	}
};

struct DerivedTestEvent
: EventImplementor<DerivedTestEvent, TestEventA, TestEventB>
{
	DerivedTestEvent(int x) noexcept
	: TestEvent(x)
	{
	}
};

struct CloneableTestEvent
: EventImplementor<CloneableTestEvent, TestEvent, CloneableEvent<>>
{
	CloneableTestEvent(int x) noexcept
	: TestEvent(x)
	{
	}

private:
	virtual CloneableTestEvent *clone() const noexcept override
	{
		return new CloneableTestEvent(x);
	}
};

int main(int nargs, char **args) noexcept
{
	LambdaEventProcessor<Event> lep
	{
		[](Event &e)
		{
			std::cout << std::endl << "E @ " << &e
			<< " is \"" << typeid(e).name() << '"' << std::endl;
		},
		ListenerPriority::FIRST
	};
	TestListener l;
	TestEvent{7}.call();
	TestEvent{-1}.call();
	TestEvent{14}.call();
	DerivedTestEvent{4}.call();
	CloneableTestEvent::Clone(CloneableTestEvent{9})->call();
}
<|endoftext|>


<commit_before>//stl list
//载入头文件
#include <iostream>
#include <list>

using namespace std;

typedef struct {
	char name[21];
	int id;
}  note ;

int main(int argc, char const *argv[])
{
	//建立
	list<int> L0;       // 空链表
	list<int> L1(9);   // 建一个含一个元素的链表
	list<int> L2(5,1); // 建一个多个个元素的链表
	list<int> L3(L2);  // 复制L2的元素，重新建立一个链表
	list<int> L4(L0.begin(), L0.end());//建一个含L0一个区域的链表

	//其他元素类型的链表

	list<double> Ld;
	list<int [3]>Larray;
	list<note> Lu;

	//链表操作
	list<int> l;
	l.push_front(1);
	l.push(2);

	return 0;
}<commit_msg>update list<commit_after>//stl list
//载入头文件
#include <iostream>
#include <list>

using namespace std;

typedef struct {
	char name[21];
	int id;
}  note ;

int main(int argc, char const *argv[])
{
	//建立
	list<int> L0;       // 空链表
	list<int> L1(9);   // 建一个含一个元素的链表
	list<int> L2(5,1); // 建一个多个个元素的链表
	list<int> L3(L2);  // 复制L2的元素，重新建立一个链表
	list<int> L4(L0.begin(), L0.end());//建一个含L0一个区域的链表

	//其他元素类型的链表

	list<double> Ld;
	list<int [3]>Larray;
	list<note> Lu;

	//链表操作
	//一个链表
	list<int> l;
	//在链表头部插入元素
	l.push_front(1);
	//尾部
	l.push_back(2);

	return 0;
}<|endoftext|>


<commit_before>#include <gspan.h>
#include <graph.h>
#include <common.h>
#include <sstream>

namespace gspan {

void GSpan::find_frequent_nodes(const vector<Graph> &graphs) {
  unordered_map<size_t, size_t> vertex_labels;
  unordered_map<size_t, size_t> edge_labels;

  for (size_t i = 0; i < graphs.size(); ++i) {
    unordered_set<size_t> vertex_set;
    unordered_set<size_t> edge_set;
    for (size_t j = 0; j < graphs[i].size(); ++j) {
      const struct vertex_t *vertex = graphs[i].get_p_vertex(j);
      vertex_set.insert(vertex->label);
      for (size_t k = 0; k < (vertex->edges).size(); ++k) {
        edge_set.insert(vertex->edges[k].label);
      }
    }
    for (unordered_set<size_t>::iterator it = vertex_set.begin(); it != vertex_set.end(); ++it) {
      ++vertex_labels[*it];
    }
    for (unordered_set<size_t>::iterator it = edge_set.begin(); it != edge_set.end(); ++it) {
      ++edge_labels[*it];
    }
  }
  for (unordered_map<size_t, size_t>::iterator it = vertex_labels.begin();
    it != vertex_labels.end(); ++it) {
    if (it->second >= nsupport_) {
      frequent_vertex_labels_.insert(std::make_pair(it->first, it->second));
    }
  }
  for (unordered_map<size_t, size_t>::iterator it = edge_labels.begin();
    it != edge_labels.end(); ++it) {
    if (it->second >= nsupport_) {
      frequent_edge_labels_.insert(std::make_pair(it->first, it->second));
    }
  }
}

void GSpan::report(const DfsCodes &dfs_codes, const Projection &projection, size_t nsupport, int prev_id) {
  std::stringstream ss;
  Graph graph;
  build_graph(dfs_codes, graph);

  for (size_t i = 0; i < graph.size(); ++i) {
    const struct vertex_t *vertex = graph.get_p_vertex(i);
    ss << "v " << vertex->id << " " << vertex->label << std::endl;
  }
  for (size_t i = 0; i < dfs_codes.size(); ++i) {
    ss << "e " << dfs_codes[i].from << " " << dfs_codes[i].to
      << " " << dfs_codes[i].edge_label << std::endl;
  }
  ss << "x: ";
  size_t prev = 0;
  for (size_t i = 0; i < projection.size(); ++i) {
    if (i == 0 || projection[i].id != prev) {
      prev = projection[i].id;
      ss << prev << " ";
    }
  }
  ss << std::endl;
  gspan_instance_t *instance = gspan_instances_ + omp_get_thread_num();
  Output *output = instance->output;
  output->push_back(ss.str(), nsupport, output->size(), prev_id);
}

void GSpan::save(bool output_parent, bool output_pattern) {
  #pragma omp parallel
  {
    gspan_instance_t *instance = gspan_instances_ + omp_get_thread_num();
    Output *output = instance->output;
    output->save(output_parent, output_pattern);
  }
}

void GSpan::mine_subgraph(
  const vector<Graph> &graphs,
  const DfsCodes &dfs_codes,
  const Projection &projection,
  size_t prev_nsupport,
  int prev_id) {
  if (!is_min(dfs_codes)) {
    return;
  }
  report(dfs_codes, projection, prev_nsupport, prev_id);
  gspan_instance_t *instance = gspan_instances_ + omp_get_thread_num();
  Output *output = instance->output;
  prev_id = output->size() - 1;

  // Find right most path
  vector<size_t> right_most_path;
  build_right_most_path(dfs_codes, right_most_path);
  size_t min_label = dfs_codes[0].from_label;

  // Enumerate backward paths and forward paths by different rules
  ProjectionMapBackward projection_map_backward;
  ProjectionMapForward projection_map_forward;
  enumerate(graphs, dfs_codes, projection, right_most_path, min_label,
    projection_map_backward, projection_map_forward);
  // Recursive mining: first backward, last backward, and then last forward to the first forward
  for (ProjectionMapBackward::iterator it = projection_map_backward.begin();
    it != projection_map_backward.end(); ++it) {
    Projection &projection = it->second;
    size_t nsupport = count_support(projection);
    if (nsupport < nsupport_) {
      continue;
    }
    size_t from = (it->first).from;
    size_t to = (it->first).to;
    size_t from_label = (it->first).from_label;
    size_t edge_label = (it->first).edge_label;
    size_t to_label = (it->first).to_label;
    #pragma omp task shared(graphs, dfs_codes, projection, prev_id) firstprivate(nsupport)
    {
      DfsCodes dfs_codes_copy(dfs_codes);
      dfs_codes_copy.push_back(dfs_code_t(from, to, from_label, edge_label, to_label));
      mine_subgraph(graphs, dfs_codes_copy, projection, nsupport, prev_id);
    }
  }
  for (ProjectionMapForward::iterator it = projection_map_forward.begin();
    it != projection_map_forward.end(); ++it) {
    Projection &projection = it->second;
    size_t nsupport = count_support(projection);
    if (nsupport < nsupport_) {
      continue;
    }
    size_t from = (it->first).from;
    size_t to = (it->first).to;
    size_t from_label = (it->first).from_label;
    size_t edge_label = (it->first).edge_label;
    size_t to_label = (it->first).to_label;
    #pragma omp task shared(graphs, dfs_codes, projection, prev_id) firstprivate(nsupport)
    {
      DfsCodes dfs_codes_copy(dfs_codes);
      dfs_codes_copy.push_back(dfs_code_t(from, to, from_label, edge_label, to_label));
      mine_subgraph(graphs, dfs_codes_copy, projection, nsupport, prev_id);
    }
  }
  #pragma omp taskwait
}

}  // namespace gspan
<commit_msg>Change to reverse iterator<commit_after>#include <gspan.h>
#include <graph.h>
#include <common.h>
#include <sstream>

namespace gspan {

void GSpan::find_frequent_nodes(const vector<Graph> &graphs) {
  unordered_map<size_t, size_t> vertex_labels;
  unordered_map<size_t, size_t> edge_labels;

  for (size_t i = 0; i < graphs.size(); ++i) {
    unordered_set<size_t> vertex_set;
    unordered_set<size_t> edge_set;
    for (size_t j = 0; j < graphs[i].size(); ++j) {
      const struct vertex_t *vertex = graphs[i].get_p_vertex(j);
      vertex_set.insert(vertex->label);
      for (size_t k = 0; k < (vertex->edges).size(); ++k) {
        edge_set.insert(vertex->edges[k].label);
      }
    }
    for (unordered_set<size_t>::iterator it = vertex_set.begin(); it != vertex_set.end(); ++it) {
      ++vertex_labels[*it];
    }
    for (unordered_set<size_t>::iterator it = edge_set.begin(); it != edge_set.end(); ++it) {
      ++edge_labels[*it];
    }
  }
  for (unordered_map<size_t, size_t>::iterator it = vertex_labels.begin();
    it != vertex_labels.end(); ++it) {
    if (it->second >= nsupport_) {
      frequent_vertex_labels_.insert(std::make_pair(it->first, it->second));
    }
  }
  for (unordered_map<size_t, size_t>::iterator it = edge_labels.begin();
    it != edge_labels.end(); ++it) {
    if (it->second >= nsupport_) {
      frequent_edge_labels_.insert(std::make_pair(it->first, it->second));
    }
  }
}

void GSpan::report(const DfsCodes &dfs_codes, const Projection &projection, size_t nsupport, int prev_id) {
  std::stringstream ss;
  Graph graph;
  build_graph(dfs_codes, graph);

  for (size_t i = 0; i < graph.size(); ++i) {
    const struct vertex_t *vertex = graph.get_p_vertex(i);
    ss << "v " << vertex->id << " " << vertex->label << std::endl;
  }
  for (size_t i = 0; i < dfs_codes.size(); ++i) {
    ss << "e " << dfs_codes[i].from << " " << dfs_codes[i].to
      << " " << dfs_codes[i].edge_label << std::endl;
  }
  ss << "x: ";
  size_t prev = 0;
  for (size_t i = 0; i < projection.size(); ++i) {
    if (i == 0 || projection[i].id != prev) {
      prev = projection[i].id;
      ss << prev << " ";
    }
  }
  ss << std::endl;
  gspan_instance_t *instance = gspan_instances_ + omp_get_thread_num();
  Output *output = instance->output;
  output->push_back(ss.str(), nsupport, output->size(), prev_id);
}

void GSpan::save(bool output_parent, bool output_pattern) {
  #pragma omp parallel
  {
    gspan_instance_t *instance = gspan_instances_ + omp_get_thread_num();
    Output *output = instance->output;
    output->save(output_parent, output_pattern);
  }
}

void GSpan::mine_subgraph(
  const vector<Graph> &graphs,
  const DfsCodes &dfs_codes,
  const Projection &projection,
  size_t prev_nsupport,
  int prev_id) {
  if (!is_min(dfs_codes)) {
    return;
  }
  report(dfs_codes, projection, prev_nsupport, prev_id);
  gspan_instance_t *instance = gspan_instances_ + omp_get_thread_num();
  Output *output = instance->output;
  prev_id = output->size() - 1;

  // Find right most path
  vector<size_t> right_most_path;
  build_right_most_path(dfs_codes, right_most_path);
  size_t min_label = dfs_codes[0].from_label;

  // Enumerate backward paths and forward paths by different rules
  ProjectionMapBackward projection_map_backward;
  ProjectionMapForward projection_map_forward;
  enumerate(graphs, dfs_codes, projection, right_most_path, min_label,
    projection_map_backward, projection_map_forward);
  // Recursive mining: first backward, last backward, and then last forward to the first forward
  for (ProjectionMapBackward::iterator it = projection_map_backward.begin();
    it != projection_map_backward.end(); ++it) {
    Projection &projection = it->second;
    size_t nsupport = count_support(projection);
    if (nsupport < nsupport_) {
      continue;
    }
    size_t from = (it->first).from;
    size_t to = (it->first).to;
    size_t from_label = (it->first).from_label;
    size_t edge_label = (it->first).edge_label;
    size_t to_label = (it->first).to_label;
    #pragma omp task shared(graphs, dfs_codes, projection, prev_id) firstprivate(nsupport)
    {
      DfsCodes dfs_codes_copy(dfs_codes);
      dfs_codes_copy.push_back(dfs_code_t(from, to, from_label, edge_label, to_label));
      mine_subgraph(graphs, dfs_codes_copy, projection, nsupport, prev_id);
    }
  }
  for (ProjectionMapForward::reverse_iterator it = projection_map_forward.rbegin();
    it != projection_map_forward.rend(); ++it) {
    Projection &projection = it->second;
    size_t nsupport = count_support(projection);
    if (nsupport < nsupport_) {
      continue;
    }
    size_t from = (it->first).from;
    size_t to = (it->first).to;
    size_t from_label = (it->first).from_label;
    size_t edge_label = (it->first).edge_label;
    size_t to_label = (it->first).to_label;
    #pragma omp task shared(graphs, dfs_codes, projection, prev_id) firstprivate(nsupport)
    {
      DfsCodes dfs_codes_copy(dfs_codes);
      dfs_codes_copy.push_back(dfs_code_t(from, to, from_label, edge_label, to_label));
      mine_subgraph(graphs, dfs_codes_copy, projection, nsupport, prev_id);
    }
  }
  #pragma omp taskwait
}

}  // namespace gspan
<|endoftext|>


<commit_before>#ifndef NODE_MDNS_INCLUDED
#define NODE_MDNS_INCLUDED

#include "mdns_settings.hpp"

#ifdef WIN32
# pragma warning( push )
# pragma warning( disable: 4251 )
#endif

// Hack attempt to fix "node.h missing ';' before identifier" build error
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#define _SSIZE_T_
#endif

#include <node.h>
#include "nan.h"

#ifdef WIN32
# pragma warning( pop )
#endif

#ifndef NODE_VERSION_AT_LEAST
# include <node_version.h>
#endif

// XXX It would be better to test UV_VERSION_MAJOR and UV_VERSION_MINOR.
//     However, libuv didn't bump the version when uv_poll_t was introduced.
#if NODE_VERSION_AT_LEAST(0, 7, 9)
# define NODE_MDNS_USE_SOCKET_WATCHER
//# warning Using SocketWatcher
#else
//# warning Using IOWatcher
#endif

#include <dns_sd.h>

#endif // NODE_MDNS_INCLUDED
<commit_msg>update SSIZE_T hack with version from latest node.h<commit_after>#ifndef NODE_MDNS_INCLUDED
#define NODE_MDNS_INCLUDED

#include "mdns_settings.hpp"

#ifdef WIN32
# pragma warning( push )
# pragma warning( disable: 4251 )
#endif

// HACK: fix "node.h missing ';' before identifier" build error
#ifdef _WIN32
# include <BaseTsd.h>
typedef SSIZE_T ssize_t;
typedef SIZE_T size_t;
#else // !_WIN32
# include <sys/types.h> // size_t, ssize_t
#endif // _WIN32

#include <node.h>
#include "nan.h"

#ifdef WIN32
# pragma warning( pop )
#endif

#ifndef NODE_VERSION_AT_LEAST
# include <node_version.h>
#endif

// XXX It would be better to test UV_VERSION_MAJOR and UV_VERSION_MINOR.
//     However, libuv didn't bump the version when uv_poll_t was introduced.
#if NODE_VERSION_AT_LEAST(0, 7, 9)
# define NODE_MDNS_USE_SOCKET_WATCHER
//# warning Using SocketWatcher
#else
//# warning Using IOWatcher
#endif

#include <dns_sd.h>

#endif // NODE_MDNS_INCLUDED
<|endoftext|>


<commit_before>#include <taichi/visual/gui.h>
#include <taichi/common/task.h>
#include <taichi/common/bit.h>

#if defined(TC_GUI_COCOA)

// https://stackoverflow.com/questions/4356441/mac-os-cocoa-draw-a-simple-pixel-on-a-canvas
// http://cocoadevcentral.com/d/intro_to_quartz/
// Modified based on
// https://github.com/CodaFi/C-Macs

// Obj-c runtime doc:
// https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc

#include <objc/objc.h>
#include <objc/message.h>
#include <objc/runtime.h>
#include <objc/runtime.h>
#include <objc/message.h>
#include <objc/NSObjCRuntime.h>
#include <CoreGraphics/CGBase.h>
#include <CoreGraphics/CGGeometry.h>
#include <ApplicationServices/ApplicationServices.h>

template <typename C = id, typename... Args>
C call(id i, const char *select, Args... args) {
  using func = C(id, SEL, Args...);
  return ((func *)(objc_msgSend))(i, sel_getUid(select), args...);
}

template <typename C = id, typename... Args>
C call(const char *class_name, const char *select, Args... args) {
  using func = C(id, SEL, Args...);
  return ((func *)(objc_msgSend))((id)objc_getClass(class_name),
                                  sel_getUid(select), args...);
}

extern id NSApp;
extern id const NSDefaultRunLoopMode;

typedef struct AppDel {
  Class isa;
  id window;
} AppDelegate;

class IdComparator {
 public:
  bool operator()(id a, id b) const {
    TC_STATIC_ASSERT(sizeof(a) == sizeof(taichi::int64));
    return taichi::bit::reinterpret_bits<taichi::int64>(a) <
           taichi::bit::reinterpret_bits<taichi::int64>(b);
  }
};

std::map<id, taichi::GUI *, IdComparator> gui_from_id;

enum {
  NSBorderlessWindowMask = 0,
  NSTitledWindowMask = 1 << 0,
  NSClosableWindowMask = 1 << 1,
  NSMiniaturizableWindowMask = 1 << 2,
  NSResizableWindowMask = 1 << 3,
};

Class ViewClass;

void redraw(id self, SEL _, CGRect __) {
  using namespace taichi;
  auto *gui = gui_from_id[self];
  auto width = gui->width, height = gui->height;
  auto &img = gui->canvas->img;
  auto &data = gui->img_data;
  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
      int index = 4 * (i + j * width);
      auto pixel = img[i][height - j - 1];
      data[index++] = uint8(clamp(int(pixel[0] * 255.0_f), 0, 255));
      data[index++] = uint8(clamp(int(pixel[1] * 255.0_f), 0, 255));
      data[index++] = uint8(clamp(int(pixel[2] * 255.0_f), 0, 255));
      data[index++] = 255;  // alpha
    }
  }

  CGDataProviderRef provider = CGDataProviderCreateWithData(
      nullptr, data.data(), gui->img_data_length, nullptr);
  CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
  CGImageRef image =
      CGImageCreate(width, height, 8, 32, width * 4, colorspace,
                    kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
                    provider, nullptr, true, kCGRenderingIntentDefault);
  CGContextRef context = call<CGContextRef>(
      call((id)objc_getClass("NSGraphicsContext"), "currentContext"),
      "graphicsPort");

  CGRect rect{{0, 0}, {CGFloat(width), CGFloat(height)}};
  CGContextDrawImage(context, rect, image);

  CGImageRelease(image);
  CGDataProviderRelease(provider);
  CGColorSpaceRelease(colorspace);
}

Class AppDelClass;
__attribute__((constructor)) static void initView() {
  ViewClass = objc_allocateClassPair((Class)objc_getClass("NSView"), "View", 0);
  // and again, we tell the runtime to add a function called -drawRect:
  // to our custom view. Note that there is an error in the type-specification
  // of this method, as I do not know the @encode sequence of 'CGRect' off
  // of the top of my head. As a result, there is a chance that the rect
  // parameter of the method may not get passed properly.
  class_addMethod(ViewClass, sel_getUid("drawRect:"), (IMP)redraw, "v@:");
  objc_registerClassPair(ViewClass);

  AppDelClass = objc_allocateClassPair((Class)objc_getClass("NSObject"),
                                       "AppDelegate", 0);
  objc_registerClassPair(AppDelClass);
}

TC_NAMESPACE_BEGIN

void GUI::create_window() {
  call("NSApplication", "sharedApplication");
  if (NSApp == nullptr) {
    fprintf(stderr, "Failed to initialized NSApplication.\nterminating.\n");
    return;
  }
  auto appDelObj = call("AppDelegate", "alloc");
  appDelObj = call(appDelObj, "init");
  call(NSApp, "setDelegate:", appDelObj);
  window = call("NSWindow", "alloc");
  auto rect = (CGRect){{0, 0}, {CGFloat(width), CGFloat(height)}};
  call(window, "initWithContentRect:styleMask:backing:defer:", rect,
       (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
        NSMiniaturizableWindowMask),
       0, false);
  view = call(call("View", "alloc"), "initWithFrame:", rect);
  gui_from_id[view] = this;
  call(window, "setContentView:", view);
  call(window, "becomeFirstResponder");
  call(window, "makeKeyAndOrderFront:", window);
  img_data_length = width * height * 4;
  img_data.resize(img_data_length);
}

void GUI::process_event() {
  call(call("NSRunLoop", "currentRunLoop"),
       "runMode:beforeDate:", NSDefaultRunLoopMode,
       call("NSDate", "distantPast"));
  while (1) {
    auto event = call(
        NSApp, "nextEventMatchingMask:untilDate:inMode:dequeue:", NSUIntegerMax,
        call("NSDate", "distantPast"), NSDefaultRunLoopMode, YES);
    if (event != nullptr) {
      auto event_type = call<NSInteger>(event, "type");
      call(NSApp, "sendEvent:", event);
      call(NSApp, "updateWindows");
      switch (event_type) {
        case 1:  // NSLeftMouseDown
          mouse_event(MouseEvent{MouseEvent::Type::press, cursor_pos});
          break;
        case 2:  // NSLeftMouseUp
          mouse_event(MouseEvent{MouseEvent::Type::release, cursor_pos});
          break;
        case 5:   // NSMouseMoved
        case 6:   // NSLeftMouseDragged
        case 7:   // NSRightMouseDragged
        case 27:  // NSNSOtherMouseDragged
          auto p = call<CGPoint>(event, "locationInWindow");
          set_mouse_pos(p.x, p.y);
          mouse_event(MouseEvent{MouseEvent::Type::move, Vector2i(p.x, p.y)});
          break;
      }
    } else {
      break;
    }
  }
}

void GUI::set_title(std::string title) {
  auto str = call("NSString", "stringWithUTF8String:", title.c_str());
  call(window, "setTitle:", str);
  call(str, "release");
}

void GUI::redraw() {
  call(view, "setNeedsDisplay:", YES);
}

GUI::~GUI() {
}

TC_NAMESPACE_END

#endif<commit_msg>Improved OS X amalgated GUI<commit_after>#include <taichi/visual/gui.h>
#include <taichi/common/task.h>
#include <taichi/common/bit.h>

#if defined(TC_GUI_COCOA)

// https://stackoverflow.com/questions/4356441/mac-os-cocoa-draw-a-simple-pixel-on-a-canvas
// http://cocoadevcentral.com/d/intro_to_quartz/
// Modified based on
// https://github.com/CodaFi/C-Macs

// Obj-c runtime doc:
// https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc

#include <objc/objc.h>
#include <objc/message.h>
#include <objc/runtime.h>
#include <objc/runtime.h>
#include <objc/message.h>
#include <objc/NSObjCRuntime.h>
#include <CoreGraphics/CGBase.h>
#include <CoreGraphics/CGGeometry.h>
#include <ApplicationServices/ApplicationServices.h>

template <typename C = id, typename... Args>
C call(id i, const char *select, Args... args) {
  using func = C(id, SEL, Args...);
  return ((func *)(objc_msgSend))(i, sel_getUid(select), args...);
}

template <typename C = id, typename... Args>
C call(const char *class_name, const char *select, Args... args) {
  using func = C(id, SEL, Args...);
  return ((func *)(objc_msgSend))((id)objc_getClass(class_name),
                                  sel_getUid(select), args...);
}

extern id NSApp;
extern id const NSDefaultRunLoopMode;

typedef struct AppDel {
  Class isa;
  id window;
} AppDelegate;

class IdComparator {
 public:
  bool operator()(id a, id b) const {
    TC_STATIC_ASSERT(sizeof(a) == sizeof(taichi::int64));
    return taichi::bit::reinterpret_bits<taichi::int64>(a) <
           taichi::bit::reinterpret_bits<taichi::int64>(b);
  }
};

std::map<id, taichi::GUI *, IdComparator> gui_from_id;

enum {
  NSBorderlessWindowMask = 0,
  NSTitledWindowMask = 1 << 0,
  NSClosableWindowMask = 1 << 1,
  NSMiniaturizableWindowMask = 1 << 2,
  NSResizableWindowMask = 1 << 3,
};

Class ViewClass;

void redraw(id self, SEL _, CGRect __) {
  using namespace taichi;
  auto *gui = gui_from_id[self];
  auto width = gui->width, height = gui->height;
  auto &img = gui->canvas->img;
  auto &data = gui->img_data;
  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
      int index = 4 * (i + j * width);
      auto pixel = img[i][height - j - 1];
      data[index++] = uint8(clamp(int(pixel[0] * 255.0_f), 0, 255));
      data[index++] = uint8(clamp(int(pixel[1] * 255.0_f), 0, 255));
      data[index++] = uint8(clamp(int(pixel[2] * 255.0_f), 0, 255));
      data[index++] = 255;  // alpha
    }
  }

  CGDataProviderRef provider = CGDataProviderCreateWithData(
      nullptr, data.data(), gui->img_data_length, nullptr);
  CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
  CGImageRef image =
      CGImageCreate(width, height, 8, 32, width * 4, colorspace,
                    kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
                    provider, nullptr, true, kCGRenderingIntentDefault);
  CGContextRef context = call<CGContextRef>(
      call((id)objc_getClass("NSGraphicsContext"), "currentContext"),
      "graphicsPort");

  CGRect rect{{0, 0}, {CGFloat(width), CGFloat(height)}};
  CGContextDrawImage(context, rect, image);

  CGImageRelease(image);
  CGDataProviderRelease(provider);
  CGColorSpaceRelease(colorspace);
}

Class AppDelClass;
__attribute__((constructor)) static void initView() {
  ViewClass = objc_allocateClassPair((Class)objc_getClass("NSView"), "View", 0);
  // and again, we tell the runtime to add a function called -drawRect:
  // to our custom view. Note that there is an error in the type-specification
  // of this method, as I do not know the @encode sequence of 'CGRect' off
  // of the top of my head. As a result, there is a chance that the rect
  // parameter of the method may not get passed properly.
  class_addMethod(ViewClass, sel_getUid("drawRect:"), (IMP)redraw, "v@:");
  objc_registerClassPair(ViewClass);

  AppDelClass = objc_allocateClassPair((Class)objc_getClass("NSObject"),
                                       "AppDelegate", 0);
  objc_registerClassPair(AppDelClass);
}

TC_NAMESPACE_BEGIN

void GUI::create_window() {
  call("NSApplication", "sharedApplication");
  if (NSApp == nullptr) {
    fprintf(stderr, "Failed to initialized NSApplication.\nterminating.\n");
    return;
  }
  auto appDelObj = call("AppDelegate", "alloc");
  appDelObj = call(appDelObj, "init");
  call(NSApp, "setDelegate:", appDelObj);
  window = call("NSWindow", "alloc");
  auto rect = (CGRect){{0, 0}, {CGFloat(width), CGFloat(height)}};
  call(window, "initWithContentRect:styleMask:backing:defer:", rect,
       (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
        NSMiniaturizableWindowMask),
       0, false);
  view = call(call("View", "alloc"), "initWithFrame:", rect);
  gui_from_id[view] = this;
  call(window, "setContentView:", view);
  call(window, "becomeFirstResponder");
  call(window, "makeKeyAndOrderFront:", window);
  call(window, "setAcceptsMouseMovedEvents:", YES);
  img_data_length = width * height * 4;
  img_data.resize(img_data_length);
}

void GUI::process_event() {
  call(call("NSRunLoop", "currentRunLoop"),
       "runMode:beforeDate:", NSDefaultRunLoopMode,
       call("NSDate", "distantPast"));
  while (1) {
    auto event = call(
        NSApp, "nextEventMatchingMask:untilDate:inMode:dequeue:", NSUIntegerMax,
        call("NSDate", "distantPast"), NSDefaultRunLoopMode, YES);
    if (event != nullptr) {
      auto event_type = call<NSInteger>(event, "type");
      call(NSApp, "sendEvent:", event);
      call(NSApp, "updateWindows");
      auto p = call<CGPoint>(event, "locationInWindow");
      switch (event_type) {
        case 1:  // NSLeftMouseDown
          set_mouse_pos(p.x, p.y);
          mouse_event(MouseEvent{MouseEvent::Type::press, cursor_pos});
          break;
        case 2:  // NSLeftMouseUp
          set_mouse_pos(p.x, p.y);
          mouse_event(MouseEvent{MouseEvent::Type::release, cursor_pos});
          break;
        case 5:   // NSMouseMoved
        case 6:   // NSLeftMouseDragged
        case 7:   // NSRightMouseDragged
        case 27:  // NSNSOtherMouseDragged
          set_mouse_pos(p.x, p.y);
          mouse_event(MouseEvent{MouseEvent::Type::move, Vector2i(p.x, p.y)});
          break;
      }
    } else {
      break;
    }
  }
}

void GUI::set_title(std::string title) {
  auto str = call("NSString", "stringWithUTF8String:", title.c_str());
  call(window, "setTitle:", str);
  call(str, "release");
}

void GUI::redraw() {
  call(view, "setNeedsDisplay:", YES);
}

GUI::~GUI() {
}

TC_NAMESPACE_END

#endif<|endoftext|>


<commit_before>/**
 * mesh.cpp
 *
 * by Mohammad Elmi
 * Created on 24 Oct 2013
 */

#include "mesh.h"

namespace aban2
{

size_t mesh::idx(size_t i, size_t j, size_t k, size_t ii, size_t jj, size_t kk)
{
    static size_t ijk[3];
    ijk[ii] = i;
    ijk[jj] = j;
    ijk[kk] = k;
    return idx(ijk[0], ijk[1], ijk[2]);
}

void mesh::get_dirs(size_t dir, size_t &ii, size_t &jj, size_t &kk)
{
    ii = dir;
    jj = (dir + 1) % 3;
    kk = (dir + 2) % 3;
}

bool mesh::exists(size_t i, size_t j, size_t k)
{
    size_t x = idx(i, j, k);
    return codes[x] == INSIDE;
}

bool mesh::exists(size_t i, size_t j, size_t k, size_t &no)
{
    size_t ix = idx(i, j, k);
    if (codes[ix] != INSIDE)return false;
    no = cellnos[ix];
    return true;
}

bool mesh::exists_and_inside(size_t i, size_t j, size_t k, size_t &no)
{
    if (i < 0 || i > ndir[0] || j < 0 || j > ndir[1] || k < 0 || k > ndir[2]) return false;
    size_t ix = idx(i, j, k);
    if (codes[ix] != INSIDE)return false;
    no = cellnos[ix];
    return true;
}

void mesh::generate_rows(size_t dir)
{
    bool inside = false;
    mesh_row row;
    std::vector<mesh_row> v;
    size_t ii , jj, kk;
    get_dirs(dir, ii, jj, kk);

    for (size_t k = 0; k < ndir[kk]; ++k)
        for (size_t j = 0; j < ndir[jj]; ++j)
            for (size_t i = 0; i < ndir[ii]; ++i)
            {
                size_t x = idx(i, j, k, ii, jj, kk);
                if (!inside)
                {
                    if (codes[x] != INSIDE) continue;
                    inside = true;
                    row.dir = dir;
                    row.start[ii] = i;
                    row.start[jj] = j;
                    row.start[kk] = k;
                    row.start_code = codes[idx(i - 1, j, k, ii, jj, kk)];
                }
                else
                {
                    if (codes[x] == INSIDE) continue;
                    inside = false;
                    row.end[ii] = i - 1;
                    row.end[jj] = j;
                    row.end[kk] = k;
                    row.n = row.end[ii] - row.start[ii] + 1;
                    row.end_code = codes[x];
                    v.push_back(row);
                }
            }

    nrows[dir] = v.size();
    rows[dir] = new mesh_row[nrows[dir]];
    for (int i = 0; i < nrows[dir]; ++i)
        rows[dir][i] = v[i];
}

void mesh::set_cell_nos()
{
    size_t ii = 0;
    cellnos = new size_t[ndir[0] * ndir[1] * ndir[2]];
    for (int i = 0; i < ndir[0]; ++i)
        for (int j = 0; j < ndir[1]; ++j)
            for (int k = 0; k < ndir[2]; ++k)
            {
                size_t x = idx(i, j, k);
                if (codes[x] == INSIDE)
                    cellnos[x] = ii++;
            }
    n = ii;
}

void mesh::init()
{
    nrows[0] = nrows[1] = nrows[2] = 0;

    for (int dir = 0; dir < NDIRS; ++dir)
        generate_rows(dir);

    set_cell_nos();
}

mesh::mesh(Json::Value *root)
{
    delta = root->get("delta", "1").asDouble();

    ndir[0] = root->get("ni", "1").asInt();
    ndir[1] = root->get("nj", "1").asInt();
    ndir[2] = root->get("nk", "1").asInt();

    std::string str;
    Json::Value codes_val = (*root)["codes"];
    for (size_t k = 0; k < ndir[2]; ++k)
    {
        Json::Value codesk = codes_val[ndir[2] - k - 1];
        for (size_t j = 0; j < ndir[1]; ++j)
            str += codesk[ndir[1] - j - 1].asString();
    }

    codes = new char[str.length() + 1];
    strcpy(codes, str.c_str());

    init();
}

}
<commit_msg>bug fix<commit_after>/**
 * mesh.cpp
 *
 * by Mohammad Elmi
 * Created on 24 Oct 2013
 */

#include "mesh.h"

namespace aban2
{

size_t mesh::idx(size_t i, size_t j, size_t k, size_t ii, size_t jj, size_t kk)
{
    static size_t ijk[3];
    ijk[ii] = i;
    ijk[jj] = j;
    ijk[kk] = k;
    return idx(ijk[0], ijk[1], ijk[2]);
}

void mesh::get_dirs(size_t dir, size_t &ii, size_t &jj, size_t &kk)
{
    ii = dir;
    jj = (dir + 1) % 3;
    kk = (dir + 2) % 3;
}

bool mesh::exists(size_t i, size_t j, size_t k)
{
    size_t x = idx(i, j, k);
    return codes[x] == INSIDE;
}

bool mesh::exists(size_t i, size_t j, size_t k, size_t &no)
{
    size_t ix = idx(i, j, k);
    if (codes[ix] != INSIDE)return false;
    no = cellnos[ix];
    return true;
}

bool mesh::exists_and_inside(size_t i, size_t j, size_t k, size_t &no)
{
    if (i < 0 || i >= ndir[0] || j < 0 || j >= ndir[1] || k < 0 || k >= ndir[2]) return false;
    size_t ix = idx(i, j, k);
    if (codes[ix] != INSIDE)return false;
    no = cellnos[ix];
    return true;
}

void mesh::generate_rows(size_t dir)
{
    bool inside = false;
    mesh_row row;
    std::vector<mesh_row> v;
    size_t ii , jj, kk;
    get_dirs(dir, ii, jj, kk);

    for (size_t k = 0; k < ndir[kk]; ++k)
        for (size_t j = 0; j < ndir[jj]; ++j)
            for (size_t i = 0; i < ndir[ii]; ++i)
            {
                size_t x = idx(i, j, k, ii, jj, kk);
                if (!inside)
                {
                    if (codes[x] != INSIDE) continue;
                    inside = true;
                    row.dir = dir;
                    row.start[ii] = i;
                    row.start[jj] = j;
                    row.start[kk] = k;
                    row.start_code = codes[idx(i - 1, j, k, ii, jj, kk)];
                }
                else
                {
                    if (codes[x] == INSIDE) continue;
                    inside = false;
                    row.end[ii] = i - 1;
                    row.end[jj] = j;
                    row.end[kk] = k;
                    row.n = row.end[ii] - row.start[ii] + 1;
                    row.end_code = codes[x];
                    v.push_back(row);
                }
            }

    nrows[dir] = v.size();
    rows[dir] = new mesh_row[nrows[dir]];
    for (int i = 0; i < nrows[dir]; ++i)
        rows[dir][i] = v[i];
}

void mesh::set_cell_nos()
{
    size_t ii = 0;
    cellnos = new size_t[ndir[0] * ndir[1] * ndir[2]];
    for (int i = 0; i < ndir[0]; ++i)
        for (int j = 0; j < ndir[1]; ++j)
            for (int k = 0; k < ndir[2]; ++k)
            {
                size_t x = idx(i, j, k);
                if (codes[x] == INSIDE)
                    cellnos[x] = ii++;
            }
    n = ii;
}

void mesh::init()
{
    nrows[0] = nrows[1] = nrows[2] = 0;

    for (int dir = 0; dir < NDIRS; ++dir)
        generate_rows(dir);

    set_cell_nos();
}

mesh::mesh(Json::Value *root)
{
    delta = root->get("delta", "1").asDouble();

    ndir[0] = root->get("ni", "1").asInt();
    ndir[1] = root->get("nj", "1").asInt();
    ndir[2] = root->get("nk", "1").asInt();

    std::string str;
    Json::Value codes_val = (*root)["codes"];
    for (size_t k = 0; k < ndir[2]; ++k)
    {
        Json::Value codesk = codes_val[ndir[2] - k - 1];
        for (size_t j = 0; j < ndir[1]; ++j)
            str += codesk[ndir[1] - j - 1].asString();
    }

    codes = new char[str.length() + 1];
    strcpy(codes, str.c_str());

    init();
}

}
<|endoftext|>