<commit_before>// File:            GameDQNBridge.cpp
// Description:     Implement the bridge class between game and DQN
// Date:            2015-07-04
// License:         Apache
// Feel free to contact me if there's any questions
//

#include "GameDQNBridge.h"
#include "defaults.h"

#include <string>
#include <qlearning/dqn.h>
#include <qlearning/ale.h>
#include <ale_interface.hpp>

GameDQNBridge::GameDQNBridge(ALEInterface& ale, qlearning::DQN& dqn, const bool update)
    : ale_(ale), dqn_(dqn), update_(update) {}

double GameDQNBridge::play(double epsilon) {
	qlearning::ALE ale;
    std::deque<qlearning::FDataP> past;
    double total = 0.0;
    for (int frame = 0; !ale_.game_over(); frame++) {
        const auto current = ale.PreprocessScreen(ale_.getScreen());
        past.push_back(current);
        if (past.size() < qlearning::ICount) {
            for (int i = 0; i < skip_frame + 1 && !ale_.game_over(); i++) {
                total += ale_.act(PLAYER_A_NOOP);
            }
        } else {
            if (past.size() > qlearning::ICount) {
                past.pop_front();
            }
            qlearning::IFrames input;
            std::copy(past.begin(), past.end(), input.begin());
            const Action action = dqn_.SelectAction(input, epsilon);
            double recent = 0.0;
            for (int i = 0; i < skip_frame + 1 && !ale_.game_over(); i++) {
                recent += ale_.act(action);
            }
            total += recent;
            const double reward = (recent == 0 ? 0 : recent /= std::abs(recent));
            if (update_) {
                const auto trans = ale_.game_over() ? qlearning::Trans(input, action, reward, boost::none) : qlearning::Trans(input, action, reward, ale.PreprocessScreen(ale_.getScreen()));
                dqn_.AddTrans(trans);
                if (dqn_.get_size() > memory_threshold) {
                    dqn_.Update();
                }
            }
        }
    }
    ale_.reset_game();
    return total;
}
<commit_msg>Add comments<commit_after>// File:            GameDQNBridge.cpp
// Description:     Implement the bridge class between game and DQN
// Date:            2015-07-04
// License:         Apache
// Feel free to contact me if there's any questions
//

#include "GameDQNBridge.h"
#include "defaults.h"

#include <string>
#include <qlearning/dqn.h>
#include <qlearning/ale.h>
#include <ale_interface.hpp>

GameDQNBridge::GameDQNBridge(ALEInterface& ale, qlearning::DQN& dqn, const bool update)
    : ale_(ale), dqn_(dqn), update_(update) {}

double GameDQNBridge::play(double epsilon) {
	qlearning::ALE ale;
    std::deque<qlearning::FDataP> past;		//frame sequence
    double total = 0.0;
    for (int frame = 0; !ale_.game_over(); frame++) {
        const auto current = ale.PreprocessScreen(ale_.getScreen());
        past.push_back(current);
        //fill frame sequence
        if (past.size() < qlearning::ICount) {
            for (int i = 0; i < skip_frame + 1 && !ale_.game_over(); i++) {
                total += ale_.act(PLAYER_A_NOOP);
            }
        } else {
			//pop history frame
            if (past.size() > qlearning::ICount) {
                past.pop_front();
            }
            qlearning::IFrames input;
            std::copy(past.begin(), past.end(), input.begin());
            //get action
            const Action action = dqn_.SelectAction(input, epsilon);
            //get recent score
            double recent = 0.0;
            for (int i = 0; i < skip_frame + 1 && !ale_.game_over(); i++) {
                recent += ale_.act(action);
            }
            total += recent;
            const double reward = (recent == 0 ? 0 : recent /= std::abs(recent));
            //update solver
            if (update_) {
                const auto trans = ale_.game_over() ? qlearning::Trans(input, action, reward, boost::none) : qlearning::Trans(input, action, reward, ale.PreprocessScreen(ale_.getScreen()));
                dqn_.AddTrans(trans);
                if (dqn_.get_size() > memory_threshold) {
                    dqn_.Update();
                }
            }
        }
    }
    ale_.reset_game();
    return total;
}
<|endoftext|>


<commit_before>#include "engine/fs/file_system.h"
#include "engine/fs/memory_file_device.h"
#include "engine/iallocator.h"
#include "engine/math_utils.h"
#include "engine/string.h"

namespace Lumix
{
	namespace FS
	{
		class LUMIX_ENGINE_API MemoryFile final : public IFile
		{
		public:
			MemoryFile(IFile* file, MemoryFileDevice& device, IAllocator& allocator)
				: m_device(device)
				, m_buffer(nullptr)
				, m_size(0)
				, m_capacity(0)
				, m_pos(0)
				, m_file(file)
				, m_write(false)
				, m_allocator(allocator)
			{
			}

			~MemoryFile()
			{
				if (m_file)
				{
					m_file->release();
				}
				m_allocator.deallocate(m_buffer);
			}

			IFileDevice& getDevice() override
			{
				return m_device;
			}

			bool open(const Path& path, Mode mode) override
			{
				ASSERT(!m_buffer); // reopen is not supported currently

				m_write = !!(mode & Mode::WRITE);
				if(m_file)
				{
					if(m_file->open(path, mode))
					{
						if(mode & Mode::READ)
						{
							m_capacity = m_size = m_file->size();
							m_buffer = (u8*)m_allocator.allocate(sizeof(u8) * m_size);
							m_file->read(m_buffer, m_size);
							m_pos = 0;
						}

						return true;
					}
				}
				else
				{
					if(mode & Mode::WRITE)
					{
						return true;
					}
				}

				return false;
			}

			void close() override
			{
				if(m_file)
				{
					if(m_write)
					{
						m_file->seek(SeekMode::BEGIN, 0);
						m_file->write(m_buffer, m_size);
					}
					m_file->close();
				}

				m_allocator.deallocate(m_buffer);
				m_buffer = nullptr;
			}

			bool read(void* buffer, size_t size) override
			{
				size_t amount = m_pos + size < m_size ? size : m_size - m_pos;
				copyMemory(buffer, m_buffer + m_pos, (int)amount);
				m_pos += amount;
				return amount == size;
			}

			bool write(const void* buffer, size_t size) override
			{
				size_t pos = m_pos;
				size_t cap = m_capacity;
				size_t sz = m_size;
				if(pos + size > cap)
				{
					size_t new_cap = Math::maximum(cap * 2, pos + size);
					u8* new_data = (u8*)m_allocator.allocate(sizeof(u8) * new_cap);
					copyMemory(new_data, m_buffer, (int)sz);
					m_allocator.deallocate(m_buffer);
					m_buffer = new_data;
					m_capacity = new_cap;
				}

				copyMemory(m_buffer + pos, buffer, (int)size);
				m_pos += size;
				m_size = pos + size > sz ? pos + size : sz;

				return true;
			}

			const void* getBuffer() const override
			{
				return m_buffer;
			}

			size_t size() override
			{
				return m_size;
			}

			bool seek(SeekMode base, size_t pos) override
			{
				switch(base)
				{
				case SeekMode::BEGIN:
					ASSERT(pos <= (i32)m_size);
					m_pos = pos;
					break;
				case SeekMode::CURRENT:
					ASSERT(0 <= i32(m_pos + pos) && i32(m_pos + pos) <= i32(m_size));
					m_pos += pos;
					break;
				case SeekMode::END:
					ASSERT(pos <= (i32)m_size);
					m_pos = m_size - pos;
					break;
				default:
					ASSERT(0);
					break;
				}

				bool ret = m_pos <= m_size;
				m_pos = Math::minimum(m_pos, m_size);
				return ret;
			}

			size_t pos() override
			{
				return m_pos;
			}

		private:
			IAllocator& m_allocator;
			MemoryFileDevice& m_device;
			u8* m_buffer;
			size_t m_size;
			size_t m_capacity;
			size_t m_pos;
			IFile* m_file;
			bool m_write;
		};

		void MemoryFileDevice::destroyFile(IFile* file)
		{
			LUMIX_DELETE(m_allocator, file);
		}

		IFile* MemoryFileDevice::createFile(IFile* child)
		{
			return LUMIX_NEW(m_allocator, MemoryFile)(child, *this, m_allocator);
		}
	} // namespace FS
} // namespace Lumix
<commit_msg>fixed - terrain material fails to load<commit_after>#include "engine/fs/file_system.h"
#include "engine/fs/memory_file_device.h"
#include "engine/iallocator.h"
#include "engine/math_utils.h"
#include "engine/string.h"

namespace Lumix
{
	namespace FS
	{
		class LUMIX_ENGINE_API MemoryFile final : public IFile
		{
		public:
			MemoryFile(IFile* file, MemoryFileDevice& device, IAllocator& allocator)
				: m_device(device)
				, m_buffer(nullptr)
				, m_size(0)
				, m_capacity(0)
				, m_pos(0)
				, m_file(file)
				, m_write(false)
				, m_allocator(allocator)
			{
			}

			~MemoryFile()
			{
				if (m_file)
				{
					m_file->release();
				}
				m_allocator.deallocate(m_buffer);
			}

			IFileDevice& getDevice() override
			{
				return m_device;
			}

			bool open(const Path& path, Mode mode) override
			{
				ASSERT(!m_buffer); // reopen is not supported currently

				m_write = !!(mode & Mode::WRITE);
				if(m_file)
				{
					if(m_file->open(path, mode))
					{
						if(mode & Mode::READ)
						{
							m_capacity = m_size = m_file->size();
							m_buffer = (u8*)m_allocator.allocate(sizeof(u8) * m_size);
							m_file->read(m_buffer, m_size);
							m_file->close();
							m_pos = 0;
						}

						return true;
					}
				}
				else
				{
					if(mode & Mode::WRITE)
					{
						return true;
					}
				}

				return false;
			}

			void close() override
			{
				if(m_file)
				{
					if(m_write)
					{
						m_file->seek(SeekMode::BEGIN, 0);
						m_file->write(m_buffer, m_size);
						m_file->close();
					}
				}

				m_allocator.deallocate(m_buffer);
				m_buffer = nullptr;
			}

			bool read(void* buffer, size_t size) override
			{
				size_t amount = m_pos + size < m_size ? size : m_size - m_pos;
				copyMemory(buffer, m_buffer + m_pos, (int)amount);
				m_pos += amount;
				return amount == size;
			}

			bool write(const void* buffer, size_t size) override
			{
				size_t pos = m_pos;
				size_t cap = m_capacity;
				size_t sz = m_size;
				if(pos + size > cap)
				{
					size_t new_cap = Math::maximum(cap * 2, pos + size);
					u8* new_data = (u8*)m_allocator.allocate(sizeof(u8) * new_cap);
					copyMemory(new_data, m_buffer, (int)sz);
					m_allocator.deallocate(m_buffer);
					m_buffer = new_data;
					m_capacity = new_cap;
				}

				copyMemory(m_buffer + pos, buffer, (int)size);
				m_pos += size;
				m_size = pos + size > sz ? pos + size : sz;

				return true;
			}

			const void* getBuffer() const override
			{
				return m_buffer;
			}

			size_t size() override
			{
				return m_size;
			}

			bool seek(SeekMode base, size_t pos) override
			{
				switch(base)
				{
				case SeekMode::BEGIN:
					ASSERT(pos <= (i32)m_size);
					m_pos = pos;
					break;
				case SeekMode::CURRENT:
					ASSERT(0 <= i32(m_pos + pos) && i32(m_pos + pos) <= i32(m_size));
					m_pos += pos;
					break;
				case SeekMode::END:
					ASSERT(pos <= (i32)m_size);
					m_pos = m_size - pos;
					break;
				default:
					ASSERT(0);
					break;
				}

				bool ret = m_pos <= m_size;
				m_pos = Math::minimum(m_pos, m_size);
				return ret;
			}

			size_t pos() override
			{
				return m_pos;
			}

		private:
			IAllocator& m_allocator;
			MemoryFileDevice& m_device;
			u8* m_buffer;
			size_t m_size;
			size_t m_capacity;
			size_t m_pos;
			IFile* m_file;
			bool m_write;
		};

		void MemoryFileDevice::destroyFile(IFile* file)
		{
			LUMIX_DELETE(m_allocator, file);
		}

		IFile* MemoryFileDevice::createFile(IFile* child)
		{
			return LUMIX_NEW(m_allocator, MemoryFile)(child, *this, m_allocator);
		}
	} // namespace FS
} // namespace Lumix
<|endoftext|>


<commit_before>#include "engine/config/precompiled.h"

#if (DEA_PLATFORM == DEA_PLATFORM_WINDOWS)
#include "engine/system/system.h"

#include <Windows.h>

DEA_START()

struct window_platform
{
	HWND hwnd;
	LPCWSTR name;
};

/* Translation unit locals */
namespace
{
	void close_windows(pod_vector<window> &windows, pod_vector<HWND> &windows_to_close)
	{
		for (auto window_to_close = windows_to_close.get_begin(); window_to_close != windows_to_close.get_end(); ++window_to_close)
		{
			for (auto window = windows.get_begin(); window != windows.get_end(); ++window)
			{
				if (*window_to_close == window->wnd->hwnd)
				{
					destroy_window(*window, false);
					windows.remove_it(window);

					break;
				}
			}
		}

		windows_to_close.clear();
	}
}

