├── .gitattributes ├── README.md ├── UNLICENSE ├── examples ├── clip │ ├── clip.nim │ └── nim.cfg ├── demo │ ├── demo.nim │ ├── greeting.txt │ ├── nim.cfg │ └── squinkle.png ├── flags │ ├── flags.nim │ └── nim.cfg ├── headless │ ├── headless.nim │ └── nim.cfg ├── hello │ ├── ch.png │ ├── hello.nim │ └── nim.cfg ├── opengl │ ├── nim.cfg │ ├── ogl.nim │ ├── oglc.nim │ ├── oglcc.nim │ ├── run.bat │ └── run.sh └── shader │ ├── nim.cfg │ └── shader.nim ├── src ├── tigr.nim └── tigr │ ├── tigr.c │ └── tigr.h ├── tests ├── nim.cfg ├── test.nim └── tester.nim └── tigr.nimble /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=nim 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TIGR - TIny GRaphics library 2 | 3 | ![](https://github.com/erkkah/tigr/blob/master/tigr.png) 4 | 5 | Copy [erkkah/tigr](https://github.com/erkkah/tigr) 6 | Use it with nim language :) 7 | 8 | TIGR is a tiny cross-platform graphics library, 9 | providing a unified API for Windows, macOS, Linux, iOS and Android. 10 | 11 | TIGR's core is a simple framebuffer library. 12 | On top of that, we provide a few helpers for the common tasks that 2D programs generally need: 13 | 14 | - Bitmap-backed windows. 15 | - Direct access to bitmaps, no locking. 16 | - Basic drawing helpers (plot, line, blitter). 17 | - Text output using bitmap fonts. 18 | - Mouse, touch and keyboard input. 19 | - PNG loading and saving. 20 | - Easy pixel shader access. 21 | 22 | TIGR is designed to be small and independent. 23 | The 'hello world' example is less than 100kB: 24 | 25 | | *Platform* | *Size* | 26 | | --- | --- | 27 | | windows x86_64 | 48k | 28 | | linux x86_64 | 43k | 29 | | macOS arm64 | 90k | 30 | | macOS x86_64 | 74k | 31 | 32 | There are no additional libraries to include; everything is baked right into your program. 33 | 34 | TIGR is free to copy with no restrictions; see [tigr.nim](src/tigr.nim). 35 | 36 | ## How do I program with TIGR? 37 | ![](https://github.com/Angluca/tigr/blob/master/demo.gif) 38 | 39 | Here's an example Hello World program. For more information, just read [tigr.nim](src/tigr.nim) to see the APIs available. 40 | 41 | ```nim 42 | import tigr 43 | 44 | var screen = window(320, 240, "Hello", 0) 45 | while screen.closed() == 0: 46 | screen.clear(RGB(0x80, 0x90, 0xa0)) 47 | screen.print(tfont, 120, 110, tigr.RGB(0xff, 0xff, 0xff), "Hello the world!"); 48 | # c: tigrUpdate,tigrRGB ... == nim: tigr.update, tigr.RGB ... 49 | update(screen) # == screen.update() == tigr.update(screen) 50 | ``` 51 | 52 | ## How to use TIGR 53 | ```bash 54 | # first install and test 55 | nimble install # or nimble install tigr 56 | nimble test 57 | ``` 58 | ### Desktop (Windows, macOS, Linux) 59 | ... 60 | ### Android 61 | 62 | Due to the complex lifecycle and packaging of Android apps 63 | (there is no such thing as a single source file Android app), 64 | a tiny wrapper around TIGR is needed. Still - the TIGR API stays the same! 65 | 66 | To keep TIGR as tiny and focused as it is, the Android wrapper lives in a separate repo. 67 | 68 | To get started on Android, head over to the [TIMOGR](https://github.com/erkkah/timogr) repo and continue there. 69 | 70 | ### iOS 71 | 72 | On iOS, TIGR is implemented as an app delegate, which can be used in your app with just a few lines of code. 73 | 74 | Building an iOS app usually requires quite a bit of tinkering in Xcode just to get up and running. To get up and running **fast**, there is an iOS starter project with a completely commandline-based tool chain, and VS Code configurations for debugging. 75 | 76 | To get started on iOS, head over to the [TIMOGRiOS](https://github.com/erkkah/timogrios) repo and continue there. 77 | 78 | > NOTE: TIGR is included in TIMOGR and TIMOGRiOS, there is no need to install TIGR separately. 79 | 80 | ## Fonts and shaders 81 | 82 | ### Custom fonts 83 | 84 | TIGR comes with a built-in bitmap font, accessed by the `tfont` variable. Custom fonts can be loaded from bitmaps using `tigrLoadFont`. A font bitmap contains rows of characters separated by same-colored borders. TIGR assumes that the borders use the same color as the top-left pixel in the bitmap. Each character is assumed to be drawn in white on a transparent background to make tinting work. 85 | 86 | Use the [tigrfont](https://github.com/erkkah/tigrfont) tool to create your own bitmap fonts from TTF or BDF font files. 87 | 88 | ### Custom pixel shaders 89 | 90 | TIGR uses a built-in pixel shader that provides a couple of stock effects as controlled by `tigrSetPostFX`. 91 | These stock effects can be replaced by calling `tigrSetPostShader` with a custom shader. 92 | The custom shader is in the form of a shader function: `void fxShader(out vec4 color, in vec2 uv)` and has access to the four parameters from `tigrSetPostFX` as a `uniform vec4` called `parameters`. 93 | 94 | See the [shader example](examples/shader/shader.nim) for more details. 95 | 96 | ## Known issues 97 | ... 98 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Our intent is that anyone is free to copy and use this software, 4 | for any purpose, in any form, and by any means. 5 | 6 | The authors dedicate any and all copyright interest in the software 7 | to the public domain, at their own expense for the betterment of mankind. 8 | 9 | The software is provided "as is", without any kind of warranty, including 10 | any implied warranty. If it breaks, you get to keep both pieces. 11 | -------------------------------------------------------------------------------- /examples/clip/clip.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | 3 | var 4 | screen = window(320, 240, "Clip", 0) 5 | c0 = RGB(0x32, 0x32, 0x32) 6 | c1 = RGB(0xff, 0xff, 0xff) 7 | c2 = tigr.RGB(0x64, 0xc8, 0x64) 8 | c3 = tigr.RGBA(0x64, 0x64, 0xc8, 0x96) 9 | cx, cy, w, d: int 10 | iquit = 200 11 | 12 | while screen.closed() == 0 and 13 | screen.keyDown(TK_ESCAPE) == 0 and 14 | iquit > 0: 15 | screen.clear(c0) 16 | cx = screen.w div 2; cy = (screen.h / 2).int # div:int, /:float 17 | w = 100; d = 50 18 | 19 | screen.clip(cx - d, cy - d, w, w) 20 | screen.fill(cx - d, cy - d, w, w, c1) 21 | 22 | screen.rect(cx - w, cy - w, w, w, c2) 23 | screen.fillRect(cx - w, cy - w, w, w, c3) 24 | 25 | screen.circle(cx + d, cy - d, d, c2) 26 | screen.fillCircle(cx + d, cy - d, d, c3) 27 | let 28 | msg = ("Half a thought is also a thought, " & $iquit).cstring 29 | tw = tfont.textWidth(msg) 30 | th = tfont.textHeight(msg) 31 | screen.print(tfont, cx - tw div 2, cy + d - th div 2, c1, msg) 32 | screen.update() 33 | iquit.dec 34 | 35 | screen.free() 36 | 37 | -------------------------------------------------------------------------------- /examples/clip/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../../src" 2 | -------------------------------------------------------------------------------- /examples/demo/demo.nim: -------------------------------------------------------------------------------- 1 | import tigr, math, system/ansi_c 2 | 3 | var 4 | playerx = 160f 5 | playery = 200'f 6 | playerxs, playerys: float 7 | standing = true 8 | jumps = 0 9 | is_fly = false 10 | remaining: float 11 | backdrop, screen: ptr Tigr 12 | 13 | proc myUpdate(dt: float) = 14 | if is_fly: return 15 | if remaining > 0: 16 | remaining -= dt 17 | 18 | # Read the keyboard and move the player. 19 | if (standing or jumps < 2) and ((keyDown(screen, TK_SPACE)!=0) or 20 | (keyDown(screen, 'W')!=0)): 21 | playerys -= (200 - jumps * 50).float 22 | jumps.inc 23 | elif screen.keyDown(TK_DOWN)!=0 or keyHeld(screen, 'S')!=0: 24 | if standing: jumps = -1 25 | playerys += 20 26 | if screen.keyDown(TK_LEFT)!=0 or keyHeld(screen, 'A')!=0: 27 | playerxs -= 10 28 | elif screen.keyDown(TK_RIGHT)!=0 or keyHeld(screen, 'D')!=0: 29 | playerxs += 10 30 | 31 | var oldx = playerx; var oldy = playery 32 | 33 | # Apply simply physics. 34 | playerxs *= exp(-10f * dt) 35 | playerys *= exp(-2f * dt) 36 | playerys += dt * 200f 37 | playerx += dt * playerxs 38 | playery += dt * playerys 39 | 40 | # Apply collision 41 | if playerx.int < 8: 42 | playerx = 8f; playerxs = 0f 43 | 44 | if playerx.int > screen.w - 8: 45 | playerx = screen.w.float - 8 46 | playerxs = 0 47 | 48 | if playery.int < 0: 49 | is_fly = true 50 | # Apply playfield collision and stepping. 51 | var 52 | dx = (playerx - oldx) / 10 53 | dy = (playery - oldy) / 10 54 | standing = false 55 | for i in 0..<10: 56 | var p = get(backdrop, oldx, oldy - 1) 57 | if p.r == 0 and p.g == 0 and p.b == 0: 58 | oldy -= 1 59 | p = get(backdrop, oldx, oldy) 60 | if p.r == 0 and p.g == 0 and p.b == 0 and playerys > 0: 61 | standing = true 62 | if jumps < 0: oldy += 2 63 | playerys = 0 64 | dy = 0 65 | oldx += dx 66 | oldy += dy 67 | if standing: jumps = 0 68 | 69 | playerx = oldx 70 | playery = oldy 71 | 72 | proc main() = 73 | # Load out sprite 74 | let squinkle = loadImage("squinkle.png") 75 | if squinkle.isNil: error(nil, "Cant load squinkle.png") 76 | 77 | # Load some UTF8 text 78 | let greeting = readFile("greeting.txt", nil) 79 | if greeting.isNil: error(nil, "Cant load greeting.txt") 80 | 81 | # Make a window and an off-screen backdrop 82 | screen = window(320, 240, greeting, TIGR_2X) 83 | backdrop = bitmap(screen.w, screen.h) 84 | 85 | # Fill in the background 86 | clear(backdrop, RGB(80, 180, 255)) 87 | fill(backdrop, 0, 200, 320, 40, RGB(60, 120, 60)) 88 | fill(backdrop, 0, 200, 320, 3, tigr.RGB(0, 0, 0)) 89 | line(backdrop, 0, 201, 320, 201, RGB(0xff, 0xff, 0xff)) 90 | 91 | # Enable post fx 92 | screen.setPostFX(1, 1, 1, 2f) 93 | 94 | # Maintain a list of characters entered. 95 | var chars: array[16, char] 96 | c_memset(chars.addr, '_', 16) 97 | var 98 | dt: float 99 | x, y, b: cint 100 | prevx, prevy, prev: int 101 | 102 | # Repeat till they close the window. 103 | while screen.closed() == 0 and 104 | screen.keyDown(TK_ESCAPE) == 0: 105 | # Update game 106 | dt = tigr.time() 107 | myUpdate(dt) 108 | 109 | # Read the mouse and draw when pressed. 110 | screen.mouse(x.addr, y.addr, b.addr) 111 | if (b and 1) > 0: 112 | if prev != 0: 113 | line(backdrop, prevx, prevy, x, y, RGB(0, 0, 0)) 114 | prevx = x; prevy = y; prev = 1 115 | else: prev = 0 116 | 117 | # Composite the backdrop and sprite onto the screen. 118 | screen.blit(backdrop, 0, 0, 0, 0, backdrop.w, backdrop.h) 119 | screen.blitAlpha(squinkle, playerx.cint - squinkle.w div 2, playery.cint - squinkle.h, 0, 0, squinkle.w, squinkle.h, 1.0f) 120 | screen.print(tfont, 10, 10, RGBA(0xc0, 0xd0, 0xff, 0xc0), greeting) 121 | screen.print(tfont, 10, 222, RGBA(0xff, 0xff, 0xff, 0xff), "W A S D + SPACE") 122 | 123 | if is_fly: 124 | screen.print(tfont, screen.w div 3, screen.h div 2 - 10, RGBA(0xff, 0x66, 0x66, 0xCC), "He has reached Mars ...") 125 | #Grab any chars and add them to our buffer. 126 | while true: 127 | let c = screen.readChar() 128 | if c == 0: break 129 | for n in 1..<16: 130 | chars[n - 1] = chars[n] 131 | chars[15] = c.chr 132 | 133 | # Print out the character buffer too. 134 | var 135 | tmp {.global.} : array[128, char] 136 | p: cstring = cast[cstring](tmp[0].addr) 137 | for n in 0..<16: 138 | p = encodeUTF8(p, chars[n]) 139 | screen.print(tfont, 160, 222, RGB(0xff, 0xff, 0xff), "Chars: %s", tmp[0].addr) 140 | zeroMem(tmp[0].addr, tmp.sizeof) 141 | 142 | # Update the window 143 | screen.update() 144 | 145 | squinkle.free() 146 | backdrop.free() 147 | screen.free() 148 | 149 | main() 150 | 151 | -------------------------------------------------------------------------------- /examples/demo/greeting.txt: -------------------------------------------------------------------------------- 1 | ¡Hola! Välkommen! 2 | You can draw in here with the mouse. 3 | -------------------------------------------------------------------------------- /examples/demo/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../../src" 2 | -------------------------------------------------------------------------------- /examples/demo/squinkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Angluca/tigr-nim/a393af23c9ba52bfc53941a08bafbb0189d5e2ff/examples/demo/squinkle.png -------------------------------------------------------------------------------- /examples/flags/flags.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | 3 | template makeDemoWindow(w, h, flags: int): ptr Tigr = 4 | window(w, h, "flag tester", flags) 5 | 6 | proc drawDemoWindow(win: ptr Tigr) = 7 | let lineColor {.global.} = RGB(100, 100, 100) 8 | win.line(0, 0, win.w - 1, win.h - 1, lineColor) 9 | win.line(0, win.h - 1, win.w - 1, 0, lineColor) 10 | line(win, 0, 0, win.w, win.h, RGB(200, 10, 10)) 11 | print(win, tfont, 5, 5, RGB(20, 200, 0), "%dx%d", win.w, win.h) 12 | 13 | var aaaa:int = 100.cint 14 | type Toggle = tuple 15 | text: cstring 16 | checked: int 17 | value: int 18 | key: int 19 | color: TPixel 20 | template mkTg(text: string, b, v: int, k: char, p:TPixel): Toggle = 21 | (text.cstring,b, v, k.ord, p) 22 | 23 | proc drawToggle(bmp: ptr Tigr, toggle: ptr Toggle, x, y, stride: int) = 24 | var 25 | height = textHeight(tfont, toggle.text) 26 | width = textWidth(tfont, toggle.text) 27 | 28 | yOffset = stride div 2 29 | xOffset = width div -2 30 | 31 | print(bmp, tfont, x + xOffset, y + yOffset, toggle.color, toggle.text) 32 | 33 | yOffset += (if toggle.checked!=0: height else: height div 3) 34 | var lineColor = toggle.color 35 | lineColor.a = 240 36 | bmp.line(x + xOffset, y + yOffset, x + xOffset + width, y + yOffset, lineColor) 37 | 38 | # main 39 | var 40 | flags = 0 41 | initialW, initialH = 400 42 | win = makeDemoWindow(initialW, initialH, flags) 43 | white = RGB(0xff, 0xff, 0xff) 44 | yellow = RGB(0xff, 0xff, 0) 45 | black = tigr.RGB(0, 0, 0) 46 | toggles = [ 47 | mkTg("Key(A)", 0, TIGR_AUTO, 'A', white), 48 | mkTg("Key(R)ETINA", 0, TIGR_RETINA, 'R', white), 49 | mkTg("Key(F)ULLSCREEN", 0, TIGR_FULLSCREEN, 'F', white), 50 | mkTg("Key(2)X", 0, TIGR_2X, '2', yellow), 51 | mkTg("Key(3)X", 0, TIGR_3X, '3', yellow), 52 | mkTg("Key(4)X", 0, TIGR_4X, '4', yellow), 53 | mkTg("Key(N)OCURSOR", 0, TIGR_NOCURSOR, 'N', white), 54 | ] 55 | 56 | while closed(win) == 0 and 57 | keyDown(win, TK_ESCAPE) == 0: 58 | win.clear(black) 59 | 60 | win.drawDemoWindow() 61 | var 62 | numToggles = toggles.sizeof div toggles[0].sizeof 63 | stepY = win.h div numToggles 64 | toggleY = 0 65 | toggleX = win.w div 2 66 | block: 67 | var newFlags = 0 68 | for i in 0.. 0: 10 | screen.clear(tigr.RGB(0x80, 0x90, 0xa0)) 11 | screen.print(tfont, 40, 96, tigr.RGB(0xff, 0xff, 0xff), "Hello the world! %d" , iquit); 12 | screen.print(font, 40, 110, tigr.RGB(0xff, 0xff, 0xff), r"你好, 让我试试//效果如何哈!!!" , iquit); 13 | screen.print(font, 40, 120, tigr.RGB(0xff, 0xff, 0xff), r"abcdefg hijklmnopqrstuvwxyzABCDEFG HIJKLMNOPQRSTUVWXYZ" , iquit); 14 | screen.print(font, 40, 130, tigr.RGB(0xff, 0xff, 0xff), r",./\!@#$%^&*(){}[]-=_+?!!" , iquit); 15 | # c: tigrUpdate,tigrRGB ... == nim: tigr.update, tigr.RGB ... 16 | update(screen) # == screen.update() == tigr.update(screen) 17 | iquit.dec 18 | -------------------------------------------------------------------------------- /examples/hello/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../../src" 2 | -------------------------------------------------------------------------------- /examples/opengl/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../../src" 2 | -------------------------------------------------------------------------------- /examples/opengl/ogl.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | import opengl 3 | # nimble install opengl 4 | 5 | var 6 | win1 = window(320, 240, "ogl #1", 0) 7 | win2 = window(320, 240, "ogl #2", 0) 8 | while not win1.isNil or not win2.isNil: 9 | if not win1.isNil: 10 | win1.clear(RGB(0x80, 0x90, 0xa0)) 11 | win1.print(tfont, 80, 110, RGB(0xff, 0xff, 0xff), 12 | "nim code -------------- #1.") 13 | win1.update() 14 | if win1.closed()!=0 or win1.keyDown(TK_ESCAPE)!=0: 15 | win1.free() 16 | win1 = nil 17 | if not win2.isNil: 18 | if win2.beginOpenGL()!=0: 19 | glClearColor(1.0, 0.0, 1.0, 10.0); 20 | glClear(GL_COLOR_BUFFER_BIT); 21 | win2.clear(RGBA(0x00, 0x00, 0x00, 0x00)) 22 | win2.print(tfont, 80, 110, RGB(0xff, 0xff, 0xff), 23 | "nim code -------------- #2.") 24 | win2.update() 25 | if win2.closed()!=0 or win2.keyDown(TK_ESCAPE)!=0: 26 | win2.free() 27 | win2 = nil 28 | if not win1.isNil(): 29 | win1.free() 30 | if not win2.isNil(): 31 | win2.free() 32 | -------------------------------------------------------------------------------- /examples/opengl/oglc.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | 3 | # Lazy write nim func bind gl header, So run c code :) 4 | {.emit: """ 5 | #include 6 | #ifdef _WIN32 7 | #include 8 | #include 9 | #elif defined __linux__ 10 | #include 11 | #else 12 | #define GL_SILENCE_DEPRECATION 13 | #include 14 | #endif 15 | 16 | NIM_EXTERNC 17 | void test(){ 18 | glClearColor(1, 0, 1, 1); 19 | glClear(GL_COLOR_BUFFER_BIT); 20 | } 21 | """.} 22 | proc test() {.importc:"$1".} 23 | 24 | var 25 | win1 = window(320, 240, "ogl #1", 0) 26 | win2 = tigr.window(320, 240, "ogl #2", 0) 27 | while not win1.isNil or not win2.isNil: 28 | if not win1.isNil: 29 | win1.clear(RGB(0x80, 0x90, 0xa0)) 30 | win1.print(tfont, 80, 110, RGB(0xff, 0xff, 0xff), 31 | "nimcc code -------------- #1.") 32 | win1.update() 33 | if win1.closed()!=0 or win1.keyDown(TK_ESCAPE)!=0: 34 | win1.free() 35 | win1 = nil 36 | if not win2.isNil: 37 | if win2.beginOpenGL()!=0: 38 | test() # test:) ------- I'm Here !! -------- 39 | win2.clear(RGBA(0x00, 0x00, 0x00, 0x00)) 40 | win2.print(tfont, 80, 110, RGB(0xff, 0xff, 0xff), 41 | "nimcc code -------------- #2.") 42 | win2.update() 43 | if win2.closed()!=0 or win2.keyDown(TK_ESCAPE)!=0: 44 | win2.free() 45 | win2 = nil 46 | if not win1.isNil(): 47 | win1.free() 48 | if not win2.isNil(): 49 | win2.free() 50 | -------------------------------------------------------------------------------- /examples/opengl/oglcc.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | # Lazy write, Direct run use c code :) 3 | proc test():cint {.importc:"$#".} 4 | {.emit:""" 5 | #include 6 | #include "tigr/tigr.h" 7 | #ifdef _WIN32 8 | #include 9 | #include 10 | #elif defined __linux__ 11 | #include 12 | #else 13 | #define GL_SILENCE_DEPRECATION 14 | #include 15 | #endif 16 | 17 | NIM_EXTERNC 18 | int test() { 19 | Tigr* win1 = tigrWindow(320, 240, "oglcc #1", 0); 20 | Tigr* win2 = tigrWindow(320, 240, "oglcc #2", 0); 21 | while (win1 || win2) { 22 | if (win1) { 23 | tigrClear(win1, tigrRGB(0x80, 0x90, 0xa0)); 24 | tigrPrint(win1, tfont, 80, 110, tigrRGB(0xff, 0xff, 0xff), "c code ===================== #1."); 25 | tigrUpdate(win1); 26 | 27 | if (tigrClosed(win1) || tigrKeyDown(win1, TK_ESCAPE)) { 28 | tigrFree(win1); 29 | win1 = NULL; 30 | } 31 | } 32 | 33 | if (win2) { 34 | if (tigrBeginOpenGL(win2)) { 35 | glClearColor(1, 0, 1, 1); 36 | glClear(GL_COLOR_BUFFER_BIT); 37 | } 38 | 39 | tigrClear(win2, tigrRGBA(0x00, 0x00, 0x00, 0x00)); 40 | tigrPrint(win2, tfont, 80, 110, tigrRGB(0xff, 0xff, 0xff), "c code ===================== #2."); 41 | tigrUpdate(win2); 42 | 43 | if (tigrClosed(win2) || tigrKeyDown(win2, TK_ESCAPE)) { 44 | tigrFree(win2); 45 | win2 = NULL; 46 | } 47 | } 48 | } 49 | if (win1) 50 | tigrFree(win1); 51 | if (win2) 52 | tigrFree(win2); 53 | 54 | return 666; 55 | } 56 | """.} 57 | echo "ogl2 test end: return ", test() 58 | -------------------------------------------------------------------------------- /examples/opengl/run.bat: -------------------------------------------------------------------------------- 1 | nimble install opengl 2 | nim c ogl.nim 3 | nim c oglc.nim 4 | nim c oglcc.nim 5 | ./oglc.exe 6 | -------------------------------------------------------------------------------- /examples/opengl/run.sh: -------------------------------------------------------------------------------- 1 | nimble install opengl 2 | nim c ogl.nim 3 | nim c oglc.nim 4 | nim c oglcc.nim 5 | ./oglc -------------------------------------------------------------------------------- /examples/shader/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../../src" 2 | -------------------------------------------------------------------------------- /examples/shader/shader.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | 3 | const fxShader: cstring = """ 4 | void fxShader(out vec4 color, in vec2 uv) { 5 | vec2 tex_size = vec2(textureSize(image, 0)); 6 | vec4 c = texture(image, (floor(uv * tex_size) + 0.5 * sin(parameters.x)) / tex_size); 7 | color = c; 8 | } 9 | """ 10 | 11 | var screen = window(320, 240, "Shady", 0) 12 | screen.setPostShader(fxShader, fxShader.len - 1); 13 | var 14 | duration = 1.0f 15 | phase = 0.0f 16 | iquit = 500 17 | p: float 18 | while screen.closed() == 0 and 19 | screen.keyDown(TK_ESCAPE) == 0 and 20 | iquit > 0: 21 | phase += tigr.time() 22 | while phase > duration: 23 | phase -= duration 24 | p = 6.28 * phase / duration 25 | screen.setPostFX(p, 0, 0, 0) 26 | screen.clear(RGB(0x80, 0x90, 0xa0)) 27 | screen.print(tfont, 120, 110, RGB(0xff, 0xff, 0xff), "Shady business: %d", iquit) 28 | screen.update() 29 | iquit.dec 30 | 31 | screen.free() 32 | -------------------------------------------------------------------------------- /src/tigr.nim: -------------------------------------------------------------------------------- 1 | ## TIGR - TIny GRaphics Library - v3.1 2 | ## ^^ ^^ 3 | ## 4 | ## rawr. 5 | ## 6 | ## This is free and unencumbered software released into the public domain. 7 | ## 8 | ## Our intent is that anyone is free to copy and use this software, 9 | ## for any purpose, in any form, and by any means. 10 | ## 11 | ## The authors dedicate any and all copyright interest in the software 12 | ## to the public domain, at their own expense for the betterment of mankind. 13 | ## 14 | ## The software is provided "as is", without any kind of warranty, including 15 | ## any implied warranty. If it breaks, you get to keep both pieces. 16 | ## 17 | 18 | ## Compiler configuration. 19 | #{.warning[CStringConv]:off.} 20 | when defined(windows): 21 | {.passL: "-s -lopengl32 -lgdi32".} 22 | elif defined(macosx): 23 | {.passL: "-framework OpenGL -framework Cocoa".} 24 | else: 25 | {.passL: "-s -lGLU -lGL -lX11".} 26 | from strutils import replace 27 | {.pragma: tigr, header: "tigr/tigr.h"} 28 | const tigrDir = currentSourcePath.replace("\\", "/")[0..^9] 29 | {.compile: "tigr/tigr.c", passC: "-I" & tigrDir.} 30 | 31 | ## Bitmaps ---------------------------------------------------------------- 32 | type 33 | tcint = cint 34 | tcuint = cuint 35 | tcfloat = cfloat 36 | ## This struct contains one pixel. 37 | type 38 | TPixel* {.importc: "TPixel", tigr, bycopy.} = object 39 | r* {.importc: "r".}: byte 40 | g* {.importc: "g".}: byte 41 | b* {.importc: "b".}: byte 42 | a* {.importc: "a".}: byte 43 | 44 | ## Window flags. 45 | const 46 | TIGR_FIXED* = 0 47 | TIGR_AUTO* = 1 48 | TIGR_2X* = 2 49 | TIGR_3X* = 4 50 | TIGR_4X* = 8 51 | TIGR_RETINA* = 16 52 | TIGR_NOCURSOR* = 32 53 | TIGR_FULLSCREEN* = 64 54 | 55 | ## A Tigr bitmap. 56 | type 57 | Tigr* {.importc: "Tigr", tigr, bycopy.} = object 58 | w* {.importc: "w".}: tcint 59 | h* {.importc: "h".}: tcint 60 | ## width/height (unscaled) 61 | cx* {.importc: "cx".}: tcint 62 | cy* {.importc: "cy".}: tcint 63 | cw* {.importc: "cw".}: tcint 64 | ch* {.importc: "ch".}: tcint 65 | ## clip rect 66 | pix* {.importc: "pix".}: ptr TPixel 67 | ## pixel data 68 | handle* {.importc: "handle".}: pointer 69 | ## OS window handle, NULL for off-screen bitmaps. 70 | blitMode* {.importc: "blitMode".}: tcint 71 | ## Target bitmap blit mode 72 | 73 | ## Creates a new empty window with a given bitmap size. 74 | ## 75 | ## Title is UTF-8. 76 | ## 77 | ## In TIGR_FIXED mode, the window is made as large as possible to contain an integer-scaled 78 | ## version of the bitmap while still fitting on the screen. Resizing the window will adapt 79 | ## the scale in integer steps to fit the bitmap. 80 | ## 81 | ## In TIGR_AUTO mode, the initial window size is set to the bitmap size times the pixel 82 | ## scale. Resizing the window will resize the bitmap using the specified scale. 83 | ## For example, in forced 2X mode, the window will be twice as wide (and high) as the bitmap. 84 | ## 85 | ## Turning on TIGR_RETINA mode will request full backing resolution on OSX, meaning that 86 | ## the effective window size might be integer scaled to a larger size. In TIGR_AUTO mode, 87 | ## this means that the Tigr bitmap will change size if the window is moved between 88 | ## retina and non-retina screens. 89 | ## 90 | proc window*(w: tcint; h: tcint; title: cstring; flags: tcint): ptr Tigr {.cdecl, importc: "tigrWindow", tigr.} 91 | 92 | ## Creates an empty off-screen bitmap. 93 | proc bitmap*(w: tcint; h: tcint): ptr Tigr {.cdecl, importc: "tigrBitmap", tigr.} 94 | 95 | ## Deletes a window/bitmap. 96 | proc free*(bmp: ptr Tigr) {.cdecl, importc: "tigrFree", tigr.} 97 | 98 | ## Returns non-zero if the user requested to close a window. 99 | proc closed*(bmp: ptr Tigr): tcint {.cdecl, importc: "tigrClosed", tigr.} 100 | 101 | ## Displays a window's contents on-screen and updates input. 102 | proc update*(bmp: ptr Tigr) {.cdecl, importc: "tigrUpdate", tigr.} 103 | 104 | ## Called before doing direct OpenGL calls and before tigrUpdate. 105 | ## Returns non-zero if OpenGL is available. 106 | proc beginOpenGL*(bmp: ptr Tigr): tcint {.cdecl, importc: "tigrBeginOpenGL", tigr.} 107 | 108 | ## Sets post shader for a window. 109 | ## This replaces the built-in post-FX shader. 110 | proc setPostShader*(bmp: ptr Tigr; code: cstring; size: tcint) {.cdecl, importc: "tigrSetPostShader", tigr.} 111 | 112 | ## Sets post-FX properties for a window. 113 | ## 114 | ## The built-in post-FX shader uses the following parameters: 115 | ## p1: hblur - use bilinear filtering along the x-axis (pixels) 116 | ## p2: vblur - use bilinear filtering along the y-axis (pixels) 117 | ## p3: scanlines - CRT scanlines effect (0-1) 118 | ## p4: contrast - contrast boost (1 = no change, 2 = 2X contrast, etc) 119 | proc setPostFX*(bmp: ptr Tigr; p1: tcfloat; p2: tcfloat; p3: tcfloat; p4: tcfloat) {.cdecl, importc: "tigrSetPostFX", tigr.} 120 | 121 | ## Drawing ---------------------------------------------------------------- 122 | ## Helper for reading pixels. 123 | ## For high performance, just access bmp->pix directly. 124 | proc get*(bmp: ptr Tigr; x: tcint; y: tcint): TPixel {.cdecl, importc: "tigrGet", tigr.} 125 | 126 | ## Plots a pixel. 127 | ## Clips and blends. 128 | ## For high performance, just access bmp->pix directly. 129 | proc plot*(bmp: ptr Tigr; x: tcint; y: tcint; pix: TPixel) {.cdecl, importc: "tigrPlot", tigr.} 130 | 131 | ## Clears a bitmap to a color. 132 | ## No blending, no clipping. 133 | proc clear*(bmp: ptr Tigr; color: TPixel) {.cdecl, importc: "tigrClear", tigr.} 134 | 135 | ## Fills a rectangular area. 136 | ## No blending, no clipping. 137 | proc fill*(bmp: ptr Tigr; x: tcint; y: tcint; w: tcint; h: tcint; color: TPixel) {.cdecl, importc: "tigrFill", tigr.} 138 | 139 | ## Draws a line. 140 | ## Start pixel is drawn, end pixel is not. 141 | ## Clips and blends. 142 | proc line*(bmp: ptr Tigr; x0: tcint; y0: tcint; x1: tcint; y1: tcint; color: TPixel) {.cdecl, importc: "tigrLine", tigr.} 143 | 144 | ## Draws an empty rectangle. 145 | ## Drawing a 1x1 rectangle yields the same result as calling tigrPlot. 146 | ## Clips and blends. 147 | proc rect*(bmp: ptr Tigr; x: tcint; y: tcint; w: tcint; h: tcint; color: TPixel) {.cdecl, importc: "tigrRect", tigr.} 148 | 149 | ## Fills a rectangle. 150 | ## Fills the inside of the specified rectangular area. 151 | ## Calling tigrRect followed by tigrFillRect using the same arguments 152 | ## causes no overdrawing. 153 | ## Clips and blends. 154 | proc fillRect*(bmp: ptr Tigr; x: tcint; y: tcint; w: tcint; h: tcint; color: TPixel) {.cdecl, importc: "tigrFillRect", tigr.} 155 | 156 | ## Draws a circle. 157 | ## Drawing a zero radius circle yields the same result as calling tigrPlot. 158 | ## Drawing a circle with radius one draws a circle three pixels wide. 159 | ## Clips and blends. 160 | proc circle*(bmp: ptr Tigr; x: tcint; y: tcint; r: tcint; color: TPixel) {.cdecl, importc: "tigrCircle", tigr.} 161 | 162 | ## Fills a circle. 163 | ## Fills the inside of the specified circle. 164 | ## Calling tigrCircle followed by tigrFillCircle using the same arguments 165 | ## causes no overdrawing. 166 | ## Filling a circle with zero radius has no effect. 167 | ## Clips and blends. 168 | proc fillCircle*(bmp: ptr Tigr; x: tcint; y: tcint; r: tcint; color: TPixel) {.cdecl, importc: "tigrFillCircle", tigr.} 169 | 170 | ## Sets clip rect. 171 | ## Set to (0, 0, -1, -1) to reset clipping to full bitmap. 172 | proc clip*(bmp: ptr Tigr; cx: tcint; cy: tcint; cw: tcint; ch: tcint) {.cdecl, importc: "tigrClip", tigr.} 173 | 174 | ## Copies bitmap data. 175 | ## dx/dy = dest co-ordinates 176 | ## sx/sy = source co-ordinates 177 | ## w/h = width/height 178 | ## 179 | ## RGBAdest = RGBAsrc 180 | ## Clips, does not blend. 181 | proc blit*(dest: ptr Tigr; src: ptr Tigr; dx: tcint; dy: tcint; sx: tcint; sy: tcint; w: tcint; h: tcint) {.cdecl, importc: "tigrBlit", tigr.} 182 | 183 | ## Same as tigrBlit, but alpha blends the source bitmap with the 184 | ## target using per pixel alpha and the specified global alpha. 185 | ## 186 | ## Ablend = Asrc * alpha 187 | ## RGBdest = RGBsrc * Ablend + RGBdest * (1 - Ablend) 188 | ## 189 | ## Blit mode == TIGR_KEEP_ALPHA: 190 | ## Adest = Adest 191 | ## 192 | ## Blit mode == TIGR_BLEND_ALPHA: 193 | ## Adest = Asrc * Ablend + Adest * (1 - Ablend) 194 | ## Clips and blends. 195 | proc blitAlpha*(dest: ptr Tigr; src: ptr Tigr; dx: tcint; dy: tcint; sx: tcint; sy: tcint; w: tcint; h: tcint; alpha: tcfloat) {.cdecl, importc: "tigrBlitAlpha", tigr.} 196 | ## Same as tigrBlit, but tcints the source bitmap with a color 197 | ## and alpha blends the resulting source with the destination. 198 | ## 199 | ## Rblend = Rsrc * Rtcint 200 | ## Gblend = Gsrc * Gtcint 201 | ## Bblend = Bsrc * Btcint 202 | ## Ablend = Asrc * Atcint 203 | ## 204 | ## RGBdest = RGBblend * Ablend + RGBdest * (1 - Ablend) 205 | ## 206 | ## Blit mode == TIGR_KEEP_ALPHA: 207 | ## Adest = Adest 208 | ## 209 | ## Blit mode == TIGR_BLEND_ALPHA: 210 | ## Adest = Ablend * Ablend + Adest * (1 - Ablend) 211 | ## Clips and blends. 212 | proc blitTint*(dest: ptr Tigr; src: ptr Tigr; dx: tcint; dy: tcint; sx: tcint; sy: tcint; w: tcint; h: tcint; tcint: TPixel) {.cdecl, importc: "tigrBlitTint", tigr.} 213 | type 214 | TIGRBlitMode* {.size: sizeof(tcint).} = enum 215 | TIGR_KEEP_ALPHA = 0, ## Keep destination alpha value 216 | TIGR_BLEND_ALPHA = 1 ## Blend destination alpha (default) 217 | 218 | 219 | ## Set destination bitmap blend mode for blit operations. 220 | proc blitMode*(dest: ptr Tigr; mode: tcint) {.cdecl, importc: "tigrBlitMode", tigr.} 221 | 222 | ## Helper for making colors. 223 | proc RGB*(r: byte; g: byte; b: byte): TPixel {.inline, cdecl, importc: "tigrRGB".} 224 | 225 | ## Helper for making colors. 226 | proc RGBA*(r: byte; g: byte; b: byte; a: byte): TPixel {.inline, cdecl, importc: "tigrRGBA".} 227 | 228 | ## Font printing ---------------------------------------------------------- 229 | type 230 | TigrGlyph* {.importc: "TigrGlyph", tigr, bycopy.} = object 231 | code* {.importc: "code".}: tcint 232 | x* {.importc: "x".}: tcint 233 | y* {.importc: "y".}: tcint 234 | w* {.importc: "w".}: tcint 235 | h* {.importc: "h".}: tcint 236 | 237 | TigrFont* {.importc: "TigrFont", tigr, bycopy.} = object 238 | bitmap* {.importc: "bitmap".}: ptr Tigr 239 | numGlyphs* {.importc: "numGlyphs".}: tcint 240 | glyphs* {.importc: "glyphs".}: ptr TigrGlyph 241 | 242 | TCodepage* {.size: sizeof(tcint).} = enum 243 | TCP_ASCII = 0 244 | TCP_1252 = 1252 245 | TCP_UTF32 = 12001 246 | 247 | ## Loads a font. The font bitmap should contain all characters 248 | ## for the given codepage, excluding the first 32 control codes. 249 | ## Supported codepages: 250 | ## 0 - Regular 7-bit ASCII 251 | ## 1252 - Windows 1252 252 | proc loadFont*(bitmap: ptr Tigr; codepage: tcint): ptr TigrFont {.cdecl, 253 | importc: "tigrLoadFont", tigr.} 254 | 255 | ## Frees a font. 256 | proc freeFont*(font: ptr TigrFont) {.cdecl, importc: "tigrFreeFont", tigr.} 257 | 258 | ## Prints UTF-8 text onto a bitmap. 259 | ## NOTE: 260 | ## This uses the target bitmap blit mode. 261 | ## See tigrBlittcint for details. 262 | proc print*(dest: ptr Tigr; font: ptr TigrFont; x: tcint; y: tcint; color: TPixel; text: cstring) {.varargs, cdecl, importc: "tigrPrint", tigr.} 263 | 264 | ## Returns the width/height of a string. 265 | proc textWidth*(font: ptr TigrFont; text: cstring): tcint {.cdecl, 266 | importc: "tigrTextWidth", tigr.} 267 | 268 | proc textHeight*(font: ptr TigrFont; text: cstring): tcint {.cdecl, 269 | importc: "tigrTextHeight", tigr.} 270 | 271 | ## The built-in font. 272 | var tfont* {.tigr.}: ptr TigrFont 273 | 274 | ## User Input ------------------------------------------------------------- 275 | ## Key scancodes. For letters/numbers, use ASCII ('A'-'Z' and '0'-'9'). 276 | type 277 | TKey* {.size: sizeof(tcint).} = enum 278 | TK_PAD0 = 128, TK_PAD1, TK_PAD2, TK_PAD3, TK_PAD4, TK_PAD5, TK_PAD6, 279 | TK_PAD7, TK_PAD8, TK_PAD9, TK_PADMUL, TK_PADADD, TK_PADENTER, TK_PADSUB, 280 | TK_PADDOT, TK_PADDIV, TK_F1, TK_F2, TK_F3, TK_F4, TK_F5, TK_F6, TK_F7, 281 | TK_F8, TK_F9, TK_F10, TK_F11, TK_F12, TK_BACKSPACE, TK_TAB, TK_RETURN, 282 | TK_SHIFT, TK_CONTROL, TK_ALT, TK_PAUSE, TK_CAPSLOCK, TK_ESCAPE, TK_SPACE, 283 | TK_PAGEUP, TK_PAGEDN, TK_END, TK_HOME, TK_LEFT, TK_UP, TK_RIGHT, TK_DOWN, 284 | TK_INSERT, TK_DELETE, TK_LWIN, TK_RWIN, TK_NUMLOCK, TK_SCROLL, TK_LSHIFT, 285 | TK_RSHIFT, TK_LCONTROL, TK_RCONTROL, TK_LALT, TK_RALT, TK_SEMICOLON, 286 | TK_EQUALS, TK_COMMA, TK_MINUS, TK_DOT, TK_SLASH, TK_BACKTICK, TK_LSQUARE, 287 | TK_BACKSLASH, TK_RSQUARE, TK_TICK 288 | 289 | 290 | ## Returns mouse input for a window. 291 | proc mouse*(bmp: ptr Tigr; x: ptr cint; y: ptr cint; buttons: ptr cint) {.cdecl, importc: "tigrMouse", tigr.} 292 | 293 | type 294 | TigrTouchPoint* {.importc: "TigrTouchPoint", tigr, bycopy.} = object 295 | x* {.importc: "x".}: tcint 296 | y* {.importc: "y".}: tcint 297 | 298 | ## Reads touch input for a window. 299 | ## Returns number of touch points read. 300 | proc touch*(bmp: ptr Tigr; points: ptr TigrTouchPoint; maxPoints: tcint): tcint {.cdecl, importc: "tigrTouch", tigr.} 301 | 302 | ## Reads the keyboard for a window. 303 | ## Returns non-zero if a key is pressed/held. 304 | ## tigrKeyDown tests for the initial press, tigrKeyHeld repeats each frame. 305 | proc keyDown*(bmp: ptr Tigr; key: tcint): tcint {.cdecl, importc: "tigrKeyDown", tigr.} 306 | 307 | proc keyHeld*(bmp: ptr Tigr; key: tcint): tcint {.cdecl, importc: "tigrKeyHeld", tigr.} 308 | 309 | ## Reads character input for a window. 310 | ## Returns the Unicode value of the last key pressed, or 0 if none. 311 | proc readChar*(bmp: ptr Tigr): tcint {.cdecl, importc: "tigrReadChar", tigr.} 312 | 313 | ## Show / hide virtual keyboard. 314 | ## (Only available on iOS / Android) 315 | proc showKeyboard*(show: tcint) {.cdecl, importc: "tigrShowKeyboard", tigr.} 316 | 317 | ## Bitmap I/O ------------------------------------------------------------- 318 | ## Loads a PNG, from either a file or memory. (fileName is UTF-8) 319 | ## On error, returns NULL and sets errno. 320 | proc loadImage*(fileName: cstring): ptr Tigr {.cdecl, importc: "tigrLoadImage", tigr.} 321 | 322 | proc loadImageMem*(data: pointer; length: tcint): ptr Tigr {.cdecl, 323 | importc: "tigrLoadImageMem", tigr.} 324 | 325 | ## Saves a PNG to a file. (fileName is UTF-8) 326 | ## On error, returns zero and sets errno. 327 | proc saveImage*(fileName: cstring; bmp: ptr Tigr): tcint {.cdecl, 328 | importc: "tigrSaveImage", tigr.} 329 | 330 | ## Helpers ---------------------------------------------------------------- 331 | ## Returns the amount of time elapsed since tigrTime was last called, 332 | ## or zero on the first call. 333 | proc time*(): tcfloat {.cdecl, importc: "tigrTime", tigr.} 334 | 335 | ## Displays an error message and quits. (UTF-8) 336 | ## 'bmp' can be NULL. 337 | proc error*(bmp: ptr Tigr; message: cstring) {.varargs, cdecl, 338 | importc: "tigrError", tigr.} 339 | 340 | ## Reads an entire file into memory. (fileName is UTF-8) 341 | ## Free it yourself after with 'free'. 342 | ## On error, returns NULL and sets errno. 343 | ## TIGR will automatically append a NUL terminator byte 344 | ## to the end (not included in the length) 345 | proc readFile*(fileName: cstring; length: ptr cint): cstring {.cdecl, importc: "tigrReadFile", tigr.} 346 | 347 | ## Decompresses DEFLATEd zip/zlib data into a buffer. 348 | ## Returns non-zero on success. 349 | proc inflate*(`out`: pointer; outlen: tcuint; `in`: pointer; inlen: tcuint): tcint {.cdecl, importc: "tigrInflate", tigr.} 350 | 351 | ## Decodes a single UTF8 codepoint and returns the next pointer. 352 | proc decodeUTF8*(text: cstring; cp: ptr cint): cstring {.cdecl, 353 | importc: "tigrDecodeUTF8", tigr.} 354 | 355 | ## Encodes a single UTF8 codepoint and returns the next pointer. 356 | proc encodeUTF8*(text: cstring; cp: tcint): cstring {.cdecl, importc: "tigrEncodeUTF8", tigr.} 357 | 358 | # converts 359 | converter totcui*(n: SomeNumber|char|enum): tcuint = n.cuint 360 | converter totci*(n: SomeNumber|char|enum): tcint = n.cint 361 | converter totcf*(n: cint): tcfloat = n.cfloat 362 | converter toAddr*[I;T](a: var array[I,T]|seq[T]): ptr T = a[0].addr 363 | 364 | 365 | -------------------------------------------------------------------------------- /src/tigr/tigr.h: -------------------------------------------------------------------------------- 1 | // TIGR - TIny GRaphics Library - v3.1 2 | // ^^ ^^ 3 | // 4 | // rawr. 5 | 6 | /* 7 | This is free and unencumbered software released into the public domain. 8 | 9 | Our intent is that anyone is free to copy and use this software, 10 | for any purpose, in any form, and by any means. 11 | 12 | The authors dedicate any and all copyright interest in the software 13 | to the public domain, at their own expense for the betterment of mankind. 14 | 15 | The software is provided "as is", without any kind of warranty, including 16 | any implied warranty. If it breaks, you get to keep both pieces. 17 | */ 18 | 19 | #pragma once 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | // Compiler configuration. 26 | #ifdef _MSC_VER 27 | #define TIGR_INLINE static __forceinline 28 | #else 29 | #define TIGR_INLINE static inline 30 | #endif 31 | 32 | // Bitmaps ---------------------------------------------------------------- 33 | 34 | // This struct contains one pixel. 35 | typedef struct { 36 | unsigned char r, g, b, a; 37 | } TPixel; 38 | 39 | // Window flags. 40 | #define TIGR_FIXED 0 // window's bitmap is a fixed size (default) 41 | #define TIGR_AUTO 1 // window's bitmap is scaled with the window 42 | #define TIGR_2X 2 // always enforce (at least) 2X pixel scale 43 | #define TIGR_3X 4 // always enforce (at least) 3X pixel scale 44 | #define TIGR_4X 8 // always enforce (at least) 4X pixel scale 45 | #define TIGR_RETINA 16 // enable retina support on OS X 46 | #define TIGR_NOCURSOR 32 // hide cursor 47 | #define TIGR_FULLSCREEN 64 // start in full-screen mode 48 | 49 | // A Tigr bitmap. 50 | typedef struct Tigr { 51 | int w, h; // width/height (unscaled) 52 | int cx, cy, cw, ch; // clip rect 53 | TPixel *pix; // pixel data 54 | void *handle; // OS window handle, NULL for off-screen bitmaps. 55 | int blitMode; // Target bitmap blit mode 56 | } Tigr; 57 | 58 | // Creates a new empty window with a given bitmap size. 59 | // 60 | // Title is UTF-8. 61 | // 62 | // In TIGR_FIXED mode, the window is made as large as possible to contain an integer-scaled 63 | // version of the bitmap while still fitting on the screen. Resizing the window will adapt 64 | // the scale in integer steps to fit the bitmap. 65 | // 66 | // In TIGR_AUTO mode, the initial window size is set to the bitmap size times the pixel 67 | // scale. Resizing the window will resize the bitmap using the specified scale. 68 | // For example, in forced 2X mode, the window will be twice as wide (and high) as the bitmap. 69 | // 70 | // Turning on TIGR_RETINA mode will request full backing resolution on OSX, meaning that 71 | // the effective window size might be integer scaled to a larger size. In TIGR_AUTO mode, 72 | // this means that the Tigr bitmap will change size if the window is moved between 73 | // retina and non-retina screens. 74 | // 75 | Tigr *tigrWindow(int w, int h, const char *title, int flags); 76 | 77 | // Creates an empty off-screen bitmap. 78 | Tigr *tigrBitmap(int w, int h); 79 | 80 | // Deletes a window/bitmap. 81 | void tigrFree(Tigr *bmp); 82 | 83 | // Returns non-zero if the user requested to close a window. 84 | int tigrClosed(Tigr *bmp); 85 | 86 | // Displays a window's contents on-screen and updates input. 87 | void tigrUpdate(Tigr *bmp); 88 | 89 | // Called before doing direct OpenGL calls and before tigrUpdate. 90 | // Returns non-zero if OpenGL is available. 91 | int tigrBeginOpenGL(Tigr *bmp); 92 | 93 | // Sets post shader for a window. 94 | // This replaces the built-in post-FX shader. 95 | void tigrSetPostShader(Tigr *bmp, const char* code, int size); 96 | 97 | // Sets post-FX properties for a window. 98 | // 99 | // The built-in post-FX shader uses the following parameters: 100 | // p1: hblur - use bilinear filtering along the x-axis (pixels) 101 | // p2: vblur - use bilinear filtering along the y-axis (pixels) 102 | // p3: scanlines - CRT scanlines effect (0-1) 103 | // p4: contrast - contrast boost (1 = no change, 2 = 2X contrast, etc) 104 | void tigrSetPostFX(Tigr *bmp, float p1, float p2, float p3, float p4); 105 | 106 | 107 | // Drawing ---------------------------------------------------------------- 108 | 109 | // Helper for reading pixels. 110 | // For high performance, just access bmp->pix directly. 111 | TPixel tigrGet(Tigr *bmp, int x, int y); 112 | 113 | // Plots a pixel. 114 | // Clips and blends. 115 | // For high performance, just access bmp->pix directly. 116 | void tigrPlot(Tigr *bmp, int x, int y, TPixel pix); 117 | 118 | // Clears a bitmap to a color. 119 | // No blending, no clipping. 120 | void tigrClear(Tigr *bmp, TPixel color); 121 | 122 | // Fills a rectangular area. 123 | // No blending, no clipping. 124 | void tigrFill(Tigr *bmp, int x, int y, int w, int h, TPixel color); 125 | 126 | // Draws a line. 127 | // Start pixel is drawn, end pixel is not. 128 | // Clips and blends. 129 | void tigrLine(Tigr *bmp, int x0, int y0, int x1, int y1, TPixel color); 130 | 131 | // Draws an empty rectangle. 132 | // Drawing a 1x1 rectangle yields the same result as calling tigrPlot. 133 | // Clips and blends. 134 | void tigrRect(Tigr *bmp, int x, int y, int w, int h, TPixel color); 135 | 136 | // Fills a rectangle. 137 | // Fills the inside of the specified rectangular area. 138 | // Calling tigrRect followed by tigrFillRect using the same arguments 139 | // causes no overdrawing. 140 | // Clips and blends. 141 | void tigrFillRect(Tigr *bmp, int x, int y, int w, int h, TPixel color); 142 | 143 | // Draws a circle. 144 | // Drawing a zero radius circle yields the same result as calling tigrPlot. 145 | // Drawing a circle with radius one draws a circle three pixels wide. 146 | // Clips and blends. 147 | void tigrCircle(Tigr *bmp, int x, int y, int r, TPixel color); 148 | 149 | // Fills a circle. 150 | // Fills the inside of the specified circle. 151 | // Calling tigrCircle followed by tigrFillCircle using the same arguments 152 | // causes no overdrawing. 153 | // Filling a circle with zero radius has no effect. 154 | // Clips and blends. 155 | void tigrFillCircle(Tigr *bmp, int x, int y, int r, TPixel color); 156 | 157 | // Sets clip rect. 158 | // Set to (0, 0, -1, -1) to reset clipping to full bitmap. 159 | void tigrClip(Tigr *bmp, int cx, int cy, int cw, int ch); 160 | 161 | // Copies bitmap data. 162 | // dx/dy = dest co-ordinates 163 | // sx/sy = source co-ordinates 164 | // w/h = width/height 165 | // 166 | // RGBAdest = RGBAsrc 167 | // Clips, does not blend. 168 | void tigrBlit(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h); 169 | 170 | // Same as tigrBlit, but alpha blends the source bitmap with the 171 | // target using per pixel alpha and the specified global alpha. 172 | // 173 | // Ablend = Asrc * alpha 174 | // RGBdest = RGBsrc * Ablend + RGBdest * (1 - Ablend) 175 | // 176 | // Blit mode == TIGR_KEEP_ALPHA: 177 | // Adest = Adest 178 | // 179 | // Blit mode == TIGR_BLEND_ALPHA: 180 | // Adest = Asrc * Ablend + Adest * (1 - Ablend) 181 | // Clips and blends. 182 | void tigrBlitAlpha(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h, float alpha); 183 | 184 | // Same as tigrBlit, but tints the source bitmap with a color 185 | // and alpha blends the resulting source with the destination. 186 | // 187 | // Rblend = Rsrc * Rtint 188 | // Gblend = Gsrc * Gtint 189 | // Bblend = Bsrc * Btint 190 | // Ablend = Asrc * Atint 191 | // 192 | // RGBdest = RGBblend * Ablend + RGBdest * (1 - Ablend) 193 | // 194 | // Blit mode == TIGR_KEEP_ALPHA: 195 | // Adest = Adest 196 | // 197 | // Blit mode == TIGR_BLEND_ALPHA: 198 | // Adest = Ablend * Ablend + Adest * (1 - Ablend) 199 | // Clips and blends. 200 | void tigrBlitTint(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h, TPixel tint); 201 | 202 | enum TIGRBlitMode { 203 | TIGR_KEEP_ALPHA = 0, // Keep destination alpha value 204 | TIGR_BLEND_ALPHA = 1, // Blend destination alpha (default) 205 | }; 206 | 207 | // Set destination bitmap blend mode for blit operations. 208 | void tigrBlitMode(Tigr *dest, int mode); 209 | 210 | // Helper for making colors. 211 | TIGR_INLINE TPixel tigrRGB(unsigned char r, unsigned char g, unsigned char b) 212 | { 213 | TPixel p; p.r = r; p.g = g; p.b = b; p.a = 0xff; return p; 214 | } 215 | 216 | // Helper for making colors. 217 | TIGR_INLINE TPixel tigrRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) 218 | { 219 | TPixel p; p.r = r; p.g = g; p.b = b; p.a = a; return p; 220 | } 221 | 222 | 223 | // Font printing ---------------------------------------------------------- 224 | 225 | typedef struct { 226 | int code, x, y, w, h; 227 | } TigrGlyph; 228 | 229 | typedef struct { 230 | Tigr *bitmap; 231 | int numGlyphs; 232 | TigrGlyph *glyphs; 233 | } TigrFont; 234 | 235 | typedef enum { 236 | TCP_ASCII = 0, 237 | TCP_1252 = 1252, 238 | TCP_UTF32 = 12001 239 | } TCodepage; 240 | 241 | // Loads a font. 242 | // 243 | // Codepages: 244 | // 245 | // TCP_ASCII - Regular 7-bit ASCII 246 | // TCP_1252 - Windows 1252 247 | // TCP_UTF32 - Unicode subset 248 | // 249 | // For ASCII and 1252, the font bitmap should contain all characters 250 | // for the given codepage, excluding the first 32 control codes. 251 | // 252 | // For UTF32 - the font bitmap contains a subset of Unicode characters 253 | // and must be in the format generated by tigrFont for UTF32. 254 | // 255 | TigrFont *tigrLoadFont(Tigr *bitmap, int codepage); 256 | 257 | // Frees a font. 258 | void tigrFreeFont(TigrFont *font); 259 | 260 | // Prints UTF-8 text onto a bitmap. 261 | // NOTE: 262 | // This uses the target bitmap blit mode. 263 | // See tigrBlitTint for details. 264 | void tigrPrint(Tigr *dest, TigrFont *font, int x, int y, TPixel color, const char *text, ...); 265 | 266 | // Returns the width/height of a string. 267 | int tigrTextWidth(TigrFont *font, const char *text); 268 | int tigrTextHeight(TigrFont *font, const char *text); 269 | 270 | // The built-in font. 271 | extern TigrFont *tfont; 272 | 273 | 274 | // User Input ------------------------------------------------------------- 275 | 276 | // Key scancodes. For letters/numbers, use ASCII ('A'-'Z' and '0'-'9'). 277 | typedef enum { 278 | TK_PAD0=128,TK_PAD1,TK_PAD2,TK_PAD3,TK_PAD4,TK_PAD5,TK_PAD6,TK_PAD7,TK_PAD8,TK_PAD9, 279 | TK_PADMUL,TK_PADADD,TK_PADENTER,TK_PADSUB,TK_PADDOT,TK_PADDIV, 280 | TK_F1,TK_F2,TK_F3,TK_F4,TK_F5,TK_F6,TK_F7,TK_F8,TK_F9,TK_F10,TK_F11,TK_F12, 281 | TK_BACKSPACE,TK_TAB,TK_RETURN,TK_SHIFT,TK_CONTROL,TK_ALT,TK_PAUSE,TK_CAPSLOCK, 282 | TK_ESCAPE,TK_SPACE,TK_PAGEUP,TK_PAGEDN,TK_END,TK_HOME,TK_LEFT,TK_UP,TK_RIGHT,TK_DOWN, 283 | TK_INSERT,TK_DELETE,TK_LWIN,TK_RWIN,TK_NUMLOCK,TK_SCROLL,TK_LSHIFT,TK_RSHIFT, 284 | TK_LCONTROL,TK_RCONTROL,TK_LALT,TK_RALT,TK_SEMICOLON,TK_EQUALS,TK_COMMA,TK_MINUS, 285 | TK_DOT,TK_SLASH,TK_BACKTICK,TK_LSQUARE,TK_BACKSLASH,TK_RSQUARE,TK_TICK 286 | } TKey; 287 | 288 | // Returns mouse input for a window. 289 | void tigrMouse(Tigr *bmp, int *x, int *y, int *buttons); 290 | 291 | typedef struct { 292 | int x; 293 | int y; 294 | } TigrTouchPoint; 295 | 296 | // Reads touch input for a window. 297 | // Returns number of touch points read. 298 | int tigrTouch(Tigr *bmp, TigrTouchPoint* points, int maxPoints); 299 | 300 | // Reads the keyboard for a window. 301 | // Returns non-zero if a key is pressed/held. 302 | // tigrKeyDown tests for the initial press, tigrKeyHeld repeats each frame. 303 | int tigrKeyDown(Tigr *bmp, int key); 304 | int tigrKeyHeld(Tigr *bmp, int key); 305 | 306 | // Reads character input for a window. 307 | // Returns the Unicode value of the last key pressed, or 0 if none. 308 | int tigrReadChar(Tigr *bmp); 309 | 310 | // Show / hide virtual keyboard. 311 | // (Only available on iOS / Android) 312 | void tigrShowKeyboard(int show); 313 | 314 | 315 | // Bitmap I/O ------------------------------------------------------------- 316 | 317 | // Loads a PNG, from either a file or memory. (fileName is UTF-8) 318 | // On error, returns NULL and sets errno. 319 | Tigr *tigrLoadImage(const char *fileName); 320 | Tigr *tigrLoadImageMem(const void *data, int length); 321 | 322 | // Saves a PNG to a file. (fileName is UTF-8) 323 | // On error, returns zero and sets errno. 324 | int tigrSaveImage(const char *fileName, Tigr *bmp); 325 | 326 | 327 | // Helpers ---------------------------------------------------------------- 328 | 329 | // Returns the amount of time elapsed since tigrTime was last called, 330 | // or zero on the first call. 331 | float tigrTime(void); 332 | 333 | // Displays an error message and quits. (UTF-8) 334 | // 'bmp' can be NULL. 335 | void tigrError(Tigr *bmp, const char *message, ...); 336 | 337 | // Reads an entire file into memory. (fileName is UTF-8) 338 | // Free it yourself after with 'free'. 339 | // On error, returns NULL and sets errno. 340 | // TIGR will automatically append a NUL terminator byte 341 | // to the end (not included in the length) 342 | void *tigrReadFile(const char *fileName, int *length); 343 | 344 | // Decompresses DEFLATEd zip/zlib data into a buffer. 345 | // Returns non-zero on success. 346 | int tigrInflate(void *out, unsigned outlen, const void *in, unsigned inlen); 347 | 348 | // Decodes a single UTF8 codepoint and returns the next pointer. 349 | const char *tigrDecodeUTF8(const char *text, int *cp); 350 | 351 | // Encodes a single UTF8 codepoint and returns the next pointer. 352 | char *tigrEncodeUTF8(char *text, int cp); 353 | 354 | #ifdef __cplusplus 355 | } 356 | #endif 357 | -------------------------------------------------------------------------------- /tests/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"../src" 2 | --outdir:"$nimcache/buildTests" 3 | -------------------------------------------------------------------------------- /tests/test.nim: -------------------------------------------------------------------------------- 1 | import tigr 2 | 3 | var a:int = 100 4 | var b:float = 22.22 5 | var c = "string" 6 | var d:array[3,char] = ['a', 'b', 'c'] 7 | let p = cast[cstring](d[0].addr) 8 | assert c == "string".cstring 9 | assert p == "abc".cstring 10 | 11 | echo d 12 | proc test(a:cint, b:cfloat, c:cstring, d:cstring):cint = 13 | echo "-- test: ", b, a, c, d, " --" 14 | 100.cint 15 | a = test(a,b,c,p) 16 | 17 | var screen = window(320, 240, "Hello", 0) 18 | var iquit = 200 19 | while screen.closed() == 0 and 20 | keyDown(screen, TK_ESCAPE) == 0 and 21 | iquit > 0: 22 | screen.clear(RGB(0x80, 0x90, 0xa0)) 23 | let str = ("Test tigr: " & $iquit).cstring 24 | screen.print(tfont, 120, 110, tigr.RGB(0xff, 0xff, 0xff), str); 25 | screen.update() 26 | iquit.dec 27 | -------------------------------------------------------------------------------- /tests/tester.nim: -------------------------------------------------------------------------------- 1 | import test 2 | -------------------------------------------------------------------------------- /tigr.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | version = "1.0" 3 | author = "Angluca" 4 | description = "TIGR is a tiny cross-platform graphics library, providing a unified API for Windows, macOS, Linux, iOS and Android." 5 | license = "MIT" 6 | srcDir = "src" 7 | installExt = @["nim","c","h"] 8 | 9 | # Dependencies 10 | requires "nim >= 1.6.6" 11 | requires "opengl" 12 | 13 | task test, "Runs the test suite": 14 | exec "nim c -r tests/tester.nim" 15 | exec "nim c -r examples/headless/headless.nim" 16 | exec "nim c -r examples/hello/hello.nim" 17 | exec "nim c -r examples/clip/clip.nim" 18 | exec "nim c -r examples/shader/shader.nim" 19 | exec "nim c -r examples/opengl/oglc.nim" 20 | exec "nim c -r examples/flags/flags.nim" 21 | withDir "examples/demo/": 22 | exec "nim c -r demo.nim" 23 | --------------------------------------------------------------------------------