forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			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);
 | |
| }
 |