<commit_before>#include "node/solid/triangle.h"

namespace Svit
{
	Triangle::Triangle (Point3 _p1, Point3 _p2, Point3 _p3)
	  : p1(_p1), p2(_p2), p3(_p3)
	{
		p1.w = 0.0f;
		p2.w = 0.0f;
		p3.w = 0.0f;

		e1 = p2 - p1;
		e2 = p3 - p1;
		normal = ~(~e1 & ~e2);
	}

	boost::optional<Intersection>
	Triangle::intersect (Ray& _ray, float _best)
	{
		Vector3 P = _ray.direction & e2;
		float det = e1 % P;
		if (det == 0.0f)
			return boost::optional<Intersection>();
		float inv_det = 1.0f / det;

		Vector3 T = _ray.origin - p1;
		float u = (T % P) * inv_det;
		if (u < 0.f || u > 1.f)
			return boost::optional<Intersection>();

		Vector3 Q = T & e1;
		float v = (_ray.direction % Q) * inv_det;
		if (v < 0.f || u + v  > 1.f)
			return boost::optional<Intersection>();

		float t = (e2 % Q) * inv_det;
		if(t > 0.0f && t < _best)
		{
			Intersection intersection;
			intersection.t = t;
			intersection.point = _ray(t);
			intersection.node = this;

			boost::optional<Intersection> result(intersection);
			return result;
		}

		return boost::optional<Intersection>();
	}

	void
	Triangle::complete_intersection (Intersection *_intersection)
	{
		_intersection->normal = normal;
	}

	void
	Triangle::dump (const char *_name, unsigned int _level)
	{
		std::cout << std::string(' ', _level*2) << _name << " = Triangle" <<
		    std::endl;

		p1.dump("p1", _level+1);
		p2.dump("p2", _level+1);
		p3.dump("p3", _level+1);
	}
}

<commit_msg>Bounding box computation for Triangle<commit_after>#include "node/solid/triangle.h"

namespace Svit
{
	Triangle::Triangle (Point3 _p1, Point3 _p2, Point3 _p3)
	  : p1(_p1), p2(_p2), p3(_p3)
	{
		p1.w = 0.0f;
		p2.w = 0.0f;
		p3.w = 0.0f;

		e1 = p2 - p1;
		e2 = p3 - p1;
		normal = ~(~e1 & ~e2);

		bounding_box.extend(_p1);
		bounding_box.extend(_p2);
		bounding_box.extend(_p3);
	}

	boost::optional<Intersection>
	Triangle::intersect (Ray& _ray, float _best)
	{
		Vector3 P = _ray.direction & e2;
		float det = e1 % P;
		if (det == 0.0f)
			return boost::optional<Intersection>();
		float inv_det = 1.0f / det;

		Vector3 T = _ray.origin - p1;
		float u = (T % P) * inv_det;
		if (u < 0.f || u > 1.f)
			return boost::optional<Intersection>();

		Vector3 Q = T & e1;
		float v = (_ray.direction % Q) * inv_det;
		if (v < 0.f || u + v  > 1.f)
			return boost::optional<Intersection>();

		float t = (e2 % Q) * inv_det;
		if(t > 0.0f && t < _best)
		{
			Intersection intersection;
			intersection.t = t;
			intersection.point = _ray(t);
			intersection.node = this;

			boost::optional<Intersection> result(intersection);
			return result;
		}

		return boost::optional<Intersection>();
	}

	void
	Triangle::complete_intersection (Intersection *_intersection)
	{
		_intersection->normal = normal;
	}

	void
	Triangle::dump (const char *_name, unsigned int _level)
	{
		std::cout << std::string(' ', _level*2) << _name << " = Triangle" <<
		    std::endl;

		p1.dump("p1", _level+1);
		p2.dump("p2", _level+1);
		p3.dump("p3", _level+1);
	}
}

<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "core/math.h"
using namespace narukami;
TEST(math,rcp){
    EXPECT_FLOAT_EQ(rcp(2.0f),0.5f);
    EXPECT_FLOAT_EQ(rcp(3.0f),1.0f/3.0f);
    EXPECT_FLOAT_EQ(rcp(5.0f),1.0f/5.0f);
    EXPECT_FLOAT_EQ(rcp(7.0f),1.0f/7.0f);
}

TEST(math,isnan){
    float x=0.0f/0.0f;
    EXPECT_TRUE(isnan(x));

    x=1.0f/0.0f;
    EXPECT_FALSE(isnan(x));
}

TEST(math,isinf){
    float x=0.0f/0.0f;
    EXPECT_FALSE(isinf(x));

    x=1.0f/0.0f;
    EXPECT_TRUE(isinf(x));
}

TEST(math,cast_i2f){
    int x=1<<23;
    float y=cast_i2f(x);
    EXPECT_EQ(cast_f2i(y),x);
}

TEST(math,min){
    float x=10;
    float y=20;
    float z=30;
    float w=5;

    EXPECT_FLOAT_EQ(min(x,y),10);
    EXPECT_FLOAT_EQ(min(x,y,z),10);
    EXPECT_FLOAT_EQ(min(x,y,z,w),5);
}

TEST(math,max){
    float x=10;
    float y=20;
    float z=30;
    float w=5;

    EXPECT_FLOAT_EQ(max(x,y),20);
    EXPECT_FLOAT_EQ(max(x,y,z),30);
    EXPECT_FLOAT_EQ(max(x,y,z,w),30);
}

int main(int argc, char* argv[]) {
    testing::InitGoogleTest(&argc,argv);
    auto ret = RUN_ALL_TESTS();
    return ret;
}
<commit_msg>update test<commit_after>#include "gtest/gtest.h"
#include "core/math.h"
using namespace narukami;
TEST(math,rcp){
    EXPECT_FLOAT_EQ(rcp(2.0f),0.5f);
    EXPECT_FLOAT_EQ(rcp(3.0f),1.0f/3.0f);
    EXPECT_FLOAT_EQ(rcp(5.0f),1.0f/5.0f);
    EXPECT_FLOAT_EQ(rcp(7.0f),1.0f/7.0f);
}

TEST(math,isnan){
    float x=0.0f/0.0f;
    EXPECT_TRUE(isnan(x));

    x=1.0f/0.0f;
    EXPECT_FALSE(isnan(x));
}

TEST(math,isinf){
    float x=0.0f/0.0f;
    EXPECT_FALSE(isinf(x));

    x=1.0f/0.0f;
    EXPECT_TRUE(isinf(x));
}

TEST(math,cast_i2f){
    int x=1<<23;
    float y=cast_i2f(x);
    EXPECT_EQ(cast_f2i(y),x);
}

TEST(math,min){
    float x=10;
    float y=20;
    float z=30;
    float w=5;

    EXPECT_FLOAT_EQ(min(x,y),10);
    EXPECT_FLOAT_EQ(min(x,y,z),10);
    EXPECT_FLOAT_EQ(min(x,y,z,w),5);
}

TEST(math,max){
    float x=10;
    float y=20;
    float z=30;
    float w=5;

    EXPECT_FLOAT_EQ(max(x,y),20);
    EXPECT_FLOAT_EQ(max(x,y,z),30);
    EXPECT_FLOAT_EQ(max(x,y,z,w),30);
}

TEST(math,deg2rad){
    float deg=180;
    float rad=deg2rad(deg);
    EXPECT_FLOAT_EQ(rad,3.1415927f);
}

TEST(math,rad2deg){
    float rad=3.1415927f;
    float deg=rad2deg(rad);
    EXPECT_FLOAT_EQ(deg,180);
}

