载入中...
搜索中...
未找到
EcsScriptPack.cpp
浏览该文件的文档.
2#include "gpgpu/GpuBuffer.h"
3
4#include "common/Exception.h"
5
6#include <simplesquirrel/simplesquirrel.hpp>
7#include <squirrel.h>
8
9#include <algorithm>
10#include <string>
11#include <vector>
12
13namespace eve::gpgpu {
14namespace {
15
16bool readStringField(HSQUIRRELVM vm, SQInteger idx, std::string &out) {
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;
20 out = s;
21 return true;
22}
23
24bool readFloatAt(HSQUIRRELVM vm, SQInteger idx, float &out) {
25 const SQObjectType t = sq_gettype(vm, idx);
26 if (t == OT_FLOAT) {
27 SQFloat v = 0;
28 sq_getfloat(vm, idx, &v);
29 out = float(v);
30 return true;
31 }
32 if (t == OT_INTEGER) {
33 SQInteger v = 0;
34 sq_getinteger(vm, idx, &v);
35 out = float(v);
36 return true;
37 }
38 return false;
39}
40
41bool getInstanceSlot(HSQUIRRELVM vm, HSQOBJECT instance, const std::string &name,
42 HSQOBJECT &out) {
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))) {
47 sq_settop(vm, top);
48 return false;
49 }
50 sq_getstackobj(vm, -1, &out);
51 sq_addref(vm, &out);
52 sq_settop(vm, top);
53 return true;
54}
55
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))) {
61 sq_settop(vm, top);
62 return false;
63 }
64 const bool ok = readFloatAt(vm, -1, out);
65 sq_settop(vm, top);
66 return ok;
67}
68
69bool setNumberField(HSQUIRRELVM vm, HSQOBJECT instance, const std::string &name, float value) {
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));
74 // Prefer set (existing slot). Fall back to newslot for unusual components.
75 if (SQ_FAILED(sq_set(vm, -3))) {
76 sq_settop(vm, top);
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))) {
81 sq_settop(vm, top);
82 return false;
83 }
84 }
85 sq_settop(vm, top);
86 return true;
87}
88
89std::vector<std::string> collectFieldNames(ssq::Object fieldsObj) {
90 std::vector<std::string> names;
91 HSQUIRRELVM vm = fieldsObj.getHandle();
92 if (!vm) return names;
93 HSQOBJECT arr = fieldsObj.getRaw();
94 if (arr._type != OT_ARRAY) return names;
95
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;
103 std::string name;
104 if (readStringField(vm, -1, name)) names.push_back(name);
105 sq_pop(vm, 1);
106 }
107 sq_settop(vm, top);
108 return names;
109}
110
111int entityArrayLen(HSQUIRRELVM vm, HSQOBJECT arr) {
112 const SQInteger top = sq_gettop(vm);
113 sq_pushobject(vm, arr);
114 const SQInteger len = sq_getsize(vm, -1);
115 sq_settop(vm, top);
116 return int(std::max<SQInteger>(0, len));
117}
118
119} // namespace
120
121int packScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot,
122 ssq::Object fieldsObj, GpuBuffer *buf) {
123 if (!buf) throw Exception("packScriptEntityFloats: buffer is null");
124 if (slot.empty()) throw Exception("packScriptEntityFloats: empty slot");
125
126 HSQUIRRELVM vm = entitiesObj.getHandle();
127 if (!vm) return 0;
128 HSQOBJECT ents = entitiesObj.getRaw();
129 if (ents._type != OT_ARRAY) return 0;
130
131 const std::vector<std::string> fields = collectFieldNames(fieldsObj);
132 if (fields.empty()) return 0;
133
134 const int n = entityArrayLen(vm, ents);
135 if (n <= 0) return 0;
136
137 const int floatsPer = int(fields.size());
138 std::vector<float> tmp(size_t(n) * size_t(floatsPer), 0.f);
139
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))) {
145 sq_settop(vm, top);
146 throw Exception("packScriptEntityFloats: bad entity index %d", i);
147 }
148 if (sq_gettype(vm, -1) != OT_INSTANCE) {
149 sq_settop(vm, top);
150 throw Exception("packScriptEntityFloats: entity[%d] is not an instance", i);
151 }
152 HSQOBJECT entity{};
153 sq_getstackobj(vm, -1, &entity);
154
155 HSQOBJECT comp{};
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);
159 sq_settop(vm, top);
160 throw Exception("packScriptEntityFloats: missing component slot '%s'", slot.c_str());
161 }
162
163 for (int f = 0; f < floatsPer; ++f) {
164 float v = 0.f;
165 if (!getNumberField(vm, comp, fields[size_t(f)], v)) {
166 sq_release(vm, &comp);
167 sq_settop(vm, top);
168 throw Exception("packScriptEntityFloats: missing field '%s.%s'", slot.c_str(),
169 fields[size_t(f)].c_str());
170 }
171 tmp[size_t(i) * size_t(floatsPer) + size_t(f)] = v;
172 }
173 sq_release(vm, &comp);
174 sq_pop(vm, 1); // entity
175 }
176 sq_settop(vm, top);
177
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(),
181 needBytes);
182 buf->writeFloat32s(tmp.data(), n * floatsPer, 0);
183 return n;
184}
185
186int unpackScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot,
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;
191
192 HSQUIRRELVM vm = entitiesObj.getHandle();
193 if (!vm) return 0;
194 HSQOBJECT ents = entitiesObj.getRaw();
195 if (ents._type != OT_ARRAY) return 0;
196
197 const std::vector<std::string> fields = collectFieldNames(fieldsObj);
198 if (fields.empty()) return 0;
199
200 const int nArr = entityArrayLen(vm, ents);
201 const int n = std::min(entityCount, nArr);
202 if (n <= 0) return 0;
203
204 const int floatsPer = int(fields.size());
205 std::vector<float> tmp(size_t(n) * size_t(floatsPer), 0.f);
206 buf->readFloat32s(tmp.data(), n * floatsPer, 0);
207
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))) {
213 sq_settop(vm, top);
214 throw Exception("unpackScriptEntityFloats: bad entity index %d", i);
215 }
216 HSQOBJECT entity{};
217 sq_getstackobj(vm, -1, &entity);
218
219 HSQOBJECT comp{};
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);
223 sq_settop(vm, top);
224 throw Exception("unpackScriptEntityFloats: missing component slot '%s'", slot.c_str());
225 }
226
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);
231 sq_settop(vm, top);
232 throw Exception("unpackScriptEntityFloats: cannot set '%s.%s'", slot.c_str(),
233 fields[size_t(f)].c_str());
234 }
235 }
236 sq_release(vm, &comp);
237 sq_pop(vm, 1);
238 }
239 sq_settop(vm, top);
240 return n;
241}
242
243} // namespace eve::gpgpu
struct SQVM * HSQUIRRELVM
std::string value
HSQUIRRELVM vm
Definition ECS.cpp:20
glm::vec3 n
Definition Grass.cpp:64
int idx
float f
const char * name
Definition RockMesh.cpp:21
int v
uint32_t s
Definition Weather.cpp:28
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
Definition GpuBuffer.h:16
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.