diff --git a/asset/AssetArchive.h b/asset/AssetArchive.h index 9c5fe4a..7dfa5e3 100644 --- a/asset/AssetArchive.h +++ b/asset/AssetArchive.h @@ -238,12 +238,14 @@ Asset* asset_archive_asset_load(const AssetArchive* archive, int32 id, AssetMana // @todo implement qoi encoding image_from_data(file.content, &texture->image); - asset->vram_size = texture->image.pixel_count * image_pixel_size_from_type(texture->image.pixel_type); + asset->vram_size = texture->image.pixel_count * image_pixel_size_from_type(texture->image.image_settings); asset->ram_size = asset->vram_size + sizeof(Texture); #if OPENGL - image_flip_vertical(ring, &texture->image); - texture->image.order_rows = IMAGE_ROW_ORDER_BOTTOM_TO_TOP; + // If opengl, we always flip + if (!(texture->image.image_settings & IMAGE_SETTING_BOTTOM_TO_TOP)) { + image_flip_vertical(ring, &texture->image); + } #endif } break; case ASSET_TYPE_AUDIO: { diff --git a/audio/Audio.cpp b/audio/Audio.cpp index 682cea1..48e7b38 100644 --- a/audio/Audio.cpp +++ b/audio/Audio.cpp @@ -38,10 +38,8 @@ int32 audio_data_size(const Audio* audio) { return (int32) (audio->size + sizeof(audio->sample_rate) - + sizeof(audio->sample_size) + sizeof(audio->channels) + sizeof(audio->bloc_size) - + sizeof(audio->byte_per_sec) + sizeof(audio->size) ); } @@ -51,17 +49,13 @@ int32 audio_from_data(const byte* data, Audio* audio) audio->sample_rate = SWAP_ENDIAN_LITTLE(*((uint16 *) data)); data += sizeof(audio->sample_rate); - audio->sample_size = *data; - data += sizeof(audio->sample_size); + audio->channels = (*data >> 4) & 0x0F; + audio->bloc_size = *data & 0x0F; + data += sizeof(byte); - audio->channels = *data; - data += sizeof(audio->channels); + audio->sample_size = audio->channels * audio->bloc_size; - audio->bloc_size = *data; - data += sizeof(audio->bloc_size); - - audio->byte_per_sec = SWAP_ENDIAN_LITTLE(*((uint32 *) data)); - data += sizeof(audio->byte_per_sec); + audio->byte_per_sec = audio->sample_rate * audio->sample_size; audio->size = SWAP_ENDIAN_LITTLE(*((uint32 *) data)); data += sizeof(audio->size); @@ -77,17 +71,9 @@ int32 audio_to_data(const Audio* audio, byte* data) *((uint16 *) data) = SWAP_ENDIAN_LITTLE(audio->sample_rate); data += sizeof(audio->sample_rate); - *data = audio->sample_size; - data += sizeof(audio->sample_size); - - *data = audio->channels; - data += sizeof(audio->channels); - - *data = audio->bloc_size; - data += sizeof(audio->bloc_size); - - *((uint32 *) data) = SWAP_ENDIAN_LITTLE(audio->byte_per_sec); - data += sizeof(audio->byte_per_sec); + // Reducing data footprint through bit fiddling + *data = ((audio->channels & 0x0F) << 4) | (audio->bloc_size & 0x0F); + data += sizeof(byte); *((uint32 *) data) = SWAP_ENDIAN_LITTLE(audio->size); data += sizeof(audio->size); diff --git a/audio/Audio.h b/audio/Audio.h index 8bc764a..cb0a016 100644 --- a/audio/Audio.h +++ b/audio/Audio.h @@ -17,11 +17,6 @@ struct Audio { // usually 48000 or 44100 uint16 sample_rate; - // bytes per bloc - // channel count * bit - // usually 2 * 16 = 4 - byte sample_size; - // audio channels // usually 2 byte channels; @@ -29,6 +24,12 @@ struct Audio { // usually 16 = 2 byte bloc_size; + // bytes per bloc + // channel count * bit + // usually 2 * 16 = 4 + // channels * bloc_size + byte sample_size; + // sample_rate * sample_size uint32 byte_per_sec; diff --git a/gpuapi/direct3d/ShaderUtils.h b/gpuapi/direct3d/ShaderUtils.h new file mode 100644 index 0000000..6bb1208 --- /dev/null +++ b/gpuapi/direct3d/ShaderUtils.h @@ -0,0 +1,57 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_GPUAPI_DIRECTX_SHADER_UTILS_H +#define TOS_GPUAPI_DIRECTX_SHADER_UTILS_H + +#include +#include + +#include "../../stdlib/Types.h" +#include "../../memory/RingMemory.h" +#include "../../log/Log.h" + +D3D12_SHADER_BYTECODE shader_make(ID3D12Device* device, const char* source, int32 source_size, RingMemory* ring) +{ + // Create the shader object (bytecode) + D3D12_SHADER_BYTECODE shaderBytecodeDesc = {}; + shaderBytecodeDesc.pShaderBytecode = source; + shaderBytecodeDesc.BytecodeLength = source_size; + + return shaderBytecodeDesc; +} + +ID3D12PipelineState* program_make( + ID3D12Device* device, + D3D12_SHADER_BYTECODE vertex_shader, + D3D12_SHADER_BYTECODE fragment_shader, + D3D12_SHADER_BYTECODE geometry_shader +) { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.VS = vertex_shader; + psoDesc.PS = fragment_shader; + psoDesc.GS = geometry_shader; + + ID3D12PipelineState* pipelineState = NULL; + HRESULT hr = device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)); + + if (FAILED(hr)) { + LOG("Failed to create program", true, true); + return NULL; + } + + return pipelineState; +} + +inline +void pipeline_use(ID3D12GraphicsCommandList* command_list, ID3D12PipelineState* pipelineState) +{ + command_list->SetPipelineState(pipelineState); +} + +#endif \ No newline at end of file diff --git a/gpuapi/opengl/OpenglUtils.h b/gpuapi/opengl/OpenglUtils.h index 8f8f904..cbc4a41 100644 --- a/gpuapi/opengl/OpenglUtils.h +++ b/gpuapi/opengl/OpenglUtils.h @@ -138,7 +138,7 @@ void load_texture_to_gpu(const Texture* texture, int32 mipmap_level = 0) glGenerateMipmap(GL_TEXTURE_2D); } - LOG_INCREMENT_BY(DEBUG_COUNTER_GPU_UPLOAD, texture->image.pixel_count * image_pixel_size_from_type(texture->image.pixel_type)); + LOG_INCREMENT_BY(DEBUG_COUNTER_GPU_UPLOAD, texture->image.pixel_count * image_pixel_size_from_type(texture->image.image_settings)); } inline @@ -156,135 +156,6 @@ void texture_use_1D(const Texture* texture, uint32 texture_unit) glBindTexture(GL_TEXTURE_1D, (GLuint) texture->id); } -GLuint shader_make(GLenum type, const char* source, RingMemory* ring) -{ - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, (GLchar **) &source, NULL); - glCompileShader(shader); - - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - - #if DEBUG || INTERNAL - if (status == GL_FALSE) { - GLint length; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - - GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar)); - - glGetShaderInfoLog(shader, length, NULL, info); - LOG(info, true, true); - - ASSERT_SIMPLE(false); - } - #endif - - return shader; -} - -inline -GLuint shader_load(GLenum type, const char* path, RingMemory* ring) { - byte* temp = ring->head; - - FileBody file; - - // @todo consider to accept file as parameter and load file before - file_read(path, &file, ring); - GLuint result = shader_make(type, (const char *) file.content, ring); - - // We can immediately dispose of it we can also reset our ring memory position - ring->head = temp; - - return result; -} - -inline -int32 program_get_size(uint32 program) -{ - int32 size; - glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &size); - - return size; -} - -GLuint program_make( - GLuint vertex_shader, - GLuint fragment_shader, - GLint geometry_shader, - RingMemory* ring -) { - GLuint program = glCreateProgram(); - - if (geometry_shader > -1) { - glAttachShader(program, geometry_shader); - } - - glAttachShader(program, vertex_shader); - glAttachShader(program, fragment_shader); - glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); - glLinkProgram(program); - - GLint status; - glGetProgramiv(program, GL_LINK_STATUS, &status); - - #if DEBUG || INTERNAL - if (status == GL_FALSE) { - GLint length; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); - - GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar)); - - glGetProgramInfoLog(program, length, NULL, info); - LOG(info, true, true); - - ASSERT_SIMPLE(false); - } - #endif - - // @question really? - if (geometry_shader > -1) { - glDetachShader(program, geometry_shader); - } - - glDetachShader(program, vertex_shader); - glDetachShader(program, fragment_shader); - - // @question really? - if (geometry_shader > -1) { - glDeleteShader(geometry_shader); - } - - glDeleteShader(vertex_shader); - glDeleteShader(fragment_shader); - - return program; -} - -GLuint program_load( - const char* path1, - const char* path2, - const char* path3, - RingMemory* ring -) { - GLuint vertex_shader = shader_load(GL_VERTEX_SHADER, path1, ring); - GLuint fragment_shader = shader_load(GL_FRAGMENT_SHADER, path2, ring); - - GLint geometry_shader = -1; - if (path3) { - geometry_shader = shader_load(GL_GEOMETRY_SHADER, path3, ring); - } - - GLuint program = program_make(vertex_shader, fragment_shader, geometry_shader, ring); - - return program; -} - -inline -void shader_use(uint32 id) -{ - glUseProgram(id); -} - inline void draw_triangles_3d(VertexRef* vertices, GLuint buffer, int32 count) { glBindBuffer(GL_ARRAY_BUFFER, buffer); diff --git a/gpuapi/opengl/ShaderUtils.h b/gpuapi/opengl/ShaderUtils.h index ca858ef..972c4d3 100644 --- a/gpuapi/opengl/ShaderUtils.h +++ b/gpuapi/opengl/ShaderUtils.h @@ -10,7 +10,8 @@ #define TOS_GPUAPI_OPENGL_SHADER_UTILS_H #include "../../stdlib/Types.h" -#include "../../math/matrix/MatrixFloat32.h" +#include "../../memory/RingMemory.h" +#include "../../log/Log.h" #include "Opengl.h" // Set value based on shader uniform name @@ -244,4 +245,98 @@ int32 shader_program_optimize(const char* input, char* output) return (int32) (write_ptr - output); } +GLuint shader_make(GLenum type, const char* source, RingMemory* ring) +{ + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, (GLchar **) &source, NULL); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + #if DEBUG || INTERNAL + if (status == GL_FALSE) { + GLint length; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + + GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar)); + + glGetShaderInfoLog(shader, length, NULL, info); + LOG(info, true, true); + + ASSERT_SIMPLE(false); + } + #endif + + return shader; +} + +inline +int32 program_get_size(uint32 program) +{ + int32 size; + glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &size); + + return size; +} + +GLuint program_make( + GLuint vertex_shader, + GLuint fragment_shader, + GLint geometry_shader, + RingMemory* ring +) { + GLuint program = glCreateProgram(); + + if (geometry_shader > -1) { + glAttachShader(program, geometry_shader); + } + + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); + glLinkProgram(program); + + GLint status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + + #if DEBUG || INTERNAL + if (status == GL_FALSE) { + GLint length; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); + + GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar)); + + glGetProgramInfoLog(program, length, NULL, info); + LOG(info, true, true); + + ASSERT_SIMPLE(false); + } + #endif + + // @question really? + if (geometry_shader > -1) { + glDetachShader(program, geometry_shader); + } + + glDetachShader(program, vertex_shader); + glDetachShader(program, fragment_shader); + + // @question really? + if (geometry_shader > -1) { + glDeleteShader(geometry_shader); + } + + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + return program; +} + +inline +void pipeline_use(uint32 id) +{ + glUseProgram(id); +} + #endif \ No newline at end of file diff --git a/gpuapi/vulkan/ShaderUtils.h b/gpuapi/vulkan/ShaderUtils.h new file mode 100644 index 0000000..50c4611 --- /dev/null +++ b/gpuapi/vulkan/ShaderUtils.h @@ -0,0 +1,143 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_GPUAPI_VULKAN_SHADER_UTILS_H +#define TOS_GPUAPI_VULKAN_SHADER_UTILS_H + +#include + +#include "../../stdlib/Types.h" +#include "../../memory/RingMemory.h" +#include "../../log/Log.h" + +inline uint32_t shader_get_uniform_location(VkWriteDescriptorSet* descriptor, VkDevice device, VkCommandBuffer commandBuffer, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType) +{ + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = descriptorType; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo->buffer = 0; + descriptorWrite.pBufferInfo->offset = 0; +} + +inline void shader_set_value(VkDevice device, VkCommandBuffer commandBuffer, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType, int32_t value) +{ + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = {}; // You should have a buffer holding the value + bufferInfo.offset = 0; + bufferInfo.range = sizeof(value); + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = descriptorType; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); +} + +VkShaderModule shader_make(VkDevice device, const char* source, int32 source_size, RingMemory* ring) +{ + // Create shader module create info + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = source_size; + createInfo.pCode = (uint32 *) source; + + // Create shader module + VkShaderModule shaderModule; + VkResult result = vkCreateShaderModule(device, &createInfo, NULL, &shaderModule); + + if (result != VK_SUCCESS) { + LOG("Failed to create shader module", true, true); + ASSERT_SIMPLE(false); + + return VK_NULL_HANDLE; + } + + return shaderModule; +} + +VkPipeline program_make( + VkDevice device, + VkShaderModule vertex_shader, + VkShaderModule fragment_shader, + VkShaderModule geometry_shader, + VkPipelineLayout pipeline_layout, + VkRenderPass render_pass, + RingMemory* ring +) { + VkPipelineShaderStageCreateInfo shaderStages[3]; + + // Vertex shader + shaderStages[0] = {}; + shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shaderStages[0].module = vertex_shader; + shaderStages[0].pName = "main"; + + // Fragment shader + shaderStages[1] = {}; + shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shaderStages[1].module = fragment_shader; + shaderStages[1].pName = "main"; + + VkPipelineShaderStageCreateInfo* geometryShaderStage = NULL; + + // Optional Geometry shader + if (geometry_shader != VK_NULL_HANDLE) { + geometryShaderStage = &shaderStages[2]; + geometryShaderStage->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + geometryShaderStage->stage = VK_SHADER_STAGE_GEOMETRY_BIT; + geometryShaderStage->module = geometry_shader; + geometryShaderStage->pName = "main"; + } + + // Create the pipeline + VkGraphicsPipelineCreateInfo pipelineCreateInfo = {}; + pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCreateInfo.stageCount = (geometry_shader != VK_NULL_HANDLE) ? 3 : 2; + pipelineCreateInfo.pStages = shaderStages; + pipelineCreateInfo.pInputAssemblyState = NULL; // Define if needed + pipelineCreateInfo.pVertexInputState = NULL; // Define if needed + pipelineCreateInfo.pViewportState = NULL; // Define if needed + pipelineCreateInfo.pRasterizationState = NULL; // Define if needed + pipelineCreateInfo.pMultisampleState = NULL; // Define if needed + pipelineCreateInfo.pDepthStencilState = NULL; // Define if needed + pipelineCreateInfo.pColorBlendState = NULL; // Define if needed + pipelineCreateInfo.pDynamicState = NULL; // Define if needed + pipelineCreateInfo.layout = pipeline_layout; + pipelineCreateInfo.renderPass = render_pass; + pipelineCreateInfo.subpass = 0; // Assumes 0 subpass + pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; + + VkPipeline graphicsPipeline; + VkResult result = vkCreateGraphicsPipeline(device, VK_NULL_HANDLE, &pipelineCreateInfo, NULL, &graphicsPipeline); + + if (result != VK_SUCCESS) { + LOG("Failed to create program", true, true); + return VK_NULL_HANDLE; + } + + return graphicsPipeline; +} + +inline +void pipeline_use(VkCommandBuffer command_list, VkPipeline pipeline) +{ + vkCmdBindPipeline(command_list, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); +} + +#endif \ No newline at end of file diff --git a/image/Bitmap.h b/image/Bitmap.h index 1f985b1..e2faec4 100644 --- a/image/Bitmap.h +++ b/image/Bitmap.h @@ -285,16 +285,12 @@ void image_bmp_generate(const FileBody* src_data, Image* image) uint32 pixel_bytes = src.dib_header.bits_per_pixel / 8; byte alpha_offset = pixel_bytes > 3; - if (pixel_bytes == 4) { - image->pixel_type = (byte) PIXEL_TYPE_RGBA; - } else if (pixel_bytes == 3) { - image->pixel_type = (byte) PIXEL_TYPE_RGB; - } else { - ASSERT_SIMPLE(false); - } + image->image_settings |= (image->image_settings & IMAGE_SETTING_CHANNEL_COUNT) == 0 + ? pixel_bytes + : image->image_settings & IMAGE_SETTING_CHANNEL_COUNT; - if (image->order_pixels == IMAGE_PIXEL_ORDER_BGRA - && image->order_rows == IMAGE_ROW_ORDER_BOTTOM_TO_TOP + if ((image->image_settings & IMAGE_SETTING_PIXEL_BGR) + && (image->image_settings & IMAGE_SETTING_BOTTOM_TO_TOP) ) { // @bug This doesn't consider the situation where we want alpha as a setting but the img doesn't have it // @bug This also copies possible padding which will corrupt the image @@ -308,13 +304,9 @@ void image_bmp_generate(const FileBody* src_data, Image* image) for (uint32 y = 0; y < src.dib_header.height; ++y) { uint32 row_pos1 = y * width_pixel_bytes; - - uint32 row_pos2; - if (image->order_rows == IMAGE_ROW_ORDER_TOP_TO_BOTTOM) { - row_pos2 = (src.dib_header.height - y - 1) * width_pixel_bytes; - } else { - row_pos2 = y * width_pixel_bytes; - } + uint32 row_pos2 = image->image_settings & IMAGE_SETTING_BOTTOM_TO_TOP + ? y * width_pixel_bytes + : (src.dib_header.height - y - 1) * width_pixel_bytes; for (uint32 x = 0; x < width; ++x) { if (x >= image->width) { @@ -324,20 +316,20 @@ void image_bmp_generate(const FileBody* src_data, Image* image) } // Invert byte order - if (image->order_pixels == IMAGE_PIXEL_ORDER_RGBA) { - for (uint32 i = 0; i < pixel_rgb_bytes; ++i) { - image->pixels[row_pos1 + x * pixel_bytes + i] = src.pixels[row_pos2 + x * pixel_bytes + pixel_rgb_bytes - i]; - } - } else { + if (image->image_settings & IMAGE_SETTING_PIXEL_BGR) { for (uint32 i = 0; i < pixel_rgb_bytes; ++i) { image->pixels[row_pos1 + x * pixel_bytes + i] = src.pixels[row_pos2 + x * pixel_bytes + i]; } + } else { + for (uint32 i = 0; i < pixel_rgb_bytes; ++i) { + image->pixels[row_pos1 + x * pixel_bytes + i] = src.pixels[row_pos2 + x * pixel_bytes + pixel_rgb_bytes - i]; + } } - // Add alpha channel at end of every RGB value + // Add alpha channel at end of every RGB value (either the image already contains it or we have to add it manually) if (alpha_offset > 0) { image->pixels[row_pos1 + x * pixel_bytes + 3] = src.pixels[row_pos2 + x * pixel_bytes + pixel_bytes + 3]; - } else if (image->pixel_type == PIXEL_TYPE_RGBA) { + } else if ((image->image_settings & IMAGE_SETTING_CHANNEL_COUNT) == 4) { image->pixels[row_pos1 + x * pixel_bytes + 3] = 0xFF; } } diff --git a/image/Image.cpp b/image/Image.cpp index bd22663..0a1cb74 100644 --- a/image/Image.cpp +++ b/image/Image.cpp @@ -61,35 +61,16 @@ void image_flip_vertical(RingMemory* ring, Image* image) } */ - image->order_rows = (byte) (!((bool) image->order_rows)); + image->image_settings ^= IMAGE_SETTING_BOTTOM_TO_TOP; } inline int32 image_pixel_size_from_type(byte type) { - switch (type) { - case PIXEL_TYPE_RGBA: { - return 4; - } break; - case PIXEL_TYPE_RGB: { - return 3; - } break; - case PIXEL_TYPE_MONO: { - return 1; - } break; - case PIXEL_TYPE_RGBA_F: { - return 16; - } break; - case PIXEL_TYPE_RGB_F: { - return 12; - } break; - case PIXEL_TYPE_MONO_F: { - return 4; - } break; - default: { - UNREACHABLE(); - } - } + int32 channel_size = type & IMAGE_SETTING_CHANNEL_4_SIZE ? 4 : 1; + int32 channel_count = type & IMAGE_SETTING_CHANNEL_COUNT; + + return channel_size * channel_count; } int32 image_from_data(const byte* data, Image* image) @@ -102,20 +83,13 @@ int32 image_from_data(const byte* data, Image* image) image->height = SWAP_ENDIAN_LITTLE(*((uint32 *) pos)); pos += sizeof(image->height); - image->pixel_count = SWAP_ENDIAN_LITTLE(*((uint32 *) pos)); - pos += sizeof(image->pixel_count); + image->pixel_count = image->width * image->height; - image->order_pixels = *pos; - pos += sizeof(image->order_pixels); - - image->order_rows = *pos; - pos += sizeof(image->order_rows); - - image->pixel_type = *pos; - pos += sizeof(image->pixel_type); + image->image_settings = *pos; + pos += sizeof(image->image_settings); int32 image_size; - memcpy(image->pixels, pos, image_size = (image_pixel_size_from_type(image->pixel_type) * image->pixel_count)); + memcpy(image->pixels, pos, image_size = (image_pixel_size_from_type(image->image_settings) * image->pixel_count)); pos += image_size; return (int32) (pos - data); @@ -131,20 +105,11 @@ int32 image_to_data(const Image* image, byte* data) *((uint32 *) pos) = SWAP_ENDIAN_LITTLE(image->height); pos += sizeof(image->height); - *((uint32 *) pos) = SWAP_ENDIAN_LITTLE(image->pixel_count); - pos += sizeof(image->pixel_count); - - *pos = image->order_pixels; - pos += sizeof(image->order_pixels); - - *pos = image->order_rows; - pos += sizeof(image->order_rows); - - *pos = image->pixel_type; - pos += sizeof(image->pixel_type); + *pos = image->image_settings; + pos += sizeof(image->image_settings); int32 image_size; - memcpy(pos, image->pixels, image_size = (image_pixel_size_from_type(image->pixel_type) * image->pixel_count)); + memcpy(pos, image->pixels, image_size = (image_pixel_size_from_type(image->image_settings) * image->pixel_count)); pos += image_size; return (int32) (pos - data); diff --git a/image/Image.h b/image/Image.h index 80f2395..fecf1ac 100644 --- a/image/Image.h +++ b/image/Image.h @@ -11,21 +11,11 @@ #include "../stdlib/Types.h" -#define IMAGE_PIXEL_ORDER_RGBA 0 -#define IMAGE_PIXEL_ORDER_BGRA 1 - -#define IMAGE_ROW_ORDER_TOP_TO_BOTTOM 0 -#define IMAGE_ROW_ORDER_BOTTOM_TO_TOP 1 - -enum PixelType -{ - PIXEL_TYPE_RGBA, // 4 bytes - PIXEL_TYPE_RGB, // 3 bytes - PIXEL_TYPE_MONO, // 1 byte - PIXEL_TYPE_RGBA_F, // 16 bytes - PIXEL_TYPE_RGB_F, // 12 bytes - PIXEL_TYPE_MONO_F, // 4 bytes -}; +#define IMAGE_SETTING_PIXEL_BGR 0b10000000 // 0 = rgba, 1 = bgra +#define IMAGE_SETTING_BOTTOM_TO_TOP 0b01000000 // 0 = ttb, 1 = btt +#define IMAGE_SETTING_COLOR_MODE_SRGB 0b00100000 // 0 = rgb, 1 = srgb +#define IMAGE_SETTING_CHANNEL_4_SIZE 0b00010000 // 0 = 1 byte, 1 = 4 byte (usually float) +#define IMAGE_SETTING_CHANNEL_COUNT 0b00001111 // This struct also functions as a setting on how to load the image data // has_alpha is defined it forces an alpha channel even for bitmaps @@ -35,12 +25,9 @@ enum PixelType struct Image { uint32 width; uint32 height; - uint32 pixel_count; // @question Do we even need this? + uint32 pixel_count; - // Image settings - byte order_pixels; // RGBA vs BGRA - byte order_rows; // top-to-bottom vs bottom-to-top - byte pixel_type; // Usually 4 or 3 bytes unless monochrome data + byte image_settings; byte* pixels; // owner of data }; diff --git a/image/Png.h b/image/Png.h index 94bbb3c..0ea302a 100644 --- a/image/Png.h +++ b/image/Png.h @@ -783,9 +783,7 @@ bool image_png_generate(const FileBody* src_data, Image* image, RingMemory* ring image->width = src.ihdr.width; image->height = src.ihdr.height; image->pixel_count = image->width * image->height; - image->pixel_type = (byte) (src.ihdr.color_type == 6 ? PIXEL_TYPE_RGBA : PIXEL_TYPE_RGB); - image->order_pixels = IMAGE_PIXEL_ORDER_RGBA; - image->order_rows = IMAGE_ROW_ORDER_TOP_TO_BOTTOM; + image->image_settings |= src.ihdr.color_type == 6 ? 4 : 3; png_filter_reconstruct(src.ihdr.width, src.ihdr.height, src.ihdr.color_type, decompressed, finalized, steps); diff --git a/image/Qoi.h b/image/Qoi.h index dc9e65a..ddf8154 100644 --- a/image/Qoi.h +++ b/image/Qoi.h @@ -11,6 +11,7 @@ #include "../stdlib/Types.h" #include "../memory/RingMemory.h" +#include "Image.h" #define QOI_OP_INDEX 0b00000000 #define QOI_OP_DIFF 0b01000000 @@ -37,14 +38,7 @@ uint32 qoi_encode_size(QoiDescription* desc) return desc->width * desc->height * (desc->channels + 1) + QOI_HEADER_SIZE; } -int32 qoi_encode(const byte* data, byte* output, const QoiDescription* desc) { - if (desc->width == 0 || desc->height == 0 || - desc->channels < 3 || desc->channels > 4 || - desc->colorspace > 1 - ) { - return; - } - +int32 qoi_encode(const Image* image, byte* output) { int32 p = 0; *((uint32 *) output[p]) = SWAP_ENDIAN_LITTLE(desc->width); p += 4; *((uint32 *) output[p]) = SWAP_ENDIAN_LITTLE(desc->height); p += 4; @@ -130,7 +124,7 @@ uint32 qoi_decode_size(QoiDescription* desc, int32 channels) return desc->width * desc->height * channels; } -void qoi_decode(const byte* data, byte* output, int32 steps = 8) +void qoi_decode(const byte* data, Image* image, int32 steps = 8) { int32 p = 0; uint32 width = SWAP_ENDIAN_LITTLE(*((uint32 *) &data[p])); p += 4; diff --git a/image/Tga.h b/image/Tga.h index 735be6a..ed006a9 100644 --- a/image/Tga.h +++ b/image/Tga.h @@ -90,17 +90,13 @@ void image_tga_generate(const FileBody* src_data, Image* image) uint32 pixel_bytes = src.header.bits_per_pixel / 8; byte alpha_offset = pixel_bytes > 3; - if (pixel_bytes == 4) { - image->pixel_type = (byte) PIXEL_TYPE_RGBA; - } else if (pixel_bytes == 3) { - image->pixel_type = (byte) PIXEL_TYPE_RGB; - } else { - ASSERT_SIMPLE(false); - } + image->image_settings |= (image->image_settings & IMAGE_SETTING_CHANNEL_COUNT) == 0 + ? pixel_bytes + : image->image_settings & IMAGE_SETTING_CHANNEL_COUNT; // We can check same settings through equality since we use the same values - if (image->order_rows == src.header.vertical_ordering - && image->order_pixels == src.header.horizonal_ordering + if ((image->image_settings & IMAGE_SETTING_BOTTOM_TO_TOP) == src.header.vertical_ordering + && src.header.horizonal_ordering == 0 ) { // @bug This doesn't consider the situation where we want alpha as a setting but the img doesn't have it memcpy((void *) image->pixels, src.pixels, image->pixel_count * pixel_bytes); @@ -113,18 +109,12 @@ void image_tga_generate(const FileBody* src_data, Image* image) for (uint32 y = 0; y < src.header.height; ++y) { uint32 row_pos1 = y * image->width * pixel_bytes; - - uint32 row_pos2; - if ((image->order_rows == IMAGE_ROW_ORDER_TOP_TO_BOTTOM && src.header.vertical_ordering == 1) - || (image->order_rows == IMAGE_ROW_ORDER_BOTTOM_TO_TOP && src.header.vertical_ordering == 0) - ) { - row_pos2 = (src.header.height - y - 1) * image->width * pixel_bytes; - } else { - row_pos2 = y * width_pixel_bytes; - } + uint32 row_pos2 = (image->image_settings & IMAGE_SETTING_BOTTOM_TO_TOP) == src.header.vertical_ordering + ? y * width_pixel_bytes + : (src.header.height - y - 1) * image->width * pixel_bytes; for (uint32 x = 0; x < src.header.width; ++x) { - if (image->order_pixels == src.header.horizonal_ordering) { + if (src.header.horizonal_ordering == 0) { for (uint32 i = 0; i < pixel_rgb_bytes; ++i) { image->pixels[row_pos1 + x * pixel_bytes + i] = src.pixels[row_pos2 + x * pixel_bytes + i]; } @@ -134,10 +124,10 @@ void image_tga_generate(const FileBody* src_data, Image* image) } } - // Add alpha channel at end of every RGB value + // Add alpha channel at end of every RGB value (either the image already contains it or we have to add it manually) if (alpha_offset > 0) { image->pixels[row_pos1 + x * pixel_bytes + 3] = src.pixels[row_pos2 + x * pixel_bytes + pixel_bytes + 3]; - } else if (image->pixel_type == PIXEL_TYPE_RGBA) { + } else if ((image->image_settings & IMAGE_SETTING_CHANNEL_COUNT) == 4) { image->pixels[row_pos1 + x * pixel_bytes + 3] = 0xFF; } } diff --git a/platform/win32/LeanWin32.h b/platform/win32/LeanWin32.h new file mode 100644 index 0000000..6442682 --- /dev/null +++ b/platform/win32/LeanWin32.h @@ -0,0 +1,55 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_LEAN_H +#define TOS_PLATFORM_WIN32_LEAN_H + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #define NOGDICAPMASKS 1 + #define NOVIRTUALKEYCODES 1 + #define NOWINMESSAGES 1 + #define NOWINSTYLES 1 + #define NOSYSMETRICS 1 + #define NOMENUS 1 + #define NOICONS 1 + #define NOKEYSTATES 1 + #define NOSYSCOMMANDS 1 + #define NORASTEROPS 1 + #define NOSHOWWINDOW 1 + #define OEMRESOURCE 1 + #define NOATOM 1 + #define NOCLIPBOARD 1 + #define NOCOLOR 1 + #define NOCTLMGR 1 + #define NODRAWTEXT 1 + #define NOGDI 1 + #define NOKERNEL 1 + #define NOUSER 1 + #define NONLS 1 + #define NOMB 1 + #define NOMEMMGR 1 + #define NOMETAFILE 1 + #define NOMINMAX 1 + #define NOMSG 1 + #define NOOPENFILE 1 + #define NOSCROLL 1 + #define NOSERVICE 1 + #define NOSOUND 1 + #define NOTEXTMETRIC 1 + #define NOWH 1 + #define NOWINOFFSETS 1 + #define NOCOMM 1 + #define NOKANJI 1 + #define NOHELP 1 + #define NOPROFILER 1 + #define NODEFERWINDOWPOS 1 + #define NOMCX 1 +#endif + +#endif \ No newline at end of file diff --git a/utils/BitUtils.h b/utils/BitUtils.h index 4f595d4..ac0c50d 100644 --- a/utils/BitUtils.h +++ b/utils/BitUtils.h @@ -16,7 +16,7 @@ // This file can remain but the callers should get adjusted // Obviously we would have to check at runtime if ABM is supported -// Left to right +// Left to right (big endian) #define IS_BIT_SET_L2R(num, pos, bits) ((bool) ((num) & (1 << ((bits - 1) - (pos))))) #define BIT_SET_L2R(num, pos, bits) ((num) | ((uint32) 1 << ((bits - 1) - (pos)))) #define BIT_UNSET_L2R(num, pos, bits) ((num) & ~((uint32) 1 << ((bits - 1) - (pos)))) @@ -27,11 +27,13 @@ #define BITS_GET_32_L2R(num, pos, to_read) (((num) >> (32 - (pos) - (to_read))) & ((1U << (to_read)) - 1)) #define BITS_GET_64_L2R(num, pos, to_read) (((num) >> (64 - (pos) - (to_read))) & ((1ULL << (to_read)) - 1)) -#define BYTES_MERGE_2_L2R(num) (((num)[0] << 8) | (num)[1]) -#define BYTES_MERGE_4_L2R(num) (((num)[0] << 24) | ((num)[1] << 16) | ((num)[2] << 8) | (num)[3]) -#define BYTES_MERGE_8_L2R(num) (((uint64_t)(num)[0] << 56) | ((uint64_t)(num)[1] << 48) | ((uint64_t)(num)[2] << 40) | ((uint64_t)(num)[3] << 32) | ((uint64_t)(num)[4] << 24) | ((uint64_t)(num)[5] << 16) | ((uint64_t)(num)[6] << 8) | ((uint64_t)(num)[7])) +// Merges an array of bytes as an int value (16bit, 32bit, 64bit) +// Depending on the endianness of the system you could simply cast the array +#define BYTES_MERGE_2_L2R(arr) (((arr)[0] << 8) | (arr)[1]) +#define BYTES_MERGE_4_L2R(arr) (((arr)[0] << 24) | ((arr)[1] << 16) | ((arr)[2] << 8) | (arr)[3]) +#define BYTES_MERGE_8_L2R(arr) (((uint64_t)(arr)[0] << 56) | ((uint64_t)(arr)[1] << 48) | ((uint64_t)(arr)[2] << 40) | ((uint64_t)(arr)[3] << 32) | ((uint64_t)(arr)[4] << 24) | ((uint64_t)(arr)[5] << 16) | ((uint64_t)(arr)[6] << 8) | ((uint64_t)(arr)[7])) -// Right to left +// Right to left (little endian) #define IS_BIT_SET_R2L(num, pos) ((bool) ((num) & (1 << (pos)))) #define BIT_SET_R2L(num, pos) ((num) | ((uint32) 1 << (pos))) #define BIT_UNSET_R2L(num, pos) ((num) & ~((uint32) 1 << (pos))) @@ -43,9 +45,11 @@ #define BITS_GET_32_R2L(num, pos, to_read) (((num) >> (pos)) & ((1U << (to_read)) - 1)) #define BITS_GET_64_R2L(num, pos, to_read) (((num) >> (pos)) & ((1ULL << (to_read)) - 1)) -#define BYTES_MERGE_2_R2L(num) (((num)[1] << 8) | (num)[0]) -#define BYTES_MERGE_4_R2L(num) (((num)[3] << 24) | ((num)[2] << 16) | ((num)[1] << 8) | (num)[0]) -#define BYTES_MERGE_8_R2L(num) (((uint64_t)(num)[7] << 56) | ((uint64_t)(num)[6] << 48) | ((uint64_t)(num)[5] << 40) | ((uint64_t)(num)[4] << 32) | ((uint64_t)(num)[3] << 24) | ((uint64_t)(num)[2] << 16) | ((uint64_t)(num)[1] << 8) | ((uint64_t)(num)[0])) +// Merges an array of bytes as an int value (16bit, 32bit, 64bit) +// Depending on the endianness of the system you could simply cast the array +#define BYTES_MERGE_2_R2L(arr) (((arr)[1] << 8) | (arr)[0]) +#define BYTES_MERGE_4_R2L(arr) (((arr)[3] << 24) | ((arr)[2] << 16) | ((arr)[1] << 8) | (arr)[0]) +#define BYTES_MERGE_8_R2L(arr) (((uint64_t)(arr)[7] << 56) | ((uint64_t)(arr)[6] << 48) | ((uint64_t)(arr)[5] << 40) | ((uint64_t)(arr)[4] << 32) | ((uint64_t)(arr)[3] << 24) | ((uint64_t)(arr)[2] << 16) | ((uint64_t)(arr)[1] << 8) | ((uint64_t)(arr)[0])) struct BitWalk { byte* pos; @@ -278,37 +282,6 @@ void bits_flush(BitWalk* stream) // return bits; // } -inline -uint32 bytes_merge(byte b0, byte b1, byte b2, byte b3) { - uint32 result = 0; - - result |= ((uint32) b0 << 24); - result |= ((uint32) b1 << 16); - result |= ((uint32) b2 << 8); - result |= (uint32) b3; - - return result; -} - -inline -uint64 bytes_merge( - byte b0, byte b1, byte b2, byte b3, - byte b4, byte b5, byte b6, byte b7 -) { - uint64 result = 0; - - result |= ((uint64) b0 << 56); - result |= ((uint64) b1 << 48); - result |= ((uint64) b2 << 40); - result |= ((uint64) b3 << 32); - result |= ((uint64) b4 << 24); - result |= ((uint64) b5 << 16); - result |= ((uint64) b6 << 8); - result |= (uint64) b7; - - return result; -} - static inline int32 find_first_set_bit(int32 value) { if (value == 0) { @@ -350,7 +323,7 @@ uint32 bits_reverse(uint32 data, uint32 count) return reversed; } -const int32 BIT_COUNT_LOOKUP_TABLE[256] = { +static const int32 BIT_COUNT_LOOKUP_TABLE[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,