int main(int argc, char* argv[]) {
    testing::InitGoogleTest(&argc,argv);
    auto ret = RUN_ALL_TESTS();
    return ret;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include "Completer.hpp"

int main()
{
	tc::Completer complete;

	complete.add("hello");
	complete.add("helli");
	complete.add("helloworld");
	complete.add("hi");
	complete.add("hellb");
	complete.add("helz");
	complete.add("greg");

	auto ret = complete.complete("hel");

	for(auto& s : ret)
		std::cout << s << '\n';
	std::cout << '\n';

	std::cin.ignore();

	return 0;
}
<commit_msg>Updated test to have more words.<commit_after>#include <iostream>
#include <fstream>
#include <string>

#include <chrono>

#include "../lib/Completer.hpp"

std::vector<std::string> readFile(const std::string& file);

int main()
{
	tc::Completer complete;

	auto contents = readFile("text.txt");

	complete.add(contents);

	std::string input = "\0";
	while(true)
	{
		std::cout << ": ";
		std::cin >> input;

		if(input == "!x")
			break;

		auto start = std::chrono::high_resolution_clock::now().time_since_epoch();
		auto ret = complete.complete(input);
		auto end = std::chrono::high_resolution_clock::now().time_since_epoch();

		for(auto& s : ret)
			std::cout << s << '\n';
		std::cout << "time to complete: " << (end - start).count() / 1000000.0 << "ms\n\n";
	}

	return 0;
}

std::vector<std::string> readFile(const std::string& file)
{
	std::ifstream fin;

	fin.open("text.txt");

	if(!fin)
		return {};

	std::vector<std::string> contents;

	std::string in;
	while(fin >> in)
		contents.push_back(in);

	return contents;
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
	@brief  NES Emulator クラス @n
			操作説明： @n
			「１」： SELECT @n
			「２」： START @n
			「Ｚ」： A-BUTTON @n
			「Ｘ」： B-BUTTON @n
			「↑」： UP-DIR @n
			「↓」： DOWN-DIR @n
			「→」： RIGHT-DIR @n
			「←」： LEFT-DIR @n
			「F1」： Filer @n
			「F4」： Log Terminal @n
			Copyright 2017 Kunihito Hiramatsu
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "main.hpp"
#include "utils/i_scene.hpp"
#include "utils/director.hpp"
#include "widgets/widget.hpp"
#include "widgets/widget_frame.hpp"
#include "widgets/widget_terminal.hpp"
#include "widgets/widget_filer.hpp"
#include "gl_fw/gltexfb.hpp"
#include "snd_io/pcm.hpp"
#include "utils/fifo.hpp"

extern "C" {
	#include "nes.h"
	#include "nesinput.h"
	extern const rgb_t* get_palette();
};

namespace app {

	class nesemu : public utils::i_scene {

		utils::director<core>&	director_;

		gui::widget_frame*		terminal_frame_;
		gui::widget_terminal*	terminal_core_;
		bool					terminal_;

		gui::widget_filer*		filer_;

		gl::texfb			texfb_;

		static const int nes_width_  = 256;
		static const int nes_height_ = 240;
		static const int sample_rate_ = 44100;
		static const int audio_len_ = sample_rate_ / 60;
		static const int audio_queue_ = 1024;

		nes_t*	nes_;

		bool	rom_active_;

		typedef utils::fifo<int16_t, audio_queue_ * 16> fifo;
		fifo		fifo_;
		al::audio	audio_;

		uint8_t	fb_[nes_width_ * nes_height_ * 4];

		nesinput_t	inp_[2];

		void pad_()
		{
	   		gl::core& core = gl::core::get_instance();

			const gl::device& dev = core.get_device();

			inp_[0].data = 0;
			inp_[1].data = 0;

			// A
			if(dev.get_level(gl::device::key::Z)) {
				inp_[0].data |= INP_PAD_A;
			}
			if(dev.get_level(gl::device::key::GAME_0)) {
				inp_[0].data |= INP_PAD_A;
			}

			// B
			if(dev.get_level(gl::device::key::X)) {
				inp_[0].data |= INP_PAD_B;
			}
			if(dev.get_level(gl::device::key::GAME_1)) {
				inp_[0].data |= INP_PAD_B;
			}

			// SELECT
			if(dev.get_level(gl::device::key::_1)) {
				inp_[0].data |= INP_PAD_SELECT;
			}
			if(dev.get_level(gl::device::key::GAME_2)) {
				inp_[0].data |= INP_PAD_SELECT;
			}
			// START
			if(dev.get_level(gl::device::key::_2)) {
				inp_[0].data |= INP_PAD_START;
			}
			if(dev.get_level(gl::device::key::GAME_3)) {
				inp_[0].data |= INP_PAD_START;
			}

			if(dev.get_level(gl::device::key::LEFT)) {
   		 		inp_[0].data |= INP_PAD_LEFT;
			}
			if(dev.get_level(gl::device::key::GAME_LEFT)) {
   		 		inp_[0].data |= INP_PAD_LEFT;
			}
			if(dev.get_level(gl::device::key::RIGHT)) {
   		 		inp_[0].data |= INP_PAD_RIGHT;
			}
			if(dev.get_level(gl::device::key::GAME_RIGHT)) {
   		 		inp_[0].data |= INP_PAD_RIGHT;
			}
			if(dev.get_level(gl::device::key::UP)) {
   		 		inp_[0].data |= INP_PAD_UP;
			}
			if(dev.get_level(gl::device::key::GAME_UP)) {
   		 		inp_[0].data |= INP_PAD_UP;
			}
			if(dev.get_level(gl::device::key::DOWN)) {
   		 		inp_[0].data |= INP_PAD_DOWN;
			}
			if(dev.get_level(gl::device::key::GAME_DOWN)) {
   		 		inp_[0].data |= INP_PAD_DOWN;
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		nesemu(utils::director<core>& d) : director_(d),
			terminal_frame_(nullptr), terminal_core_(nullptr), terminal_(false),
			nes_(nullptr), rom_active_(false)
		{ }

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		virtual ~nesemu() { }

		//-----------------------------------------------------------------//
		/*!
			@brief  初期化
		*/
		//-----------------------------------------------------------------//
		void initialize()
		{
	   		gl::core& core = gl::core::get_instance();

			using namespace gui;
			widget_director& wd = director_.at().widget_director_;
			{  	// ターミナル
				{
					widget::param wp(vtx::irect(10, 10, 200, 200));
					widget_frame::param wp_;
					wp_.plate_param_.set_caption(15);
					terminal_frame_ = wd.add_widget<widget_frame>(wp, wp_);
					terminal_frame_->enable(terminal_);
				}
				{
					widget::param wp(vtx::irect(0), terminal_frame_);
					widget_terminal::param wp_;
					terminal_core_ = wd.add_widget<widget_terminal>(wp, wp_);
				}
			}

			{  	// ファイラー
				widget::param wp(vtx::irect(10, 10, 200, 200));
				widget_filer::param wp_(core.get_current_path(), "", true);
				wp_.select_file_func_ = [this](const std::string& fn) {
					if(nes_insertcart(fn.c_str(), nes_) == 0) {
						rom_active_ = true;
					} else {
						//
					}
				};
				filer_ = wd.add_widget<widget_filer>(wp, wp_);
				filer_->enable(false);
			}

			texfb_.initialize(nes_width_, nes_height_, 32);

			nes_ = nes_create(sample_rate_, 16);

			// regist input
			inp_[0].type = INP_JOYPAD0;
			inp_[0].data = 0;
			input_register(&inp_[0]);
			inp_[1].type = INP_JOYPAD1;
			inp_[1].data = 0;
			input_register(&inp_[1]);

			audio_ = al::create_audio(al::audio_format::PCM16_MONO);
			audio_->create(sample_rate_, audio_queue_);

//			auto path = core.get_current_path();

//			path += "/GALAXIAN.NES";
//			path += "/Zombie.nes";
//			path += "/DRAGONQ1.NES";
//			path += "/DRAGONW2.NES";
//			path += "/SOLSTICE.NES";
//			path += "/GRADIUS.NES";

//			nes_insertcart(path.c_str(), nes_);

			// プリファレンスの取得
			sys::preference& pre = director_.at().preference_;
			if(filer_) {
				filer_->load(pre);
			}
			if(terminal_frame_) {
				terminal_frame_->load(pre);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  アップデート
		*/
		//-----------------------------------------------------------------//
		void update()
		{
	   		gl::core& core = gl::core::get_instance();
			const gl::device& dev = core.get_device();

			if(dev.get_negative(gl::device::key::F1)) {
				filer_->enable(!filer_->get_enable());
			}
			if(dev.get_negative(gl::device::key::F5)) {
				terminal_ = !terminal_;
				terminal_frame_->enable(terminal_);
			}

        	gui::widget_director& wd = director_.at().widget_director_;

			if(nes_ != nullptr && rom_active_) {
				pad_();

				nes_emulate(1);

				// copy sound
				int16_t tmp[audio_len_];
				apu_process(tmp, audio_len_);
				for(int i = 0; i < audio_len_; ++i) {
					fifo_.put(tmp[i]);
				}

				if(fifo_.length() >= (audio_queue_ * 2) && audio_) {
					al::sound& sound = director_.at().sound_;
					for(int i = 0; i < audio_queue_; ++i) {
						al::pcm16_m w(fifo_.get());
						audio_->put(i, w);
					}
					sound.queue_audio(audio_);
				}

				// copy video
				bitmap_t* v = nes_->vidbuf;
				const rgb_t* lut = get_palette();
				if(v != nullptr && lut != nullptr) {
					for(int h = 0; h < nes_height_; ++h) {
						const uint8_t* src = &v->data[h * v->pitch];
						uint8_t* dst = &fb_[h * nes_width_ * 4];
						for(int w = 0; w < nes_width_; ++w) {
							auto idx = *src++;
							idx &= 63;
							*dst++ = lut[idx].r;  // R
							*dst++ = lut[idx].g;  // G
							*dst++ = lut[idx].b;  // B
							*dst++ = 255;  // alpha
						}
					}
					texfb_.rendering(gl::texfb::image::RGBA, (const char*)&fb_[0]);
				}

			}

			texfb_.flip();

			wd.update();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  レンダリング
		*/
		//-----------------------------------------------------------------//
		void render()
		{
	   		gl::core& core = gl::core::get_instance();

			const vtx::spos& siz = core.get_rect().size;

			texfb_.setup_matrix(0, 0, siz.x, siz.y);

			float scale = 1.0f;
			float ofsx = 0.0f;
			float ofsy = 0.0f;
			if(siz.x < siz.y) {
				scale = static_cast<float>(siz.x) / static_cast<float>(nes_width_);
				float h = static_cast<float>(nes_height_);
				ofsy = (static_cast<float>(siz.y) - h * scale) * 0.5f;
			} else {
				scale = static_cast<float>(siz.y) / static_cast<float>(nes_height_);
				float w = static_cast<float>(nes_width_);
				ofsx = (static_cast<float>(siz.x) - w * scale) * 0.5f;
			}
			gl::glTranslate(ofsx, ofsy);
			gl::glScale(scale);
			texfb_.draw();

			director_.at().widget_director_.service();
			director_.at().widget_director_.render();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  廃棄
		*/
		//-----------------------------------------------------------------//
		void destroy()
		{
			nes_destroy(nes_);

			sys::preference& pre = director_.at().preference_;
			if(filer_) {
				filer_->save(pre);
			}
			if(terminal_frame_) {
				terminal_frame_->save(pre);
			}
		}

	};

}
<commit_msg>update filer setting<commit_after>#pragma once
//=====================================================================//
/*! @file
	@brief  NES Emulator クラス @n
			操作説明： @n
			「１」： SELECT @n
			「２」： START @n
			「Ｚ」： A-BUTTON @n
			「Ｘ」： B-BUTTON @n
			「↑」： UP-DIR @n
			「↓」： DOWN-DIR @n
			「→」： RIGHT-DIR @n
			「←」： LEFT-DIR @n
			「F1」： Filer @n
			「F4」： Log Terminal @n
			Copyright 2017 Kunihito Hiramatsu
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "main.hpp"
#include "utils/i_scene.hpp"
#include "utils/director.hpp"
#include "widgets/widget.hpp"
#include "widgets/widget_frame.hpp"
#include "widgets/widget_terminal.hpp"
#include "widgets/widget_filer.hpp"
#include "gl_fw/gltexfb.hpp"
#include "snd_io/pcm.hpp"
#include "utils/fifo.hpp"

extern "C" {
	#include "nes.h"
	#include "nesinput.h"
	extern const rgb_t* get_palette();
};

namespace app {

	class nesemu : public utils::i_scene {

		utils::director<core>&	director_;

		gui::widget_frame*		terminal_frame_;
		gui::widget_terminal*	terminal_core_;
		bool					terminal_;

		gui::widget_filer*		filer_;

		gl::texfb			texfb_;

		static const int nes_width_  = 256;
		static const int nes_height_ = 240;
		static const int sample_rate_ = 44100;
		static const int audio_len_ = sample_rate_ / 60;
		static const int audio_queue_ = 1024;

		nes_t*	nes_;

		bool	rom_active_;

		typedef utils::fifo<int16_t, audio_queue_ * 16> fifo;
		fifo		fifo_;
		al::audio	audio_;

		uint8_t	fb_[nes_width_ * nes_height_ * 4];

		nesinput_t	inp_[2];

		void pad_()
		{
	   		gl::core& core = gl::core::get_instance();

			const gl::device& dev = core.get_device();

			inp_[0].data = 0;
			inp_[1].data = 0;

			// A
			if(dev.get_level(gl::device::key::Z)) {
				inp_[0].data |= INP_PAD_A;
			}
			if(dev.get_level(gl::device::key::GAME_0)) {
				inp_[0].data |= INP_PAD_A;
			}

			// B
			if(dev.get_level(gl::device::key::X)) {
				inp_[0].data |= INP_PAD_B;
			}
			if(dev.get_level(gl::device::key::GAME_1)) {
				inp_[0].data |= INP_PAD_B;
			}

			// SELECT
			if(dev.get_level(gl::device::key::_1)) {
				inp_[0].data |= INP_PAD_SELECT;
			}
			if(dev.get_level(gl::device::key::GAME_2)) {
				inp_[0].data |= INP_PAD_SELECT;
			}
			// START
			if(dev.get_level(gl::device::key::_2)) {
				inp_[0].data |= INP_PAD_START;
			}
			if(dev.get_level(gl::device::key::GAME_3)) {
				inp_[0].data |= INP_PAD_START;
			}

			if(dev.get_level(gl::device::key::LEFT)) {
   		 		inp_[0].data |= INP_PAD_LEFT;
			}
			if(dev.get_level(gl::device::key::GAME_LEFT)) {
   		 		inp_[0].data |= INP_PAD_LEFT;
			}
			if(dev.get_level(gl::device::key::RIGHT)) {
   		 		inp_[0].data |= INP_PAD_RIGHT;
			}
			if(dev.get_level(gl::device::key::GAME_RIGHT)) {
   		 		inp_[0].data |= INP_PAD_RIGHT;
			}
			if(dev.get_level(gl::device::key::UP)) {
   		 		inp_[0].data |= INP_PAD_UP;
			}
			if(dev.get_level(gl::device::key::GAME_UP)) {
   		 		inp_[0].data |= INP_PAD_UP;
			}
			if(dev.get_level(gl::device::key::DOWN)) {
   		 		inp_[0].data |= INP_PAD_DOWN;
			}
			if(dev.get_level(gl::device::key::GAME_DOWN)) {
   		 		inp_[0].data |= INP_PAD_DOWN;
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		nesemu(utils::director<core>& d) : director_(d),
			terminal_frame_(nullptr), terminal_core_(nullptr), terminal_(false),
			nes_(nullptr), rom_active_(false)
		{ }

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		virtual ~nesemu() { }

		//-----------------------------------------------------------------//
		/*!
			@brief  初期化
		*/
		//-----------------------------------------------------------------//
		void initialize()
		{
	   		gl::core& core = gl::core::get_instance();

			using namespace gui;
			widget_director& wd = director_.at().widget_director_;
			{  	// ターミナル
				{
					widget::param wp(vtx::irect(10, 10, 200, 200));
					widget_frame::param wp_;
					wp_.plate_param_.set_caption(15);
					terminal_frame_ = wd.add_widget<widget_frame>(wp, wp_);
					terminal_frame_->enable(terminal_);
				}
				{
					widget::param wp(vtx::irect(0), terminal_frame_);
					widget_terminal::param wp_;
					terminal_core_ = wd.add_widget<widget_terminal>(wp, wp_);
				}
			}

			{  	// ファイラー
				widget::param wp(vtx::irect(10, 10, 200, 200));
				widget_filer::param wp_(core.get_current_path(), "");
				wp_.select_file_func_ = [this](const std::string& fn) {
					if(nes_insertcart(fn.c_str(), nes_) == 0) {
						rom_active_ = true;
					} else {
						//
					}
				};
				filer_ = wd.add_widget<widget_filer>(wp, wp_);
				filer_->enable(false);
			}

			texfb_.initialize(nes_width_, nes_height_, 32);

			nes_ = nes_create(sample_rate_, 16);

			// regist input
			inp_[0].type = INP_JOYPAD0;
			inp_[0].data = 0;
			input_register(&inp_[0]);
			inp_[1].type = INP_JOYPAD1;
			inp_[1].data = 0;
			input_register(&inp_[1]);

			audio_ = al::create_audio(al::audio_format::PCM16_MONO);
			audio_->create(sample_rate_, audio_queue_);

//			auto path = core.get_current_path();

//			path += "/GALAXIAN.NES";
//			path += "/Zombie.nes";
//			path += "/DRAGONQ1.NES";
//			path += "/DRAGONW2.NES";
//			path += "/SOLSTICE.NES";
//			path += "/GRADIUS.NES";

//			nes_insertcart(path.c_str(), nes_);

			// プリファレンスの取得
			sys::preference& pre = director_.at().preference_;
			if(filer_) {
				filer_->load(pre);
			}
			if(terminal_frame_) {
				terminal_frame_->load(pre);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  アップデート
		*/
		//-----------------------------------------------------------------//
		void update()
		{
	   		gl::core& core = gl::core::get_instance();
			const gl::device& dev = core.get_device();

			if(dev.get_negative(gl::device::key::F1)) {
				filer_->enable(!filer_->get_enable());
			}
			if(dev.get_negative(gl::device::key::F5)) {
				terminal_ = !terminal_;
				terminal_frame_->enable(terminal_);
			}

        	gui::widget_director& wd = director_.at().widget_director_;

			if(nes_ != nullptr && rom_active_) {
				pad_();

				nes_emulate(1);

				// copy sound
				int16_t tmp[audio_len_];
				apu_process(tmp, audio_len_);
				for(int i = 0; i < audio_len_; ++i) {
					fifo_.put(tmp[i]);
				}

				if(fifo_.length() >= (audio_queue_ * 2) && audio_) {
					al::sound& sound = director_.at().sound_;
					for(int i = 0; i < audio_queue_; ++i) {
						al::pcm16_m w(fifo_.get());
						audio_->put(i, w);
					}
					sound.queue_audio(audio_);
				}

				// copy video
				bitmap_t* v = nes_->vidbuf;
				const rgb_t* lut = get_palette();
				if(v != nullptr && lut != nullptr) {
					for(int h = 0; h < nes_height_; ++h) {
						const uint8_t* src = &v->data[h * v->pitch];
						uint8_t* dst = &fb_[h * nes_width_ * 4];
						for(int w = 0; w < nes_width_; ++w) {
							auto idx = *src++;
							idx &= 63;
							*dst++ = lut[idx].r;  // R
							*dst++ = lut[idx].g;  // G
							*dst++ = lut[idx].b;  // B
							*dst++ = 255;  // alpha
						}
					}
					texfb_.rendering(gl::texfb::image::RGBA, (const char*)&fb_[0]);
				}

			}

			texfb_.flip();

			wd.update();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  レンダリング
		*/
		//-----------------------------------------------------------------//
		void render()
		{
	   		gl::core& core = gl::core::get_instance();

			const vtx::spos& siz = core.get_rect().size;

			texfb_.setup_matrix(0, 0, siz.x, siz.y);

			float scale = 1.0f;
			float ofsx = 0.0f;
			float ofsy = 0.0f;
			if(siz.x < siz.y) {
				scale = static_cast<float>(siz.x) / static_cast<float>(nes_width_);
				float h = static_cast<float>(nes_height_);
				ofsy = (static_cast<float>(siz.y) - h * scale) * 0.5f;
			} else {
				scale = static_cast<float>(siz.y) / static_cast<float>(nes_height_);
				float w = static_cast<float>(nes_width_);
				ofsx = (static_cast<float>(siz.x) - w * scale) * 0.5f;
			}
			gl::glTranslate(ofsx, ofsy);
			gl::glScale(scale);
			texfb_.draw();

			director_.at().widget_director_.service();
			director_.at().widget_director_.render();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  廃棄
		*/
		//-----------------------------------------------------------------//
		void destroy()
		{
			nes_destroy(nes_);

			sys::preference& pre = director_.at().preference_;
			if(filer_) {
				filer_->save(pre);
			}
			if(terminal_frame_) {
				terminal_frame_->save(pre);
			}
		}

	};

}
<|endoftext|>


<commit_before>// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// 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 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.
//
// For more information, please refer to <http://unlicense.org/>

#include "utest.h"

#ifdef _MSC_VER
#pragma warning(push)

// disable 'conditional expression is constant' - our examples below use this!
#pragma warning(disable : 4127)
#endif

UTEST(cpp, ASSERT_TRUE) { ASSERT_TRUE(1); }

UTEST(cpp, ASSERT_FALSE) { ASSERT_FALSE(0); }

UTEST(cpp, ASSERT_EQ) { ASSERT_EQ(1, 1); }

UTEST(cpp, ASSERT_NE) { ASSERT_NE(1, 2); }

UTEST(cpp, ASSERT_LT) { ASSERT_LT(1, 2); }

UTEST(cpp, ASSERT_LE) {
  ASSERT_LE(1, 1);
  ASSERT_LE(1, 2);
}

UTEST(cpp, ASSERT_GT) { ASSERT_GT(2, 1); }

UTEST(cpp, ASSERT_GE) {
  ASSERT_GE(1, 1);
  ASSERT_GE(2, 1);
}

UTEST(c, ASSERT_STREQ) { ASSERT_STREQ("foo", "foo"); }

UTEST(c, ASSERT_STRNE) { ASSERT_STRNE("foo", "bar"); }

UTEST(cpp, EXPECT_TRUE) { EXPECT_TRUE(1); }

UTEST(cpp, EXPECT_FALSE) { EXPECT_FALSE(0); }

UTEST(cpp, EXPECT_EQ) { EXPECT_EQ(1, 1); }

UTEST(cpp, EXPECT_NE) { EXPECT_NE(1, 2); }

UTEST(cpp, EXPECT_LT) { EXPECT_LT(1, 2); }

UTEST(cpp, EXPECT_LE) {
  EXPECT_LE(1, 1);
  EXPECT_LE(1, 2);
}

UTEST(cpp, EXPECT_GT) { EXPECT_GT(2, 1); }

UTEST(cpp, EXPECT_GE) {
  EXPECT_GE(1, 1);
  EXPECT_GE(2, 1);
}

UTEST(c, EXPECT_STREQ) { EXPECT_STREQ("foo", "foo"); }

UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); }

struct MyTestF {
  int foo;
};

UTEST_F_SETUP(MyTestF) {
  ASSERT_EQ(0, utest_fixture->foo);
  utest_fixture->foo = 42;
}

UTEST_F_TEARDOWN(MyTestF) {
  ASSERT_EQ(13, utest_fixture->foo);
}

UTEST_F(MyTestF, cpp) {
  ASSERT_EQ(42, utest_fixture->foo);
  utest_fixture->foo = 13;
}

UTEST_F(MyTestF, cpp2) {
  ASSERT_EQ(42, utest_fixture->foo);
  utest_fixture->foo = 13;
}

struct MyTestI {
  size_t foo;
  size_t bar;
};

UTEST_I_SETUP(MyTestI) {
  ASSERT_EQ(0, utest_fixture->foo);
  ASSERT_EQ(0, utest_fixture->bar);
  utest_fixture->foo = 42;
  utest_fixture->bar = utest_index;
}

UTEST_I_TEARDOWN(MyTestI) {
  ASSERT_EQ(13, utest_fixture->foo);
  ASSERT_EQ(utest_index, utest_fixture->bar);
}

UTEST_I(MyTestI, cpp, 2) {
  ASSERT_GT(2, utest_fixture->bar);
  utest_fixture->foo = 13;
}

UTEST_I(MyTestI, cpp2, 128) {
  ASSERT_GT(128, utest_fixture->bar);
  utest_fixture->foo = 13;
}
<commit_msg>MR: Remove spurious pragma warning push.@<commit_after>// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// 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 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.
//
// For more information, please refer to <http://unlicense.org/>

#include "utest.h"

#ifdef _MSC_VER
// disable 'conditional expression is constant' - our examples below use this!
#pragma warning(disable : 4127)
#endif

UTEST(cpp, ASSERT_TRUE) { ASSERT_TRUE(1); }

UTEST(cpp, ASSERT_FALSE) { ASSERT_FALSE(0); }

UTEST(cpp, ASSERT_EQ) { ASSERT_EQ(1, 1); }

UTEST(cpp, ASSERT_NE) { ASSERT_NE(1, 2); }

UTEST(cpp, ASSERT_LT) { ASSERT_LT(1, 2); }

UTEST(cpp, ASSERT_LE) {
  ASSERT_LE(1, 1);
  ASSERT_LE(1, 2);
}

UTEST(cpp, ASSERT_GT) { ASSERT_GT(2, 1); }

UTEST(cpp, ASSERT_GE) {
  ASSERT_GE(1, 1);
  ASSERT_GE(2, 1);
}

UTEST(c, ASSERT_STREQ) { ASSERT_STREQ("foo", "foo"); }

UTEST(c, ASSERT_STRNE) { ASSERT_STRNE("foo", "bar"); }

UTEST(cpp, EXPECT_TRUE) { EXPECT_TRUE(1); }

UTEST(cpp, EXPECT_FALSE) { EXPECT_FALSE(0); }

UTEST(cpp, EXPECT_EQ) { EXPECT_EQ(1, 1); }

UTEST(cpp, EXPECT_NE) { EXPECT_NE(1, 2); }

UTEST(cpp, EXPECT_LT) { EXPECT_LT(1, 2); }

UTEST(cpp, EXPECT_LE) {
  EXPECT_LE(1, 1);
  EXPECT_LE(1, 2);
}

UTEST(cpp, EXPECT_GT) { EXPECT_GT(2, 1); }

UTEST(cpp, EXPECT_GE) {
  EXPECT_GE(1, 1);
  EXPECT_GE(2, 1);
}

UTEST(c, EXPECT_STREQ) { EXPECT_STREQ("foo", "foo"); }

UTEST(c, EXPECT_STRNE) { EXPECT_STRNE("foo", "bar"); }

struct MyTestF {
  int foo;
};

UTEST_F_SETUP(MyTestF) {
  ASSERT_EQ(0, utest_fixture->foo);
  utest_fixture->foo = 42;
}

UTEST_F_TEARDOWN(MyTestF) {
  ASSERT_EQ(13, utest_fixture->foo);
}

UTEST_F(MyTestF, cpp) {
  ASSERT_EQ(42, utest_fixture->foo);
  utest_fixture->foo = 13;
}

UTEST_F(MyTestF, cpp2) {
  ASSERT_EQ(42, utest_fixture->foo);
  utest_fixture->foo = 13;
}

struct MyTestI {
  size_t foo;
  size_t bar;
};

UTEST_I_SETUP(MyTestI) {
  ASSERT_EQ(0, utest_fixture->foo);
  ASSERT_EQ(0, utest_fixture->bar);
  utest_fixture->foo = 42;
  utest_fixture->bar = utest_index;
}

UTEST_I_TEARDOWN(MyTestI) {
  ASSERT_EQ(13, utest_fixture->foo);
  ASSERT_EQ(utest_index, utest_fixture->bar);
}

UTEST_I(MyTestI, cpp, 2) {
  ASSERT_GT(2, utest_fixture->bar);
  utest_fixture->foo = 13;
}

UTEST_I(MyTestI, cpp2, 128) {
  ASSERT_GT(128, utest_fixture->bar);
  utest_fixture->foo = 13;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <memory>

#include <../bindings/python/JointPython.h>
#include <Tests_adapters.hpp>
#include <test/core/Tests.hpp>

using namespace test;

test::TestEngine		g_engine;

class Tests
{
private:
	joint::Module			_module;

public:
	Tests(joint::Module module)
		: _module(std::move(module))
	{ }

	void RunBasicTests()
	{
		ScopedTest t(g_engine, "Basic tests");

		joint::Ptr<IBasicTests> basic = _module.GetRootObject<IBasicTests>("GetBasicTests");

		TEST_THROWS_ANYTHING(basic->Throw());
		TEST_THROWS_NOTHING(basic->ReturnI32());
		TEST_EQUALS(14, basic->AddI32(2, 12));
	}
};

int main()
{
	try
	{
		Joint_SetLogLevel(JOINT_LOGLEVEL_WARNING);

		JOINT_CALL( JointPython_Register() );

		Tests t(joint::Module("python", "Tests"));
		t.RunBasicTests();

		JOINT_CALL( JointPython_Unregister() );
	}
	catch (const std::exception& ex)
	{
		std::cerr << "Uncaught exception: " << ex.what() << std::endl;
		return 1;
	}

	return 0;
}
<commit_msg>Fixed a memory corruption in test<commit_after>#include <iostream>
#include <memory>

#include <../bindings/python/JointPython.h>
#include <Tests_adapters.hpp>
#include <test/core/Tests.hpp>

using namespace test;

test::TestEngine		g_engine;

class Tests
{
private:
	joint::Module			_module;

public:
	Tests(joint::Module module)
		: _module(std::move(module))
	{ }

	void RunBasicTests()
	{
		ScopedTest t(g_engine, "Basic tests");

		joint::Ptr<IBasicTests> basic = _module.GetRootObject<IBasicTests>("GetBasicTests");

		TEST_THROWS_ANYTHING(basic->Throw());
		TEST_THROWS_NOTHING(basic->ReturnI32());
		TEST_EQUALS(14, basic->AddI32(2, 12));
	}
};

int main()
{
	try
	{
		Joint_SetLogLevel(JOINT_LOGLEVEL_WARNING);

		JOINT_CALL( JointPython_Register() );

		{
			Tests t(joint::Module("python", "Tests"));
			t.RunBasicTests();
		}

		JOINT_CALL( JointPython_Unregister() );
	}
	catch (const std::exception& ex)
	{
		std::cerr << "Uncaught exception: " << ex.what() << std::endl;
		return 1;
	}

	return 0;
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright 2012-2016 Masanori Morise. All Rights Reserved.
// Author: mmorise [at] yamanashi.ac.jp (Masanori Morise)
//
// Test program for WORLD 0.1.2 (2012/08/19)
// Test program for WORLD 0.1.3 (2013/07/26)
// Test program for WORLD 0.1.4 (2014/04/29)
// Test program for WORLD 0.1.4_3 (2015/03/07)
// Test program for WORLD 0.2.0 (2015/05/29)
// Test program for WORLD 0.2.0_1 (2015/05/31)
// Test program for WORLD 0.2.0_2 (2015/06/06)
// Test program for WORLD 0.2.0_3 (2015/07/28)
// Test program for WORLD 0.2.0_4 (2015/11/15)
// Test program for WORLD in GitHub (2015/11/16-)
// Latest update: 2016/02/01

// test.exe input.wav outout.wav f0 spec
// input.wav  : Input file
// output.wav : Output file
// f0         : F0 scaling (a positive number)
// spec       : Formant scaling (a positive number)
//-----------------------------------------------------------------------------

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#if (defined (__WIN32__) || defined (_WIN32)) && !defined (__MINGW32__)
#include <conio.h>
#include <windows.h>
#pragma comment(lib, "winmm.lib")
#pragma warning(disable : 4996)
#endif
#if (defined (__linux__) || defined(__CYGWIN__) || defined(__APPLE__))
#include <stdint.h>
#include <sys/time.h>
#endif

// For .wav input/output functions.
#include "./audioio.h"

// WORLD core functions.
#include "./../src/d4c.h"
#include "./../src/dio.h"
#include "./../src/matlabfunctions.h"
#include "./../src/cheaptrick.h"
#include "./../src/stonemask.h"
#include "./../src/synthesis.h"

// Frame shift [msec]
#define FRAMEPERIOD 5.0
// F0_floor used for CheapTrick and D4C [Hz]
#define F0_FLOOR 71

#if (defined (__linux__) || defined(__CYGWIN__) || defined(__APPLE__))
// Linux porting section: implement timeGetTime() by gettimeofday(),
#ifndef DWORD
#define DWORD uint32_t
#endif
DWORD timeGetTime() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  DWORD ret = static_cast<DWORD>(tv.tv_usec / 1000 + tv.tv_sec * 1000);
  return ret;
}
#endif

namespace {

void DisplayInformation(double *x, int fs, int nbit, int x_length) {
  printf("File information\n");
  printf("Sampling : %d Hz %d Bit\n", fs, nbit);
  printf("Length %d [sample]\n", x_length);
  printf("Length %f [sec]\n", static_cast<double>(x_length) / fs);
}

void F0Estimation(double *x, int x_length, int fs, int f0_length,
    DioOption *option, double *f0, double *time_axis) {
  double *refined_f0 = new double[f0_length];
  // Modification of the option
  option->frame_period = FRAMEPERIOD;
  // Valuable option.speed represents the ratio for downsampling.
  // The signal is downsampled to fs / speed Hz.
  // If you want to obtain the accurate result, speed should be set to 1.
  option->speed = 1;
  // You should not set option.f0_floor to under world::kFloorF0.
  // If you want to analyze such low F0 speech, please change world::kFloorF0.
  // Processing speed may sacrify, provided that the FFT length changes.
  option->f0_floor = 71.0;
  // You can give a positive real number as the threshold.
  // Most strict value is 0, but almost all results are counted as unvoiced.
  // The value from 0.02 to 0.2 would be reasonable.
  option->allowed_range = 0.1;

  printf("\nAnalysis\n");
  DWORD elapsed_time = timeGetTime();
  Dio(x, x_length, fs, option, time_axis, f0);
  printf("DIO: %d [msec]\n", timeGetTime() - elapsed_time);

  // StoneMask is carried out to improve the estimation performance.
  elapsed_time = timeGetTime();
  StoneMask(x, x_length, fs, time_axis, f0, f0_length, refined_f0);
  printf("StoneMask: %d [msec]\n", timeGetTime() - elapsed_time);

  for (int i = 0; i < f0_length; ++i) f0[i] = refined_f0[i];

  delete[] refined_f0;
  return;
}

void SpectralEnvelopeEstimation(double *x, int x_length, int fs,
    double *time_axis, double *f0, int f0_length, CheapTrickOption *option,
    double **spectrogram) {
  option->q1 = -0.15;  // This value may be better one for HMM speech synthesis.

  DWORD elapsed_time = timeGetTime();
  CheapTrick(x, x_length, fs, time_axis, f0, f0_length, option, spectrogram);
  printf("CheapTrick: %d [msec]\n", timeGetTime() - elapsed_time);
}

void AperiodicityEstimation(double *x, int x_length, int fs, double *time_axis,
    double *f0, int f0_length, int fft_size, D4COption *option,
    double **aperiodicity) {
//  D4COption option;
//  InitializeD4COption(&option);  // Initialize the option

  DWORD elapsed_time = timeGetTime();
  // option is not implemented in this version. This is for future update.
  // We can use "NULL" as the argument.
  D4C(x, x_length, fs, time_axis, f0, f0_length, fft_size, option,
      aperiodicity);
  printf("D4C: %d [msec]\n", timeGetTime() - elapsed_time);
}

void ParameterModification(int argc, char *argv[], int fs, int f0_length,
    int fft_size, double *f0, double **spectrogram) {
  // F0 scaling
  if (argc >= 4) {
    double shift = atof(argv[3]);
    for (int i = 0; i < f0_length; ++i) f0[i] *= shift;
  }
  // Spectral stretching
  if (argc >= 5) {
    double ratio = atof(argv[4]);
    double *freq_axis1 = new double[fft_size];
    double *freq_axis2 = new double[fft_size];
    double *spectrum1 = new double[fft_size];
    double *spectrum2 = new double[fft_size];

    for (int i = 0; i <= fft_size / 2; ++i) {
      freq_axis1[i] = ratio * i / fft_size * fs;
      freq_axis2[i] = static_cast<double>(i) / fft_size * fs;
    }
    for (int i = 0; i < f0_length; ++i) {
      for (int j = 0; j <= fft_size / 2; ++j)
        spectrum1[j] = log(spectrogram[i][j]);
      interp1(freq_axis1, spectrum1, fft_size / 2 + 1, freq_axis2,
        fft_size / 2 + 1, spectrum2);
      for (int j = 0; j <= fft_size / 2; ++j)
        spectrogram[i][j] = exp(spectrum2[j]);
      if (ratio < 1.0) {
        for (int j = static_cast<int>(fft_size / 2.0 * ratio);
            j <= fft_size / 2; ++j)
          spectrogram[i][j] =
          spectrogram[i][static_cast<int>(fft_size / 2.0 * ratio) - 1];
      }
    }
    delete[] spectrum1;
    delete[] spectrum2;
    delete[] freq_axis1;
    delete[] freq_axis2;
  }
}

void WaveformSynthesis(double *f0, int f0_length, double **spectrogram,
    double **aperiodicity, int fft_size, double frame_period, int fs,
    int y_length, double *y) {
  DWORD elapsed_time;
  // Synthesis by the aperiodicity
  printf("\nSynthesis\n");
  elapsed_time = timeGetTime();
  Synthesis(f0, f0_length, spectrogram, aperiodicity,
      fft_size, FRAMEPERIOD, fs, y_length, y);
  printf("WORLD: %d [msec]\n", timeGetTime() - elapsed_time);
}

}  // namespace

//-----------------------------------------------------------------------------
// Test program.
// test.exe input.wav outout.wav f0 spec flag
// input.wav  : argv[1] Input file
// output.wav : argv[2] Output file
// f0         : argv[3] F0 scaling (a positive number)
// spec       : argv[4] Formant shift (a positive number)
//-----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
  if (argc != 2 && argc != 3 && argc != 4 && argc != 5) {
    printf("error\n");
    return -2;
  }
  int fs, nbit, x_length;

  // 2016/01/28: Important modification.
  // Memory allocation is carried out in advanse.
  // This is for compatibility with C language.
  x_length = GetAudioLength(argv[1]);
  if (x_length <= 0) {
    if (x_length == 0)
      printf("error: File not found.\n");
    else
      printf("error: The file is not .wav format.\n");
    return -1;
  }
  double *x = new double[x_length];
  // wavread() must be called after GetAudioLength().
  wavread(argv[1], &fs, &nbit, x);
  DisplayInformation(x, fs, nbit, x_length);

  // Allocate memories
  // The number of samples for F0
  int f0_length = GetSamplesForDIO(fs, x_length, FRAMEPERIOD);
  double *f0 = new double[f0_length];
  double *time_axis = new double[f0_length];
  DioOption dio_option;
  InitializeDioOption(&dio_option);  // Initialize the option
  // F0 estimation
  F0Estimation(x, x_length, fs, f0_length, &dio_option, f0, time_axis);

  CheapTrickOption cheaptrick_option;
  InitializeCheapTrickOption(&cheaptrick_option);  // Initialize the option
  // FFT size for CheapTrick and D4C
  // Important notice (2016/02/01)
  // You can control a parameter used for the lowest F0 in speech.
  // You must not set the f0_floor to 0.
  // You must not change the f0_floor after setting fft_size.
  // It will cause a fatal error because fft_size indicates the infinity.
  // You should check the fft_size before excucing the analysis/synthesis.
  cheaptrick_option.f0_floor = F0_FLOOR;
  int fft_size = GetFFTSizeForCheapTrick(fs, &cheaptrick_option);
  printf("FFT_SIZE: %d [sample]\n", fft_size);
  double **spectrogram = new double *[f0_length];
  double **aperiodicity = new double *[f0_length];
  for (int i = 0; i < f0_length; ++i) {
    spectrogram[i] = new double[fft_size / 2 + 1];
    aperiodicity[i] = new double[fft_size / 2 + 1];
  }

  // Spectral envelope estimation
  SpectralEnvelopeEstimation(x, x_length, fs, time_axis, f0, f0_length,
      &cheaptrick_option, spectrogram);

  // Aperiodicity estimation by D4C
  D4COption d4c_option;
  InitializeD4COption(&d4c_option);  // Initialize the option
  AperiodicityEstimation(x, x_length, fs, time_axis, f0, f0_length,
      fft_size, &d4c_option, aperiodicity);

  // Note that F0 must not be changed until all parameters are estimated.
  ParameterModification(argc, argv, fs, f0_length, fft_size, f0, spectrogram);

  // The length of the output waveform
  int y_length =
    static_cast<int>((f0_length - 1) * FRAMEPERIOD / 1000.0 * fs) + 1;
  double *y = new double[y_length];
  // Synthesis
  WaveformSynthesis(f0, f0_length, spectrogram, aperiodicity, fft_size,
      FRAMEPERIOD, fs, y_length, y);

  // Output
  wavwrite(y, y_length, fs, 16, argv[2]);

  printf("complete.\n");

  delete[] x;
  delete[] time_axis;
  delete[] f0;
  delete[] y;
  for (int i = 0; i < f0_length; ++i) {
    delete[] spectrogram[i];
    delete[] aperiodicity[i];
  }
  delete[] spectrogram;
  delete[] aperiodicity;

  return 0;
}
<commit_msg>Modification (test.cpp) for more safe implementation<commit_after>//-----------------------------------------------------------------------------
// Copyright 2012-2016 Masanori Morise. All Rights Reserved.
// Author: mmorise [at] yamanashi.ac.jp (Masanori Morise)
//
// Test program for WORLD 0.1.2 (2012/08/19)
// Test program for WORLD 0.1.3 (2013/07/26)
// Test program for WORLD 0.1.4 (2014/04/29)
// Test program for WORLD 0.1.4_3 (2015/03/07)
// Test program for WORLD 0.2.0 (2015/05/29)
// Test program for WORLD 0.2.0_1 (2015/05/31)
// Test program for WORLD 0.2.0_2 (2015/06/06)
// Test program for WORLD 0.2.0_3 (2015/07/28)
// Test program for WORLD 0.2.0_4 (2015/11/15)
// Test program for WORLD in GitHub (2015/11/16-)
// Latest update: 2016/02/02

// test.exe input.wav outout.wav f0 spec
// input.wav  : Input file
// output.wav : Output file
// f0         : F0 scaling (a positive number)
// spec       : Formant scaling (a positive number)
//-----------------------------------------------------------------------------

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#if (defined (__WIN32__) || defined (_WIN32)) && !defined (__MINGW32__)
#include <conio.h>
#include <windows.h>
#pragma comment(lib, "winmm.lib")
#pragma warning(disable : 4996)
#endif
#if (defined (__linux__) || defined(__CYGWIN__) || defined(__APPLE__))
#include <stdint.h>
#include <sys/time.h>
#endif

// For .wav input/output functions.
#include "./audioio.h"

// WORLD core functions.
#include "./../src/d4c.h"
#include "./../src/dio.h"
#include "./../src/matlabfunctions.h"
#include "./../src/cheaptrick.h"
#include "./../src/stonemask.h"
#include "./../src/synthesis.h"

#if (defined (__linux__) || defined(__CYGWIN__) || defined(__APPLE__))
// Linux porting section: implement timeGetTime() by gettimeofday(),
#ifndef DWORD
#define DWORD uint32_t
#endif
DWORD timeGetTime() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  DWORD ret = static_cast<DWORD>(tv.tv_usec / 1000 + tv.tv_sec * 1000);
  return ret;
}
#endif

//-----------------------------------------------------------------------------
// struct for WORLD
// This struct is an option.
// Users are NOT forced to use this struct.
//-----------------------------------------------------------------------------
typedef struct {
  double frame_period;
  int fs;

  double *f0;
  double *time_axis;
  int f0_length;

  double **spectrogram;
  double **aperiodicity;
  int fft_size;
} WorldParameters;

namespace {

void DisplayInformation(int fs, int nbit, int x_length) {
  printf("File information\n");
  printf("Sampling : %d Hz %d Bit\n", fs, nbit);
  printf("Length %d [sample]\n", x_length);
  printf("Length %f [sec]\n", static_cast<double>(x_length) / fs);
}

void F0Estimation(double *x, int x_length, WorldParameters *world_parameters) {
  DioOption option = {0};
  InitializeDioOption(&option);

  // Modification of the option
  // When you You must set the same value.
  // If a different value is used, you may suffer a fatal error because of a
  // illegal memory access.
  option.frame_period = world_parameters->frame_period;

  // Valuable option.speed represents the ratio for downsampling.
  // The signal is downsampled to fs / speed Hz.
  // If you want to obtain the accurate result, speed should be set to 1.
  option.speed = 1;

  // You should not set option.f0_floor to under world::kFloorF0.
  // If you want to analyze such low F0 speech, please change world::kFloorF0.
  // Processing speed may sacrify, provided that the FFT length changes.
  option.f0_floor = 71.0;

  // You can give a positive real number as the threshold.
  // Most strict value is 0, but almost all results are counted as unvoiced.
  // The value from 0.02 to 0.2 would be reasonable.
  option.allowed_range = 0.1;

  // Parameters setting and memory allocation.
  world_parameters->f0_length = GetSamplesForDIO(world_parameters->fs,
    x_length, world_parameters->frame_period);
  world_parameters->f0 = new double[world_parameters->f0_length];
  world_parameters->time_axis = new double[world_parameters->f0_length];
  double *refined_f0 = new double[world_parameters->f0_length];

  printf("\nAnalysis\n");
  DWORD elapsed_time = timeGetTime();
  Dio(x, x_length, world_parameters->fs, &option, world_parameters->time_axis,
      world_parameters->f0);
  printf("DIO: %d [msec]\n", timeGetTime() - elapsed_time);

  // StoneMask is carried out to improve the estimation performance.
  elapsed_time = timeGetTime();
  StoneMask(x, x_length, world_parameters->fs, world_parameters->time_axis,
      world_parameters->f0, world_parameters->f0_length, refined_f0);
  printf("StoneMask: %d [msec]\n", timeGetTime() - elapsed_time);

  for (int i = 0; i < world_parameters->f0_length; ++i)
    world_parameters->f0[i] = refined_f0[i];

  delete[] refined_f0;
  return;
}

void SpectralEnvelopeEstimation(double *x, int x_length,
    WorldParameters *world_parameters) {
  CheapTrickOption option = {0};
  InitializeCheapTrickOption(&option);

  // This value may be better one for HMM speech synthesis.
  // Default value is -0.09.
  option.q1 = -0.15;

  // Important notice (2016/02/02)
  // You can control a parameter used for the lowest F0 in speech.
  // You must not set the f0_floor to 0.
  // It will cause a fatal error because fft_size indicates the infinity.
  // You must not change the f0_floor after memory allocation.
  // You should check the fft_size before excucing the analysis/synthesis.
  // The default value (71.0) is strongly recommended.
  // On the other hand, setting the lowest F0 of speech is a good choice
  // to reduce the fft_size.
  option.f0_floor = 71.0;

  // Parameters setting and memory allocation.
  world_parameters->fft_size =
    GetFFTSizeForCheapTrick(world_parameters->fs, &option);
  world_parameters->spectrogram = new double *[world_parameters->f0_length];
  for (int i = 0; i < world_parameters->f0_length; ++i) {
    world_parameters->spectrogram[i] =
      new double[world_parameters->fft_size / 2 + 1];
  }

  DWORD elapsed_time = timeGetTime();
  CheapTrick(x, x_length, world_parameters->fs, world_parameters->time_axis,
      world_parameters->f0, world_parameters->f0_length, &option,
      world_parameters->spectrogram);
  printf("CheapTrick: %d [msec]\n", timeGetTime() - elapsed_time);
}

void AperiodicityEstimation(double *x, int x_length,
    WorldParameters *world_parameters) {
  D4COption option = {0};
  InitializeD4COption(&option);

  // Parameters setting and memory allocation.
  world_parameters->aperiodicity = new double *[world_parameters->f0_length];
  for (int i = 0; i < world_parameters->f0_length; ++i) {
    world_parameters->aperiodicity[i] =
      new double[world_parameters->fft_size / 2 + 1];
  }

  DWORD elapsed_time = timeGetTime();
  // option is not implemented in this version. This is for future update.
  // We can use "NULL" as the argument.
  D4C(x, x_length, world_parameters->fs, world_parameters->time_axis,
      world_parameters->f0, world_parameters->f0_length,
      world_parameters->fft_size, &option, world_parameters->aperiodicity);
  printf("D4C: %d [msec]\n", timeGetTime() - elapsed_time);
}

void ParameterModification(int argc, char *argv[], int fs, int f0_length,
    int fft_size, double *f0, double **spectrogram) {
  // F0 scaling
  if (argc >= 4) {
    double shift = atof(argv[3]);
    for (int i = 0; i < f0_length; ++i) f0[i] *= shift;
  }
  if (argc < 5) return;

  // Spectral stretching
  double ratio = atof(argv[4]);
  double *freq_axis1 = new double[fft_size];
  double *freq_axis2 = new double[fft_size];
  double *spectrum1 = new double[fft_size];
  double *spectrum2 = new double[fft_size];

  for (int i = 0; i <= fft_size / 2; ++i) {
    freq_axis1[i] = ratio * i / fft_size * fs;
    freq_axis2[i] = static_cast<double>(i) / fft_size * fs;
  }
  for (int i = 0; i < f0_length; ++i) {
    for (int j = 0; j <= fft_size / 2; ++j)
      spectrum1[j] = log(spectrogram[i][j]);
    interp1(freq_axis1, spectrum1, fft_size / 2 + 1, freq_axis2,
      fft_size / 2 + 1, spectrum2);
    for (int j = 0; j <= fft_size / 2; ++j)
      spectrogram[i][j] = exp(spectrum2[j]);
    if (ratio >= 1.0) continue;
    for (int j = static_cast<int>(fft_size / 2.0 * ratio);
        j <= fft_size / 2; ++j)
      spectrogram[i][j] =
      spectrogram[i][static_cast<int>(fft_size / 2.0 * ratio) - 1];
  }
  delete[] spectrum1;
  delete[] spectrum2;
  delete[] freq_axis1;
  delete[] freq_axis2;
}

void WaveformSynthesis(WorldParameters *world_parameters, int fs,
    int y_length, double *y) {
  DWORD elapsed_time;
  // Synthesis by the aperiodicity
  printf("\nSynthesis\n");
  elapsed_time = timeGetTime();
  Synthesis(world_parameters->f0, world_parameters->f0_length,
      world_parameters->spectrogram, world_parameters->aperiodicity,
      world_parameters->fft_size, world_parameters->frame_period, fs,
      y_length, y);
  printf("WORLD: %d [msec]\n", timeGetTime() - elapsed_time);
}

void DestroyMemory(WorldParameters *world_parameters) {
  delete[] world_parameters->time_axis;
  delete[] world_parameters->f0;
  for (int i = 0; i < world_parameters->f0_length; ++i) {
    delete[] world_parameters->spectrogram[i];
    delete[] world_parameters->aperiodicity[i];
  }
  delete[] world_parameters->spectrogram;
  delete[] world_parameters->aperiodicity;
}

}  // namespace

//-----------------------------------------------------------------------------
// Test program.
// test.exe input.wav outout.wav f0 spec flag
// input.wav  : argv[1] Input file
// output.wav : argv[2] Output file
// f0         : argv[3] F0 scaling (a positive number)
// spec       : argv[4] Formant shift (a positive number)
//-----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
  if (argc != 2 && argc != 3 && argc != 4 && argc != 5) {
    printf("error\n");
    return -2;
  }

  // 2016/01/28: Important modification.
  // Memory allocation is carried out in advanse.
  // This is for compatibility with C language.
  int x_length = GetAudioLength(argv[1]);
  if (x_length <= 0) {
    if (x_length == 0)
      printf("error: File not found.\n");
    else
      printf("error: The file is not .wav format.\n");
    return -1;
  }
  double *x = new double[x_length];
  // wavread() must be called after GetAudioLength().
  int fs, nbit;
  wavread(argv[1], &fs, &nbit, x);
  DisplayInformation(fs, nbit, x_length);

  //---------------------------------------------------------------------------
  // Analysis part
  //---------------------------------------------------------------------------
  // 2016/02/02
  // A new struct is introduced to implement safe program.
  WorldParameters world_parameters = { 0 };
  // You must set fs and frame_period before analysis/synthesis.
  world_parameters.fs = fs;

  // 5.0 ms is the default value.
  // Generally, the inverse of the lowest F0 of speech is the best.
  // However, the more elapsed time is required.
  world_parameters.frame_period = 5.0;

  // F0 estimation
  F0Estimation(x, x_length, &world_parameters);

  // Spectral envelope estimation
  SpectralEnvelopeEstimation(x, x_length, &world_parameters);

  // Aperiodicity estimation by D4C
  AperiodicityEstimation(x, x_length, &world_parameters);

  // Note that F0 must not be changed until all parameters are estimated.
  ParameterModification(argc, argv, fs, world_parameters.f0_length,
    world_parameters.fft_size, world_parameters.f0,
    world_parameters.spectrogram);

  //---------------------------------------------------------------------------
  // Synthesis part
  //---------------------------------------------------------------------------
  // The length of the output waveform
  int y_length = static_cast<int>((world_parameters.f0_length - 1) *
    world_parameters.frame_period / 1000.0 * fs) + 1;
  double *y = new double[y_length];
  // Synthesis
  WaveformSynthesis(&world_parameters, fs, y_length, y);

  // Output
  wavwrite(y, y_length, fs, 16, argv[2]);

  delete[] y;
  delete[] x;
  DestroyMemory(&world_parameters);

  printf("complete.\n");
  return 0;
}
<|endoftext|>


<commit_before>#include <stdint.h>

#ifndef __clockid_t_defined
#define __clockid_t_defined 1

typedef int32_t clockid_t;

#define CLOCK_REALTIME               0
#define CLOCK_MONOTONIC              1
#define CLOCK_PROCESS_CPUTIME_ID     2
#define CLOCK_THREAD_CPUTIME_ID      3
#define CLOCK_MONOTONIC_RAW          4
#define CLOCK_REALTIME_COARSE        5
#define CLOCK_MONOTONIC_COARSE       6
#define CLOCK_BOOTTIME               7
#define CLOCK_REALTIME_ALARM         8
#define CLOCK_BOOTTIME_ALARM         9

#endif  // __clockid_t_defined

#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC

struct timespec {
    long tv_sec;            /* Seconds.  */
    long tv_nsec;           /* Nanoseconds.  */
};

#endif  // _STRUCT_TIMESPEC

extern "C" {

extern int clock_gettime(clockid_t clk_id, struct timespec *tp);

WEAK bool halide_reference_clock_inited = false;
WEAK timespec halide_reference_clock;

WEAK int halide_start_clock() {
    // Guard against multiple calls
    if (!halide_reference_clock_inited) {
      clock_gettime(CLOCK_REALTIME, &halide_reference_clock);
      halide_reference_clock_inited = true;
    }
    return 0;
}

WEAK int64_t halide_current_time_ns() {
    timespec now;
    clock_gettime(CLOCK_REALTIME, &now);
    int64_t d = int64_t(now.tv_sec - halide_reference_clock.tv_sec)*1000000000;
    int64_t nd = (now.tv_nsec - halide_reference_clock.tv_nsec);
    return d + nd;
}

}
<commit_msg>Made linux_clock do the syscall directly to dodge linking woes.<commit_after>#include <stdint.h>

#ifndef __clockid_t_defined
#define __clockid_t_defined 1

typedef int32_t clockid_t;

#define CLOCK_REALTIME               0
#define CLOCK_MONOTONIC              1
#define CLOCK_PROCESS_CPUTIME_ID     2
#define CLOCK_THREAD_CPUTIME_ID      3
#define CLOCK_MONOTONIC_RAW          4
#define CLOCK_REALTIME_COARSE        5
#define CLOCK_MONOTONIC_COARSE       6
#define CLOCK_BOOTTIME               7
#define CLOCK_REALTIME_ALARM         8
#define CLOCK_BOOTTIME_ALARM         9

#endif  // __clockid_t_defined

#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC

struct timespec {
    long tv_sec;            /* Seconds.  */
    long tv_nsec;           /* Nanoseconds.  */
};

#endif  // _STRUCT_TIMESPEC

// Should be safe to include these, given that we know we're on linux
// if we're compiling this file.
#include <sys/syscall.h>
#include <unistd.h>

extern "C" {

WEAK bool halide_reference_clock_inited = false;
WEAK timespec halide_reference_clock;

WEAK int halide_start_clock() {
    // Guard against multiple calls
    if (!halide_reference_clock_inited) {
        syscall(SYS_clock_gettime, CLOCK_REALTIME, &halide_reference_clock);
        halide_reference_clock_inited = true;
    }
    return 0;
}

WEAK int64_t halide_current_time_ns() {
    timespec now;
    // To avoid requiring people to link -lrt, we just make the syscall directly.
    syscall(SYS_clock_gettime, CLOCK_REALTIME, &now);
    int64_t d = int64_t(now.tv_sec - halide_reference_clock.tv_sec)*1000000000;
    int64_t nd = (now.tv_nsec - halide_reference_clock.tv_nsec);
    return d + nd;
}

}
<|endoftext|>


<commit_before>#include "osg/Node"

#include "osgDB/Registry"
#include "osgDB/Input"
#include "osgDB/Output"

using namespace osg;
using namespace osgDB;

// forward declare functions to use later.
bool Node_readLocalData(Object& obj, Input& fr);
bool Node_writeLocalData(const Object& obj, Output& fw);

// register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_NodeProxy
(
    new osg::Node,
    "Node",
    "Object Node",
    &Node_readLocalData,
    &Node_writeLocalData
);

bool Node_readLocalData(Object& obj, Input& fr)
{
    bool iteratorAdvanced = false;

    Node& node = static_cast<Node&>(obj);

    if (fr.matchSequence("name %s"))
    {
        node.setName(fr[1].getStr());
        fr+=2;
        iteratorAdvanced = true;
    }

    if (fr[0].matchWord("cullingActive"))
    {
        if (fr[1].matchWord("FALSE"))
        {
            node.setCullingActive(false);
            iteratorAdvanced = true;
            fr+=2;
        }
        else if (fr[1].matchWord("TRUE"))
        {
            node.setCullingActive(true);
            iteratorAdvanced = true;
            fr+=2;
        }
    }

    //     if (fr.matchSequence("user_data {"))
    //     {
    //         notify(DEBUG) << "Matched user_data {"<< std::endl;
    //         int entry = fr[0].getNoNestedBrackets();
    //         fr += 2;
    //
    //         while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
    //         {
    //             Object* object = fr.readObject();
    //             if (object) setUserData(object);
    //             notify(DEBUG) << "read "<<object<< std::endl;
    //             ++fr;
    //         }
    //         iteratorAdvanced = true;
    //     }

    while (fr.matchSequence("description {"))
    {
        int entry = fr[0].getNoNestedBrackets();
        fr += 2;

        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            node.addDescription(fr[0].getStr());
            ++fr;
        }
        iteratorAdvanced = true;

    }

    while (fr.matchSequence("description %s"))
    {
        node.addDescription(fr[1].getStr());
        fr+=2;
        iteratorAdvanced = true;
    }

    static ref_ptr<StateSet> s_drawstate = new osg::StateSet;
    if (StateSet* readState = static_cast<StateSet*>(fr.readObjectOfType(*s_drawstate)))
    {
        node.setStateSet(readState);
        iteratorAdvanced = true;
    }

    static ref_ptr<NodeCallback> s_nodecallback = new osg::NodeCallback;
    while (fr.matchSequence("UpdateCallback {"))
    {
        int entry = fr[0].getNoNestedBrackets();
        fr += 2;

        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            NodeCallback* nodecallback = dynamic_cast<NodeCallback*>(fr.readObjectOfType(*s_nodecallback));
            if (nodecallback) node.setUpdateCallback(nodecallback);
            else ++fr;
        }
        iteratorAdvanced = true;

    }

    while (fr.matchSequence("CullCallback {"))
    {
        int entry = fr[0].getNoNestedBrackets();
        fr += 2;

        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            NodeCallback* nodecallback = dynamic_cast<NodeCallback*>(fr.readObjectOfType(*s_nodecallback));
            if (nodecallback) node.setUpdateCallback(nodecallback);
            else ++fr;
        }
        iteratorAdvanced = true;

    }

    return iteratorAdvanced;
}

bool Node_writeLocalData(const Object& obj, Output& fw)
{
    const Node& node = static_cast<const Node&>(obj);

    if (!node.getName().empty()) fw.indent() << "name "<<fw.wrapString(node.getName())<< std::endl;

    fw.indent() << "cullingActive ";
    if (node.getCullingActive()) fw << "TRUE"<< std::endl;
    else fw << "FALSE"<< std::endl;

    //     if (_userData)
    //     {
    //         Object* object = dynamic_cast<Object*>(_userData);
    //         if (object)
    //         {
    //             fw.indent() << "user_data {"<< std::endl;
    //             fw.moveIn();
    //             object->write(fw);
    //             fw.moveOut();
    //             fw.indent() << "}"<< std::endl;
    //         }
    //     }

    if (!node.getDescriptions().empty())
    {
        if (node.getDescriptions().size()==1)
        {
            fw.indent() << "description "<<fw.wrapString(node.getDescriptions().front())<< std::endl;
        }
        else
        {
            fw.indent() << "description {"<< std::endl;
            fw.moveIn();
            for(Node::DescriptionList::const_iterator ditr=node.getDescriptions().begin();
                ditr!=node.getDescriptions().end();
                ++ditr)
            {
                fw.indent() << fw.wrapString(*ditr)<< std::endl;
            }
            fw.moveOut();
            fw.indent() << "}"<< std::endl;
        }
    }

    if (node.getStateSet())
    {
        fw.writeObject(*node.getStateSet());
    }

    if (node.getUpdateCallback())
    {
        fw.indent() << "UpdateCallbacks {" << std::endl;
        fw.moveIn();
        fw.writeObject(*node.getUpdateCallback());
        fw.moveOut();
        fw.indent() << "}" << std::endl;
    }

    if (node.getCullCallback())
    {
        fw.indent() << "CullCallbacks {" << std::endl;
        fw.moveIn();
        fw.writeObject(*node.getCullCallback());
        fw.moveOut();
        fw.indent() << "}" << std::endl;
    }

    return true;
}
<commit_msg>Added if (!null) guard around description strings.<commit_after>#include "osg/Node"

#include "osgDB/Registry"
#include "osgDB/Input"
#include "osgDB/Output"

using namespace osg;
using namespace osgDB;

// forward declare functions to use later.
bool Node_readLocalData(Object& obj, Input& fr);
bool Node_writeLocalData(const Object& obj, Output& fw);

// register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_NodeProxy
(
    new osg::Node,
    "Node",
    "Object Node",
    &Node_readLocalData,
    &Node_writeLocalData
);

bool Node_readLocalData(Object& obj, Input& fr)
{
    bool iteratorAdvanced = false;

    Node& node = static_cast<Node&>(obj);

    if (fr.matchSequence("name %s"))
    {
        node.setName(fr[1].getStr());
        fr+=2;
        iteratorAdvanced = true;
    }

    if (fr[0].matchWord("cullingActive"))
    {
        if (fr[1].matchWord("FALSE"))
        {
            node.setCullingActive(false);
            iteratorAdvanced = true;
            fr+=2;
        }
        else if (fr[1].matchWord("TRUE"))
        {
            node.setCullingActive(true);
            iteratorAdvanced = true;
            fr+=2;
        }
    }

    //     if (fr.matchSequence("user_data {"))
    //     {
    //         notify(DEBUG) << "Matched user_data {"<< std::endl;
    //         int entry = fr[0].getNoNestedBrackets();
    //         fr += 2;
    //
    //         while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
    //         {
    //             Object* object = fr.readObject();
    //             if (object) setUserData(object);
    //             notify(DEBUG) << "read "<<object<< std::endl;
    //             ++fr;
    //         }
    //         iteratorAdvanced = true;
    //     }

    while (fr.matchSequence("description {"))
    {
        int entry = fr[0].getNoNestedBrackets();
        fr += 2;

        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            if (fr[0].getStr()) node.addDescription(std::string(fr[0].getStr()));
            ++fr;
        }
        iteratorAdvanced = true;

    }

    while (fr.matchSequence("description %s"))
    {
        node.addDescription(fr[1].getStr());
        fr+=2;
        iteratorAdvanced = true;
    }

    static ref_ptr<StateSet> s_drawstate = new osg::StateSet;
    if (StateSet* readState = static_cast<StateSet*>(fr.readObjectOfType(*s_drawstate)))
    {
        node.setStateSet(readState);
        iteratorAdvanced = true;
    }

    static ref_ptr<NodeCallback> s_nodecallback = new osg::NodeCallback;
    while (fr.matchSequence("UpdateCallback {"))
    {
        int entry = fr[0].getNoNestedBrackets();
        fr += 2;

        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            NodeCallback* nodecallback = dynamic_cast<NodeCallback*>(fr.readObjectOfType(*s_nodecallback));
            if (nodecallback) node.setUpdateCallback(nodecallback);
            else ++fr;
        }
        iteratorAdvanced = true;

    }

    while (fr.matchSequence("CullCallback {"))
    {
        int entry = fr[0].getNoNestedBrackets();
        fr += 2;

        while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
        {
            NodeCallback* nodecallback = dynamic_cast<NodeCallback*>(fr.readObjectOfType(*s_nodecallback));
            if (nodecallback) node.setUpdateCallback(nodecallback);
            else ++fr;
        }
        iteratorAdvanced = true;

    }

    return iteratorAdvanced;
}

bool Node_writeLocalData(const Object& obj, Output& fw)
{
    const Node& node = static_cast<const Node&>(obj);

    if (!node.getName().empty()) fw.indent() << "name "<<fw.wrapString(node.getName())<< std::endl;

    fw.indent() << "cullingActive ";
    if (node.getCullingActive()) fw << "TRUE"<< std::endl;
    else fw << "FALSE"<< std::endl;

    //     if (_userData)
    //     {
    //         Object* object = dynamic_cast<Object*>(_userData);
    //         if (object)
    //         {
    //             fw.indent() << "user_data {"<< std::endl;
    //             fw.moveIn();
    //             object->write(fw);
    //             fw.moveOut();
    //             fw.indent() << "}"<< std::endl;
    //         }
    //     }

    if (!node.getDescriptions().empty())
    {
        if (node.getDescriptions().size()==1)
        {
            fw.indent() << "description "<<fw.wrapString(node.getDescriptions().front())<< std::endl;
        }
        else
        {
            fw.indent() << "description {"<< std::endl;
            fw.moveIn();
            for(Node::DescriptionList::const_iterator ditr=node.getDescriptions().begin();
                ditr!=node.getDescriptions().end();
                ++ditr)
            {
                fw.indent() << fw.wrapString(*ditr)<< std::endl;
            }
            fw.moveOut();
            fw.indent() << "}"<< std::endl;
        }
    }

    if (node.getStateSet())
    {
        fw.writeObject(*node.getStateSet());
    }

    if (node.getUpdateCallback())
    {
        fw.indent() << "UpdateCallbacks {" << std::endl;
        fw.moveIn();
        fw.writeObject(*node.getUpdateCallback());
        fw.moveOut();
        fw.indent() << "}" << std::endl;
    }

    if (node.getCullCallback())
    {
        fw.indent() << "CullCallbacks {" << std::endl;
        fw.moveIn();
        fw.writeObject(*node.getCullCallback());
        fw.moveOut();
        fw.indent() << "}" << std::endl;
    }

    return true;
}
<|endoftext|>


<commit_before>/**
*  Copyright (C) 2018 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "repo_file_handler_fs.h"

#include "../../model/repo_model_global.h"
#include "../../../lib/repo_log.h"
#include "../../../lib/repo_exception.h"
#include "../../../lib/repo_utils.h"

using namespace repo::core::handler::fileservice;

FSFileHandler::FSFileHandler(
	const std::string &dir,
	const int &nLevel) :
	AbstractFileHandler(),
	dirPath(dir),
	level(nLevel)
{
	if (!repo::lib::doesDirExist(dir)) {
		throw repo::lib::RepoException("Cannot initialise fileshare: " + dir + " is does not exist/is not a directory");
	}
}

/**
 * A Deconstructor
 */
FSFileHandler::~FSFileHandler()
{

}

bool FSFileHandler::deleteFile(
	const std::string          &database,
	const std::string          &collection,
	const std::string &keyName)
{
	bool success = false;

	auto fullPath = boost::filesystem::absolute(keyName, dirPath);
	if (repo::lib::doesFileExist(fullPath)) {
		auto fileStr = fullPath.string();
		success = std::remove(fileStr.c_str()) == 0;
	}
	return success;
}

std::vector<std::string> FSFileHandler::determineHierachy(
	const std::string &name
) const {
	auto nameChunkLen = name.length() / level;
	nameChunkLen = nameChunkLen < minChunkLength ? minChunkLength : nameChunkLen;

	std::hash<std::string> stringHasher;
	std::vector<std::string> levelNames;
	for (int i = 0; i < level; ++i) {
		auto chunkStart = (i * nameChunkLen) % (name.length() - nameChunkLen);
		auto stringToHash = name.substr(i, nameChunkLen) + std::to_string((float)std::rand()/ RAND_MAX);
		levelNames.push_back(std::to_string(stringHasher(stringToHash)));
	}

	return levelNames;
}

std::string FSFileHandler::uploadFile(
	const std::string          &database,
	const std::string          &collection,
	const std::string          &keyName,
	const std::vector<uint8_t> &bin
	)
{
	auto hierachy = determineHierachy(keyName);

	boost::filesystem::path path(dirPath);
	std::stringstream ss;

	for (const auto &levelName : hierachy) {
		path /= levelName;
		ss << levelName << "/";
		if (!repo::lib::doesDirExist(path)) {
			boost::filesystem::create_directories(path);
		}
	}

	path /= keyName;
	ss <<  keyName;

	std::ofstream outs(path.string(), std::ios::out | std::ios::binary);
	outs.write((char*)bin.data(), bin.size());
	outs.close();

	return ss.str();
}

<commit_msg>ISSUE #320 take the first 255 bits of the hashed value<commit_after>/**
*  Copyright (C) 2018 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "repo_file_handler_fs.h"

#include "../../model/repo_model_global.h"
#include "../../../lib/repo_log.h"
#include "../../../lib/repo_exception.h"
#include "../../../lib/repo_utils.h"

using namespace repo::core::handler::fileservice;

FSFileHandler::FSFileHandler(
	const std::string &dir,
	const int &nLevel) :
	AbstractFileHandler(),
	dirPath(dir),
	level(nLevel)
{
	if (!repo::lib::doesDirExist(dir)) {
		throw repo::lib::RepoException("Cannot initialise fileshare: " + dir + " is does not exist/is not a directory");
	}
}

/**
 * A Deconstructor
 */
FSFileHandler::~FSFileHandler()
{

}

bool FSFileHandler::deleteFile(
	const std::string          &database,
	const std::string          &collection,
	const std::string &keyName)
{
	bool success = false;

	auto fullPath = boost::filesystem::absolute(keyName, dirPath);
	if (repo::lib::doesFileExist(fullPath)) {
		auto fileStr = fullPath.string();
		success = std::remove(fileStr.c_str()) == 0;
	}
	return success;
}

std::vector<std::string> FSFileHandler::determineHierachy(
	const std::string &name
) const {
	auto nameChunkLen = name.length() / level;
	nameChunkLen = nameChunkLen < minChunkLength ? minChunkLength : nameChunkLen;

	std::hash<std::string> stringHasher;
	std::vector<std::string> levelNames;
	for (int i = 0; i < level; ++i) {
		auto chunkStart = (i * nameChunkLen) % (name.length() - nameChunkLen);
		auto stringToHash = name.substr(i, nameChunkLen) + std::to_string((float)std::rand()/ RAND_MAX);
		auto hashedValue = stringHasher(stringToHash) & 255;
		levelNames.push_back(std::to_string(hashedValue));
	}

	return levelNames;
}

std::string FSFileHandler::uploadFile(
	const std::string          &database,
	const std::string          &collection,
	const std::string          &keyName,
	const std::vector<uint8_t> &bin
	)
{
	auto hierachy = determineHierachy(keyName);

	boost::filesystem::path path(dirPath);
	std::stringstream ss;

	for (const auto &levelName : hierachy) {
		path /= levelName;
		ss << levelName << "/";
		if (!repo::lib::doesDirExist(path)) {
			boost::filesystem::create_directories(path);
		}
	}

	path /= keyName;
	ss <<  keyName;

	std::ofstream outs(path.string(), std::ios::out | std::ios::binary);
	outs.write((char*)bin.data(), bin.size());
	outs.close();

	return ss.str();
}

<|endoftext|>


<commit_before>#include "lib/output.h"
#include "lib/image.h"
#include "lib/lambertian.h"
#include "lib/range.h"
#include "lib/runtime.h"
#include "lib/triangle.h"

#include <assimp/Importer.hpp>      // C++ importer interface
#include <assimp/scene.h>           // Output data structure
#include <assimp/postprocess.h>     // Post processing flags
#include <docopt.h>

#include <math.h>
#include <vector>
#include <map>
#include <iostream>
#include <chrono>

ssize_t ray_intersection(const aiRay& ray, const Triangles& triangles,
        float& min_r, float& min_s, float& min_t) {

    ssize_t triangle_index = -1;
    min_r = -1;
    float r, s, t;
    for (size_t i = 0; i < triangles.size(); i++) {
        auto intersect = triangles[i].intersect(ray, r, s, t);
        if (intersect) {
            if (triangle_index < 0 || r < min_r) {
                min_r = r;
                min_s = s;
                min_t = t;
                triangle_index = i;
            }
        }
    }

    return triangle_index;
}

Triangles triangles_from_scene(const aiScene* scene) {
    Triangles triangles;
    for (auto node : make_range(
            scene->mRootNode->mChildren, scene->mRootNode->mNumChildren))
    {
        const auto& T = node->mTransformation;
        if (node->mNumMeshes == 0) {
            continue;
        }

        for (auto mesh_index : make_range(node->mMeshes, node->mNumMeshes)) {
            const auto& mesh = *scene->mMeshes[mesh_index];

            aiColor4D ambient, diffuse;
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_AMBIENT, ambient);
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_DIFFUSE, diffuse);

            for (aiFace face : make_range(mesh.mFaces, mesh.mNumFaces)) {
                assert(face.mNumIndices == 3);
                triangles.push_back(Triangle{
                    // vertices
                    {{
                        T * mesh.mVertices[face.mIndices[0]],
                        T * mesh.mVertices[face.mIndices[1]],
                        T * mesh.mVertices[face.mIndices[2]]
                    }},
                    // normals
                    {{
                        T * mesh.mNormals[face.mIndices[0]],
                        T * mesh.mNormals[face.mIndices[1]],
                        T * mesh.mNormals[face.mIndices[2]]
                    }},
                    ambient,
                    diffuse
                });
            }
        }
    }
    return triangles;
}

