Skip to content

Commit e6ad570

Browse files
committed
Simple Wren reflection + Wren call handle caching + General cleanup
1 parent b9f5ea6 commit e6ad570

13 files changed

Lines changed: 161 additions & 79 deletions

File tree

OverEngine/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ target_include_directories(OverEngine PUBLIC
7878
"vendor/fmt/include"
7979
"vendor/yaml-cpp/include"
8080
"vendor/wren/src/include"
81+
"vendor/wren/src/vm"
8182
)
8283

8384
string(LENGTH "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LEN)

OverEngine/src/OverEngine/Renderer/Texture.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ namespace OverEngine
1818

1919
virtual void Bind(uint32_t slot = 0) = 0;
2020

21-
// Filter
2221
virtual TextureFilter GetFilter() const = 0;
2322
virtual void SetFilter(TextureFilter filter) = 0;
2423

25-
// Wrap
2624
virtual TextureWrap GetUWrap() const = 0;
2725
virtual void SetUWrap(TextureWrap wrap) = 0;
2826

OverEngine/src/OverEngine/Scene/Scene.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ namespace OverEngine
104104
}
105105

106106
// In both cases; we need to perform this
107-
// 1. we've pushed the changes to physics system and we need to remove the flag
108-
// 2. we've pushed the changes to OverEngine's transform system and it added the
109-
// flag which we don't want
107+
// 1. We've pushed changes to Box2d, so we need to remove the flag
108+
// 2. We've pushed changes to OverEngine which unwantedly set the
109+
// flag, which we don't want
110110
tc.m_ChangedFlags ^= TransformComponent::ChangedFlags_ChangedForPhysics;
111111
}
112112
});

OverEngine/src/OverEngine/Scripting/Wren.cpp

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#include "pcheader.h"
22
#include "Wren.h"
33

