6#include <simplesquirrel/simplesquirrel.hpp>
17 if (sq_gettype(
vm,
idx) != OT_STRING)
return false;
18 const SQChar *
s =
nullptr;
19 if (SQ_FAILED(sq_getstring(
vm,
idx, &
s)) || !
s)
return false;
25 const SQObjectType t = sq_gettype(
vm,
idx);
32 if (t == OT_INTEGER) {
34 sq_getinteger(
vm,
idx, &
v);
43 const SQInteger top = sq_gettop(
vm);
44 sq_pushobject(
vm, instance);
45 sq_pushstring(
vm,
name.c_str(), -1);
46 if (SQ_FAILED(sq_get(
vm, -2))) {
50 sq_getstackobj(
vm, -1, &out);
56bool getNumberField(
HSQUIRRELVM vm, HSQOBJECT instance,
const std::string &
name,
float &out) {
57 const SQInteger top = sq_gettop(
vm);
58 sq_pushobject(
vm, instance);
59 sq_pushstring(
vm,
name.c_str(), -1);
60 if (SQ_FAILED(sq_get(
vm, -2))) {
64 const bool ok = readFloatAt(
vm, -1, out);
70 const SQInteger top = sq_gettop(
vm);
71 sq_pushobject(
vm, instance);
72 sq_pushstring(
vm,
name.c_str(), -1);
73 sq_pushfloat(
vm, SQFloat(
value));
75 if (SQ_FAILED(sq_set(
vm, -3))) {
77 sq_pushobject(
vm, instance);
78 sq_pushstring(
vm,
name.c_str(), -1);
79 sq_pushfloat(
vm, SQFloat(
value));
80 if (SQ_FAILED(sq_newslot(
vm, -3, SQFalse))) {
89std::vector<std::string> collectFieldNames(ssq::Object fieldsObj) {
90 std::vector<std::string> names;
92 if (!
vm)
return names;
93 HSQOBJECT arr = fieldsObj.getRaw();
94 if (arr._type != OT_ARRAY)
return names;
96 const SQInteger top = sq_gettop(
vm);
97 sq_pushobject(
vm, arr);
98 const SQInteger len = sq_getsize(
vm, -1);
99 names.reserve(
size_t(std::max<SQInteger>(0, len)));
100 for (SQInteger i = 0; i < len; ++i) {
101 sq_pushinteger(
vm, i);
102 if (SQ_FAILED(sq_get(
vm, -2)))
continue;
104 if (readStringField(
vm, -1,
name)) names.push_back(
name);
112 const SQInteger top = sq_gettop(
vm);
113 sq_pushobject(
vm, arr);
114 const SQInteger len = sq_getsize(
vm, -1);
116 return int(std::max<SQInteger>(0, len));
123 if (!buf)
throw Exception(
"packScriptEntityFloats: buffer is null");
124 if (slot.empty())
throw Exception(
"packScriptEntityFloats: empty slot");
128 HSQOBJECT ents = entitiesObj.getRaw();
129 if (ents._type != OT_ARRAY)
return 0;
131 const std::vector<std::string> fields = collectFieldNames(fieldsObj);
132 if (fields.empty())
return 0;
134 const int n = entityArrayLen(
vm, ents);
135 if (
n <= 0)
return 0;
137 const int floatsPer = int(fields.size());
138 std::vector<float> tmp(
size_t(
n) *
size_t(floatsPer), 0.f);
140 const SQInteger top = sq_gettop(
vm);
141 sq_pushobject(
vm, ents);
142 for (
int i = 0; i <
n; ++i) {
143 sq_pushinteger(
vm, i);
144 if (SQ_FAILED(sq_get(
vm, -2))) {
146 throw Exception(
"packScriptEntityFloats: bad entity index %d", i);
148 if (sq_gettype(
vm, -1) != OT_INSTANCE) {
150 throw Exception(
"packScriptEntityFloats: entity[%d] is not an instance", i);
153 sq_getstackobj(
vm, -1, &entity);
156 sq_resetobject(&comp);
157 if (!getInstanceSlot(
vm, entity, slot, comp) || comp._type != OT_INSTANCE) {
158 if (comp._type != OT_NULL) sq_release(
vm, &comp);
160 throw Exception(
"packScriptEntityFloats: missing component slot '%s'", slot.c_str());
163 for (
int f = 0;
f < floatsPer; ++
f) {
165 if (!getNumberField(
vm, comp, fields[
size_t(
f)],
v)) {
166 sq_release(
vm, &comp);
168 throw Exception(
"packScriptEntityFloats: missing field '%s.%s'", slot.c_str(),
169 fields[
size_t(
f)].c_str());
171 tmp[size_t(i) * size_t(floatsPer) + size_t(
f)] =
v;
173 sq_release(
vm, &comp);
178 const int needBytes =
n * floatsPer * int(
sizeof(
float));
179 if (buf->
getSize() < needBytes)
180 throw Exception(
"packScriptEntityFloats: buffer too small (%d < %d)", buf->
getSize(),
187 ssq::Object fieldsObj,
GpuBuffer *buf,
int entityCount) {
188 if (!buf)
throw Exception(
"unpackScriptEntityFloats: buffer is null");
189 if (slot.empty())
throw Exception(
"unpackScriptEntityFloats: empty slot");
190 if (entityCount <= 0)
return 0;
194 HSQOBJECT ents = entitiesObj.getRaw();
195 if (ents._type != OT_ARRAY)
return 0;
197 const std::vector<std::string> fields = collectFieldNames(fieldsObj);
198 if (fields.empty())
return 0;
200 const int nArr = entityArrayLen(
vm, ents);
201 const int n = std::min(entityCount, nArr);
202 if (
n <= 0)
return 0;
204 const int floatsPer = int(fields.size());
205 std::vector<float> tmp(
size_t(
n) *
size_t(floatsPer), 0.f);
208 const SQInteger top = sq_gettop(
vm);
209 sq_pushobject(
vm, ents);
210 for (
int i = 0; i <
n; ++i) {
211 sq_pushinteger(
vm, i);
212 if (SQ_FAILED(sq_get(
vm, -2))) {
214 throw Exception(
"unpackScriptEntityFloats: bad entity index %d", i);
217 sq_getstackobj(
vm, -1, &entity);
220 sq_resetobject(&comp);
221 if (!getInstanceSlot(
vm, entity, slot, comp) || comp._type != OT_INSTANCE) {
222 if (comp._type != OT_NULL) sq_release(
vm, &comp);
224 throw Exception(
"unpackScriptEntityFloats: missing component slot '%s'", slot.c_str());
227 for (
int f = 0;
f < floatsPer; ++
f) {
228 const float v = tmp[size_t(i) * size_t(floatsPer) + size_t(
f)];
229 if (!setNumberField(
vm, comp, fields[
size_t(
f)],
v)) {
230 sq_release(
vm, &comp);
232 throw Exception(
"unpackScriptEntityFloats: cannot set '%s.%s'", slot.c_str(),
233 fields[
size_t(
f)].c_str());
236 sq_release(
vm, &comp);
struct SQVM * HSQUIRRELVM
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
virtual void writeFloat32s(const float *data, int count, int startIndex=0)=0
Bulk float upload/download (one transfer). startIndex is in floats.
virtual int getSize() const =0
virtual void readFloat32s(float *out, int count, int startIndex=0) const =0
int packScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf)
Pack script ECS entities' component number fields into a GpuBuffer (AoS). entities: Squirrel array of...
int unpackScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf, int entityCount)
Inverse of packScriptEntityFloats; entityCount should match pack result.