<commit_before>//Created by: Sec-Mini-Projects (2015) under the MIT License - See "LICENSE" for Details.
//Description: Checks whether shellcode is running within a program by hooking API calls using anti-anti-API Hooking techniques and memory forensics.
//Usage: Please run the program without any parameters to show the usage menu.
//TitanEngine is used as the debugging engine in this program - http://reversinglabs.com/open-source/titanengine.html.

#include "stdafx.h"
#define MAX_WHITELIST 200
ULONG_PTR ep = NULL;
PROCESS_INFORMATION * info = NULL;
LPSTR api_file = NULL;
LPSTR addr_exclude_file = NULL;
bool found_shellcode = false;
unsigned long exclude_addrs[MAX_WHITELIST];
LPSTR exclude_libs[MAX_WHITELIST];
bool debug_mode = false;

//Checks for shellcode located at the current IP
void __stdcall CheckForShellcode()
{
	if(found_shellcode == false)
	{
		ThreaderPauseAllThreads(false);
		int buf_len = 600;
		ULONG_PTR ip = (ULONG_PTR)GetContextData(UE_EIP);
		LPSTR temp = (char*)calloc(255,sizeof(char));
		LPSTR mod_name = (LPSTR)calloc(1,buf_len);
		GetMappedFileName(info->hProcess,(LPVOID)ip,(LPSTR)mod_name,buf_len);
		unsigned short last_16_bits = (unsigned short)(ip);
		bool is_Avoid = false;
		//This will need to be changed for x64 bit code due to ALSR and other differences, as will other sections of this code.
		//The existing code deals with Microsoft doing something weird when processing OLE objects embedded in a DOCX/XLSX/etc file.
		int x = 0;
		while (x < MAX_WHITELIST && exclude_addrs[x] != NULL && exclude_libs[x] != NULL && is_Avoid == false)
		{
			char * dll_name = strrchr(mod_name,'\\');
			if(dll_name != NULL)
			{
				if(StrCmpI(dll_name+1,exclude_libs[x]) == NULL)
				{
					if(last_16_bits == exclude_addrs[x])
					{
						is_Avoid = true;
					}
				}
			}
			x++;
		}
		if(is_Avoid == false)
		{
			LPSTR instr = _strlwr((char*)Disassemble((LPVOID)ip));
			MEMORY_BASIC_INFORMATION * mem_info = (MEMORY_BASIC_INFORMATION*)calloc(1,sizeof(MEMORY_BASIC_INFORMATION));
			SIZE_T temp = VirtualQueryEx(info->hProcess,(LPCVOID)ip,mem_info,sizeof(*mem_info));
			if(temp && mem_info)
			{
				if(mod_name == NULL || mem_info->Protect > 0x20 || StrRChr(mod_name,NULL,'.') == NULL)
				{
					LPSTR seg_dump_name = (LPSTR)calloc(buf_len,sizeof(char));
					sprintf_s(seg_dump_name,buf_len,"%x Seg Dump.bin",mem_info->BaseAddress);
					printf("Found exploit at address %x - creating full and partial dumps. Mod Name is: %s Mem Protect: %x\n(Note: If this was unexpected, please run using the \"-d\" option to retrieve the last 2 bytes of the address for whitelisting)",ip,mod_name, mem_info->Protect);
					DumpMemory(info->hProcess,mem_info->BaseAddress,mem_info->RegionSize,seg_dump_name);
					DumpRegions(info->hProcess,"Full Region Dump Files",false);
					DumpProcess(info->hProcess,(LPVOID)GetDebuggedFileBaseAddress(),"Full Memory Image Dump.bin",ep);
					found_shellcode = true;
					if(seg_dump_name)
						free(seg_dump_name);
					StopDebug();
					exit(1);
				}
				if(debug_mode == true)
				{
					printf("Checked for shellcode %s %x %s 4\n",instr,ip,mod_name);
				}
			}
			if(mem_info)
				free(mem_info);
			StepOver(OnStep);
		}
		if(mod_name)
			free(mod_name);
		if(temp)
			free(temp);
	}
	ThreaderResumeAllThreads(false);
}

//Steps over code, determining whether a return instruction has been encountered, if not, just keeps on stepping over.
void  __stdcall OnStep()
{
	ULONG_PTR ip = (ULONG_PTR)GetContextData(UE_EIP);
	LPSTR mod_name = NULL;
	unsigned char instr= NULL;
	SIZE_T bytes_read = NULL;
	bool is_ret = false;
	ReadProcessMemory(info->hProcess,(LPCVOID)ip,&instr,sizeof(instr),&bytes_read);
	if(bytes_read != NULL)
	{
		if(instr ==0xC2 || instr ==0xC3 || instr ==0xCA || instr ==0xCB)
		{
			StepOver(CheckForShellcode);
		}
		else
		{
			StepOver(OnStep);
		}
	}
}

void __stdcall OnSingleStepException(void* ExceptionData)
{
	SetNextDbgContinueStatus(DBG_CONTINUE);
	printf("***###Received### - Single step exception.***\n");
}

//Creates a thread for each breakpoint hit to reduce bottlenecks.
void __stdcall BPHandler()
{
	StepOver(OnStep);
}

//Searches for the first JXX or call and creates a breakpoint.
bool  __stdcall SetAPIBP(ULONG_PTR api_addr)
{
	bool found = false;
	ULONG_PTR addr = api_addr;
	LPSTR instr = NULL;
	if(addr != NULL)
	{
		while(found == false)
		{
			instr = _strlwr((LPSTR)Disassemble((LPVOID)addr));
			if(StrStrI(instr,"j") == NULL && StrStrI(instr,"call") == NULL && StrStrI(instr,"ret") == NULL)
			{
				addr = addr + LengthDisassembleEx(info->hProcess,(LPVOID)addr);
			}
			else
			{
				found = true;
			}
		}
		SetBPX(addr,UE_BREAKPOINT,BPHandler);
		//printf("Breakpoing set for instr %s at %x \n",instr,api_addr);
	}
	else
	{
		found = false;
	}
	return found;
}

//Entry point handler for the program, reads the APIS to be hooked and applies them through the SetAPIBP fucntion.
void __stdcall OnEntry()
{
	ep = GetContextData(UE_EIP);
	int buf_len = 500;
    LPSTR buf = (LPSTR)calloc(buf_len,sizeof(char));
	LPSTR exclude_buf = (LPSTR)calloc(buf_len,sizeof(char));
	int temp = strlen(buf);
	FILE * f_api_file = fopen(api_file,"r");
	FILE * f_exclude_file = NULL;
	if (addr_exclude_file == NULL)
	{
		if(debug_mode == true)
			printf("***###LOGGING### - Address exclude file could not be found.***\n");
	}
	else
	{
		f_exclude_file = fopen(addr_exclude_file,"r");
		int x = 0;
		while (fgets(exclude_buf,buf_len/sizeof(*exclude_buf), f_exclude_file) && x < MAX_WHITELIST)
		{
			LPSTR exclude_lib = strtok(exclude_buf,",");
			LPSTR exclude_addr = strtok(NULL,",");
			if(exclude_lib != NULL && exclude_addr != NULL)
			{
				bool dll_failed =false;
				if(exclude_addr[strlen(exclude_addr)-1] == 0x0a)
					exclude_addr[strlen(exclude_addr)-1] = 0x00;
				if(exclude_lib[strlen(exclude_lib)-1] == 0x0a)
					exclude_lib[strlen(exclude_lib)-1] = 0x00;
				long exclude_this_addr = strtol(exclude_addr,NULL,16);
				exclude_libs[x] = (LPSTR)calloc(buf_len,sizeof(char));
				exclude_addrs[x] = exclude_this_addr;
				strcpy_s(exclude_libs[x],buf_len,exclude_lib);
				if(debug_mode == true)
					printf("***###LOGGING### - Read exclude addr entry: %s %x***\n",exclude_lib,exclude_this_addr);
			}
			x++;
		}
	}

	if (f_api_file == NULL)
	{
		printf("***###FATAL### - API's to hook file could not be found.***\n");
		StopDebug();
		exit(1);
	}
	else
	{
		while (fgets(buf,buf_len/sizeof(*buf), f_api_file)!=NULL)
		{
			LPSTR lib_name = strtok(buf,",");
			LPSTR api_name = strtok(NULL,",");
			bool dll_failed =false;
			if(api_name[strlen(api_name)-1] == 0x0a)
				api_name[strlen(api_name)-1] = 0x00;
			if(LoadLibrary(lib_name) == NULL)
			{
				if(debug_mode == true)
					printf("***###FAILED### - Could not load %s locally.***\n",lib_name);
			}
			else
			{
				if(debug_mode == true)
					printf("***###LOGGING### - Loaded %s locally.***\n",lib_name);
				if(LibrarianGetLibraryInfo(lib_name) == NULL)
				{
					if(RemoteLoadLibrary(info->hProcess,lib_name,false) == NULL)
					{
						if(debug_mode == true)
							printf("***###FAILED### - Could not load %s into the remote address space.***\n",lib_name);
						dll_failed = true;
					}
				}
				else
				{
					if(debug_mode == true)
						printf("***###LOGGING### - %s already loaded within the remote address space.***\n",lib_name);
				}
				if(!dll_failed)
				{
					ULONG_PTR api_addr = (ULONG_PTR)ImporterGetRemoteAPIAddressEx(lib_name,api_name);
					if(SetAPIBP(api_addr))
					{
						if(debug_mode == true)
							printf("***###LOGGING### - Breakpoint set for %s %x.***\n",api_name,api_addr);
					}
					else
					{
						if(debug_mode == true)
							printf("***###FAILED### - Breakpoint could not be set for %s.***\n",api_name);
					}
				}
			}
		}
	}
	if(f_api_file)
		fclose(f_api_file);
	if(f_exclude_file)
		fclose(f_exclude_file);
	if(buf)
		free(buf);
}

