bug fixes, improved input handling and started testing with typing mode

This commit is contained in:
Dennis Eichhorn 2025-01-11 01:26:44 +01:00
parent 2ecb47117b
commit a02963607d
61 changed files with 949 additions and 755 deletions

View File

@ -10,8 +10,8 @@
#ifndef TOS_ANIMATION_H
#define TOS_ANIMATION_H
#include <math.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
#include "AnimationEaseType.h"

View File

@ -165,6 +165,11 @@ void asset_archive_load(AssetArchive* archive, const char* path, BufferMemory* b
file.content = ring_get_memory(ring, file.size);
file_read(archive->fd, &file, 0, file.size);
asset_archive_header_load(&archive->header, file.content, steps);
LOG_LEVEL_2(
"Loaded AssetArchive %s with %d assets",
{{LOG_DATA_CHAR_STR, (void *) path}, {LOG_DATA_UINT32, (void *) &archive->header.asset_count}}
);
}
// @question Do we want to allow a callback function?
@ -294,6 +299,11 @@ Asset* asset_archive_asset_load(const AssetArchive* archive, int32 id, AssetMana
// the main program should still be able to do some work if possible
thrd_ams_set_loaded(asset);
LOG_LEVEL_2(
"Asset %d loaded from archive %d for AMS %d with %n B compressed and %n B uncompressed",
{{LOG_DATA_UINT64, &id}, {LOG_DATA_UINT32, &element->type}, {LOG_DATA_BYTE, &component_id}, {LOG_DATA_UINT32, &element->length}, {LOG_DATA_UINT32, &element->uncompressed}}
);
// @performance maybe do in worker threads? This just feels very slow
// @bug dependencies might be stored in different archives?
for (uint32 i = 0; i < element->dependency_count; ++i) {

View File

@ -45,6 +45,8 @@ void ams_create(AssetManagementSystem* ams, BufferMemory* buf, int32 asset_compo
hashmap_create(&ams->hash_map, count, sizeof(HashEntry) + sizeof(Asset), buf);
ams->asset_component_count = asset_component_count;
ams->asset_components = (AssetComponent *) buffer_get_memory(buf, asset_component_count * sizeof(AssetComponent), 64, true);
LOG_LEVEL_2("Created AMS for %n assets", {{LOG_DATA_INT32, &count}});
}
inline
@ -54,6 +56,8 @@ void ams_component_create(AssetComponent* ac, BufferMemory* buf, int32 chunk_siz
chunk_init(&ac->asset_memory, buf, count, chunk_size, 64);
pthread_mutex_init(&ac->mutex, NULL);
LOG_LEVEL_2("Created AMS Component for %n assets and %n B = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_UINT32, &chunk_size}, {LOG_DATA_UINT64, &ac->asset_memory.size}});
}
inline
@ -69,6 +73,8 @@ void ams_component_create(AssetComponent* ac, byte* buf, int32 chunk_size, int32
ac->asset_memory.free = (uint64 *) (ac->asset_memory.memory + ac->asset_memory.chunk_size * count);
pthread_mutex_init(&ac->mutex, NULL);
LOG_LEVEL_2("Created AMS Component for %n assets and %n B = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_UINT32, &chunk_size}, {LOG_DATA_UINT64, &ac->asset_memory.size}});
}
inline
@ -216,7 +222,7 @@ Asset* thrd_ams_get_reserve_asset_wait(AssetManagementSystem* ams, byte type, co
ac->ram_size += asset->ram_size;
++ac->asset_count;
DEBUG_MEMORY_RESERVE((uint64) asset, asset->ram_size, 180);
DEBUG_MEMORY_RESERVE((uintptr_t) asset, asset->ram_size, 180);
return asset;
}
@ -389,7 +395,7 @@ Asset* ams_reserve_asset(AssetManagementSystem* ams, byte type, const char* name
ac->ram_size += asset->ram_size;
++ac->asset_count;
DEBUG_MEMORY_RESERVE((uint64) asset, asset->ram_size, 180);
DEBUG_MEMORY_RESERVE((uintptr_t) asset, asset->ram_size, 180);
return asset;
}
@ -422,7 +428,7 @@ Asset* thrd_ams_reserve_asset(AssetManagementSystem* ams, byte type, const char*
ac->ram_size += asset.ram_size;
++ac->asset_count;
DEBUG_MEMORY_RESERVE((uint64) asset_data, asset.ram_size, 180);
DEBUG_MEMORY_RESERVE((uintptr_t) asset_data, asset.ram_size, 180);
ASSERT_SIMPLE(strlen(name) < HASH_MAP_MAX_KEY_LENGTH - 1);
@ -499,7 +505,7 @@ Asset* ams_insert_asset(AssetManagementSystem* ams, Asset* asset_temp, const cha
++ac->asset_count;
Asset* asset = (Asset *) hashmap_insert(&ams->hash_map, name, (byte *) asset_temp)->value;
DEBUG_MEMORY_RESERVE((uint64) asset->self, asset->ram_size, 180);
DEBUG_MEMORY_RESERVE((uintptr_t) asset->self, asset->ram_size, 180);
return asset;
}
@ -530,7 +536,7 @@ Asset* thrd_ams_insert_asset(AssetManagementSystem* ams, Asset* asset_temp, cons
++ac->asset_count;
Asset* asset = (Asset *) hashmap_insert(&ams->hash_map, name, (byte *) asset_temp)->value;
DEBUG_MEMORY_RESERVE((uint64) asset->self, asset->ram_size, 180);
DEBUG_MEMORY_RESERVE((uintptr_t) asset->self, asset->ram_size, 180);
atomic_set_release(&asset->is_loaded, 1);

View File

@ -13,7 +13,6 @@
#include "Audio.h"
#include "AudioSetting.h"
#include "../utils/Utils.h"
#include "../utils/MathUtils.h"
#include "../memory/ChunkMemory.h"
#include "../math/matrix/MatrixFloat32.h"
#include "../thread/Atomic.h"

View File

@ -14,7 +14,6 @@
#include <string.h>
#include "../../EngineDependencies/curl/include/curl/curl.h"
#include "../utils/MathUtils.h"
#define MAX_AUTH_POST_LENGTH 1024
#define MAX_AUTH_RESPONSE_LENGTH 1024

View File

@ -29,6 +29,8 @@ void cmd_buffer_create(AppCmdBuffer* cb, BufferMemory* buf, int32 commands_count
{
chunk_init(&cb->commands, buf, commands_count, sizeof(Command), 64);
pthread_mutex_init(&cb->mutex, NULL);
LOG_LEVEL_2("Created AppCmdBuffer: %n B", {{LOG_DATA_UINT64, &cb->commands.size}});
}
// This doesn't load the asset directly but tells (most likely) a worker thread to load an asset

View File

@ -14,7 +14,6 @@
#include "../stdlib/Types.h"
#include "../utils/BitUtils.h"
#include "../utils/MathUtils.h"
#include "../utils/EndianUtils.h"
struct HuffmanNode {

View File

@ -108,7 +108,7 @@ Entity* ecs_insert_entity(EntityComponentSystem* ecs, Entity* entity_temp, int32
memcpy(entity, entity_temp, mem->chunk_size);
// @todo log entity stats (count, ram, vram)
//DEBUG_MEMORY_RESERVE((uint64) entity, entity->ram_size, 180);
//DEBUG_MEMORY_RESERVE((uintptr_t) entity, entity->ram_size, 180);
return entity;
}

View File

@ -2,7 +2,6 @@
#define TOS_ENVIRONMENT_GLOBE_H
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
#include <math.h>
/**

View File

@ -363,6 +363,8 @@ void text_calculate_dimensions(
// @todo implement shadow (offset + angle + diffuse) or should this be a shader only thing? if so this would be a problem for us since we are handling text in the same shader as simple shapes
// we might want to implement distance field font atlas
// @todo We should be able to cut off text at an arbitrary position, not just at a line_height incremental
// we could probably get the MIN of the glyph height and the remaining window height
v2_f32 vertex_text_create(
Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v,
@ -395,11 +397,19 @@ v2_f32 vertex_text_create(
}
}
f32 line_height_scaled = font->line_height * scale;
f32 rendered_width = 0;
f32 rendered_height = line_height_scaled;
f32 offset_x = x;
for (int32 i = 0; i < length; ++i) {
int32 character = is_ascii ? text[i] : utf8_get_char_at(text, i);
if (character == '\n') {
y -= font->line_height * scale;
rendered_height += line_height_scaled;
rendered_width = OMS_MAX(rendered_width, offset_x - x);
y -= line_height_scaled;
offset_x = x;
continue;
@ -429,7 +439,7 @@ v2_f32 vertex_text_create(
// This way we can ensure no overflow easily
// @todo implement line alignment, currently only total alignment is considered
return {offset_x, y};
return {rendered_width, rendered_height};
}
// @todo implement shadow (offset + angle + diffuse) or should this be a shader only thing? if so this would be a problem for us since we are handling text in the same shader as simple shapes

View File

@ -41,7 +41,7 @@ ID3D12PipelineState* program_make(
HRESULT hr = device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState));
if (FAILED(hr)) {
LOG("Failed to create program", true, true);
LOG(true, "Failed to create program");
return NULL;
}

View File

@ -44,7 +44,7 @@ void opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severit
return;
}
LOG(message, true, true);
LOG(true, message);
ASSERT_SIMPLE(false);
}
@ -490,6 +490,7 @@ void gpuapi_error()
{
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
LOG_FORMAT(true, "Opengl error: %d", {{LOG_DATA_INT32, (int32 *) &err}});
ASSERT_SIMPLE(err == GL_NO_ERROR);
}
}

View File

@ -275,7 +275,7 @@ GLuint shader_make(GLenum type, const char* source, RingMemory* ring)
GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar));
glGetShaderInfoLog(shader, length, NULL, info);
LOG(info, true, true);
LOG(true, info);
ASSERT_SIMPLE(false);
}
@ -321,7 +321,7 @@ GLuint program_make(
GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar));
glGetProgramInfoLog(program, length, NULL, info);
LOG(info, true, true);
LOG(true, info);
ASSERT_SIMPLE(false);
}

View File

@ -58,7 +58,7 @@ VkShaderModule shader_make(VkDevice device, const char* source, int32 source_siz
VkResult result = vkCreateShaderModule(device, &create_info, NULL, &shader_module);
if (result != VK_SUCCESS) {
LOG("Failed to create shader module", true, true);
LOG(true, "Failed to create shader module");
ASSERT_SIMPLE(false);
return VK_NULL_HANDLE;

View File

@ -111,7 +111,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_callback(
if ((severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|| (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
) {
LOG(debug_callback_data->pMessage, true, true);
LOG(true, debug_callback_data->pMessage);
}
return VK_FALSE;
@ -158,14 +158,14 @@ void vulkan_instance_create(
if (validation_layer_count
&& (err = vulkan_check_validation_layer_support(validation_layers, validation_layer_count, ring))
) {
LOG_FORMAT("Vulkan validation_layer missing: %d\n", LOG_DATA_CHAR_STR, (void *) validation_layers[-err - 1], true, true);
LOG_FORMAT(true, "Vulkan validation_layer missing: %d", {{LOG_DATA_CHAR_STR, (void *) validation_layers[-err - 1]}});
ASSERT_SIMPLE(false);
}
if (extension_count
&& (err = vulkan_check_extension_support(extensions, extension_count, ring))
) {
LOG_FORMAT("Vulkan extension missing: %d\n", LOG_DATA_CHAR_STR, (void *) extensions[-err - 1], true, true);
LOG_FORMAT(true, "Vulkan extension missing: %d", {{LOG_DATA_CHAR_STR, (void *) extensions[-err - 1]}});
ASSERT_SIMPLE(false);
}
@ -195,7 +195,7 @@ void vulkan_instance_create(
VkResult result;
if ((result = vkCreateInstance(&create_info, NULL, instance)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateInstance: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateInstance: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
}
@ -210,7 +210,7 @@ void vulkan_surface_create(VkInstance instance, VkSurfaceKHR* surface, Window* w
VkResult result;
if ((result = vkCreateWin32SurfaceKHR(instance, &surface_create_info, NULL, surface)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateWin32SurfaceKHR: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateWin32SurfaceKHR: %d", LOG_DATA_INT32, (int32 *) &result);
return;
}
#elif __linux__
@ -345,7 +345,7 @@ void gpuapi_pick_physical_device(
}
}
LOG("Vulkan failed to find physical device\n", true, true);
LOG(true, "Vulkan failed to find physical device");
ASSERT_SIMPLE(false);
}
@ -392,7 +392,7 @@ void gpuapi_create_logical_device(
VkResult result;
if ((result = vkCreateDevice(physical_device, &create_info, NULL, device)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateDevice: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateDevice: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
@ -480,7 +480,7 @@ void vulkan_swap_chain_create(
VkResult result;
if ((result = vkCreateSwapchainKHR(device, &create_info, NULL, swapchain)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateSwapchainKHR: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateSwapchainKHR: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
@ -521,7 +521,7 @@ void vulkan_image_views_create(
create_info.subresourceRange.layerCount = 1;
if ((result = vkCreateImageView(device, &create_info, NULL, &swapchain_image_views[i])) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateImageView: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateImageView: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
}
@ -568,7 +568,7 @@ void create_render_pass(
VkResult result;
if ((result = vkCreateRenderPass(device, &renderPassInfo, NULL, render_pass)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateRenderPass: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateRenderPass: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
}
@ -665,7 +665,7 @@ void vulkan_pipeline_create(
VkResult result;
if ((result = vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL, pipeline_layout)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreatePipelineLayout: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreatePipelineLayout: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
@ -686,7 +686,7 @@ void vulkan_pipeline_create(
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
if ((result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, pipeline)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateGraphicsPipelines: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateGraphicsPipelines: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
@ -717,7 +717,7 @@ void vulkan_framebuffer_create(
framebufferInfo.layers = 1;
if ((result = vkCreateFramebuffer(device, &framebufferInfo, NULL, &swapchain_framebuffers[i])) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateFramebuffer: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateFramebuffer: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
}
@ -736,7 +736,7 @@ void vulkan_command_pool_create(
VkResult result;
if ((result = vkCreateCommandPool(device, &poolInfo, NULL, command_pool)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkCreateCommandPool: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkCreateCommandPool: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
}
@ -751,7 +751,7 @@ void vulkan_command_buffer_create(VkDevice device, VkCommandBuffer* command_buff
VkResult result;
if ((result = vkAllocateCommandBuffers(device, &allocInfo, command_buffer)) != VK_SUCCESS) {
LOG_FORMAT("Vulkan vkAllocateCommandBuffers: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vkAllocateCommandBuffers: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}
}
@ -770,7 +770,7 @@ void vulkan_sync_objects_create(VkDevice device, VkSemaphore* image_available_se
|| (result = vkCreateSemaphore(device, &semaphoreInfo, NULL, render_finished_semaphore)) != VK_SUCCESS
|| (result = vkCreateFence(device, &fenceInfo, NULL, in_flight_fence)) != VK_SUCCESS
) {
LOG_FORMAT("Vulkan vulkan_sync_objects_create: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
LOG_FORMAT(true, "Vulkan vulkan_sync_objects_create: %d", LOG_DATA_INT32, (int32 *) &result);
ASSERT_SIMPLE(false);
}

View File

@ -15,7 +15,6 @@
#include "../stdlib/Types.h"
#include "../utils/Utils.h"
#include "../utils/EndianUtils.h"
#include "../utils/MathUtils.h"
#include "Image.h"
// See: https://en.wikipedia.org/wiki/BMP_file_format

View File

@ -15,22 +15,22 @@
// @todo basically all the dark colors could be made darker -> space out some of the very bright colors a little bit more (see 3rd - 5th column)
const uint32 default_colors_256[256] = {
0xFFFFFF00, 0xFFFFFFFF, 0xF1EEEDFF, 0xDCDEDEFF, 0xBFC1BFFF, 0xAEB0ADFF, 0x9E9D9EFF, 0x8E8F94FF, 0x717373FF, 0x5E5F61FF, 0x4D4D4CFF, 0x3F403AFF, 0x332C2AFF, 0x241E22FF, 0x0C1210FF, 0x000000FF,
0xF6D3CFFF, 0xFABABCFF, 0xFBA699FF, 0xF19580FF, 0xFB837AFF, 0xFC615AFF, 0xFF4E4BFF, 0xFF4040FF, 0xF72128FF, 0xF60303FF, 0xE40000FF, 0xC70002FF, 0x900009FF, 0x630604FF, 0x4f0107FF, 0x2d0205FF,
0xFDDDCEFF, 0xFCC5ACFF, 0xFFB9A4FF, 0xF6A378FF, 0xF49A80FF, 0xFF7D4FFF, 0xF8742CFF, 0xFE5A22FF, 0xF44A0BFF, 0xDA3A06FF, 0xC03500FF, 0x853004FF, 0x912600FF, 0x672300FF, 0x471608FF, 0x2b0d05FF,
0xFCEBCFFF, 0xFCD8AAFF, 0xFFCD98FF, 0xFCC27FFF, 0xF3B267FF, 0xFDA660FF, 0xFD942DFF, 0xFF8001FF, 0xDF6E00FF, 0xCC6B00FF, 0xA85D00FF, 0xA55300FF, 0x734700FF, 0x612D08FF, 0x562600FF, 0x351700FF,
0xFFF6C9FF, 0xFFECA8FF, 0xFDE884FF, 0xFADC6DFF, 0xF8DE6FFF, 0xFFCF43FF, 0xFFBD00FF, 0xEBB800FF, 0xC1A800FF, 0xBC8F09FF, 0x9B7A00FF, 0x8E6C08FF, 0x795F01FF, 0x5C4A00FF, 0x523B00FF, 0x392900FF,
0xFFFFCDFF, 0xFDFEAFFF, 0xFCFBA1FF, 0xFDFF69FF, 0xF9FF2AFF, 0xFFFE04FF, 0xEFEE00FF, 0xE0DE00FF, 0xBDBF13FF, 0xB4AF00FF, 0x9F9900FF, 0x909002FF, 0x717300FF, 0x505400FF, 0x4A4F00FF, 0x343700FF,
0xE4FFBDFF, 0xDFFEB9FF, 0xD1FF8FFF, 0xCAFC84FF, 0xC0F96BFF, 0xBAF353FF, 0x98FB00FF, 0x9AEE0FFF, 0x78CE00FF, 0x74C100FF, 0x61A401FF, 0x578A03FF, 0x4F7E02FF, 0x3C6200FF, 0x2E4F00FF, 0x203700FF,
0xE1F8D8FF, 0xBBFEADFF, 0xA2F592FF, 0xA1F79AFF, 0x81FF7AFF, 0x5DFF59FF, 0x48FF58FF, 0x00F600FF, 0x12D31FFF, 0x0ACB04FF, 0x10A40AFF, 0x089811FF, 0x06780EFF, 0x05640FFF, 0x005200FF, 0x003100FF,
0xD5FFF8FF, 0xBCFFEAFF, 0xA7FED3FF, 0x99F2C4FF, 0x6CFFB5FF, 0x53F29EFF, 0x4CFEA1FF, 0x0AF779FF, 0x0CD56AFF, 0x0BC868FF, 0x01AA50FF, 0x07A557FF, 0x008642FF, 0x075A30FF, 0x00562CFF, 0x00331aFF,
0xD9FDFEFF, 0xB3FCFFFF, 0xACFFFFFF, 0x90FFFFFF, 0x76FEFFFF, 0x5FFAFDFF, 0x08FEFEFF, 0x22F3F2FF, 0x06C9C2FF, 0x08B2C4FF, 0x049FA4FF, 0x078C97FF, 0x008286FF, 0x025D5DFF, 0x005056FF, 0x003135FF,
0xE2F5FFFF, 0xB4EBFFFF, 0xA3DAFFFF, 0x89CCF8FF, 0x79D1FFFF, 0x61C3F7FF, 0x59C5F3FF, 0x3FB9F6FF, 0x05A4FAFF, 0x0592F0FF, 0x0677B8FF, 0x00649AFF, 0x065A77FF, 0x004974FF, 0x003154FF, 0x00243eFF,
0xD1DDFFFF, 0xB5D0EFFF, 0xA7BFF6FF, 0x90B6F4FF, 0x85AAF7FF, 0x67AAFFFF, 0x5386FFFF, 0x437AFFFF, 0x3A6AFFFF, 0x044EFCFF, 0x034EF7FF, 0x0A37BFFF, 0x09268BFF, 0x062871FF, 0x001D4CFF, 0x001435FF,
0xC7C3FFFF, 0xC7C6FEFF, 0x9D9CFFFF, 0x9194F6FF, 0x7E81FEFF, 0x776FF7FF, 0x595AFFFF, 0x4852FFFF, 0x2D2EFFFF, 0x2020F8FF, 0x0400E1FF, 0x0000DDFF, 0x010097FF, 0x000086FF, 0x03005DFF, 0x020035FF,
0xE1D4FFFF, 0xD8ACFFFF, 0xCD9BFFFF, 0xC88DFAFF, 0xBD8AF9FF, 0xB160FFFF, 0xAA52FEFF, 0x9841FDFF, 0x8726FFFF, 0x8700F5FF, 0x7200F4FF, 0x5C00B7FF, 0x460489FF, 0x350077FF, 0x28004FFF, 0x1c0037FF,
0xFFC7FFFF, 0xFFB2FFFF, 0xFF9AFFFF, 0xF181F1FF, 0xFB6FFDFF, 0xF850FBFF, 0xFB46FFFF, 0xF91FFFFF, 0xF900FFFF, 0xDD00E6FF, 0xBF00C7FF, 0x9B0199FF, 0xB70090FF, 0x670362FF, 0x4F0153FF, 0x330035FF,
0xFDD2E6FF, 0xF9B5DAFF, 0xF7A4D4FF, 0xF198CBFF, 0xF682BDFF, 0xFF5FAEFF, 0xFF4CA9FF, 0xFF3CA4FF, 0xFF1A94FF, 0xF90979FF, 0xE80071FF, 0xC40061FF, 0x96004AFF, 0x670132FF, 0x4F0024FF, 0x310016FF
0xFFFFFF00, 0xFFFFFFFF, 0xE9E9E9FF, 0xD9D9D9FF, 0xC9C9C9FF, 0xB9B9B9FF, 0xA9A9A9FF, 0x999999FF, 0x898989FF, 0x797979FF, 0x696969FF, 0x595959FF, 0x494949FF, 0x393939FF, 0x1F1F1FFF, 0x000000FF,
0xF6D3CFFF, 0xF8C2BDFF, 0xFB9E91FF, 0xFC8B7EFF, 0xFC796CFF, 0xFD675BFF, 0xFF554BFF, 0xFF4340FF, 0xF82D2EFF, 0xF6171BFF, 0xE60412FF, 0xCC0004FF, 0xA70004FF, 0x7A0306FF, 0x4f0107FF, 0x330004FF,
0xFDDDCEFF, 0xFCCFB6FF, 0xFDB69EFF, 0xF5A78CFF, 0xF69B7EFF, 0xFF8A65FF, 0xFF7A50FF, 0xFB683AFF, 0xF95523FF, 0xF34413FF, 0xD8390AFF, 0xB22F07FF, 0x8F2905FF, 0x742406FF, 0x57200AFF, 0x2b0d05FF,
0xFCEBCFFF, 0xFCDAB2FF, 0xFCCB96FF, 0xFBBE7CFF, 0xF3B067FF, 0xFCA45FFF, 0xFB913EFF, 0xFF7F1CFF, 0xE76E09FF, 0xD06B00FF, 0xB05F00FF, 0x9C5300FF, 0x824A00FF, 0x6E3B06FF, 0x5A2E05FF, 0x351700FF,
0xFFF6C9FF, 0xFFEDB1FF, 0xFFE593FF, 0xFDDC74FF, 0xF9D36AFF, 0xFFC94FFF, 0xFFBD1EFF, 0xF4B600FF, 0xD2A200FF, 0xB78E04FF, 0x9D7D00FF, 0x8C6F07FF, 0x776300FF, 0x614F00FF, 0x503D00FF, 0x392900FF,
0xFFFFCDFF, 0xFEFDBCFF, 0xFCF9A3FF, 0xFBF583FF, 0xFAF065FF, 0xFFEA2BFF, 0xFEEB04FF, 0xE9DC00FF, 0xD7CC00FF, 0xC4BA00FF, 0xADA500FF, 0x9A9200FF, 0x7C7700FF, 0x605B00FF, 0x4F4C00FF, 0x343700FF,
0xE4FFBDFF, 0xDBFDBCFF, 0xCEF9A3FF, 0xC4F48EFF, 0xBAEE76FF, 0xB1E760FF, 0x9FEF29FF, 0x97E313FF, 0x7FC900FF, 0x78BB00FF, 0x67A201FF, 0x5C8E02FF, 0x527F01FF, 0x426600FF, 0x334F00FF, 0x203700FF,
0xE1F8D8FF, 0xC7F8C2FF, 0xADF5ABFF, 0x9EEC97FF, 0x85E47FFF, 0x66DF66FF, 0x4EDB5FFF, 0x23D138FF, 0x12C72CFF, 0x0EB522FF, 0x109B17FF, 0x0A8913FF, 0x077311FF, 0x066011FF, 0x004F06FF, 0x003100FF,
0xD5FFF8FF, 0xC5FDF4FF, 0xA8F7E5FF, 0x99F0D7FF, 0x7BF1C6FF, 0x60E6B1FF, 0x53E0A0FF, 0x1CE76FFF, 0x0DD763FF, 0x0AD056FF, 0x02B548FF, 0x04A94DFF, 0x009A40FF, 0x088133FF, 0x005A2BFF, 0x00331AFF,
0xD9FDFEFF, 0xB5FBFEFF, 0xA8FFFFFF, 0x92FFFFFF, 0x7AFDFFFF, 0x66F9FDFF, 0x0FF8FEFF, 0x1CE7F5FF, 0x06C5C9FF, 0x0BA2B2FF, 0x04A39EFF, 0x079A8EFF, 0x008B7DFF, 0x027A7AFF, 0x004D4FFF, 0x003135FF,
0xE2F5FFFF, 0xB4EBFFFF, 0xA3DAFFFF, 0x89CCF8FF, 0x79D1FFFF, 0x61C3F7FF, 0x59C5F3FF, 0x3FB9F6FF, 0x05A4FAFF, 0x0592F0FF, 0x0677B8FF, 0x00649AFF, 0x065A77FF, 0x004974FF, 0x003154FF, 0x00243eFF,
0xD1DDFFFF, 0xB5D0EFFF, 0xA7BFF6FF, 0x90B6F4FF, 0x85AAF7FF, 0x67AAFFFF, 0x5386FFFF, 0x437AFFFF, 0x3A6AFFFF, 0x044EFCFF, 0x034EF7FF, 0x0A37BFFF, 0x09268BFF, 0x062871FF, 0x001D4CFF, 0x001435FF,
0xC7C3FFFF, 0xC7C6FEFF, 0x9D9CFFFF, 0x9194F6FF, 0x7E81FEFF, 0x776FF7FF, 0x595AFFFF, 0x4852FFFF, 0x2D2EFFFF, 0x2020F8FF, 0x0400E1FF, 0x0000DDFF, 0x010097FF, 0x000086FF, 0x03005DFF, 0x020035FF,
0xE1D4FFFF, 0xD8ACFFFF, 0xCD9BFFFF, 0xC88DFAFF, 0xBD8AF9FF, 0xB160FFFF, 0xAA52FEFF, 0x9841FDFF, 0x8726FFFF, 0x8700F5FF, 0x7200F4FF, 0x5C00B7FF, 0x460489FF, 0x350077FF, 0x28004FFF, 0x1c0037FF,
0xFFC7FFFF, 0xFFB8FFFF, 0xFFAAFFFF, 0xF194F7FF, 0xF681F5FF, 0xF77CF1FF, 0xF76DFFFF, 0xF956FFFF, 0xF82FFFFF, 0xEA00E6FF, 0xD200CBFF, 0xB500B3FF, 0xA6009CFF, 0x8A0084FF, 0x6F005EFF, 0x330035FF,
0xFDD2E6FF, 0xF9B5DAFF, 0xF7A4D4FF, 0xF198CBFF, 0xF682BDFF, 0xFF5FAEFF, 0xFF4CA9FF, 0xFF3CA4FF, 0xFF1A94FF, 0xF90979FF, 0xE80071FF, 0xC40061FF, 0x96004AFF, 0x670132FF, 0x4F0024FF, 0x310016FF,
};
// @todo Implement (extends the default_colors_256 -> both together form 1024 colors)

View File

@ -28,7 +28,7 @@
// How many concurrent primary key/button presses can be handled?
#define MAX_KEY_PRESSES 5
#define MAX_KEY_STATES (2 * MAX_KEY_PRESSES)
#define MAX_KEY_PRESS_TYPES (2 * MAX_KEY_PRESSES)
// How many keys/buttons do we support for the devices
#define MAX_KEYBOARD_KEYS 255
@ -36,10 +36,6 @@
#define MIN_INPUT_DEVICES 2
// How often can a key be assigned to a different hotkey
#define MAX_KEY_TO_HOTKEY 5
#define MEX_KEY_LENGTH ((MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS + MAX_CONTROLLER_KEYS) * MAX_KEY_TO_HOTKEY)
// How many buttons together are allowed to form a hotkey
#define MAX_HOTKEY_COMBINATION 3
@ -63,6 +59,7 @@ enum InputType {
#ifdef _WIN32
#include <windows.h>
#include <dinput.h>
#include "../platform/win32/UtilsWin32.h"
#endif
typedef void (*InputCallback)(void* data);
@ -70,43 +67,49 @@ typedef void (*InputCallback)(void* data);
// @todo I'm not sure if I like the general input handling
// Having separate keyboard_down and mouse_down etc. is a little bit weird in the functions below
struct InputMapping {
// A key/button can be bound to up to 5 different hotkeys
// This is used to check if a key/button has a hotkey association
uint8 keys[MEX_KEY_LENGTH];
// A hotkey can be bound to a combination of up to 3 key/button presses
uint8 hotkey_count;
enum KeyPressType : byte {
KEY_PRESS_TYPE_NONE,
KEY_PRESS_TYPE_PRESSED,
KEY_PRESS_TYPE_HELD,
KEY_PRESS_TYPE_RELEASED,
};
struct Hotkey {
// negative hotkeys mean any of them needs to be matched, positive hotkeys means all of them need to be matched
// mixing positive and negative keys for one hotkey is not possible
// index = hotkey, value = key id
int16* hotkeys;
InputCallback* callbacks;
int16 scan_codes[MAX_HOTKEY_COMBINATION];
KeyPressType key_state;
InputCallback callback;
};
enum KeyState {
KEY_STATE_PRESSED,
KEY_STATE_HELD,
KEY_STATE_RELEASED,
struct InputMapping {
// A hotkey can be bound to a combination of up to 3 key/button presses
// The indices represent the hotkey id
uint8 hotkey_count;
Hotkey* hotkeys;
};
struct InputKey {
// Includes flag for mouse, keyboard, controller
uint16 key_id;
uint16 key_state;
int16 value; // e.g. stick/trigger keys have additional values
uint16 scan_code;
uint16 virtual_code;
KeyPressType key_state;
uint64 time; // when was this action performed (useful to decide if key state is held vs pressed)
bool is_processed;
int16 value; // e.g. stick/trigger keys have additional values
};
// @question Maybe we should also add a third key_down array for controllers and some special controller functions here to just handle everything in one struct
// Or think about completely splitting all states (mouse, keyboard, other)
struct InputState {
// State of the hotkeys, resulting from the device input
uint8 state_hotkeys[MAX_KEY_PRESSES];
// Active hotkeys
uint16 active_hotkeys[MAX_KEY_PRESSES];
InputKey state_keys[MAX_KEY_STATES];
// Active keys
InputKey active_keys[MAX_KEY_PRESS_TYPES];
// @question Couldn't we make the values below 16 bit?
int32 dx;
int32 dy;
@ -128,6 +131,13 @@ struct InputState {
uint32 y3;
};
enum GeneralInputState : byte {
INPUT_STATE_GENERAL_BUTTON_CHANGE = 1 << 0,
INPUT_STATE_GENERAL_MOUSE_CHANGE = 1 << 1,
INPUT_STATE_GENERAL_MOUSE_MOVEMENT = 1 << 2,
INPUT_STATE_GENERAL_TYPING_MODE = 1 << 3,
};
struct Input {
// Device
InputConnectionType connection_type;
@ -145,17 +155,15 @@ struct Input {
#endif
byte controller_type;
bool state_change_button;
bool state_change_mouse;
// Do we want to capture mouse events = true,
// or do we want to poll the position whenever needed = false
bool mouse_movement;
byte general_states;
InputState state;
uint64 time_last_input_check;
// @todo this should probably be somewhere else
// @todo don't we need multiple deadzones? triggers, sticks
uint32 deadzone = 10;
uint32 characters[10];
// This data is passed to the hotkey callback
void* callback_data;
@ -172,247 +180,202 @@ void input_init(Input* input, uint8 size, void* callback_data, BufferMemory* buf
// Init mapping1
input->input_mapping1.hotkey_count = size;
input->input_mapping1.hotkeys = (int16 *) buffer_get_memory(
input->input_mapping1.hotkeys = (Hotkey *) buffer_get_memory(
buf,
input->input_mapping1.hotkey_count * MAX_HOTKEY_COMBINATION * sizeof(int16)
);
input->input_mapping1.callbacks = (InputCallback *) buffer_get_memory(
buf,
input->input_mapping1.hotkey_count * sizeof(InputCallback),
0, true
input->input_mapping1.hotkey_count * sizeof(Hotkey),
4, true
);
// Init mapping2
input->input_mapping2.hotkey_count = size;
input->input_mapping2.hotkeys = (int16 *) buffer_get_memory(
input->input_mapping2.hotkeys = (Hotkey *) buffer_get_memory(
buf,
input->input_mapping2.hotkey_count * MAX_HOTKEY_COMBINATION * sizeof(int16)
);
input->input_mapping2.callbacks = (InputCallback *) buffer_get_memory(
buf,
input->input_mapping2.hotkey_count * sizeof(InputCallback),
0, true
input->input_mapping2.hotkey_count * sizeof(Hotkey),
4, true
);
}
inline
void input_clean_state(InputKey* state_keys)
void input_clean_state(InputKey* active_keys, KeyPressType press_status = KEY_PRESS_TYPE_RELEASED)
{
for (int32 i = 0; i < MAX_KEY_STATES; ++i) {
if (state_keys[i].key_state == KEY_STATE_RELEASED) {
state_keys[i].key_id = 0;
if (press_status) {
for (int32 i = 0; i < MAX_KEY_PRESS_TYPES; ++i) {
if (active_keys[i].key_state == press_status) {
memset(&active_keys[i], 0, sizeof(InputKey));
}
}
} else {
memset(active_keys, 0, MAX_KEY_PRESS_TYPES * sizeof(InputKey));
}
}
inline
bool input_action_exists(const InputKey* state_keys, int16 key)
bool input_action_exists(const InputKey* active_keys, int16 key, KeyPressType press_type = KEY_PRESS_TYPE_PRESSED)
{
return state_keys[0].key_id == key
|| state_keys[1].key_id == key
|| state_keys[2].key_id == key
|| state_keys[3].key_id == key
|| state_keys[4].key_id == key
|| state_keys[4].key_id == key
|| state_keys[5].key_id == key
|| state_keys[6].key_id == key
|| state_keys[7].key_id == key
|| state_keys[8].key_id == key
|| state_keys[9].key_id == key;
return (active_keys[0].scan_code == key && active_keys[0].key_state == press_type)
|| (active_keys[1].scan_code == key && active_keys[1].key_state == press_type)
|| (active_keys[2].scan_code == key && active_keys[2].key_state == press_type)
|| (active_keys[3].scan_code == key && active_keys[3].key_state == press_type)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == press_type)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == press_type)
|| (active_keys[5].scan_code == key && active_keys[5].key_state == press_type)
|| (active_keys[6].scan_code == key && active_keys[6].key_state == press_type)
|| (active_keys[7].scan_code == key && active_keys[7].key_state == press_type)
|| (active_keys[8].scan_code == key && active_keys[8].key_state == press_type)
|| (active_keys[9].scan_code == key && active_keys[9].key_state == press_type);
}
inline
bool input_is_down(const InputKey* state_keys, int16 key)
bool input_is_down(const InputKey* active_keys, int16 key)
{
return (state_keys[0].key_id == key && state_keys[0].key_state != KEY_STATE_RELEASED)
|| (state_keys[1].key_id == key && state_keys[1].key_state != KEY_STATE_RELEASED)
|| (state_keys[2].key_id == key && state_keys[2].key_state != KEY_STATE_RELEASED)
|| (state_keys[3].key_id == key && state_keys[3].key_state != KEY_STATE_RELEASED)
|| (state_keys[4].key_id == key && state_keys[4].key_state != KEY_STATE_RELEASED)
|| (state_keys[5].key_id == key && state_keys[5].key_state != KEY_STATE_RELEASED)
|| (state_keys[6].key_id == key && state_keys[6].key_state != KEY_STATE_RELEASED)
|| (state_keys[7].key_id == key && state_keys[7].key_state != KEY_STATE_RELEASED)
|| (state_keys[8].key_id == key && state_keys[8].key_state != KEY_STATE_RELEASED)
|| (state_keys[9].key_id == key && state_keys[9].key_state != KEY_STATE_RELEASED);
return (active_keys[0].scan_code == key && active_keys[0].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[1].scan_code == key && active_keys[1].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[2].scan_code == key && active_keys[2].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[3].scan_code == key && active_keys[3].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[4].scan_code == key && active_keys[4].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[5].scan_code == key && active_keys[5].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[6].scan_code == key && active_keys[6].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[7].scan_code == key && active_keys[7].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[8].scan_code == key && active_keys[8].key_state != KEY_PRESS_TYPE_RELEASED)
|| (active_keys[9].scan_code == key && active_keys[9].key_state != KEY_PRESS_TYPE_RELEASED);
}
inline
bool input_is_pressed(const InputKey* state_keys, int16 key)
bool input_is_pressed(const InputKey* active_keys, int16 key)
{
return (state_keys[0].key_id == key && state_keys[0].key_state == KEY_STATE_PRESSED)
|| (state_keys[1].key_id == key && state_keys[1].key_state == KEY_STATE_PRESSED)
|| (state_keys[2].key_id == key && state_keys[2].key_state == KEY_STATE_PRESSED)
|| (state_keys[3].key_id == key && state_keys[3].key_state == KEY_STATE_PRESSED)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_PRESSED)
|| (state_keys[5].key_id == key && state_keys[5].key_state == KEY_STATE_PRESSED)
|| (state_keys[6].key_id == key && state_keys[6].key_state == KEY_STATE_PRESSED)
|| (state_keys[7].key_id == key && state_keys[7].key_state == KEY_STATE_PRESSED)
|| (state_keys[8].key_id == key && state_keys[8].key_state == KEY_STATE_PRESSED)
|| (state_keys[9].key_id == key && state_keys[9].key_state == KEY_STATE_PRESSED);
return (active_keys[0].scan_code == key && active_keys[0].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[1].scan_code == key && active_keys[1].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[2].scan_code == key && active_keys[2].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[3].scan_code == key && active_keys[3].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[5].scan_code == key && active_keys[5].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[6].scan_code == key && active_keys[6].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[7].scan_code == key && active_keys[7].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[8].scan_code == key && active_keys[8].key_state == KEY_PRESS_TYPE_PRESSED)
|| (active_keys[9].scan_code == key && active_keys[9].key_state == KEY_PRESS_TYPE_PRESSED);
}
inline
bool input_is_held(const InputKey* state_keys, int16 key)
bool input_is_held(const InputKey* active_keys, int16 key)
{
return (state_keys[0].key_id == key && state_keys[0].key_state == KEY_STATE_HELD)
|| (state_keys[1].key_id == key && state_keys[1].key_state == KEY_STATE_HELD)
|| (state_keys[2].key_id == key && state_keys[2].key_state == KEY_STATE_HELD)
|| (state_keys[3].key_id == key && state_keys[3].key_state == KEY_STATE_HELD)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_HELD)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_HELD)
|| (state_keys[5].key_id == key && state_keys[5].key_state == KEY_STATE_HELD)
|| (state_keys[6].key_id == key && state_keys[6].key_state == KEY_STATE_HELD)
|| (state_keys[7].key_id == key && state_keys[7].key_state == KEY_STATE_HELD)
|| (state_keys[8].key_id == key && state_keys[8].key_state == KEY_STATE_HELD)
|| (state_keys[9].key_id == key && state_keys[9].key_state == KEY_STATE_HELD);
return (active_keys[0].scan_code == key && active_keys[0].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[1].scan_code == key && active_keys[1].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[2].scan_code == key && active_keys[2].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[3].scan_code == key && active_keys[3].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[5].scan_code == key && active_keys[5].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[6].scan_code == key && active_keys[6].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[7].scan_code == key && active_keys[7].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[8].scan_code == key && active_keys[8].key_state == KEY_PRESS_TYPE_HELD)
|| (active_keys[9].scan_code == key && active_keys[9].key_state == KEY_PRESS_TYPE_HELD);
}
inline
bool input_is_released(const InputKey* state_keys, int16 key)
bool input_is_released(const InputKey* active_keys, int16 key)
{
return (state_keys[0].key_id == key && state_keys[0].key_state == KEY_STATE_RELEASED)
|| (state_keys[1].key_id == key && state_keys[1].key_state == KEY_STATE_RELEASED)
|| (state_keys[2].key_id == key && state_keys[2].key_state == KEY_STATE_RELEASED)
|| (state_keys[3].key_id == key && state_keys[3].key_state == KEY_STATE_RELEASED)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_RELEASED)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_RELEASED)
|| (state_keys[5].key_id == key && state_keys[5].key_state == KEY_STATE_RELEASED)
|| (state_keys[6].key_id == key && state_keys[6].key_state == KEY_STATE_RELEASED)
|| (state_keys[7].key_id == key && state_keys[7].key_state == KEY_STATE_RELEASED)
|| (state_keys[8].key_id == key && state_keys[8].key_state == KEY_STATE_RELEASED)
|| (state_keys[9].key_id == key && state_keys[9].key_state == KEY_STATE_RELEASED);
return (active_keys[0].scan_code == key && active_keys[0].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[1].scan_code == key && active_keys[1].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[2].scan_code == key && active_keys[2].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[3].scan_code == key && active_keys[3].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[5].scan_code == key && active_keys[5].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[6].scan_code == key && active_keys[6].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[7].scan_code == key && active_keys[7].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[8].scan_code == key && active_keys[8].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[9].scan_code == key && active_keys[9].key_state == KEY_PRESS_TYPE_RELEASED);
}
inline
bool input_was_down(const InputKey* state_keys, int16 key)
bool input_was_down(const InputKey* active_keys, int16 key)
{
return (state_keys[0].key_id == key && state_keys[0].key_state == KEY_STATE_RELEASED)
|| (state_keys[1].key_id == key && state_keys[1].key_state == KEY_STATE_RELEASED)
|| (state_keys[2].key_id == key && state_keys[2].key_state == KEY_STATE_RELEASED)
|| (state_keys[3].key_id == key && state_keys[3].key_state == KEY_STATE_RELEASED)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_RELEASED)
|| (state_keys[4].key_id == key && state_keys[4].key_state == KEY_STATE_RELEASED)
|| (state_keys[5].key_id == key && state_keys[5].key_state == KEY_STATE_RELEASED)
|| (state_keys[6].key_id == key && state_keys[6].key_state == KEY_STATE_RELEASED)
|| (state_keys[7].key_id == key && state_keys[7].key_state == KEY_STATE_RELEASED)
|| (state_keys[8].key_id == key && state_keys[8].key_state == KEY_STATE_RELEASED)
|| (state_keys[9].key_id == key && state_keys[9].key_state == KEY_STATE_RELEASED);
return (active_keys[0].scan_code == key && active_keys[0].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[1].scan_code == key && active_keys[1].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[2].scan_code == key && active_keys[2].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[3].scan_code == key && active_keys[3].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[4].scan_code == key && active_keys[4].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[5].scan_code == key && active_keys[5].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[6].scan_code == key && active_keys[6].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[7].scan_code == key && active_keys[7].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[8].scan_code == key && active_keys[8].key_state == KEY_PRESS_TYPE_RELEASED)
|| (active_keys[9].scan_code == key && active_keys[9].key_state == KEY_PRESS_TYPE_RELEASED);
}
inline
bool inputs_are_down(
const InputKey* state_keys,
const InputKey* active_keys,
int16 key0, int16 key1 = 0, int16 key2 = 0, int16 key3 = 0, int16 key4 = 0
) {
return (key0 != 0 && input_is_down(state_keys, key0))
&& (key1 == 0 || input_is_down(state_keys, key1))
&& (key2 == 0 || input_is_down(state_keys, key2))
&& (key3 == 0 || input_is_down(state_keys, key3))
&& (key4 == 0 || input_is_down(state_keys, key4));
return (key0 != 0 && input_is_down(active_keys, key0))
&& (key1 == 0 || input_is_down(active_keys, key1))
&& (key2 == 0 || input_is_down(active_keys, key2))
&& (key3 == 0 || input_is_down(active_keys, key3))
&& (key4 == 0 || input_is_down(active_keys, key4));
}
void input_add_callback(InputMapping* mapping, uint8 hotkey, InputCallback callback)
{
mapping->callbacks[hotkey] = callback;
mapping->hotkeys[hotkey].callback = callback;
}
// We are binding hotkeys bi-directional
// We are binding hotkeys bi-directional:
// Which keys are required for a certain hotkey
// What are the hotkeys a key can trigger
void
input_add_hotkey(
InputMapping* mapping, uint8 hotkey,
int32 key0, int32 key1 = 0, int32 key2 = 0
int16 key0, int16 key1 = 0, int16 key2 = 0,
KeyPressType press_type = KEY_PRESS_TYPE_PRESSED
)
{
int32 count = 0;
mapping->hotkeys[(hotkey - 1)].key_state = press_type;
// Define required keys for hotkey
if (key0 != 0) {
// Note: -1 since the hotkeys always MUST start at 1 (0 is a special value for empty)
if (key0) {
mapping->hotkeys[(hotkey - 1)].scan_codes[count++] = key0;
key0 = OMS_ABS_INT16(key0);
}
if (key1) {
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION] = (int16) key0;
++count;
mapping->hotkeys[(hotkey - 1)].scan_codes[count++] = key1;
key1 = OMS_ABS_INT16(key1);
}
if (key1 != 0) {
if (key2) {
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + count] = (int16) key1;
++count;
}
if (key2 != 0) {
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + count] = (int16) key2;
}
if (key0 < 0) {
key0 *= -1;
}
if (key1 < 0) {
key1 *= -1;
}
if (key2 < 0) {
key2 *= -1;
}
int32 key0_offset = ((bool) (key0 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
+ ((bool) (key0 & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
int32 key1_offset = ((bool) (key1 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
+ ((bool) (key1 & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
int32 key2_offset = ((bool) (key2 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
+ ((bool) (key2 & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
key0 = (key0 & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX));
key1 = (key1 & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX));
key2 = (key2 & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX));
// Bind key to hotkey
for (int32 i = 0; i < MAX_KEY_TO_HOTKEY; ++i) {
if (key0 == 0 && key1 == 0 && key2 == 0) {
break;
}
if (key0 != 0 && mapping->keys[(key0 + key0_offset - 1) * MAX_KEY_TO_HOTKEY + i] == 0) {
mapping->keys[(key0 + key0_offset - 1) * MAX_KEY_TO_HOTKEY + i] = hotkey;
key0 = 0; // prevent adding same key again
}
if (key1 != 0 && mapping->keys[(key1 + key1_offset - 1) * MAX_KEY_TO_HOTKEY + i] == 0) {
mapping->keys[(key1 + key1_offset - 1) * MAX_KEY_TO_HOTKEY + i] = hotkey;
key1 = 0; // prevent adding same key again
}
if (key2 != 0 && mapping->keys[(key2 + key2_offset - 1) * MAX_KEY_TO_HOTKEY + i] == 0) {
mapping->keys[(key2 + key2_offset - 1) * MAX_KEY_TO_HOTKEY + i] = hotkey;
key2 = 0; // prevent adding same key again
}
mapping->hotkeys[(hotkey - 1)].scan_codes[count++] = key2;
key2 = OMS_ABS_INT16(key2);
}
}
inline
bool hotkey_is_active(const uint8* state_hotkeys, uint8 hotkey)
bool hotkey_is_active(const uint16* active_hotkeys, uint16 hotkey)
{
return state_hotkeys[0] == hotkey
|| state_hotkeys[1] == hotkey
|| state_hotkeys[2] == hotkey
|| state_hotkeys[3] == hotkey
|| state_hotkeys[4] == hotkey;
return active_hotkeys[0] == hotkey
|| active_hotkeys[1] == hotkey
|| active_hotkeys[2] == hotkey
|| active_hotkeys[3] == hotkey
|| active_hotkeys[4] == hotkey;
}
// similar to hotkey_is_active but instead of just performing a lookup in the input_hotkey_state created results
// this is actively checking the current input state (not the hotkey state)
inline
bool hotkey_keys_are_active(const InputKey* state_keys, const InputMapping* mapping, uint8 hotkey)
bool hotkey_keys_are_active(const InputKey* active_keys, const InputMapping* mapping, uint16 hotkey)
{
int16 key0 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION];
int16 key1 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + 1];
int16 key2 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + 2];
int16 key0 = mapping->hotkeys[(hotkey - 1)].scan_codes[0];
int16 key1 = mapping->hotkeys[(hotkey - 1)].scan_codes[1];
int16 key2 = mapping->hotkeys[(hotkey - 1)].scan_codes[2];
if (!key0 && !key1 && !key2) {
return false;
}
// This may seem a little bit confusing but we don't care if a input key is down or up
// Any state means it was used recently BUT NOT YET HANDLED
@ -420,41 +383,43 @@ bool hotkey_keys_are_active(const InputKey* state_keys, const InputMapping* mapp
// Therefore, if a key has a state -> treat it as if active
// The code below also allows optional keys which have a negative sign (at least one of the optional keys must be valid)
bool is_active = input_action_exists(state_keys, (int16) OMS_ABS(key0));
if ((!is_active && (key0 > 0 || key1 >= 0)) || (is_active && key0 < 0)) {
bool is_active = input_action_exists(active_keys, OMS_ABS_INT16(key0), mapping->hotkeys[(hotkey - 1)].key_state);
if ((!is_active && (key0 > 0 || key1 >= 0)) || (is_active && key0 < 0) || (key1 == 0 && key2 == 0)) {
return is_active;
}
is_active = input_action_exists(state_keys, (int16) OMS_ABS(key1));
if ((!is_active && (key1 > 0 || key2 >= 0)) || (is_active && key1 < 0)) {
is_active = input_action_exists(active_keys, OMS_ABS_INT16(key1), mapping->hotkeys[(hotkey - 1)].key_state);
if ((!is_active && (key1 > 0 || key2 >= 0)) || (is_active && key1 < 0) || (key2 == 0)) {
return is_active;
}
return input_action_exists(state_keys, (int16) OMS_ABS(key2));
return input_action_exists(active_keys, OMS_ABS_INT16(key2), mapping->hotkeys[(hotkey - 1)].key_state);
}
inline
void input_set_state(InputKey* state_keys, InputKey* __restrict new_key)
void input_set_state(InputKey* __restrict active_keys, const InputKey* __restrict new_key)
{
InputKey* free_state = NULL;
bool action_required = true;
for (int32 i = 0; i < MAX_KEY_STATES; ++i) {
if (!free_state && state_keys[i].key_id == 0) {
free_state = &state_keys[i];
} else if (state_keys[i].key_id == new_key->key_id) {
state_keys[i].key_state = new_key->key_state;
state_keys[i].value += new_key->value;
state_keys[i].time = new_key->time;
action_required = false;
// Insert new key state or change if key already exists
for (int32 i = 0; i < MAX_KEY_PRESS_TYPES; ++i) {
if (!free_state && active_keys[i].scan_code == 0) {
free_state = &active_keys[i];
} else if (active_keys[i].scan_code == new_key->scan_code) {
active_keys[i].key_state = new_key->key_state;
active_keys[i].value += new_key->value;
active_keys[i].time = new_key->time;
return;
}
}
if (!action_required || !free_state) {
if (!free_state) {
return;
}
free_state->key_id = new_key->key_id;
free_state->scan_code = new_key->scan_code;
free_state->virtual_code = new_key->virtual_code;
free_state->key_state = new_key->key_state;
free_state->value = new_key->value;
free_state->time = new_key->time;
@ -470,15 +435,15 @@ void input_set_controller_state(Input* input, ControllerInput* controller, uint6
{
// Check active keys that might need to be set to inactive
for (int32 i = 0; i < MAX_KEY_PRESSES; ++i) {
if ((input->state.state_keys[i].key_id & INPUT_CONTROLLER_PREFIX)
&& input->state.state_keys[i].key_state != KEY_STATE_RELEASED
if ((input->state.active_keys[i].scan_code & INPUT_CONTROLLER_PREFIX)
&& input->state.active_keys[i].key_state != KEY_PRESS_TYPE_RELEASED
) {
uint32 key_id = input->state.state_keys[i].key_id & ~INPUT_CONTROLLER_PREFIX;
uint32 scan_code = input->state.active_keys[i].scan_code & ~INPUT_CONTROLLER_PREFIX;
if ((controller->is_analog[key_id] && OMS_ABS(controller->button[key_id]) < input->deadzone)
|| (!controller->is_analog[key_id] && controller->button[key_id] == 0)
if ((controller->is_analog[scan_code] && OMS_ABS_INT8(controller->button[scan_code]) < input->deadzone)
|| (!controller->is_analog[scan_code] && controller->button[scan_code] == 0)
) {
input->state.state_keys[i].key_state = KEY_STATE_RELEASED;
input->state.active_keys[i].key_state = KEY_PRESS_TYPE_RELEASED;
}
}
}
@ -486,28 +451,28 @@ void input_set_controller_state(Input* input, ControllerInput* controller, uint6
// Special keys
// @todo this code means we cannot change this behavior (e.g. swap mouse view to dpad, swap sticks, ...)
// @todo This is also not very general, maybe we can fix it like we did with analog vs digital key (instead of bool flag maybe bit flag)
if (OMS_ABS(controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL]) > input->deadzone) {
if (OMS_ABS_INT8(controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL]) > input->deadzone) {
input->state.dx += controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] / 8;
input->state_change_mouse = true;
input->general_states |= INPUT_STATE_GENERAL_MOUSE_CHANGE;
} else {
input->state.dx = 0;
}
if (OMS_ABS(controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL]) > input->deadzone) {
if (OMS_ABS_INT8(controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL]) > input->deadzone) {
input->state.dy += controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] / 8;
input->state_change_mouse = true;
input->general_states |= INPUT_STATE_GENERAL_MOUSE_CHANGE;
} else {
input->state.dy = 0;
}
if (OMS_ABS(controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL]) > input->deadzone) {
if (OMS_ABS_INT8(controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL]) > input->deadzone) {
input->state.dx2 += controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] / 8;
// @todo needs state change flag like mouse?!
} else {
input->state.dx2 = 0;
}
if (OMS_ABS(controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL]) > input->deadzone) {
if (OMS_ABS_INT8(controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL]) > input->deadzone) {
input->state.dy2 += controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] / 8;
// @todo needs state change flag like mouse?!
} else {
@ -519,11 +484,11 @@ void input_set_controller_state(Input* input, ControllerInput* controller, uint6
InputKey keys[5];
for (uint16 i = 0; i < 32; ++i) {
if ((controller->is_analog[i] && OMS_ABS(controller->button[i]) > input->deadzone)
if ((controller->is_analog[i] && OMS_ABS_INT8(controller->button[i]) > input->deadzone)
|| (!controller->is_analog[i] && controller->button[i] != 0)
) {
keys[count].key_id = i | INPUT_CONTROLLER_PREFIX;
keys[count].key_state = KEY_STATE_PRESSED;
keys[count].scan_code = i | INPUT_CONTROLLER_PREFIX;
keys[count].key_state = KEY_PRESS_TYPE_PRESSED;
keys[count].value = controller->button[i];
keys[count].time = time;
@ -533,102 +498,117 @@ void input_set_controller_state(Input* input, ControllerInput* controller, uint6
if (count > 0) {
for (int32 i = 0; i < count; ++i) {
input_set_state(input->state.state_keys, &keys[i]);
input_set_state(input->state.active_keys, &keys[i]);
}
}
input->state_change_button = true;
input->general_states |= INPUT_STATE_GENERAL_BUTTON_CHANGE;
}
void
input_hotkey_state(Input* input)
void input_hotkey_state(Input* input)
{
uint8 old_hotkeys[MAX_KEY_PRESSES];
InputState* state = &input->state;
memset(state->active_hotkeys, 0, sizeof(uint16) * MAX_KEY_PRESSES);
memcpy(old_hotkeys, state->state_hotkeys, sizeof(uint8) * MAX_KEY_PRESSES);
// Check if we have any active keys
if (memcmp(state->active_keys, ((byte *) state->active_keys) + 1, sizeof(state->active_keys) - 1) == 0) {
input_clean_state(state->active_keys);
return;
}
memset(state->state_hotkeys, 0, sizeof(uint8) * MAX_KEY_PRESSES);
// Check typing mode
if (input->general_states & INPUT_STATE_GENERAL_TYPING_MODE) {
// @todo If this function becomes threaded we must maintain the input characters as a persistent state
int32 input_characters = 0;
memset(input->characters, 0, sizeof(uint32) * ARRAY_COUNT(input->characters));
// Create keyboard state array
byte keyboard_state[256] = {};
for (int32 key_state = 0; key_state < MAX_KEY_PRESS_TYPES; ++key_state) {
if (state->active_keys[key_state].scan_code == 0
|| state->active_keys[key_state].key_state == KEY_PRESS_TYPE_RELEASED
) {
// no key defined for this down state
continue;
}
keyboard_state[state->active_keys[key_state].virtual_code & 0x00FF] = 0x80;
}
// Check if all keys result in text, if not -> is potential hotkey -> shouldn't output any text
for (int32 key_state = 0; key_state < MAX_KEY_PRESS_TYPES; ++key_state) {
if ((input->general_states & INPUT_STATE_GENERAL_TYPING_MODE)
&& (state->active_keys[key_state].scan_code & INPUT_KEYBOARD_PREFIX)
&& state->active_keys[key_state].key_state != KEY_PRESS_TYPE_RELEASED
) {
if (input_characters >= ARRAY_COUNT(input->characters)) {
break;
}
uint32 code = key_to_unicode(
state->active_keys[key_state].scan_code & 0x00FF,
state->active_keys[key_state].virtual_code & 0x00FF,
keyboard_state
);
// Is the pressed key a keyboard input
if (!code) {
// Is not text -> we have to reset characters
memset(input->characters, 0, sizeof(uint32) * input_characters);
input_characters = 0;
break;
}
input->characters[input_characters++] = code;
}
}
if (input_characters) {
for (int32 key_state = 0; key_state < MAX_KEY_PRESS_TYPES; ++key_state) {
state->active_keys[key_state].is_processed = true;
state->active_keys[key_state].time = 0; // @todo fix
}
input_clean_state(state->active_keys);
return;
}
}
int32 active_hotkeys = 0;
// Check every key down state
for (int key_state = 0; key_state < MAX_KEY_STATES; ++key_state) {
if (state->state_keys[key_state].key_id == 0
|| state->state_keys[key_state].key_state == KEY_STATE_RELEASED
) {
// no key defined for this down state
continue;
}
// Check every mapping
for (int32 i = 0; i < 2; ++i) {
InputMapping* mapping = i == 0 ? &input->input_mapping1 : &input->input_mapping2;
// Is a key defined for this state AND is at least one hotkey defined for this key
// If no hotkey is defined we don't care
// Careful, remember MAX_MOUSE_KEYS offset
InputKey* key = &state->state_keys[key_state];
int32 internal_key_id = (key->key_id & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX))
+ ((bool) (key->key_id & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
+ ((bool) (key->key_id & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
// Check all possible hotkeys if all of their required keys are active
for (int16 hotkey_idx = 1; hotkey_idx <= mapping->hotkey_count; ++hotkey_idx) {
// We only support a limited amount of active hotkeys
if (active_hotkeys >= MAX_KEY_PRESSES) {
hotkey_idx = mapping->hotkey_count + 1;
i = 2;
break;
}
// Handle 2 input devices (1 = keyboard + mouse, 2 = controller)
// @performance Could it make sense to only loop over one mapping (create a pointer that references the correct mapping)
// We then swap this pointer whenever we detect a input from keyboard+mouse vs controller
// This would allow us even to add context specific mappings
for (int32 i = 0; i < 2; ++i) {
InputMapping* mapping;
if (i == 0) {
mapping = &input->input_mapping1;
} else if ((input->handle_controller || input->direct_controller)
&& key->key_id > INPUT_CONTROLLER_PREFIX
if (hotkey_is_active(state->active_hotkeys, hotkey_idx),
!hotkey_keys_are_active(state->active_keys, mapping, hotkey_idx)
) {
mapping = &input->input_mapping2;
} else {
// Hotkey already active, we don't need to check if it needs to be activated
// Or not all keys for the hotkey are pressed or the KeyPressType is not the same
continue;
}
if (mapping->keys[(internal_key_id - 1) * MAX_KEY_TO_HOTKEY] == 0) {
// no possible hotkey associated with this key
continue;
}
state->active_hotkeys[active_hotkeys++] = hotkey_idx;
const uint8* hotkeys_for_key = mapping->keys + (internal_key_id - 1) * MAX_KEY_TO_HOTKEY;
// Check every possible hotkey
// Since multiple input devices have their own button/key indices whe have to do this weird range handling
for (int32 possible_hotkey_idx = 0; possible_hotkey_idx < MAX_KEY_TO_HOTKEY; ++possible_hotkey_idx) {
// We only support a slimited amount of active hotkeys
if (active_hotkeys >= MAX_KEY_PRESSES) {
return;
}
// Hotkey already active
// @question Do we even need this? This shouldn't happen anyway?!
if (hotkey_is_active(state->state_hotkeys, hotkeys_for_key[possible_hotkey_idx])) {
continue;
}
// store active hotkey, if it is not already active
bool is_pressed = hotkey_keys_are_active(state->state_keys, mapping, hotkeys_for_key[possible_hotkey_idx]);
if (!is_pressed) {
continue;
}
state->state_hotkeys[active_hotkeys] = hotkeys_for_key[possible_hotkey_idx];
++active_hotkeys;
// Run callback if defined
if (input->input_mapping1.callbacks[hotkeys_for_key[possible_hotkey_idx]] != 0
&& old_hotkeys[0] != hotkeys_for_key[possible_hotkey_idx]
&& old_hotkeys[1] != hotkeys_for_key[possible_hotkey_idx]
&& old_hotkeys[2] != hotkeys_for_key[possible_hotkey_idx]
&& old_hotkeys[3] != hotkeys_for_key[possible_hotkey_idx]
&& old_hotkeys[4] != hotkeys_for_key[possible_hotkey_idx]
) {
input->input_mapping1.callbacks[hotkeys_for_key[possible_hotkey_idx]](input->callback_data);
}
// Run callback if defined
if (mapping->hotkeys[hotkey_idx].callback != 0) {
mapping->hotkeys[hotkey_idx].callback(input->callback_data);
}
}
}
input_clean_state(state->active_keys);
// @bug how to handle priority? e.g. there might be a hotkey for 1 and one for alt+1
// in this case only the hotkey for alt+1 should be triggered
// @bug how to handle other conditions besides buttons pressed together? some hotkeys are only available in certain situations
@ -639,10 +619,11 @@ input_hotkey_state(Input* input)
// It doesn't always happen but you can test it rather consistently within a couple of seconds
}
bool input_key_is_longpress(InputState* state, uint16 key, uint64 time, f32 dt = 0.0f) {
for (int32 i = 0; i < MAX_KEY_STATES; ++i) {
if (state->state_keys[i].key_id == key) {
return (f32) (time - state->state_keys[i].time) / 1000.0f >= (dt == 0.0f ? INPUT_LONG_PRESS_DURATION : dt);
// @todo We probably need a way to unset a specific key and hotkey after processing it
bool input_key_is_longpress(const InputState* state, int16 key, uint64 time, f32 dt = 0.0f) {
for (int32 i = 0; i < MAX_KEY_PRESS_TYPES; ++i) {
if (state->active_keys[i].scan_code == key) {
return (f32) (time - state->active_keys[i].time) / 1000.0f >= (dt == 0.0f ? INPUT_LONG_PRESS_DURATION : dt);
}
}
@ -650,10 +631,10 @@ bool input_key_is_longpress(InputState* state, uint16 key, uint64 time, f32 dt =
}
// @todo I wrote this code at 9am after staying awake for the whole night and that is how that code looks like... fix it!
bool input_hotkey_is_longpress(Input* input, uint8 hotkey, uint64 time, f32 dt = 0.0f) {
bool input_hotkey_is_longpress(const Input* input, uint8 hotkey, uint64 time, f32 dt = 0.0f) {
bool is_longpress = false;
for (int32 i = 0; i < MAX_KEY_PRESSES; ++i) {
if (input->state.state_hotkeys[i] != hotkey) {
if (input->state.active_hotkeys[i] != hotkey) {
continue;
}
@ -662,8 +643,8 @@ bool input_hotkey_is_longpress(Input* input, uint8 hotkey, uint64 time, f32 dt =
for (int32 j = 0; j < MAX_HOTKEY_COMBINATION; ++j) {
bool potential_miss = true;
bool both_empty = false;
if (input->input_mapping1.hotkeys[hotkey * MAX_HOTKEY_COMBINATION + j] > 0) {
if(!input_key_is_longpress(&input->state, input->input_mapping1.hotkeys[hotkey + j], time, dt)) {
if (input->input_mapping1.hotkeys[hotkey].scan_codes[j] > 0) {
if(!input_key_is_longpress(&input->state, input->input_mapping1.hotkeys[hotkey].scan_codes[j], time, dt)) {
potential_miss = true;
} else {
potential_miss = false;
@ -676,8 +657,8 @@ bool input_hotkey_is_longpress(Input* input, uint8 hotkey, uint64 time, f32 dt =
continue;
}
if (input->input_mapping2.hotkeys[hotkey * MAX_HOTKEY_COMBINATION + j] > 0) {
if(!input_key_is_longpress(&input->state, input->input_mapping2.hotkeys[hotkey + j], time, dt)) {
if (input->input_mapping2.hotkeys[hotkey].scan_codes[j] > 0) {
if(!input_key_is_longpress(&input->state, input->input_mapping2.hotkeys[hotkey].scan_codes[j], time, dt)) {
potential_miss = true;
} else {
potential_miss = false;
@ -697,4 +678,48 @@ bool input_hotkey_is_longpress(Input* input, uint8 hotkey, uint64 time, f32 dt =
return is_longpress;
}
uint32 input_get_typed_character(InputState* state, uint64 time, uint64 dt)
{
byte keyboard_state[256] = {};
for (int32 key_state = 0; key_state < MAX_KEY_PRESS_TYPES; ++key_state) {
if (state->active_keys[key_state].scan_code == 0
|| state->active_keys[key_state].key_state == KEY_PRESS_TYPE_RELEASED
) {
// no key defined for this down state
continue;
}
keyboard_state[state->active_keys[key_state].virtual_code & 0x00FF] = 0x80;
}
for (int32 key_state = 0; key_state < MAX_KEY_PRESS_TYPES; ++key_state) {
if (state->active_keys[key_state].scan_code == 0
|| (state->active_keys[key_state].is_processed
&& state->active_keys[key_state].time - time <= dt)
) {
// no key defined for this down state
// key is already released
// key was already processed and is not yet eligible for continuous output
continue;
}
uint32 code = key_to_unicode(
state->active_keys[key_state].scan_code & 0x00FF,
state->active_keys[key_state].virtual_code & 0x00FF,
keyboard_state
);
if (code) {
// We are not outputting a repeat character multiple times in low fps situations.
// It is annoying as a user to suddenly have 10s of repeated character just because the game lagged
state->active_keys[key_state].is_processed = true;
state->active_keys[key_state].time = time;
return code;
}
}
return 0;
}
#endif

View File

@ -8,7 +8,6 @@
#include "TimingStat.h"
#include "../utils/StringUtils.h"
#include "../utils/TestUtils.h"
#include "../utils/MathUtils.h"
#include "../thread/Atomic.h"
// Required for rdtsc();
@ -69,34 +68,24 @@ void log_to_file()
#if _WIN32
DWORD written;
if (!WriteFile(
WriteFile(
debug_container->log_fp,
(char *) debug_container->log_memory.memory,
(uint32) debug_container->log_memory.pos - 1,
(uint32) debug_container->log_memory.pos,
&written,
NULL
)) {
CloseHandle(debug_container->log_fp);
}
);
#else
if (debug_container->log_fp < 0) {
return;
}
if (!write(
write(
debug_container->log_fp,
(char *) debug_container->log_memory.memory,
(uint32) debug_container->log_memory.pos - 1
)) {
close(debug_container->log_fp);
}
(uint32) debug_container->log_memory.pos
);
#endif
memset(debug_container->log_memory.memory, 0, debug_container->log_memory.size);
// reset log position to start of memory pool
debug_container->log_memory.pos = 0;
debug_container->log_memory.start = 0;
}
// IMPORTANT: This function should only be called when you actually use this data
@ -184,9 +173,8 @@ void log_counter(int32 id, int64 value)
atomic_set_acquire(&debug_container->counter[id], value);
}
// @todo don't use a pointer to this should be in a global together with other logging data (see Log.h)
inline
DebugMemory* debug_memory_find(uint64 start)
DebugMemory* debug_memory_find(uintptr_t start)
{
for (uint64 i = 0; i < debug_container->dmc.memory_size; ++i) {
if (debug_container->dmc.memory_stats[i].start <= start
@ -199,7 +187,7 @@ DebugMemory* debug_memory_find(uint64 start)
return NULL;
}
void debug_memory_init(uint64 start, uint64 size)
void debug_memory_init(uintptr_t start, uint64 size)
{
if (!start || !debug_container) {
return;
@ -231,7 +219,7 @@ void debug_memory_init(uint64 start, uint64 size)
++dmc->memory_element_idx;
}
void debug_memory_log(uint64 start, uint64 size, int32 type, const char* function)
void debug_memory_log(uintptr_t start, uint64 size, int32 type, const char* function)
{
if (!start || !debug_container) {
return;
@ -263,7 +251,7 @@ void debug_memory_log(uint64 start, uint64 size, int32 type, const char* functio
}
}
void debug_memory_reserve(uint64 start, uint64 size, int32 type, const char* function)
void debug_memory_reserve(uintptr_t start, uint64 size, int32 type, const char* function)
{
if (!start || !debug_container) {
return;
@ -290,7 +278,7 @@ void debug_memory_reserve(uint64 start, uint64 size, int32 type, const char* fun
}
// undo reserve
void debug_memory_free(uint64 start, uint64 size)
void debug_memory_free(uintptr_t start, uint64 size)
{
if (!start || !debug_container) {
return;
@ -331,124 +319,118 @@ void debug_memory_reset()
}
// @bug This probably requires thread safety
byte* log_get_memory(uint64 size, byte aligned = 4, bool zeroed = false)
byte* log_get_memory()
{
if (!debug_container) {
return 0;
}
LogMemory* log_mem = &debug_container->log_memory;
ASSERT_SIMPLE(size <= log_mem->size);
if (aligned > 1) {
uintptr_t address = (uintptr_t) log_mem->memory;
log_mem->pos += (aligned - ((address + log_mem->pos) & (aligned - 1))) % aligned;
}
size = ROUND_TO_NEAREST(size, aligned);
if (log_mem->pos + size > log_mem->size) {
if (log_mem->pos + MAX_LOG_LENGTH > log_mem->size) {
log_mem->pos = 0;
if (aligned > 1) {
uintptr_t address = (uintptr_t) log_mem->memory;
log_mem->pos += (aligned - ((address + log_mem->pos) & (aligned - 1))) % aligned;
}
}
byte* offset = (byte *) (log_mem->memory + log_mem->pos);
if (zeroed) {
memset((void *) offset, 0, size);
}
memset((void *) offset, 0, MAX_LOG_LENGTH);
log_mem->pos += size;
log_mem->pos += MAX_LOG_LENGTH;
return offset;
}
// @todo add file name, function name and function line
void log(const char* str, bool should_log, bool save, const char* file, const char* function, int32 line)
void log(const char* str, bool should_log, const char* file, const char* function, int32 line)
{
if (!should_log || !debug_container) {
return;
}
size_t str_len = OMS_MIN(strlen(str), MAX_LOG_LENGTH - 128);
size_t file_len = strlen(file);
size_t function_len = strlen(function);
int64 len = strlen(str);
while (len > 0) {
LogMessage* msg = (LogMessage *) log_get_memory();
char line_str[14];
uint_to_str(line, line_str);
// Fill file
msg->file = file;
msg->function = function;
msg->line = line;
msg->message = (char *) (msg + 1);
size_t line_len = strlen(line_str);
int32 message_length = (int32) OMS_MIN(MAX_LOG_LENGTH - sizeof(LogMessage) - 1, len);
ASSERT_SIMPLE(str_len + file_len + function_len + line_len + 3 < MAX_LOG_LENGTH);
memcpy(msg->message, str, message_length);
msg->message[message_length] = '\0';
str += message_length;
len -= MAX_LOG_LENGTH - sizeof(LogMessage);
char* temp = (char *) log_get_memory(str_len + file_len + function_len + line_len + 3 + 1);
memcpy(temp, file, file_len);
temp[file_len] = ';';
memcpy(&temp[file_len], function, function_len);
temp[file_len + 1 + function_len] = ';';
memcpy(&temp[file_len + 1 + function_len], line_str, line_len);
temp[file_len + 1 + function_len + 1 + line_len] = ';';
memcpy(&temp[file_len + 1 + function_len + 1 + line_len + 1], str, str_len);
temp[file_len + 1 + function_len + 1 + line_len + 1 + str_len] = '\0';
if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) {
log_to_file();
if (debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) {
log_to_file();
debug_container->log_memory.pos = 0;
}
}
}
void log(const char* format, LogDataType data_type, void* data, bool should_log, bool save, const char* file, const char* function, int32 line)
void log(const char* format, LogDataArray data, bool should_log, const char* file, const char* function, int32 line)
{
ASSERT_SIMPLE(strlen(format) + strlen(file) + strlen(function) + 50 < MAX_LOG_LENGTH);
if (!should_log || !debug_container) {
return;
}
if (data_type == LOG_DATA_VOID) {
log(format, should_log, save, file, function, line);
if (data.data[0].type == LOG_DATA_VOID) {
log(format, should_log, file, function, line);
return;
}
char* temp = (char *) log_get_memory(MAX_LOG_LENGTH);
LogMessage* msg = (LogMessage *) log_get_memory();
msg->file = file;
msg->function = function;
msg->line = line;
msg->message = (char *) (msg + 1);
switch (data_type) {
case LOG_DATA_INT32: {
sprintf(temp, format, *((int32 *) data));
} break;
case LOG_DATA_UINT32: {
sprintf(temp, format, *((uint32 *) data));
} break;
case LOG_DATA_INT64: {
sprintf(temp, format, *((int64 *) data));
} break;
case LOG_DATA_UINT64: {
sprintf(temp, format, *((uint64 *) data));
} break;
case LOG_DATA_CHAR: {
sprintf(temp, format, *((char *) data));
} break;
case LOG_DATA_CHAR_STR: {
sprintf(temp, format, *((char *) data));
} break;
case LOG_DATA_FLOAT32: {
sprintf(temp, format, *((f32 *) data));
} break;
case LOG_DATA_FLOAT64: {
sprintf(temp, format, *((f64 *) data));
} break;
default: {
UNREACHABLE();
char temp_format[MAX_LOG_LENGTH];
str_copy_short(msg->message, format);
for (int32 i = 0; i < LOG_DATA_ARRAY; ++i) {
if (data.data[i].type == LOG_DATA_VOID) {
break;
}
str_copy_short(temp_format, msg->message);
switch (data.data[i].type) {
case LOG_DATA_BYTE: {
sprintf_fast_iter(msg->message, temp_format, (int32) *((byte *) data.data[i].value));
} break;
case LOG_DATA_INT32: {
sprintf_fast_iter(msg->message, temp_format, *((int32 *) data.data[i].value));
} break;
case LOG_DATA_UINT32: {
sprintf_fast_iter(msg->message, temp_format, *((uint32 *) data.data[i].value));
} break;
case LOG_DATA_INT64: {
sprintf_fast_iter(msg->message, temp_format, *((int64 *) data.data[i].value));
} break;
case LOG_DATA_UINT64: {
sprintf_fast_iter(msg->message, temp_format, *((uint64 *) data.data[i].value));
} break;
case LOG_DATA_CHAR: {
sprintf_fast_iter(msg->message, temp_format, *((char *) data.data[i].value));
} break;
case LOG_DATA_CHAR_STR: {
sprintf_fast_iter(msg->message, temp_format, (const char *) data.data[i].value);
} break;
case LOG_DATA_FLOAT32: {
sprintf_fast_iter(msg->message, temp_format, *((f32 *) data.data[i].value));
} break;
case LOG_DATA_FLOAT64: {
sprintf_fast_iter(msg->message, temp_format, *((f64 *) data.data[i].value));
} break;
default: {
UNREACHABLE();
}
}
}
if (save || debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) {
if (debug_container->log_memory.size - debug_container->log_memory.pos < MAX_LOG_LENGTH) {
log_to_file();
debug_container->log_memory.pos = 0;
}
ASSERT_SIMPLE(false);
}
#endif

View File

@ -18,15 +18,56 @@
#include <windows.h>
#endif
#ifndef MAX_LOG_LENGTH
#define MAX_LOG_LENGTH 256
#endif
#ifndef MAX_LOG_MESSAGES
#define MAX_LOG_MESSAGES 256
#endif
#ifndef LOG_LEVEL
#define LOG_LEVEL 0
#endif
#define LOG_DATA_ARRAY 5
enum LogDataType {
LOG_DATA_NONE,
LOG_DATA_VOID,
LOG_DATA_BYTE,
LOG_DATA_INT32,
LOG_DATA_UINT32,
LOG_DATA_INT64,
LOG_DATA_UINT64,
LOG_DATA_CHAR,
LOG_DATA_CHAR_STR,
LOG_DATA_FLOAT32,
LOG_DATA_FLOAT64
};
struct LogMemory {
byte* memory;
uint32 id;
uint64 size;
uint64 pos;
uint32 alignment;
uint64 start;
uint64 end;
};
struct LogMessage {
const char* file;
const char* function;
int32 line;
uint64 time;
char* message;
};
struct LogData {
LogDataType type;
void* value;
};
struct LogDataArray{
LogData data[LOG_DATA_ARRAY];
};
struct DebugContainer {

View File

@ -16,7 +16,7 @@
struct DebugMemoryRange {
int32 type;
uint64 start;
uintptr_t start;
uint64 size;
uint64 time;
@ -25,7 +25,7 @@ struct DebugMemoryRange {
struct DebugMemory {
uint64 usage;
uint64 start;
uintptr_t start;
uint64 size;
uint64 action_idx;
@ -42,10 +42,10 @@ struct DebugMemoryContainer {
};
#if DEBUG || INTERNAL
void debug_memory_init(uint64, uint64);
void debug_memory_log(uint64, uint64, int32, const char*);
void debug_memory_reserve(uint64, uint64, int32, const char*);
void debug_memory_free(uint64, uint64);
void debug_memory_init(uintptr_t, uint64);
void debug_memory_log(uintptr_t, uint64, int32, const char*);
void debug_memory_reserve(uintptr_t, uint64, int32, const char*);
void debug_memory_free(uintptr_t, uint64);
void debug_memory_reset();
#define DEBUG_MEMORY_INIT(start, size) debug_memory_init((start), (size))

View File

@ -13,63 +13,37 @@
#include "../stdlib/Types.h"
#include "Debug.h"
#ifndef MAX_LOG_LENGTH
#define MAX_LOG_LENGTH 1024
#endif
enum LogDataType {
LOG_DATA_VOID,
LOG_DATA_INT32,
LOG_DATA_UINT32,
LOG_DATA_INT64,
LOG_DATA_UINT64,
LOG_DATA_CHAR,
LOG_DATA_CHAR_STR,
LOG_DATA_FLOAT32,
LOG_DATA_FLOAT64
};
void log_to_file();
void log(const char* str, bool should_log, bool save, const char* file, const char* function, int32 line);
void log(const char* format, LogDataType data_type, void* data, bool should_log, bool save, const char* file, const char* function, int32 line);
void log(const char* str, bool should_log, const char* file, const char* function, int32 line);
void log(const char* format, LogDataArray data, bool should_log, const char* file, const char* function, int32 line);
void log_increment(int32, int64);
void log_counter(int32, int64);
#define LOG_PERFORMANCE_START(time_start) \
({ \
time_start = __rdtsc(); \
})
#define LOG(should_log, str) log((str), (should_log), __FILE__, __func__, __LINE__)
#define LOG_FORMAT(should_log, format, ...) log((format), LogDataArray{__VA_ARGS__}, (should_log), __FILE__, __func__, __LINE__)
#define LOG_TO_FILE() log_to_file()
#define LOG_PERFORMANCE_END(time_start) \
({ \
printf("%ld\n", __rdtsc() - (time_start)); \
})
#if LOG_LEVEL == 2
#define LOG_LEVEL_1(format, ...) log((format), LogDataArray{__VA_ARGS__}, true, __FILE__, __func__, __LINE__)
#define LOG_LEVEL_2(format, ...) log((format), LogDataArray{__VA_ARGS__}, true, __FILE__, __func__, __LINE__)
#elif LOG_LEVEL == 1
#define LOG_LEVEL_1(format, ...) log((format), LogDataArray{__VA_ARGS__}, true, __FILE__, __func__, __LINE__)
#define LOG_LEVEL_2(format, ...) ((void) 0)
#elif LOG_LEVEL == 0
#define LOG_LEVEL_1(format, ...) ((void) 0)
#define LOG_LEVEL_2(format, ...) ((void) 0)
#endif
#if (!DEBUG && !INTERNAL) || RELEASE
// Don't perform any logging at log level 0
#define LOG(str, should_log, save) log((str), (should_log), (save), __FILE__, __func__, __LINE__)
#define LOG_FORMAT(format, data_type, data, should_log, save) log((format), (data_type), (data), (should_log), (save), __FILE__, __func__, __LINE__)
#define LOG_TO_FILE() ((void) 0)
#define LOG_INCREMENT(a) ((void) 0)
#define LOG_INCREMENT_BY(a, b) ((void) 0)
#define LOG_COUNTER(a, b) ((void) 0)
#define RESET_COUNTER(a) ((void) 0)
#else
#define LOG(str, should_log, save) log((str), (should_log), (save), __FILE__, __func__, __LINE__)
#define LOG_FORMAT(format, data_type, data, should_log, save) log((format), (data_type), (data), (should_log), (save), __FILE__, __func__, __LINE__)
#define LOG_TO_FILE() log_to_file()
#define LOG_INCREMENT(a) log_increment((a), 1)
#define LOG_INCREMENT_BY(a, b) log_increment((a), (b))
#define LOG_COUNTER(a, b) log_counter((a), (b))
#define RESET_COUNTER(a) reset_counter((a))
#endif
#if DEBUG
#define DEBUG_LOG(str, should_log, save) log((str), (should_log), (save), __FILE__, __func__, __LINE__)
#define DEBUG_LOG_FORMAT(format, data_type, data, should_log, save) log((format), (data_type), (data), (should_log), (save), __FILE__, __func__, __LINE__)
#else
#define DEBUG_LOG(str, should_log, save) ((void) 0)
#define DEBUG_LOG_FORMAT(format, data_type, data, should_log, save) ((void) 0)
#endif
#endif

View File

@ -12,7 +12,6 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "../../utils/MathUtils.h"
#include "../../utils/TestUtils.h"
#if ARM
@ -345,7 +344,7 @@ void mat4_identity(__m128* matrix)
// https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
void mat4_rotation(f32* matrix, f32 x, f32 y, f32 z, f32 angle)
{
ASSERT_SIMPLE(OMS_ABS(x * x + y * y + z * z - 1.0f) < 0.01);
ASSERT_SIMPLE(OMS_ABS_F32(x * x + y * y + z * z - 1.0f) < 0.01);
// @todo replace with quaternions
f32 s = sinf(angle);

View File

@ -9,8 +9,6 @@
#ifndef TOS_MATH_MATRIX_INT32_H
#define TOS_MATH_MATRIX_INT32_H
#include "../../utils/MathUtils.h"
#if ARM
#include "../../stdlib/IntrinsicsArm.h"
#else

View File

@ -9,8 +9,6 @@
#ifndef TOS_MATH_MATRIX_INT64_H
#define TOS_MATH_MATRIX_INT64_H
#include "../../utils/MathUtils.h"
#if ARM
#include "../../stdlib/IntrinsicsArm.h"
#else

View File

@ -10,7 +10,6 @@
#ifndef TOS_MATH_MATRIX_QUATERNION_FLOAT32_H
#define TOS_MATH_MATRIX_QUATERNION_FLOAT32_H
#include "../../utils/MathUtils.h"
#include "../../utils/TestUtils.h"
#include "MatrixFloat32.h"
@ -97,7 +96,7 @@ void quaternion_to_euler(const v4_f32* __restrict quat, v3_f32* __restrict v) {
v->pitch = atan2f(sinp, cosp);
// Check for gimbal lock
if (OMS_ABS(sinp) >= 0.9999f) {
if (OMS_ABS_F32(sinp) >= 0.9999f) {
v->yaw = atan2f(quat->x * quat->z - quat->w * quat->y, quat->w * quat->x + quat->y * quat->z);
v->roll = 0.0f;
} else {
@ -225,7 +224,7 @@ void quaternion_rotate_vector(v3_f32* __restrict vec, const v4_f32* __restrict q
inline
void quaternion_rotate_active(v4_f32* __restrict p, const v4_f32* __restrict quat, const v4_f32* __restrict quat_inv)
{
//ASSERT_SIMPLE(OMS_ABS(x * x + y * y + z * z + w * z - 1.0f) < 0.01);
//ASSERT_SIMPLE(OMS_ABS_F32(x * x + y * y + z * z + w * z - 1.0f) < 0.01);
v4_f32 p_tmp;
quaternion_multiply(&p_tmp, quat_inv, p);
@ -236,7 +235,7 @@ void quaternion_rotate_active(v4_f32* __restrict p, const v4_f32* __restrict qua
inline
void quaternion_rotate_passive(v4_f32* __restrict p, const v4_f32* __restrict quat, const v4_f32* __restrict quat_inv)
{
//ASSERT_SIMPLE(OMS_ABS(x * x + y * y + z * z + w * w - 1.0f) < 0.01);
//ASSERT_SIMPLE(OMS_ABS_F32(x * x + y * y + z * z + w * w - 1.0f) < 0.01);
v4_f32 p_tmp;
quaternion_multiply(&p_tmp, quat, p);

View File

@ -9,7 +9,6 @@
#ifndef TOS_MATH_MATRIX_VECTOR_FLOAT32_H
#define TOS_MATH_MATRIX_VECTOR_FLOAT32_H
#include "../../utils/MathUtils.h"
#include "../../stdlib/Simd.h"
struct v3_f32_4 {

View File

@ -9,7 +9,6 @@
#ifndef TOS_MATH_MATRIX_VECTOR_FLOAT64_H
#define TOS_MATH_MATRIX_VECTOR_FLOAT64_H
#include "../../utils/MathUtils.h"
#include "../../stdlib/Simd.h"
#endif

View File

@ -12,7 +12,6 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../../utils/MathUtils.h"
#include "../../stdlib/Simd.h"
struct v3_int32_4 {

View File

@ -12,7 +12,6 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../../utils/MathUtils.h"
#include "../../stdlib/Simd.h"
struct v3_int64_2 {

View File

@ -11,7 +11,6 @@
#include <string.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
#include "../utils/EndianUtils.h"
#include "../utils/TestUtils.h"
#include "../log/DebugMemory.h"
@ -46,13 +45,15 @@ void buffer_alloc(BufferMemory* buf, uint64 size, int32 alignment = 64)
memset(buf->memory, 0, buf->size);
DEBUG_MEMORY_INIT((uint64) buf->memory, size);
DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size);
LOG_INCREMENT_BY(DEBUG_COUNTER_MEM_ALLOC, buf->size);
LOG_LEVEL_2("Allocated BufferMemory: %n B", {{LOG_DATA_UINT64, &buf->size}});
}
inline
void buffer_free(BufferMemory* buf)
{
DEBUG_MEMORY_DELETE((uint64) buf->memory, buf->size);
DEBUG_MEMORY_DELETE((uintptr_t) buf->memory, buf->size);
if (buf->alignment < 2) {
platform_free((void **) &buf->memory);
} else {
@ -74,15 +75,15 @@ void buffer_init(BufferMemory* buf, byte* data, uint64 size, int32 alignment = 6
buf->alignment = alignment;
buf->element_alignment = 0;
DEBUG_MEMORY_INIT((uint64) buf->memory, buf->size);
DEBUG_MEMORY_RESERVE((uint64) buf->memory, buf->size, 187);
DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size);
DEBUG_MEMORY_RESERVE((uintptr_t) buf->memory, buf->size, 187);
}
inline
void buffer_reset(BufferMemory* buf)
{
// @bug aren't we wasting element 0 (see get_memory, we are not using 0 only next element)
DEBUG_MEMORY_DELETE((uint64) buf->memory, buf->head - buf->memory);
DEBUG_MEMORY_DELETE((uintptr_t) buf->memory, buf->head - buf->memory);
buf->head = buf->memory;
}
@ -107,7 +108,7 @@ byte* buffer_get_memory(BufferMemory* buf, uint64 size, int32 aligned = 4, bool
memset((void *) buf->head, 0, size);
}
DEBUG_MEMORY_WRITE((uint64) buf->head, size);
DEBUG_MEMORY_WRITE((uintptr_t) buf->head, size);
byte* offset = buf->head;
buf->head += size;

View File

@ -11,7 +11,6 @@
#include <string.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
#include "../utils/TestUtils.h"
#include "../utils/EndianUtils.h"
#include "../utils/BitUtils.h"
@ -58,7 +57,9 @@ void chunk_alloc(ChunkMemory* buf, uint32 count, uint32 chunk_size, int32 alignm
memset(buf->memory, 0, buf->size);
DEBUG_MEMORY_INIT((uint64) buf->memory, buf->size);
DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size);
LOG_INCREMENT_BY(DEBUG_COUNTER_MEM_ALLOC, buf->size);
LOG_LEVEL_2("Allocated ChunkMemory: %n B", {{LOG_DATA_UINT64, &buf->size}});
}
inline
@ -82,8 +83,8 @@ void chunk_init(ChunkMemory* buf, BufferMemory* data, uint32 count, uint32 chunk
// On another hand we could by accident overwrite the values in free if we are not careful
buf->free = (uint64 *) (buf->memory + count * chunk_size);
DEBUG_MEMORY_INIT((uint64) buf->memory, buf->size);
DEBUG_MEMORY_RESERVE((uint64) buf->memory, buf->size, 187);
DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size);
DEBUG_MEMORY_RESERVE((uintptr_t) buf->memory, buf->size, 187);
}
inline
@ -108,14 +109,14 @@ void chunk_init(ChunkMemory* buf, byte* data, uint32 count, uint32 chunk_size, i
// On another hand we could by accident overwrite the values in free if we are not careful
buf->free = (uint64 *) (buf->memory + count * chunk_size);
DEBUG_MEMORY_INIT((uint64) buf->memory, buf->size);
DEBUG_MEMORY_RESERVE((uint64) buf->memory, buf->size, 187);
DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size);
DEBUG_MEMORY_RESERVE((uintptr_t) buf->memory, buf->size, 187);
}
inline
void chunk_free(ChunkMemory* buf)
{
DEBUG_MEMORY_DELETE((uint64) buf->memory, buf->size);
DEBUG_MEMORY_DELETE((uintptr_t) buf->memory, buf->size);
if (buf->alignment < 2) {
platform_free((void **) &buf->memory);
} else {
@ -138,7 +139,7 @@ byte* chunk_get_element(ChunkMemory* buf, uint64 element, bool zeroed = false)
memset((void *) offset, 0, buf->chunk_size);
}
DEBUG_MEMORY_READ((uint64) offset, buf->chunk_size);
DEBUG_MEMORY_READ((uintptr_t) offset, buf->chunk_size);
return offset;
}
@ -246,7 +247,7 @@ int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1)
return -1;
}
DEBUG_MEMORY_WRITE((uint64) (buf->memory + free_element * buf->chunk_size), elements * buf->chunk_size);
DEBUG_MEMORY_WRITE((uintptr_t) (buf->memory + free_element * buf->chunk_size), elements * buf->chunk_size);
buf->last_pos = free_element;
@ -256,14 +257,14 @@ int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1)
inline
void chunk_free_element(ChunkMemory* buf, uint64 free_index, int32 bit_index)
{
DEBUG_MEMORY_DELETE((uint64) (buf->memory + (free_index * 64 + bit_index) * buf->chunk_size), buf->chunk_size);
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + (free_index * 64 + bit_index) * buf->chunk_size), buf->chunk_size);
buf->free[free_index] &= ~(1LL << bit_index);
}
inline
void chunk_free_elements(ChunkMemory* buf, uint64 element, uint32 element_count = 1)
{
DEBUG_MEMORY_DELETE((uint64) (buf->memory + element * buf->chunk_size), buf->chunk_size);
DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + element * buf->chunk_size), buf->chunk_size);
int64 free_index = element / 64;
int32 bit_index = element & 63;
@ -349,6 +350,8 @@ int64 chunk_load(ChunkMemory* buf, const byte* data)
buf->free = (uint64 *) (buf->memory + buf->count * buf->chunk_size);
LOG_LEVEL_2("Loaded ChunkMemory: %n B", {{LOG_DATA_UINT64, &buf->size}});
return buf->size;
}

View File

@ -39,12 +39,12 @@ void heap_alloc(Heap* heap, uint32 element_size, uint64 capacity, int32 (*compar
heap->compare = compare;
heap->helper_mem = heap->elements + element_size;
DEBUG_MEMORY_INIT((uint64) heap->elements, element_size * capacity);
DEBUG_MEMORY_INIT((uintptr_t) heap->elements, element_size * capacity);
}
void heap_free(Heap* heap)
{
DEBUG_MEMORY_DELETE((uint64) heap->elements, heap->element_size * heap->capacity);
DEBUG_MEMORY_DELETE((uintptr_t) heap->elements, heap->element_size * heap->capacity);
platform_free((void **) &heap->elements);
}
@ -61,7 +61,7 @@ void heap_init(Heap* heap, BufferMemory* buf, uint32 element_size, uint64 capaci
heap->size = 0;
heap->compare = compare;
DEBUG_MEMORY_INIT((uint64) heap->elements, element_size * capacity);
DEBUG_MEMORY_INIT((uintptr_t) heap->elements, element_size * capacity);
}
void heapify_down(Heap* heap, uint64 index) {
@ -127,7 +127,7 @@ void heap_pop(Heap* heap, void* out) {
return;
}
DEBUG_MEMORY_READ((uint64) heap->elements, heap->element_size);
DEBUG_MEMORY_READ((uintptr_t) heap->elements, heap->element_size);
memcpy(out, heap->elements, heap->element_size);
void* last_element = heap->elements + ((heap->size - 1) * heap->element_size);
@ -138,7 +138,7 @@ void heap_pop(Heap* heap, void* out) {
inline
void* heap_peek(Heap* heap) {
DEBUG_MEMORY_READ((uint64) heap->elements, heap->element_size);
DEBUG_MEMORY_READ((uintptr_t) heap->elements, heap->element_size);
return heap->elements;
}

View File

@ -13,7 +13,6 @@
#include <immintrin.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
#include "../utils/EndianUtils.h"
#include "../utils/TestUtils.h"
@ -59,7 +58,9 @@ void ring_alloc(RingMemory* ring, uint64 size, uint32 alignment = 64)
memset(ring->memory, 0, ring->size);
DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size);
DEBUG_MEMORY_INIT((uintptr_t) ring->memory, ring->size);
LOG_INCREMENT_BY(DEBUG_COUNTER_MEM_ALLOC, ring->size);
LOG_LEVEL_2("Allocated RingMemory: %n B", {{LOG_DATA_UINT64, &ring->size}});
}
inline
@ -75,8 +76,8 @@ void ring_init(RingMemory* ring, BufferMemory* buf, uint64 size, uint32 alignmen
ring->size = size;
ring->alignment = alignment;
DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size);
DEBUG_MEMORY_RESERVE((uint64) ring->memory, ring->size, 187);
DEBUG_MEMORY_INIT((uintptr_t) ring->memory, ring->size);
DEBUG_MEMORY_RESERVE((uintptr_t) ring->memory, ring->size, 187);
}
inline
@ -94,8 +95,8 @@ void ring_init(RingMemory* ring, byte* buf, uint64 size, uint32 alignment = 64)
memset(ring->memory, 0, ring->size);
DEBUG_MEMORY_INIT((uint64) ring->memory, ring->size);
DEBUG_MEMORY_RESERVE((uint64) ring->memory, ring->size, 187);
DEBUG_MEMORY_INIT((uintptr_t) ring->memory, ring->size);
DEBUG_MEMORY_RESERVE((uintptr_t) ring->memory, ring->size, 187);
}
inline
@ -134,7 +135,7 @@ byte* ring_calculate_position(const RingMemory* ring, uint64 size, uint32 aligne
inline
void ring_reset(RingMemory* ring)
{
DEBUG_MEMORY_DELETE((uint64) ring->memory, ring->size);
DEBUG_MEMORY_DELETE((uintptr_t) ring->memory, ring->size);
ring->head = ring->memory;
}
@ -145,7 +146,7 @@ void ring_move_pointer(RingMemory* ring, byte** pos, uint64 size, uint32 aligned
// Actually, we cannot be sure that this is a read, it could also be a write.
// However, we better do it once here than manually in every place that uses this function
DEBUG_MEMORY_READ((uint64) *pos, size);
DEBUG_MEMORY_READ((uintptr_t) *pos, size);
if (aligned > 1) {
uintptr_t address = (uintptr_t) *pos;
@ -188,7 +189,7 @@ byte* ring_get_memory(RingMemory* ring, uint64 size, uint32 aligned = 4, bool ze
memset((void *) ring->head, 0, size);
}
DEBUG_MEMORY_WRITE((uint64) ring->head, size);
DEBUG_MEMORY_WRITE((uintptr_t) ring->head, size);
byte* offset = ring->head;
ring->head += size;
@ -224,7 +225,7 @@ byte* ring_get_memory_nomove(RingMemory* ring, uint64 size, uint32 aligned = 4,
memset((void *) pos, 0, size);
}
DEBUG_MEMORY_WRITE((uint64) pos, size);
DEBUG_MEMORY_WRITE((uintptr_t) pos, size);
return pos;
}
@ -236,7 +237,7 @@ byte* ring_get_element(const RingMemory* ring, uint64 element_count, uint64 elem
{
int64 index = (element % element_count) - 1;
DEBUG_MEMORY_READ((uint64) (ring->memory + index * size), 1);
DEBUG_MEMORY_READ((uintptr_t) (ring->memory + index * size), 1);
return ring->memory + index * size;
}

View File

@ -9,7 +9,6 @@
#ifndef TOS_MODELS_MOB_C
#define TOS_MODELS_MOB_C
#include "../../utils/MathUtils.h"
#include "Mob.h"
#include "MobState.h"

View File

@ -11,7 +11,6 @@
#include "../../../stdlib/Types.h"
#include "../../../utils/Utils.h"
#include "../../../utils/MathUtils.h"
#include "Drop.h"
// @todo how to do class specific loot table?

View File

@ -14,7 +14,6 @@
#include <stdlib.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
struct JPSNode {
int32 x, y;

View File

@ -14,7 +14,6 @@
#include <stdlib.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
f32 manhattan_2d(v2_f32 a, v2_f32 b) {
return fabs(a.x - b.x) + fabs(a.y - b.y);

View File

@ -14,7 +14,6 @@
#include <stdlib.h>
#include "../stdlib/Types.h"
#include "../utils/MathUtils.h"
struct Path {

View File

@ -14,7 +14,6 @@
#include <stdlib.h>
#include "../../stdlib/Types.h"
#include "../../utils/MathUtils.h"
#include "JpsGrid.h"
#include "../Path.h"

View File

@ -14,7 +14,6 @@
#include <stdlib.h>
#include "../../stdlib/Types.h"
#include "../../utils/MathUtils.h"
#include "JpsNode.h"

View File

@ -14,7 +14,6 @@
#include <stdlib.h>
#include "../../stdlib/Types.h"
#include "../../utils/MathUtils.h"
struct JpsNode {
bool is_walkable;

View File

@ -15,6 +15,7 @@
#include "../../utils/TestUtils.h"
// @todo Currently alignment only effects the starting position, but it should also effect the ending/size
// @todo Consider to rename file to Allocator.h
inline
void* platform_alloc(size_t size)
@ -22,10 +23,6 @@ void* platform_alloc(size_t size)
return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
// @question Since we store at least the size of the memory in the beginning,
// does this have a negative impact on caching?
// Our Memory doesn't start at the cache line beginning but at least offset by sizeof(size_t)
inline
void* platform_alloc_aligned(size_t size, int32 alignment)
{

View File

@ -276,6 +276,7 @@ int network_info_get(NetworkInfo* info) {
// Get the size of the adapter addresses buffer
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &dwSize) == ERROR_BUFFER_OVERFLOW) {
// @todo Remove malloc
pAdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(dwSize);
if (pAdapterAddresses == NULL) {
WSACleanup();

View File

@ -9,10 +9,27 @@
#ifndef TOS_PLATFORM_WIN32_UTILS_H
#define TOS_PLATFORM_WIN32_UTILS_H
#include "../../stdlib/Types.h"
#include <stdio.h>
#include <windows.h>
#include <string.h>
#define strtok_r strtok_s
uint32 key_to_unicode(byte scan_code, byte vkey, byte keyboard_state[256])
{
WCHAR char_buffer[5] = {};
int32 result = ToUnicode(vkey, scan_code, keyboard_state, char_buffer, 5, 0);
if (result == 1) {
return (uint32) char_buffer[0];
} else if (result == 2) {
return (uint32) *((uint16 *) char_buffer);
} else if (result == 4) {
return *((uint32 *) char_buffer);
} else {
return 0;
}
}
#endif

View File

@ -28,6 +28,7 @@ struct Window {
// 3. size
// 4. fullscreen
byte state_changes;
// @todo replace bools with states
bool is_focused;
bool is_fullscreen;
@ -39,6 +40,7 @@ struct Window {
// The problem is the main program doesn't know which gpuapi we are using, so maybe a void pointer?
HGLRC openGLRC;
// @question why do we need the name?
char name[32];
WindowState state_old;
};

View File

@ -15,7 +15,6 @@
#include "../../../stdlib/Types.h"
#include "../../../audio/AudioSetting.h"
#include "../../../utils/MathUtils.h"
#include "../../../log/Log.h"
#include "../../../audio/Audio.cpp"
@ -35,7 +34,7 @@ HRESULT WINAPI DirectSoundCreate8Stub(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN) {
void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_setting) {
HMODULE lib = LoadLibraryExA((LPCSTR) "dsound.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!lib) {
LOG("DirectSound: Couldn't load dsound.dll\n", true, true);
LOG(true, "DirectSound: Couldn't load dsound.dll\n");
return;
}
@ -43,13 +42,13 @@ void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_settin
DirectSoundCreate8_t* DirectSoundCreate8 = (DirectSoundCreate8_t *) GetProcAddress(lib, "DirectSoundCreate8");
if (!DirectSoundCreate8 || !SUCCEEDED(DirectSoundCreate8(0, &api_setting->audio_handle, 0))) {
LOG("DirectSound: DirectSoundCreate8 failed\n", true, true);
LOG(true, "DirectSound: DirectSoundCreate8 failed\n");
return;
}
if(!SUCCEEDED(api_setting->audio_handle->SetCooperativeLevel(hwnd, DSSCL_PRIORITY))) {
LOG("DirectSound: SetCooperativeLevel failed.\n", true, true);
LOG(true, "DirectSound: SetCooperativeLevel failed.\n");
return;
}
@ -71,13 +70,13 @@ void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_settin
buffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if(!SUCCEEDED(api_setting->audio_handle->CreateSoundBuffer(&buffer_desc, &api_setting->primary_buffer, 0))) {
LOG("DirectSound: CreateSoundBuffer1 failed.\n", true, true);
LOG(true, "DirectSound: CreateSoundBuffer1 failed.\n");
return;
}
if (!SUCCEEDED(api_setting->primary_buffer->SetFormat(&wf))) {
LOG("DirectSound: SetFormat failed.\n", true, true);
LOG(true, "DirectSound: SetFormat failed.\n");
return;
}
@ -93,7 +92,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_settin
buffer_desc2.lpwfxFormat = &wf;
if(!SUCCEEDED(api_setting->audio_handle->CreateSoundBuffer(&buffer_desc2, &api_setting->secondary_buffer, 0))) {
LOG("DirectSound: CreateSoundBuffer2 failed.\n", true, true);
LOG(true, "DirectSound: CreateSoundBuffer2 failed.\n");
return;
}
@ -143,7 +142,7 @@ uint32 audio_buffer_fillable(const AudioSetting* setting, const DirectSoundSetti
DWORD player_cursor;
DWORD write_cursor;
if (!SUCCEEDED(api_setting->secondary_buffer->GetCurrentPosition(&player_cursor, &write_cursor))) {
LOG("DirectSound: GetCurrentPosition failed.\n", true, true);
LOG(true, "DirectSound: GetCurrentPosition failed.\n");
return 0;
}

View File

@ -18,7 +18,6 @@
#include "../../../stdlib/Types.h"
#include "../../../audio/AudioSetting.h"
#include "../../../utils/MathUtils.h"
#include "../../../log/Log.h"
#include "../../../audio/Audio.cpp"
@ -44,7 +43,7 @@ typedef HRESULT WINAPI IAudioClient_GetService_t(IAudioClient*, REFIID, void**);
void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
HMODULE ole32 = LoadLibraryExA((LPCSTR) "ole32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!ole32) {
LOG("Wasapi: Couldn't load ole32.dll\n", true, true);
LOG(true, "Wasapi: Couldn't load ole32.dll\n");
return;
}
@ -53,14 +52,14 @@ void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
CoCreateInstance_t* co_create_instance = (CoCreateInstance_t *) GetProcAddress(ole32, "CoCreateInstance");
if (!co_initialize_ex || !co_create_instance) {
LOG("Wasapi: ole32 function binding failed\n", true, true);
LOG(true, "Wasapi: ole32 function binding failed\n");
return;
}
HMODULE mmdevapi = LoadLibraryExA((LPCSTR) "mmdevapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!mmdevapi) {
LOG("Wasapi: Couldn't load mmdevapi.dll\n", true, true);
LOG(true, "Wasapi: Couldn't load mmdevapi.dll\n");
return;
}
@ -69,14 +68,14 @@ void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
IMMDevice_Activate_t* IMMDevice_Activate = (IMMDevice_Activate_t *) GetProcAddress(mmdevapi, "IMMDevice_Activate");
if (!IMMDeviceEnumerator_GetDefaultAudioEndpoint || !IMMDevice_Activate) {
LOG("Wasapi: mmdevapi function binding failed\n", true, true);
LOG(true, "Wasapi: mmdevapi function binding failed\n");
return;
}
HMODULE audioclient = LoadLibraryExA((LPCSTR) "audioclient.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!audioclient) {
LOG("Wasapi: Couldn't load audioclient.dll\n", true, true);
LOG(true, "Wasapi: Couldn't load audioclient.dll\n");
return;
}
@ -88,14 +87,14 @@ void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
IAudioClient_GetService_t* pIAudioClient_GetService = (IAudioClient_GetService_t *) GetProcAddress(audioclient, "IAudioClient_GetService");
if (!pIAudioClient_GetMixFormat || !pIAudioClient_Initialize || !pIAudioClient_Start || !pIAudioClient_Stop || !pIAudioClient_GetService) {
LOG("Wasapi: audioclient function binding failed\n", true, true);
LOG(true, "Wasapi: audioclient function binding failed\n");
return;
}
HRESULT hr = co_initialize_ex(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) {
LOG("Wasapi: Wasapi initialize failed\n", true, true);
LOG(true, "Wasapi: Wasapi initialize failed\n");
return;
}
@ -105,14 +104,14 @@ void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
hr = co_create_instance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **) &enumerator);
if (FAILED(hr)) {
LOG("Wasapi: Wasapi CreateInstance failed\n", true, true);
LOG(true, "Wasapi: Wasapi CreateInstance failed\n");
return;
}
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
if (FAILED(hr)) {
LOG("Wasapi: Wasapi DefaultAudioEndpoint failed\n", true, true);
LOG(true, "Wasapi: Wasapi DefaultAudioEndpoint failed\n");
enumerator->Release();
@ -121,7 +120,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
hr = IMMDevice_Activate(device, IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &api_setting->audio_handle);
if (FAILED(hr)) {
LOG("Wasapi: Wasapi DeviceActivate failed\n", true, true);
LOG(true, "Wasapi: Wasapi DeviceActivate failed\n");
device->Release();
enumerator->Release();

View File

@ -37,20 +37,20 @@ void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
CoInitialize(NULL);
HMODULE lib = LoadLibraryExA((LPCSTR) "xaudio2_9.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!lib) {
LOG("Xaudio2: Couldn't load xaudio2_9.dll\n", true, true);
LOG(true, "Xaudio2: Couldn't load xaudio2_9.dll\n");
lib = LoadLibraryExA((LPCSTR) "xaudio2_8.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (!lib) {
LOG("Xaudio2: Couldn't load xaudio2_8.dll\n", true, true);
LOG(true, "Xaudio2: Couldn't load xaudio2_8.dll\n");
return;
}
XAudio2Create_t* XAudio2Create = (XAudio2Create_t *) GetProcAddress(lib, "XAudio2Create");
if (!XAudio2Create || !SUCCEEDED(XAudio2Create(&api_setting->audio_handle, 0, XAUDIO2_DEFAULT_PROCESSOR))) {
LOG("Xaudio2: XAudio2Create failed\n", true, true);
LOG(true, "Xaudio2: XAudio2Create failed\n");
return;
}
@ -63,7 +63,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
0,
NULL))
) {
LOG("Xaudio2: CreateMasteringVoice failed\n", true, true);
LOG(true, "Xaudio2: CreateMasteringVoice failed\n");
return;
}
@ -78,7 +78,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
wf.cbSize = 0;
if (!SUCCEEDED(api_setting->audio_handle->CreateSourceVoice(&api_setting->source_voice, &wf))) {
LOG("Xaudio2: CreateSourceVoice failed\n", true, true);
LOG(true, "Xaudio2: CreateSourceVoice failed\n");
return;
}
@ -187,7 +187,7 @@ void audio_play_buffer(AudioSetting* setting, XAudio2Setting* api_setting) {
);
if (!SUCCEEDED(api_setting->source_voice->SubmitSourceBuffer(&api_setting->internal_buffer[idx]))) {
LOG("Xaudio2: SubmitSourceBuffer failed\n", true, true);
LOG(true, "Xaudio2: SubmitSourceBuffer failed\n");
return;
}

View File

@ -155,7 +155,7 @@ uint32 hid_device_poll(Input* state, uint64 time) {
}
input_set_controller_state(state, &controller, time);
state->state_change_button = true;
state->general_states |= INPUT_STATE_GENERAL_BUTTON_CHANGE;
state->time_last_input_check = time;
return 0;

View File

@ -226,44 +226,44 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* __restrict states, int32
InputKey key;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) {
key.key_state = KEY_STATE_PRESSED;
key.key_id = INPUT_MOUSE_BUTTON_1;
key.key_state = KEY_PRESS_TYPE_PRESSED;
key.scan_code = INPUT_MOUSE_BUTTON_1;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) {
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_1;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_1;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
key.key_state = KEY_STATE_PRESSED;
key.key_id = INPUT_MOUSE_BUTTON_2;
key.key_state = KEY_PRESS_TYPE_PRESSED;
key.scan_code = INPUT_MOUSE_BUTTON_2;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) {
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_2;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_2;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) {
key.key_state = KEY_STATE_PRESSED;
key.key_id = INPUT_MOUSE_BUTTON_3;
key.key_state = KEY_PRESS_TYPE_PRESSED;
key.scan_code = INPUT_MOUSE_BUTTON_3;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) {
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_3;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_3;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
key.key_state = KEY_STATE_PRESSED;
key.key_id = INPUT_MOUSE_BUTTON_4;
key.key_state = KEY_PRESS_TYPE_PRESSED;
key.scan_code = INPUT_MOUSE_BUTTON_4;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_4;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_4;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
key.key_state = KEY_STATE_PRESSED;
key.key_id = INPUT_MOUSE_BUTTON_5;
key.key_state = KEY_PRESS_TYPE_PRESSED;
key.scan_code = INPUT_MOUSE_BUTTON_5;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_5;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_5;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
// @bug not working
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_WHEEL;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_WHEEL;
key.value = (int16) raw->data.mouse.usButtonData;
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) {
// @bug not working
key.key_state = KEY_STATE_RELEASED;
key.key_id = INPUT_MOUSE_BUTTON_HWHEEL;
key.key_state = KEY_PRESS_TYPE_RELEASED;
key.scan_code = INPUT_MOUSE_BUTTON_HWHEEL;
key.value = (int16) raw->data.mouse.usButtonData;
} else {
return 0;
@ -271,12 +271,12 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* __restrict states, int32
++input_count;
key.key_id |= INPUT_MOUSE_PREFIX;
key.scan_code |= INPUT_MOUSE_PREFIX;
key.time = time;
input_set_state(states[i].state.state_keys, &key);
states[i].state_change_button = true;
} else if (states[i].mouse_movement) {
input_set_state(states[i].state.active_keys, &key);
states[i].general_states |= INPUT_STATE_GENERAL_BUTTON_CHANGE;
} else if (states[i].general_states & INPUT_STATE_GENERAL_MOUSE_MOVEMENT) {
// @question do we want to handle mouse movement for every individual movement, or do we want to pull it
if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
RECT rect;
@ -301,7 +301,7 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* __restrict states, int32
states[i].state.x = MulDiv(raw->data.mouse.lLastX, rect.right, 65535) + rect.left;
states[i].state.y = MulDiv(raw->data.mouse.lLastY, rect.bottom, 65535) + rect.top;
states[i].state_change_mouse = true;
states[i].general_states |= INPUT_STATE_GENERAL_MOUSE_CHANGE;
} else if (raw->data.mouse.lLastX != 0 || raw->data.mouse.lLastY != 0) {
states[i].state.dx += raw->data.mouse.lLastX;
states[i].state.dy += raw->data.mouse.lLastY;
@ -309,7 +309,7 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* __restrict states, int32
states[i].state.x = states[i].state.x + raw->data.mouse.lLastX;
states[i].state.y = states[i].state.y + raw->data.mouse.lLastY;
states[i].state_change_mouse = true;
states[i].general_states |= INPUT_STATE_GENERAL_MOUSE_CHANGE;
}
}
} else if (raw->header.dwType == RIM_TYPEKEYBOARD) {
@ -324,21 +324,26 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* __restrict states, int32
return 0;
}
uint16 new_state;
KeyPressType new_state;
if (raw->data.keyboard.Flags == RI_KEY_BREAK) {
new_state = KEY_STATE_RELEASED;
new_state = KEY_PRESS_TYPE_RELEASED;
} else if (raw->data.keyboard.Flags == RI_KEY_MAKE) {
new_state = KEY_STATE_PRESSED;
new_state = KEY_PRESS_TYPE_PRESSED;
} else {
return 0;
}
++input_count;
// @todo change to MakeCode instead of VKey
InputKey key = {(uint16) (raw->data.keyboard.VKey | INPUT_KEYBOARD_PREFIX), new_state, 0, time};
input_set_state(states[i].state.state_keys, &key);
states[i].state_change_button = true;
// @todo we need to support vkey and MakeCode/ScanCode for input mode -> typing and recognizing the respective unicode
InputKey key = {
(uint16) (raw->data.keyboard.MakeCode | INPUT_KEYBOARD_PREFIX),
(uint16) (raw->data.keyboard.VKey | INPUT_KEYBOARD_PREFIX),
new_state, time, 0, false
};
input_set_state(states[i].state.active_keys, &key);
states[i].general_states |= INPUT_STATE_GENERAL_BUTTON_CHANGE;
} else if (raw->header.dwType == RIM_TYPEHID
&& raw->header.dwSize > sizeof(RAWINPUT)
) {
@ -369,7 +374,7 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* __restrict states, int32
}
input_set_controller_state(&states[i], &controller, time);
states[i].state_change_button = true;
states[i].general_states |= INPUT_STATE_GENERAL_BUTTON_CHANGE;
states[i].time_last_input_check = time;
}

View File

@ -14,7 +14,6 @@
#include "../../../input/ControllerInput.h"
#include "../../../stdlib/Types.h"
#include "../../../utils/MathUtils.h"
// @todo consider to remove some global_persist and defines since we are never calling it somewhere else

View File

@ -14,7 +14,6 @@
#include "../../../../input/ControllerInput.h"
#include "../../../../input/InputConnectionType.h"
#include "../../../../utils/BitUtils.h"
#include "../../../../utils/MathUtils.h"
// @bug bluetooth and USB have different formats?!
// https://github.com/nondebug/dualsense

View File

@ -14,7 +14,6 @@
#include "../../../../input/ControllerInput.h"
#include "../../../../input/InputConnectionType.h"
#include "../../../../utils/BitUtils.h"
#include "../../../../utils/MathUtils.h"
inline
void input_map_dualshock4(ControllerInput* controller, InputConnectionType connection_type, byte* data)

View File

@ -351,7 +351,7 @@ void atomic_and_relaxed(volatile uint64* value, uint64 mask)
inline
void atomic_and_relaxed(volatile int64* value, int64 mask)
{
InterlockedAnd64NoFence((volatile LONG64 *) value, mask);
InterlockedAnd64NoFence((volatile LONG64 *) value, (LONG64) mask);
}
inline
@ -456,7 +456,7 @@ int32 atomic_get_acquire(volatile int32* value)
inline
int64 atomic_get_acquire(volatile int64* value)
{
return (int64) InterlockedCompareExchangeAcquire((long *) value, 0, 0);
return (int64) InterlockedCompareExchangeAcquire64((LONG64 *) value, 0, 0);
}
inline
@ -492,13 +492,13 @@ void atomic_decrement_acquire(volatile int32* value)
inline
void atomic_increment_acquire(volatile int64* value)
{
InterlockedIncrementAcquire((long *) value);
InterlockedIncrementAcquire64((LONG64 *) value);
}
inline
void atomic_decrement_acquire(volatile int64* value)
{
InterlockedDecrementAcquire((long *) value);
InterlockedDecrementAcquire64((LONG64 *) value);
}
inline
@ -516,13 +516,13 @@ void atomic_sub_acquire(volatile int32* value, int32 decrement)
inline
void atomic_add_acquire(volatile int64* value, int64 increment)
{
InterlockedAddAcquire((long *) value, (long) increment);
InterlockedAddAcquire64((LONG64 *) value, (LONG64) increment);
}
inline
void atomic_sub_acquire(volatile int64* value, int64 decrement)
{
InterlockedAddAcquire((long *) value, -1 * ((long) decrement));
InterlockedAddAcquire64((LONG64 *) value, -1 * ((LONG64) decrement));
}
inline
@ -819,7 +819,7 @@ int32 atomic_get_release(volatile int32* value)
inline
int64 atomic_get_release(volatile int64* value)
{
return (int64) InterlockedCompareExchangeRelease((long *) value, 0, 0);
return (int64) InterlockedCompareExchangeRelease64((LONG64 *) value, 0, 0);
}
inline
@ -1314,7 +1314,7 @@ void atomic_set_acquire_release(volatile uint32* value, uint32 new_value)
inline
void atomic_set_acquire_release(volatile uint64* value, uint64 new_value)
{
InterlockedExchange((long *) value, (long) new_value);
InterlockedExchange64((LONG64 *) value, (LONG64) new_value);
}
inline

View File

@ -140,6 +140,8 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ri
hm->table = (void **) data;
chunk_init(&hm->buf, data + sizeof(void *) * count, count, element_size, 8);
LOG_LEVEL_2("Created HashMap for %n elements with %n B per element = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}, {LOG_DATA_UINT64, &hm->buf.size}});
}
// WARNING: element_size = element size + remaining HashEntry data size
@ -153,6 +155,8 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, BufferMemory*
hm->table = (void **) data;
chunk_init(&hm->buf, data + sizeof(void *) * count, count, element_size, 8);
LOG_LEVEL_2("Created HashMap for %n elements with %n B per element = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}, {LOG_DATA_UINT64, &hm->buf.size}});
}
// WARNING: element_size = element size + remaining HashEntry data size
@ -160,6 +164,8 @@ void hashmap_create(HashMap* hm, int32 count, int32 element_size, byte* buf)
{
hm->table = (void **) buf;
chunk_init(&hm->buf, buf + sizeof(void *) * count, count, element_size, 8);
LOG_LEVEL_2("Created HashMap for %n elements with %n B per element = %n B", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}, {LOG_DATA_UINT64, &hm->buf.size}});
}
// Calculates how large a hashmap will be
@ -399,7 +405,7 @@ HashEntry* hashmap_get_reserve(HashMap* hm, const char* key)
while (entry != NULL) {
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
DEBUG_MEMORY_READ((uint64) entry, sizeof(HashEntry));
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
return entry;
}
@ -434,7 +440,7 @@ HashEntry* hashmap_get_entry(const HashMap* hm, const char* key) {
while (entry != NULL) {
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
DEBUG_MEMORY_READ((uint64) entry, sizeof(HashEntry));
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
return entry;
}
@ -452,7 +458,7 @@ HashEntry* hashmap_get_entry(const HashMap* hm, const char* key, uint64 hash) {
while (entry != NULL) {
if (str_compare(entry->key, key, HASH_MAP_MAX_KEY_LENGTH) == 0) {
DEBUG_MEMORY_READ((uint64) entry, sizeof(HashEntry));
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntry));
return entry;
}
@ -664,7 +670,7 @@ HashEntryKeyInt32* hashmap_get_entry(const HashMap* hm, int32 key) {
while (entry != NULL) {
if (entry->key == key) {
DEBUG_MEMORY_READ((uint64) entry, sizeof(HashEntryKeyInt32));
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntryKeyInt32));
return entry;
}
@ -682,7 +688,7 @@ HashEntryKeyInt32* hashmap_get_entry(const HashMap* hm, int32 key, uint64 hash)
while (entry != NULL) {
if (entry->key == key) {
DEBUG_MEMORY_READ((uint64) entry, sizeof(HashEntryKeyInt32));
DEBUG_MEMORY_READ((uintptr_t) entry, sizeof(HashEntryKeyInt32));
return entry;
}
@ -851,6 +857,8 @@ int64 hashmap_load(HashMap* hm, const byte* data)
}
chunk_iterate_end;
LOG_LEVEL_2("Loaded HashMap: %n B", {{LOG_DATA_UINT64, &hm->buf.size}});
// How many bytes was read from data
return sizeof(hm->buf.count) // hash map count = buffer count
+ hm->buf.count * sizeof(uint64) // table content

View File

@ -54,6 +54,42 @@ typedef char sbyte;
typedef uintptr_t umm;
typedef intptr_t smm;
#define OMS_PI 3.14159265358979323846f
#define OMS_PI_OVER_TWO (OMS_PI / 2.0f)
#define OMS_PI_OVER_FOUR (OMS_PI / 4.0f)
#define OMS_TWO_PI (2.0f * OMS_PI)
#define OMS_MAX(a, b) ((a) > (b) ? (a) : (b))
#define OMS_MIN(a, b) ((a) > (b) ? (b) : (a))
// @todo Switch the order of high and low
#define OMS_CLAMP(val, high, low) ((val) < (low) ? (low) : ((val) > (high) ? (high) : (val)))
#define OMS_ABS(a) ((a) > 0 ? (a) : -(a))
#define OMS_ABS_INT8(a) ((a) & 0x7F)
#define OMS_ABS_INT16(a) ((a) & 0x7FFF)
#define OMS_ABS_INT32(a) ((a) & 0x7FFFFFFF)
#define OMS_ABS_INT64(a) ((a) & 0x7FFFFFFFFFFFFFFF)
#define OMS_ABS_F32(a) ((f32) (((int32) (a)) & 0x7FFFFFFF))
#define OMS_ABS_F64(a) ((f64) (((int64) (a)) & 0x7FFFFFFFFFFFFFFF))
#define OMS_DEG2RAD(angle) ((angle) * OMS_PI / 180.0f)
#define OMS_RAD2DEG(angle) ((angle) * 180.0f / OMS_PI)
#define ROUND_TO_NEAREST(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
#define OMS_ROUND_POSITIVE(x) ((int32)((x) + 0.5f))
#define OMS_ROUND(x) (((x) >= 0) ? ((int32)((x) + 0.5f)) : ((int32)((x) - 0.5f)))
#define CEIL_DIV(a, b) (((a) + (b) - 1) / (b))
#define OMS_CEIL(x) ((x) == (int32)(x) ? (int32)(x) : ((x) > 0 ? (int32)(x) + 1 : (int32)(x)))
#define FLOAT_CAST_EPS 0.001953125
// Modulo function when b is a power of 2
#define MODULO_2(a, b) ((a) & (b - 1))
#define SQRT_2 1.4142135623730950488016887242097f
#define KILOBYTE 1024
#define MEGABYTE 1048576
#define GIGABYTE 1073741824
@ -203,6 +239,10 @@ struct v2_f32 {
f32 x, y;
};
struct {
f32 width, height;
};
f32 v[2];
};
};

View File

@ -26,6 +26,7 @@
void thread_create(Worker* worker, ThreadJobFunc routine, void* arg)
{
LOG_LEVEL_2("Thread started", {});
pthread_create(&worker->thread, NULL, routine, arg);
}
@ -33,6 +34,7 @@ void thread_stop(Worker* worker)
{
atomic_set_acquire(&worker->state, 0);
pthread_join(worker->thread, NULL);
LOG_LEVEL_2("Thread ended", {});
}
#endif

View File

@ -63,9 +63,12 @@ static THREAD_RETURN thread_pool_worker(void* arg)
atomic_increment_relaxed(&pool->working_cnt);
atomic_set_release(&work->state, 2);
LOG_LEVEL_2("ThreadPool worker started", {});
work->func(work);
LOG_LEVEL_2("ThreadPool worker ended", {});
// At the end of a thread the ring memory automatically is considered freed
DEBUG_MEMORY_FREE((uint64) work->ring.memory, work->ring.size);
DEBUG_MEMORY_FREE((uintptr_t) work->ring.memory, work->ring.size);
LOG_LEVEL_2("Freed thread RingMemory: %n B", {{LOG_DATA_UINT64, &work->ring.size}});
atomic_set_release(&work->state, 1);
// Job gets marked after completion -> can be overwritten now

View File

@ -1,38 +0,0 @@
/**
* Jingga
*
* @package Utils
* @copyright Jingga
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
#ifndef TOS_UTILS_MATH_UTILS_H
#define TOS_UTILS_MATH_UTILS_H
#include <math.h>
#define OMS_PI 3.14159265358979323846f
#define OMS_PI_OVER_TWO (OMS_PI / 2.0f)
#define OMS_PI_OVER_FOUR (OMS_PI / 4.0f)
#define OMS_TWO_PI (2.0f * OMS_PI)
#define OMS_MAX(a, b) ((a) > (b) ? (a) : (b))
#define OMS_MIN(a, b) ((a) > (b) ? (b) : (a))
#define OMS_CLAMP(val, high, low) (OMS_MAX(OMS_MIN((val), (high)), (low)))
#define OMS_ABS(a) ((a) > 0 ? (a) : -(a))
#define OMS_DEG2RAD(angle) ((angle) * OMS_PI / 180.0f)
#define OMS_RAD2DEG(angle) ((angle) * 180.0f / OMS_PI)
#define ROUND_TO_NEAREST(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
#define CEIL_DIV(a, b) (((a) + (b) - 1) / (b))
#define OMS_CEIL(x) ((x) == (int)(x) ? (int)(x) : ((x) > 0 ? (int)(x) + 1 : (int)(x)))
#define OMS_ROUND(x) (((x) >= 0) ? ((int)((x) + 0.5f)) : ((int)((x) - 0.5f)))
#define OMS_ROUND_POSITIVE(x) ((int)((x) + 0.5f))
#define FLOAT_CAST_EPS 0.001953125
// Modulo function when b is a power of 2
#define MODULO_2(a, b) ((a) & (b - 1))
#define SQRT_2 1.4142135623730950488016887242097f
#endif

View File

@ -15,7 +15,6 @@
#include <ctype.h>
#include "../stdlib/Types.h"
#include "MathUtils.h"
inline
int32 utf8_encode(uint32 codepoint, char* out)
@ -80,6 +79,39 @@ int32 utf8_decode(const char* __restrict in, uint32* __restrict codepoint) {
return -1;
}
inline
int32 utf8_decode(const uint32 codepoint, char* __restrict out) {
if (codepoint <= 0x7F) {
// 1-byte sequence (ASCII)
out[0] = (char) codepoint;
return 1;
} else if (codepoint <= 0x7FF) {
// 2-byte sequence
out[0] = (char) (0xC0 | ((codepoint >> 6) & 0x1F));
out[1] = (char) (0x80 | (codepoint & 0x3F));
return 2;
} else if (codepoint <= 0xFFFF) {
// 3-byte sequence
out[0] = (char) (0xE0 | ((codepoint >> 12) & 0x0F));
out[1] = (char) (0x80 | ((codepoint >> 6) & 0x3F));
out[2] = (char) (0x80 | (codepoint & 0x3F));
return 3;
} else if (codepoint <= 0x10FFFF) {
// 4-byte sequence
out[0] = (char) (0xF0 | ((codepoint >> 18) & 0x07));
out[1] = (char) (0x80 | ((codepoint >> 12) & 0x3F));
out[2] = (char) (0x80 | ((codepoint >> 6) & 0x3F));
out[3] = (char) (0x80 | (codepoint & 0x3F));
return 4;
}
return -1; // Invalid codepoint
}
inline
int32 utf8_strlen(const char* in) {
int32 length = 0;
@ -400,6 +432,17 @@ int32 str_copy_until(char* __restrict dest, const char* __restrict src, char del
return len;
}
inline
void str_copy_short(char* __restrict dest, const char* __restrict src, int32 length, char delim = '\0')
{
int32 i = -1;
while (*src != delim && ++i < length) {
*dest++ = *src++;
}
*dest = '\0';
}
inline
void str_copy_short(char* __restrict dest, const char* __restrict src, char delim = '\0')
{
@ -981,66 +1024,40 @@ void str_pad(const char* input, char* output, char pad, size_t len) {
}
}
void sprintf_fast(char *buffer, const char* format, ...) {
void sprintf_fast(char* __restrict buffer, const char* __restrict format, ...) {
va_list args;
va_start(args, format);
const char* ptr = format;
char *buf_ptr = buffer;
while (*ptr) {
if (*ptr != '%') {
*buf_ptr++ = *ptr;
} else if (*ptr == '\\' && *(ptr + 1) == '%') {
++ptr;
*buf_ptr++ = *ptr;
while (*format) {
if (*format != '%') {
*buffer++ = *format;
} else if (*format == '\\' && *(format + 1) == '%') {
++format;
*buffer++ = *format;
} else {
++ptr;
++format;
switch (*ptr) {
switch (*format) {
case 's': {
const char* str = va_arg(args, const char*);
while (*str) {
*buf_ptr++ = *str++;
*buffer++ = *str++;
}
} break;
case 'c': {
*buffer++ = va_arg(args, char);
} break;
case 'n': {
int64 val = va_arg(args, int64);
buffer += int_to_str(val, buffer, ',');
} break;
case 'd': {
int32 val = va_arg(args, int32);
if (val < 0) {
*buf_ptr++ = '-';
val = -val;
}
char temp[20];
int32 index = 0;
do {
temp[index++] = (val % 10) + '0';
val /= 10;
} while (val > 0);
while (index > 0) {
*buf_ptr++ = temp[--index];
}
buffer += int_to_str(val, buffer);
} break;
case 'l': {
int64 val = va_arg(args, int64);
if (val < 0) {
*buf_ptr++ = '-';
val = -val;
}
char temp[20];
int64 index = 0;
do {
temp[index++] = (val % 10) + '0';
val /= 10;
} while (val > 0);
while (index > 0) {
*buf_ptr++ = temp[--index];
}
buffer += int_to_str(val, buffer);
} break;
case 'f': {
f64 val = va_arg(args, f64);
@ -1049,7 +1066,7 @@ void sprintf_fast(char *buffer, const char* format, ...) {
int32 precision = 5;
// Check for optional precision specifier
const char* prec_ptr = ptr + 1;
const char* prec_ptr = format + 1;
if (*prec_ptr >= '0' && *prec_ptr <= '9') {
precision = 0;
while (*prec_ptr >= '0' && *prec_ptr <= '9') {
@ -1057,11 +1074,11 @@ void sprintf_fast(char *buffer, const char* format, ...) {
prec_ptr++;
}
ptr = prec_ptr - 1;
format = prec_ptr - 1;
}
if (val < 0) {
*buf_ptr++ = '-';
*buffer++ = '-';
val = -val;
}
@ -1087,31 +1104,143 @@ void sprintf_fast(char *buffer, const char* format, ...) {
} while (int_part > 0);
while (index > 0) {
*buf_ptr++ = temp[--index];
*buffer++ = temp[--index];
}
// Handle fractional part
if (precision > 0) {
*buf_ptr++ = '.';
*buffer++ = '.';
while (precision--) {
frac_part *= 10;
int32 digit = (int32) frac_part;
*buf_ptr++ = (char) (digit + '0');
*buffer++ = (char) (digit + '0');
frac_part -= digit;
}
}
} break;
default: {
// Handle unknown format specifiers
*buf_ptr++ = '%';
*buffer++ = '%';
} break;
}
}
++ptr;
++format;
}
*buf_ptr = '\0';
*buffer = '\0';
va_end(args);
}
// There are situations where you only want to replace a certain amount of %
void sprintf_fast_iter(char* buffer, const char* format, ...) {
va_list args;
va_start(args, format);
int32 count_index = 0;
while (*format) {
if (*format != '%' || count_index >= 1) {
*buffer++ = *format;
} else if (*format == '\\' && *(format + 1) == '%') {
++format;
*buffer++ = *format;
} else {
++count_index;
++format;
switch (*format) {
case 's': {
const char* str = va_arg(args, const char*);
while (*str) {
*buffer++ = *str++;
}
} break;
case 'c': {
*buffer++ = va_arg(args, char);
} break;
case 'n': {
int64 val = va_arg(args, int64);
buffer += int_to_str(val, buffer, ',');
} break;
case 'd': {
int32 val = va_arg(args, int32);
buffer += int_to_str(val, buffer);
} break;
case 'l': {
int64 val = va_arg(args, int64);
buffer += int_to_str(val, buffer);
} break;
case 'f': {
f64 val = va_arg(args, f64);
// Default precision
int32 precision = 5;
// Check for optional precision specifier
const char* prec_ptr = format + 1;
if (*prec_ptr >= '0' && *prec_ptr <= '9') {
precision = 0;
while (*prec_ptr >= '0' && *prec_ptr <= '9') {
precision = precision * 10 + (*prec_ptr - '0');
prec_ptr++;
}
format = prec_ptr - 1;
}
if (val < 0) {
*buffer++ = '-';
val = -val;
}
if (precision < 6) {
static const float powers_of_ten[] = {
1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f, 100000.0f
};
f32 scale = powers_of_ten[precision];
val = OMS_ROUND_POSITIVE(val * scale) / scale;
}
// Handle integer part
int32 int_part = (int32) val;
f64 frac_part = val - int_part;
char temp[20];
int32 index = 0;
do {
temp[index++] = (int_part % 10) + '0';
int_part /= 10;
} while (int_part > 0);
while (index > 0) {
*buffer++ = temp[--index];
}
// Handle fractional part
if (precision > 0) {
*buffer++ = '.';
while (precision--) {
frac_part *= 10;
int32 digit = (int32) frac_part;
*buffer++ = (char) (digit + '0');
frac_part -= digit;
}
}
} break;
default: {
// Handle unknown format specifiers
*buffer++ = '%';
} break;
}
}
++format;
}
*buffer = '\0';
va_end(args);
}