個人的注意点
・find_libraryの第一引数はライブラリファイル名だが、.libはつけない
・gui_app: true を必ずつける
project('myapp', 'cpp') wxwidgets_incdir = include_directories( 'C:/libraries/wxWidgets/include', 'C:/libraries/wxWidgets/release/lib/vc_x64_dll/mswu' ) wxwidgets_libdir = 'C:/libraries/wxWidgets/release/lib/vc_x64_dll' cpp = meson.get_compiler('cpp') executable('myapp', 'main.cpp', gui_app: true, dependencies: [ cpp.find_library('wxbase32u' , dirs: wxwidgets_libdir), cpp.find_library('wxbase32u_net' , dirs: wxwidgets_libdir), cpp.find_library('wxbase32u_xml' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_adv' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_aui' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_core' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_gl' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_html' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_media' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_propgrid', dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_qa' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_ribbon' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_richtext', dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_stc' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_webview' , dirs: wxwidgets_libdir), cpp.find_library('wxmsw32u_xrc' , dirs: wxwidgets_libdir), ], include_directories: wxwidgets_incdir, cpp_args: [ '/D__WXMSW__' , # windows は /D '/DWXUSINGDLL' # linux系 は -D ], link_args: [ '/SUBSYSTEM:WINDOWS' ] )
// プリプロセッサに以下二つを追加 // __WXMSW__ // WXUSINGDLL // サブシステムをWindowsに設定(WinMainで呼び出すので) // Windows (/SUBSYSTEM:WINDOWS) #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/frame.h> // wxFrameに必要 ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // ウィンドウ作成 class MyFrame : public wxFrame { public: MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { } private: // イベント処理しないときはこれを入れない // wxDECLARE_EVENT_TABLE(); }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340)); frame->Show(true); return true; } }; ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);
調べていて思ったこと。
ユーザー定義リテラルは、リテラルの末尾につけるサフィックスを自分で定義する機能。「1.0f」のfの部分を自分で定義できる。
あくまでリテラルにつけるものなので、変数等には使えない。
operator"" の後にサフィックスを与える。 「_」開始でなくてもビルドは通るが、必ず先頭に「_」をつけなければいけないらしい。
以下のような定義例がしばしばみられる。
#include <iostream> // 名前空間を定義することで、これが有効な範囲でだけ使用できる namespace suffix { long double operator"" _k(const long double value) { return value * pow(10, 3); } long double operator"" _h(const long double value) { return value * pow(10, 2); } long double operator"" _da(const long double value) { return value * pow(10, 1); } /* 10^0 に接頭語はない */ long double operator"" _d(const long double value) { return value / pow(10, 1); } long double operator"" _c(const long double value) { return value / pow(10, 2); } long double operator"" _m(const long double value) { return value / pow(10, 3); } } int main() { using namespace suffix; // 1.0 × 10^3 + 2 × 10^(-3) auto length = 1.0_k + 2.0_m; printf("%lf\n", length); }
しかし何か違う気がする。
C++には主に数値系で精度や範囲などを指定するsuffix(f,LLなど)と、文字列系で文字コードを指定するprefix(u8"hello"など)があるわけだが、両方とも定数の解釈方法を指定しているだけで、別にその定数に対して演算をしているのとは違う(気がする)。
だからどちらかというと以下のような使い方のほうが本来の用途に近いのでは...?と思う。
class Radian { double value; public: Radian(const Radian& rad) { value = rad.value; } Radian(double value) { this->value = value; } }; class Degree { double value; public: Degree(const Degree& deg) { value = deg.value; } Degree(double value) { this->value = value; } }; namespace suffix { Radian operator"" _rad(const long double value) { return Radian( value ); } Degree operator"" _deg(const long double value) { return Degree( value ); } } int main() { using namespace suffix; Radian rad = 1.0_rad; Degree deg = 1.0_deg; // エラー // Radian rad2 = 1.0_deg; }
つまりキャストのようなものだ。しかしこれでは rad=1.0;としても通ってしまう。別に間違ってはいないがせっかく使うならミスを減らせるような機能にしたい。
というわけで以下のようにしてみる。これで単位が不明な浮動小数点をうっかり代入してしまうのを防ぐことができた。
#include <iostream> class Radian; class Degree; namespace suffix { Radian operator"" _rad(const long double value); Degree operator"" _deg(const long double value); } class Radian { double value; private: Radian(double value) { this->value = value; }// ユーザー定義リテラルからしか呼び出せないようにする public: Radian(const Radian& rad) { value = rad.value; } // ユーザー定義リテラルがコンストラクタへアクセスするために必要 friend Radian suffix::operator"" _rad(const long double value); operator double()const { return value; } }; class Degree { double value; private: Degree(double value) { this->value = value; }// ユーザー定義リテラルからしか呼び出せないようにする public: Degree(const Degree& deg) { value = deg.value; } // ユーザー定義リテラルがコンストラクタへアクセスするために必要 friend Degree suffix::operator"" _deg(const long double value); operator double()const { return value; } }; namespace suffix { Radian operator"" _rad(const long double value) { return Radian( value ); } Degree operator"" _deg(const long double value) { return Degree( value ); } } int main() { using namespace suffix; Radian rad = 2.5_rad; Degree deg = 1.0_deg; // エラー // Radian rad2 = 1.0_deg; // これもエラー //rad = 1.0; rad = 3.0_rad; std::cout << rad << std::endl; }
キャストしろ。
OpenAI APIというよりPythonがわからない話。
function callingは、「こんな関数を用意したけど『???』という質問に回答するためには、どの関数を呼び出せばよい?」という問いに、「関数名と引数で答えてくれる」機能である。
この、「こんな関数を用意した」という部分、用意した関数についての説明をOpenAI APIに渡すためのリストfunctionsパラメータについて。
私はPython素人なので、functions = [{...}]の部分について調べた。
以下のようなプログラムで見る。
import openai # OpenAI API への送信と、その結果の受信は、json形式で行われる import json ############################################################### import os import re
############################### # 処理に必要な関数を用意 ############################### # @brief Google検索する # @param keyword 検索キーワード # @param datefrom 記事の更新日時範囲 # @param dateto 記事の更新日時範囲 def getGoogleSearch(keyword,datefrom,dateto): # 本当はここに関数の処理を書くのだが、今回はOpenAI APIの返答のためのサンプルなので実装しない # function callingを呼び出すだけなら別に定義の必要もないわけだが格好がつかないので一応。 pass # @brief 決められたサイトからニュースを取得する # @param newssite サイトのURL # @param count 取得する結果の件数 def getNews(newssite,count): # こちらも同じ pass # @brief 自分のハードディスクからキーワードを持つファイルを検索する # @param keyword 検索ワード # @param extension 拡張子 def searchDocument(keyword,extention): # こちらも同じ pass
############################### # どんな関数を用意したかをOpenAI APIに教えるためのリスト。今回知らせる関数は三つ。 ############################### functions = [ { # 用意した関数の名前 "name": "getGoogleSearch", # 関数の説明 "description": "Google検索する", # パラメータ一覧 "parameters": { "type": "object", "properties": { "keyword" : { "type": "string", "description": "検索キーワード。スペース区切りで複数可" }, "datefrom" : { "type": "string", "description": "記事の更新日の範囲の古いほう。yyyy/mm/ddで指定" }, "dateto": { "type": "string", "description": "記事の更新日の範囲の新しいほう。yyyy/mm/ddで指定" }, }, # 必須パラメータ "required": ["keyword"], }, }, ############################################### { # 用意した関数の名前 "name": "getNews", # 関数の説明 "description": "決められたサイトからニュースを取得する", # パラメータ一覧 "parameters": { "type": "object", "properties": { "newssite" : { "type": "string", "description": "サイトのURL" }, "count" : { "type": "integer", "description": "取得する結果の件数" }, }, # 必須パラメータ "required": ["newssite","count"], }, }, ############################################### { # 用意した関数の名前 "name": "searchDocument", # 関数の説明 "description": "自分のハードディスクからキーワードを持つファイルを検索する", # パラメータ一覧 "parameters": { "type": "object", "properties": { "keyword" : { "type": "string", "description": "検索するキーワード" }, "extention" : { "type": "string", "description": "拡張子" }, }, # 必須パラメータ "required": ["keyword","extention"], }, } ]
############################### # OpenAIに何かしら問いかける ############################### # APIキー openai.api_key = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 問いかけの内容 ask_get_allitem = [ { "role": "user", "content": "飲み会の時の画像を探してください。田中さんが写っています。" } ] # OpenAIに送信 response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=ask_get_allitem, functions=functions, ) # 結果を取得 res_message = response['choices'][0]['message']
############################### # OpenAIからの返答を確認する ############################### # もし、OpenAIが、この応答には関数呼び出しが必要と判断したら、 # res_message['function_call'] に、関数呼び出しに必要な情報が入っている if res_message.get('function_call'): # OpenAIが処理にふさわしいと判断した関数の名前 function_name = res_message['function_call']['name'] # OpenAIが処理にふさわしいと判断した関数の引数 arguments = json.loads(res_message['function_call']['arguments']) # 何を呼び出すべきと判断したか、確認のために表示 print("function_name: ", function_name) print("arguments: ", arguments) else: # OpenAIが関数呼び出しをしないと判断した場合、messageの中身をそのまま表示する print(response.choices[0]["message"]["content"].strip())
functionsは辞書のリストで表す。リストは [項目1, 項目2 , 項目3]の形をしている。つまり
functions=[ 関数1について , 関数2について , 関数3について }
という形をしている。で、関数1について、これは辞書になっている。辞書はkeyとvalueのペアを一つの項目とし、ペアを複数持つ。
keyとvalueのペアは、key : valueの形で持ち、それらを{}でまとめて一つの辞書にする。つまり
dic = {
key1 : value1 , # アイテム1
key2 : value2 , # アイテム2
key3 : value3 , # アイテム3
}
という形をしている。
結果、各関数に関する情報を辞書としてまとめ、それをリストとしたものをfunctionsに渡すということになる。
functions = [
# 関数1に関する情報を辞書で指定
{
"name" : "function1", # keyは"name" , valueは"function1"
"description" : "関数1の説明", # keyは"description" , valueは"関数1の説明"
},
# 関数2に関する情報を辞書で指定
{
# 略
},
# 関数3に関する情報を辞書で指定
{
# 略
}
]
# こんな風にアクセス
print( functions[0]['name'] )
Blenderで作ったモデルをUE5に移行するにはfbx経由で行う。
まずUV展開し、テクスチャをロードしマテリアルとして設定する。
エクスポートする際に、Selected Objectsを選択。あるいは、Meshだけを選択する。このあたりの設定をしないと、ライトなどもエクスポートされてしまう。
ファイル→レベルにインポート。特に気を付けるところはない。

「コンテンツ」の中に、マテリアルとSphereが追加されている。

wxWidgetsのwxScrollBarの使用例。これはスクロールバーのみのコントロールになる。
スクロールバーとしての設定はSetScrollbar関数で行う。
https://docs.wxwidgets.org/3.0/classwx_scroll_bar.html#ae69c239fd6af4ebcabf46efa9fc5092e
#include <wx/wx.h> #include <wx/sizer.h> #include <wx/frame.h> #include <wx/panel.h> class MyFrame : public wxFrame { std::vector<int> _itemlist; int row = 3; int col = 1; int itemcount() { return _itemlist.size(); } wxScrollBar* _scroll; wxGridSizer* _gridSizer; public:
MyFrame() : wxFrame(NULL, wxID_ANY, "wxGridSizer サンプル", wxDefaultPosition, wxSize(400, 300)) { for (size_t i = 0; i < 17; i++) { _itemlist.push_back(i); } int vgap = 2;// 垂直方向の間隔 int hgap = 2;// 水平方向の間隔 _gridSizer = new wxGridSizer(row, col, vgap, hgap); for (int i = 0; i < row*col; ++i) { //// 新しいパネルを作成 wxPanel* panel = new wxPanel(this/*MyFrameで管理*/, wxID_ANY); //// パネルの背景色を設定 panel->SetBackgroundColour(wxColour(200, 200, 100 * (i + 1) % 256)); //// パネルをgridSizer追加 _gridSizer->Add(panel, 1, wxEXPAND); // パネルにラベルを追加 wxStaticText* label = new wxStaticText(panel, wxID_ANY, wxString::Format("Panel %d", i)); wxBoxSizer* boxSizer = new wxBoxSizer(wxHORIZONTAL); boxSizer->Add(label, 1, wxALIGN_CENTER); panel->SetSizer(boxSizer); } // 水平分割のSizer作成 wxBoxSizer* boxSizer = new wxBoxSizer(wxHORIZONTAL); boxSizer->Add(_gridSizer, 1, wxEXPAND); //スクロールバー作成 _scroll = new wxScrollBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL); boxSizer->Add(_scroll, 0, wxEXPAND); // OnScrollをscrollにBind _scroll->Bind(wxEVT_SCROLL_CHANGED, &MyFrame::OnScroll, this); _scroll->SetScrollbar( 0, // position スクロールバーの位置 row, // thumbSize つまみのサイズ。これは一度に画面上に表示する行数と等しいことが望ましい itemcount(), // range 総行数 2, // pageSize ページ単位でのスクロールを行ったときに移動する量 true // refresh trueにするとスクロールバーの位置を更新する ); // 初期表示を行う panel_update(); // MyFrameにgridSizerを指定 SetSizer(boxSizer); Centre();// ウィンドウを画面中央に表示 }
// wxScrollBarをクリックしたときに呼び出されるイベントハンドラ void OnScroll(wxScrollEvent& event) { // スクロールバーの位置を取得 int pos = event.GetPosition(); // pos をデバッグ出力 wxLogDebug(wxString::Format("pos = %d", pos)); panel_update(); }
// panelの内容を更新する void panel_update() { // _scroll の位置を取得 int pos = _scroll->GetThumbPosition(); // 一行ずつスクロールしたいので、 // 一番左上のパネルに表示するアイテム番号を計算 int offset = pos * col; for (int i = 0; i < row * col; ++i) { // _gridSizerに登録されているpanelを取得 wxPanel* panel = (wxPanel*)_gridSizer->GetItem(i)->GetWindow(); // panel上にあるlabelを取得 wxStaticText* label = (wxStaticText*)panel->GetChildren()[0]; if ((offset + i) >= itemcount()) { // アイテム数を超えたら *** を表示 label->SetLabelText("***"); } else { if (offset + i == itemcount()-1) { // 最後のアイテムなら (last item) を表示 label->SetLabelText(wxString::Format("Panel %d (last item)", _itemlist[offset + i])); } else { // それ以外はアイテム番号を表示 label->SetLabelText(wxString::Format("Panel %d", _itemlist[offset + i])); } } } }
}; class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame(); frame->Show(true); return true; } }; wxIMPLEMENT_APP(MyApp);
wxGridSizerを使うとコントロールをタイル状に並べられる。
#include <wx/wx.h> #include <wx/sizer.h> #include <wx/frame.h> #include <wx/panel.h> class MyFrame : public wxFrame { public:
MyFrame() : wxFrame(NULL, wxID_ANY, "wxGridSizer サンプル", wxDefaultPosition, wxSize(400, 300)) { int row = 3; // 行数 int col = 4; // 列数 int vgap = 2;// 垂直方向の間隔 int hgap = 2;// 水平方向の間隔 wxGridSizer* gridSizer = new wxGridSizer(row, col, vgap, hgap); for (int i = 0; i < row*col; ++i) { // 新しいパネルを作成 wxPanel* panel = new wxPanel(this/*MyFrameで管理*/, wxID_ANY); // パネルの背景色を設定 panel->SetBackgroundColour(wxColour(100, 100, 100 * (i + 1) % 256)); // パネルをgridSizer追加 gridSizer->Add(panel, 1, wxEXPAND); // パネルにイベントハンドラを設定 panel->Bind(wxEVT_LEFT_DOWN, &MyFrame::OnClick, this); } // MyFrameにgridSizerを指定 SetSizer(gridSizer); Centre();// ウィンドウを画面中央に表示 }
// wxPanelをクリックしたときのイベントハンドラ void OnClick(wxMouseEvent& event) { wxPanel* panel = dynamic_cast<wxPanel*>(event.GetEventObject()); if (panel) { wxColour color = panel->GetBackgroundColour(); wxLogMessage("%d", color.Blue()); } }
}; class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame(); frame->Show(true); return true; } }; wxIMPLEMENT_APP(MyApp);
// wxPanelをクリックしたときのイベントハンドラ void OnClick(wxMouseEvent& event) { wxGridSizer * gridSizer = dynamic_cast<wxGridSizer*>(this->GetSizer()); // gridSizerの全ての要素へアクセスするfor文 for (int i = 0; i < gridSizer->GetItemCount(); ++i) { wxSizerItemList& item = gridSizer->GetChildren(); wxWindow* panel = item.Item(i)->GetData()->GetWindow(); panel->SetBackgroundColour(wxColour(255, 0, 0));// パネルを着色 panel->Refresh(); // 再描画指示 panel->Update(); // 再描画を即座に実行 } }
まず、MyFrameのコンストラクタでメニューを作成して、OnClickにBindする。
// 画面上部にメニューバーを作成 wxMenuBar* menuBar = new wxMenuBar(); wxMenu* menu = new wxMenu(); menu->Append(wxID_DELETE, "削除"); menuBar->Append(menu, "メニュー"); SetMenuBar(menuBar); Bind(wxEVT_MENU, &MyFrame::OnClick, this, wxID_DELETE);
Sizerの削除は要素の管理関係が厄介。管理自体は親(MyFrame)がしているのだが、Sizerを外したりdeleteしたりすると一緒に削除されたり、削除されたことが親に知らされずに不正なアクセスになったりする。
まずはGetChildren()でSizerでサイズ管理しているアイテム一覧を取り出し、個別に削除してからSizerを削除することになる。
// 「削除」メニューをクリックしたときのイベントハンドラ void OnClick(wxCommandEvent& event) { wxGridSizer* gridSizer = dynamic_cast<wxGridSizer*>(this->GetSizer()); if (gridSizer) { // gridSizer->Clear(true); // gridSizerから全ての要素を削除する // trueを指定した場合、全ての子要素は削除されるが、親がそれを知らないので後で知らせる必要がある // falseを指定した場合、子要素は削除されないので、後で削除する必要がある // 使いにくいので今回は使用しない // gridSizerから全てのウィジェットを取り出し、破棄する const wxSizerItemList list = gridSizer->GetChildren(); for (wxSizerItem* item : list) { wxWindow* window = item->GetWindow();// パネルを取得 if (window) { window->Destroy();// パネルを削除 delete ではなくDestroy()を呼び出すべき } } // MyFrameからgridSizerを取り外す // 第二引数がtrueのときは、現在のSizerを削除する // 第二引数がfalseのときは、削除しない this->SetSizer(nullptr,true); } }
パネルだけをほかに移行するような場合、パネルのポインタを保存しておき、MyFrame側のSetSizerの第二引数にfalseを渡すと、gridSizerが勝手に削除されなくなるので、後で自分でgridSizerだけを削除する。
// 「削除」メニューをクリックしたときのイベントハンドラ void OnClick(wxCommandEvent& event) { wxGridSizer* gridSizer = dynamic_cast<wxGridSizer*>(this->GetSizer()); if (gridSizer) { std::vector<wxWindow*> panels; // パネルのバックアップ先 // gridSizerから全てのウィジェットを取り出し、破棄する const wxSizerItemList list = gridSizer->GetChildren(); for (wxSizerItem* item : list) { wxWindow* window = item->GetWindow(); if (window) { panels.push_back(window);// パネルをバックアップ //window->Destroy(); // 削除はしないようにする } } // 第二引数がfalseのときは、現在のSizerを削除しない this->SetSizer(nullptr,false); }
}
// インクルードディレクトリ // /wxWidgets/include // /wxWidgets/release/lib/vc_x64_dll/mswu // ライブラリディレクトリ // /wxWidgets/release/lib/vc_x64_dll // プリプロセッサ // __WXMSW__ // WXUSINGDLL #if defined(_DEBUG) #pragma comment(lib,"wxbase32ud.lib") #pragma comment(lib,"wxbase32ud_net.lib") #pragma comment(lib,"wxbase32ud_xml.lib") #pragma comment(lib,"wxmsw32ud_adv.lib") #pragma comment(lib,"wxmsw32ud_aui.lib") #pragma comment(lib,"wxmsw32ud_core.lib") #pragma comment(lib,"wxmsw32ud_gl.lib") #pragma comment(lib,"wxmsw32ud_html.lib") #pragma comment(lib,"wxmsw32ud_media.lib") #pragma comment(lib,"wxmsw32ud_propgrid.lib") #pragma comment(lib,"wxmsw32ud_qa.lib") #pragma comment(lib,"wxmsw32ud_ribbon.lib") #pragma comment(lib,"wxmsw32ud_richtext.lib") #pragma comment(lib,"wxmsw32ud_stc.lib") #pragma comment(lib,"wxmsw32ud_webview.lib") #pragma comment(lib,"wxmsw32ud_xrc.lib") #else #pragma comment(lib,"wxbase32u.lib") #pragma comment(lib,"wxbase32u_net.lib") #pragma comment(lib,"wxbase32u_xml.lib") #pragma comment(lib,"wxmsw32u_adv.lib") #pragma comment(lib,"wxmsw32u_aui.lib") #pragma comment(lib,"wxmsw32u_core.lib") #pragma comment(lib,"wxmsw32u_gl.lib") #pragma comment(lib,"wxmsw32u_html.lib") #pragma comment(lib,"wxmsw32u_media.lib") #pragma comment(lib,"wxmsw32u_propgrid.lib") #pragma comment(lib,"wxmsw32u_qa.lib") #pragma comment(lib,"wxmsw32u_ribbon.lib") #pragma comment(lib,"wxmsw32u_richtext.lib") #pragma comment(lib,"wxmsw32u_stc.lib") #pragma comment(lib,"wxmsw32u_webview.lib") #pragma comment(lib,"wxmsw32u_xrc.lib") #endif #include <wx/wxprec.h> #include <wx/glcanvas.h> #include <wx/frame.h> #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <GL/gl.h> #pragma comment(lib, "opengl32.lib")
class MyGLCanvas : public wxGLCanvas { public: MyGLCanvas(wxFrame* parent, int* attribList = NULL); void Render(wxPaintEvent& evt); private: wxGLContext* m_context; // OpenGL context }; MyGLCanvas::MyGLCanvas(wxFrame* parent, int* attribList) : wxGLCanvas(parent, wxID_ANY, attribList) { m_context = new wxGLContext(this); // windowsでちらつき防止 SetBackgroundStyle(wxBG_STYLE_CUSTOM); } void MyGLCanvas::Render(wxPaintEvent& evt) { if (!IsShown()) return; int w, h; GetClientSize(&w, &h); glViewport(0, 0, w, h); wxGLCanvas::SetCurrent(*m_context); wxPaintDC(this); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBegin(GL_TRIANGLES); glColor3d(1.0, 0.0, 0.0); glVertex3f(0.0, 1.0, 0.0); glColor3d(0.0, 1.0, 0.0); glVertex3f(-1.0, -1.0, 0.0); glColor3d(0.0, 0.0, 1.0); glVertex3f(1.0, -1.0, 0.0); glEnd(); glFlush(); SwapBuffers(); }
class MyFrame : public wxFrame { public: MyFrame(const wxString& title, int xpos, int ypos, int width, int height); ~MyFrame(); void OnSize(wxSizeEvent& event); MyGLCanvas* m_canvas = NULL; }; MyFrame::MyFrame(const wxString& title, int xpos, int ypos, int width, int height) : wxFrame((wxFrame*)NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height)) { int args[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 }; m_canvas = new MyGLCanvas(this, args); m_canvas->Bind(wxEVT_PAINT, &MyGLCanvas::Render, m_canvas); Bind(wxEVT_SIZE, &MyFrame::OnSize, this); } void MyFrame::OnSize(wxSizeEvent& event) { m_canvas->SetSize(event.GetSize()); } MyFrame::~MyFrame() { delete m_canvas; }
class MyApp : public wxApp { public: bool OnInit(); }; bool MyApp::OnInit() { MyFrame* frame = new MyFrame(wxT("wxWidgets OpenGL"), 50, 50, 400, 400); frame->Show(); return true; } IMPLEMENT_APP(MyApp)
SQLite3は公式が.libを配布していない。代わりに.dllと.defが提供されているので、そこからlibコマンドで作成する。
まず windows用の、win64のdllをダウンロードする。
https://www.sqlite.org/download.html

