载入中...
搜索中...
未找到
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 <limits>
11#include <string>
12#include <vector>
13
14namespace eve::gpgpu {
15namespace {
16
17bool readStringField(HSQUIRRELVM vm, SQInteger idx, std::string &out) {
18 if (sq_gettype(vm, idx) != OT_STRING) return false;
19 const SQChar *s = nullptr;
20 if (SQ_FAILED(sq_getstring(vm, idx, &s)) || !s) return false;
21 out = s;
22 return true;
23}
24
25bool readFloatAt(HSQUIRRELVM vm, SQInteger idx, float &out) {
26 const SQObjectType t = sq_gettype(vm, idx);
27 if (t == OT_FLOAT) {
28 SQFloat v = 0;
29 sq_getfloat(vm, idx, &v);
30 out = float(v);
31 return true;
32 }
33 if (t == OT_INTEGER) {
34 SQInteger v = 0;
35 sq_getinteger(vm, idx, &v);
36 out = float(v);
37 return true;
38 }
39 return false;
40}
41
42bool getInstanceSlot(HSQUIRRELVM vm, HSQOBJECT instance, const std::string &name,
43 HSQOBJECT &out) {
44 const SQInteger top = sq_gettop(vm);
45 sq_pushobject(vm, instance);
46 sq_pushstring(vm, name.c_str(), -1);
47 if (SQ_FAILED(sq_get(vm, -2))) {
48 sq_settop(vm, top);
49 return false;
50 }
51 sq_getstackobj(vm, -1, &out);
52 sq_addref(vm, &out);
53 sq_settop(vm, top);
54 return true;
55}
56
57bool getNumberField(HSQUIRRELVM vm, HSQOBJECT instance, const std::string &name, float &out) {
58 const SQInteger top = sq_gettop(vm);
59 sq_pushobject(vm, instance);
60 sq_pushstring(vm, name.c_str(), -1);
61 if (SQ_FAILED(sq_get(vm, -2))) {
62 sq_settop(vm, top);
63 return false;
64 }
65 const bool ok = readFloatAt(vm, -1, out);
66 sq_settop(vm, top);
67 return ok;
68}
69
70bool setNumberField(HSQUIRRELVM vm, HSQOBJECT instance, const std::string &name, float value) {
71 const SQInteger top = sq_gettop(vm);
72 sq_pushobject(vm, instance);
73 sq_pushstring(vm, name.c_str(), -1);
74 sq_pushfloat(vm, SQFloat(value));
75 // Prefer set (existing slot). Fall back to newslot for unusual components.
76 if (SQ_FAILED(sq_set(vm, -3))) {
77 sq_settop(vm, top);
78 sq_pushobject(vm, instance);
79 sq_pushstring(vm, name.c_str(), -1);
80 sq_pushfloat(vm, SQFloat(value));
81 if (SQ_FAILED(sq_newslot(vm, -3, SQFalse))) {
82 sq_settop(vm, top);
83 return false;
84 }
85 }
86 sq_settop(vm, top);
87 return true;
88}
89
90std::vector<std::string> collectFieldNames(ssq::Object fieldsObj) {
91 std::vector<std::string> names;
92 HSQUIRRELVM vm = fieldsObj.getHandle();
93 if (!vm) return names;
94 HSQOBJECT arr = fieldsObj.getRaw();
95 if (arr._type != OT_ARRAY) return names;
96
97 const SQInteger top = sq_gettop(vm);
98 sq_pushobject(vm, arr);
99 const SQInteger len = sq_getsize(vm, -1);
100 names.reserve(size_t(std::max<SQInteger>(0, len)));
101 for (SQInteger i = 0; i < len; ++i) {
102 sq_pushinteger(vm, i);
103 if (SQ_FAILED(sq_get(vm, -2))) continue;
104 std::string name;
105 if (readStringField(vm, -1, name)) names.push_back(name);
106 sq_pop(vm, 1);
107 }
108 sq_settop(vm, top);
109 return names;
110}
111
112int entityArrayLen(HSQUIRRELVM vm, HSQOBJECT arr) {
113 const SQInteger top = sq_gettop(vm);
114 sq_pushobject(vm, arr);
115 const SQInteger len = sq_getsize(vm, -1);
116 sq_settop(vm, top);
117 return int(std::max<SQInteger>(0, len));
118}
119
120} // namespace
121
122int packScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot,
123 ssq::Object fieldsObj, GpuBuffer *buf) {
124 return packScriptEntityFloatsRange(entitiesObj, slot, fieldsObj, buf, 0, std::numeric_limits<int>::max());
125}
126
127int packScriptEntityFloatsRange(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf,
128 int firstEntity, int entityCount) {
129 if (!buf) throw Exception("packScriptEntityFloats: buffer is null");
130 if (slot.empty()) throw Exception("packScriptEntityFloats: empty slot");
131
132 HSQUIRRELVM vm = entitiesObj.getHandle();
133 if (!vm) return 0;
134 HSQOBJECT ents = entitiesObj.getRaw();
135 if (ents._type != OT_ARRAY) return 0;
136
137 const std::vector<std::string> fields = collectFieldNames(fieldsObj);
138 if (fields.empty()) return 0;
139
140 const int total = entityArrayLen(vm, ents);
141 const int first = std::clamp(firstEntity, 0, total);
142 const int n = std::clamp(entityCount, 0, total - first);
143 if (n <= 0) return 0;
144
145 const int floatsPer = int(fields.size());
146 std::vector<float> tmp(size_t(n) * size_t(floatsPer), 0.f);
147
148 const SQInteger top = sq_gettop(vm);
149 sq_pushobject(vm, ents);
150 for (int i = 0; i < n; ++i) {
151 sq_pushinteger(vm, first + i);
152 if (SQ_FAILED(sq_get(vm, -2))) {
153 sq_settop(vm, top);
154 throw Exception("packScriptEntityFloats: bad entity index %d", first + i);
155 }
156 if (sq_gettype(vm, -1) != OT_INSTANCE) {
157 sq_settop(vm, top);
158 throw Exception("packScriptEntityFloats: entity[%d] is not an instance", first + i);
159 }
160 HSQOBJECT entity{};
161 sq_getstackobj(vm, -1, &entity);
162
163 HSQOBJECT comp{};
164 sq_resetobject(&comp);
165 if (!getInstanceSlot(vm, entity, slot, comp) || comp._type != OT_INSTANCE) {
166 if (comp._type != OT_NULL) sq_release(vm, &comp);
167 sq_settop(vm, top);
168 throw Exception("packScriptEntityFloats: missing component slot '%s'", slot.c_str());
169 }
170
171 for (int f = 0; f < floatsPer; ++f) {
172 float v = 0.f;
173 if (!getNumberField(vm, comp, fields[size_t(f)], v)) {
174 sq_release(vm, &comp);
175 sq_settop(vm, top);
176 throw Exception("packScriptEntityFloats: missing field '%s.%s'", slot.c_str(),
177 fields[size_t(f)].c_str());
178 }
179 tmp[size_t(i) * size_t(floatsPer) + size_t(f)] = v;
180 }
181 sq_release(vm, &comp);
182 sq_pop(vm, 1); // entity
183 }
184 sq_settop(vm, top);
185
186 const int needBytes = (first + n) * floatsPer * int(sizeof(float));
187 if (buf->getSize() < needBytes)
188 throw Exception("packScriptEntityFloats: buffer too small (%d < %d)", buf->getSize(),
189 needBytes);
190 buf->writeFloat32s(tmp.data(), n * floatsPer, first * floatsPer);
191 return n;
192}
193
194int unpackScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot,
195 ssq::Object fieldsObj, GpuBuffer *buf, int entityCount) {
196 return unpackScriptEntityFloatsRange(entitiesObj, slot, fieldsObj, buf, 0, entityCount);
197}
198
199int unpackScriptEntityFloatsRange(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj,
200 GpuBuffer *buf, int firstEntity, int entityCount) {
201 if (!buf) throw Exception("unpackScriptEntityFloats: buffer is null");
202 if (slot.empty()) throw Exception("unpackScriptEntityFloats: empty slot");
203 if (entityCount <= 0) return 0;
204
205 HSQUIRRELVM vm = entitiesObj.getHandle();
206 if (!vm) return 0;
207 HSQOBJECT ents = entitiesObj.getRaw();
208 if (ents._type != OT_ARRAY) return 0;
209
210 const std::vector<std::string> fields = collectFieldNames(fieldsObj);
211 if (fields.empty()) return 0;
212
213 const int nArr = entityArrayLen(vm, ents);
214 const int first = std::clamp(firstEntity, 0, nArr);
215 const int n = std::clamp(entityCount, 0, nArr - first);
216 if (n <= 0) return 0;
217
218 const int floatsPer = int(fields.size());
219 std::vector<float> tmp(size_t(n) * size_t(floatsPer), 0.f);
220 const int needBytes = (first + n) * floatsPer * int(sizeof(float));
221 if (buf->getSize() < needBytes)
222 throw Exception("unpackScriptEntityFloats: buffer too small (%d < %d)", buf->getSize(), needBytes);
223 buf->readFloat32s(tmp.data(), n * floatsPer, first * floatsPer);
224
225 const SQInteger top = sq_gettop(vm);
226 sq_pushobject(vm, ents);
227 for (int i = 0; i < n; ++i) {
228 sq_pushinteger(vm, first + i);
229 if (SQ_FAILED(sq_get(vm, -2))) {
230 sq_settop(vm, top);
231 throw Exception("unpackScriptEntityFloats: bad entity index %d", first + i);
232 }
233 HSQOBJECT entity{};
234 sq_getstackobj(vm, -1, &entity);
235
236 HSQOBJECT comp{};
237 sq_resetobject(&comp);
238 if (!getInstanceSlot(vm, entity, slot, comp) || comp._type != OT_INSTANCE) {
239 if (comp._type != OT_NULL) sq_release(vm, &comp);
240 sq_settop(vm, top);
241 throw Exception("unpackScriptEntityFloats: missing component slot '%s'", slot.c_str());
242 }
243
244 for (int f = 0; f < floatsPer; ++f) {
245 const float v = tmp[size_t(i) * size_t(floatsPer) + size_t(f)];
246 if (!setNumberField(vm, comp, fields[size_t(f)], v)) {
247 sq_release(vm, &comp);
248 sq_settop(vm, top);
249 throw Exception("unpackScriptEntityFloats: cannot set '%s.%s'", slot.c_str(),
250 fields[size_t(f)].c_str());
251 }
252 }
253 sq_release(vm, &comp);
254 sq_pop(vm, 1);
255 }
256 sq_settop(vm, top);
257 return n;
258}
259
260} // namespace eve::gpgpu
double value
SQInteger top
const std::string & s
struct SQVM * HSQUIRRELVM
HSQUIRRELVM vm
Definition ECS.cpp:20
glm::vec3 n
Definition Grass.cpp:63
float v
std::int32_t first
std::string name
int idx
float f
std::vector< std::string > fields
Definition PlayHost.cpp:111
float t
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
Definition GpuBuffer.h:18
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
Byte length of the owned buffer.
virtual void readFloat32s(float *out, int count, int startIndex=0) const =0
Reads float 32 s.
Fluids module — interactive surface fluid simulation.
Definition Fluids.h:34
int unpackScriptEntityFloatsRange(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf, int firstEntity, int entityCount)
Unpack a contiguous buffer range into the matching stable ECS view range.
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.
int packScriptEntityFloatsRange(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf, int firstEntity, int entityCount)
Pack a contiguous entity range into the matching range of an existing buffer.