pod_vector<HWND> *windows_to_close = NULL;

void init_system_data()
{
	/* TODO: Memory manager */
	windows_to_close = new pod_vector<HWND>(1);
}

void destroy_system_data()
{
	/* TODO: Memory manager */
	if (windows_to_close)
		delete windows_to_close;
}

void error_popup(const char *msg, const bool kill_program)
{
	dea_assert(msg && "error_popup: msg is NULL");

	MessageBoxA(NULL, msg, kill_program ? "Fatal Error" : "Error", MB_OK | MB_ICONERROR);
	if (kill_program)
		ExitProcess(~(UINT)0);
}

LRESULT CALLBACK wnd_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
	/* Unused parametres, can't get rid of these */
	(void *)hwnd;
	(void *)wparam;
	(void *)lparam;

	switch (umessage)
	{
		case WM_DESTROY:
		{
			/* We don't want to do anything as we manually destroy windows */
			return 0;
		}
		case WM_CLOSE:
		{
			if (windows_to_close)
			{
				windows_to_close->push_back(hwnd);
			}
			else
			{
				/* TODO: Localization/Error number */
				error_popup("Error closing a window", false);
			}

			return 0;
		}
		default:
		{
			return DefWindowProc(hwnd, umessage, wparam, lparam);
		}
	}
}

void create_window(const uint width, const uint height, const float pos_x, const float pos_y, const wchar_t *name, const bool fullscreen, window &out_wnd)
{
	int position_x = 0;
	int position_y = 0;

	HINSTANCE hinstance = GetModuleHandle(NULL);

	/* TODO: Memory manager */
	out_wnd.wnd = new window_platform;
	out_wnd.wnd->hwnd = NULL;
	out_wnd.wnd->name = name;
	out_wnd.width = width;
	out_wnd.height = height;

	/* Setup the windows class with default settings */
	WNDCLASSEX wc;
	memset(&wc, 0, sizeof(wc));
	wc.cbSize = sizeof(wc);
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = wnd_proc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hinstance;
	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
	wc.hIconSm = wc.hIcon;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = name;

	// Register the window class.
	if (RegisterClassEx(&wc) == 0)
	{
		/* TODO: Localization/Error number */
		error_popup("Failed to register window class", true);
	}

	if (!fullscreen)
	{
		position_x = (int)((GetSystemMetrics(SM_CXSCREEN) - width) * pos_x);
		position_y = (int)((GetSystemMetrics(SM_CYSCREEN) - height) * pos_y);
	}
	else
	{
		DEVMODE screen_settings;
		memset(&screen_settings, 0, sizeof(screen_settings));
		screen_settings.dmSize = sizeof(screen_settings);
		screen_settings.dmPelsHeight = (unsigned long)height;
		screen_settings.dmPelsWidth = (unsigned long)width;
		screen_settings.dmBitsPerPel = 32;
		screen_settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN);
	}

	DWORD style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
	DWORD exStyle = 0;

	// Create the window with the screen settings and get the handle to it.
	out_wnd.wnd->hwnd = CreateWindowEx(exStyle,
	                                  name,
	                                  name,
	                                  style,
	                                  position_x, position_y,
	                                  (int)width, (int)height,
	                                  NULL,
	                                  NULL,
	                                  hinstance,
	                                  NULL);

	if (out_wnd.wnd->hwnd == NULL)
	{
		/* TODO: Localization/Error number */
		error_popup("Failed to create a window", true);
	}

	ShowWindow(out_wnd.wnd->hwnd, SW_SHOW);
}

void destroy_window(window &wnd, const bool fullscreen)
{
	dea_assert(wnd.wnd && "destroy_window: Platform specific window pointer is NULL");

	if (fullscreen)
	{
		ChangeDisplaySettings(NULL, 0);
	}

	DestroyWindow(wnd.wnd->hwnd);
	wnd.wnd->hwnd = NULL;

	HINSTANCE hinstance = GetModuleHandle(NULL);
	UnregisterClass(wnd.wnd->name, hinstance);
	hinstance = NULL;

	/* TODO: Memory manager */
	delete wnd.wnd;
}

void focus_window(window &wnd)
{
	dea_assert(wnd.wnd && wnd.wnd->hwnd);
	SetForegroundWindow(wnd.wnd->hwnd);
	SetFocus(wnd.wnd->hwnd);
}

void run(pod_vector<window> &windows)
{
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	bool running = true;
	while (running)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		if (msg.message == WM_QUIT)
		{
			running = false;
		}
		else
		{
			if (windows_to_close && !windows_to_close->empty())
			{
				close_windows(windows, *windows_to_close);

				if (windows.empty())
					running = false;
			}

			/* Run frame */
		}
	}
}

DEA_END()

#endif // DEA_PLATFORM == DEA_PLATFORM_WINDOWS<commit_msg>System: Just a bit of re-organizing.<commit_after>#include "engine/config/precompiled.h"

#if (DEA_PLATFORM == DEA_PLATFORM_WINDOWS)
#include "engine/system/system.h"

#include <Windows.h>

DEA_START()

struct window_platform
{
	HWND hwnd;
	LPCWSTR name;
};

/* Translation unit locals */
namespace
{
	void close_windows(pod_vector<window> &windows, pod_vector<HWND> &windows_to_close)
	{
		for (auto window_to_close = windows_to_close.get_begin(); window_to_close != windows_to_close.get_end(); ++window_to_close)
		{
			for (auto window = windows.get_begin(); window != windows.get_end(); ++window)
			{
				if (*window_to_close == window->wnd->hwnd)
				{
					destroy_window(*window, false);
					windows.remove_it(window);

					break;
				}
			}
		}

		windows_to_close.clear();
	}

	/* Could use a better implementation */
	pod_vector<HWND> *windows_to_close = NULL;

	LRESULT CALLBACK wnd_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
	{
		/* Unused parametres, can't get rid of these */
		(void *)hwnd;
		(void *)wparam;
		(void *)lparam;

		switch (umessage)
		{
		case WM_DESTROY:
		{
			/* We don't want to do anything as we manually destroy windows */
			return 0;
		}
		case WM_CLOSE:
		{
			if (windows_to_close)
			{
				windows_to_close->push_back(hwnd);
			}
			else
			{
				/* TODO: Localization/Error number */
				error_popup("Error closing a window", false);
			}

			return 0;
		}
		default:
		{
			return DefWindowProc(hwnd, umessage, wparam, lparam);
		}
		}
	}
}

void init_system_data()
{
	/* TODO: Memory manager */
	windows_to_close = new pod_vector<HWND>(1);
}

void destroy_system_data()
{
	/* TODO: Memory manager */
	if (windows_to_close)
		delete windows_to_close;
}

void error_popup(const char *msg, const bool kill_program)
{
	dea_assert(msg && "error_popup: msg is NULL");

	MessageBoxA(NULL, msg, kill_program ? "Fatal Error" : "Error", MB_OK | MB_ICONERROR);
	if (kill_program)
		ExitProcess(~(UINT)0);
}

/* TODO: Create a string class for the name */
void create_window(const uint width, const uint height, const float pos_x, const float pos_y, const wchar_t *name, const bool fullscreen, window &out_wnd)
{
	int position_x = 0;
	int position_y = 0;

	HINSTANCE hinstance = GetModuleHandle(NULL);

	/* TODO: Memory manager */
	out_wnd.wnd = new window_platform;
	out_wnd.wnd->hwnd = NULL;
	out_wnd.wnd->name = name;
	out_wnd.width = width;
	out_wnd.height = height;

	/* Setup the windows class with default settings */
	WNDCLASSEX wc;
	memset(&wc, 0, sizeof(wc));
	wc.cbSize = sizeof(wc);
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = wnd_proc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hinstance;
	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
	wc.hIconSm = wc.hIcon;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = name;

	// Register the window class.
	if (RegisterClassEx(&wc) == 0)
	{
		/* TODO: Localization/Error number */
		error_popup("Failed to register window class", true);
	}

	if (!fullscreen)
	{
		position_x = (int)((GetSystemMetrics(SM_CXSCREEN) - width) * pos_x);
		position_y = (int)((GetSystemMetrics(SM_CYSCREEN) - height) * pos_y);
	}
	else
	{
		DEVMODE screen_settings;
		memset(&screen_settings, 0, sizeof(screen_settings));
		screen_settings.dmSize = sizeof(screen_settings);
		screen_settings.dmPelsHeight = (unsigned long)height;
		screen_settings.dmPelsWidth = (unsigned long)width;
		screen_settings.dmBitsPerPel = 32;
		screen_settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN);
	}

	DWORD style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
	DWORD exStyle = 0;

	// Create the window with the screen settings and get the handle to it.
	out_wnd.wnd->hwnd = CreateWindowEx(exStyle,
	                                  name,
	                                  name,
	                                  style,
	                                  position_x, position_y,
	                                  (int)width, (int)height,
	                                  NULL,
	                                  NULL,
	                                  hinstance,
	                                  NULL);

	if (out_wnd.wnd->hwnd == NULL)
	{
		/* TODO: Localization/Error number */
		error_popup("Failed to create a window", true);
	}

	ShowWindow(out_wnd.wnd->hwnd, SW_SHOW);
}

void destroy_window(window &wnd, const bool fullscreen)
{
	dea_assert(wnd.wnd && "destroy_window: Platform specific window pointer is NULL");

	if (fullscreen)
	{
		ChangeDisplaySettings(NULL, 0);
	}

	DestroyWindow(wnd.wnd->hwnd);
	wnd.wnd->hwnd = NULL;

	HINSTANCE hinstance = GetModuleHandle(NULL);
	UnregisterClass(wnd.wnd->name, hinstance);
	hinstance = NULL;

	/* TODO: Memory manager */
	delete wnd.wnd;
}

void focus_window(window &wnd)
{
	dea_assert(wnd.wnd && wnd.wnd->hwnd);
	SetForegroundWindow(wnd.wnd->hwnd);
	SetFocus(wnd.wnd->hwnd);
}

void run(pod_vector<window> &windows)
{
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	bool running = true;
	while (running)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		if (msg.message == WM_QUIT)
		{
			running = false;
		}
		else
		{
			if (windows_to_close && !windows_to_close->empty())
			{
				close_windows(windows, *windows_to_close);

				if (windows.empty())
					running = false;
			}

			/* Run frame */
		}
	}
}

DEA_END()

#endif // DEA_PLATFORM == DEA_PLATFORM_WINDOWS<|endoftext|>


<commit_before>#include "util/funcs.h"
#include "util/bitmap.h"
#include "night_atmosphere.h"
#include "util/file-system.h"
#include "util/token.h"
#include "resource.h"
#include "util/sound.h"
#include "globals.h"
#include <vector>

using namespace std;

/*
static int screenX(){
	return 320;
}

static int screenY(){
	return 240;
}
*/

NightAtmosphere::NightAtmosphere():
Atmosphere(),
darkness(128),
lightning(false){

    lamp = new Bitmap(Filesystem::find(Filesystem::RelativePath("sprites/lamp.png")).path());
    thunder = Resource::getSound("sounds/thunder.wav");
    /*
    addLight(500, 30, 50, 30, Bitmap::makeColor(32,32,0), 0);
    addLight(300, 30, 70, 30, Bitmap::makeColor(0,32,192), 128);
    */
}

NightAtmosphere::~NightAtmosphere(){
    for (vector<Light*>::iterator it = lights.begin(); it != lights.end(); it++){
        delete (*it);
    }
    delete lamp;
}

/* lights should not overlap! the effect completely messes up if they do
 */
void NightAtmosphere::drawLight(Bitmap * original, Bitmap * work, const int x, const int y, const int lower_width, const int upper_width, const int black, const int dark_alpha, const int light, const int light_alpha, bool draw_light){
    int center_x = x;
    // int center_x = screenX();

    /*
    const int black = Bitmap::makeColor(0,0,0);
    const int light = Bitmap::makeColor(32,32,0);
    const int light_alpha = 0;
    const int dark_alpha = 128;
    */

    int where_x = center_x - lower_width;
    int total = lower_width * 2;
    if (where_x < 0){
        total += where_x;
        where_x = 0;
    }
    if (total <= 0){
        return;
    }

    int left = total - lower_width * 2;
    int middle = total - lower_width;
    int right = total;
    if (center_x - lower_width > 0){
        left = 0;
        middle = lower_width;
        right = lower_width * 2;
    }

    Bitmap save(*original, where_x, 0, total, work->getWidth());
    int top = y;

    if (draw_light){
        Bitmap::transBlender(0, 0, 0, dark_alpha);
        Bitmap::drawingMode(Bitmap::MODE_TRANS);
        /*
        int top = -save.getHeight() / 3;
        top = 30;
        */
        int lamp_height = save.getHeight() - top;

        /* y = tan(theta) * x */
        int lamp_top = (int)(((double)lower_width * 2.0 / (double)lamp_height) * (double)upper_width);

        // int top = 0;
        save.triangle(left, top, middle, top, left, save.getHeight(), black);
        save.triangle(right, top, middle, top, right, save.getHeight(), black);
        int nwidth = (int)((double) lamp_top / ((double) lamp_height / (double) lower_width));
        save.triangle(middle, top, middle - nwidth, top + lamp_top, middle + nwidth, top + lamp_top, black);

        save.rectangleFill(0, 0, right, top, black);
        Bitmap::drawingMode(Bitmap::MODE_SOLID);
        int xwidth = (int)((double) lamp_height / ((double)(save.getHeight() - top) / (double) lower_width));
        save.light(middle, top, xwidth, lamp_height, lamp_top, light_alpha, dark_alpha, light, black);
        lamp->draw(middle - 8, top, save);
    } else {
        lamp->draw(middle - 8, top, save);
    }
    save.draw(where_x, 0, *work);
}

