]> git.bts.cx Git - benzene.git/blob - src/bz/game/scene.c
Sprites
[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 imageFrames, imageWidth, imageHeight;
184                 void *imageData = bzGfxLoadAsepriteImage(arena, &imageFrames, &imageWidth, &imageHeight, spritesheetName); // FIXME, temp arena
185                 bzGfxPrepareSpritesheet(arena, imageFrames, imageWidth, imageHeight, imageData);
186                 //free(imageData);
187         }
188
189         const char *fontName = json_object_get_string(sceneJsonObject, "font");
190         if (fontName != NULL) {
191                 BZFont *font = bzGfxLoadFont(arena, fontName); // FIXME, temp arena??
192                 bzGfxPrepareFont(arena, font);
193         }
194
195         JSON_Array *actorDefinitionsArray = json_object_get_array(sceneJsonObject, "actors");
196         size_t actorDefinitionsArrayCount = json_array_get_count(actorDefinitionsArray);
197         scene->actorDefinitionCount = actorDefinitionsArrayCount;
198
199         size_t startDefinition = 0;
200         const char *sceneActorName = json_object_get_string(sceneJsonObject, "scene_actor");
201         if (sceneActorName != NULL) {
202                 scene->actorDefinitionCount += 1;
203                 startDefinition = 1;
204         }
205
206         scene->actorDefinitions = (BZSceneActorDefinition *)bzMemoryAlloc(arena, scene->actorDefinitionCount * sizeof(BZSceneActorDefinition));
207         
208         size_t maxInstanceSize = 0;
209
210         if (sceneActorName != NULL) {
211                 bzGameSceneActorLoadDefinition(&scene->actorDefinitions[0], scene, arena, "%s", sceneActorName); // fixme
212                 maxInstanceSize = scene->actorDefinitions[0].instanceSize;
213         }
214
215         for (size_t i = 0; i < actorDefinitionsArrayCount; ++i) {
216                 const char *actorName = json_array_get_string(actorDefinitionsArray, i);
217                 size_t outIdx = i + startDefinition;
218                 bzGameSceneActorLoadDefinition(&scene->actorDefinitions[outIdx], scene, arena, "%s", actorName); // fixme
219                 maxInstanceSize = bzMax(maxInstanceSize, scene->actorDefinitions[outIdx].instanceSize);
220         }
221
222         // FIXME, alignment for instance size
223
224         scene->lastActorIndex = 0;
225         scene->actorInstanceCount = 1024;
226
227         scene->actorInstances = (BZSceneActor *)bzMemoryAlloc(arena, scene->actorInstanceCount * sizeof(BZSceneActor));
228         for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
229                 scene->actorInstances[i].actor.instance = bzMemoryAlloc(arena, maxInstanceSize);
230         }
231
232         if (sceneActorName != NULL) {
233                 bzGameSceneSetupActor(&scene->actorInstances[0], scene, &scene->actorDefinitions[0], "scene");
234         }
235
236 //      int hasAgents = json_object_get_boolean(sceneJsonObject, "agents");
237 //      if (hasAgents > 0) {
238 //              scene->agentSimulation = bzFXCreateAgentSimulation(arena, scene->actorInstanceCount, "%s.agents", identifier);
239 //      }
240
241         JSON_Array *layerDefinitionsArray = json_object_get_array(sceneJsonObject, "layers");
242         scene->layerCount = json_array_get_count(layerDefinitionsArray);
243         scene->layers = bzMemoryAlloc(arena, scene->layerCount * sizeof(BZSceneLayer));
244         for (size_t i = 0; i < scene->layerCount; ++i) {
245                 JSON_Object *layerDefinition = json_array_get_object(layerDefinitionsArray, i);
246                 stbsp_snprintf(scene->layers[i].identifier, kBZMaxIdentifierLength, "%s", json_object_get_string(layerDefinition, "identifier"));
247                 scene->layers[i].identifierHash = bzIdentifierHashFromIdentifier(scene->layers[i].identifier);
248
249                 const char *particleSystemName = json_object_get_string(layerDefinition, "particles");
250                 if (particleSystemName != NULL) {
251                         BZParticleSystemID particleSystem = bzFXLoadParticleSystem(arena, "%s", particleSystemName); // FIXME, pool these...
252                         int hasCollision2 = json_object_get_boolean(layerDefinition, "collision"); // FIXME
253                         scene->layers[i].particleSimulation = bzFXCreateParticleSimulation(arena, (hasCollision2 > 0) ? 1024 : (5 * 1024), particleSystem, "%s.particles", scene->layers[i].identifier); // FIXME, memory
254                 }
255
256                 if (json_object_has_value_of_type(layerDefinition, "output", JSONNumber)) {
257                         scene->layers[i].outputBuffer = (int)json_object_get_number(layerDefinition, "output");
258                         if (particleSystemName == NULL || json_object_get_boolean(layerDefinition, "custom-particle") > 0) {
259                                 scene->layers[i].drawQueue = bzGfxDrawQueueCreate(arena, "scene.%s.drawQueue", scene->layers[i].identifier);
260                         }
261                 }
262
263                 const char *tilemapName = json_object_get_string(layerDefinition, "tilemap");
264                 if (tilemapName != NULL) {
265                         scene->layers[i].tilemap = bzGameLoadTilemap(arena, "%s", tilemapName);
266                 }
267
268                 int hasCollision = json_object_get_boolean(layerDefinition, "collision");
269                 if (hasCollision > 0) {
270                         if (scene->layers[i].particleSimulation == NULL) {
271                                 scene->layers[i].collisionSpace = bzCollisionMakeSpace(arena, scene->actorInstanceCount, "%s.collision", scene->layers[i].identifier);
272                         } else {
273                                 scene->layers[i].collisionSpace = bzCollisionMakeSpace(arena, 1024, "%s.particle.collision", scene->layers[i].identifier);
274
275                                 if (json_object_has_value_of_type(layerDefinition, "collision-radius", JSONNumber)) {
276                                         scene->layers[i].particleCollisionRadiusMultiplier = json_object_get_number(layerDefinition, "collision-radius");
277                                 } else {
278                                         scene->layers[i].particleCollisionRadiusMultiplier = 1.0f;
279                                 }
280                                 scene->layers[i].particleCollisionTagHash = bzIdentifierHashFromIdentifier(particleSystemName);
281                         }
282                 }
283         }
284
285         scene->currentEvents = bzMemoryAlloc(arena, kBZScriptingEnvironmentEventCount * sizeof(BZSceneEvent));
286         scene->enqueuedEvents = bzMemoryAlloc(arena, kBZScriptingEnvironmentEventCount * sizeof(BZSceneEvent));
287
288         json_value_free(sceneJson);
289
290         bzLog("Opened scene %s", identifier);
291
292         return scene;
293 }
294
295 bool bzGameSceneUpdate(BZSceneID scene, uint8_t pauseFlags, uint8_t systemTicks) {
296         float deltaTime = (float)systemTicks / (float)gSystemTicksPerSecond;
297
298         for (size_t i = 0; i < scene->layerCount; ++i) {
299                 BZSceneLayer *layer = &scene->layers[i];
300                 if (layer->particleSimulation == NULL) {
301                         bzGfxDrawQueueClear(layer->drawQueue);
302                 }
303                 if (layer->collisionSpace != NULL) {
304                         bzCollisionResetSpace(layer->collisionSpace);
305                 }
306         }
307
308 //      if (scene->agentSimulation != NULL) {
309 //              SVMOperand playerX;
310 //              bzScriptingGetEnvironmentPublic(&playerX, scene, bzIdentifierHashFromIdentifier("shipX"));
311 //
312 //              SVMOperand playerY;
313 //              bzScriptingGetEnvironmentPublic(&playerY, scene, bzIdentifierHashFromIdentifier("shipY"));
314 //
315 //              BZVector playerPos = bzVectorMake(FIXED_TO_FLOAT(playerX.floatLiteral), FIXED_TO_FLOAT(playerY.floatLiteral));
316 //
317 //              bzFXUpdateAgentSimulation(scene->agentSimulation, deltaTime, NULL, &playerPos);
318 //      }
319
320         for (size_t i = 0; i < scene->layerCount; ++i) {
321                 BZSceneLayer *layer = &scene->layers[i];
322                 if (layer->particleSimulation != NULL) {
323                         bzFXUpdateParticleSystem(layer->particleSimulation, deltaTime);
324                         if (layer->collisionSpace != NULL) {
325                                 bzCollisionPopulateParticles(layer->collisionSpace, layer->particleSimulation, layer->particleCollisionTagHash, layer->particleCollisionRadiusMultiplier);
326                         }
327                 }
328         }
329
330         for (int32_t priority = scene->minActorPriority; priority <= scene->maxActorPriority; ++priority) {
331                 for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
332                         BZSceneActor *sceneActor = &scene->actorInstances[i];
333                         if (sceneActor->running && sceneActor->priority == priority) {
334                                 SVMRunOutcome outcome = svmRunModuleInstance(sceneActor->actor.instance);
335                                 sceneActor->running = (outcome == SVMRunOutcomeSuspended);
336                         }
337                 }
338         }
339         
340         scene->ticks += systemTicks;
341
342         scene->eventCount = scene->nextEnqueuedEvent;
343         scene->nextEnqueuedEvent = 0;
344
345         BZSceneEvent *tmp = scene->currentEvents;
346         scene->currentEvents = scene->enqueuedEvents;
347         scene->enqueuedEvents = tmp;
348
349         return scene->actorInstances[0].running;
350 }
351
352 void bzGameSceneDraw(BZSceneID scene) {
353         for (size_t i = 0; i < scene->layerCount; ++i) {
354                 bzSetOutputBuffer(scene->layers[i].outputBuffer);
355                 if (scene->layers[i].particleSimulation != NULL) {
356                         bzGfxDrawParticles(scene->layers[i].particleSimulation, scene->layers[i].drawQueue);
357                 } else {
358                         bzGfxDrawQueueRun(scene->layers[i].drawQueue);
359                 }
360                 
361                 //if (scene->layers[i].collisionSpace != NULL) {
362                 //      bzCollisionDrawDebug(scene->layers[i].collisionSpace);
363                 //}
364
365 //              if (i == 3 && scene->agentSimulation != NULL) { // FIXME
366 //                      bzFXAgentSimulationDrawDebug(scene->agentSimulation);
367 //              }
368         }
369
370         
371 }
372
373 BZActorID bzGameSceneAddActor(BZSceneID scene, const char *identifierFmt, ...) {
374         bzMakeIdentifier(identifier, identifierFmt);
375
376         BZIdentifierHash definitionIdentifierHash = bzIdentifierHashFromIdentifier(identifier);
377         BZSceneActorDefinition *definition = NULL;
378         for (size_t i = 0; i < scene->actorDefinitionCount; ++i) { // fixme
379                 if (definitionIdentifierHash == scene->actorDefinitions[i].identifierHash) {
380                         definition = &scene->actorDefinitions[i];
381                         break;
382                 }
383         }
384         bzAssertMessage(definition != NULL, "Undefined actor '%s'", identifier);
385
386         BZSceneActor *sceneActor = NULL;
387         for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
388                 ++scene->lastActorIndex;
389
390                 size_t idx = (scene->lastActorIndex % (scene->actorInstanceCount - 1)) + 1; // 0 is only for the scene script
391                 if (scene->actorInstances[idx].running == false) {
392                         sceneActor = &scene->actorInstances[idx];
393                         break;
394                 }
395         }
396         bzAssertMessage(sceneActor != NULL, "Out of actors");
397
398         definition->spawnCount += 1;
399
400         return bzGameSceneSetupActor(sceneActor, scene, definition, "%s-%u", identifier, definition->spawnCount);
401 }
402
403 BZActorID bzGameSceneFindActor(BZSceneID scene, const char *identifierFmt, ...) {
404         bzMakeIdentifier(identifier, identifierFmt);
405         BZIdentifierHash identifierHash = bzIdentifierHashFromIdentifier(identifier);
406         for (size_t i = 0; i < scene->actorInstanceCount; ++i) { // fixme
407                 if (scene->actorInstances[i].actor.identifierHash == identifierHash) {
408                         return &scene->actorInstances[i].actor;
409                 }
410         }
411         return NULL;
412 }
413
414 float bzGameSceneGetTime(BZSceneID scene) {
415         float time = (float)scene->ticks / (float)gSystemTicksPerSecond;
416         return time;
417 }
418
419 bool bzGameSceneQueryEvent(BZSceneEventData *dataOut, BZSceneID scene, BZIdentifierHash eventIdentifier) {
420         for (size_t i = 0; i < scene->eventCount; ++i) {
421                 BZSceneEvent *event = &scene->currentEvents[i];
422                 if (event->identifierHash == eventIdentifier) {
423                         if (dataOut != NULL) {
424                                 *dataOut = event->data;
425                         }
426                         return true;
427                 }
428         }
429         return false;
430 }
431
432 void bzGameScenePostEvent(BZSceneID scene, BZIdentifierHash eventIdentifier, const BZSceneEventData *data) {
433         bzAssert(scene->nextEnqueuedEvent < kBZScriptingEnvironmentEventCount);
434         BZSceneEvent *event = &scene->enqueuedEvents[scene->nextEnqueuedEvent++];
435         event->identifierHash = eventIdentifier;
436         if (data != NULL) {
437                 event->data = *data;
438         }
439 }
440
441 BZSceneLayer *getLayer(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
442         for (size_t i = 0; i < scene->layerCount; ++i) {
443                 if (scene->layers[i].identifierHash == layerIdentifierHash) {
444                         return &scene->layers[i];
445                 }
446         }
447         return NULL;
448 }
449
450 BZTilemapID bzGameGetSceneLayerTilemap(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
451         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
452         if (layer != NULL) {
453                 return layer->tilemap;
454         } else {
455                 return NULL;
456         }
457 }
458
459 BZDrawQueueID bzGameGetSceneLayerDrawQueue(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
460         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
461         if (layer != NULL) {
462                 return layer->drawQueue;
463         } else {
464                 return NULL;
465         }
466 }
467
468 BZParticleSimulationID bzGameGetSceneLayerParticleSimulation(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
469         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
470         if (layer != NULL) {
471                 return layer->particleSimulation;
472         } else {
473                 return NULL;
474         }
475 }
476
477 BZCollisionSpaceID bzGameGetSceneLayerCollisionSpace(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
478         BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
479         if (layer != NULL) {
480                 return layer->collisionSpace;
481         } else {
482                 return NULL;
483         }
484 }
485
486
487 /*
488 extern void bzGameSceneSetTimeTicksPerSecond(uint8_t tps);
489 extern void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags); // Pause timer on these flags
490 extern float bzGameSceneTime(uint8_t timeIdx);
491
492 void bzGameSceneSetTimeTicksPerSecond(uint8_t tps) {
493         sceneTPS = tps;
494 }
495
496 void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags) {
497         times[timeIdx].pauseFlags = pauseFlags;
498 }
499
500 float bzGameSceneTime(uint8_t timeIdx) {
501         float time = (float)times[timeIdx].ticks / (float)sceneTPS;
502         return time;
503 }
504 */
505
506 //BZAgentSimulationID bzGameGetAgentSimulation(BZSceneID scene) {
507 //      return scene->agentSimulation;
508 //}
509
510 BZAudioPlaybackEngineID bzGameGetAudioPlaybackEngine(BZSceneID scene) {
511         return scene->audioEngine;
512 }
513
514 bool bzScriptingGetEnvironmentPublic(SVMOperand *out, BZSceneID scene, BZIdentifierHash identifierHash) {
515         for (size_t i = 0; i < kBZScriptingEnvironmentPublicCount; ++i) {
516                 if (scene->publics[i].identifierHash == identifierHash) {
517                         if (out != NULL) {
518                                 out->__raw = scene->publics[i].value.__raw;
519                         }
520                         return true;
521                 }
522         }
523         return false;
524 }
525
526 void bzScriptingSetEnvironmentPublic(BZSceneID scene, BZIdentifierHash identifierHash, SVMOperand value) {
527         for (size_t i = 0; i < kBZScriptingEnvironmentPublicCount; ++i) {
528                 if (scene->publics[i].identifierHash == 0) {
529                         scene->publics[i].identifierHash = identifierHash;
530                 }
531                 if (scene->publics[i].identifierHash == identifierHash) {
532                         scene->publics[i].value.__raw = value.__raw;
533                         return;
534                 } 
535         }
536         bzError("Out of globals!!");
537 }
538
539 size_t bzGameGetSceneLayerCount(BZSceneID scene) {
540         return scene->layerCount;
541 }
542
543 BZSceneLayerID bzGameGetSceneLayerAtIndex(BZSceneID scene, size_t idx) {
544         bzAssert(idx < scene->layerCount);
545         return &scene->layers[idx];
546 }
547
548
549 BZCollisionSpaceID bzGameGetSceneLayerCollisionSpace2(BZSceneLayerID layer) {
550         return layer->collisionSpace;
551 }
552
553 BZParticleSimulationID bzGameGetSceneLayerParticleSimulation2(BZSceneLayerID layer) {
554         return layer->particleSimulation;
555 }