# paint

An alternative method of creating visuals & graphics on higher level access.
Instead of using in-game drawing systems, this uses an external version on a separated thread.


# Optimizing

When you perform drawing objects, its good practice to localize & reuse data.
Try to minimize object creation if you can, paint.point.* may be harder to localize.
This is due to the idea of dynamically changing vectors, which can be a problem but do-able.

paint.add("example", function(w, h)
    -- don't do this, you are creating a new object every time
    local color = paint.color.rgba(255, 255, 255, 255)
end)

-- instead do this
local white = paint.color.rgba(255, 255, 255, 255)
paint.add("example", function(w, h)
    -- access white here, its now an upvalue
end)

-- if you need to change it at runtime
local dynamic = paint.color.rgba(255, 255, 255, 255)
paint.add("example", function(w, h)
    dynamic.r = (os.clock() % 1) * 255
    -- in here we are just changing the color object's "R" stat
end)

# Interstate

Paint works everywhere no matter where you call it.
An example of this is by using linker's ability to attach to certain events.
This allows you to have a unique way of inline calls for accurate points.

linker.hook.add("Think", "paint!", function()
    -- perform paint operations here as well
end)

# Types

Paint uses two different vector types.
Both types are recognized by their index characteristics.
Which means using internal game-software mechanics like "Vector", would also work.

# paint.point.vector2(x: number, y: number): paint_point

paint.point.vector2(x: number, y: number): paint_point
  • Creates a 2D vector for paint to recognize

# paint.point.vector3(x: number, y: number, z: number): paint_point

paint.point.vector3(x: number, y: number, z: number): paint_point
  • Creates a 3D vector for paint to recognize

Paint also uses its own color system due to the fact of interop with other frameworks.

# paint.color.rgb(r: number, g: number, b: number): paint_color

paint.color.rgb(r: number, g: number, b: number): paint_color
  • Creates an RGB based color

# paint.color.rgba(r: number, g: number, b: number, a?: number): paint_color

paint.color.rgba(r: number, g: number, b: number, a?: number): paint_color
  • Creates an RGBA based color

# paint.color.hex(hex: string): paint_color

paint.color.hex(hex: string): paint_color
  • Creates an RGBA based color from hex strings
  • Accepts format #RRGGBBAA or #RRGGBB

# paint.color.hsv(h: number, s: number, v: number, a?: number): paint_color

paint.color.hsv(h: number, s: number, v: number, a?: number): paint_color
  • Creates an RGBA based color from HSV

# paint.color.hsl(h: number, s: number, l: number, a?: number): paint_color

paint.color.hsl(h: number, s: number, l: number, a?: number): paint_color
  • Creates an RGBA based color from HSL

# Functions

# paint.line(p1: paint_point, p2: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.line(p1: paint_point, p2: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a line between points A and B

# paint.circle.filled(center: paint_point, color: paint_color, radius: number, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.circle.filled(center: paint_point, color: paint_color, radius: number, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a circle around a center point that is filled

# paint.circle.hollow(center: paint_point, color: paint_color, radius: number, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.circle.hollow(center: paint_point, color: paint_color, radius: number, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a circle around a center point that is hollow

# paint.tri.filled(p1: paint_point, p2: paint_point, p3: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.tri.filled(p1: paint_point, p2: paint_point, p3: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a triangle from three points that is filled

# paint.tri.hollow(p1: paint_point, p2: paint_point, p3: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.tri.hollow(p1: paint_point, p2: paint_point, p3: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a triangle from three points that is hollow

# paint.rect.filled(top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.rect.filled(top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle that is filled

# paint.rect.hollow(top_left: paint_point, size: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.rect.hollow(top_left: paint_point, size: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle that is hollow

# paint.rect.rfilled(rounding: number, top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.rect.rfilled(rounding: number, top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle that is filled with rounding

# paint.rect.rhollow(rounding: number, top_left: paint_point, size: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.rect.rhollow(rounding: number, top_left: paint_point, size: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle that is hollow with rounding