4+
#include <imgui.h>
5+
6+
extern "C" {
7+
#include <wren_vm.h>
8+
}
9+
410
namespace WrenSources
511
{
612
#include "Wren/components.wren.inc"
@@ -31,6 +37,7 @@ namespace OverEngine
3137
Wren::Wren()
3238
: m_VM()
3339
{
40+
// FIXME: Only one VM instance can exist, because there callbacks are static variables.
3441
wrenpp::VM::writeFn = [](const char* message) { if (strcmp(message, "\n")) OE_INFO("[wren] {}", message); };
3542
wrenpp::VM::errorFn = [](WrenErrorType type, const char* moduleName, int line, const char* message) -> void {
3643
const char* typeStr = ErrorTypeToString(type);
@@ -40,6 +47,15 @@ namespace OverEngine
4047
OE_ERROR("{}> {}", typeStr, message);
4148
};
4249

50+
// This wont register superclasses fields.
51+
wrenpp::VM::reportClassFn = [this](ClassInfo* classInfo) {
52+
this->m_FieldNames[classInfo->name->value] = Vector<String>();
53+
auto& fieldNames = this->m_FieldNames[classInfo->name->value];
54+
55+
SymbolTable* syms = &classInfo->fields;
56+
for (ObjString** current = syms->data; current < syms->data + syms->count; current++)
57+
fieldNames.push_back((*current)->value);
58+
};
4359

4460
wrenpp::VM::loadModuleFn = [](const char* mod) -> char* {
4561
#define WREN_MOD(m) if (strcmp(mod, #m) == 0) return const_cast<char*>(WrenSources::m##ModuleSource);
@@ -73,6 +89,8 @@ namespace OverEngine
7389
};
7490

7591
InitializeBindings();
92+
93+
m_Scheduler = GetVariable("scheduler", "Scheduler");
7694

7795
m_OnCreateMethod = wrenMakeCallHandle(m_VM, "onCreate()");
7896
m_OnDestroyMethod = wrenMakeCallHandle(m_VM, "onDestroy()");
@@ -92,17 +110,45 @@ namespace OverEngine
92110

93111
wrenReleaseHandle(m_VM, m_OnCollisionEnterMethod);
94112
wrenReleaseHandle(m_VM, m_OnCollisionExitMethod);
113+
114+
for (auto [_, handle] : m_CallHandles)
115+
wrenReleaseHandle(m_VM, handle);
95116
}
96117

97-
WrenScriptClass::WrenScriptClass(const Ref<Wren>& vm, const char* moduleName, const char* className)
98-
: m_VM(vm)
118+
WrenHandle* Wren::CallHandle(const char* signature) const
99119
{
100-
wrenEnsureSlots(m_VM->GetRaw(), 1);
101-
wrenGetVariable(m_VM->GetRaw(), moduleName, className, 0);
120+
if (auto handle = m_CallHandles.find(signature); handle != m_CallHandles.end())
121+
return handle->second;
102122

103-
OE_CORE_ASSERT(wrenGetSlotType(m_VM->GetRaw(), 0) != WREN_TYPE_NULL, "Wren class is null! Maybe it failed to compile.");
123+
WrenHandle* callHandle = wrenMakeCallHandle(m_VM, signature);
124+
m_CallHandles[signature] = callHandle;
125+
return callHandle;
126+
}
127+
128+
WrenHandle* Wren::GetVariable(const char* moduleName, const char* variableName)
129+
{
130+
wrenEnsureSlots(m_VM, 1);
131+
wrenGetVariable(m_VM, moduleName, variableName, 0);
132+
return wrenGetSlotType(m_VM, 0) == WREN_TYPE_NULL ? nullptr : wrenGetSlotHandle(m_VM, 0);
133+
}
134+
135+
String Wren::ToString(WrenHandle* handle) const
136+
{
137+
Call(handle, CallHandle("toString"));
138+
return String(wrenGetSlotString(m_VM, 0));
139+
}
140+
141+
String Wren::ToString(Value value) const
142+
{
143+
WrenHandle handle { value, nullptr, nullptr };
144+
return ToString(&handle);
145+
}
104146

105-
m_ClassHandle = wrenGetSlotHandle(m_VM->GetRaw(), 0);
147+
WrenScriptClass::WrenScriptClass(const Ref<Wren>& vm, const char* moduleName, const char* className)
148+
: m_VM(vm)
149+
{
150+
m_ClassHandle = m_VM->GetVariable(moduleName, className);
151+
OE_CORE_ASSERT(m_ClassHandle, "Wren class is null! Maybe it failed to compile.");
106152
m_ConstructorHandle = wrenMakeCallHandle(m_VM->GetRaw(), "new(_)");
107153
}
108154

@@ -114,7 +160,7 @@ namespace OverEngine
114160

115161
Ref<WrenScriptInstance> WrenScriptClass::Construct(const Entity& entity) const
116162
{
117-
if (m_VM->CallMethod(m_ClassHandle, m_ConstructorHandle, entity) != WREN_RESULT_SUCCESS)
163+
if (m_VM->Call(m_ClassHandle, m_ConstructorHandle, entity) != WREN_RESULT_SUCCESS)
118164
{
119165
OE_CORE_ASSERT(false, "Script instantiation failure!");
120166
return nullptr;
@@ -134,34 +180,38 @@ namespace OverEngine
134180
wrenReleaseHandle(m_VM->GetRaw(), m_InstanceHandle);
135181
}
136182

137-
// TODO: Return result
138-
void WrenScriptInstance::OnCreate() const
139-
{
140-
m_VM->CallMethod(m_InstanceHandle, m_VM->GetOnCreateMethod());
141-
}
183+
#define IMPL_METHOD_CALL_NO_PARAM(methode) \
184+
WrenInterpretResult WrenScriptInstance::methode() const \
185+
{ \
186+
return Call(m_VM->Get##methode##Method()); \
187+
}
142188

143-
void WrenScriptInstance::OnDestroy() const
144-
{
145-
m_VM->CallMethod(m_InstanceHandle, m_VM->GetOnDestroyMethod());
146-
}
189+
#define IMPL_METHOD_CALL_WITH_PARAM(methode, params, wrenParams) \
190+
WrenInterpretResult WrenScriptInstance::methode(params) const \
191+
{ \
192+
return Call(m_VM->Get##methode##Method(), wrenParams); \
193+
}
147194

148-
void WrenScriptInstance::OnUpdate(float delta) const
149-
{
150-
m_VM->CallMethod(m_InstanceHandle, m_VM->GetOnUpdateMethod(), delta);
151-
}
195+
IMPL_METHOD_CALL_NO_PARAM(OnCreate)
196+
IMPL_METHOD_CALL_NO_PARAM(OnDestroy)
197+
IMPL_METHOD_CALL_WITH_PARAM(OnUpdate, float delta, delta)
198+
IMPL_METHOD_CALL_WITH_PARAM(OnLateUpdate, float delta, delta)
199+
IMPL_METHOD_CALL_NO_PARAM(OnCollisionEnter)
200+
IMPL_METHOD_CALL_NO_PARAM(OnCollisionExit)
152201

153-
void WrenScriptInstance::OnLateUpdate(float delta) const
202+
void WrenScriptInstance::Inspect() const
154203
{
155-
m_VM->CallMethod(m_InstanceHandle, m_VM->GetOnLateUpdateMethod(), delta);
156-
}
204+
ObjClass* klass = wrenGetClass(m_VM->GetRaw(), m_InstanceHandle->value);
205+
ObjInstance* instance = AS_INSTANCE(m_InstanceHandle->value);
157206

158-
void WrenScriptInstance::OnCollisionEnter() const
159-
{
160-
m_VM->CallMethod(m_InstanceHandle, m_VM->GetOnCollisionEnterMethod());
161-
}
207+
auto& fields = m_VM->GetFields(klass->name->value);
162208

163-
void WrenScriptInstance::OnCollisionExit() const
164-
{
165-
m_VM->CallMethod(m_InstanceHandle, m_VM->GetOnCollisionExitMethod());
209+
for (int i = 0; i < klass->numFields; i++)
210+
{
211+
// FIXME: Climb the inheritance chain to access superclass fields.
212+
ImGui::TextUnformatted(i == 0 ? "_entity" : fields[i - 1].c_str());
213+
ImGui::SameLine();
214+
ImGui::TextUnformatted(m_VM->ToString(instance->fields[i]).c_str());
215+
}
166216
}
167217
}

OverEngine/src/OverEngine/Scripting/Wren.h

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
#include <wrenpp/Wren++.h>
77

8+
extern "C" {
9+
#include <wren_value.h>
10+
}
11+
812
namespace OverEngine
913
{
1014
class WrenScriptClass;
@@ -28,42 +32,49 @@ namespace OverEngine
2832
inline ::WrenVM* GetRaw() const { return &*m_VM; }
2933
inline wrenpp::VM& GetWrenpp() { return m_VM; }
3034

35+
WrenHandle* CallHandle(const char* signature) const;
36+
WrenHandle* GetVariable(const char* moduleName, const char* variableName);
37+
38+
String ToString(WrenHandle* handle) const;
39+
String ToString(Value value) const;
40+
3141
template<typename... Args>
32-
WrenInterpretResult CallMethod(WrenHandle* reciver, WrenHandle* method, Args... args) const
42+
WrenInterpretResult Call(WrenHandle* reciver, WrenHandle* method, Args... args) const
3343
{
34-
::WrenVM *vm = GetRaw();
35-
3644
// Copied from Wrenpp
37-
constexpr const std::size_t Arity = sizeof...(Args);
38-
wrenEnsureSlots(vm, Arity + 1u);
39-
wrenSetSlotHandle(vm, 0, reciver);
45+
constexpr const std::size_t arity = sizeof...(Args);
46+
wrenEnsureSlots(m_VM, arity + 1u);
47+
wrenSetSlotHandle(m_VM, 0, reciver);
4048

41-
std::tuple<Args...> tuple = std::make_tuple(args...);
42-
wrenpp::detail::passArgumentsToWren(vm, tuple, std::make_index_sequence<Arity>{});
43-
44-
return wrenCall(vm, method);
49+
wrenpp::detail::passArgumentsToWren(m_VM, std::make_tuple(args...), std::make_index_sequence<arity>{});
50+
return wrenCall(m_VM, method);
4551
}
4652

47-
inline wrenpp::Result LoadModule(const char* moduleName)
48-
{
49-
return m_VM.executeModule(moduleName);
50-
}
53+
inline wrenpp::Result LoadModule(const char* moduleName) { return m_VM.executeModule(moduleName); }
54+
wrenpp::ModuleContext beginModule(const String& name) { return m_VM.beginModule(name); }
5155

5256
inline Ref<WrenScriptClass> GetScriptClass(const char* moduleName, const char* className)
5357
{
5458
return CreateRef<WrenScriptClass>(shared_from_this(), moduleName, className);
5559
}
5660

57-
wrenpp::ModuleContext beginModule(const String& name) { return m_VM.beginModule(name); }
61+
inline WrenHandle* GetScheduler() { return m_Scheduler; }
62+
63+
inline const Vector<String>& GetFields(const char* className) const { return m_FieldNames.at(className); }
5864

5965
private:
6066
// Implemented in WrenBindings.cpp
6167
void InitializeBindings();
6268

6369
private:
6470
wrenpp::VM m_VM;
71+
UnorderedMap<String, Vector<String>> m_FieldNames;
72+
73+
WrenHandle* m_Scheduler;
6574

6675
// Call Handles
76+
mutable UnorderedMap<String, WrenHandle*> m_CallHandles;
77+
6778
WrenHandle* m_OnCreateMethod;
6879
WrenHandle* m_OnDestroyMethod;
6980
WrenHandle* m_OnUpdateMethod;
@@ -93,32 +104,38 @@ namespace OverEngine
93104
WrenHandle* m_ConstructorHandle;
94105
};
95106

96-
class WrenScriptInstance {
107+
class WrenScriptInstance
108+
{
97109
public:
98110
WrenScriptInstance(const Ref<Wren>& vm, WrenHandle* instanceHandle);
99111
~WrenScriptInstance();
100112

101113
WrenScriptInstance(const WrenScriptInstance&) = delete;
102114
WrenScriptInstance& operator=(const WrenScriptInstance&) = delete;
103115

104-
void OnCreate() const;
105-
void OnDestroy() const;
106-
void OnUpdate(float delta) const;
107-
void OnLateUpdate(float delta) const;
116+
WrenInterpretResult OnCreate() const;
117+
WrenInterpretResult OnDestroy() const;
118+
WrenInterpretResult OnUpdate(float delta) const;
119+
WrenInterpretResult OnLateUpdate(float delta) const;
108120

109-
void OnCollisionEnter() const;
110-
void OnCollisionExit() const;
121+
WrenInterpretResult OnCollisionEnter() const;
122+
WrenInterpretResult OnCollisionExit() const;
111123

112124
template<typename... Args>
113-
WrenInterpretResult CallMethod(const String& sig, Args... args)
125+
WrenInterpretResult Call(const char* sig, Args... args) const
114126
{
115-
WrenHandle* methodSig = wrenMakeCallHandle(m_VM->GetRaw(), sig.c_str());
116-
WrenInterpretResult result = m_VM->CallMethod(m_InstanceHandle, methodSig, args...);
117-
wrenReleaseHandle(m_VM->GetRaw(), methodSig);
127+
return Call(m_VM->CallHandle(sig), args...);
128+
}
118129

119-
return result;
130+
template<typename... Args>
131+
WrenInterpretResult Call(WrenHandle* method, Args... args) const
132+
{
133+
return m_VM->Call(m_InstanceHandle, method, args...);
120134
}
121135

136+
// Dump field data to log.
137+
void Inspect() const;
138+
122139
private:
123140
Ref<Wren> m_VM;
124141
WrenHandle* m_InstanceHandle;

OverEngine/src/OverEngine/Scripting/WrenBindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ namespace OverEngine
175175
.endClass()
176176
.endModule();
177177

178+
// Load some modules which are referenced from C++
178179
LoadModule("lib");
179180
}
180181
}

OverEngine/src/Platform/OpenGL/OpenGLShader.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ namespace OverEngine
7171
OE_CORE_ASSERT(ShaderTypeFromString(type), "Invalid shader type specified!");
7272

7373
size_t nextLinePos = source.find_first_not_of("\r\n", eol); // Start of shader code after shader type declaration line
74-
OE_CORE_ASSERT(nextLinePos != std::string::npos, "Syntax error");
74+
OE_CORE_ASSERT(nextLinePos != String::npos, "Syntax error");
7575
pos = source.find(typeToken, nextLinePos); // Start of next shader type declaration line
76-
shaderSources[ShaderTypeFromString(type)] = (pos == std::string::npos) ? source.substr(nextLinePos) : source.substr(nextLinePos, pos - nextLinePos);
76+
shaderSources[ShaderTypeFromString(type)] = (pos == String::npos) ? source.substr(nextLinePos) : source.substr(nextLinePos, pos - nextLinePos);
7777
}
7878

7979
return shaderSources;

OverEngine/src/Wren/lib.wren

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,2 @@
1-
// Load engine interface
2-
// Is it really needed?
3-
import "entity"
4-
import "math"
5-
import "script"
6-
import "keycodes"
7-
import "input"
1+
// Load modules accessed from C++
2+
import "scheduler"

OverEngine/vendor/wrenpp

0 commit comments

Comments
 (0)