Я маленький котёночек

This commit is contained in:
Андреев Григорий 2025-08-05 15:04:43 +03:00
parent f5fff09144
commit fb10c204ad
15 changed files with 393 additions and 66 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.30)
project(splitter_draft C)
project(prototype1 C)
#include_directories(${CMAKE_SOURCE_DIR})
set(CMAKE_C_FLAGS "-Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type --std=c99 -g -ggdb -O0")

View File

@ -86,6 +86,9 @@ void VecT##_drop(VecT obj) { \
T ## _drop(obj.buf[i]); \
free(obj.buf); \
} \
VecT VecT##_new_reserved(size_t n) {\
return (VecT){ .buf = safe_calloc(n, sizeof(T)), .len = 0, .capacity = n };\
} \
NODISCARD VecT VecT##_new_filled(size_t len, const T* el) { \
VecT res = (VecT){.buf = safe_calloc(len, sizeof(T)), .len = len, .capacity = len}; \
for (size_t i = 0; i < len; i++) \

17
src/l1/system/fsmanip.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef PROTOTYPE1_SRC_L1_SYSTEM_FSMANIP_H
#define PROTOTYPE1_SRC_L1_SYSTEM_FSMANIP_H
/* For posix */
#include "sys/stat.h"
#include <errno.h>
#include "../core/util.h"
/* Aborts on error */
void make_dir_nofail(const char* filename) {
int ret = mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP);
if (ret < 0 && errno != EEXIST)
abortf("Unable to create directory %s\n", filename);
}
#endif

View File

@ -1,8 +1,13 @@
#include "codegen/geom.h"
#include "codegen/pixel_masses.h"
#include "codegen/clipping.h"
#include "../l1/system/fsmanip.h"
int main() {
make_dir_nofail("l2");
generate_geom_header();
generate_pixel_masses_header();
make_dir_nofail("l2/marie");
generate_clipping_header();
return 0;
}

179
src/l2/codegen/clipping.h Normal file
View File

