VC++のC++言語標準をISO C++ 20に設定したところ、以下のエラーが出た。
Open3DConfig.h を確認してみると、バージョン 0.9.0.0だった。
#define OPEN3D_VERSION "0.9.0.0"
調べた限りまともな対処法がないので、Open3Dを最新版にする。
公式 https://www.open3d.org/ の下のほうへ行き、0.18.0を選択する。
展開してC++20で使用。
そのままだとC4996が出るので、#pragma warning(disalbe:4996) を入れる。
あるいは
_SILENCE_CXX20_IS_POD_DEPRECATION_WARNING
_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
を定義する。
#pragma warning(disable:4996) #if defined(_DEBUG) #pragma comment(lib,"C:\\libraries\\Open3D-0.18.0\\debug\\lib\\Open3D.lib") #else #pragma comment(lib,"C:\\libraries\\Open3D-0.18.0\\release\\lib\\Open3D.lib") #endif #include <Open3D/Open3D.h> #include <iostream> int main() { std::string filename = "bunny.ply"; auto mesh = open3d::io::CreateMeshFromFile(filename); auto pcd = open3d::io::CreatePointCloudFromFile(filename); }
以下のように、StatisticalOutlierRemovalを使ってみると、Eigenのコード内で、aligned_freeで例外が発生する。
#include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> #include <pcl/filters/statistical_outlier_removal.h> pcl::PointCloud<pcl::PointXYZ>::Ptr create_cloud() { // 点群データの生成 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>()); cloud->width = 1000; cloud->height = 1; cloud->is_dense = false; cloud->points.resize(cloud->width * cloud->height); for (size_t i = 0; i < cloud->points.size(); ++i) { cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f); cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f); cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f); } return cloud; }
int main(int argc, char** argv) { auto cloud = create_cloud(); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud(cloud); sor.setMeanK(50); sor.setStddevMulThresh(1.0); sor.filter(*cloud_filtered); return 0; }
C:/Program Files/PCL 1.14.1/3rdParty/Eigen3/include/eigen3/Eigen/src/Core/util/memory.h
ファイル内、以下の部分で例外が発生。
/** \internal Frees memory allocated with aligned_malloc. */ EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr) { #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED EIGEN_USING_STD(free) free(ptr); #else handmade_aligned_free(ptr); #endif }
C/C++ → コード生成 → 拡張命令セットを有効にする → Advanced Vector Extensions (X86/X64) (/arch:AVX)
に設定
VTKのvtkSmartPointerは参照カウンタ付きだが、vtkWeakPointerもある(初めて知った)。
まず以下は、vtkSmartPointerを使った場合で、ポインタをコピーするたびに参照カウンタが増え、ポインタにnullptrを代入して無効化することで参照カウンタが減ることを確認する。
vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New(); std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; vtkSmartPointer<vtkActor> actor2 = actor1; std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl; actor1 = nullptr;// actor1を無効化 std::cout << "Delete" << std::endl; // ここは通らない if(actor1) std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; if(actor2) std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl;
vtkWeakPointer<vtkActor> weak_actor; // WeakPointerを定義
{ vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New(); std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; weak_actor = actor1;// actor1 を弱参照 参照カウンタは増えない std::cout << "weak_actor reference count: " << weak_actor->GetReferenceCount() << std::endl; vtkSmartPointer<vtkActor> actor2 = actor1; std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl; actor1 = nullptr; std::cout << "Delete" << std::endl; // ここは通らない if (actor1) std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; if (actor2) std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl; }
if (weak_actor) { // ここは通らない std::cout << "actor1 reference count: " << weak_actor->GetReferenceCount() << std::endl; } else { // こちらを通る std::cout << "actor is deleted" << std::endl; }
gumbo-parseがどのようにデータを保持しているのかをチェックするためのコード。
タグはenumで区別するため、タグ名は保持していない。<から始まっていることを利用してstd::regexでタグ名を取得している。
#include <iostream> #include <fstream> #include <sstream> #include <regex> #include <gumbo.h>
std::string getTagName(std::string str) { // HTMLのタグ名を取得する関数 // タグは< > で囲まれているが、attribute等があるかもしれないので // < スペース 文字列 という構造になっている部分の文字列部分だけを取り出す std::regex tagPattern("<\\s*([^ >]+)\\s*"); std::smatch matches; std::regex_search(str, matches, tagPattern); return matches[1].str(); }
void myTraceCore(const GumboNode* node, const char* src) { switch (node->type) { case GUMBO_NODE_ELEMENT: { // 要素開始位置 const char* tag_start = node->v.element.original_tag.data; // 要素終了位置 const char* tag_end = node->v.element.original_end_tag.data; std::string tagname; // タグ名を抽出 tagname = getTagName(tag_start); std::cout << "tag: '" << tagname << "'" << std::endl; // 子要素一覧へアクセス const GumboVector* children = &node->v.element.children; // 子要素がある場合 if (children->length > 0) { for (unsigned int i = 0; i < children->length; ++i) { const GumboNode* node = static_cast<GumboNode*>(children->data[i]); myTraceCore(node, src); } } // タグ名を抽出 tagname = getTagName(tag_end); std::cout << "tag: '" << tagname << "'" << std::endl; break; } case GUMBO_NODE_TEXT: // テキストノードの場合 std::cout << "text: '" << node->v.text.text << "'" << std::endl; break; case GUMBO_NODE_WHITESPACE: // 空白ノードの場合 std::cout << "whitespace: '" << node->v.text.text << "'" << std::endl; break; default: std::cout << "others: '" << node->v.text.text << "'" << std::endl; break; } }
void myTrace(std::string html) { // Gumboでパース GumboOutput* output = gumbo_parse(html.c_str()); // 自作関数の本体呼び出し myTraceCore(output->root,html.c_str()); // GumboOutputの解放 gumbo_destroy_output(&kGumboDefaultOptions, output); } int main() { std::string html = R"( <!DOCTYPE html> <html> <head> <title>The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; myTrace(html); }
tag: 'html' tag: 'head' whitespace: ' ' tag: 'title' text: 'The Title' tag: '/title' whitespace: ' ' tag: '/head' whitespace: ' ' tag: 'body' whitespace: ' ' tag: 'h1' text: 'Test' tag: '/h1' whitespace: ' ' tag: '/body' tag: '/html'
node->typeがGUMBO_NODE_ELEMENTの時は、属性を取得できる。
#include <iostream> #include <fstream> #include <sstream> #include <regex> #include <gumbo.h>
// 要素の属性を取得する関数 void myAttributes(const GumboNode* node) { if (node->type != GUMBO_NODE_ELEMENT) { return; } // 要素の属性を取得 const GumboVector* attributes = &node->v.element.attributes; // 属性リストへアクセス for (unsigned int i = 0; i < attributes->length; ++i) { GumboAttribute* attr = (GumboAttribute*)attributes->data[i]; std::cout << " "; std::cout << " " << attr->name << " : " << attr->value << std::endl; } }
void myTraceCore(const GumboNode* node, const char* src) { switch (node->type) { case GUMBO_NODE_ELEMENT: {
/* ... */ myAttributes(node); // 要素の取得
/* ... */ break; } /* ... */ } }
int main() { std::string html = R"( <!DOCTYPE html> <html> <head> <title id = "bodyid" style="color:red;">The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; myTrace(html); }
id : bodyid
style : color:red;
HTMLを扱う方法を探している。gumbo-parserはgoogleが公開したApache-2.0 licenseのパーサー。
ソースコードをGitHubからダウンロード・展開する。
https://github.com/google/gumbo-parser
CMake不要。.cファイルをコピーしてプロジェクトに加える。
注意点として、windowsにはstrings.hが存在しない。
追加のインクルードディレクトリ:
visualc/includeにはstrings.hが入っている。
・gumbo-parser-master/src
・gumbo-parser-master/visualc/include
プロジェクトへ追加
src/*.c ファイルをプロジェクトへ追加する。
attribute.c
char_ref.c
error.c
parser.c
string_buffer.c
string_piece.c
tag.c
tokenizer.c
utf8.c
util.c
vector.c
・gumbo_parse関数でパースを行う。
・GumboVectorはGumboNodeの配列となっている。
・node->v.element.children->data から子ノードにアクセスできる
#include <iostream> #include <fstream> #include <sstream> #include <gumbo.h>
std::unique_ptr<std::string> getTitleCore(const GumboNode* node) { // ノードがHTML要素の場合だけ処理 if (node->type == GUMBO_NODE_ELEMENT) { // titleタグの場合 if (node->v.element.tag == GUMBO_TAG_TITLE) {
// 子要素一覧へアクセス const GumboVector* children = &node->v.element.children; // 子要素がある場合 if (children->length > 0) { // 子要素の先頭を取得 const GumboNode* child = static_cast<GumboNode*>(children->data[0]); if (child->type == GUMBO_NODE_TEXT) { return std::make_unique<std::string>(child->v.text.text); } }
}
// titleタグ以外の場合、このタグの子要素を全て調査。それを再帰的に行う else {
const GumboVector* children = &node->v.element.children; for (unsigned int i = 0; i < children->length; ++i) { std::unique_ptr<std::string> result = getTitleCore(static_cast<GumboNode*>(children->data[i])); if (result != nullptr) { return result; } }
}
} return nullptr; }
std::unique_ptr<std::string> getTitle(std::string html) { // Gumboでパース GumboOutput* output = gumbo_parse(html.c_str()); // タイトルを取得する自作関数の本体呼び出し std::unique_ptr<std::string> result = getTitleCore(output->root); // GumboOutputの解放 gumbo_destroy_output(&kGumboDefaultOptions, output); return result; }
int main() { std::string html = R"( <html> <head> <title>The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; std::unique_ptr<std::string> mytitle = getTitle(html); if (mytitle != nullptr) { std::cout << *mytitle << std::endl; } else { std::cout << "** No title **" << std::endl; } }
wxStyledTextCtrlはscintillaというオープンソースのエディタを元に実装されたコントロールで、様々な言語をハイライトできる。
例えば以下のようにStyleSetForegroundを使用すると設定した項目をハイライトできる
//wxStyledTextCtrl #include <wx/stc/stc.h> /* ... */ // ウィンドウ作成 class MyFrame : public wxFrame { public: void PostCreate() {
auto editor = new wxStyledTextCtrl(this, wxID_ANY); editor->SetLexer(wxSTC_LEX_HTML); // HTMLのシンタックスハイライトを設定 editor->StyleSetForeground(wxSTC_H_TAG, wxColour(0, 0, 255)); // タグの色を青に設定 editor->StyleSetForeground(wxSTC_H_ATTRIBUTE, wxColour(255, 255, 0)); editor->StyleSetForeground(wxSTC_H_VALUE, wxColour(0, 0, 0)); editor->StyleSetForeground(wxSTC_H_COMMENT, wxColour(0, 255, 0));
this->Layout(); // レイアウトの更新 } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { CallAfter(&MyFrame::PostCreate); } private: }; /* ... */
void PostCreate() { // #include <wx/stc/stc.h> が必要 auto editor = new wxStyledTextCtrl(this, wxID_ANY); // テキストの設定 editor->SetText("<html>\n<head>\n<title>Sample</title>\n</head>\n<body>\n<!-- 本文 -->\n<h1>Hello World</h1>\n</body>\n</html>"); // テキストの設定 editor->SetLexer(wxSTC_LEX_HTML); // HTMLのシンタックスハイライトを設定 editor->StyleSetForeground(wxSTC_H_TAG, wxColour(0, 0, 255)); // タグの色を赤に設定 editor->StyleSetForeground(wxSTC_H_ATTRIBUTE, wxColour(255, 0, 255)); editor->StyleSetForeground(wxSTC_H_VALUE, wxColour(0, 0, 0)); editor->StyleSetForeground(wxSTC_H_COMMENT, wxColour(0, 255, 0)); // コメントの色を緑に設定 editor->StyleSetBackground(wxSTC_H_COMMENT, wxColour(0, 0, 0)); // コメントの背景色を黒に設定 this->Layout(); // レイアウトの更新 }
void PostCreate() { auto editor = new wxStyledTextCtrl(this, wxID_ANY); editor->SetLexer(wxSTC_LEX_HTML); // HTMLのシンタックスハイライトを設定 //// 左側にマージンを追加し、その列に表示するものを設定 //// マージンインデクスは左側に追加する列番号と考えればよい //// マージンに表示するものを行番号に設定 editor->SetMarginType(0, wxSTC_MARGIN_NUMBER);
//// 左側にマージン(スペース)を作成 editor->SetMarginWidth(0/*マージンインデクス*/, 40/*マージンのピクセル幅*/); // テキストの設定 editor->SetText(R"( <html> <body> <div> <!-- 本文 --> <h1>Hello World</h1> </div> </body> </html>)"); /* ... */
this->Layout(); // レイアウトの更新 }
void PostCreate() { auto editor = new wxStyledTextCtrl(this, wxID_ANY); editor->SetLexer(wxSTC_LEX_HTML); // HTMLのシンタックスハイライトを設定 // インデントガイド editor->SetIndentationGuides(wxSTC_IV_LOOKBOTH); //editor->SetTabWidth(4); editor->SetIndent(4); editor->StyleSetForeground(wxSTC_STYLE_INDENTGUIDE, wxColour(50, 50, 50)); // インデントガイドの色を設定 // テキストの設定 editor->SetText(R"( <html> <body> <div> <!-- 本文 --> <h1>Hello World</h1> </div> </body> </html>)"); // テキストの設定 /* ... */
this->Layout(); // レイアウトの更新 }
void PostCreate() { editor = new wxStyledTextCtrl(this, wxID_ANY); //editor->SetLexer(wxSTC_LEX_HTML); // HTMLのシンタックスハイライトを設定 editor->SetLexer(wxSTC_LEX_CPP); // マージン1をコード折り畳み用のシンボルマージンとして設定 folder_margin_id = 1; editor->SetMarginType(folder_margin_id, wxSTC_MARGIN_SYMBOL); editor->SetMarginMask(folder_margin_id, wxSTC_MASK_FOLDERS); //editor->SetMarginWidth(1, 16); // マージンの幅を設定 editor->SetMarginSensitive(folder_margin_id, true); // マージンをクリック可能にする // 折り畳みのマーカーの設定 // editor->MarkerDefine(設定する対象 , どのマークを使うか , 背景色, 前景色) // トップレベルの+/-マーカーを設定 editor->MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, wxColour(255, 255, 255), wxColour(0, 0, 0)); editor->MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, wxColour(255, 255, 255), wxColour(0, 0, 0)); // 垂直線を引く editor->MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE,wxColour(0,0,0), wxColour(0, 0, 0)); // 折り畳みの中間の+/-マーカーを設定 editor->MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, wxColour(255, 0, 0), wxColour(0, 0, 0)); editor->MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, wxColour(0,255, 0), wxColour(255, 255, 255)); // 折り畳みの中間の終了マーク editor->MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, wxColour(0, 0, 0), wxColour(255, 0, 255)); // トップレベルの終了マーク editor->MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, wxColour(0, 0, 0), wxColour(0, 255, 255)); // 折り畳みの有効化 editor->SetProperty("fold", "1"); editor->SetFoldFlags(0 /*wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED | wxSTC_FOLDFLAG_LINEAFTER_EXPANDED*/); // テキストの設定 editor->SetText(R"(
#include <iostream> int main() { int i = 0; for(i = 0; i < 10; i++) { if( i % 2 == 0) { std::cout << "even "; } else { std::cout << "odd "; } std::cout << i << std::endl; } return 0; }
)"); editor->Bind(wxEVT_STC_MARGINCLICK, &MyFrame::OnMarginClick, this); this->Layout(); // レイアウトの更新 }
void OnMarginClick(wxStyledTextEvent& event) { // マージンに表示されたマークをクリックしたときのイベント処理 if (event.GetMargin() == folder_margin_id) { int lineClick = editor->LineFromPosition(event.GetPosition()); int levelClick = editor->GetFoldLevel(lineClick); if ((levelClick & wxSTC_FOLDLEVELHEADERFLAG) > 0) { editor->ToggleFold(lineClick); } } }
公式に詳しく書いてある。
{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} ... C++であることを表すGUID。定数。
TestApplicationCPP ... プロジェクト名。ただし変えても影響ない(なぜ)。
TestApplicationCPP\TestApplicationCPP.vcxproj ... プロジェクトファイルへのパス
{BCFFEF98-34EF-437F-BE38-8A084328984F} ... プロジェクトを一意に表す識別子。GUID。プロジェクトを作るたびに変わる。
{722044A8-0732-4C11-87C7-85A5DDFF9F78} ... ソリューションを一意に表す識別子。GUID。ソリューションを作るたびに変わる。
Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33530.505 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestApplicationCPP", "TestApplicationCPP\TestApplicationCPP.vcxproj", "{BCFFEF98-34EF-437F-BE38-8A084328984F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {BCFFEF98-34EF-437F-BE38-8A084328984F}.Debug|x64.ActiveCfg = Debug|x64 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Debug|x64.Build.0 = Debug|x64 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Debug|x86.ActiveCfg = Debug|Win32 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Debug|x86.Build.0 = Debug|Win32 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Release|x64.ActiveCfg = Release|x64 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Release|x64.Build.0 = Release|x64 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Release|x86.ActiveCfg = Release|Win32 {BCFFEF98-34EF-437F-BE38-8A084328984F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {722044A8-0732-4C11-87C7-85A5DDFF9F78} EndGlobalSection EndGlobal
TestApplicationCPPの部分は変更してもどこにも反映されず影響もないが、直後のvcxprojへのパスが間違った場合のみ、エラー表記中にこの文字列が表示される。
せっかくなので.vcxprojファイルの中も見てみる。こちらはxmlファイル。
例としてLuaのinclude設定、ライブラリ設定をしたプロジェクトを作成した。
<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <Configuration>Release</Configuration> <Platform>Win32</Platform> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64"> <Configuration>Debug</Configuration> <Platform>x64</Platform> </ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <Configuration>Release</Configuration> <Platform>x64</Platform> </ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals"> <VCProjectVersion>16.0</VCProjectVersion> <Keyword>Win32Proj</Keyword> <ProjectGuid>{bcffef98-34ef-437f-be38-8a084328984f}</ProjectGuid> <RootNamespace>TestApplicationCPP</RootNamespace> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <ProjectName>TestApplicationCPP</ProjectName> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <PlatformToolset>v143</PlatformToolset> <CharacterSet>Unicode</CharacterSet> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <PlatformToolset>v143</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>Unicode</CharacterSet> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <PlatformToolset>v143</PlatformToolset> <CharacterSet>Unicode</CharacterSet> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <PlatformToolset>v143</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>Unicode</CharacterSet> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> <ImportGroup Label="Shared"> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <WarningLevel>Level3</WarningLevel> <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> </ClCompile>
<Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> </Link> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <WarningLevel>Level3</WarningLevel> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> </ClCompile>
<Link> <SubSystem>Console</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <GenerateDebugInformation>true</GenerateDebugInformation> </Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <WarningLevel>Level3</WarningLevel> <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> <AdditionalIncludeDirectories>C:\libraries\lua\include</AdditionalIncludeDirectories> </ClCompile>
<Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> <AdditionalDependencies>lua54.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories>C:\libraries\lua</AdditionalLibraryDirectories> </Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <WarningLevel>Level3</WarningLevel> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> <AdditionalIncludeDirectories>C:\libraries\lua\include</AdditionalIncludeDirectories> </ClCompile>
<Link> <SubSystem>Console</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <GenerateDebugInformation>true</GenerateDebugInformation> <AdditionalLibraryDirectories>C:\libraries\lua</AdditionalLibraryDirectories> <AdditionalDependencies>lua54.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link>
</ItemDefinitionGroup>
<ItemGroup> <ClCompile Include="TestApplicationCPP.cpp" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup>
</Project>
Voxel Pluginを使ってみる。なお著者はUnreal Engineのプラグインを使うのが初めてである。
以下からダウンロード・インストール。なんかクリックしていくといつの間にか入っている。
https://www.unrealengine.com/marketplace/ja/product/voxel-plugin-free
どれでもいいが今回は地形をVoxelWorldで作成するので、「ファーストパーソン」を選択し、床を削除する。
次にプラグインを有効にする。[編集][プラグイン]でプラグイン画面を開き、検索にvoxelと打つと補完で出てくるのでチェックする。
有効化のためには再起動が必要。
[Voxel] → [VoxelWorld]を選択するとボクセルの地形が追加される。
少し上のほうに出てくるかもしれないので位置は自分のスポーン位置より低いところに移動する
Static Cylinderを追加して、自分のスポーン位置の目の前、少し上のあたりに配置。
まずブループリントクラスに変換する。
VoxelWorldの設定からOn Component Hitイベントを追加する。
Cylinderが落下して発生するOn Component Hitでは、ぶつかったものがCylinderで、ぶつけられたほうがVoxelWorldになる。
On Component Hit が発生したら、ぶつけられたほうをVoxelWorld型に変更し、ボクセルを消す処理をを呼び出す。
後で重力の設定をして落下とOn Component Hitの処理を有効化する。
GUIDは全世界でユニークなID。
UUID(Universally Unique Identifier)は、ソフトウェア上でオブジェクトを一意に識別するための識別子である。
https://ja.wikipedia.org/wiki/UUID
https://ja.wikipedia.org/wiki/UUID
GUID (英: Globally Unique Identifier) またはグローバル一意識別子(ぐろーばるいちいしきべつし)は、UUIDの実装のひとつ、あるいは(事実上)UUIDの別名である。
https://ja.wikipedia.org/wiki/GUID
#include <iostream> // CoCreateGuidを使用するためのヘッダファイル #include <combaseapi.h> //※ #include <Windows.h>をインクルードすれば使える int main() { GUID guid; CoCreateGuid(&guid); // GUIDを生成 wchar_t* guidString; StringFromCLSID(guid, &guidString); // GUIDを文字列に変換 // GUIDを表示 std::wcout << guidString << std::endl; // メモリ解放 CoTaskMemFree(guidString); }
記事があまりにさみしいので.NET版を置いておく。Guid.NewGuid()でGUIDを取得できる。
using System; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { System.Guid guid = Guid.NewGuid(); Console.WriteLine("D " + guid.ToString("D")); Console.WriteLine("N " + guid.ToString("N")); Console.WriteLine("B " + guid.ToString("B")); Console.WriteLine("P " + guid.ToString("P")); Console.ReadKey(); } } }
Boost.Scopeにも実装されているらしい。
https://www.boost.org/doc/libs/1_85_0/libs/scope/doc/html/index.html
ただBoostの導入は面倒なので、今回は有志がGithubで公開しているものを使う。
https://github.com/okdshin/unique_resource
例えば、C++にはstd::unique_ptrがあり、メモリリークを防げる。この時、カスタムデリータを指定すれば、普通のnew/deleteとは異なった破棄処理を行うこともできる。
// ファイルをクローズするデリータ struct MyFileCloser { void operator()(FILE* ptr) const { fclose(ptr); } };
int main() { { // ファイルを開く std::unique_ptr<FILE, MyFileCloser> pfile(fopen("test", "r"), MyFileCloser()); char buffer[1024]; fgets(buffer, sizeof(buffer), pfile.get()); std::cout << buffer << std::endl; // ファイルはスコープを抜けると自動的にクローズされる } }
問題は管理したい参照がポインタでない場合で、unique_ptrではエラーになる。
#include <memory> #include <unordered_map> // リソースはハンドルでアクセス using HANDLE = int; // リソース管理用のコンテナ std::unordered_map<HANDLE, int*> myresource;
// リソースの確保 HANDLE MyNew(size_t size) { HANDLE handle = 0; myresource.insert({ handle,new int[size] }); return handle++; }
// リソースの解放 void MyDelete(HANDLE handle) { delete[] myresource[handle]; myresource.erase(handle); }
struct My_HANDLE_Release { void operator()(HANDLE handle) const { MyDelete(handle); } };
int main() { // エラー MyNew が返す HANDLE はポインタでない std::unique_ptr<HANDLE, My_HANDLE_Release> uptr(MyNew(100), My_HANDLE_Release()); }
以下から、unique_resource.hpp をダウンロード。
https://github.com/okdshin/unique_resource
#include "unique_resource.hpp"
int main() { HANDLE test; { auto unique_handle = std_experimental::make_unique_resource<HANDLE, My_HANDLE_Release>(MyNew(100), My_HANDLE_Release()); test = unique_handle.get(); // リソースを使う int* p = myresource.at(unique_handle.get()); std::cout << "access " << p << std::endl; for (size_t i = 0; i < 100; ++i) { p[i] = i; }
// リソースが解放される
}
// リソースが解放されているかチェック if( myresource.find(test) == myresource.end() ) { std::cout << "リソースは解放されています" << std::endl; } else { std::cout << "リソースは解放されていません" << std::endl; } }