<commit_before>/*
* Copyright (c) 2015-2018 JlnWntr (jlnwntr@gmail.com)
*
* 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.
*/
#ifndef LUA_ADAPTER_H
#define LUA_ADAPTER_H

#include <iostream>
#include <lua.hpp>

typedef int (*Lua_callback_function)(lua_State *L);

class LuaAdapter {

public:
  /**
  * Default constructor
  * Hint: Calls init()!
  * @param lua (re-)uses an existing lua_state. See example in test.cpp at
  * testCFunction()
  */
  LuaAdapter(lua_State *const lua = nullptr);

  /**
  * This constructor inits lua and loads a .lua-file directly.
  * @param filename .lua-file to load
  */
  LuaAdapter(const std::string &filename);

  /**
  * Destructor
  */
  ~LuaAdapter();

  /**
  * Initialize Lua and all its libs
  * Does NOT load any lua-sourcefile
  * LuaAdapter calls this internally single-handed.
  */
  void Init();

  /**
  * Calls lua_pcall(Lua, 0, 0, 0)
  * @return true on success, false on error
  */
  bool Eval();

  /**
  * Loads a *.lua-sourcefile
  * Set your default (local) lua-vars before you call this function!
  * @param filename lua-file to load
  * @return true on success, false on error
  */
  bool Load(const char *filename);
  bool Load(const std::string &filename);

  /**
  * Gets the value of a variable.
  * @param name of the variable inside loaded lua state
  * @param result value is saved in this variable
  * @return true on success, false on error
  */
  bool Get(const char *name, int &result);
  bool Get(const char *name, std::string &result);
  bool Get(const char *name, double &result);
  bool Get(const char *name, float &result);
  bool Get(const char *name, bool &result);

  /**
  * Opens a lua-table
  * @param name Name of the table inside loaded lua state
  * @return true on success, false on error
  */
  bool OpenTable(const char *name);
  bool OpenTable(const std::string &name) {
    return this->OpenTable(name.c_str());
  }

  /**
  * Opens a table(-field) inside a table
  * @param name Name of the table inside the opened table
  * @return true on success, false on error
  */
  bool OpenNestedTable(const char *name);
  bool OpenNestedTable(const std::string &name) {
    return this->OpenNestedTable(name.c_str());
  }

  /**
  * Get the length of the current (opened) table
  * [tables with integer keys and without 'nil-holes']
  * @return the length of the table
  */
  unsigned short int GetTableLength();

  /**
  * Gets a field from an opened table
  * @param name Name of the field
  * @param result value of the field
  * @return true on success, false on error
  */
  bool GetField(const char *name, std::string &result);
  bool GetField(const char *name, int &result);

  /**
  * Gets a field from an opened table
  * @param i i-th field (starting at 1)
  * @param result value of the field
  * @return true on success, false on error
  */
  bool GetField(unsigned short int i, int &result);
  bool GetField(unsigned short int i, double &result);
  bool GetField(unsigned short int i, float &result);
  bool GetField(unsigned short int i, std::string &result);

  /**
  * Gets a ("2D"-)field value from an opened table.
  * NOTE: DO NOT CALL openNestedTable(name) for this!
  * Example: identity ={
  *               {1, 0, 0},
  *               {0, 1, 0},
  *               {0, 0, 1},
  *           }
  * @param j row
  * @param i col
  * @param result value of the field
  * @return true on success, false on error
  */
  bool GetNestedField(unsigned short int j, unsigned short int i,
                      double &result);
  bool GetNestedField(unsigned short int j, unsigned short int i,
                      float &result);
  bool GetNestedField(unsigned short int j, unsigned short int i, int &result);
  bool GetNestedField(unsigned short int j, unsigned short int i,
                      std::string &result);
  /**
      * Like above but gets a ("3D"-)field value.
  * @param k row
      * @param j col
      * @param i inner table
      * @param result value
      * @return true on success, false on error
      */
  bool GetNestedField(unsigned short int k, unsigned short int j,
                      unsigned short int i, int &result);

  /**
  * Sets the value of global lua-var.
  * @param name of the variable
  * @param value the var's value
  * @return true on success, false on error
  */
  bool Set(const char *name, const char *value);
  bool Set(const char *name, int value);
  bool Set(const char *name, const double value);
  bool Set(const char *name, const float value);
  bool Set(const char *name, const bool value);

  /**
  * Closes a table
  * Call this function after every opening (and use) of a table!
  * (Prevents "stack-smashing".)
  */
  void CloseTable() { return this->Pop(1); }

  /**
      * Execute any string
  * @param string to execute, for example "test = io.read()"
      */
  bool DoString(const char *string) { return luaL_dostring(this->Lua, string); }

  /**
  * Calls a lua-function
  * @param name of the lua-function
  * @param argc number of arguments passed to the lua-function
  * @param args function-arguments
  * @param result new value from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const unsigned short int argc,
                    int args[], int &result);
  /**
  * Calls a lua-function
  * @param functionName of the lua-function
  * @param string a string-argument
  * @param length of this string
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const char *const string, const size_t length);

  /**
  * Calls a lua-function
  * @param functionName of the lua-function
  * @param string a string-argument
  * @param length of this string
  * @param result new value (string) from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const char *const string, size_t &length, std::string &result);

  /**
  * Calls a lua-function
  * @param name of the lua-function
  * @param result new value from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, double &result);

  /**
  * Calls a lua-function
  * @param name of the lua-function
  * @param arg argument of the lua-function
  * @param result new value (string) from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const std::string arg, std::string &result);

  /**
  * Makes a C-/C++-function-call available for lua
  * (it's called pushFunction(), but you're not 'incrementing' the stack)
  * @param function C-/C++-function
  * @param functionName name of the function
  * @return true on success, false on error
  */
  bool PushFunction(Lua_callback_function function, const char *functionName);

  /**
  * Push data on the lua-stack. (Mind the stack!)
  * @param number number to push
  * @param string string to push
  * @return true on success, false on error
  */
  bool Push(double number);
  bool Push(const char *string);
  bool Push(const std::string &string) { return this->Push(string.c_str()); }

  /**
  * Resets Lua's internal stack
  * @return true on success, false on error
  */
  bool Flush();

  /**
  * After calling debug(),
  * lua-adapter will print out debug-information for each following
  * function-call.
  */
  void Debug() { this->SetLogMode(true); }
  /**
  * Set debug output on or off
  * @param mode if mode==true, see debug()
  */
  void SetLogMode(bool mode);

  /**
  * Pops i entries from Lua's internal stack
  * @param i number of entries
  */
  void Pop(signed short int i = 1) { lua_pop(this->Lua, i); }

  /**
  * Gets the stack position
  * @return the stack position
  */
  int GetTop() const { return lua_gettop(this->Lua); }

  /**
  * Gets the value-type of the current stack position
  * @return the type
  */
  int GetType() const { return lua_type(this->Lua, 0); }

  /**
  * "Closes" the loaded *.lua-sourcefile
  * This function is called by the destructor of this class!
  * */
  void Close();

private:
  lua_State *Lua;
  bool print;
  bool single;
  const std::string outputPrefix;

  /**
  * Gets a field from an opened table and puts its value on the stack
  * @param name Name of the field
  * @return true on success, false on error
  */
  bool GetField(const char *name);

  /**
  * Gets the i-th (nested) field from an opened table
  * @param i the i-th field
  * @return true on success, false on error
  */
  bool GetI(unsigned short int i);

  /**
  * Gets the value of a globally loaded lua-variable
  * @param name Name of the vairable
  * @return true on success, false on error
  */
  bool GetGlobal(const char *name);
};
#endif
<commit_msg>Fix C2679 on MSVC<commit_after>/*
* Copyright (c) 2015-2018 JlnWntr (jlnwntr@gmail.com)
*
* 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.
*/
#ifndef LUA_ADAPTER_H
#define LUA_ADAPTER_H

#include <iostream>
#include <string>
#include <lua.hpp>

typedef int (*Lua_callback_function)(lua_State *L);

class LuaAdapter {

public:
  /**
  * Default constructor
  * Hint: Calls init()!
  * @param lua (re-)uses an existing lua_state. See example in test.cpp at
  * testCFunction()
  */
  LuaAdapter(lua_State *const lua = nullptr);

  /**
  * This constructor inits lua and loads a .lua-file directly.
  * @param filename .lua-file to load
  */
  LuaAdapter(const std::string &filename);

  /**
  * Destructor
  */
  ~LuaAdapter();

  /**
  * Initialize Lua and all its libs
  * Does NOT load any lua-sourcefile
  * LuaAdapter calls this internally single-handed.
  */
  void Init();

  /**
  * Calls lua_pcall(Lua, 0, 0, 0)
  * @return true on success, false on error
  */
  bool Eval();

  /**
  * Loads a *.lua-sourcefile
  * Set your default (local) lua-vars before you call this function!
  * @param filename lua-file to load
  * @return true on success, false on error
  */
  bool Load(const char *filename);
  bool Load(const std::string &filename);

  /**
  * Gets the value of a variable.
  * @param name of the variable inside loaded lua state
  * @param result value is saved in this variable
  * @return true on success, false on error
  */
  bool Get(const char *name, int &result);
  bool Get(const char *name, std::string &result);
  bool Get(const char *name, double &result);
  bool Get(const char *name, float &result);
  bool Get(const char *name, bool &result);

  /**
  * Opens a lua-table
  * @param name Name of the table inside loaded lua state
  * @return true on success, false on error
  */
  bool OpenTable(const char *name);
  bool OpenTable(const std::string &name) {
    return this->OpenTable(name.c_str());
  }

  /**
  * Opens a table(-field) inside a table
  * @param name Name of the table inside the opened table
  * @return true on success, false on error
  */
  bool OpenNestedTable(const char *name);
  bool OpenNestedTable(const std::string &name) {
    return this->OpenNestedTable(name.c_str());
  }

  /**
  * Get the length of the current (opened) table
  * [tables with integer keys and without 'nil-holes']
  * @return the length of the table
  */
  unsigned short int GetTableLength();

  /**
  * Gets a field from an opened table
  * @param name Name of the field
  * @param result value of the field
  * @return true on success, false on error
  */
  bool GetField(const char *name, std::string &result);
  bool GetField(const char *name, int &result);

  /**
  * Gets a field from an opened table
  * @param i i-th field (starting at 1)
  * @param result value of the field
  * @return true on success, false on error
  */
  bool GetField(unsigned short int i, int &result);
  bool GetField(unsigned short int i, double &result);
  bool GetField(unsigned short int i, float &result);
  bool GetField(unsigned short int i, std::string &result);

