Initial commit

This commit is contained in:
Synthasmagoria 2026-09-23 15:54:19 +02:00
commit dd58a721ec
8 changed files with 617 additions and 0 deletions

347
main.odin Normal file
View file

@ -0,0 +1,347 @@
package main
import "base:runtime"
import "core:fmt"
import "core:math"
double :: f64
v2 :: [2]f32
v3 :: [3]f32
v4 :: [4]f32
Color :: [4]byte
System :: struct {
particle_number: int,
index: int,
tpage_size: int,
vertices: [^]Vertex,
instances: [^]Instance,
}
Instance :: struct {
life: int,
image_uv_width: f32,
image_index, image_speed, image_number: f32,
position, speed, gravity: v3,
image_blend, image_blend_add: v4,
scale, grow: v2,
image_angle, image_angle_speed: f32,
hsv, hsv_add: v3,
}
Vertex :: struct {
position: v3,
color: Color,
texcoord: v2,
offset: v3,
scale: v2,
angle: f32,
rotation_direction: v3,
animation: f32,
hsv: v3,
}
system_current: ^System
pem_show_error :: proc(message: string, loc: runtime.Source_Code_Location) {
context = context
fmt.println("Error (", loc.procedure, ") L", loc.line, ": ", message, sep = "")
}
@(export)
pem_get_size :: proc "c" (number: double) -> double {
number := int(number)
system := size_of(System)
vertices := _projectile_system_get_vertex_buffer_size(number)
instances := size_of(Instance) * number
return double(system + vertices + instances)
}
@(export)
pem_get_vertex_buffer_size :: proc "c" (number: double) -> double {
return double(_projectile_system_get_vertex_buffer_size(int(number)))
}
_projectile_system_get_vertex_buffer_size :: proc "c" (number: int) -> int {
return size_of(Vertex) * 6 * number
}
@(export)
pem_get_vertex_buffer_offset :: proc "c" () -> double {
return double(_projectile_system_get_vertex_buffer_offset())
}
_projectile_system_get_vertex_buffer_offset :: proc "c" () -> int {
return size_of(System)
}
@(export)
pem_init :: proc "c" (memory: [^]byte, particle_number, tpage_size: double) {
context = runtime.default_context()
particle_number := int(particle_number)
system := cast(^System)memory
system.particle_number = particle_number
system.tpage_size = int(tpage_size)
system.index = 0
vertex_buffer_offset := _projectile_system_get_vertex_buffer_offset()
system.vertices = cast([^]Vertex)&memory[vertex_buffer_offset]
instance_buffer_offset := vertex_buffer_offset + _projectile_system_get_vertex_buffer_size(particle_number)
system.instances = cast([^]Instance)&memory[instance_buffer_offset]
}
@(export)
_pem_update :: proc "c" (system: ^System) {
vertices := system.vertices
instances := system.instances
for i in 0 ..< system.particle_number {
instances[i].life = max(instances[i].life - 1, -1)
if instances[i].life == 0 {
instances[i].grow = v2{0.0, 0.0}
instances[i].image_blend.a = 0.0
instances[i].image_blend_add.a = 0.0
}
instances[i].speed += instances[i].gravity
instances[i].position += instances[i].speed
instances[i].image_blend += instances[i].image_blend_add
instances[i].scale += instances[i].grow
instances[i].image_angle += instances[i].image_angle_speed
instances[i].image_index = math.wrap(instances[i].image_index + instances[i].image_speed, instances[i].image_number)
instances[i].hsv = v3 {
instances[i].hsv.x + instances[i].hsv_add.x,
clamp(instances[i].hsv.y + instances[i].hsv_add.y, 0.0, 2.0),
clamp(instances[i].hsv.z + instances[i].hsv_add.z, 0.0, 2.0),
}
offset := i * 6
#unroll for j in 0 ..< 6 {
vertices[offset + j].color = {
u8(clamp(instances[i].image_blend.r, 0, 255)),
u8(clamp(instances[i].image_blend.g, 0, 255)),
u8(clamp(instances[i].image_blend.b, 0, 255)),
u8(clamp(instances[i].image_blend.a, 0, 255)),
}
vertices[offset + j].offset = instances[i].position
vertices[offset + j].scale = instances[i].scale
vertices[offset + j].angle = instances[i].image_angle
vertices[offset + j].animation = math.floor(instances[i].image_index) * instances[i].image_uv_width
vertices[offset + j].hsv = instances[i].hsv
}
}
}
@(export)
_pem_set :: proc "c" (system: ^System) {
system_current = system
}
Origin :: enum {
TopLeft,
TopMiddle,
TopRight,
MiddleLeft,
Middle,
MiddleRight,
BottomLeft,
BottomMiddle,
BottomRight,
}
@(export)
pem_instance_create_origin :: proc "c" (x, y, w, h, origin, uv_left, uv_top, uv_right, uv_bottom, image_number: double) -> double {
xorigin, yorigin: double
origin := Origin(int(origin))
switch origin {
case .TopLeft:
xorigin = 0.0; yorigin = 0.0
case .TopMiddle:
xorigin = w / 2.0; yorigin = 0.0
case .TopRight:
xorigin = w; yorigin = 0.0
case .MiddleLeft:
xorigin = 0.0; yorigin = h / 2.0
case .Middle:
xorigin = w / 2.0; yorigin = h / 2.0
case .MiddleRight:
xorigin = w; yorigin = h / 2.0
case .BottomLeft:
xorigin = 0.0; yorigin = h
case .BottomMiddle:
xorigin = w; yorigin = h
case .BottomRight:
xorigin = w / 2.0; yorigin = h
}
return pem_instance_create(x, y, w, h, xorigin, yorigin, uv_left, uv_top, uv_right, uv_bottom, image_number)
}
@(export)
pem_instance_create :: proc "c" (x, y, w, h, xorigin, yorigin, uv_left, uv_top, uv_right, uv_bottom, image_number: double) -> double {
position := v3{f32(x), f32(y), 1.0}
size := v3{f32(w), f32(h), 1.0}
origin := v3{f32(xorigin), f32(yorigin), 0.0}
uv_left := f32(uv_left)
uv_right := f32(uv_right)
uv_top := f32(uv_top)
uv_bottom := f32(uv_bottom)
image_number := f32(max(0.0, image_number))
uv_tl := v2{uv_left, uv_top}
uv_br := v2{uv_left + (uv_right - uv_left) / image_number, uv_bottom}
index := system_current.index
offset := system_current.index * 6
system_current.index = (system_current.index + 1) % system_current.particle_number
system_current.instances[index] = {
life = -1,
image_uv_width = (uv_right - uv_left) / image_number,
image_index = 0.0,
image_number = image_number,
image_speed = 1.0,
position = position,
image_blend = {255.0, 255.0, 255.0, 255.0},
scale = {1.0, 1.0},
image_angle = 0.0,
hsv = {0.0, 1.0, 1.0},
}
tl := v3{0.0, 0.0, 1.0}
tr := v3{1.0, 0.0, 1.0}
bl := v3{0.0, 1.0, 1.0}
br := v3{1.0, 1.0, 1.0}
pos := [6]v3{tl, bl, tr, tr, bl, br}
#unroll for i in 0 ..< 6 {
system_current.vertices[offset + i] = {
position = pos[i] * size - origin,
color = {255, 255, 255, 255},
texcoord = math.lerp(uv_tl, uv_br, pos[i].xy),
offset = system_current.instances[index].position,
scale = system_current.instances[index].scale,
angle = system_current.instances[index].image_angle,
rotation_direction = v3{0.0, 0.0, -1.0},
hsv = system_current.instances[index].hsv,
}
}
return double(index)
}
@(export)
pem_instance_set_life :: proc "c" (id, life: double) {
system_current.instances[int(id)].life = int(life)
}
@(export)
pem_instance_set_life_to_animation :: proc "c" (id, animation_count: double) {
id := int(id)
image_number_from_index := system_current.instances[id].image_number - system_current.instances[id].image_index
if image_number_from_index <= 0.0 {
context = runtime.default_context()
pem_show_error("image number left is 0", #location())
system_current.instances[id].life = -1
return
}
system_current.instances[id].life = int(image_number_from_index / system_current.instances[id].image_speed) * int(animation_count)
}
@(export)
pem_instance_set_life_to_alpha_fade :: proc "c" (id: double) {
id := int(id)
a := system_current.instances[id].image_blend.a
a_add := system_current.instances[id].image_blend_add.a
if a <= 0.0 {
context = runtime.default_context()
pem_show_error("alpha started at 0.0 or lower", #location())
system_current.instances[id].life = -1
return
}
frames := int((a / a_add) * -1.0)
if frames <= 0 {
context = runtime.default_context()
pem_show_error("alpha never reaches 0.0", #location())
system_current.instances[id].life = -1
return
}
system_current.instances[id].life = frames
}
@(export)
pem_instance_set_life_to_shrink :: proc "c" (id: double) {
id := int(id)
scale := v2{system_current.instances[id].scale.x, system_current.instances[id].scale.y}
grow := v2{system_current.instances[id].grow.x, system_current.instances[id].grow.y}
frames := v2{scale.x / grow.x * -1.0, scale.y / grow.y * -1.0}
frames_max := max(frames.x, frames.y)
if frames_max <= 0.0 {
context = runtime.default_context()
pem_show_error("instance never shrinks in on itself", #location())
system_current.instances[id].life = -1
return
}
system_current.instances[id].life = int(frames_max)
}
@(export)
pem_instance_set_image_blend :: proc "c" (id, r, g, b, a: double) {
system_current.instances[int(id)].image_blend = {f32(r), f32(g), f32(b), f32(a)} * 255.0
}
@(export)
pem_instance_set_image_blend_add :: proc "c" (id, r, g, b, a: double) {
system_current.instances[int(id)].image_blend_add = {f32(r), f32(g), f32(b), f32(a)} * 255.0
}
@(export)
pem_instance_set_speed :: proc "c" (id, hspeed, vspeed: double) {
system_current.instances[int(id)].speed = {f32(hspeed), f32(vspeed), 0.0}
}
@(export)
pem_instance_set_gravity :: proc "c" (id, x, y: double) {
system_current.instances[int(id)].gravity = {f32(x), f32(y), 0.0}
}
@(export)
pem_instance_set_scale :: proc "c" (id, xscale, yscale: double) {
system_current.instances[int(id)].scale = {f32(xscale), f32(yscale)}
}
@(export)
pem_instance_set_grow :: proc "c" (id, xgrow, ygrow: double) {
system_current.instances[int(id)].grow = {f32(xgrow), f32(ygrow)}
}
@(export)
pem_instance_set_image_angle :: proc "c" (id, angle: double) {
system_current.instances[int(id)].image_angle = f32(angle) * math.RAD_PER_DEG
}
@(export)
pem_instance_set_image_angle_speed :: proc "c" (id, angular_velocity: double) {
system_current.instances[int(id)].image_angle_speed = f32(angular_velocity) * math.RAD_PER_DEG
}
@(export)
pem_instance_set_image_angle_direction :: proc "c" (id, x, y, z: double) {
offset := int(id) * 6
#unroll for i in 0 ..< 6 {
system_current.vertices[offset + i].rotation_direction = {f32(x), f32(y), f32(z)}
}
}
@(export)
pem_instance_set_image_index :: proc "c" (id, index: double) {
system_current.instances[int(id)].image_index = f32(index)
}
@(export)
pem_instance_set_image_speed :: proc "c" (id, speed: double) {
system_current.instances[int(id)].image_speed = f32(speed)
}
@(export)
pem_instance_set_hsv :: proc "c" (id, h, s, v: double) {
system_current.instances[int(id)].hsv = v3{f32(h) / 360.0, f32(s) / 100.0, f32(v) / 100.0}
}
@(export)
pem_instance_set_hsv_add :: proc "c" (id, h, s, v: double) {
system_current.instances[int(id)].hsv_add = v3{f32(h) / 360.0, f32(s) / 100.0, f32(v) / 100.0}
}