static const char USAGE[] =
R"(Usage: raytracer <filename> [options]

Options:
  -w --width=<px>           Width of the image [default: 640].
  -a --aspect=<num>         Aspect ratio of the image. If the model has
                            specified the aspect ratio, it will be used.
                            Otherwise default value is 1.
  -b --background=<color>   Background color of the world. [default: 0 0 0 0].
)";

int main(int argc, char const *argv[])
{
    // parameters
    std::map<std::string, docopt::value> args =
        docopt::docopt(USAGE, {argv + 1, argv + argc}, true, "raytracer 0.2");

    // import scene
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(
        args["<filename>"].asString().c_str(),
        aiProcess_CalcTangentSpace       |
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
        aiProcess_GenNormals             |
        aiProcess_SortByPType);

    if (!scene) {
        std::cout << importer.GetErrorString() << std::endl;
        return 1;
    }

    // setup camera
    assert(scene->mNumCameras == 1);  // we can deal only with a single camera
    auto& sceneCam = *scene->mCameras[0];
    if (args["--aspect"]) {
        sceneCam.mAspect = std::stof(args["--aspect"].asString());
        assert(sceneCam.mAspect > 0);
    } else if (sceneCam.mAspect == 0) {
        sceneCam.mAspect = 1.f;
    }
    auto* camNode = scene->mRootNode->FindNode(sceneCam.mName);
    assert(camNode != nullptr);

    const Camera cam(camNode->mTransformation, sceneCam);
    std::cerr << "Camera" << std::endl;
    std::cerr << cam << std::endl;

    // setup light
    assert(scene->mNumLights == 1);  // we can deal only with a single light
    auto& light = *scene->mLights[0];

    std::cerr << "Light" << std::endl;
    std::cerr << "Diffuse: " << light.mColorDiffuse << std::endl;

    auto* lightNode = scene->mRootNode->FindNode(light.mName);
    assert(lightNode != nullptr);
    const auto& LT = lightNode->mTransformation;
    std::cerr << "Light Trafo: " << LT << std::endl;
    auto light_pos = LT * aiVector3D();
    auto light_color = aiColor4D{
        light.mColorDiffuse.r,
        light.mColorDiffuse.g,
        light.mColorDiffuse.b,
        1};

    // load triangles from the scene
    auto triangles = triangles_from_scene(scene);

    //
    // Raytracer
    //

    int width = args["--width"].asLong();
    assert(width > 0);
    int height = width / cam.mAspect;
    auto background_color = parse_color4(args["--background"].asString());

    Image image(width, height);
    {
        auto rt = Runtime(std::cerr, "Rendering time: ");
        float r, s, t;
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                // intersection
                auto cam_dir = cam.raster2cam(aiVector2D(x, y), width, height);
                auto triangle_index = ray_intersection(
                    aiRay(cam.mPosition, cam_dir), triangles, r, s, t);
                if (triangle_index < 0) {
                    image(x, y) = background_color;
                    continue;
                }

                // light direction
                auto p = cam.mPosition + r * cam_dir;
                auto light_dir = light_pos - p;
                light_dir.Normalize();

                // interpolate normal
                const auto& triangle = triangles[triangle_index];
                const auto& n0 = triangle.normals[0];
                const auto& n1 = triangle.normals[1];
                const auto& n2 = triangle.normals[2];
                auto normal = ((1.f - s - t)*n0 + s*n1 + t*n2).Normalize();

                // calculate shadow
                float distance_to_next_triangle, s2, t2;
                auto p2 = p + normal * 0.0001f;
                float distance_to_light = (light_pos - p2).Length();
                auto shadow_triangle = ray_intersection(
                    aiRay(p2, light_dir),
                    triangles,
                    distance_to_next_triangle, s2, t2);
                if (shadow_triangle >= 0 &&
                    distance_to_next_triangle < distance_to_light)
                {
                    image(x, y) = triangle.ambient;
                    continue;
                }

                image(x, y) += lambertian(
                    light_dir, normal, triangle.diffuse, light_color);
                image(x, y) += triangle.ambient;
            }
        }
    }

    // output image
    std::cout << image << std::endl;
    return 0;
}
<commit_msg>Show progress bar.<commit_after>#include "lib/output.h"
#include "lib/image.h"
#include "lib/lambertian.h"
#include "lib/range.h"
#include "lib/runtime.h"
#include "lib/triangle.h"