int NightAtmosphere::getSkyColor() const {
    if (lightning){
        return Bitmap::makeColor(255, 255, 255);
    } else {
        return Bitmap::makeColor(0, 0, 0);
    }
}

int NightAtmosphere::getSkyDarkness() const {
    if (lightning){
        return lightningFade;
    } else {
        return 255 - darkness;
    }
}

void NightAtmosphere::drawFront(Bitmap * work, int x){
    Bitmap::transBlender(0, 0, 0, getSkyDarkness());
    work->applyTrans(getSkyColor());
}

void NightAtmosphere::drawBackground(Bitmap * work, int x){
}

void NightAtmosphere::drawScreen(Bitmap * work, int x){
}

void NightAtmosphere::addLight(const int x, const int y, const int lower_width, const int upper_width, const int color, const int alpha){
    lights.push_back(new Light(x, y, lower_width, upper_width, color, alpha));
}

void NightAtmosphere::drawForeground(Bitmap * work, int x){
    const int sky = getSkyColor();
    Bitmap save = Bitmap::temporaryBitmap(work->getWidth(), work->getHeight());
    work->Blit(save);
    Bitmap::transBlender(0, 0, 0, getSkyDarkness());
    work->applyTrans(sky);

    for (vector<Light*>::iterator it = lights.begin(); it != lights.end(); it++){
        Light * light = *it;
        int my_x = light->x - x;
        int my_y = light->y;
        drawLight(&save, work, my_x, my_y, light->lower_width, light->upper_width, sky, darkness, light->color, light->alpha, ! lightning);
    }
}

void NightAtmosphere::act(const Scene & level){
    if (lightning){
        if (lightningFade > 0){
            lightningFade *= 0.7;
        } else {
            lightning = false;
        }
        if (thunderPause == 0){
            thunder->play();
            thunderPause -= 1;
        } else if (thunderPause > 0){
            thunderPause -= 1;
        }
    } else if (Util::rnd(300) == 0){
        lightning = true;
        lightningFade = 255;
        thunderPause = 2 + Util::rnd(6);
        // thunder->play();
    }
}

void NightAtmosphere::processLight(Token * token){
    int x;
    *token >> x;
    addLight(x, 30, 50, 30, Bitmap::makeColor(32,32,0), 0);
}

void NightAtmosphere::interpret(Token * message){
    Token * night = message->findToken("message/night");
    if (night != NULL){
        vector<Token*> lights = night->findTokens("night/lamp");
        for (vector<Token*>::iterator it = lights.begin(); it != lights.end(); it++){
            Token * token = *it;
            try{
                processLight(token);
            } catch (const TokenException & e){
                Global::debug(0) << "Could not add light to night atmosphere: " << e.getReason() << endl;
            }
        }
    }
}
<commit_msg>delay thunder more<commit_after>#include "util/funcs.h"
#include "util/bitmap.h"
#include "night_atmosphere.h"
#include "util/file-system.h"
#include "util/token.h"
#include "resource.h"
#include "util/sound.h"
#include "globals.h"
#include <vector>

using namespace std;

/*
static int screenX(){
	return 320;
}

static int screenY(){
	return 240;
}
*/

NightAtmosphere::NightAtmosphere():
Atmosphere(),
darkness(128),
lightning(false),
thunder(NULL),
thunderPause(-1){

    lamp = new Bitmap(Filesystem::find(Filesystem::RelativePath("sprites/lamp.png")).path());
    thunder = Resource::getSound("sounds/thunder.wav");
    /*
    addLight(500, 30, 50, 30, Bitmap::makeColor(32,32,0), 0);
    addLight(300, 30, 70, 30, Bitmap::makeColor(0,32,192), 128);
    */
}

NightAtmosphere::~NightAtmosphere(){
    for (vector<Light*>::iterator it = lights.begin(); it != lights.end(); it++){
        delete (*it);
    }
    delete lamp;
}

/* lights should not overlap! the effect completely messes up if they do
 */
void NightAtmosphere::drawLight(Bitmap * original, Bitmap * work, const int x, const int y, const int lower_width, const int upper_width, const int black, const int dark_alpha, const int light, const int light_alpha, bool draw_light){
    int center_x = x;
    // int center_x = screenX();

    /*
    const int black = Bitmap::makeColor(0,0,0);
    const int light = Bitmap::makeColor(32,32,0);
    const int light_alpha = 0;
    const int dark_alpha = 128;
    */

    int where_x = center_x - lower_width;
    int total = lower_width * 2;
    if (where_x < 0){
        total += where_x;
        where_x = 0;
    }
    if (total <= 0){
        return;
    }

    int left = total - lower_width * 2;
    int middle = total - lower_width;
    int right = total;
    if (center_x - lower_width > 0){
        left = 0;
        middle = lower_width;
        right = lower_width * 2;
    }

    Bitmap save(*original, where_x, 0, total, work->getWidth());
    int top = y;

    if (draw_light){
        Bitmap::transBlender(0, 0, 0, dark_alpha);
        Bitmap::drawingMode(Bitmap::MODE_TRANS);
        /*
        int top = -save.getHeight() / 3;
        top = 30;
        */
        int lamp_height = save.getHeight() - top;

        /* y = tan(theta) * x */
        int lamp_top = (int)(((double)lower_width * 2.0 / (double)lamp_height) * (double)upper_width);

        // int top = 0;
        save.triangle(left, top, middle, top, left, save.getHeight(), black);
        save.triangle(right, top, middle, top, right, save.getHeight(), black);
        int nwidth = (int)((double) lamp_top / ((double) lamp_height / (double) lower_width));
        save.triangle(middle, top, middle - nwidth, top + lamp_top, middle + nwidth, top + lamp_top, black);

        save.rectangleFill(0, 0, right, top, black);
        Bitmap::drawingMode(Bitmap::MODE_SOLID);
        int xwidth = (int)((double) lamp_height / ((double)(save.getHeight() - top) / (double) lower_width));
        save.light(middle, top, xwidth, lamp_height, lamp_top, light_alpha, dark_alpha, light, black);
        lamp->draw(middle - 8, top, save);
    } else {
        lamp->draw(middle - 8, top, save);
    }
    save.draw(where_x, 0, *work);
}

int NightAtmosphere::getSkyColor() const {
    if (lightning){
        return Bitmap::makeColor(255, 255, 255);
    } else {
        return Bitmap::makeColor(0, 0, 0);
    }
}

int NightAtmosphere::getSkyDarkness() const {
    if (lightning){
        return lightningFade;
    } else {
        return 255 - darkness;
    }
}

void NightAtmosphere::drawFront(Bitmap * work, int x){
    Bitmap::transBlender(0, 0, 0, getSkyDarkness());
    work->applyTrans(getSkyColor());
}

void NightAtmosphere::drawBackground(Bitmap * work, int x){
}

void NightAtmosphere::drawScreen(Bitmap * work, int x){
}

void NightAtmosphere::addLight(const int x, const int y, const int lower_width, const int upper_width, const int color, const int alpha){
    lights.push_back(new Light(x, y, lower_width, upper_width, color, alpha));
}

void NightAtmosphere::drawForeground(Bitmap * work, int x){
    const int sky = getSkyColor();
    Bitmap save = Bitmap::temporaryBitmap(work->getWidth(), work->getHeight());
    work->Blit(save);
    Bitmap::transBlender(0, 0, 0, getSkyDarkness());
    work->applyTrans(sky);

    for (vector<Light*>::iterator it = lights.begin(); it != lights.end(); it++){
        Light * light = *it;
        int my_x = light->x - x;
        int my_y = light->y;
        drawLight(&save, work, my_x, my_y, light->lower_width, light->upper_width, sky, darkness, light->color, light->alpha, ! lightning);
    }
}

void NightAtmosphere::act(const Scene & level){
    if (lightning){
        if (lightningFade > 0){
            lightningFade *= 0.7;
        } else {
            lightning = false;
        }
    } else if (Util::rnd(300) == 0){
        lightning = true;
        lightningFade = 255;
        thunderPause = 20 + Util::rnd(4);
        // thunder->play();
    }

    if (thunderPause == 0){
        thunder->play();
        thunderPause -= 1;
    } else if (thunderPause > 0){
        thunderPause -= 1;
    }
}

void NightAtmosphere::processLight(Token * token){
    int x;
    *token >> x;
    addLight(x, 30, 50, 30, Bitmap::makeColor(32,32,0), 0);
}

