import bpy
# textオブジェクトの追加
fontCurve1 = bpy.data.curves.new(type="FONT",name="fontCurve1") obj = bpy.data.objects.new("textObject",fontCurve1) obj.data.body = "Hello"# textオブジェクトの内容 # 新しいCollrectionを作成 newCol = bpy.data.collections.new('Collection 1') # 現在のシーンにコレクションをリンク bpy.context.scene.collection.children.link(newCol) newCol.objects.link(obj)
# フォントの変更
fnt = bpy.data.fonts.load('C:\Windows\Fonts\HARNGTON.TTF') obj.data.font = fnt
すっかり忘れていたが今までのパターンではdouble型にしか対応していなかった。
#pragma once ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // プライマリテンプレート template<typename T> struct GETTER; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 特殊化用の構造体 //小文字 x,y,z用特殊化用の構造体 template<typename T> struct access_xyz { using scalar_t = decltype(T::x); static inline scalar_t& X(T& v) { return v.x; } static inline scalar_t& Y(T& v) { return v.y; } static inline scalar_t& Z(T& v) { return v.z; } static inline const scalar_t& X(const T& v) { return v.x; } static inline const scalar_t& Y(const T& v) { return v.y; } static inline const scalar_t& Z(const T& v) { return v.z; } }; //大文字 X,Y,Z用特殊化用の構造体 template<typename T> struct access_XYZ { using scalar_t = decltype(T::X); static inline scalar_t& X(T& v) { return v.X; } static inline scalar_t& Y(T& v) { return v.Y; } static inline scalar_t& Z(T& v) { return v.Z; } static inline const scalar_t& X(const T& v) { return v.X; } static inline const scalar_t& Y(const T& v) { return v.Y; } static inline const scalar_t& Z(const T& v) { return v.Z; } }; //配列用特殊化用の構造体 template<typename U,typename T> struct access_ARRAY{ static inline U& X(T& v) { return v[0]; } static inline U& Y(T& v) { return v[1]; } static inline U& Z(T& v) { return v[2]; } static inline const U& X(const T& v) { return v[0]; } static inline const U& Y(const T& v) { return v[1]; } static inline const U& Z(const T& v) { return v[2]; } }; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // データ型(サンプル) // 型1 struct vec_t { double x, y, z; }; // 型2 struct VEC_t { double X, Y, Z; }; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// //特殊化1(デフォルトの型) template<> struct GETTER<vec_t> :public access_xyz<vec_t> {}; template<> struct GETTER<VEC_t> :public access_XYZ<VEC_t> {}; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 特殊化2(ポインタ版) template<typename T> struct GETTER<T*> : public access_ARRAY<T,T*> {}; template<class T, std::size_t N> struct GETTER<T[N]> : public access_ARRAY<T, T[N]> {}; template<typename T, std::size_t N> struct GETTER<std::array<T, N> > : public access_ARRAY<T, std::array<T, N> > {}; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 関数本体 template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); } template< typename T, class G = GETTER<T> > void normalize(T & v) { double L = length(v); G::X(v) = G::X(v) / L; G::Y(v) = G::Y(v) / L; G::Z(v) = G::Z(v) / L; }
前回、配列版の事を忘れていたので追加。
#pragma once ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // プライマリテンプレート template<typename T> struct GETTER; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 特殊化用の構造体//小文字 x,y,z用特殊化用の構造体 template<typename T> struct access_xyz { static inline double& X(T& v) { return v.x; } static inline double& Y(T& v) { return v.y; } static inline double& Z(T& v) { return v.z; } static inline const double& X(const T& v) { return v.x; } static inline const double& Y(const T& v) { return v.y; } static inline const double& Z(const T& v) { return v.z; } }; //大文字 X,Y,Z用特殊化用の構造体 template<typename T> struct access_XYZ { static inline double& X(T& v) { return v.X; } static inline double& Y(T& v) { return v.Y; } static inline double& Z(T& v) { return v.Z; } static inline const double& X(const T& v) { return v.X; } static inline const double& Y(const T& v) { return v.Y; } static inline const double& Z(const T& v) { return v.Z; } }; //配列用特殊化用の構造体 template<typename T> struct access_ARRAY{ static inline double& X(T& v) { return v[0]; } static inline double& Y(T& v) { return v[1]; } static inline double& Z(T& v) { return v[2]; } static inline const double& X(const T& v) { return v[0]; } static inline const double& Y(const T& v) { return v[1]; } static inline const double& Z(const T& v) { return v[2]; } };////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // データ型(サンプル)
// 型1 struct vec_t { double x, y, z; }; // 型2 struct VEC_t { double X, Y, Z; };
////////////////////////////////////////////////////// ////////////////////////////////////////////////////// //特殊化1(デフォルトの型) template<> struct GETTER<vec_t> :public access_xyz<vec_t> {}; template<> struct GETTER<VEC_t> :public access_XYZ<VEC_t> {}; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 特殊化2(ポインタ版) template<typename T> struct GETTER<T*> : public access_ARRAY<T*> {}; template<class T, std::size_t N> struct GETTER<T[N]> : public access_ARRAY<T[N]> {}; template<typename T, std::size_t N> struct GETTER<std::array<T, N> > : public access_ARRAY< std::array<T, N> > {};////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 関数本体 template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); } template< typename T, class G = GETTER<T> > void normalize(T & v) { double L = length(v); G::X(v) = G::X(v) / L; G::Y(v) = G::Y(v) / L; G::Z(v) = G::Z(v) / L; }
#include <iostream> #include <array> #include "len.hpp" ////エントリポイント int main() { double L; vec_t vv={ 1,1,1 }; L = length(vv); std::cout << L << std::endl; double xyz[3] = { 1,1,1 }; L = length(xyz); std::cout << L << std::endl; double* ptr = new double[3]{ 1,1,1 }; L = length(ptr); std::cout << L << std::endl; std::array<double, 3> ary = { 1,1,1 }; L = length(ary); std::cout << L << std::endl; int i; std::cin >> i; }
続き
せっかくテンプレートを使用しているのに、GETTERの特殊化が長すぎる問題がある。
今回はlength関数しか使用していないので特にそう感じる。x,y,zの要素をとる関数が、例えばinnner,outer,distance...等沢山あれば気にならない。
とはいえ、短いほうがいいのは間違いないので、できる限り少ない行数で特殊化できないか考える。
あらかじめ、要素がx,y,zの時に使えるaccess_xyzと、X,Y,Zの時に使えるaccess_XYZを用意しておく。
#pragma once ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // プライマリテンプレート template<typename T> struct GETTER;
////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // テンプレート
template<typename T> struct access_xyz { using arg_t = T; using carg_t = const T; static inline double& X(arg_t& v) { return v.x; } static inline double& Y(arg_t& v) { return v.y; } static inline double& Z(arg_t& v) { return v.z; } static inline const double& X(carg_t& v) { return v.x; } static inline const double& Y(carg_t& v) { return v.y; } static inline const double& Z(carg_t& v) { return v.z; } };template<typename T> struct access_XYZ { using arg_t = T; using carg_t = const T; static inline double& X(arg_t& v) { return v.X; } static inline double& Y(arg_t& v) { return v.Y; } static inline double& Z(arg_t& v) { return v.Z; } static inline const double& X(carg_t& v) { return v.X; } static inline const double& Y(carg_t& v) { return v.Y; } static inline const double& Z(carg_t& v) { return v.Z; } };////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // ポインタ版 (変更なし) template<typename T> struct GETTER<T*> { using arg_t = T *; using carg_t = const T*; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; template<class T, std::size_t N> struct GETTER<T[N]> { using arg_t = T[N]; using carg_t = const T[N]; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; template<typename T, std::size_t N> struct GETTER<std::array<T, N> > { using arg_t = std::array<T, N> &; using carg_t = const std::array<T, N> &; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 関数本体 template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); }
使用したい構造体に合わせて、継承元を変える。
#include <array> #include "len.hpp" ////////////////////////////////////////////////////// // 型1 struct vec_t { double x, y, z; }; ////////////////////////////////////////////////////// // 型2 struct VEC_t { double X, Y, Z; }; //特殊化1 template<> struct GETTER<vec_t> :public access_xyz<vec_t> {};
//特殊化2 template<> struct GETTER<VEC_t> :public access_XYZ<VEC_t> {}; //エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; VEC_t VV; VV.X = 1; VV.Y = 1; VV.Z = 1; L = length(VV); std::cout << L << std::endl; int i; std::cin >> i; }
前回の続き
構造体が渡されたときとは別に、ポインタや配列が渡されたときも特殊化する必要がある。
プライマリテンプレートが以下の時、
//プライマリテンプレート template<typename T> struct GETTER;
ポインタ、配列、std::arrayで別の特殊化が必要
相手がポインタの場合、それを配列とみなすとする。
特殊化は以下のようになる。
template<typename T> struct GETTER<T*> { // ... };
相手が配列の場合、ポインタとは別の特殊化が必要になる
template<class T, std::size_t N> struct GETTER<T[N]> { // ... };
相手がstd::arrayの場合の特殊化は以下
template<typename T, std::size_t N> struct GETTER<std::array<T, N> > { // ... };
#include <type_traits> #include <array> #include "len.hpp"template<typename T> struct GETTER<T*> { using arg_t = T*; using carg_t = const T*; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } };template<class T, std::size_t N> struct GETTER<T[N]> { using arg_t = T[N]; using carg_t = const T[N]; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } };template<typename T, std::size_t N> struct GETTER<std::array<T, N> > { using arg_t = std::array<T, N> &; using carg_t = const std::array<T, N> &; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } };//エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl;//配列 double xyz[3]; xyz[0] = 1; xyz[1] = 1; xyz[2] = 1; L = length(xyz); std::cout << L << std::endl;//ポインタ double *pxyz = new double[3]; pxyz[0] = 1; pxyz[1] = 1; pxyz[2] = 1; L = length(pxyz); std::cout << L << std::endl;//std::array std::array<double, 3> ary; ary[0] = 1; ary[1] = 1; ary[2] = 1; L = length(ary); std::cout << L << std::endl;int i; std::cin >> i; }
以下のようなコードがある。vec_tは三次元のベクトル型で、lengthはその長さを計算する
#pragma oncestruct vec_t { double x, y, z; };double length(const vec_t& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }
#include <iostream> #include "len.hpp" int main() { vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; double dbl = length(vv); std::cout << dbl << std::endl; int i; std::cin >>i; }
lengthはシンプルで可読性が高いが、移植性には欠ける。
具体的にはvec_tにしか対応していない。(故に読みやすいのだが。)
length関数をテンプレート化する
#pragma oncestruct vec_t { double x, y, z; };template<typename T> double length(const T& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }
これでx,y,zというメンバ変数がpublicにあればコンパイルできる。
#include <iostream> #include "len.hpp"struct xyz_t { double x, y, z; };int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; xyz_t xyz; xyz.x = 1; xyz.y = 1; xyz.z = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >>i; }
ではx,y,zがないときはどうすればいいのか。
#pragma once//デフォルトの型 struct vec_t { double x, y, z; };//プライマリテンプレート template<typename T> struct GETTER;//特殊化1(デフォルトの型) template<> struct GETTER<vec_t> { using arg_t = vec_t; using carg_t = const vec_t; static inline double& X(arg_t& v) { return v.x; } static inline double& Y(arg_t& v) { return v.y; } static inline double& Z(arg_t& v) { return v.z; } static inline const double& X(carg_t& v) { return v.x; } static inline const double& Y(carg_t& v) { return v.y; } static inline const double& Z(carg_t& v) { return v.z; } };template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); }
#include <iostream> #include "len.hpp" //自作の型 struct XYZ_t { double X, Y, Z; };
//特殊化2(自作の型用) template<> struct GETTER<XYZ_t> { using arg_t = XYZ_t; using carg_t = const XYZ_t; static inline double& X(arg_t& v) { return v.X; } static inline double& Y(arg_t& v) { return v.Y; } static inline double& Z(arg_t& v) { return v.Z; } static inline const double& X(carg_t& v) { return v.X; } static inline const double& Y(carg_t& v) { return v.Y; } static inline const double& Z(carg_t& v) { return v.Z; } };//エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; XYZ_t xyz; xyz.X = 1; xyz.X = 1; xyz.X = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >> i; }
これでGETTERを定義すればどんな型でも使える。
続く...
https://github.com/HowardHinnant/hash_append/issues/7
最新のC++にはBoostから正式に仕様に含められたhashが「unordered_map」という名前で入っているが、hash_combineは取り入れられていないらしい。なので自分で作る必要がある。
この時、多くはBoostを参考にすると思うのだが、Boostの中のマジックナンバーがどうやら32bitのもので、64bit版の場合、この数字はどうなるんだ?というのが上記サイトの議論の内容となっている。
そもそもこの数字はTEAアルゴリズムというものが根拠らしく、64bitの場合と、さらに128bitの場合の値が上げられている。
| ビット数 | 16進数表記の値 |
|---|---|
| 8 | 0x9e |
| 16 | 0x9e37 |
| 32 | 0x9e3779b9 |
| 64 | 0x9e3779b97f4a7c15 |
| 128 | 0x9e3779b97f4a7c15f39cc0605d396154 |
そして64bitは32bitの二倍なので、シフト量も二倍にする。
↓
なおこの(Boostの)HashCombineはさして優れているわけでは無いと言うことで、別の方法があるならそれを使うべきと言うような主張をちらほら見かける。
CityHashはGoogleが考案したハッシュアルゴリズムで、MITライセンス(らしい)。そこから転用したコードが紹介されている。
template <class T> inline void hash_combine(std::size_t& seed, const T& v) { std::hash<T> hasher; const std::size_t kMul = 0x9ddfea08eb382d69ULL; std::size_t a = (hasher(v) ^ seed) * kMul; a ^= (a >> 47); std::size_t b = (seed ^ a) * kMul; b ^= (b >> 47); seed = b * kMul; }
(このスニペットは、CityHashコードの「実質的な部分」を構成するものではないため、ここや他の場所に複製しても問題ないと思いますが、CityHashのソースとライセンス契約を確認して、自分で決めてください)
(Google翻訳)
c2220 警告をエラーとして扱いました。'object' ファイルは生成されません。
Open3DのCMakeを試していたのだけれど、VC++2017でC2220が大量発生した。関連するプロジェクトが無数にある場合で、一つ一つプロパティを開くのは避けたい場合、王道な方法が見つからなかったのでCMakeList.txtを編集して対処した。
単体のプロジェクトなら、以下のように /WX オプションを解除することで対処できる。

CMakeLists.txtをテキストエディタで開き、中の「/WX」という部分を削除する。
https://github.com/nigels-com/glew#copyright-and-licensing
GLEW is originally derived from the EXTGL project by Lev Povalahev. The source code is licensed under the Modified BSD License, the Mesa 3-D License (MIT) and the Khronos License (MIT).
The automatic code generation scripts are released under the GNU GPL.
glewはBSD LicenseかMITライセンス。普通誰も気にしないが、気に入らない場合は使用できない。
けれどやっていることはヘッダファイル側で定数を#defineしているのと、dll側でwglGetProcAddressしているだけ(多分)なので、必要な部分だけ自前で書くことも不可能ではない。
#pragma once #include <gl/GL.h> typedef ptrdiff_t GLsizeiptr; typedef char GLchar; //サンプルのコンパイルに必要なものだけを取り出したもの // 関数ポインタ型 using PFNGLGENBUFFERSPROC = void(_stdcall*) (GLsizei n, GLuint* buffers); using PFNGLBINDBUFFERPROC = void(_stdcall*) (GLenum target, GLuint buffer); using PFNGLBUFFERDATAPROC = void(_stdcall*) (GLenum target, GLsizeiptr size, const void* data, GLenum usage); using PFNGLCREATESHADERPROC = GLuint(_stdcall*) (GLenum type); using PFNGLSHADERSOURCEPROC = void(_stdcall*) (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); using PFNGLCOMPILESHADERPROC = void(_stdcall*) (GLuint shader); using PFNGLGETSHADERIVPROC = void(_stdcall*) (GLuint shader, GLenum pname, GLint* param); using PFNGLGETSHADERINFOLOGPROC = void(_stdcall*) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); using PFNGLCREATEPROGRAMPROC = GLuint(_stdcall*) (void); using PFNGLATTACHSHADERPROC = void(_stdcall*) (GLuint program, GLuint shader); using PFNGLLINKPROGRAMPROC = void(_stdcall*) (GLuint program); using PFNGLGETPROGRAMIVPROC = void(_stdcall*) (GLuint program, GLenum pname, GLint* param); using PFNGLGETPROGRAMINFOLOGPROC = void(_stdcall*) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); using PFNGLUSEPROGRAMPROC = void(_stdcall*) (GLuint program); using PFNGLENABLEVERTEXATTRIBARRAYPROC = void(_stdcall*) (GLuint index); using PFNGLVERTEXATTRIBPOINTERPROC = void(_stdcall*) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); using PFNGLDISABLEVERTEXATTRIBARRAYPROC = void(_stdcall*) (GLuint index); // 定数 #define GL_ARRAY_BUFFER 0x8892 #define GL_STATIC_DRAW 0x88E4 #define GL_VERTEX_SHADER 0x8B31 #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_LINK_STATUS 0x8B82 // wglGetProcAddressで取得したアドレスを格納する変数(グローバル) PFNGLGENBUFFERSPROC glGenBuffers; PFNGLBINDBUFFERPROC glBindBuffer; PFNGLBUFFERDATAPROC glBufferData; PFNGLCREATESHADERPROC glCreateShader; PFNGLSHADERSOURCEPROC glShaderSource; PFNGLCOMPILESHADERPROC glCompileShader; PFNGLGETSHADERIVPROC glGetShaderiv; PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLATTACHSHADERPROC glAttachShader; PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLGETPROGRAMIVPROC glGetProgramiv; PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; PFNGLUSEPROGRAMPROC glUseProgram; PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; //関数のアドレスを取得 inline void myglinit() { glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"); glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer"); glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData"); glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"); glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"); glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"); glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray"); glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray"); glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers"); glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog"); glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv"); glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog"); glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv"); glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"); glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"); glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"); glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer"); }
元のソースコード
#include <iostream> #pragma warning(disable:4996) //#pragma comment(lib,"glew32.lib") --- しない //#include <gl/glew.h> --- しない #include <Windows.h> #include <GL/glut.h> #include <fstream> #include <sstream> #include <vector> #include <algorithm> #include "myglinit.hpp" void init(void); void display(void); void link_program(); void prepare_buffers(); void prepare_vertex_shader(); void prepare_fragment_shader(); int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); //■ glewInit(); // glewの初期化 --- しない myglinit();// glewInit()関数の代わり init(); glutMainLoop(); return 0; } void init(void) { //頂点データと色情報の作成 prepare_buffers(); //頂点シェーダの準備 prepare_vertex_shader(); //フラグメントシェーダの準備 prepare_fragment_shader(); //プログラムのリンク link_program(); } //バッファとデータ typedef GLfloat points_t[3]; GLuint vertexbuffer;//バッファのIDを格納する変数 GLuint colorbuffer;//バッファのIDを格納する変数 points_t position[3]; points_t color[3]; ////////////////////////////////////////////////// void prepare_buffers() { //頂点座標 position[0][0] = 0; position[0][1] = 0.5; position[0][2] = 0; position[1][0] = 0.5; position[1][1] = -0.5; position[1][2] = 0; position[2][0] = -0.5; position[2][1] = -0.5; position[2][2] = 0; //色 color[0][0] = 1.0; color[0][1] = 0.0; color[0][2] = 0.0; color[1][0] = 0.0; color[1][1] = 1.0; color[1][2] = 0.0; color[2][0] = 0.0; color[2][1] = 0.0; color[2][2] = 1.0; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), position, GL_STATIC_DRAW); glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), color, GL_STATIC_DRAW); } GLuint VertexShaderID; void prepare_vertex_shader() { ////////////////////////////////////////////// // シェーダを作ります // (作るといっても宣言みたいなもの) VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、 // OpenGL命令は一つも無い。 const char * vertex_file_path = ".\\verts.sh"; std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); } //////////////////////////////////////////// // 頂点シェーダをコンパイルします。 printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); glCompileShader(VertexShaderID); //////////////////////////////////////////// // エラーチェック GLint Result = GL_FALSE; int InfoLogLength; // 頂点シェーダをチェックします。 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (Result == FALSE) { std::vector<char> VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); } } GLuint FragmentShaderID; void prepare_fragment_shader() { ///////////////////////////////////////////// // シェーダを作ります。 FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 const char * fragment_file_path = ".\\frags.sh"; std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } ///////////////////////////////////////////// // フラグメントシェーダをコンパイルします。 printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); glCompileShader(FragmentShaderID); GLint Result = GL_FALSE; int InfoLogLength; ///////////////////////////////////////////// // フラグメントシェーダをチェックします。 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (Result == GL_FALSE) { std::vector<char> FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); } } GLuint ProgramID; void link_program() { GLint Result = GL_FALSE; int InfoLogLength; //////////////////////////////////////// // プログラムをリンクします。 fprintf(stdout, "Linking program\n"); ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); //////////////////////////////////////// // プログラムをチェックします。 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector<char> ProgramErrorMessage((std::max)(InfoLogLength, int(1))); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); } void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslated(0.5, 0.0, 0.0);//平行移動 // シェーダを使う glUseProgram(ProgramID); // 頂点バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(x,y,z)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glVertexAttribPointer( 1, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(r,g,b)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(0);//バッファを無効にする glDisableVertexAttribArray(1); glFlush(); }
他にもリンクしちゃいけないときとかもこの方法をとることになると思う。ただその場合はglext.hを使えば自分で#define やtypedefを並べたりしなくて良くなる・・・のか?
「MIT Licenseを気にする状況ってどんな状況?」とか言う人がいそうなのだけれど、個人でならともかく業務でやっていると、自分より上の層で「俺が理解できないものは低品質なガラクタ」とか「俺の知らないものは使えないゴミ」等の謎理論で意味不明な利用制限がかかったりするので、できるかできないかぐらいは把握しておいた方がいい。後は、そういう契約になってるんだ!とか後から言われたり。しないかな?しないよね。
・ビットシフト(>>)には算術シフトと論理シフトがある。
・算術シフトは負数をシフトすると左側が1で埋まる (Arithmetic shift)
・論理シフトは負数をシフトすると左側が0で埋まる (Logical shift)
・どちらの挙動をするかは処理系依存
ということで、強制的に論理シフトしたい時は工夫する必要がある。
unsignedにキャストする。以下C++のコード。
#include <iostream> //表示のためにbitsetを使う #include <bitset> int main() { char val = -40; char S = val; char A = val >> 2;//処理系依存 VC++2019では算術シフト char L = static_cast<unsigned char>(val) >> 2;//論理シフト std::bitset<8> Sdisp(S); std::bitset<8> Adisp(A); std::bitset<8> Ldisp(L); std::cout << "source : " << Sdisp << " == " << static_cast<int>(S) << '\n'; std::cout << "not cast and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n'; std::cout << "cast to unsigned and >>2 : " << Ldisp << " == " << static_cast<int>(L) << '\n'; getchar(); return 0; }
同じ事を関数化するなら以下のような感じになる。
#include <iostream> #include<type_traits>
//! @brief 論理右シフト //! @param [in] val 右シフトする値 //! @param [in] shift 右シフトするビット数 //! @return val >> shift template<typename T> inline auto logical_right_shift(const T val,const int shift) { return static_cast< typename std::make_unsigned<T>::type>(val) >> shift; }
int main() { char val = -40; char S = val; char A = val >> 2;//処理系依存 VC++2019では算術シフト char L = logical_right_shift(val, 2);//論理シフト std::bitset<8> Sdisp(S); std::bitset<8> Adisp(A); std::bitset<8> Ldisp(L); std::cout << "source : " << Sdisp << " == " << static_cast<int>(S) << '\n'; std::cout << "not cast and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n'; std::cout << "logicalrightshift 2 : " << Ldisp << " == " << static_cast<int>(L) << '\n'; getchar(); }
負数の算術シフトが処理系依存とは。流石Cと言わざるを得ない。