|
| 1 | +# Complete Font Systems Guide - From DOS to Modern CNC |
| 2 | + |
| 3 | +## Understanding Font Systems Logic |
| 4 | + |
| 5 | +This guide explains different font rendering approaches, from classic DOS bitmap fonts to modern vector systems, with practical implementations in GGcode. |
| 6 | + |
| 7 | +## 1. Historical Context: DOS Font Systems |
| 8 | + |
| 9 | +### The Character Cell Concept |
| 10 | +DOS computers used a **fixed character cell** system where each character occupied a rectangular grid: |
| 11 | + |
| 12 | +``` |
| 13 | +Standard DOS Character: 8×16 pixels |
| 14 | +┌────────┐ |
| 15 | +│████████│ ← Each row is 8 bits |
| 16 | +│█ █│ stored as byte values |
| 17 | +│█ █│ |
| 18 | +│████████│ |
| 19 | +│█ █│ |
| 20 | +│█ █│ |
| 21 | +│████████│ |
| 22 | +└────────┘ |
| 23 | +``` |
| 24 | + |
| 25 | +### Memory Layout |
| 26 | +```c |
| 27 | +// DOS font stored as byte arrays |
| 28 | +unsigned char font_A[16] = { |
| 29 | + 0x00, // ........ (top padding) |
| 30 | + 0x18, // ...██... |
| 31 | + 0x24, // ..█..█.. |
| 32 | + 0x42, // .█....█. |
| 33 | + 0x42, // .█....█. |
| 34 | + 0x7E, // .██████. (crossbar) |
| 35 | + 0x81, // █......█ |
| 36 | + 0x81, // █......█ |
| 37 | + 0x81, // █......█ |
| 38 | + 0x00, // ........ (bottom padding) |
| 39 | + // ... more rows |
| 40 | +}; |
| 41 | +``` |
| 42 | + |
| 43 | +### Advantages of DOS Bitmap Fonts |
| 44 | +- **Fast rendering**: Direct memory copy to screen |
| 45 | +- **Pixel-perfect**: Exact control over every pixel |
| 46 | +- **Consistent spacing**: Fixed character width |
| 47 | +- **Low CPU usage**: No calculations needed |
| 48 | + |
| 49 | +### Disadvantages |
| 50 | +- **Fixed size**: Scaling creates pixelation |
| 51 | +- **Memory intensive**: Large fonts need lots of storage |
| 52 | +- **Limited resolution**: Bound by pixel grid |
| 53 | + |
| 54 | +## 2. Modern Vector Font Systems |
| 55 | + |
| 56 | +### Mathematical Representation |
| 57 | +Vector fonts store characters as mathematical descriptions: |
| 58 | + |
| 59 | +``` |
| 60 | +Character 'A' as vectors: |
| 61 | +Point P1: (0, 0) ← Bottom left |
| 62 | +Point P2: (4, 8) ← Top center |
| 63 | +Point P3: (8, 0) ← Bottom right |
| 64 | +Point P4: (2, 4) ← Crossbar left |
| 65 | +Point P5: (6, 4) ← Crossbar right |
| 66 | +
|
| 67 | +Strokes: |
| 68 | +1. Line P1 → P2 (left diagonal) |
| 69 | +2. Line P2 → P3 (right diagonal) |
| 70 | +3. Line P4 → P5 (crossbar) |
| 71 | +``` |
| 72 | + |
| 73 | +### Scalability Mathematics |
| 74 | +```c |
| 75 | +// Scale character to any size |
| 76 | +void scale_character(float scale_factor) { |
| 77 | + for (each_point in character) { |
| 78 | + point.x *= scale_factor; |
| 79 | + point.y *= scale_factor; |
| 80 | + } |
| 81 | +} |
| 82 | +``` |
| 83 | +
|
| 84 | +## 3. Seven-Segment Display Logic |
| 85 | +
|
| 86 | +### Segment Mapping |
| 87 | +``` |
| 88 | +Seven-segment layout: |
| 89 | + AAA Segment bits: |
| 90 | +F B A = bit 0 |
| 91 | +F B B = bit 1 |
| 92 | + GGG C = bit 2 |
| 93 | +E C D = bit 3 |
| 94 | +E C E = bit 4 |
| 95 | + DDD F = bit 5 |
| 96 | + G = bit 6 |
| 97 | +``` |
| 98 | +
|
| 99 | +### Character Encoding Table |
| 100 | +```c |
| 101 | +// Seven-segment patterns (A=LSB, G=MSB) |
| 102 | +unsigned char seven_seg_digits[10] = { |
| 103 | + 0b00111111, // 0: A,B,C,D,E,F (all except G) |
| 104 | + 0b00000110, // 1: B,C only |
| 105 | + 0b01011011, // 2: A,B,G,E,D |
| 106 | + 0b01001111, // 3: A,B,G,C,D |
| 107 | + 0b01100110, // 4: F,G,B,C |
| 108 | + 0b01101101, // 5: A,F,G,C,D |
| 109 | + 0b01111101, // 6: A,F,G,E,D,C |
| 110 | + 0b00000111, // 7: A,B,C |
| 111 | + 0b01111111, // 8: All segments |
| 112 | + 0b01101111 // 9: A,B,C,D,F,G |
| 113 | +}; |
| 114 | +``` |
| 115 | + |
| 116 | +## 4. Font System Comparison Matrix |
| 117 | + |
| 118 | +| Feature | DOS Bitmap | Vector | Seven-Segment | Modern (TrueType) | |
| 119 | +|---------|------------|--------|---------------|-------------------| |
| 120 | +| **Storage** | Pixel arrays | Line segments | Bit patterns | Bezier curves | |
| 121 | +| **Scalability** | Poor (pixelated) | Excellent | Good | Excellent | |
| 122 | +| **Rendering Speed** | Very fast | Medium | Fast | Medium | |
| 123 | +| **Memory Usage** | High | Low | Very low | Medium | |
| 124 | +| **Character Quality** | Pixel-perfect | Smooth | Geometric | Professional | |
| 125 | +| **Implementation** | Simple | Medium | Simple | Complex | |
| 126 | +| **Best Use Case** | Retro displays | CNC/Plotting | Digital displays | Text documents | |
| 127 | + |
| 128 | +## 5. CNC-Specific Considerations |
| 129 | + |
| 130 | +### Tool Path Efficiency |
| 131 | +```ggcode |
| 132 | +// Efficient vector font approach |
| 133 | +function draw_char_A(x, y, size) { |
| 134 | + // Single continuous path where possible |
| 135 | + G0 Z[safe_z] X[x-size/2] Y[y-size/2] // Move to start |
| 136 | + G0 Z[0] // Lower tool |
| 137 | + G1 X[x] Y[y+size/2] // Left stroke |
| 138 | + G1 X[x+size/2] Y[y-size/2] // Right stroke |
| 139 | + G0 Z[safe_z] // Lift tool |
| 140 | + |
| 141 | + // Separate crossbar (unavoidable lift) |
| 142 | + G0 X[x-size/4] Y[y] // Move to crossbar |
| 143 | + G0 Z[0] // Lower tool |
| 144 | + G1 X[x+size/4] Y[y] // Draw crossbar |
| 145 | + G0 Z[safe_z] // Lift tool |
| 146 | +} |
| 147 | +``` |
| 148 | + |
| 149 | +### Optimization Strategies |
| 150 | +1. **Minimize tool lifts**: Group connected strokes |
| 151 | +2. **Optimize travel paths**: Shortest distance between characters |
| 152 | +3. **Single-stroke fonts**: Each line drawn only once |
| 153 | +4. **Consistent tool depth**: Avoid unnecessary Z movements |
| 154 | + |
| 155 | +## 6. Implementation Patterns |
| 156 | + |
| 157 | +### DOS-Style Bitmap Renderer |
| 158 | +```c |
| 159 | +void render_bitmap_char(char c, int x, int y, int scale) { |
| 160 | + unsigned char *bitmap = get_char_bitmap(c); |
| 161 | + |
| 162 | + for (int row = 0; row < CHAR_HEIGHT; row++) { |
| 163 | + unsigned char line = bitmap[row]; |
| 164 | + |
| 165 | + for (int col = 0; col < CHAR_WIDTH; col++) { |
| 166 | + if (line & (0x80 >> col)) { // Test bit |
| 167 | + // Draw scaled pixel |
| 168 | + fill_rect(x + col*scale, y + row*scale, |
| 169 | + scale, scale); |
| 170 | + } |
| 171 | + } |
| 172 | + } |
| 173 | +} |
| 174 | +``` |
| 175 | +
|
| 176 | +### Vector Font Renderer |
| 177 | +```c |
| 178 | +typedef struct { |
| 179 | + float x, y; |
| 180 | +} Point; |
| 181 | +
|
| 182 | +typedef struct { |
| 183 | + Point start, end; |
| 184 | + int pen_down; // 0=move, 1=draw |
| 185 | +} Stroke; |
| 186 | +
|
| 187 | +void render_vector_char(char c, float x, float y, float scale) { |
| 188 | + Stroke *strokes = get_char_strokes(c); |
| 189 | + int stroke_count = get_stroke_count(c); |
| 190 | + |
| 191 | + for (int i = 0; i < stroke_count; i++) { |
| 192 | + Point start = { |
| 193 | + x + strokes[i].start.x * scale, |
| 194 | + y + strokes[i].start.y * scale |
| 195 | + }; |
| 196 | + Point end = { |
| 197 | + x + strokes[i].end.x * scale, |
| 198 | + y + strokes[i].end.y * scale |
| 199 | + }; |
| 200 | + |
| 201 | + if (strokes[i].pen_down) { |
| 202 | + draw_line(start.x, start.y, end.x, end.y); |
| 203 | + } else { |
| 204 | + move_to(end.x, end.y); |
| 205 | + } |
| 206 | + } |
| 207 | +} |
| 208 | +``` |
| 209 | + |
| 210 | +## 7. Character Set Design Principles |
| 211 | + |
| 212 | +### Legibility Rules |
| 213 | +1. **Consistent stroke width**: All lines same thickness |
| 214 | +2. **Adequate spacing**: Characters don't touch |
| 215 | +3. **Clear distinctions**: 0 vs O, 1 vs I vs l |
| 216 | +4. **Proper proportions**: Width-to-height ratios |
| 217 | + |
| 218 | +### Geometric Constraints |
| 219 | +``` |
| 220 | +Standard character proportions: |
| 221 | +- Width: 0.6 × Height (for most letters) |
| 222 | +- Ascenders: 1.2 × x-height (b, d, f, h, k, l, t) |
| 223 | +- Descenders: 0.3 × x-height (g, j, p, q, y) |
| 224 | +- Cap height: 1.0 × x-height (A-Z) |
| 225 | +- Stroke width: 0.1 × height |
| 226 | +``` |
| 227 | + |
| 228 | +## 8. Advanced Font Features |
| 229 | + |
| 230 | +### Kerning Tables |
| 231 | +```c |
| 232 | +// Adjust spacing between specific character pairs |
| 233 | +int kerning_table[256][256] = { |
| 234 | + ['A']['V'] = -2, // Move AV closer together |
| 235 | + ['T']['o'] = -1, // Move To closer together |
| 236 | + ['W']['A'] = -1, // Move WA closer together |
| 237 | + // ... more pairs |
| 238 | +}; |
| 239 | +``` |
| 240 | + |
| 241 | +### Hinting for Small Sizes |
| 242 | +```c |
| 243 | +// Snap stems to pixel boundaries at small sizes |
| 244 | +if (font_size < 12) { |
| 245 | + // Round stroke positions to nearest pixel |
| 246 | + stroke.x = round(stroke.x); |
| 247 | + stroke.y = round(stroke.y); |
| 248 | + |
| 249 | + // Ensure minimum stroke width |
| 250 | + if (stroke_width < 1.0) stroke_width = 1.0; |
| 251 | +} |
| 252 | +``` |
| 253 | + |
| 254 | +## 9. Performance Optimization |
| 255 | + |
| 256 | +### Caching Strategies |
| 257 | +```c |
| 258 | +// Cache rendered characters for reuse |
| 259 | +typedef struct { |
| 260 | + char character; |
| 261 | + float size; |
| 262 | + void *rendered_data; |
| 263 | +} CacheEntry; |
| 264 | + |
| 265 | +CacheEntry font_cache[256]; |
| 266 | + |
| 267 | +void *get_cached_char(char c, float size) { |
| 268 | + for (int i = 0; i < cache_size; i++) { |
| 269 | + if (font_cache[i].character == c && |
| 270 | + font_cache[i].size == size) { |
| 271 | + return font_cache[i].rendered_data; |
| 272 | + } |
| 273 | + } |
| 274 | + return NULL; // Not cached, need to render |
| 275 | +} |
| 276 | +``` |
| 277 | +
|
| 278 | +### Memory Management |
| 279 | +```c |
| 280 | +// Efficient font storage |
| 281 | +typedef struct { |
| 282 | + unsigned short offset; // Offset into stroke data |
| 283 | + unsigned char count; // Number of strokes |
| 284 | + unsigned char width; // Character width |
| 285 | +} CharInfo; |
| 286 | +
|
| 287 | +// Compact stroke storage |
| 288 | +typedef struct { |
| 289 | + signed char dx, dy; // Relative coordinates |
| 290 | + unsigned char flags; // Pen up/down, end marker |
| 291 | +} CompactStroke; |
| 292 | +``` |
| 293 | + |
| 294 | +## 10. Practical Applications |
| 295 | + |
| 296 | +### CNC Text Engraving |
| 297 | +- Use vector fonts for smooth curves |
| 298 | +- Optimize tool paths to minimize air time |
| 299 | +- Consider material properties (wood vs metal) |
| 300 | +- Single-stroke fonts for efficiency |
| 301 | + |
| 302 | +### Embedded Displays |
| 303 | +- Use bitmap fonts for speed |
| 304 | +- Compress font data for memory savings |
| 305 | +- Consider subpixel rendering for LCD |
| 306 | +- Cache frequently used characters |
| 307 | + |
| 308 | +### 3D Printing Text |
| 309 | +- Vector fonts with extrusion |
| 310 | +- Consider overhang limitations |
| 311 | +- Optimize for layer adhesion |
| 312 | +- Support material considerations |
| 313 | + |
| 314 | +This comprehensive understanding enables you to choose the right font system for your specific application and implement it efficiently. |
0 commit comments