  /**
  * Gets a ("2D"-)field value from an opened table.
  * NOTE: DO NOT CALL openNestedTable(name) for this!
  * Example: identity ={
  *               {1, 0, 0},
  *               {0, 1, 0},
  *               {0, 0, 1},
  *           }
  * @param j row
  * @param i col
  * @param result value of the field
  * @return true on success, false on error
  */
  bool GetNestedField(unsigned short int j, unsigned short int i,
                      double &result);
  bool GetNestedField(unsigned short int j, unsigned short int i,
                      float &result);
  bool GetNestedField(unsigned short int j, unsigned short int i, int &result);
  bool GetNestedField(unsigned short int j, unsigned short int i,
                      std::string &result);
  /**
      * Like above but gets a ("3D"-)field value.
  * @param k row
      * @param j col
      * @param i inner table
      * @param result value
      * @return true on success, false on error
      */
  bool GetNestedField(unsigned short int k, unsigned short int j,
                      unsigned short int i, int &result);

  /**
  * Sets the value of global lua-var.
  * @param name of the variable
  * @param value the var's value
  * @return true on success, false on error
  */
  bool Set(const char *name, const char *value);
  bool Set(const char *name, int value);
  bool Set(const char *name, const double value);
  bool Set(const char *name, const float value);
  bool Set(const char *name, const bool value);

  /**
  * Closes a table
  * Call this function after every opening (and use) of a table!
  * (Prevents "stack-smashing".)
  */
  void CloseTable() { return this->Pop(1); }

  /**
      * Execute any string
  * @param string to execute, for example "test = io.read()"
      */
  bool DoString(const char *string) { return luaL_dostring(this->Lua, string); }

  /**
  * Calls a lua-function
  * @param name of the lua-function
  * @param argc number of arguments passed to the lua-function
  * @param args function-arguments
  * @param result new value from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const unsigned short int argc,
                    int args[], int &result);
  /**
  * Calls a lua-function
  * @param functionName of the lua-function
  * @param string a string-argument
  * @param length of this string
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const char *const string, const size_t length);

  /**
  * Calls a lua-function
  * @param functionName of the lua-function
  * @param string a string-argument
  * @param length of this string
  * @param result new value (string) from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const char *const string, size_t &length, std::string &result);

  /**
  * Calls a lua-function
  * @param name of the lua-function
  * @param result new value from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, double &result);

  /**
  * Calls a lua-function
  * @param name of the lua-function
  * @param arg argument of the lua-function
  * @param result new value (string) from the lua-function
  * @return true on success, false on error
  */
  bool CallFunction(const char *functionName, const std::string arg, std::string &result);

  /**
  * Makes a C-/C++-function-call available for lua
  * (it's called pushFunction(), but you're not 'incrementing' the stack)
  * @param function C-/C++-function
  * @param functionName name of the function
  * @return true on success, false on error
  */
  bool PushFunction(Lua_callback_function function, const char *functionName);

  /**
  * Push data on the lua-stack. (Mind the stack!)
  * @param number number to push
  * @param string string to push
  * @return true on success, false on error
  */
  bool Push(double number);
  bool Push(const char *string);
  bool Push(const std::string &string) { return this->Push(string.c_str()); }

  /**
  * Resets Lua's internal stack
  * @return true on success, false on error
  */
  bool Flush();

  /**
  * After calling debug(),
  * lua-adapter will print out debug-information for each following
  * function-call.
  */
  void Debug() { this->SetLogMode(true); }
  /**
  * Set debug output on or off
  * @param mode if mode==true, see debug()
  */
  void SetLogMode(bool mode);

  /**
  * Pops i entries from Lua's internal stack
  * @param i number of entries
  */
  void Pop(signed short int i = 1) { lua_pop(this->Lua, i); }

  /**
  * Gets the stack position
  * @return the stack position
  */
  int GetTop() const { return lua_gettop(this->Lua); }

  /**
  * Gets the value-type of the current stack position
  * @return the type
  */
  int GetType() const { return lua_type(this->Lua, 0); }

  /**
  * "Closes" the loaded *.lua-sourcefile
  * This function is called by the destructor of this class!
  * */
  void Close();

private:
  lua_State *Lua;
  bool print;
  bool single;
  const std::string outputPrefix;

  /**
  * Gets a field from an opened table and puts its value on the stack
  * @param name Name of the field
  * @return true on success, false on error
  */
  bool GetField(const char *name);

  /**
  * Gets the i-th (nested) field from an opened table
  * @param i the i-th field
  * @return true on success, false on error
  */
  bool GetI(unsigned short int i);

  /**
  * Gets the value of a globally loaded lua-variable
  * @param name Name of the vairable
  * @return true on success, false on error
  */
  bool GetGlobal(const char *name);
};
#endif
<|endoftext|>


