rectangle shading
This commit is contained in:
@@ -20,6 +20,7 @@ function full_upload(buffers)
|
|||||||
function queue_sprite_mesh(queue)
|
function queue_sprite_mesh(queue)
|
||||||
{
|
{
|
||||||
var sprites = queue.filter(x => x.type === 'sprite');
|
var sprites = queue.filter(x => x.type === 'sprite');
|
||||||
|
if (sprites.length === 0) return [];
|
||||||
var mesh = render._main.make_sprite_mesh(sprites);
|
var mesh = render._main.make_sprite_mesh(sprites);
|
||||||
for (var i = 0; i < sprites.length; i++) {
|
for (var i = 0; i < sprites.length; i++) {
|
||||||
sprites[i].mesh = mesh;
|
sprites[i].mesh = mesh;
|
||||||
@@ -111,6 +112,12 @@ sprite_pipeline.blend = {
|
|||||||
op_alpha: "add"
|
op_alpha: "add"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var rect_pipeline = Object.create(sprite_pipeline)
|
||||||
|
rect_pipeline.fragment = "rectangle.frag"
|
||||||
|
|
||||||
|
var line_pipeline = Object.create(rect_pipeline);
|
||||||
|
line_pipeline.primitive = "line"
|
||||||
|
|
||||||
var dbgline_pipeline = Object.create(base_pipeline);
|
var dbgline_pipeline = Object.create(base_pipeline);
|
||||||
dbgline_pipeline.vertex = "dbgline.vert.hlsl"
|
dbgline_pipeline.vertex = "dbgline.vert.hlsl"
|
||||||
dbgline_pipeline.fragment = "dbgline.frag.hlsl"
|
dbgline_pipeline.fragment = "dbgline.frag.hlsl"
|
||||||
@@ -124,7 +131,7 @@ post_camera.size = [640,360];
|
|||||||
post_camera.mode = 'keep';
|
post_camera.mode = 'keep';
|
||||||
post_camera.viewport = {x:0,y:0,width:1,height:1}
|
post_camera.viewport = {x:0,y:0,width:1,height:1}
|
||||||
post_camera.fov = 45;
|
post_camera.fov = 45;
|
||||||
post_camera.type = 'ortho';
|
post_camera.ortho = true;
|
||||||
post_camera.aspect = 16/9;
|
post_camera.aspect = 16/9;
|
||||||
|
|
||||||
function get_pipeline_ubo_slot(pipeline, name)
|
function get_pipeline_ubo_slot(pipeline, name)
|
||||||
@@ -227,7 +234,7 @@ render.hotreload = function shader_hotreload(file) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function make_pipeline(pipeline) {
|
function make_pipeline(pipeline) {
|
||||||
if (pipeline.gpu) return; // this pipeline has already been made
|
if (pipeline.hasOwnProperty("gpu")) return; // this pipeline has already been made
|
||||||
|
|
||||||
if (typeof pipeline.vertex === 'string')
|
if (typeof pipeline.vertex === 'string')
|
||||||
pipeline.vertex = make_shader(pipeline.vertex);
|
pipeline.vertex = make_shader(pipeline.vertex);
|
||||||
@@ -302,9 +309,8 @@ var shader_type;
|
|||||||
|
|
||||||
function make_shader(sh_file) {
|
function make_shader(sh_file) {
|
||||||
var file = `shaders/${shader_type}/${sh_file}.${shader_type}`
|
var file = `shaders/${shader_type}/${sh_file}.${shader_type}`
|
||||||
|
|
||||||
var refl = json.decode(io.slurp(`shaders/reflection/${sh_file}.json`))
|
|
||||||
if (shader_cache[file]) return shader_cache[file]
|
if (shader_cache[file]) return shader_cache[file]
|
||||||
|
var refl = json.decode(io.slurp(`shaders/reflection/${sh_file}.json`))
|
||||||
|
|
||||||
var shader = {
|
var shader = {
|
||||||
code: io.slurpbytes(file),
|
code: io.slurpbytes(file),
|
||||||
@@ -358,6 +364,9 @@ render.device = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var render_queue = [];
|
var render_queue = [];
|
||||||
|
var hud_queue = [];
|
||||||
|
|
||||||
|
var current_queue = render_queue;
|
||||||
|
|
||||||
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
||||||
var std_sampler = {
|
var std_sampler = {
|
||||||
@@ -495,11 +504,15 @@ function render_camera(cmds, camera)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render_queue.length == 0) return;
|
var buffers = [];
|
||||||
var buffers = queue_sprite_mesh(render_queue);
|
buffers = buffers.concat(queue_sprite_mesh(render_queue));
|
||||||
for (var q of render_queue) {
|
for (var q of render_queue)
|
||||||
if (q.type === 'geometry') buffers = buffers.concat([q.mesh.pos, q.mesh.color,q.mesh.uv,q.mesh.indices]);
|
if (q.type === 'geometry') buffers = buffers.concat([q.mesh.pos, q.mesh.color,q.mesh.uv,q.mesh.indices]);
|
||||||
}
|
|
||||||
|
buffers = buffers.concat(queue_sprite_mesh(hud_queue));
|
||||||
|
for (var q of hud_queue)
|
||||||
|
if (q.type === 'geometry') buffers = buffers.concat([q.mesh.pos, q.mesh.color,q.mesh.uv,q.mesh.indices]);
|
||||||
|
|
||||||
full_upload(buffers)
|
full_upload(buffers)
|
||||||
|
|
||||||
var pass = cmds.render_pass(camera.target);
|
var pass = cmds.render_pass(camera.target);
|
||||||
@@ -517,7 +530,7 @@ function render_camera(cmds, camera)
|
|||||||
|
|
||||||
var camslot = get_pipeline_ubo_slot(pipeline, 'TransformBuffer');
|
var camslot = get_pipeline_ubo_slot(pipeline, 'TransformBuffer');
|
||||||
if (typeof camslot !== 'undefined')
|
if (typeof camslot !== 'undefined')
|
||||||
cmds.camera(camera, pass, undefined, camslot);
|
cmds.camera(camera, camslot);
|
||||||
|
|
||||||
modelslot = get_pipeline_ubo_slot(pipeline, "model");
|
modelslot = get_pipeline_ubo_slot(pipeline, "model");
|
||||||
if (typeof modelslot !== 'undefined') {
|
if (typeof modelslot !== 'undefined') {
|
||||||
@@ -531,7 +544,37 @@ function render_camera(cmds, camera)
|
|||||||
bind_model(pass,pipeline,mesh);
|
bind_model(pass,pipeline,mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (img != group.image) {
|
if (group.image && img != group.image) {
|
||||||
|
img = group.image;
|
||||||
|
img.sampler = std_sampler;
|
||||||
|
bind_mat(pass,pipeline,{diffuse:img});
|
||||||
|
}
|
||||||
|
|
||||||
|
pass.draw_indexed(group.num_indices, 1, group.first_index, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var group of hud_queue) {
|
||||||
|
if (pipeline != group.pipeline) {
|
||||||
|
pipeline = group.pipeline;
|
||||||
|
bind_pipeline(pass, pipeline);
|
||||||
|
|
||||||
|
var camslot = get_pipeline_ubo_slot(pipeline, 'TransformBuffer');
|
||||||
|
if (typeof camslot !== 'undefined')
|
||||||
|
cmds.hud(camera.size, camslot);
|
||||||
|
|
||||||
|
modelslot = get_pipeline_ubo_slot(pipeline, "model");
|
||||||
|
if (typeof modelslot !== 'undefined') {
|
||||||
|
var ubo = ubo_obj_to_array(pipeline, 'model', sprite_model_ubo);
|
||||||
|
cmds.push_vertex_uniform_data(modelslot, ubo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh != group.mesh) {
|
||||||
|
mesh = group.mesh;
|
||||||
|
bind_model(pass,pipeline,mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.image && img != group.image) {
|
||||||
img = group.image;
|
img = group.image;
|
||||||
img.sampler = std_sampler;
|
img.sampler = std_sampler;
|
||||||
bind_mat(pass,pipeline,{diffuse:img});
|
bind_mat(pass,pipeline,{diffuse:img});
|
||||||
@@ -597,7 +640,7 @@ function gpupresent()
|
|||||||
cmds.cancel();
|
cmds.cancel();
|
||||||
else {
|
else {
|
||||||
var mode = prosperon.camera.presentation || "letterbox"
|
var mode = prosperon.camera.presentation || "letterbox"
|
||||||
var src_rect = {x:0,y:0,width:640,height:360}
|
var src_rect = {x:0,y:0,width:prosperon.camera.size.x,height:prosperon.camera.size.y}
|
||||||
var dst_rect = {x:0,y:0,width:swapchain_tex.width,height:swapchain_tex.height};
|
var dst_rect = {x:0,y:0,width:swapchain_tex.width,height:swapchain_tex.height};
|
||||||
var torect = mode_rect(src_rect,dst_rect,mode);
|
var torect = mode_rect(src_rect,dst_rect,mode);
|
||||||
torect.texture = swapchain_tex;
|
torect.texture = swapchain_tex;
|
||||||
@@ -713,7 +756,8 @@ render.poly = function render_poly(points, color, transform) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// render.line has uv and can be texture mapped; dbg_line is hardware standard lines
|
// render.line has uv and can be texture mapped; dbg_line is hardware standard lines
|
||||||
render.line = function render_line(points, color = Color.white, thickness = 1, pipe = base_pipeline) {
|
render.line = function render_line(points, color = Color.white, thickness = 1, pipeline = line_pipeline) {
|
||||||
|
var mesh = os.make_line_prim(points);
|
||||||
// render._main.line(points, color);
|
// render._main.line(points, color);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -732,14 +776,14 @@ render.point = function (pos, size, color = Color.blue) {
|
|||||||
render._main.point(pos,color);
|
render._main.point(pos,color);
|
||||||
};
|
};
|
||||||
|
|
||||||
render.cross = function render_cross(pos, size, color = Color.red, thickness = 1, pipe = base_pipeline) {
|
render.cross = function render_cross(pos, size, color = Color.red, thickness = 1, pipe = sprite_pipeline) {
|
||||||
var a = [pos.add([0, size]), pos.add([0, -size])];
|
var a = [pos.add([0, size]), pos.add([0, -size])];
|
||||||
var b = [pos.add([size, 0]), pos.add([-size, 0])];
|
var b = [pos.add([size, 0]), pos.add([-size, 0])];
|
||||||
render.line(a, color, thickness);
|
render.line(a, color, thickness);
|
||||||
render.line(b, color, thickness);
|
render.line(b, color, thickness);
|
||||||
};
|
};
|
||||||
|
|
||||||
render.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe = base_pipeline) {
|
render.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe = sprite_pipeline) {
|
||||||
var dir = end.sub(start).normalized();
|
var dir = end.sub(start).normalized();
|
||||||
var wing1 = [Vector.rotate(dir, wingangle).scale(wingspan).add(end), end];
|
var wing1 = [Vector.rotate(dir, wingangle).scale(wingspan).add(end), end];
|
||||||
var wing2 = [Vector.rotate(dir, -wingangle).scale(wingspan).add(end), end];
|
var wing2 = [Vector.rotate(dir, -wingangle).scale(wingspan).add(end), end];
|
||||||
@@ -755,8 +799,15 @@ render.coordinate = function render_coordinate(pos, size, color) {
|
|||||||
|
|
||||||
var queued_shader;
|
var queued_shader;
|
||||||
var queued_pipe;
|
var queued_pipe;
|
||||||
render.rectangle = function render_rectangle(rect, color = Color.white, pipe = base_pipeline) {
|
render.rectangle = function render_rectangle(rect, color = Color.white, pipeline = rect_pipeline) {
|
||||||
render._main.fillrect(rect,color);
|
var T = os.make_transform();
|
||||||
|
T.rect(rect);
|
||||||
|
current_queue.push({
|
||||||
|
type:'sprite',
|
||||||
|
transform:T,
|
||||||
|
color,
|
||||||
|
pipeline
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render.text = function text(text, rect, font = prosperon.font, size = 0, color = Color.white, wrap = 0, pipeline = sprite_pipeline) {
|
render.text = function text(text, rect, font = prosperon.font, size = 0, color = Color.white, wrap = 0, pipeline = sprite_pipeline) {
|
||||||
@@ -765,7 +816,7 @@ render.text = function text(text, rect, font = prosperon.font, size = 0, color =
|
|||||||
var mesh = os.make_text_buffer(text, rect, 0, color, wrap, font);
|
var mesh = os.make_text_buffer(text, rect, 0, color, wrap, font);
|
||||||
// full_upload(mesh)
|
// full_upload(mesh)
|
||||||
|
|
||||||
render_queue.push({
|
current_queue.push({
|
||||||
type: 'geometry',
|
type: 'geometry',
|
||||||
mesh: mesh,
|
mesh: mesh,
|
||||||
image: font,
|
image: font,
|
||||||
@@ -894,12 +945,12 @@ render.image = function image(image, rect = [0,0], rotation = 0, color = Color.w
|
|||||||
rect.height ??= image.texture.height;
|
rect.height ??= image.texture.height;
|
||||||
var T = os.make_transform();
|
var T = os.make_transform();
|
||||||
T.rect(rect);
|
T.rect(rect);
|
||||||
render_queue.push({
|
current_queue.push({
|
||||||
type: 'sprite',
|
type: 'sprite',
|
||||||
transform: T,
|
transform: T,
|
||||||
color: color,
|
image,
|
||||||
image:image,
|
pipeline,
|
||||||
pipeline: pipeline
|
color
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1019,17 +1070,6 @@ prosperon.make_camera = function make_camera() {
|
|||||||
cam.screen2cam = screen2cam;
|
cam.screen2cam = screen2cam;
|
||||||
cam.screen2hud = screen2hud;
|
cam.screen2hud = screen2hud;
|
||||||
cam.zoom = 1; // the "scale factor" this camera demonstrates
|
cam.zoom = 1; // the "scale factor" this camera demonstrates
|
||||||
// camera renders draw calls, and then hud
|
|
||||||
cam.render = function() {
|
|
||||||
prosperon.draw();
|
|
||||||
draw_sprites();
|
|
||||||
render._main.camera(this.transform,true);
|
|
||||||
render._main.scale([this.zoom, this.zoom]);
|
|
||||||
prosperon.hud();
|
|
||||||
render._main.scale([1,1]);
|
|
||||||
render._main.camera(unit_transform,false);
|
|
||||||
|
|
||||||
}
|
|
||||||
return cam;
|
return cam;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1136,34 +1176,6 @@ var imgui_fn = function imgui_fn() {
|
|||||||
*/
|
*/
|
||||||
prosperon.imgui();
|
prosperon.imgui();
|
||||||
// imgui.endframe(render._main);
|
// imgui.endframe(render._main);
|
||||||
};
|
|
||||||
|
|
||||||
// figure out the highest resolution we can render at that's an integer
|
|
||||||
/* var basesize = prosperon.camera.size.slice();
|
|
||||||
var baseview = prosperon.camera.view();
|
|
||||||
var wh = [baseview[2]-baseview[0], baseview[3]-baseview[1]];
|
|
||||||
var mult = 1;
|
|
||||||
var trysize = basesize.scale(mult);
|
|
||||||
while (trysize.x <= wh.x && trysize.y <= wh.y) {
|
|
||||||
mult++;
|
|
||||||
trysize = basesize.scale(mult);
|
|
||||||
}
|
|
||||||
if (Math.abs(wh.x - basesize.scale(mult-1).x) < Math.abs(wh.x - trysize.x))
|
|
||||||
mult--;
|
|
||||||
|
|
||||||
\prosperon.window_render(basesize.scale(mult));
|
|
||||||
*/
|
|
||||||
|
|
||||||
prosperon.render = function prosperon_render() {
|
|
||||||
try{
|
|
||||||
try {
|
|
||||||
imgui_fn();
|
|
||||||
} catch(e) { console.error(e) }
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e)
|
|
||||||
} finally {
|
|
||||||
render._main.present();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//if (dmon) dmon.watch('.');
|
//if (dmon) dmon.watch('.');
|
||||||
@@ -1222,8 +1234,14 @@ try {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
try { prosperon.draw(); } catch(e) {console.error(e)}
|
current_queue = render_queue;
|
||||||
prosperon.render();
|
try { prosperon.draw(); } catch(e) { console.error(e) }
|
||||||
|
current_queue = hud_queue;
|
||||||
|
try { prosperon.hud(); } catch(e) { console.error(e) }
|
||||||
|
|
||||||
|
try { imgui_fn(); } catch(e) { console.error(e) }
|
||||||
|
|
||||||
|
render._main.present();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Ensure directories exist
|
# Ensure directories exist
|
||||||
mkdir -p spirv
|
mkdir -p spv
|
||||||
mkdir -p msl
|
mkdir -p msl
|
||||||
|
mkdir -p dxil
|
||||||
mkdir -p reflection
|
mkdir -p reflection
|
||||||
|
|
||||||
# Vertex shaders
|
# Vertex shaders
|
||||||
for filename in *.vert.hlsl; do
|
for filename in *.vert.hlsl; do
|
||||||
if [ -f "$filename" ]; then echo "compiling ${filename}"
|
if [ -f "$filename" ]; then echo "compiling ${filename}"
|
||||||
|
# Produce SPIR-V
|
||||||
dxc -spirv -T vs_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
|
dxc -spirv -T vs_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
|
||||||
|
# Produce DXIL
|
||||||
|
dxc -T vs_6_0 -Fo "dxil/${filename/.hlsl/.dxil}" "$filename"
|
||||||
|
# Convert SPIR-V to Metal Shader Language
|
||||||
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
|
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
|
||||||
|
# Generate reflection
|
||||||
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
|
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -17,8 +23,13 @@ done
|
|||||||
# Fragment shaders
|
# Fragment shaders
|
||||||
for filename in *.frag.hlsl; do
|
for filename in *.frag.hlsl; do
|
||||||
if [ -f "$filename" ]; then echo "compiling ${filename}"
|
if [ -f "$filename" ]; then echo "compiling ${filename}"
|
||||||
|
# Produce SPIR-V
|
||||||
dxc -spirv -T ps_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
|
dxc -spirv -T ps_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
|
||||||
|
# Produce DXIL
|
||||||
|
dxc -T ps_6_0 -Fo "dxil/${filename/.hlsl/.dxil}" "$filename"
|
||||||
|
# Convert SPIR-V to Metal Shader Language
|
||||||
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
|
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
|
||||||
|
# Generate reflection
|
||||||
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
|
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -26,8 +37,13 @@ done
|
|||||||
# Compute shaders
|
# Compute shaders
|
||||||
for filename in *.comp.hlsl; do
|
for filename in *.comp.hlsl; do
|
||||||
if [ -f "$filename" ]; then echo "compiling ${filename}"
|
if [ -f "$filename" ]; then echo "compiling ${filename}"
|
||||||
|
# Produce SPIR-V
|
||||||
dxc -spirv -T cs_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
|
dxc -spirv -T cs_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
|
||||||
|
# Produce DXIL
|
||||||
|
dxc -T cs_6_0 -Fo "dxil/${filename/.hlsl/.dxil}" "$filename"
|
||||||
|
# Convert SPIR-V to Metal Shader Language
|
||||||
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
|
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
|
||||||
|
# Generate reflection
|
||||||
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
|
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
shaders/dxil/rectangle.frag.dxil
Normal file
BIN
shaders/dxil/rectangle.frag.dxil
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
22
shaders/msl/rectangle.frag.msl
Normal file
22
shaders/msl/rectangle.frag.msl
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 out_var_SV_TARGET [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 in_var_COLOR0 [[user(locn1)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
out.out_var_SV_TARGET = in.in_var_COLOR0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
7
shaders/rectangle.frag.hlsl
Normal file
7
shaders/rectangle.frag.hlsl
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "common/pixel.hlsl"
|
||||||
|
|
||||||
|
// Pixel shader main function
|
||||||
|
float4 main(PSInput input) : SV_TARGET
|
||||||
|
{
|
||||||
|
return input.color;
|
||||||
|
}
|
||||||
22
shaders/reflection/rectangle.frag.json
Normal file
22
shaders/reflection/rectangle.frag.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"entryPoints" : [
|
||||||
|
{
|
||||||
|
"name" : "main",
|
||||||
|
"mode" : "frag"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputs" : [
|
||||||
|
{
|
||||||
|
"type" : "vec4",
|
||||||
|
"name" : "in.var.COLOR0",
|
||||||
|
"location" : 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs" : [
|
||||||
|
{
|
||||||
|
"type" : "vec4",
|
||||||
|
"name" : "out.var.SV_TARGET",
|
||||||
|
"location" : 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
35
shaders/sdf.hlsl
Normal file
35
shaders/sdf.hlsl
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
struct SDF {
|
||||||
|
float circle(vec2 p, float r)
|
||||||
|
{
|
||||||
|
return length(p) - r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// p = uv point
|
||||||
|
// b = width,height
|
||||||
|
// r = roundedness of the 4 corners
|
||||||
|
float rounded_box(vec2 p, vec2 b, vec4 r)
|
||||||
|
{
|
||||||
|
r.xy = (p.x>0.0)?r.xy : r.zw;
|
||||||
|
r.x = (p.y>0.0)?r.x : r.y;
|
||||||
|
vec2 q = abs(p)-b+r.x;
|
||||||
|
return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float box(vec2 p, vec2 b)
|
||||||
|
{
|
||||||
|
vec2 d = abs(p)-b;
|
||||||
|
return length(max(d,0)) + min(max(d.x,d.y),0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float heart( in vec2 p )
|
||||||
|
{
|
||||||
|
p.x = abs(p.x);
|
||||||
|
|
||||||
|
if( p.y+p.x>1.0 )
|
||||||
|
return sqrt(dot2(p-vec2(0.25,0.75))) - sqrt(2.0)/4.0;
|
||||||
|
|
||||||
|
return sqrt(min(dot2(p-vec2(0.00,1.00)), dot2(p-0.5*max(p.x+p.y,0.0)))) * sign(p.x-p.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDF sdf;
|
||||||
BIN
shaders/spv/rectangle.frag.spv
Normal file
BIN
shaders/spv/rectangle.frag.spv
Normal file
Binary file not shown.
159
source/jsffi.c
159
source/jsffi.c
@@ -4545,129 +4545,81 @@ JSC_CCALL(cmd_submit,
|
|||||||
return SDL_GPUFence2js(js,fence);
|
return SDL_GPUFence2js(js,fence);
|
||||||
)
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(cmd_hud,
|
||||||
|
SDL_GPUCommandBuffer *cmds = js2SDL_GPUCommandBuffer(js,self);
|
||||||
|
HMM_Vec2 size = js2vec2(js,argv[0]);
|
||||||
|
HMM_Mat4 proj = HMM_Orthographic_RH_NO(0,size.x,0,size.y,-1,1);
|
||||||
|
shader_globals data = {0};
|
||||||
|
data.world_to_projection = proj;
|
||||||
|
data.projection_to_world = HMM_InvGeneralM4(proj);
|
||||||
|
data.viewport_min_z = -1,
|
||||||
|
data.viewport_max_z = 1;
|
||||||
|
data.render_size = size;
|
||||||
|
data.view_to_projection = proj;
|
||||||
|
data.viewport_size = (HMM_Vec2){1,1};
|
||||||
|
data.viewport_offset = (HMM_Vec2){0,0};
|
||||||
|
data.time = SDL_GetTicksNS() / 1000000000.0f;
|
||||||
|
SDL_PushGPUVertexUniformData(cmds, js2number(js,argv[1]), &data, sizeof(data));
|
||||||
|
)
|
||||||
|
|
||||||
JSC_CCALL(cmd_camera,
|
JSC_CCALL(cmd_camera,
|
||||||
SDL_GPUCommandBuffer *cmds = js2SDL_GPUCommandBuffer(js, self);
|
SDL_GPUCommandBuffer *cmds = js2SDL_GPUCommandBuffer(js, self);
|
||||||
JSValue camera = argv[0];
|
JSValue camera = argv[0];
|
||||||
SDL_GPURenderPass *pass = js2SDL_GPURenderPass(js, argv[1]);
|
|
||||||
|
|
||||||
HMM_Vec2 size;
|
HMM_Vec2 size;
|
||||||
HMM_Vec2 drawsize;
|
|
||||||
JS_PULLPROPSTR(js,argv[1],size,vec2);
|
|
||||||
drawsize = size;
|
|
||||||
transform *transform;
|
transform *transform;
|
||||||
|
|
||||||
JS_PULLPROPSTR(js, camera, size, vec2)
|
|
||||||
JS_PULLPROPSTR(js, camera, transform, transform)
|
|
||||||
|
|
||||||
// Pull out fov and aspect if needed (e.g. for perspective)
|
|
||||||
double fov;
|
double fov;
|
||||||
JS_PULLPROPSTR(js, camera, fov, number)
|
|
||||||
double aspect;
|
double aspect;
|
||||||
JS_PULLPROPSTR(js, camera, aspect, number)
|
int ortho;
|
||||||
|
double near;
|
||||||
|
double far;
|
||||||
|
|
||||||
|
JS_GETPROP(js, size, camera, size, vec2)
|
||||||
|
JS_GETPROP(js, transform, camera, transform, transform)
|
||||||
|
JS_GETPROP(js, fov, camera, fov, number)
|
||||||
|
JS_GETPROP(js, aspect, camera, aspect, number)
|
||||||
|
JS_GETPROP(js, ortho, camera,ortho,bool)
|
||||||
|
JS_GETPROP(js,near,camera,near,number)
|
||||||
|
JS_GETPROP(js,far,camera,far,number)
|
||||||
|
|
||||||
// Retrieve the user-specified viewport (could be normalized or exact)
|
|
||||||
JSValue jsViewport = JS_GetPropertyStr(js, camera, "viewport");
|
|
||||||
SDL_FRect cameraViewport = js2rect(js, jsViewport); // note: rect is typedef SDL_FRect
|
|
||||||
JS_FreeValue(js, jsViewport);
|
|
||||||
|
|
||||||
// Determine if we're in normalized or exact mode.
|
|
||||||
// If any dimension is > 1, treat them all as pixels (and clamp).
|
|
||||||
bool isNormalized = (cameraViewport.x <= 1.0f && cameraViewport.y <= 1.0f &&
|
|
||||||
cameraViewport.w <= 1.0f && cameraViewport.h <= 1.0f);
|
|
||||||
|
|
||||||
if (isNormalized) {
|
|
||||||
// Convert fraction -> pixels
|
|
||||||
cameraViewport.x *= drawsize.x;
|
|
||||||
cameraViewport.y *= drawsize.y;
|
|
||||||
cameraViewport.w *= drawsize.x;
|
|
||||||
cameraViewport.h *= drawsize.y;
|
|
||||||
} else {
|
|
||||||
// Clamp pixel coords to window bounds
|
|
||||||
if (cameraViewport.x < 0) cameraViewport.x = 0;
|
|
||||||
if (cameraViewport.y < 0) cameraViewport.y = 0;
|
|
||||||
if (cameraViewport.x + cameraViewport.w > drawsize.x) cameraViewport.w = drawsize.x - cameraViewport.x;
|
|
||||||
if (cameraViewport.y + cameraViewport.h > drawsize.y) cameraViewport.h = drawsize.y - cameraViewport.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the camera mode
|
|
||||||
JSValue jsmode = JS_GetPropertyStr(js, camera, "mode");
|
|
||||||
char *mode = JS_ToCString(js, jsmode);
|
|
||||||
JS_FreeValue(js, jsmode);
|
|
||||||
|
|
||||||
// finalVP: the actual region in which we'll render this camera
|
|
||||||
SDL_FRect finalVP = cameraViewport;
|
|
||||||
|
|
||||||
// Apply the mode to figure out how to place/scale 'size' in finalVP
|
|
||||||
// “stretch” = fill entire finalVP
|
|
||||||
// “fit” = scale down so entire size is visible, preserving aspect
|
|
||||||
// “cover” = fill the entire region, preserving aspect (crop if needed)
|
|
||||||
// “keep” (or unknown) = no scaling; just center the camera’s nominal size
|
|
||||||
if (!strcmp(mode, "stretch")) {
|
|
||||||
finalVP.w = cameraViewport.w;
|
|
||||||
finalVP.h = cameraViewport.h;
|
|
||||||
finalVP.x = cameraViewport.x;
|
|
||||||
finalVP.y = cameraViewport.y;
|
|
||||||
} else if (!strcmp(mode, "fit")) {
|
|
||||||
float scale = fminf(cameraViewport.w / size.x, cameraViewport.h / size.y);
|
|
||||||
finalVP.w = size.x * scale;
|
|
||||||
finalVP.h = size.y * scale;
|
|
||||||
finalVP.x = cameraViewport.x + (cameraViewport.w - finalVP.w) * 0.5f;
|
|
||||||
finalVP.y = cameraViewport.y + (cameraViewport.h - finalVP.h) * 0.5f;
|
|
||||||
} else if (!strcmp(mode, "cover")) {
|
|
||||||
float scale = fmaxf(cameraViewport.w / size.x, cameraViewport.h / size.y);
|
|
||||||
finalVP.w = size.x * scale;
|
|
||||||
finalVP.h = size.y * scale;
|
|
||||||
finalVP.x = cameraViewport.x + (cameraViewport.w - finalVP.w) * 0.5f;
|
|
||||||
finalVP.y = cameraViewport.y + (cameraViewport.h - finalVP.h) * 0.5f;
|
|
||||||
} else {
|
|
||||||
// "keep": do not scale
|
|
||||||
finalVP.w = size.x;
|
|
||||||
finalVP.h = size.y;
|
|
||||||
finalVP.x = cameraViewport.x + (cameraViewport.w - finalVP.w) * 0.5f;
|
|
||||||
finalVP.y = cameraViewport.y + (cameraViewport.h - finalVP.h) * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FreeCString(js, mode);
|
|
||||||
|
|
||||||
// Build an orthographic projection
|
|
||||||
// - If pass is defined, treat (0,0) as screen center.
|
|
||||||
// - Otherwise, treat (0,0) as bottom-left corner.
|
|
||||||
HMM_Mat4 proj;
|
HMM_Mat4 proj;
|
||||||
if (!JS_IsUndefined(argv[2])) {
|
if (ortho)
|
||||||
proj = HMM_Orthographic_RH_NO(
|
proj = HMM_Orthographic_RH_NO(
|
||||||
-finalVP.w * 0.5f, finalVP.w * 0.5f,
|
-size.x*0.5, 0.5*size.x,
|
||||||
-finalVP.h * 0.5f, finalVP.h * 0.5f,
|
-size.y*0.5, 0.5*size.y,
|
||||||
-1.0f, 1.0f
|
-1.0f, 1.0f
|
||||||
);
|
);
|
||||||
} else {
|
else
|
||||||
proj = HMM_Orthographic_RH_NO(
|
proj = HMM_Perspective_RH_NO(fov, aspect,near,far);
|
||||||
0.0f, finalVP.w,
|
|
||||||
0.0f, finalVP.h,
|
|
||||||
-1.0f, 1.0f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the view matrix (translate by -camera.pos)
|
// Build the view matrix (translate by -camera.pos)
|
||||||
HMM_Mat4 view = HMM_Translate((HMM_Vec3){ -transform->pos.x, -transform->pos.y, 0.0f });
|
HMM_Mat4 view;
|
||||||
|
if (ortho)
|
||||||
|
view = HMM_Translate((HMM_Vec3){ -transform->pos.x, -transform->pos.y, 0.0f });
|
||||||
|
else {
|
||||||
|
HMM_Mat4 camera_transform = HMM_Translate(transform->pos);
|
||||||
|
camera_transform = HMM_MulM4(camera_transform, HMM_QToM4(transform->rotation));
|
||||||
|
// camera_transform = HMM_MulM4(camera_transform, HMM_Scale(transform->scale)); // don't bother w/ scale
|
||||||
|
view = HMM_InvGeneralM4(camera_transform);
|
||||||
|
}
|
||||||
|
|
||||||
// Update your shader globals
|
// Update your shader globals
|
||||||
shader_globals data = {0};
|
shader_globals data = {0};
|
||||||
data.world_to_projection = HMM_MulM4(proj, view);
|
data.world_to_projection = HMM_MulM4(proj, view);
|
||||||
|
data.projection_to_world = HMM_InvGeneralM4(data.world_to_projection);
|
||||||
|
data.camera_pos_world = transform->pos;
|
||||||
|
data.viewport_min_z = near;
|
||||||
|
data.viewport_max_z = far;
|
||||||
|
data.render_size = size;
|
||||||
|
data.world_to_view = view;
|
||||||
|
data.view_to_projection = proj;
|
||||||
|
data.camera_dir_world = HMM_NormV3(HMM_QVRot((HMM_Vec3){0,0,-1},transform->rotation));
|
||||||
|
data.viewport_size = (HMM_Vec2){0.5,0.5};
|
||||||
|
data.viewport_offset = (HMM_Vec2){0,0};
|
||||||
data.time = SDL_GetTicksNS() / 1000000000.0f;
|
data.time = SDL_GetTicksNS() / 1000000000.0f;
|
||||||
|
|
||||||
// SDL_SetGPUViewport expects an SDL_GPUViewport (with float x,y,w,h and min/max depth)
|
SDL_PushGPUVertexUniformData(cmds, js2number(js,argv[1]), &data, sizeof(data));
|
||||||
// We'll fill that struct from finalVP, with default depth range [0..1].
|
|
||||||
SDL_GPUViewport sdlvp;
|
|
||||||
sdlvp.x = finalVP.x;
|
|
||||||
sdlvp.y = finalVP.y;
|
|
||||||
sdlvp.w = finalVP.w;
|
|
||||||
sdlvp.h = finalVP.h;
|
|
||||||
sdlvp.min_depth = 0.0f;
|
|
||||||
sdlvp.max_depth = 1.0f;
|
|
||||||
|
|
||||||
// Set the final viewport and push uniform data
|
|
||||||
// SDL_SetGPUViewport(pass, &sdlvp);
|
|
||||||
SDL_PushGPUVertexUniformData(cmds, js2number(js,argv[3]), &data, sizeof(data));
|
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_SCALL(cmd_push_debug_group,
|
JSC_SCALL(cmd_push_debug_group,
|
||||||
@@ -4774,7 +4726,8 @@ static const JSCFunctionListEntry js_SDL_GPUCommandBuffer_funcs[] = {
|
|||||||
MIST_FUNC_DEF(cmd, push_compute_uniform_data, 2),
|
MIST_FUNC_DEF(cmd, push_compute_uniform_data, 2),
|
||||||
MIST_FUNC_DEF(cmd, submit, 0),
|
MIST_FUNC_DEF(cmd, submit, 0),
|
||||||
MIST_FUNC_DEF(cmd, cancel, 0),
|
MIST_FUNC_DEF(cmd, cancel, 0),
|
||||||
MIST_FUNC_DEF(cmd, camera, 4),
|
MIST_FUNC_DEF(cmd, camera, 2),
|
||||||
|
MIST_FUNC_DEF(cmd, hud, 2),
|
||||||
MIST_FUNC_DEF(cmd, push_debug_group, 1),
|
MIST_FUNC_DEF(cmd, push_debug_group, 1),
|
||||||
MIST_FUNC_DEF(cmd, pop_debug_group, 0),
|
MIST_FUNC_DEF(cmd, pop_debug_group, 0),
|
||||||
MIST_FUNC_DEF(cmd, debug_label, 1),
|
MIST_FUNC_DEF(cmd, debug_label, 1),
|
||||||
|
|||||||
Reference in New Issue
Block a user