├── README.md ├── UNLICENSE ├── src ├── assets │ └── bg.jpg ├── common.nim ├── core.nim ├── data.nim └── vim3.nim ├── vim3.gif └── vim3.nimble /README.md: -------------------------------------------------------------------------------- 1 | ## Vim³ 2 | 3 | Most people use vim in two stupid dimensions. But not me. I use it in three: 4 | 5 |

6 | 7 |

8 | 9 | To run it, [install Nim](https://nim-lang.org/install.html), and from this repo do: 10 | 11 | ``` 12 | nimble run vim3 13 | ``` 14 | 15 | Once you're ready to start using it as your main editor, do: 16 | 17 | ``` 18 | nimble install paravim 19 | nimble install 20 | ``` 21 | 22 | As long as `~/.nimble/bin` is on your PATH, you will now be able to open files like this: 23 | 24 | ``` 25 | vim3 path/to/myfile.txt 26 | ``` 27 | 28 | ## Q & A 29 | 30 | ### How do i acquire your power? 31 | 32 | It's not that hard 33 | 34 | ### How do i stop the cube from spinning 35 | 36 | no 37 | 38 | ### I don't even have vim installed, how is this possible? 39 | 40 | It's using [paravim](https://github.com/paranim/paravim) which has a real copy of vim built in 41 | 42 | ### Which OS does it work on? 43 | 44 | All of them pretty much 45 | 46 | ### Why can't i run it on linux? 47 | 48 | Could be you need opengl libraries, try `sudo apt install xorg-dev libgl1-mesa-dev` 49 | 50 | You might also need to do `sudo apt install libtinfo5` 51 | 52 | ### I use arch btw 53 | 54 | Try this: `sudo ln -s /usr/lib/libtinfo.so.6 /usr/lib/libtinfo.so.5` 55 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oakes/vim_cubed/ea33fc71ae8d27351978e7e37057e69e3eb629e3/src/assets/bg.jpg -------------------------------------------------------------------------------- /src/common.nim: -------------------------------------------------------------------------------- 1 | import paranim/gl, paranim/gl/uniforms, paranim/gl/attributes 2 | import nimgl/opengl 3 | import glm 4 | from sequtils import map 5 | from std/math import nil 6 | import paranim/math as pmath 7 | 8 | type 9 | Game* = object of RootGame 10 | deltaTime*: float 11 | totalTime*: float 12 | frameWidth*: int 13 | frameHeight*: int 14 | 15 | proc project*[UniT, AttrT](entity: var Entity[UniT, AttrT], left: GLfloat, right: GLfloat, bottom: GLfloat, top: GLfloat, near: GLfloat, far: GLfloat) = 16 | entity.uniforms.u_matrix.project(left, right, bottom, top, near, far) 17 | 18 | proc project*[UniT, AttrT](entity: var Entity[UniT, AttrT], fieldOfView: GLfloat, aspect: GLfloat, near: GLfloat, far: GLfloat) = 19 | entity.uniforms.u_matrix.project(fieldOfView, aspect, near, far) 20 | 21 | proc translate*[UniT, AttrT](entity: var Entity[UniT, AttrT], x: GLfloat, y: GLfloat, z: GLfloat) = 22 | entity.uniforms.u_matrix.translate(x, y, z) 23 | 24 | proc scale*[UniT, AttrT](entity: var Entity[UniT, AttrT], x: GLfloat, y: GLfloat, z: GLfloat) = 25 | entity.uniforms.u_matrix.scale(x, y, z) 26 | 27 | proc rotateX*[UniT, AttrT](entity: var Entity[UniT, AttrT], angle: GLFloat) = 28 | entity.uniforms.u_matrix.rotateX(angle) 29 | 30 | proc rotateY*[UniT, AttrT](entity: var Entity[UniT, AttrT], angle: GLFloat) = 31 | entity.uniforms.u_matrix.rotateY(angle) 32 | 33 | proc rotateZ*[UniT, AttrT](entity: var Entity[UniT, AttrT], angle: GLFloat) = 34 | entity.uniforms.u_matrix.rotateZ(angle) 35 | 36 | proc invert*[UniT, AttrT](entity: var Entity[UniT, AttrT], cam: Mat4x4[GLfloat]) = 37 | entity.uniforms.u_matrix.invert(cam) 38 | 39 | proc degToRad*(degrees: GLfloat): GLfloat = 40 | (degrees * math.PI) / 180f 41 | 42 | # textured 3D entity 43 | 44 | const threeDTextureVertexShader* = 45 | """ 46 | #version 330 47 | uniform mat4 u_matrix; 48 | in vec4 a_position; 49 | in vec2 a_texcoord; 50 | out vec2 v_texcoord; 51 | void main() 52 | { 53 | gl_Position = u_matrix * a_position; 54 | v_texcoord = a_texcoord; 55 | v_texcoord.y = 1.0 - v_texcoord.y; // flip y axis 56 | } 57 | """ 58 | 59 | const threeDTextureFragmentShader* = 60 | """ 61 | #version 330 62 | precision mediump float; 63 | uniform sampler2D u_texture; 64 | in vec2 v_texcoord; 65 | out vec4 outColor; 66 | void main() 67 | { 68 | outColor = texture(u_texture, v_texcoord); 69 | } 70 | """ 71 | 72 | -------------------------------------------------------------------------------- /src/core.nim: -------------------------------------------------------------------------------- 1 | import nimgl/opengl 2 | import paranim/gl, paranim/gl/uniforms, paranim/gl/attributes, paranim/gl/entities 3 | import paranim/math as pmath 4 | import common, data 5 | from bitops import bitor 6 | from std/math import nil 7 | import glm 8 | from paravim/core as paravim_core import nil 9 | from paravim import nil 10 | import stb_image/read as stbi 11 | from pararules import nil 12 | 13 | type 14 | ThreeDMetaTextureEntityUniforms = tuple[u_matrix: Uniform[Mat4x4[GLfloat]], u_texture: Uniform[RenderToTexture[GLubyte, Game]]] 15 | ThreeDMetaTextureEntityAttributes = tuple[a_position: Attribute[GLfloat], a_texcoord: Attribute[GLfloat]] 16 | ThreeDMetaTextureEntity = object of ArrayEntity[ThreeDMetaTextureEntityUniforms, ThreeDMetaTextureEntityAttributes] 17 | UncompiledThreeDMetaTextureEntity = object of UncompiledEntity[ThreeDMetaTextureEntity, ThreeDMetaTextureEntityUniforms, ThreeDMetaTextureEntityAttributes] 18 | 19 | proc initThreeDMetaTextureEntity(posData: openArray[GLfloat], texcoordData: openArray[GLfloat], image: RenderToTexture[GLubyte, Game]): UncompiledThreeDMetaTextureEntity = 20 | result.vertexSource = threeDTextureVertexShader 21 | result.fragmentSource = threeDTextureFragmentShader 22 | # position 23 | var position = Attribute[GLfloat](size: 3, iter: 1) 24 | new(position.data) 25 | position.data[] = @posData 26 | # texcoord 27 | var texcoord = Attribute[GLfloat](size: 2, iter: 1, normalize: true) 28 | new(texcoord.data) 29 | texcoord.data[] = @texcoordData 30 | # set attrs and unis 31 | result.attributes = (a_position: position, a_texcoord: texcoord) 32 | result.uniforms = ( 33 | u_matrix: Uniform[Mat4x4[GLfloat]](data: mat4f(1)), 34 | u_texture: Uniform[RenderToTexture[GLubyte, Game]](data: image) 35 | ) 36 | 37 | var 38 | entity: ThreeDMetaTextureEntity 39 | imageEntity: ImageEntity 40 | rx = degToRad(180f) 41 | ry = degToRad(40f) 42 | imageWidth: int 43 | imageHeight: int 44 | 45 | const image = staticRead("assets/bg.jpg") 46 | 47 | proc init*(game: var Game) = 48 | doAssert glInit() 49 | 50 | glEnable(GL_BLEND) 51 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 52 | glEnable(GL_DEPTH_TEST) 53 | 54 | let 55 | windowWidth = pararules.query(paravim_core.session, paravim_core.rules.getWindow).windowWidth 56 | cubeSize = int(windowWidth / 2) 57 | paravim_core.onWindowResize(cubeSize, cubeSize) 58 | paravim_core.insert(paravim_core.session, paravim_core.Global, paravim_core.AsciiArt, "") 59 | 60 | let outerImage = RenderToTexture[GLubyte, Game]( 61 | opts: TextureOpts( 62 | mipLevel: 0, 63 | internalFmt: GL_RGBA, 64 | width: GLsizei(cubeSize), 65 | height: GLsizei(cubeSize), 66 | border: 0, 67 | srcFmt: GL_RGBA 68 | ), 69 | params: @[ 70 | (GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE), 71 | (GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE), 72 | (GL_TEXTURE_MIN_FILTER, GL_LINEAR) 73 | ], 74 | render: proc (game: Game) = 75 | glDisable(GL_CULL_FACE) 76 | discard paravim.tick(game, true) 77 | glEnable(GL_CULL_FACE) 78 | ) 79 | 80 | entity = compile(game, initThreeDMetaTextureEntity(cube, cubeTexcoords, outerImage)) 81 | 82 | var 83 | channels: int 84 | data: seq[uint8] 85 | data = stbi.loadFromMemory(cast[seq[uint8]](image), imageWidth, imageHeight, channels, stbi.RGBA) 86 | imageEntity = compile(game, initImageEntity(data, imageWidth, imageHeight)) 87 | 88 | proc tick*(game: Game) = 89 | glClearColor(1f, 1f, 1f, 1f) 90 | glClear(GLbitfield(bitor(GL_COLOR_BUFFER_BIT.ord, GL_DEPTH_BUFFER_BIT.ord))) 91 | glViewport(0, 0, GLsizei(game.frameWidth), GLsizei(game.frameHeight)) 92 | 93 | block: 94 | glDisable(GL_CULL_FACE) 95 | let 96 | frameRatio = game.frameWidth.float / game.frameHeight.float 97 | imageRatio = imageWidth.float / imageHeight.float 98 | (width, height) = 99 | if frameRatio > imageRatio: 100 | (game.frameWidth.float, game.frameWidth.float * (imageHeight.float / imageWidth.float)) 101 | else: 102 | (game.frameHeight.float * imageRatio, game.frameHeight.float) 103 | var e = imageEntity 104 | e.project(float(game.frameWidth), float(game.frameHeight)) 105 | e.translate(0f, 0f) 106 | e.scale(width, height) 107 | render(game, e) 108 | 109 | var camera = mat4f(1) 110 | camera.translate(0f, 0f, 2f) 111 | camera.lookAt(vec3(0f, 0f, 0f), vec3(0f, 1f, 0f)) 112 | 113 | var e = entity 114 | e.project(degToRad(60f), float(game.frameWidth) / float(game.frameHeight), 1f, 2000f) 115 | e.invert(camera) 116 | e.rotateX(rx) 117 | e.rotateY(ry) 118 | e.scale(1.15f, 1.15f, 1.15f) 119 | render(game, e) 120 | 121 | rx += 0.5f * game.deltaTime 122 | ry += 0.5f * game.deltaTime 123 | 124 | -------------------------------------------------------------------------------- /src/data.nim: -------------------------------------------------------------------------------- 1 | const cube* = [ 2 | -0.5f, -0.5f, -0.5f, 3 | -0.5f, 0.5f, -0.5f, 4 | 0.5f, -0.5f, -0.5f, 5 | -0.5f, 0.5f, -0.5f, 6 | 0.5f, 0.5f, -0.5f, 7 | 0.5f, -0.5f, -0.5f, 8 | 9 | -0.5f, -0.5f, 0.5f, 10 | 0.5f, -0.5f, 0.5f, 11 | -0.5f, 0.5f, 0.5f, 12 | -0.5f, 0.5f, 0.5f, 13 | 0.5f, -0.5f, 0.5f, 14 | 0.5f, 0.5f, 0.5f, 15 | 16 | -0.5f, 0.5f, -0.5f, 17 | -0.5f, 0.5f, 0.5f, 18 | 0.5f, 0.5f, -0.5f, 19 | -0.5f, 0.5f, 0.5f, 20 | 0.5f, 0.5f, 0.5f, 21 | 0.5f, 0.5f, -0.5f, 22 | 23 | -0.5f, -0.5f, -0.5f, 24 | 0.5f, -0.5f, -0.5f, 25 | -0.5f, -0.5f, 0.5f, 26 | -0.5f, -0.5f, 0.5f, 27 | 0.5f, -0.5f, -0.5f, 28 | 0.5f, -0.5f, 0.5f, 29 | 30 | -0.5f, -0.5f, -0.5f, 31 | -0.5f, -0.5f, 0.5f, 32 | -0.5f, 0.5f, -0.5f, 33 | -0.5f, -0.5f, 0.5f, 34 | -0.5f, 0.5f, 0.5f, 35 | -0.5f, 0.5f, -0.5f, 36 | 37 | 0.5f, -0.5f, -0.5f, 38 | 0.5f, 0.5f, -0.5f, 39 | 0.5f, -0.5f, 0.5f, 40 | 0.5f, -0.5f, 0.5f, 41 | 0.5f, 0.5f, -0.5f, 42 | 0.5f, 0.5f, 0.5f, 43 | ] 44 | 45 | const cubeTexcoords* = [ 46 | 0f, 0f, 47 | 0f, 1f, 48 | 1f, 0f, 49 | 0f, 1f, 50 | 1f, 1f, 51 | 1f, 0f, 52 | 53 | 0f, 0f, 54 | 0f, 1f, 55 | 1f, 0f, 56 | 1f, 0f, 57 | 0f, 1f, 58 | 1f, 1f, 59 | 60 | 0f, 0f, 61 | 0f, 1f, 62 | 1f, 0f, 63 | 0f, 1f, 64 | 1f, 1f, 65 | 1f, 0f, 66 | 67 | 0f, 0f, 68 | 0f, 1f, 69 | 1f, 0f, 70 | 1f, 0f, 71 | 0f, 1f, 72 | 1f, 1f, 73 | 74 | 0f, 0f, 75 | 0f, 1f, 76 | 1f, 0f, 77 | 0f, 1f, 78 | 1f, 1f, 79 | 1f, 0f, 80 | 81 | 0f, 0f, 82 | 0f, 1f, 83 | 1f, 0f, 84 | 1f, 0f, 85 | 0f, 1f, 86 | 1f, 1f, 87 | ] 88 | -------------------------------------------------------------------------------- /src/vim3.nim: -------------------------------------------------------------------------------- 1 | import nimgl/glfw 2 | import common 3 | from core import nil 4 | from paravim import nil 5 | from os import nil 6 | 7 | var game = Game() 8 | 9 | proc keyCallback(window: GLFWWindow, key: int32, scancode: int32, action: int32, mods: int32) {.cdecl.} = 10 | paravim.keyCallback(window, key, scancode, action, mods) 11 | 12 | proc charCallback(window: GLFWWindow, codepoint: uint32) {.cdecl.} = 13 | paravim.charCallback(window, codepoint) 14 | 15 | proc frameSizeCallback(window: GLFWWindow, width: int32, height: int32) {.cdecl.} = 16 | game.frameWidth = width 17 | game.frameHeight = height 18 | 19 | when isMainModule: 20 | doAssert glfwInit() 21 | 22 | glfwWindowHint(GLFWContextVersionMajor, 3) 23 | glfwWindowHint(GLFWContextVersionMinor, 3) 24 | glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE) # Used for Mac 25 | glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE) 26 | glfwWindowHint(GLFWResizable, GLFW_TRUE) 27 | 28 | let w: GLFWWindow = glfwCreateWindow(1024, 768, "Vim³ - You can begin by typing `:e path/to/myfile.txt`") 29 | if w == nil: 30 | quit(-1) 31 | 32 | w.makeContextCurrent() 33 | glfwSwapInterval(1) 34 | 35 | discard w.setKeyCallback(keyCallback) 36 | discard w.setCharCallback(charCallback) 37 | discard w.setFramebufferSizeCallback(frameSizeCallback) 38 | 39 | var width, height: int32 40 | w.getFramebufferSize(width.addr, height.addr) 41 | w.frameSizeCallback(width, height) 42 | 43 | let params = os.commandLineParams() 44 | paravim.init(game, w, params) 45 | core.init(game) 46 | 47 | game.totalTime = glfwGetTime() 48 | 49 | while not w.windowShouldClose: 50 | let ts = glfwGetTime() 51 | game.deltaTime = ts - game.totalTime 52 | game.totalTime = ts 53 | core.tick(game) 54 | w.swapBuffers() 55 | glfwPollEvents() 56 | 57 | w.destroyWindow() 58 | glfwTerminate() 59 | -------------------------------------------------------------------------------- /vim3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oakes/vim_cubed/ea33fc71ae8d27351978e7e37057e69e3eb629e3/vim3.gif -------------------------------------------------------------------------------- /vim3.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.1.0" 4 | author = "oakes" 5 | description = "Vim for masochists" 6 | license = "Public Domain" 7 | srcDir = "src" 8 | bin = @["vim3"] 9 | 10 | task dev, "Run dev version": 11 | exec "nimble run vim3" 12 | 13 | # Dependencies 14 | 15 | requires "nim >= 1.2.6" 16 | requires "paranim >= 0.10.0" 17 | requires "paravim >= 0.18.2" 18 | requires "stb_image >= 2.5" 19 | --------------------------------------------------------------------------------