#include <assimp/Importer.hpp>      // C++ importer interface
#include <assimp/scene.h>           // Output data structure
#include <assimp/postprocess.h>     // Post processing flags
#include <docopt.h>

#include <math.h>
#include <vector>
#include <map>
#include <iostream>
#include <chrono>

ssize_t ray_intersection(const aiRay& ray, const Triangles& triangles,
        float& min_r, float& min_s, float& min_t) {

    ssize_t triangle_index = -1;
    min_r = -1;
    float r, s, t;
    for (size_t i = 0; i < triangles.size(); i++) {
        auto intersect = triangles[i].intersect(ray, r, s, t);
        if (intersect) {
            if (triangle_index < 0 || r < min_r) {
                min_r = r;
                min_s = s;
                min_t = t;
                triangle_index = i;
            }
        }
    }

    return triangle_index;
}

Triangles triangles_from_scene(const aiScene* scene) {
    Triangles triangles;
    for (auto node : make_range(
            scene->mRootNode->mChildren, scene->mRootNode->mNumChildren))
    {
        const auto& T = node->mTransformation;
        if (node->mNumMeshes == 0) {
            continue;
        }

        for (auto mesh_index : make_range(node->mMeshes, node->mNumMeshes)) {
            const auto& mesh = *scene->mMeshes[mesh_index];

            aiColor4D ambient, diffuse;
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_AMBIENT, ambient);
            scene->mMaterials[mesh.mMaterialIndex]->Get(
                AI_MATKEY_COLOR_DIFFUSE, diffuse);

            for (aiFace face : make_range(mesh.mFaces, mesh.mNumFaces)) {
                assert(face.mNumIndices == 3);
                triangles.push_back(Triangle{
                    // vertices
                    {{
                        T * mesh.mVertices[face.mIndices[0]],
                        T * mesh.mVertices[face.mIndices[1]],
                        T * mesh.mVertices[face.mIndices[2]]
                    }},
                    // normals
                    {{
                        T * mesh.mNormals[face.mIndices[0]],
                        T * mesh.mNormals[face.mIndices[1]],
                        T * mesh.mNormals[face.mIndices[2]]
                    }},
                    ambient,
                    diffuse
                });
            }
        }
    }
    return triangles;
}

