Generating a f***ed up normal texture
This commit is contained in:
parent
b526157870
commit
af94aeeef7
5
.gitignore
vendored
5
.gitignore
vendored
@ -5,6 +5,9 @@ vgcore.*
|
||||
/gen/
|
||||
*.pdf
|
||||
*.r8g8b8a8
|
||||
*.r8b8g8
|
||||
*.r8g8b8
|
||||
*.r8
|
||||
*.a8
|
||||
*.xcf
|
||||
*_NORMAL.png
|
||||
*_TEMPLATE.png
|
||||
@ -310,4 +310,8 @@ T OptionT##_expect(OptionT self){ \
|
||||
#define OptionT_struct_Definition(T) OptionT_struct_Definition_custom_name(T, Option##T)
|
||||
#define OptionT_method_Definition(T) OptionT_method_Definition_custom_name(T, Option##T)
|
||||
|
||||
float pow2f(float x) {
|
||||
return x * x;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -214,6 +214,43 @@ NODISCARD VecU8 generate_xvecy_method_and_one(ConstSpanU8 xvec, int n) {
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_xvecy_method_dot(ConstSpanU8 xvec, ConstSpanU8 member, int n) {
|
||||
VecU8 res = VecU8_from_span(member);
|
||||
VecU8_append(&res, ' ');
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append_span(&res, cstr("_dot("));
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append_span(&res, cstr(" A, "));
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return "));
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i)
|
||||
VecU8_append_span(&res, cstr(" + "));
|
||||
VecU8_append_span(&res, cstr("A."));
|
||||
string_append_vec_field_name(&res, i);
|
||||
VecU8_append_span(&res, cstr(" * B."));
|
||||
string_append_vec_field_name(&res, i);
|
||||
}
|
||||
VecU8_append_span(&res, cstr(";\n}\n\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_xvec3_method_cross(ConstSpanU8 xvec) {
|
||||
VecU8 res = VecU8_new();
|
||||
string_append_xvecy(&res, xvec, 3);
|
||||
VecU8_append(&res, ' ');
|
||||
string_append_xvecy(&res, xvec, 3);
|
||||
VecU8_append_span(&res, cstr("_cross("));
|
||||
string_append_xvecy(&res, xvec, 3);
|
||||
VecU8_append_span(&res, cstr(" A, "));
|
||||
string_append_xvecy(&res, xvec, 3);
|
||||
VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return ("));
|
||||
string_append_xvecy(&res, xvec, 3);
|
||||
VecU8_append_span(&res, cstr("){A.y * B.z - A.z * B.y, -A.x * B.z + A.z * B.x, A.x * B.y - A.y * B.x};\n}\n\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void string_append_xmatnm(VecU8* str, ConstSpanU8 xmat, int cols, int rows) {
|
||||
VecU8_append_span(str, xmat);
|
||||
VecU8_append(str, '0' + cols);
|
||||
@ -439,29 +476,6 @@ NODISCARD VecU8 generate_xmatnm_method_div_by_scal(ConstSpanU8 xmat, ConstSpanU8
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_xvecn_method_dot_xvecn(ConstSpanU8 xvec, ConstSpanU8 member, int n) {
|
||||
VecU8 res = VecU8_from_span(member);
|
||||
VecU8_append(&res, ' ');
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append_span(&res, cstr("_dot_"));
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append(&res, '(');
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append_span(&res, cstr(" A, "));
|
||||
string_append_xvecy(&res, xvec, n);
|
||||
VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return "));
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i)
|
||||
VecU8_append_span(&res, cstr(" + "));
|
||||
VecU8_append_span(&res, cstr("A."));
|
||||
string_append_vec_field_name(&res, i);
|
||||
VecU8_append_span(&res, cstr(" * B."));
|
||||
string_append_vec_field_name(&res, i);
|
||||
}
|
||||
VecU8_append_span(&res, cstr(";\n}\n\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_xmatnm_method_mul_xvecn(ConstSpanU8 xmat, ConstSpanU8 xvec, int n, int m) {
|
||||
VecU8 res = VecU8_new();
|
||||
string_append_xvecy(&res, xvec, m);
|
||||
@ -575,9 +589,11 @@ NODISCARD VecU8 generate_xvec234_structs_and_methods(ConstSpanU8 xvec, ConstSpan
|
||||
VecU8_append_vec(&res, generate_xvecy_method_mul_scal(xvec, member, cc));
|
||||
VecU8_append_vec(&res, generate_xvecy_method_div_by_scal(xvec, member, cc));
|
||||
VecU8_append_vec(&res, generate_xvecy_method_mul_xvecy(xvec, member, cc));
|
||||
VecU8_append_vec(&res, generate_xvecy_method_dot(xvec, member, cc));
|
||||
}
|
||||
for (int n = 2; n <= 3; n++)
|
||||
VecU8_append_vec(&res, generate_xvecy_method_and_one(xvec, n));
|
||||
VecU8_append_vec(&res, generate_xvec3_method_cross(xvec));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -848,7 +848,7 @@ VkSwapchainKHR MargaretSwapchainBundle_pop_swapchain_drop_rest(VkDevice device,
|
||||
// Not a regular _drop method, because it requires a bundled VkDevice
|
||||
void MargaretSwapchainBundle_drop_with_device(VkDevice device, MargaretSwapchainBundle swfb) {
|
||||
VkSwapchainKHR swapchain = MargaretSwapchainBundle_pop_swapchain_drop_rest(device, swfb);
|
||||
vkDestroySwapchainKHR(device, swfb.swapchain, NULL);
|
||||
vkDestroySwapchainKHR(device, swapchain, NULL);
|
||||
// Now swapchain bundle is 100% dropped
|
||||
}
|
||||
|
||||
@ -1114,11 +1114,16 @@ MargaretBufferInMemoryInfo margaret_prep_buffer_mem_info_of_small_local_ubo(size
|
||||
return (MargaretBufferInMemoryInfo){ .sz = struct_sz, .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT };
|
||||
}
|
||||
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_rgba(uint32_t w, uint32_t h) {
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_srgba(uint32_t w, uint32_t h) {
|
||||
return (MargaretImageInMemoryInfo){ .width = w, .height = h, .format = VK_FORMAT_R8G8B8A8_SRGB,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
|
||||
}
|
||||
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_unorm_32(uint32_t w, uint32_t h) {
|
||||
return (MargaretImageInMemoryInfo){ .width = w, .height = h, .format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
|
||||
}
|
||||
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_zbuffer(uint32_t max_width, uint32_t max_height, VkFormat zbuf_format) {
|
||||
return (MargaretImageInMemoryInfo){ .width = max_width, .height = max_height, .format = zbuf_format,
|
||||
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT };
|
||||
@ -1303,16 +1308,16 @@ VkImageView margaret_create_view_for_image (
|
||||
}
|
||||
|
||||
// For texture
|
||||
VkSampler margaret_create_sampler(VkPhysicalDevice physical_device, VkDevice device) {
|
||||
VkSampler margaret_create_sampler(VkPhysicalDevice physical_device, VkDevice device, bool make_linear) {
|
||||
VkPhysicalDeviceProperties physical_device_properties;
|
||||
vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties);
|
||||
VkPhysicalDeviceFeatures physical_device_features;
|
||||
vkGetPhysicalDeviceFeatures(physical_device, &physical_device_features);
|
||||
VkSamplerCreateInfo crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = VK_FILTER_LINEAR,
|
||||
.minFilter = VK_FILTER_LINEAR,
|
||||
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
||||
.magFilter = make_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST,
|
||||
.minFilter = make_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST,
|
||||
.mipmapMode = make_linear? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST,
|
||||
.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
|
||||
.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
|
||||
.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
|
||||
|
||||
@ -74,4 +74,13 @@ mat3 marie_simple_camera_rot_m_basis_in_cols(float yaw, float pitch, float roll)
|
||||
};
|
||||
}
|
||||
|
||||
vec2 marie_trigonom_circle(float angle) {
|
||||
return (vec2){cosf(angle), sinf(angle)};
|
||||
}
|
||||
|
||||
vec3 marie_normal_from_tang_space_gradient(float delt_x, float delta_z) {
|
||||
float N = 1 / sqrtf(delt_x * delt_x + delta_z * delta_z + 1);
|
||||
return (vec3){-delt_x * N, N, -delta_z * N};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -205,7 +205,6 @@ PipelineHands create_graphics_pipeline_0(
|
||||
|
||||
VkDescriptorSetLayoutBinding bindings_for_my_descr_set_layout[] = {
|
||||
{
|
||||
// Binding in shader
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
// our shader variable is not an array of descriptors, so this stays 1
|
||||
@ -218,6 +217,12 @@ PipelineHands create_graphics_pipeline_0(
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
},
|
||||
{
|
||||
.binding = 2,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
},
|
||||
};
|
||||
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
@ -715,14 +720,19 @@ int main() {
|
||||
ModelTopology cylinder_1 = generate_one_fourth_of_a_cylinder(10, 2, 6);
|
||||
ModelTopology cylinder_2 = generate_one_fourth_of_a_cylinder(5, 5, 10);
|
||||
// TextureDataR8G8B8A8 wood_texture_data = generate_texture_for_one_fourth_of_a_cylinder(20, 10, 2, 6);
|
||||
TextureDataR8G8B8A8 wood_texture_data = TextureDataR8G8B8A8_read_from_file("test_textures/log_10_2_6.r8g8b8a8");
|
||||
// todo: learn how to use libpng
|
||||
TextureDataR8G8B8A8 cyl_1_diffuse_tex = TextureDataR8G8B8A8_read_from_file("test_textures/log_10_2_6.r8g8b8a8");
|
||||
// todo: learn how to write texture immediately from file to mapped host memory buffer
|
||||
// todo: and at the same time I need to add methods to convert between these formats
|
||||
TextureDataR8G8B8A8 cyl_1_normal_tex = TextureDataR8G8B8A8_read_from_file("test_textures/log_10_2_6_NORMAL.r8g8b8a8");
|
||||
|
||||
// We have only one staging buffer in host memory (because we don't really need more)
|
||||
MargaretBufferInMemoryInfo host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz =
|
||||
MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_1),
|
||||
MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_2),
|
||||
MAX_U64(sizeof(Pipeline0UBO),
|
||||
MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&wood_texture_data), 0))))
|
||||
MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_diffuse_tex),
|
||||
MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_normal_tex), 0)))))
|
||||
, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT };
|
||||
VkDeviceMemory host_mem = margaret_initialize_buffers_and_images(physical_device, device,
|
||||
(SpanMargaretBufferInMemoryInfo){.data = &host_mem_buffer, .len = 1}, (SpanMargaretImageInMemoryInfo){ 0 },
|
||||
@ -736,11 +746,14 @@ int main() {
|
||||
margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)),
|
||||
};
|
||||
MargaretImageInMemoryInfo device_mem_images[] = {
|
||||
margaret_prep_image_mem_info_of_gpu_texture_rgba(wood_texture_data.width,
|
||||
TextureDataR8G8B8A8_get_height(&wood_texture_data)),
|
||||
margaret_prep_image_mem_info_of_colorbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, IT1_format.some),
|
||||
margaret_prep_image_mem_info_of_zbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some),
|
||||
margaret_prep_image_mem_info_of_gpu_texture_srgba(cyl_1_diffuse_tex.width,
|
||||
TextureDataR8G8B8A8_get_height(&cyl_1_diffuse_tex)),
|
||||
margaret_prep_image_mem_info_of_gpu_texture_srgba(cyl_1_normal_tex.width,
|
||||
TextureDataR8G8B8A8_get_height(&cyl_1_normal_tex)),
|
||||
};
|
||||
// todo: replace this ugly garbage with pointer spans. Seriously, this is fucking digusting
|
||||
VkDeviceMemory device_mem = margaret_initialize_buffers_and_images(physical_device, device,
|
||||
(SpanMargaretBufferInMemoryInfo){ .data = device_mem_buffers, .len = ARRAY_SIZE(device_mem_buffers)},
|
||||
(SpanMargaretImageInMemoryInfo){ .data = device_mem_images, .len = ARRAY_SIZE(device_mem_images) },
|
||||
@ -750,9 +763,10 @@ int main() {
|
||||
MargaretBufferInMemoryInfo device_vbo_2_buffer = device_mem_buffers[2];
|
||||
MargaretBufferInMemoryInfo device_ebo_2_buffer = device_mem_buffers[3];
|
||||
MargaretBufferInMemoryInfo device_ubo_my_buffer = device_mem_buffers[4];
|
||||
MargaretImageInMemoryInfo device_wood_texture = device_mem_images[0];
|
||||
MargaretImageInMemoryInfo device_IT1_image = device_mem_images[1];
|
||||
MargaretImageInMemoryInfo device_zbuffer_image = device_mem_images[2];
|
||||
MargaretImageInMemoryInfo device_IT1_image = device_mem_images[0];
|
||||
MargaretImageInMemoryInfo device_zbuffer_image = device_mem_images[1];
|
||||
MargaretImageInMemoryInfo device_cyl_1_diffuse_texture = device_mem_images[2];
|
||||
MargaretImageInMemoryInfo device_cyl_1_normal_texture = device_mem_images[3];
|
||||
|
||||
VkCommandPool command_pool = margaret_create_resettable_command_pool(device, queue_fam.for_graphics);
|
||||
VkCommandBuffer rendering_command_buffer_0 = margaret_allocate_command_buffer(device, command_pool);
|
||||
@ -790,14 +804,20 @@ int main() {
|
||||
margaret_copy_buffer_imm(device, command_pool, graphics_queue,
|
||||
device_ebo_2_buffer.buffer, host_mem_buffer.buffer, size);
|
||||
}
|
||||
memcpy(host_mem_buffer_mem, wood_texture_data.pixels.buf,
|
||||
TextureDataR8G8B8A8_get_size_in_bytes(&wood_texture_data));
|
||||
margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue,
|
||||
&device_wood_texture, host_mem_buffer.buffer);
|
||||
{
|
||||
memcpy(host_mem_buffer_mem, cyl_1_diffuse_tex.pixels.buf,
|
||||
TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_diffuse_tex));
|
||||
margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue,
|
||||
&device_cyl_1_diffuse_texture, host_mem_buffer.buffer);
|
||||
}
|
||||
{
|
||||
memcpy(host_mem_buffer_mem, cyl_1_normal_tex.pixels.buf, TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_normal_tex));
|
||||
margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue,
|
||||
&device_cyl_1_normal_texture, host_mem_buffer.buffer);
|
||||
}
|
||||
|
||||
// We sent everything we needed. but host_mem_buffer_mem may be used later
|
||||
|
||||
// My wood texture needs VkImageView
|
||||
VkImageView wood_texture_view = margaret_create_view_for_image(device, &device_wood_texture, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
// My zbuffer also needs a view
|
||||
VkImageView zbuffer_view = margaret_create_view_for_image(device, &device_zbuffer_image, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
/* Here we create an image view into a temporary IT1 texture and a framebuffer for scene rendering */
|
||||
@ -805,17 +825,23 @@ int main() {
|
||||
VkFramebuffer IT1_framebuffer = create_IT1_framebuffer(device, IT1_view, zbuffer_view, render_pass_0,
|
||||
MAX_WIN_WIDTH, MAX_WIN_HEIGHT);
|
||||
|
||||
// My cylinder 1 texture needs VkImageView
|
||||
VkImageView cyl_1_diffuse_texture_view = margaret_create_view_for_image(device, &device_cyl_1_diffuse_texture, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
// My cylinder 1 normal texture also needs NkImageView
|
||||
VkImageView cyl_1_normal_texture_view = margaret_create_view_for_image(device, &device_cyl_1_normal_texture, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
|
||||
Scene scene = Scene_new();
|
||||
VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){.model = {
|
||||
.vbo = device_vbo_1_buffer.buffer, .ebo = device_ebo_1_buffer.buffer, .indexes = cylinder_1.indexes.len
|
||||
}, .model_t = marie_translation_mat4((vec3){1, -1, 5}) });
|
||||
VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){.model = {
|
||||
.vbo = device_vbo_2_buffer.buffer, .ebo = device_ebo_2_buffer.buffer, .indexes = cylinder_2.indexes.len
|
||||
}, .model_t = marie_translation_mat4((vec3){6, -3, 7}) });
|
||||
}, .model_t = marie_translation_mat4((vec3){6, -3, 16}) });
|
||||
|
||||
// Sampler is global for a lot of my future textures
|
||||
VkSampler my_texture_sampler = margaret_create_sampler(physical_device, device);
|
||||
VkDescriptorPool descriptor_pool = margaret_create_descriptor_set_pool(device, 1, 2, 2);
|
||||
// These samplers are global for a lot of my future textures
|
||||
VkSampler linear_sampler = margaret_create_sampler(physical_device, device, true);
|
||||
VkSampler nearest_sampler = margaret_create_sampler(physical_device, device, false);
|
||||
VkDescriptorPool descriptor_pool = margaret_create_descriptor_set_pool(device, 1, 3, 2);
|
||||
|
||||
VkDescriptorSet descriptor_set_for_pipeline_0 = margaret_allocate_descriptor_set(device, descriptor_pool, pipeline_hands_0.descriptor_set_layout);
|
||||
VkDescriptorSet descriptor_set_for_pipeline_1 = margaret_allocate_descriptor_set(device, descriptor_pool, pipeline_hands_1.descriptor_set_layout);
|
||||
@ -827,12 +853,17 @@ int main() {
|
||||
.range = sizeof(Pipeline0UBO),
|
||||
};
|
||||
VkDescriptorImageInfo image_info_for_descriptor_1_in_set_0 = {
|
||||
.sampler = my_texture_sampler,
|
||||
.imageView = wood_texture_view,
|
||||
.sampler = linear_sampler,
|
||||
.imageView = cyl_1_diffuse_texture_view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
};
|
||||
VkDescriptorImageInfo image_info_for_descriptor_2_in_set_0 = {
|
||||
.sampler = nearest_sampler,
|
||||
.imageView = cyl_1_normal_texture_view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
};
|
||||
VkDescriptorImageInfo image_info_for_descriptor_0_in_set_1 = {
|
||||
.sampler = my_texture_sampler,
|
||||
.sampler = nearest_sampler,
|
||||
.imageView = IT1_view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
};
|
||||
@ -855,6 +886,15 @@ int main() {
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &image_info_for_descriptor_1_in_set_0,
|
||||
},
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = descriptor_set_for_pipeline_0,
|
||||
.dstBinding = 2,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &image_info_for_descriptor_2_in_set_0,
|
||||
},
|
||||
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
@ -887,7 +927,6 @@ int main() {
|
||||
break;
|
||||
for (size_t i = 0; i < events.len; i++) {
|
||||
Xlib_Event* ev = VecXlib_Event_at(&events, i);
|
||||
// printf("%lu %lu\n", ev->xany.window, wep.win);
|
||||
if (ev->xany.window != wep.win)
|
||||
continue;
|
||||
Margaret_WEP_update_with_new_event(&wep, ev);
|
||||
@ -1086,16 +1125,20 @@ int main() {
|
||||
ModelTopology_drop(cylinder_2);
|
||||
// destroying vulkan objects
|
||||
vkDestroyDescriptorPool(device, descriptor_pool, NULL);
|
||||
vkDestroySampler(device, my_texture_sampler, NULL);
|
||||
vkDestroyImageView(device, wood_texture_view, NULL);
|
||||
vkDestroySampler(device, linear_sampler, NULL);
|
||||
vkDestroySampler(device, nearest_sampler, NULL);
|
||||
vkDestroyImageView(device, cyl_1_diffuse_texture_view, NULL);
|
||||
vkDestroyImageView(device, cyl_1_normal_texture_view, NULL);
|
||||
|
||||
vkDestroyBuffer(device, device_vbo_1_buffer.buffer, NULL);
|
||||
vkDestroyBuffer(device, device_ebo_1_buffer.buffer, NULL);
|
||||
vkDestroyBuffer(device, device_vbo_2_buffer.buffer, NULL);
|
||||
vkDestroyBuffer(device, device_ebo_2_buffer.buffer, NULL);
|
||||
vkDestroyBuffer(device, device_ubo_my_buffer.buffer, NULL);
|
||||
vkDestroyImage(device, device_wood_texture.image, NULL);
|
||||
vkDestroyImage(device, device_cyl_1_diffuse_texture.image, NULL);
|
||||
vkDestroyImage(device, device_cyl_1_normal_texture.image, NULL);
|
||||
vkDestroyImage(device, device_IT1_image.image, NULL);
|
||||
vkDestroyImage(device, device_zbuffer_image.image, NULL);
|
||||
vkDestroyBuffer(device, host_mem_buffer.buffer, NULL);
|
||||
|
||||
vkFreeMemory(device, device_mem, NULL);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "../../l1/system/fileio.h"
|
||||
#include <math.h>
|
||||
#include "../../../gen/pixel_masses.h"
|
||||
#include "../marie/rasterization.h"
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
@ -76,8 +77,8 @@ VecT_trivmove_struct_Definition(Pipeline0PointLight)
|
||||
VecT_trivmove_method_Definition(Pipeline0PointLight)
|
||||
VecT_primitive_zeroinit_method_Definition(Pipeline0PointLight)
|
||||
|
||||
const size_t pipeline_0_ubo_point_light_max_count = 20;
|
||||
const size_t pipeline_0_ubo_spotlight_max_count = 120;
|
||||
#define pipeline_0_ubo_point_light_max_count 20
|
||||
#define pipeline_0_ubo_spotlight_max_count 120
|
||||
|
||||
typedef struct {
|
||||
int spotlight_count;
|
||||
@ -165,20 +166,20 @@ void TextureDataR8_draw_vertical_inner_line_maxing(TextureDataR8* self,
|
||||
}
|
||||
|
||||
void TextureDataR8_draw_inner_line_maxing(TextureDataR8* self,
|
||||
float x1, float y1, float x2, float y2, float r_cut, float r_decay) {
|
||||
float dx = fabsf(x2 - x1);
|
||||
float dy = fabsf(y2 - y1);
|
||||
vec2 v1, vec2 v2, float r_cut, float r_decay) {
|
||||
float dx = fabsf(v2.x - v1.x);
|
||||
float dy = fabsf(v2.y - v1.y);
|
||||
if (dx > dy) {
|
||||
if (x1 < x2) {
|
||||
TextureDataR8_draw_horizontal_inner_line_maxing(self, x1, y1, x2, y2, r_cut, r_decay);
|
||||
if (v1.x < v2.x) {
|
||||
TextureDataR8_draw_horizontal_inner_line_maxing(self, v1.x, v1.y, v2.x, v2.y, r_cut, r_decay);
|
||||
} else {
|
||||
TextureDataR8_draw_horizontal_inner_line_maxing(self, x2, y2, x1, y1, r_cut, r_decay);
|
||||
TextureDataR8_draw_horizontal_inner_line_maxing(self, v2.x, v2.y, v1.x, v1.y, r_cut, r_decay);
|
||||
}
|
||||
} else {
|
||||
if (y1 < y2) {
|
||||
TextureDataR8_draw_vertical_inner_line_maxing(self, x1, y1, x2, y2, r_cut, r_decay);
|
||||
if (v1.y < v2.y) {
|
||||
TextureDataR8_draw_vertical_inner_line_maxing(self, v1.x, v1.y, v2.x, v2.y, r_cut, r_decay);
|
||||
} else {
|
||||
TextureDataR8_draw_vertical_inner_line_maxing(self, x2, y2, x1, y1, r_cut, r_decay);
|
||||
TextureDataR8_draw_vertical_inner_line_maxing(self, v2.x, v2.y, v1.x, v1.y, r_cut, r_decay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,35 +202,35 @@ void TextureDataR8_draw_one_segment_maxing(TextureDataR8* self,
|
||||
vec2 v1, vec2 v2, float r_cut, float r_decay) {
|
||||
TextureDataR8_draw_spot_maxing(self, v1, r_cut, r_decay);
|
||||
TextureDataR8_draw_spot_maxing(self, v2, r_cut, r_decay);
|
||||
TextureDataR8_draw_inner_line_maxing(self, v1.x, v1.y, v2.x, v2.y, r_cut, r_decay);
|
||||
TextureDataR8_draw_inner_line_maxing(self, v1, v2, r_cut, r_decay);
|
||||
}
|
||||
|
||||
TextureDataR8G8B8A8 generate_wood_texture() {
|
||||
const U32 width = 100;
|
||||
const U32 height = 100;
|
||||
TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width, height);
|
||||
for (U32 y = 0; y < width; y++) {
|
||||
for (U32 col = 0; col < height; col++) {
|
||||
*TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){150, 30, 50, 255};
|
||||
}
|
||||
}
|
||||
for (U32 i = 0; i < 10; i++) {
|
||||
for (U32 y = 0; y < height; y++) {
|
||||
U32 col = 3 + i * 10 + ((30 < y + 3 * i && y - i < 60) ? 1 : 0);
|
||||
|
||||
*TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){130, 25, 40, 255};
|
||||
*TextureDataR8G8B8A8_at(&res, col + 1, y) = (cvec4){80, 10, 15, 255};
|
||||
*TextureDataR8G8B8A8_at(&res, col + 2, y) = (cvec4){70, 11, 12, 255};
|
||||
*TextureDataR8G8B8A8_at(&res, col + 3, y) = (cvec4){125, 20, 20, 255};
|
||||
}
|
||||
}
|
||||
for (U32 y = 0; y < 10; y++) {
|
||||
for (U32 col = 0; col < 10; col++) {
|
||||
*TextureDataR8G8B8A8_at(&res, col + 4, y + 13) = (cvec4){60, 8, 6, 255};
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
// TextureDataR8G8B8A8 generate_wood_texture() {
|
||||
// const U32 width = 100;
|
||||
// const U32 height = 100;
|
||||
// TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width, height);
|
||||
// for (U32 y = 0; y < width; y++) {
|
||||
// for (U32 col = 0; col < height; col++) {
|
||||
// *TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){150, 30, 50, 255};
|
||||
// }
|
||||
// }
|
||||
// for (U32 i = 0; i < 10; i++) {
|
||||
// for (U32 y = 0; y < height; y++) {
|
||||
// U32 col = 3 + i * 10 + ((30 < y + 3 * i && y - i < 60) ? 1 : 0);
|
||||
//
|
||||
// *TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){130, 25, 40, 255};
|
||||
// *TextureDataR8G8B8A8_at(&res, col + 1, y) = (cvec4){80, 10, 15, 255};
|
||||
// *TextureDataR8G8B8A8_at(&res, col + 2, y) = (cvec4){70, 11, 12, 255};
|
||||
// *TextureDataR8G8B8A8_at(&res, col + 3, y) = (cvec4){125, 20, 20, 255};
|
||||
// }
|
||||
// }
|
||||
// for (U32 y = 0; y < 10; y++) {
|
||||
// for (U32 col = 0; col < 10; col++) {
|
||||
// *TextureDataR8G8B8A8_at(&res, col + 4, y + 13) = (cvec4){60, 8, 6, 255};
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
@ -244,49 +245,73 @@ ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) {
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {w, 0, 0}, .tex = v1tex});
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {0, r, 0}, .tex = v2tex});
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {w, r, 0}, .tex = v3tex});
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {0, 0, r}, .tex = {r / (2 * r + w), 0}});
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {w, 0, r}, .tex = {(r + w) / (2 * r + w), 0}});
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {0, 0, -r}, .tex = {r / (2 * r + w), 0}});
|
||||
VecVertex_append(&vertices, (Vertex){.pos = {w, 0, -r}, .tex = {(r + w) / (2 * r + w), 0}});
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecVertex_append(&vertices, (Vertex){
|
||||
.pos = {0, cosf(a * i) * r, sinf(a * i) * r},
|
||||
.pos = {0, cosf(a * i) * r, -sinf(a * i) * r},
|
||||
.tex = vec2_add_vec2(v0tex, (vec2){r / (2 * r + w) * -sinf(a * i), r / (2 * r + k * l) * cos(a * i)})
|
||||
});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecVertex_append(&vertices, (Vertex){
|
||||
.pos = {w, cosf(a * i) * r, sinf(a * i) * r},
|
||||
.pos = {w, cosf(a * i) * r, -sinf(a * i) * r},
|
||||
.tex = vec2_add_vec2(v1tex, (vec2){r / (2 * r + w) * sinf(a * i), r / (2*r + k * l) * cos(a * i)})
|
||||
});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecVertex_append(&vertices, (Vertex){
|
||||
.pos = {0, cosf(a * i) * r, sinf(a * i) * r},
|
||||
.pos = {0, cosf(a * i) * r, -sinf(a * i) * r},
|
||||
.tex = {v2tex.x, v2tex.y + i * l / (2*r + k * l)}
|
||||
});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecVertex_append(&vertices, (Vertex){
|
||||
.pos = {w, cosf(a * i) * r, sinf(a * i) * r},
|
||||
.pos = {w, cosf(a * i) * r, -sinf(a * i) * r},
|
||||
.tex = {v3tex.x, v3tex.y + i * l / (2*r + k * l)}
|
||||
});
|
||||
}
|
||||
VecU32 indexes = VecU32_new(); // todo: reserve 3 * (2+2+2*k+2*k)<
|
||||
{
|
||||
U32 _span_0[] = { 5, 0, 1, 5, 4, 0, 1, 0, 3, 3, 0, 2 };
|
||||
U32 _span_0[] = {5, 1, 0, 5, 0, 4, 1, 3, 0, 3, 2, 0};
|
||||
VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
U32 _span_1[] = {
|
||||
0, 5 + i, i > 1 ? 5 + i - 1 : 2,
|
||||
1, i > 1 ? 5 + k + i - 1 : 3, 5 + k + i,
|
||||
i > 1 ? 5 + 2 * k + i - 1 : 2, 5 + 2 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3,
|
||||
5 + 3 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3, 5 + 2 * k + i
|
||||
0, i > 1 ? 5 + i - 1 : 2, 5 + i,
|
||||
1, 5 + k + i, i > 1 ? 5 + k + i - 1 : 3,
|
||||
i > 1 ? 5 + 2 * k + i - 1 : 2, i > 1 ? 5 + 3 * k + i - 1 : 3, 5 + 2 * k + i,
|
||||
5 + 3 * k + i, 5 + 2 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3,
|
||||
};
|
||||
VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)});
|
||||
}
|
||||
return (ModelTopology){.vertices = vertices, .indexes = indexes};
|
||||
}
|
||||
|
||||
#define vec2_drop(x) {}
|
||||
#define vec2_clone(x) (*(x))
|
||||
|
||||
VecT_trivmove_struct_Definition(vec2)
|
||||
VecT_trivmove_method_Definition(vec2)
|
||||
VecT_primitive_zeroinit_method_Definition(vec2)
|
||||
SpanT_struct_Definition(vec2)
|
||||
SpanT_method_Definition(vec2)
|
||||
SpanT_VecT_method_Definition(vec2)
|
||||
|
||||
void TextureDataR8_draw_perimeter_maxing(TextureDataR8* self, ConstSpanvec2 P) {
|
||||
float r_cut = 2;
|
||||
float r_decay = 1;
|
||||
size_t S = P.len;
|
||||
for (size_t i = 0; i < S; i++) {
|
||||
TextureDataR8_draw_spot_maxing(self, *ConstSpanvec2_at(P, i), r_cut, r_decay);
|
||||
}
|
||||
for (size_t i = 1; i < S; i++) {
|
||||
TextureDataR8_draw_inner_line_maxing(self, *ConstSpanvec2_at(P, i - 1), *ConstSpanvec2_at(P, i), r_cut, r_decay);
|
||||
}
|
||||
if (S > 2)
|
||||
TextureDataR8_draw_inner_line_maxing(self, *ConstSpanvec2_at(P, S - 1), *ConstSpanvec2_at(P, 0), r_cut, r_decay);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
vec2 bl;
|
||||
vec2 tr;
|
||||
@ -303,7 +328,7 @@ VecT_primitive_zeroinit_method_Definition(Wimbzle)
|
||||
|
||||
typedef struct {
|
||||
vec2 center;
|
||||
vec2 rad;
|
||||
float rad;
|
||||
float hc;
|
||||
} Nibzle;
|
||||
|
||||
@ -315,22 +340,22 @@ VecT_trivmove_method_Definition(Nibzle)
|
||||
VecT_primitive_zeroinit_method_Definition(Nibzle)
|
||||
|
||||
typedef struct {
|
||||
VecWimbzle wibmzles;
|
||||
VecWimbzle wimbzles;
|
||||
VecNibzle nibzles;
|
||||
} Bublazhuzhka;
|
||||
|
||||
Bublazhuzhka Bublazhuzhka_new() {
|
||||
return (Bublazhuzhka){.wibmzles = VecWimbzle_new(), .nibzles = VecNibzle_new()};
|
||||
return (Bublazhuzhka){.wimbzles = VecWimbzle_new(), .nibzles = VecNibzle_new()};
|
||||
}
|
||||
|
||||
void Bublazhuzhka_drop(Bublazhuzhka self) {
|
||||
VecWimbzle_drop(self.wibmzles);
|
||||
VecWimbzle_drop(self.wimbzles);
|
||||
VecNibzle_drop(self.nibzles);
|
||||
}
|
||||
|
||||
void Bublazhuzhka_TextureDataR8_draw_maxing(const Bublazhuzhka* self, TextureDataR8* canvas, vec2) {
|
||||
for (size_t i = 0; i < self->wibmzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_cat(&self->wibmzles, i);
|
||||
void Bublazhuzhka_TextureDataR8_draw_maxing(const Bublazhuzhka* self, TextureDataR8* canvas, mat3x2 trop) {
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_cat(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
@ -340,16 +365,199 @@ void Bublazhuzhka_TextureDataR8_draw_maxing(const Bublazhuzhka* self, TextureDat
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
|
||||
TextureDataR8_draw_one_segment_maxing(canvas, A, B, 1.5, 1);
|
||||
vec2 p1[4] = {mat3x2_mul_vec3(trop, vec2_and_one(A)), mat3x2_mul_vec3(trop, vec2_and_one(B)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(D)), mat3x2_mul_vec3(trop, vec2_and_one(C))};
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, (ConstSpanvec2){.data = p1, ARRAY_SIZE(p1)});
|
||||
vec2 p2[4] = {mat3x2_mul_vec3(trop, vec2_and_one(E)), mat3x2_mul_vec3(trop, vec2_and_one(F)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(H)), mat3x2_mul_vec3(trop, vec2_and_one(G))};
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, (ConstSpanvec2){.data = p2, ARRAY_SIZE(p2)});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_cat(&self->nibzles, i);
|
||||
Vecvec2 p = Vecvec2_new_zeroinit(13);
|
||||
for (int j = 0; j < 13; j++) {
|
||||
float a = (float)j * 2 * M_PI / 13;
|
||||
*Vecvec2_at(&p, j) = vec2_add_vec2(sphere.center, vec2_mul_scal(marie_trigonom_circle(a), sphere.rad));
|
||||
}
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, Vecvec2_to_ConstSpanvec2(&p));
|
||||
Vecvec2_drop(p);
|
||||
TextureDataR8_draw_spot_maxing(canvas, mat3x2_mul_vec3(trop, vec2_and_one(sphere.center)), 3, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#define vec2_drop(x) {}
|
||||
#define vec2_clone(x) (*(x))
|
||||
Bublazhuzhka fill_rectangle_with_crap(float w, float h) {
|
||||
// Bublazhuzhka res = Bublazhuzhka_new();
|
||||
S32 k = MAX_S32(0, (S32)floorf((w/h + 0.1f) / 0.7f));
|
||||
VecWimbzle wimbzles = VecWimbzle_new_zeroinit(k);
|
||||
VecNibzle nibzles = VecNibzle_new_zeroinit(2 * k);
|
||||
float start = k != 1 ? h * 0.2f : ((w - 0.2f * h) / 2);
|
||||
float d = k > 1 ? ((w - h * 0.4f - h * 0.2f * k) / (float)(k - 1)) : 0;
|
||||
for (S32 i = 0; i < k; i++) {
|
||||
float x = start + (d + h * 0.2) * i;
|
||||
*VecWimbzle_at(&wimbzles, i) = (Wimbzle){.bl = {x + 0.02 * h, 0.27 * h}, .tr = {x + 0.18 * h, h * 0.73}, .height = h * 0.03, .brd = h * 0.03};
|
||||
/* hc is a height coefficient*/
|
||||
*VecNibzle_at(&nibzles, 2 * i) = (Nibzle){.center = {x + 0.10 * h, 0.11 * h}, .rad = h * 0.05, .hc = 0.75};
|
||||
*VecNibzle_at(&nibzles, 2 * i + 1) = (Nibzle){.center = {x + 0.10 * h, 0.89 * h}, .rad = h * 0.05, .hc = 0.75};
|
||||
}
|
||||
return (Bublazhuzhka){.wimbzles = wimbzles, .nibzles = nibzles};
|
||||
}
|
||||
|
||||
vec2 Bublazhuzhka_get_derivative(const Bublazhuzhka* self, vec2 v) {
|
||||
vec2 sum = { 0 };
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_cat(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
vec2 D = {B.x, C.y};
|
||||
vec2 F = rect.tr;
|
||||
vec2 G = rect.bl;
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
float slp = rect.height / rect.brd;
|
||||
if (A.x < v.x && v.x < E.x && marie_surface(E, A, v) > 0 && marie_surface(C, G, v) > 0) {
|
||||
sum.x += slp;
|
||||
} else if (F.x < v.x && v.x < B.x && marie_surface(B, F, v) > 0 && marie_surface(H, D, v) > 0) {
|
||||
sum.x -= slp;
|
||||
} else if (C.y < v.y && v.y < G.y && marie_surface(G, C, v) > 0 && marie_surface(D, H, v) > 0) {
|
||||
sum.y += slp;
|
||||
} else if (F.y < v.y && v.y < B.y && marie_surface(A, E, v) > 0 && marie_surface(F, B, v) > 0) {
|
||||
sum.y -= slp;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_cat(&self->nibzles, i);
|
||||
float sq_h = pow2f(sphere.rad) - pow2f(v.x - sphere.center.x) - pow2f(v.y - sphere.center.y);
|
||||
if (sq_h <= 0)
|
||||
continue;
|
||||
float w = sphere.hc / sqrtf(sq_h);
|
||||
sum = vec2_add_vec2(sum, vec2_mul_scal(vec2_minus_vec2(sphere.center, v), w));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
cvec3 compress_normal_vec_into_norm_texel(vec3 n) {
|
||||
return (cvec3){(U32)roundf(255 * (n.x + 1) / 2), (U32)roundf(255 * (n.y + 1) / 2), (U32)roundf(255 * (n.z + 1) / 2)};
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> normal vector in model space */
|
||||
vec3 (*fn)(void*, vec2);
|
||||
void* guest;
|
||||
} FnNormalVectorGenCallback;
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8* tex;
|
||||
FnNormalVectorGenCallback my_client;
|
||||
} draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest* g = ug;
|
||||
vec3 normal = g->my_client.fn(g->my_client.guest, (vec2){attr.x, attr.y});
|
||||
*TextureDataR8G8B8_at(g->tex, x, y) = compress_normal_vec_into_norm_texel(normal);
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_smooth_param_surf(
|
||||
TextureDataR8G8B8* tex, vec2 pa, vec2 pb, vec2 pc, mat3x2 trop, FnNormalVectorGenCallback cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest aboba = {.tex = tex, .my_client = cb};
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pa)), .attr = {pa.x, pa.y, 0, 0} },
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pb)), .attr = {pb.x, pb.y, 0, 0} },
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pc)), .attr = {pc.x, pc.y, 0, 0} },
|
||||
(FnMarieRasterizerCallback){draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb, (void*)&aboba});
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> normal vector in model space */
|
||||
vec3 (*fn)(void*, vec3);
|
||||
void* guest;
|
||||
} FnNormalVectorGenExaggParamCallback;
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8* tex;
|
||||
FnNormalVectorGenExaggParamCallback my_client;
|
||||
} draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest* g = ug;
|
||||
vec3 normal = g->my_client.fn(g->my_client.guest, (vec3){attr.x, attr.y, attr.z});
|
||||
*TextureDataR8G8B8_at(g->tex, x, y) = compress_normal_vec_into_norm_texel(normal);
|
||||
}
|
||||
|
||||
/* We can't derive texture coordinates from parameter space coordinates, you have to do it yourself */
|
||||
void draw_polygon_on_normal_texture_nat_cords_exaggerated_param_surf(
|
||||
TextureDataR8G8B8* tex, vec2 ta, vec2 tb, vec2 tc, vec3 pa, vec3 pb, vec3 pc, FnNormalVectorGenExaggParamCallback cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest aboba = {.tex = tex, .my_client = cb};
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = ta, .attr = {pa.x, pa.y, pa.z, 0} },
|
||||
(MariePlaneVertAttr){.pos = tb, .attr = {pb.x, pb.y, pb.z, 0} },
|
||||
(MariePlaneVertAttr){.pos = tc, .attr = {pc.x, pc.y, pc.z, 0} },
|
||||
(FnMarieRasterizerCallback){draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb, (void*)&aboba});
|
||||
}
|
||||
// todo: add a version for that function with non-native coordinate system (on vertex) (like I did with absolutely flat surface)
|
||||
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8* tex;
|
||||
cvec3 normal_compr;
|
||||
} draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb(void* ug, S32 x, S32 y, vec4) {
|
||||
draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest* g = ug;
|
||||
*TextureDataR8G8B8_at(g->tex, x, y) = g->normal_compr;
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_nat_cords_absolutely_flat(TextureDataR8G8B8* tex,
|
||||
vec2 ta, vec2 tb, vec2 tc, vec3 c_normal
|
||||
) {
|
||||
draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest aboba = {tex, compress_normal_vec_into_norm_texel(c_normal)};
|
||||
marie_rasterize_triangle_with_attr((MariePlaneVertAttr){.pos = ta}, (MariePlaneVertAttr){.pos = tb},
|
||||
(MariePlaneVertAttr){.pos = tc}, (FnMarieRasterizerCallback){
|
||||
.fn = draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb, .guest = (void*)&aboba});
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_absolutely_flat(TextureDataR8G8B8* tex,
|
||||
vec2 pa, vec2 pb, vec2 pc, mat3x2 trop, vec3 c_normal
|
||||
) {
|
||||
draw_polygon_on_normal_texture_nat_cords_absolutely_flat(tex, mat3x2_mul_vec3(trop, vec2_and_one(pa)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(pb)), mat3x2_mul_vec3(trop, vec2_and_one(pc)), c_normal);
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> height gradient */
|
||||
vec2 (*fn)(void*, vec2);
|
||||
void* guest;
|
||||
} FnHeightMapGradFlatSurfCallback;
|
||||
|
||||
typedef struct {
|
||||
mat3 surf_orient;
|
||||
FnHeightMapGradFlatSurfCallback my_client;
|
||||
} draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest;
|
||||
|
||||
vec3 draw_polygon_on_normal_texture_flat_param_surf_h_draw_cb(void* ug, vec2 p) {
|
||||
draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest* g = ug;
|
||||
vec2 grad = g->my_client.fn(g->my_client.guest, p);
|
||||
return mat3_mul_vec3(g->surf_orient, marie_normal_from_tang_space_gradient(grad.x, grad.y));
|
||||
}
|
||||
|
||||
/* The simplest case of normal texture generation: for a smooth flat surface of a polygon */
|
||||
void draw_polygon_on_normal_texture_flat_param_surf(TextureDataR8G8B8* tex, vec2 pa, vec2 pb, vec2 pc, mat3x2 trop,
|
||||
mat3 surf_orient, FnHeightMapGradFlatSurfCallback height_map_cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest aboba = {surf_orient, height_map_cb};
|
||||
draw_polygon_on_normal_texture_smooth_param_surf(tex, pa, pb, pc, trop, (FnNormalVectorGenCallback){
|
||||
.fn = draw_polygon_on_normal_texture_flat_param_surf_h_draw_cb, .guest = (void*)&aboba});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
VecT_trivmove_struct_Definition(vec2)
|
||||
VecT_trivmove_method_Definition(vec2)
|
||||
VecT_primitive_zeroinit_method_Definition(vec2)
|
||||
|
||||
TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
@ -382,22 +590,24 @@ TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol,
|
||||
for (size_t i = 1; i <= k; i++) {
|
||||
Vecvec2_append(&P, (vec2){r - r * sinf(a * i), r + r * cos(a * i)});
|
||||
}
|
||||
size_t S = 6 + 4 * k;
|
||||
assert(P.len == S);
|
||||
float r_cut = 2;
|
||||
float r_decay = 1;
|
||||
for (size_t i = 0; i < S; i++) {
|
||||
vec2 p = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol);
|
||||
TextureDataR8_draw_spot_maxing(&res, p, r_cut, r_decay);
|
||||
}
|
||||
for (size_t i = 0; i < S; i++) {
|
||||
vec2 pp = vec2_mul_vec2(*Vecvec2_at(&P, i ? i - 1 : S - 1), cord_resol);
|
||||
vec2 p = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol);
|
||||
TextureDataR8_draw_inner_line_maxing(&res, pp.x, pp.y, p.x, p.y, r_cut, r_decay);
|
||||
for (size_t i = 0; i < P.len; i++) {
|
||||
*Vecvec2_at(&P, i) = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol);
|
||||
}
|
||||
TextureDataR8_draw_perimeter_maxing(&res, Vecvec2_to_ConstSpanvec2(&P));
|
||||
|
||||
Bublazhuzhka crap_on_back_side = fill_rectangle_with_crap(w, r);
|
||||
Bublazhuzhka_TextureDataR8_draw_maxing(&crap_on_back_side, &res,
|
||||
(mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)});
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Use it as a callback in normal map drawing functions that work with smooth (smooth / flat / cylindrical)
|
||||
* height maps. Guest pointer is of type Bublazhuzhka* */
|
||||
vec2 height_map_cb_that_uses_bublazhuzhka(void* ug, vec2 v) {
|
||||
Bublazhuzhka* bzh = ug;
|
||||
return Bublazhuzhka_get_derivative(bzh, v);
|
||||
}
|
||||
|
||||
TextureDataR8G8B8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
@ -409,35 +619,40 @@ TextureDataR8G8B8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol
|
||||
const vec2 v1tex = {r + w, r};
|
||||
const vec2 v2tex = {r, 2 * r};
|
||||
const vec2 v3tex = {r + w, 2 * r};
|
||||
const vec2 v4tex = {r, 0};
|
||||
const vec2 v5tex = {r + w, 0};
|
||||
TextureDataR8G8B8 res = TextureDataR8G8B8_new(width_pix, height_pix);
|
||||
// Vecvec2 P = Vecvec2_new(); // todo: reserve 6 + k * 4
|
||||
// for (size_t i = k; i > 0; i--) {
|
||||
// Vecvec2_append(&P, (vec2){r + w + r * sinf(a * i), r + r * cos(a * i)});
|
||||
// }
|
||||
// Vecvec2_append(&P, v3tex);
|
||||
// for (size_t i = 1; i <= k; i++) {
|
||||
// Vecvec2_append(&P, (vec2){r + w, 2 * r + i * l});
|
||||
// }
|
||||
// for (size_t i = k; i > 0; i--) {
|
||||
// Vecvec2_append(&P, (vec2){r, 2 * r + i * l});
|
||||
// }
|
||||
// Vecvec2_append(&P, v2tex);
|
||||
// for (size_t i = 1; i <= k; i++) {
|
||||
// Vecvec2_append(&P, (vec2){r - r * sinf(a * i), r + r * cos(a * i)});
|
||||
// }
|
||||
// size_t S = 6 + 4 * k;
|
||||
// assert(P.len == S);
|
||||
// float r_cut = 2;
|
||||
// float r_decay = 1;
|
||||
// for (size_t i = 0; i < S; i++) {
|
||||
// vec2 p = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol);
|
||||
// TextureDataR8_draw_spot_maxing(&res, p.x, p.y, r_cut, r_decay);
|
||||
// }
|
||||
// for (size_t i = 0; i < S; i++) {
|
||||
// vec2 pp = vec2_mul_vec2(*Vecvec2_at(&P, i ? i - 1 : S - 1), cord_resol);
|
||||
// vec2 p = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol);
|
||||
// TextureDataR8_draw_inner_line_maxing(&res, pp.x, pp.y, p.x, p.y, r_cut, r_decay);
|
||||
// }
|
||||
|
||||
Bublazhuzhka crap_on_the_back_side = fill_rectangle_with_crap(w, r);
|
||||
mat3x2 trop_back_side = {.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)};
|
||||
mat3 orient_back_side = {.x = {1, 0, 0}, .y = {0, 0, 1}, {0, 1, 0}};
|
||||
draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){w, 0}, (vec2){w, r}, trop_back_side, orient_back_side,
|
||||
(FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side});
|
||||
draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){0, r}, (vec2){w, r}, trop_back_side, orient_back_side,
|
||||
(FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side});
|
||||
|
||||
mat3x2 str = {.x.x = cord_resol.x, .y.y = cord_resol.y};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, v0tex, v1tex, v4tex, str, (vec3){0, -1, 0});
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, v1tex, v4tex, v5tex, str, (vec3){0, -1, 0});
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r - sinf(i * a) * r, r + cosf(i * a) * r};
|
||||
vec2 B = {r - sinf((i + 1) * a) * r, r + cosf((i + 1) * a) * r};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r, r}, str, (vec3){-1, 0, 0});
|
||||
}
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r + w + sinf(i * a) * r, r + cos(i * a) * r};
|
||||
vec2 B = {r + w + sinf((i + 1) * a) * r, r + cos((i + 1) * a) * r};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r + w, r}, str, (vec3){1, 0, 0});
|
||||
}
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r, 2 * r + i * l};
|
||||
vec2 B = {r + w, 2 * r + i * l};
|
||||
vec2 C = {r, 2 * r + i * l + l};
|
||||
vec2 D = {r + w, 2 * r + i * l + l};
|
||||
vec3 n = {0, cos(a / 2 + a * i), -sin(a / 2 + a * i)};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, C, str, n);
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, D, B, C, str, n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -16,19 +16,29 @@ void draw_cool_triangle(TextureDataR8G8B8* tex, vec2 A, vec2 B, vec2 C) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
// TextureDataR8 tex_1 = generate_tex_template_for_one_fourth_of_a_cylinder(20, 10, 2, 6);
|
||||
// TextureDataR8_write_to_file(&tex_1, "log_10_2_6_TEMPLATE.r8");
|
||||
// TextureDataR8_drop(tex_1);
|
||||
TextureDataR8G8B8 t = TextureDataR8G8B8_new(1000, 1000);\
|
||||
vec2 center = {500, 500};
|
||||
for (int i = 0; i < 70; i++) {
|
||||
float a1 = (float)i * 2 * M_PIf / 70;
|
||||
float a2 = (float)(i + 1) * 2 * M_PIf / 70;
|
||||
vec2 A = vec2_add_vec2(center, vec2_mul_scal((vec2){cosf(a1), sinf(a1)}, 480));
|
||||
vec2 B = vec2_add_vec2(center, vec2_mul_scal((vec2){cosf(a2), sinf(a2)}, 480));
|
||||
draw_cool_triangle(&t, B, A, center);
|
||||
TextureDataR8 tex_1 = generate_tex_template_for_one_fourth_of_a_cylinder(120, 10, 2, 6);
|
||||
TextureDataR8_write_to_file(&tex_1, "log_10_2_6_TEMPLATE.a8");
|
||||
TextureDataR8_drop(tex_1);
|
||||
TextureDataR8G8B8 tex_2 = generate_normal_tex_for_one_fourth_of_a_cylinder(120, 10, 2, 6);
|
||||
TextureDataR8G8B8A8 tex_2_big = TextureDataR8G8B8A8_new(tex_2.width, TextureDataR8G8B8_get_height(&tex_2));
|
||||
for (size_t i = 0; i < tex_2.pixels.len; i++) {
|
||||
cvec3 rgb = *Veccvec3_at(&tex_2.pixels, i);
|
||||
*Veccvec4_at(&tex_2_big.pixels, i) = (cvec4){rgb.x, rgb.y, rgb.z, 255};
|
||||
}
|
||||
TextureDataR8G8B8_write_to_file(&t, "experiment.r8g8b8");
|
||||
TextureDataR8G8B8_drop(t);
|
||||
TextureDataR8G8B8A8_write_to_file(&tex_2_big, "log_10_2_6_NORMAL.r8g8b8a8");
|
||||
TextureDataR8G8B8A8_drop(tex_2_big);
|
||||
TextureDataR8G8B8_drop(tex_2);
|
||||
|
||||
// TextureDataR8G8B8 t = TextureDataR8G8B8_new(1000, 1000);\
|
||||
// vec2 center = {500, 500};
|
||||
// for (int i = 0; i < 70; i++) {
|
||||
// float a1 = (float)i * 2 * M_PIf / 70;
|
||||
// float a2 = (float)(i + 1) * 2 * M_PIf / 70;
|
||||
// vec2 A = vec2_add_vec2(center, vec2_mul_scal((vec2){cosf(a1), sinf(a1)}, 480));
|
||||
// vec2 B = vec2_add_vec2(center, vec2_mul_scal((vec2){cosf(a2), sinf(a2)}, 480));
|
||||
// draw_cool_triangle(&t, B, A, center);
|
||||
// }
|
||||
// TextureDataR8G8B8_write_to_file(&t, "experiment.r8g8b8");
|
||||
// TextureDataR8G8B8_drop(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ layout(location = 0) out vec4 fin_color;
|
||||
|
||||
layout(binding = 1) uniform sampler2D color_tex;
|
||||
|
||||
layout(binding = 2) uniform sampler2D normal_map;
|
||||
|
||||
struct Pipeline0Spotlight
|
||||
{
|
||||
@ -31,5 +32,5 @@ layout(std140, binding = 0) uniform Pipeline0UBO
|
||||
};
|
||||
|
||||
void main(){
|
||||
fin_color = texture(color_tex, fsin_tex);
|
||||
fin_color = texture(normal_map, fsin_tex);
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
raw_png_conv.py
|
||||
===============
|
||||
|
||||
Convert between custom bottom‑up raw files (.r8g8b8a8 / .r8b8g8 / .r8)
|
||||
"""
|
||||
Convert between custom bottom‑up raw files (.r8g8b8a8 / .r8b8g8 / .r8 / .a8)
|
||||
and normal PNG using Pillow.
|
||||
|
||||
Format
|
||||
@ -14,6 +12,7 @@ pixel data rows bottom‑first:
|
||||
* .r8g8b8a8 : R G B A (4× uint8)
|
||||
* .r8b8g8 : R G B (3× uint8)
|
||||
* .r8 : R (1× uint8 <- grayscale)
|
||||
* .a8 : A (can convert from it, but can't convert to it)
|
||||
|
||||
CLI
|
||||
---
|
||||
@ -29,10 +28,12 @@ from PIL import Image
|
||||
# Helpers
|
||||
# --------------------------------------------------------------------- #
|
||||
|
||||
|
||||
RAW_FORMATS = {
|
||||
".r8g8b8a8": {"pix_size": 4, "mode": "RGBA"},
|
||||
".r8g8b8": {"pix_size": 3, "mode": "RGB"},
|
||||
".r8": {"pix_size": 1, "mode": "L"},
|
||||
".a8": {"pix_size": 1, "mode": None}, # special-cased (alpha-only)
|
||||
}
|
||||
|
||||
|
||||
@ -43,37 +44,52 @@ def get_fmt(path: Path):
|
||||
return fmt
|
||||
|
||||
|
||||
def read_raw(path: Path) -> Image.Image:
|
||||
"""Load any supported raw file -> Pillow Image."""
|
||||
spec = get_fmt(path)
|
||||
def read_header_and_data(path: Path, pix_size: int):
|
||||
with path.open("rb") as f:
|
||||
header = f.read(8)
|
||||
if len(header) != 8:
|
||||
raise ValueError("File too short for header")
|
||||
w, h = struct.unpack("<II", header)
|
||||
expected = w * h * spec["pix_size"]
|
||||
expected = w * h * pix_size
|
||||
data = f.read()
|
||||
if len(data) != expected:
|
||||
raise ValueError(
|
||||
f"Pixel data length mismatch: expected {expected}, got {len(data)}"
|
||||
)
|
||||
return w, h, data
|
||||
|
||||
|
||||
def read_raw(path: Path) -> Image.Image:
|
||||
"""Load any supported raw file -> Pillow Image."""
|
||||
spec = get_fmt(path)
|
||||
w, h, data = read_header_and_data(path, spec["pix_size"])
|
||||
|
||||
row_len = w * spec["pix_size"]
|
||||
rows = [data[i : i + row_len] for i in range(0, expected, row_len)]
|
||||
img_bytes = b"".join(reversed(rows)) # flip bottom‑up -> top‑down
|
||||
return Image.frombytes(spec["mode"], (w, h), img_bytes)
|
||||
rows = [data[i : i + row_len] for i in range(0, len(data), row_len)]
|
||||
top_down = b"".join(reversed(rows)) # flip bottom‑up -> top‑down
|
||||
|
||||
# Special handling for .a8 (alpha-only -> LA with black color)
|
||||
if path.suffix.lower() == ".a8":
|
||||
big = bytearray(4 * len(top_down))
|
||||
big[3::4] = top_down
|
||||
big = bytes(big)
|
||||
return Image.frombytes("RGBA", (w, h), big)
|
||||
|
||||
# Normal cases can be constructed directly
|
||||
return Image.frombytes(spec["mode"], (w, h), top_down)
|
||||
|
||||
|
||||
def write_raw(img: Image.Image, path: Path) -> None:
|
||||
"""Write Pillow Image -> raw file chosen by path suffix."""
|
||||
ext = path.suffix.lower()
|
||||
spec = get_fmt(path)
|
||||
# Convert to required mode
|
||||
if img.mode != spec["mode"]:
|
||||
if spec["mode"] == "L":
|
||||
img = img.convert("L")
|
||||
elif spec["mode"] == "RGB":
|
||||
img = img.convert("RGB")
|
||||
else: # RGBA
|
||||
img = img.convert("RGBA")
|
||||
|
||||
if ext == ".a8":
|
||||
raise ValueError("Don't convert to .a8 format")
|
||||
|
||||
target_mode = spec["mode"]
|
||||
if img.mode != target_mode:
|
||||
img = img.convert(target_mode)
|
||||
|
||||
w, h = img.size
|
||||
data = img.tobytes()
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
Loading…
x
Reference in New Issue
Block a user