//Inits the debugger library and callbacks.
int main(int argc, char * argv[])
{

	int x = 1;
	LPSTR program = NULL;
	LPSTR working = NULL;
	LPSTR cmd_line = NULL;
	while (x < argc)
	{
		if(StrCmpI(argv[x],"--program") == 0 || StrCmpI(argv[x],"-p") ==0)
		{
			program = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--working_dir") == 0 || StrCmpI(argv[x],"-w") == 0)
		{
			working = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--cmd_line") == 0 || StrCmpI(argv[x],"-c") == 0)
		{
			cmd_line = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--api_list") == 0 || StrCmpI(argv[x],"-a") == 0)
		{
			api_file = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--addr_exclude") == 0 || StrCmpI(argv[x],"-e") == 0)
		{
			addr_exclude_file = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--debug_mode") == 0 || StrCmpI(argv[x],"-d") == 0)
		{
			debug_mode = true;
			x--;
		}
		x = x+2;
	}
	if(program != NULL && working != NULL && api_file != NULL)
	{
		info = (PROCESS_INFORMATION *)InitDebugEx(program,cmd_line,working,OnEntry);
		SetCustomHandler(UE_CH_SINGLESTEP,OnSingleStepException);
		SetBPXOptions(UE_BREAKPOINT_INT3);
		if(info == NULL)
		{
			printf("***###FATAL### - Failed init.***\n");
		}
		else
		{
			DebugLoop();
		}
		printf("***###LOGGING### - Exiting.***\n");
	}
	else
	{
		printf("\nFlyOnAShellcode V3.0.\n");
		printf("Sec-Mini-Projects (2015) under the MIT License - See \"LICENSE\" for Details.\n");
		printf("TitanEngine is used as the debugging engine in this program - http://reversinglabs.com/open-source/titanengine.html.\n");
		printf("***WARNING*** - This program will RUN the supplied executable and malicious input file. USE ONLY IN MALWARE RESEARCH LABS.\n\n");
		printf("Note 1 - This program can be anywhere from very stable to very unstable depending on which APIs are hooked.\n\n");
		printf("Note 2 - Avoid manually navigating the \"File Open\", etc dialogs from within the program will help eliminate crashes.\n\n");
		printf("Usage: \n--program[-p] <Program full path and name> \n--working_dir[-w] <working directory> \n--cmd_line[-c] <Command line arguments> (Optional)\n--api_list[-a] <API hook list path and name> \n--addr_exclude[-e] <address exclude file> (Optional)\n--debug_mode[-d] - Enables debug mode(Optional)\n\n");
		printf("Usage - API library/names format is for each API call a new line matching (without the quotes) \"<lib name>,<api name>\"\n\n");
	}
	//printf("%x",argc);
	return 0;
}

<commit_msg>Update FlyOnAShellcode.cpp<commit_after>//Created by: Sec-Mini-Projects (2015) under the MIT License - See "LICENSE" for Details.
//Description: Checks whether shellcode is running within a program by hooking API calls using anti-anti-API Hooking techniques and memory forensics.
//Usage: Please run the program without any parameters to show the usage menu.
//TitanEngine is used as the debugging engine in this program - http://reversinglabs.com/open-source/titanengine.html.

#include "stdafx.h"
#define MAX_WHITELIST 200
ULONG_PTR ep = NULL;
PROCESS_INFORMATION * info = NULL;
LPSTR api_file = NULL;
LPSTR addr_exclude_file = NULL;
bool found_shellcode = false;
unsigned long exclude_addrs[MAX_WHITELIST];
LPSTR exclude_libs[MAX_WHITELIST];
bool debug_mode = false;

//Checks for shellcode located at the current IP
void __stdcall CheckForShellcode()
{
	ThreaderPauseAllThreads(false);
	if(found_shellcode == false)
	{
		int buf_len = 600;
		ULONG_PTR ip = (ULONG_PTR)GetContextData(UE_EIP);
		LPSTR temp = (char*)calloc(255,sizeof(char));
		LPSTR mod_name = (LPSTR)calloc(1,buf_len);
		GetMappedFileName(info->hProcess,(LPVOID)ip,(LPSTR)mod_name,buf_len);
		unsigned short last_16_bits = (unsigned short)(ip);
		bool is_Avoid = false;
		//This will need to be changed for x64 bit code due to ALSR and other differences, as will other sections of this code.
		//The existing code deals with Microsoft doing something weird when processing OLE objects embedded in a DOCX/XLSX/etc file.
		int x = 0;
		while (x < MAX_WHITELIST && exclude_addrs[x] != NULL && exclude_libs[x] != NULL && is_Avoid == false)
		{
			char * dll_name = strrchr(mod_name,'\\');
			if(dll_name != NULL)
			{
				if(StrCmpI(dll_name+1,exclude_libs[x]) == NULL)
				{
					if(last_16_bits == exclude_addrs[x])
					{
						is_Avoid = true;
					}
				}
			}
			x++;
		}
		if(is_Avoid == false)
		{
			LPSTR instr = _strlwr((char*)Disassemble((LPVOID)ip));
			MEMORY_BASIC_INFORMATION * mem_info = (MEMORY_BASIC_INFORMATION*)calloc(1,sizeof(MEMORY_BASIC_INFORMATION));
			SIZE_T temp = VirtualQueryEx(info->hProcess,(LPCVOID)ip,mem_info,sizeof(*mem_info));
			if(temp && mem_info)
			{
				if(mod_name == NULL || mem_info->Protect > 0x20 || StrRChr(mod_name,NULL,'.') == NULL)
				{
					LPSTR seg_dump_name = (LPSTR)calloc(buf_len,sizeof(char));
					sprintf_s(seg_dump_name,buf_len,"%x Seg Dump.bin",mem_info->BaseAddress);
					printf("Found exploit at address %x - creating full and partial dumps. Mod Name is: %s Mem Protect: %x\n(Note: If this was unexpected, please run using the \"-d\" option to retrieve the last 2 bytes of the address for whitelisting)",ip,mod_name, mem_info->Protect);
					DumpMemory(info->hProcess,mem_info->BaseAddress,mem_info->RegionSize,seg_dump_name);
					DumpRegions(info->hProcess,"Full Region Dump Files",false);
					DumpProcess(info->hProcess,(LPVOID)GetDebuggedFileBaseAddress(),"Full Memory Image Dump.bin",ep);
					found_shellcode = true;
					if(seg_dump_name)
						free(seg_dump_name);
					StopDebug();
					exit(1);
				}
				if(debug_mode == true)
				{
					printf("Checked for shellcode %s %x %s 4\n",instr,ip,mod_name);
				}
			}
			if(mem_info)
				free(mem_info);
			StepOver(OnStep);
		}
		if(mod_name)
			free(mod_name);
		if(temp)
			free(temp);
	}
	ThreaderResumeAllThreads(false);
}

//Steps over code, determining whether a return instruction has been encountered, if not, just keeps on stepping over.
void  __stdcall OnStep()
{
	ULONG_PTR ip = (ULONG_PTR)GetContextData(UE_EIP);
	LPSTR mod_name = NULL;
	unsigned char instr= NULL;
	SIZE_T bytes_read = NULL;
	bool is_ret = false;
	ReadProcessMemory(info->hProcess,(LPCVOID)ip,&instr,sizeof(instr),&bytes_read);
	if(bytes_read != NULL)
	{
		if(instr ==0xC2 || instr ==0xC3 || instr ==0xCA || instr ==0xCB)
		{
			StepOver(CheckForShellcode);
		}
		else
		{
			StepOver(OnStep);
		}
	}
}

void __stdcall OnSingleStepException(void* ExceptionData)
{
	SetNextDbgContinueStatus(DBG_CONTINUE);
	printf("***###Received### - Single step exception.***\n");
}

//Creates a thread for each breakpoint hit to reduce bottlenecks.
void __stdcall BPHandler()
{
	StepOver(OnStep);
}

//Searches for the first JXX or call and creates a breakpoint.
bool  __stdcall SetAPIBP(ULONG_PTR api_addr)
{
	bool found = false;
	ULONG_PTR addr = api_addr;
	LPSTR instr = NULL;
	if(addr != NULL)
	{
		while(found == false)
		{
			instr = _strlwr((LPSTR)Disassemble((LPVOID)addr));
			if(StrStrI(instr,"j") == NULL && StrStrI(instr,"call") == NULL && StrStrI(instr,"ret") == NULL)
			{
				addr = addr + LengthDisassembleEx(info->hProcess,(LPVOID)addr);
			}
			else
			{
				found = true;
			}
		}
		SetBPX(addr,UE_BREAKPOINT,BPHandler);
		//printf("Breakpoing set for instr %s at %x \n",instr,api_addr);
	}
	else
	{
		found = false;
	}
	return found;
}

//Entry point handler for the program, reads the APIS to be hooked and applies them through the SetAPIBP fucntion.
void __stdcall OnEntry()
{
	ep = GetContextData(UE_EIP);
	int buf_len = 500;
    LPSTR buf = (LPSTR)calloc(buf_len,sizeof(char));
	LPSTR exclude_buf = (LPSTR)calloc(buf_len,sizeof(char));
	int temp = strlen(buf);
	FILE * f_api_file = fopen(api_file,"r");
	FILE * f_exclude_file = NULL;
	if (addr_exclude_file == NULL)
	{
		if(debug_mode == true)
			printf("***###LOGGING### - Address exclude file could not be found.***\n");
	}
	else
	{
		f_exclude_file = fopen(addr_exclude_file,"r");
		int x = 0;
		while (fgets(exclude_buf,buf_len/sizeof(*exclude_buf), f_exclude_file) && x < MAX_WHITELIST)
		{
			LPSTR exclude_lib = strtok(exclude_buf,",");
			LPSTR exclude_addr = strtok(NULL,",");
			if(exclude_lib != NULL && exclude_addr != NULL)
			{
				bool dll_failed =false;
				if(exclude_addr[strlen(exclude_addr)-1] == 0x0a)
					exclude_addr[strlen(exclude_addr)-1] = 0x00;
				if(exclude_lib[strlen(exclude_lib)-1] == 0x0a)
					exclude_lib[strlen(exclude_lib)-1] = 0x00;
				long exclude_this_addr = strtol(exclude_addr,NULL,16);
				exclude_libs[x] = (LPSTR)calloc(buf_len,sizeof(char));
				exclude_addrs[x] = exclude_this_addr;
				strcpy_s(exclude_libs[x],buf_len,exclude_lib);
				if(debug_mode == true)
					printf("***###LOGGING### - Read exclude addr entry: %s %x***\n",exclude_lib,exclude_this_addr);
			}
			x++;
		}
	}

	if (f_api_file == NULL)
	{
		printf("***###FATAL### - API's to hook file could not be found.***\n");
		StopDebug();
		exit(1);
	}
	else
	{
		while (fgets(buf,buf_len/sizeof(*buf), f_api_file)!=NULL)
		{
			LPSTR lib_name = strtok(buf,",");
			LPSTR api_name = strtok(NULL,",");
			bool dll_failed =false;
			if(api_name[strlen(api_name)-1] == 0x0a)
				api_name[strlen(api_name)-1] = 0x00;
			if(LoadLibrary(lib_name) == NULL)
			{
				if(debug_mode == true)
					printf("***###FAILED### - Could not load %s locally.***\n",lib_name);
			}
			else
			{
				if(debug_mode == true)
					printf("***###LOGGING### - Loaded %s locally.***\n",lib_name);
				if(LibrarianGetLibraryInfo(lib_name) == NULL)
				{
					if(RemoteLoadLibrary(info->hProcess,lib_name,false) == NULL)
					{
						if(debug_mode == true)
							printf("***###FAILED### - Could not load %s into the remote address space.***\n",lib_name);
						dll_failed = true;
					}
				}
				else
				{
					if(debug_mode == true)
						printf("***###LOGGING### - %s already loaded within the remote address space.***\n",lib_name);
				}
				if(!dll_failed)
				{
					ULONG_PTR api_addr = (ULONG_PTR)ImporterGetRemoteAPIAddressEx(lib_name,api_name);
					if(SetAPIBP(api_addr))
					{
						if(debug_mode == true)
							printf("***###LOGGING### - Breakpoint set for %s %x.***\n",api_name,api_addr);
					}
					else
					{
						if(debug_mode == true)
							printf("***###FAILED### - Breakpoint could not be set for %s.***\n",api_name);
					}
				}
			}
		}
	}
	if(f_api_file)
		fclose(f_api_file);
	if(f_exclude_file)
		fclose(f_exclude_file);
	if(buf)
		free(buf);
}

//Inits the debugger library and callbacks.
int main(int argc, char * argv[])
{

	int x = 1;
	LPSTR program = NULL;
	LPSTR working = NULL;
	LPSTR cmd_line = NULL;
	while (x < argc)
	{
		if(StrCmpI(argv[x],"--program") == 0 || StrCmpI(argv[x],"-p") ==0)
		{
			program = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--working_dir") == 0 || StrCmpI(argv[x],"-w") == 0)
		{
			working = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--cmd_line") == 0 || StrCmpI(argv[x],"-c") == 0)
		{
			cmd_line = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--api_list") == 0 || StrCmpI(argv[x],"-a") == 0)
		{
			api_file = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--addr_exclude") == 0 || StrCmpI(argv[x],"-e") == 0)
		{
			addr_exclude_file = argv[x+1];
		}
		else if(StrCmpI(argv[x],"--debug_mode") == 0 || StrCmpI(argv[x],"-d") == 0)
		{
			debug_mode = true;
			x--;
		}
		x = x+2;
	}
	if(program != NULL && working != NULL && api_file != NULL)
	{
		info = (PROCESS_INFORMATION *)InitDebugEx(program,cmd_line,working,OnEntry);
		SetCustomHandler(UE_CH_SINGLESTEP,OnSingleStepException);
		SetBPXOptions(UE_BREAKPOINT_INT3);
		if(info == NULL)
		{
			printf("***###FATAL### - Failed init.***\n");
		}
		else
		{
			DebugLoop();
		}
		printf("***###LOGGING### - Exiting.***\n");
	}
	else
	{
		printf("\nFlyOnAShellcode V3.0.\n");
		printf("Sec-Mini-Projects (2015) under the MIT License - See \"LICENSE\" for Details.\n");
		printf("TitanEngine is used as the debugging engine in this program - http://reversinglabs.com/open-source/titanengine.html.\n");
		printf("***WARNING*** - This program will RUN the supplied executable and malicious input file. USE ONLY IN MALWARE RESEARCH LABS.\n\n");
		printf("Note 1 - This program can be anywhere from very stable to very unstable depending on which APIs are hooked.\n\n");
		printf("Note 2 - Avoid manually navigating the \"File Open\", etc dialogs from within the program will help eliminate crashes.\n\n");
		printf("Usage: \n--program[-p] <Program full path and name> \n--working_dir[-w] <working directory> \n--cmd_line[-c] <Command line arguments> (Optional)\n--api_list[-a] <API hook list path and name> \n--addr_exclude[-e] <address exclude file> (Optional)\n--debug_mode[-d] - Enables debug mode(Optional)\n\n");
		printf("Usage - API library/names format is for each API call a new line matching (without the quotes) \"<lib name>,<api name>\"\n\n");
	}
	//printf("%x",argc);
	return 0;
}

<|endoftext|>


<commit_before>/***********************************************************************
    created:    Tue Feb 17 2009
    author:     Henri I Hyyryläinen (based on code by Paul D Turner)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/RendererModules/Ogre/GeometryBuffer.h"
#include "CEGUI/RendererModules/Ogre/Texture.h"
#include "CEGUI/RendererModules/Ogre/ShaderWrapper.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/RenderEffect.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/ShaderParameterBindings.h"

#include <OgreRenderSystem.h>
#include <OgreHardwareBufferManager.h>
#include <OgreQuaternion.h>
#include <OgreManualObject.h>
#include <OgreRenderOperation.h>
#include <OgreSceneManager.h>

#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"

#define FLOATS_PER_TEXTURED     9
#define FLOATS_PER_COLOURED     7

// Start of CEGUI namespace section
namespace CEGUI
{

OgreGeometryBuffer::OgreGeometryBuffer(OgreRenderer& owner,
    Ogre::RenderSystem& rs, CEGUI::RefCounted<RenderMaterial> renderMaterial) :
    GeometryBuffer(renderMaterial),
    d_owner(owner),
    d_renderSystem(rs),
    d_clipRect(0, 0, 0, 0),
    d_expectedData(MT_INVALID),
    d_dataAppended(false),
    d_matrix(1.0),
    d_previousAlphaValue(-1.f)
{

}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::~OgreGeometryBuffer()
{
    cleanUpVertexAttributes();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::draw() const
{
    if (d_vertexData.empty())
        return;

    if (d_dataAppended)
        syncVertexData();

    if (d_hwBuffer.isNull())
        return;

    // setup clip region
    if (d_clippingActive)
    {
        setScissorRects();
    }

    // Update the matrix
    updateMatrix();

    CEGUI::ShaderParameterBindings* shaderParameterBindings =
        (*d_renderMaterial).getShaderParamBindings();

    // Set the ModelViewProjection matrix in the bindings
    shaderParameterBindings->setParameter("modelViewPerspMatrix", d_matrix);

    if (d_alpha != d_previousAlphaValue)
    {
        d_previousAlphaValue = d_alpha;

        shaderParameterBindings->setParameter("alphaPercentage",
            d_previousAlphaValue);
    }

    // activate the desired blending mode
    d_owner.bindBlendMode(d_blendMode);

    const int pass_count = d_effect ? d_effect->getPassCount() : 1;
    for (int pass = 0; pass < pass_count; ++pass)
    {
        // set up RenderEffect
        if (d_effect)
            d_effect->performPreRenderFunctions(pass);

        setTextureStates();

        //Prepare for the rendering process according to the used render material
        d_renderMaterial->prepareForRendering();

        // draw the geometry
        d_renderSystem._render(d_renderOp);
    }

    // clean up RenderEffect
    if (d_effect)
        d_effect->performPostRenderFunctions();

    // Disable clipping after rendering
    if (d_clippingActive)
    {
        d_renderSystem.setScissorTest(false);
    }

    updateRenderTargetData(d_owner.getActiveRenderTarget());
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setClippingRegion(const Rectf& region)
{
    d_clipRect.top(ceguimax(0.0f, region.top()));
    d_clipRect.bottom(ceguimax(0.0f, region.bottom()));
    d_clipRect.left(ceguimax(0.0f, region.left()));
    d_clipRect.right(ceguimax(0.0f, region.right()));
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendGeometry(const float* vertex_data, std::size_t array_size)
{
    GeometryBuffer::appendGeometry(vertex_data, array_size);

    d_dataAppended = true;
}

void OgreGeometryBuffer::syncVertexData() const
{
    if (!d_dataAppended)
        return;

    // Make sure that our vertex buffer is large enough
    size_t current_size;

    if (!d_hwBuffer.isNull() &&
        (current_size = d_hwBuffer->getNumVertices()) < d_vertexCount)
    {
        size_t new_size = current_size;

        // Reallocate the buffer to be large enough
        while(new_size < d_vertexCount)
            new_size *= 2;

        setVertexBuffer(new_size);
    }

    // copy vertex data into the Ogre hardware buffer
    if (d_vertexCount > 0)
    {
        if (d_hwBuffer.isNull())
        {

            setVertexBuffer(d_vertexCount);
        }

        void* copy_target = d_hwBuffer->lock(
            Ogre::HardwareVertexBuffer::HBL_DISCARD);

        assert(copy_target && "Ogre vertex buffer is invalid");

        std::memcpy(copy_target, &d_vertexData[0], d_vertexData.size()*
            sizeof(float));

        d_hwBuffer->unlock();
    }

    // Update rendering for the new vertices
    d_renderOp.vertexData->vertexStart = 0;
    d_renderOp.vertexData->vertexCount = d_vertexCount;

    d_dataAppended = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::updateMatrix() const
{
    d_matrixValid = false;
    if ( !d_matrixValid || !isRenderTargetDataValid(d_owner.getActiveRenderTarget()) )
    {
        // Apply the view projection matrix to the model matrix and save the result as cached matrix
        d_matrix = getModelMatrix() * d_owner.getViewProjectionMatrix();

        //If necessary: transpose
        const OgreShaderWrapper* ogreShader = static_cast<const OgreShaderWrapper*>(d_renderMaterial->getShaderWrapper());
        if (ogreShader->getVertexParameters()->getTransposeMatrices())
            d_matrix = glm::transpose(d_matrix);

        d_matrixValid = true;
    }
}

//----------------------------------------------------------------------------//
glm::mat4 OgreGeometryBuffer::getModelMatrix() const
{
    // translation to position geometry and offset to pivot point
    Ogre::Matrix4 trans;

    trans.makeTrans(d_translation.x + d_pivot.x,
                    d_translation.y + d_pivot.y,
                    d_translation.z + d_pivot.z);

    // rotation
    Ogre::Matrix4 rot(Ogre::Quaternion(d_rotation.w, d_rotation.x, d_rotation.y, d_rotation.z));

    // translation to remove rotation pivot offset
    Ogre::Matrix4 inv_pivot_trans;
    inv_pivot_trans.makeTrans(-d_pivot.x, -d_pivot.y, -d_pivot.z);

    // calculate final matrix
    Ogre::Matrix4 finalMatrix = trans * rot * inv_pivot_trans;

    //Reinterpret as glm matrix
    return OgreRenderer::ogreToGlmMatrix(finalMatrix);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::finaliseVertexAttributes(MANUALOBJECT_TYPE type)
{
    d_expectedData = type;

    // basic initialisation of render op
    d_renderOp.vertexData = OGRE_NEW Ogre::VertexData();
    d_renderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
    d_renderOp.useIndexes = false;

    // Setup our render operation to match the type
    Ogre::VertexDeclaration* vd = d_renderOp.vertexData->vertexDeclaration;

    switch(d_expectedData)
    {
    case MT_COLOURED:
    {
        vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);

        vd->addElement(0, sizeof(float)*3, Ogre::VET_COLOUR,
            Ogre::VES_DIFFUSE);
        break;
    }
    case MT_TEXTURED:
    {
        vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);

        vd->addElement(0, sizeof(float)*3, Ogre::VET_FLOAT4,
            Ogre::VES_DIFFUSE);

        vd->addElement(0, sizeof(float)*(3+4), Ogre::VET_FLOAT2,
            Ogre::VES_TEXTURE_COORDINATES);
        break;
    }
    default:
        CEGUI_THROW(RendererException(
            "Unknown d_expectedData type."));
    }

}

void OgreGeometryBuffer::setVertexBuffer(size_t count) const
{
    // We first check if some other buffer has already allocated a suited buffer
    // for us
    Ogre::HardwareVertexBufferSharedPtr already_created =
        d_owner.getVertexBuffer(count);

    if (!already_created.isNull())
    {

        d_hwBuffer = already_created;

    } else {

        // Create the a new vertex buffer
        d_hwBuffer = Ogre::HardwareBufferManager::getSingleton().
            createVertexBuffer(getVertexAttributeElementCount()*sizeof(float), count,
            Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
            false);
    }

    if (d_hwBuffer.isNull())
    {
        CEGUI_THROW(RendererException("Failed to create Ogre vertex buffer, "
            "probably because the vertex layout is invalid."));
    }

    // bind the vertex buffer for rendering
    d_renderOp.vertexData->vertexBufferBinding->setBinding(0, d_hwBuffer);
}

void OgreGeometryBuffer::cleanUpVertexAttributes()
{
    OGRE_DELETE d_renderOp.vertexData;
    d_renderOp.vertexData = 0;

    // Store the hardware buffer so that other instances can use it later
    d_owner.returnVertexBuffer(d_hwBuffer);

    d_hwBuffer.setNull();
}

// ------------------------------------ //
void OgreGeometryBuffer::setScissorRects() const
{
    d_renderSystem.setScissorTest(true, static_cast<size_t>(d_clipRect.left()),
        static_cast<size_t>(d_clipRect.top()), static_cast<size_t>(d_clipRect.right()), static_cast<size_t>(d_clipRect.bottom()));
}

// ------------------------------------ //
void OgreGeometryBuffer::reset()
{
    d_vertexData.clear();
    d_clippingActive = true;
}

// ------------------------------------ //
void OgreGeometryBuffer::setTextureStates() const
{
    using namespace Ogre;
    // Set texture states
    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_NONE);
}

// ------------------------------------ //
int OgreGeometryBuffer::getVertexAttributeElementCount() const
{
    switch(d_expectedData)
    {
        case MT_COLOURED:
            return FLOATS_PER_COLOURED;
            break;
        case MT_TEXTURED:
            return FLOATS_PER_TEXTURED;
            break;
        default:
            return 0;
            break;
    }
}

} // End of  CEGUI namespace section
<commit_msg>MOD: Using the matrix function that OpenGL and Direct3D use<commit_after>/***********************************************************************
    created:    Tue Feb 17 2009
    author:     Henri I Hyyryläinen (based on code by Paul D Turner)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/RendererModules/Ogre/GeometryBuffer.h"
#include "CEGUI/RendererModules/Ogre/Texture.h"
#include "CEGUI/RendererModules/Ogre/ShaderWrapper.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/RenderEffect.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/ShaderParameterBindings.h"

#include <OgreRenderSystem.h>
#include <OgreHardwareBufferManager.h>
#include <OgreQuaternion.h>
#include <OgreManualObject.h>
#include <OgreRenderOperation.h>
#include <OgreSceneManager.h>

#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"

#define FLOATS_PER_TEXTURED     9
#define FLOATS_PER_COLOURED     7

// Start of CEGUI namespace section
namespace CEGUI
{

OgreGeometryBuffer::OgreGeometryBuffer(OgreRenderer& owner,
    Ogre::RenderSystem& rs, CEGUI::RefCounted<RenderMaterial> renderMaterial) :
    GeometryBuffer(renderMaterial),
    d_owner(owner),
    d_renderSystem(rs),
    d_clipRect(0, 0, 0, 0),
    d_expectedData(MT_INVALID),
    d_dataAppended(false),
    d_matrix(1.0),
    d_previousAlphaValue(-1.f)
{

}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::~OgreGeometryBuffer()
{
    cleanUpVertexAttributes();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::draw() const
{
    if (d_vertexData.empty())
        return;

    if (d_dataAppended)
        syncVertexData();

    if (d_hwBuffer.isNull())
        return;

    // setup clip region
    if (d_clippingActive)
    {
        setScissorRects();
    }

    // Update the matrix
    updateMatrix();

    CEGUI::ShaderParameterBindings* shaderParameterBindings =
        (*d_renderMaterial).getShaderParamBindings();

    // Set the ModelViewProjection matrix in the bindings
    shaderParameterBindings->setParameter("modelViewPerspMatrix", d_matrix);

    if (d_alpha != d_previousAlphaValue)
    {
        d_previousAlphaValue = d_alpha;

        shaderParameterBindings->setParameter("alphaPercentage",
            d_previousAlphaValue);
    }

    // activate the desired blending mode
    d_owner.bindBlendMode(d_blendMode);

    const int pass_count = d_effect ? d_effect->getPassCount() : 1;
    for (int pass = 0; pass < pass_count; ++pass)
    {
        // set up RenderEffect
        if (d_effect)
            d_effect->performPreRenderFunctions(pass);

        setTextureStates();

        //Prepare for the rendering process according to the used render material
        d_renderMaterial->prepareForRendering();

        // draw the geometry
        d_renderSystem._render(d_renderOp);
    }

    // clean up RenderEffect
    if (d_effect)
        d_effect->performPostRenderFunctions();

    // Disable clipping after rendering
    if (d_clippingActive)
    {
        d_renderSystem.setScissorTest(false);
    }

    updateRenderTargetData(d_owner.getActiveRenderTarget());
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setClippingRegion(const Rectf& region)
{
    d_clipRect.top(ceguimax(0.0f, region.top()));
    d_clipRect.bottom(ceguimax(0.0f, region.bottom()));
    d_clipRect.left(ceguimax(0.0f, region.left()));
    d_clipRect.right(ceguimax(0.0f, region.right()));
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendGeometry(const float* vertex_data, std::size_t array_size)
{
    GeometryBuffer::appendGeometry(vertex_data, array_size);

    d_dataAppended = true;
}

void OgreGeometryBuffer::syncVertexData() const
{
    if (!d_dataAppended)
        return;

    // Make sure that our vertex buffer is large enough
    size_t current_size;

    if (!d_hwBuffer.isNull() &&
        (current_size = d_hwBuffer->getNumVertices()) < d_vertexCount)
    {
        size_t new_size = current_size;

        // Reallocate the buffer to be large enough
        while(new_size < d_vertexCount)
            new_size *= 2;

        setVertexBuffer(new_size);
    }

    // copy vertex data into the Ogre hardware buffer
    if (d_vertexCount > 0)
    {
        if (d_hwBuffer.isNull())
        {

            setVertexBuffer(d_vertexCount);
        }

        void* copy_target = d_hwBuffer->lock(
            Ogre::HardwareVertexBuffer::HBL_DISCARD);

        assert(copy_target && "Ogre vertex buffer is invalid");

        std::memcpy(copy_target, &d_vertexData[0], d_vertexData.size()*
            sizeof(float));

        d_hwBuffer->unlock();
    }

    // Update rendering for the new vertices
    d_renderOp.vertexData->vertexStart = 0;
    d_renderOp.vertexData->vertexCount = d_vertexCount;

    d_dataAppended = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::updateMatrix() const
{
    d_matrixValid = false;
    if ( !d_matrixValid || !isRenderTargetDataValid(d_owner.getActiveRenderTarget()) )
    {
        // Apply the view projection matrix to the model matrix and save the result as cached matrix
        d_matrix = glm::transpose( glm::transpose( d_owner.getViewProjectionMatrix()) * getModelMatrix());

        //If necessary: transpose
        const OgreShaderWrapper* ogreShader = static_cast<const OgreShaderWrapper*>(d_renderMaterial->getShaderWrapper());
        if (ogreShader->getVertexParameters()->getTransposeMatrices())
            d_matrix = glm::transpose(d_matrix);

        d_matrixValid = true;
    }
}

//----------------------------------------------------------------------------//
glm::mat4 OgreGeometryBuffer::getModelMatrix() const
{
    glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), d_translation + d_pivot);

    const glm::mat4 scale_matrix(glm::scale(glm::mat4(1.0f), d_scale));
    modelMatrix *= glm::mat4_cast(d_rotation) * scale_matrix;

    const glm::mat4 translMatrix = glm::translate(glm::mat4(1.0f), -d_pivot);
    modelMatrix *=  translMatrix * d_customTransform;

    return modelMatrix;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::finaliseVertexAttributes(MANUALOBJECT_TYPE type)
{
    d_expectedData = type;

    // basic initialisation of render op
    d_renderOp.vertexData = OGRE_NEW Ogre::VertexData();
    d_renderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
    d_renderOp.useIndexes = false;

    // Setup our render operation to match the type
    Ogre::VertexDeclaration* vd = d_renderOp.vertexData->vertexDeclaration;

    switch(d_expectedData)
    {
    case MT_COLOURED:
    {
        vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);

        vd->addElement(0, sizeof(float)*3, Ogre::VET_COLOUR,
            Ogre::VES_DIFFUSE);
        break;
    }
    case MT_TEXTURED:
    {
        vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);

        vd->addElement(0, sizeof(float)*3, Ogre::VET_FLOAT4,
            Ogre::VES_DIFFUSE);

        vd->addElement(0, sizeof(float)*(3+4), Ogre::VET_FLOAT2,
            Ogre::VES_TEXTURE_COORDINATES);
        break;
    }
    default:
        CEGUI_THROW(RendererException(
            "Unknown d_expectedData type."));
    }

}

void OgreGeometryBuffer::setVertexBuffer(size_t count) const
{
    // We first check if some other buffer has already allocated a suited buffer
    // for us
    Ogre::HardwareVertexBufferSharedPtr already_created =
        d_owner.getVertexBuffer(count);

    if (!already_created.isNull())
    {

        d_hwBuffer = already_created;

    } else {

        // Create the a new vertex buffer
        d_hwBuffer = Ogre::HardwareBufferManager::getSingleton().
            createVertexBuffer(getVertexAttributeElementCount()*sizeof(float), count,
            Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
            false);
    }

    if (d_hwBuffer.isNull())
    {
        CEGUI_THROW(RendererException("Failed to create Ogre vertex buffer, "
            "probably because the vertex layout is invalid."));
    }

    // bind the vertex buffer for rendering
    d_renderOp.vertexData->vertexBufferBinding->setBinding(0, d_hwBuffer);
}

void OgreGeometryBuffer::cleanUpVertexAttributes()
{
    OGRE_DELETE d_renderOp.vertexData;
    d_renderOp.vertexData = 0;

    // Store the hardware buffer so that other instances can use it later
    d_owner.returnVertexBuffer(d_hwBuffer);

    d_hwBuffer.setNull();
}

// ------------------------------------ //
void OgreGeometryBuffer::setScissorRects() const
{
    d_renderSystem.setScissorTest(true, static_cast<size_t>(d_clipRect.left()),
        static_cast<size_t>(d_clipRect.top()), static_cast<size_t>(d_clipRect.right()), static_cast<size_t>(d_clipRect.bottom()));
}

// ------------------------------------ //
void OgreGeometryBuffer::reset()
{
    d_vertexData.clear();
    d_clippingActive = true;
}

// ------------------------------------ //
void OgreGeometryBuffer::setTextureStates() const
{
    using namespace Ogre;
    // Set texture states
    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_NONE);
}

// ------------------------------------ //
int OgreGeometryBuffer::getVertexAttributeElementCount() const
{
    switch(d_expectedData)
    {
        case MT_COLOURED:
            return FLOATS_PER_COLOURED;
            break;
        case MT_TEXTURED:
            return FLOATS_PER_TEXTURED;
            break;
        default:
            return 0;
            break;
    }
}

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>/*  -*- mode: C++; c-file-style: "gnu" -*-
    qgpgmebackend.cpp

    This file is part of libkleopatra, the KDE keymanagement library
    Copyright (c) 2004 Klarlvdalens Datakonsult AB

    Libkleopatra is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.

    Libkleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "qgpgmebackend.h"

#include "qgpgmecryptoconfig.h"
#include "cryptplugwrapper.h"

#include <gpgmepp/context.h>
#include <gpgmepp/engineinfo.h>

#include <klocale.h>

#include <qfile.h>
#include <qstring.h>

Kleo::QGpgMEBackend::QGpgMEBackend()
  : Kleo::CryptoBackend(),
    mCryptoConfig( 0 ),
    mOpenPGPProtocol( 0 ),
    mSMIMEProtocol( 0 )
{

}

Kleo::QGpgMEBackend::~QGpgMEBackend() {
  delete mCryptoConfig; mCryptoConfig = 0;
  delete mOpenPGPProtocol; mOpenPGPProtocol = 0;
  delete mSMIMEProtocol; mSMIMEProtocol = 0;
}

QString Kleo::QGpgMEBackend::name() const {
  return "gpgme";
}

QString Kleo::QGpgMEBackend::displayName() const {
  return i18n( "GpgME" );
}

Kleo::CryptoConfig * Kleo::QGpgMEBackend::config() const {
  if ( !mCryptoConfig )
    mCryptoConfig = new QGpgMECryptoConfig();
  return mCryptoConfig;
}

static bool check( GpgME::Context::Protocol proto, QString * reason ) {
  if ( !GpgME::checkEngine( proto ) )
    return true;
  if ( !reason )
    return false;
  // error, check why:
  const GpgME::EngineInfo ei = GpgME::engineInfo( proto );
  if ( ei.isNull() )
    *reason = i18n("GPGME was compiled without support for %1").arg( proto == GpgME::Context::CMS ? "S/MIME" : "OpenPGP" );
  else if ( ei.fileName() && !ei.version() )
    *reason = i18n("Engine %1 is not installed properly").arg( QFile::decodeName( ei.fileName() ) );
  else if ( ei.fileName() && ei.version() && ei.requiredVersion() )
    *reason = i18n("Engine %1 version %2 installed, "
		   "but at least version %3 is required")
      .arg( QFile::decodeName( ei.fileName() ), ei.version(), ei.requiredVersion() );
  else
    *reason = i18n("Unknown problem with engine for protocol %1").arg( proto == GpgME::Context::CMS ? "S/MIME" : "OpenPGP" );
  return false;
}

bool Kleo::QGpgMEBackend::checkForOpenPGP( QString * reason ) const {
  return check( GpgME::Context::OpenPGP, reason );
}

bool Kleo::QGpgMEBackend::checkForSMIME( QString * reason ) const {
  return check( GpgME::Context::CMS, reason );
}

Kleo::CryptoBackend::Protocol * Kleo::QGpgMEBackend::openpgp() const {
  if ( !mOpenPGPProtocol )
    if ( checkForOpenPGP() )
      mOpenPGPProtocol = new CryptPlugWrapper( "gpg", "openpgp" );
  return mOpenPGPProtocol;
}

Kleo::CryptoBackend::Protocol * Kleo::QGpgMEBackend::smime() const {
  if ( !mSMIMEProtocol )
    if ( checkForSMIME() )
      mSMIMEProtocol = new CryptPlugWrapper( "gpgsm", "smime" );
  return mSMIMEProtocol;
}
<commit_msg>CVS_SILENT The end of a sentence SHOULD be marked with a dot, no?<commit_after>/*  -*- mode: C++; c-file-style: "gnu" -*-
    qgpgmebackend.cpp

    This file is part of libkleopatra, the KDE keymanagement library
    Copyright (c) 2004 Klarlvdalens Datakonsult AB

    Libkleopatra is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.

    Libkleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "qgpgmebackend.h"

#include "qgpgmecryptoconfig.h"
#include "cryptplugwrapper.h"

#include <gpgmepp/context.h>
#include <gpgmepp/engineinfo.h>

#include <klocale.h>

#include <qfile.h>
#include <qstring.h>

Kleo::QGpgMEBackend::QGpgMEBackend()
  : Kleo::CryptoBackend(),
    mCryptoConfig( 0 ),
    mOpenPGPProtocol( 0 ),
    mSMIMEProtocol( 0 )
{

}

Kleo::QGpgMEBackend::~QGpgMEBackend() {
  delete mCryptoConfig; mCryptoConfig = 0;
  delete mOpenPGPProtocol; mOpenPGPProtocol = 0;
  delete mSMIMEProtocol; mSMIMEProtocol = 0;
}

QString Kleo::QGpgMEBackend::name() const {
  return "gpgme";
}

QString Kleo::QGpgMEBackend::displayName() const {
  return i18n( "GpgME" );
}

Kleo::CryptoConfig * Kleo::QGpgMEBackend::config() const {
  if ( !mCryptoConfig )
    mCryptoConfig = new QGpgMECryptoConfig();
  return mCryptoConfig;
}

static bool check( GpgME::Context::Protocol proto, QString * reason ) {
  if ( !GpgME::checkEngine( proto ) )
    return true;
  if ( !reason )
    return false;
  // error, check why:
  const GpgME::EngineInfo ei = GpgME::engineInfo( proto );
  if ( ei.isNull() )
    *reason = i18n("GPGME was compiled without support for %1.").arg( proto == GpgME::Context::CMS ? "S/MIME" : "OpenPGP" );
  else if ( ei.fileName() && !ei.version() )
    *reason = i18n("Engine %1 is not installed properly.").arg( QFile::decodeName( ei.fileName() ) );
  else if ( ei.fileName() && ei.version() && ei.requiredVersion() )
    *reason = i18n("Engine %1 version %2 installed, "
		   "but at least version %3 is required.")
      .arg( QFile::decodeName( ei.fileName() ), ei.version(), ei.requiredVersion() );
  else
    *reason = i18n("Unknown problem with engine for protocol %1.").arg( proto == GpgME::Context::CMS ? "S/MIME" : "OpenPGP" );
  return false;
}

bool Kleo::QGpgMEBackend::checkForOpenPGP( QString * reason ) const {
  return check( GpgME::Context::OpenPGP, reason );
}

bool Kleo::QGpgMEBackend::checkForSMIME( QString * reason ) const {
  return check( GpgME::Context::CMS, reason );
}

Kleo::CryptoBackend::Protocol * Kleo::QGpgMEBackend::openpgp() const {
  if ( !mOpenPGPProtocol )
    if ( checkForOpenPGP() )
      mOpenPGPProtocol = new CryptPlugWrapper( "gpg", "openpgp" );
  return mOpenPGPProtocol;
}

Kleo::CryptoBackend::Protocol * Kleo::QGpgMEBackend::smime() const {
  if ( !mSMIMEProtocol )
    if ( checkForSMIME() )
      mSMIMEProtocol = new CryptPlugWrapper( "gpgsm", "smime" );
  return mSMIMEProtocol;
}
<|endoftext|>


<commit_before>
#include "stdafx.h"
#include "boundingbox.h"

using namespace graphic;

cBoundingBox::cBoundingBox()
{
	SetBoundingBox(Vector3(0,0,0), Vector3(1,1,1), Quaternion(0,0,0,1));
}

cBoundingBox::cBoundingBox(const cCube &cube)
{
	operator=(cube);
}

cBoundingBox::cBoundingBox(const Vector3 &center, const Vector3 &scale, const Quaternion &q )
{
	SetBoundingBox(center, scale, q);
}

void cBoundingBox::SetBoundingBox(const Vector3 &center, const Vector3 &scale, const Quaternion &q)
{
	m_bbox = BoundingOrientedBox(*(XMFLOAT3*)&center, *(XMFLOAT3*)&scale, *(XMFLOAT4*)&q);
}

void cBoundingBox::SetBoundingBox(const Transform &tfm)
{
	m_bbox = BoundingOrientedBox(*(XMFLOAT3*)&tfm.pos, *(XMFLOAT3*)&tfm.scale, *(XMFLOAT4*)&tfm.rot);
}

void cBoundingBox::SetBoundingBox(const sMinMax &minMax)
{
	const Vector3 center = (minMax._min + minMax._max) / 2;
	const Vector3 scale = Vector3(abs(minMax._min.x - minMax._max.x)*0.5f
		, abs(minMax._min.y - minMax._max.y)*0.5f
		, abs(minMax._min.z - minMax._max.z)*0.5f);
	SetBoundingBox(center, scale, Quaternion());
}

void cBoundingBox::SetLineBoundingBox(const Vector3 &p0, const Vector3 &p1, const float width)
{
	Vector3 v = p1 - p0;
	const float len = v.Length();
	v.Normalize();

	m_bbox.Extents = XMFLOAT3(width, width, len/2.f);
	m_bbox.Center = *(XMFLOAT3*)&((p0 + p1) / 2.f);

	Quaternion q(Vector3(0, 0, 1), v);
	m_bbox.Orientation = *(XMFLOAT4*)&q;
}

void SATtest( const Vector3& axis, const Vector3 ptSet[8], float& minAlong, float& maxAlong )
{
	minAlong = (float)HUGE, maxAlong = (float)-HUGE;
	for( u_int i = 0 ; i < 8; i++ )
	{
		// just dot it to get the min/max along this axis.
		float dotVal = ptSet[ i].DotProduct( axis ) ;
		if( dotVal < minAlong )  minAlong=dotVal;
		if( dotVal > maxAlong )  maxAlong=dotVal;
	}
}

inline bool isBetweenOrdered( float val, float lowerBound, float upperBound ) {
	return lowerBound <= val && val <= upperBound ;
}

bool overlaps( float min1, float max1, float min2, float max2 )
{
	return isBetweenOrdered( min2, min1, max1 ) || isBetweenOrdered( min1, min2, max2 ) ;
}

// OBB vs OBB 浹ó.
bool cBoundingBox::Collision( cBoundingBox &box )
{
	const ContainmentType result = m_bbox.Contains(box.m_bbox);
	switch (result)
	{
	case INTERSECTS:
	case CONTAINS:
		return true;
	}
	return false;
}

// OBB vs Sphere 浹ó
bool cBoundingBox::Collision(cBoundingSphere &sphere)
{
	const ContainmentType result = m_bbox.Contains(sphere.m_bsphere);
	switch (result)
	{
	case INTERSECTS:
	case CONTAINS:
		return true;
	}
	return false;
}

// X-Y, Z-Y Plane Collision Test
// return Collision Position
bool cBoundingBox::Collision2D(cBoundingSphere &sphere
	, OUT Vector3 *out //= NULL
)
{
	Vector3 N = Vector3(1, 0, 0) * *(Quaternion*)&m_bbox.Orientation;
	Plane planeZY(N, Center());
	const float dist = planeZY.Collision(sphere.GetPos());
	if (abs(dist) > sphere.GetRadius())
		return false;

	// Collision Position
	if (out)
		*out = sphere.GetPos() + -planeZY.N * dist;

	return true;
}

// ŷ Ǿٸ true Ѵ.
// orig, dir : ray .
bool cBoundingBox::Pick(const Vector3 &orig, const Vector3 &dir
	, OUT float *distance //=NULL
)
{
	XMVECTOR o = XMLoadFloat3((XMFLOAT3*)&orig);
	XMVECTOR d = XMLoadFloat3((XMFLOAT3*)&dir);
	float dist = 0;
	if (!m_bbox.Intersects(o, d, dist))
		return false;

	if (distance)
		*distance = dist;

	return true;
}

bool cBoundingBox::Pick(const Ray &ray
	, OUT float *distance //= NULL
)
{
	return Pick(ray.orig, ray.dir, distance);
}

// Ҵ .
cBoundingBox& cBoundingBox::operator=(const cCube &cube)
{
	*this = cube.m_boundingBox;
	*this *= cube.GetWorldMatrix();
	return *this;
}

// ڽ  Ѵ.
Vector3 cBoundingBox::Center() const
{
	return *(Vector3*)&m_bbox.Center;
}

void cBoundingBox::Scale(const Vector3 &scale)
{
	m_bbox.Extents = *(XMFLOAT3*)&scale;
}

// return x,y,z dimension
Vector3 cBoundingBox::GetDimension() const
{
	Vector3 scale = *(Vector3*)&m_bbox.Extents;
	Quaternion q = *(Quaternion*)&m_bbox.Orientation;
	scale *= q.GetMatrix();
	return scale * 2.f;
	//return (*(Vector3*)&m_bbox.Extents) * 2.f;
}

//void cBoundingBox::MultiyplyTransform(const Matrix44 &tm)
//{
//	XMVECTOR center = XMLoadFloat3(&m_bbox.Center);
//	XMVECTOR pos = XMLoadFloat3((XMFLOAT3*)&tm.GetPosition());
//	center += pos;
//
//	XMVECTOR extents = XMLoadFloat3(&m_bbox.Extents);
//	XMVECTOR scale = XMLoadFloat3((XMFLOAT3*)&tm.GetScale());
//	extents *= scale;
//
//	XMVECTOR q = XMLoadFloat4(&m_bbox.Orientation);
//	XMMATRIX rot = XMMatrixRotationQuaternion(q);
//	XMMATRIX rot2 = XMLoadFloat4x4((XMFLOAT4X4*)&tm);
//
//	rot *= rot2;
//	q = XMQuaternionRotationMatrix(rot);
//
//	XMStoreFloat3(&m_bbox.Center, center);
//	XMStoreFloat3(&m_bbox.Extents, extents);
//	XMStoreFloat4(&m_bbox.Orientation, q);
//}

XMMATRIX cBoundingBox::GetMatrixXM() const
{
	XMVECTOR q = XMLoadFloat4(&m_bbox.Orientation);
	XMMATRIX rot = XMMatrixRotationQuaternion(q);
	XMMATRIX tm = XMMatrixScaling(m_bbox.Extents.x, m_bbox.Extents.y, m_bbox.Extents.z) * rot
		* XMMatrixTranslation(m_bbox.Center.x, m_bbox.Center.y, m_bbox.Center.z);
	return tm;
}

Matrix44 cBoundingBox::GetMatrix() const
{
	Matrix44 S;
	S.SetScale(Vector3(m_bbox.Extents.x, m_bbox.Extents.y, m_bbox.Extents.z));
	Quaternion q = *(Quaternion*)&m_bbox.Orientation;
	Matrix44 R = q.GetMatrix();
	Matrix44 T;
	T.SetTranslate(Vector3(m_bbox.Center.x, m_bbox.Center.y, m_bbox.Center.z));
	return S * R * T;
}

Transform cBoundingBox::GetTransform() const
{
	Transform tfm;
	tfm.pos = *(Vector3*)&m_bbox.Center;
	tfm.scale = *(Vector3*)&m_bbox.Extents;
	tfm.rot = *(Quaternion*)&m_bbox.Orientation;
	return tfm;
}

Vector3 cBoundingBox::BoundingPoint(const Vector3 &pos)
{
	Vector3 reVal;

	const Vector3 center = *(Vector3*)&m_bbox.Center;
	const Vector3 extents = *(Vector3*)&m_bbox.Extents;
	const Vector3 _min = center - extents;
	const Vector3 _max = center + extents;

	reVal = _min.Maximum(pos);
	reVal = _max.Minimum(reVal);
	return reVal;
}

cBoundingBox cBoundingBox::operator * (const XMMATRIX &rhs)
{
	// BoundingOrientedBox::Transform() Լ x,y,z Scaling Ҷ  Ѵ.
	//  ڵ BoundingBox pos,scale,rot  ó ̿ؼ ȯѴ.
	// 2017-11-20, jjuiddong

	Transform tfm1;
	tfm1.pos = *(Vector3*)&m_bbox.Center;
	tfm1.scale = *(Vector3*)&m_bbox.Extents;
	tfm1.rot = *(Quaternion*)&m_bbox.Orientation;

	XMMATRIX m = tfm1.GetMatrixXM() * rhs;
	Transform temp = m;

	BoundingOrientedBox bbox;
	bbox.Center = *(XMFLOAT3*)&temp.pos;
	bbox.Extents = *(XMFLOAT3*)&temp.scale;
	bbox.Orientation = *(XMFLOAT4*)&temp.rot;

	cBoundingBox ret;
	ret.m_bbox = bbox;
	return ret;
}

cBoundingBox cBoundingBox::operator * (const Matrix44 &rhs)
{
	cBoundingBox bbox = *this;
	bbox *= rhs;
	return bbox;
}

const cBoundingBox& cBoundingBox::operator *= (const Matrix44 &rhs)
{
	*this = operator*(rhs.GetMatrixXM());
	return *this;
}

const cBoundingBox& cBoundingBox::operator *= (const XMMATRIX &rhs)
{
	*this = operator*(rhs);
	return *this;
}
<commit_msg>update boundingbox 2d collision<commit_after>
#include "stdafx.h"
#include "boundingbox.h"

using namespace graphic;

cBoundingBox::cBoundingBox()
{
	SetBoundingBox(Vector3(0,0,0), Vector3(1,1,1), Quaternion(0,0,0,1));
}

cBoundingBox::cBoundingBox(const cCube &cube)
{
	operator=(cube);
}

cBoundingBox::cBoundingBox(const Vector3 &center, const Vector3 &scale, const Quaternion &q )
{
	SetBoundingBox(center, scale, q);
}

void cBoundingBox::SetBoundingBox(const Vector3 &center, const Vector3 &scale, const Quaternion &q)
{
	m_bbox = BoundingOrientedBox(*(XMFLOAT3*)&center, *(XMFLOAT3*)&scale, *(XMFLOAT4*)&q);
}

void cBoundingBox::SetBoundingBox(const Transform &tfm)
{
	m_bbox = BoundingOrientedBox(*(XMFLOAT3*)&tfm.pos, *(XMFLOAT3*)&tfm.scale, *(XMFLOAT4*)&tfm.rot);
}

void cBoundingBox::SetBoundingBox(const sMinMax &minMax)
{
	const Vector3 center = (minMax._min + minMax._max) / 2;
	const Vector3 scale = Vector3(abs(minMax._min.x - minMax._max.x)*0.5f
		, abs(minMax._min.y - minMax._max.y)*0.5f
		, abs(minMax._min.z - minMax._max.z)*0.5f);
	SetBoundingBox(center, scale, Quaternion());
}

void cBoundingBox::SetLineBoundingBox(const Vector3 &p0, const Vector3 &p1, const float width)
{
	Vector3 v = p1 - p0;
	const float len = v.Length();
	v.Normalize();

	m_bbox.Extents = XMFLOAT3(width, width, len/2.f);
	m_bbox.Center = *(XMFLOAT3*)&((p0 + p1) / 2.f);

	Quaternion q(Vector3(0, 0, 1), v);
	m_bbox.Orientation = *(XMFLOAT4*)&q;
}

void SATtest( const Vector3& axis, const Vector3 ptSet[8], float& minAlong, float& maxAlong )
{
	minAlong = (float)HUGE, maxAlong = (float)-HUGE;
	for( u_int i = 0 ; i < 8; i++ )
	{
		// just dot it to get the min/max along this axis.
		float dotVal = ptSet[ i].DotProduct( axis ) ;
		if( dotVal < minAlong )  minAlong=dotVal;
		if( dotVal > maxAlong )  maxAlong=dotVal;
	}
}

inline bool isBetweenOrdered( float val, float lowerBound, float upperBound ) {
	return lowerBound <= val && val <= upperBound ;
}

bool overlaps( float min1, float max1, float min2, float max2 )
{
	return isBetweenOrdered( min2, min1, max1 ) || isBetweenOrdered( min1, min2, max2 ) ;
}

// OBB vs OBB 浹ó.
bool cBoundingBox::Collision( cBoundingBox &box )
{
	const ContainmentType result = m_bbox.Contains(box.m_bbox);
	switch (result)
	{
	case INTERSECTS:
	case CONTAINS:
		return true;
	}
	return false;
}

// OBB vs Sphere 浹ó
bool cBoundingBox::Collision(cBoundingSphere &sphere)
{
	const ContainmentType result = m_bbox.Contains(sphere.m_bsphere);
	switch (result)
	{
	case INTERSECTS:
	case CONTAINS:
		return true;
	}
	return false;
}

// X-Y, Z-Y Plane Collision Test
// return Collision Position
bool cBoundingBox::Collision2D(cBoundingSphere &sphere
	, OUT Vector3 *out //= NULL
)
{
	const Quaternion &q = *(Quaternion*)&m_bbox.Orientation;
	const Vector3 zyN = Vector3(1, 0, 0) * q;
	Plane planeZY(zyN, Center());
	const float distZY = planeZY.Collision(sphere.GetPos());
	const float r1 = m_bbox.Extents.x;

	const Vector3 xyN = Vector3(0, 0, 1) * q;
	Plane planeXY(xyN, Center());
	const float distXY = planeXY.Collision(sphere.GetPos());
	const float r2 = m_bbox.Extents.z;

	const float d1 = (abs(distZY) - r1);
	const float d2 = (abs(distXY) - r2);
	if (d1 > sphere.GetRadius())
		return false;
	if (d2 > sphere.GetRadius())
		return false;

	const bool isZy = abs(d1) < abs(d2);
	const float dist = isZy? abs(distZY) : abs(distXY);
	const float r = isZy ? r1 : r2;

	const Vector3 N = isZy ? zyN : xyN;
	const float minDist = isZy ? distZY : distXY;
	const float rr = (minDist < 0) ? -(dist - r) : dist - r;

	// Collision Position
	if (out)
		*out = sphere.GetPos() + -N * rr;

	return true;
}

// ŷ Ǿٸ true Ѵ.
// orig, dir : ray .
bool cBoundingBox::Pick(const Vector3 &orig, const Vector3 &dir
	, OUT float *distance //=NULL
)
{
	XMVECTOR o = XMLoadFloat3((XMFLOAT3*)&orig);
	XMVECTOR d = XMLoadFloat3((XMFLOAT3*)&dir);
	float dist = 0;
	if (!m_bbox.Intersects(o, d, dist))
		return false;

	if (distance)
		*distance = dist;

	return true;
}

bool cBoundingBox::Pick(const Ray &ray
	, OUT float *distance //= NULL
)
{
	return Pick(ray.orig, ray.dir, distance);
}

// Ҵ .
cBoundingBox& cBoundingBox::operator=(const cCube &cube)
{
	*this = cube.m_boundingBox;
	*this *= cube.GetWorldMatrix();
	return *this;
}

// ڽ  Ѵ.
Vector3 cBoundingBox::Center() const
{
	return *(Vector3*)&m_bbox.Center;
}

void cBoundingBox::Scale(const Vector3 &scale)
{
	m_bbox.Extents = *(XMFLOAT3*)&scale;
}

// return x,y,z dimension
Vector3 cBoundingBox::GetDimension() const
{
	Vector3 scale = *(Vector3*)&m_bbox.Extents;
	Quaternion q = *(Quaternion*)&m_bbox.Orientation;
	scale *= q.GetMatrix();
	return scale * 2.f;
	//return (*(Vector3*)&m_bbox.Extents) * 2.f;
}

//void cBoundingBox::MultiyplyTransform(const Matrix44 &tm)
//{
//	XMVECTOR center = XMLoadFloat3(&m_bbox.Center);
//	XMVECTOR pos = XMLoadFloat3((XMFLOAT3*)&tm.GetPosition());
//	center += pos;
//
//	XMVECTOR extents = XMLoadFloat3(&m_bbox.Extents);
//	XMVECTOR scale = XMLoadFloat3((XMFLOAT3*)&tm.GetScale());
//	extents *= scale;
//
//	XMVECTOR q = XMLoadFloat4(&m_bbox.Orientation);
//	XMMATRIX rot = XMMatrixRotationQuaternion(q);
//	XMMATRIX rot2 = XMLoadFloat4x4((XMFLOAT4X4*)&tm);
//
//	rot *= rot2;
//	q = XMQuaternionRotationMatrix(rot);
//
//	XMStoreFloat3(&m_bbox.Center, center);
//	XMStoreFloat3(&m_bbox.Extents, extents);
//	XMStoreFloat4(&m_bbox.Orientation, q);
//}

XMMATRIX cBoundingBox::GetMatrixXM() const
{
	XMVECTOR q = XMLoadFloat4(&m_bbox.Orientation);
	XMMATRIX rot = XMMatrixRotationQuaternion(q);
	XMMATRIX tm = XMMatrixScaling(m_bbox.Extents.x, m_bbox.Extents.y, m_bbox.Extents.z) * rot
		* XMMatrixTranslation(m_bbox.Center.x, m_bbox.Center.y, m_bbox.Center.z);
	return tm;
}

Matrix44 cBoundingBox::GetMatrix() const
{
	Matrix44 S;
	S.SetScale(Vector3(m_bbox.Extents.x, m_bbox.Extents.y, m_bbox.Extents.z));
	Quaternion q = *(Quaternion*)&m_bbox.Orientation;
	Matrix44 R = q.GetMatrix();
	Matrix44 T;
	T.SetTranslate(Vector3(m_bbox.Center.x, m_bbox.Center.y, m_bbox.Center.z));
	return S * R * T;
}

Transform cBoundingBox::GetTransform() const
{
	Transform tfm;
	tfm.pos = *(Vector3*)&m_bbox.Center;
	tfm.scale = *(Vector3*)&m_bbox.Extents;
	tfm.rot = *(Quaternion*)&m_bbox.Orientation;
	return tfm;
}

Vector3 cBoundingBox::BoundingPoint(const Vector3 &pos)
{
	Vector3 reVal;

	const Vector3 center = *(Vector3*)&m_bbox.Center;
	const Vector3 extents = *(Vector3*)&m_bbox.Extents;
	const Vector3 _min = center - extents;
	const Vector3 _max = center + extents;

	reVal = _min.Maximum(pos);
	reVal = _max.Minimum(reVal);
	return reVal;
}

cBoundingBox cBoundingBox::operator * (const XMMATRIX &rhs)
{
	// BoundingOrientedBox::Transform() Լ x,y,z Scaling Ҷ  Ѵ.
	//  ڵ BoundingBox pos,scale,rot  ó ̿ؼ ȯѴ.
	// 2017-11-20, jjuiddong

	Transform tfm1;
	tfm1.pos = *(Vector3*)&m_bbox.Center;
	tfm1.scale = *(Vector3*)&m_bbox.Extents;
	tfm1.rot = *(Quaternion*)&m_bbox.Orientation;

	XMMATRIX m = tfm1.GetMatrixXM() * rhs;
	Transform temp = m;

	BoundingOrientedBox bbox;
	bbox.Center = *(XMFLOAT3*)&temp.pos;
	bbox.Extents = *(XMFLOAT3*)&temp.scale;
	bbox.Orientation = *(XMFLOAT4*)&temp.rot;

	cBoundingBox ret;
	ret.m_bbox = bbox;
	return ret;
}

cBoundingBox cBoundingBox::operator * (const Matrix44 &rhs)
{
	cBoundingBox bbox = *this;
	bbox *= rhs;
	return bbox;
}

const cBoundingBox& cBoundingBox::operator *= (const Matrix44 &rhs)
{
	*this = operator*(rhs.GetMatrixXM());
	return *this;
}

const cBoundingBox& cBoundingBox::operator *= (const XMMATRIX &rhs)
{
	*this = operator*(rhs);
	return *this;
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "nodes/values/characteristic_curve.h"

#include <QDebug>
#include <QDoubleSpinBox>
#include <QPushButton>
#include <QSpinBox>
#include <QTableWidget>
#include <QtCharts/QChart>
#include <QtCharts/QLineSeries>
#include <QtCharts/QValueAxis>

#include "elements/values/characteristic_curve.h"
#include "nodes/values/characteristic_curve/editor_window.h"
#include "nodes/values/characteristic_curve/point.h"
#include "spaghetti/package.h"

using namespace QtCharts;

using ElementType = spaghetti::elements::values::CharacteristicCurve;

namespace spaghetti::nodes::values {

CharacteristicCurve::CharacteristicCurve()
  : m_widget{ new QChart }
  , m_series{ new QLineSeries }
  , m_xAxis{ new QValueAxis }
  , m_yAxis{ new QValueAxis }
  , m_lastPoint{ -1.0, -1.0 }
  , m_current{ new characteristic_curve::Point{ m_widget } }
  , m_editor{ new characteristic_curve::EditorWindow{ this } }
{
  setCentralWidget(m_widget);

  m_widget->legend()->hide();
  m_widget->setTheme(QChart::ChartThemeDark);
  m_widget->addAxis(m_xAxis, Qt::AlignBottom);
  m_widget->addAxis(m_yAxis, Qt::AlignLeft);
  m_widget->addSeries(m_series);

  m_series->attachAxis(m_xAxis);
  m_series->attachAxis(m_yAxis);

  QFont labelsFont{};
  labelsFont.setPixelSize(10);
  m_xAxis->setLabelsFont(labelsFont);
  m_yAxis->setLabelsFont(labelsFont);

  m_current->setType(characteristic_curve::Point::Type::eCurrent);
}

CharacteristicCurve::~CharacteristicCurve()
{
  delete m_editor;
}

void CharacteristicCurve::refreshCentralWidget()
{
  if (!m_element) return;

  updateCurrentValue(false);
  calculateBoundingRect();
}

void CharacteristicCurve::showProperties()
{
  showCommonProperties();
  showIOProperties(IOSocketsType::eInputs);
  showIOProperties(IOSocketsType::eOutputs);

  propertiesInsertTitle("X range");

  int currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  auto const scaler = static_cast<ElementType *const>(m_element);

  QTableWidgetItem *item{};
  item = new QTableWidgetItem{ "Min" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const xMinValue = new QDoubleSpinBox{};
  xMinValue->setRange(-10000.0, 10000.0);
  xMinValue->setValue(static_cast<qreal>(scaler->xMinimum()));
  m_properties->setCellWidget(currentIndex, 1, xMinValue);

  QObject::connect(xMinValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement = static_cast<ElementType *const>(m_element);
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setXMinimum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Max" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const xMaxValue = new QDoubleSpinBox{};
  xMaxValue->setRange(-10000.0, 10000.0);
  xMaxValue->setValue(static_cast<qreal>(scaler->xMaximum()));
  m_properties->setCellWidget(currentIndex, 1, xMaxValue);

  QObject::connect(xMaxValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement{ static_cast<ElementType *const>(m_element) };
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setXMaximum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  propertiesInsertTitle("Y range");

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Min" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const yMinValue = new QDoubleSpinBox{};
  yMinValue->setRange(-10000.0, 10000.0);
  yMinValue->setValue(static_cast<qreal>(scaler->yMinimum()));
  m_properties->setCellWidget(currentIndex, 1, yMinValue);

  QObject::connect(yMinValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement{ static_cast<ElementType *const>(m_element) };
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setYMinimum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Max" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const yMaxValue = new QDoubleSpinBox{};
  yMaxValue->setRange(-10000.0, 10000.0);
  yMaxValue->setValue(static_cast<qreal>(scaler->yMaximum()));
  m_properties->setCellWidget(currentIndex, 1, yMaxValue);

  QObject::connect(yMaxValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement{ static_cast<ElementType *const>(m_element) };
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setYMaximum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  propertiesInsertTitle("Series");

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Count" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const countValue = new QSpinBox{};
  countValue->setRange(2, 100);
  countValue->setValue(static_cast<int32_t>(scaler->seriesCount()));
  m_properties->setCellWidget(currentIndex, 1, countValue);

  QObject::connect(countValue, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int a_value) {
    auto const scalerElement{ static_cast<ElementType *const>(m_element) };
    auto const package = scalerElement->package();
    package->pauseDispatchThread();
    scalerElement->setSeriesCount(static_cast<size_t>(a_value));
    synchronizeFromElement();
    package->resumeDispatchThread();
  });

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  auto const editSeries = new QPushButton{ "Edit Series" };
  m_properties->setSpan(currentIndex, 0, 1, 2);
  m_properties->setCellWidget(currentIndex, 0, editSeries);

  QObject::connect(editSeries, &QPushButton::clicked, [this] { open(); });
}

void CharacteristicCurve::elementSet()
{
  constexpr qreal const CHART_SIZE{ 400. };
  m_widget->resize({ CHART_SIZE, CHART_SIZE });

  synchronizeFromElement();
}

bool CharacteristicCurve::open()
{
  m_editor->synchronizeFromNode();
  m_editor->show();
  return true;
}

void CharacteristicCurve::synchronizeFromElement()
{
  assert(m_element);

  auto const element = static_cast<ElementType *>(m_element);

  m_xAxis->setMin(static_cast<qreal>(element->xMinimum()));
  m_xAxis->setMax(static_cast<qreal>(element->xMaximum()));
  m_xAxis->setTitleText(inputs()[0]->name());
  m_yAxis->setMin(static_cast<qreal>(element->yMinimum()));
  m_yAxis->setMax(static_cast<qreal>(element->yMaximum()));
  m_yAxis->setTitleText(outputs()[0]->name());

  m_series->clear();

  auto &series = element->series();
  for (auto &point : series) m_series->append(static_cast<qreal>(point.x), static_cast<qreal>(point.y));

  updateCurrentValue(true);
}

void CharacteristicCurve::updateCurrentValue(bool const a_force)
{
  auto const element = static_cast<ElementType *>(m_element);
  auto const POINT = element->value();
  QPointF const position{ static_cast<qreal>(POINT.x), static_cast<qreal>(POINT.y) };

  if (a_force || position != m_lastPoint) {
    m_current->setPos(m_widget->mapToPosition(position));
    calculateBoundingRect();
    m_lastPoint = position;
    if (m_editor->isVisible())
      m_editor->setValue(static_cast<qreal>(POINT.x));
  }
}

} // namespace spaghetti::nodes::values
<commit_msg>Use m_editor->exec() instead of show()<commit_after>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "nodes/values/characteristic_curve.h"

#include <QDebug>
#include <QDoubleSpinBox>
#include <QPushButton>
#include <QSpinBox>
#include <QTableWidget>
#include <QtCharts/QChart>
#include <QtCharts/QLineSeries>
#include <QtCharts/QValueAxis>

#include "elements/values/characteristic_curve.h"
#include "nodes/values/characteristic_curve/editor_window.h"
#include "nodes/values/characteristic_curve/point.h"
#include "spaghetti/package.h"

using namespace QtCharts;

using ElementType = spaghetti::elements::values::CharacteristicCurve;

namespace spaghetti::nodes::values {

CharacteristicCurve::CharacteristicCurve()
  : m_widget{ new QChart }
  , m_series{ new QLineSeries }
  , m_xAxis{ new QValueAxis }
  , m_yAxis{ new QValueAxis }
  , m_lastPoint{ -1.0, -1.0 }
  , m_current{ new characteristic_curve::Point{ m_widget } }
  , m_editor{ new characteristic_curve::EditorWindow{ this } }
{
  setCentralWidget(m_widget);

  m_widget->legend()->hide();
  m_widget->setTheme(QChart::ChartThemeDark);
  m_widget->addAxis(m_xAxis, Qt::AlignBottom);
  m_widget->addAxis(m_yAxis, Qt::AlignLeft);
  m_widget->addSeries(m_series);

  m_series->attachAxis(m_xAxis);
  m_series->attachAxis(m_yAxis);

  QFont labelsFont{};
  labelsFont.setPixelSize(10);
  m_xAxis->setLabelsFont(labelsFont);
  m_yAxis->setLabelsFont(labelsFont);

  m_current->setType(characteristic_curve::Point::Type::eCurrent);
}

CharacteristicCurve::~CharacteristicCurve()
{
  delete m_editor;
}

void CharacteristicCurve::refreshCentralWidget()
{
  if (!m_element) return;

  updateCurrentValue(false);
  calculateBoundingRect();
}

void CharacteristicCurve::showProperties()
{
  showCommonProperties();
  showIOProperties(IOSocketsType::eInputs);
  showIOProperties(IOSocketsType::eOutputs);

  propertiesInsertTitle("X range");

  int currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  auto const scaler = static_cast<ElementType *const>(m_element);

  QTableWidgetItem *item{};
  item = new QTableWidgetItem{ "Min" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const xMinValue = new QDoubleSpinBox{};
  xMinValue->setRange(-10000.0, 10000.0);
  xMinValue->setValue(static_cast<qreal>(scaler->xMinimum()));
  m_properties->setCellWidget(currentIndex, 1, xMinValue);

  QObject::connect(xMinValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement = static_cast<ElementType *const>(m_element);
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setXMinimum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Max" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const xMaxValue = new QDoubleSpinBox{};
  xMaxValue->setRange(-10000.0, 10000.0);
  xMaxValue->setValue(static_cast<qreal>(scaler->xMaximum()));
  m_properties->setCellWidget(currentIndex, 1, xMaxValue);

  QObject::connect(xMaxValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement{ static_cast<ElementType *const>(m_element) };
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setXMaximum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  propertiesInsertTitle("Y range");

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Min" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const yMinValue = new QDoubleSpinBox{};
  yMinValue->setRange(-10000.0, 10000.0);
  yMinValue->setValue(static_cast<qreal>(scaler->yMinimum()));
  m_properties->setCellWidget(currentIndex, 1, yMinValue);

  QObject::connect(yMinValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement{ static_cast<ElementType *const>(m_element) };
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setYMinimum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Max" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const yMaxValue = new QDoubleSpinBox{};
  yMaxValue->setRange(-10000.0, 10000.0);
  yMaxValue->setValue(static_cast<qreal>(scaler->yMaximum()));
  m_properties->setCellWidget(currentIndex, 1, yMaxValue);

  QObject::connect(yMaxValue, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged),
                   [this](qreal a_value) {
                     auto const scalerElement{ static_cast<ElementType *const>(m_element) };
                     auto const package = scalerElement->package();
                     package->pauseDispatchThread();
                     scalerElement->setYMaximum(static_cast<float>(a_value));
                     synchronizeFromElement();
                     package->resumeDispatchThread();
                   });

  propertiesInsertTitle("Series");

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  item = new QTableWidgetItem{ "Count" };
  item->setFlags(item->flags() & ~Qt::ItemIsEditable);
  m_properties->setItem(currentIndex, 0, item);

  auto const countValue = new QSpinBox{};
  countValue->setRange(2, 100);
  countValue->setValue(static_cast<int32_t>(scaler->seriesCount()));
  m_properties->setCellWidget(currentIndex, 1, countValue);

  QObject::connect(countValue, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int a_value) {
    auto const scalerElement{ static_cast<ElementType *const>(m_element) };
    auto const package = scalerElement->package();
    package->pauseDispatchThread();
    scalerElement->setSeriesCount(static_cast<size_t>(a_value));
    synchronizeFromElement();
    package->resumeDispatchThread();
  });

  currentIndex = m_properties->rowCount();
  m_properties->insertRow(currentIndex);

  auto const editSeries = new QPushButton{ "Edit Series" };
  m_properties->setSpan(currentIndex, 0, 1, 2);
  m_properties->setCellWidget(currentIndex, 0, editSeries);

  QObject::connect(editSeries, &QPushButton::clicked, [this] { open(); });
}

void CharacteristicCurve::elementSet()
{
  constexpr qreal const CHART_SIZE{ 400. };
  m_widget->resize({ CHART_SIZE, CHART_SIZE });

  synchronizeFromElement();
}

bool CharacteristicCurve::open()
{
  m_editor->synchronizeFromNode();
  m_editor->exec();
  return true;
}

void CharacteristicCurve::synchronizeFromElement()
{
  assert(m_element);

  auto const element = static_cast<ElementType *>(m_element);

  m_xAxis->setMin(static_cast<qreal>(element->xMinimum()));
  m_xAxis->setMax(static_cast<qreal>(element->xMaximum()));
  m_xAxis->setTitleText(inputs()[0]->name());
  m_yAxis->setMin(static_cast<qreal>(element->yMinimum()));
  m_yAxis->setMax(static_cast<qreal>(element->yMaximum()));
  m_yAxis->setTitleText(outputs()[0]->name());

  m_series->clear();

  auto &series = element->series();
  for (auto &point : series) m_series->append(static_cast<qreal>(point.x), static_cast<qreal>(point.y));

  updateCurrentValue(true);
}

void CharacteristicCurve::updateCurrentValue(bool const a_force)
{
  auto const element = static_cast<ElementType *>(m_element);
  auto const POINT = element->value();
  QPointF const position{ static_cast<qreal>(POINT.x), static_cast<qreal>(POINT.y) };

  if (a_force || position != m_lastPoint) {
    m_current->setPos(m_widget->mapToPosition(position));
    calculateBoundingRect();
    m_lastPoint = position;
    if (m_editor->isVisible())
      m_editor->setValue(static_cast<qreal>(POINT.x));
  }
}

} // namespace spaghetti::nodes::values
<|endoftext|>