Added full clay border support to draw #28
+39
-27
@@ -1,54 +1,71 @@
|
|||||||
package draw_qr
|
package draw_qr
|
||||||
|
|
||||||
|
import "core:mem"
|
||||||
|
import "core:slice"
|
||||||
|
|
||||||
import draw ".."
|
import draw ".."
|
||||||
import "../../qrcode"
|
import "../../qrcode"
|
||||||
|
|
||||||
DFT_QR_DARK :: draw.BLACK // Default QR code dark module color.
|
DFT_QR_DARK :: draw.BLACK // Default QR code dark module color.
|
||||||
DFT_QR_LIGHT :: draw.WHITE // Default QR code light module color.
|
DFT_QR_LIGHT :: draw.WHITE // Default QR code light module color.
|
||||||
DFT_QR_BOOST_ECL :: true // Default QR error correction level boost.
|
DFT_QR_BOOST_ECL :: true // Default QR error correction level boost.
|
||||||
|
DFT_QR_QUIET_ZONE :: 4 // Default light-pixel border on each side; 4 is the QR spec value.
|
||||||
|
|
||||||
// Returns the number of bytes to_texture will write for the given encoded
|
// Returns the number of bytes to_texture will write. Equals dim*dim*4 where
|
||||||
// QR buffer. Equivalent to size*size*4 where size = qrcode.get_size(qrcode_buf).
|
// dim = qrcode.get_size(qrcode_buf) + 2*quiet_zone.
|
||||||
texture_size :: #force_inline proc(qrcode_buf: []u8) -> int {
|
texture_size :: #force_inline proc(qrcode_buf: []u8, quiet_zone: int = DFT_QR_QUIET_ZONE) -> int {
|
||||||
size := qrcode.get_size(qrcode_buf)
|
size := qrcode.get_size(qrcode_buf)
|
||||||
return size * size * 4
|
if size == 0 || quiet_zone < 0 do return 0
|
||||||
|
padded_size := size + 2 * quiet_zone
|
||||||
|
return padded_size * padded_size * 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decodes an encoded QR buffer into tightly-packed RGBA pixel data written to
|
// Decodes an encoded QR buffer into tightly-packed RGBA pixel data written to
|
||||||
// texture_buf. No allocations, no GPU calls. Returns the Texture_Desc the
|
// texture_buf. No allocations, no GPU calls. Returns the Texture_Desc the
|
||||||
// caller should pass to draw.register_texture alongside texture_buf.
|
// caller should pass to draw.register_texture alongside texture_buf.
|
||||||
//
|
//
|
||||||
|
// quiet_zone adds that many `light` pixels on each side; the spec value is 4.
|
||||||
|
// Final dimension is qrcode.get_size + 2*quiet_zone on each axis.
|
||||||
|
//
|
||||||
// Returns ok=false when:
|
// Returns ok=false when:
|
||||||
// - qrcode_buf is invalid (qrcode.get_size returns 0).
|
// - qrcode_buf is invalid (qrcode.get_size returns 0).
|
||||||
// - texture_buf is smaller than texture_size(qrcode_buf).
|
// - quiet_zone is negative.
|
||||||
|
// - texture_buf is smaller than texture_size(qrcode_buf, quiet_zone).
|
||||||
@(require_results)
|
@(require_results)
|
||||||
to_texture :: proc(
|
to_texture :: proc(
|
||||||
qrcode_buf: []u8,
|
qrcode_buf: []u8,
|
||||||
texture_buf: []u8,
|
texture_buf: []u8,
|
||||||
dark: draw.Color = DFT_QR_DARK,
|
dark: draw.Color = DFT_QR_DARK,
|
||||||
light: draw.Color = DFT_QR_LIGHT,
|
light: draw.Color = DFT_QR_LIGHT,
|
||||||
|
quiet_zone: int = DFT_QR_QUIET_ZONE,
|
||||||
) -> (
|
) -> (
|
||||||
desc: draw.Texture_Desc,
|
desc: draw.Texture_Desc,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
) {
|
) {
|
||||||
size := qrcode.get_size(qrcode_buf)
|
size := qrcode.get_size(qrcode_buf)
|
||||||
if size == 0 do return {}, false
|
if size == 0 || quiet_zone < 0 do return
|
||||||
if len(texture_buf) < size * size * 4 do return {}, false
|
padded_size := size + 2 * quiet_zone
|
||||||
|
if len(texture_buf) < padded_size * padded_size * 4 do return
|
||||||
|
|
||||||
|
// Type-pun to []Color so each store is a single 32-bit write.
|
||||||
|
pixels := mem.slice_data_cast([]draw.Color, texture_buf[:padded_size * padded_size * 4])
|
||||||
|
|
||||||
|
// Bulk-fill with light: handles the border and every light QR module at once.
|
||||||
|
slice.fill(pixels, light)
|
||||||
|
|
||||||
|
// Overwrite only the dark modules, offset by the quiet-zone border.
|
||||||
for y in 0 ..< size {
|
for y in 0 ..< size {
|
||||||
|
row := (y + quiet_zone) * padded_size + quiet_zone
|
||||||
for x in 0 ..< size {
|
for x in 0 ..< size {
|
||||||
i := (y * size + x) * 4
|
if qrcode.get_module(qrcode_buf, x, y) {
|
||||||
c := dark if qrcode.get_module(qrcode_buf, x, y) else light
|
pixels[row + x] = dark
|
||||||
texture_buf[i + 0] = c[0]
|
}
|
||||||
texture_buf[i + 1] = c[1]
|
|
||||||
texture_buf[i + 2] = c[2]
|
|
||||||
texture_buf[i + 3] = c[3]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return draw.Texture_Desc {
|
return draw.Texture_Desc {
|
||||||
width = u32(size),
|
width = u32(padded_size),
|
||||||
height = u32(size),
|
height = u32(padded_size),
|
||||||
depth_or_layers = 1,
|
depth_or_layers = 1,
|
||||||
type = .D2,
|
type = .D2,
|
||||||
format = .R8G8B8A8_UNORM,
|
format = .R8G8B8A8_UNORM,
|
||||||
@@ -71,19 +88,20 @@ register_texture_from_raw :: proc(
|
|||||||
qrcode_buf: []u8,
|
qrcode_buf: []u8,
|
||||||
dark: draw.Color = DFT_QR_DARK,
|
dark: draw.Color = DFT_QR_DARK,
|
||||||
light: draw.Color = DFT_QR_LIGHT,
|
light: draw.Color = DFT_QR_LIGHT,
|
||||||
|
quiet_zone: int = DFT_QR_QUIET_ZONE,
|
||||||
temp_allocator := context.temp_allocator,
|
temp_allocator := context.temp_allocator,
|
||||||
) -> (
|
) -> (
|
||||||
texture: draw.Texture_Id,
|
texture: draw.Texture_Id,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
) {
|
) {
|
||||||
tex_size := texture_size(qrcode_buf)
|
tex_size := texture_size(qrcode_buf, quiet_zone)
|
||||||
if tex_size == 0 do return draw.INVALID_TEXTURE, false
|
if tex_size == 0 do return draw.INVALID_TEXTURE, false
|
||||||
|
|
||||||
pixels, alloc_err := make([]u8, tex_size, temp_allocator)
|
pixels, alloc_err := make([]u8, tex_size, temp_allocator)
|
||||||
if alloc_err != nil do return draw.INVALID_TEXTURE, false
|
if alloc_err != nil do return draw.INVALID_TEXTURE, false
|
||||||
defer delete(pixels, temp_allocator)
|
defer delete(pixels, temp_allocator)
|
||||||
|
|
||||||
desc := to_texture(qrcode_buf, pixels, dark, light) or_return
|
desc := to_texture(qrcode_buf, pixels, dark, light, quiet_zone) or_return
|
||||||
return draw.register_texture(desc, pixels)
|
return draw.register_texture(desc, pixels)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +121,7 @@ register_texture_from_text :: proc(
|
|||||||
boost_ecl: bool = DFT_QR_BOOST_ECL,
|
boost_ecl: bool = DFT_QR_BOOST_ECL,
|
||||||
dark: draw.Color = DFT_QR_DARK,
|
dark: draw.Color = DFT_QR_DARK,
|
||||||
light: draw.Color = DFT_QR_LIGHT,
|
light: draw.Color = DFT_QR_LIGHT,
|
||||||
|
quiet_zone: int = DFT_QR_QUIET_ZONE,
|
||||||
temp_allocator := context.temp_allocator,
|
temp_allocator := context.temp_allocator,
|
||||||
) -> (
|
) -> (
|
||||||
texture: draw.Texture_Id,
|
texture: draw.Texture_Id,
|
||||||
@@ -123,7 +142,7 @@ register_texture_from_text :: proc(
|
|||||||
temp_allocator,
|
temp_allocator,
|
||||||
) or_return
|
) or_return
|
||||||
|
|
||||||
return register_texture_from_raw(qrcode_buf, dark, light, temp_allocator)
|
return register_texture_from_raw(qrcode_buf, dark, light, quiet_zone, temp_allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encodes arbitrary binary data as a QR Code and registers the result as an RGBA texture.
|
// Encodes arbitrary binary data as a QR Code and registers the result as an RGBA texture.
|
||||||
@@ -142,6 +161,7 @@ register_texture_from_binary :: proc(
|
|||||||
boost_ecl: bool = DFT_QR_BOOST_ECL,
|
boost_ecl: bool = DFT_QR_BOOST_ECL,
|
||||||
dark: draw.Color = DFT_QR_DARK,
|
dark: draw.Color = DFT_QR_DARK,
|
||||||
light: draw.Color = DFT_QR_LIGHT,
|
light: draw.Color = DFT_QR_LIGHT,
|
||||||
|
quiet_zone: int = DFT_QR_QUIET_ZONE,
|
||||||
temp_allocator := context.temp_allocator,
|
temp_allocator := context.temp_allocator,
|
||||||
) -> (
|
) -> (
|
||||||
texture: draw.Texture_Id,
|
texture: draw.Texture_Id,
|
||||||
@@ -162,18 +182,10 @@ register_texture_from_binary :: proc(
|
|||||||
temp_allocator,
|
temp_allocator,
|
||||||
) or_return
|
) or_return
|
||||||
|
|
||||||
return register_texture_from_raw(qrcode_buf, dark, light, temp_allocator)
|
return register_texture_from_raw(qrcode_buf, dark, light, quiet_zone, temp_allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
register_texture_from :: proc {
|
register_texture_from :: proc {
|
||||||
register_texture_from_text,
|
register_texture_from_text,
|
||||||
register_texture_from_binary,
|
register_texture_from_binary,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default fit=.Fit preserves the QR's square aspect; override as needed.
|
|
||||||
clay_image :: #force_inline proc(
|
|
||||||
texture: draw.Texture_Id,
|
|
||||||
tint: draw.Color = draw.DFT_TINT,
|
|
||||||
) -> draw.Clay_Image_Data {
|
|
||||||
return draw.clay_image_data(texture, fit = .Fit, tint = tint)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user