main.go raw

   1  // Command cubegif generates an animated GIF of a cube rotating through
   2  // its 6 canonical S_3 viewing angles. At each vertex, the projection
   3  // glyph is drawn using the dendrite 8-color scheme.
   4  //
   5  // Usage: go run ./cmd/cubegif [-o output.gif]
   6  package main
   7  
   8  import (
   9  	"flag"
  10  	"fmt"
  11  	"image"
  12  	"image/color"
  13  	"image/gif"
  14  	"math"
  15  	"os"
  16  )
  17  
  18  const (
  19  	width  = 480
  20  	height = 480
  21  	cx     = width / 2  // center x
  22  	cy     = height / 2 // center y
  23  	scale  = 120.0      // cube half-size in pixels
  24  )
  25  
  26  // 8-color palette: black, red, orange, yellow, green, blue, purple, white.
  27  // Plus background (dark navy) and wireframe gray.
  28  var palette = []color.Color{
  29  	color.RGBA{15, 23, 42, 255},    // 0: background
  30  	color.RGBA{26, 26, 26, 255},    // 1: black (vertex 000)
  31  	color.RGBA{239, 68, 68, 255},   // 2: red (vertex 001)
  32  	color.RGBA{249, 115, 22, 255},  // 3: orange (vertex 010)
  33  	color.RGBA{234, 179, 8, 255},   // 4: yellow (vertex 011)
  34  	color.RGBA{34, 197, 94, 255},   // 5: green (vertex 100)
  35  	color.RGBA{59, 130, 246, 255},  // 6: blue (vertex 101)
  36  	color.RGBA{168, 85, 247, 255},  // 7: purple (vertex 110)
  37  	color.RGBA{240, 240, 240, 255}, // 8: white (vertex 111)
  38  	color.RGBA{71, 85, 105, 255},   // 9: wireframe gray
  39  	color.RGBA{148, 163, 184, 255}, // 10: label gray
  40  	color.RGBA{226, 232, 240, 255}, // 11: bright label
  41  }
  42  
  43  const (
  44  	colBG        = 0
  45  	colBlack     = 1
  46  	colRed       = 2
  47  	colOrange    = 3
  48  	colYellow    = 4
  49  	colGreen     = 5
  50  	colBlue      = 6
  51  	colPurple    = 7
  52  	colWhite     = 8
  53  	colWireframe = 9
  54  	colLabel     = 10
  55  	colBright    = 11
  56  )
  57  
  58  // vertexColor maps vertex index (0-7) to palette index.
  59  var vertexColor = [8]uint8{
  60  	colBlack, colRed, colOrange, colYellow,
  61  	colGreen, colBlue, colPurple, colWhite,
  62  }
  63  
  64  // Bit-to-color: bit₀ = red, bit₁ = orange, bit₂ = green.
  65  var bitColor = [3]uint8{colRed, colOrange, colGreen}
  66  
  67  // 3D point.
  68  type vec3 struct{ x, y, z float64 }
  69  
  70  // 8 cube vertices at (±1, ±1, ±1), indexed by 3-bit address.
  71  // Bit 0 → x axis (bonding), bit 1 → y axis (constraint), bit 2 → z axis (energy).
  72  var cubeVerts [8]vec3
  73  
  74  func init() {
  75  	for i := range 8 {
  76  		cubeVerts[i] = vec3{
  77  			x: btof(i & 1),
  78  			y: btof((i >> 1) & 1),
  79  			z: btof((i >> 2) & 1),
  80  		}
  81  	}
  82  }
  83  
  84  // btof maps 0 → -1, 1 → +1.
  85  func btof(b int) float64 {
  86  	return float64(b)*2 - 1
  87  }
  88  
  89  // 12 cube edges: pairs of vertices differing by exactly 1 bit.
  90  var cubeEdges = [12][2]int{
  91  	{0, 1}, {0, 2}, {0, 4},
  92  	{1, 3}, {1, 5},
  93  	{2, 3}, {2, 6},
  94  	{3, 7},
  95  	{4, 5}, {4, 6},
  96  	{5, 7},
  97  	{6, 7},
  98  }
  99  
 100  // Rotation matrix: rotate by angle around a unit axis (ax, ay, az).
 101  func rotateAxis(v vec3, ax, ay, az, angle float64) vec3 {
 102  	c := math.Cos(angle)
 103  	s := math.Sin(angle)
 104  	t := 1 - c
 105  	return vec3{
 106  		x: (t*ax*ax + c)*v.x + (t*ax*ay - s*az)*v.y + (t*ax*az + s*ay)*v.z,
 107  		y: (t*ax*ay + s*az)*v.x + (t*ay*ay + c)*v.y + (t*ay*az - s*ax)*v.z,
 108  		z: (t*ax*az - s*ay)*v.x + (t*ay*az + s*ax)*v.y + (t*az*az + c)*v.z,
 109  	}
 110  }
 111  
 112  // Composite rotation: first around Y by yaw, then around X by pitch.
 113  func rotate(v vec3, yaw, pitch float64) vec3 {
 114  	// Yaw around Y axis.
 115  	v = rotateAxis(v, 0, 1, 0, yaw)
 116  	// Pitch around X axis.
 117  	v = rotateAxis(v, 1, 0, 0, pitch)
 118  	return v
 119  }
 120  
 121  // project maps a 3D point to 2D screen coordinates (orthographic).
 122  func project(v vec3) (int, int) {
 123  	return int(cx + v.x*scale), int(cy - v.y*scale)
 124  }
 125  
 126  // viewAngle defines a viewing direction for one frame.
 127  type viewAngle struct {
 128  	yaw, pitch float64
 129  	name       string
 130  	permName   string
 131  }
 132  
 133  // tilt adds a small offset so vertices never perfectly overlap.
 134  // This ensures all 8 vertices are distinguishable in every frame,
 135  // making all 48 = 2^n × n! configurations visible across 6 frames.
 136  const tilt = 0.21 // ~12 degrees
 137  
 138  // 6 canonical viewing angles, one per S_3 permutation.
 139  // Each has a small tilt so back-face vertices are displaced from front ones.
 140  var views = []viewAngle{
 141  	// Face-on views: tilted slightly so all 8 vertices separate.
 142  	{tilt, tilt, "Face XY", "Identity"},                                           // near -Z axis
 143  	{math.Pi/2 + tilt, tilt, "Face XZ", "Swap(C,E)"},                             // near -Y axis
 144  	{tilt, math.Pi/2 + tilt, "Face YZ", "Swap(B,E)"},                             // near -X axis
 145  	{math.Pi/4 + tilt/2, tilt, "Edge-on", "Swap(B,C)"},                           // edge view
 146  	{math.Pi / 4, math.Atan(1/math.Sqrt2) + tilt/3, "Vertex A", "Cycle(012)"},    // isometric A
 147  	{-math.Pi / 4, math.Atan(1/math.Sqrt2) + tilt/3, "Vertex B", "Cycle(021)"},   // isometric B
 148  }
 149  
 150  func main() {
 151  	outPath := flag.String("o", "projection_cube.gif", "output file path")
 152  	flag.Parse()
 153  
 154  	g := &gif.GIF{}
 155  
 156  	for _, view := range views {
 157  		img := image.NewPaletted(image.Rect(0, 0, width, height), palette)
 158  		// Fill background.
 159  		for y := range height {
 160  			for x := range width {
 161  				img.SetColorIndex(x, y, colBG)
 162  			}
 163  		}
 164  
 165  		// Transform all vertices.
 166  		var projected [8]vec3
 167  		var screenX, screenY [8]int
 168  		for i := range 8 {
 169  			projected[i] = rotate(cubeVerts[i], view.yaw, view.pitch)
 170  			screenX[i], screenY[i] = project(projected[i])
 171  		}
 172  
 173  		// Draw edges (sorted by average depth — back edges first).
 174  		type edgeDepth struct {
 175  			i, j  int
 176  			depth float64
 177  		}
 178  		var edges []edgeDepth
 179  		for _, e := range cubeEdges {
 180  			avgZ := (projected[e[0]].z + projected[e[1]].z) / 2
 181  			edges = append(edges, edgeDepth{e[0], e[1], avgZ})
 182  		}
 183  		// Sort: deeper edges first (they get drawn underneath).
 184  		for i := range len(edges) {
 185  			for j := i + 1; j < len(edges); j++ {
 186  				if edges[j].depth < edges[i].depth {
 187  					edges[i], edges[j] = edges[j], edges[i]
 188  				}
 189  			}
 190  		}
 191  		for _, e := range edges {
 192  			drawLine(img, screenX[e.i], screenY[e.i], screenX[e.j], screenY[e.j], colWireframe)
 193  		}
 194  
 195  		// Sort vertices by depth (back to front) for drawing.
 196  		type vertDepth struct {
 197  			idx   int
 198  			depth float64
 199  		}
 200  		var verts []vertDepth
 201  		for i := range 8 {
 202  			verts = append(verts, vertDepth{i, projected[i].z})
 203  		}
 204  		for i := range len(verts) {
 205  			for j := i + 1; j < len(verts); j++ {
 206  				if verts[j].depth < verts[i].depth {
 207  					verts[i], verts[j] = verts[j], verts[i]
 208  				}
 209  			}
 210  		}
 211  
 212  		// Draw glyphs and vertices (back to front).
 213  		for _, vd := range verts {
 214  			v := vd.idx
 215  			sx, sy := screenX[v], screenY[v]
 216  
 217  			// Draw glyph arms: for each set bit, draw a short line in that bit's color.
 218  			armLen := 18.0
 219  			for bit := range 3 {
 220  				if v&(1<<bit) == 0 {
 221  					continue
 222  				}
 223  				// Arm direction in 3D: unit vector along the bit's axis.
 224  				var dir vec3
 225  				switch bit {
 226  				case 0:
 227  					dir = vec3{1, 0, 0}
 228  				case 1:
 229  					dir = vec3{0, 1, 0}
 230  				case 2:
 231  					dir = vec3{0, 0, 1}
 232  				}
 233  				// Rotate the direction by the same view angle.
 234  				dir = rotate(dir, view.yaw, view.pitch)
 235  				ex := sx + int(dir.x*armLen)
 236  				ey := sy - int(dir.y*armLen) // y is inverted
 237  				// Line thickness: bit₀ widest (3 px), bit₂ narrowest (1 px).
 238  				thickness := 3 - bit
 239  				drawThickLine(img, sx, sy, ex, ey, bitColor[bit], thickness)
 240  			}
 241  
 242  			// Draw vertex dot.
 243  			r := 5
 244  			fillCircle(img, sx, sy, r, vertexColor[v])
 245  		}
 246  
 247  		// Frame label.
 248  		drawString(img, 10, 18, fmt.Sprintf("%s  (%s)", view.name, view.permName), colBright)
 249  		drawString(img, 10, height-12, "dendrite - cubic projection", colLabel)
 250  
 251  		g.Image = append(g.Image, img)
 252  		g.Delay = append(g.Delay, 150) // 1.5 seconds per frame
 253  	}
 254  
 255  	f, err := os.Create(*outPath)
 256  	if err != nil {
 257  		fmt.Fprintf(os.Stderr, "error: %v\n", err)
 258  		os.Exit(1)
 259  	}
 260  	defer f.Close()
 261  
 262  	if err := gif.EncodeAll(f, g); err != nil {
 263  		fmt.Fprintf(os.Stderr, "error encoding gif: %v\n", err)
 264  		os.Exit(1)
 265  	}
 266  	fmt.Printf("wrote %s (%d frames)\n", *outPath, len(g.Image))
 267  }
 268  
 269  // --- Drawing primitives (no external deps) ---
 270  
 271  // drawLine draws a 1-pixel line using Bresenham's algorithm.
 272  func drawLine(img *image.Paletted, x0, y0, x1, y1 int, col uint8) {
 273  	dx := abs(x1 - x0)
 274  	dy := -abs(y1 - y0)
 275  	sx, sy := 1, 1
 276  	if x0 >= x1 {
 277  		sx = -1
 278  	}
 279  	if y0 >= y1 {
 280  		sy = -1
 281  	}
 282  	err := dx + dy
 283  	for {
 284  		if x0 >= 0 && x0 < width && y0 >= 0 && y0 < height {
 285  			img.SetColorIndex(x0, y0, col)
 286  		}
 287  		if x0 == x1 && y0 == y1 {
 288  			break
 289  		}
 290  		e2 := 2 * err
 291  		if e2 >= dy {
 292  			err += dy
 293  			x0 += sx
 294  		}
 295  		if e2 <= dx {
 296  			err += dx
 297  			y0 += sy
 298  		}
 299  	}
 300  }
 301  
 302  // drawThickLine draws a line with thickness (by offsetting perpendicular).
 303  func drawThickLine(img *image.Paletted, x0, y0, x1, y1 int, col uint8, thickness int) {
 304  	if thickness <= 1 {
 305  		drawLine(img, x0, y0, x1, y1, col)
 306  		return
 307  	}
 308  	dx := float64(x1 - x0)
 309  	dy := float64(y1 - y0)
 310  	length := math.Sqrt(dx*dx + dy*dy)
 311  	if length < 0.5 {
 312  		return
 313  	}
 314  	// Perpendicular unit vector.
 315  	px := -dy / length
 316  	py := dx / length
 317  
 318  	half := float64(thickness) / 2
 319  	for t := -half; t <= half; t += 0.5 {
 320  		ox := int(math.Round(px * t))
 321  		oy := int(math.Round(py * t))
 322  		drawLine(img, x0+ox, y0+oy, x1+ox, y1+oy, col)
 323  	}
 324  }
 325  
 326  // fillCircle draws a filled circle.
 327  func fillCircle(img *image.Paletted, cx, cy, r int, col uint8) {
 328  	for dy := -r; dy <= r; dy++ {
 329  		for dx := -r; dx <= r; dx++ {
 330  			if dx*dx+dy*dy <= r*r {
 331  				px, py := cx+dx, cy+dy
 332  				if px >= 0 && px < width && py >= 0 && py < height {
 333  					img.SetColorIndex(px, py, col)
 334  				}
 335  			}
 336  		}
 337  	}
 338  }
 339  
 340  // drawString renders text using a simple built-in 5x7 bitmap font.
 341  // Only supports ASCII printable characters.
 342  func drawString(img *image.Paletted, x, y int, s string, col uint8) {
 343  	for _, ch := range s {
 344  		if ch < 32 || ch > 126 {
 345  			ch = '?'
 346  		}
 347  		glyph := font5x7[ch-32]
 348  		for row := range 7 {
 349  			for col_bit := range 5 {
 350  				if glyph[row]&(1<<(4-col_bit)) != 0 {
 351  					px, py := x+col_bit, y+row
 352  					if px >= 0 && px < width && py >= 0 && py < height {
 353  						img.SetColorIndex(px, py, col)
 354  					}
 355  				}
 356  			}
 357  		}
 358  		x += 6 // 5 pixels + 1 space
 359  	}
 360  }
 361  
 362  func abs(x int) int {
 363  	if x < 0 {
 364  		return -x
 365  	}
 366  	return x
 367  }
 368  
 369  // font5x7 is a minimal 5×7 bitmap font for ASCII 32-126.
 370  // Each character is 7 rows of 5-bit bitmaps (MSB = leftmost pixel).
 371  var font5x7 = [95][7]uint8{
 372  	// ' ' (32)
 373  	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 374  	// '!' (33)
 375  	{0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04},
 376  	// '"' (34)
 377  	{0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00},
 378  	// '#' (35)
 379  	{0x0A, 0x1F, 0x0A, 0x0A, 0x1F, 0x0A, 0x00},
 380  	// '$' (36)
 381  	{0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04},
 382  	// '%' (37)
 383  	{0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03},
 384  	// '&' (38)
 385  	{0x08, 0x14, 0x14, 0x08, 0x15, 0x12, 0x0D},
 386  	// '\'' (39)
 387  	{0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00},
 388  	// '(' (40)
 389  	{0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02},
 390  	// ')' (41)
 391  	{0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08},
 392  	// '*' (42)
 393  	{0x00, 0x0A, 0x04, 0x1F, 0x04, 0x0A, 0x00},
 394  	// '+' (43)
 395  	{0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00},
 396  	// ',' (44)
 397  	{0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08},
 398  	// '-' (45)
 399  	{0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00},
 400  	// '.' (46)
 401  	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04},
 402  	// '/' (47)
 403  	{0x01, 0x02, 0x02, 0x04, 0x08, 0x08, 0x10},
 404  	// '0' (48)
 405  	{0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E},
 406  	// '1' (49)
 407  	{0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E},
 408  	// '2' (50)
 409  	{0x0E, 0x11, 0x01, 0x06, 0x08, 0x10, 0x1F},
 410  	// '3' (51)
 411  	{0x0E, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0E},
 412  	// '4' (52)
 413  	{0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02},
 414  	// '5' (53)
 415  	{0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E},
 416  	// '6' (54)
 417  	{0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E},
 418  	// '7' (55)
 419  	{0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08},
 420  	// '8' (56)
 421  	{0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E},
 422  	// '9' (57)
 423  	{0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C},
 424  	// ':' (58)
 425  	{0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00},
 426  	// ';' (59)
 427  	{0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08},
 428  	// '<' (60)
 429  	{0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02},
 430  	// '=' (61)
 431  	{0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00},
 432  	// '>' (62)
 433  	{0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08},
 434  	// '?' (63)
 435  	{0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04},
 436  	// '@' (64)
 437  	{0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0E},
 438  	// 'A' (65)
 439  	{0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11},
 440  	// 'B' (66)
 441  	{0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E},
 442  	// 'C' (67)
 443  	{0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E},
 444  	// 'D' (68)
 445  	{0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E},
 446  	// 'E' (69)
 447  	{0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F},
 448  	// 'F' (70)
 449  	{0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10},
 450  	// 'G' (71)
 451  	{0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F},
 452  	// 'H' (72)
 453  	{0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11},
 454  	// 'I' (73)
 455  	{0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E},
 456  	// 'J' (74)
 457  	{0x01, 0x01, 0x01, 0x01, 0x11, 0x11, 0x0E},
 458  	// 'K' (75)
 459  	{0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11},
 460  	// 'L' (76)
 461  	{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F},
 462  	// 'M' (77)
 463  	{0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11},
 464  	// 'N' (78)
 465  	{0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11},
 466  	// 'O' (79)
 467  	{0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E},
 468  	// 'P' (80)
 469  	{0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10},
 470  	// 'Q' (81)
 471  	{0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D},
 472  	// 'R' (82)
 473  	{0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11},
 474  	// 'S' (83)
 475  	{0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E},
 476  	// 'T' (84)
 477  	{0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04},
 478  	// 'U' (85)
 479  	{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E},
 480  	// 'V' (86)
 481  	{0x11, 0x11, 0x11, 0x11, 0x0A, 0x0A, 0x04},
 482  	// 'W' (87)
 483  	{0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11},
 484  	// 'X' (88)
 485  	{0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11},
 486  	// 'Y' (89)
 487  	{0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04},
 488  	// 'Z' (90)
 489  	{0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F},
 490  	// '[' (91)
 491  	{0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E},
 492  	// '\' (92)
 493  	{0x10, 0x08, 0x08, 0x04, 0x02, 0x02, 0x01},
 494  	// ']' (93)
 495  	{0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E},
 496  	// '^' (94)
 497  	{0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00},
 498  	// '_' (95)
 499  	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F},
 500  	// '`' (96)
 501  	{0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00},
 502  	// 'a' (97)
 503  	{0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F},
 504  	// 'b' (98)
 505  	{0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x1E},
 506  	// 'c' (99)
 507  	{0x00, 0x00, 0x0E, 0x11, 0x10, 0x11, 0x0E},
 508  	// 'd' (100)
 509  	{0x01, 0x01, 0x0F, 0x11, 0x11, 0x11, 0x0F},
 510  	// 'e' (101)
 511  	{0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E},
 512  	// 'f' (102)
 513  	{0x06, 0x08, 0x1E, 0x08, 0x08, 0x08, 0x08},
 514  	// 'g' (103)
 515  	{0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x0E},
 516  	// 'h' (104)
 517  	{0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x11},
 518  	// 'i' (105)
 519  	{0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E},
 520  	// 'j' (106)
 521  	{0x02, 0x00, 0x02, 0x02, 0x02, 0x12, 0x0C},
 522  	// 'k' (107)
 523  	{0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12},
 524  	// 'l' (108)
 525  	{0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E},
 526  	// 'm' (109)
 527  	{0x00, 0x00, 0x1A, 0x15, 0x15, 0x11, 0x11},
 528  	// 'n' (110)
 529  	{0x00, 0x00, 0x1E, 0x11, 0x11, 0x11, 0x11},
 530  	// 'o' (111)
 531  	{0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E},
 532  	// 'p' (112)
 533  	{0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10},
 534  	// 'q' (113)
 535  	{0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x01},
 536  	// 'r' (114)
 537  	{0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10},
 538  	// 's' (115)
 539  	{0x00, 0x00, 0x0F, 0x10, 0x0E, 0x01, 0x1E},
 540  	// 't' (116)
 541  	{0x08, 0x08, 0x1E, 0x08, 0x08, 0x09, 0x06},
 542  	// 'u' (117)
 543  	{0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D},
 544  	// 'v' (118)
 545  	{0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04},
 546  	// 'w' (119)
 547  	{0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A},
 548  	// 'x' (120)
 549  	{0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11},
 550  	// 'y' (121)
 551  	{0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E},
 552  	// 'z' (122)
 553  	{0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F},
 554  	// '{' (123)
 555  	{0x02, 0x04, 0x04, 0x08, 0x04, 0x04, 0x02},
 556  	// '|' (124)
 557  	{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04},
 558  	// '}' (125)
 559  	{0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08},
 560  	// '~' (126)
 561  	{0x00, 0x00, 0x08, 0x15, 0x02, 0x00, 0x00},
 562  }
 563