Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / VarVisitorsLua.cpp
blobd6d0848118c602968fa6f1ad2629ac93f755f5df
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #include "VarVisitorsLua.hpp"
9 extern "C"
11 #include <lua.h>
12 #include <lauxlib.h>
15 #include <cctype>
18 using namespace cf::TypeSys;
21 /***************************/
22 /*** VarVisitorGetToLuaT ***/
23 /***************************/
25 VarVisitorGetToLuaT::VarVisitorGetToLuaT(lua_State* LuaState)
26 : m_LuaState(LuaState),
27 m_NumResults(0)
32 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<float>& Var)
34 lua_pushnumber(m_LuaState, Var.Get());
35 m_NumResults++;
39 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<double>& Var)
41 lua_pushnumber(m_LuaState, Var.Get());
42 m_NumResults++;
46 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<int>& Var)
48 lua_pushinteger(m_LuaState, Var.Get());
49 m_NumResults++;
53 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<unsigned int>& Var)
55 lua_pushinteger(m_LuaState, Var.Get());
56 m_NumResults++;
60 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<uint16_t>& Var)
62 lua_pushinteger(m_LuaState, Var.Get());
63 m_NumResults++;
67 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<uint8_t>& Var)
69 lua_pushinteger(m_LuaState, Var.Get());
70 m_NumResults++;
74 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<bool>& Var)
76 lua_pushboolean(m_LuaState, Var.Get());
77 m_NumResults++;
81 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<std::string>& Var)
83 lua_pushstring(m_LuaState, Var.Get().c_str());
84 m_NumResults++;
88 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<Vector2fT>& Var)
90 lua_pushnumber(m_LuaState, Var.Get().x); m_NumResults++;
91 lua_pushnumber(m_LuaState, Var.Get().y); m_NumResults++;
95 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<Vector3fT>& Var)
97 lua_pushnumber(m_LuaState, Var.Get().x); m_NumResults++;
98 lua_pushnumber(m_LuaState, Var.Get().y); m_NumResults++;
99 lua_pushnumber(m_LuaState, Var.Get().z); m_NumResults++;
103 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<Vector3dT>& Var)
105 lua_pushnumber(m_LuaState, Var.Get().x); m_NumResults++;
106 lua_pushnumber(m_LuaState, Var.Get().y); m_NumResults++;
107 lua_pushnumber(m_LuaState, Var.Get().z); m_NumResults++;
111 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarT<BoundingBox3dT>& Var)
113 lua_pushnumber(m_LuaState, Var.Get().Min.x); m_NumResults++;
114 lua_pushnumber(m_LuaState, Var.Get().Min.y); m_NumResults++;
115 lua_pushnumber(m_LuaState, Var.Get().Min.z); m_NumResults++;
117 lua_pushnumber(m_LuaState, Var.Get().Max.x); m_NumResults++;
118 lua_pushnumber(m_LuaState, Var.Get().Max.y); m_NumResults++;
119 lua_pushnumber(m_LuaState, Var.Get().Max.z); m_NumResults++;
123 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarArrayT<uint32_t>& Var)
125 lua_newtable(m_LuaState);
126 m_NumResults++;
128 for (unsigned int i = 0; i < Var.Size(); i++)
130 lua_pushinteger(m_LuaState, Var[i]);
131 lua_rawseti(m_LuaState, -2, i + 1); // Lua array numbering starts per convention at 1.
136 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarArrayT<uint16_t>& Var)
138 lua_newtable(m_LuaState);
139 m_NumResults++;
141 for (unsigned int i = 0; i < Var.Size(); i++)
143 lua_pushinteger(m_LuaState, Var[i]);
144 lua_rawseti(m_LuaState, -2, i + 1); // Lua array numbering starts per convention at 1.
149 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarArrayT<uint8_t>& Var)
151 lua_newtable(m_LuaState);
152 m_NumResults++;
154 for (unsigned int i = 0; i < Var.Size(); i++)
156 lua_pushinteger(m_LuaState, Var[i]);
157 lua_rawseti(m_LuaState, -2, i + 1); // Lua array numbering starts per convention at 1.
162 void VarVisitorGetToLuaT::visit(const cf::TypeSys::VarArrayT<std::string>& Var)
164 lua_newtable(m_LuaState);
165 m_NumResults++;
167 for (unsigned int i = 0; i < Var.Size(); i++)
169 lua_pushstring(m_LuaState, Var[i].c_str());
170 lua_rawseti(m_LuaState, -2, i + 1); // Lua array numbering starts per convention at 1.
175 /*****************************/
176 /*** VarVisitorSetFromLuaT ***/
177 /*****************************/
179 VarVisitorSetFromLuaT::VarVisitorSetFromLuaT(lua_State* LuaState)
180 : m_LuaState(LuaState)
185 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<float>& Var)
187 Var.Set(float(luaL_checknumber(m_LuaState, -1)));
191 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<double>& Var)
193 Var.Set(luaL_checknumber(m_LuaState, -1));
197 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<int>& Var)
199 Var.Set(luaL_checkint(m_LuaState, -1));
203 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<unsigned int>& Var)
205 Var.Set(luaL_checkint(m_LuaState, -1));
209 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<uint16_t>& Var)
211 Var.Set(luaL_checkint(m_LuaState, -1));
215 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<uint8_t>& Var)
217 Var.Set(luaL_checkint(m_LuaState, -1));
221 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<bool>& Var)
223 // Also treat the number 0 as false, not just "false" and "nil".
224 if (lua_isnumber(m_LuaState, -1))
225 Var.Set(lua_tonumber(m_LuaState, -1) != 0.0);
226 else
227 Var.Set(lua_toboolean(m_LuaState, -1) != 0);
231 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<std::string>& Var)
233 Var.Set(luaL_checkstring(m_LuaState, -1));
237 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<Vector2fT>& Var)
239 Vector2fT v;
241 if (lua_istable(m_LuaState, -1))
243 lua_rawgeti(m_LuaState, -1, 1); v.x = float(lua_tonumber(m_LuaState, -1)); lua_pop(m_LuaState, 1);
244 lua_rawgeti(m_LuaState, -1, 2); v.y = float(lua_tonumber(m_LuaState, -1)); lua_pop(m_LuaState, 1);
246 else
248 v.x = float(luaL_checknumber(m_LuaState, -2));
249 v.y = float(luaL_checknumber(m_LuaState, -1));
252 Var.Set(v);
256 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<Vector3fT>& Var)
258 Vector3fT v;
260 if (lua_istable(m_LuaState, -1))
262 lua_rawgeti(m_LuaState, -1, 1); v.x = float(lua_tonumber(m_LuaState, -1)); lua_pop(m_LuaState, 1);
263 lua_rawgeti(m_LuaState, -1, 2); v.y = float(lua_tonumber(m_LuaState, -1)); lua_pop(m_LuaState, 1);
264 lua_rawgeti(m_LuaState, -1, 3); v.z = float(lua_tonumber(m_LuaState, -1)); lua_pop(m_LuaState, 1);
266 else
268 v.x = float(luaL_checknumber(m_LuaState, -3));
269 v.y = float(luaL_checknumber(m_LuaState, -2));
270 v.z = float(luaL_checknumber(m_LuaState, -1));
273 Var.Set(v);
277 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<Vector3dT>& Var)
279 Vector3dT v;
281 if (lua_istable(m_LuaState, -1))
283 lua_rawgeti(m_LuaState, -1, 1); v.x = lua_tonumber(m_LuaState, -1); lua_pop(m_LuaState, 1);
284 lua_rawgeti(m_LuaState, -1, 2); v.y = lua_tonumber(m_LuaState, -1); lua_pop(m_LuaState, 1);
285 lua_rawgeti(m_LuaState, -1, 3); v.z = lua_tonumber(m_LuaState, -1); lua_pop(m_LuaState, 1);
287 else
289 v.x = luaL_checknumber(m_LuaState, -3);
290 v.y = luaL_checknumber(m_LuaState, -2);
291 v.z = luaL_checknumber(m_LuaState, -1);
294 Var.Set(v);
298 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarT<BoundingBox3dT>& Var)
300 BoundingBox3dT BB;
302 BB.Min.x = luaL_checknumber(m_LuaState, -6);
303 BB.Min.y = luaL_checknumber(m_LuaState, -5);
304 BB.Min.z = luaL_checknumber(m_LuaState, -4);
306 BB.Max.x = luaL_checknumber(m_LuaState, -3);
307 BB.Max.y = luaL_checknumber(m_LuaState, -2);
308 BB.Max.z = luaL_checknumber(m_LuaState, -1);
310 Var.Set(BB);
314 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarArrayT<uint32_t>& Var)
316 Var.Overwrite();
318 if (lua_istable(m_LuaState, -1))
320 const int Num = int(lua_rawlen(m_LuaState, -1));
322 for (int i = 1; i <= Num; i++)
324 lua_rawgeti(m_LuaState, -1, i);
325 Var.PushBack(lua_tointeger(m_LuaState, -1));
326 lua_pop(m_LuaState, 1);
329 else
331 // Stack index 1 has the "this" object,
332 // stack index 2 has the variable name.
333 for (int i = 3; i <= lua_gettop(m_LuaState); i++)
334 Var.PushBack(lua_tointeger(m_LuaState, i));
339 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarArrayT<uint16_t>& Var)
341 Var.Overwrite();
343 if (lua_istable(m_LuaState, -1))
345 const int Num = int(lua_rawlen(m_LuaState, -1));
347 for (int i = 1; i <= Num; i++)
349 lua_rawgeti(m_LuaState, -1, i);
350 Var.PushBack(lua_tointeger(m_LuaState, -1));
351 lua_pop(m_LuaState, 1);
354 else
356 // Stack index 1 has the "this" object,
357 // stack index 2 has the variable name.
358 for (int i = 3; i <= lua_gettop(m_LuaState); i++)
359 Var.PushBack(lua_tointeger(m_LuaState, i));
364 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarArrayT<uint8_t>& Var)
366 Var.Overwrite();
368 if (lua_istable(m_LuaState, -1))
370 const int Num = int(lua_rawlen(m_LuaState, -1));
372 for (int i = 1; i <= Num; i++)
374 lua_rawgeti(m_LuaState, -1, i);
375 Var.PushBack(lua_tointeger(m_LuaState, -1));
376 lua_pop(m_LuaState, 1);
379 else
381 // Stack index 1 has the "this" object,
382 // stack index 2 has the variable name.
383 for (int i = 3; i <= lua_gettop(m_LuaState); i++)
384 Var.PushBack(lua_tointeger(m_LuaState, i));
389 void VarVisitorSetFromLuaT::visit(cf::TypeSys::VarArrayT<std::string>& Var)
391 Var.Overwrite();
393 if (lua_istable(m_LuaState, -1))
395 const int Num = int(lua_rawlen(m_LuaState, -1));
397 for (int i = 1; i <= Num; i++)
399 lua_rawgeti(m_LuaState, -1, i);
400 const char* s = lua_tostring(m_LuaState, -1);
401 Var.PushBack(s ? s : "NULL");
402 lua_pop(m_LuaState, 1);
405 else
407 // Stack index 1 has the "this" object,
408 // stack index 2 has the variable name.
409 for (int i = 3; i <= lua_gettop(m_LuaState); i++)
411 const char* s = lua_tostring(m_LuaState, i);
412 Var.PushBack(s ? s : "NULL");
418 /***************************/
419 /*** VarVisitorSetFloatT ***/
420 /***************************/
422 VarVisitorSetFloatT::VarVisitorSetFloatT(unsigned int Suffix, float Value)
423 : m_Suffix(Suffix),
424 m_Value(Value)
429 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<float>& Var)
431 Var.Set(m_Value);
435 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<Vector2fT>& Var)
437 Vector2fT v = Var.Get();
439 v[m_Suffix % 2] = m_Value;
441 Var.Set(v);
445 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<Vector3fT>& Var)
447 Vector3fT v = Var.Get();
449 v[m_Suffix % 3] = m_Value;
451 Var.Set(v);
455 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<double>& Var) { }
456 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<int>& Var) { }
457 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<unsigned int>& Var) { }
458 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<uint16_t>& Var) { }
459 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<uint8_t>& Var) { }
460 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<bool>& Var) { }
461 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<std::string>& Var) { }
462 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<Vector3dT>& Var) { }
463 void VarVisitorSetFloatT::visit(cf::TypeSys::VarT<BoundingBox3dT>& Var) { }
464 void VarVisitorSetFloatT::visit(cf::TypeSys::VarArrayT<uint32_t>& Var) { }
465 void VarVisitorSetFloatT::visit(cf::TypeSys::VarArrayT<uint16_t>& Var) { }
466 void VarVisitorSetFloatT::visit(cf::TypeSys::VarArrayT<uint8_t>& Var) { }
467 void VarVisitorSetFloatT::visit(cf::TypeSys::VarArrayT<std::string>& Var) { }
470 /****************************/
471 /*** VarVisitorToLuaCodeT ***/
472 /****************************/
474 namespace
476 /// This function serializes a given float f1 to a string s, such that:
477 /// - s is minimal (uses the least number of decimal digits required),
478 /// - unserializing s back to a float f2 yields f1 == f2.
479 /// See my post "float to string to float, with first float == second float"
480 /// to comp.lang.c++ on 2009-10-06 for additional details.
481 template<class T> std::string serialize(const T f1)
483 // Make sure that if f1 is -0, "0" instead of "-0" is returned.
484 if (f1 == 0.0f) return "0";
486 // From MSDN documentation: "digits10 returns the number of decimal digits that the type can represent without loss of precision."
487 // For floats, that's usually 6, for doubles, that's usually 15. However, we want to use the number of *significant* decimal digits here,
488 // that is, max_digits10. See http://www.open-std.org/JTC1/sc22/wg21/docs/papers/2006/n2005.pdf for details.
489 const unsigned int DIGITS10 = std::numeric_limits<T>::digits10;
490 const unsigned int MAX_DIGITS10 = DIGITS10 + 3;
492 std::string s;
493 unsigned int prec;
495 for (prec = DIGITS10; prec <= MAX_DIGITS10; prec++)
497 std::stringstream ss;
499 ss.precision(prec);
500 ss << f1;
502 s = ss.str();
504 #if defined(_MSC_VER) && (_MSC_VER <= 1900) // 1900 == Visual C++ 14.0 (2015)
505 // There is a bug in Microsoft's iostream implementation up to Visual C++ 2015,
506 // see http://trac.cafu.de/ticket/150 for details.
507 const T f2 = T(atof(s.c_str()));
508 #else
509 T f2;
510 ss >> f2;
511 #endif
513 if (f2 == f1) break;
516 assert(prec <= MAX_DIGITS10);
517 return s;
522 VarVisitorToLuaCodeT::VarVisitorToLuaCodeT(std::ostream& Out)
523 : m_Out(Out)
528 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<float>& Var)
530 m_Out << serialize(Var.Get());
534 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<double>& Var)
536 m_Out << serialize(Var.Get());
540 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<int>& Var)
542 m_Out << Var.Get();
546 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<unsigned int>& Var)
548 m_Out << Var.Get();
552 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<uint16_t>& Var)
554 m_Out << Var.Get();
558 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<uint8_t>& Var)
560 m_Out << uint16_t(Var.Get()); // Write numbers, not characters.
564 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<bool>& Var)
566 m_Out << (Var.Get() ? "true" : "false");
570 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<std::string>& Var)
572 WriteString(Var.Get());
576 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<Vector2fT>& Var)
578 m_Out << serialize(Var.Get().x) << ", " << serialize(Var.Get().y);
582 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<Vector3fT>& Var)
584 m_Out << serialize(Var.Get().x) << ", " << serialize(Var.Get().y) << ", " << serialize(Var.Get().z);
588 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<Vector3dT>& Var)
590 m_Out << serialize(Var.Get().x) << ", " << serialize(Var.Get().y) << ", " << serialize(Var.Get().z);
594 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarT<BoundingBox3dT>& Var)
596 m_Out << serialize(Var.Get().Min.x) << ", " << serialize(Var.Get().Min.y) << ", " << serialize(Var.Get().Min.z) << ", ";
597 m_Out << serialize(Var.Get().Max.x) << ", " << serialize(Var.Get().Max.y) << ", " << serialize(Var.Get().Max.z);
601 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarArrayT<uint32_t>& Var)
603 m_Out << "{ ";
605 for (unsigned int i = 0; i < Var.Size(); i++)
607 m_Out << Var[i];
608 if (i+1 < Var.Size()) m_Out << ", ";
611 m_Out << " }";
615 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarArrayT<uint16_t>& Var)
617 m_Out << "{ ";
619 for (unsigned int i = 0; i < Var.Size(); i++)
621 m_Out << Var[i];
622 if (i+1 < Var.Size()) m_Out << ", ";
625 m_Out << " }";
629 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarArrayT<uint8_t>& Var)
631 m_Out << "{ ";
633 for (unsigned int i = 0; i < Var.Size(); i++)
635 m_Out << uint16_t(Var[i]); // Write numbers, not characters.
636 if (i+1 < Var.Size()) m_Out << ", ";
639 m_Out << " }";
643 void VarVisitorToLuaCodeT::visit(const cf::TypeSys::VarArrayT<std::string>& Var)
645 m_Out << "{ ";
647 for (unsigned int i = 0; i < Var.Size(); i++)
649 WriteString(Var[i]);
650 if (i+1 < Var.Size()) m_Out << ", ";
653 m_Out << " }";
657 void VarVisitorToLuaCodeT::WriteString(const std::string& s) const
659 for (size_t i = 0; i < s.size(); i++)
660 if (iscntrl(s[i]) || s[i] == '"' || s[i] == '\\')
662 std::string Equals = "";
664 while (s.find("[" + Equals + "[") != std::string::npos ||
665 s.find("]" + Equals + "]") != std::string::npos)
666 Equals += "=";
668 // Why do we write an extra newline following the opening long bracket?
669 // The answer is given in the Lua reference manual:
671 // > For convenience, when the opening long bracket is immediately
672 // > followed by a newline, the newline is not included in the string.
674 // That is, if s begins with a character that is *not* a newline, prepending the extra newline
675 // doesn't make a difference. But if the first character in s happened to be a newline, it would
676 // get lost if the extra newline was not written.
677 m_Out << "[" << Equals << "[\n";
678 m_Out << s;
679 m_Out << "]" << Equals << "]";
680 return;
683 m_Out << "\"" << s << "\"";