Skip to content

o-murphy/bcrg

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

46 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

BCRG - Ballistic reticle generator

Simple tool to generate dynamic ballistics reticles by .lua templates

Π£ΠΊΡ€Π°Ρ—Π½ΡΡŒΠΊΠΎΡŽ


Installation πŸš€

Install the BCRG ballistic reticle generator using pip (the standard method) or the newer uv tool (recommended for speed and efficiency).

Using uv (Recommended)

If you have the uv tool installed, you can manage the package directly:

Installation:

uv tool install bcrg

Upgrade:

uv tool upgrade bcrg

Using pip (Standard Method)

If you are using the standard Python package manager:

Installation:

pip install bcrg

Upgrade:

pip install --upgrade bcrg

Usage

As CLI tool (Via Command Line)

Use bcrg or python -m bcrg to generate reticle images (BMP) from Lua templates:

usage: bcr [-h] [-o OUTPUT] [-f] [-W <int>] [-H <int>] [-cx <float>] [-cy <float>] [-z [<int> ...]] [-T | -Z] file

positional arguments:
  file                  Reticle template file in .lua format

options:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output directory path, defaults to ./
  -f, --force           Force overwrite existing files without prompt
  -W <int>, --width <int>
                        Canvas width (px)
  -H <int>, --height <int>
                        Canvas height (px)
  -cx <float>, --click-x <float>
                        Horizontal click size (cm/100m)
  -cy <float>, --click-y <float>
                        Vertical click size (cm/100m)
  -z [<int> ...], --zoom [<int> ...]
                        Zoom value (int)
  -V, --version         show program\'s version number and exit
  
archiving options:
  -T, --tar             Store as .tar.gz (overrides --zip)
  -Z, --zip             Store as .zip

As Imported module

You can integrate the generator directly into your Python code:

from bcrg import LuaReticleLoader
loader = LuaReticleLoader('my_reticle_template.lua')

# Create 1bit-depth .bmp bytearray
# Parameters: width, height, click_x, click_y, zoom, adjustment
byte_stream = loader.make_bmp(640, 480, 2.27, 2.27, 4, None)
with open("myreticle.bmp", 'wb') as f:
    f.write(byte_stream)

References

  • A reticle template has to implement make_reticle function, that gets required arguments and has to return self:to_bmp or self:to_bmp_1bit.
  • Examples in ./templates dir.

πŸ“ Reticle Template API (Lua)

This section details how to create Lua templates using the ReticleDraw library, which extends FrameBuffer.

πŸ› οΈ Reticle File Structure and make_reticle

Every reticle file must declare a dependency on reticledraw

-- Load the framebuffer module
require("reticledraw") -- πŸ‘ˆ THIS LINE IS CRUCIAL!

Every reticle file must contain a single make_reticle function.

function make_reticle(width, height, click_x, click_y, zoom, adjustment)
    -- ... Your drawing code ...
end
Parameter Type Description
width number Framebuffer (display) width in pixels.
height number Framebuffer (display) height in pixels.
click_x number Click Value (Correction Value) on the X-axis (e.g., MILs/MOAs per pixel at minimum zoom).
click_y number Click Value (Correction Value) on the Y-axis.
zoom number Current scope magnification (zoom value).
adjustment table Optional additional reticle parameters/settings.

πŸš€ General Code Template and Scaling Logic (With Examples)

The core logic converts reticle units (MILs/MOAs) into screen pixels using the scaling coefficients ax and ay.

require("reticledraw")

local BLACK = 0
local WHITE = 1

-- Rounding function (ensures the pixel value is an integer)
local function round(v)
    if v < 0 then
        return math.ceil(v)
    elseif v > 0 then
        return math.floor(v)
    else
        return 0
    end
end

