218 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			218 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#include "loader.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <kinc/audio1/sound.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/image.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/io/filereader.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/threads/event.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/threads/mutex.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/threads/thread.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define STB_DS_IMPLEMENTATION
							 | 
						||
| 
								 | 
							
								#include "stb_ds.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <assert.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static kinc_thread_t thread;
							 | 
						||
| 
								 | 
							
								static kinc_event_t event;
							 | 
						||
| 
								 | 
							
								static kinc_mutex_t loading_mutex;
							 | 
						||
| 
								 | 
							
								static kinc_mutex_t loaded_mutex;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static kha_index_t next_index = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static kha_file_reference_t *loading_files = NULL;
							 | 
						||
| 
								 | 
							
								static kha_file_reference_t *loaded_files = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static bool string_ends_with(char *str, const char *end) {
							 | 
						||
| 
								 | 
							
									size_t str_len = strlen(str);
							 | 
						||
| 
								 | 
							
									size_t end_len = strlen(end);
							 | 
						||
| 
								 | 
							
									if (end_len > str_len) {
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return strcmp(&str[str_len - end_len], end) == 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void run(void *param) {
							 | 
						||
| 
								 | 
							
									for (;;) {
							 | 
						||
| 
								 | 
							
										kinc_event_wait(&event);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										bool has_next = false;
							 | 
						||
| 
								 | 
							
										kha_file_reference_t next;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										kinc_mutex_lock(&loading_mutex);
							 | 
						||
| 
								 | 
							
										if (arrlen(loading_files) > 0) {
							 | 
						||
| 
								 | 
							
											has_next = true;
							 | 
						||
| 
								 | 
							
											next = arrpop(loading_files);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											kinc_event_reset(&event);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										kinc_mutex_unlock(&loading_mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										while (has_next) {
							 | 
						||
| 
								 | 
							
											switch (next.type) {
							 | 
						||
| 
								 | 
							
											case KHA_FILE_TYPE_BLOB: {
							 | 
						||
| 
								 | 
							
												kinc_file_reader_t reader;
							 | 
						||
| 
								 | 
							
												if (kinc_file_reader_open(&reader, next.name, KINC_FILE_TYPE_ASSET)) {
							 | 
						||
| 
								 | 
							
													next.data.blob.size = kinc_file_reader_size(&reader);
							 | 
						||
| 
								 | 
							
													next.data.blob.bytes = (uint8_t *)malloc(next.data.blob.size);
							 | 
						||
| 
								 | 
							
													kinc_file_reader_read(&reader, next.data.blob.bytes, next.data.blob.size);
							 | 
						||
| 
								 | 
							
													kinc_file_reader_close(&reader);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												else {
							 | 
						||
| 
								 | 
							
													next.error = true;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											case KHA_FILE_TYPE_IMAGE: {
							 | 
						||
| 
								 | 
							
												kinc_image_t image;
							 | 
						||
| 
								 | 
							
												size_t size = kinc_image_size_from_file(next.name);
							 | 
						||
| 
								 | 
							
												if (size > 0) {
							 | 
						||
| 
								 | 
							
													void *data = malloc(size);
							 | 
						||
| 
								 | 
							
													if (kinc_image_init_from_file(&image, data, next.name) != 0) {
							 | 
						||
| 
								 | 
							
														next.data.image.image = image;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													else {
							 | 
						||
| 
								 | 
							
														free(data);
							 | 
						||
| 
								 | 
							
														next.error = true;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												else {
							 | 
						||
| 
								 | 
							
													next.error = true;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											case KHA_FILE_TYPE_SOUND: {
							 | 
						||
| 
								 | 
							
												memset(&next.data.sound, 0, sizeof(next.data.sound));
							 | 
						||
| 
								 | 
							
												if (string_ends_with(next.name, ".ogg")) {
							 | 
						||
| 
								 | 
							
													kinc_file_reader_t reader;
							 | 
						||
| 
								 | 
							
													if (kinc_file_reader_open(&reader, next.name, KINC_FILE_TYPE_ASSET)) {
							 | 
						||
| 
								 | 
							
														next.data.sound.size = kinc_file_reader_size(&reader);
							 | 
						||
| 
								 | 
							
														next.data.sound.compressed_samples = (uint8_t *)malloc(next.data.sound.size);
							 | 
						||
| 
								 | 
							
														kinc_file_reader_read(&reader, next.data.sound.compressed_samples, kinc_file_reader_size(&reader));
							 | 
						||
| 
								 | 
							
														kinc_file_reader_close(&reader);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													else {
							 | 
						||
| 
								 | 
							
														next.error = true;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												else {
							 | 
						||
| 
								 | 
							
													kinc_a1_sound_t *sound = kinc_a1_sound_create(next.name);
							 | 
						||
| 
								 | 
							
													if (sound != NULL) {
							 | 
						||
| 
								 | 
							
														next.data.sound.size = sound->size * 2;
							 | 
						||
| 
								 | 
							
														next.data.sound.samples = (float *)malloc(next.data.sound.size * sizeof(float));
							 | 
						||
| 
								 | 
							
														for (int i = 0; i < sound->size; ++i) {
							 | 
						||
| 
								 | 
							
															next.data.sound.samples[i * 2 + 0] = (float)(sound->left[i] / 32767.0);
							 | 
						||
| 
								 | 
							
															next.data.sound.samples[i * 2 + 1] = (float)(sound->right[i] / 32767.0);
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
														next.data.sound.channels = sound->format.channels;
							 | 
						||
| 
								 | 
							
														next.data.sound.sample_rate = sound->format.samples_per_second;
							 | 
						||
| 
								 | 
							
														next.data.sound.length =
							 | 
						||
| 
								 | 
							
														    (sound->size / (sound->format.bits_per_sample / 8) / sound->format.channels) / (float)sound->format.samples_per_second;
							 | 
						||
| 
								 | 
							
														kinc_a1_sound_destroy(sound);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													else {
							 | 
						||
| 
								 | 
							
														next.error = true;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											kinc_mutex_lock(&loaded_mutex);
							 | 
						||
| 
								 | 
							
											arrput(loaded_files, next);
							 | 
						||
| 
								 | 
							
											kinc_mutex_unlock(&loaded_mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											has_next = false;
							 | 
						||
| 
								 | 
							
											kinc_mutex_lock(&loading_mutex);
							 | 
						||
| 
								 | 
							
											if (arrlen(loading_files) > 0) {
							 | 
						||
| 
								 | 
							
												has_next = true;
							 | 
						||
| 
								 | 
							
												next = arrpop(loading_files);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else {
							 | 
						||
| 
								 | 
							
												kinc_event_reset(&event);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											kinc_mutex_unlock(&loading_mutex);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void kha_loader_init(void) {
							 | 
						||
| 
								 | 
							
									kinc_mutex_init(&loaded_mutex);
							 | 
						||
| 
								 | 
							
									kinc_mutex_init(&loading_mutex);
							 | 
						||
| 
								 | 
							
									kinc_event_init(&event, false);
							 | 
						||
| 
								 | 
							
									kinc_thread_init(&thread, run, NULL);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								kha_index_t kha_loader_load_blob(const char *filename) {
							 | 
						||
| 
								 | 
							
									assert(strlen(filename) <= KHA_MAX_PATH_LENGTH);
							 | 
						||
| 
								 | 
							
									kha_file_reference_t file;
							 | 
						||
| 
								 | 
							
									memset(&file, 0, sizeof(file));
							 | 
						||
| 
								 | 
							
									file.index = next_index++;
							 | 
						||
| 
								 | 
							
									strcpy(file.name, filename);
							 | 
						||
| 
								 | 
							
									file.type = KHA_FILE_TYPE_BLOB;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_mutex_lock(&loading_mutex);
							 | 
						||
| 
								 | 
							
									arrput(loading_files, file);
							 | 
						||
| 
								 | 
							
									kinc_event_signal(&event);
							 | 
						||
| 
								 | 
							
									kinc_mutex_unlock(&loading_mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return file.index;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								kha_index_t kha_loader_load_image(const char *filename, bool readable) {
							 | 
						||
| 
								 | 
							
									assert(strlen(filename) <= KHA_MAX_PATH_LENGTH);
							 | 
						||
| 
								 | 
							
									kha_file_reference_t file;
							 | 
						||
| 
								 | 
							
									memset(&file, 0, sizeof(file));
							 | 
						||
| 
								 | 
							
									file.index = next_index++;
							 | 
						||
| 
								 | 
							
									strcpy(file.name, filename);
							 | 
						||
| 
								 | 
							
									file.type = KHA_FILE_TYPE_IMAGE;
							 | 
						||
| 
								 | 
							
									file.data.image.readable = readable;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_mutex_lock(&loading_mutex);
							 | 
						||
| 
								 | 
							
									arrput(loading_files, file);
							 | 
						||
| 
								 | 
							
									kinc_event_signal(&event);
							 | 
						||
| 
								 | 
							
									kinc_mutex_unlock(&loading_mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return file.index;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								kha_index_t kha_loader_load_sound(const char *filename) {
							 | 
						||
| 
								 | 
							
									assert(strlen(filename) <= KHA_MAX_PATH_LENGTH);
							 | 
						||
| 
								 | 
							
									kha_file_reference_t file;
							 | 
						||
| 
								 | 
							
									memset(&file, 0, sizeof(file));
							 | 
						||
| 
								 | 
							
									file.index = next_index++;
							 | 
						||
| 
								 | 
							
									strcpy(file.name, filename);
							 | 
						||
| 
								 | 
							
									file.type = KHA_FILE_TYPE_SOUND;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_mutex_lock(&loading_mutex);
							 | 
						||
| 
								 | 
							
									arrput(loading_files, file);
							 | 
						||
| 
								 | 
							
									kinc_event_signal(&event);
							 | 
						||
| 
								 | 
							
									kinc_mutex_unlock(&loading_mutex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return file.index;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								kha_file_reference_t kha_loader_get_file(void) {
							 | 
						||
| 
								 | 
							
									kinc_mutex_lock(&loaded_mutex);
							 | 
						||
| 
								 | 
							
									if (arrlen(loaded_files) > 0) {
							 | 
						||
| 
								 | 
							
										kha_file_reference_t file = arrpop(loaded_files);
							 | 
						||
| 
								 | 
							
										kinc_mutex_unlock(&loaded_mutex);
							 | 
						||
| 
								 | 
							
										return file;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else {
							 | 
						||
| 
								 | 
							
										kinc_mutex_unlock(&loaded_mutex);
							 | 
						||
| 
								 | 
							
										kha_file_reference_t file;
							 | 
						||
| 
								 | 
							
										memset(&file, 0, sizeof(file));
							 | 
						||
| 
								 | 
							
										return file;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void kha_loader_cleanup_blob(kha_blob_t blob) {
							 | 
						||
| 
								 | 
							
									free(blob.bytes);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void kha_loader_cleanup_sound(kha_sound_t sound) {
							 | 
						||
| 
								 | 
							
									// sound.samples is transferred to a Float32Array in LoaderImpl.hx and will go into hxcpp GC
							 | 
						||
| 
								 | 
							
									free(sound.compressed_samples);
							 | 
						||
| 
								 | 
							
								}
							 |