<commit_before>/**
 * @file llmimetypes.cpp
 * @brief Translates a MIME type like "video/quicktime" into a
 * localizable user-friendly string like "QuickTime Movie"
 *
 * $LicenseInfo:firstyear=2007&license=viewergpl$
 *
 * Copyright (c) 2007-2008, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llmimetypes.h"

#include "llvieweruictrlfactory.h"

LLMIMETypes::mime_info_map_t LLMIMETypes::sMap;
LLMIMETypes::mime_widget_set_map_t LLMIMETypes::sWidgetMap;

LLString sDefaultLabel;
	// Returned when we don't know what to do with the mime type
LLString sDefaultWidgetType;
	// Returned when we don't know what widget set to use
LLString sDefaultImpl;
	// Returned when we don't know what impl to use

/////////////////////////////////////////////////////////////////////////////

// static
bool LLMIMETypes::parseMIMETypes(const LLString& xml_filename)
{
	LLXMLNodePtr root;
	bool success = LLViewerUICtrlFactory::getLayeredXMLNode(xml_filename, root);
	if (!success || !root || !root->hasName("mimetypes"))
	{
		llwarns << "Unable to read MIME type file: "
			<< xml_filename << llendl;
		return false;
	}

	for (LLXMLNode* node = root->getFirstChild();
		 node != NULL;
		 node = node->getNextSibling())
	{
		if (node->hasName("defaultlabel"))
		{
			sDefaultLabel = node->getTextContents();
		}
		else if (node->hasName("defaultwidget"))
		{
			sDefaultWidgetType = node->getTextContents();
		}
		else if (node->hasName("defaultimpl"))
		{
			sDefaultImpl = node->getTextContents();
		}
		else if (node->hasName("mimetype") || node->hasName("scheme"))
		{
			LLString mime_type;
			node->getAttributeString("name", mime_type);
			LLMIMEInfo info;
			for (LLXMLNode* child = node->getFirstChild();
				 child != NULL;
				 child = child->getNextSibling())
			{
				if (child->hasName("label"))
				{
					info.mLabel = child->getTextContents();
				}
				else if (child->hasName("widgettype"))
				{
					info.mWidgetType = child->getTextContents();
				}
				else if (child->hasName("impl"))
				{
					info.mImpl = child->getTextContents();
				}
			}
			sMap[mime_type] = info;
		}
		else if (node->hasName("widgetset"))
		{
			LLString set_name;
			node->getAttributeString("name", set_name);
			LLMIMEWidgetSet info;
			for (LLXMLNode* child = node->getFirstChild();
				child != NULL;
				child = child->getNextSibling())
			{
				if (child->hasName("label"))
				{
					info.mLabel = child->getTextContents();
				}
				if (child->hasName("icon"))
				{
					info.mIcon = child->getTextContents();
				}
				if (child->hasName("default_type"))
				{
					info.mDefaultMimeType = child->getTextContents();
				}
				if (child->hasName("tooltip"))
				{
					info.mToolTip = child->getTextContents();
				}
				if (child->hasName("playtip"))
				{
					info.mPlayTip = child->getTextContents();
				}
				if (child->hasName("allow_resize"))
				{
					child->getBoolValue( 1, (BOOL*)&( info.mAllowResize ) );
				}
				if (child->hasName("allow_looping"))
				{
					child->getBoolValue( 1, (BOOL*)&( info.mAllowLooping ) );
				}
			}
			sWidgetMap[set_name] = info;
		}
	}
	return true;
}

// static
LLString LLMIMETypes::translate(const LLString& mime_type)
{
	mime_info_map_t::const_iterator it = sMap.find(mime_type);
	if (it != sMap.end())
	{
		return it->second.mLabel;
	}
	else
	{
		return sDefaultLabel;
	}
}

// static
LLString LLMIMETypes::widgetType(const LLString& mime_type)
{
	mime_info_map_t::const_iterator it = sMap.find(mime_type);
	if (it != sMap.end())
	{
		return it->second.mWidgetType;
	}
	else
	{
		return sDefaultWidgetType;
	}
}

// static
LLString LLMIMETypes::implType(const LLString& mime_type)
{
	mime_info_map_t::const_iterator it = sMap.find(mime_type);
	if (it != sMap.end())
	{
		return it->second.mImpl;
	}
	else
	{
		return sDefaultImpl;
	}
}

// static
LLString LLMIMETypes::findIcon(const LLString& mime_type)
{
	LLString icon = "";
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		icon = it->second.mIcon;
	}
	return icon;
}

// static
LLString LLMIMETypes::findDefaultMimeType(const LLString& widget_type)
{
	LLString mime_type = "none/none";
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		mime_type = it->second.mDefaultMimeType;
	}
	return mime_type;
}

// static
LLString LLMIMETypes::findToolTip(const LLString& mime_type)
{
	LLString tool_tip = "";
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		tool_tip = it->second.mToolTip;
	}
	return tool_tip;
}

// static
LLString LLMIMETypes::findPlayTip(const LLString& mime_type)
{
	LLString play_tip = "";
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		play_tip = it->second.mPlayTip;
	}
	return play_tip;
}

// static
bool LLMIMETypes::findAllowResize(const LLString& mime_type)
{
	bool allow_resize = false;
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		allow_resize = it->second.mAllowResize;
	}
	return allow_resize;
}

// static
bool LLMIMETypes::findAllowLooping(const LLString& mime_type)
{
	bool allow_looping = false;
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		allow_looping = it->second.mAllowLooping;
	}
	return allow_looping;
}
<commit_msg>DEV-10924 -- Release build is broken using "Debug" configuration Quite a few tweaks to get it to build/run - details in the Jira Reviewed by Mani<commit_after>/**
 * @file llmimetypes.cpp
 * @brief Translates a MIME type like "video/quicktime" into a
 * localizable user-friendly string like "QuickTime Movie"
 *
 * $LicenseInfo:firstyear=2007&license=viewergpl$
 *
 * Copyright (c) 2007-2008, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llmimetypes.h"

#include "llvieweruictrlfactory.h"

LLMIMETypes::mime_info_map_t LLMIMETypes::sMap;
LLMIMETypes::mime_widget_set_map_t LLMIMETypes::sWidgetMap;

LLString sDefaultLabel;
	// Returned when we don't know what to do with the mime type
LLString sDefaultWidgetType;
	// Returned when we don't know what widget set to use
LLString sDefaultImpl;
	// Returned when we don't know what impl to use

/////////////////////////////////////////////////////////////////////////////

// static
bool LLMIMETypes::parseMIMETypes(const LLString& xml_filename)
{
	LLXMLNodePtr root;
	bool success = LLViewerUICtrlFactory::getLayeredXMLNode(xml_filename, root);
	if ( ! success || ! root.isNull() || ! root->hasName( "mimetypes" ) )
	{
		llwarns << "Unable to read MIME type file: "
			<< xml_filename << llendl;
		return false;
	}

	for (LLXMLNode* node = root->getFirstChild();
		 node != NULL;
		 node = node->getNextSibling())
	{
		if (node->hasName("defaultlabel"))
		{
			sDefaultLabel = node->getTextContents();
		}
		else if (node->hasName("defaultwidget"))
		{
			sDefaultWidgetType = node->getTextContents();
		}
		else if (node->hasName("defaultimpl"))
		{
			sDefaultImpl = node->getTextContents();
		}
		else if (node->hasName("mimetype") || node->hasName("scheme"))
		{
			LLString mime_type;
			node->getAttributeString("name", mime_type);
			LLMIMEInfo info;
			for (LLXMLNode* child = node->getFirstChild();
				 child != NULL;
				 child = child->getNextSibling())
			{
				if (child->hasName("label"))
				{
					info.mLabel = child->getTextContents();
				}
				else if (child->hasName("widgettype"))
				{
					info.mWidgetType = child->getTextContents();
				}
				else if (child->hasName("impl"))
				{
					info.mImpl = child->getTextContents();
				}
			}
			sMap[mime_type] = info;
		}
		else if (node->hasName("widgetset"))
		{
			LLString set_name;
			node->getAttributeString("name", set_name);
			LLMIMEWidgetSet info;
			for (LLXMLNode* child = node->getFirstChild();
				child != NULL;
				child = child->getNextSibling())
			{
				if (child->hasName("label"))
				{
					info.mLabel = child->getTextContents();
				}
				if (child->hasName("icon"))
				{
					info.mIcon = child->getTextContents();
				}
				if (child->hasName("default_type"))
				{
					info.mDefaultMimeType = child->getTextContents();
				}
				if (child->hasName("tooltip"))
				{
					info.mToolTip = child->getTextContents();
				}
				if (child->hasName("playtip"))
				{
					info.mPlayTip = child->getTextContents();
				}
				if (child->hasName("allow_resize"))
				{
					child->getBoolValue( 1, (BOOL*)&( info.mAllowResize ) );
				}
				if (child->hasName("allow_looping"))
				{
					child->getBoolValue( 1, (BOOL*)&( info.mAllowLooping ) );
				}
			}
			sWidgetMap[set_name] = info;
		}
	}
	return true;
}

// static
LLString LLMIMETypes::translate(const LLString& mime_type)
{
	mime_info_map_t::const_iterator it = sMap.find(mime_type);
	if (it != sMap.end())
	{
		return it->second.mLabel;
	}
	else
	{
		return sDefaultLabel;
	}
}

// static
LLString LLMIMETypes::widgetType(const LLString& mime_type)
{
	mime_info_map_t::const_iterator it = sMap.find(mime_type);
	if (it != sMap.end())
	{
		return it->second.mWidgetType;
	}
	else
	{
		return sDefaultWidgetType;
	}
}

// static
LLString LLMIMETypes::implType(const LLString& mime_type)
{
	mime_info_map_t::const_iterator it = sMap.find(mime_type);
	if (it != sMap.end())
	{
		return it->second.mImpl;
	}
	else
	{
		return sDefaultImpl;
	}
}

// static
LLString LLMIMETypes::findIcon(const LLString& mime_type)
{
	LLString icon = "";
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		icon = it->second.mIcon;
	}
	return icon;
}

// static
LLString LLMIMETypes::findDefaultMimeType(const LLString& widget_type)
{
	LLString mime_type = "none/none";
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		mime_type = it->second.mDefaultMimeType;
	}
	return mime_type;
}

// static
LLString LLMIMETypes::findToolTip(const LLString& mime_type)
{
	LLString tool_tip = "";
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		tool_tip = it->second.mToolTip;
	}
	return tool_tip;
}

// static
LLString LLMIMETypes::findPlayTip(const LLString& mime_type)
{
	LLString play_tip = "";
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		play_tip = it->second.mPlayTip;
	}
	return play_tip;
}

// static
bool LLMIMETypes::findAllowResize(const LLString& mime_type)
{
	bool allow_resize = false;
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		allow_resize = it->second.mAllowResize;
	}
	return allow_resize;
}

// static
bool LLMIMETypes::findAllowLooping(const LLString& mime_type)
{
	bool allow_looping = false;
	LLString widget_type = LLMIMETypes::widgetType(mime_type);
	mime_widget_set_map_t::iterator it = sWidgetMap.find(widget_type);
	if(it != sWidgetMap.end())
	{
		allow_looping = it->second.mAllowLooping;
	}
	return allow_looping;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "KeyboardOSD.h"

KeyboardOSD::KeyboardOSD() :
OSD(L"3RVX-KeyOSDDispatcher"),
_mWnd(L"3RVX-KeyboardOSD", L"3RVX-KeyboardOSD") {

}
<commit_msg>Add empty destructor<commit_after>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "KeyboardOSD.h"

KeyboardOSD::KeyboardOSD() :
OSD(L"3RVX-KeyOSDDispatcher"),
_mWnd(L"3RVX-KeyboardOSD", L"3RVX-KeyboardOSD") {

}

KeyboardOSD::~KeyboardOSD() {

}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  spring_arm_3d.cpp                                                    */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "spring_arm_3d.h"
#include "core/engine.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/resources/sphere_shape_3d.h"
#include "servers/physics_server_3d.h"

SpringArm3D::SpringArm3D() :
		spring_length(1),
		current_spring_length(0),
		keep_child_basis(false),
		mask(1),
		margin(0.01) {}

void SpringArm3D::_notification(int p_what) {
	switch (p_what) {
		case NOTIFICATION_ENTER_TREE:
			if (!Engine::get_singleton()->is_editor_hint()) {
				set_process_internal(true);
			}
			break;
		case NOTIFICATION_EXIT_TREE:
			if (!Engine::get_singleton()->is_editor_hint()) {
				set_process_internal(false);
			}
			break;
		case NOTIFICATION_INTERNAL_PROCESS:
			process_spring();
			break;
	}
}

void SpringArm3D::_bind_methods() {

	ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm3D::get_hit_length);

	ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm3D::set_length);
	ClassDB::bind_method(D_METHOD("get_length"), &SpringArm3D::get_length);

	ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm3D::set_shape);
	ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm3D::get_shape);

	ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm3D::add_excluded_object);
	ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm3D::remove_excluded_object);
	ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm3D::clear_excluded_objects);

	ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm3D::set_mask);
	ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm3D::get_mask);

	ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm3D::set_margin);
	ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm3D::get_margin);

	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spring_length"), "set_length", "get_length");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin");
}

float SpringArm3D::get_length() const {
	return spring_length;
}

void SpringArm3D::set_length(float p_length) {
	if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint()))
		update_gizmo();

	spring_length = p_length;
}

void SpringArm3D::set_shape(Ref<Shape3D> p_shape) {
	shape = p_shape;
}

Ref<Shape3D> SpringArm3D::get_shape() const {
	return shape;
}

void SpringArm3D::set_mask(uint32_t p_mask) {
	mask = p_mask;
}

uint32_t SpringArm3D::get_mask() {
	return mask;
}

float SpringArm3D::get_margin() {
	return margin;
}

void SpringArm3D::set_margin(float p_margin) {
	margin = p_margin;
}

void SpringArm3D::add_excluded_object(RID p_rid) {
	excluded_objects.insert(p_rid);
}

bool SpringArm3D::remove_excluded_object(RID p_rid) {
	return excluded_objects.erase(p_rid);
}

void SpringArm3D::clear_excluded_objects() {
	excluded_objects.clear();
}

float SpringArm3D::get_hit_length() {
	return current_spring_length;
}

void SpringArm3D::process_spring() {
	// From
	real_t motion_delta(1);
	real_t motion_delta_unsafe(1);

	Vector3 motion;
	const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));

	if (shape.is_null()) {
		motion = Vector3(cast_direction * (spring_length));
		PhysicsDirectSpaceState3D::RayResult r;
		bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
		if (intersected) {
			float dist = get_global_transform().origin.distance_to(r.position);
			dist -= margin;
			motion_delta = dist / (spring_length);
		}
	} else {
		motion = Vector3(cast_direction * spring_length);
		get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
	}

	current_spring_length = spring_length * motion_delta;
	Transform childs_transform;
	childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);

	for (int i = get_child_count() - 1; 0 <= i; --i) {

		Node3D *child = Object::cast_to<Node3D>(get_child(i));
		if (child) {
			childs_transform.basis = child->get_global_transform().basis;
			child->set_global_transform(childs_transform);
		}
	}
}
<commit_msg>Run SpringArm3D's process within physics.<commit_after>/*************************************************************************/
/*  spring_arm_3d.cpp                                                    */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "spring_arm_3d.h"
#include "core/engine.h"
#include "scene/3d/collision_object_3d.h"
#include "scene/resources/sphere_shape_3d.h"
#include "servers/physics_server_3d.h"

SpringArm3D::SpringArm3D() :
		spring_length(1),
		current_spring_length(0),
		keep_child_basis(false),
		mask(1),
		margin(0.01) {}

void SpringArm3D::_notification(int p_what) {
	switch (p_what) {
		case NOTIFICATION_ENTER_TREE:
			if (!Engine::get_singleton()->is_editor_hint()) {
				set_process_internal(true);
			}
			break;
		case NOTIFICATION_EXIT_TREE:
			if (!Engine::get_singleton()->is_editor_hint()) {
				set_process_internal(false);
			}
			break;
		case NOTIFICATION_INTERNAL_PHYSICS_PROCESS:
			process_spring();
			break;
	}
}

void SpringArm3D::_bind_methods() {

	ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm3D::get_hit_length);

	ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm3D::set_length);
	ClassDB::bind_method(D_METHOD("get_length"), &SpringArm3D::get_length);

	ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm3D::set_shape);
	ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm3D::get_shape);

	ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm3D::add_excluded_object);
	ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm3D::remove_excluded_object);
	ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm3D::clear_excluded_objects);

	ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm3D::set_mask);
	ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm3D::get_mask);

	ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm3D::set_margin);
	ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm3D::get_margin);

	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spring_length"), "set_length", "get_length");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin");
}