void NightAtmosphere::interpret(Token * message){
    Token * night = message->findToken("message/night");
    if (night != NULL){
        vector<Token*> lights = night->findTokens("night/lamp");
        for (vector<Token*>::iterator it = lights.begin(); it != lights.end(); it++){
            Token * token = *it;
            try{
                processLight(token);
            } catch (const TokenException & e){
                Global::debug(0) << "Could not add light to night atmosphere: " << e.getReason() << endl;
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * This file is part of `et engine`
 * Copyright 2009-2015 by Sergey Reznik
 * Please, modify content only if you know what are you doing.
 *
 */

#include <et/core/tools.h>

#if (ET_PLATFORM_WIN)

#include <et/platform/platformtools.h>
#include <et/core/filesystem.h>
#include <et/core/containers.h>

#include <Shlobj.h>
#include <ShellAPI.h>
#include <CommDlg.h>

static bool shouldInitializeTime = true;

static uint64_t performanceFrequency = 0;
static uint64_t initialCounter = 0;

static const ET_STRING_TYPE currentFolder = ET_STRING_FROM_CONST_CHAR(".");
static const ET_STRING_TYPE previousFolder = ET_STRING_FROM_CONST_CHAR("..");
static const ET_STRING_TYPE allFilesMask = ET_STRING_FROM_CONST_CHAR("*.*");

void initTime()
{
	LARGE_INTEGER c = { };
	LARGE_INTEGER f = { };

	shouldInitializeTime = false;

	QueryPerformanceCounter(&c);
	QueryPerformanceFrequency(&f);

	initialCounter = c.QuadPart;
	performanceFrequency = f.QuadPart;
}

uint64_t et::queryContiniousTimeInMilliSeconds()
{
	if (shouldInitializeTime)
		initTime();

	LARGE_INTEGER c = { };
	QueryPerformanceCounter(&c);

	return 1000 * (c.QuadPart - initialCounter) / performanceFrequency;
}

float et::queryContiniousTimeInSeconds()
{
	return static_cast<float>(queryContiniousTimeInMilliSeconds()) / 1000.0f;
}

uint64_t et::queryCurrentTimeInMicroSeconds()
{
	LARGE_INTEGER c = { };
	QueryPerformanceCounter(&c);
	return 1000000 * c.QuadPart / performanceFrequency;
}

const char et::pathDelimiter = '\\';
const char et::invalidPathDelimiter = '/';

std::string et::applicationPath()
{
	char ExePath[MAX_PATH] = { };
	GetModuleFileNameA(nullptr, ExePath, MAX_PATH);
	return getFilePath(normalizeFilePath(ExePath));
}

bool et::fileExists(const std::string& name)
{
	auto attr = GetFileAttributes(ET_STRING_TO_PARAM_TYPE(name).c_str());
	return (attr != INVALID_FILE_ATTRIBUTES) && ((attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY);
}

bool et::folderExists(const std::string& folder)
{
	auto attr = GetFileAttributes(ET_STRING_TO_PARAM_TYPE(folder).c_str());
	return (attr != INVALID_FILE_ATTRIBUTES) && ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
}

void et::findFiles(const std::string& folder, const std::string& mask, bool recursive, StringList& list)
{
	ET_STRING_TYPE normalizedFolder = ET_STRING_TO_PARAM_TYPE(addTrailingSlash(folder));
	ET_STRING_TYPE searchPath = normalizedFolder + ET_STRING_TO_PARAM_TYPE(mask);

	StringList folderList;
	if (recursive)
	{
		ET_STRING_TYPE foldersSearchPath = normalizedFolder + allFilesMask;

		WIN32_FIND_DATA folders = { };
		HANDLE folderSearch = FindFirstFile(foldersSearchPath.c_str(), &folders);
		if (folderSearch != INVALID_HANDLE_VALUE)
		{
			do
			{
				bool isFolder = (folders.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
				ET_STRING_TYPE name(folders.cFileName);
				if (isFolder && (name != currentFolder) && (name != previousFolder))
					folderList.push_back(ET_STRING_TO_OUTPUT_TYPE(normalizedFolder + name));

			}
			while (FindNextFile(folderSearch, &folders));
			FindClose(folderSearch);
		}
	}

	WIN32_FIND_DATA data = { };
	HANDLE search = FindFirstFile(searchPath.c_str(), &data);
	if (search != INVALID_HANDLE_VALUE)
	{
		do
		{
			bool isAcceptable =
				((data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) == FILE_ATTRIBUTE_NORMAL) ||
				((data.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE) ||
				((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY);

			ET_STRING_TYPE name(data.cFileName);

			if (isAcceptable && (name != currentFolder) && (name != previousFolder))
				list.push_back(ET_STRING_TO_OUTPUT_TYPE(normalizedFolder + name));
		}
		while (FindNextFile(search, &data));
		FindClose(search);
	}

	if (recursive)
	{
		for (const std::string& i : folderList)
			findFiles(i, mask, recursive, list);
	}
}

std::string et::applicationPackagePath()
{
	ET_CHAR_TYPE buffer[MAX_PATH] = { };
	GetCurrentDirectory(MAX_PATH, buffer);
	return addTrailingSlash(ET_STRING_TO_OUTPUT_TYPE(buffer));
}

std::string et::applicationDataFolder()
{
	ET_CHAR_TYPE buffer[MAX_PATH] = { };
	GetCurrentDirectory(MAX_PATH, buffer);
	return addTrailingSlash(ET_STRING_TO_OUTPUT_TYPE(buffer));
}

std::string et::documentsBaseFolder()
{
	wchar_t* path = nullptr;
	SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &path);

	if (path == nullptr)
		return emptyString;

	std::string result = addTrailingSlash(unicodeToUtf8(path));
	CoTaskMemFree(path);
	return result;
}

std::string et::libraryBaseFolder()
{
	wchar_t* path = nullptr;
	SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path);

	if (path == nullptr)
		return emptyString;

	std::string result = addTrailingSlash(unicodeToUtf8(path));
	CoTaskMemFree(path);
	return result;
}

bool et::createDirectory(const std::string& name, bool recursive)
{
	if (recursive)
	{
		char delim[] = {pathDelimiter, 0};
		bool gotError = false;
		StringList components = split(name, std::string(delim));
		std::string path;
		for (auto& dir : components)
		{
			path += dir + "\\";
			if (!folderExists(path))
				gotError |= ::CreateDirectory(ET_STRING_TO_PARAM_TYPE(path).c_str(), nullptr) == 0;
		}

		return !gotError;
	}

	return ::CreateDirectory(ET_STRING_TO_PARAM_TYPE(name).c_str(), nullptr) == 0;
}

bool et::removeFile(const std::string& name)
{
	ET_STRING_TYPE aName = ET_STRING_TO_PARAM_TYPE(name);
	aName.resize(aName.size() + 1);
	aName.back() = 0;

	SHFILEOPSTRUCT fop = { };

	fop.wFunc = FO_DELETE;
	fop.pFrom = aName.c_str();
	fop.fFlags = FOF_NO_UI;

	return SHFileOperation(&fop) == 0;
}

bool et::copyFile(const std::string& from, const std::string& to)
{
	ET_STRING_TYPE aFrom= ET_STRING_TO_PARAM_TYPE(from);
	ET_STRING_TYPE aTo = ET_STRING_TO_PARAM_TYPE(to);
	aFrom.resize(aFrom.size() + 1);
	aTo.resize(aTo.size() + 1);
	aFrom.back() = 0;
	aTo.back() = 0;

	SHFILEOPSTRUCT fop = { };

	fop.wFunc = FO_COPY;
	fop.pFrom = aFrom.c_str();
	fop.pTo = aTo.c_str();
	fop.fFlags = FOF_NO_UI;

	return SHFileOperation(&fop) == 0;
}

bool et::removeDirectory(const std::string& name)
{
	ET_STRING_TYPE aName = ET_STRING_TO_PARAM_TYPE(name);
	aName.resize(aName.size() + 1);
	aName.back() = 0;

	SHFILEOPSTRUCT fop = { };

	fop.wFunc = FO_DELETE;
	fop.pFrom = aName.c_str();
	fop.fFlags = FOF_NO_UI;

	return SHFileOperation(&fop) == 0;
}

void et::findSubfolders(const std::string& folder, bool recursive, StringList& list)
{
	StringList folderList;

	ET_STRING_TYPE normalizedFolder = ET_STRING_TO_PARAM_TYPE(addTrailingSlash(folder));
	ET_STRING_TYPE foldersSearchPath = normalizedFolder + allFilesMask;

	WIN32_FIND_DATA folders = { };
	HANDLE folderSearch = FindFirstFile(foldersSearchPath.c_str(), &folders);
	if (folderSearch != INVALID_HANDLE_VALUE)
	{
		do
		{
			ET_STRING_TYPE name(folders.cFileName);
			bool isFolder = (folders.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
			if (isFolder && (name != currentFolder) && (name != previousFolder))
			{
				folderList.push_back(ET_STRING_TO_OUTPUT_TYPE(normalizedFolder +
					name + ET_STRING_FROM_CONST_CHAR("\\")));
			}
		}
		while (FindNextFile(folderSearch, &folders));
		FindClose(folderSearch);
	}

	if (recursive)
	{
		for (const std::string& i : folderList)
			findSubfolders(i, true, list);
	}

	list.insert(list.end(), folderList.begin(), folderList.end());
}

void et::openUrl(const std::string& url)
{
	ShellExecute(nullptr, ET_STRING_FROM_CONST_CHAR("open"),
		ET_STRING_TO_PARAM_TYPE(url).c_str(), 0, 0, SW_SHOWNORMAL);
}

std::string et::unicodeToUtf8(const std::wstring& w)
{
	int mbcWidth = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, 0, 0, 0, 0);

	if (mbcWidth == 0)
		return emptyString;

	DataStorage<char> result(mbcWidth + 1, 0);
	WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, result.data(), static_cast<int>(result.size()), 0, 0);

	return std::string(result.data());
}

std::wstring et::utf8ToUnicode(const std::string& mbcs)
{
	int uWidth = MultiByteToWideChar(CP_UTF8, 0, mbcs.c_str(), -1, 0, 0);
	if (uWidth == 0)
	{
		switch (GetLastError())
		{
		case ERROR_INSUFFICIENT_BUFFER:
			std::cout << "A supplied buffer size was not large enough, "
				"or it was incorrectly set to NULL." << std::endl;
			break;

		case ERROR_INVALID_FLAGS:
			std::cout << "The values supplied for flags were not valid." << std::endl;
			break;

		case ERROR_INVALID_PARAMETER:
			std::cout << "Any of the parameter values was invalid." << std::endl;
			break;

		case ERROR_NO_UNICODE_TRANSLATION:
			std::cout << "Invalid Unicode was found in a string" << std::endl;
			break;

		default:
			std::cout << "Failed to convert utf-8 to wchar_t" << std::endl;
		}

		return std::wstring();
	}

	DataStorage<wchar_t> result(uWidth + 1, 0);
	MultiByteToWideChar(CP_UTF8, 0, mbcs.c_str(), -1, result.data(), static_cast<int>(result.size()));

	return std::wstring(result.data());
}

std::string et::applicationIdentifierForCurrentProject()
	{ return "com.et.app"; }

uint64_t et::getFileDate(const std::string& path)
{
	WIN32_FIND_DATA findData = { };
	HANDLE search = FindFirstFile(ET_STRING_TO_PARAM_TYPE(path).c_str(), &findData);
	FindClose(search);

	return findData.ftLastWriteTime.dwLowDateTime |
		(static_cast<uint64_t>(findData.ftLastWriteTime.dwHighDateTime) << 32);
}

std::vector<et::Screen> et::availableScreens()
{
	std::vector<et::Screen> result;

	EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData) -> BOOL
	{
		MONITORINFO info = { sizeof(MONITORINFO) };

		GetMonitorInfo(hMonitor,  &info);

		recti screenRect(info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right - info.rcMonitor.left,
			info.rcMonitor.bottom - info.rcMonitor.top);

		recti workarea(info.rcWork.left, info.rcWork.top, info.rcWork.right - info.rcWork.left,
			info.rcWork.bottom - info.rcWork.top);

		std::vector<et::Screen>* r = reinterpret_cast<std::vector<et::Screen>*>(dwData);
		r->emplace_back(screenRect, workarea, 1);
		return 1;
	},
	reinterpret_cast<LPARAM>(&result));

	return result;
}

std::string et::selectFile(const StringList&, SelectFileMode mode, const std::string& defaultName)
{
	ET_STRING_TYPE defaultFileName = ET_STRING_TO_PARAM_TYPE(defaultName);

	DataStorage<ET_CHAR_TYPE> defaultFileNameData(etMax(size_t(MAX_PATH), defaultFileName.size()) + 1, 0);
	etCopyMemory(defaultFileNameData.data(), defaultFileName.data(), defaultFileName.size());

	OPENFILENAME of = { };
	of.lStructSize = sizeof(of);
	of.hInstance = GetModuleHandle(nullptr);
	of.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
	of.lpstrFile = defaultFileNameData.data();
	of.nMaxFile = MAX_PATH;

#if (_UNICODE)
	of.lpstrFilter = L"All Files\0*.*\0\0";
#else
	of.lpstrFilter = "All Files\0*.*\0\0";
#endif

	auto func = (mode == SelectFileMode::Save) ? GetSaveFileName : GetOpenFileName;

	return func(&of) ? ET_STRING_TO_OUTPUT_TYPE(of.lpstrFile) : emptyString;
}

void et::alert(const std::string& title, const std::string& message, const std::string&, AlertType type)
{
	UINT alType = MB_ICONINFORMATION;

	switch (type)
	{
	case AlertType::Warning:
		{
			alType = MB_ICONWARNING;
			break;
		}

	case AlertType::Error:
		{
			alType = MB_ICONERROR;
			break;
		}

	default:
		break;
	}

	MessageBoxA(nullptr, message.c_str(), title.c_str(), alType);
}

#endif // ET_PLATFORM_WIN
<commit_msg>currentScreen function added to windows<commit_after>/*
 * This file is part of `et engine`
 * Copyright 2009-2015 by Sergey Reznik
 * Please, modify content only if you know what are you doing.
 *
 */

#include <et/core/tools.h>

#if (ET_PLATFORM_WIN)

#include <et/platform/platformtools.h>
#include <et/core/filesystem.h>
#include <et/core/containers.h>

#include <Shlobj.h>
#include <ShellAPI.h>
#include <CommDlg.h>

static bool shouldInitializeTime = true;

static uint64_t performanceFrequency = 0;
static uint64_t initialCounter = 0;

static const ET_STRING_TYPE currentFolder = ET_STRING_FROM_CONST_CHAR(".");
static const ET_STRING_TYPE previousFolder = ET_STRING_FROM_CONST_CHAR("..");
static const ET_STRING_TYPE allFilesMask = ET_STRING_FROM_CONST_CHAR("*.*");

void initTime()
{
	LARGE_INTEGER c = { };
	LARGE_INTEGER f = { };

	shouldInitializeTime = false;

	QueryPerformanceCounter(&c);
	QueryPerformanceFrequency(&f);

	initialCounter = c.QuadPart;
	performanceFrequency = f.QuadPart;
}

uint64_t et::queryContiniousTimeInMilliSeconds()
{
	if (shouldInitializeTime)
		initTime();

	LARGE_INTEGER c = { };
	QueryPerformanceCounter(&c);

	return 1000 * (c.QuadPart - initialCounter) / performanceFrequency;
}

float et::queryContiniousTimeInSeconds()
{
	return static_cast<float>(queryContiniousTimeInMilliSeconds()) / 1000.0f;
}

uint64_t et::queryCurrentTimeInMicroSeconds()
{
	LARGE_INTEGER c = { };
	QueryPerformanceCounter(&c);
	return 1000000 * c.QuadPart / performanceFrequency;
}

const char et::pathDelimiter = '\\';
const char et::invalidPathDelimiter = '/';

std::string et::applicationPath()
{
	char ExePath[MAX_PATH] = { };
	GetModuleFileNameA(nullptr, ExePath, MAX_PATH);
	return getFilePath(normalizeFilePath(ExePath));
}

bool et::fileExists(const std::string& name)
{
	auto attr = GetFileAttributes(ET_STRING_TO_PARAM_TYPE(name).c_str());
	return (attr != INVALID_FILE_ATTRIBUTES) && ((attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY);
}

bool et::folderExists(const std::string& folder)
{
	auto attr = GetFileAttributes(ET_STRING_TO_PARAM_TYPE(folder).c_str());
	return (attr != INVALID_FILE_ATTRIBUTES) && ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
}

void et::findFiles(const std::string& folder, const std::string& mask, bool recursive, StringList& list)
{
	ET_STRING_TYPE normalizedFolder = ET_STRING_TO_PARAM_TYPE(addTrailingSlash(folder));
	ET_STRING_TYPE searchPath = normalizedFolder + ET_STRING_TO_PARAM_TYPE(mask);

	StringList folderList;
	if (recursive)
	{
		ET_STRING_TYPE foldersSearchPath = normalizedFolder + allFilesMask;

		WIN32_FIND_DATA folders = { };
		HANDLE folderSearch = FindFirstFile(foldersSearchPath.c_str(), &folders);
		if (folderSearch != INVALID_HANDLE_VALUE)
		{
			do
			{
				bool isFolder = (folders.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
				ET_STRING_TYPE name(folders.cFileName);
				if (isFolder && (name != currentFolder) && (name != previousFolder))
					folderList.push_back(ET_STRING_TO_OUTPUT_TYPE(normalizedFolder + name));

			}
			while (FindNextFile(folderSearch, &folders));
			FindClose(folderSearch);
		}
	}

	WIN32_FIND_DATA data = { };
	HANDLE search = FindFirstFile(searchPath.c_str(), &data);
	if (search != INVALID_HANDLE_VALUE)
	{
		do
		{
			bool isAcceptable =
				((data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) == FILE_ATTRIBUTE_NORMAL) ||
				((data.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE) ||
				((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY);

			ET_STRING_TYPE name(data.cFileName);

			if (isAcceptable && (name != currentFolder) && (name != previousFolder))
				list.push_back(ET_STRING_TO_OUTPUT_TYPE(normalizedFolder + name));
		}
		while (FindNextFile(search, &data));
		FindClose(search);
	}

	if (recursive)
	{
		for (const std::string& i : folderList)
			findFiles(i, mask, recursive, list);
	}
}

std::string et::applicationPackagePath()
{
	ET_CHAR_TYPE buffer[MAX_PATH] = { };
	GetCurrentDirectory(MAX_PATH, buffer);
	return addTrailingSlash(ET_STRING_TO_OUTPUT_TYPE(buffer));
}

std::string et::applicationDataFolder()
{
	ET_CHAR_TYPE buffer[MAX_PATH] = { };
	GetCurrentDirectory(MAX_PATH, buffer);
	return addTrailingSlash(ET_STRING_TO_OUTPUT_TYPE(buffer));
}

std::string et::documentsBaseFolder()
{
	wchar_t* path = nullptr;
	SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &path);

	if (path == nullptr)
		return emptyString;

	std::string result = addTrailingSlash(unicodeToUtf8(path));
	CoTaskMemFree(path);
	return result;
}

std::string et::libraryBaseFolder()
{
	wchar_t* path = nullptr;
	SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path);

	if (path == nullptr)
		return emptyString;

	std::string result = addTrailingSlash(unicodeToUtf8(path));
	CoTaskMemFree(path);
	return result;
}

bool et::createDirectory(const std::string& name, bool recursive)
{
	if (recursive)
	{
		char delim[] = {pathDelimiter, 0};
		bool gotError = false;
		StringList components = split(name, std::string(delim));
		std::string path;
		for (auto& dir : components)
		{
			path += dir + "\\";
			if (!folderExists(path))
				gotError |= ::CreateDirectory(ET_STRING_TO_PARAM_TYPE(path).c_str(), nullptr) == 0;
		}

		return !gotError;
	}

	return ::CreateDirectory(ET_STRING_TO_PARAM_TYPE(name).c_str(), nullptr) == 0;
}

bool et::removeFile(const std::string& name)
{
	ET_STRING_TYPE aName = ET_STRING_TO_PARAM_TYPE(name);
	aName.resize(aName.size() + 1);
	aName.back() = 0;

	SHFILEOPSTRUCT fop = { };

	fop.wFunc = FO_DELETE;
	fop.pFrom = aName.c_str();
	fop.fFlags = FOF_NO_UI;

	return SHFileOperation(&fop) == 0;
}

bool et::copyFile(const std::string& from, const std::string& to)
{
	ET_STRING_TYPE aFrom= ET_STRING_TO_PARAM_TYPE(from);
	ET_STRING_TYPE aTo = ET_STRING_TO_PARAM_TYPE(to);
	aFrom.resize(aFrom.size() + 1);
	aTo.resize(aTo.size() + 1);
	aFrom.back() = 0;
	aTo.back() = 0;

	SHFILEOPSTRUCT fop = { };

	fop.wFunc = FO_COPY;
	fop.pFrom = aFrom.c_str();
	fop.pTo = aTo.c_str();
	fop.fFlags = FOF_NO_UI;

	return SHFileOperation(&fop) == 0;
}

bool et::removeDirectory(const std::string& name)
{
	ET_STRING_TYPE aName = ET_STRING_TO_PARAM_TYPE(name);
	aName.resize(aName.size() + 1);
	aName.back() = 0;

	SHFILEOPSTRUCT fop = { };

	fop.wFunc = FO_DELETE;
	fop.pFrom = aName.c_str();
	fop.fFlags = FOF_NO_UI;

	return SHFileOperation(&fop) == 0;
}

void et::findSubfolders(const std::string& folder, bool recursive, StringList& list)
{
	StringList folderList;

	ET_STRING_TYPE normalizedFolder = ET_STRING_TO_PARAM_TYPE(addTrailingSlash(folder));
	ET_STRING_TYPE foldersSearchPath = normalizedFolder + allFilesMask;

	WIN32_FIND_DATA folders = { };
	HANDLE folderSearch = FindFirstFile(foldersSearchPath.c_str(), &folders);
	if (folderSearch != INVALID_HANDLE_VALUE)
	{
		do
		{
			ET_STRING_TYPE name(folders.cFileName);
			bool isFolder = (folders.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
			if (isFolder && (name != currentFolder) && (name != previousFolder))
			{
				folderList.push_back(ET_STRING_TO_OUTPUT_TYPE(normalizedFolder +
					name + ET_STRING_FROM_CONST_CHAR("\\")));
			}
		}
		while (FindNextFile(folderSearch, &folders));
		FindClose(folderSearch);
	}

	if (recursive)
	{
		for (const std::string& i : folderList)
			findSubfolders(i, true, list);
	}

	list.insert(list.end(), folderList.begin(), folderList.end());
}

void et::openUrl(const std::string& url)
{
	ShellExecute(nullptr, ET_STRING_FROM_CONST_CHAR("open"),
		ET_STRING_TO_PARAM_TYPE(url).c_str(), 0, 0, SW_SHOWNORMAL);
}

std::string et::unicodeToUtf8(const std::wstring& w)
{
	int mbcWidth = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, 0, 0, 0, 0);

	if (mbcWidth == 0)
		return emptyString;

	DataStorage<char> result(mbcWidth + 1, 0);
	WideCharToMultiByte(CP_UTF8, 0, w.c_str(), -1, result.data(), static_cast<int>(result.size()), 0, 0);

	return std::string(result.data());
}

std::wstring et::utf8ToUnicode(const std::string& mbcs)
{
	int uWidth = MultiByteToWideChar(CP_UTF8, 0, mbcs.c_str(), -1, 0, 0);
	if (uWidth == 0)
	{
		switch (GetLastError())
		{
		case ERROR_INSUFFICIENT_BUFFER:
			std::cout << "A supplied buffer size was not large enough, "
				"or it was incorrectly set to NULL." << std::endl;
			break;

		case ERROR_INVALID_FLAGS:
			std::cout << "The values supplied for flags were not valid." << std::endl;
			break;

		case ERROR_INVALID_PARAMETER:
			std::cout << "Any of the parameter values was invalid." << std::endl;
			break;

		case ERROR_NO_UNICODE_TRANSLATION:
			std::cout << "Invalid Unicode was found in a string" << std::endl;
			break;

		default:
			std::cout << "Failed to convert utf-8 to wchar_t" << std::endl;
		}

		return std::wstring();
	}

	DataStorage<wchar_t> result(uWidth + 1, 0);
	MultiByteToWideChar(CP_UTF8, 0, mbcs.c_str(), -1, result.data(), static_cast<int>(result.size()));

	return std::wstring(result.data());
}

std::string et::applicationIdentifierForCurrentProject()
	{ return "com.et.app"; }

uint64_t et::getFileDate(const std::string& path)
{
	WIN32_FIND_DATA findData = { };
	HANDLE search = FindFirstFile(ET_STRING_TO_PARAM_TYPE(path).c_str(), &findData);
	FindClose(search);

	return findData.ftLastWriteTime.dwLowDateTime |
		(static_cast<uint64_t>(findData.ftLastWriteTime.dwHighDateTime) << 32);
}

std::vector<et::Screen> et::availableScreens()
{
	std::vector<et::Screen> result;

	EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData) -> BOOL
	{
		MONITORINFO info = { sizeof(MONITORINFO) };

		GetMonitorInfo(hMonitor,  &info);

		recti screenRect(info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.right - info.rcMonitor.left,
			info.rcMonitor.bottom - info.rcMonitor.top);

		recti workarea(info.rcWork.left, info.rcWork.top, info.rcWork.right - info.rcWork.left,
			info.rcWork.bottom - info.rcWork.top);

		std::vector<et::Screen>* r = reinterpret_cast<std::vector<et::Screen>*>(dwData);
		r->emplace_back(screenRect, workarea, 1);
		return 1;
	},
	reinterpret_cast<LPARAM>(&result));

	return result;
}

et::Screen et::currentScreen()
{
	return availableScreens().front();
}

std::string et::selectFile(const StringList&, SelectFileMode mode, const std::string& defaultName)
{
	ET_STRING_TYPE defaultFileName = ET_STRING_TO_PARAM_TYPE(defaultName);

	DataStorage<ET_CHAR_TYPE> defaultFileNameData(etMax(size_t(MAX_PATH), defaultFileName.size()) + 1, 0);
	etCopyMemory(defaultFileNameData.data(), defaultFileName.data(), defaultFileName.size());

	OPENFILENAME of = { };
	of.lStructSize = sizeof(of);
	of.hInstance = GetModuleHandle(nullptr);
	of.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
	of.lpstrFile = defaultFileNameData.data();
	of.nMaxFile = MAX_PATH;

#if (_UNICODE)
	of.lpstrFilter = L"All Files\0*.*\0\0";
#else
	of.lpstrFilter = "All Files\0*.*\0\0";
#endif

	auto func = (mode == SelectFileMode::Save) ? GetSaveFileName : GetOpenFileName;

	return func(&of) ? ET_STRING_TO_OUTPUT_TYPE(of.lpstrFile) : emptyString;
}

void et::alert(const std::string& title, const std::string& message, const std::string&, AlertType type)
{
	UINT alType = MB_ICONINFORMATION;

	switch (type)
	{
	case AlertType::Warning:
		{
			alType = MB_ICONWARNING;
			break;
		}

	case AlertType::Error:
		{
			alType = MB_ICONERROR;
			break;
		}

	default:
		break;
	}

	MessageBoxA(nullptr, message.c_str(), title.c_str(), alType);
}

#endif // ET_PLATFORM_WIN
<|endoftext|>


<commit_before>#include "Buttongrid.h"

Buttongrid::Buttongrid(){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
}

Buttongrid::Buttongrid(unsigned char size){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	columns = size;
	rows = size;
	gridSize = size;

	//Allocate memory for labels
	if(gridSize!=NULL){
		if(labels = (unsigned char**)malloc(gridSize * sizeof(unsigned char*))){
			for(int i=0; i<gridSize; i++)
			{
				if(labels[i] = (unsigned char*)malloc(gridSize)){
					memset(labels[i],0,gridSize);
				}
			}
		}
	}

	this->init();
}

Buttongrid::Buttongrid(unsigned char r, unsigned char c){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	columns = c;
	rows = r;
	//gridSize = size;

	//Allocate memory for labels
	if(rows!=NULL){
		if(labels = (unsigned char**)malloc(rows * sizeof(unsigned char*))){
			for(int i=0; i<rows; i++)
			{
				if(labels[i] = (unsigned char*)malloc(columns)){
					memset(labels[i],0,columns);
				}
			}
		}
	}

	//Allocate memory for names
	if(rows >= 0 && columns >= 0){
		char qty = rows * columns;
		if(names = (const char**) malloc(qty * 8 * sizeof(char))){
			memset(names,0,qty*8*sizeof(char));
		}
	}

	//this->init();

}

Buttongrid::Buttongrid(unsigned int width, unsigned int height, int backgroundColor, int textColor, int borderColor){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	x = 0;
	y = 0;
	this->setSize(width,height);
	this->setColors(backgroundColor,textColor,borderColor);
	this->init();
}

Buttongrid::~Buttongrid(){
	if(text) free(text);
}

void Buttongrid::init(){
	Button::init();
	type = 0x31;
	borderWidth = 2;
	charPos = 0;

	// Initialize labels with position ID
	for(byte r=1; r<=rows; r++)
	{
		for(byte c=1; c<=columns; c++)
		{
			labels[r-1][c-1] = c+columns*(r-1);
			//Serial.print("Row ");
			//Serial.print(r);
			//Serial.print(" Col ");
			//Serial.print(c);
			//Serial.print(" Num ");
			//Serial.println(c+columns*(r-1));
		}
	}
}

void Buttongrid::drawGrid(){
  int xPos,yPos,width,height;
  int btnWidth,btnHeight;

  xPos = x;
  yPos = y;
  width = w;
  height = h;
  btnWidth = w / columns;
  btnHeight = h / rows;

  //--nums background rectangle
  Tft.fillRectangle(xPos,yPos,width,height,bgColor);

	//-- outer border
  for(byte i=borderWidth; i!=0;i--){
    Tft.drawRectangle(xPos++,yPos++,width--,height--,borderColor);
    width--;
    height--;
  }

  //-- horizontal lines
  for(byte j=1;j<rows;j++)
  {
	  // draw # horizontal lines depending on borderWidth
  	for(byte i=0; i<borderWidth;i++){
    	Tft.drawHorizontalLine(x,y+btnHeight*j+i-vGap,width+borderWidth,borderColor);
  	}

		//Only draw gaps in between edges
		if(vGap>0){
			//Tft.fillRectangle(xPos,y-vGap+btnHeight*j+1,width,btnHeight-1,BLACK);
			for(byte i=0; i<borderWidth;i++){
				Tft.drawHorizontalLine(x,y+btnHeight*j+i+borderWidth+vGap,width+borderWidth,borderColor);
			}
		}

  }

  //-- vertical lines
  for(byte j=1;j<columns;j++)
  {
	// draw # of vertical lines depending on borderWidth
  	for(byte i=0; i<borderWidth;i++){
    	Tft.drawVerticalLine(x+btnWidth*j+i-hGap,y+borderWidth,height+borderWidth,borderColor);
  	}

		//Only draw gaps in between edges
		if(hGap>0){
			//Tft.fillRectangle(xPos,y-vGap+btnHeight*j+1,width,btnHeight-1,BLACK);
			for(byte i=0; i<borderWidth;i++){
				Tft.drawVerticalLine(x+btnWidth*j+i+borderWidth+hGap,y+borderWidth,height+borderWidth,borderColor);
			}
		}

  }

  //-- Gaps fill
  if(hGap > 0){
		for(byte j=1;j<columns;j++){
			Tft.fillRectangle(x+j*btnWidth+borderWidth-hGap,y,hGap*2,h,myCanvas->bgColor);
		}
  }
  if(vGap > 0){
		for(byte j=1;j<rows;j++){
			Tft.fillRectangle(x,y+j*btnHeight+borderWidth-vGap,w,vGap*2,myCanvas->bgColor);
		}
  }

  //-- draw contents
  byte colIndex=0;
  byte rowIndex=0;
  for(byte r=1; r<=rows; r++)
  {
	  for(byte c=1; c<=columns; c++)
	  {
		  printName(getNumber(r,c));
	  }
  }

}

void Buttongrid::setEventHandler(void (*functionPointer)(Buttongrid *, unsigned char)){
	eventHandler = functionPointer;
}

void Buttongrid::configure(byte size, byte f){
	columns = size;
	rows = size;
	gridSize = size;
	font_size = f;
	show();
}

unsigned char Buttongrid::getColumn(unsigned char num){
	unsigned char val = num%columns;
	return val==0 ? columns : val;
}

unsigned char Buttongrid::getRow(unsigned char num){
	num -= 1;
	unsigned char mod = num%columns;
	return num/columns + 1;
}

unsigned char Buttongrid::getNumber(unsigned char row, unsigned char column){
	unsigned char val = column + (row - 1) * columns;
	return val;
}

void Buttongrid::setNum(unsigned char id){
	int boundX1, boundX2, boundY1, boundY2;
	int btnWidth = w/columns;
	int btnHeight = h/rows;
	unsigned char colIndex = getColumn(id)-1;
	unsigned char rowIndex = getRow(id)-1;
	unsigned char digits = Tft.Get_Digits(id);

	//Calculates initial position of text inside the btnWidth
	//considering the number's width and font size.
	int xPos = btnWidth/2 - (digits*FONT_X*font_size)/2;//btnWidth/(2) - 6*digits -2;
	int yPos = btnHeight/(2) - 8;

	//Calculates position of the text considering
	//its column or row and the btnWidth.
  	xPos = x+(colIndex*btnWidth)+xPos+borderWidth;
  	yPos = y+yPos+(rowIndex*btnHeight);

  	//Draw contents function
  	Tft.drawNumber(id,xPos,yPos,font_size,BLACK);
}

void Buttongrid::setLabel(unsigned char id, unsigned char label){
	int boundX1, boundX2, boundY1, boundY2;
	int btnWidth = w/columns;
	int btnHeight = h/rows;
	unsigned char colIndex = getColumn(id)-1;
	unsigned char rowIndex = getRow(id)-1;
	unsigned char digits = Tft.Get_Digits(label);

	//labels[rowIndex][colIndex] = label; <---- No, can't do this! No enough memory to hold strings for each button
	//Calculates initial position of text inside the btnWidth
	//considering the number's width and font size.

	int xPos = (btnWidth - digits*6*font_size)/2;//btnWidth/(2) - 6*digits -2;
	int yPos = (btnHeight-FONT_Y*fontSize)/2;//btnHeight/(2) - 8;

	//Calculates position of the text considering
	//its column or row and the btnWidth.
	xPos = x+(colIndex*btnWidth)+xPos+borderWidth+hGap;//+(2*borderWidth);//+borderWidth;
	yPos = y+(rowIndex*btnHeight)+yPos+borderWidth+vGap;//+(2*borderWidth);

	//Draw contents function
	Tft.drawNumber(label,xPos,yPos,font_size,BLACK);
}

void Buttongrid::setName(unsigned char id, const char name[8]){
	names[id] = name;
	return;
}

void Buttongrid::setName(unsigned char id, char number){
	//names[id] = ;
	return;
}

void Buttongrid::printName(unsigned char id){
	const char* name = names[id];
	// Calculate characters in name
	int n;
	for(n=0;n<8;n++){
		if(name[n] == 0) break;
	}

	Serial.print(n);
	Serial.print(" characters for id: ");
	Serial.print(id);
	Serial.print(" ");
	Serial.println(names[id]);

	//setNum(id);
	setLabel(id,labels[getRow(id)-1][getColumn(id)-1]);
	return;

	// If name is empty draw the id, else draw the name
	if(n==0){
		setNum(id);
	}else{
		//i++;
		int boundX1, boundX2, boundY1, boundY2;
		int btnWidth = w/columns;
		int btnHeight = h/rows;
		unsigned char colIndex = getColumn(id)-1;
		unsigned char rowIndex = getRow(id)-1;

		int xPos = btnWidth/2 - (n*FONT_X*font_size)/2;
		int yPos = btnHeight/(2) - 8;

		xPos = x+(colIndex*btnWidth)+xPos+3*borderWidth;
		yPos = y+yPos+(rowIndex*btnHeight);

		Tft.drawString((char*)names[id],xPos, yPos, font_size, fgColor);
	}

	return;
}

void Buttongrid::clear(){
	drawGrid();
	lastPressed = 0;
}

//Overriden virtual methods

bool Buttongrid::checkTouch(Point* p){
	int boundX1, boundX2, boundY1, boundY2;
	int btnWidth = w/columns;
	int btnHeight = h/rows;
	bool pressed = false;
	if(lastMillis + debounceTime < millis()){
		if((p->x > x+borderWidth) && (p->x < x+w-borderWidth) && (p->y > y+borderWidth) && (p->y < y+h-borderWidth)){
			//num coordinates
			for(int r = 1;(r <= rows)&&(!pressed); r++)
			{
				// Determine the bounding y's for this row
				boundY1 = y+(btnHeight)*(r-1)+borderWidth;
				boundY2 = y+(btnHeight)*r-borderWidth;
				for(int c = 1;(c <= columns)&&(!pressed);c++)
				{
					// Determine the bounding x's for this column
					boundX1 = x + (btnWidth)*(c-1) + borderWidth;
					boundX2 = x + (btnWidth)*c - borderWidth;
					int num = columns*(r - 1) + c;
					if((p->x > boundX1) && (p->x < boundX2) && (p->y > boundY1) && (p->y < boundY2)){

						// Restore last button pressed appearance
						if(clearLastPressed && lastPressed != 0){
							int lastX = x + (btnWidth)*(getColumn(lastPressed)-1) + borderWidth;
							int lastY = y+(btnHeight)*(getRow(lastPressed)-1)+borderWidth;
							if(HIGHLIGHT == 1){
								Tft.fillRectangle(lastX,lastY,btnWidth-borderWidth-1,btnHeight-borderWidth-1,bgColor);
							}
							//setLabel(lastPressed,labels[getRow(lastPressed)-1][getColumn(lastPressed)-1]);
							printName(lastPressed);
						}

						// Highlight currently pressed button
						if(HIGHLIGHT == 1){
							Tft.fillRectangle(boundX1,boundY1,btnWidth-borderWidth-1,btnHeight-borderWidth-1,highlightColor);
						}
						//setNum(num);
						//setLabel(num,labels[r-1][c-1]);
						printName(num);

						// Call event handler with pressed button id
						eventHandler(this,num);
						pressed = true;
						lastPressed = num;
					}
				}// -- columns for loop
			}// --rows for loop
		}// -- if touch within widget area
		touched = !touched;
		lastMillis = millis();
	}// -- debounce
	return true; // <--- False means block further event checking.
}

void Buttongrid::show(){
	drawGrid();
	update();
}

void Buttongrid::update(){
	return;
}
<commit_msg>Removed Serial prints from printName in ButtonGrid<commit_after>#include "Buttongrid.h"

Buttongrid::Buttongrid(){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
}

Buttongrid::Buttongrid(unsigned char size){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	columns = size;
	rows = size;
	gridSize = size;

	//Allocate memory for labels
	if(gridSize!=NULL){
		if(labels = (unsigned char**)malloc(gridSize * sizeof(unsigned char*))){
			for(int i=0; i<gridSize; i++)
			{
				if(labels[i] = (unsigned char*)malloc(gridSize)){
					memset(labels[i],0,gridSize);
				}
			}
		}
	}

	this->init();
}

Buttongrid::Buttongrid(unsigned char r, unsigned char c){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	columns = c;
	rows = r;
	//gridSize = size;

	//Allocate memory for labels
	if(rows!=NULL){
		if(labels = (unsigned char**)malloc(rows * sizeof(unsigned char*))){
			for(int i=0; i<rows; i++)
			{
				if(labels[i] = (unsigned char*)malloc(columns)){
					memset(labels[i],0,columns);
				}
			}
		}
	}

	//Allocate memory for names
	if(rows >= 0 && columns >= 0){
		char qty = rows * columns;
		if(names = (const char**) malloc(qty * 8 * sizeof(char))){
			memset(names,0,qty*8*sizeof(char));
		}
	}

	//this->init();

}

Buttongrid::Buttongrid(unsigned int width, unsigned int height, int backgroundColor, int textColor, int borderColor){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	x = 0;
	y = 0;
	this->setSize(width,height);
	this->setColors(backgroundColor,textColor,borderColor);
	this->init();
}

Buttongrid::~Buttongrid(){
	if(text) free(text);
}

void Buttongrid::init(){
	Button::init();
	type = 0x31;
	borderWidth = 2;
	charPos = 0;

	// Initialize labels with position ID
	for(byte r=1; r<=rows; r++)
	{
		for(byte c=1; c<=columns; c++)
		{
			labels[r-1][c-1] = c+columns*(r-1);
			//Serial.print("Row ");
			//Serial.print(r);
			//Serial.print(" Col ");
			//Serial.print(c);
			//Serial.print(" Num ");
			//Serial.println(c+columns*(r-1));
		}
	}
}

void Buttongrid::drawGrid(){
  int xPos,yPos,width,height;
  int btnWidth,btnHeight;

  xPos = x;
  yPos = y;
  width = w;
  height = h;
  btnWidth = w / columns;
  btnHeight = h / rows;

  //--nums background rectangle
  Tft.fillRectangle(xPos,yPos,width,height,bgColor);

	//-- outer border
  for(byte i=borderWidth; i!=0;i--){
    Tft.drawRectangle(xPos++,yPos++,width--,height--,borderColor);
    width--;
    height--;
  }

  //-- horizontal lines
  for(byte j=1;j<rows;j++)
  {
	  // draw # horizontal lines depending on borderWidth
  	for(byte i=0; i<borderWidth;i++){
    	Tft.drawHorizontalLine(x,y+btnHeight*j+i-vGap,width+borderWidth,borderColor);
  	}

		//Only draw gaps in between edges
		if(vGap>0){
			//Tft.fillRectangle(xPos,y-vGap+btnHeight*j+1,width,btnHeight-1,BLACK);
			for(byte i=0; i<borderWidth;i++){
				Tft.drawHorizontalLine(x,y+btnHeight*j+i+borderWidth+vGap,width+borderWidth,borderColor);
			}
		}

  }

  //-- vertical lines
  for(byte j=1;j<columns;j++)
  {
	// draw # of vertical lines depending on borderWidth
  	for(byte i=0; i<borderWidth;i++){
    	Tft.drawVerticalLine(x+btnWidth*j+i-hGap,y+borderWidth,height+borderWidth,borderColor);
  	}

		//Only draw gaps in between edges
		if(hGap>0){
			//Tft.fillRectangle(xPos,y-vGap+btnHeight*j+1,width,btnHeight-1,BLACK);
			for(byte i=0; i<borderWidth;i++){
				Tft.drawVerticalLine(x+btnWidth*j+i+borderWidth+hGap,y+borderWidth,height+borderWidth,borderColor);
			}
		}

  }

  //-- Gaps fill
  if(hGap > 0){
		for(byte j=1;j<columns;j++){
			Tft.fillRectangle(x+j*btnWidth+borderWidth-hGap,y,hGap*2,h,myCanvas->bgColor);
		}
  }
  if(vGap > 0){
		for(byte j=1;j<rows;j++){
			Tft.fillRectangle(x,y+j*btnHeight+borderWidth-vGap,w,vGap*2,myCanvas->bgColor);
		}
  }

  //-- draw contents
  byte colIndex=0;
  byte rowIndex=0;
  for(byte r=1; r<=rows; r++)
  {
	  for(byte c=1; c<=columns; c++)
	  {
		  printName(getNumber(r,c));
	  }
  }

}

void Buttongrid::setEventHandler(void (*functionPointer)(Buttongrid *, unsigned char)){
	eventHandler = functionPointer;
}

void Buttongrid::configure(byte size, byte f){
	columns = size;
	rows = size;
	gridSize = size;
	font_size = f;
	show();
}

unsigned char Buttongrid::getColumn(unsigned char num){
	unsigned char val = num%columns;
	return val==0 ? columns : val;
}

unsigned char Buttongrid::getRow(unsigned char num){
	num -= 1;
	unsigned char mod = num%columns;
	return num/columns + 1;
}

unsigned char Buttongrid::getNumber(unsigned char row, unsigned char column){
	unsigned char val = column + (row - 1) * columns;
	return val;
}

void Buttongrid::setNum(unsigned char id){
	int boundX1, boundX2, boundY1, boundY2;
	int btnWidth = w/columns;
	int btnHeight = h/rows;
	unsigned char colIndex = getColumn(id)-1;
	unsigned char rowIndex = getRow(id)-1;
	unsigned char digits = Tft.Get_Digits(id);

	//Calculates initial position of text inside the btnWidth
	//considering the number's width and font size.
	int xPos = btnWidth/2 - (digits*FONT_X*font_size)/2;//btnWidth/(2) - 6*digits -2;
	int yPos = btnHeight/(2) - 8;

	//Calculates position of the text considering
	//its column or row and the btnWidth.
  	xPos = x+(colIndex*btnWidth)+xPos+borderWidth;
  	yPos = y+yPos+(rowIndex*btnHeight);

  	//Draw contents function
  	Tft.drawNumber(id,xPos,yPos,font_size,BLACK);
}

void Buttongrid::setLabel(unsigned char id, unsigned char label){
	int boundX1, boundX2, boundY1, boundY2;
	int btnWidth = w/columns;
	int btnHeight = h/rows;
	unsigned char colIndex = getColumn(id)-1;
	unsigned char rowIndex = getRow(id)-1;
	unsigned char digits = Tft.Get_Digits(label);

	//labels[rowIndex][colIndex] = label; <---- No, can't do this! No enough memory to hold strings for each button
	//Calculates initial position of text inside the btnWidth
	//considering the number's width and font size.

	int xPos = (btnWidth - digits*6*font_size)/2;//btnWidth/(2) - 6*digits -2;
	int yPos = (btnHeight-FONT_Y*fontSize)/2;//btnHeight/(2) - 8;

	//Calculates position of the text considering
	//its column or row and the btnWidth.
	xPos = x+(colIndex*btnWidth)+xPos+borderWidth+hGap;//+(2*borderWidth);//+borderWidth;
	yPos = y+(rowIndex*btnHeight)+yPos+borderWidth+vGap;//+(2*borderWidth);

	//Draw contents function
	Tft.drawNumber(label,xPos,yPos,font_size,BLACK);
}

void Buttongrid::setName(unsigned char id, const char name[8]){
	names[id] = name;
	return;
}

void Buttongrid::setName(unsigned char id, char number){
	//names[id] = ;
	return;
}

void Buttongrid::printName(unsigned char id){
	const char* name = names[id];
	// Calculate characters in name
	int n;
	for(n=0;n<8;n++){
		if(name[n] == 0) break;
	}

	//Serial.print(n);
	//Serial.print(" characters for id: ");
	//Serial.print(id);
	//Serial.print(" ");
	//Serial.println(names[id]);

	//setNum(id);
	setLabel(id,labels[getRow(id)-1][getColumn(id)-1]);
	return;

	// If name is empty draw the id, else draw the name
	if(n==0){
		setNum(id);
	}else{
		//i++;
		int boundX1, boundX2, boundY1, boundY2;
		int btnWidth = w/columns;
		int btnHeight = h/rows;
		unsigned char colIndex = getColumn(id)-1;
		unsigned char rowIndex = getRow(id)-1;

		int xPos = btnWidth/2 - (n*FONT_X*font_size)/2;
		int yPos = btnHeight/(2) - 8;

		xPos = x+(colIndex*btnWidth)+xPos+3*borderWidth;
		yPos = y+yPos+(rowIndex*btnHeight);

		Tft.drawString((char*)names[id],xPos, yPos, font_size, fgColor);
	}

	return;
}

void Buttongrid::clear(){
	drawGrid();
	lastPressed = 0;
}

//Overriden virtual methods

bool Buttongrid::checkTouch(Point* p){
	int boundX1, boundX2, boundY1, boundY2;
	int btnWidth = w/columns;
	int btnHeight = h/rows;
	bool pressed = false;
	if(lastMillis + debounceTime < millis()){
		if((p->x > x+borderWidth) && (p->x < x+w-borderWidth) && (p->y > y+borderWidth) && (p->y < y+h-borderWidth)){
			//num coordinates
			for(int r = 1;(r <= rows)&&(!pressed); r++)
			{
				// Determine the bounding y's for this row
				boundY1 = y+(btnHeight)*(r-1)+borderWidth;
				boundY2 = y+(btnHeight)*r-borderWidth;
				for(int c = 1;(c <= columns)&&(!pressed);c++)
				{
					// Determine the bounding x's for this column
					boundX1 = x + (btnWidth)*(c-1) + borderWidth;
					boundX2 = x + (btnWidth)*c - borderWidth;
					int num = columns*(r - 1) + c;
					if((p->x > boundX1) && (p->x < boundX2) && (p->y > boundY1) && (p->y < boundY2)){

						// Restore last button pressed appearance
						if(clearLastPressed && lastPressed != 0){
							int lastX = x + (btnWidth)*(getColumn(lastPressed)-1) + borderWidth;
							int lastY = y+(btnHeight)*(getRow(lastPressed)-1)+borderWidth;
							if(HIGHLIGHT == 1){
								Tft.fillRectangle(lastX,lastY,btnWidth-borderWidth-1,btnHeight-borderWidth-1,bgColor);
							}
							//setLabel(lastPressed,labels[getRow(lastPressed)-1][getColumn(lastPressed)-1]);
							printName(lastPressed);
						}

						// Highlight currently pressed button
						if(HIGHLIGHT == 1){
							Tft.fillRectangle(boundX1,boundY1,btnWidth-borderWidth-1,btnHeight-borderWidth-1,highlightColor);
						}
						//setNum(num);
						//setLabel(num,labels[r-1][c-1]);
						printName(num);

						// Call event handler with pressed button id
						eventHandler(this,num);
						pressed = true;
						lastPressed = num;
					}
				}// -- columns for loop
			}// --rows for loop
		}// -- if touch within widget area
		touched = !touched;
		lastMillis = millis();
	}// -- debounce
	return true; // <--- False means block further event checking.
}

void Buttongrid::show(){
	drawGrid();
	update();
}

void Buttongrid::update(){
	return;
}
<|endoftext|>


<commit_before>#include "chimera/render/BSPTree.hpp"
#include <SDL2/SDL.h>

template <class T> void swapFace(T& a, T& b) {
    T c = b;
    b = a;
    a = c;
}

glm::vec3 aprox(const glm::vec3& dado) {
    return glm::vec3((fabs(dado.x) < EPSILON) ? 0.0f : dado.x, (fabs(dado.y) < EPSILON) ? 0.0f : dado.y,
                     (fabs(dado.z) < EPSILON) ? 0.0f : dado.z);
}

glm::vec3 intersect(const glm::vec3& linestart, const glm::vec3& lineend, const glm::vec3& vertex,
                    const glm::vec3& normal, float& percentage) {

    float num = glm::dot(normal, linestart);
    glm::vec3 direction = lineend - linestart;

    float linelength = glm::dot(normal, direction);
    float D = -glm::dot(normal, vertex); // direção inversa

    percentage = -(num + D) / linelength;

    glm::vec3 intersection = linestart + percentage * direction;
    return aprox(intersection);
}

void splitTriangle(const glm::vec3& fx, Chimera::Triangle* _pTriangle, Chimera::Triangle* _partition,
                   std::vector<Chimera::Triangle>* _pListPolygon) {
    glm::vec3& a = _pTriangle->vertex[0].position;
    glm::vec3& b = _pTriangle->vertex[1].position;
    glm::vec3& c = _pTriangle->vertex[2].position;

    // acerto para vertex do tex final igualar a rotacao do triangulo
    Chimera::VertexData* pVertex_a = nullptr;
    Chimera::VertexData* pVertex_b = nullptr;
    Chimera::VertexData* pVertex_c = nullptr;

    // Normaliza Triangulo para que o corte do hiper-plano esteja nos segmentos de reta CA e CB (corte em a e b)
    if (fx.x * fx.z >= 0) { // corte em a e c
        swapFace(b, c);
        swapFace(a, b);

        pVertex_a = &_pTriangle->vertex[2]; // old c
        pVertex_b = &_pTriangle->vertex[0]; // old a
        pVertex_c = &_pTriangle->vertex[1]; // old b

    } else if (fx.y * fx.z >= 0) { // corte em b e c
        swapFace(a, c);
        swapFace(a, b);
        //--
        pVertex_a = &_pTriangle->vertex[1]; // old b
        pVertex_b = &_pTriangle->vertex[2]; // old c
        pVertex_c = &_pTriangle->vertex[0]; // old a

    } else { // Cortre em a e b

        pVertex_a = &_pTriangle->vertex[0]; // old a
        pVertex_b = &_pTriangle->vertex[1]; // old b
        pVertex_c = &_pTriangle->vertex[2]; // old c
    }

    float propAC = 0.0;
    float propBC = 0.0;
    glm::vec3 A = intersect(a, c, _partition->vertex[0].position, _partition->normal(), propAC);
    glm::vec3 B = intersect(b, c, _partition->vertex[0].position, _partition->normal(), propBC);

    // PA texture coord
    glm::vec2 deltaA = (pVertex_c->texture - pVertex_a->texture) * propAC;
    glm::vec2 texA = pVertex_a->texture + deltaA;

    // PB texture coord
    glm::vec2 deltaB = (pVertex_c->texture - pVertex_b->texture) * propBC;
    glm::vec2 texB = pVertex_b->texture + deltaB;

    //-- T1
    Chimera::Triangle T1(a, b, A);
    T1.vertex[0].texture = pVertex_a->texture; // a old b
    T1.vertex[1].texture = pVertex_b->texture; // b old c
    T1.vertex[2].texture = texA;               // A

    //-- T2
    Chimera::Triangle T2(b, B, A);
    T2.vertex[0].texture = pVertex_b->texture; // b old c
    T2.vertex[1].texture = texB;               // B
    T2.vertex[2].texture = texA;               // A

    // -- T3
    Chimera::Triangle T3(A, B, c);
    T3.vertex[0].texture = texA;               // A
    T3.vertex[1].texture = texB;               // B
    T3.vertex[2].texture = pVertex_c->texture; // c old a

    for (int i = 0; i < 3; i++) {
        T1.vertex[i].normal = _pTriangle->vertex[i].normal;
        T2.vertex[i].normal = _pTriangle->vertex[i].normal;
        T3.vertex[i].normal = _pTriangle->vertex[i].normal;
    }

    _pListPolygon->push_back(T1);
    _pListPolygon->push_back(T2);
    _pListPolygon->push_back(T3);
}

SIDE classifyPoly(Chimera::Triangle* plane, Chimera::Triangle* poly, glm::vec3& _resultTest) {
    // ref: http://www.cs.utah.edu/~jsnider/SeniorProj/BSP/default.htm
    unsigned short infront = 0;
    unsigned short behind = 0;
    unsigned short onPlane = 0;
    float result[3];

    for (unsigned short a = 0; a < 3; a++) {
        glm::vec3 direction = plane->vertex[0].position - poly->vertex[a].position;
        result[a] = glm::dot(direction, plane->normal());
        if (result[a] > EPSILON) {
            behind++;
        } else if (result[a] < -EPSILON) {
            infront++;
        } else {
            onPlane++;
            infront++;
            behind++;
        }
    }

    _resultTest.x = result[0];
    _resultTest.y = result[1];
    _resultTest.z = result[2];

    if (onPlane == 3)
        return SIDE::CP_ONPLANE;

    if (behind == 3)
        return SIDE::CP_BACK;

    if (infront == 3)
        return SIDE::CP_FRONT;

    return SIDE::CP_SPANNING;
}

BSPTreeNode* bsptreeBuild(std::vector<Chimera::Triangle>* _pListPolygon) {
    if (_pListPolygon->empty() == true)
        return nullptr;
    // tree->partition
    BSPTreeNode* tree = new BSPTreeNode(_pListPolygon->back());
    _pListPolygon->pop_back();
    tree->polygons.push_back(tree->partition);

    std::vector<Chimera::Triangle> front_list;
    std::vector<Chimera::Triangle> back_list;

    while (_pListPolygon->empty() == false) {

        Chimera::Triangle poly = _pListPolygon->back();
        _pListPolygon->pop_back();
        glm::vec3 result;
        SIDE teste = classifyPoly(&tree->partition, &poly, result);

        if (teste == SIDE::CP_BACK)
            back_list.push_back(poly);
        else if (teste == SIDE::CP_FRONT)
            front_list.push_back(poly);
        else if (teste == SIDE::CP_ONPLANE)
            tree->polygons.push_back(poly);
        else // CP_SPANNING
            splitTriangle(result, &poly, &tree->partition, _pListPolygon);
    }
    tree->front = bsptreeBuild(&front_list);
    tree->back = bsptreeBuild(&back_list);
    return tree;
}

//------PARSER METODOS------

SIDE classifyPoint(Chimera::Triangle* plane, glm::vec3* eye) {
    // ref: http://www.cs.utah.edu/~jsnider/SeniorProj/BSP/default.htm
    float result;
    glm::vec3* vec1 = (glm::vec3*)&plane->vertex[0];
    glm::vec3 dir = (*vec1) - (*eye);
    result = glm::dot(dir, plane->normal());

    if (result < -EPSILON)
        return SIDE::CP_FRONT;

    if (result > EPSILON)
        return SIDE::CP_BACK;

    return SIDE::CP_ONPLANE;
}

void drawPolygon(BSPTreeNode* tree, std::vector<Chimera::VertexData>* _pOutVertex, bool logdata, bool frontSide) {
    // tree->arrayTriangle.DrawPolygons(); // Abaixo equivale a esta linha
    for (auto it = tree->polygons.begin(); it != tree->polygons.end(); it++) {
        Chimera::Triangle t = (*it);

        // if (t.getSerial() == 10) // 8, 9, 10
        //     continue;

        _pOutVertex->push_back(t.vertex[0]);
        _pOutVertex->push_back(t.vertex[1]);
        _pOutVertex->push_back(t.vertex[2]);

        // FIXME: remover depois de concluir o algoritmo
        if (logdata == true) {
            if (frontSide == true)
                SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Face F: %d", t.getSerial());
            else
                SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Face B: %d", t.getSerial());
        }
    }
}

void traverseTree(BSPTreeNode* tree, glm::vec3* eye, std::vector<Chimera::VertexData>* _pOutVertex, bool logdata) {
    // ref: https://web.cs.wpi.edu/~matt/courses/cs563/talks/bsp/document.html
    if (tree == nullptr)
        return;

    SIDE result = classifyPoint(&tree->partition, eye);
    if (result == SIDE::CP_FRONT) {

        traverseTree(tree->back, eye, _pOutVertex, logdata);
        drawPolygon(tree, _pOutVertex, logdata, true);
        traverseTree(tree->front, eye, _pOutVertex, logdata);

    } else if (result == SIDE::CP_BACK) {

        traverseTree(tree->front, eye, _pOutVertex, logdata);
        drawPolygon(tree, _pOutVertex, logdata, false);
        traverseTree(tree->back, eye, _pOutVertex, logdata);

    } else { // result == SIDE::CP_ONPLANE
        // the eye point is on the partition plane...
        traverseTree(tree->front, eye, _pOutVertex, logdata);
        traverseTree(tree->back, eye, _pOutVertex, logdata);
    }
}

void bsptreeDraw(BSPTreeNode* _pRoot, glm::vec3* eye, std::vector<Chimera::VertexData>* _pOutVertex, bool logdata) {
    traverseTree(_pRoot, eye, _pOutVertex, logdata);
}

bool getIntersect(glm::vec3* linestart, glm::vec3* lineend, glm::vec3* vertex, glm::vec3* normal,
                  glm::vec3* intersection, float* percentage) {
    glm::vec3 direction, L1;
    float linelength, dist_from_plane;

    direction.x = lineend->x - linestart->x;
    direction.y = lineend->y - linestart->y;
    direction.z = lineend->z - linestart->z;

    linelength = glm::dot(direction, *normal);

    if (fabsf(linelength) < 0.0001) {
        return false;
    }

    L1.x = vertex->x - linestart->x;
    L1.y = vertex->y - linestart->y;
    L1.z = vertex->z - linestart->z;

    dist_from_plane = glm::dot(L1, *normal);
    *percentage = dist_from_plane / linelength;

    if (*percentage < 0.0f) {
        return false;
    } else if (*percentage > 1.0f) {
        return false;
    }

    intersection->x = linestart->x + direction.x * (*percentage);
    intersection->y = linestart->y + direction.y * (*percentage);
    intersection->z = linestart->z + direction.z * (*percentage);
    return true;
}<commit_msg>melhoria<commit_after>#include "chimera/render/BSPTree.hpp"
#include <SDL2/SDL.h>

template <class T> void swapFace(T& a, T& b) {
    T c = b;
    b = a;
    a = c;
}

glm::vec3 aprox(const glm::vec3& dado) {
    return glm::vec3((fabs(dado.x) < EPSILON) ? 0.0f : dado.x, (fabs(dado.y) < EPSILON) ? 0.0f : dado.y,
                     (fabs(dado.z) < EPSILON) ? 0.0f : dado.z);
}

bool intersect(const glm::vec3& linestart, const glm::vec3& lineend, const glm::vec3& vertex, const glm::vec3& normal,
               glm::vec3& intersection, float& percentage) {

    glm::vec3 direction = lineend - linestart;
    float linelength = glm::dot(direction, normal);
    if (fabsf(linelength) < 0.0001)
        return false;

    glm::vec3 L1 = vertex - linestart;

    float dist_from_plane = glm::dot(L1, normal);
    percentage = dist_from_plane / linelength;

    if (percentage < 0.0f)
        return false;
    else if (percentage > 1.0f)
        return false;

    intersection = linestart + (direction * percentage);
    return true;
}

void splitTriangle(const glm::vec3& fx, Chimera::Triangle* _pTriangle, Chimera::Triangle* _partition,
                   std::vector<Chimera::Triangle>* _pListPolygon) {
    glm::vec3& a = _pTriangle->vertex[0].position;
    glm::vec3& b = _pTriangle->vertex[1].position;
    glm::vec3& c = _pTriangle->vertex[2].position;

    // acerto para vertex do tex final igualar a rotacao do triangulo
    Chimera::VertexData* pVertex_a = nullptr;
    Chimera::VertexData* pVertex_b = nullptr;
    Chimera::VertexData* pVertex_c = nullptr;

    // Normaliza Triangulo para que o corte do hiper-plano esteja nos segmentos de reta CA e CB (corte em a e b)
    if (fx.x * fx.z >= 0) { // corte em a e c
        swapFace(b, c);
        swapFace(a, b);

        pVertex_a = &_pTriangle->vertex[2]; // old c
        pVertex_b = &_pTriangle->vertex[0]; // old a
        pVertex_c = &_pTriangle->vertex[1]; // old b

    } else if (fx.y * fx.z >= 0) { // corte em b e c
        swapFace(a, c);
        swapFace(a, b);
        //--
        pVertex_a = &_pTriangle->vertex[1]; // old b
        pVertex_b = &_pTriangle->vertex[2]; // old c
        pVertex_c = &_pTriangle->vertex[0]; // old a

    } else { // Cortre em a e b

        pVertex_a = &_pTriangle->vertex[0]; // old a
        pVertex_b = &_pTriangle->vertex[1]; // old b
        pVertex_c = &_pTriangle->vertex[2]; // old c
    }

    float propAC = 0.0;
    float propBC = 0.0;
    glm::vec3 A, B;
    intersect(a, c, _partition->vertex[0].position, _partition->normal(), A, propAC);
    intersect(b, c, _partition->vertex[0].position, _partition->normal(), B, propBC);

    // PA texture coord
    glm::vec2 deltaA = (pVertex_c->texture - pVertex_a->texture) * propAC;
    glm::vec2 texA = pVertex_a->texture + deltaA;

    // PB texture coord
    glm::vec2 deltaB = (pVertex_c->texture - pVertex_b->texture) * propBC;
    glm::vec2 texB = pVertex_b->texture + deltaB;

    //-- T1
    Chimera::Triangle T1(a, b, A);
    T1.vertex[0].texture = pVertex_a->texture; // a old b
    T1.vertex[1].texture = pVertex_b->texture; // b old c
    T1.vertex[2].texture = texA;               // A

    //-- T2
    Chimera::Triangle T2(b, B, A);
    T2.vertex[0].texture = pVertex_b->texture; // b old c
    T2.vertex[1].texture = texB;               // B
    T2.vertex[2].texture = texA;               // A

    // -- T3
    Chimera::Triangle T3(A, B, c);
    T3.vertex[0].texture = texA;               // A
    T3.vertex[1].texture = texB;               // B
    T3.vertex[2].texture = pVertex_c->texture; // c old a

    for (int i = 0; i < 3; i++) {
        T1.vertex[i].normal = _pTriangle->vertex[i].normal;
        T2.vertex[i].normal = _pTriangle->vertex[i].normal;
        T3.vertex[i].normal = _pTriangle->vertex[i].normal;
    }

    _pListPolygon->push_back(T1);
    _pListPolygon->push_back(T2);
    _pListPolygon->push_back(T3);
}

SIDE classifyPoly(Chimera::Triangle* plane, Chimera::Triangle* poly, glm::vec3& _resultTest) {
    // ref: http://www.cs.utah.edu/~jsnider/SeniorProj/BSP/default.htm
    unsigned short infront = 0;
    unsigned short behind = 0;
    unsigned short onPlane = 0;
    float result[3];

    for (unsigned short a = 0; a < 3; a++) {
        glm::vec3 direction = plane->vertex[0].position - poly->vertex[a].position;
        result[a] = glm::dot(direction, plane->normal());
        if (result[a] > EPSILON) {
            behind++;
        } else if (result[a] < -EPSILON) {
            infront++;
        } else {
            onPlane++;
            infront++;
            behind++;
        }
    }

    _resultTest.x = result[0];
    _resultTest.y = result[1];
    _resultTest.z = result[2];

    if (onPlane == 3)
        return SIDE::CP_ONPLANE;

    if (behind == 3)
        return SIDE::CP_BACK;

    if (infront == 3)
        return SIDE::CP_FRONT;

    return SIDE::CP_SPANNING;
}

BSPTreeNode* bsptreeBuild(std::vector<Chimera::Triangle>* _pListPolygon) {
    if (_pListPolygon->empty() == true)
        return nullptr;
    // tree->partition
    BSPTreeNode* tree = new BSPTreeNode(_pListPolygon->back());
    _pListPolygon->pop_back();
    tree->polygons.push_back(tree->partition);

    std::vector<Chimera::Triangle> front_list;
    std::vector<Chimera::Triangle> back_list;

    while (_pListPolygon->empty() == false) {

        Chimera::Triangle poly = _pListPolygon->back();
        _pListPolygon->pop_back();
        glm::vec3 result;
        SIDE teste = classifyPoly(&tree->partition, &poly, result);

        if (teste == SIDE::CP_BACK)
            back_list.push_back(poly);
        else if (teste == SIDE::CP_FRONT)
            front_list.push_back(poly);
        else if (teste == SIDE::CP_ONPLANE)
            tree->polygons.push_back(poly);
        else // CP_SPANNING
            splitTriangle(result, &poly, &tree->partition, _pListPolygon);
    }
    tree->front = bsptreeBuild(&front_list);
    tree->back = bsptreeBuild(&back_list);
    return tree;
}

//------PARSER METODOS------

SIDE classifyPoint(Chimera::Triangle* plane, glm::vec3* eye) {
    // ref: http://www.cs.utah.edu/~jsnider/SeniorProj/BSP/default.htm
    float result;
    glm::vec3* vec1 = (glm::vec3*)&plane->vertex[0];
    glm::vec3 dir = (*vec1) - (*eye);
    result = glm::dot(dir, plane->normal());

    if (result < -EPSILON)
        return SIDE::CP_FRONT;

    if (result > EPSILON)
        return SIDE::CP_BACK;

    return SIDE::CP_ONPLANE;
}

void drawPolygon(BSPTreeNode* tree, std::vector<Chimera::VertexData>* _pOutVertex, bool logdata, bool frontSide) {
    // tree->arrayTriangle.DrawPolygons(); // Abaixo equivale a esta linha
    for (auto it = tree->polygons.begin(); it != tree->polygons.end(); it++) {
        Chimera::Triangle t = (*it);

        // if (t.getSerial() == 10) // 8, 9, 10
        //     continue;

        _pOutVertex->push_back(t.vertex[0]);
        _pOutVertex->push_back(t.vertex[1]);
        _pOutVertex->push_back(t.vertex[2]);

        // FIXME: remover depois de concluir o algoritmo
        if (logdata == true) {
            if (frontSide == true)
                SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Face F: %d", t.getSerial());
            else
                SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Face B: %d", t.getSerial());
        }
    }
}

void traverseTree(BSPTreeNode* tree, glm::vec3* eye, std::vector<Chimera::VertexData>* _pOutVertex, bool logdata) {
    // ref: https://web.cs.wpi.edu/~matt/courses/cs563/talks/bsp/document.html
    if (tree == nullptr)
        return;

    SIDE result = classifyPoint(&tree->partition, eye);
    if (result == SIDE::CP_FRONT) {

        traverseTree(tree->back, eye, _pOutVertex, logdata);
        drawPolygon(tree, _pOutVertex, logdata, true);
        traverseTree(tree->front, eye, _pOutVertex, logdata);

    } else if (result == SIDE::CP_BACK) {

        traverseTree(tree->front, eye, _pOutVertex, logdata);
        drawPolygon(tree, _pOutVertex, logdata, false);
        traverseTree(tree->back, eye, _pOutVertex, logdata);

    } else { // result == SIDE::CP_ONPLANE
        // the eye point is on the partition plane...
        traverseTree(tree->front, eye, _pOutVertex, logdata);
        traverseTree(tree->back, eye, _pOutVertex, logdata);
    }
}

void bsptreeDraw(BSPTreeNode* _pRoot, glm::vec3* eye, std::vector<Chimera::VertexData>* _pOutVertex, bool logdata) {
    traverseTree(_pRoot, eye, _pOutVertex, logdata);
}
<|endoftext|>


<commit_before><commit_msg>Reverse prefetch field trial defaults<commit_after><|endoftext|>