Tidy up footprint of app libray
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							parent
							
								
									cf8124eb20
								
							
						
					
					
						commit
						ba5bc0674c
					
				
							
								
								
									
										529
									
								
								source/app.cpp
									
									
									
									
									
								
							
							
						
						
									
										529
									
								
								source/app.cpp
									
									
									
									
									
								
							| @ -12,270 +12,213 @@ import coral.math; | |||||||
| 
 | 
 | ||||||
| import oar; | import oar; | ||||||
| 
 | 
 | ||||||
| namespace app { | using native_path = coral::fixed_buffer<4096>; | ||||||
| 	struct directory : public coral::fs { |  | ||||||
| 		struct rules { |  | ||||||
| 			bool can_read; |  | ||||||
| 
 | 
 | ||||||
| 			bool can_write; | struct native_file : public coral::file_reader, public coral::file_writer { | ||||||
| 		}; | 	enum class open_mode { | ||||||
| 
 | 		read_only, | ||||||
| 		virtual rules access_rules() const = 0; | 		overwrite, | ||||||
| 
 |  | ||||||
| 		virtual coral::slice<char const> native_path() const = 0; |  | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct file : public coral::file_reader, public coral::file_writer { | 	enum class [[nodiscard]] close_result { | ||||||
| 		enum class open_mode { | 		ok, | ||||||
| 			read_only, | 		io_unavailable, | ||||||
| 			overwrite, |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		enum class [[nodiscard]] close_result { |  | ||||||
| 			ok, |  | ||||||
| 			io_unavailable, |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		enum class [[nodiscard]] open_result { |  | ||||||
| 			ok, |  | ||||||
| 			io_unavailable, |  | ||||||
| 			access_denied, |  | ||||||
| 			not_found, |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		file(directory * file_directory) : rw_ops{nullptr} { |  | ||||||
| 			this->file_directory = file_directory; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		close_result close() { |  | ||||||
| 			if (::SDL_RWclose(this->rw_ops) != 0) return close_result::io_unavailable; |  | ||||||
| 
 |  | ||||||
| 			this->rw_ops = nullptr; |  | ||||||
| 
 |  | ||||||
| 			return close_result::ok; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		bool is_open() const { |  | ||||||
| 			return this->rw_ops != nullptr; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		open_result open(coral::path const & file_path, open_mode mode) { |  | ||||||
| 			if (this->is_open()) switch (this->close()) { |  | ||||||
| 				case close_result::ok: break; |  | ||||||
| 				case close_result::io_unavailable: return open_result::io_unavailable; |  | ||||||
| 				default: coral::unreachable(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// Windows system path max is something like 512 bytes (depending on the version) and
 |  | ||||||
| 			// on Linux it's 4096.
 |  | ||||||
| 			coral::fixed_buffer<4096> path_buffer{0}; |  | ||||||
| 
 |  | ||||||
| 			if (!path_buffer.write(this->file_directory->native_path().as_bytes()).is_ok()) |  | ||||||
| 				// What kind of directory path is being used that would be longer than 4096 bytes?
 |  | ||||||
| 				return open_result::not_found; |  | ||||||
| 
 |  | ||||||
| 			if (!path_buffer.write(file_path.as_slice().as_bytes()).is_ok()) |  | ||||||
| 				// This happening is still implausible but slightly more reasonable?
 |  | ||||||
| 				return open_result::not_found; |  | ||||||
| 
 |  | ||||||
| 			// No room for zero terminator.
 |  | ||||||
| 			if (path_buffer.is_full()) return open_result::not_found; |  | ||||||
| 
 |  | ||||||
| 			switch (mode) { |  | ||||||
| 				case open_mode::read_only: { |  | ||||||
| 					if (!this->file_directory->access_rules().can_read) |  | ||||||
| 						return open_result::access_denied; |  | ||||||
| 
 |  | ||||||
| 					this->rw_ops = ::SDL_RWFromFile( |  | ||||||
| 						reinterpret_cast<char const *>(path_buffer.begin()), "rb"); |  | ||||||
| 
 |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				case open_mode::overwrite: { |  | ||||||
| 					if (!this->file_directory->access_rules().can_write) |  | ||||||
| 						return open_result::access_denied; |  | ||||||
| 
 |  | ||||||
| 					this->rw_ops = ::SDL_RWFromFile( |  | ||||||
| 						reinterpret_cast<char const *>(path_buffer.begin()), "wb"); |  | ||||||
| 
 |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				default: coral::unreachable(); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (this->rw_ops == nullptr) return open_result::not_found; |  | ||||||
| 
 |  | ||||||
| 			return open_result::ok; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & data) override { |  | ||||||
| 			if (!this->is_open()) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			coral::usize const data_read{::SDL_RWread(this->rw_ops, data.pointer, sizeof(uint8_t), data.length)}; |  | ||||||
| 
 |  | ||||||
| 			if ((data_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			return data_read; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override { |  | ||||||
| 			if (!this->is_open()) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			// TODO: Fix cast.
 |  | ||||||
| 			coral::i64 const byte_position{ |  | ||||||
| 				::SDL_RWseek(this->rw_ops, static_cast<coral::i64>(offset), RW_SEEK_SET)}; |  | ||||||
| 
 |  | ||||||
| 			if (byte_position == -1) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			return static_cast<coral::u64>(byte_position); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		coral::expected<coral::u64, coral::io_error> tell() override { |  | ||||||
| 			if (!this->is_open()) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			coral::i64 const byte_position{::SDL_RWseek(this->rw_ops, 0, RW_SEEK_SET)}; |  | ||||||
| 
 |  | ||||||
| 			if (byte_position == -1) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			return static_cast<coral::u64>(byte_position); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		coral::expected<coral::usize, coral::io_error> write(coral::slice<coral::u8 const> const & data) override { |  | ||||||
| 			if (!this->is_open()) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			coral::usize const data_written{::SDL_RWwrite(this->rw_ops, data.pointer, sizeof(uint8_t), data.length)}; |  | ||||||
| 
 |  | ||||||
| 			if ((data_written == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable; |  | ||||||
| 
 |  | ||||||
| 			return data_written; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		private: |  | ||||||
| 		directory * file_directory; |  | ||||||
| 
 |  | ||||||
| 		::SDL_RWops * rw_ops; |  | ||||||
| 	}; | 	}; | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| struct base_directory : public app::directory { | 	enum class [[nodiscard]] open_result { | ||||||
| 	base_directory() : directory_path{} { | 		ok, | ||||||
| 		char * const path{::SDL_GetBasePath()}; | 		io_unavailable, | ||||||
|  | 		access_denied, | ||||||
|  | 		not_found, | ||||||
|  | 	}; | ||||||
| 
 | 
 | ||||||
| 		if (path == nullptr) return; | 	native_file() = default; | ||||||
| 
 | 
 | ||||||
| 		coral::usize path_length{0}; | 	close_result close() { | ||||||
|  | 		if (SDL_RWclose(this->rw_ops) != 0) return close_result::io_unavailable; | ||||||
| 
 | 
 | ||||||
| 		while (path[path_length] != 0) path_length += 1; | 		this->rw_ops = nullptr; | ||||||
| 
 | 
 | ||||||
| 		if (path_length == 0) { | 		return close_result::ok; | ||||||
| 			::SDL_free(path); | 	} | ||||||
| 
 | 
 | ||||||
| 			return; | 	bool is_open() const { | ||||||
|  | 		return this->rw_ops != nullptr; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	open_result open(native_path const & file_path, open_mode mode) { | ||||||
|  | 		if (this->is_open()) switch (this->close()) { | ||||||
|  | 			case close_result::ok: break; | ||||||
|  | 			case close_result::io_unavailable: return open_result::io_unavailable; | ||||||
|  | 			default: coral::unreachable(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		this->directory_path = {path, path_length}; | 		// No room for zero terminator.
 | ||||||
|  | 		if (file_path.is_full()) return open_result::not_found; | ||||||
|  | 
 | ||||||
|  | 		switch (mode) { | ||||||
|  | 			case open_mode::read_only: { | ||||||
|  | 				this->rw_ops = SDL_RWFromFile(file_path.as_slice().as_chars().begin(), "rb"); | ||||||
|  | 
 | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			case open_mode::overwrite: { | ||||||
|  | 				this->rw_ops = SDL_RWFromFile(file_path.as_slice().as_chars().begin(), "wb"); | ||||||
|  | 
 | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			default: coral::unreachable(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (this->rw_ops == nullptr) return open_result::not_found; | ||||||
|  | 
 | ||||||
|  | 		return open_result::ok; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	~base_directory() override { | 	coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & data) override { | ||||||
| 		::SDL_free(this->directory_path.begin()); | 		if (!this->is_open()) return coral::io_error::unavailable; | ||||||
|  | 
 | ||||||
|  | 		coral::usize const data_read{SDL_RWread(this->rw_ops, data.pointer, sizeof(uint8_t), data.length)}; | ||||||
|  | 
 | ||||||
|  | 		if ((data_read == 0) && (SDL_GetError() != nullptr)) return coral::io_error::unavailable; | ||||||
|  | 
 | ||||||
|  | 		return data_read; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rules access_rules() const override { | 	coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override { | ||||||
| 		return { | 		if (!this->is_open()) return coral::io_error::unavailable; | ||||||
| 			.can_read = true, | 
 | ||||||
| 			.can_write = false, | 		// TODO: Fix cast.
 | ||||||
| 		}; | 		coral::i64 const byte_position{ | ||||||
|  | 			SDL_RWseek(this->rw_ops, static_cast<coral::i64>(offset), RW_SEEK_SET)}; | ||||||
|  | 
 | ||||||
|  | 		if (byte_position == -1) return coral::io_error::unavailable; | ||||||
|  | 
 | ||||||
|  | 		return static_cast<coral::u64>(byte_position); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	coral::slice<const char> native_path() const override { | 	coral::expected<coral::u64, coral::io_error> tell() override { | ||||||
| 		return this->directory_path; | 		if (!this->is_open()) return coral::io_error::unavailable; | ||||||
|  | 
 | ||||||
|  | 		coral::i64 const byte_position{SDL_RWseek(this->rw_ops, 0, RW_SEEK_SET)}; | ||||||
|  | 
 | ||||||
|  | 		if (byte_position == -1) return coral::io_error::unavailable; | ||||||
|  | 
 | ||||||
|  | 		return static_cast<coral::u64>(byte_position); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override { | 	coral::expected<coral::usize, coral::io_error> write(coral::slice<coral::u8 const> const & data) override { | ||||||
| 		if (this->directory_path.length == 0) return; | 		if (!this->is_open()) return coral::io_error::unavailable; | ||||||
| 
 | 
 | ||||||
| 		app::file file{this}; | 		coral::usize const data_written{SDL_RWwrite(this->rw_ops, data.pointer, sizeof(uint8_t), data.length)}; | ||||||
| 
 | 
 | ||||||
| 		if (file.open(file_path, app::file::open_mode::read_only) != app::file::open_result::ok) | 		if ((data_written == 0) && (SDL_GetError() != nullptr)) return coral::io_error::unavailable; | ||||||
| 			return; |  | ||||||
| 
 | 
 | ||||||
| 		then(file); | 		return data_written; | ||||||
| 
 |  | ||||||
| 		if (file.close() != app::file::close_result::ok) return; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override { | 	private: | ||||||
| 		// Directory is read-only.
 | 	SDL_RWops * rw_ops{nullptr}; | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	protected: |  | ||||||
| 	coral::slice<char> directory_path; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct user_directory : public app::directory { | struct sandboxed_fs : public coral::fs { | ||||||
| 	user_directory(coral::path const & title) : directory_path{} { | 	sandboxed_fs() { | ||||||
| 		char * const path{::SDL_GetPrefPath("ona", title.begin())}; | 		char * const path{SDL_GetBasePath()}; | ||||||
| 
 | 
 | ||||||
| 		if (path == nullptr) return; | 		if (path == nullptr) return; | ||||||
| 
 | 
 | ||||||
| 		coral::usize path_length{0}; | 		for (coral::usize index = 0; path[index] != 0; index += 1) | ||||||
|  | 			this->sandbox_path.put(path[index]); | ||||||
| 
 | 
 | ||||||
| 		while (path[path_length] != 0) path_length += 1; | 		SDL_free(path); | ||||||
| 
 | 
 | ||||||
| 		if (path_length == 0) { | 		this->access_rules.can_read = true; | ||||||
| 			::SDL_free(path); |  | ||||||
| 
 |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		this->directory_path = {path, path_length}; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	~user_directory() override { | 	sandboxed_fs(coral::path const & organization_name, coral::path const & app_name) { | ||||||
| 		::SDL_free(this->directory_path.begin()); | 		char * const path{SDL_GetPrefPath(organization_name.begin(), app_name.begin())}; | ||||||
|  | 
 | ||||||
|  | 		if (path == nullptr) return; | ||||||
|  | 
 | ||||||
|  | 		for (coral::usize index = 0; path[index] != 0; index += 1) | ||||||
|  | 			this->sandbox_path.put(path[index]); | ||||||
|  | 
 | ||||||
|  | 		SDL_free(path); | ||||||
|  | 
 | ||||||
|  | 		this->access_rules.can_read = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rules access_rules() const override { | 	access_rules query_access() override { | ||||||
| 		return { | 		return this->access_rules; | ||||||
| 			.can_read = true, |  | ||||||
| 			.can_write = false, |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	coral::slice<const char> native_path() const override { |  | ||||||
| 		return this->directory_path; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override { | 	void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override { | ||||||
| 		if (this->directory_path.length == 0) return; | 		if (!this->access_rules.can_read) return; | ||||||
| 
 | 
 | ||||||
| 		app::file file{this}; | 		native_path sandbox_file_path{0}; | ||||||
|  | 		{ | ||||||
|  | 			coral::expected const written = sandbox_file_path.write(this->sandbox_path.as_slice()); | ||||||
| 
 | 
 | ||||||
| 		if (file.open(file_path, app::file::open_mode::read_only) != app::file::open_result::ok) | 			if (!written.is_ok() || (written.value() != this->sandbox_path.count())) return; | ||||||
| 			return; | 		} | ||||||
|  | 
 | ||||||
|  | 		{ | ||||||
|  | 			coral::expected const written = | ||||||
|  | 				sandbox_file_path.write(file_path.as_slice().as_bytes()); | ||||||
|  | 
 | ||||||
|  | 			if (!written.is_ok() || (written.value() != this->sandbox_path.count())) return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		native_file file; | ||||||
|  | 
 | ||||||
|  | 		if (file.open(sandbox_file_path, native_file::open_mode::read_only) != | ||||||
|  | 			native_file::open_result::ok) return; | ||||||
| 
 | 
 | ||||||
| 		then(file); | 		then(file); | ||||||
| 
 | 
 | ||||||
| 		if (file.close() != app::file::close_result::ok) return; | 		if (file.close() != native_file::close_result::ok) | ||||||
|  | 			// Error orphaned file handle!
 | ||||||
|  | 			return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override { | 	void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override { | ||||||
| 		if (this->directory_path.length == 0) return; | 		if (!this->access_rules.can_write) return; | ||||||
| 
 | 
 | ||||||
| 		app::file file{this}; | 		native_path sandbox_file_path{0}; | ||||||
|  | 		{ | ||||||
|  | 			coral::expected const written = sandbox_file_path.write(this->sandbox_path.as_slice()); | ||||||
| 
 | 
 | ||||||
| 		if (file.open(file_path, app::file::open_mode::overwrite) != app::file::open_result::ok) | 			if (!written.is_ok() || (written.value() != this->sandbox_path.count())) return; | ||||||
| 			return; | 		} | ||||||
|  | 
 | ||||||
|  | 		{ | ||||||
|  | 			coral::expected const written = | ||||||
|  | 				sandbox_file_path.write(file_path.as_slice().as_bytes()); | ||||||
|  | 
 | ||||||
|  | 			if (!written.is_ok() || (written.value() != this->sandbox_path.count())) return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		native_file file; | ||||||
|  | 
 | ||||||
|  | 		if (file.open(sandbox_file_path, native_file::open_mode::overwrite) != | ||||||
|  | 			native_file::open_result::ok) return; | ||||||
| 
 | 
 | ||||||
| 		then(file); | 		then(file); | ||||||
| 
 | 
 | ||||||
| 		if (file.close() != app::file::close_result::ok) return; | 		if (file.close() != native_file::close_result::ok) | ||||||
|  | 			// Error orphaned file handle!
 | ||||||
|  | 			return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	protected: | 	private: | ||||||
| 	coral::slice<char> directory_path; | 	native_path sandbox_path{0}; | ||||||
|  | 
 | ||||||
|  | 	access_rules access_rules{ | ||||||
|  | 		.can_read = false, | ||||||
|  | 		.can_write = false, | ||||||
|  | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export namespace app { | export namespace app { | ||||||
| @ -285,17 +228,27 @@ export namespace app { | |||||||
| 		error, | 		error, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	struct system { | 	struct client { | ||||||
| 		system(coral::path const & title) : user_directory{title}, | 		coral::fs & base() { | ||||||
| 			res_archive{&base_directory, res_archive_path} {} | 			return this->base_sandbox; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		app::directory & base_dir() { | 		void display(coral::u16 screen_width, coral::u16 screen_height) { | ||||||
| 			return this->base_directory; | 			SDL_SetWindowSize(this->window, screen_width, screen_height); | ||||||
|  | 			SDL_ShowWindow(this->window); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		void log(log_level level, coral::slice<char const> const & message) { | ||||||
|  | 			coral::i32 const length{static_cast<coral::i32>( | ||||||
|  | 				coral::min(message.length, static_cast<size_t>(coral::i32_max)))}; | ||||||
|  | 
 | ||||||
|  | 			SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, | ||||||
|  | 				SDL_LOG_PRIORITY_INFO, "%.*s", length, message.pointer); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		bool poll() { | 		bool poll() { | ||||||
| 			while (::SDL_PollEvent(&this->sdl_event) != 0) { | 			while (SDL_PollEvent(&this->event) != 0) { | ||||||
| 				switch (this->sdl_event.type) { | 				switch (this->event.type) { | ||||||
| 					case SDL_QUIT: return false; | 					case SDL_QUIT: return false; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @ -303,124 +256,62 @@ export namespace app { | |||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		coral::fs & res_fs() { | 		coral::fs & resources() { | ||||||
| 			return this->res_archive; | 			return this->resources_archive; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		void log(app::log_level level, coral::slice<char const> const & message) { | 		static int run(coral::path const & title, coral::callable<int(client &)> const & start) { | ||||||
| 			coral::i32 const length{static_cast<coral::i32>( | 			constexpr int windowpos {SDL_WINDOWPOS_UNDEFINED}; | ||||||
| 				coral::min(message.length, static_cast<size_t>(coral::i32_max)))}; | 			constexpr coral::u32 windowflags {SDL_WINDOW_HIDDEN}; | ||||||
|  | 			constexpr int window_width {640}; | ||||||
|  | 			constexpr int window_height {480}; | ||||||
| 
 | 
 | ||||||
| 			::SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, | 			SDL_Window * const window {SDL_CreateWindow( | ||||||
| 				SDL_LOG_PRIORITY_INFO, "%.*s", length, message.pointer); | 				title.begin(), windowpos, windowpos, window_width, window_height, windowflags)}; | ||||||
|  | 
 | ||||||
|  | 			if (window == nullptr) return 0xff; | ||||||
|  | 
 | ||||||
|  | 			struct : public coral::allocator { | ||||||
|  | 				coral::u8 * reallocate(coral::u8 * allocation, coral::usize requested_size) override { | ||||||
|  | 					return reinterpret_cast<coral::u8 *>(SDL_realloc(allocation, requested_size)); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				void deallocate(void * allocation) override { | ||||||
|  | 					SDL_free(allocation); | ||||||
|  | 				} | ||||||
|  | 			} allocator; | ||||||
|  | 
 | ||||||
|  | 			client app_client {&allocator, window, title}; | ||||||
|  | 
 | ||||||
|  | 			return start(app_client); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		coral::allocator & thread_safe_allocator() { | 		coral::allocator & thread_safe_allocator() { | ||||||
| 			return this->allocator; | 			return *this->allocator; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		app::directory & user_dir() { | 		coral::fs & user() { | ||||||
| 			return this->user_directory; | 			return this->user_sandbox; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		private: | 		private: | ||||||
| 		static constexpr coral::path res_archive_path{"base.oar"}; | 		client(coral::allocator * allocator, SDL_Window * window, | ||||||
|  | 			coral::path const & title) : user_sandbox{"ona", title} { | ||||||
| 
 | 
 | ||||||
| 		::SDL_Event sdl_event; | 			this->allocator = allocator; | ||||||
|  | 			this->window = window; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		struct : public coral::allocator { | 		coral::allocator * allocator; | ||||||
| 			coral::u8 * reallocate(coral::u8 * maybe_allocation, coral::usize requested_size) override { |  | ||||||
| 				return reinterpret_cast<coral::u8 *>(::SDL_malloc(requested_size)); |  | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			void deallocate(void * allocation) override { | 		SDL_Window * window; | ||||||
| 				::SDL_free(allocation); |  | ||||||
| 			} |  | ||||||
| 		} allocator; |  | ||||||
| 
 | 
 | ||||||
| 		struct base_directory base_directory; | 		SDL_Event event; | ||||||
| 
 | 
 | ||||||
| 		struct user_directory user_directory; | 		sandboxed_fs base_sandbox; | ||||||
| 
 | 
 | ||||||
| 		oar::archive res_archive; | 		sandboxed_fs user_sandbox; | ||||||
|  | 
 | ||||||
|  | 		oar::archive resources_archive{&base_sandbox, "base.oar"}; | ||||||
| 	}; | 	}; | ||||||
| 
 |  | ||||||
| 	struct graphics { |  | ||||||
| 		enum class [[nodiscard]] show_result { |  | ||||||
| 			ok, |  | ||||||
| 			out_of_memory, |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		struct canvas { |  | ||||||
| 			coral::color background_color; |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		graphics(coral::path const & title) { |  | ||||||
| 			this->retitle(title); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		void present() { |  | ||||||
| 			if (this->sdl_renderer != nullptr) { |  | ||||||
| 				::SDL_RenderPresent(this->sdl_renderer); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		void render(canvas & source_canvas) { |  | ||||||
| 			if (this->sdl_renderer != nullptr) { |  | ||||||
| 				SDL_SetRenderDrawColor(this->sdl_renderer, source_canvas.background_color.to_r8(), |  | ||||||
| 					source_canvas.background_color.to_g8(), source_canvas.background_color.to_b8(), |  | ||||||
| 						source_canvas.background_color.to_a8()); |  | ||||||
| 
 |  | ||||||
| 				SDL_RenderClear(this->sdl_renderer); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		void retitle(coral::path const & title) { |  | ||||||
| 			this->title = title; |  | ||||||
| 
 |  | ||||||
| 			if (this->sdl_window != nullptr) |  | ||||||
| 				::SDL_SetWindowTitle(this->sdl_window, this->title.begin()); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		show_result show(coral::u16 physical_width, coral::u16 physical_height) { |  | ||||||
| 			if (this->sdl_window == nullptr) { |  | ||||||
| 				constexpr int sdl_windowpos = SDL_WINDOWPOS_UNDEFINED; |  | ||||||
| 				constexpr coral::u32 sdl_windowflags = 0; |  | ||||||
| 
 |  | ||||||
| 				this->sdl_window = ::SDL_CreateWindow(this->title.begin(), sdl_windowpos, |  | ||||||
| 					sdl_windowpos, static_cast<int>(physical_width), static_cast<int>(physical_height), |  | ||||||
| 						sdl_windowflags); |  | ||||||
| 
 |  | ||||||
| 				if (this->sdl_window == nullptr) return show_result::out_of_memory; |  | ||||||
| 			} else { |  | ||||||
| 				::SDL_ShowWindow(this->sdl_window); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (this->sdl_renderer == nullptr) { |  | ||||||
| 				constexpr coral::u32 sdl_rendererflags = 0; |  | ||||||
| 
 |  | ||||||
| 				this->sdl_renderer = ::SDL_CreateRenderer(this->sdl_window, -1, sdl_rendererflags); |  | ||||||
| 
 |  | ||||||
| 				if (this->sdl_renderer == nullptr) return show_result::out_of_memory; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return show_result::ok; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		private: |  | ||||||
| 		coral::path title; |  | ||||||
| 
 |  | ||||||
| 		::SDL_Window * sdl_window = nullptr; |  | ||||||
| 
 |  | ||||||
| 		::SDL_Renderer * sdl_renderer = nullptr; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	using graphical_runnable = coral::callable<int(system &, graphics &)>; |  | ||||||
| 
 |  | ||||||
| 	int display(coral::path const & title, graphical_runnable const & run) { |  | ||||||
| 		system app_system{title}; |  | ||||||
| 		graphics app_graphics{title}; |  | ||||||
| 
 |  | ||||||
| 		return run(app_system, app_graphics); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -171,6 +171,13 @@ export namespace oar { | |||||||
| 			this->archive_path = archive_path; | 			this->archive_path = archive_path; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		access_rules query_access() override { | ||||||
|  | 			return { | ||||||
|  | 				.can_read = true, | ||||||
|  | 				.can_write = false, | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		void read_file(coral::path const & file_path, | 		void read_file(coral::path const & file_path, | ||||||
| 			coral::callable<void(coral::file_reader &)> const & then) override { | 			coral::callable<void(coral::file_reader &)> const & then) override { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,12 +9,12 @@ import coral.math; | |||||||
| import coral.sequence; | import coral.sequence; | ||||||
| 
 | 
 | ||||||
| extern "C" int main(int argc, char const * const * argv) { | extern "C" int main(int argc, char const * const * argv) { | ||||||
| 	return app::display("Ona Runtime", [](app::system & system, app::graphics & graphics) -> int { | 	return app::client::run("Ona Runtime", [](app::client & client) -> int { | ||||||
| 		constexpr coral::path config_path{"config.kym"}; | 		constexpr coral::path config_path{"config.kym"}; | ||||||
| 		bool is_config_loaded{false}; | 		bool is_config_loaded{false}; | ||||||
| 
 | 
 | ||||||
| 		system.res_fs().read_file(config_path, [&](coral::reader & file) { | 		client.resources().read_file(config_path, [&](coral::reader & file) { | ||||||
| 			coral::allocator * const allocator{&system.thread_safe_allocator()}; | 			coral::allocator * const allocator{&client.thread_safe_allocator()}; | ||||||
| 
 | 
 | ||||||
| 			coral::stack<coral::u8> script_source{allocator}; | 			coral::stack<coral::u8> script_source{allocator}; | ||||||
| 			{ | 			{ | ||||||
| @ -24,13 +24,13 @@ extern "C" int main(int argc, char const * const * argv) { | |||||||
| 				if (!coral::stream(script_writer, file, stream_buffer).is_ok()) return; | 				if (!coral::stream(script_writer, file, stream_buffer).is_ok()) return; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			system.log(app::log_level::notice, script_source.as_slice().as_chars()); | 			client.log(app::log_level::notice, script_source.as_slice().as_chars()); | ||||||
| 
 | 
 | ||||||
| 			is_config_loaded = true; | 			is_config_loaded = true; | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		if (!is_config_loaded) { | 		if (!is_config_loaded) { | ||||||
| 			coral::stack<coral::u8> error_message{&system.thread_safe_allocator()}; | 			coral::stack<coral::u8> error_message{&client.thread_safe_allocator()}; | ||||||
| 			{ | 			{ | ||||||
| 				coral::contiguous_writer error_writer{&error_message}; | 				coral::contiguous_writer error_writer{&error_message}; | ||||||
| 
 | 
 | ||||||
| @ -44,11 +44,10 @@ extern "C" int main(int argc, char const * const * argv) { | |||||||
| 			return coral::u8_max; | 			return coral::u8_max; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// app::canvas canvas_2d();
 | 		client.display(1280, 800); | ||||||
|  | 
 | ||||||
|  | 		while (client.poll()) { | ||||||
| 
 | 
 | ||||||
| 		while (system.poll()) { |  | ||||||
| 			// canvas_2d.render(graphics);
 |  | ||||||
| 			graphics.present(); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return 0; | 		return 0; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user