Generating a f***ed up normal texture

This commit is contained in:
Андреев Григорий 2025-07-30 14:43:38 +03:00
parent b526157870
commit af94aeeef7
12 changed files with 512 additions and 190 deletions

5
.gitignore vendored
View File

@ -5,6 +5,9 @@ vgcore.*
/gen/
*.pdf
*.r8g8b8a8
*.r8b8g8
*.r8g8b8
*.r8
*.a8
*.xcf
*_NORMAL.png
*_TEMPLATE.png

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,7 @@
#!/usr/bin/env python3
"""
raw_png_conv.py
===============
Convert between custom bottomup raw files (.r8g8b8a8 / .r8b8g8 / .r8)
"""
Convert between custom bottomup raw files (.r8g8b8a8 / .r8b8g8 / .r8 / .a8)
and normal PNG using Pillow.
Format
@ -14,6 +12,7 @@ pixel data rows bottomfirst:
* .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 bottomup -> topdown
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 bottomup -> topdown
# 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