├── .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 |
--------------------------------------------------------------------------------