Luaエンジンに算数ライブラリの追加、マトリックスライブラリ、そして3Dシェーダー

守矢諏訪子 <suwako@076.moe>、2026-06-27 06:30
コミット 41e54a766d031765ef525d2e4766a6d6d7fe9478 ・親 d49c308 ・ファイルを見る

10個のファイル、+728 -65

@@ -45,12 +45,17 @@
4545 NewShader(Info *info);
4646 ~NewShader();
4747
48- db::ShaderData Make();
48+ void DrawPopup();
49+ db::ShaderData Make(bool is3D = false);
4950
5051 private:
51- string getDefaultVert();
52- string getDefaultFrag();
53- string getDefaultLua();
52+ string getDefaultVert2D();
53+ string getDefaultFrag2D();
54+ string getDefaultLua2D();
55+
56+ string getDefaultVert3D();
57+ string getDefaultFrag3D();
58+ string getDefaultLua3D();
5459
5560 private:
5661 Info *m_Info;
@@ -61,6 +61,10 @@
6161 };
6262
6363 std::vector<Attribute> attr;
64+
65+ GLsizei GetIndexCount() const {
66+ return static_cast<GLsizei>(indices.size());
67+ }
6468 };
6569
6670 class LuaEngine {
@@ -87,10 +91,12 @@
8791 private:
8892 void LogError(sol::error err);
8993 void LogError(const std::exception &err);
94+ void LogError(const string &err);
9095 sol::state MakeAPI();
9196 void BindEngine(sol::state &lua);
9297 void BindSystem(sol::state &lua);
9398 void BindIO(sol::state &lua);
99+ void BindMath(sol::state &lua);
94100 void BindGraphics(sol::state &lua);
95101 void Execute(sol::state &lua);
96102
@@ -0,0 +1,212 @@
1+/*
2+# 076 Free License
3+
4+Copyright (c) テクニカル諏訪子
5+
6+Permission is hereby granted to any person obtaining a copy of the software
7+C++ Utils (the "Software") to use, modify, merge, copy, publish, distribute,
8+sublicense, and/or sell copies of the Software, subject to the following conditions:
9+
10+ 1. **Origin Attribution**:
11+ - You must not misrepresent the origin of the Software; you must not claim
12+ you created the original Software.
13+ 2. **Notice Preservation**:
14+ - This license and the above copyright notice must remain intact in all copies
15+ of the source code.
16+
17+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
19+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
22+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+*/
24+#ifndef MATRIX_HH
25+#define MATRIX_HH
26+
27+#include <util/types.hh>
28+#include <util/vector.hh>
29+
30+typedef struct {
31+ f32 m[16];
32+} Matrix4;
33+
34+typedef struct {
35+ f32 m[16];
36+} Matrix4x4;
37+
38+typedef struct {
39+ f32 m[12];
40+} Matrix4x3;
41+
42+inline Matrix4 operator*(const Matrix4 &a, const Matrix4 &b) {
43+ Matrix4 out = {};
44+
45+ for (int i = 0; i < 4; ++i) {
46+ for (int j = 0; j < 4; ++j) {
47+ float sum = 0.0f;
48+ for (int k = 0; k < 4; ++k) {
49+ sum += a.m[i + k * 4] * b.m[k + j * 4];
50+ }
51+ out.m[i + j * 4] = sum;
52+ }
53+ }
54+ return out;
55+}
56+
57+inline Matrix4 &operator*=(Matrix4 &a, const Matrix4 &b) {
58+ a = a * b;
59+ return a;
60+}
61+
62+inline Matrix4 mat4Identity() {
63+ Matrix4 out{};
64+
65+ out.m[0] = 1.f;
66+ out.m[5] = 1.f;
67+ out.m[10] = 1.f;
68+ out.m[15] = 1.f;
69+
70+ return out;
71+}
72+
73+inline Matrix4x4 mat4x4Identity() {
74+ Matrix4x4 out{};
75+
76+ out.m[0] = 1.f;
77+ out.m[5] = 1.f;
78+ out.m[10] = 1.f;
79+ out.m[15] = 1.f;
80+
81+ return out;
82+}
83+
84+inline Matrix4 mat4Mul(const Matrix4 &a, const Matrix4 &b) {
85+ Matrix4 out{};
86+
87+ for (int row = 0; row < 4; ++row) {
88+ for (int col = 0; col < 4; ++col) {
89+ out.m[col * 4 + row] =
90+ a.m[0 * 4 + row] * b.m[col * 4 + 0] +
91+ a.m[1 * 4 + row] * b.m[col * 4 + 1] +
92+ a.m[2 * 4 + row] * b.m[col * 4 + 2] +
93+ a.m[3 * 4 + row] * b.m[col * 4 + 3];
94+ }
95+ }
96+
97+ return out;
98+}
99+
100+inline Matrix4 mat4Translate(f32 x, f32 y, f32 z) {
101+ Matrix4 out = mat4Identity();
102+
103+ out.m[12] = x;
104+ out.m[13] = y;
105+ out.m[14] = z;
106+
107+ return out;
108+}
109+
110+inline Matrix4 mat4Scale(f32 x, f32 y, f32 z) {
111+ Matrix4 out = {};
112+
113+ out.m[0] = x;
114+ out.m[5] = y;
115+ out.m[10] = z;
116+ out.m[15] = 1.f;
117+
118+ return out;
119+}
120+
121+inline Matrix4 mat4RotateX(f32 angle) {
122+ Matrix4 out = mat4Identity();
123+
124+ f32 c = cosf(angle);
125+ f32 s = sinf(angle);
126+
127+ out.m[5] = c; // m[1][1]
128+ out.m[6] = s; // m[1][2]
129+ out.m[9] = -s; // m[2][1]
130+ out.m[10] = c; // m[2][2]
131+
132+ return out;
133+}
134+
135+inline Matrix4 mat4RotateY(f32 angle) {
136+ Matrix4 out = mat4Identity();
137+
138+ f32 c = cosf(angle);
139+ f32 s = sinf(angle);
140+
141+ out.m[0] = c; // m[0][0]
142+ out.m[2] = -s; // m[0][2]
143+ out.m[8] = s; // m[2][0]
144+ out.m[10] = c; // m[2][2]
145+
146+ return out;
147+}
148+
149+inline Matrix4 mat4RotateZ(f32 angle) {
150+ Matrix4 out = mat4Identity();
151+
152+ f32 c = cosf(angle);
153+ f32 s = sinf(angle);
154+
155+ out.m[0] = c; // m[0][0]
156+ out.m[1] = s; // m[0][1]
157+ out.m[4] = -s; // m[1][0]
158+ out.m[5] = c; // m[1][1]
159+
160+ return out;
161+}
162+
163+inline Matrix4 mat4Rotate(f32 pitch, f32 yaw, f32 roll) {
164+ return mat4RotateZ(roll) * mat4RotateY(yaw) * mat4RotateX(pitch);
165+}
166+
167+inline Matrix4 mat4Perspective(f32 fov, f32 aspect, f32 near, f32 far) {
168+ Matrix4 out = {};
169+ fov *= (3.14159265f / 180.f);
170+
171+ f32 tanHalf = tanf(fov * 0.5f);
172+
173+ out.m[0] = 1.f / (aspect * tanHalf);
174+ out.m[5] = 1.f / tanHalf;
175+ out.m[10] = -(far + near) / (far - near);
176+ out.m[11] = -1.f;
177+ out.m[14] = -(2.f * far * near) / (far - near);
178+
179+ return out;
180+}
181+
182+inline Matrix4 mat4LookAt(Vector3 eye, Vector3 target, Vector3 up) {
183+ Vector3 f = vec3Normalize(vec3Sub(target, eye));
184+ Vector3 r = vec3Normalize(vec3Cross(f, up));
185+ Vector3 u = vec3Cross(r, f);
186+
187+ Matrix4 out = {};
188+
189+ out.m[0] = r.pos.x;
190+ out.m[1] = u.pos.x;
191+ out.m[2] = -f.pos.x;
192+ out.m[3] = 0.f;
193+
194+ out.m[4] = r.pos.y;
195+ out.m[5] = u.pos.y;
196+ out.m[6] = -f.pos.y;
197+ out.m[7] = 0.f;
198+
199+ out.m[8] = r.pos.z;
200+ out.m[9] = u.pos.z;
201+ out.m[10] = -f.pos.z;
202+ out.m[11] = 0.f;
203+
204+ out.m[12] = -vec3Dot(r, eye);
205+ out.m[13] = -vec3Dot(u, eye);
206+ out.m[14] = vec3Dot(f, eye);
207+ out.m[15] = 1.f;
208+
209+ return out;
210+}
211+
212+#endif // MATRIX_HH
@@ -63,6 +63,8 @@
6363 bool isLangChange = false;
6464 bool isNewShader = false;
6565
66+ bool showNewShaderPopup = false;
67+
6668 std::string version = version::full;
6769 uint32_t shaderId = 0;
6870 std::string shaderName = "";
@@ -24,7 +24,7 @@
2424 #ifndef VECTOR_HH
2525 #define VECTOR_HH
2626
27-#include "types.hh"
27+#include <util/types.hh>
2828
2929 union Vector2 {
3030 struct Position {
@@ -265,5 +265,27 @@
265265 Position pos;
266266 RGBA rgba;
267267 };
268+
269+inline Vector3 vec3Sub(Vector3 a, Vector3 b) {
270+ return { a.pos.x - b.pos.x, a.pos.y - b.pos.y, a.pos.z - b.pos.z };
271+}
272+
273+inline f32 vec3Dot(Vector3 a, Vector3 b) {
274+ return a.pos.x * b.pos.x + a.pos.y * b.pos.y + a.pos.z * b.pos.z;
275+}
276+
277+inline Vector3 vec3Cross(Vector3 a, Vector3 b) {
278+ return {
279+ a.pos.y * b.pos.z - a.pos.z * b.pos.y,
280+ a.pos.z * b.pos.x - a.pos.x * b.pos.z,
281+ a.pos.x * b.pos.y - a.pos.y * b.pos.x,
282+ };
283+}
284+
285+inline Vector3 vec3Normalize(Vector3 v) {
286+ f32 len = sqrtf(v.pos.x * v.pos.x + v.pos.y * v.pos.y + v.pos.z * v.pos.z);
287+ if (len == 0.f) return { 0, 0, 0 };
288+ return { v.pos.x / len, v.pos.y / len, v.pos.z / len };
289+}
268290
269291 #endif // VECTOR_HH
変更 main.cc
@@ -87,6 +87,10 @@
8787 return -1;
8888 }
8989
90+ // 3Dを有効
91+ glEnable(GL_DEPTH_TEST);
92+ //glEnable(GL_CULL_FACE);
93+
9094 // ImGui設定
9195 gui::GuiEngine ge(&window);
9296
@@ -205,10 +209,17 @@
205209 }
206210
207211 shaderProgram.Reload(info.VERT.code, info.FRAG.code);
212+ shaderProgram.Use();
208213 luaEngine.SetProgram(&shaderProgram);
209214 luaEngine.Reload(info.LUA.code);
210215 {
211216 lua::LuaMesh newMesh = luaEngine.GetMesh();
217+ if (newMesh.vertices.empty() || newMesh.indices.empty()) {
218+ string msg;
219+ if (info.i18n->GetCurrentLanguage().code == "ja_JP") msg = "メッシュデータが空です。";
220+ else "Mesh data is empty.";
221+ throw std::runtime_error(msg);
222+ }
212223
213224 VAO.BindVertexArray();
214225
@@ -313,34 +324,79 @@
313324 };
314325
315326 info.create = [&]() {
316- gui::NewShader newShader(&info);
317- auto shdr = newShader.Make();
327+ if (ImGui::BeginPopupModal(info.i18n->GetWord("filenewcreateshader").c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
328+ if (ImGui::Button(info.i18n->GetWord("filenew2dshader").c_str(), ImVec2(200, 0))) {
329+ gui::NewShader newShader(&info);
330+ auto shdr = newShader.Make(false);
331+ info.shaderId = shdr.id;
332+ info.shaderName = shdr.name;
333+ info.VERT = shdr.vertexShader;
334+ info.FRAG = shdr.fragmentShader;
335+ info.LUA = shdr.luaCode;
318336
319- info.shaderId = shdr.id;
320- info.shaderName = shdr.name;
321- info.VERT = shdr.vertexShader;
322- info.FRAG = shdr.fragmentShader;
323- info.LUA = shdr.luaCode;
337+ vertEditor.SetCode(info.VERT.code);
338+ string nTit = info.shaderName + "(" + info.i18n->GetWord("editorvertshader") + ")";
339+ vertEditor.SetTitle(nTit + "###VertexEditor");
324340
325- vertEditor.SetCode(info.VERT.code);
326- string nTit = info.shaderName + "(" + info.i18n->GetWord("editorvertshader") + ")";
327- vertEditor.SetTitle(nTit + "###VertexEditor");
341+ fragEditor.SetCode(info.FRAG.code);
342+ nTit = info.shaderName + "(" + info.i18n->GetWord("editorfragshader") + ")";
343+ fragEditor.SetTitle(nTit + "###FragmentEditor");
328344
329- fragEditor.SetCode(info.FRAG.code);
330- nTit = info.shaderName + "(" + info.i18n->GetWord("editorfragshader") + ")";
331- fragEditor.SetTitle(nTit + "###FragmentEditor");
345+ luaEditor.SetCode(info.LUA.code);
346+ nTit = info.shaderName + "(" + info.i18n->GetWord("editorlua") + ")";
347+ luaEditor.SetTitle(nTit + "###LuaEditor");
332348
333- luaEditor.SetCode(info.LUA.code);
334- nTit = info.shaderName + "(" + info.i18n->GetWord("editorlua") + ")";
335- luaEditor.SetTitle(nTit + "###LuaEditor");
349+ info.compile();
336350
337- info.compile();
351+ gui::LogEntry entry;
352+ entry.type = gui::LogType::Info;
353+ entry.text = info.i18n->GetWord("consoleloginfocreateok");
354+ info.cmd->Add(entry);
355+ std::cout << entry.text << std::endl;
338356
339- gui::LogEntry entry;
340- entry.type = gui::LogType::Info;
341- entry.text = info.i18n->GetWord("consoleloginfocreateok");
342- info.cmd->Add(entry);
343- std::cout << entry.text << std::endl;
357+ ImGui::CloseCurrentPopup();
358+ }
359+
360+ if (ImGui::Button(info.i18n->GetWord("filenew3dshader").c_str(), ImVec2(200, 0))) {
361+ gui::NewShader newShader(&info);
362+ auto shdr = newShader.Make(true);
363+ info.shaderId = shdr.id;
364+ info.shaderName = shdr.name;
365+ info.VERT = shdr.vertexShader;
366+ info.FRAG = shdr.fragmentShader;
367+ info.LUA = shdr.luaCode;
368+
369+ vertEditor.SetCode(info.VERT.code);
370+ string nTit = info.shaderName + "(" + info.i18n->GetWord("editorvertshader") + ")";
371+ vertEditor.SetTitle(nTit + "###VertexEditor");
372+
373+ fragEditor.SetCode(info.FRAG.code);
374+ nTit = info.shaderName + "(" + info.i18n->GetWord("editorfragshader") + ")";
375+ fragEditor.SetTitle(nTit + "###FragmentEditor");
376+
377+ luaEditor.SetCode(info.LUA.code);
378+ nTit = info.shaderName + "(" + info.i18n->GetWord("editorlua") + ")";
379+ luaEditor.SetTitle(nTit + "###LuaEditor");
380+
381+ info.compile();
382+
383+ gui::LogEntry entry;
384+ entry.type = gui::LogType::Info;
385+ entry.text = info.i18n->GetWord("consoleloginfocreateok");
386+ info.cmd->Add(entry);
387+ std::cout << entry.text << std::endl;
388+
389+ ImGui::CloseCurrentPopup();
390+ }
391+
392+ ImGui::Separator();
393+
394+ if (ImGui::Button(info.i18n->GetWord("cancel").c_str())) {
395+ ImGui::CloseCurrentPopup();
396+ }
397+
398+ ImGui::EndPopup();
399+ }
344400 };
345401 #pragma endregion
346402
@@ -367,7 +423,7 @@
367423 }
368424
369425 if (isNewKey) {
370- info.create();
426+ info.showNewShaderPopup = true;
371427 }
372428
373429 if (isOpenKey) {}
@@ -419,6 +475,13 @@
419475
420476 gui::showTitleBar(info);
421477
478+ if (info.showNewShaderPopup) {
479+ ImGui::OpenPopup(info.i18n->GetWord("filenewcreateshader").c_str());
480+ info.showNewShaderPopup = false;
481+ }
482+
483+ info.create();
484+
422485 #ifndef PRODUCTION_BUILD
423486 if (showDemo) ImGui::ShowDemoWindow(&showDemo);
424487 #endif
@@ -448,7 +511,7 @@
448511
449512 // クアッドを描画
450513 VAO.BindVertexArray();
451- glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
514+ glDrawElements(GL_TRIANGLES, mesh.GetIndexCount(), GL_UNSIGNED_INT, nullptr);
452515 glBindFramebuffer(GL_FRAMEBUFFER, 0);
453516
454517 // バッファをスワップし、イベントを処理
@@ -180,12 +180,22 @@
180180 createWord(db, 2, "file", "File");
181181 createWord(db, 1, "filenew", "新しいファイル");
182182 createWord(db, 2, "filenew", "New File");
183+ createWord(db, 1, "filenewcreateshader", "新しいシェーダーを作成");
184+ createWord(db, 2, "filenewcreateshader", "New Shader Creation");
185+ createWord(db, 1, "filenew2dshader", "2D シェーダー");
186+ createWord(db, 2, "filenew2dshader", "2D Shader");
187+ createWord(db, 1, "filenew3dshader", "3D シェーダー");
188+ createWord(db, 2, "filenew3dshader", "3D Shader");
183189 createWord(db, 1, "fileopen", "開く");
184190 createWord(db, 2, "fileopen", "Open");
185191 createWord(db, 1, "filesave", "保存");
186192 createWord(db, 2, "filesave", "Save");
187193 createWord(db, 1, "quit", "終了");
188194 createWord(db, 2, "quit", "Quit");
195+ createWord(db, 1, "cancel", "キャンセル");
196+ createWord(db, 2, "cancel", "Cancel");
197+ createWord(db, 1, "ok", "OK");
198+ createWord(db, 2, "ok", "OK");
189199 createWord(db, 1, "editorvertshader", "頂点シェーダー");
190200 createWord(db, 2, "editorvertshader", "Vertex Shader");
191201 createWord(db, 1, "editorfragshader", "フラグメントシェーダー");
@@ -36,12 +36,25 @@
3636 */
3737 #include <gui/newshader.hh>
3838 #include <database/locale.hh>
39+#include <imgui.h>
3940
4041 namespace gui {
4142 NewShader::NewShader(Info *info) : m_Info(info) {}
4243 NewShader::~NewShader() {}
4344
44- db::ShaderData NewShader::Make() {
45+ void NewShader::DrawPopup() {
46+ if (ImGui::BeginPopupModal("NewShaderPopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
47+ ImGui::Text(m_Info->i18n->GetWord("filenewcreateshader").c_str());
48+ ImGui::Separator();
49+
50+ if (ImGui::Button("2D Shader", ImVec2(200, 0))) {
51+ Make(false);
52+ m_Info->create();
53+ }
54+ }
55+ }
56+
57+ db::ShaderData NewShader::Make(bool is3D) {
4558 db::ShaderData newShader = {};
4659 auto curLang = m_Info->i18n->GetCurrentLanguage().code;
4760 newShader.id = 0;
@@ -51,17 +64,17 @@
5164
5265 newShader.vertexShader.id = 0;
5366 newShader.vertexShader.type = db::ShaderCodeType::GlslVertex;
54- newShader.vertexShader.code = getDefaultVert();
67+ newShader.vertexShader.code = is3D ? getDefaultVert3D() : getDefaultVert2D();
5568 newShader.vertexShader.filename = "";
5669
5770 newShader.fragmentShader.id = 0;
5871 newShader.fragmentShader.type = db::ShaderCodeType::GlslFragment;
59- newShader.fragmentShader.code = getDefaultFrag();
72+ newShader.fragmentShader.code = is3D ? getDefaultFrag3D() : getDefaultFrag2D();
6073 newShader.fragmentShader.filename = "";
6174
6275 newShader.luaCode.id = 0;
6376 newShader.luaCode.type = db::ShaderCodeType::Lua;
64- newShader.luaCode.code = getDefaultLua();
77+ newShader.luaCode.code = is3D ? getDefaultLua3D() : getDefaultLua2D();
6578 newShader.luaCode.filename = "";
6679
6780 return newShader;
@@ -69,7 +82,7 @@
6982
7083 ///////////////////////////
7184
72- string NewShader::getDefaultVert() {
85+ string NewShader::getDefaultVert2D() {
7386 return R"(#version 460 core
7487
7588 layout(location = 0) in vec2 aPosition;
@@ -82,7 +95,7 @@
8295 })";
8396 }
8497
85- string NewShader::getDefaultFrag() {
98+ string NewShader::getDefaultFrag2D() {
8699 return R"(#version 460 core
87100
88101 in vec3 vColor;
@@ -93,7 +106,7 @@
93106 })";
94107 }
95108
96- string NewShader::getDefaultLua() {
109+ string NewShader::getDefaultLua2D() {
97110 return R"(local stride = le.sizeof("vec2") + le.sizeof("vec3")
98111
99112 local mesh = {
@@ -126,6 +139,110 @@
126139 end
127140
128141 function update()
142+end)";
143+ }
144+
145+ string NewShader::getDefaultVert3D() {
146+ return R"(#version 460 core
147+
148+layout(location = 0) in vec3 aPosition;
149+layout(location = 1) in vec3 aColor;
150+
151+out vec3 vColor;
152+
153+uniform mat4 uModel;
154+uniform mat4 uView;
155+uniform mat4 uProjection;
156+
157+void main() {
158+ vColor = aColor;
159+ gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0);
160+})";
161+ }
162+
163+ string NewShader::getDefaultFrag3D() {
164+ return R"(#version 460 core
165+
166+in vec3 vColor;
167+out vec4 out_color;
168+
169+void main() {
170+ out_color = vec4(vColor, 1.0);
171+})";
172+ }
173+
174+ string NewShader::getDefaultLua3D() {
175+ return R"(local offset = le.sizeof("vec3")
176+local stride = offset * 2
177+
178+local mesh = {
179+ vertices = {
180+ -- position -- uv
181+ -- mae
182+ -0.5, -0.5, -0.5, 1,0,0,
183+ 0.5, -0.5, -0.5, 0,1,0,
184+ 0.5, 0.5, -0.5, 0,0,1,
185+ -0.5, 0.5, -0.5, 1,1,0,
186+ -- usiro
187+ -0.5, -0.5, 0.5, 1,0,1,
188+ 0.5, -0.5, 0.5, 0,1,1,
189+ 0.5, 0.5, 0.5, 1,1,1,
190+ -0.5, 0.5, 0.5, 1,0,1,
191+ },
192+
193+ indices = {
194+ -- mae
195+ 0,1,2, 2,3,0,
196+ -- migi
197+ 1,5,6, 6,2,1,
198+ -- usiro
199+ 5,4,7, 7,6,5,
200+ -- hidari
201+ 4,0,3, 3,7,4,
202+ -- ue
203+ 3,2,6, 6,7,3,
204+ -- sita
205+ 4,5,1, 1,0,4
206+ },
207+
208+ attributes = {
209+ { location = 0, size = 3, stride = stride, offset = 0 },
210+ { location = 1, size = 3, stride = stride, offset = offset }
211+ }
212+}
213+
214+le.gfx.set_mesh(mesh)
215+
216+function init()
217+end
218+
219+function update()
220+ local t = le.sys.get_time()
221+ local reso = le.sys.get_resolution()
222+ local aspect = reso.x / reso.y
223+
224+ local model = le.math.rotate(
225+ t * 0.7,
226+ t * 1.0,
227+ t * 0.4
228+ )
229+
230+ local view = le.math.look_at(
231+ 0, 0, 4, -- eye
232+ 0, 0, 0, -- target
233+ 0, 1, 0 -- up
234+ )
235+
236+ local projection = le.math.perspective(
237+ 45.0,
238+ aspect,
239+ 0.1,
240+ 100.0
241+ )
242+
243+ le.gfx.set_uniform_mat4("uModel", model)
244+ le.gfx.set_uniform_mat4("uView", view)
245+ le.gfx.set_uniform_mat4("uProjection", projection)
129246 end)";
130247 }
131248 } // namespace gui
@@ -40,6 +40,7 @@
4040 #include <glfw/glfw3.h>
4141 #include <util/glfwpp.hh>
4242 #include <util/vector.hh>
43+#include <util/matrix.hh>
4344 #include <util/random.hh>
4445 #include <database/locale.hh>
4546 #include <gui/consolelog.hh>
@@ -102,7 +103,7 @@
102103 }
103104
104105 sol::state testApi = MakeAPI();
105- sol::load_result resApi = m_Lua.load(code);
106+ sol::load_result resApi = testApi.load(code);
106107 //sol::protected_function_result resApi = testApi.safe_script(code);
107108 if (!resApi.valid()) {
108109 sol::error err = resApi;
@@ -124,7 +125,7 @@
124125 entry.type = gui::LogType::Error;
125126 entry.text = err.what();
126127 m_Info->cmd->Add(entry);
127- std::cerr << err.what() << std::endl;
128+ std::cerr << entry.text << std::endl;
128129 }
129130
130131 void LuaEngine::LogError(const std::exception &err) {
@@ -132,9 +133,17 @@
132133 entry.type = gui::LogType::Error;
133134 entry.text = err.what();
134135 m_Info->cmd->Add(entry);
135- std::cerr << err.what() << std::endl;
136+ std::cerr << entry.text << std::endl;
136137 }
137138
139+ void LuaEngine::LogError(const string &err) {
140+ gui::LogEntry entry = {};
141+ entry.type = gui::LogType::Error;
142+ entry.text = err;
143+ m_Info->cmd->Add(entry);
144+ std::cerr << entry.text << std::endl;
145+ }
146+
138147 sol::state LuaEngine::MakeAPI() {
139148 sol::state out;
140149
@@ -341,6 +350,7 @@
341350 BindEngine(out);
342351 BindSystem(out);
343352 BindIO(out);
353+ BindMath(out);
344354 BindGraphics(out);
345355 } catch (const std::exception &e) {
346356 LogError(e);
@@ -446,11 +456,7 @@
446456
447457 auto it = sizes.find(type);
448458 if (it == sizes.end()) {
449- gui::LogEntry entry = {};
450- entry.type = gui::LogType::Error;
451- entry.text = "不正な値類: " + type;
452- m_Info->cmd->Add(entry);
453- std::cerr << entry.text << std::endl;
459+ LogError("不正な値類: " + type);
454460 return 0;
455461 }
456462
@@ -502,6 +508,107 @@
502508 };
503509 }
504510
511+ void LuaEngine::BindMath(sol::state &lua) {
512+ lua["le"]["math"] = lua.create_table();
513+
514+ lua["le"]["math"]["identity"] = [](sol::this_state ts) -> sol::table {
515+ sol::state_view lua(ts);
516+ Matrix4 m = mat4Identity();
517+ sol::table t = lua.create_table();
518+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
519+ return t;
520+ };
521+
522+ lua["le"]["math"]["translate"] = [](sol::this_state ts, f32 x, f32 y, f32 z) -> sol::table {
523+ sol::state_view lua(ts);
524+ Matrix4 m = mat4Translate(x, y, z);
525+ sol::table t = lua.create_table();
526+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
527+ return t;
528+ };
529+
530+ lua["le"]["math"]["scale"] = [](sol::this_state ts, f32 x, f32 y, f32 z) -> sol::table {
531+ sol::state_view lua(ts);
532+ Matrix4 m = mat4Scale(x, y, z);
533+ sol::table t = lua.create_table();
534+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
535+ return t;
536+ };
537+
538+ lua["le"]["math"]["rotate_x"] = [](sol::this_state ts, f32 angle) -> sol::table {
539+ sol::state_view lua(ts);
540+ Matrix4 m = mat4RotateX(angle);
541+ sol::table t = lua.create_table();
542+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
543+ return t;
544+ };
545+
546+ lua["le"]["math"]["rotate_y"] = [](sol::this_state ts, f32 angle) -> sol::table {
547+ sol::state_view lua(ts);
548+ Matrix4 m = mat4RotateY(angle);
549+ sol::table t = lua.create_table();
550+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
551+ return t;
552+ };
553+
554+ lua["le"]["math"]["rotate_z"] = [](sol::this_state ts, f32 angle) -> sol::table {
555+ sol::state_view lua(ts);
556+ Matrix4 m = mat4RotateZ(angle);
557+ sol::table t = lua.create_table();
558+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
559+ return t;
560+ };
561+
562+ lua["le"]["math"]["rotate"] = [](sol::this_state ts, f32 pitch, f32 yaw, f32 roll) -> sol::table {
563+ sol::state_view lua(ts);
564+ Matrix4 m = mat4Rotate(pitch, yaw, roll);
565+ sol::table t = lua.create_table();
566+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
567+ return t;
568+ };
569+
570+ lua["le"]["math"]["perspective"] = [](sol::this_state ts, f32 fov, f32 aspect, f32 near, f32 far) -> sol::table {
571+ sol::state_view lua(ts);
572+ Matrix4 m = mat4Perspective(fov, aspect, near, far);
573+ sol::table t = lua.create_table();
574+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
575+ return t;
576+ };
577+
578+ lua["le"]["math"]["mul"] = [](sol::this_state ts, sol::table a, sol::table b) -> sol::table {
579+ sol::state_view lua(ts);
580+ Matrix4 ma{}, mb{};
581+
582+ for (i32 i = 0; i < 16; ++i) {
583+ ma.m[i] = a[i + 1];
584+ mb.m[i] = b[i + 1];
585+ }
586+
587+ Matrix4 out = mat4Mul(ma, mb);
588+ sol::table t = lua.create_table();
589+ for (i32 i = 0; i < 16; ++i) t[i + 1] = out.m[i];
590+
591+ return t;
592+ };
593+
594+ lua["le"]["math"]["look_at"] = [](sol::this_state ts,
595+ f32 ex, f32 ey, f32 ez,
596+ f32 tx, f32 ty, f32 tz,
597+ f32 ux, f32 uy, f32 uz) -> sol::table {
598+ sol::state_view lua(ts);
599+ Matrix4 m = mat4LookAt(
600+ { ex, ey, ez },
601+ { tx, ty, tz },
602+ { ux, uy, uz }
603+ );
604+
605+ sol::table t = lua.create_table();
606+ for (i32 i = 0; i < 16; ++i) t[i + 1] = m.m[i];
607+
608+ return t;
609+ };
610+ }
611+
505612 void LuaEngine::BindGraphics(sol::state &lua) {
506613 lua["le"]["gfx"] = lua.create_table();
507614
@@ -540,102 +647,221 @@
540647
541648 lua["le"]["gfx"]["set_uniform1"] = [&](const string &name, f32 x) {
542649 if (!m_Program) return;
543- glUniform1f(m_Program->GetUniformLocation(name), x);
650+ GLint loc = m_Program->GetUniformLocation(name);
651+ if (loc == -1) {
652+ LogError("ユニフォーム見つけられません: " + name);
653+ return;
654+ }
655+ glUniform1f(loc, x);
544656 };
545657
546658 lua["le"]["gfx"]["set_uniform2"] = [&](const string &name, f32 x, f32 y) {
547659 if (!m_Program) return;
548- glUniform2f(m_Program->GetUniformLocation(name), x, y);
660+ GLint loc = m_Program->GetUniformLocation(name);
661+ if (loc == -1) {
662+ LogError("ユニフォーム見つけられません: " + name);
663+ return;
664+ }
665+ glUniform2f(loc, x, y);
549666 };
550667
551668 lua["le"]["gfx"]["set_uniform3"] = [&](const string &name, f32 x, f32 y, f32 z) {
552669 if (!m_Program) return;
553- glUniform3f(m_Program->GetUniformLocation(name), x, y, z);
670+ GLint loc = m_Program->GetUniformLocation(name);
671+ if (loc == -1) {
672+ LogError("ユニフォーム見つけられません: " + name);
673+ return;
674+ }
675+ glUniform3f(loc, x, y, z);
554676 };
555677
556678 lua["le"]["gfx"]["set_uniform4"] = [&](const string &name, f32 x, f32 y, f32 z, f32 w) {
557679 if (!m_Program) return;
558- glUniform4f(m_Program->GetUniformLocation(name), x, y, z, w);
680+ GLint loc = m_Program->GetUniformLocation(name);
681+ if (loc == -1) {
682+ LogError("ユニフォーム見つけられません: " + name);
683+ return;
684+ }
685+ glUniform4f(loc, x, y, z, w);
559686 };
560687
561688 lua["le"]["gfx"]["set_uniform_float1"] = [&](const string &name, f32 x) {
562689 if (!m_Program) return;
563- glUniform1f(m_Program->GetUniformLocation(name), x);
690+ GLint loc = m_Program->GetUniformLocation(name);
691+ if (loc == -1) {
692+ LogError("ユニフォーム見つけられません: " + name);
693+ return;
694+ }
695+ glUniform1f(loc, x);
564696 };
565697
566698 lua["le"]["gfx"]["set_uniform_float2"] = [&](const string &name, f32 x, f32 y) {
567699 if (!m_Program) return;
568- glUniform2f(m_Program->GetUniformLocation(name), x, y);
700+ GLint loc = m_Program->GetUniformLocation(name);
701+ if (loc == -1) {
702+ LogError("ユニフォーム見つけられません: " + name);
703+ return;
704+ }
705+ glUniform2f(loc, x, y);
569706 };
570707
571708 lua["le"]["gfx"]["set_uniform_float3"] = [&](const string &name, f32 x, f32 y, f32 z) {
572709 if (!m_Program) return;
573- glUniform3f(m_Program->GetUniformLocation(name), x, y, z);
710+ GLint loc = m_Program->GetUniformLocation(name);
711+ if (loc == -1) {
712+ LogError("ユニフォーム見つけられません: " + name);
713+ return;
714+ }
715+ glUniform3f(loc, x, y, z);
574716 };
575717
576718 lua["le"]["gfx"]["set_uniform_float4"] = [&](const string &name, f32 x, f32 y, f32 z, f32 w) {
577719 if (!m_Program) return;
578- glUniform4f(m_Program->GetUniformLocation(name), x, y, z, w);
720+ GLint loc = m_Program->GetUniformLocation(name);
721+ if (loc == -1) {
722+ LogError("ユニフォーム見つけられません: " + name);
723+ return;
724+ }
725+ glUniform4f(loc, x, y, z, w);
579726 };
580727
581728 lua["le"]["gfx"]["set_uniform_double1"] = [&](const string &name, f64 x) {
582729 if (!m_Program) return;
583- glUniform1d(m_Program->GetUniformLocation(name), x);
730+ GLint loc = m_Program->GetUniformLocation(name);
731+ if (loc == -1) {
732+ LogError("ユニフォーム見つけられません: " + name);
733+ return;
734+ }
735+ glUniform1d(loc, x);
584736 };
585737
586738 lua["le"]["gfx"]["set_uniform_double2"] = [&](const string &name, f64 x, f64 y) {
587739 if (!m_Program) return;
588- glUniform2d(m_Program->GetUniformLocation(name), x, y);
740+ GLint loc = m_Program->GetUniformLocation(name);
741+ if (loc == -1) {
742+ LogError("ユニフォーム見つけられません: " + name);
743+ return;
744+ }
745+ glUniform2d(loc, x, y);
589746 };
590747
591748 lua["le"]["gfx"]["set_uniform_double3"] = [&](const string &name, f64 x, f64 y, f64 z) {
592749 if (!m_Program) return;
593- glUniform3d(m_Program->GetUniformLocation(name), x, y, z);
750+ GLint loc = m_Program->GetUniformLocation(name);
751+ if (loc == -1) {
752+ LogError("ユニフォーム見つけられません: " + name);
753+ return;
754+ }
755+ glUniform3d(loc, x, y, z);
594756 };
595757
596758 lua["le"]["gfx"]["set_uniform_double4"] = [&](const string &name, f64 x, f64 y, f64 z, f64 w) {
597759 if (!m_Program) return;
598- glUniform4d(m_Program->GetUniformLocation(name), x, y, z, w);
760+ GLint loc = m_Program->GetUniformLocation(name);
761+ if (loc == -1) {
762+ LogError("ユニフォーム見つけられません: " + name);
763+ return;
764+ }
765+ glUniform4d(loc, x, y, z, w);
599766 };
600767
601768 lua["le"]["gfx"]["set_uniform_int1"] = [&](const string &name, i32 x) {
602769 if (!m_Program) return;
603- glUniform1i(m_Program->GetUniformLocation(name), x);
770+ GLint loc = m_Program->GetUniformLocation(name);
771+ if (loc == -1) {
772+ LogError("ユニフォーム見つけられません: " + name);
773+ return;
774+ }
775+ glUniform1i(loc, x);
604776 };
605777
606778 lua["le"]["gfx"]["set_uniform_int2"] = [&](const string &name, i32 x, i32 y) {
607779 if (!m_Program) return;
608- glUniform2i(m_Program->GetUniformLocation(name), x, y);
780+ GLint loc = m_Program->GetUniformLocation(name);
781+ if (loc == -1) {
782+ LogError("ユニフォーム見つけられません: " + name);
783+ return;
784+ }
785+ glUniform2i(loc, x, y);
609786 };
610787
611788 lua["le"]["gfx"]["set_uniform_int3"] = [&](const string &name, i32 x, i32 y, i32 z) {
612789 if (!m_Program) return;
613- glUniform3i(m_Program->GetUniformLocation(name), x, y, z);
790+ GLint loc = m_Program->GetUniformLocation(name);
791+ if (loc == -1) {
792+ LogError("ユニフォーム見つけられません: " + name);
793+ return;
794+ }
795+ glUniform3i(loc, x, y, z);
614796 };
615797
616798 lua["le"]["gfx"]["set_uniform_int4"] = [&](const string &name, i32 x, i32 y, i32 z, i32 w) {
617799 if (!m_Program) return;
618- glUniform4i(m_Program->GetUniformLocation(name), x, y, z, w);
800+ GLint loc = m_Program->GetUniformLocation(name);
801+ if (loc == -1) {
802+ LogError("ユニフォーム見つけられません: " + name);
803+ return;
804+ }
805+ glUniform4i(loc, x, y, z, w);
619806 };
620807
621808 lua["le"]["gfx"]["set_uniform_uint1"] = [&](const string &name, u32 x) {
622809 if (!m_Program) return;
623- glUniform1ui(m_Program->GetUniformLocation(name), x);
810+ GLint loc = m_Program->GetUniformLocation(name);
811+ if (loc == -1) {
812+ LogError("ユニフォーム見つけられません: " + name);
813+ return;
814+ }
815+ glUniform1ui(loc, x);
624816 };
625817
626818 lua["le"]["gfx"]["set_uniform_uint2"] = [&](const string &name, u32 x, u32 y) {
627819 if (!m_Program) return;
628- glUniform2ui(m_Program->GetUniformLocation(name), x, y);
820+ GLint loc = m_Program->GetUniformLocation(name);
821+ if (loc == -1) {
822+ LogError("ユニフォーム見つけられません: " + name);
823+ return;
824+ }
825+ glUniform2ui(loc, x, y);
629826 };
630827
631828 lua["le"]["gfx"]["set_uniform_uint3"] = [&](const string &name, u32 x, u32 y, u32 z) {
632829 if (!m_Program) return;
633- glUniform3ui(m_Program->GetUniformLocation(name), x, y, z);
830+ GLint loc = m_Program->GetUniformLocation(name);
831+ if (loc == -1) {
832+ LogError("ユニフォーム見つけられません: " + name);
833+ return;
834+ }
835+ glUniform3ui(loc, x, y, z);
634836 };
635837
636838 lua["le"]["gfx"]["set_uniform_uint4"] = [&](const string &name, u32 x, u32 y, u32 z, u32 w) {
637839 if (!m_Program) return;
638- glUniform4ui(m_Program->GetUniformLocation(name), x, y, z, w);
840+ GLint loc = m_Program->GetUniformLocation(name);
841+ if (loc == -1) {
842+ LogError("ユニフォーム見つけられません: " + name);
843+ return;
844+ }
845+ glUniform4ui(loc, x, y, z, w);
846+ };
847+
848+ lua["le"]["gfx"]["set_uniform_mat4"] = [&](const string &name, sol::table t) {
849+ if (!m_Program) return;
850+ if (t.size() != 16) {
851+ if (m_Info->i18n->GetCurrentLanguage().code == "ja_JP") LogError("mat4は16個の値が必要です。");
852+ else LogError("mat4 must have 16 values.");
853+ return;
854+ }
855+
856+ Matrix4 mat{};
857+ for (i32 i = 0; i < 16; ++i) mat.m[i] = t[i + 1];
858+
859+ GLint loc = m_Program->GetUniformLocation(name);
860+ if (loc == -1) {
861+ LogError("ユニフォーム見つけられません: " + name);
862+ return;
863+ }
864+ glUniformMatrix4fv(loc, 1, GL_FALSE, mat.m);
639865 };
640866 }
641867
@@ -96,7 +96,7 @@
9696 }
9797
9898 void Program::Clear(GLbitfield mask) {
99- glClear(GL_COLOR_BUFFER_BIT);
99+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
100100 }
101101
102102 GLint Program::GetUniformLocation(string var) {