# paint.rect.gradient(top_left: paint_point, size: paint_point, up_left: paint_color, up_right: paint_color, bottom_left: color_paint, bottom_right: color_paint, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.rect.gradient(top_left: paint_point, size: paint_point, up_left: paint_color, up_right: paint_color, bottom_left: color_paint, bottom_right: color_paint, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle using a gradient of colors

# paint.qrot.filled(center: paint_point, size: paint_point, color: paint_color, rotation: number, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.qrot.filled(center: paint_point, size: paint_point, color: paint_color, rotation: number, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle that is filled with rotation in degrees
  • These rectangles are centered

# paint.qrot.hollow(center: paint_point, size: paint_point, color: paint_color, rotation: number, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.qrot.hollow(center: paint_point, size: paint_point, color: paint_color, rotation: number, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a rectangle that is hollow with rotation in degrees
  • These rectangles are centered

# paint.quad.filled(p1: paint_point, p2: paint_point, p3: paint_point, p4: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.quad.filled(p1: paint_point, p2: paint_point, p3: paint_point, p4: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a quadrilateral that is filled

# paint.quad.hollow(p1: paint_point, p2: paint_point, p3: paint_point, p4: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.quad.hollow(p1: paint_point, p2: paint_point, p3: paint_point, p4: paint_point, color: paint_color, thickness?: number = 1, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates a quadrilateral that is hollow

# paint.text.left(point: paint_point, text: string, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.text.left(point: paint_point, text: string, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates text thats aligned to the left

# paint.text.center(point: paint_point, text: string, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.text.center(point: paint_point, text: string, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates text thats aligned to the center

# paint.text.right(point: paint_point, text: string, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)

paint.text.right(point: paint_point, text: string, color: paint_color, outline?: paint_color = {0, 0, 0, 255}, outline_thickness?: number = 0)
  • Creates text thats aligned to the right

# paint.text.bake(font_name: string, font_data: string, size: number): boolean

paint.text.bake(font_name: string, font_data: string, size: number): boolean
  • Bakes a font into memory, so that you can use it
  • Fonts already created under a name will simply return true as existing
local proggy_data = fs.read("proggy_clean.ttf")
if not paint.text.bake("Proggy", proggy_data, 14) then
    error("Couldn't load proggy font!")
end

local point = paint.point.vector2(40, 40)
local white = paint.color.rgb(255, 255, 255)
paint.add("example", function(w, h)
    paint.text.font("Proggy")
    paint.text.left(point, "hello world", white)
end)

# paint.text.unbake(font_name: string): boolean

paint.text.unbake(font_name: string): boolean
  • De-allocates a font from memory, effectively unloading it

# paint.text.isbaked(font_name: string): boolean

paint.text.isbaked(font_name: string): boolean
  • Check if a font has been added

# paint.text.font(font_name?: string): string

paint.text.font(font_name?: string): string
  • Makes all future text renderers use a specific font
  • Returns the current font being used currently

# paint.image.bake(data: string): image | false

paint.image.bake(data: string): image | false
  • Bakes an image into memory, so that you can use it
  • Images are managed by reference, so if its no longer used in lua, it will eventually de-allocate
local data = fs.read("sample.jpg")
local image = paint.image.bake(data)
if not image then
    error("Couldn't load image!")
end

local point = paint.point.vector2(50, 50)
local size = paint.point.vector2(128, 128)
local white = paint.color.rgb(255, 255, 255)
paint.add("example", function(w, h)
    paint.image.normal(image, point, size, white)
end)

# paint.image.normal(image: image, top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255})

paint.image.normal(image: image, top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255})
  • Creates a rectangle image

# paint.image.round(image: image, rounding: number, top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255})

paint.image.round(image: image, rounding: number, top_left: paint_point, size: paint_point, color: paint_color, outline?: paint_color = {0, 0, 0, 255})
  • Creates a rectangle image with rounding

# Events

Paint uses a slightly different type of Signal
You don't have to provide a name, instead its just an identifier.

-- instead of:
paint.listener.add("paint", "identity", function(w, h) end)
-- its:
paint.add("identity", function(w, h) end)

This is to make it simpler since paint really only has one event handler.