luv

Workshop wiki

block-icon.lisp

mcclim/block-icon.lisp

system luvcraft/mcclim · 12 definitions · on GitHub

Isometric block icons.

A material shown to the player as a flat swatch is a colour; shown as a cube it is the thing they are about to place. These are the same procedural tiles the block atlas generates for the world, projected onto the three faces of a 2:1 dimetric cube and lit the way the world lights them -- top full, left in half shadow, right darker still.

Each icon is rasterized once into an rgba array and kept as a CLIM pattern, so drawing one is a single image command rather than seven hundred little parallelograms. That is what makes it affordable to put the same icon in the hotbar, the inventory grid, the quickbar, and the item inspector.

in-package#:mcluv
defconstant+block-icon-tile-size+16

The atlas's tile edge, in texels. It is 16 for the same reason Minecraft's is: it is enough to read a material and few enough to author by hand.

defparameter*block-icon-face-shades*'
:top1.0:left0.74:right0.55

How much of the light each visible face gets. The ratios matter more than the numbers: equal faces read as a hexagon rather than as a cube.

defunblock-icon-atlas

The shared block atlas, built on first use.

Generating it walks every tile of every material, which is far too much to do per frame and trivial to do once. clear-block-icon-cache drops it, which is how a redefined paint-block-atlas-tile method reaches the icons.

defvar*block-icon-cache*
make-hash-table:test#'equal
defunclear-block-icon-cache

Forget every rasterized icon and the atlas behind them.

values
defunblock-icon-face-tile
blockface

The atlas tile block shows on face, falling back the way the world does.

let
tiles
luvcraft:block-kind-face-tilesblock
ecaseface
:top
or
getftiles:top
getftiles:all
getftiles:side
:left:right
or
getftiles:side
getftiles:all
getftiles:top
defunshaded-icon-word
wordshade

Pack an atlas word into a CLIM pattern word at shade.

The atlas keeps red in the low byte; a pattern wants it in the third, which is the same turn-around the video path makes.

flet
channel
min255
round
*shade
ldbword
logior
ash25524
ash
channel0
16
ash
channel8
8
channel16
defunrasterize-block-icon
blocksize

Draw block as a size by size isometric cube of rgba words.

The cube is the standard two-to-one projection: a diamond size wide and half that tall for the top, and two parallelograms of the same half-height below it. Every pixel asks which of the three faces it belongs to and reads the matching texel, so the icon carries the material's real texture rather than its average colour.

let*
pixels
make-array
listsizesize
:element-type'
unsigned-byte32
:initial-element0
half
quarter
tiles
list:top:left:right
flet
paint
xyfaceuv
let
word
block-icon-texelatlas
getftilesface
floor
*uedge
floor
*vedge
setf
arefpixelsyx
dotimes
ysizepixels
dotimes
xsize
let*
px
+x0.5
py
+y0.5

Coordinates along the diamond's two edges from its left corner. Both inside the unit square means the top face.

dy
-pyquarter
cond
and
<=0.0a
<a1.0
<=0.0b
<b1.0
paintxy:topab
<pxhalf
let
top-edge
+quarter
/px2.0
when
and
<=top-edgepy
<py
+top-edgehalf
paintxy:left
/pxhalf
/
-pytop-edge
half
t
let
top-edge
-half
/
-pxhalf
2.0
when
and
<=top-edgepy
<py
+top-edgehalf
paintxy:right
/
-pxhalf
half
/
-pytop-edge
half
defunblock-icon-pattern
block&optional
size32

block's isometric icon at size, rasterized on first ask and kept.

let
key
cons
luvcraft:block-kind-nameblock
size
or
setf
make-patternnil
defundraw-block-icon
streamblockxy&optional
size32

Draw block's cube with its top-left corner at X,Y.

draw-pattern*streamxy