├── .gitignore ├── Consolines.psd ├── Consolines.svg ├── LICENSE ├── Makefile ├── README.md ├── consolines.c └── generate.py /.gitignore: -------------------------------------------------------------------------------- 1 | consolines.exe 2 | *__pycache__* 3 | gmon.out -------------------------------------------------------------------------------- /Consolines.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orangeduck/Consolines/db797f0e55ac9ef03787918f110418fe46f2847a/Consolines.psd -------------------------------------------------------------------------------- /Consolines.svg: -------------------------------------------------------------------------------- 1 | 2 | Consolines 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Daniel Holden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PLATFORM ?= PLATFORM_DESKTOP 2 | # BUILD_MODE ?= RELEASE 3 | BUILD_MODE ?= DEBUG 4 | RAYLIB_DIR = C:/raylib 5 | INCLUDE_DIR = -I ./ -I $(RAYLIB_DIR)/raylib/src -I $(RAYLIB_DIR)/raygui/src 6 | LIBRARY_DIR = -L $(RAYLIB_DIR)/raylib/src 7 | DEFINES = -D _DEFAULT_SOURCE -D RAYLIB_BUILD_MODE=$(BUILD_MODE) -D $(PLATFORM) 8 | 9 | ifeq ($(PLATFORM),PLATFORM_DESKTOP) 10 | CC = gcc 11 | EXT = .exe 12 | ifeq ($(BUILD_MODE),RELEASE) 13 | CFLAGS ?= $(DEFINES) -ffast-math -march=native -D NDEBUG -O3 $(RAYLIB_DIR)/raylib/src/raylib.rc.data $(INCLUDE_DIR) $(LIBRARY_DIR) 14 | else 15 | CFLAGS ?= $(DEFINES) -pg $(RAYLIB_DIR)/raylib/src/raylib.rc.data $(INCLUDE_DIR) $(LIBRARY_DIR) 16 | endif 17 | LIBS = -lraylib -lopengl32 -lgdi32 -lwinmm 18 | endif 19 | 20 | ifeq ($(PLATFORM),PLATFORM_WEB) 21 | CC = emcc 22 | EXT = .html 23 | CFLAGS ?= $(DEFINES) $(RAYLIB_DIR)/raylib/src/libraylib.bc -ffast-math -D NDEBUG -O3 -s USE_GLFW=3 -s FORCE_FILESYSTEM=1 -s MAX_WEBGL_VERSION=2 -s ALLOW_MEMORY_GROWTH=1 --shell-file ./shell.html $(INCLUDE_DIR) $(LIBRARY_DIR) 24 | endif 25 | 26 | SOURCE = $(wildcard *.c) 27 | HEADER = $(wildcard *.h) 28 | 29 | .PHONY: all 30 | 31 | all: consolines 32 | 33 | consolines: $(SOURCE) $(HEADER) 34 | $(CC) -o $@$(EXT) $(SOURCE) $(CFLAGS) $(LIBS) 35 | 36 | clean: 37 | rm consolines$(EXT) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Consolines 2 | 3 | Simple way of debug drawing text using 3d line segments as discussed [here](http://www.theorangeduck.com/page/debug-draw-text-lines). 4 | 5 | 6 | 7 | https://github.com/user-attachments/assets/67df1ea8-aab2-4c26-9819-a8fc1962484f 8 | 9 | -------------------------------------------------------------------------------- /consolines.c: -------------------------------------------------------------------------------- 1 | #include "raylib.h" 2 | #include "raymath.h" 3 | #define RAYGUI_IMPLEMENTATION 4 | #include "raygui.h" 5 | 6 | #include 7 | 8 | //---------------------------------------------------------------------------------- 9 | // Camera 10 | //---------------------------------------------------------------------------------- 11 | 12 | // Basic Orbit Camera with simple controls 13 | typedef struct { 14 | 15 | Camera3D cam3d; 16 | float azimuth; 17 | float altitude; 18 | float distance; 19 | Vector3 offset; 20 | 21 | } OrbitCamera; 22 | 23 | static inline void OrbitCameraInit(OrbitCamera* camera) 24 | { 25 | memset(&camera->cam3d, 0, sizeof(Camera3D)); 26 | camera->cam3d.position = (Vector3){ 2.0f, 3.0f, 5.0f }; 27 | camera->cam3d.target = (Vector3){ -0.5f, 1.0f, 0.0f }; 28 | camera->cam3d.up = (Vector3){ 0.0f, 1.0f, 0.0f }; 29 | camera->cam3d.fovy = 45.0f; 30 | camera->cam3d.projection = CAMERA_PERSPECTIVE; 31 | 32 | camera->azimuth = 0.0f; 33 | camera->altitude = 0.4f; 34 | camera->distance = 4.0f; 35 | camera->offset = Vector3Zero(); 36 | } 37 | 38 | static inline void OrbitCameraUpdate( 39 | OrbitCamera* camera, 40 | Vector3 target, 41 | float azimuthDelta, 42 | float altitudeDelta, 43 | float offsetDeltaX, 44 | float offsetDeltaY, 45 | float mouseWheel, 46 | float dt) 47 | { 48 | camera->azimuth = camera->azimuth + 1.0f * dt * -azimuthDelta; 49 | camera->altitude = Clamp(camera->altitude + 1.0f * dt * altitudeDelta, 0.0, 0.4f * PI); 50 | camera->distance = Clamp(camera->distance + 20.0f * dt * -mouseWheel, 0.1f, 100.0f); 51 | 52 | Quaternion rotationAzimuth = QuaternionFromAxisAngle((Vector3){0, 1, 0}, camera->azimuth); 53 | Vector3 position = Vector3RotateByQuaternion((Vector3){0, 0, camera->distance}, rotationAzimuth); 54 | Vector3 axis = Vector3Normalize(Vector3CrossProduct(position, (Vector3){0, 1, 0})); 55 | 56 | Quaternion rotationAltitude = QuaternionFromAxisAngle(axis, camera->altitude); 57 | 58 | Vector3 localOffset = (Vector3){ dt * offsetDeltaX, dt * -offsetDeltaY, 0.0f }; 59 | localOffset = Vector3RotateByQuaternion(localOffset, rotationAzimuth); 60 | 61 | camera->offset = Vector3Add(camera->offset, Vector3RotateByQuaternion(localOffset, rotationAltitude)); 62 | 63 | Vector3 cameraTarget = Vector3Add(camera->offset, target); 64 | Vector3 eye = Vector3Add(cameraTarget, Vector3RotateByQuaternion(position, rotationAltitude)); 65 | 66 | camera->cam3d.target = cameraTarget; 67 | camera->cam3d.position = eye; 68 | } 69 | 70 | //---------------------------------------------------------------------------------- 71 | // LineFont 72 | //---------------------------------------------------------------------------------- 73 | 74 | static const char consolines_nums[94] = { 75 | 2, 6, 4, 10, 15, 16, 4, 5, 5, 3, 2, 3, 1, 1, 1, 13, 3, 6, 76 | 11, 4, 8, 13, 2, 14, 15, 2, 4, 2, 2, 2, 7, 28, 3, 12, 10, 9, 77 | 4, 3, 11, 3, 3, 5, 4, 2, 4, 3, 12, 7, 15, 8, 12, 2, 6, 2, 78 | 4, 2, 3, 3, 3, 1, 3, 2, 1, 1, 11, 10, 8, 10, 12, 5, 26, 6, 79 | 4, 6, 4, 3, 11, 6, 10, 9, 9, 5, 10, 5, 6, 2, 4, 2, 4, 3, 80 | 10, 1, 10, 7 81 | }; 82 | 83 | static const int consolines_offsets[94] = { 84 | 0, 2, 8, 12, 22, 37, 53, 57, 62, 67, 70, 72, 75, 76, 85 | 77, 78, 91, 94, 100, 111, 115, 123, 136, 138, 152, 167, 169, 173, 86 | 175, 177, 179, 186, 214, 217, 229, 239, 248, 252, 255, 266, 269, 272, 87 | 277, 281, 283, 287, 290, 302, 309, 324, 332, 344, 346, 352, 354, 358, 88 | 360, 363, 366, 369, 370, 373, 375, 376, 377, 388, 398, 406, 416, 428, 89 | 433, 459, 465, 469, 475, 479, 482, 493, 499, 509, 518, 527, 532, 542, 90 | 547, 553, 555, 559, 561, 565, 568, 578, 579, 589 91 | }; 92 | 93 | static const int consolines_lines[596] = { 94 | 0x701F3C1F, 0x2A1F281F, 0x59135206, 0x63175913, 0x6D116317, 0x59305223, 95 | 0x63345930, 0x6D2E6334, 0x563A5608, 0x3B373B05, 0x6A172610, 0x26276A2E, 96 | 0x27222909, 0x2D2F2722, 0x35342D2F, 0x3E313534, 0x510F3E31, 0x590B510F, 97 | 0x620E590B, 0x681A620E, 0x6730681A, 0x19187425, 0x26077038, 0x6D096105, 98 | 0x70156D09, 0x671D7015, 0x5B1B671D, 0x55125B1B, 0x59085512, 0x61055908, 99 | 0x3D263122, 0x40323D26, 0x373A4032, 0x2B38373A, 0x252F2B38, 0x2925252F, 100 | 0x31222925, 0x2538590E, 0x55265F2B, 0x610D590E, 0x6A12610D, 0x6E1C6A12, 101 | 0x6B266E1C, 0x662A6B26, 0x5F2B662A, 0x3F085526, 0x2A282519, 0x290F2519, 102 | 0x2F09290F, 0x37062F09, 0x3F083706, 0x39332A28, 0x46343933, 0x6E1D6621, 103 | 0x5D226621, 0x541A5D22, 0x5210541A, 0x5C1B722B, 0x49165C1B, 0x37164916, 104 | 0x271B3716, 0x102B271B, 0x5C247214, 0x49295C24, 0x37294929, 0x27243729, 105 | 0x10142724, 0x70204620, 0x65324E0D, 0x650E4F32, 0x291F5A1F, 0x42074238, 106 | 0x2423301D, 0x191E2423, 0x1310191E, 0x422D4212, 0x2A1F2C1F, 0x70301A0C, 107 | 0x5A35360A, 0x4A08360A, 0x5F0D4A08, 0x66145F0D, 0x6A206614, 0x652C6A20, 108 | 0x5A35652C, 0x46375A35, 0x31324637, 0x2B2B3132, 0x261F2B2B, 0x2B13261F, 109 | 0x360A2B13, 0x2735270D, 0x6A222722, 0x5E0C6A22, 0x270B2735, 0x502F270B, 110 | 0x5C30502F, 0x672A5C30, 0x6B1D672A, 0x630D6B1D, 0x2625270C, 0x2F2F2625, 111 | 0x38332F2F, 0x40313833, 0x49224031, 0x522C4922, 0x5C2F522C, 0x652B5C2F, 112 | 0x6A1D652B, 0x670E6A1D, 0x49164922, 0x37053739, 0x262B6A2B, 0x6A233705, 113 | 0x6A2B6A23, 0x680F6830, 0x4A0F680F, 0x4A274A0F, 0x270D261F, 0x2E2E261F, 114 | 0x3A322E2E, 0x442F3A32, 0x4A27442F, 0x671E6930, 0x5E12671E, 0x4E0C5E12, 115 | 0x460B4E0C, 0x360C460B, 0x460B4D1D, 0x2914360C, 0x25212914, 0x2A2E2521, 116 | 0x35352A2E, 0x43333535, 0x4C294333, 0x4D1D4C29, 0x6935690A, 0x26156935, 117 | 0x67125C0C, 0x6B206712, 0x662E6B20, 0x5C32662E, 0x522E5C32, 0x3E0E522E, 118 | 0x350B3E0E, 0x2813350B, 0x261F2813, 0x2A2D261F, 0x32332A2D, 0x3C313233, 119 | 0x53103C31, 0x5C0C5310, 0x2920270D, 0x322D2920, 0x3E32322D, 0x4C333E32, 120 | 0x4C334529, 0x5F304C33, 0x67295F30, 0x6A1E6729, 0x66126A1E, 0x5E0B6612, 121 | 0x550A5E0B, 0x4A0D550A, 0x44144A0D, 0x421E4414, 0x4529421E, 0x531F561F, 122 | 0x291F2C1F, 0x531F561F, 0x23242E1E, 0x181E2324, 0x1311181E, 0x420D262E, 123 | 0x5C2D420D, 0x4C354C0B, 0x380A3835, 0x42312610, 0x5C114231, 0x3B1B4A1B, 124 | 0x4D2A4A1B, 0x59304D2A, 0x622D5930, 0x6B22622D, 0x6E146B22, 0x271B2A1B, 125 | 0x0F25122D, 0x0E1C0F25, 0x12100E1C, 0x1F071210, 0x34041F07, 0x4B063404, 126 | 0x5E0C4B06, 0x6C185E0C, 0x70246C18, 0x6D2F7024, 0x65366D2F, 0x563A6536, 127 | 0x483B563A, 0x3538483B, 0x2B333538, 0x292E2B33, 0x2C29292E, 0x37282C29, 128 | 0x2D203728, 0x4F2B3728, 0x53274F2B, 0x54225327, 0x4E195422, 0x41154E19, 129 | 0x32144115, 0x2B173214, 0x291B2B17, 0x2D20291B, 0x6A1F2606, 0x26396A1F, 130 | 0x3832380D, 0x6A0D260D, 0x672B6A0D, 0x490D4924, 0x260D292C, 0x3032292C, 131 | 0x39353032, 0x40323935, 0x49244032, 0x502E4924, 0x5932502E, 0x61305932, 132 | 0x672B6130, 0x26272A35, 0x29182627, 0x30102918, 0x390C3010, 0x460A390C, 133 | 0x560C460A, 0x6112560C, 0x691E6112, 0x6A27691E, 0x66356A27, 0x690A260A, 134 | 0x6920690A, 0x260A2620, 0x632C6920, 0x5933632C, 0x49375933, 0x39344937, 135 | 0x2E2E3934, 0x26202E2E, 0x260F2632, 0x690F260F, 0x6932690F, 0x490F4931, 136 | 0x6A102510, 0x6A326A10, 0x4810482F, 0x48354823, 0x28354835, 0x6A276635, 137 | 0x67196A27, 0x5D0E6719, 0x4A085D0E, 0x3C094A08, 0x300E3C09, 0x2819300E, 138 | 0x26252819, 0x28352625, 0x6B0A240A, 0x4936490A, 0x24366B36, 0x2633260C, 139 | 0x6933690C, 0x261F691F, 0x692D690E, 0x312D692D, 0x2A25312D, 0x261B2A25, 140 | 0x2A0D261B, 0x6A0D250D, 0x49176A32, 0x25334917, 0x490D4917, 0x26126A12, 141 | 0x26342612, 0x6A0B2507, 0x3F1F6A0B, 0x6A353F1F, 0x25386A35, 0x6B0C250C, 142 | 0x24356B0C, 0x6A352435, 0x662D6A20, 0x5E33662D, 0x4C385E33, 0x39354C38, 143 | 0x2C2E3935, 0x26202C2E, 0x28142620, 0x340A2814, 0x4707340A, 0x580A4707, 144 | 0x6613580A, 0x6A206613, 0x6A0D260D, 0x420D4226, 0x4A304226, 0x56354A30, 145 | 0x632F5635, 0x6A1F632F, 0x6A0D6A1F, 0x122B153A, 0x1E1F122B, 0x251F1E1F, 146 | 0x2B2D251F, 0x3C362B2D, 0x49383C36, 0x59354938, 0x662D5935, 0x6A20662D, 147 | 0x64116A20, 0x560A6411, 0x4707560A, 0x360A4707, 0x2A12360A, 0x251F2A12, 148 | 0x6A0D250D, 0x6A206A0D, 0x652C6A20, 0x5A31652C, 0x512F5A31, 0x512F4822, 149 | 0x480D4822, 0x25344822, 0x6A20682F, 0x67136A20, 0x610D6713, 0x5A0B610D, 150 | 0x520E5A0B, 0x4A1A520E, 0x412E4A1A, 0x3D32412E, 0x35343D32, 0x2D303534, 151 | 0x26222D30, 0x280A2622, 0x69396908, 0x261F691F, 0x340B6A0B, 0x6A353435, 152 | 0x2A10340B, 0x251F2A10, 0x292B251F, 0x3435292B, 0x251F6A06, 0x6A3A251F, 153 | 0x260E6A06, 0x511F260E, 0x2634511F, 0x6A382634, 0x6A352508, 0x6A0A2536, 154 | 0x40206A06, 0x6A394020, 0x25204020, 0x6936690B, 0x26096936, 0x26362609, 155 | 0x7117712C, 0x0F177117, 0x0F2C0F17, 0x1933700E, 0x71287112, 0x0F287128, 156 | 0x0F130F28, 0x6A1F4B0C, 0x4B336A1F, 0x0F3C0F03, 0x681D7013, 0x560F5920, 157 | 0x4E312531, 0x562C4E31, 0x5920562C, 0x3F153F31, 0x370D3F15, 0x2F0B370D, 158 | 0x26112F0B, 0x251B2611, 0x2825251B, 0x32312825, 0x290D6F0D, 0x251C290D, 159 | 0x2728251C, 0x36332728, 0x43353633, 0x50314335, 0x562C5031, 0x5924562C, 160 | 0x551B5924, 0x4B0D551B, 0x59255632, 0x55185925, 0x4A0F5518, 0x3F0C4A0F, 161 | 0x330F3F0C, 0x2819330F, 0x26252819, 0x29322625, 0x25317031, 0x27213731, 162 | 0x25192721, 0x29112519, 0x310C2911, 0x3E0A310C, 0x4E0E3E0A, 0x55154E0E, 163 | 0x59215515, 0x53315921, 0x4035400B, 0x4B334035, 0x532F4B33, 0x5728532F, 164 | 0x59205728, 0x56155920, 0x4C0D5615, 0x400B4C0D, 0x320D400B, 0x2815320D, 165 | 0x25242815, 0x28332524, 0x661B261B, 0x6E397027, 0x6D20661B, 0x70276D20, 166 | 0x4F074F37, 0x58285837, 0x512E5828, 0x591C5828, 0x5411591C, 0x4A0D5411, 167 | 0x3D124A0D, 0x391E3D12, 0x370E3D12, 0x310C370E, 0x2B0F310C, 0x28142B0F, 168 | 0x282A2814, 0x220C2814, 0x2532282A, 0x21352532, 0x1C362135, 0x16331C36, 169 | 0x122D1633, 0x0E1E122D, 0x110F0E1E, 0x150A110F, 0x1B09150A, 0x220C1B09, 170 | 0x3C2A391E, 0x47303C2A, 0x512E4730, 0x250D700D, 0x25324F32, 0x5519490D, 171 | 0x59235519, 0x562D5923, 0x4F32562D, 0x2634260D, 0x57212621, 0x570E5721, 172 | 0x6A1F6D1F, 0x6A296D29, 0x572B570D, 0x1E2B572B, 0x0E16110A, 0x11220E16, 173 | 0x1E2B1122, 0x250F700F, 0x411B410F, 0x5932411B, 0x2533411B, 0x2633260D, 174 | 0x6F212621, 0x6F0E6F21, 0x25085808, 0x25204C20, 0x25365136, 0x56134808, 175 | 0x59195613, 0x551E5919, 0x4C20551E, 0x572A4C20, 0x5930572A, 0x57345930, 176 | 0x51365734, 0x580D250D, 0x25324E32, 0x54174A0D, 0x59245417, 0x542F5924, 177 | 0x4E32542F, 0x500E3E09, 0x591D500E, 0x552E591D, 0x4834552E, 0x35354834, 178 | 0x292C3535, 0x251F292C, 0x2A11251F, 0x330B2A11, 0x3E09330B, 0x570D0E0D, 179 | 0x571C490D, 0x5925571C, 0x54305925, 0x43355430, 0x31324335, 0x28283132, 180 | 0x251D2828, 0x290D251D, 0x0F315531, 0x591F5531, 0x5312591F, 0x400A5312, 181 | 0x2E0D400A, 0x27132E0D, 0x251B2713, 0x2B26251B, 0x37312B26, 0x570F250F, 182 | 0x571F480F, 0x5928571F, 0x55325928, 0x49355532, 0x5921572F, 0x56145921, 183 | 0x4D0F5614, 0x44134D0F, 0x3B2B4413, 0x36303B2B, 0x30323630, 0x292C3032, 184 | 0x251D292C, 0x280D251D, 0x69173317, 0x2A1B3317, 0x26272A1B, 0x27342627, 185 | 0x58345806, 0x2F0D580D, 0x26325932, 0x28132F0D, 0x251B2813, 0x2A26251B, 186 | 0x34322A26, 0x251F5809, 0x5835251F, 0x25115806, 0x4A1F2511, 0x24314A1F, 187 | 0x58382431, 0x5833250B, 0x580D2534, 0x171A5935, 0x1113171A, 0x10071113, 188 | 0x241F580A, 0x5831580D, 0x260C5831, 0x2634260C, 0x6F24712F, 0x671D6F24, 189 | 0x4E1D671D, 0x48194E1D, 0x430C4819, 0x3F19430C, 0x371E3F19, 0x1B1E371E, 190 | 0x13221B1E, 0x0F2F1322, 0x0F1F7C1F, 0x6F1A710F, 0x67216F1A, 0x4E216721, 191 | 0x48254E21, 0x43324825, 0x3F254332, 0x37203F25, 0x1B203720, 0x131C1B20, 192 | 0x0F0F131C, 0x450A3D08, 0x4A13450A, 0x431E4A13, 0x3B27431E, 0x392D3B27, 193 | 0x3F35392D, 0x47373F35 194 | }; 195 | 196 | void DrawDebugText3D( 197 | const char* string, 198 | Vector3 location, 199 | Quaternion rotation, 200 | Color color, 201 | float thick, // Thickness. Set to 0.0f for pixel lines. 202 | float scale, // Overall scale. Default to 1.0f 203 | float width, // Width. Default to 1.0f 204 | float height, // Height. Default to 1.0f 205 | float spacing, // Character Spacing. Default to 0.0f 206 | float lineheight) // Line Spacing. Default to 1.0f 207 | { 208 | int slen = strlen(string); 209 | 210 | float xOffset = 0.0; 211 | float yOffset = 0.0; 212 | 213 | for (int i = 0; i < slen; i++) 214 | { 215 | if (string[i] == '\n') 216 | { 217 | // If we have a line break then reset xOffset and move to next line 218 | xOffset = 0.0; 219 | yOffset -= lineheight * scale * height; 220 | } 221 | else if (string[i] == '\r') 222 | { 223 | // Carriage return resets the xOffset 224 | xOffset = 0.0; 225 | } 226 | else if (string[i] == '\t') 227 | { 228 | // Tab is like four spaces 229 | xOffset += 4.0f * 0.5f * scale * width + spacing; 230 | } 231 | else if (string[i] < '!' || string[i] > '~') 232 | { 233 | // Every other non-printable character is rendered as a space 234 | xOffset += 0.5f * scale * width + spacing; 235 | } 236 | else 237 | { 238 | // Get the look-up table index from the character code 239 | int ci = string[i] - '!'; 240 | 241 | // Get the number of line segments and the offset into the lines array 242 | int lnum = consolines_nums[ci]; 243 | int loff = consolines_offsets[ci]; 244 | 245 | for (int li = 0; li < lnum; li++) 246 | { 247 | // Unpack integer coordinates 248 | int xStartInt = (0x000000FF & (consolines_lines[loff + li] >> 0)); 249 | int yStartInt = (0x000000FF & (consolines_lines[loff + li] >> 8)); 250 | int xEndInt = (0x000000FF & (consolines_lines[loff + li] >> 16)); 251 | int yEndInt = (0x000000FF & (consolines_lines[loff + li] >> 24)); 252 | 253 | // Compute the line start position in 3D space 254 | Vector3 start = (Vector3){ 255 | xOffset + scale * width * ( ((float)xStartInt) / 128), 256 | yOffset - scale * height * (1.0f - ((float)yStartInt) / 128), 257 | 0.0f }; 258 | 259 | start = Vector3Add( 260 | Vector3RotateByQuaternion(start, rotation), location); 261 | 262 | // Compute the line end position in 3D space 263 | Vector3 end = (Vector3){ 264 | xOffset + scale * width * ( ((float)xEndInt) / 128), 265 | yOffset - scale * height * (1.0f - ((float)yEndInt) / 128), 266 | 0.0f }; 267 | 268 | end = Vector3Add( 269 | Vector3RotateByQuaternion(end, rotation), location); 270 | 271 | // If thickness is zero draw as a line otherwise draw as a capsule 272 | if (thick == 0.0f) 273 | { 274 | DrawLine3D(start, end, color); 275 | } 276 | else 277 | { 278 | DrawCapsule(start, end, thick, 5, 2, color); 279 | } 280 | } 281 | 282 | // Shift forward to next location 283 | xOffset += 0.5f * scale * width + spacing; 284 | } 285 | } 286 | } 287 | 288 | //---------------------------------------------------------------------------------- 289 | // App 290 | //---------------------------------------------------------------------------------- 291 | 292 | int main(int argc, char **argv) 293 | { 294 | // Init Window 295 | 296 | const int screenWidth = 640; 297 | const int screenHeight = 360; 298 | 299 | SetConfigFlags(FLAG_VSYNC_HINT); 300 | SetConfigFlags(FLAG_MSAA_4X_HINT); 301 | InitWindow(screenWidth, screenHeight, "Consolines"); 302 | SetTargetFPS(60); 303 | 304 | // Camera 305 | 306 | OrbitCamera camera; 307 | OrbitCameraInit(&camera); 308 | 309 | // Drawing properties 310 | 311 | float thickness = 0.025; 312 | float scale = 1.0f; 313 | float width = 1.0f; 314 | float height = 1.0f; 315 | float spacing = 0.0; 316 | float lineheight = 1.0f; 317 | 318 | // Go 319 | 320 | while (!WindowShouldClose()) 321 | { 322 | // Update Camera 323 | 324 | OrbitCameraUpdate( 325 | &camera, 326 | (Vector3){ 0.0f, 1.5f, 0.0f }, 327 | (IsKeyDown(KEY_LEFT_CONTROL) && IsMouseButtonDown(0)) ? GetMouseDelta().x : 0.0f, 328 | (IsKeyDown(KEY_LEFT_CONTROL) && IsMouseButtonDown(0)) ? GetMouseDelta().y : 0.0f, 329 | (IsKeyDown(KEY_LEFT_CONTROL) && IsMouseButtonDown(1)) ? GetMouseDelta().x : 0.0f, 330 | (IsKeyDown(KEY_LEFT_CONTROL) && IsMouseButtonDown(1)) ? GetMouseDelta().y : 0.0f, 331 | GetMouseWheelMove(), 332 | GetFrameTime()); 333 | 334 | // Draw Text 335 | 336 | BeginDrawing(); 337 | 338 | BeginMode3D(camera.cam3d); 339 | 340 | ClearBackground(RAYWHITE); 341 | 342 | const char* testSentence = 343 | "the quick brown fox jumps over the lazy dog\n" 344 | "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\n" 345 | "!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`{|}~"; 346 | 347 | DrawDebugText3D( 348 | testSentence, 349 | (Vector3){ -10.0f, 3.1f, 0.0f }, 350 | QuaternionIdentity(), 351 | RED, 352 | thickness, 353 | scale, 354 | width, 355 | height, 356 | spacing, 357 | lineheight); 358 | 359 | DrawGrid(10, 1.0f); 360 | 361 | EndMode3D(); 362 | 363 | // UI 364 | 365 | GuiSliderBar((Rectangle){ 80, 10, 80, 20 }, "thickness", TextFormat("%4.2f", thickness), &thickness, 0.0f, 0.1f); 366 | GuiSliderBar((Rectangle){ 80, 40, 80, 20 }, "scale", TextFormat("%4.2f", scale), &scale, 0.0f, 2.0f); 367 | GuiSliderBar((Rectangle){ 280, 10, 80, 20 }, "width", TextFormat("%4.2f", width), &width, 0.0f, 2.0f); 368 | GuiSliderBar((Rectangle){ 280, 40, 80, 20 }, "height", TextFormat("%4.2f", height), &height, 0.0f, 2.0f); 369 | GuiSliderBar((Rectangle){ 480, 10, 80, 20 }, "spacing", TextFormat("%4.2f", spacing), &spacing, 0.0f, 1.0f); 370 | GuiSliderBar((Rectangle){ 480, 40, 80, 20 }, "lineheight", TextFormat("%4.2f", lineheight), &lineheight, 0.0f, 2.0f); 371 | 372 | EndDrawing(); 373 | } 374 | 375 | CloseWindow(); 376 | 377 | return 0; 378 | } -------------------------------------------------------------------------------- /generate.py: -------------------------------------------------------------------------------- 1 | from xml.dom import minidom 2 | from svgpathtools import parse_path 3 | import numpy as np 4 | 5 | """ Parse SVG XML and extract lines """ 6 | 7 | doc = minidom.parse('Consolines.svg') 8 | path_strings = [path.getAttribute('d') for path in doc.getElementsByTagName('path')] 9 | doc.unlink() 10 | 11 | lines = [] 12 | 13 | for path_string in path_strings: 14 | 15 | elem = parse_path(path_string) 16 | 17 | c0 = np.array([elem[0].start.real, 128 - elem[0].start.imag]) 18 | c1 = np.array([elem[1].start.real, 128 - elem[1].start.imag]) 19 | c2 = np.array([elem[2].start.real, 128 - elem[2].start.imag]) 20 | c3 = np.array([elem[3].start.real, 128 - elem[3].start.imag]) 21 | 22 | lines.append([(c0 + c1) / 2, (c2 + c3) / 2]) 23 | 24 | lines = np.round((np.array(lines) - 0.5)).astype(np.int32) 25 | 26 | """ Extract lines for each individual character """ 27 | 28 | numchars = 94 29 | cwidth = 64 30 | cheight = 128 31 | 32 | charlines = [] 33 | 34 | for i in range(numchars): 35 | 36 | minwidth = (i + 0) * cwidth 37 | maxwidth = (i + 1) * cwidth 38 | 39 | charlines.append([]) 40 | for line in lines: 41 | if np.all((line[:,0] > minwidth) & (line[:,0] <= maxwidth)): 42 | charlines[i].append(line - np.array([minwidth, 0])) 43 | 44 | charlines[i] = np.clip(np.array(charlines[i]), 0, 127) 45 | 46 | """ Plot each Character """ 47 | 48 | debug = False 49 | # debug = True 50 | if debug: 51 | for ci, char in enumerate(charlines): 52 | print(chr(ci + ord('!')), len(char)) 53 | 54 | import matplotlib.pyplot as plt 55 | for char in charlines: 56 | for line in char: 57 | plt.plot(line[:,0], line[:,1], color='red', linewidth=1.0) 58 | plt.xlim([0, cwidth]) 59 | plt.ylim([0, cheight]) 60 | plt.gca().set_aspect('equal') 61 | plt.show() 62 | 63 | """ Generate lookup table """ 64 | 65 | sizes = np.array([len(char) for char in charlines]) 66 | offsets = [] 67 | data = [] 68 | 69 | for ci, char in enumerate(charlines): 70 | 71 | offsets.append(len(data)) 72 | 73 | for li in range(len(char)): 74 | 75 | data.append( 76 | (char[li,0,0] << 0) | 77 | (char[li,0,1] << 8) | 78 | (char[li,1,0] << 16) | 79 | (char[li,1,1] << 24)) 80 | 81 | output = "static const char consolines_nums[94] = {\n " 82 | 83 | for ci in range(len(charlines)): 84 | 85 | output += ('%2i' % sizes[ci]) 86 | 87 | if ci != len(charlines) - 1: output += ', ' 88 | if ci != len(charlines) - 1 and ci > 0 and (ci + 1) % 18 == 0: 89 | output += '\n ' 90 | 91 | output += "\n};\n\n" 92 | 93 | 94 | output += "static const int consolines_offsets[94] = {\n " 95 | 96 | for ci in range(len(charlines)): 97 | 98 | output += ('%3i' % offsets[ci]) 99 | 100 | if ci != len(charlines) - 1: output += ', ' 101 | if ci != len(charlines) - 1 and ci > 0 and (ci + 1) % 14 == 0: 102 | output += '\n ' 103 | 104 | output += "\n};\n\n" 105 | 106 | output += "static const int consolines_lines[%i] = {\n " % len(data) 107 | 108 | for di in range(len(data)): 109 | 110 | output += ('0x%08X' % data[di]) 111 | 112 | if di != len(data) - 1: output += ', ' 113 | if di != len(data) - 1 and di > 0 and (di + 1) % 6 == 0: 114 | output += '\n ' 115 | 116 | output += "\n};\n\n" 117 | 118 | print('\n\n') 119 | print(output) 120 | 121 | --------------------------------------------------------------------------------