static const char USAGE[] =
R"(Usage: raytracer <filename> [options]

Options:
  -w --width=<px>           Width of the image [default: 640].
  -a --aspect=<num>         Aspect ratio of the image. If the model has
                            specified the aspect ratio, it will be used.
                            Otherwise default value is 1.
  -b --background=<color>   Background color of the world. [default: 0 0 0 0].
)";

int main(int argc, char const *argv[])
{
    // parameters
    std::map<std::string, docopt::value> args =
        docopt::docopt(USAGE, {argv + 1, argv + argc}, true, "raytracer 0.2");

    // import scene
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(
        args["<filename>"].asString().c_str(),
        aiProcess_CalcTangentSpace       |
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
        aiProcess_GenNormals             |
        aiProcess_SortByPType);

    if (!scene) {
        std::cout << importer.GetErrorString() << std::endl;
        return 1;
    }

    // setup camera
    assert(scene->mNumCameras == 1);  // we can deal only with a single camera
    auto& sceneCam = *scene->mCameras[0];
    if (args["--aspect"]) {
        sceneCam.mAspect = std::stof(args["--aspect"].asString());
        assert(sceneCam.mAspect > 0);
    } else if (sceneCam.mAspect == 0) {
        sceneCam.mAspect = 1.f;
    }
    auto* camNode = scene->mRootNode->FindNode(sceneCam.mName);
    assert(camNode != nullptr);

    const Camera cam(camNode->mTransformation, sceneCam);
    std::cerr << "Camera" << std::endl;
    std::cerr << cam << std::endl;

    // setup light
    assert(scene->mNumLights == 1);  // we can deal only with a single light
    auto& light = *scene->mLights[0];

    std::cerr << "Light" << std::endl;
    std::cerr << "Diffuse: " << light.mColorDiffuse << std::endl;

    auto* lightNode = scene->mRootNode->FindNode(light.mName);
    assert(lightNode != nullptr);
    const auto& LT = lightNode->mTransformation;
    std::cerr << "Light Trafo: " << LT << std::endl;
    auto light_pos = LT * aiVector3D();
    auto light_color = aiColor4D{
        light.mColorDiffuse.r,
        light.mColorDiffuse.g,
        light.mColorDiffuse.b,
        1};

    // load triangles from the scene
    auto triangles = triangles_from_scene(scene);

    //
    // Raytracer
    //

    int width = args["--width"].asLong();
    assert(width > 0);
    int height = width / cam.mAspect;
    auto background_color = parse_color4(args["--background"].asString());

    Image image(width, height);
    {
        auto rt = Runtime(std::cerr, "Rendering time: ");

        std::cerr << "Rendering ";

        float r, s, t;
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                // intersection
                auto cam_dir = cam.raster2cam(aiVector2D(x, y), width, height);
                auto triangle_index = ray_intersection(
                    aiRay(cam.mPosition, cam_dir), triangles, r, s, t);
                if (triangle_index < 0) {
                    image(x, y) = background_color;
                    continue;
                }

                // light direction
                auto p = cam.mPosition + r * cam_dir;
                auto light_dir = light_pos - p;
                light_dir.Normalize();

                // interpolate normal
                const auto& triangle = triangles[triangle_index];
                const auto& n0 = triangle.normals[0];
                const auto& n1 = triangle.normals[1];
                const auto& n2 = triangle.normals[2];
                auto normal = ((1.f - s - t)*n0 + s*n1 + t*n2).Normalize();

                // calculate shadow
                float distance_to_next_triangle, s2, t2;
                auto p2 = p + normal * 0.0001f;
                float distance_to_light = (light_pos - p2).Length();
                auto shadow_triangle = ray_intersection(
                    aiRay(p2, light_dir),
                    triangles,
                    distance_to_next_triangle, s2, t2);
                if (shadow_triangle >= 0 &&
                    distance_to_next_triangle < distance_to_light)
                {
                    image(x, y) = triangle.ambient;
                    continue;
                }

                image(x, y) += lambertian(
                    light_dir, normal, triangle.diffuse, light_color);
                image(x, y) += triangle.ambient;
            }

            // update prograss bar
            auto height_fraction = height / 20;
            if (y % height_fraction == 0) {
                std::cerr << ".";
            }
        }
        std::cerr << std::endl;
    }

    // output image
    std::cout << image << std::endl;
    return 0;
}
<|endoftext|>