float SpringArm3D::get_length() const {
	return spring_length;
}

void SpringArm3D::set_length(float p_length) {
	if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint()))
		update_gizmo();

	spring_length = p_length;
}

void SpringArm3D::set_shape(Ref<Shape3D> p_shape) {
	shape = p_shape;
}

Ref<Shape3D> SpringArm3D::get_shape() const {
	return shape;
}

void SpringArm3D::set_mask(uint32_t p_mask) {
	mask = p_mask;
}

uint32_t SpringArm3D::get_mask() {
	return mask;
}

float SpringArm3D::get_margin() {
	return margin;
}

void SpringArm3D::set_margin(float p_margin) {
	margin = p_margin;
}

void SpringArm3D::add_excluded_object(RID p_rid) {
	excluded_objects.insert(p_rid);
}

bool SpringArm3D::remove_excluded_object(RID p_rid) {
	return excluded_objects.erase(p_rid);
}

void SpringArm3D::clear_excluded_objects() {
	excluded_objects.clear();
}

float SpringArm3D::get_hit_length() {
	return current_spring_length;
}

void SpringArm3D::process_spring() {
	// From
	real_t motion_delta(1);
	real_t motion_delta_unsafe(1);

	Vector3 motion;
	const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));

	if (shape.is_null()) {
		motion = Vector3(cast_direction * (spring_length));
		PhysicsDirectSpaceState3D::RayResult r;
		bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
		if (intersected) {
			float dist = get_global_transform().origin.distance_to(r.position);
			dist -= margin;
			motion_delta = dist / (spring_length);
		}
	} else {
		motion = Vector3(cast_direction * spring_length);
		get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
	}

	current_spring_length = spring_length * motion_delta;
	Transform childs_transform;
	childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);

	for (int i = get_child_count() - 1; 0 <= i; --i) {

		Node3D *child = Object::cast_to<Node3D>(get_child(i));
		if (child) {
			childs_transform.basis = child->get_global_transform().basis;
			child->set_global_transform(childs_transform);
		}
	}
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    Copyright (c) 2013-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *      This file implements the CHIP Connection object that maintains a UDP connection.
 *      TODO This class should be extended to support TCP as well...
 *
 */

#include <string.h>
#include <support/CodeUtils.h>
#include <support/logging/CHIPLogging.h>
#include <transport/SecureTransport.h>

#include <inttypes.h>

namespace chip {

// Maximum length of application data that can be encrypted as one block.
// The limit is derived from IPv6 MTU (1280 bytes) - expected header overheads.
// This limit would need additional reviews once we have formalized Secure Transport header.
static const size_t kMax_SecureSDU_Length         = 1024;
static const char * kManualKeyExchangeChannelInfo = "Manual Key Exchanged Channel";

SecureTransport::SecureTransport() : mState(kState_NotReady), mRefCount(1)
{
    mUDPEndPoint      = NULL;
    OnMessageReceived = NULL;
    OnReceiveError    = NULL;
}

void SecureTransport::Init(Inet::InetLayer * inetLayer)
{
    if (mState != kState_NotReady)
    {
        return;
    }

    mInetLayer = inetLayer;
    mState     = kState_ReadyToConnect;

} // namespace chip

CHIP_ERROR SecureTransport::ManualKeyExchange(const unsigned char * remote_public_key, const size_t public_key_length,
                                              const unsigned char * local_private_key, const size_t private_key_length)
{
    CHIP_ERROR err  = CHIP_NO_ERROR;
    size_t info_len = strlen(kManualKeyExchangeChannelInfo);

    VerifyOrExit(mState == kState_Connected, err = CHIP_ERROR_INCORRECT_STATE);

    err = mSecureChannel.Init(remote_public_key, public_key_length, local_private_key, private_key_length, NULL, 0,
                              (const unsigned char *) kManualKeyExchangeChannelInfo, info_len);
    SuccessOrExit(err);
    mState = kState_SecureConnected;
exit:
    return err;
}

CHIP_ERROR SecureTransport::Connect(IPAddressType addrType, InterfaceId intfId)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(mState == kState_ReadyToConnect, err = CHIP_ERROR_INCORRECT_STATE);

    // Bump the reference count when we start the connection process. The corresponding decrement happens when the
    // DoClose() method is called. This ensures the object stays live while there's the possibility of a callback
    // happening from an underlying layer.
    mRefCount++;

    ChipLogProgress(Inet, "Connection start");

    err = mInetLayer->NewUDPEndPoint(&mUDPEndPoint);
    if (err != CHIP_NO_ERROR)
    {
        ChipLogProgress(Inet, "Error: %s\n Couldn't create connection\n", ErrorStr(err));
        SuccessOrExit(err);
    }

    err = mUDPEndPoint->Bind(addrType, IPAddress::Any, CHIP_PORT, intfId);
    if (err != CHIP_NO_ERROR)
    {
        ChipLogProgress(Inet, "Error: %s\n Bind failed\n", ErrorStr(err));
        SuccessOrExit(err);
    }

    err = mUDPEndPoint->Listen();
    if (err != CHIP_NO_ERROR)
    {
        ChipLogProgress(Inet, "Error: %s\n Listen failed\n", ErrorStr(err));
        SuccessOrExit(err);
    }

    mUDPEndPoint->AppState          = this;
    mUDPEndPoint->OnMessageReceived = HandleDataReceived;
    mUDPEndPoint->OnReceiveError    = HandleReceiveError;
    mState                          = kState_Connected;
exit:
    return err;
}

CHIP_ERROR SecureTransport::SendMessage(PacketBuffer * msgBuf, const IPAddress & peerAddr, uint32_t msg_id)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(StateAllowsSend(), err = CHIP_ERROR_INCORRECT_STATE);

    VerifyOrExit(msgBuf != NULL, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == NULL, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    IPPacketInfo addrInfo;
    addrInfo.Clear();
    addrInfo.DestAddress = peerAddr;
    addrInfo.DestPort    = CHIP_PORT;

    {
        uint8_t * plainText = msgBuf->Start();
        size_t plainTextlen = msgBuf->TotalLength();

        uint8_t * encryptedText = plainText - CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;
        size_t encryptedLen     = plainTextlen + CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;

        err = mSecureChannel.Encrypt(plainText, plainTextlen, encryptedText, encryptedLen);
        SuccessOrExit(err);

        msgBuf->SetStart(encryptedText);

        ChipLogProgress(Inet, "Secure transport transmitting msg %d after encryption", msg_id);
    }

    err    = mUDPEndPoint->SendMsg(&addrInfo, msgBuf);
    msgBuf = NULL;

exit:
    if (msgBuf != NULL)
    {
        ChipLogProgress(Inet, "Secure transport failed to encrypt msg %d", msg_id);
        PacketBuffer::Free(msgBuf);
        msgBuf = NULL;
    }

    return err;
}

void SecureTransport::HandleDataReceived(IPEndPointBasis * endPoint, chip::System::PacketBuffer * msg, const IPPacketInfo * pktInfo)
{
    UDPEndPoint * udpEndPoint    = static_cast<UDPEndPoint *>(endPoint);
    SecureTransport * connection = (SecureTransport *) udpEndPoint->AppState;

    // TODO this is where messages should be decoded
    if (connection->StateAllowsReceive() && msg != NULL)
    {
        uint8_t * encryptedText = msg->Start();
        uint16_t encryptedLen   = msg->TotalLength();

        if (encryptedLen < CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE)
        {
            PacketBuffer::Free(msg);
            ChipLogProgress(Inet, "Secure transport received smaller than encryption header, discarding");
            return;
        }

        chip::System::PacketBuffer * origMsg = NULL;
#if CHIP_SYSTEM_CONFIG_USE_LWIP
        /* This is a workaround for the case where PacketBuffer payload is not allocated
           as an inline buffer to PacketBuffer structure */
        origMsg = msg;
        msg     = PacketBuffer::NewWithAvailableSize(encryptedLen);
        msg->SetDataLength(encryptedLen, msg);
#endif

        uint8_t * plainText = msg->Start() + CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;
        size_t plainTextlen = encryptedLen - CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;

        CHIP_ERROR err = connection->mSecureChannel.Decrypt(encryptedText, encryptedLen, plainText, plainTextlen);

        if (origMsg != NULL)
        {
            PacketBuffer::Free(origMsg);
        }

        if (err == CHIP_NO_ERROR)
        {
            msg->Consume(CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE);
            connection->OnMessageReceived(connection, msg, pktInfo);
        }
        else
        {
            connection->OnReceiveError(connection, CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE_FROM_PEER, pktInfo);
            PacketBuffer::Free(msg);
            ChipLogProgress(Inet, "Secure transport failed to decrypt msg: err %d", err);
        }
    }
}

void SecureTransport::HandleReceiveError(IPEndPointBasis * endPoint, CHIP_ERROR err, const IPPacketInfo * pktInfo)
{
    UDPEndPoint * udpEndPoint    = static_cast<UDPEndPoint *>(endPoint);
    SecureTransport * connection = (SecureTransport *) udpEndPoint->AppState;
    if (connection->StateAllowsReceive())
    {
        connection->OnReceiveError(connection, err, pktInfo);
    }
}
/**
 *  Performs a non-blocking graceful close of the UDP based SecureTransport, delivering any
 *  remaining outgoing data before resetting the connection.
 *
 *  This method provides no strong guarantee that any outgoing message not acknowledged at the application
 *  protocol level has been received by the remote peer.
 *
 *  Once Close() has been called, the SecureTransport object can no longer be used for further communication.
 *
 *  Calling Close() decrements the reference count associated with the SecureTransport object, whether or not
 *  the connection is open/active at the time the method is called.  If this results in the reference count
 *  reaching zero, the resources associated with the connection object are freed.  When this happens, the
 *  application must have no further interactions with the object.
 *
 *  @sa Shutdown(), Abort(), Retain() and Release().
 *
 *  @return #CHIP_NO_ERROR unconditionally.
 *
 */
CHIP_ERROR SecureTransport::Close()
{
    // Perform a graceful close.
    DoClose(CHIP_NO_ERROR);

    // Decrement the ref count that was added when the SecureTransport object
    // was allocated.
    VerifyOrDie(mRefCount != 0);
    mRefCount--;

    return CHIP_NO_ERROR;
}

