├── .editorconfig ├── .github └── workflows │ └── build-and-deploy.yml ├── .gitignore ├── .images ├── lmb.png ├── msw.png └── tmp3d_2x.png ├── .nvmrc ├── CONVENTIONS ├── FILES ├── LICENSE ├── Procfile ├── README.md ├── TODO.md ├── assets ├── favicon.ico ├── models │ ├── crash │ │ ├── back.png │ │ ├── color_pallete.png │ │ ├── crashbandicoot.mtl │ │ ├── crashbandicoot.obj │ │ └── shoes.png │ ├── daxter │ │ ├── Textures │ │ │ ├── Buckle.png │ │ │ ├── Cloth.png │ │ │ ├── Eyes.png │ │ │ ├── Fur1.png │ │ │ ├── Fur2.png │ │ │ ├── Fur3.png │ │ │ └── Metal.png │ │ ├── daxter.mtl │ │ └── daxter.obj │ ├── doom │ │ ├── BIGDOOR2.PNG │ │ ├── BIGDOOR4.PNG │ │ ├── BRNBIGC.PNG │ │ ├── BRNBIGL.PNG │ │ ├── BRNBIGR.PNG │ │ ├── BROWN1.PNG │ │ ├── BROWN144.PNG │ │ ├── BROWN96.PNG │ │ ├── BROWNGRN.PNG │ │ ├── CEIL3_5.PNG │ │ ├── CEIL5_1.PNG │ │ ├── CEIL5_2.PNG │ │ ├── COMPSPAN.PNG │ │ ├── COMPTALL.PNG │ │ ├── COMPTILE.PNG │ │ ├── COMPUTE2.PNG │ │ ├── COMPUTE3.PNG │ │ ├── DOOR3.PNG │ │ ├── DOORSTOP.PNG │ │ ├── DOORTRAK.PNG │ │ ├── EXITDOOR.PNG │ │ ├── EXITSIGN.PNG │ │ ├── FLAT14.PNG │ │ ├── FLAT18.PNG │ │ ├── FLAT20.PNG │ │ ├── FLAT23.PNG │ │ ├── FLAT5_5.PNG │ │ ├── FLOOR1_1.PNG │ │ ├── FLOOR4_8.PNG │ │ ├── FLOOR5_1.PNG │ │ ├── FLOOR5_2.PNG │ │ ├── FLOOR6_2.PNG │ │ ├── FLOOR7_1.PNG │ │ ├── FLOOR7_2.PNG │ │ ├── F_SKY1.PNG │ │ ├── F_SKY1_.PNG │ │ ├── LITE3.PNG │ │ ├── NUKAGE3.PNG │ │ ├── NUKE24.PNG │ │ ├── PLANET1.PNG │ │ ├── SLADWALL.PNG │ │ ├── STARG3.PNG │ │ ├── STARGR1.PNG │ │ ├── STARTAN1.PNG │ │ ├── STARTAN3.PNG │ │ ├── STEP1.PNG │ │ ├── STEP2.PNG │ │ ├── STEP6.PNG │ │ ├── SUPPORT2.PNG │ │ ├── SW1COMP.PNG │ │ ├── SW1STRTN.PNG │ │ ├── TEKWALL1.PNG │ │ ├── TEKWALL4.PNG │ │ ├── TLITE6_1.PNG │ │ ├── TLITE6_4.PNG │ │ ├── TLITE6_5.PNG │ │ ├── TLITE6_6.PNG │ │ ├── doom-e1m1.mtl │ │ └── doom-e1m1.obj │ ├── jak3 │ │ ├── EyelidL.png │ │ ├── EyelidR.png │ │ ├── Jak.mtl │ │ ├── Jak.obj │ │ ├── armbandage.png │ │ ├── armorother.png │ │ ├── armskin.png │ │ ├── backclothred.png │ │ ├── beltstrap.png │ │ ├── bluebandarm.png │ │ ├── buckleshine.png │ │ ├── chestarmorstraps.png │ │ ├── chestlegstraps.png │ │ ├── chestmetal.png │ │ ├── chestring.png │ │ ├── ears.png │ │ ├── eyebrow.png │ │ ├── eyel.png │ │ ├── eyer.png │ │ ├── eyeshine.png │ │ ├── facefingers.png │ │ ├── feetblue.png │ │ ├── footbottom.png │ │ ├── glove.png │ │ ├── glovebuckle.png │ │ ├── gloveshine.png │ │ ├── gogglecheststrap.png │ │ ├── gogglemetal.png │ │ ├── gogglered.png │ │ ├── goggleshine.png │ │ ├── gunholster.png │ │ ├── hair.png │ │ ├── hairshine.png │ │ ├── legbuckle.png │ │ ├── leglether.png │ │ ├── metalshine.png │ │ ├── pants.png │ │ ├── scarf.png │ │ ├── shirt.png │ │ ├── teeth.png │ │ ├── toemetal.png │ │ └── waistcloth.png │ ├── lara │ │ ├── lara.mtl │ │ ├── lara.obj │ │ ├── lara.png │ │ └── ponytail.png │ ├── mario64 │ │ ├── 114626C6_c.png │ │ ├── 148EB7B9_c.png │ │ ├── 154B175A_c.png │ │ ├── 1916F8C5_c.png │ │ ├── 19D5421D_c.png │ │ ├── 1D0CA178_c.png │ │ ├── 1FEE462_c.png │ │ ├── 1FFBC780_c.png │ │ ├── 20EF7F7C_c.png │ │ ├── 2BC808F1_c.png │ │ ├── 31BEEA74_c.png │ │ ├── 36B9F48_c.png │ │ ├── 3AB7B2BC_c.png │ │ ├── 3C6851DA_c.png │ │ ├── 3FBAB8A0_c.png │ │ ├── 41EDCCB_c.png │ │ ├── 49254A53_c.png │ │ ├── 5EDC83BD_c.png │ │ ├── 60A64656_c.png │ │ ├── 61BE951F_c.png │ │ ├── 6AE21407_c.png │ │ ├── 6DAF90F6_c.png │ │ ├── 7EB1C6A1_c.png │ │ ├── peaches-castle.mtl │ │ └── peaches-castle.obj │ ├── pslogo │ │ ├── blue.png │ │ ├── green.png │ │ ├── ps.mtl │ │ ├── ps.obj │ │ ├── red.png │ │ └── yellow.png │ ├── quake │ │ ├── +0basebtn.png │ │ ├── +0basebtn_emission.png │ │ ├── +0planet.png │ │ ├── +0slip.png │ │ ├── +0slip_emission.png │ │ ├── +0slipbot.png │ │ ├── +0sliptop.png │ │ ├── +1basebtn.png │ │ ├── +1planet.png │ │ ├── +1slip.png │ │ ├── +1slip_emission.png │ │ ├── +2planet.png │ │ ├── +2slip.png │ │ ├── +2slip_emission.png │ │ ├── +3planet.png │ │ ├── +3slip.png │ │ ├── +3slip_emission.png │ │ ├── +4slip.png │ │ ├── +4slip_emission.png │ │ ├── +5slip.png │ │ ├── +5slip_emission.png │ │ ├── +6slip.png │ │ ├── +6slip_emission.png │ │ ├── +abasebtn.png │ │ ├── _slime0.png │ │ ├── _teleport.png │ │ ├── _water0.png │ │ ├── basebutn3.png │ │ ├── basebutn3_emission.png │ │ ├── clip.png │ │ ├── comp1_1.png │ │ ├── comp1_2.png │ │ ├── comp1_3.png │ │ ├── comp1_4.png │ │ ├── comp1_5.png │ │ ├── comp1_6.png │ │ ├── comp1_6_emission.png │ │ ├── crate0_side.png │ │ ├── crate0_top.png │ │ ├── door02_1.png │ │ ├── ecop1_1.png │ │ ├── ecop1_4.png │ │ ├── ecop1_6.png │ │ ├── edoor01_1.png │ │ ├── ground1_2.png │ │ ├── ground1_6.png │ │ ├── key01_3.png │ │ ├── plat_side1.png │ │ ├── plat_stem.png │ │ ├── plat_top1.png │ │ ├── quake-e1m1.mtl │ │ ├── quake-e1m1.obj │ │ ├── sfloor4_2.png │ │ ├── sfloor4_5.png │ │ ├── sky4.png │ │ ├── slip1.png │ │ ├── slip1_emission.png │ │ ├── slipbotsd.png │ │ ├── sliplite.png │ │ ├── sliplite_emission.png │ │ ├── slipside.png │ │ ├── slipside_emission.png │ │ ├── sliptopsd.png │ │ ├── switch_1.png │ │ ├── switch_1_emission.png │ │ ├── tech01_1.png │ │ ├── tech01_6.png │ │ ├── tech01_7.png │ │ ├── tech01_9.png │ │ ├── tech04_1.png │ │ ├── tech04_2.png │ │ ├── tech04_3.png │ │ ├── tech07_2.png │ │ ├── tech08_1.png │ │ ├── tech09_3.png │ │ ├── tech10_1.png │ │ ├── tech10_3.png │ │ ├── tech11_2.png │ │ ├── tlight01.png │ │ ├── tlight01_emission.png │ │ ├── tlight02.png │ │ ├── tlight02_emission.png │ │ ├── tlight07.png │ │ ├── tlight07_emission.png │ │ ├── tlight08.png │ │ ├── tlight10.png │ │ ├── tlight11.png │ │ ├── tlight11_emission.png │ │ ├── trigger.png │ │ ├── twall1_1.png │ │ ├── twall1_2.png │ │ ├── twall2_1.png │ │ ├── twall2_2.png │ │ ├── twall2_3.png │ │ ├── twall2_5.png │ │ ├── twall2_6.png │ │ ├── twall3_1.png │ │ ├── twall5_1.png │ │ ├── twall5_3.png │ │ ├── uwall1_2.png │ │ ├── z_exit.png │ │ └── z_exit_emission.png │ ├── sandshark │ │ ├── Tire1.png │ │ ├── bolts.png │ │ ├── cap1.png │ │ ├── cap2.png │ │ ├── gun1.png │ │ ├── gun2.png │ │ ├── gunbarrel.png │ │ ├── metal1.png │ │ ├── metal2.png │ │ ├── metal3.png │ │ ├── metal4.png │ │ ├── metal5.png │ │ ├── pipe1.png │ │ ├── pipe2.png │ │ ├── pipe3.png │ │ ├── pipe4.png │ │ ├── pipe5.png │ │ ├── pipeinner.png │ │ ├── sandshark.mtl │ │ ├── sandshark.obj │ │ ├── seat.png │ │ ├── tex1.png │ │ ├── tire2.png │ │ └── tire3.png │ ├── spaceship.obj │ ├── spiderman │ │ ├── 0474ba03.png │ │ ├── 150d18e8.png │ │ ├── 19292d60.png │ │ ├── 492b2fc7.png │ │ ├── 58a5e3de.png │ │ ├── 606228de.png │ │ ├── 65b3a447.png │ │ ├── 798ef42f.png │ │ ├── 848f5e3b.png │ │ ├── a1454207.png │ │ ├── cd057eda.png │ │ ├── dafccfaa.png │ │ ├── f99ea9d9.png │ │ ├── spiderman.mtl │ │ └── spiderman.obj │ ├── spyro │ │ ├── High.png │ │ ├── Low.png │ │ ├── artisans-hub.mtl │ │ └── artisans-hub.obj │ ├── teapot.obj │ ├── tmp3dcube │ │ ├── cube.mtl │ │ ├── cube.obj │ │ └── wood.png │ └── vader │ │ ├── Vader.mtl │ │ ├── Vader.obj │ │ ├── Vader.png │ │ └── Vaderbody.png └── textures │ └── tmp3d_2x.png ├── nodemon.json ├── package-lock.json ├── package.json ├── src ├── data │ ├── d_player.ts │ ├── d_textures.ts │ └── mesh │ │ ├── d_artisans-hub.ts │ │ ├── d_crashbandicoot.ts │ │ ├── d_cube.ts │ │ ├── d_daxter.ts │ │ ├── d_doom-e1m1.ts │ │ ├── d_jak.ts │ │ ├── d_lara.ts │ │ ├── d_peaches-castle.ts │ │ ├── d_ps.ts │ │ ├── d_quake-e1m1.ts │ │ ├── d_sandshark.ts │ │ ├── d_spaceship.ts │ │ ├── d_spiderman.ts │ │ ├── d_teapot.ts │ │ └── d_vader.ts ├── engine │ ├── a_assets.ts │ ├── an_animation.ts │ ├── i_input.ts │ ├── m_aabb3.ts │ ├── m_collision.ts │ ├── m_mat4.ts │ ├── m_math.ts │ ├── m_tri3.ts │ ├── m_vec2.ts │ ├── m_vec3.ts │ ├── r_camera.ts │ ├── r_draw.ts │ ├── r_drawers.ts │ ├── r_geometry.ts │ └── r_screen.ts ├── game │ ├── g_const.ts │ ├── g_main.ts │ ├── g_run.ts │ └── g_setup.ts ├── typedef.d.ts └── view │ └── index.ejs ├── tools ├── build.js ├── file.js ├── log.js ├── misc.js ├── obj.js ├── server.js └── watch.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | end_of_line = lf 11 | -------------------------------------------------------------------------------- /.github/workflows/build-and-deploy.yml: -------------------------------------------------------------------------------- 1 | # this workflow will do a clean installation of node dependencies, cache/restore 2 | # them and build the source code. 3 | # 4 | # for more info: 5 | # https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#creating-a-custom-github-actions-workflow-to-publish-your-site 6 | 7 | name: Build & Deploy CI 8 | on: 9 | push: 10 | branches: [master] 11 | jobs: 12 | build-and-upload: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | node-version: [16.x] 17 | steps: 18 | # checkout the repository over at GitHub 19 | - uses: actions/checkout@v4 20 | # setup a Node.js environment with the given configuration 21 | - name: 'Use Node.js ${{ matrix.node-version }}' 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: '${{ matrix.node-version }}' 25 | cache: npm 26 | # install dependencies 27 | - run: npm ci 28 | # build the site 29 | - run: npm run build 30 | # setup and configure GitHub Pages 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v5 33 | # a composite action for packaging and uploading an artifact that 34 | # can be deployed at GitHub Pages 35 | - name: Upload artifact 36 | uses: actions/upload-pages-artifact@v3 37 | with: 38 | path: dist/ # path to serve/deploy at GitHub Pages 39 | deploy: 40 | runs-on: ubuntu-latest 41 | # configure the environment for GitHub Pages 42 | environment: 43 | name: github-pages 44 | url: '${{ steps.deployment.outputs.page_url }}' 45 | # grant GITHUB_TOKEN the permissions required to make a Pages deployment 46 | permissions: 47 | # to deploy to GitHub Pages 48 | pages: write 49 | # to verify that the deployment originates from an appropriate 50 | # source 51 | id-token: write 52 | needs: build-and-upload # add a dependency to the build job 53 | steps: 54 | - name: Deploy to GitHub Pages 55 | id: deployment 56 | uses: actions/deploy-pages@v4 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # directories 2 | node_modules 3 | screenshots 4 | dist 5 | 6 | # dotfiles 7 | .DS_Store 8 | .Python 9 | *.sublime-workspace 10 | 11 | # misc. 12 | *.zip 13 | -------------------------------------------------------------------------------- /.images/lmb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/.images/lmb.png -------------------------------------------------------------------------------- /.images/msw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/.images/msw.png -------------------------------------------------------------------------------- /.images/tmp3d_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/.images/tmp3d_2x.png -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.14.0 2 | 3 | -------------------------------------------------------------------------------- /CONVENTIONS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | Coordinate systems 3 | -------------------------------------------------------------------------------- 4 | 5 | Tmp3D uses column-vectors. 6 | 7 | ┌ ┐ 8 | | x.x y.x z.x t.x | 9 | | x.y y.y z.y t.y | 10 | | x.z y.z z.z t.z | 11 | | x.w y.w z.w t.w | 12 | └ ┘ 13 | 14 | A right-handed coordinate system is used, and the untransformed camera is 15 | situated at the origin <0, 0, 0>, looking towards +z. 16 | 17 | _ +z 18 | /| 19 | / 20 | / 21 | <0, 0, 0> -----> +x 22 | | 23 | | 24 | | 25 | \|/ 26 | +y 27 | 28 | The projection plane has its center at <0, 0, zNear>, where `zNear' is 29 | determined by the vertical FOV (`fovy'), where: 30 | 31 | screenHeight 32 | zNear = ------------------- 33 | 2 * tan(fovy / 2) 34 | 35 | +z 36 | _______ 37 | | | 38 | |__/____| 39 | / 40 | <0, 0, 0> ----> +x 41 | | 42 | | 43 | | 44 | \|/ 45 | +y 46 | 47 | The camera has six degrees of freedom and its rotations use Rodrigues' 48 | Axis-angle representation. The yaw is always followed by the pitch. The positive 49 | rotations follow the right-hand rule as well: they are clockwise when looking 50 | towards the positive direction of that particular axis. 51 | 52 | The screen-space origin is at <0, 0> and the +y points downwards. 53 | 54 | <0, 0>-------------> +x 55 | | | 56 | | | 57 | |___________| 58 | | 59 | \|/ 60 | +y 61 | 62 | The triangles facing the camera have counter-clockwise winding. 63 | 64 | /\ 65 | / \ 66 | / \ 67 | / \ 68 | / ↺ \ 69 | / \ 70 | /____________\ 71 | 72 | -------------------------------------------------------------------------------- 73 | Renderer 74 | -------------------------------------------------------------------------------- 75 | 76 | The renderer has no sub-pixel accuracy, the screen coordinates are strictly 77 | integers. 78 | 79 | The triangle rasterization routines follow the "top-left" coverage rule (as seen 80 | in OpenGL and D3D): 81 | 82 | Every pixel that falls inside the triangle is drawn--A pixel is assumed to be 83 | inside the triangle if it satisfies the top-left rule: 84 | 85 | - A pixel is considered to lie inside the triangle if its center lies completely 86 | inside the triangle, without touching any of the edges except for the "top" 87 | and the "left" edges. 88 | - A top edge is above all of the other edges and is perfectly horizontal. 89 | - A left edge is any edge that is not perfectly horizontal and is on the left of 90 | the triangle. At most two edges in a triangle can be identified as a left 91 | edge. 92 | 93 | The top-left rule guarantees that pixels that are shared by two adjacent 94 | triangles are drawn exactly once. 95 | -------------------------------------------------------------------------------- /FILES: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | A (Game) Assets 3 | -------------------------------------------------------------------------------- 4 | a_assets.ts - load game assets into memory and read them on-the-fly 5 | 6 | -------------------------------------------------------------------------------- 7 | AN ANimation 8 | -------------------------------------------------------------------------------- 9 | an_animation.ts - animate in-engine objects 10 | 11 | -------------------------------------------------------------------------------- 12 | G Game loops and top-level stuff 13 | -------------------------------------------------------------------------------- 14 | g_const.ts - constants 15 | g_main.ts - the main program 16 | g_run.ts - game loops 17 | g_setup.ts - setup routines 18 | 19 | -------------------------------------------------------------------------------- 20 | I Interfaces, I/O controllers 21 | -------------------------------------------------------------------------------- 22 | i_input.ts - mouse & keyboard controller 23 | 24 | -------------------------------------------------------------------------------- 25 | M Math 26 | -------------------------------------------------------------------------------- 27 | m_math.ts - math utilities 28 | m_mat4.ts - 4x4 matrix 29 | m_tri3.ts - 3-D triangle 30 | m_vec2.ts - 2-D vector 31 | m_vec3.ts - 3-D vector 32 | m_aabb3.ts - 3-D axis-aligned bounding-box 33 | m_collision.ts - Collisions in 2-D & 3-D 34 | 35 | -------------------------------------------------------------------------------- 36 | R Rendering 37 | -------------------------------------------------------------------------------- 38 | r_camera.ts - camera controller, and view & perspective transformations 39 | r_draw.ts - rendering back-end--drawing routines 40 | r_drawers.ts - render various menus, screens, etc. 41 | r_geometry.ts - load, update & render 3-D geometry data 42 | r_screen.ts - rendering front-end--access to framebuffer APIs 43 | 44 | -------------------------------------------------------------------------------- 45 | D Data 46 | -------------------------------------------------------------------------------- 47 | mesh/d_*.ts - initial mesh data 48 | d_player.ts - initial player data 49 | d_textures.ts - texture lookup tables 50 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 |
5 | itch.io 6 | • 7 | 8 | Play in the browser 9 | 10 | • 11 | 13 | Feature showcases 14 | 15 |

16 |

17 | 20 | 21 | 24 | 25 | 28 | 29 | 32 | 33 | 36 | 37 | 40 | 41 |

