Skip to content

Commit

Permalink
added labels constants and new functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Acepie committed Jul 28, 2024
1 parent 229d942 commit 6045c97
Show file tree
Hide file tree
Showing 5 changed files with 384 additions and 129 deletions.
3 changes: 2 additions & 1 deletion examples/minimal/src/minimal.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ fn setup(p: P5) -> String {
}

fn draw(p: P5, state: String) {
p5.background(p, "#ffffff")
p5.background(p, "#888888")
p5.fill(p, "#000000")
p5.text_align(p, p5.center, p5.center)
p5.text(p, state, 400.0, 300.0)
}

Expand Down
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "p5js_gleam"
version = "2.1.2"
version = "3.0.0"
target = "javascript"

description = "A simple game library providing p5.js bindings for Gleam in a functional style to make basic games and animations. Heavily inspired by the Racket library 2htdp/universe"
Expand Down
298 changes: 248 additions & 50 deletions scripts/generate_p5.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,281 @@
interface Binding {
arguments: string[];
interface Argument {
label: string;
type: string;
}

function argumentToString(argument: Argument) {
return `${argument.label} ${argument.label}: ${argument.type}`;
}

interface FunctionBinding {
arguments: Argument[];
returnType?: string; // defaults to P5
bindingName?: string; // if not provided, the name of the function will be used
}

const elements: Record<string, Binding> = {
createCanvas: { arguments: ["width: Float", "height: Float"] },
const functions: Record<string, FunctionBinding> = {
createCanvas: {
arguments: [
{
label: "width",
type: "Float",
},
{
label: "height",
type: "Float",
},
],
},
text: {
arguments: [
"text: String",
"bottom_corner_x: Float",
"bottom_corner_y: Float",
{
label: "text",
type: "String",
},
{
label: "bottom_corner_x",
type: "Float",
},
{
label: "bottom_corner_y",
type: "Float",
},
],
},
textAlign: {
arguments: [
{
label: "horizontal",
type: "String",
},
{
label: "vertical",
type: "String",
},
],
},
textFont: {
arguments: [
{
label: "font",
type: "P5Font",
},
],
},
textFontFromString: {
arguments: [
{
label: "font",
type: "String",
},
],
bindingName: "textFont",
},
textSize: {
arguments: [
{
label: "size",
type: "Int",
},
],
},
textWidth: {
arguments: [
{
label: "text",
type: "String",
},
],
returnType: "Float",
},
background: {
arguments: [
{
label: "color",
type: "String",
},
],
},
textFont: { arguments: ["font: P5Font"] },
textFontFromString: { arguments: ["font: String"], bindingName: "textFont" },
textSize: { arguments: ["size: Int"] },
textWidth: { arguments: ["text: String"], returnType: "Float" },
background: { arguments: ["color: String"] },
ellipse: {
arguments: [
"x_center: Float",
"y_center: Float",
"width: Float",
"height: Float",
{
label: "x_center",
type: "Float",
},
{
label: "y_center",
type: "Float",
},
{
label: "width",
type: "Float",
},
{
label: "height",
type: "Float",
},
],
},
circle: {
arguments: ["x_center: Float", "y_center: Float", "diameter: Float"],
arguments: [
{
label: "x_center",
type: "Float",
},
{
label: "y_center",
type: "Float",
},
{
label: "diameter",
type: "Float",
},
],
},
rect: {
arguments: [
"top_left_x: Float",
"top_left_y: Float",
"width: Float",
"height: Float",
{
label: "top_left_x",
type: "Float",
},
{
label: "top_left_y",
type: "Float",
},
{
label: "width",
type: "Float",
},
{
label: "height",
type: "Float",
},
],
},
triangle: {
arguments: [
{
label: "point1_x",
type: "Float",
},
{
label: "point1_y",
type: "Float",
},
{
label: "point2_x",
type: "Float",
},
{
label: "point2_y",
type: "Float",
},
{
label: "point3_x",
type: "Float",
},
{
label: "point3_y",
type: "Float",
},
],
},
square: {
arguments: ["top_left_x: Float", "top_left_y: Float", "side_length: Float"],
arguments: [
{
label: "top_left_x",
type: "Float",
},
{
label: "top_left_y",
type: "Float",
},
{
label: "side_length",
type: "Float",
},
],
},
line: {
arguments: [
"point1_x: Float",
"point1_y: Float",
"point2_x: Float",
"point2_y: Float",
{
label: "point1_x",
type: "Float",
},
{
label: "point1_y",
type: "Float",
},
{
label: "point2_x",
type: "Float",
},
{
label: "point2_y",
type: "Float",
},
],
},
quad: {
arguments: [
"p1_x: Float",
"p1_y: Float",
"p2_x: Float",
"p2_y: Float",
"p3_x: Float",
"p3_y: Float",
"p4_x: Float",
"p4_y: Float",
{ label: "point1_x", type: "Float" },
{ label: "point1_y", type: "Float" },
{ label: "point2_x", type: "Float" },
{ label: "point2_y", type: "Float" },
{ label: "point3_x", type: "Float" },
{ label: "point3_y", type: "Float" },
{ label: "point4_x", type: "Float" },
{ label: "point4_y", type: "Float" },
],
},
image: {
arguments: [
"image: P5Image",
"top_left_x: Float",
"top_left_y: Float",
"width: Float",
"height: Float",
{ label: "image", type: "P5Image" },
{ label: "top_left_x", type: "Float" },
{ label: "top_left_y", type: "Float" },
{ label: "width", type: "Float" },
{ label: "height", type: "Float" },
],
},
fill: { arguments: ["color_hex: String"] },
fill: { arguments: [{ label: "color_hex", type: "String" }] },
noFill: { arguments: [] },
stroke: { arguments: ["color_hex: String"] },
stroke: { arguments: [{ label: "color_hex", type: "String" }] },
noStroke: { arguments: [] },
strokeWeight: { arguments: ["weight: Int"] },
erase: { arguments: ["strength: Int", "edge_strength: Int"] },
strokeWeight: { arguments: [{ label: "weight", type: "Int" }] },
erase: {
arguments: [
{ label: "strength", type: "Int" },
{ label: "edge_strength", type: "Int" },
],
},
noErase: { arguments: [] },
loadImage: {
arguments: ["path: String"],
arguments: [{ label: "path", type: "String" }],
returnType: "P5Image",
},
loadFont: {
arguments: ["path: String"],
arguments: [{ label: "path", type: "String" }],
returnType: "P5Font",
},
};

interface ConstantBinding {
value?: any; // if not provided, the name of the constant will be used
type?: string; // defaults to string
bindingName?: string; // if not provided, the name of the constant will be used
}

const constants: Record<string, ConstantBinding> = {
right: {},
left: {},
center: {},
top: {},
bottom: {},
baseline: {
value: "alphabetic",
},
};

const camelToSnakeCase = (str: string) =>
str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);

Expand All @@ -105,16 +295,18 @@ const js = (name: string, bindingName: string, isReturningOriginal: boolean) =>
`;

const gleam = (name: string, binding: Binding) =>
const gleam = (name: string, binding: FunctionBinding) =>
`/// A binding to the p5.js [\`${
binding.bindingName ?? name
}\`](https://p5js.org/reference/#/p5/${
}\`](https://p5js.org/reference/p5/${
binding.bindingName ?? name
}) function. Takes a p5 instance and the function's arguments and returns the p5 instance.
@external(javascript, "../p5js_ffi.mjs", "${name}")
pub fn ${camelToSnakeCase(name)}(p: P5${
pub fn ${camelToSnakeCase(name)}(sketch_instance p: P5${
binding.arguments.length ? ", " : ""
}${binding.arguments.join(", ")}) -> ${binding.returnType ?? "P5"}
}${binding.arguments.map((a) => argumentToString(a)).join(", ")}) -> ${
binding.returnType ?? "P5"
}
`;

Expand Down Expand Up @@ -177,7 +369,7 @@ export const startSketch = (config) => {
`;

for (const [elementName, elementBinding] of Object.entries(elements)) {
for (const [elementName, elementBinding] of Object.entries(functions)) {
outGleam += gleam(elementName, elementBinding);
outJs += js(
elementName,
Expand All @@ -186,6 +378,12 @@ for (const [elementName, elementBinding] of Object.entries(elements)) {
);
}

for (const [constantName, constantBinding] of Object.entries(constants)) {
outGleam += `pub const ${constantBinding.bindingName ?? constantName} = "${
constantBinding.value ?? constantName
}"\n\n`;
}

await Promise.all([
Bun.write("src/p5js_gleam/bindings.gleam", outGleam),
Bun.write("src/p5js_ffi.mjs", outJs),
Expand Down
Loading

0 comments on commit 6045c97

Please sign in to comment.