void SecureTransport::DoClose(CHIP_ERROR err)
{
    if (mState != kState_Closed)
    {
        if (mUDPEndPoint != NULL)
        {
            if (err == CHIP_NO_ERROR)
            {
                mUDPEndPoint->Close();
            }
            mUDPEndPoint->Free();
            mUDPEndPoint = NULL;
        }
    }
    uint8_t oldState = mState;
    mState           = kState_Closed;
    ChipLogProgress(Inet, "Connection closed %ld", (long) err);

    // Decrement the ref count that was added when the connection started.
    if (oldState != kState_ReadyToConnect && oldState != kState_Closed)
    {
        VerifyOrDie(mRefCount != 0);
        mRefCount--;
    }
}

/**
 * Reserve a reference to the SecureTransport object.
 *
 * The Retain() method increments the reference count associated with the SecureTransport object.  For every
 * call to Retain(), the application is responsible for making a corresponding call to either Release(), Close()
 * or Abort().
 */
void SecureTransport::Retain()
{
    VerifyOrDie(mRefCount < UINT8_MAX);
    ++mRefCount;
}

/**
 *  Decrement the reference count on the SecureTransport object.
 *
 *  The Release() method decrements the reference count associated with the SecureTransport object.  If
 *  this results in the reference count reaching zero, the connection is closed and the connection object
 *  is freed.  When this happens, the application must have no further interactions with the object.
 */
void SecureTransport::Release()
{
    // If the only reference that will remain after this call is the one that was automatically added
    // when the connection started, close the connection.
    if (mRefCount == 2 && mState != kState_ReadyToConnect && mState != kState_Closed)
    {
        DoClose(CHIP_NO_ERROR);
    }

    VerifyOrDie(mRefCount != 0);
    mRefCount--;
}

} // namespace chip
<commit_msg>Fix memory leak in SecureTransport::HandleDataReceived (#1106)<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    Copyright (c) 2013-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *      This file implements the CHIP Connection object that maintains a UDP connection.
 *      TODO This class should be extended to support TCP as well...
 *
 */

#include <string.h>
#include <support/CodeUtils.h>
#include <support/logging/CHIPLogging.h>
#include <transport/SecureTransport.h>

#include <inttypes.h>

namespace chip {

// Maximum length of application data that can be encrypted as one block.
// The limit is derived from IPv6 MTU (1280 bytes) - expected header overheads.
// This limit would need additional reviews once we have formalized Secure Transport header.
static const size_t kMax_SecureSDU_Length         = 1024;
static const char * kManualKeyExchangeChannelInfo = "Manual Key Exchanged Channel";

SecureTransport::SecureTransport() : mState(kState_NotReady), mRefCount(1)
{
    mUDPEndPoint      = NULL;
    OnMessageReceived = NULL;
    OnReceiveError    = NULL;
}

void SecureTransport::Init(Inet::InetLayer * inetLayer)
{
    if (mState != kState_NotReady)
    {
        return;
    }

    mInetLayer = inetLayer;
    mState     = kState_ReadyToConnect;

} // namespace chip

CHIP_ERROR SecureTransport::ManualKeyExchange(const unsigned char * remote_public_key, const size_t public_key_length,
                                              const unsigned char * local_private_key, const size_t private_key_length)
{
    CHIP_ERROR err  = CHIP_NO_ERROR;
    size_t info_len = strlen(kManualKeyExchangeChannelInfo);

    VerifyOrExit(mState == kState_Connected, err = CHIP_ERROR_INCORRECT_STATE);

    err = mSecureChannel.Init(remote_public_key, public_key_length, local_private_key, private_key_length, NULL, 0,
                              (const unsigned char *) kManualKeyExchangeChannelInfo, info_len);
    SuccessOrExit(err);
    mState = kState_SecureConnected;
exit:
    return err;
}

CHIP_ERROR SecureTransport::Connect(IPAddressType addrType, InterfaceId intfId)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(mState == kState_ReadyToConnect, err = CHIP_ERROR_INCORRECT_STATE);

    // Bump the reference count when we start the connection process. The corresponding decrement happens when the
    // DoClose() method is called. This ensures the object stays live while there's the possibility of a callback
    // happening from an underlying layer.
    mRefCount++;

    ChipLogProgress(Inet, "Connection start");

    err = mInetLayer->NewUDPEndPoint(&mUDPEndPoint);
    if (err != CHIP_NO_ERROR)
    {
        ChipLogProgress(Inet, "Error: %s\n Couldn't create connection\n", ErrorStr(err));
        SuccessOrExit(err);
    }

    err = mUDPEndPoint->Bind(addrType, IPAddress::Any, CHIP_PORT, intfId);
    if (err != CHIP_NO_ERROR)
    {
        ChipLogProgress(Inet, "Error: %s\n Bind failed\n", ErrorStr(err));
        SuccessOrExit(err);
    }

    err = mUDPEndPoint->Listen();
    if (err != CHIP_NO_ERROR)
    {
        ChipLogProgress(Inet, "Error: %s\n Listen failed\n", ErrorStr(err));
        SuccessOrExit(err);
    }

    mUDPEndPoint->AppState          = this;
    mUDPEndPoint->OnMessageReceived = HandleDataReceived;
    mUDPEndPoint->OnReceiveError    = HandleReceiveError;
    mState                          = kState_Connected;
exit:
    return err;
}

CHIP_ERROR SecureTransport::SendMessage(PacketBuffer * msgBuf, const IPAddress & peerAddr, uint32_t msg_id)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(StateAllowsSend(), err = CHIP_ERROR_INCORRECT_STATE);

    VerifyOrExit(msgBuf != NULL, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == NULL, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    IPPacketInfo addrInfo;
    addrInfo.Clear();
    addrInfo.DestAddress = peerAddr;
    addrInfo.DestPort    = CHIP_PORT;

    {
        uint8_t * plainText = msgBuf->Start();
        size_t plainTextlen = msgBuf->TotalLength();

        uint8_t * encryptedText = plainText - CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;
        size_t encryptedLen     = plainTextlen + CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;

        err = mSecureChannel.Encrypt(plainText, plainTextlen, encryptedText, encryptedLen);
        SuccessOrExit(err);

        msgBuf->SetStart(encryptedText);

        ChipLogProgress(Inet, "Secure transport transmitting msg %d after encryption", msg_id);
    }

    err    = mUDPEndPoint->SendMsg(&addrInfo, msgBuf);
    msgBuf = NULL;

exit:
    if (msgBuf != NULL)
    {
        ChipLogProgress(Inet, "Secure transport failed to encrypt msg %d", msg_id);
        PacketBuffer::Free(msgBuf);
        msgBuf = NULL;
    }

    return err;
}

void SecureTransport::HandleDataReceived(IPEndPointBasis * endPoint, chip::System::PacketBuffer * msg, const IPPacketInfo * pktInfo)
{
    UDPEndPoint * udpEndPoint    = static_cast<UDPEndPoint *>(endPoint);
    SecureTransport * connection = (SecureTransport *) udpEndPoint->AppState;

    // TODO this is where messages should be decoded
    if (connection->StateAllowsReceive() && msg != nullptr)
    {
        uint8_t * encryptedText = msg->Start();
        uint16_t encryptedLen   = msg->TotalLength();

        if (encryptedLen < CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE)
        {
            PacketBuffer::Free(msg);
            ChipLogProgress(Inet, "Secure transport received smaller than encryption header, discarding");
            return;
        }

        chip::System::PacketBuffer * origMsg = nullptr;
#if CHIP_SYSTEM_CONFIG_USE_LWIP
        /* This is a workaround for the case where PacketBuffer payload is not allocated
           as an inline buffer to PacketBuffer structure */
        origMsg = msg;
        msg     = PacketBuffer::NewWithAvailableSize(encryptedLen);
        msg->SetDataLength(encryptedLen, msg);
#endif

        uint8_t * plainText = msg->Start() + CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;
        size_t plainTextlen = encryptedLen - CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE;

        CHIP_ERROR err = connection->mSecureChannel.Decrypt(encryptedText, encryptedLen, plainText, plainTextlen);

        if (origMsg != nullptr)
        {
            PacketBuffer::Free(origMsg);
        }

        if (err == CHIP_NO_ERROR)
        {
            msg->Consume(CHIP_SYSTEM_CRYPTO_HEADER_RESERVE_SIZE);
            connection->OnMessageReceived(connection, msg, pktInfo);
        }
        else
        {
            connection->OnReceiveError(connection, CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE_FROM_PEER, pktInfo);
            PacketBuffer::Free(msg);
            ChipLogProgress(Inet, "Secure transport failed to decrypt msg: err %d", err);
        }
    }
    else if (msg != nullptr)
    {
        PacketBuffer::Free(msg);
        ChipLogProgress(Inet, "Secure transport failed: state not allows receive");
    }
}

void SecureTransport::HandleReceiveError(IPEndPointBasis * endPoint, CHIP_ERROR err, const IPPacketInfo * pktInfo)
{
    UDPEndPoint * udpEndPoint    = static_cast<UDPEndPoint *>(endPoint);
    SecureTransport * connection = (SecureTransport *) udpEndPoint->AppState;
    if (connection->StateAllowsReceive())
    {
        connection->OnReceiveError(connection, err, pktInfo);
    }
}
/**
 *  Performs a non-blocking graceful close of the UDP based SecureTransport, delivering any
 *  remaining outgoing data before resetting the connection.
 *
 *  This method provides no strong guarantee that any outgoing message not acknowledged at the application
 *  protocol level has been received by the remote peer.
 *
 *  Once Close() has been called, the SecureTransport object can no longer be used for further communication.
 *
 *  Calling Close() decrements the reference count associated with the SecureTransport object, whether or not
 *  the connection is open/active at the time the method is called.  If this results in the reference count
 *  reaching zero, the resources associated with the connection object are freed.  When this happens, the
 *  application must have no further interactions with the object.
 *
 *  @sa Shutdown(), Abort(), Retain() and Release().
 *
 *  @return #CHIP_NO_ERROR unconditionally.
 *
 */
CHIP_ERROR SecureTransport::Close()
{
    // Perform a graceful close.
    DoClose(CHIP_NO_ERROR);

    // Decrement the ref count that was added when the SecureTransport object
    // was allocated.
    VerifyOrDie(mRefCount != 0);
    mRefCount--;

    return CHIP_NO_ERROR;
}

void SecureTransport::DoClose(CHIP_ERROR err)
{
    if (mState != kState_Closed)
    {
        if (mUDPEndPoint != NULL)
        {
            if (err == CHIP_NO_ERROR)
            {
                mUDPEndPoint->Close();
            }
            mUDPEndPoint->Free();
            mUDPEndPoint = NULL;
        }
    }
    uint8_t oldState = mState;
    mState           = kState_Closed;
    ChipLogProgress(Inet, "Connection closed %ld", (long) err);

    // Decrement the ref count that was added when the connection started.
    if (oldState != kState_ReadyToConnect && oldState != kState_Closed)
    {
        VerifyOrDie(mRefCount != 0);
        mRefCount--;
    }
}

/**
 * Reserve a reference to the SecureTransport object.
 *
 * The Retain() method increments the reference count associated with the SecureTransport object.  For every
 * call to Retain(), the application is responsible for making a corresponding call to either Release(), Close()
 * or Abort().
 */
void SecureTransport::Retain()
{
    VerifyOrDie(mRefCount < UINT8_MAX);
    ++mRefCount;
}

/**
 *  Decrement the reference count on the SecureTransport object.
 *
 *  The Release() method decrements the reference count associated with the SecureTransport object.  If
 *  this results in the reference count reaching zero, the connection is closed and the connection object
 *  is freed.  When this happens, the application must have no further interactions with the object.
 */
void SecureTransport::Release()
{
    // If the only reference that will remain after this call is the one that was automatically added
    // when the connection started, close the connection.
    if (mRefCount == 2 && mState != kState_ReadyToConnect && mState != kState_Closed)
    {
        DoClose(CHIP_NO_ERROR);
    }

    VerifyOrDie(mRefCount != 0);
    mRefCount--;
}

} // namespace chip
<|endoftext|>