42 | 43 | Tmp3D is a 3-D software renderer written from scratch in nothing but 44 | [TypeScript](https://www.typescriptlang.org/) (which itself transpiles into 45 | plain-old JavaScript before going into your browser), just for kicks. It makes 46 | use of the `2d` graphics context of the HTML5 `` to draw some graphics 47 | primitives and nothing more (no WebGL, THREE.js, no hardware acceleration, no 48 | nothin'). 49 | 50 | The project is still heavily a work-in-progress and in its very early stages, so 51 | you may take it as it is and expect many more features to follow very soon. 52 | 53 | Tmp3D currently supports 54 | 55 | - efficient drawing of such graphics primitives as lines, rectangles and 56 | triangles 57 | - a first-person camera with _6_ degrees-of-freedom: translating along _x_, 58 | _y_ & _z_ axes, and _yaw_, _pitch_ & _roll_ 59 | - back-face culling 60 | - AABB-based, crude frustum-culling 61 | - raster-clipping, i.e., 2-D clipping in the raster space 62 | - clipping geometry against the near-clipping plane 63 | - flat and diffuse lighting w/ directional lights 64 | - perspective-correct texture-mapping 65 | - loading & rendering 3-D models in the [Wavefront `.obj` format](https://en.wikipedia.org/wiki/Wavefront_.obj_file) 66 | - depth-buffering & depth-sorting 67 | - double-buffering 68 | 69 | and plans to support 70 | 71 | - Phong reflection model 72 | - affine texture-mapping 73 | - occlusion culling (😩) 74 | - a more de-coupled & user-friendly shader pipeline 75 | 76 | ### Why? 77 | 78 | My main motive for undertaking this project was that it'd be educational, 79 | recreational, and entertaining. I may or may not try and make a game with it at 80 | some point if I'm satisfied with its progress. So, the fact of the matter is, 81 | [have some fun while re-inventing the wheel](https://youtu.be/WniZwxGA_-s). 82 | 83 | ### Setting up 84 | 85 | #### Requirements 86 | 87 | - Node.js 88 | - `ejs` 89 | - `express` 90 | 91 | After cloning the repository, navigate to the root folder and install the 92 | dependencies using `npm`. 93 | 94 | ```bash 95 | $ npm install 96 | ``` 97 | 98 | Once all the dependencies are installed, you can start up an Express development 99 | server with: 100 | 101 | ```bash 102 | $ npm run start 103 | ``` 104 | 105 | To enable the debugging features, run: 106 | 107 | ```bash 108 | $ npm run start:debug 109 | ``` 110 | 111 | Finally, open up your browser of choice and go to 112 | [127.0.0.1:3000](https://127.0.0.1:3000). 113 | 114 | ### Loading `.obj` models 115 | 116 | To load `.obj` models into Tmp3D in a format that the engine can operate on, 117 | you may use the integrated CLI tool: 118 | 119 | ```bash 120 | $ npm run load-obj path/to/obj 121 | ``` 122 | 123 | If your `.obj` model has a reference to a material library, you can load that as 124 | well, by passing the path to it in an optional argument with `--material`, or 125 | `-m`: 126 | 127 | ```bash 128 | $ npm run load-obj path/to/obj -- -m path/to/mtl 129 | ``` 130 | 131 | You may optionally offset the model by translating it along the z-axis by a 132 | certain amount: 133 | 134 | ```bash 135 | $ npm run load-obj path/to/obj -- -z 100 136 | ``` 137 | 138 | To view the full list of arguments, you may run: 139 | 140 | ```bash 141 | $ npm run load-obj -- -h 142 | ``` 143 | 144 | Once loaded, refresh the page to view your model in 3D! 145 | 146 | > ⚠️ *Tmp3D can process and render only triangles at this point in time, so 147 | please make sure your source geometries consist strictly of triangles--the CLI 148 | will reject it otherwise.* 149 | 150 | ### Controls 151 | 152 | | **Action** | **Keys** | 153 | |--------------------------------|-----------------------------------------------------------------------------------| 154 | | Movement | W A S D | 155 | | Free-look | , or the mouse__*__ | 156 | | Change elevation | Q E, or ![MSW]__*__ | 157 | | Toggle model rotation on/off | G | 158 | | Switch between rendering modes | R | 159 | 160 | > ⚠️ *__\*__ You should first click ![LMB] on the `canvas` to 161 | activate mouse controls.* 162 | 163 | ### Live Demo 164 | 165 | You can check out the live demo [here](https://emre-aki.github.io/tmp3d/)! 166 | 167 | ### Trivia 168 | 169 | The project is named after the fact that I'm too lazy to come up with an 170 | original name, so I make up a placeholder name to keep me going until the 171 | first-ever public release of the project, by which time I had already grown 172 | accustomed to the placeholder name and it's too late to come up with a new name, 173 | so I decide to go with it thinking I can pretend it is a deliberate choice of a 174 | name so I can make some silly _backronyms_ with it. 175 | 176 |

177 | 179 | Conventions 180 | 181 | • 182 | 184 | File descriptions 185 | 186 | • 187 | 189 | To-do 190 | 191 |

192 | 193 | [LMB]: https://raw.githubusercontent.com/emre-aki/tmp3d/master/.images/lmb.png (left mouse button) 194 | [MSW]: https://raw.githubusercontent.com/emre-aki/tmp3d/master/.images/msw.png (mouse scroll whell) 195 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Unsorted 2 | 3 | ## Debugging-aid 4 | 5 | - [x] Draw axes 6 | - [ ] Draw surface & vertex normals 7 | 8 | ## Feature-wise 9 | 10 | - [x] Camera transformations w/ 2 degrees-of-freedom (yaw and pitch) 11 | - [x] Perspective transformation 12 | - [x] Back-face culling 13 | - [x] Raster-clipping 14 | - [ ] Culling & clipping based on the view space 15 | - [ ] Frustum-culling 16 | - [x] Crude (AABB vs. AABB) 17 | - [ ] Smart (some other more optimized technique) 18 | - [ ] Clipping geometries against the view frustum 19 | - [x] Clipping against the near-plane 20 | - [ ] Clipping against the far-plane 21 | - [ ] Clipping against other planes? (Or would raster-clipping be 22 | enough?) 23 | - [x] Flat-shading 24 | - [ ] Phong reflection model 25 | - [x] Ambient lighting 26 | - [x] Diffuse lighting 27 | - [ ] Specular reflections 28 | 29 | - [ ] Texture-mapping 30 | - [ ] Affine 31 | - [x] Perspective-correct 32 | - [ ] Occlusion culling (😩) 33 | - [ ] Functionality for dynamically (re)loading mesh data (should go to server?) 34 | 35 | ## Primitives 36 | 37 | - [x] Rectangles 38 | - [x] Lines 39 | - [x] Triangles 40 | - [ ] Circles 41 | 42 | ## Project Organization 43 | 44 | - [x] `README.md` 45 | - [x] File descriptions 46 | - [x] `CONVENTIONS` 47 | - [x] Migrate to TypeScript 48 | - [ ] Decoupling? Inspiration from `OLC_PixelGameEngine`, or 49 | `OLC_ConsoleGameEngine`, or OpenGL shading pipeline? 50 | 51 | # Tentative Backlog 52 | 53 | ### release: 0.0.4 54 | - [x] Loading Wavefront `.obj` files 55 | 56 | ### release: 0.0.5 57 | - [x] Z-buffering 58 | 59 | ### release: 0.0.6 60 | - [x] Clipping geometries against the view frustum (Against the near-plane 61 | specifically for the time being) 62 | - #### release 0.0.6.1 63 | - [x] Migrate the engine to TypeScript 🎉 64 | 65 | ### release: 0.0.7 66 | - [x] Crude frustum-culling 67 | - [x] Diffuse lighting 68 | 69 | ### release: 0.0.8 70 | - [ ] Point light(s) 71 | - [ ] The complete Phong Reflection Model 72 | - [x] Ambient 73 | - [x] Diffuse 74 | - [ ] Specular 75 | 76 | ### release: 0.0.9 77 | - [ ] Fix the oscillation in the frametimes 78 | 79 | ### release: 0.0.x 80 | - [ ] Occlusion-culling 81 | -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/favicon.ico -------------------------------------------------------------------------------- /assets/models/crash/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/crash/back.png -------------------------------------------------------------------------------- /assets/models/crash/color_pallete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/crash/color_pallete.png -------------------------------------------------------------------------------- /assets/models/crash/crashbandicoot.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware 2 | # File Created: 06.05.2018 03:44:31 3 | 4 | newmtl shoes 5 | Ns 0.0000 6 | Ni 1.5000 7 | d 1.0000 8 | Tr 0.0000 9 | Tf 1.0000 1.0000 1.0000 10 | illum 2 11 | Ka 0.5880 0.5880 0.5880 12 | Kd 0.0000 0.0000 0.0000 13 | Ks 0.0000 0.0000 0.0000 14 | Ke 0.0000 0.0000 0.0000 15 | map_Ka shoes.png 16 | map_Kd shoes.png 17 | 18 | newmtl back 19 | Ns 10.0000 20 | Ni 1.5000 21 | d 1.0000 22 | Tr 0.0000 23 | Tf 1.0000 1.0000 1.0000 24 | illum 2 25 | Ka 0.5880 0.5880 0.5880 26 | Kd 0.5880 0.5880 0.5880 27 | Ks 0.0000 0.0000 0.0000 28 | Ke 0.0000 0.0000 0.0000 29 | map_Ka back.png 30 | map_Kd back.png 31 | 32 | newmtl color_pallete 33 | Ns 0.0000 34 | Ni 1.5000 35 | d 1.0000 36 | Tr 0.0000 37 | Tf 1.0000 1.0000 1.0000 38 | illum 2 39 | Ka 0.5880 0.5880 0.5880 40 | Kd 0.0000 0.0000 0.0000 41 | Ks 0.0000 0.0000 0.0000 42 | Ke 0.0000 0.0000 0.0000 43 | map_Ka color_pallete.png 44 | map_Kd color_pallete.png 45 | -------------------------------------------------------------------------------- /assets/models/crash/shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/crash/shoes.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Buckle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Buckle.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Cloth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Cloth.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Eyes.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Fur1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Fur1.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Fur2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Fur2.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Fur3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Fur3.png -------------------------------------------------------------------------------- /assets/models/daxter/Textures/Metal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/daxter/Textures/Metal.png -------------------------------------------------------------------------------- /assets/models/daxter/daxter.mtl: -------------------------------------------------------------------------------- 1 | # Blender3D MTL File: Daxter.blend 2 | # Material Count: 11 3 | newmtl material3489_Imag.016_Cloth.png 4 | Ns 84.313725 5 | Ka 0.000000 0.000000 0.000000 6 | Kd 0.262144 0.262144 0.262144 7 | Ks 0.000000 0.000000 0.000000 8 | Ni 1.000000 9 | d 0.000000 10 | illum 2 11 | map_Kd Textures/Cloth.png 12 | 13 | newmtl material3489_Imag.017_Fur2.png 14 | Ns 84.313725 15 | Ka 0.000000 0.000000 0.000000 16 | Kd 0.262144 0.262144 0.262144 17 | Ks 0.000000 0.000000 0.000000 18 | Ni 1.000000 19 | d 0.000000 20 | illum 2 21 | map_Kd Textures/Fur2.png 22 | 23 | newmtl material3666_Imag_Fur1.png 24 | Ns 84.313725 25 | Ka 0.000000 0.000000 0.000000 26 | Kd 0.262144 0.262144 0.262144 27 | Ks 0.000000 0.000000 0.000000 28 | Ni 1.000000 29 | d 0.000000 30 | illum 2 31 | map_Kd Textures/Fur1.png 32 | 33 | newmtl material3489_Imag.014_Eyes.png 34 | Ns 84.313725 35 | Ka 0.000000 0.000000 0.000000 36 | Kd 0.262144 0.262144 0.262144 37 | Ks 0.000000 0.000000 0.000000 38 | Ni 1.000000 39 | d 0.000000 40 | illum 2 41 | map_Kd Textures/Eyes.png 42 | 43 | newmtl material3489_Imag.012_Eyes.png 44 | Ns 84.313725 45 | Ka 0.000000 0.000000 0.000000 46 | Kd 0.262144 0.262144 0.262144 47 | Ks 0.000000 0.000000 0.000000 48 | Ni 1.000000 49 | d 0.000000 50 | illum 2 51 | map_Kd Textures/Eyes.png 52 | 53 | newmtl material3489_Imag.009_Eyes.png 54 | Ns 84.313725 55 | Ka 0.000000 0.000000 0.000000 56 | Kd 0.262144 0.262144 0.262144 57 | Ks 0.000000 0.000000 0.000000 58 | Ni 1.000000 59 | d 0.000000 60 | illum 2 61 | map_Kd Textures/Eyes.png 62 | 63 | newmtl material3489_Imag.013_Buckle.png 64 | Ns 84.313725 65 | Ka 0.000000 0.000000 0.000000 66 | Kd 0.262144 0.262144 0.262144 67 | Ks 0.000000 0.000000 0.000000 68 | Ni 1.000000 69 | d 0.000000 70 | illum 2 71 | map_Kd Textures/Buckle.png 72 | 73 | newmtl material3489_Imag.015_Metal.png 74 | Ns 84.313725 75 | Ka 0.000000 0.000000 0.000000 76 | Kd 0.262144 0.262144 0.262144 77 | Ks 0.000000 0.000000 0.000000 78 | Ni 1.000000 79 | d 0.000000 80 | illum 2 81 | map_Kd Textures/Metal.png 82 | 83 | newmtl material3489_Imag.010_Fur1.png 84 | Ns 84.313725 85 | Ka 0.000000 0.000000 0.000000 86 | Kd 0.262144 0.262144 0.262144 87 | Ks 0.000000 0.000000 0.000000 88 | Ni 1.000000 89 | d 0.000000 90 | illum 2 91 | map_Kd Textures/Fur1.png 92 | 93 | newmtl material3489_Imag_Met_Metal.png 94 | Ns 84.313725 95 | Ka 0.000000 0.000000 0.000000 96 | Kd 0.262144 0.262144 0.262144 97 | Ks 0.000000 0.000000 0.000000 98 | Ni 1.000000 99 | d 0.000000 100 | illum 2 101 | map_Kd Textures/Metal.png 102 | 103 | newmtl material3489_Imag.011_Fur3.png 104 | Ns 84.313725 105 | Ka 0.000000 0.000000 0.000000 106 | Kd 0.262144 0.262144 0.262144 107 | Ks 0.000000 0.000000 0.000000 108 | Ni 1.000000 109 | d 0.000000 110 | illum 2 111 | map_Kd Textures/Fur3.png 112 | -------------------------------------------------------------------------------- /assets/models/doom/BIGDOOR2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BIGDOOR2.PNG -------------------------------------------------------------------------------- /assets/models/doom/BIGDOOR4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BIGDOOR4.PNG -------------------------------------------------------------------------------- /assets/models/doom/BRNBIGC.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BRNBIGC.PNG -------------------------------------------------------------------------------- /assets/models/doom/BRNBIGL.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BRNBIGL.PNG -------------------------------------------------------------------------------- /assets/models/doom/BRNBIGR.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BRNBIGR.PNG -------------------------------------------------------------------------------- /assets/models/doom/BROWN1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BROWN1.PNG -------------------------------------------------------------------------------- /assets/models/doom/BROWN144.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BROWN144.PNG -------------------------------------------------------------------------------- /assets/models/doom/BROWN96.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BROWN96.PNG -------------------------------------------------------------------------------- /assets/models/doom/BROWNGRN.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/BROWNGRN.PNG -------------------------------------------------------------------------------- /assets/models/doom/CEIL3_5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/CEIL3_5.PNG -------------------------------------------------------------------------------- /assets/models/doom/CEIL5_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/CEIL5_1.PNG -------------------------------------------------------------------------------- /assets/models/doom/CEIL5_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/CEIL5_2.PNG -------------------------------------------------------------------------------- /assets/models/doom/COMPSPAN.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/COMPSPAN.PNG -------------------------------------------------------------------------------- /assets/models/doom/COMPTALL.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/COMPTALL.PNG -------------------------------------------------------------------------------- /assets/models/doom/COMPTILE.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/COMPTILE.PNG -------------------------------------------------------------------------------- /assets/models/doom/COMPUTE2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/COMPUTE2.PNG -------------------------------------------------------------------------------- /assets/models/doom/COMPUTE3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/COMPUTE3.PNG -------------------------------------------------------------------------------- /assets/models/doom/DOOR3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/DOOR3.PNG -------------------------------------------------------------------------------- /assets/models/doom/DOORSTOP.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/DOORSTOP.PNG -------------------------------------------------------------------------------- /assets/models/doom/DOORTRAK.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/DOORTRAK.PNG -------------------------------------------------------------------------------- /assets/models/doom/EXITDOOR.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/EXITDOOR.PNG -------------------------------------------------------------------------------- /assets/models/doom/EXITSIGN.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/EXITSIGN.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLAT14.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLAT14.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLAT18.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLAT18.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLAT20.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLAT20.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLAT23.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLAT23.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLAT5_5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLAT5_5.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR1_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR1_1.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR4_8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR4_8.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR5_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR5_1.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR5_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR5_2.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR6_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR6_2.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR7_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR7_1.PNG -------------------------------------------------------------------------------- /assets/models/doom/FLOOR7_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/FLOOR7_2.PNG -------------------------------------------------------------------------------- /assets/models/doom/F_SKY1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/F_SKY1.PNG -------------------------------------------------------------------------------- /assets/models/doom/F_SKY1_.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/F_SKY1_.PNG -------------------------------------------------------------------------------- /assets/models/doom/LITE3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/LITE3.PNG -------------------------------------------------------------------------------- /assets/models/doom/NUKAGE3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/NUKAGE3.PNG -------------------------------------------------------------------------------- /assets/models/doom/NUKE24.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/NUKE24.PNG -------------------------------------------------------------------------------- /assets/models/doom/PLANET1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/PLANET1.PNG -------------------------------------------------------------------------------- /assets/models/doom/SLADWALL.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/SLADWALL.PNG -------------------------------------------------------------------------------- /assets/models/doom/STARG3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STARG3.PNG -------------------------------------------------------------------------------- /assets/models/doom/STARGR1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STARGR1.PNG -------------------------------------------------------------------------------- /assets/models/doom/STARTAN1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STARTAN1.PNG -------------------------------------------------------------------------------- /assets/models/doom/STARTAN3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STARTAN3.PNG -------------------------------------------------------------------------------- /assets/models/doom/STEP1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STEP1.PNG -------------------------------------------------------------------------------- /assets/models/doom/STEP2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STEP2.PNG -------------------------------------------------------------------------------- /assets/models/doom/STEP6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/STEP6.PNG -------------------------------------------------------------------------------- /assets/models/doom/SUPPORT2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/SUPPORT2.PNG -------------------------------------------------------------------------------- /assets/models/doom/SW1COMP.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/SW1COMP.PNG -------------------------------------------------------------------------------- /assets/models/doom/SW1STRTN.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/SW1STRTN.PNG -------------------------------------------------------------------------------- /assets/models/doom/TEKWALL1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/TEKWALL1.PNG -------------------------------------------------------------------------------- /assets/models/doom/TEKWALL4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/TEKWALL4.PNG -------------------------------------------------------------------------------- /assets/models/doom/TLITE6_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/TLITE6_1.PNG -------------------------------------------------------------------------------- /assets/models/doom/TLITE6_4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/TLITE6_4.PNG -------------------------------------------------------------------------------- /assets/models/doom/TLITE6_5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/TLITE6_5.PNG -------------------------------------------------------------------------------- /assets/models/doom/TLITE6_6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/doom/TLITE6_6.PNG -------------------------------------------------------------------------------- /assets/models/jak3/EyelidL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/EyelidL.png -------------------------------------------------------------------------------- /assets/models/jak3/EyelidR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/EyelidR.png -------------------------------------------------------------------------------- /assets/models/jak3/Jak.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware 2 | # File Created: 23.10.2014 01:38:59 3 | 4 | newmtl Material__156 5 | Ns 10.0000 6 | Ni 1.5000 7 | d 1.0000 8 | Tr 0.0000 9 | Tf 1.0000 1.0000 1.0000 10 | illum 2 11 | Ka 0.5880 0.5880 0.5880 12 | Kd 0.5880 0.5880 0.5880 13 | Ks 0.0000 0.0000 0.0000 14 | Ke 0.0000 0.0000 0.0000 15 | map_Ka scarf.png 16 | map_Kd scarf.png 17 | 18 | newmtl Material__211 19 | Ns 10.0000 20 | Ni 1.5000 21 | d 1.0000 22 | Tr 0.0000 23 | Tf 1.0000 1.0000 1.0000 24 | illum 2 25 | Ka 0.5880 0.5880 0.5880 26 | Kd 0.5880 0.5880 0.5880 27 | Ks 0.0000 0.0000 0.0000 28 | Ke 0.0000 0.0000 0.0000 29 | map_Ka footbottom.png 30 | map_Kd footbottom.png 31 | 32 | newmtl Material__125 33 | Ns 10.0000 34 | Ni 1.5000 35 | d 1.0000 36 | Tr 0.0000 37 | Tf 1.0000 1.0000 1.0000 38 | illum 2 39 | Ka 0.5880 0.5880 0.5880 40 | Kd 0.5880 0.5880 0.5880 41 | Ks 0.0000 0.0000 0.0000 42 | Ke 0.0000 0.0000 0.0000 43 | map_Ka leglether.png 44 | map_Kd leglether.png 45 | 46 | newmtl Material__161 47 | Ns 10.0000 48 | Ni 1.5000 49 | d 1.0000 50 | Tr 0.0000 51 | Tf 1.0000 1.0000 1.0000 52 | illum 2 53 | Ka 0.5880 0.5880 0.5880 54 | Kd 0.5880 0.5880 0.5880 55 | Ks 0.0000 0.0000 0.0000 56 | Ke 0.0000 0.0000 0.0000 57 | map_Ka eyebrow.png 58 | map_Kd eyebrow.png 59 | map_refl hairshine.png 60 | 61 | newmtl Material__158 62 | Ns 10.0000 63 | Ni 1.5000 64 | d 1.0000 65 | Tr 0.0000 66 | Tf 1.0000 1.0000 1.0000 67 | illum 2 68 | Ka 0.5880 0.5880 0.5880 69 | Kd 0.5880 0.5880 0.5880 70 | Ks 0.0000 0.0000 0.0000 71 | Ke 0.0000 0.0000 0.0000 72 | map_Ka teeth.png 73 | map_Kd teeth.png 74 | 75 | newmtl Material__150 76 | Ns 10.0000 77 | Ni 1.5000 78 | d 1.0000 79 | Tr 0.0000 80 | Tf 1.0000 1.0000 1.0000 81 | illum 2 82 | Ka 0.5880 0.5880 0.5880 83 | Kd 0.5880 0.5880 0.5880 84 | Ks 0.0000 0.0000 0.0000 85 | Ke 0.0000 0.0000 0.0000 86 | map_Ka armskin.png 87 | map_Kd armskin.png 88 | 89 | newmtl Material__151 90 | Ns 10.0000 91 | Ni 1.5000 92 | d 1.0000 93 | Tr 0.0000 94 | Tf 1.0000 1.0000 1.0000 95 | illum 2 96 | Ka 0.5880 0.5880 0.5880 97 | Kd 0.5880 0.5880 0.5880 98 | Ks 0.0000 0.0000 0.0000 99 | Ke 0.0000 0.0000 0.0000 100 | map_Ka shirt.png 101 | map_Kd shirt.png 102 | 103 | newmtl Material__182 104 | Ns 10.0000 105 | Ni 1.5000 106 | d 1.0000 107 | Tr 0.0000 108 | Tf 1.0000 1.0000 1.0000 109 | illum 2 110 | Ka 0.5880 0.5880 0.5880 111 | Kd 0.5880 0.5880 0.5880 112 | Ks 0.0000 0.0000 0.0000 113 | Ke 0.0000 0.0000 0.0000 114 | map_Ka gunholster.png 115 | map_Kd gunholster.png 116 | 117 | newmtl Material__208 118 | Ns 10.0000 119 | Ni 1.5000 120 | d 1.0000 121 | Tr 0.0000 122 | Tf 1.0000 1.0000 1.0000 123 | illum 2 124 | Ka 0.5880 0.5880 0.5880 125 | Kd 0.5880 0.5880 0.5880 126 | Ks 0.0000 0.0000 0.0000 127 | Ke 0.0000 0.0000 0.0000 128 | map_Ka pants.png 129 | map_Kd pants.png 130 | 131 | newmtl Material__152 132 | Ns 10.0000 133 | Ni 1.5000 134 | d 1.0000 135 | Tr 0.0000 136 | Tf 1.0000 1.0000 1.0000 137 | illum 2 138 | Ka 0.5880 0.5880 0.5880 139 | Kd 0.5880 0.5880 0.5880 140 | Ks 0.0000 0.0000 0.0000 141 | Ke 0.0000 0.0000 0.0000 142 | map_Ka ears.png 143 | map_Kd ears.png 144 | 145 | newmtl Material__126 146 | Ns 10.0000 147 | Ni 1.5000 148 | d 1.0000 149 | Tr 0.0000 150 | Tf 1.0000 1.0000 1.0000 151 | illum 2 152 | Ka 0.5880 0.5880 0.5880 153 | Kd 0.5880 0.5880 0.5880 154 | Ks 0.0000 0.0000 0.0000 155 | Ke 0.0000 0.0000 0.0000 156 | map_Ka armbandage.png 157 | map_Kd armbandage.png 158 | 159 | newmtl Material__155 160 | Ns 10.0000 161 | Ni 1.5000 162 | d 1.0000 163 | Tr 0.0000 164 | Tf 1.0000 1.0000 1.0000 165 | illum 2 166 | Ka 0.5880 0.5880 0.5880 167 | Kd 0.5880 0.5880 0.5880 168 | Ks 0.0000 0.0000 0.0000 169 | Ke 0.0000 0.0000 0.0000 170 | map_Ka scarf.png 171 | map_Kd scarf.png 172 | 173 | newmtl Material__124sd 174 | Ns 10.0000 175 | Ni 1.5000 176 | d 1.0000 177 | Tr 0.0000 178 | Tf 1.0000 1.0000 1.0000 179 | illum 2 180 | Ka 0.5880 0.5880 0.5880 181 | Kd 0.5880 0.5880 0.5880 182 | Ks 0.0000 0.0000 0.0000 183 | Ke 0.0000 0.0000 0.0000 184 | map_Ka eyel.png 185 | map_Kd eyel.png 186 | map_refl eyeshine.png 187 | 188 | newmtl Material__128 189 | Ns 10.0000 190 | Ni 1.5000 191 | d 1.0000 192 | Tr 0.0000 193 | Tf 1.0000 1.0000 1.0000 194 | illum 2 195 | Ka 0.5880 0.5880 0.5880 196 | Kd 0.5880 0.5880 0.5880 197 | Ks 0.0000 0.0000 0.0000 198 | Ke 0.0000 0.0000 0.0000 199 | map_Ka glove.png 200 | map_Kd glove.png 201 | map_refl gloveshine.png 202 | 203 | newmtl Material__129 204 | Ns 10.0000 205 | Ni 1.5000 206 | d 1.0000 207 | Tr 0.0000 208 | Tf 1.0000 1.0000 1.0000 209 | illum 2 210 | Ka 0.5880 0.5880 0.5880 211 | Kd 0.5880 0.5880 0.5880 212 | Ks 0.0000 0.0000 0.0000 213 | Ke 0.0000 0.0000 0.0000 214 | map_Ka glovebuckle.png 215 | map_Kd glovebuckle.png 216 | map_refl buckleshine.png 217 | 218 | newmtl Material__148 219 | Ns 10.0000 220 | Ni 1.5000 221 | d 1.0000 222 | Tr 0.0000 223 | Tf 1.0000 1.0000 1.0000 224 | illum 2 225 | Ka 0.5880 0.5880 0.5880 226 | Kd 0.5880 0.5880 0.5880 227 | Ks 0.0000 0.0000 0.0000 228 | Ke 0.0000 0.0000 0.0000 229 | map_Ka hair.png 230 | map_Kd hair.png 231 | map_refl hairshine.png 232 | 233 | newmtl Material__98 234 | Ns 10.0000 235 | Ni 1.5000 236 | d 1.0000 237 | Tr 0.0000 238 | Tf 1.0000 1.0000 1.0000 239 | illum 2 240 | Ka 0.5880 0.5880 0.5880 241 | Kd 0.5880 0.5880 0.5880 242 | Ks 0.0000 0.0000 0.0000 243 | Ke 0.0000 0.0000 0.0000 244 | map_Ka chestarmorstraps.png 245 | map_Kd chestarmorstraps.png 246 | 247 | newmtl Material__176 248 | Ns 10.0000 249 | Ni 1.5000 250 | d 1.0000 251 | Tr 0.0000 252 | Tf 1.0000 1.0000 1.0000 253 | illum 2 254 | Ka 0.5880 0.5880 0.5880 255 | Kd 0.5880 0.5880 0.5880 256 | Ks 0.0000 0.0000 0.0000 257 | Ke 0.0000 0.0000 0.0000 258 | map_Ka chestarmorstraps.png 259 | map_Kd chestarmorstraps.png 260 | 261 | newmtl Material__170 262 | Ns 10.0000 263 | Ni 1.5000 264 | d 1.0000 265 | Tr 0.0000 266 | Tf 1.0000 1.0000 1.0000 267 | illum 2 268 | Ka 0.5880 0.5880 0.5880 269 | Kd 0.5880 0.5880 0.5880 270 | Ks 0.0000 0.0000 0.0000 271 | Ke 0.0000 0.0000 0.0000 272 | map_Ka armorother.png 273 | map_Kd armorother.png 274 | map_refl metalshine.png 275 | 276 | newmtl Material__123 277 | Ns 10.0000 278 | Ni 1.5000 279 | d 1.0000 280 | Tr 0.0000 281 | Tf 1.0000 1.0000 1.0000 282 | illum 2 283 | Ka 0.5880 0.5880 0.5880 284 | Kd 0.5880 0.5880 0.5880 285 | Ks 0.0000 0.0000 0.0000 286 | Ke 0.0000 0.0000 0.0000 287 | map_Ka gogglered.png 288 | map_Kd gogglered.png 289 | map_refl goggleshine.png 290 | 291 | newmtl Material__149 292 | Ns 10.0000 293 | Ni 1.5000 294 | d 1.0000 295 | Tr 0.0000 296 | Tf 1.0000 1.0000 1.0000 297 | illum 2 298 | Ka 0.5880 0.5880 0.5880 299 | Kd 0.5880 0.5880 0.5880 300 | Ks 0.0000 0.0000 0.0000 301 | Ke 0.0000 0.0000 0.0000 302 | map_Ka gogglemetal.png 303 | map_Kd gogglemetal.png 304 | map_refl metalshine.png 305 | 306 | newmtl Material__122 307 | Ns 10.0000 308 | Ni 1.5000 309 | d 1.0000 310 | Tr 0.0000 311 | Tf 1.0000 1.0000 1.0000 312 | illum 2 313 | Ka 0.5880 0.5880 0.5880 314 | Kd 0.5880 0.5880 0.5880 315 | Ks 0.0000 0.0000 0.0000 316 | Ke 0.0000 0.0000 0.0000 317 | map_Ka chestring.png 318 | map_Kd chestring.png 319 | map_refl metalshine.png 320 | 321 | newmtl Material__146 322 | Ns 10.0000 323 | Ni 1.5000 324 | d 1.0000 325 | Tr 0.0000 326 | Tf 1.0000 1.0000 1.0000 327 | illum 2 328 | Ka 0.5880 0.5880 0.5880 329 | Kd 0.5880 0.5880 0.5880 330 | Ks 0.0000 0.0000 0.0000 331 | Ke 0.0000 0.0000 0.0000 332 | map_Ka legbuckle.png 333 | map_Kd legbuckle.png 334 | map_refl buckleshine.png 335 | 336 | newmtl Material__175 337 | Ns 10.0000 338 | Ni 1.5000 339 | d 1.0000 340 | Tr 0.0000 341 | Tf 1.0000 1.0000 1.0000 342 | illum 2 343 | Ka 0.5880 0.5880 0.5880 344 | Kd 0.5880 0.5880 0.5880 345 | Ks 0.0000 0.0000 0.0000 346 | Ke 0.0000 0.0000 0.0000 347 | map_Ka chestmetal.png 348 | map_Kd chestmetal.png 349 | map_refl metalshine.png 350 | 351 | newmtl Material__111 352 | Ns 10.0000 353 | Ni 1.5000 354 | d 1.0000 355 | Tr 0.0000 356 | Tf 1.0000 1.0000 1.0000 357 | illum 2 358 | Ka 0.5880 0.5880 0.5880 359 | Kd 0.5880 0.5880 0.5880 360 | Ks 0.0000 0.0000 0.0000 361 | Ke 0.0000 0.0000 0.0000 362 | map_Ka beltstrap.png 363 | map_Kd beltstrap.png 364 | 365 | newmtl Material__124 366 | Ns 10.0000 367 | Ni 1.5000 368 | d 1.0000 369 | Tr 0.0000 370 | Tf 1.0000 1.0000 1.0000 371 | illum 2 372 | Ka 0.5880 0.5880 0.5880 373 | Kd 0.5880 0.5880 0.5880 374 | Ks 0.0000 0.0000 0.0000 375 | Ke 0.0000 0.0000 0.0000 376 | map_Ka eyer.png 377 | map_Kd eyer.png 378 | map_refl eyeshine.png 379 | 380 | newmtl Material__45 381 | Ns 10.0000 382 | Ni 1.5000 383 | d 1.0000 384 | Tr 0.0000 385 | Tf 1.0000 1.0000 1.0000 386 | illum 2 387 | Ka 0.5880 0.5880 0.5880 388 | Kd 0.5880 0.5880 0.5880 389 | Ks 0.0000 0.0000 0.0000 390 | Ke 0.0000 0.0000 0.0000 391 | map_Ka gogglecheststrap.png 392 | map_Kd gogglecheststrap.png 393 | 394 | newmtl Material__163 395 | Ns 10.0000 396 | Ni 1.5000 397 | d 1.0000 398 | Tr 0.0000 399 | Tf 1.0000 1.0000 1.0000 400 | illum 2 401 | Ka 0.5880 0.5880 0.5880 402 | Kd 0.5880 0.5880 0.5880 403 | Ks 0.0000 0.0000 0.0000 404 | Ke 0.0000 0.0000 0.0000 405 | map_Ka facefingers.png 406 | map_Kd facefingers.png 407 | 408 | newmtl Material__97 409 | Ns 10.0000 410 | Ni 1.5000 411 | d 1.0000 412 | Tr 0.0000 413 | Tf 1.0000 1.0000 1.0000 414 | illum 2 415 | Ka 0.5880 0.5880 0.5880 416 | Kd 0.5880 0.5880 0.5880 417 | Ks 0.0000 0.0000 0.0000 418 | Ke 0.0000 0.0000 0.0000 419 | map_Ka bluebandarm.png 420 | map_Kd bluebandarm.png 421 | 422 | newmtl Material__184 423 | Ns 10.0000 424 | Ni 1.5000 425 | d 1.0000 426 | Tr 0.0000 427 | Tf 1.0000 1.0000 1.0000 428 | illum 2 429 | Ka 0.5880 0.5880 0.5880 430 | Kd 0.5880 0.5880 0.5880 431 | Ks 0.0000 0.0000 0.0000 432 | Ke 0.0000 0.0000 0.0000 433 | map_Ka backclothred.png 434 | map_Kd backclothred.png 435 | 436 | newmtl Material__213 437 | Ns 10.0000 438 | Ni 1.5000 439 | d 1.0000 440 | Tr 0.0000 441 | Tf 1.0000 1.0000 1.0000 442 | illum 2 443 | Ka 0.5880 0.5880 0.5880 444 | Kd 0.5880 0.5880 0.5880 445 | Ks 0.0000 0.0000 0.0000 446 | Ke 0.0000 0.0000 0.0000 447 | map_Ka waistcloth.png 448 | map_Kd waistcloth.png 449 | 450 | newmtl Material__210 451 | Ns 10.0000 452 | Ni 1.5000 453 | d 1.0000 454 | Tr 0.0000 455 | Tf 1.0000 1.0000 1.0000 456 | illum 2 457 | Ka 0.5880 0.5880 0.5880 458 | Kd 0.5880 0.5880 0.5880 459 | Ks 0.0000 0.0000 0.0000 460 | Ke 0.0000 0.0000 0.0000 461 | map_Ka feetblue.png 462 | map_Kd feetblue.png 463 | 464 | newmtl Material__212 465 | Ns 10.0000 466 | Ni 1.5000 467 | d 1.0000 468 | Tr 0.0000 469 | Tf 1.0000 1.0000 1.0000 470 | illum 2 471 | Ka 0.5880 0.5880 0.5880 472 | Kd 0.5880 0.5880 0.5880 473 | Ks 0.0000 0.0000 0.0000 474 | Ke 0.0000 0.0000 0.0000 475 | map_Ka toemetal.png 476 | map_Kd toemetal.png 477 | map_refl buckleshine.png 478 | 479 | newmtl Material__84 480 | Ns 10.0000 481 | Ni 1.5000 482 | d 1.0000 483 | Tr 0.0000 484 | Tf 1.0000 1.0000 1.0000 485 | illum 2 486 | Ka 0.5880 0.5880 0.5880 487 | Kd 0.5880 0.5880 0.5880 488 | Ks 0.0000 0.0000 0.0000 489 | Ke 0.0000 0.0000 0.0000 490 | map_Ka chestlegstraps.png 491 | map_Kd chestlegstraps.png 492 | -------------------------------------------------------------------------------- /assets/models/jak3/armbandage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/armbandage.png -------------------------------------------------------------------------------- /assets/models/jak3/armorother.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/armorother.png -------------------------------------------------------------------------------- /assets/models/jak3/armskin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/armskin.png -------------------------------------------------------------------------------- /assets/models/jak3/backclothred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/backclothred.png -------------------------------------------------------------------------------- /assets/models/jak3/beltstrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/beltstrap.png -------------------------------------------------------------------------------- /assets/models/jak3/bluebandarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/bluebandarm.png -------------------------------------------------------------------------------- /assets/models/jak3/buckleshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/buckleshine.png -------------------------------------------------------------------------------- /assets/models/jak3/chestarmorstraps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/chestarmorstraps.png -------------------------------------------------------------------------------- /assets/models/jak3/chestlegstraps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/chestlegstraps.png -------------------------------------------------------------------------------- /assets/models/jak3/chestmetal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/chestmetal.png -------------------------------------------------------------------------------- /assets/models/jak3/chestring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/chestring.png -------------------------------------------------------------------------------- /assets/models/jak3/ears.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/ears.png -------------------------------------------------------------------------------- /assets/models/jak3/eyebrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/eyebrow.png -------------------------------------------------------------------------------- /assets/models/jak3/eyel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/eyel.png -------------------------------------------------------------------------------- /assets/models/jak3/eyer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/eyer.png -------------------------------------------------------------------------------- /assets/models/jak3/eyeshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/eyeshine.png -------------------------------------------------------------------------------- /assets/models/jak3/facefingers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/facefingers.png -------------------------------------------------------------------------------- /assets/models/jak3/feetblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/feetblue.png -------------------------------------------------------------------------------- /assets/models/jak3/footbottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/footbottom.png -------------------------------------------------------------------------------- /assets/models/jak3/glove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/glove.png -------------------------------------------------------------------------------- /assets/models/jak3/glovebuckle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/glovebuckle.png -------------------------------------------------------------------------------- /assets/models/jak3/gloveshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/gloveshine.png -------------------------------------------------------------------------------- /assets/models/jak3/gogglecheststrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/gogglecheststrap.png -------------------------------------------------------------------------------- /assets/models/jak3/gogglemetal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/gogglemetal.png -------------------------------------------------------------------------------- /assets/models/jak3/gogglered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/gogglered.png -------------------------------------------------------------------------------- /assets/models/jak3/goggleshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/goggleshine.png -------------------------------------------------------------------------------- /assets/models/jak3/gunholster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/gunholster.png -------------------------------------------------------------------------------- /assets/models/jak3/hair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/hair.png -------------------------------------------------------------------------------- /assets/models/jak3/hairshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/hairshine.png -------------------------------------------------------------------------------- /assets/models/jak3/legbuckle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/legbuckle.png -------------------------------------------------------------------------------- /assets/models/jak3/leglether.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/leglether.png -------------------------------------------------------------------------------- /assets/models/jak3/metalshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/metalshine.png -------------------------------------------------------------------------------- /assets/models/jak3/pants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/pants.png -------------------------------------------------------------------------------- /assets/models/jak3/scarf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/scarf.png -------------------------------------------------------------------------------- /assets/models/jak3/shirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/shirt.png -------------------------------------------------------------------------------- /assets/models/jak3/teeth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/teeth.png -------------------------------------------------------------------------------- /assets/models/jak3/toemetal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/toemetal.png -------------------------------------------------------------------------------- /assets/models/jak3/waistcloth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/jak3/waistcloth.png -------------------------------------------------------------------------------- /assets/models/lara/lara.mtl: -------------------------------------------------------------------------------- 1 | newmtl tile0 2 | Ns 94.117647 3 | Ka 1.000000 1.000000 1.000000 4 | Kd 0.796863 0.796863 0.796863 5 | Ks 0.000000 0.000000 0.000000 6 | Ke 0.000000 0.000000 0.000000 7 | Ni 1.000000 8 | d 1.000000 9 | illum 2 10 | map_Kd Lara.png 11 | 12 | newmtl tile0.001 13 | Ns 94.117647 14 | Ka 1.000000 1.000000 1.000000 15 | Kd 0.796863 0.796863 0.796863 16 | Ks 0.000000 0.000000 0.000000 17 | Ke 0.000000 0.000000 0.000000 18 | Ni 1.000000 19 | d 1.000000 20 | illum 2 21 | map_Kd ponytail.png 22 | map_d ponytail.png 23 | -------------------------------------------------------------------------------- /assets/models/lara/lara.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/lara/lara.png -------------------------------------------------------------------------------- /assets/models/lara/ponytail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/lara/ponytail.png -------------------------------------------------------------------------------- /assets/models/mario64/114626C6_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/114626C6_c.png -------------------------------------------------------------------------------- /assets/models/mario64/148EB7B9_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/148EB7B9_c.png -------------------------------------------------------------------------------- /assets/models/mario64/154B175A_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/154B175A_c.png -------------------------------------------------------------------------------- /assets/models/mario64/1916F8C5_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/1916F8C5_c.png -------------------------------------------------------------------------------- /assets/models/mario64/19D5421D_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/19D5421D_c.png -------------------------------------------------------------------------------- /assets/models/mario64/1D0CA178_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/1D0CA178_c.png -------------------------------------------------------------------------------- /assets/models/mario64/1FEE462_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/1FEE462_c.png -------------------------------------------------------------------------------- /assets/models/mario64/1FFBC780_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/1FFBC780_c.png -------------------------------------------------------------------------------- /assets/models/mario64/20EF7F7C_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/20EF7F7C_c.png -------------------------------------------------------------------------------- /assets/models/mario64/2BC808F1_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/2BC808F1_c.png -------------------------------------------------------------------------------- /assets/models/mario64/31BEEA74_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/31BEEA74_c.png -------------------------------------------------------------------------------- /assets/models/mario64/36B9F48_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/36B9F48_c.png -------------------------------------------------------------------------------- /assets/models/mario64/3AB7B2BC_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/3AB7B2BC_c.png -------------------------------------------------------------------------------- /assets/models/mario64/3C6851DA_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/3C6851DA_c.png -------------------------------------------------------------------------------- /assets/models/mario64/3FBAB8A0_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/3FBAB8A0_c.png -------------------------------------------------------------------------------- /assets/models/mario64/41EDCCB_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/41EDCCB_c.png -------------------------------------------------------------------------------- /assets/models/mario64/49254A53_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/49254A53_c.png -------------------------------------------------------------------------------- /assets/models/mario64/5EDC83BD_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/5EDC83BD_c.png -------------------------------------------------------------------------------- /assets/models/mario64/60A64656_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/60A64656_c.png -------------------------------------------------------------------------------- /assets/models/mario64/61BE951F_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/61BE951F_c.png -------------------------------------------------------------------------------- /assets/models/mario64/6AE21407_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/6AE21407_c.png -------------------------------------------------------------------------------- /assets/models/mario64/6DAF90F6_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/6DAF90F6_c.png -------------------------------------------------------------------------------- /assets/models/mario64/7EB1C6A1_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/mario64/7EB1C6A1_c.png -------------------------------------------------------------------------------- /assets/models/pslogo/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/pslogo/blue.png -------------------------------------------------------------------------------- /assets/models/pslogo/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/pslogo/green.png -------------------------------------------------------------------------------- /assets/models/pslogo/ps.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware 2 | # File Created: 17.07.2019 05:58:33 3 | 4 | newmtl Material__26 5 | Ns 10.0000 6 | Ni 1.5000 7 | d 1.0000 8 | Tr 0.0000 9 | Tf 1.0000 1.0000 1.0000 10 | illum 2 11 | Ka 0.5880 0.5880 0.5880 12 | Kd 0.5880 0.5880 0.5880 13 | Ks 0.0000 0.0000 0.0000 14 | Ke 0.0000 0.0000 0.0000 15 | map_Ka green.png 16 | map_Kd green.png 17 | 18 | newmtl Material__27 19 | Ns 10.0000 20 | Ni 1.5000 21 | d 1.0000 22 | Tr 0.0000 23 | Tf 1.0000 1.0000 1.0000 24 | illum 2 25 | Ka 0.5880 0.5880 0.5880 26 | Kd 0.5880 0.5880 0.5880 27 | Ks 0.0000 0.0000 0.0000 28 | Ke 0.0000 0.0000 0.0000 29 | map_Ka red.png 30 | map_Kd red.png 31 | 32 | newmtl Material__28 33 | Ns 10.0000 34 | Ni 1.5000 35 | d 1.0000 36 | Tr 0.0000 37 | Tf 1.0000 1.0000 1.0000 38 | illum 2 39 | Ka 0.5880 0.5880 0.5880 40 | Kd 0.5880 0.5880 0.5880 41 | Ks 0.0000 0.0000 0.0000 42 | Ke 0.0000 0.0000 0.0000 43 | map_Ka yellow.png 44 | map_Kd yellow.png 45 | 46 | newmtl Material__25 47 | Ns 10.0000 48 | Ni 1.5000 49 | d 1.0000 50 | Tr 0.0000 51 | Tf 1.0000 1.0000 1.0000 52 | illum 2 53 | Ka 0.5880 0.5880 0.5880 54 | Kd 0.5880 0.5880 0.5880 55 | Ks 0.0000 0.0000 0.0000 56 | Ke 0.0000 0.0000 0.0000 57 | map_Ka blue.png 58 | map_Kd blue.png 59 | -------------------------------------------------------------------------------- /assets/models/pslogo/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/pslogo/red.png -------------------------------------------------------------------------------- /assets/models/pslogo/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/pslogo/yellow.png -------------------------------------------------------------------------------- /assets/models/quake/+0basebtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0basebtn.png -------------------------------------------------------------------------------- /assets/models/quake/+0basebtn_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0basebtn_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+0planet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0planet.png -------------------------------------------------------------------------------- /assets/models/quake/+0slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0slip.png -------------------------------------------------------------------------------- /assets/models/quake/+0slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+0slipbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0slipbot.png -------------------------------------------------------------------------------- /assets/models/quake/+0sliptop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+0sliptop.png -------------------------------------------------------------------------------- /assets/models/quake/+1basebtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+1basebtn.png -------------------------------------------------------------------------------- /assets/models/quake/+1planet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+1planet.png -------------------------------------------------------------------------------- /assets/models/quake/+1slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+1slip.png -------------------------------------------------------------------------------- /assets/models/quake/+1slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+1slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+2planet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+2planet.png -------------------------------------------------------------------------------- /assets/models/quake/+2slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+2slip.png -------------------------------------------------------------------------------- /assets/models/quake/+2slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+2slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+3planet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+3planet.png -------------------------------------------------------------------------------- /assets/models/quake/+3slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+3slip.png -------------------------------------------------------------------------------- /assets/models/quake/+3slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+3slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+4slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+4slip.png -------------------------------------------------------------------------------- /assets/models/quake/+4slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+4slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+5slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+5slip.png -------------------------------------------------------------------------------- /assets/models/quake/+5slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+5slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+6slip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+6slip.png -------------------------------------------------------------------------------- /assets/models/quake/+6slip_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+6slip_emission.png -------------------------------------------------------------------------------- /assets/models/quake/+abasebtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/+abasebtn.png -------------------------------------------------------------------------------- /assets/models/quake/_slime0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/_slime0.png -------------------------------------------------------------------------------- /assets/models/quake/_teleport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/_teleport.png -------------------------------------------------------------------------------- /assets/models/quake/_water0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/_water0.png -------------------------------------------------------------------------------- /assets/models/quake/basebutn3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/basebutn3.png -------------------------------------------------------------------------------- /assets/models/quake/basebutn3_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/basebutn3_emission.png -------------------------------------------------------------------------------- /assets/models/quake/clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/clip.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_1.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_2.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_3.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_4.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_5.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_6.png -------------------------------------------------------------------------------- /assets/models/quake/comp1_6_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/comp1_6_emission.png -------------------------------------------------------------------------------- /assets/models/quake/crate0_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/crate0_side.png -------------------------------------------------------------------------------- /assets/models/quake/crate0_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/crate0_top.png -------------------------------------------------------------------------------- /assets/models/quake/door02_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/door02_1.png -------------------------------------------------------------------------------- /assets/models/quake/ecop1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/ecop1_1.png -------------------------------------------------------------------------------- /assets/models/quake/ecop1_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/ecop1_4.png -------------------------------------------------------------------------------- /assets/models/quake/ecop1_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/ecop1_6.png -------------------------------------------------------------------------------- /assets/models/quake/edoor01_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/edoor01_1.png -------------------------------------------------------------------------------- /assets/models/quake/ground1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/ground1_2.png -------------------------------------------------------------------------------- /assets/models/quake/ground1_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/ground1_6.png -------------------------------------------------------------------------------- /assets/models/quake/key01_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/key01_3.png -------------------------------------------------------------------------------- /assets/models/quake/plat_side1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/plat_side1.png -------------------------------------------------------------------------------- /assets/models/quake/plat_stem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/plat_stem.png -------------------------------------------------------------------------------- /assets/models/quake/plat_top1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/plat_top1.png -------------------------------------------------------------------------------- /assets/models/quake/sfloor4_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/sfloor4_2.png -------------------------------------------------------------------------------- /assets/models/quake/sfloor4_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/sfloor4_5.png -------------------------------------------------------------------------------- /assets/models/quake/sky4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/sky4.png -------------------------------------------------------------------------------- /assets/models/quake/slip1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/slip1.png -------------------------------------------------------------------------------- /assets/models/quake/slip1_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/slip1_emission.png -------------------------------------------------------------------------------- /assets/models/quake/slipbotsd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/slipbotsd.png -------------------------------------------------------------------------------- /assets/models/quake/sliplite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/sliplite.png -------------------------------------------------------------------------------- /assets/models/quake/sliplite_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/sliplite_emission.png -------------------------------------------------------------------------------- /assets/models/quake/slipside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/slipside.png -------------------------------------------------------------------------------- /assets/models/quake/slipside_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/slipside_emission.png -------------------------------------------------------------------------------- /assets/models/quake/sliptopsd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/sliptopsd.png -------------------------------------------------------------------------------- /assets/models/quake/switch_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/switch_1.png -------------------------------------------------------------------------------- /assets/models/quake/switch_1_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/switch_1_emission.png -------------------------------------------------------------------------------- /assets/models/quake/tech01_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech01_1.png -------------------------------------------------------------------------------- /assets/models/quake/tech01_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech01_6.png -------------------------------------------------------------------------------- /assets/models/quake/tech01_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech01_7.png -------------------------------------------------------------------------------- /assets/models/quake/tech01_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech01_9.png -------------------------------------------------------------------------------- /assets/models/quake/tech04_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech04_1.png -------------------------------------------------------------------------------- /assets/models/quake/tech04_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech04_2.png -------------------------------------------------------------------------------- /assets/models/quake/tech04_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech04_3.png -------------------------------------------------------------------------------- /assets/models/quake/tech07_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech07_2.png -------------------------------------------------------------------------------- /assets/models/quake/tech08_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech08_1.png -------------------------------------------------------------------------------- /assets/models/quake/tech09_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech09_3.png -------------------------------------------------------------------------------- /assets/models/quake/tech10_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech10_1.png -------------------------------------------------------------------------------- /assets/models/quake/tech10_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech10_3.png -------------------------------------------------------------------------------- /assets/models/quake/tech11_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tech11_2.png -------------------------------------------------------------------------------- /assets/models/quake/tlight01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight01.png -------------------------------------------------------------------------------- /assets/models/quake/tlight01_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight01_emission.png -------------------------------------------------------------------------------- /assets/models/quake/tlight02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight02.png -------------------------------------------------------------------------------- /assets/models/quake/tlight02_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight02_emission.png -------------------------------------------------------------------------------- /assets/models/quake/tlight07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight07.png -------------------------------------------------------------------------------- /assets/models/quake/tlight07_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight07_emission.png -------------------------------------------------------------------------------- /assets/models/quake/tlight08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight08.png -------------------------------------------------------------------------------- /assets/models/quake/tlight10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight10.png -------------------------------------------------------------------------------- /assets/models/quake/tlight11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight11.png -------------------------------------------------------------------------------- /assets/models/quake/tlight11_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/tlight11_emission.png -------------------------------------------------------------------------------- /assets/models/quake/trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/trigger.png -------------------------------------------------------------------------------- /assets/models/quake/twall1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall1_1.png -------------------------------------------------------------------------------- /assets/models/quake/twall1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall1_2.png -------------------------------------------------------------------------------- /assets/models/quake/twall2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall2_1.png -------------------------------------------------------------------------------- /assets/models/quake/twall2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall2_2.png -------------------------------------------------------------------------------- /assets/models/quake/twall2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall2_3.png -------------------------------------------------------------------------------- /assets/models/quake/twall2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall2_5.png -------------------------------------------------------------------------------- /assets/models/quake/twall2_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall2_6.png -------------------------------------------------------------------------------- /assets/models/quake/twall3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall3_1.png -------------------------------------------------------------------------------- /assets/models/quake/twall5_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall5_1.png -------------------------------------------------------------------------------- /assets/models/quake/twall5_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/twall5_3.png -------------------------------------------------------------------------------- /assets/models/quake/uwall1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/uwall1_2.png -------------------------------------------------------------------------------- /assets/models/quake/z_exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/z_exit.png -------------------------------------------------------------------------------- /assets/models/quake/z_exit_emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/quake/z_exit_emission.png -------------------------------------------------------------------------------- /assets/models/sandshark/Tire1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/Tire1.png -------------------------------------------------------------------------------- /assets/models/sandshark/bolts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/bolts.png -------------------------------------------------------------------------------- /assets/models/sandshark/cap1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/cap1.png -------------------------------------------------------------------------------- /assets/models/sandshark/cap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/cap2.png -------------------------------------------------------------------------------- /assets/models/sandshark/gun1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/gun1.png -------------------------------------------------------------------------------- /assets/models/sandshark/gun2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/gun2.png -------------------------------------------------------------------------------- /assets/models/sandshark/gunbarrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/gunbarrel.png -------------------------------------------------------------------------------- /assets/models/sandshark/metal1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/metal1.png -------------------------------------------------------------------------------- /assets/models/sandshark/metal2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/metal2.png -------------------------------------------------------------------------------- /assets/models/sandshark/metal3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/metal3.png -------------------------------------------------------------------------------- /assets/models/sandshark/metal4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/metal4.png -------------------------------------------------------------------------------- /assets/models/sandshark/metal5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/metal5.png -------------------------------------------------------------------------------- /assets/models/sandshark/pipe1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/pipe1.png -------------------------------------------------------------------------------- /assets/models/sandshark/pipe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/pipe2.png -------------------------------------------------------------------------------- /assets/models/sandshark/pipe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/pipe3.png -------------------------------------------------------------------------------- /assets/models/sandshark/pipe4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/pipe4.png -------------------------------------------------------------------------------- /assets/models/sandshark/pipe5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/pipe5.png -------------------------------------------------------------------------------- /assets/models/sandshark/pipeinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/pipeinner.png -------------------------------------------------------------------------------- /assets/models/sandshark/sandshark.mtl: -------------------------------------------------------------------------------- 1 | # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware 2 | # File Created: 09.11.2014 09:06:56 3 | 4 | newmtl Material__26 5 | Ns 10.0000 6 | Ni 1.5000 7 | d 1.0000 8 | Tr 0.0000 9 | Tf 1.0000 1.0000 1.0000 10 | illum 2 11 | Ka 0.5880 0.5880 0.5880 12 | Kd 0.5880 0.5880 0.5880 13 | Ks 0.0000 0.0000 0.0000 14 | Ke 0.0000 0.0000 0.0000 15 | map_Ka metal5.png 16 | map_Kd metal5.png 17 | 18 | newmtl Material__30 19 | Ns 10.0000 20 | Ni 1.5000 21 | d 1.0000 22 | Tr 0.0000 23 | Tf 1.0000 1.0000 1.0000 24 | illum 2 25 | Ka 0.5880 0.5880 0.5880 26 | Kd 0.5880 0.5880 0.5880 27 | Ks 0.0000 0.0000 0.0000 28 | Ke 0.0000 0.0000 0.0000 29 | map_Ka gun1.png 30 | map_Kd gun1.png 31 | 32 | newmtl Material__31 33 | Ns 10.0000 34 | Ni 1.5000 35 | d 1.0000 36 | Tr 0.0000 37 | Tf 1.0000 1.0000 1.0000 38 | illum 2 39 | Ka 0.5880 0.5880 0.5880 40 | Kd 0.5880 0.5880 0.5880 41 | Ks 0.0000 0.0000 0.0000 42 | Ke 0.0000 0.0000 0.0000 43 | map_Ka gun2.png 44 | map_Kd gun2.png 45 | 46 | newmtl Material__50 47 | Ns 10.0000 48 | Ni 1.5000 49 | d 1.0000 50 | Tr 0.0000 51 | Tf 1.0000 1.0000 1.0000 52 | illum 2 53 | Ka 0.5880 0.5880 0.5880 54 | Kd 0.5880 0.5880 0.5880 55 | Ks 0.0000 0.0000 0.0000 56 | Ke 0.0000 0.0000 0.0000 57 | map_Ka gunbarrel.png 58 | map_Kd gunbarrel.png 59 | 60 | newmtl Material__47 61 | Ns 10.0000 62 | Ni 1.5000 63 | d 1.0000 64 | Tr 0.0000 65 | Tf 1.0000 1.0000 1.0000 66 | illum 2 67 | Ka 0.5880 0.5880 0.5880 68 | Kd 0.5880 0.5880 0.5880 69 | Ks 0.0000 0.0000 0.0000 70 | Ke 0.0000 0.0000 0.0000 71 | map_Ka pipeinner.png 72 | map_Kd pipeinner.png 73 | 74 | newmtl Material__35 75 | Ns 10.0000 76 | Ni 1.5000 77 | d 1.0000 78 | Tr 0.0000 79 | Tf 1.0000 1.0000 1.0000 80 | illum 2 81 | Ka 0.5880 0.5880 0.5880 82 | Kd 0.5880 0.5880 0.5880 83 | Ks 0.0000 0.0000 0.0000 84 | Ke 0.0000 0.0000 0.0000 85 | map_Ka pipe3.png 86 | map_Kd pipe3.png 87 | 88 | newmtl Material__48 89 | Ns 10.0000 90 | Ni 1.5000 91 | d 1.0000 92 | Tr 0.0000 93 | Tf 1.0000 1.0000 1.0000 94 | illum 2 95 | Ka 0.5880 0.5880 0.5880 96 | Kd 0.5880 0.5880 0.5880 97 | Ks 0.0000 0.0000 0.0000 98 | Ke 0.0000 0.0000 0.0000 99 | map_Ka cap2.png 100 | map_Kd cap2.png 101 | 102 | newmtl Material__34 103 | Ns 10.0000 104 | Ni 1.5000 105 | d 1.0000 106 | Tr 0.0000 107 | Tf 1.0000 1.0000 1.0000 108 | illum 2 109 | Ka 0.5880 0.5880 0.5880 110 | Kd 0.5880 0.5880 0.5880 111 | Ks 0.0000 0.0000 0.0000 112 | Ke 0.0000 0.0000 0.0000 113 | map_Ka pipe4.png 114 | map_Kd pipe4.png 115 | 116 | newmtl Material__36 117 | Ns 10.0000 118 | Ni 1.5000 119 | d 1.0000 120 | Tr 0.0000 121 | Tf 1.0000 1.0000 1.0000 122 | illum 2 123 | Ka 0.5880 0.5880 0.5880 124 | Kd 0.5880 0.5880 0.5880 125 | Ks 0.0000 0.0000 0.0000 126 | Ke 0.0000 0.0000 0.0000 127 | map_Ka metal4.png 128 | map_Kd metal4.png 129 | 130 | newmtl Material__37 131 | Ns 10.0000 132 | Ni 1.5000 133 | d 1.0000 134 | Tr 0.0000 135 | Tf 1.0000 1.0000 1.0000 136 | illum 2 137 | Ka 0.5880 0.5880 0.5880 138 | Kd 0.5880 0.5880 0.5880 139 | Ks 0.0000 0.0000 0.0000 140 | Ke 0.0000 0.0000 0.0000 141 | map_Ka metal3.png 142 | map_Kd metal3.png 143 | 144 | newmtl Material__38 145 | Ns 10.0000 146 | Ni 1.5000 147 | d 1.0000 148 | Tr 0.0000 149 | Tf 1.0000 1.0000 1.0000 150 | illum 2 151 | Ka 0.5880 0.5880 0.5880 152 | Kd 0.5880 0.5880 0.5880 153 | Ks 0.0000 0.0000 0.0000 154 | Ke 0.0000 0.0000 0.0000 155 | map_Ka pipe5.png 156 | map_Kd pipe5.png 157 | 158 | newmtl Material__49 159 | Ns 10.0000 160 | Ni 1.5000 161 | d 1.0000 162 | Tr 0.0000 163 | Tf 1.0000 1.0000 1.0000 164 | illum 2 165 | Ka 0.5880 0.5880 0.5880 166 | Kd 0.5880 0.5880 0.5880 167 | Ks 0.0000 0.0000 0.0000 168 | Ke 0.0000 0.0000 0.0000 169 | map_Ka cap1.png 170 | map_Kd cap1.png 171 | 172 | newmtl Material__45 173 | Ns 10.0000 174 | Ni 1.5000 175 | d 1.0000 176 | Tr 0.0000 177 | Tf 1.0000 1.0000 1.0000 178 | illum 2 179 | Ka 0.5880 0.5880 0.5880 180 | Kd 0.5880 0.5880 0.5880 181 | Ks 0.0000 0.0000 0.0000 182 | Ke 0.0000 0.0000 0.0000 183 | map_Ka metal1.png 184 | map_Kd metal1.png 185 | 186 | newmtl Material__33 187 | Ns 10.0000 188 | Ni 1.5000 189 | d 1.0000 190 | Tr 0.0000 191 | Tf 1.0000 1.0000 1.0000 192 | illum 2 193 | Ka 0.5880 0.5880 0.5880 194 | Kd 0.5880 0.5880 0.5880 195 | Ks 0.0000 0.0000 0.0000 196 | Ke 0.0000 0.0000 0.0000 197 | map_Ka seat.png 198 | map_Kd seat.png 199 | 200 | newmtl Material__43 201 | Ns 10.0000 202 | Ni 1.5000 203 | d 1.0000 204 | Tr 0.0000 205 | Tf 1.0000 1.0000 1.0000 206 | illum 2 207 | Ka 0.5880 0.5880 0.5880 208 | Kd 0.5880 0.5880 0.5880 209 | Ks 0.0000 0.0000 0.0000 210 | Ke 0.0000 0.0000 0.0000 211 | map_Ka tex1.png 212 | map_Kd tex1.png 213 | 214 | newmtl Material__29 215 | Ns 10.0000 216 | Ni 1.5000 217 | d 1.0000 218 | Tr 0.0000 219 | Tf 1.0000 1.0000 1.0000 220 | illum 2 221 | Ka 0.5880 0.5880 0.5880 222 | Kd 0.5880 0.5880 0.5880 223 | Ks 0.0000 0.0000 0.0000 224 | Ke 0.0000 0.0000 0.0000 225 | map_Ka bolts.png 226 | map_Kd bolts.png 227 | 228 | newmtl Material__41 229 | Ns 10.0000 230 | Ni 1.5000 231 | d 1.0000 232 | Tr 0.0000 233 | Tf 1.0000 1.0000 1.0000 234 | illum 2 235 | Ka 0.5880 0.5880 0.5880 236 | Kd 0.5880 0.5880 0.5880 237 | Ks 0.0000 0.0000 0.0000 238 | Ke 0.0000 0.0000 0.0000 239 | map_Ka pipe1.png 240 | map_Kd pipe1.png 241 | 242 | newmtl Material__32 243 | Ns 10.0000 244 | Ni 1.5000 245 | d 1.0000 246 | Tr 0.0000 247 | Tf 1.0000 1.0000 1.0000 248 | illum 2 249 | Ka 0.5880 0.5880 0.5880 250 | Kd 0.5880 0.5880 0.5880 251 | Ks 0.0000 0.0000 0.0000 252 | Ke 0.0000 0.0000 0.0000 253 | map_Ka metal2.png 254 | map_Kd metal2.png 255 | 256 | newmtl Material__42 257 | Ns 10.0000 258 | Ni 1.5000 259 | d 1.0000 260 | Tr 0.0000 261 | Tf 1.0000 1.0000 1.0000 262 | illum 2 263 | Ka 0.5880 0.5880 0.5880 264 | Kd 0.5880 0.5880 0.5880 265 | Ks 0.0000 0.0000 0.0000 266 | Ke 0.0000 0.0000 0.0000 267 | map_Ka pipe2.png 268 | map_Kd pipe2.png 269 | 270 | newmtl Material__25 271 | Ns 10.0000 272 | Ni 1.5000 273 | d 1.0000 274 | Tr 0.0000 275 | Tf 1.0000 1.0000 1.0000 276 | illum 2 277 | Ka 0.5880 0.5880 0.5880 278 | Kd 0.5880 0.5880 0.5880 279 | Ks 0.0000 0.0000 0.0000 280 | Ke 0.0000 0.0000 0.0000 281 | map_Ka tire2.png 282 | map_Kd tire2.png 283 | 284 | newmtl Material__28 285 | Ns 10.0000 286 | Ni 1.5000 287 | d 1.0000 288 | Tr 0.0000 289 | Tf 1.0000 1.0000 1.0000 290 | illum 2 291 | Ka 0.5880 0.5880 0.5880 292 | Kd 0.5880 0.5880 0.5880 293 | Ks 0.0000 0.0000 0.0000 294 | Ke 0.0000 0.0000 0.0000 295 | map_Ka tire3.png 296 | map_Kd tire3.png 297 | 298 | newmtl Material__27 299 | Ns 10.0000 300 | Ni 1.5000 301 | d 1.0000 302 | Tr 0.0000 303 | Tf 1.0000 1.0000 1.0000 304 | illum 2 305 | Ka 0.5880 0.5880 0.5880 306 | Kd 0.5880 0.5880 0.5880 307 | Ks 0.0000 0.0000 0.0000 308 | Ke 0.0000 0.0000 0.0000 309 | map_Ka Tire1.png 310 | map_Kd Tire1.png 311 | -------------------------------------------------------------------------------- /assets/models/sandshark/seat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/seat.png -------------------------------------------------------------------------------- /assets/models/sandshark/tex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/tex1.png -------------------------------------------------------------------------------- /assets/models/sandshark/tire2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/tire2.png -------------------------------------------------------------------------------- /assets/models/sandshark/tire3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/sandshark/tire3.png -------------------------------------------------------------------------------- /assets/models/spaceship.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.79 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | v 1.000000 -1.000000 -1.000000 4 | v 1.000000 1.000000 -1.000000 5 | v 1.000000 -1.000000 1.000000 6 | v 1.000000 1.000000 1.000000 7 | v -1.000000 -1.000000 -1.000000 8 | v -1.000000 1.000000 -1.000000 9 | v -1.000000 -1.000000 1.000000 10 | v -1.000000 1.000000 1.000000 11 | v -0.720000 0.120000 -1.400000 12 | v 0.300000 0.000000 5.000000 13 | v -0.600000 -0.600000 -1.400000 14 | v -0.300000 0.000000 5.000000 15 | v -1.200000 0.200000 1.000000 16 | v -0.600000 0.600000 -1.400000 17 | v -1.200000 -0.200000 -1.000000 18 | v -1.200000 0.200000 -1.000000 19 | v 1.200000 -0.200000 1.000000 20 | v 1.200000 -0.200000 -1.000000 21 | v 1.200000 0.200000 -1.000000 22 | v 1.200000 0.200000 1.000000 23 | v -1.200000 -0.200000 1.000000 24 | v 0.600000 0.600000 -1.400000 25 | v 0.600000 -0.600000 -1.400000 26 | v -4.200000 0.060000 1.000000 27 | v -4.200000 -0.060000 1.000000 28 | v -4.200000 -0.060000 -1.000000 29 | v -4.200000 0.060000 -1.000000 30 | v 4.200000 -0.060000 1.000000 31 | v 4.200000 -0.060000 -1.000000 32 | v 4.200000 0.060000 -1.000000 33 | v 4.200000 0.060000 1.000000 34 | v 4.200000 -0.180000 1.000000 35 | v 4.200000 -0.180000 -1.000000 36 | v 4.200000 0.180000 -1.000000 37 | v 4.200000 0.180000 1.000000 38 | v 4.500000 -0.180000 1.000000 39 | v 4.500000 -0.180000 -1.000000 40 | v 4.500000 0.180000 -1.000000 41 | v 4.500000 0.180000 1.000000 42 | v -4.200000 0.180000 1.000000 43 | v -4.200000 -0.180000 1.000000 44 | v -4.200000 -0.180000 -1.000000 45 | v -4.200000 0.180000 -1.000000 46 | v -4.500000 0.180000 1.000000 47 | v -4.500000 -0.180000 1.000000 48 | v -4.500000 -0.180000 -1.000000 49 | v -4.500000 0.180000 -1.000000 50 | v 4.350000 -0.180000 3.000000 51 | v 4.350000 0.180000 3.000000 52 | v -4.350000 0.180000 3.000000 53 | v -4.350000 -0.180000 3.000000 54 | v 0.000000 -0.700000 3.000000 55 | v -0.720000 -0.120000 -1.400000 56 | v 0.720000 -0.120000 -1.400000 57 | v 0.720000 0.120000 -1.400000 58 | s off 59 | f 21 52 12 60 | f 6 13 8 61 | f 5 23 1 62 | f 7 1 3 63 | f 4 6 8 64 | f 4 12 10 65 | f 17 20 10 66 | f 20 4 10 67 | f 17 52 3 68 | f 7 3 52 69 | f 16 14 9 70 | f 7 15 5 71 | f 20 30 19 72 | f 18 23 54 73 | f 4 19 2 74 | f 1 17 3 75 | f 13 25 21 76 | f 13 21 12 77 | f 12 52 10 78 | f 8 13 12 79 | f 27 42 43 80 | f 15 27 16 81 | f 21 26 15 82 | f 16 24 13 83 | f 31 34 30 84 | f 18 28 17 85 | f 17 31 20 86 | f 19 29 18 87 | f 32 49 35 88 | f 29 32 28 89 | f 31 32 35 90 | f 29 34 33 91 | f 38 36 37 92 | f 34 37 33 93 | f 35 38 34 94 | f 33 36 32 95 | f 43 44 40 96 | f 25 42 26 97 | f 27 40 24 98 | f 25 40 41 99 | f 44 46 45 100 | f 40 44 50 101 | f 42 47 43 102 | f 41 46 42 103 | f 44 47 46 104 | f 32 36 48 105 | f 39 35 49 106 | f 39 48 36 107 | f 45 51 50 108 | f 40 51 41 109 | f 45 41 51 110 | f 45 50 44 111 | f 18 29 28 112 | f 17 28 31 113 | f 4 2 6 114 | f 18 55 19 115 | f 15 11 5 116 | f 19 22 2 117 | f 2 14 6 118 | f 16 53 15 119 | f 53 9 54 120 | f 19 30 29 121 | f 15 26 27 122 | f 16 27 24 123 | f 13 24 25 124 | f 21 25 26 125 | f 7 21 15 126 | f 7 5 1 127 | f 21 7 52 128 | f 1 18 17 129 | f 17 10 52 130 | f 4 20 19 131 | f 20 31 30 132 | f 4 8 12 133 | f 43 47 44 134 | f 6 16 13 135 | f 40 50 51 136 | f 41 45 46 137 | f 42 46 47 138 | f 2 22 14 139 | f 19 55 22 140 | f 18 54 55 141 | f 18 1 23 142 | f 5 11 23 143 | f 15 53 11 144 | f 16 9 53 145 | f 16 6 14 146 | f 9 14 22 147 | f 22 55 9 148 | f 55 54 9 149 | f 54 23 11 150 | f 11 53 54 151 | f 34 38 37 152 | f 38 39 36 153 | f 39 49 48 154 | f 35 39 38 155 | f 33 37 36 156 | f 25 41 42 157 | f 27 43 40 158 | f 31 35 34 159 | f 29 33 32 160 | f 32 48 49 161 | f 27 26 42 162 | f 31 28 32 163 | f 29 30 34 164 | f 25 24 40 165 | -------------------------------------------------------------------------------- /assets/models/spiderman/0474ba03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/0474ba03.png -------------------------------------------------------------------------------- /assets/models/spiderman/150d18e8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/150d18e8.png -------------------------------------------------------------------------------- /assets/models/spiderman/19292d60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/19292d60.png -------------------------------------------------------------------------------- /assets/models/spiderman/492b2fc7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/492b2fc7.png -------------------------------------------------------------------------------- /assets/models/spiderman/58a5e3de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/58a5e3de.png -------------------------------------------------------------------------------- /assets/models/spiderman/606228de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/606228de.png -------------------------------------------------------------------------------- /assets/models/spiderman/65b3a447.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/65b3a447.png -------------------------------------------------------------------------------- /assets/models/spiderman/798ef42f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/798ef42f.png -------------------------------------------------------------------------------- /assets/models/spiderman/848f5e3b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/848f5e3b.png -------------------------------------------------------------------------------- /assets/models/spiderman/a1454207.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/a1454207.png -------------------------------------------------------------------------------- /assets/models/spiderman/cd057eda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/cd057eda.png -------------------------------------------------------------------------------- /assets/models/spiderman/dafccfaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/dafccfaa.png -------------------------------------------------------------------------------- /assets/models/spiderman/f99ea9d9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spiderman/f99ea9d9.png -------------------------------------------------------------------------------- /assets/models/spiderman/spiderman.mtl: -------------------------------------------------------------------------------- 1 | # Material file for spiderman.obj 2 | 3 | newmtl face 4 | Ns 0 5 | d 1 6 | illum 2 7 | Kd 0.8 0.8 0.8 8 | Ks 0.0 0.0 0.0 9 | Ka 0.2 0.2 0.2 10 | map_Kd 848f5e3b.png 11 | 12 | newmtl front 13 | Ns 0 14 | d 1 15 | illum 2 16 | Kd 0.8 0.8 0.8 17 | Ks 0.0 0.0 0.0 18 | Ka 0.2 0.2 0.2 19 | map_Kd 606228de.png 20 | 21 | newmtl back 22 | Ns 0 23 | d 1 24 | illum 2 25 | Kd 0.8 0.8 0.8 26 | Ks 0.0 0.0 0.0 27 | Ka 0.2 0.2 0.2 28 | map_Kd dafccfaa.png 29 | 30 | newmtl leg 31 | Ns 0 32 | d 1 33 | illum 2 34 | Kd 0.8 0.8 0.8 35 | Ks 0.0 0.0 0.0 36 | Ka 0.2 0.2 0.2 37 | map_Kd f99ea9d9.png 38 | 39 | newmtl crotch 40 | Ns 0 41 | d 1 42 | illum 2 43 | Kd 0.8 0.8 0.8 44 | Ks 0.0 0.0 0.0 45 | Ka 0.2 0.2 0.2 46 | map_Kd 0474ba03.png 47 | 48 | newmtl hand 49 | Ns 0 50 | d 1 51 | illum 2 52 | Kd 0.8 0.8 0.8 53 | Ks 0.0 0.0 0.0 54 | Ka 0.2 0.2 0.2 55 | map_Kd 492b2fc7.png 56 | 57 | newmtl ass 58 | Ns 0 59 | d 1 60 | illum 2 61 | Kd 0.8 0.8 0.8 62 | Ks 0.0 0.0 0.0 63 | Ka 0.2 0.2 0.2 64 | map_Kd 19292d60.png 65 | 66 | newmtl red 67 | Ns 0 68 | d 1 69 | illum 2 70 | Kd 0.8 0.8 0.8 71 | Ks 0.0 0.0 0.0 72 | Ka 0.2 0.2 0.2 73 | map_Kd 58a5e3de.png 74 | 75 | newmtl shoulder 76 | Ns 0 77 | d 1 78 | illum 2 79 | Kd 0.8 0.8 0.8 80 | Ks 0.0 0.0 0.0 81 | Ka 0.2 0.2 0.2 82 | map_Kd cd057eda.png 83 | 84 | newmtl arma 85 | Ns 0 86 | d 1 87 | illum 2 88 | Kd 0.8 0.8 0.8 89 | Ks 0.0 0.0 0.0 90 | Ka 0.2 0.2 0.2 91 | map_Kd 150d18e8.png 92 | 93 | newmtl armb 94 | Ns 0 95 | d 1 96 | illum 2 97 | Kd 0.8 0.8 0.8 98 | Ks 0.0 0.0 0.0 99 | Ka 0.2 0.2 0.2 100 | map_Kd a1454207.png 101 | 102 | newmtl foot 103 | Ns 0 104 | d 1 105 | illum 2 106 | Kd 0.8 0.8 0.8 107 | Ks 0.0 0.0 0.0 108 | Ka 0.2 0.2 0.2 109 | map_Kd 150d18e8.png 110 | 111 | -------------------------------------------------------------------------------- /assets/models/spyro/High.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spyro/High.png -------------------------------------------------------------------------------- /assets/models/spyro/Low.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/spyro/Low.png -------------------------------------------------------------------------------- /assets/models/spyro/artisans-hub.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl Material.001 5 | Ns 92.156863 6 | Ka 1.000000 1.000000 1.000000 7 | Kd 0.512000 0.512000 0.512000 8 | Ks 0.250000 0.250000 0.250000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | map_Kd High.png 14 | -------------------------------------------------------------------------------- /assets/models/tmp3dcube/cube.mtl: -------------------------------------------------------------------------------- 1 | newmtl wood 2 | map_Kd wood.png 3 | -------------------------------------------------------------------------------- /assets/models/tmp3dcube/cube.obj: -------------------------------------------------------------------------------- 1 | mtllib cube.mtl 2 | v -10 -10 10 3 | v 10 -10 10 4 | v 10 10 10 5 | v -10 10 10 6 | v -10 -10 30 7 | v 10 -10 30 8 | v 10 10 30 9 | v -10 10 30 10 | vt 0 0 11 | vt 0 1 12 | vt 1 0 13 | vt 1 1 14 | usemtl wood 15 | f 1/1 4/2 2/3 16 | f 2/3 4/2 3/4 17 | f 5/1 8/2 1/3 18 | f 1/3 8/2 4/4 19 | f 6/1 7/2 5/3 20 | f 5/3 7/2 8/4 21 | f 2/1 3/2 6/3 22 | f 6/3 3/2 7/4 23 | f 5/1 1/2 6/3 24 | f 6/3 1/2 2/4 25 | f 4/1 8/2 3/3 26 | f 3/3 8/2 7/4 27 | -------------------------------------------------------------------------------- /assets/models/tmp3dcube/wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/tmp3dcube/wood.png -------------------------------------------------------------------------------- /assets/models/vader/Vader.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 2 3 | 4 | newmtl None.002 5 | Ns 0.000000 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.800000 0.800000 0.800000 8 | Ks 0.800000 0.800000 0.800000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | map_Kd Vaderbody.png 14 | 15 | newmtl None_Vader.png.001 16 | Ns 0.000000 17 | Ka 0.000000 0.000000 0.000000 18 | Kd 0.800000 0.800000 0.800000 19 | Ks 0.800000 0.800000 0.800000 20 | Ke 0.000000 0.000000 0.000000 21 | Ni 1.000000 22 | d 1.000000 23 | illum 2 24 | map_Kd Vader.png 25 | -------------------------------------------------------------------------------- /assets/models/vader/Vader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/vader/Vader.png -------------------------------------------------------------------------------- /assets/models/vader/Vaderbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/models/vader/Vaderbody.png -------------------------------------------------------------------------------- /assets/textures/tmp3d_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emre-aki/tmp3d/b244744e9bfe3cffa99d8c4d4febc6bc88cdaeb8/assets/textures/tmp3d_2x.png -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src", "tools/server.js", "tools/watch.js", "tools/build.js"], 3 | "ext": "js,ejs,ts,d.ts", 4 | "delay": 3 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tmp3d", 3 | "version": "0.0.7.1", 4 | "description": "A 3-D software renderer written from scratch in nothing but JavaScript", 5 | "main": "./tools/server.js", 6 | "scripts": { 7 | "check": "tsc --noEmit", 8 | "start": "node ./tools/server.js", 9 | "start:debug": "DEBUG=1 node ./tools/server.js", 10 | "watch": "./node_modules/nodemon/bin/nodemon.js ./tools/watch.js", 11 | "watch:debug": "DEBUG=1 ./node_modules/nodemon/bin/nodemon.js ./tools/watch.js", 12 | "build": "node ./tools/build.js -v", 13 | "build:debug": "node ./tools/build.js -d -v", 14 | "load-obj": "node ./tools/obj.js convert" 15 | }, 16 | "repository": { 17 | "type": "git" 18 | }, 19 | "keywords": [ 20 | "rendering engine", 21 | "3-D graphics", 22 | "software renderer", 23 | "software rasterizer", 24 | "canvas", 25 | "html5" 26 | ], 27 | "author": "Emre Akı", 28 | "license": "GPL-3.0-or-later", 29 | "devDependencies": { 30 | "commander": "^11.0.0", 31 | "ejs": "^3.1.9", 32 | "express": "^4.18.2", 33 | "nodemon": "^2.0.22", 34 | "typescript": "^5.1.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/data/d_player.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * d_player.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * Initial player data. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const D_Velocity = 1; 14 | 15 | function D_Eye (): pvec3_t 16 | { 17 | return [0, -20, -100]; 18 | } 19 | 20 | window.__import__D_Player = function () 21 | { 22 | return { D_Velocity, D_Eye }; 23 | }; 24 | })(); 25 | -------------------------------------------------------------------------------- /src/data/d_textures.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * d_textures.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-05-03. 6 | * 7 | * SYNOPSIS: 8 | * Lookup tables for "global" textures. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const GLOB_TEXTURE_ID_TABLE = { TITLE_TMP3D: "TITLE_TMP3D" } as const; 14 | 15 | function D_GlobTextureIdTable (): typeof GLOB_TEXTURE_ID_TABLE 16 | { 17 | return GLOB_TEXTURE_ID_TABLE; 18 | } 19 | 20 | function 21 | D_GlobTextureFilenameTable 22 | (): { [id in (keyof typeof GLOB_TEXTURE_ID_TABLE)]: string } 23 | { 24 | return { [GLOB_TEXTURE_ID_TABLE.TITLE_TMP3D]: "textures/tmp3d_2x.png" }; 25 | } 26 | 27 | window.__import__D_GlobTextures = function () 28 | { 29 | return { 30 | D_GlobTextureIdTable: D_GlobTextureIdTable(), 31 | D_GlobTextureFilenameTable: D_GlobTextureFilenameTable(), 32 | }; 33 | }; 34 | })(); 35 | -------------------------------------------------------------------------------- /src/data/mesh/d_cube.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * d_cube.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-07-08. 6 | * 7 | * SYNOPSIS: 8 | * The initial 3-D geometry data and their respective UV mappings. 9 | */ 10 | 11 | (function (): void 12 | { 13 | function D_Vertices (): pvec3_t[] 14 | { 15 | return [ 16 | [-10, -10, -10], 17 | [10, -10, -10], 18 | [10, 10, -10], 19 | [-10, 10, -10], 20 | [-10, -10, 10], 21 | [10, -10, 10], 22 | [10, 10, 10], 23 | [-10, 10, 10] 24 | ]; 25 | } 26 | 27 | function D_UV (): pvec2_t[] 28 | { 29 | return [ 30 | [0, 0], 31 | [0, 1], 32 | [1, 0], 33 | [1, 1] 34 | ]; 35 | } 36 | 37 | function D_Triangles (): pvec3_t[] 38 | { 39 | return [ 40 | [0, 3, 1], 41 | [1, 3, 2], 42 | [4, 7, 0], 43 | [0, 7, 3], 44 | [5, 6, 4], 45 | [4, 6, 7], 46 | [1, 2, 5], 47 | [5, 2, 6], 48 | [4, 0, 5], 49 | [5, 0, 1], 50 | [3, 7, 2], 51 | [2, 7, 6] 52 | ]; 53 | } 54 | 55 | function D_UVMap (): uvface_t[] 56 | { 57 | return [ 58 | [0, 1, 2, "wood"], 59 | [2, 1, 3, "wood"], 60 | [0, 1, 2, "wood"], 61 | [2, 1, 3, "wood"], 62 | [0, 1, 2, "wood"], 63 | [2, 1, 3, "wood"], 64 | [0, 1, 2, "wood"], 65 | [2, 1, 3, "wood"], 66 | [0, 1, 2, "wood"], 67 | [2, 1, 3, "wood"], 68 | [0, 1, 2, "wood"], 69 | [2, 1, 3, "wood"] 70 | ]; 71 | } 72 | 73 | function D_TextureAtlas (): { [textureId: string]: string } 74 | { 75 | return { 76 | "wood": "models/tmp3dcube/wood.png" 77 | }; 78 | } 79 | 80 | window.__import__D_Mesh = function () 81 | { 82 | return { D_Vertices, D_UV, D_Triangles, D_UVMap, D_TextureAtlas }; 83 | }; 84 | })(); 85 | -------------------------------------------------------------------------------- /src/data/mesh/d_spaceship.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * d_spaceship.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-07-08. 6 | * 7 | * SYNOPSIS: 8 | * The initial 3-D geometry data and their respective UV mappings. 9 | */ 10 | 11 | (function (): void 12 | { 13 | function D_Vertices (): pvec3_t[] 14 | { 15 | return [ 16 | [1, -1, -1], 17 | [1, 1, -1], 18 | [1, -1, 1], 19 | [1, 1, 1], 20 | [-1, -1, -1], 21 | [-1, 1, -1], 22 | [-1, -1, 1], 23 | [-1, 1, 1], 24 | [-0.72, 0.12, -1.4], 25 | [0.3, 0, 5], 26 | [-0.6, -0.6, -1.4], 27 | [-0.3, 0, 5], 28 | [-1.2, 0.2, 1], 29 | [-0.6, 0.6, -1.4], 30 | [-1.2, -0.2, -1], 31 | [-1.2, 0.2, -1], 32 | [1.2, -0.2, 1], 33 | [1.2, -0.2, -1], 34 | [1.2, 0.2, -1], 35 | [1.2, 0.2, 1], 36 | [-1.2, -0.2, 1], 37 | [0.6, 0.6, -1.4], 38 | [0.6, -0.6, -1.4], 39 | [-4.2, 0.06, 1], 40 | [-4.2, -0.06, 1], 41 | [-4.2, -0.06, -1], 42 | [-4.2, 0.06, -1], 43 | [4.2, -0.06, 1], 44 | [4.2, -0.06, -1], 45 | [4.2, 0.06, -1], 46 | [4.2, 0.06, 1], 47 | [4.2, -0.18, 1], 48 | [4.2, -0.18, -1], 49 | [4.2, 0.18, -1], 50 | [4.2, 0.18, 1], 51 | [4.5, -0.18, 1], 52 | [4.5, -0.18, -1], 53 | [4.5, 0.18, -1], 54 | [4.5, 0.18, 1], 55 | [-4.2, 0.18, 1], 56 | [-4.2, -0.18, 1], 57 | [-4.2, -0.18, -1], 58 | [-4.2, 0.18, -1], 59 | [-4.5, 0.18, 1], 60 | [-4.5, -0.18, 1], 61 | [-4.5, -0.18, -1], 62 | [-4.5, 0.18, -1], 63 | [4.35, -0.18, 3], 64 | [4.35, 0.18, 3], 65 | [-4.35, 0.18, 3], 66 | [-4.35, -0.18, 3], 67 | [0, -0.7, 3], 68 | [-0.72, -0.12, -1.4], 69 | [0.72, -0.12, -1.4], 70 | [0.72, 0.12, -1.4] 71 | ]; 72 | } 73 | 74 | function D_UV (): pvec2_t[] 75 | { 76 | return [ 77 | 78 | ]; 79 | } 80 | 81 | function D_Triangles (): pvec3_t[] 82 | { 83 | return [ 84 | [20, 51, 11], 85 | [5, 12, 7], 86 | [4, 22, 0], 87 | [6, 0, 2], 88 | [3, 5, 7], 89 | [3, 11, 9], 90 | [16, 19, 9], 91 | [19, 3, 9], 92 | [16, 51, 2], 93 | [6, 2, 51], 94 | [15, 13, 8], 95 | [6, 14, 4], 96 | [19, 29, 18], 97 | [17, 22, 53], 98 | [3, 18, 1], 99 | [0, 16, 2], 100 | [12, 24, 20], 101 | [12, 20, 11], 102 | [11, 51, 9], 103 | [7, 12, 11], 104 | [26, 41, 42], 105 | [14, 26, 15], 106 | [20, 25, 14], 107 | [15, 23, 12], 108 | [30, 33, 29], 109 | [17, 27, 16], 110 | [16, 30, 19], 111 | [18, 28, 17], 112 | [31, 48, 34], 113 | [28, 31, 27], 114 | [30, 31, 34], 115 | [28, 33, 32], 116 | [37, 35, 36], 117 | [33, 36, 32], 118 | [34, 37, 33], 119 | [32, 35, 31], 120 | [42, 43, 39], 121 | [24, 41, 25], 122 | [26, 39, 23], 123 | [24, 39, 40], 124 | [43, 45, 44], 125 | [39, 43, 49], 126 | [41, 46, 42], 127 | [40, 45, 41], 128 | [43, 46, 45], 129 | [31, 35, 47], 130 | [38, 34, 48], 131 | [38, 47, 35], 132 | [44, 50, 49], 133 | [39, 50, 40], 134 | [44, 40, 50], 135 | [44, 49, 43], 136 | [17, 28, 27], 137 | [16, 27, 30], 138 | [3, 1, 5], 139 | [17, 54, 18], 140 | [14, 10, 4], 141 | [18, 21, 1], 142 | [1, 13, 5], 143 | [15, 52, 14], 144 | [52, 8, 53], 145 | [18, 29, 28], 146 | [14, 25, 26], 147 | [15, 26, 23], 148 | [12, 23, 24], 149 | [20, 24, 25], 150 | [6, 20, 14], 151 | [6, 4, 0], 152 | [20, 6, 51], 153 | [0, 17, 16], 154 | [16, 9, 51], 155 | [3, 19, 18], 156 | [19, 30, 29], 157 | [3, 7, 11], 158 | [42, 46, 43], 159 | [5, 15, 12], 160 | [39, 49, 50], 161 | [40, 44, 45], 162 | [41, 45, 46], 163 | [1, 21, 13], 164 | [18, 54, 21], 165 | [17, 53, 54], 166 | [17, 0, 22], 167 | [4, 10, 22], 168 | [14, 52, 10], 169 | [15, 8, 52], 170 | [15, 5, 13], 171 | [8, 13, 21], 172 | [21, 54, 8], 173 | [54, 53, 8], 174 | [53, 22, 10], 175 | [10, 52, 53], 176 | [33, 37, 36], 177 | [37, 38, 35], 178 | [38, 48, 47], 179 | [34, 38, 37], 180 | [32, 36, 35], 181 | [24, 40, 41], 182 | [26, 42, 39], 183 | [30, 34, 33], 184 | [28, 32, 31], 185 | [31, 47, 48], 186 | [26, 25, 41], 187 | [30, 27, 31], 188 | [28, 29, 33], 189 | [24, 23, 39] 190 | ]; 191 | } 192 | 193 | function D_UVMap (): uvface_t[] 194 | { 195 | return [ 196 | 197 | ]; 198 | } 199 | 200 | function D_TextureAtlas (): { [textureId: string]: string } 201 | { 202 | return { 203 | 204 | }; 205 | } 206 | 207 | window.__import__D_Mesh = function () 208 | { 209 | return { D_Vertices, D_UV, D_Triangles, D_UVMap, D_TextureAtlas }; 210 | }; 211 | })(); 212 | -------------------------------------------------------------------------------- /src/engine/a_assets.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * a_assets.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-05-03. 6 | * 7 | * SYNOPSIS: 8 | * The module that allows loading game assets into the memory and accessing 9 | * them on-the-fly. 10 | */ 11 | 12 | (function (): void 13 | { 14 | const TEXTURES_LUT: { [id: string]: texture_t } = {}; 15 | 16 | function A_ToBitmap (texture: HTMLImageElement): bitmap_t 17 | { 18 | const textureWidth = texture.width, textureHeight = texture.height; 19 | const tmpCanvas = document.createElement("canvas"); 20 | const tmpCtx = tmpCanvas.getContext("2d")!; 21 | tmpCanvas.width = textureWidth; tmpCanvas.height = textureHeight; 22 | tmpCtx.drawImage(texture, 0, 0); 23 | 24 | return tmpCtx.getImageData(0, 0, textureWidth, textureHeight).data; 25 | } 26 | 27 | function 28 | A_OnTextureLoad 29 | ( resolve: () => void, 30 | texture: HTMLImageElement, 31 | id: string ): void 32 | { 33 | TEXTURES_LUT[id] = { 34 | id: id, 35 | bitmap: A_ToBitmap(texture), 36 | width: texture.width, 37 | height: texture.height, 38 | }; 39 | resolve(); 40 | } 41 | 42 | function A_TexturePromise (id: string, filename: string): Promise 43 | { 44 | return new Promise(function A_TexturePromiseExecutor (resolve, reject) 45 | { 46 | const texture = new Image(); 47 | texture.onload = A_OnTextureLoad.bind(texture, resolve, 48 | texture, id); 49 | texture.onerror = reject; 50 | texture.src = filename; 51 | }); 52 | } 53 | 54 | function 55 | A_LoadTextures 56 | ( ids: string[], 57 | filenames: string[], 58 | numTextures: number ): Promise 59 | { 60 | // TODO: throw an error should the `filenames` and `ids` have different 61 | // lengths, maybe?? 62 | const texturePromises = Array>(numTextures); 63 | for (let i = 0; i < numTextures; ++i) 64 | texturePromises[i] = A_TexturePromise(ids[i], filenames[i]); 65 | 66 | return Promise.all(texturePromises); 67 | } 68 | 69 | function A_Texture (id: string): texture_t 70 | { 71 | return TEXTURES_LUT[id]; 72 | } 73 | 74 | window.__import__A_Assets = function () 75 | { 76 | return { A_LoadTextures, A_Texture }; 77 | }; 78 | })(); 79 | -------------------------------------------------------------------------------- /src/engine/an_animation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * an_animation.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-05-04. 6 | * 7 | * SYNOPSIS: 8 | * The module for animating various in-engine objects. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const runningAnimations: RunningAnimationTable = {}; 14 | const queuedAnimations: QueuedAnimationTable = {}; 15 | 16 | type AN_OnFrameArgs = { 17 | animationIndex: Uint32Array, 18 | id: string, 19 | onFrame: (animationIndex: number) => void, 20 | shouldEnd?: (animationIndex: number) => boolean, 21 | cleanUp?: () => void 22 | }; 23 | 24 | function 25 | AN_GenerateAnimationId 26 | ( candidateId: string, 27 | goingIntoQueue?: 1 ): string 28 | { 29 | const candidate = candidateId || "(anonymous)"; 30 | if (goingIntoQueue) 31 | return queuedAnimations[candidate] 32 | ? AN_GenerateAnimationId(candidate + "_1") 33 | : candidate; 34 | 35 | return runningAnimations[candidate] 36 | ? AN_GenerateAnimationId(candidate + "_1") 37 | : candidate; 38 | } 39 | 40 | function AN_CancelAnimation (id: string, cleanUp?: () => void): void 41 | { 42 | clearInterval(runningAnimations[id]); 43 | delete runningAnimations[id]; 44 | if (cleanUp) cleanUp(); 45 | } 46 | 47 | function 48 | AN_OnFrame 49 | ( { animationIndex, 50 | id, 51 | onFrame, 52 | shouldEnd, 53 | cleanUp }: AN_OnFrameArgs ): void 54 | { 55 | const index = animationIndex[0]++; 56 | if (shouldEnd && shouldEnd(index)) AN_CancelAnimation(id, cleanUp); 57 | else onFrame(index); 58 | } 59 | 60 | function 61 | AN_StartAnimation 62 | ( onFrame: (animationIndex: number) => void, 63 | interval: number, 64 | shouldEnd?: (animationIndex: number) => boolean, 65 | cleanUp?: () => void ): string 66 | { 67 | const id = AN_GenerateAnimationId(arguments.callee.caller.name); 68 | const animationIndex = new Uint32Array(1); 69 | const args = { animationIndex, id, onFrame, shouldEnd, cleanUp }; 70 | runningAnimations[id] = setInterval(AN_OnFrame, interval, args); 71 | 72 | return id; 73 | } 74 | 75 | function 76 | AN_QueueAnimation 77 | ( onFrame: (animationIndex: number) => void, 78 | interval: number, 79 | shouldEnd?: (animationIndex: number) => boolean, 80 | cleanUp?: () => void ): string 81 | { 82 | const id = AN_GenerateAnimationId(arguments.callee.caller.name, 1); 83 | const animationIndex = new Uint32Array(1); 84 | const args = { animationIndex, id, onFrame, shouldEnd, cleanUp }; 85 | const boundOnFrame = AN_OnFrame.bind(undefined, args); 86 | queuedAnimations[id] = { onFrame: boundOnFrame, interval }; 87 | 88 | return id; 89 | } 90 | 91 | function AN_RunQueuedAnimation (id: string): void 92 | { 93 | const animation = queuedAnimations[id]; 94 | if (!animation) return; 95 | const onFrame = animation.onFrame, interval = animation.interval; 96 | runningAnimations[id] = setInterval(onFrame, interval); 97 | delete queuedAnimations[id]; 98 | } 99 | 100 | window.__import__AN_Animation = function () 101 | { 102 | return { 103 | AN_StartAnimation, 104 | AN_CancelAnimation, 105 | AN_QueueAnimation, 106 | AN_RunQueuedAnimation, 107 | }; 108 | }; 109 | })(); 110 | -------------------------------------------------------------------------------- /src/engine/i_input.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * i_input.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * Manage player input on keyboard and mouse. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const KEY = { 14 | /* standard keys */ 15 | A: "A", 16 | D: "D", 17 | E: "E", 18 | G: "G", 19 | Q: "Q", 20 | R: "R", 21 | S: "S", 22 | W: "W", 23 | /* arrow keys */ 24 | ARW_DOWN: "ARW_DOWN", 25 | ARW_LEFT: "ARW_LEFT", 26 | ARW_RIGHT: "ARW_RIGHT", 27 | ARW_UP: "ARW_UP", 28 | /* special keys */ 29 | RTN: "RTN", 30 | SPC: "SPC", 31 | } as const; 32 | 33 | const KEY_CODES = { 34 | Enter: KEY.RTN, 35 | Space: KEY.SPC, 36 | ArrowLeft: KEY.ARW_LEFT, 37 | ArrowUp: KEY.ARW_UP, 38 | ArrowRight: KEY.ARW_RIGHT, 39 | ArrowDown: KEY.ARW_DOWN, 40 | KeyA: KEY.A, 41 | KeyD: KEY.D, 42 | KeyE: KEY.E, 43 | KeyG: KEY.G, 44 | KeyW: KEY.W, 45 | KeyQ: KEY.Q, 46 | KeyR: KEY.R, 47 | KeyS: KEY.S, 48 | } as const; 49 | 50 | const MOUSE = { 51 | LEFT: "LEFT", 52 | MIDDLE: "MIDDLE", 53 | RIGHT: "RIGHT", 54 | BRWS_BWD: "BRWS_BWD", 55 | BRWS_FWD: "BRWS_FWD", 56 | MOVING: "MOVING", 57 | MOVEMENT_X: "MOVEMENT_X", 58 | MOVEMENT_Y: "MOVEMENT_Y", 59 | WHEELING: "WHEELING", 60 | DELTA_WHEEL: "DELTA_WHEEL", 61 | } as const; 62 | 63 | const MOUSE_CODES = [ 64 | MOUSE.LEFT, 65 | MOUSE.MIDDLE, 66 | MOUSE.RIGHT, 67 | MOUSE.BRWS_BWD, 68 | MOUSE.BRWS_FWD, 69 | ] as const; 70 | 71 | const keyState: { [key in (keyof KEY)]: 0 | 1 } = { 72 | [KEY.A]: 0, 73 | [KEY.D]: 0, 74 | [KEY.E]: 0, 75 | [KEY.G]: 0, 76 | [KEY.Q]: 0, 77 | [KEY.R]: 0, 78 | [KEY.S]: 0, 79 | [KEY.W]: 0, 80 | [KEY.ARW_DOWN]: 0, 81 | [KEY.ARW_LEFT]: 0, 82 | [KEY.ARW_RIGHT]: 0, 83 | [KEY.ARW_UP]: 0, 84 | [KEY.RTN]: 0, 85 | [KEY.SPC]: 0, 86 | }; 87 | 88 | const mouseState: { [key in (keyof MOUSE)]: number } = { 89 | [MOUSE.LEFT]: 0, 90 | [MOUSE.MIDDLE]: 0, 91 | [MOUSE.RIGHT]: 0, 92 | [MOUSE.BRWS_BWD]: 0, 93 | [MOUSE.BRWS_FWD]: 0, 94 | [MOUSE.MOVING]: 0, 95 | [MOUSE.MOVEMENT_X]: 0, 96 | [MOUSE.MOVEMENT_Y]: 0, 97 | [MOUSE.WHEELING]: 0, 98 | [MOUSE.DELTA_WHEEL]: 0, 99 | }; 100 | 101 | const MOUSE_RESET_DELAY = 100; 102 | let mouseStopTimeout: number, mouseWheelTimeout: number; 103 | 104 | function I_KeyDown (event: KeyboardEvent): void 105 | { 106 | const code = event.code; 107 | if (code in KEY_CODES) 108 | keyState[KEY_CODES[code as keyof typeof KEY_CODES]] = 1; 109 | } 110 | 111 | function I_KeyUp (event: KeyboardEvent): void 112 | { 113 | const code = event.code; 114 | if (code in KEY_CODES) 115 | keyState[KEY_CODES[code as keyof typeof KEY_CODES]] = 0; 116 | } 117 | 118 | function I_GetKeyState (key: keyof typeof KEY): 0 | 1 119 | { 120 | return keyState[KEY[key]]; 121 | } 122 | 123 | function I_InitKeyboard (onElement: Document | HTMLElement): void 124 | { 125 | onElement.onkeydown = I_KeyDown; 126 | onElement.onkeyup = I_KeyUp; 127 | } 128 | 129 | function I_MouseDown (event: MouseEvent): void 130 | { 131 | const button = event.button; 132 | if (MOUSE_CODES[button]) mouseState[MOUSE_CODES[button]] = 1; 133 | } 134 | 135 | function I_MouseUp (event: MouseEvent): void 136 | { 137 | const button = event.button; 138 | if (MOUSE_CODES[button]) mouseState[MOUSE_CODES[button]] = 0; 139 | } 140 | 141 | function I_ResetMouseMovement (): void 142 | { 143 | mouseState.MOVING = 0; 144 | mouseState.MOVEMENT_X = 0; mouseState.MOVEMENT_Y = 0; 145 | } 146 | 147 | function I_MouseMove (event: MouseEvent): void 148 | { 149 | mouseState.MOVING = 1; 150 | mouseState.MOVEMENT_X = event.movementX; 151 | mouseState.MOVEMENT_Y = event.movementY; 152 | // reset mouse movement after some time has passed 153 | if (mouseStopTimeout !== undefined) clearTimeout(mouseStopTimeout); 154 | mouseStopTimeout = setTimeout(I_ResetMouseMovement, MOUSE_RESET_DELAY); 155 | } 156 | 157 | function I_ResetMouseWheel (): void 158 | { 159 | mouseState.WHEELING = 0; mouseState.DELTA_WHEEL = 0; 160 | } 161 | 162 | function I_MouseWheel (event: WheelEvent): void 163 | { 164 | event.preventDefault(); // prevent scrolling the page 165 | mouseState.WHEELING = 1; mouseState.DELTA_WHEEL = event.deltaY; 166 | // reset mouse wheel after some time has passed 167 | if (mouseWheelTimeout !== undefined) clearTimeout(mouseWheelTimeout); 168 | mouseWheelTimeout = setTimeout(I_ResetMouseWheel, MOUSE_RESET_DELAY); 169 | } 170 | 171 | function I_PointerLocked (onElement: HTMLElement): boolean 172 | { 173 | return document.pointerLockElement === onElement || 174 | // @ts-ignore 175 | document.mozPointerLockElement === onElement; 176 | } 177 | 178 | function I_RequestPointerLock (onElement: HTMLElement): void 179 | { 180 | if (!I_PointerLocked(onElement)) 181 | { 182 | onElement.requestPointerLock = onElement.requestPointerLock || 183 | // @ts-ignore 184 | onElement.mozRequestPointerLock; 185 | onElement.requestPointerLock(); 186 | } 187 | } 188 | 189 | function I_AttachMouseEventListeners (onElement: HTMLElement): void 190 | { 191 | onElement.onclick = null; 192 | onElement.onmousedown = I_MouseDown; 193 | onElement.onmouseup = I_MouseUp; 194 | onElement.onmousemove = I_MouseMove; 195 | onElement.onwheel = I_MouseWheel; 196 | } 197 | 198 | function I_DetachMouseEventListeners (fromElement: HTMLElement): void 199 | { 200 | fromElement.onclick = I_RequestPointerLock.bind(undefined, fromElement); 201 | fromElement.onmousedown = null; 202 | fromElement.onmouseup = null; 203 | fromElement.onmousemove = null; 204 | fromElement.onwheel = null; 205 | } 206 | 207 | function I_PointerLockChange (onElement: HTMLElement): void 208 | { 209 | // pointer locked, attach mouse listeners 210 | if (I_PointerLocked(onElement)) I_AttachMouseEventListeners(onElement); 211 | // pointer unlocked, detach mouse listeners 212 | else I_DetachMouseEventListeners(onElement); 213 | } 214 | 215 | function I_GetMouseState (key: keyof typeof MOUSE): number 216 | { 217 | return mouseState[MOUSE[key]]; 218 | } 219 | 220 | function I_InitMouse (onElement: HTMLElement): void 221 | { 222 | onElement.onclick = I_RequestPointerLock.bind(undefined, onElement); 223 | document.onpointerlockchange = I_PointerLockChange.bind(undefined, 224 | onElement); 225 | // @ts-ignore 226 | document.onmozpointerlockchange = I_PointerLockChange.bind(undefined, 227 | onElement); 228 | } 229 | 230 | window.__import__I_Input = function () 231 | { 232 | return { 233 | I_Keys: KEY, 234 | I_Mouse: MOUSE, 235 | I_GetKeyState, 236 | I_InitKeyboard, 237 | I_GetMouseState, 238 | I_InitMouse, 239 | }; 240 | }; 241 | })(); 242 | -------------------------------------------------------------------------------- /src/engine/m_aabb3.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_aabb3.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-11-20. 6 | * 7 | * SYNOPSIS: 8 | * 3-D axis-aligned bounding-box. 9 | */ 10 | 11 | (function (): void 12 | { 13 | function M_AABB3 (origin3: vec3_t, dimensions3: vec3_t): aabb3_t 14 | { 15 | return Float32Array.from([ 16 | origin3[0], origin3[1], origin3[2], 17 | dimensions3[0], dimensions3[1], dimensions3[2] 18 | ]); 19 | } 20 | 21 | window.__import__M_AABB3 = function () 22 | { 23 | return { M_AABB3 }; 24 | }; 25 | })(); 26 | -------------------------------------------------------------------------------- /src/engine/m_collision.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_collision.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-10-07. 6 | * 7 | * SYNOPSIS: 8 | * Routines for detecting various collisions in 2-D and 3-D. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const M_Vec2 = __import__M_Vec2(); 14 | const M_Add2 = M_Vec2.M_Add2; 15 | const M_Cross2 = M_Vec2.M_Cross2; 16 | const M_Scale2 = M_Vec2.M_Scale2; 17 | const M_Sub2 = M_Vec2.M_Sub2; 18 | const Vec2 = M_Vec2.M_Vec2; 19 | 20 | const M_Vec3 = __import__M_Vec3(); 21 | const M_Add3 = M_Vec3.M_Add3; 22 | const M_DistToPlane3 = M_Vec3.M_DistToPlane3; 23 | const M_Scale3 = M_Vec3.M_Scale3; 24 | const M_Sub3 = M_Vec3.M_Sub3; 25 | 26 | function 27 | M_LineVsLine2 28 | ( ax: number, ay: number, 29 | bx: number, by: number, 30 | cx: number, cy: number, 31 | dx: number, dy: number, 32 | segment?: 1 ): vec2_t | undefined 33 | { 34 | const a = Vec2(ax, ay), b = Vec2(bx, by); 35 | const c = Vec2(cx, cy), d = Vec2(dx, dy); 36 | const s = M_Sub2(b, a), t = M_Sub2(d, c); 37 | const c_a = M_Sub2(c, a); 38 | const denom = 1 / M_Cross2(s, t); 39 | const X = M_Cross2(c_a, t) * denom; 40 | if (segment) 41 | { 42 | const Y = M_Cross2(c_a, s) * denom; 43 | if (X < 0 || X > 1 || Y < 0 || Y > 1) return; 44 | } 45 | 46 | return M_Add2(a, M_Scale2(s, X)); 47 | } 48 | 49 | function 50 | M_TimeBeforePlaneCollision3 51 | ( lineSrc: vec3_t, lineDest: vec3_t, 52 | planeRef: vec3_t, planeNormal: vec3_t ): number | undefined 53 | { 54 | const distToPlaneSrc = M_DistToPlane3(lineSrc, planeRef, planeNormal); 55 | const distToPlaneDest = M_DistToPlane3(lineDest, planeRef, planeNormal); 56 | /* if both ends of the line segment are on the same side of the plane, 57 | * then they do not intersect--return immediately 58 | */ 59 | if (distToPlaneSrc >= 0 && distToPlaneDest >= 0 || 60 | distToPlaneSrc < 0 && distToPlaneDest < 0) 61 | return; 62 | const absDistToPlaneSrc = Math.abs(distToPlaneSrc); 63 | const absDistToPlaneDest = Math.abs(distToPlaneDest); 64 | 65 | // how far we should walk along the line segment, from its start, before 66 | // we get to the intersection with the plane 67 | return absDistToPlaneSrc / (absDistToPlaneSrc + absDistToPlaneDest); 68 | } 69 | 70 | function 71 | M_LineSegmentVsPlaneCollision3 72 | ( lineSrc: vec3_t, lineDest: vec3_t, 73 | planeRef: vec3_t, planeNormal: vec3_t ): vec3_t | undefined 74 | { 75 | const scale = M_TimeBeforePlaneCollision3(lineSrc, lineDest, 76 | planeRef, planeNormal); 77 | if (scale === undefined) return; // early return if there's no collision 78 | 79 | return M_Add3(lineSrc, M_Scale3(M_Sub3(lineDest, lineSrc), scale)); 80 | } 81 | 82 | function 83 | M_BoundingBoxVsBoundingBoxCollision3 84 | ( aabb0: aabb3_t, 85 | aabb1: aabb3_t ): boolean 86 | { 87 | return aabb0[0] + aabb0[3] > aabb1[0] && 88 | aabb1[0] + aabb1[3] >= aabb0[0] && 89 | aabb0[1] + aabb0[4] > aabb1[1] && 90 | aabb1[1] + aabb1[4] >= aabb0[1] && 91 | aabb0[2] + aabb0[5] > aabb1[2] && 92 | aabb1[2] + aabb1[5] >= aabb0[2]; 93 | } 94 | 95 | window.__import__M_Collision = function () 96 | { 97 | return { 98 | M_LineVsLine2, 99 | M_TimeBeforePlaneCollision3, 100 | M_LineSegmentVsPlaneCollision3, 101 | M_BoundingBoxVsBoundingBoxCollision3, 102 | }; 103 | }; 104 | })(); 105 | -------------------------------------------------------------------------------- /src/engine/m_mat4.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_mat4.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * The module that houses some 4x4 matrix utilities that help transform 3-D 9 | * vectors. 10 | */ 11 | 12 | (function (): void 13 | { 14 | const N_COLS = 4; 15 | const SIZE = N_COLS * N_COLS; 16 | 17 | function M_Vec4 (x: number, y: number, z: number, w: number): vec4_t 18 | { 19 | return Float32Array.from([x, y, z, w]); 20 | } 21 | 22 | function M_Vec4FromVec3 (u: pvec3_t | vec3_t, w: number): vec4_t 23 | { 24 | return M_Vec4(u[0], u[1], u[2], w); 25 | } 26 | 27 | function M_Dot4 (u: vec4_t, v: vec4_t): number 28 | { 29 | return u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + u[3] * v[3]; 30 | } 31 | 32 | function M_Mat4 (x: vec4_t, y: vec4_t, z: vec4_t, w: vec4_t): mat4_t 33 | { 34 | const mat = new Float32Array(SIZE); 35 | mat[0] = x[0]; mat[4] = x[1]; mat[8] = x[2]; mat[12] = x[3]; 36 | mat[1] = y[0]; mat[5] = y[1]; mat[9] = y[2]; mat[13] = y[3]; 37 | mat[2] = z[0]; mat[6] = z[1]; mat[10] = z[2]; mat[14] = z[3]; 38 | mat[3] = w[0]; mat[7] = w[1]; mat[11] = w[2]; mat[15] = w[3]; 39 | 40 | return mat; 41 | } 42 | 43 | function M_QuickInv4 (mat: mat4_t): mat4_t 44 | { 45 | /* we can hack our way here and decompose the original transform matrix 46 | * `m` as such: 47 | * 48 | * m = T * R 49 | * 50 | * ┌ ┐ ┌ ┐ 51 | * | 1 0 0 tx | | x.x y.x z.x 0 | 52 | * = | 0 1 0 ty | * | x.y y.y z.y 0 | 53 | * | 0 0 1 tz | | x.z y.z z.z 0 | 54 | * | 0 0 0 1 | | 0 0 0 1 | 55 | * └ ┘ └ ┘ 56 | * 57 | * decomposing this way, we can invert `T` and `R` separately: 58 | * 59 | * m^(-1) = R^(-1) * T^(-1) 60 | * 61 | * ┌ ┐ ┌ ┐ 62 | * | x.x x.y x.z 0 | | 1 0 0 -t.x | 63 | * = | y.x y.y y.z 0 | * | 0 1 0 -t.y | 64 | * | z.x z.y z.z 0 | | 0 0 1 -t.z | 65 | * | 0 0 0 1 | | 0 0 0 1 | 66 | * └ ┘ └ ┘ 67 | * 68 | * because the basis vectors `x`, `y`, and `z` (the first 3 columns in 69 | * `R`) are guaranteed to be orthonormal, we were able to take a 70 | * shortcut in calculating the inverse by simply transposing `R`. 71 | * likewise, to invert the translation matrix `T`, all we need to do is 72 | * scale the translation vector `t` (the final column in `T`) by `-1`. 73 | * 74 | * this gives us the inverted transform: 75 | * 76 | * ┌ ┐ 77 | * | x.x x.y x.z - | 78 | * m^(-1) = | y.x y.y y.z - | 79 | * | z.x z.y z.z - | 80 | * | 0 0 0 1 | 81 | * └ ┘ 82 | */ 83 | /* invert `R` */ 84 | const inv = new Float32Array(SIZE); 85 | inv[0] = mat[0]; inv[4] = mat[1]; inv[8] = mat[2]; 86 | inv[1] = mat[4]; inv[5] = mat[5]; inv[9] = mat[6]; 87 | inv[2] = mat[8]; inv[6] = mat[9]; inv[10] = mat[10]; 88 | /* invert `T` */ 89 | const T = M_Vec4(mat[3], mat[7], mat[11], mat[15]); 90 | inv[3] = -M_Dot4(M_Vec4(inv[0], inv[1], inv[2], mat[12]), T); 91 | inv[7] = -M_Dot4(M_Vec4(inv[4], inv[5], inv[6], mat[13]), T); 92 | inv[11] = -M_Dot4(M_Vec4(inv[8], inv[9], inv[10], mat[14]), T); 93 | inv[15] = 1; 94 | 95 | return inv; 96 | } 97 | 98 | /* 99 | function M_Inv4 (mat: mat4_t): mat4_t 100 | { 101 | // TODO: implement 102 | } 103 | */ 104 | 105 | function M_Transform4 (mat: mat4_t, vec: vec4_t): vec4_t 106 | { 107 | const matRow0 = M_Vec4(mat[0], mat[1], mat[2], mat[3]); 108 | const matRow1 = M_Vec4(mat[4], mat[5], mat[6], mat[7]); 109 | const matRow2 = M_Vec4(mat[8], mat[9], mat[10], mat[11]); 110 | const matRow3 = M_Vec4(mat[12], mat[13], mat[14], mat[15]); 111 | 112 | return M_Vec4(M_Dot4(matRow0, vec), M_Dot4(matRow1, vec), 113 | M_Dot4(matRow2, vec), M_Dot4(matRow3, vec)); 114 | } 115 | 116 | window.__import__M_Mat4 = function () 117 | { 118 | return { M_Vec4FromVec3, M_Mat4, M_QuickInv4, M_Transform4 }; 119 | }; 120 | })(); 121 | -------------------------------------------------------------------------------- /src/engine/m_math.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_math.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * Various math utilities. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const PI_2 = Math.PI * 0.5; 14 | const TWO_PI = Math.PI * 2; 15 | const DEG_IN_RAD = 180 / Math.PI; 16 | 17 | function M_RadToDeg (radian: number): number 18 | { 19 | return (((radian % TWO_PI) + TWO_PI) % TWO_PI) * DEG_IN_RAD; 20 | } 21 | 22 | function M_Clamp (number: number, lower: number, upper: number): number 23 | { 24 | return Math.min(Math.max(number, lower), upper); 25 | } 26 | 27 | function M_ToFixedDigits (number: number, nDigits: number): number 28 | { 29 | const orderOfMag = Math.pow(10, nDigits || 1); 30 | 31 | return Math.round(number * orderOfMag) / orderOfMag; 32 | } 33 | 34 | function M_FastSign (number: number): number 35 | { 36 | return (number >> 31) - (-number >> 31); 37 | } 38 | 39 | window.__import__M_Math = function () 40 | { 41 | return { PI_2, M_RadToDeg, M_Clamp, M_ToFixedDigits, M_FastSign }; 42 | }; 43 | })(); 44 | -------------------------------------------------------------------------------- /src/engine/m_tri3.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_tri3.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-20. 6 | * 7 | * SYNOPSIS: 8 | * The module that houses some utilities to operate on triangles in 3-D. 9 | */ 10 | 11 | (function (): void 12 | { 13 | /* NOTE: Triangles employ counter-clockwise order */ 14 | // TODO: maybe, no need for a Tri3 object at all?? 15 | 16 | const M_Vec3 = __import__M_Vec3(); 17 | const M_Sub3 = M_Vec3.M_Sub3; 18 | const M_Cross3 = M_Vec3.M_Cross3; 19 | const M_Norm3 = M_Vec3.M_Norm3; 20 | const M_RotateAroundAxis3 = M_Vec3.M_RotateAroundAxis3; 21 | const M_Vec3FromVec4 = M_Vec3.M_Vec3FromVec4; 22 | const Vec3 = M_Vec3.M_Vec3; 23 | 24 | const M_AABB3 = __import__M_AABB3(); 25 | const AABB3 = M_AABB3.M_AABB3; 26 | 27 | const M_Mat4 = __import__M_Mat4(); 28 | const M_Transform4 = M_Mat4.M_Transform4; 29 | const M_Vec4FromVec3 = M_Mat4.M_Vec4FromVec3; 30 | 31 | function M_Tri3 (a3: vec3_t, b3: vec3_t, c3: vec3_t): tri3_t 32 | { 33 | return [a3, b3, c3]; 34 | } 35 | 36 | function M_TriNormal3 (tri3: tri3_t): vec3_t 37 | { 38 | // (b - a) x (c - a) === (b - a) x (c - b) 39 | const ab = M_Sub3(tri3[1], tri3[0]), bc = M_Sub3(tri3[2], tri3[1]); 40 | 41 | return M_Norm3(M_Cross3(ab, bc)); 42 | } 43 | 44 | function M_TransformTri3 (transform4: mat4_t, tri3: tri3_t): tri3_t 45 | { 46 | const triA3 = tri3[0], triB3 = tri3[1], triC3 = tri3[2]; 47 | const triA4 = M_Vec4FromVec3(triA3, 1); 48 | const triB4 = M_Vec4FromVec3(triB3, 1); 49 | const triC4 = M_Vec4FromVec3(triC3, 1); 50 | const triATransformed4 = M_Transform4(transform4, triA4); 51 | const triBTransformed4 = M_Transform4(transform4, triB4); 52 | const triCTransformed4 = M_Transform4(transform4, triC4); 53 | 54 | return M_Tri3(M_Vec3FromVec4(triATransformed4), 55 | M_Vec3FromVec4(triBTransformed4), 56 | M_Vec3FromVec4(triCTransformed4)); 57 | } 58 | 59 | function M_AABB3FromTri3 (tri3: tri3_t): aabb3_t 60 | { 61 | const triA3 = tri3[0], triB3 = tri3[1], triC3 = tri3[2]; 62 | const origin3 = Vec3(Math.min(triA3[0], triB3[0], triC3[0]), 63 | Math.min(triA3[1], triB3[1], triC3[1]), 64 | Math.min(triA3[2], triB3[2], triC3[2])); 65 | const dimensions3 = Vec3( 66 | Math.max(triA3[0], triB3[0], triC3[0]) - origin3[0], 67 | Math.max(triA3[1], triB3[1], triC3[1]) - origin3[1], 68 | Math.max(triA3[2], triB3[2], triC3[2]) - origin3[2] 69 | ); 70 | 71 | return AABB3(origin3, dimensions3); 72 | } 73 | 74 | function 75 | M_RotateTriAroundAxis3 76 | ( tri3: tri3_t, 77 | axis3: vec3_t, 78 | angle: number ): tri3_t 79 | { 80 | const triRotatedA3 = M_RotateAroundAxis3(tri3[0], axis3, angle); 81 | const triRotatedB3 = M_RotateAroundAxis3(tri3[1], axis3, angle); 82 | const triRotatedC3 = M_RotateAroundAxis3(tri3[2], axis3, angle); 83 | 84 | return M_Tri3(triRotatedA3, triRotatedB3, triRotatedC3); 85 | } 86 | 87 | window.__import__M_Tri3 = function () 88 | { 89 | return { 90 | M_Tri3, 91 | M_TriNormal3, 92 | M_TransformTri3, 93 | M_AABB3FromTri3, 94 | M_RotateTriAroundAxis3, 95 | }; 96 | }; 97 | })(); 98 | -------------------------------------------------------------------------------- /src/engine/m_vec2.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_vec2.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2023-10-08. 6 | * 7 | * SYNOPSIS: 8 | * The module for carrying out 2-D vector math. 9 | */ 10 | 11 | (function (): void 12 | { 13 | function M_Vec2 (x: number, y: number): vec2_t 14 | { 15 | return Float32Array.from([x, y]); 16 | } 17 | 18 | function M_Cross2 (u: vec2_t, v: vec2_t): number 19 | { 20 | return u[0] * v[1] - u[1] * v[0]; 21 | } 22 | 23 | function M_Add2 (u: vec2_t, v: vec2_t): vec2_t 24 | { 25 | return M_Vec2(u[0] + v[0], u[1] + v[1]); 26 | } 27 | 28 | function M_Sub2 (u: vec2_t, v: vec2_t): vec2_t 29 | { 30 | return M_Vec2(u[0] - v[0], u[1] - v[1]); 31 | } 32 | 33 | function M_Scale2 (u: vec2_t, s: number): vec2_t 34 | { 35 | return M_Vec2(s * u[0], s * u[1]); 36 | } 37 | 38 | window.__import__M_Vec2 = function () 39 | { 40 | return { M_Vec2, M_Cross2, M_Add2, M_Sub2, M_Scale2 }; 41 | }; 42 | })(); 43 | -------------------------------------------------------------------------------- /src/engine/m_vec3.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * m_vec3.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * The module for carrying out 3-D vector math. 9 | */ 10 | 11 | (function (): void 12 | { 13 | function M_Vec3 (x: number, y: number, z: number): vec3_t 14 | { 15 | return Float32Array.from([x, y, z]); 16 | } 17 | 18 | function M_Vec3FromVec4 (u: vec4_t): vec3_t 19 | { 20 | const w_ = 1 / u[3]; 21 | 22 | return M_Vec3(u[0] * w_, u[1] * w_, u[2] * w_); 23 | } 24 | 25 | function M_Dot3 (u: vec3_t, v: vec3_t): number 26 | { 27 | return u[0] * v[0] + u[1] * v[1] + u[2] * v[2]; 28 | } 29 | 30 | function M_Cross3 (u: vec3_t, v: vec3_t): vec3_t 31 | { 32 | return M_Vec3(u[1] * v[2] - u[2] * v[1], 33 | u[2] * v[0] - u[0] * v[2], 34 | u[0] * v[1] - u[1] * v[0]); 35 | } 36 | 37 | function M_Add3 (u: vec3_t, v: vec3_t): vec3_t 38 | { 39 | return M_Vec3(u[0] + v[0], u[1] + v[1], u[2] + v[2]); 40 | } 41 | 42 | function M_Sub3 (u: vec3_t, v: vec3_t): vec3_t 43 | { 44 | return M_Vec3(u[0] - v[0], u[1] - v[1], u[2] - v[2]); 45 | } 46 | 47 | function M_Scale3 (u: vec3_t, s: number): vec3_t 48 | { 49 | return M_Vec3(s * u[0], s * u[1], s * u[2]); 50 | } 51 | 52 | function M_Mag3 (u: vec3_t): number 53 | { 54 | return Math.sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]); 55 | } 56 | 57 | function M_Norm3 (u: vec3_t): vec3_t 58 | { 59 | const mag_ = 1 / M_Mag3(u); 60 | 61 | return M_Vec3(u[0] * mag_, u[1] * mag_, u[2] * mag_); 62 | } 63 | 64 | function M_Perp3 (vec: vec3_t, base: vec3_t): vec3_t 65 | { 66 | return M_Sub3(vec, M_Scale3(base, M_Dot3(base, vec))); 67 | } 68 | 69 | /* NOTE: Rodrigues' axis-angle rotations */ 70 | function 71 | M_RotateAroundAxis3 72 | ( point: vec3_t, 73 | axis: vec3_t, 74 | angle: number ): vec3_t 75 | { 76 | const cos = Math.cos(angle), sin = Math.sin(angle); 77 | const a = M_Scale3(axis, M_Dot3(axis, point) * (1 - cos)); 78 | const b = M_Scale3(point, cos); 79 | const c = M_Scale3(M_Cross3(axis, point), sin); 80 | 81 | return M_Add3(M_Add3(a, b), c); 82 | } 83 | 84 | function 85 | M_DistToPlane3 86 | ( vec: vec3_t, 87 | ref: vec3_t, 88 | normal: vec3_t, 89 | isAbs?: 1 ): number 90 | { 91 | const distance = M_Dot3(vec, normal) - M_Dot3(ref, normal); 92 | 93 | return isAbs ? Math.abs(distance) : distance; 94 | } 95 | 96 | function 97 | M_IsInFrontOfPlane3 98 | ( vec: vec3_t, 99 | ref: vec3_t, 100 | normal: vec3_t ): boolean 101 | { 102 | return M_DistToPlane3(vec, ref, normal) > 0; 103 | } 104 | 105 | window.__import__M_Vec3 = function () 106 | { 107 | return { 108 | M_Vec3, 109 | M_Vec3FromVec4, 110 | M_Dot3, 111 | M_Cross3, 112 | M_Add3, 113 | M_Sub3, 114 | M_Scale3, 115 | M_Mag3, 116 | M_Norm3, 117 | M_Perp3, 118 | M_RotateAroundAxis3, 119 | M_DistToPlane3, 120 | M_IsInFrontOfPlane3, 121 | }; 122 | }; 123 | })(); 124 | -------------------------------------------------------------------------------- /src/engine/r_drawers.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * r_drawers.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-05-03. 6 | * 7 | * SYNOPSIS: 8 | * Module that houses some static drawer routines that render various 9 | * menus, screens, etc. 10 | */ 11 | 12 | (function (): void 13 | { 14 | const AN_Animation = __import__AN_Animation(); 15 | const AN_StartAnimation = AN_Animation.AN_StartAnimation; 16 | 17 | const G_Const = __import__G_Const(); 18 | const SCREEN_W = G_Const.SCREEN_W, SCREEN_H = G_Const.SCREEN_H; 19 | const SCREEN_W_2 = G_Const.SCREEN_W_2, SCREEN_H_2 = G_Const.SCREEN_H_2; 20 | 21 | const R_Draw = __import__R_Draw(); 22 | const R_DrawImage = R_Draw.R_DrawImage; 23 | const R_FillRect = R_Draw.R_FillRect; 24 | const R_FlushFrame = R_Draw.R_FlushFrame; 25 | const R_Print = R_Draw.R_Print; 26 | 27 | const R_Screen = __import__R_Screen(); 28 | const R_Ctx = R_Screen.R_Ctx; 29 | 30 | const N_LOADING_STATES = 4, LOADING_INTERVAL = 375; 31 | const LOADING_FONT_COLOR = "#FFFFFF"; 32 | const LOADING_FONT_SIZE = 36; 33 | 34 | const TITLE_INTERVAL = 375; 35 | const TITLE_FONT_COLOR = "#FFFFFF"; 36 | const TITLE_PRIMARY_FONT_SIZE = 32, TITLE_SECONDARY_FONT_SIZE = 16; 37 | 38 | const ERROR_PREFIX = "fatal error: "; 39 | const ERROR_FONT_COLOR = "#FF0000"; 40 | const ERROR_FONT_SIZE = 16; 41 | 42 | function R_DrawLoadingFrame (index: number): void 43 | { 44 | const dots = Array(index % N_LOADING_STATES).fill(".").join(""); 45 | R_Ctx.fillStyle = "#000000"; 46 | R_Ctx.fillRect(0, 0, SCREEN_W, SCREEN_H); 47 | R_Print("Loading" + dots, SCREEN_W_2 - 75, SCREEN_H_2, 48 | LOADING_FONT_COLOR, LOADING_FONT_SIZE); 49 | } 50 | 51 | function R_LoadingDrawer (onEnd?: () => void): string 52 | { 53 | return AN_StartAnimation(R_DrawLoadingFrame, LOADING_INTERVAL, 54 | undefined, onEnd); 55 | } 56 | 57 | function R_DrawTitleFrame (index: number, decor: texture_t): void 58 | { 59 | R_FillRect(0, 0, SCREEN_W, SCREEN_H, 0, 0, 0, 255); 60 | R_DrawImage(decor, 61 | 0, 0, decor.width, decor.height, 62 | SCREEN_W_2 - 100, SCREEN_H_2 - 217, 63 | decor.width, decor.height); 64 | R_FlushFrame(); 65 | R_Print("Tmp3D Engine", SCREEN_W_2 - 117, SCREEN_H_2 + 20, 66 | TITLE_FONT_COLOR, TITLE_PRIMARY_FONT_SIZE); 67 | R_Print("v" + __VERSION__, SCREEN_W_2 - 30, SCREEN_H_2 + 44, 68 | TITLE_FONT_COLOR, TITLE_SECONDARY_FONT_SIZE); 69 | R_Print("by Emre Akı, 2022.", SCREEN_W_2 - 86, SCREEN_H_2 + 87, 70 | TITLE_FONT_COLOR, TITLE_SECONDARY_FONT_SIZE); 71 | if (index & 1) 72 | R_Print("Press any key to start", SCREEN_W_2 - 106, SCREEN_H - 50, 73 | TITLE_FONT_COLOR, TITLE_SECONDARY_FONT_SIZE); 74 | } 75 | 76 | function R_TitleDrawer (decor: texture_t, onEnd?: () => void): string 77 | { 78 | return AN_StartAnimation(function R_OnTitleFrame (index) 79 | { 80 | R_DrawTitleFrame(index, decor); 81 | }, TITLE_INTERVAL, undefined, onEnd); 82 | } 83 | 84 | function R_ErrorDrawer (reason: string): void 85 | { 86 | R_Ctx.fillStyle = "#000000"; 87 | R_Ctx.fillRect(0, 0, SCREEN_W, SCREEN_H); 88 | R_Print(ERROR_PREFIX + reason, 50, SCREEN_H - 50, 89 | ERROR_FONT_COLOR, ERROR_FONT_SIZE); 90 | } 91 | 92 | window.__import__R_Drawers = function () 93 | { 94 | return { R_LoadingDrawer, R_TitleDrawer, R_ErrorDrawer }; 95 | }; 96 | })(); 97 | -------------------------------------------------------------------------------- /src/engine/r_screen.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * r_screen.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * The frontend for the rendering. 9 | * 10 | * Exposes some routines for setting up an HTML5 `canvas` element, as well 11 | * as for clearing, and flushing the frame buffer onto the actual screen 12 | * for the rendering backend to operate on. 13 | */ 14 | 15 | (function (): void 16 | { 17 | const screen = document.getElementById("canvas") as HTMLCanvasElement; 18 | const ctx = screen.getContext("2d")!; 19 | 20 | function R_FlushBuffer (buffer: ImageData): void 21 | { 22 | ctx.putImageData(buffer, 0, 0); 23 | } 24 | 25 | function R_InitBuffer (w: number, h: number): ImageData 26 | { 27 | screen.width = w; screen.height = h; 28 | 29 | return ctx.getImageData(0, 0, w, h); 30 | } 31 | 32 | window.__import__R_Screen = function () 33 | { 34 | return { 35 | R_ScreenElement: screen, 36 | R_Ctx: ctx, 37 | R_FlushBuffer, 38 | R_InitBuffer, 39 | }; 40 | }; 41 | })(); 42 | -------------------------------------------------------------------------------- /src/game/g_const.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * g_const.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * Some common constant values that will not change during the entire 9 | * lifetime of the engine. 10 | */ 11 | 12 | (function () 13 | { 14 | const M_Vec3 = __import__M_Vec3(); 15 | const Vec3 = M_Vec3.M_Vec3; 16 | 17 | const M_AABB3 = __import__M_AABB3(); 18 | const AABB3 = M_AABB3.M_AABB3; 19 | 20 | const SCREEN_W = 640, SCREEN_H = 480; 21 | const SCREEN_W_2 = SCREEN_W * 0.5, SCREEN_H_2 = SCREEN_H * 0.5; 22 | const ASPECT = SCREEN_W / SCREEN_H; 23 | 24 | const FOV_Y = Math.PI / 3, TAN_FOV_Y_2 = Math.tan(FOV_Y * 0.5); 25 | const FOV_X = 2 * Math.atan(ASPECT * TAN_FOV_Y_2); 26 | 27 | const MAX_MOV_TILT = Math.PI / 90; 28 | 29 | const NEAR_H = 2, NEAR_W = ASPECT * NEAR_H; 30 | const Z_NEAR = NEAR_H / (2 * TAN_FOV_Y_2), Z_FAR = 500 * Z_NEAR; 31 | const FAR_W = Z_FAR / Z_NEAR * NEAR_W, FAR_W_2 = FAR_W * 0.5; 32 | const FAR_H = FAR_W / ASPECT, FAR_H_2 = FAR_H * 0.5; 33 | 34 | const FPS = 30; 35 | 36 | const FRUSTUM_AABB3 = AABB3(Vec3(-FAR_W_2, -FAR_H_2, Z_NEAR), 37 | Vec3(FAR_W, FAR_H, Z_FAR - Z_NEAR)); 38 | 39 | window.__import__G_Const = function () 40 | { 41 | return { 42 | FPS, 43 | FOV_X, 44 | FOV_Y, 45 | MAX_MOV_TILT, 46 | SCREEN_W, 47 | SCREEN_H, 48 | SCREEN_W_2, 49 | SCREEN_H_2, 50 | ASPECT, 51 | Z_NEAR, 52 | Z_FAR, 53 | FRUSTUM_AABB3, 54 | }; 55 | }; 56 | })(); 57 | -------------------------------------------------------------------------------- /src/game/g_main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * g_main.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * The main program--the entry-point of the engine. 9 | */ 10 | 11 | (function (): void 12 | { 13 | const G_Setup = __import__G_Setup().G_Setup; 14 | const G_Run = __import__G_Run().G_Run; 15 | 16 | G_Setup().then(G_Run); 17 | })(); 18 | -------------------------------------------------------------------------------- /src/game/g_run.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * g_run.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * The main module that houses the routines that are going to kickstart the 9 | * engine and update both the game state and the frame buffer at each 10 | * frame. 11 | */ 12 | 13 | (function (): void 14 | { 15 | const DEBUG_MODE = window.__DEBUG_MODE__; 16 | 17 | const A_Assets = __import__A_Assets(); 18 | const A_Texture = A_Assets.A_Texture; 19 | 20 | const AN_Animation = __import__AN_Animation(); 21 | const AN_CancelAnimation = AN_Animation.AN_CancelAnimation; 22 | 23 | const D_GlobTextures = __import__D_GlobTextures(); 24 | const D_GlobTextureIdTable = D_GlobTextures.D_GlobTextureIdTable; 25 | 26 | const G_Const = __import__G_Const(); 27 | const FPS = G_Const.FPS; 28 | 29 | const R_Camera = __import__R_Camera(); 30 | const R_UpdateCamera = R_Camera.R_UpdateCamera; 31 | const R_DebugStats = R_Camera.R_DebugStats; 32 | 33 | const R_Draw = __import__R_Draw(); 34 | const R_FlushFrame = R_Draw.R_FlushFrame; 35 | 36 | const R_Drawers = __import__R_Drawers(); 37 | const R_TitleDrawer = R_Drawers.R_TitleDrawer; 38 | 39 | const R_Geometry = __import__R_Geometry(); 40 | const R_ChangeRenderMode = R_Geometry.R_ChangeRenderMode; 41 | const R_RenderGeometries = R_Geometry.R_RenderGeometries; 42 | const R_ToggleGlobalRotation = R_Geometry.R_ToggleGlobalRotation; 43 | const R_UpdateGeometry = R_Geometry.R_UpdateGeometry; 44 | 45 | const TICK_DELAY = 1000 / FPS; 46 | 47 | // the unix timestamp of the latest game tick 48 | let lastTick: number | undefined; 49 | 50 | const nTrisOnScreen = new Uint32Array(2); 51 | 52 | function G_UpdateScreen (deltaT: number): void 53 | { 54 | R_ChangeRenderMode(); 55 | R_RenderGeometries(nTrisOnScreen); 56 | R_FlushFrame(); 57 | if (DEBUG_MODE) R_DebugStats(deltaT, nTrisOnScreen); 58 | } 59 | 60 | function G_UpdateGame (_deltaT: number): void 61 | { 62 | R_UpdateCamera(1); // TODO: take `deltaT` into account 63 | R_ToggleGlobalRotation(); 64 | R_UpdateGeometry(); 65 | } 66 | 67 | function G_Tick (deltaT: number): void 68 | { 69 | G_UpdateGame(deltaT); // update actors & game state 70 | G_UpdateScreen(deltaT); // update screen buffer 71 | } 72 | 73 | function G_AdvanceTick (currentTick: number): void 74 | { 75 | if (lastTick === undefined) lastTick = currentTick; 76 | const deltaT = currentTick - lastTick; 77 | if (deltaT >= TICK_DELAY) 78 | { 79 | // TODO: consider executing only the screen updates in the `RAF` 80 | // callback 81 | G_Tick(deltaT); 82 | lastTick = currentTick; 83 | } 84 | requestAnimationFrame(G_AdvanceTick); 85 | } 86 | 87 | function G_StartGame (titleId: string): void 88 | { 89 | // first, clear the title screen animation that is running 90 | AN_CancelAnimation(titleId); 91 | requestAnimationFrame(G_AdvanceTick); // then, kickstart the game ticks 92 | } 93 | 94 | function G_Run (setupResolution?: setup_resolution_t): void 95 | { 96 | if (!setupResolution) return; // exit with error 97 | // first, clear the frame buffer for any further drawing to take place 98 | R_FlushFrame(); 99 | // then, clear the loading animation that is currently running 100 | AN_CancelAnimation(setupResolution.loadingId); 101 | /* finally, start the animation for the title screen */ 102 | const titleId = 103 | R_TitleDrawer(A_Texture(D_GlobTextureIdTable.TITLE_TMP3D)); 104 | document.addEventListener("keydown", 105 | G_StartGame.bind(undefined, titleId), 106 | { once: true }); 107 | } 108 | 109 | window.__import__G_Run = function () 110 | { 111 | return { G_Run }; 112 | }; 113 | })(); 114 | -------------------------------------------------------------------------------- /src/game/g_setup.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * g_setup.ts 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-02-13. 6 | * 7 | * SYNOPSIS: 8 | * The module for setting up various controllers, including I/O, static 9 | * game data, and 3-D meshes for the engine to run off of. 10 | */ 11 | 12 | (function (): void 13 | { 14 | const A_Assets = __import__A_Assets(); 15 | const A_LoadTextures = A_Assets.A_LoadTextures; 16 | 17 | const AN_Animation = __import__AN_Animation(); 18 | const AN_CancelAnimation = AN_Animation.AN_CancelAnimation; 19 | 20 | const D_Mesh = __import__D_Mesh(); 21 | const D_Vertices = D_Mesh.D_Vertices(); 22 | const D_Triangles = D_Mesh.D_Triangles(); 23 | const D_UV = D_Mesh.D_UV(); 24 | const D_UVMap = D_Mesh.D_UVMap(); 25 | const D_TextureAtlas = D_Mesh.D_TextureAtlas(); 26 | 27 | const D_Player = __import__D_Player(); 28 | const D_Velocity = D_Player.D_Velocity; 29 | const D_Eye = D_Player.D_Eye(); 30 | 31 | const D_GlobTextures = __import__D_GlobTextures(); 32 | const D_GlobTextureIdTable = D_GlobTextures.D_GlobTextureIdTable; 33 | const D_GlobTextureFilenameTable = 34 | D_GlobTextures.D_GlobTextureFilenameTable; 35 | 36 | const G_Const = __import__G_Const(); 37 | const ASPECT = G_Const.ASPECT; 38 | const FOV_Y = G_Const.FOV_Y; 39 | const Z_NEAR = G_Const.Z_NEAR, Z_FAR = G_Const.Z_FAR; 40 | 41 | const I_Input = __import__I_Input(); 42 | const I_InitKeyboard = I_Input.I_InitKeyboard; 43 | const I_InitMouse = I_Input.I_InitMouse; 44 | 45 | const R_Camera = __import__R_Camera(); 46 | const R_InitCamera = R_Camera.R_InitCamera; 47 | 48 | const R_Draw = __import__R_Draw(); 49 | const R_InitFrameBuffer = R_Draw.R_InitFrameBuffer; 50 | const R_InitZBuffer = R_Draw.R_InitZBuffer; 51 | 52 | const R_Drawers = __import__R_Drawers(); 53 | const R_LoadingDrawer = R_Drawers.R_LoadingDrawer; 54 | const R_ErrorDrawer = R_Drawers.R_ErrorDrawer; 55 | 56 | const R_Geometry = __import__R_Geometry(); 57 | const R_InitUVTable = R_Geometry.R_InitUVTable; 58 | const R_LoadGeometry = R_Geometry.R_LoadGeometry; 59 | 60 | const R_Screen = __import__R_Screen(); 61 | const R_ScreenElement = R_Screen.R_ScreenElement; 62 | 63 | function G_LoadTextures (): Promise 64 | { 65 | const meshTextureIds = Object.keys(D_TextureAtlas); 66 | const globTextureIds = Object.keys(D_GlobTextureIdTable); 67 | const textureIds = meshTextureIds.concat(globTextureIds); 68 | const meshTextureFilenames = Object.values(D_TextureAtlas); 69 | const globTextureFilenames = Object.values(D_GlobTextureFilenameTable); 70 | const textureFilenames = meshTextureFilenames 71 | .concat(globTextureFilenames); 72 | const numTextures = textureFilenames.length; 73 | 74 | return A_LoadTextures(textureIds, textureFilenames, numTextures); 75 | } 76 | 77 | function G_SetupPromise (): Promise 78 | { 79 | return G_LoadTextures(); 80 | // TODO: other async operations will go here, chained by `.then`s 81 | } 82 | 83 | function G_Setup (): Promise 84 | { 85 | // initialize the frame buffer first, before anything could be drawn on 86 | // the screen 87 | R_InitFrameBuffer(); 88 | // play a loading animation during the setup procedure 89 | const resolution = { loadingId: R_LoadingDrawer() }; 90 | /* sync operations */ 91 | try 92 | { 93 | I_InitKeyboard(document); 94 | I_InitMouse(R_ScreenElement); 95 | R_InitZBuffer(); 96 | R_InitCamera(FOV_Y, ASPECT, Z_NEAR, Z_FAR, D_Eye, D_Velocity); 97 | R_LoadGeometry(D_Vertices, D_Vertices.length, 98 | D_Triangles, D_Triangles.length); 99 | /* initialize the uv table if the mesh data have texture-mapping */ 100 | if (D_UV.length && D_UVMap.length) 101 | R_InitUVTable(D_UV, D_UVMap, D_UVMap.length); 102 | } 103 | catch (error) 104 | { 105 | AN_CancelAnimation(resolution.loadingId); 106 | R_ErrorDrawer("setup error"); 107 | throw error; 108 | } 109 | 110 | /* async operations */ 111 | return G_SetupPromise() 112 | .then(function G_SetupResolver () 113 | { 114 | return resolution; 115 | }) 116 | .catch(function G_SetupRejector () 117 | { 118 | AN_CancelAnimation(resolution.loadingId); 119 | R_ErrorDrawer("setup error"); 120 | 121 | return undefined; 122 | }); 123 | } 124 | 125 | window.__import__G_Setup = function () 126 | { 127 | return { G_Setup }; 128 | }; 129 | })(); 130 | -------------------------------------------------------------------------------- /src/view/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tmp3D 7 | 26 | <%_ if (env.debugMode) { _%> 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 | -------------------------------------------------------------------------------- /tools/build.js: -------------------------------------------------------------------------------- 1 | /* 2 | * build.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-12-13. 6 | * 7 | * SYNOPSIS: 8 | * The module that helps build a static site to serve the Tmp3D Engine. 9 | */ 10 | 11 | const cli = require("commander"); 12 | const path = require("path"); 13 | const ejs = require("ejs"); 14 | const { transpileModule } = require("typescript"); 15 | 16 | const packageJson = require("../package.json"); 17 | const tsConfig = require("../tsconfig.json"); 18 | const { 19 | ReadFile, 20 | WriteFile, 21 | CopyFile, 22 | IsDir, 23 | Mkdir, 24 | ReadDir, 25 | RemovePath 26 | } = require("../tools/file"); 27 | const { LogInfo } = require("./log"); 28 | 29 | const ROOT = path.dirname(__dirname); // the project root 30 | const SRC = path.join(ROOT, "src"); // the source directory 31 | const ASSETS = path.join(ROOT, "assets"); // the assets directory 32 | // path to the view template 33 | const TEMPLATE_PATH = path.join(SRC, "view", "index.ejs"); 34 | // path to the view template directory 35 | const TEMPLATE_DIR = path.dirname(TEMPLATE_PATH); 36 | const FAVICON_PATH = path.join(ASSETS, "favicon.ico"); // path to the favicon 37 | const LOG_OPTIONS = { context: "build" }; 38 | 39 | function BuildView (debug) 40 | { 41 | // read the template 42 | const template = ReadFile(TEMPLATE_PATH, { encoding: "utf8" }); 43 | // the environment variables to pass onto `ejs` for the rendering of the 44 | // template 45 | const clientEnv = { debugMode: !!debug, version: packageJson.version }; 46 | // render and return the `index.html` 47 | return ejs.render(template, { env: clientEnv }); 48 | } 49 | 50 | function TranspileTs (filepath, outputPath) 51 | { 52 | /* if the input file is not of typescript source, copy it directly without 53 | * transpiling 54 | */ 55 | if (path.extname(filepath) !== ".ts") 56 | { 57 | CopyFile(filepath, path.join(outputPath, path.basename(filepath))); 58 | return; 59 | } 60 | const transpiledFilename = path.basename(filepath).replace(/\.ts$/, ".js"); 61 | const transpiledPath = path.join(outputPath, transpiledFilename); 62 | WriteFile(transpiledPath, 63 | transpileModule(ReadFile(filepath).toString(), 64 | tsConfig.compilerOptions).outputText); 65 | LogInfo(`Transpiled ${filepath}.`, LOG_OPTIONS); 66 | } 67 | 68 | function CopyStatic (sourceDir, outputDir, onFile) 69 | { 70 | // queue the directory entries to copy from `sourceDir` to `outputDir` 71 | const copyQueue = []; 72 | /* iterate over the entries in the `sourceDir` to determine whether or not 73 | * they should be copied over to `outputDir` 74 | */ 75 | for (const entry of ReadDir(sourceDir)) 76 | { 77 | const copySrc = path.join(sourceDir, entry); 78 | if ( 79 | // copy if it's any directory other than the `TEMPLATE_DIR`... 80 | copySrc !== TEMPLATE_DIR && IsDir(copySrc) || 81 | // ...or if it's the favicon 82 | copySrc === FAVICON_PATH 83 | ) 84 | copyQueue.push(entry); 85 | } 86 | /* exhaust the entries in the queue and copy them over to `outputDir` */ 87 | while (copyQueue.length) 88 | { 89 | const entry = copyQueue.shift(); 90 | const copySrc = path.join(sourceDir, entry); 91 | const copyDest = path.join(outputDir, entry); 92 | /* check to see if the entry popped from the queue is in fact a file, 93 | * and if so, copy it directly over to the `outputDir` 94 | * 95 | * (this case only applies to the favicon for the time being) 96 | */ 97 | if (!IsDir(copySrc)) 98 | { 99 | CopyFile(copySrc, copyDest); 100 | continue; 101 | } 102 | Mkdir(copyDest); // create the sub-directory in the `outputDir` 103 | /* iterate over the sub-entries in the `copySrc`... */ 104 | for (const subEntry of ReadDir(copySrc)) 105 | { 106 | const copySrcAbspath = path.join(copySrc, subEntry); 107 | /* ...and push the sub-entry to the queue if it's a sub-directory */ 108 | if (IsDir(copySrcAbspath)) 109 | copyQueue.push(path.join(entry, subEntry)); 110 | /* ...or run a custom callback, if specified */ 111 | else if (onFile) 112 | onFile(copySrcAbspath, copyDest); 113 | /* ...or copy it over to the `copyDest` if it's a file */ 114 | else 115 | CopyFile(copySrcAbspath, path.join(copyDest, subEntry)); 116 | } 117 | } 118 | } 119 | 120 | function Build (outputPath, debug, verbose) 121 | { 122 | LOG_OPTIONS.verbose = verbose; 123 | const outputDir = path.join(ROOT, outputPath); 124 | /* start with a clean slate and clear any previously built artefacts */ 125 | if (IsDir(outputDir)) 126 | { 127 | LogInfo(`Cleaning ${outputDir}...`, LOG_OPTIONS); 128 | RemovePath(outputDir, true); 129 | } 130 | Mkdir(outputDir, true); // create the output directory 131 | LogInfo(`Created the output directory at ${outputDir}.`, LOG_OPTIONS); 132 | LogInfo("Building view...", LOG_OPTIONS); 133 | const pathToView = path.join(outputDir, "index.html"); 134 | // compile the `index.html` 135 | WriteFile(pathToView, BuildView(debug), { encoding: "utf8" }); 136 | LogInfo(`Saved view at ${pathToView}.`, LOG_OPTIONS); 137 | LogInfo(`Copying ${SRC}...`, LOG_OPTIONS); 138 | /* copy the static files, i.e, scripts, assets, and anything that is static, 139 | * over to the output directory 140 | */ 141 | CopyStatic(SRC, outputDir, TranspileTs); 142 | LogInfo(`Copied contents of ${SRC} to ${outputDir}.`, LOG_OPTIONS); 143 | LogInfo(`Copying ${ASSETS}...`, LOG_OPTIONS); 144 | CopyStatic(ASSETS, outputDir); 145 | LogInfo(`Copied contents of ${ASSETS} to ${outputDir}.`, LOG_OPTIONS); 146 | } 147 | 148 | function HandleCommand (args) 149 | { 150 | const { outputPath, debug, verbose } = args; // read optional arguments 151 | // build the project to be served as a static site from the provided 152 | // `outputPath` 153 | Build(outputPath, debug, verbose ?? false); 154 | } 155 | 156 | function main () 157 | { 158 | cli 159 | .name("build") 160 | .description("Build a static site to serve the Tmp3D Engine") 161 | .version("0.0.1"); 162 | cli 163 | .option("-o, --output-path", 164 | "The path in which the built site will be saved", 165 | "./dist") 166 | .option("-d, --debug", "Build in debug mode") 167 | .option("-v, --verbose", "Verbose mode") 168 | .action(HandleCommand); 169 | cli.parse(process.argv); 170 | } 171 | 172 | if (require.main === module) main(); 173 | 174 | exports.Build = Build; 175 | -------------------------------------------------------------------------------- /tools/file.js: -------------------------------------------------------------------------------- 1 | /* 2 | * file.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-07-03. 6 | * 7 | * SYNOPSIS: 8 | * The module that helps with filesystem I/O. 9 | */ 10 | 11 | const fs = require("fs"); 12 | 13 | function ReadFile (path, options) 14 | { 15 | try { return fs.readFileSync(path, options); } 16 | catch (error) { throw new Error(`ReadFile: ${error}`); } 17 | } 18 | 19 | function WriteFile (path, data, options) 20 | { 21 | try { fs.writeFileSync(path, data, options); } 22 | catch (error) { throw new Error(`WriteFile: ${error}`); } 23 | } 24 | 25 | function CopyFile (src, dest) 26 | { 27 | try { fs.copyFileSync(src, dest); } 28 | catch (error) { throw new Error(`CopyFile: ${error}`); } 29 | } 30 | 31 | function IsDir (path) 32 | { 33 | try 34 | { 35 | if (!fs.existsSync(path)) return false; 36 | return fs.lstatSync(path).isDirectory(); 37 | } 38 | catch (error) 39 | { 40 | throw new Error(`IsDir: ${error}`); 41 | } 42 | } 43 | 44 | function Mkdir (path, recursive) 45 | { 46 | try { fs.mkdirSync(path, { recursive }); } 47 | catch (error) { throw new Error(`Mkdir: ${error}`); } 48 | } 49 | 50 | function ReadDir (path) 51 | { 52 | try { return fs.readdirSync(path); } 53 | catch (error) { throw new Error(`ReadDir: ${error}`); } 54 | } 55 | 56 | function RemovePath (path, recursive) 57 | { 58 | try { fs.rmSync(path, { recursive }); } 59 | catch (error) { throw new Error(`RemovePath: ${error}`); } 60 | } 61 | 62 | exports.ReadFile = ReadFile; 63 | exports.WriteFile = WriteFile; 64 | exports.CopyFile = CopyFile; 65 | exports.IsDir = IsDir; 66 | exports.Mkdir = Mkdir; 67 | exports.ReadDir = ReadDir; 68 | exports.RemovePath = RemovePath; 69 | -------------------------------------------------------------------------------- /tools/log.js: -------------------------------------------------------------------------------- 1 | /* 2 | * log.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2023-04-22. 6 | * 7 | * SYNOPSIS: 8 | * A module for local runtime logging. 9 | */ 10 | 11 | const LOG_LEVEL = { 12 | DEBUG: "DEBUG", 13 | INFO: "INFO", 14 | WARNING: "WARNING", 15 | ERROR: "ERROR", 16 | }; 17 | 18 | function Log (level, message, context) 19 | { 20 | const prefix = `[tmp3d${context ? `-${context}` : ""}]`; 21 | console.log(`${prefix} ${level}: ${message}`); 22 | } 23 | 24 | function LogDebug (message, context) 25 | { 26 | Log(LOG_LEVEL.DEBUG, message, context); 27 | } 28 | 29 | function LogInfo (message, options) 30 | { 31 | let context, verbose; 32 | if (options) ({ context, verbose } = options); 33 | if (!(verbose ?? true)) return; 34 | Log(LOG_LEVEL.INFO, message, context); 35 | } 36 | 37 | function LogWarning (message, context) 38 | { 39 | Log(LOG_LEVEL.WARNING, message, context); 40 | } 41 | 42 | function LogError (message, context) 43 | { 44 | Log(LOG_LEVEL.ERROR, message, context); 45 | } 46 | 47 | exports.LogDebug = LogDebug; 48 | exports.LogInfo = LogInfo; 49 | exports.LogWarning = LogWarning; 50 | exports.LogError = LogError; 51 | -------------------------------------------------------------------------------- /tools/misc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * misc.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-07-03. 6 | * 7 | * SYNOPSIS: 8 | * Miscellaneous tools & utilities. 9 | */ 10 | 11 | function ArrayToStr (array) 12 | { 13 | return `[${array.join(", ")}]`; 14 | } 15 | 16 | function DateToStr (date) 17 | { 18 | const year = date.getFullYear(); 19 | const month = `${(date.getMonth() + 1)}`.padStart(2, "0"); 20 | const day = `${date.getDate()}`.padStart(2, "0"); 21 | return `${year}-${month}-${day}`; 22 | } 23 | 24 | exports.ArrayToStr = ArrayToStr; 25 | exports.DateToStr = DateToStr; 26 | -------------------------------------------------------------------------------- /tools/obj.js: -------------------------------------------------------------------------------- 1 | /* 2 | * obj.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-07-03. 6 | * 7 | * SYNOPSIS: 8 | * A CLI that provides some utility functions to help work with .obj files. 9 | */ 10 | 11 | const cli = require("commander"); 12 | const path = require("path"); 13 | 14 | const { ReadFile, WriteFile } = require("./file"); 15 | const { LogInfo } = require("./log"); 16 | const { ArrayToStr, DateToStr } = require("./misc"); 17 | 18 | const ROOT = path.join(__dirname, ".."); 19 | const ASSETS_PATH = path.join(ROOT, "assets"); 20 | const MESH_PATH = path.join(ROOT, "src", "data", "mesh"); 21 | const VIEW_PATH = path.join(ROOT, "src", "view", "index.ejs"); 22 | 23 | const DELIMITER = ",\n "; 24 | 25 | const tmp3DMeshTemplate = `/* 26 | * %filename 27 | * tmp3d 28 | * 29 | * Created by Emre Akı on %dateCreated. 30 | * 31 | * SYNOPSIS: 32 | * The initial 3-D geometry data and their respective UV mappings. 33 | */ 34 | 35 | (function (): void 36 | { 37 | function D_Vertices (): pvec3_t[] 38 | { 39 | return [ 40 | %v 41 | ]; 42 | } 43 | 44 | function D_UV (): pvec2_t[] 45 | { 46 | return [ 47 | %vt 48 | ]; 49 | } 50 | 51 | function D_Triangles (): pvec3_t[] 52 | { 53 | return [ 54 | %f 55 | ]; 56 | } 57 | 58 | function D_UVMap (): uvface_t[] 59 | { 60 | return [ 61 | %vf 62 | ]; 63 | } 64 | 65 | function D_TextureAtlas (): { [textureId: string]: string } 66 | { 67 | return { 68 | %ta 69 | }; 70 | } 71 | 72 | window.__import__D_Mesh = function () 73 | { 74 | return { 75 | D_Vertices: D_Vertices, 76 | D_UV: D_UV, 77 | D_Triangles: D_Triangles, 78 | D_UVMap: D_UVMap, 79 | D_TextureAtlas: D_TextureAtlas, 80 | }; 81 | }; 82 | })(); 83 | `; 84 | 85 | function ParseLine (line) 86 | { 87 | return line.split(/\ +/); 88 | } 89 | 90 | function TextureAtlas (pathToMtl) 91 | { 92 | const textureAtlas = {}; 93 | // early return if there's no material file to be read 94 | if (!pathToMtl) return textureAtlas; 95 | const rawMtl = ReadFile(pathToMtl, { encoding: "utf8" }); 96 | const lines = rawMtl.split("\n"); 97 | let mtlId; // current material id 98 | for (const line of lines) 99 | { 100 | const tokens = ParseLine(line); 101 | // encountered a new material definition: 102 | // update the current material id 103 | if (tokens[0] === "newmtl") mtlId = tokens[1]; 104 | /* encountered a texture map definition for the current material: 105 | * save the path to the texture in the `textureAtlas` with its key 106 | * being the current material id 107 | */ 108 | else if (tokens[0].match(/map\_K[ads]/)) 109 | { 110 | const pathToTexture = `${path.join(path.dirname(pathToMtl), 111 | tokens[1])}`; 112 | textureAtlas[mtlId] = path.relative(ASSETS_PATH, pathToTexture); 113 | } 114 | } 115 | return textureAtlas; 116 | } 117 | 118 | function ObjToTmp3D (pathToObj, pathToMtl, outputFilename, zOffset) 119 | { 120 | const textureAtlas = TextureAtlas(pathToMtl); // construct a texture atlas 121 | let mtlId; // current material id 122 | // TODO: consider not using dynamic allocation 123 | const vertices = [], triangles = [], uvVertices = [], uvMap = []; 124 | const rawObj = ReadFile(pathToObj, { encoding: "utf8" }); 125 | const lines = rawObj.split("\n"); 126 | for (const line of lines) 127 | { 128 | const tokens = ParseLine(line); 129 | const dataType = tokens[0]; 130 | switch (dataType) 131 | { 132 | case "v": // vertex 133 | { 134 | const vertex = tokens.slice(1); // world space coordinates 135 | /* rotate the vertex read around the x-axis by π radians as the 136 | * +y axis in Tmp3D point down whereas in Blender it points up 137 | */ 138 | const vertexParsed = [parseFloat(vertex[0]), 139 | -parseFloat(vertex[1]), 140 | -parseFloat(vertex[2]) + zOffset]; 141 | vertices.push(vertexParsed); 142 | 143 | break; 144 | } 145 | case "vt": // texture vertices 146 | { 147 | const uv = tokens.slice(1); // texture space coordinates 148 | // flip the `v` coordinate, as it points up in Blender but down 149 | // in Tmp3D 150 | uvVertices.push([parseFloat(uv[0]), 1 - parseFloat(uv[1])]); 151 | 152 | break; 153 | } 154 | case "f": // face 155 | { 156 | const texturedMatch = line.match(/(\d+)\/(\d+)/g); 157 | /* encountered a textured face data */ 158 | if (texturedMatch) 159 | { 160 | /* Tmp3D can only process triangles */ 161 | if (texturedMatch.length !== 3) 162 | throw new Error("ObjToTmp3D: Invalid face geometry in" + 163 | pathToObj + "."); 164 | const texturedMatchA = texturedMatch[0].split("/"); 165 | const texturedMatchB = texturedMatch[1].split("/"); 166 | const texturedMatchC = texturedMatch[2].split("/"); 167 | /* offset the indices of the vertices by `-1` because 168 | * Blender start counting from 1 169 | */ 170 | const triangle = [parseInt(texturedMatchA[0]) - 1, 171 | parseInt(texturedMatchB[0]) - 1, 172 | parseInt(texturedMatchC[0]) - 1]; 173 | triangles.push(triangle); 174 | const texture = [parseInt(texturedMatchA[1]) - 1, 175 | parseInt(texturedMatchB[1]) - 1, 176 | parseInt(texturedMatchC[1]) - 1]; 177 | // if there's a material defined for the face, write it in 178 | // the uv-map 179 | if (mtlId) texture.push(`"${mtlId}"`); 180 | uvMap.push(texture); 181 | } 182 | /* encountered a textureless face data */ 183 | else 184 | { 185 | const vertexIndices = tokens.slice(1); 186 | /* Tmp3D can only process triangles */ 187 | if (vertexIndices.length !== 3) 188 | throw new Error("ObjToTmp3D: Invalid face geometry in" + 189 | pathToObj + "."); 190 | /* offset the indices of the vertices by `-1` because 191 | * Blender start counting from 1 192 | */ 193 | const triangle = [parseInt(vertexIndices[0]) - 1, 194 | parseInt(vertexIndices[1]) - 1, 195 | parseInt(vertexIndices[2]) - 1]; 196 | triangles.push(triangle); 197 | } 198 | 199 | break; 200 | } 201 | case "usemtl": // use material definition 202 | mtlId = tokens[1]; 203 | 204 | break; 205 | default: 206 | break; 207 | } 208 | } 209 | const verticesSerialized = vertices.map(vertex => ArrayToStr(vertex)); 210 | const trianglesSerialized = triangles.map(triangle => ArrayToStr(triangle)); 211 | const uvVerticesSerialized = uvVertices.map(vertex => ArrayToStr(vertex)); 212 | const uvMapSerialized = uvMap.map(uvIndices => ArrayToStr(uvIndices)); 213 | const textureAtlasSerialized = Object 214 | .entries(textureAtlas) 215 | .map(([textureId, texturePath]) => `"${textureId}": "${texturePath}"`); 216 | /* replace serialized mesh data in the template and return the resulting 217 | * file 218 | */ 219 | return tmp3DMeshTemplate 220 | .replace(/\%filename$/m, outputFilename) 221 | .replace(/\%dateCreated/m, DateToStr(new Date())) 222 | .replace(/\%v$/m, `${verticesSerialized.join(DELIMITER)}`) 223 | .replace(/\%f$/m, `${trianglesSerialized.join(DELIMITER)}`) 224 | .replace(/\%vt$/m, `${uvVerticesSerialized.join(DELIMITER)}`) 225 | .replace(/\%vf$/m, `${uvMapSerialized.join(DELIMITER)}`) 226 | .replace(/\%ta$/m, `${textureAtlasSerialized.join(DELIMITER)}`); 227 | } 228 | 229 | function ReplaceModelPathInView (modelFilename) 230 | { 231 | const indexEjs = ReadFile(VIEW_PATH, { encoding: "utf8" }); 232 | const replaced = indexEjs.replace(/data\/mesh\/.+\.js/, 233 | `data/mesh/${modelFilename}`); 234 | WriteFile(VIEW_PATH, replaced, { encoding: "utf8" }); 235 | } 236 | 237 | function HandleCommand (pathToObj, args) 238 | { 239 | /* read optional arguments */ 240 | const { material: pathToMtl, verbose } = args; 241 | const zOffset = parseFloat(args.zOffset); 242 | /* throw an error if the input is not an `.obj` file */ 243 | const objFilename = path.basename(pathToObj).match(/(.+)\.obj$/)[1]; 244 | if (!objFilename) 245 | throw new Error("HandleCommand: The input is not an .obj file."); 246 | /* determine the path into which the output will be written */ 247 | const outputPath = path.join(MESH_PATH, 248 | `d_${objFilename.toLowerCase()}.ts`); 249 | const outputFilename = path.basename(outputPath); 250 | const tmp3Data = ObjToTmp3D(pathToObj, pathToMtl, outputFilename, zOffset); 251 | LogInfo(tmp3Data, { verbose: verbose ?? false }); 252 | WriteFile(outputPath, tmp3Data, { encoding: "utf8" }); 253 | ReplaceModelPathInView(outputFilename.replace(/\.ts$/, ".js")); 254 | LogInfo(`Mesh saved at ${path.relative(ROOT, outputPath)}.`); 255 | } 256 | 257 | function main () 258 | { 259 | cli 260 | .name("obj-utils") 261 | .description("A set of utility functions to help work with .obj files") 262 | .version("0.0.1"); 263 | cli 264 | .command("convert") 265 | .argument("", "Path to the .obj file to convert") 266 | .alias("c") 267 | .description("Convert a Wavefront .obj file into a format that Tmp3D could operate on") 268 | .option("-m, --material [value]", "Material library file") 269 | .option("-z, --z-offset [value]", "Offset the model along z-axis", "0") 270 | .option("-v, --verbose", "Verbose mode") 271 | .action(HandleCommand); 272 | cli.parse(process.argv); 273 | } 274 | 275 | main(); 276 | -------------------------------------------------------------------------------- /tools/server.js: -------------------------------------------------------------------------------- 1 | /* 2 | * server.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2022-04-23. 6 | * 7 | * SYNOPSIS: 8 | * The module that helps serve the Tmp3D Engine locally as a static site. 9 | */ 10 | 11 | const express = require("express"); 12 | const path = require("path"); 13 | 14 | const packageJson = require("../package.json"); 15 | const { LogInfo } = require("./log"); 16 | 17 | const ENV = process.env; 18 | const PORT = ENV.PORT || 3000; 19 | const ROOT = path.join(__dirname, "..", "dist"); 20 | const CLIENT_ENV = { debugMode: ENV.DEBUG, version: packageJson.version }; 21 | const LOG_OPTIONS = { context: "server" }; 22 | 23 | function serve () 24 | { 25 | LogInfo(`Serving ${ROOT} through port ${PORT}`, LOG_OPTIONS); 26 | } 27 | 28 | function main () 29 | { 30 | express() 31 | .use(express.static(path.join(ROOT, "..", "assets"))) 32 | .use("/engine", express.static(path.join(ROOT, "engine"))) 33 | .use("/game", express.static(path.join(ROOT, "game"))) 34 | .use("/data", express.static(path.join(ROOT, "data"))) 35 | .set("view engine", "ejs") 36 | .set("views", path.join(ROOT, "..", "src", "view")) 37 | .get("/", (_, res) => res.render("index", { env: CLIENT_ENV })) 38 | .listen(PORT, serve); 39 | } 40 | 41 | main(); 42 | -------------------------------------------------------------------------------- /tools/watch.js: -------------------------------------------------------------------------------- 1 | /* 2 | * watch.js 3 | * tmp3d 4 | * 5 | * Created by Emre Akı on 2023-04-22. 6 | * 7 | * SYNOPSIS: 8 | * A module for watching and re-building changes in the local project tree. 9 | */ 10 | 11 | const { Build } = require("./build"); 12 | 13 | const ENV = process.env; 14 | 15 | function main () 16 | { 17 | Build("dist", ENV.DEBUG, 1); 18 | require("./server"); 19 | } 20 | 21 | main(); 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "moduleResolution": "node", 5 | "outDir": "dist", 6 | "strict": true, 7 | "noImplicitAny": true, 8 | "noUnusedLocals": true, 9 | "noUnusedParameters": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "lib": ["es2017", "dom"], 13 | "typeRoots": ["./src/typedef.d.ts"] 14 | } 15 | } 16 | --------------------------------------------------------------------------------