]> git.bts.cx Git - benzene.git/blob - src/bz/game/scene.c
907fccb03e72b55a1c54bc051ba8ff59524895f9
[benzene.git] / src / bz / game / scene.c
1 #include <bz/game/scene_internal.h>
2
3 #include <bz/collision/particle_collision.h>
4 //#include <bz/fx/agent_simulation.h>
5 #include <bz/fx/particle_simulation.h>
6 #include <bz/fx/particle_system.h>
7 #include <bz/game/actor_internal.h>
8 #include <bz/game/tilemap.h>
9 #include <bz/gfx/aseprite.h>
10 #include <bz/gfx/font_internal.h>
11 #include <bz/gfx/gfx_internal.h>
12 #include <bz/gfx/particle_drawing.h>
13 #include <bz/math/math.h>
14 #include <bz/memory/allocator.h>
15 #include <bz/resources/resource.h>
16 #include <bz/scripting/bindings_internal.h>
17 #include <bz/scripting/script.h>
18 #include <bz/types/identifier_internal.h>
19 #include <parson.h>
20 #include <string.h> // strncpy
21
22 struct BZSceneActorDefinition {
23         //char identifier[kBZMaxIdentifierLength]; // fixme
24         BZIdentifierHash identifierHash;
25         SVMModule *module;
26         size_t instanceSize;
27         int32_t priority;
28         size_t spawnCount;
29 };
30 typedef struct BZSceneActorDefinition BZSceneActorDefinition;
31
32 /*struct BZSceneParticleSystem {
33         char identifier[kBZMaxIdentifierLength]; // fixme
34         BZIdentifierHash identifierHash;
35         BZParticleSystemID particleSystem;
36 };
37 typedef struct BZSceneParticleSystem BZSceneParticleSystem;*/
38
39 struct BZSceneLayer {
40         char identifier[kBZMaxIdentifierLength]; // fixme
41         BZIdentifierHash identifierHash;
42         BZDrawQueueID drawQueue;
43         BZTilemapID tilemap;
44         BZParticleSimulationID particleSimulation;
45         BZCollisionSpaceID collisionSpace;
46         BZIdentifierHash particleCollisionTagHash;
47         float particleCollisionRadiusMultiplier;
48         int outputBuffer;
49 };
50
51 ////#define kMaxActorInstances 50//256
52
53 struct BZSceneActor {
54         BZActor actor;
55         BZScriptBindingMetadata scriptMetadata;
56         int32_t priority;
57         bool running;
58 };
59 typedef struct BZSceneActor BZSceneActor;
60
61 #define kBZScriptingEnvironmentPublicCount 256
62 #define kBZScriptingEnvironmentEventCount 256
63
64 struct BZScriptingEnvironmentPublic {
65         BZIdentifierHash identifierHash;
66         SVMOperand value;
67 };
68 typedef struct BZScriptingEnvironmentPublic BZScriptingEnvironmentPublic;
69
70 struct BZSceneEvent {
71         BZIdentifierHash identifierHash;
72         BZSceneEventData data;
73 };
74 typedef struct BZSceneEvent BZSceneEvent;
75
76 struct BZScene {
77 //      BZScriptingEnvironmentID sceneEnvironment;
78 //      BZScriptID sceneScript;
79 //      BZScriptBindingMetadata sceneScriptMetadata;
80 //      BZScriptInstanceID sceneScriptInstance;
81         BZSceneActorDefinition *actorDefinitions;
82         size_t actorDefinitionCount;
83         BZSceneLayer *layers;
84         size_t layerCount;
85         uint64_t ticks;
86
87         int32_t minActorPriority;
88         int32_t maxActorPriority;
89
90         size_t lastActorIndex;
91         size_t actorInstanceCount;
92         BZSceneActor *actorInstances;
93
94         BZScriptingEnvironmentPublic publics[kBZScriptingEnvironmentPublicCount];
95
96         BZAudioPlaybackEngineID audioEngine;
97
98 //      BZAgentSimulationID agentSimulation;
99
100         size_t eventCount;
101         BZSceneEvent *currentEvents;
102         size_t nextEnqueuedEvent;
103         BZSceneEvent *enqueuedEvents;
104
105 //      char targetSceneIdentifier[kBZMaxIdentifierLength]; // fixme
106 };
107
108 uint8_t gSystemTicksPerSecond;
109
110 static void bzGameSceneActorLoadDefinition(BZSceneActorDefinition *definitionOut, BZSceneID scene, BZMemoryArenaID arena, const char *identifierFmt, ...) {
111         bzMakeIdentifier(identifier, identifierFmt);
112         definitionOut->identifierHash = bzIdentifierHashFromIdentifier(identifier);
113
114         BZResourceID handle = bzResourcesOpenResource("scene", "assets/actors/%s.actor.json", identifier);
115         bzAssertMessage(handle != NULL, "Invalid actor definition '%s'", identifier);
116
117         size_t length = bzResourcesFileLength(handle);
118         char *data = alloca(length);//(char *)bzMemoryAlloc(kBZSystemMemoryArena, length);//alloca(length); // FIXME, need working space off the stack
119         bzResourcesReadBytes(handle, data, length);
120         bzResourcesCloseResource(handle);
121
122         //json_set_allocation_functions
123         JSON_Value *actorDefinitionJson = json_parse_string(data);
124         JSON_Object *actorDefinitionJsonObject = json_object(actorDefinitionJson);
125
126         const char *scriptName = json_object_get_string(actorDefinitionJsonObject, "script");
127         if (scriptName != NULL) {
128                 definitionOut->module = bzScriptingLoadScriptModule(arena, "%s", scriptName);
129                 definitionOut->instanceSize = svmGetModuleInstanceSize(definitionOut->module);
130         }
131
132         definitionOut->priority = json_object_get_number(actorDefinitionJsonObject, "priority");
133         scene->minActorPriority = bzMin(scene->minActorPriority, definitionOut->priority);
134         scene->maxActorPriority = bzMax(scene->maxActorPriority, definitionOut->priority);
135
136         json_value_free(actorDefinitionJson);
137
138         bzLog("Opened actor %s", identifier);
139 }
140
141 static BZActorID bzGameSceneSetupActor(BZSceneActor *sceneActor, BZSceneID scene, const BZSceneActorDefinition *definition, const char *identifierFmt, ...) {
142         BZActorID actor = &sceneActor->actor;
143         BZScriptBindingMetadata *metadata = &sceneActor->scriptMetadata;
144
145         bzInsertIdentifier(actor->identifier, identifierFmt);
146         actor->identifierHash = bzIdentifierHashFromIdentifier(actor->identifier);
147
148         bzAssertMessage(definition != NULL, "Could not find definition for '%s'", actor->identifier);
149
150         sceneActor->priority = definition->priority;
151
152         actor->instance = svnResetModuleInstanceMemory(definition->module, actor->instance, metadata, bzScriptingBindingsLookupNativeFunction);
153         bzScriptingInitialiseMetadata((BZScriptBindingMetadata *)&sceneActor->scriptMetadata, actor, scene, scene->lastActorIndex);
154
155         sceneActor->running = true;
156
157         return actor;
158 }
159
160 BZSceneID bzGameSceneSwitch(BZMemoryArenaID arena, BZAudioPlaybackEngineID audioEngine, const char *identifierFmt, ...) {
161         bzMakeIdentifier(identifier, identifierFmt);
162
163         BZSceneID scene = bzMemoryAlloc(arena, sizeof(BZScene));
164         
165         BZResourceID handle = bzResourcesOpenResource("scene", "assets/scenes/%s.scene.json", identifier);
166         size_t length = bzResourcesFileLength(handle);
167         char *data = alloca(length);//(char *)bzMemoryAlloc(kBZSystemMemoryArena, length);//alloca(length); // FIXME, need working space off the stack
168         bzResourcesReadBytes(handle, data, length);
169         bzResourcesCloseResource(handle);
170
171         //json_set_allocation_functions
172         JSON_Value *sceneJson = json_parse_string(data);
173         JSON_Object *sceneJsonObject = json_object(sceneJson);
174
175         const char *soundbankName = json_object_get_string(sceneJsonObject, "soundbank");
176         if (soundbankName != NULL && audioEngine != NULL) {
177                 scene->audioEngine = audioEngine;
178                 bzAudioPlaybackUseSoundbank(scene->audioEngine, arena, soundbankName);
179         }
180
181         const char *spritesheetName = json_object_get_string(sceneJsonObject, "spritesheet");
182         if (spritesheetName != NULL) {
183                 size_t imageWidth, imageHeight;
184                 void *imageData = bzGfxLoadAsepriteImage(arena, &imageWidth, &imageHeight, spritesheetName); // FIXME, temp arena
185                 bzGfxPrepareSpritesheet(arena, imageWidth, imageHeight, imageData);
186                 //free(imageData);
187         }
188
189         const char *fontName = json_object_get_string(sceneJsonObject, "font");
190         BZFont *font = bzGfxLoadFont(arena, fontName); // FIXME, temp arena??
191         bzGfxPrepareFont(arena, font);
192
193         JSON_Array *actorDefinitionsArray = json_object_get_array(sceneJsonObject, "actors");
194         size_t actorDefinitionsArrayCount = json_array_get_count(actorDefinitionsArray);
195         scene->actorDefinitionCount = actorDefinitionsArrayCount;
196
197         size_t startDefinition = 0;
198         const char *sceneActorName = json_object_get_string(sceneJsonObject, "scene_actor");
199         if (sceneActorName != NULL) {
200                 scene->actorDefinitionCount += 1;
201                 startDefinition = 1;
202         }
203
204         scene->actorDefinitions = (BZSceneActorDefinition *)bzMemoryAlloc(arena, scene->actorDefinitionCount * sizeof(BZSceneActorDefinition));
205         
206         size_t maxInstanceSize = 0;
207
208         if (sceneActorName != NULL) {
209                 bzGameSceneActorLoadDefinition(&scene->actorDefinitions[0], scene, arena, "%s", sceneActorName); // fixme
210                 maxInstanceSize = scene->actorDefinitions[0].instanceSize;
211         }
212
213         for (size_t i = 0; i < actorDefinitionsArrayCount; ++i) {
214                 const char *actorName = json_array_get_string(actorDefinitionsArray, i);
215                 size_t outIdx = i + startDefinition;
216                 bzGameSceneActorLoadDefinition(&scene->actorDefinitions[outIdx], scene, arena, "%s", actorName); // fixme
217                 maxInstanceSize = bzMax(maxInstanceSize, scene->actorDefinitions[outIdx].instanceSize);
218         }
219
220         // FIXME, alignment for instance size
221
222         scene->lastActorIndex = 0;
223         scene->actorInstanceCount = 1024;
224
225         scene->actorInstances = (BZSceneActor *)bzMemoryAlloc(arena, scene->actorInstanceCount * sizeof(BZSceneActor));
226         for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
227                 scene->actorInstances[i].actor.instance = bzMemoryAlloc(arena, maxInstanceSize);
228         }
229
230         if (sceneActorName != NULL) {
231                 bzGameSceneSetupActor(&scene->actorInstances[0], scene, &scene->actorDefinitions[0], "scene");
232         }
233
234 //      int hasAgents = json_object_get_boolean(sceneJsonObject, "agents");
235 //      if (hasAgents > 0) {
236 //              scene->agentSimulation = bzFXCreateAgentSimulation(arena, scene->actorInstanceCount, "%s.agents", identifier);
237 //      }
238
239         JSON_Array *layerDefinitionsArray = json_object_get_array(sceneJsonObject, "layers");
240         scene->layerCount = json_array_get_count(layerDefinitionsArray);
241         scene->layers = bzMemoryAlloc(arena, scene->layerCount * sizeof(BZSceneLayer));
242         for (size_t i = 0; i < scene->layerCount; ++i) {
243                 JSON_Object *layerDefinition = json_array_get_object(layerDefinitionsArray, i);
244                 stbsp_snprintf(scene->layers[i].identifier, kBZMaxIdentifierLength, "%s", json_object_get_string(layerDefinition, "identifier"));
245                 scene->layers[i].identifierHash = bzIdentifierHashFromIdentifier(scene->layers[i].identifier);
246
247                 const char *particleSystemName = json_object_get_string(layerDefinition, "particles");
248                 if (particleSystemName != NULL) {
249                         BZParticleSystemID particleSystem = bzFXLoadParticleSystem(arena, "%s", particleSystemName); // FIXME, pool these...
250                         int hasCollision2 = json_object_get_boolean(layerDefinition, "collision"); // FIXME
251                         scene->layers[i].particleSimulation = bzFXCreateParticleSimulation(arena, (hasCollision2 > 0) ? 1024 : (5 * 1024), particleSystem, "%s.particles", scene->layers[i].identifier); // FIXME, memory
252                 }
253
254                 if (json_object_has_value_of_type(layerDefinition, "output", JSONNumber)) {
255                         scene->layers[i].outputBuffer = (int)json_object_get_number(layerDefinition, "output");
256                         if (particleSystemName == NULL || json_object_get_boolean(layerDefinition, "custom-particle") > 0) {
257                                 scene->layers[i].drawQueue = bzGfxDrawQueueCreate(arena, "scene.%s.drawQueue", scene->layers[i].identifier);
258                         }
259                 }
260
261                 const char *tilemapName = json_object_get_string(layerDefinition, "tilemap");
262                 if (tilemapName != NULL) {
263                         scene->layers[i].tilemap = bzGameLoadTilemap(arena, "%s", tilemapName);
264                 }
265
266                 int hasCollision = json_object_get_boolean(layerDefinition, "collision");
267                 if (hasCollision > 0) {
268                         if (scene->layers[i].particleSimulation == NULL) {
269                                 scene->layers[i].collisionSpace = bzCollisionMakeSpace(arena, scene->actorInstanceCount, "%s.collision", scene->layers[i].identifier);
270                         } else {
271                                 scene->layers[i].collisionSpace = bzCollisionMakeSpace(arena, 1024, "%s.particle.collision", scene->layers[i].identifier);
272
273                                 if (json_object_has_value_of_type(layerDefinition, "collision-radius", JSONNumber)) {
274                                         scene->layers[i].particleCollisionRadiusMultiplier = json_object_get_number(layerDefinition, "collision-radius");
275                                 } else {
276                                         scene->layers[i].particleCollisionRadiusMultiplier = 1.0f;
277                                 }
278                                 scene->layers[i].particleCollisionTagHash = bzIdentifierHashFromIdentifier(particleSystemName);
279                         }
280                 }
281         }
282
283         scene->currentEvents = bzMemoryAlloc(arena, kBZScriptingEnvironmentEventCount * sizeof(BZSceneEvent));
284         scene->enqueuedEvents = bzMemoryAlloc(arena, kBZScriptingEnvironmentEventCount * sizeof(BZSceneEvent));
285
286         json_value_free(sceneJson);
287
288         bzLog("Opened scene %s", identifier);
289
290         return scene;
291 }
292
293 bool bzGameSceneUpdate(BZSceneID scene, uint8_t pauseFlags, uint8_t systemTicks) {
294         float deltaTime = (float)systemTicks / (float)gSystemTicksPerSecond;
295
296         for (size_t i = 0; i < scene->layerCount; ++i) {
297                 BZSceneLayer *layer = &scene->layers[i];
298                 if (layer->particleSimulation == NULL) {
299                         bzGfxDrawQueueClear(layer->drawQueue);
300                 }
301                 if (layer->collisionSpace != NULL) {
302                         bzCollisionResetSpace(layer->collisionSpace);
303                 }
304         }
305
306 //      if (scene->agentSimulation != NULL) {
307 //              SVMOperand playerX;
308 //              bzScriptingGetEnvironmentPublic(&playerX, scene, bzIdentifierHashFromIdentifier("shipX"));
309 //
310 //              SVMOperand playerY;
311 //              bzScriptingGetEnvironmentPublic(&playerY, scene, bzIdentifierHashFromIdentifier("shipY"));
312 //
313 //              BZVector playerPos = bzVectorMake(FIXED_TO_FLOAT(playerX.floatLiteral), FIXED_TO_FLOAT(playerY.floatLiteral));
314 //
315 //              bzFXUpdateAgentSimulation(scene->agentSimulation, deltaTime, NULL, &playerPos);
316 //      }
317
318         for (size_t i = 0; i < scene->layerCount; ++i) {
319                 BZSceneLayer *layer = &scene->layers[i];
320                 if (layer->particleSimulation != NULL) {
321                         bzFXUpdateParticleSystem(layer->particleSimulation, deltaTime);
322                         if (layer->collisionSpace != NULL) {
323                                 bzCollisionPopulateParticles(layer->collisionSpace, layer->particleSimulation, layer->particleCollisionTagHash, layer->particleCollisionRadiusMultiplier);
324                         }
325                 }
326         }
327
328         for (int32_t priority = scene->minActorPriority; priority <= scene->maxActorPriority; ++priority) {
329                 for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
330                         BZSceneActor *sceneActor = &scene->actorInstances[i];
331                         if (sceneActor->running && sceneActor->priority == priority) {
332                                 SVMRunOutcome outcome = svmRunModuleInstance(sceneActor->actor.instance);
333                                 sceneActor->running = (outcome == SVMRunOutcomeSuspended);
334                         }
335                 }
336         }
337         
338         scene->ticks += systemTicks;
339
340         scene->eventCount = scene->nextEnqueuedEvent;
341         scene->nextEnqueuedEvent = 0;
342
343         BZSceneEvent *tmp = scene->currentEvents;
344         scene->currentEvents = scene->enqueuedEvents;
345         scene->enqueuedEvents = tmp;
346
347         return scene->actorInstances[0].running;
348 }
349
350 void bzGameSceneDraw(BZSceneID scene) {
351         for (size_t i = 0; i < scene->layerCount; ++i) {
352                 bzSetOutputBuffer(scene->layers[i].outputBuffer);
353                 if (scene->layers[i].particleSimulation != NULL) {
354                         bzGfxDrawParticles(scene->layers[i].particleSimulation, scene->layers[i].drawQueue);
355                 } else {
356                         bzGfxDrawQueueRun(scene->layers[i].drawQueue);
357                 }
358                 
359                 //if (scene->layers[i].collisionSpace != NULL) {
360                 //      bzCollisionDrawDebug(scene->layers[i].collisionSpace);
361                 //}
362
363 //              if (i == 3 && scene->agentSimulation != NULL) { // FIXME
364 //                      bzFXAgentSimulationDrawDebug(scene->agentSimulation);
365 //              }
366         }
367
368         
369 }
370
371 BZActorID bzGameSceneAddActor(BZSceneID scene, const char *identifierFmt, ...) {
372         bzMakeIdentifier(identifier, identifierFmt);
373
374         BZIdentifierHash definitionIdentifierHash = bzIdentifierHashFromIdentifier(identifier);
375         BZSceneActorDefinition *definition = NULL;
376         for (size_t i = 0; i < scene->actorDefinitionCount; ++i) { // fixme
377                 if (definitionIdentifierHash == scene->actorDefinitions[i].identifierHash) {
378                         definition = &scene->actorDefinitions[i];
379                         break;
380                 }
381         }
382         bzAssertMessage(definition != NULL, "Undefined actor '%s'", identifier);
383
384         BZSceneActor *sceneActor = NULL;
385         for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
386                 ++scene->lastActorIndex;
387
388                 size_t idx = (scene->lastActorIndex % (scene->actorInstanceCount - 1)) + 1; // 0 is only for the scene script
389                 if (scene->actorInstances[idx].running == false) {
390                         sceneActor = &scene->actorInstances[idx];
391                         break;
392                 }
393         }
394         bzAssertMessage(sceneActor != NULL, "Out of actors");
395
396         definition->spawnCount += 1;
397
398         return bzGameSceneSetupActor(sceneActor, scene, definition, "%s-%u", identifier, definition->spawnCount);
399 }
400
401 BZActorID bzGameSceneFindActor(BZSceneID scene, const char *identifierFmt, ...) {
402         bzMakeIdentifier(identifier, identifierFmt);
403         BZIdentifierHash identifierHash = bzIdentifierHashFromIdentifier(identifier);
404         for (size_t i = 0; i < scene->actorInstanceCount; ++i) { // fixme
405                 if (scene->actorInstances[i].actor.identifierHash == identifierHash) {
406                         return &scene->actorInstances[i].actor;
407                 }
408         }
409         return NULL;
410 }
411
412 float bzGameSceneGetTime(BZSceneID scene) {
413         float time = (float)scene->ticks / (float)gSystemTicksPerSecond;
414         return time;
415 }
416
417 bool bzGameSceneQueryEvent(BZSceneEventData *dataOut, BZSceneID scene, BZIdentifierHash eventIdentifier) {
418         for (size_t i = 0; i < scene->eventCount; ++i) {
419                 BZSceneEvent *event = &scene->currentEvents[i];
420                 if (event->identifierHash == eventIdentifier) {
421                         if (dataOut != NULL) {
422                                 *dataOut = event->data;
423                         }
424                         return true;
425                 }
426         }
427         return false;
428 }
429
430 void bzGameScenePostEvent(BZSceneID scene, BZIdentifierHash eventIdentifier, const BZSceneEventData *data) {
431         bzAssert(scene->nextEnqueuedEvent < kBZScriptingEnvironmentEventCount);
432         BZSceneEvent *event = &scene->enqueuedEvents[scene->nextEnqueuedEvent++];
433         event->identifierHash = eventIdentifier;
434         if (data != NULL) {
435                 event->data = *data;
436         }
437 }
438
439 BZSceneLayer *getLayer(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
440         for (size_t i = 0; i < scene->layerCount; ++i) {
441                 if (scene->layers[i].identifierHash == layerIdentifierHash) {
442                         return &scene->layers[i];
443                 }
444         }
445         return NULL;
446 }
447
448 BZTilemapID bzGameGetSceneLayerTilemap(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
449         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
450         if (layer != NULL) {
451                 return layer->tilemap;
452         } else {
453                 return NULL;
454         }
455 }
456
457 BZDrawQueueID bzGameGetSceneLayerDrawQueue(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
458         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
459         if (layer != NULL) {
460                 return layer->drawQueue;
461         } else {
462                 return NULL;
463         }
464 }
465
466 BZParticleSimulationID bzGameGetSceneLayerParticleSimulation(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
467         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
468         if (layer != NULL) {
469                 return layer->particleSimulation;
470         } else {
471                 return NULL;
472         }
473 }
474
475 BZCollisionSpaceID bzGameGetSceneLayerCollisionSpace(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
476         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
477         if (layer != NULL) {
478                 return layer->collisionSpace;
479         } else {
480                 return NULL;
481         }
482 }
483
484
485 /*
486 extern void bzGameSceneSetTimeTicksPerSecond(uint8_t tps);
487 extern void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags); // Pause timer on these flags
488 extern float bzGameSceneTime(uint8_t timeIdx);
489
490 void bzGameSceneSetTimeTicksPerSecond(uint8_t tps) {
491         sceneTPS = tps;
492 }
493
494 void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags) {
495         times[timeIdx].pauseFlags = pauseFlags;
496 }
497
498 float bzGameSceneTime(uint8_t timeIdx) {
499         float time = (float)times[timeIdx].ticks / (float)sceneTPS;
500         return time;
501 }
502 */
503
504 //BZAgentSimulationID bzGameGetAgentSimulation(BZSceneID scene) {
505 //      return scene->agentSimulation;
506 //}
507
508 BZAudioPlaybackEngineID bzGameGetAudioPlaybackEngine(BZSceneID scene) {
509         return scene->audioEngine;
510 }
511
512 bool bzScriptingGetEnvironmentPublic(SVMOperand *out, BZSceneID scene, BZIdentifierHash identifierHash) {
513         for (size_t i = 0; i < kBZScriptingEnvironmentPublicCount; ++i) {
514                 if (scene->publics[i].identifierHash == identifierHash) {
515                         if (out != NULL) {
516                                 out->__raw = scene->publics[i].value.__raw;
517                         }
518                         return true;
519                 }
520         }
521         return false;
522 }
523
524 void bzScriptingSetEnvironmentPublic(BZSceneID scene, BZIdentifierHash identifierHash, SVMOperand value) {
525         for (size_t i = 0; i < kBZScriptingEnvironmentPublicCount; ++i) {
526                 if (scene->publics[i].identifierHash == 0) {
527                         scene->publics[i].identifierHash = identifierHash;
528                 }
529                 if (scene->publics[i].identifierHash == identifierHash) {
530                         scene->publics[i].value.__raw = value.__raw;
531                         return;
532                 } 
533         }
534         bzError("Out of globals!!");
535 }
536
537 size_t bzGameGetSceneLayerCount(BZSceneID scene) {
538         return scene->layerCount;
539 }
540
541 BZSceneLayerID bzGameGetSceneLayerAtIndex(BZSceneID scene, size_t idx) {
542         bzAssert(idx < scene->layerCount);
543         return &scene->layers[idx];
544 }
545
546
547 BZCollisionSpaceID bzGameGetSceneLayerCollisionSpace2(BZSceneLayerID layer) {
548         return layer->collisionSpace;
549 }
550
551 BZParticleSimulationID bzGameGetSceneLayerParticleSimulation2(BZSceneLayerID layer) {
552         return layer->particleSimulation;
553 }