<commit_before>
#include "rtkGgoFunctions.h"

#include "rtkThreeDCircularProjectionGeometryXMLFile.h"
#include "rtkRayBoxIntersectionImageFilter.h"
#include "rtkDrawSheppLoganFilter.h"

#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include "rtkJosephForwardProjectionImageFilter.h"
#include <itkExtractImageFilter.h>
#include <itkMultiplyByConstantImageFilter.h>
#include <rtkSheppLoganPhantomFilter.h>

template<class TImage>
void CheckImageQuality(typename TImage::Pointer recon, typename TImage::Pointer ref)
{
  typedef itk::ImageRegionConstIterator<TImage> ImageIteratorType;
  ImageIteratorType itTest( recon, recon->GetBufferedRegion() );
  ImageIteratorType itRef( ref, ref->GetBufferedRegion() );

  typedef double ErrorType;
  ErrorType TestError = 0.;
  ErrorType EnerError = 0.;

  itTest.GoToBegin();
  itRef.GoToBegin();

  while( !itRef.IsAtEnd() )
    {
    typename TImage::PixelType TestVal = itTest.Get();
    typename TImage::PixelType RefVal = itRef.Get();

    if( TestVal != RefVal )
      {
        TestError += vcl_abs(RefVal - TestVal);
        EnerError += vcl_pow(ErrorType(RefVal - TestVal), 2.);
      }
    ++itTest;
    ++itRef;
    }
  // Error per Pixel
  ErrorType ErrorPerPixel = TestError/recon->GetBufferedRegion().GetNumberOfPixels();
  std::cout << "\nError per Pixel = " << ErrorPerPixel << std::endl;
  // MSE
  ErrorType MSE = EnerError/ref->GetBufferedRegion().GetNumberOfPixels();
  std::cout << "MSE = " << MSE << std::endl;
  // PSNR
  ErrorType PSNR = 20*log10(255.0) - 10*log10(MSE);
  std::cout << "PSNR = " << PSNR << "dB" << std::endl;
  // QI
  ErrorType QI = (255.0-ErrorPerPixel)/255.0;
  std::cout << "QI = " << QI << std::endl;

  // Checking results
  if (ErrorPerPixel > 0.5)
  {
    std::cerr << "Test Failed, Error per pixel not valid! "
              << ErrorPerPixel << " instead of 0.005" << std::endl;
    exit( EXIT_FAILURE);
  }
  if (PSNR < 25.)
  {
    std::cerr << "Test Failed, PSNR not valid! "
              << PSNR << " instead of 25" << std::endl;
    exit( EXIT_FAILURE);
  }
}