function make_reticle(width, height, click_x, click_y, zoom, adjustment)
    -- 1. Calculate scaling coefficients (AX, AY)
    -- AX/AY: how many reticle units correspond to 1 pixel on the screen at the current ZOOM.
    local ax = click_x / zoom
    local ay = click_y / zoom

    -- 2. Helper functions: convert reticle units (v) to pixels
    local function _x(v)
        return round(v / ax)
    end
    local function _y(v)
        return round(v / ay)
    end

    local fb = make_canvas(width, height, 1)
    fb:fill(WHITE)

    -- 3. Examples of drawing reticle elements:

    -- Center dot (3x3 pixels)
    fb:c_fill_rect(0, 0, 3, 3, BLACK) 

    -- Main horizontal line (from -100 to +100 units)
    fb:c_line(_x(-100), 0, _x(100), 0, BLACK) 
    
    -- Dynamic markers: drawing lines every 10 units
    local marker_length = 5 -- marker length in pixels
    local marker_step = 10  -- step in reticle units (MILs/MOAs)
    
    for i = marker_step, 50, marker_step do
        -- Line up
        fb:c_vline(_x(0), _y(i), marker_length, BLACK) 
        -- Line down
        fb:c_vline(_x(0), _y(-i), marker_length, BLACK) 
        
        -- Numerical markers (using 6x6 font)
        fb:c_text6(tostring(i), _x(5), _y(i), BLACK)
    end

    -- Dynamic detail adaptation
    -- If zoom is high (ax < 0.5), draw additional markers every 5 units
    if ax < 0.5 then
        for i = 5, 50, 5 do
            -- Small pixel dot at 5 units to the right
            fb:c_pixel(_x(i), _y(-5), BLACK) 
        end
    end
    
    return fb 
end

🎨 ReticleDraw Methods (Centered Coordinates)

These methods automatically draw relative to the display center (0,0). Always use _x() and _y() for all coordinates measured in reticle units.

Method Description Example
fb:c_pixel(x, y, color) Draws a single pixel. fb:c_pixel(_x(10), _y(10), BLACK)
fb:c_line(x0, y0, x1, y1, color) Draws a line. fb:c_line(0, 0, _x(50), 0, BLACK)
fb:c_hline(x, y, width, color) Draws a horizontal line. fb:c_hline(_x(-50), _y(20), _x(100), BLACK)
fb:c_vline(x, y, height, color) Draws a vertical line. fb:c_vline(_x(30), _y(-50), _y(100), BLACK)
fb:c_rect(x, y, w, h, color) Draws a rectangle outline (center x, y). fb:c_rect(_x(10), _y(10), 20, 20, BLACK)
fb:c_fill_rect(x, y, w, h, color) Draws a filled rectangle. fb:c_fill_rect(0, 0, 3, 3, BLACK)
fb:c_circle(x, y, r, color) Draws a circle outline. r is the radius in pixels. fb:c_circle(0, _y(30), 5, BLACK)
fb:c_fill_circle(x, y, r, color) Draws a filled circle. fb:c_fill_circle(0, 0, 2, BLACK)
fb:c_text6(s, x, y, color) Draws text using the 6x6 pixel font. fb:c_text6("10", _x(10), _y(-10), BLACK)
fb:c_arc(x, y, rx, ry, start_angle, end_angle, color) Draws an arc from start_angle to end_angle (degrees, 0Β° = 12 o'clock). fb:c_arc(0, 0, 20, 20, 0, 90, BLACK)

πŸ“ Inherited FrameBuffer Methods (Absolute Coordinates)

These methods require absolute pixel coordinates (0,0 is the top-left corner).

Method Coordinate Requirement Description
fb:pixel(x, y, color) Absolute Sets the color of a pixel.
fb:fill(color) Absolute Fills the entire buffer.
fb:fill_rect(x, y, w, h, c) Absolute Fills a rectangle.
fb:rect(x, y, w, h, c) Absolute Draws a rectangle outline.
fb:line(x0, y0, x1, y1, color) Absolute Draws an arbitrary line.
fb:hline(x, y, w, color) Absolute Draws a horizontal line.
fb:vline(x, y, h, color) Absolute Draws a vertical line.
fb:circle(x, y, r, color) Absolute Draws a circle outline.
fb:fill_circle(x, y, r, color) Absolute Draws a filled circle.
fb:ellipse(x, y, rx, ry, color) Absolute Draws an ellipse outline.
fb:polygon(points, color) Absolute Draws a filled polygon.
fb:text(s, x0, y0, col) Absolute Draws text using the standard 8x8 pixel font.
fb:arc(cx, cy, rx, ry, start_angle, end_angle, color) Absolute Draws an arc. Angles in degrees, 0Β° = 12 o'clock.

About

Simple lua-based engine to generate dynamic ballistics reticles

Topics

Resources

License

Stars

Watchers

Forks

Contributors