1 #include <bz/game/scene_internal.h>
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>
20 #include <string.h> // strncpy
22 struct BZSceneActorDefinition {
23 //char identifier[kBZMaxIdentifierLength]; // fixme
24 BZIdentifierHash identifierHash;
30 typedef struct BZSceneActorDefinition BZSceneActorDefinition;
32 /*struct BZSceneParticleSystem {
33 char identifier[kBZMaxIdentifierLength]; // fixme
34 BZIdentifierHash identifierHash;
35 BZParticleSystemID particleSystem;
37 typedef struct BZSceneParticleSystem BZSceneParticleSystem;*/
40 char identifier[kBZMaxIdentifierLength]; // fixme
41 BZIdentifierHash identifierHash;
42 BZDrawQueueID drawQueue;
44 BZParticleSimulationID particleSimulation;
45 BZCollisionSpaceID collisionSpace;
46 BZIdentifierHash particleCollisionTagHash;
47 float particleCollisionRadiusMultiplier;
51 ////#define kMaxActorInstances 50//256
55 BZScriptBindingMetadata scriptMetadata;
59 typedef struct BZSceneActor BZSceneActor;
61 #define kBZScriptingEnvironmentPublicCount 256
62 #define kBZScriptingEnvironmentEventCount 256
64 struct BZScriptingEnvironmentPublic {
65 BZIdentifierHash identifierHash;
68 typedef struct BZScriptingEnvironmentPublic BZScriptingEnvironmentPublic;
71 BZIdentifierHash identifierHash;
72 BZSceneEventData data;
74 typedef struct BZSceneEvent BZSceneEvent;
77 // BZScriptingEnvironmentID sceneEnvironment;
78 // BZScriptID sceneScript;
79 // BZScriptBindingMetadata sceneScriptMetadata;
80 // BZScriptInstanceID sceneScriptInstance;
81 BZSceneActorDefinition *actorDefinitions;
82 size_t actorDefinitionCount;
87 int32_t minActorPriority;
88 int32_t maxActorPriority;
90 size_t lastActorIndex;
91 size_t actorInstanceCount;
92 BZSceneActor *actorInstances;
94 BZScriptingEnvironmentPublic publics[kBZScriptingEnvironmentPublicCount];
96 BZAudioPlaybackEngineID audioEngine;
98 // BZAgentSimulationID agentSimulation;
101 BZSceneEvent *currentEvents;
102 size_t nextEnqueuedEvent;
103 BZSceneEvent *enqueuedEvents;
105 // char targetSceneIdentifier[kBZMaxIdentifierLength]; // fixme
108 uint8_t gSystemTicksPerSecond;
110 static void bzGameSceneActorLoadDefinition(BZSceneActorDefinition *definitionOut, BZSceneID scene, BZMemoryArenaID arena, const char *identifierFmt, ...) {
111 bzMakeIdentifier(identifier, identifierFmt);
112 definitionOut->identifierHash = bzIdentifierHashFromIdentifier(identifier);
114 BZResourceID handle = bzResourcesOpenResource("scene", "assets/actors/%s.actor.json", identifier);
115 bzAssertMessage(handle != NULL, "Invalid actor definition '%s'", identifier);
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);
122 //json_set_allocation_functions
123 JSON_Value *actorDefinitionJson = json_parse_string(data);
124 JSON_Object *actorDefinitionJsonObject = json_object(actorDefinitionJson);
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);
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);
136 json_value_free(actorDefinitionJson);
138 bzLog("Opened actor %s", identifier);
141 static BZActorID bzGameSceneSetupActor(BZSceneActor *sceneActor, BZSceneID scene, const BZSceneActorDefinition *definition, const char *identifierFmt, ...) {
142 BZActorID actor = &sceneActor->actor;
143 BZScriptBindingMetadata *metadata = &sceneActor->scriptMetadata;
145 bzInsertIdentifier(actor->identifier, identifierFmt);
146 actor->identifierHash = bzIdentifierHashFromIdentifier(actor->identifier);
148 bzAssertMessage(definition != NULL, "Could not find definition for '%s'", actor->identifier);
150 sceneActor->priority = definition->priority;
152 actor->instance = svnResetModuleInstanceMemory(definition->module, actor->instance, metadata, bzScriptingBindingsLookupNativeFunction);
153 bzScriptingInitialiseMetadata((BZScriptBindingMetadata *)&sceneActor->scriptMetadata, actor, scene, scene->lastActorIndex);
155 sceneActor->running = true;
160 BZSceneID bzGameSceneSwitch(BZMemoryArenaID arena, BZAudioPlaybackEngineID audioEngine, const char *identifierFmt, ...) {
161 bzMakeIdentifier(identifier, identifierFmt);
163 BZSceneID scene = bzMemoryAlloc(arena, sizeof(BZScene));
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);
171 //json_set_allocation_functions
172 JSON_Value *sceneJson = json_parse_string(data);
173 JSON_Object *sceneJsonObject = json_object(sceneJson);
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);
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);
189 const char *fontName = json_object_get_string(sceneJsonObject, "font");
190 BZFont *font = bzGfxLoadFont(arena, fontName); // FIXME, temp arena??
191 bzGfxPrepareFont(arena, font);
193 JSON_Array *actorDefinitionsArray = json_object_get_array(sceneJsonObject, "actors");
194 size_t actorDefinitionsArrayCount = json_array_get_count(actorDefinitionsArray);
195 scene->actorDefinitionCount = actorDefinitionsArrayCount;
197 size_t startDefinition = 0;
198 const char *sceneActorName = json_object_get_string(sceneJsonObject, "scene_actor");
199 if (sceneActorName != NULL) {
200 scene->actorDefinitionCount += 1;
204 scene->actorDefinitions = (BZSceneActorDefinition *)bzMemoryAlloc(arena, scene->actorDefinitionCount * sizeof(BZSceneActorDefinition));
206 size_t maxInstanceSize = 0;
208 if (sceneActorName != NULL) {
209 bzGameSceneActorLoadDefinition(&scene->actorDefinitions[0], scene, arena, "%s", sceneActorName); // fixme
210 maxInstanceSize = scene->actorDefinitions[0].instanceSize;
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);
220 // FIXME, alignment for instance size
222 scene->lastActorIndex = 0;
223 scene->actorInstanceCount = 1024;
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);
230 if (sceneActorName != NULL) {
231 bzGameSceneSetupActor(&scene->actorInstances[0], scene, &scene->actorDefinitions[0], "scene");
234 // int hasAgents = json_object_get_boolean(sceneJsonObject, "agents");
235 // if (hasAgents > 0) {
236 // scene->agentSimulation = bzFXCreateAgentSimulation(arena, scene->actorInstanceCount, "%s.agents", identifier);
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);
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
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);
261 const char *tilemapName = json_object_get_string(layerDefinition, "tilemap");
262 if (tilemapName != NULL) {
263 scene->layers[i].tilemap = bzGameLoadTilemap(arena, "%s", tilemapName);
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);
271 scene->layers[i].collisionSpace = bzCollisionMakeSpace(arena, 1024, "%s.particle.collision", scene->layers[i].identifier);
273 if (json_object_has_value_of_type(layerDefinition, "collision-radius", JSONNumber)) {
274 scene->layers[i].particleCollisionRadiusMultiplier = json_object_get_number(layerDefinition, "collision-radius");
276 scene->layers[i].particleCollisionRadiusMultiplier = 1.0f;
278 scene->layers[i].particleCollisionTagHash = bzIdentifierHashFromIdentifier(particleSystemName);
283 scene->currentEvents = bzMemoryAlloc(arena, kBZScriptingEnvironmentEventCount * sizeof(BZSceneEvent));
284 scene->enqueuedEvents = bzMemoryAlloc(arena, kBZScriptingEnvironmentEventCount * sizeof(BZSceneEvent));
286 json_value_free(sceneJson);
288 bzLog("Opened scene %s", identifier);
293 bool bzGameSceneUpdate(BZSceneID scene, uint8_t pauseFlags, uint8_t systemTicks) {
294 float deltaTime = (float)systemTicks / (float)gSystemTicksPerSecond;
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);
301 if (layer->collisionSpace != NULL) {
302 bzCollisionResetSpace(layer->collisionSpace);
306 // if (scene->agentSimulation != NULL) {
307 // SVMOperand playerX;
308 // bzScriptingGetEnvironmentPublic(&playerX, scene, bzIdentifierHashFromIdentifier("shipX"));
310 // SVMOperand playerY;
311 // bzScriptingGetEnvironmentPublic(&playerY, scene, bzIdentifierHashFromIdentifier("shipY"));
313 // BZVector playerPos = bzVectorMake(FIXED_TO_FLOAT(playerX.floatLiteral), FIXED_TO_FLOAT(playerY.floatLiteral));
315 // bzFXUpdateAgentSimulation(scene->agentSimulation, deltaTime, NULL, &playerPos);
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);
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);
338 scene->ticks += systemTicks;
340 scene->eventCount = scene->nextEnqueuedEvent;
341 scene->nextEnqueuedEvent = 0;
343 BZSceneEvent *tmp = scene->currentEvents;
344 scene->currentEvents = scene->enqueuedEvents;
345 scene->enqueuedEvents = tmp;
347 return scene->actorInstances[0].running;
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);
356 bzGfxDrawQueueRun(scene->layers[i].drawQueue);
359 //if (scene->layers[i].collisionSpace != NULL) {
360 // bzCollisionDrawDebug(scene->layers[i].collisionSpace);
363 // if (i == 3 && scene->agentSimulation != NULL) { // FIXME
364 // bzFXAgentSimulationDrawDebug(scene->agentSimulation);
371 BZActorID bzGameSceneAddActor(BZSceneID scene, const char *identifierFmt, ...) {
372 bzMakeIdentifier(identifier, identifierFmt);
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];
382 bzAssertMessage(definition != NULL, "Undefined actor '%s'", identifier);
384 BZSceneActor *sceneActor = NULL;
385 for (size_t i = 0; i < scene->actorInstanceCount; ++i) {
386 ++scene->lastActorIndex;
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];
394 bzAssertMessage(sceneActor != NULL, "Out of actors");
396 definition->spawnCount += 1;
398 return bzGameSceneSetupActor(sceneActor, scene, definition, "%s-%u", identifier, definition->spawnCount);
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;
412 float bzGameSceneGetTime(BZSceneID scene) {
413 float time = (float)scene->ticks / (float)gSystemTicksPerSecond;
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;
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;
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];
448 BZTilemapID bzGameGetSceneLayerTilemap(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
449 BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
451 return layer->tilemap;
457 BZDrawQueueID bzGameGetSceneLayerDrawQueue(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
458 BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
460 return layer->drawQueue;
466 BZParticleSimulationID bzGameGetSceneLayerParticleSimulation(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
467 BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
469 return layer->particleSimulation;
475 BZCollisionSpaceID bzGameGetSceneLayerCollisionSpace(BZSceneID scene, BZIdentifierHash layerIdentifierHash) {
476 BZSceneLayer *layer = getLayer(scene, layerIdentifierHash);
478 return layer->collisionSpace;
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);
490 void bzGameSceneSetTimeTicksPerSecond(uint8_t tps) {
494 void bzGameSceneSetTimePauseFlags(uint8_t timeIdx, uint8_t pauseFlags) {
495 times[timeIdx].pauseFlags = pauseFlags;
498 float bzGameSceneTime(uint8_t timeIdx) {
499 float time = (float)times[timeIdx].ticks / (float)sceneTPS;
504 //BZAgentSimulationID bzGameGetAgentSimulation(BZSceneID scene) {
505 // return scene->agentSimulation;
508 BZAudioPlaybackEngineID bzGameGetAudioPlaybackEngine(BZSceneID scene) {
509 return scene->audioEngine;
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) {
516 out->__raw = scene->publics[i].value.__raw;
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;
529 if (scene->publics[i].identifierHash == identifierHash) {
530 scene->publics[i].value.__raw = value.__raw;
534 bzError("Out of globals!!");
537 size_t bzGameGetSceneLayerCount(BZSceneID scene) {
538 return scene->layerCount;
541 BZSceneLayerID bzGameGetSceneLayerAtIndex(BZSceneID scene, size_t idx) {
542 bzAssert(idx < scene->layerCount);
543 return &scene->layers[idx];
547 BZCollisionSpaceID bzGameGetSceneLayerCollisionSpace2(BZSceneLayerID layer) {
548 return layer->collisionSpace;
551 BZParticleSimulationID bzGameGetSceneLayerParticleSimulation2(BZSceneLayerID layer) {
552 return layer->particleSimulation;