int main(int , char** )
{
  const unsigned int Dimension = 3;
  typedef float                                    OutputPixelType;
  typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
  typedef itk::Vector<double, 3>                   VectorType;
  const unsigned int NumberOfProjectionImages = 1;

  // Constant image sources
  typedef rtk::ConstantImageSource< OutputImageType > ConstantImageSourceType;
  ConstantImageSourceType::PointType origin;
  ConstantImageSourceType::SizeType size;
  ConstantImageSourceType::SpacingType spacing;

  // Resized Volume, it is used as the reference to calculate the Joseph Forward Projector quality.
  const ConstantImageSourceType::Pointer resizedInput = ConstantImageSourceType::New();
  origin[0] = -127;
  origin[1] = -127;
  origin[2] = -127;
  size[0] = 255;
  size[1] = 255;
  size[2] = 175;
  spacing[0] = 1.;
  spacing[1] = 1.;
  spacing[2] = 1.;
  resizedInput->SetOrigin( origin );
  resizedInput->SetSpacing( spacing );
  resizedInput->SetSize( size );
  resizedInput->SetConstant( 1. );

  // Full Volume, it is used in the Joseph Forward Projector in order to check
  // the case of an inner ray source.
  const ConstantImageSourceType::Pointer fullInput = ConstantImageSourceType::New();
  origin[0] = -127;
  origin[1] = -127;
  origin[2] = -127;
  size[0] = 255;
  size[1] = 255;
  size[2] = 255;
  spacing[0] = 1.;
  spacing[1] = 1.;
  spacing[2] = 1.;
  fullInput->SetOrigin( origin );
  fullInput->SetSpacing( spacing );
  fullInput->SetSize( size );
  fullInput->SetConstant( 1. );

  // Initialization Volume, it is used in the Joseph Forward Projector and in the
  // Ray Box Intersection Filter in order to initialize the stack of projections.
  const ConstantImageSourceType::Pointer initInput = ConstantImageSourceType::New();
  origin[0] = -127;
  origin[1] = -127;
  origin[2] = -127;
  size[0] = 255;
  size[1] = 255;
  size[2] = NumberOfProjectionImages;
  spacing[0] = 1.;
  spacing[1] = 1.;
  spacing[2] = 1.;
  initInput->SetOrigin( origin );
  initInput->SetSpacing( spacing );
  initInput->SetSize( size );
  initInput->SetConstant( 0. );

  // Shepp-Logan Full Volume
  const ConstantImageSourceType::Pointer sheppFullInput = ConstantImageSourceType::New();
  origin[0] = -127;
  origin[1] = -127;
  origin[2] = -127;
  size[0] = 255;
  size[1] = 255;
  size[2] = 255;
  spacing[0] = 1.;
  spacing[1] = 1.;
  spacing[2] = 1.;
  sheppFullInput->SetOrigin( origin );
  sheppFullInput->SetSpacing( spacing );
  sheppFullInput->SetSize( size );
  sheppFullInput->SetConstant( 0. );

  // Ray Box Intersection filter
  typedef rtk::RayBoxIntersectionImageFilter<OutputImageType, OutputImageType> RBIType;
  RBIType::Pointer rbi = RBIType::New();

  // Joseph Forward Projection filter
  typedef rtk::JosephForwardProjectionImageFilter<OutputImageType, OutputImageType> JFPType;
  JFPType::Pointer jfp = JFPType::New();

//  // Writer
  typedef itk::ImageFileWriter<OutputImageType> WriterType;
  WriterType::Pointer writer = WriterType::New();

  std::cout << "\n\n****** Case 1: inner ray source ******" << std::endl;
  // Geometry
  typedef rtk::ThreeDCircularProjectionGeometry GeometryType;
  GeometryType::Pointer geometry = GeometryType::New();
  // Creating geometry
  for(unsigned int noProj=0; noProj<NumberOfProjectionImages; noProj++)
    geometry->AddProjection(47.5, 1000., noProj);

  // Calculating ray box intersection of the resized Input
  resizedInput->UpdateOutputInformation();
  rbi->SetInput( initInput->GetOutput() );
  rbi->SetBoxFromImage( resizedInput->GetOutput() );
  rbi->SetGeometry( geometry );
  rbi->Update();

  // Calculating Joseph forward projection of the full Input with an inner ray source
  jfp->SetInput(initInput->GetOutput());
  jfp->SetInput( 1, fullInput->GetOutput() );
  jfp->SetGeometry( geometry );
  jfp->Update();

  CheckImageQuality<OutputImageType>(rbi->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  std::cout << "\n\n****** Case 2: inner ray source, 90 degrees and source not in the middle of a pixel ******" << std::endl;
  // Geometry
  geometry = GeometryType::New();
  // Creating geometry
  for(unsigned int noProj=0; noProj<NumberOfProjectionImages; noProj++)
    geometry->AddProjection(47.3, 1000., noProj+90);
  // Creating the Box
  VectorType boxMin, boxMax;
  boxMin[0] = -127.;
  boxMin[1] = -127.;
  boxMin[2] = -127.;
  boxMax[0] = boxMin[0]+174.8;
  boxMax[1] = boxMin[1]+255.;
  boxMax[2] = boxMin[2]+255.;

  // Calculating ray box intersection of the resized Input
  resizedInput->UpdateOutputInformation();
  rbi->SetInput( initInput->GetOutput() );
  rbi->SetBoxMin(boxMin);
  rbi->SetBoxMax(boxMax);
  rbi->SetGeometry( geometry );
  rbi->Update();

  // Calculating Joseph forward projection of the full Input with an inner ray source
  jfp->SetInput(initInput->GetOutput());
  jfp->SetInput( 1, fullInput->GetOutput() );
  jfp->SetGeometry( geometry );
  jfp->SetNumberOfThreads(1);
  jfp->Update();

  CheckImageQuality<OutputImageType>(rbi->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  std::cout << "\n\n****** Case 3: outer ray source ******" << std::endl;
  // Geometry
  geometry = GeometryType::New();
  // Creating geometry
  for(unsigned int noProj=0; noProj<NumberOfProjectionImages; noProj++)
    geometry->AddProjection(128.5, 1000., noProj);
  // We resize resizedInput, in order to have a full Input 255x255x255
  size[0] = 255;
  size[1] = 255;
  size[2] = 255;
  resizedInput->SetSize( size );

  // Calculating ray box intersection of the resized Input
  resizedInput->UpdateOutputInformation();
  rbi->SetInput( initInput->GetOutput() );
  rbi->SetBoxFromImage( resizedInput->GetOutput() );
  rbi->SetGeometry( geometry );
  rbi->Update();

  // Calculating Joseph forward projection of the full Input with an inner ray source
  jfp->SetInput(initInput->GetOutput());
  jfp->SetInput( 1, fullInput->GetOutput() );
  jfp->SetGeometry( geometry );
  jfp->Update();

  CheckImageQuality<OutputImageType>(rbi->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  std::cout << "\n\n****** Case 4: Shepp-Logan, outer ray source ******" << std::endl;
  // Geometry
  geometry = GeometryType::New();
  // Creating geometry
  for(unsigned int noProj=0; noProj<NumberOfProjectionImages; noProj++)
    geometry->AddProjection(120, 256., noProj);

  // Create a reference object (in this case a 3D phantom reference).
  typedef rtk::DrawSheppLoganFilter<OutputImageType, OutputImageType> DSLType;
  DSLType::Pointer dsl = DSLType::New();

  size[0] = 255;
  size[1] = 255;
  size[2] = 1; //Number of Projections
  initInput->SetSize( size );
  initInput->UpdateOutputInformation();

  typedef rtk::SheppLoganPhantomFilter<OutputImageType, OutputImageType> SLPType;
  SLPType::Pointer slp=SLPType::New();
  slp->SetInput(initInput->GetOutput());
  slp->SetGeometry(geometry);
  slp->SetPhantomScale(128.);
  slp->Update();

  dsl = DSLType::New();
  dsl->SetInput( sheppFullInput->GetOutput() );
  dsl->SetPhantomScale(128.);
  TRY_AND_EXIT_ON_ITK_EXCEPTION( dsl->Update() )

  // Calculating Joseph forward projection of the full Input with an inner ray source
  jfp->SetInput(initInput->GetOutput());
  jfp->SetInput( 1, dsl->GetOutput() );
  jfp->SetGeometry( geometry );
  jfp->Update();

  CheckImageQuality<OutputImageType>(slp->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  return EXIT_SUCCESS;
}
<commit_msg>Improved forward projection test<commit_after>
#include "rtkThreeDCircularProjectionGeometryXMLFile.h"
#include "rtkRayBoxIntersectionImageFilter.h"
#include "rtkJosephForwardProjectionImageFilter.h"
#include "rtkSheppLoganPhantomFilter.h"
#include "rtkDrawSheppLoganFilter.h"
#include "rtkConstantImageSource.h"

template<class TImage>
void CheckImageQuality(typename TImage::Pointer recon, typename TImage::Pointer ref)
{
  typedef itk::ImageRegionConstIterator<TImage> ImageIteratorType;
  ImageIteratorType itTest( recon, recon->GetBufferedRegion() );
  ImageIteratorType itRef( ref, ref->GetBufferedRegion() );

  typedef double ErrorType;
  ErrorType TestError = 0.;
  ErrorType EnerError = 0.;

  itTest.GoToBegin();
  itRef.GoToBegin();

  while( !itRef.IsAtEnd() )
    {
    typename TImage::PixelType TestVal = itTest.Get();
    typename TImage::PixelType RefVal = itRef.Get();

    if( TestVal != RefVal )
      {
      TestError += vcl_abs(RefVal - TestVal);
      EnerError += vcl_pow(ErrorType(RefVal - TestVal), 2.);
      }
    ++itTest;
    ++itRef;
    }
  // Error per Pixel
  ErrorType ErrorPerPixel = TestError/recon->GetBufferedRegion().GetNumberOfPixels();
  std::cout << "\nError per Pixel = " << ErrorPerPixel << std::endl;
  // MSE
  ErrorType MSE = EnerError/ref->GetBufferedRegion().GetNumberOfPixels();
  std::cout << "MSE = " << MSE << std::endl;
  // PSNR
  ErrorType PSNR = 20*log10(255.0) - 10*log10(MSE);
  std::cout << "PSNR = " << PSNR << "dB" << std::endl;
  // QI
  ErrorType QI = (255.0-ErrorPerPixel)/255.0;
  std::cout << "QI = " << QI << std::endl;

  // Checking results
  if (ErrorPerPixel > 1.25)
    {
    std::cerr << "Test Failed, Error per pixel not valid! "
              << ErrorPerPixel << " instead of 1.25" << std::endl;
    exit( EXIT_FAILURE);
    }
  if (PSNR < 44.)
    {
    std::cerr << "Test Failed, PSNR not valid! "
              << PSNR << " instead of 44" << std::endl;
    exit( EXIT_FAILURE);
    }
}

int main(int , char** )
{
  const unsigned int Dimension = 3;
  typedef float                                    OutputPixelType;
  typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
  typedef itk::Vector<double, 3>                   VectorType;
  const unsigned int NumberOfProjectionImages = 45;

  // Constant image sources
  typedef rtk::ConstantImageSource< OutputImageType > ConstantImageSourceType;
  ConstantImageSourceType::PointType origin;
  ConstantImageSourceType::SizeType size;
  ConstantImageSourceType::SpacingType spacing;

  // The test projects a volume filled with ones. The forward projector should
  // then return the intersection of the ray with the box and it is compared
  // with the analytical intersection of a box with a ray.

  // Create Joseph Forward Projector volume input.
  const ConstantImageSourceType::Pointer volInput = ConstantImageSourceType::New();
  origin[0] = -126;
  origin[1] = -126;
  origin[2] = -126;
  size[0] = 64;
  size[1] = 64;
  size[2] = 64;
  spacing[0] = 4.;
  spacing[1] = 4.;
  spacing[2] = 4.;
  volInput->SetOrigin( origin );
  volInput->SetSpacing( spacing );
  volInput->SetSize( size );
  volInput->SetConstant( 1. );
  volInput->UpdateOutputInformation();

  // Initialization Volume, it is used in the Joseph Forward Projector and in the
  // Ray Box Intersection Filter in order to initialize the stack of projections.
  const ConstantImageSourceType::Pointer projInput = ConstantImageSourceType::New();
  size[2] = NumberOfProjectionImages;
  projInput->SetOrigin( origin );
  projInput->SetSpacing( spacing );
  projInput->SetSize( size );
  projInput->SetConstant( 0. );
  projInput->Update();

  // Joseph Forward Projection filter
  typedef rtk::JosephForwardProjectionImageFilter<OutputImageType, OutputImageType> JFPType;
  JFPType::Pointer jfp = JFPType::New();
  jfp->InPlaceOff();
  jfp->SetInput( projInput->GetOutput() );
  jfp->SetInput( 1, volInput->GetOutput() );

  // Ray Box Intersection filter (reference)
  typedef rtk::RayBoxIntersectionImageFilter<OutputImageType, OutputImageType> RBIType;
  RBIType::Pointer rbi = RBIType::New();
  rbi->InPlaceOff();
  rbi->SetInput( projInput->GetOutput() );
  VectorType boxMin, boxMax;
  boxMin[0] = -128.0;
  boxMin[1] = -128.0;
  boxMin[2] = -128.0;
  boxMax[0] =  128.0;
  boxMax[1] =  128.0;
  boxMax[2] =   47.6;
  rbi->SetBoxMin(boxMin);
  rbi->SetBoxMax(boxMax);

  std::cout << "\n\n****** Case 1: inner ray source ******" << std::endl;
  // The circle is divided in 4 quarters
  for(int q=0; q<4; q++) {
    // Geometry
    typedef rtk::ThreeDCircularProjectionGeometry GeometryType;
    GeometryType::Pointer geometry = GeometryType::New();
    for(unsigned int i=0; i<NumberOfProjectionImages;i++)
      {
      const double angle = -45. + i*2.;
      geometry->AddProjection(47.6 / vcl_cos(angle*itk::Math::pi/180.), 1000., q*90+angle);
      }

    if(q==0) {
      rbi->SetGeometry( geometry );
      rbi->Update();
    }

    jfp->SetGeometry(geometry);
    jfp->Update();

    CheckImageQuality<OutputImageType>(rbi->GetOutput(), jfp->GetOutput());
    std::cout << "\n\nTest of quarter #" << q << " PASSED! " << std::endl;
  }

  std::cout << "\n\n****** Case 2: outer ray source ******" << std::endl;
  boxMax[2] = 128.0;
  rbi->SetBoxMax(boxMax);

  // Geometry
  typedef rtk::ThreeDCircularProjectionGeometry GeometryType;
  GeometryType::Pointer geometry = GeometryType::New();
  for(unsigned int i=0; i<NumberOfProjectionImages; i++)
    geometry->AddProjection(500., 1000., i*8.);

  rbi->SetGeometry( geometry );
  rbi->Update();

  jfp->SetGeometry( geometry );
  jfp->Update();

  CheckImageQuality<OutputImageType>(rbi->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  std::cout << "\n\n****** Case 3: Shepp-Logan, outer ray source ******" << std::endl;

  // Create Shepp Logan reference projections
  typedef rtk::SheppLoganPhantomFilter<OutputImageType, OutputImageType> SLPType;
  SLPType::Pointer slp = SLPType::New();
  slp->InPlaceOff();
  slp->SetInput( projInput->GetOutput() );
  slp->SetGeometry(geometry);
  slp->Update();

  // Create a Shepp Logan reference volume (finer resolution)
  origin.Fill(-127);
  size.Fill(128);
  spacing.Fill(2.);
  volInput->SetOrigin( origin );
  volInput->SetSpacing( spacing );
  volInput->SetSize( size );
  volInput->SetConstant( 0. );

  typedef rtk::DrawSheppLoganFilter<OutputImageType, OutputImageType> DSLType;
  DSLType::Pointer dsl = DSLType::New();
  dsl->InPlaceOff();
  dsl->SetInput( volInput->GetOutput() );
  dsl->Update();

  // Forward projection
  jfp->SetInput( 1, dsl->GetOutput() );
  jfp->Update();

  CheckImageQuality<OutputImageType>(slp->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  std::cout << "\n\n****** Case 4: Shepp-Logan, inner ray source ******" << std::endl;
  geometry = GeometryType::New();
  for(unsigned int i=0; i<NumberOfProjectionImages; i++)
    geometry->AddProjection(120., 1000., i*8.);

  slp->SetGeometry(geometry);
  slp->Update();

  jfp->SetGeometry( geometry );
  jfp->Update();

  CheckImageQuality<OutputImageType>(slp->GetOutput(), jfp->GetOutput());
  std::cout << "\n\nTest PASSED! " << std::endl;

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// This reads a file stored using write_file_blocking.cc using the blocking API

#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <inttypes.h>

#include "protobufutil/message_stream.h"

#include "kinetic/connection_options.h"
#include "kinetic/kinetic_connection_factory.h"
#include "value_factory.h"

using com::seagate::kinetic::HmacProvider;
using com::seagate::kinetic::proto::Message;
using com::seagate::kinetic::proto::Message_MessageType_GET;
using com::seagate::kinetic::proto::Message_Algorithm_SHA1;
using com::seagate::kinetic::ValueFactory;
using kinetic::KineticConnectionFactory;
using kinetic::Status;
using kinetic::KineticRecord;
using palominolabs::protobufutil::MessageStreamFactory;

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

    if (argc != 4) {
        printf("%s: <host> <kinetic key> <output file name>\n", argv[0]);
        return 1;
    }

    const char* host = argv[1];
    const char* kinetic_key = argv[2];
    const char* output_file_name = argv[3];

    kinetic::ConnectionOptions options;
    options.host = host;
    options.port = 8123;
    options.user_id = 1;
    options.hmac_key = "asdfasdf";

    KineticConnectionFactory kinetic_connection_factory = kinetic::NewKineticConnectionFactory();

    kinetic::ConnectionHandle* connection;
    if(!kinetic_connection_factory.NewConnection(options, &connection).ok()) {
        printf("Unable to connect\n");
        return 1;
    }

    KineticRecord* record;
    if(!connection->blocking().Get(kinetic_key, &record).ok()) {
        printf("Unable to get metadata\n");
        return 1;
    }

    ssize_t file_size = std::stoll(record->value());
    delete record;
    printf("Reading file of size %zd\n", file_size);

    int file = open(output_file_name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if(!file) {
        printf("Unable to open output file\n");
        return 1;
    }
    if(file_size - 1 != lseek(file, file_size - 1, SEEK_SET)) {
        printf("Unable to seek\n");
        return 1;
    }
    if(write(file, " ", 1) != 1) {
        printf("Unable to resize file\n");
        return 1;
    }
    char* output_buffer = (char*)mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
    char key_buffer[100];
    for (int64_t i = 0; i < file_size; i += 1024*1024) {
        int block_length = 1024*1024;
        if (i + block_length > file_size) {
            block_length = file_size - i;
        }

        sprintf(key_buffer, "%s-%10" PRId64, kinetic_key, i);
        std::string key(key_buffer);

        KineticRecord* record;
        if(!connection->blocking().Get(key, &record).ok()) {
            printf("Unable to get chunk\n");
            return 1;
        }
        delete record;
        record->value().copy(output_buffer + i, block_length);
        printf(".");
        fflush(stdout);
    }
    printf("\n");

    if(close(file)) {
        printf("Unable to close file\n");
        return 1;
    }

    printf("Done!\n");

    return 0;
}
<commit_msg>Fixed memory leak in read_file_blocking<commit_after>// This reads a file stored using write_file_blocking.cc using the blocking API

#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <inttypes.h>

#include "protobufutil/message_stream.h"

#include "kinetic/connection_options.h"
#include "kinetic/kinetic_connection_factory.h"
#include "value_factory.h"

using com::seagate::kinetic::HmacProvider;
using com::seagate::kinetic::proto::Message;
using com::seagate::kinetic::proto::Message_MessageType_GET;
using com::seagate::kinetic::proto::Message_Algorithm_SHA1;
using com::seagate::kinetic::ValueFactory;
using kinetic::KineticConnectionFactory;
using kinetic::Status;
using kinetic::KineticRecord;
using palominolabs::protobufutil::MessageStreamFactory;

int main(int argc, char* argv[]) {
    google::InitGoogleLogging(argv[0]);

    if (argc != 4) {
        printf("%s: <host> <kinetic key> <output file name>\n", argv[0]);
        return 1;
    }

    const char* host = argv[1];
    const char* kinetic_key = argv[2];
    const char* output_file_name = argv[3];

    kinetic::ConnectionOptions options;
    options.host = host;
    options.port = 8123;
    options.user_id = 1;
    options.hmac_key = "asdfasdf";

    KineticConnectionFactory kinetic_connection_factory = kinetic::NewKineticConnectionFactory();

    kinetic::ConnectionHandle* connection;
    if(!kinetic_connection_factory.NewConnection(options, &connection).ok()) {
        printf("Unable to connect\n");
        return 1;
    }

    KineticRecord* record;
    if(!connection->blocking().Get(kinetic_key, &record).ok()) {
        printf("Unable to get metadata\n");
        return 1;
    }

    ssize_t file_size = std::stoll(record->value());
    delete record;
    printf("Reading file of size %zd\n", file_size);

    int file = open(output_file_name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if(!file) {
        printf("Unable to open output file\n");
        return 1;
    }
    if(file_size - 1 != lseek(file, file_size - 1, SEEK_SET)) {
        printf("Unable to seek\n");
        return 1;
    }
    if(write(file, " ", 1) != 1) {
        printf("Unable to resize file\n");
        return 1;
    }
    char* output_buffer = (char*)mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, file, 0);
    char key_buffer[100];
    for (int64_t i = 0; i < file_size; i += 1024*1024) {
        int block_length = 1024*1024;
        if (i + block_length > file_size) {
            block_length = file_size - i;
        }

        sprintf(key_buffer, "%s-%10" PRId64, kinetic_key, i);
        std::string key(key_buffer);

        KineticRecord* record;
        if(!connection->blocking().Get(key, &record).ok()) {
            printf("Unable to get chunk\n");
            return 1;
        }

        record->value().copy(output_buffer + i, block_length);
        delete record;

        printf(".");
        fflush(stdout);
    }
    printf("\n");

    if(close(file)) {
        printf("Unable to close file\n");
        return 1;
    }

    printf("Done!\n");

    delete connection;

    google::protobuf::ShutdownProtobufLibrary();
    google::ShutdownGoogleLogging();
    google::ShutDownCommandLineFlags();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Author: Dino Wernli
 */

#include "scene/geometry/triangle.h"

#include "renderer/intersection_data.h"
#include "util/ray.h"

Triangle::Triangle(const Point3& c1, const Point3& c2, const Point3& c3,
                   const Material* material, const Vector3* n1,
                   const Vector3* n2, const Vector3* n3)
    : material_(material), owns_vertices_(true) {
  Vector3 inferred_normal = c1.VectorTo(c2).Cross(c1.VectorTo(c3)).Normalized();
  vertex1_ = new Vertex(c1, n1 == NULL ? inferred_normal : n1->Normalized());
  vertex2_ = new Vertex(c2, n2 == NULL ? inferred_normal : n2->Normalized());
  vertex3_ = new Vertex(c3, n3 == NULL ? inferred_normal : n3->Normalized());
}

Triangle::Triangle(const Vertex* v1, const Vertex* v2, const Vertex* v3,
                   const Material* material)
    :  material_(material), vertex1_(v1), vertex2_(v2), vertex3_(v3),
       owns_vertices_(false) {
}

Triangle::~Triangle() {
  if (owns_vertices_) {
    delete vertex1_;
    delete vertex2_;
    delete vertex3_;
  }
}

bool Triangle::Intersect(const Ray& ray, IntersectionData* data) {
  Vector3 edge12(vertex1_->point().VectorTo(vertex2_->point()));
  Vector3 edge13(vertex1_->point().VectorTo(vertex3_->point()));

  Vector3 dir_cross_first(ray.direction().Cross(edge13));
  Scalar determinant = edge12.Dot(dir_cross_first);
  if (determinant > -EPSILON && determinant < EPSILON) {
    return false;
  }
  Scalar invdet = 1 / determinant;

  // Compute barycentric u.
  Vector3 vertex_to_origin(vertex1_->point().VectorTo(ray.origin()));
  Scalar u = vertex_to_origin.Dot(dir_cross_first) * invdet;
  if (u < 0 || u > 1) {
    return false;
  }

  // Compute barycentric v.
  Vector3 plane_normal = vertex_to_origin.Cross(edge12);
  Scalar v = ray.direction().Dot(plane_normal) * invdet;
  if (v < 0 || v > 1) {
    return false;
  }

  Scalar t = edge13.Dot(plane_normal) * invdet;
  bool found = ray.InRange(t) && (data == NULL || t < data->t);
  if (found && data != NULL) {
    data->element = this;
    data->position = ray.PointAt(t);
    data->normal = vertex1_->normal() * (1 - u - v) + vertex2_->normal() * u
                   + vertex3_->normal() * v;
    data->material = material_;
    data->t = t;
  }
  return found;
}
<commit_msg>Fix triangle intersection.<commit_after>/*
 * Author: Dino Wernli
 */

#include "scene/geometry/triangle.h"

#include "renderer/intersection_data.h"
#include "util/ray.h"

Triangle::Triangle(const Point3& c1, const Point3& c2, const Point3& c3,
                   const Material* material, const Vector3* n1,
                   const Vector3* n2, const Vector3* n3)
    : material_(material), owns_vertices_(true) {
  Vector3 inferred_normal = c1.VectorTo(c2).Cross(c1.VectorTo(c3)).Normalized();
  vertex1_ = new Vertex(c1, n1 == NULL ? inferred_normal : n1->Normalized());
  vertex2_ = new Vertex(c2, n2 == NULL ? inferred_normal : n2->Normalized());
  vertex3_ = new Vertex(c3, n3 == NULL ? inferred_normal : n3->Normalized());
}

Triangle::Triangle(const Vertex* v1, const Vertex* v2, const Vertex* v3,
                   const Material* material)
    :  material_(material), vertex1_(v1), vertex2_(v2), vertex3_(v3),
       owns_vertices_(false) {
}

Triangle::~Triangle() {
  if (owns_vertices_) {
    delete vertex1_;
    delete vertex2_;
    delete vertex3_;
  }
}

bool Triangle::Intersect(const Ray& ray, IntersectionData* data) {
  Vector3 edge12(vertex1_->point().VectorTo(vertex2_->point()));
  Vector3 edge13(vertex1_->point().VectorTo(vertex3_->point()));

  Vector3 dir_cross_first(ray.direction().Cross(edge13));
  Scalar determinant = edge12.Dot(dir_cross_first);
  if (determinant > -EPSILON && determinant < EPSILON) {
    return false;
  }
  Scalar invdet = 1 / determinant;

  // Compute barycentric u.
  Vector3 vertex_to_origin(vertex1_->point().VectorTo(ray.origin()));
  Scalar u = vertex_to_origin.Dot(dir_cross_first) * invdet;
  if (u < 0 || u > 1) {
    return false;
  }

  // Compute barycentric v.
  Vector3 plane_normal = vertex_to_origin.Cross(edge12);
  Scalar v = ray.direction().Dot(plane_normal) * invdet;
  if (v < 0 || v + u > 1) {
    return false;
  }

  Scalar t = edge13.Dot(plane_normal) * invdet;
  bool found = ray.InRange(t) && (data == NULL || t < data->t);
  if (found && data != NULL) {
    data->element = this;
    data->position = ray.PointAt(t);
    data->normal = vertex1_->normal() * (1 - u - v) + vertex2_->normal() * u
                   + vertex3_->normal() * v;
    data->material = material_;
    data->t = t;
  }
  return found;
}
<|endoftext|>