@ -0,0 +1,179 @@
#ifndef PROTOTYPE1_SRC_L2_CODEGEN_CLIPPING_H
#define PROTOTYPE1_SRC_L2_CODEGEN_CLIPPING_H
#include "../../l1/codegen/codegen.h"
// todo: move all of this to marie namespace
typedef struct {
int order;
bool negate;
} PossiblyNegatedTriangle;
int comparison_triang_groups[18][3] = {
{10, 11, 20}, {10, 11, 21}, {10, 11, 22},
{11, 12, 20}, {11, 12, 21}, {11, 12, 22},
{12, 10, 20}, {12, 10, 21}, {12, 10, 22},
{20, 21, 10}, {20, 21, 11}, {20, 21, 12},
{21, 22, 10}, {21, 22, 11}, {21, 22, 12},
{22, 20, 10}, {22, 20, 11}, {22, 20, 12},
};
int permutations_of_sigma3(int ns[static 3]) {
return (ns[0] > ns[1]) + (ns[1] > ns[2]) + (ns[0] > ns[2]);
}
PossiblyNegatedTriangle get_order_var_of_triangle_merged_ns(int arg[static 3]) {
for (int ord = 0; ord < 18; ord++) {
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if (comparison_triang_groups[ord][y] == arg[x])
goto found_this_one;
}
goto nah_not_this_one;
found_this_one:
}
return (PossiblyNegatedTriangle){ .order = ord,
.negate = ((permutations_of_sigma3(comparison_triang_groups[ord]) +
permutations_of_sigma3(arg)) % 2 == 1) };
nah_not_this_one: /* We continue out search*/
}
abortf("Impossible");
}
PossiblyNegatedTriangle get_order_var_of_triangle(char tri, int idi, char trj, int idj, char tru, int idu) {
assert(tri == 'C' || tri == 'T');
assert(trj == 'C' || trj == 'T');
assert(tru == 'C' || tru == 'T');
assert(0 <= idi && idi < 3);
assert(0 <= idj && idj < 3);
assert(0 <= idu && idu < 3);
assert(!(tri == trj && trj == tru));
assert(!(tri == trj && idi == idj));
assert(!(trj == tru && idj == idu));
assert(!(tri == tru && idi == idu));
int arg[3] = { (tri == 'C' ? 10 : 20) + idi, (trj == 'C' ? 10 : 20) + idj, (tru == 'C' ? 10 : 20) + idu };
return get_order_var_of_triangle_merged_ns(arg);
}
/* Appends code to string with code.
* Triangle is either 'T' or 'C'
* Vertexes in triangle are numbered 0,1,2
* vertex vi: (index idi of triangle tri)
* vertex vj: (index idj of triangle trj)
* vertex u: (index idu of triangle tru)
* We walk along the vi -> vj ray. If u is on the left, this statement will show true
*/
void append_on_the_left_stmt(VecU8* str, char tri, int idi, char trj, int idj, char tru, int idu) {
PossiblyNegatedTriangle measure = get_order_var_of_triangle(tri, idi, trj, idj, tru, idu);
if (measure.negate)
VecU8_append(str, '!');
VecU8_append_vec(str, VecU8_format("M%d", measure.order));
}
void append_on_the_right_stmt(VecU8* str, char tri, int idi, char trj, int idj, char tru, int idu) {
PossiblyNegatedTriangle measure = get_order_var_of_triangle(tri, idi, trj, idj, tru, idu);
if (!measure.negate)
VecU8_append(str, '!');
VecU8_append_vec(str, VecU8_format("M%d", measure.order));
}
/* Generates statement that intersects two segments from 2 different triangles:
* First segment: (tr1::A1) to (tr1::B1)
* Second segment: (tr2::A2) to (tr2::B2)
* */
void append_intersection_stmt(VecU8* str, char tr1, int A1, int B1, char tr2, int A2, int B2) {
assert((tr1 == 'C' && tr2 == 'T') || (tr1 == 'T' && tr2 == 'C'));
assert(0 <= A1 && A1 < 3);
assert(0 <= B1 && B1 < 3);
assert(0 <= A2 && A2 < 3);
assert(0 <= B2 && B2 < 3);
assert(A1 != B1 && A2 != B2);
VecU8_append_vec(str, VecU8_format("marie_intersect_lines(T.v%d, T.v%d, C.v%d, C.v%d)",
A1, B1, A2, B2));
}
ConstSpanU8 marie_names_of_two_clipping_triangles[6] = {
{"C.v0", 4}, {"C.v1", 4}, {"C.v2", 4},
{"T.v0", 4}, {"T.v1", 4}, {"T.v2", 4},
};
NODISCARD ConstSpanU8 get_firstborn_vertex_stmt(char tr, int id) {
assert(0 <= id && id < 3);
if (tr == 'C')
return marie_names_of_two_clipping_triangles[id];
if (tr == 'T')
return marie_names_of_two_clipping_triangles[3 + id];
abortf("Wrong triangle");
}
void append_triangle_registration_stmt(VecU8* str, ConstSpanU8 P0, ConstSpanU8 P1, ConstSpanU8 P2) {
VecU8_append_span(str, cstr("VecMarieTriangle_append(pile, (MarieTriangle){"));
VecU8_append_span(str, P0);
VecU8_append_span(str, cstr(", "));
VecU8_append_span(str, P1);
VecU8_append_span(str, cstr(", "));
VecU8_append_span(str, P2);
VecU8_append_span(str, cstr("});\n"));
}
int mod3_inc(int x) {
return x == 2 ? 0 : x + 1;
}
int mod3_dec(int x) {
return x ? x - 1 : 2;
}
void generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(VecU8* res, char tC, char tT) {
/* Case where all 3 vertices of tT are inside tC */
VecU8_append_span(res, cstr(SPACE4 "if ("));
for (int cs = 0; cs < 3; cs++) {
for (int tv = 0; tv < 3; tv++) {
if (cs != 0 || tv != 0)
VecU8_append_span(res, cstr(" && "));
append_on_the_left_stmt(res, tC, cs, tC, (cs + 1) % 3, tT, tv);
}
}
VecU8_append_span(res, cstr(") {\n" SPACE8));
append_triangle_registration_stmt(res,
get_firstborn_vertex_stmt(tT, 0), get_firstborn_vertex_stmt(tT, 1), get_firstborn_vertex_stmt(tT, 2));
VecU8_append_span(res, cstr(SPACE8 "return;\n" SPACE4 "}\n"));
/* Cases where two vertices of tT are inside tC, but one is outside */
}
NODISCARD VecU8 generate_func_clip_ccw_triang_with_ccw_triang_append_to_Vec() {
VecU8 res = VecU8_from_cstr(
"void marie_clip_ccw_triang_with_ccw_triang_append_to_Vec(MarieTriangle C, MarieTriangle T, VecMarieTriangle* pile) {\n");
for (int ord = 0; ord < 18; ord++) {
VecU8_append_vec(&res, VecU8_format(SPACE4 "bool M%d = marie_surface(", ord));
for (int a = 0; a < 3; a++) {
if (a)
VecU8_append_span(&res, cstr(", "));
int vsh = comparison_triang_groups[ord][a];
VecU8_append(&res, (vsh / 10) == 1 ? 'C' : 'T');
VecU8_append_span(&res, cstr(".v"));
VecU8_append(&res, '0' + vsh % 10);
}
VecU8_append_span(&res, cstr(") > 0;\n"));
}
generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'C', 'T');
generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'T', 'C');
VecU8_append_span(&res, cstr("abortf(\"todo\\n\");\n")); // todo: check for 3 hard cases: David, wedge and non-intersecting
VecU8_append_span(&res, cstr("}\n\n"));
return res;
}
void generate_clipping_header() {
VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_L2_MARIE_CLIPPING"));
VecU8_append_span(&res, cstr("#include \"../geom.h\"\n"
"#include \"../../../src/l2/marie/geom_alg_utils.h\"\n\n"));
VecU8_append_vec(&res, generate_func_clip_ccw_triang_with_ccw_triang_append_to_Vec());
finish_header(res, "l2/marie/clipping.h");
}
#endif

