ChocolateBird/test/audio_renderer.gd

94 lines
3.6 KiB
GDScript3
Raw Normal View History

extends Control
2024-07-11 22:49:53 +09:30
const INPUT_TEX_WIDTH := 2048
const INPUT_FORMAT := Image.FORMAT_RGBA8 # Image.FORMAT_LA8
const INPUT_BYTES_PER_TEXEL := 4 # 2
2024-07-13 20:08:51 +09:30
const OUTPUT_BYTES_PER_TEXEL := 4
2024-07-11 22:49:53 +09:30
const OUTPUT_WIDTH := 4096
2024-07-13 20:08:51 +09:30
const QUAD_COLOR := PoolColorArray([Color.white, Color.white, Color.white, Color.white])
var viewport: Viewport
2024-07-11 22:49:53 +09:30
var render_queue: Array # of Images
var result_queue: Array # of PoolByteArrays
var current_tex: ImageTexture # Needed to prevent GC before draw
2024-07-13 20:08:51 +09:30
var waiting_for_viewport: int
var done_first_draw: bool
func _ready() -> void:
self.viewport = get_parent()
self.render_queue = []
self.result_queue = []
2024-07-13 20:08:51 +09:30
self.waiting_for_viewport = 0
self.done_first_draw = false
self.current_tex = ImageTexture.new()
2024-07-13 20:08:51 +09:30
func push_image(img: Image, uv_rows: int = 4096) -> void:
self.render_queue.append([img, uv_rows])
2024-07-11 22:49:53 +09:30
2024-07-13 20:08:51 +09:30
func push_bytes(data: PoolByteArray, uv_rows: int = 4096) -> void:
2024-07-11 22:49:53 +09:30
# print(data.subarray(0, 15))
var rows = int(pow(2, ceil(log((len(data)/INPUT_BYTES_PER_TEXEL) / INPUT_TEX_WIDTH)/log(2))))
var target_length = rows * INPUT_BYTES_PER_TEXEL * INPUT_FORMAT
while len(data) < target_length: # This is inefficient, but this function should be called with pre-padded data anyway
data.append(0)
2024-07-13 20:08:51 +09:30
var image := Image.new()
image.create_from_data(INPUT_TEX_WIDTH, rows, false, INPUT_FORMAT, data)
self.render_queue.append([image, uv_rows])
2024-07-11 22:49:53 +09:30
func _process(_delta) -> void:
update()
func _draw() -> void:
# Seems like the first one always fails
if not self.done_first_draw:
self.done_first_draw = true
return
if self.waiting_for_viewport:
# Another node later in the draw sequence can call this within the same frame,
# otherwise, this picks it up the following frame
get_result()
if not self.render_queue:
return
# Draw the next ImageTexture
2024-07-13 20:08:51 +09:30
var image_and_uv_rows = self.render_queue.pop_front()
self.current_tex.create_from_image(image_and_uv_rows[0], 0)
2024-07-11 22:49:53 +09:30
self.material.set_shader_param('midi_events', self.current_tex)
self.material.set_shader_param('midi_events_size', self.current_tex.get_size())
2024-07-13 20:08:51 +09:30
var uv_rows: int = image_and_uv_rows[1]
var uv_rows_inv: int = 4096 - uv_rows
var uv_v: float = uv_rows / float(OUTPUT_WIDTH)
var points := PoolVector2Array([Vector2(0, uv_rows_inv), Vector2(OUTPUT_WIDTH, uv_rows_inv), Vector2(OUTPUT_WIDTH, OUTPUT_WIDTH), Vector2(0, OUTPUT_WIDTH)])
var uvs := PoolVector2Array([Vector2(0, 1-uv_v), Vector2(1, 1-uv_v), Vector2(1, 1), Vector2(0, 1)])
draw_primitive(points, QUAD_COLOR, uvs, self.current_tex)
self.waiting_for_viewport = uv_rows # Grab the result next draw
func get_result() -> void:
var result_texture := self.viewport.get_texture()
var result_image := result_texture.get_data()
var result_bytes := result_image.get_data()
2024-07-13 20:08:51 +09:30
var result_byte_count := waiting_for_viewport * OUTPUT_WIDTH * OUTPUT_BYTES_PER_TEXEL
result_bytes.resize(result_byte_count)
self.result_queue.append(result_bytes)
2024-07-13 20:08:51 +09:30
self.waiting_for_viewport = 0
2024-07-11 22:49:53 +09:30
# # Debugging: compare a sequence of all the possible 16bit integers
# print_debug('result_image format is %d and has size'%result_image.get_format(), result_image.get_size(), result_bytes.subarray(0, 11))
# test_readback(result_bytes)
func test_readback(result_bytes: PoolByteArray):
# Debugging: compare a sequence of all the possible 16bit integers
var buff := StreamPeerBuffer.new()
buff.set_data_array(result_bytes)
var tex_readback = 0
var uv_readback = 0
for i in 0x1000:
tex_readback = buff.get_u16()
uv_readback = buff.get_u16()
if tex_readback != i:
print('tex readback %d (0x%04x) was instead %d (0x%04x)'%[i, i, tex_readback, tex_readback])
if uv_readback != i:
print('uv readback %d (0x%04x) was instead %d (0x%04x)'%[i, i, uv_readback, uv_readback])