展開すると、sqlite3.def , sqlite3.dllが生成される。
x64 Native Tools Command Prompt を起動し、 lib コマンドを実行する。

>lib /DEF:sqlite3.def /OUT:sqlite3.lib /MACHINE:x64
sqlite3.libが生成される。
C++からSQLite3を使用してみる。
まずソースコードをダウンロードするが、.hと.cの構成になっており、プロジェクトに組み込んでビルドするので、CMakeやlibのlinkなどはしない。
まず、以下からSource Codeをダウンロード。
https://www.sqlite.org/download.html
展開して、sqlite3.cをプロジェクトに追加。以下のコードを実行すると、カレントディレクトリにwebsites.dbが作成される。
#include "sqlite3.h" #include <iostream> int main() { int result; sqlite3* database; result = sqlite3_open("websites.db", &database);// ファイルを開く if (result) { std::cerr << "失敗 " << sqlite3_errmsg(database) << std::endl; return(0); } const char* sql_query; sql_query = "CREATE TABLE WEBSITES(" "SITE_NAME TEXT NOT NULL," "URL TEXT NOT NULL," "ACCESS_COUNT INT NOT NULL);" ; // SQL実行 char* errormsg = 0; result = sqlite3_exec(database, sql_query, 0, 0, &errormsg); if (result != SQLITE_OK) { std::cerr << "失敗: " << errormsg << std::endl; sqlite3_free(errormsg); } sqlite3_close(database);// ファイルを閉じる }
#include "sqlite3.h" #include <iostream> #pragma warning(disable:4996)
// データを追加
void insert(sqlite3* database, const char* site_name, const char* url, int access_count) { char* errormsg = 0; char query[1024]; sprintf(query, "INSERT INTO WEBSITES VALUES('%s', '%s', %d);", site_name, url, access_count); int result = sqlite3_exec(database, query, 0, 0, &errormsg); if (result != SQLITE_OK) { std::cerr << "失敗: " << errormsg << std::endl; sqlite3_free(errormsg); } }
////////////////////////////////////////////////// ////////////////////////////////////////////////// //////////////////////////////////////////////////
// sqlite3_execで、抽出したデータ一軒ごとにこのコールバック関数が呼び出される int callback_per_row(void* NotUsed, int argc, char** argv, char** azColName) { // 一軒分のデータを表示する // 今回は、SITE_NAME , URL , ACCESS_COUNT の三つのカラムがあるので、argc==3 となる for (int i = 0; i < argc; i++) { const char* column_name = azColName[i]; const char* value = argv[i]; // 値は NULL があり得るので、その場合は NULL と表示する if (value != nullptr) { std::cout << column_name << " == " << value << std::endl; } else { std::cout << column_name << " == NULL" << std::endl; } } std::cout << "\n"; return 0; }
// WHERE SITE_NAME で SELECT する void getitem(sqlite3* database ,const char* sitename) { char* errormsg = nullptr; // SQLクエリ char sql_query[1024]; sprintf(sql_query,"SELECT * FROM WEBSITES WHERE SITE_NAME = '%s';",sitename); // SQLクエリ実行 int result = sqlite3_exec(database, sql_query, callback_per_row, 0, &errormsg); if (result != SQLITE_OK) { std::cerr << "失敗: " << errormsg << std::endl; sqlite3_free(errormsg); } }
////////////////////////////////////////////////// ////////////////////////////////////////////////// ////////////////////////////////////////////////// int main() { int result; sqlite3* database; result = sqlite3_open("websites.db", &database); if (result) { std::cerr << "失敗 " << sqlite3_errmsg(database) << std::endl; return(0); } const char* sql_query; sql_query = "CREATE TABLE WEBSITES(" "SITE_NAME TEXT NOT NULL," "URL TEXT NOT NULL," "ACCESS_COUNT INT NOT NULL);" ; // SQL実行 char* errormsg = nullptr; result = sqlite3_exec(database, sql_query, 0, 0, &errormsg); if (result != SQLITE_OK) { std::cerr << "失敗: " << errormsg << std::endl; sqlite3_free(errormsg); } insert(database, "Google", "http://www.google.com", 0); insert(database, "Yahoo!", "http://www.yahoo.co.jp", 5); insert(database, "Amazon", "http://www.amazon.co.jp", 10); insert(database, "Facebook", "http://www.facebook.com", 15); insert(database, "Twitter", "http://www.twitter.com", 20); getitem(database,"Amazon"); sqlite3_close(database); }
某C#ベースのゲームエンジンが炎上しているので、少しUEを使えるようになっておきたいので基本的な所を勉強したいと考えている。スタティックメッシュにテクスチャを与えるところからやってみたい。
コンテンツブラウザにテクスチャファイルをドラッグ&ドロップして読み込む。
なお、テクスチャデータが1チャンネル16bitだと色が正常に出ないらしいので8bitを用意する。
作成したマテリアルをダブルクリックして、ノードエディタにテクスチャをドラッグして取り込み、ノードを接続する
最後に、画面左上付近にある適用ボタンを押す。
1チャンネルが16bitの画像を読み込むと色が淡くなる。画像を確認して、色が変わっているなら変換する必要がある。