View File

@ -610,8 +610,8 @@ NODISCARD VecU8 generate_xmat234x234_structs_and_methods(ConstSpanU8 xmat, Const
}
void generate_geom_header() {
VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_GEOM"));
VecU8_append_span(&res, cstr("#include \"../src/l1/core/int_primitives.h\"\n\n"));
VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_L2_GEOM"));
VecU8_append_span(&res, cstr("#include \"../../src/l1/core/int_primitives.h\"\n\n"));
VecU8_append_vec(&res, generate_xvec234_structs_and_important_methods(cstr("cvec"), cstr("U8")));
VecU8_append_vec(&res, generate_xvec234_structs_and_important_methods(cstr("ivec"), cstr("S32")));
@ -619,7 +619,7 @@ void generate_geom_header() {
VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("dvec"), cstr("double")));
VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("mat"), cstr("vec"), cstr("float"), sizeof(float)));
VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("dmat"), cstr("dvec"), cstr("double"), sizeof(double)));
finish_header(res, "geom.h");
finish_header(res, "l2/geom.h");
}
#endif

View File

@ -172,16 +172,16 @@ VecU8 generate_texture_data_struct_and_necc_methods(ConstSpanU8 texdatat, ConstS
}
void generate_pixel_masses_header() {
VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_PIXEL_MASSES"));
VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_L2_PIXEL_MASSES"));
VecU8_append_span(&res, cstr("#include \"geom.h\"\n\n"));
VecU8_append_span(&res, cstr("#include \"../src/l1/core/VecSpan_int_primitives.h\"\n\n"));
VecU8_append_span(&res, cstr("#include \"../src/l1/system/fileio.h\"\n\n"));
VecU8_append_span(&res, cstr("#include \"../../src/l1/core/VecSpan_int_primitives.h\"\n\n"));
VecU8_append_span(&res, cstr("#include \"../../src/l1/system/fileio.h\"\n\n"));
VecU8_append_vec(&res, generate_type_triv_methods_and_vec(cstr("cvec3")));
VecU8_append_vec(&res, generate_type_triv_methods_and_vec(cstr("cvec4")));
VecU8_append_vec(&res, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8"), cstr("U8")));
VecU8_append_vec(&res, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8"), cstr("cvec3")));
VecU8_append_vec(&res, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8A8"), cstr("cvec4")));
finish_header(res, "pixel_masses.h");
finish_header(res, "l2/pixel_masses.h");
}

View File

@ -1,8 +0,0 @@
#ifndef PROTOTYPE1_SRC_L2_MARIE_CLIPPING_H
#define PROTOTYPE1_SRC_L2_MARIE_CLIPPING_H
#include "graphics_geom.h"
#endif

View File

@ -0,0 +1,86 @@
#ifndef PROTOTYPE_1_SRC_L2_MARIE_GEOM_ALG_UTILS_H
#define PROTOTYPE_1_SRC_L2_MARIE_GEOM_ALG_UTILS_H
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <float.h>
#include "../../../gen/l2/geom.h"
#include "../../l1/core/util.h"
/* float size check and IEEE754 binary32 characteristic checks */
_Static_assert(sizeof(float) == 4,
"This code assumes 32bit floats");
#if defined(__STDC_IEC_559__) /* implementation claims IEC 60559 */
_Static_assert(__STDC_IEC_559__, "Implementation is not IEC 60559");
#else
/* Fall back to valuebased checks: radix 2, 24bit mantissa, exponent ranges.
These values are unique to binary32 among the formats in actual use. */
_Static_assert(FLT_RADIX == 2, "Nonbinary radix");
_Static_assert(FLT_MANT_DIG == 24, "Float is not binary32");
_Static_assert(FLT_MAX_EXP == 128, "Float is not binary32");
_Static_assert(FLT_MIN_EXP == -125, "Float is not binary32");
#endif
uint32_t marie_pun_float2u32(float f) {
uint32_t u;
memcpy(&u, &f, sizeof u);
return u;
}
bool marie_same_dir3(float A0, float A1, float A2, float B) {
uint32_t bb = marie_pun_float2u32(B);
uint32_t diff = (marie_pun_float2u32(A0) ^ bb) |
(marie_pun_float2u32(A1) ^ bb) |
(marie_pun_float2u32(A2) ^ bb);
return A0 == 0 || A1 == 0 || A2 == 0 || (diff & 0x80000000u) == 0;
}
float marie_surface(vec2 vi, vec2 vj, vec2 u) {
return u.x * (vi.y - vj.y) + u.y * (vj.x - vi.x) + (vi.x * vj.y - vj.x * vi.y);
}
typedef vec4 MarieVertAttr;
typedef struct {
vec2 pos;
MarieVertAttr attr;
} MariePlaneVertAttr;
typedef struct {
vec2 v0;
vec2 v1;
vec2 v2;
} MarieTriangle;
#define MarieTriangle_drop(x) {}
#define MarieTriangle_clone(xp) (*(xp))
VecT_trivmove_struct_Definition(MarieTriangle)
VecT_trivmove_method_Definition(MarieTriangle)
VecT_primitive_zeroinit_method_Definition(MarieTriangle)
typedef struct {
MariePlaneVertAttr v0;
MariePlaneVertAttr v1;
MariePlaneVertAttr v2;
} MarieTriangleAttr;
#define MarieTriangleAttr_drop(x) {}
#define MarieTriangleAttr_clone(xp) (*(xp))
VecT_trivmove_struct_Definition(MarieTriangleAttr)
VecT_trivmove_method_Definition(MarieTriangleAttr)
VecT_primitive_zeroinit_method_Definition(MarieTriangleAttr)
vec2 marie_intersect_lines(vec2 A1, vec2 B1, vec2 A2, vec2 B2) {
vec2 alpha = vec2_minus_vec2(B1, A1);
vec2 beta = vec2_minus_vec2(A2, B2);
vec2 gamma = vec2_minus_vec2(A2, A1);
float det_alpha_beta = alpha.x * beta.y - alpha.y * beta.x;
float det_gamma_beta = gamma.x * beta.y - gamma.y * beta.x;
float t1 = det_gamma_beta / det_alpha_beta;
return vec2_add_vec2(A1, vec2_mul_scal(alpha, t1));
}
#endif

View File

@ -83,9 +83,5 @@ vec3 marie_normal_from_tang_space_gradient(float delt_x, float delta_z) {
return (vec3){-delt_x * N, N, -delta_z * N};
}
float marie_surface(vec2 vi, vec2 vj, vec2 u) {
return u.x * (vi.y - vj.y) + u.y * (vj.x - vi.x) + (vi.x * vj.y - vj.x * vi.y);
}
#endif

View File

@ -1,44 +1,10 @@
#ifndef SPLITTER_DRAFT_SRC_L2_MARIE_RASTERIZATION_H
#define SPLITTER_DRAFT_SRC_L2_MARIE_RASTERIZATION_H
#include "../../../gen/geom.h"
#include "../../../gen/pixel_masses.h"
#include "../../../gen/l2/geom.h"
#include "../../../gen/l2/pixel_masses.h"
#include "math.h"
#include <stdint.h>
#include <float.h>
/* float size check and IEEE754 binary32 characteristic checks */
_Static_assert(sizeof(float) == 4,
"This code assumes 32bit floats");
#if defined(__STDC_IEC_559__) /* implementation claims IEC 60559 */
_Static_assert(__STDC_IEC_559__, "Implementation is not IEC 60559");
#else
/* Fall back to valuebased checks: radix 2, 24bit mantissa, exponent ranges.
These values are unique to binary32 among the formats in actual use. */
_Static_assert(FLT_RADIX == 2, "Nonbinary radix");
_Static_assert(FLT_MANT_DIG == 24, "Float is not binary32");
_Static_assert(FLT_MAX_EXP == 128, "Float is not binary32");
_Static_assert(FLT_MIN_EXP == -125, "Float is not binary32");
#endif
// todo: move line rasterization here (from r0 test)
uint32_t marie_pun_float2u32(float f) {
uint32_t u;
memcpy(&u, &f, sizeof u);
return u;
}
bool marie_same_dir3(float A0, float A1, float A2, float B) {
uint32_t bb = marie_pun_float2u32(B);
uint32_t diff = (marie_pun_float2u32(A0) ^ bb) |
(marie_pun_float2u32(A1) ^ bb) |
(marie_pun_float2u32(A2) ^ bb);
return A0 == 0 || A1 == 0 || A2 == 0 || (diff & 0x80000000u) == 0;
}
typedef vec4 MarieVertAttr;
#include "geom_alg_utils.h"
typedef struct {
/* guest, x, y, attribute (custom) */
@ -46,11 +12,6 @@ typedef struct {
void* guest;
} FnMarieRasterizerCallback;
typedef struct {
vec2 pos;
MarieVertAttr attr;
} MariePlaneVertAttr;
typedef struct {
float c1;
float c0;

View File

@ -6,7 +6,7 @@
#include "../../../l1/core/VecSpan_int_primitives.h"
#include "../../../l1/system/fileio.h"
#include <math.h>
#include "../../../../gen/pixel_masses.h"
#include "../../../../gen/l2/pixel_masses.h"
#include "../../marie/rasterization.h"
typedef struct {
@ -73,6 +73,13 @@ typedef struct {
vec3 normal;
} ShinyMeshVertex;
#define ShinyMeshVertex_drop(vp) {}
#define ShinyMeshVertex_clone(vp) (*(vp))
VecT_trivmove_struct_Definition(ShinyMeshVertex)
VecT_trivmove_method_Definition(ShinyMeshVertex)
VecT_primitive_zeroinit_method_Definition(ShinyMeshVertex)
typedef struct {
mat4 model_t;
vec3 color_off;

View File

@ -55,8 +55,7 @@ void main(){
Pipeline0Spotlight lamp = spotlight_arr[i];
}
vec3 natural_color = texture(color_tex, fsin_tex).xyz;
// todo: add specular texture
// vec3 color = natural_color * (diffuse_illumination + specular_illumination);
vec3 color = natural_color * ( specular_illumination);
// todo: add specular map texture
vec3 color = natural_color * diffuse_illumination + 0.5 * specular_illumination;
fin_color = vec4(color, 1);
}

View File

@ -0,0 +1,55 @@
#version 450
layout(location = 0) in vec3 norm;
layout(location = 1) in vec3 color_off;
layout(location = 2) in vec3 color_on;
layout(location = 3) in vec3 pos;
layout(location = 0) out vec4 fin_color;
layout(push_constant, std430) uniform pc {
layout(offset = 64) vec3 camera_pos;
};
struct Pipeline0Spotlight {
vec3 pos;
vec3 dir;
vec3 color;
float range;
};
struct Pipeline0PointLight {
vec3 pos;
vec3 color;
};
layout(std140, binding = 0) uniform Pipeline0UBO {
int point_light_count;
int spotlight_count;
Pipeline0PointLight point_light_arr[20];
Pipeline0Spotlight spotlight_arr [120];
};
float get_intensity(float dist){
return 1 / pow(dist + 1, 2);
}
void main(){
vec3 diffuse_illumination = vec3(0);
vec3 specular_illumination = vec3(0);
for (int i = 0; i < point_light_count; i++) {
Pipeline0PointLight lamp = point_light_arr[i];
vec3 to_light = -fsin_pos + lamp.pos;
float dist = length(to_light);
vec3 U = to_light / dist;
diffuse_illumination += get_intensity(dist) * max(0.02, dot(U, norm)) * lamp.color;
vec3 A = reflect(-U, norm);
vec3 B = normalize(-fsin_pos+camera_pos);
specular_illumination += get_intensity(dist) * pow(max(0, dot(A, B)), 256) * lamp.color;
}
for (int i = 0; i < spotlight_count; i++) {
Pipeline0Spotlight lamp = spotlight_arr[i];
}
vec3 color = color_off * diffuse_illumination + 0.5 * specular_illumination + color_on;
fin_color = vec4(color, 1);
}

View File

@ -0,0 +1,27 @@
#version 450
layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 normal;
layout(location = 2) in mat4 model_t;
/* 2 <- 3,4,5 */
layout(location = 6) in vec3 color_off;
layout(location = 7) in vec3 color_on;
layout(location = 0) out vec3 vsout_normal;
layout(location = 1) out vec3 vsout_color_off;
layout(location = 2) out vec3 vsout_color_on;
layout(location = 3) out vec3 vsout_pos;
layout(push_constant, std430) uniform pc {
mat4 proj_cam_t;
};
void main(){
vsout_normal = normal;
vsout_color_off = color_off;
vsout_color_on = color_on;
vec4 real_pos = model_t * vec4(pos, 1);
vsout_pos = real_pos.xyz;
gl_Position = proj_cam_t * real_pos;
}