image header optimizations

This commit is contained in:
Dennis Eichhorn 2024-12-21 22:36:48 +01:00
parent 5d7943016d
commit d983df0158
15 changed files with 433 additions and 324 deletions

View File

@ -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: {

View File

@ -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);

View File

@ -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;

View File

@ -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 <d3d12.h>
#include <d3dcompiler.h>
#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

View File

@ -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);

View File

@ -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

143
gpuapi/vulkan/ShaderUtils.h Normal file
View File

@ -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 <vulkan/vulkan.h>
#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

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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
};

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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,