├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .idea
├── .gitignore
├── DOOM.iml
├── inspectionProfiles
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── .vscode
├── c_cpp_properties.json
└── tasks.json
├── LICENSE
├── README.md
├── build.bat
├── built_rom.bin
├── res
├── enemy1.png
├── graphics_res.h
├── graphics_res.res
├── hud.h
├── hud.res
├── images
│ ├── HUD.png
│ ├── HUD2.png
│ ├── SHOTGUN.png
│ ├── SKYBOX1.png
│ ├── armor_inv.png
│ ├── blue_key_inv.png
│ ├── bullet_inv.png
│ ├── heart_inv.png
│ └── shield_inv.png
├── music_res.h
├── music_res.res
├── no_dist_lighting_palette_tweaked.png
├── palette_for_bright_wall.png
├── palette_old.png
├── sfx
│ ├── closedoor.wav
│ ├── opendoor.wav
│ ├── select.wav
│ └── shoot.wav
├── sfx_res.h
├── sfx_res.res
├── sprite_pal.png
├── sprites_res.h
├── sprites_res.res
├── textures
│ ├── DOOR.png
│ ├── DOOR_15COL.png
│ ├── DOOR_MORE_COLOR.png
│ ├── KEY.png
│ ├── KEY_32_32.png
│ ├── STAIRS.png
│ ├── TEXTURE_SHEET.png
│ ├── WALLA_15COL.png
│ ├── WALLB_15COL.png
│ ├── WALLC_15COL.png
│ ├── WALL_A.png
│ ├── WALL_A_DARKER.png
│ ├── WALL_A_DARKEST.png
│ ├── WALL_A_FOG.png
│ ├── WALL_A_FOG_DARKER.png
│ ├── WALL_A_FOG_DARKEST.png
│ ├── WALL_B.png
│ ├── WALL_B_DARKER.png
│ ├── WALL_B_DARKEST.png
│ ├── WALL_C.png
│ ├── WALL_C_DARKER.png
│ ├── WALL_C_DARKEST.png
│ ├── doobguy.png
│ ├── sci-fi-wall-texture-atlas.png
│ ├── sci-fi-wallc.png
│ ├── sci-fi-wallc_dark.png
│ ├── sprites.png
│ ├── texture_atlas.png
│ └── texture_atlas_sprite_palette.png
└── two_light_levels_pal.png
├── screen0.png
├── screen1.png
├── screen2.png
├── screen3.png
└── src
├── NOTES
├── TODO.md
├── active_sectors.c
├── active_sectors.h
├── bob.c
├── boot
├── rom_head.c
└── sega.s
├── building_test_map.c
├── building_test_map.h
├── bunch_render.c
├── bunch_render.h
├── clip_buf.c
├── clip_buf.h
├── collision.c
├── collision.h
├── colors.c
├── colors.h
├── config.h
├── console.c
├── console.h
├── div_lut.c
├── div_lut.h
├── draw.c
├── draw.h
├── editor_test_map.c
├── editor_test_map.h
├── fire.c
├── fire.h
├── fire_native.s
├── fire_tables.py
├── game.c
├── game.h
├── game_mode.c
├── game_mode.h
├── imgui.ini
├── init.c
├── init.h
├── inventory.c
├── inventory.h
├── joy_helper.c
├── joy_helper.h
├── js
├── pvs.html
└── pvs.js
├── level.c
├── level.h
├── main.c
├── main_menu.c
├── main_menu.h
├── map_table.c
├── map_table.h
├── maps.h
├── math3d.c
├── math3d.h
├── menu_helper.c
├── menu_helper.h
├── music.c
├── music.h
├── my_bmp.c
├── my_bmp.h
├── my_bmp_a.s
├── obj_sprite.c
├── obj_sprite.h
├── object.c
├── object.h
├── overlapping_test_map.c
├── overlapping_test_map.h
├── portal.c
├── portal.h
├── portal_map.c
├── portal_map.h
├── python
├── __init__.py
├── bsp.py
├── draw.py
├── e1m1.c
├── editor
│ ├── .idea
│ │ ├── editor.iml
│ │ ├── inspectionProfiles
│ │ │ └── profiles_settings.xml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ ├── vcs.xml
│ │ └── workspace.xml
│ ├── DLLs
│ │ └── geos_c.dll
│ ├── README
│ ├── README.md
│ ├── build_conf.ini
│ ├── compress.py
│ ├── defaults.py
│ ├── editor.py
│ ├── editor.spec
│ ├── file_utils.py
│ ├── geos_c.dll
│ ├── imgui.ini
│ ├── levels.py
│ ├── light_levels.py
│ ├── light_remapping_table.png
│ ├── light_remapping_table_autogen.png
│ ├── light_remapping_table_mix.png
│ ├── light_remapping_table_mix_rotated.png
│ ├── light_remapping_table_no_mix_rotated.png
│ ├── line.py
│ ├── map.py
│ ├── modes.py
│ ├── music.py
│ ├── palette.py
│ ├── palette_light_table.py
│ ├── poetry.lock
│ ├── pvs.py
│ ├── pyproject.toml
│ ├── remapping.py
│ ├── render_3d.py
│ ├── requirements.txt
│ ├── rom.py
│ ├── run_editor.bat
│ ├── script.py
│ ├── sector.py
│ ├── sector_group.py
│ ├── sprite_utils.py
│ ├── state.py
│ ├── texture_utils.py
│ ├── things.py
│ ├── tree.py
│ ├── trigger.py
│ ├── undo.py
│ ├── utils.py
│ ├── vertex.py
│ └── wad.py
├── gen_font_shadow_lut.py
├── gen_linedef_rasterizer.py
├── gen_postinc_tex_tables.py
├── gen_raster_loops.py
├── gen_recip_table.py
├── gen_sprite_scale_routine_tables.py
├── gen_sprite_scale_tables.py
├── main.py
├── optimizer.py
├── plane_lighting_pre_calc.py
├── portal.py
├── profile.stats
├── span_buffer.py
├── util.py
└── wad.py
├── random.c
├── random.h
├── real_timer.c
├── real_timer.h
├── sector_group.c
├── sector_group.h
├── sfx.c
├── sfx.h
├── sprite
├── tex_draw_tables.s
├── tex_table_lookup.c
├── tex_tables_lookup.h
├── texture.c
├── texture.h
├── textures.c
├── textures.h
├── tile.h
├── utils.c
├── utils.h
├── vertex.h
├── vwf.c
├── vwf.h
├── vwf_decl.c
├── weapon_sprites.c
└── weapon_sprites.h
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build editor exe with Pyinstaller
2 |
3 | on:
4 | # Triggers the workflow on push or pull request events but only for the "master" branch
5 | push:
6 | branches: [ "master" ]
7 | pull_request:
8 | branches: [ "master" ]
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 |
17 | - name: Add path
18 | run: export PATH=src/python/editor/DLLs:$PATH
19 |
20 | - name: Package Application
21 | uses: JackMcKew/pyinstaller-action-windows@main
22 | with:
23 | path: src/python/editor
24 |
25 | - name: Copy config file
26 | run: sudo cp src/python/editor/build_conf.ini src/python/editor/dist/windows/conf.ini
27 |
28 | - name: Copy readme
29 | run: sudo cp src/python/editor/README src/python/editor/dist/windows/README
30 |
31 | - name: Copy engine binary
32 | run: sudo cp built_rom.bin src/python/editor/dist/windows/rom.bin
33 |
34 | - name: Create textures directory
35 | run: sudo mkdir src/python/editor/dist/windows/textures
36 |
37 | - name: Create sprites directory
38 | run: sudo mkdir src/python/editor/dist/windows/sprites
39 |
40 | - name: Create music directory
41 | run: sudo mkdir src/python/editor/dist/windows/music
42 |
43 | - uses: actions/upload-artifact@v2
44 | with:
45 | name: portal-editor
46 | path: src/python/editor/dist/windows/*
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.so
27 | *.so.*
28 | *.dylib
29 |
30 | # Executables
31 | *.exe
32 | *.out
33 | *.app
34 | *.i*86
35 | *.x86_64
36 | *.hex
37 |
38 | # Debug files
39 | *.dSYM/
40 | *.su
41 | *.idb
42 | *.pdb
43 |
44 | # Kernel Module Compile Results
45 | *.mod*
46 | *.cmd
47 | .tmp_versions/
48 | modules.order
49 | Module.symvers
50 | Mkfile.old
51 | dkms.conf
52 | out/
53 |
54 | # cached python modules, and cached wads loaded by python tool
55 | *.pyc
56 | *.cache
57 |
58 | .vscode*
59 | .vscode/
60 | .vscode/*
61 | .idea
62 | .idea*
63 | .idea/*
64 | .venv/
65 | src/python/editor/build/
66 | imgui.ini
67 | src/python/dist.7z
68 | src/python/editor/dist/
69 | *.vgm
70 | src/python/editor/imgui.ini
71 | src/python/editor/sprites/
72 | src/python/editor/textures/
73 | res/sprites/
74 | src/python/editor/editor.build/
75 | src/python/editor/editor.dist/
76 | src/python/editor/conf.ini
77 | res/sfx/*.wav
78 | res/music/*.wav
79 | res/sprites/*.png
80 | res/images/*.png
81 | res/textures/*.png
82 | src/python/editor/SDL2.dll
83 | src/python/editor/editor.onefile-build/
84 | src/python/editor/editor.dist.7z
85 | src/python/editor/DLLs/
86 | src/python/editor/fixed_rom.bin
87 | src/python/editor/xgm_output.bin
88 | src/python/editor/maps/
89 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/DOOM.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.vscode/c_cpp_properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 4,
3 | "configurations": [
4 | {
5 | "name": "SGDK",
6 | "includePath": [
7 | "${env:GDK_WIN}/inc/",
8 | "${env:GDK_WIN}/res/",
9 | "res/"
10 | ],
11 | "browse" : {
12 | "limitSymbolsToIncludedHeaders" : true,
13 | "databaseFilename" : ""
14 | }
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "SGDK - Build",
8 | "type": "shell",
9 | "command": ".\\build.bat release",
10 | "group": "build",
11 | "presentation": {
12 | "reveal": "always",
13 | "panel": "new"
14 | },
15 | "problemMatcher": []
16 | },
17 | {
18 | "label": "SGDK - Clean Build",
19 | "type": "shell",
20 | "command": ".\\build.bat cleanbuild",
21 | "group": "build",
22 | "presentation": {
23 | "reveal": "always",
24 | "panel": "new"
25 | },
26 | "problemMatcher": []
27 | },
28 | {
29 | "label": "SGDK - Asm",
30 | "type": "shell",
31 | "command": ".\\build.bat asm",
32 | "group": "build",
33 | "presentation": {
34 | "reveal": "always",
35 | "panel": "new"
36 | },
37 | "problemMatcher": []
38 | },
39 | {
40 | "label": "SGDK - Build & Test",
41 | "type": "shell",
42 | "command": ".\\build.bat",
43 | "group": "build",
44 | "presentation": {
45 | "reveal": "always",
46 | "panel": "new"
47 | },
48 | "problemMatcher": []
49 | },
50 | {
51 | "label": "SGDK - Build & Debug",
52 | "type": "shell",
53 | "command": ".\\build.bat debug",
54 | "group": "build",
55 | "presentation": {
56 | "reveal": "always",
57 | "panel": "new"
58 | },
59 | "problemMatcher": []
60 | },
61 | {
62 | "label": "Build and launch on mega everdrive pro",
63 | "type": "shell",
64 | "command": ".\\build.bat medbuild",
65 | "group": {
66 | "kind": "build",
67 | "isDefault": true
68 | },
69 | "presentation": {
70 | "echo": true,
71 | "reveal": "always",
72 | "focus": false,
73 | "panel": "shared",
74 | "showReuseMessage": true,
75 | "clear": false
76 | }
77 | }
78 | ]
79 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Erik Haliewicz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Manifold
2 | Portal renderer for Sega Genesis/Megadrive.
3 |
4 | Uses a "2.5D", doom or build engine-style rendering pipeline, but with convex sectors and portals.
5 |
6 | Graphics features
7 | - Arbitrary angled walls, ala doom and build-engine.
8 | - Perspective-correct texture mapping
9 | - Sector-based lighting levels with per-pixel distance lighting.
10 | - Overlapping "non-euclidean" geometry
11 | - Transparent surfaces.
12 |
13 | 
14 |
15 | 
16 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 |
2 | IF "x%1" == "x" (
3 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen
4 | %GENS% %CD%\out\rom.bin
5 | ) ELSE IF "%1" == "test" (
6 | %GENS% %CD%\out\rom.bin
7 | ) ELSE IF "%1" == "asm" (
8 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen asm
9 | ) ELSE IF "%1" == "debug" (
10 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen debug
11 | REM %GENS% %CD%\out\rom.bin -D
12 | REM %GENS_KMOD% %CD%\out\rom.bin
13 | %BLASTEM% %CD%\out\rom.bin -D
14 | ) ELSE IF "%1" == "cleanbuild" (
15 |
16 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen clean
17 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen release
18 | ) ELSE IF "%1" == "medbuild" (
19 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen
20 | %MEGALINK% %CD%\out\rom.bin
21 | ) ELSE (
22 | %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen %1
23 | )
24 |
--------------------------------------------------------------------------------
/built_rom.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/built_rom.bin
--------------------------------------------------------------------------------
/res/enemy1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/enemy1.png
--------------------------------------------------------------------------------
/res/graphics_res.h:
--------------------------------------------------------------------------------
1 | #ifndef _RES_GRAPHICS_RES_H_
2 | #define _RES_GRAPHICS_RES_H_
3 |
4 | extern const Palette two_light_levels_pal;
5 | extern const TileSet pause_checker;
6 | extern const Image skybox_gradient;
7 |
8 | #endif // _RES_GRAPHICS_RES_H_
9 |
--------------------------------------------------------------------------------
/res/graphics_res.res:
--------------------------------------------------------------------------------
1 | PALETTE two_light_levels_pal "two_light_levels_pal.png" NONE
2 | IMAGE skybox_gradient "images/SKYBOX1.png" NONE ALL
3 | TILESET pause_checker "images/pause_checker.png" NONE NONE
--------------------------------------------------------------------------------
/res/hud.h:
--------------------------------------------------------------------------------
1 | #ifndef _RES_HUD_H_
2 | #define _RES_HUD_H_
3 |
4 | extern const Image hud;
5 | extern const Image armor_inv;
6 | extern const Image blue_key_inv;
7 | extern const Image green_key_inv;
8 | extern const Image red_key_inv;
9 | extern const Image bullet_inv;
10 | extern const Image heart_inv;
11 | extern const Image shield_inv;
12 |
13 | #endif // _RES_HUD_H_
14 |
--------------------------------------------------------------------------------
/res/hud.res:
--------------------------------------------------------------------------------
1 | IMAGE hud "images/HUD2.png" NONE ALL
2 | IMAGE armor_inv "images/armor_inv.png" NONE ALL
3 | IMAGE blue_key_inv "images/blue_key_inv.png" NONE ALL
4 | IMAGE green_key_inv "images/green_key_inv.png" NONE ALL
5 | IMAGE red_key_inv "images/red_key_inv.png" NONE ALL
6 | IMAGE bullet_inv "images/bullet_inv.png" NONE ALL
7 | IMAGE heart_inv "images/heart_inv.png" NONE ALL
8 | IMAGE shield_inv "images/shield_inv.png" NONE ALL
--------------------------------------------------------------------------------
/res/images/HUD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/HUD.png
--------------------------------------------------------------------------------
/res/images/HUD2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/HUD2.png
--------------------------------------------------------------------------------
/res/images/SHOTGUN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/SHOTGUN.png
--------------------------------------------------------------------------------
/res/images/SKYBOX1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/SKYBOX1.png
--------------------------------------------------------------------------------
/res/images/armor_inv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/armor_inv.png
--------------------------------------------------------------------------------
/res/images/blue_key_inv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/blue_key_inv.png
--------------------------------------------------------------------------------
/res/images/bullet_inv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/bullet_inv.png
--------------------------------------------------------------------------------
/res/images/heart_inv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/heart_inv.png
--------------------------------------------------------------------------------
/res/images/shield_inv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/images/shield_inv.png
--------------------------------------------------------------------------------
/res/music_res.h:
--------------------------------------------------------------------------------
1 | #ifndef _RES_MUSIC_RES_H_
2 | #define _RES_MUSIC_RES_H_
3 |
4 |
5 | #endif // _RES_MUSIC_RES_H_
6 |
--------------------------------------------------------------------------------
/res/music_res.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/music_res.res
--------------------------------------------------------------------------------
/res/no_dist_lighting_palette_tweaked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/no_dist_lighting_palette_tweaked.png
--------------------------------------------------------------------------------
/res/palette_for_bright_wall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/palette_for_bright_wall.png
--------------------------------------------------------------------------------
/res/palette_old.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/palette_old.png
--------------------------------------------------------------------------------
/res/sfx/closedoor.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/sfx/closedoor.wav
--------------------------------------------------------------------------------
/res/sfx/opendoor.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/sfx/opendoor.wav
--------------------------------------------------------------------------------
/res/sfx/select.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/sfx/select.wav
--------------------------------------------------------------------------------
/res/sfx/shoot.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/sfx/shoot.wav
--------------------------------------------------------------------------------
/res/sfx_res.h:
--------------------------------------------------------------------------------
1 | #ifndef _RES_SFX_RES_H_
2 | #define _RES_SFX_RES_H_
3 |
4 | extern const u8 sfx_select[1792];
5 | extern const u8 sfx_shotgun[20480];
6 | extern const u8 sfx_jump1[4352];
7 | extern const u8 sfx_jump2[3072];
8 | extern const u8 sfx_lift_go_up[18176];
9 | extern const u8 sfx_door_open[9984];
10 | extern const u8 sfx_door_close[9728];
11 | extern const u8 sfx_enemy_a_wake[7680];
12 |
13 | #endif // _RES_SFX_RES_H_
14 |
--------------------------------------------------------------------------------
/res/sfx_res.res:
--------------------------------------------------------------------------------
1 | WAV sfx_select "sfx/select.wav" XGM
2 | WAV sfx_shotgun "sfx/shotgun.wav" XGM
3 | WAV sfx_jump1 "sfx/jump1.wav" XGM
4 | WAV sfx_jump2 "sfx/jump2.wav" XGM
5 | WAV sfx_lift_go_up "sfx/liftgoup.wav" XGM
6 | WAV sfx_door_open "sfx/opendoor.wav" XGM
7 | WAV sfx_door_close "sfx/closedoor.wav" XGM
8 | WAV sfx_enemy_a_wake "sfx/enemya_wake.wav" XGM
--------------------------------------------------------------------------------
/res/sprite_pal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/sprite_pal.png
--------------------------------------------------------------------------------
/res/sprites_res.h:
--------------------------------------------------------------------------------
1 | #ifndef _RES_SPRITES_RES_H_
2 | #define _RES_SPRITES_RES_H_
3 |
4 | extern const Palette sprite_pal;
5 | extern const TileSet smile;
6 | extern const TileSet frown;
7 | extern const SpriteDefinition shotgun;
8 | extern const SpriteDefinition shotgun_reload;
9 |
10 | #endif // _RES_SPRITES_RES_H_
11 |
--------------------------------------------------------------------------------
/res/sprites_res.res:
--------------------------------------------------------------------------------
1 | SPRITE shotgun "images/SHOTGUN.png" 8 8 0 0 NONE TILE
2 | SPRITE shotgun_reload "images/SHOTGUN_RELOAD.png" 8 16 0 0 NONE SPRITE
3 | PALETTE sprite_pal "sprite_pal.png" NONE
4 | TILESET smile "images/SMILE.png" NONE
5 | TILESET frown "images/FROWN.png" NONE
--------------------------------------------------------------------------------
/res/textures/DOOR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/DOOR.png
--------------------------------------------------------------------------------
/res/textures/DOOR_15COL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/DOOR_15COL.png
--------------------------------------------------------------------------------
/res/textures/DOOR_MORE_COLOR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/DOOR_MORE_COLOR.png
--------------------------------------------------------------------------------
/res/textures/KEY.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/KEY.png
--------------------------------------------------------------------------------
/res/textures/KEY_32_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/KEY_32_32.png
--------------------------------------------------------------------------------
/res/textures/STAIRS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/STAIRS.png
--------------------------------------------------------------------------------
/res/textures/TEXTURE_SHEET.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/TEXTURE_SHEET.png
--------------------------------------------------------------------------------
/res/textures/WALLA_15COL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALLA_15COL.png
--------------------------------------------------------------------------------
/res/textures/WALLB_15COL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALLB_15COL.png
--------------------------------------------------------------------------------
/res/textures/WALLC_15COL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALLC_15COL.png
--------------------------------------------------------------------------------
/res/textures/WALL_A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_A.png
--------------------------------------------------------------------------------
/res/textures/WALL_A_DARKER.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_A_DARKER.png
--------------------------------------------------------------------------------
/res/textures/WALL_A_DARKEST.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_A_DARKEST.png
--------------------------------------------------------------------------------
/res/textures/WALL_A_FOG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_A_FOG.png
--------------------------------------------------------------------------------
/res/textures/WALL_A_FOG_DARKER.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_A_FOG_DARKER.png
--------------------------------------------------------------------------------
/res/textures/WALL_A_FOG_DARKEST.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_A_FOG_DARKEST.png
--------------------------------------------------------------------------------
/res/textures/WALL_B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_B.png
--------------------------------------------------------------------------------
/res/textures/WALL_B_DARKER.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_B_DARKER.png
--------------------------------------------------------------------------------
/res/textures/WALL_B_DARKEST.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_B_DARKEST.png
--------------------------------------------------------------------------------
/res/textures/WALL_C.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_C.png
--------------------------------------------------------------------------------
/res/textures/WALL_C_DARKER.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_C_DARKER.png
--------------------------------------------------------------------------------
/res/textures/WALL_C_DARKEST.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/WALL_C_DARKEST.png
--------------------------------------------------------------------------------
/res/textures/doobguy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/doobguy.png
--------------------------------------------------------------------------------
/res/textures/sci-fi-wall-texture-atlas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/sci-fi-wall-texture-atlas.png
--------------------------------------------------------------------------------
/res/textures/sci-fi-wallc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/sci-fi-wallc.png
--------------------------------------------------------------------------------
/res/textures/sci-fi-wallc_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/sci-fi-wallc_dark.png
--------------------------------------------------------------------------------
/res/textures/sprites.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/sprites.png
--------------------------------------------------------------------------------
/res/textures/texture_atlas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/texture_atlas.png
--------------------------------------------------------------------------------
/res/textures/texture_atlas_sprite_palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/textures/texture_atlas_sprite_palette.png
--------------------------------------------------------------------------------
/res/two_light_levels_pal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/res/two_light_levels_pal.png
--------------------------------------------------------------------------------
/screen0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/screen0.png
--------------------------------------------------------------------------------
/screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/screen1.png
--------------------------------------------------------------------------------
/screen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/screen2.png
--------------------------------------------------------------------------------
/screen3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/screen3.png
--------------------------------------------------------------------------------
/src/NOTES:
--------------------------------------------------------------------------------
1 | NEED portal walls inserted into pvs when floor/ceil color or height changes. Otherwise they are unnecessary.
--------------------------------------------------------------------------------
/src/TODO.md:
--------------------------------------------------------------------------------
1 | # 3d view
2 |
3 | # -
4 |
5 | Wall lengths are CONSTANT!
6 | pre-calculate them, and determine how many times a texture repeats at map-build time.
7 | For now we use an efficient distance algorithm, but it's not ideal.
--------------------------------------------------------------------------------
/src/active_sectors.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "active_sectors.h"
3 | #include "portal_map.h"
4 | #include "utils.h"
5 |
6 |
7 | static u32* active_sectors;
8 |
9 | void init_active_sectors(u16 num_sect_groups) {
10 | // 64 bytes
11 | if(num_sect_groups > MAX_SECTOR_GROUPS) {
12 | die("Too many sector groups!");
13 | }
14 | active_sectors = malloc((num_sect_groups + (8-1))/8, "active_sector_bitmap");
15 | }
16 |
17 | void cleanup_active_sectors() {
18 | free(active_sectors, "active_sector_bitmap");
19 | }
20 |
21 | void register_sect_group_as_active(u16 sect_group) {
22 | u16 lw_index = sect_group>>5;
23 | u8 bit_index = sect_group & 0b111;
24 | active_sectors[lw_index] |= (1 << bit_index);
25 | }
26 |
27 | void register_sect_group_as_inactive(u16 sect_group) {
28 | u16 lw_index = sect_group>>5;
29 | u8 bit_index = sect_group & 0b111;
30 | active_sectors[lw_index] &= ~(1 << bit_index);
31 | }
32 |
33 |
34 | void iterate_active_sectors(active_sector_callback cb) {
35 | for(u16 lw_index = 0; lw_index < MAX_SECTOR_GROUPS/32; lw_index++) {
36 | u32 lw = active_sectors[lw_index];
37 | if(lw == 0) { continue; }
38 |
39 | u16 base_index = lw_index<<5;
40 |
41 | for(u32 bit_index = 0; bit_index < 32; bit_index++) {
42 | if(lw & (1<
5 |
6 | typedef void(*active_sector_callback)(u16 sect_group);
7 |
8 |
9 | void init_active_sectors(u16 num_sect_groups);
10 |
11 | void cleanup_active_sectors();
12 |
13 | void register_sect_group_as_active(u16 sect_group);
14 |
15 | void register_sect_group_as_inactive(u16 sect_group);
16 |
17 | void iterate_active_sectors(active_sector_callback cb);
18 |
19 | #endif
--------------------------------------------------------------------------------
/src/bob.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/bob.c
--------------------------------------------------------------------------------
/src/boot/rom_head.c:
--------------------------------------------------------------------------------
1 | #include "types.h"
2 |
3 | __attribute__((externally_visible))
4 | const struct
5 | {
6 | char console[16]; /* Console Name (16) */
7 | char copyright[16]; /* Copyright Information (16) */
8 | char title_local[48]; /* Domestic Name (48) */
9 | char title_int[48]; /* Overseas Name (48) */
10 | char serial[14]; /* Serial Number (2, 12) */
11 | u16 checksum; /* Checksum (2) */
12 | char IOSupport[16]; /* I/O Support (16) */
13 | u32 rom_start; /* ROM Start Address (4) */
14 | u32 rom_end; /* ROM End Address (4) */
15 | u32 ram_start; /* Start of Backup RAM (4) */
16 | u32 ram_end; /* End of Backup RAM (4) */
17 | char sram_sig[2]; /* "RA" for save ram (2) */
18 | u16 sram_type; /* 0xF820 for save ram on odd bytes (2) */
19 | u32 sram_start; /* SRAM start address - normally 0x200001 (4) */
20 | u32 sram_end; /* SRAM end address - start + 2*sram_size (4) */
21 | char modem_support[12]; /* Modem Support (24) */
22 | char notes[40]; /* Memo (40) */
23 | char region[16]; /* Country Support (16) */
24 | } rom_header = {
25 | "SEGA MEGA DRIVE ",
26 | "(C)FLEMTEAM 2013",
27 | "PORTAL_ENGINE ",
28 | "PORTAL_ENGINE ",
29 | "GM 00000000-00",
30 | 0x0000,
31 | "JD ",
32 | 0x00000000,
33 | 0x00100000,
34 | 0x00FF0000,
35 | 0x00FFFFFF,
36 | "RA",
37 | 0xE020,
38 | 0x00200000,
39 | 0x0027FFFF,
40 | " ",
41 | " ",
42 | "JUE "
43 | };
44 |
--------------------------------------------------------------------------------
/src/building_test_map.h:
--------------------------------------------------------------------------------
1 | #ifndef BUILDING_TEST_MAP_H
2 | #define BUILDING_TEST_MAP_H
3 |
4 | #include "portal_map.h"
5 |
6 | extern const portal_map building_test_map;
7 |
8 | #endif
--------------------------------------------------------------------------------
/src/bunch_render.h:
--------------------------------------------------------------------------------
1 | #ifndef BUNCH_RENDER_H
2 | #define BUNCH_RENDER_H
3 |
4 | #include
5 |
6 | void prepare_bunches(u16 src_sector, u32 cur_frame);
7 | //void draw_bunches();
8 | void draw_bunches(u16 src_sector, u32 cur_frame);
9 |
10 |
11 | #endif
--------------------------------------------------------------------------------
/src/clip_buf.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "clip_buf.h"
3 | #include "utils.h"
4 |
5 |
6 | clip_buf *clip_buffers;
7 |
8 | clip_buf* clip_buf_list_head = NULL;
9 |
10 | static int sp;
11 |
12 | void init_clip_buffer_list() {
13 | clip_buffers = malloc(sizeof(clip_buf) * NUM_CLIP_BUFS, "silhouette clip buffers");
14 | sp = 0;
15 | clip_buf_list_head = &clip_buffers[0];
16 | for(int i = 0; i < NUM_CLIP_BUFS; i++) {
17 | clip_buffers[i].id = i;
18 | }
19 | }
20 |
21 | void free_clip_buffer_list() {
22 | free(clip_buffers, "silhouette clip buffers");
23 | }
24 |
25 | clip_buf* alloc_clip_buffer() {
26 | //KLog("allocating clip buffer");
27 | if(sp >= NUM_CLIP_BUFS) {
28 | die("no more clip bufs");
29 | return NULL;
30 | }
31 | return &clip_buffers[sp++];
32 | }
33 |
34 | void free_clip_buffer(clip_buf* buf) {
35 | clip_buf* freed = &clip_buffers[--sp];
36 | //KLog("free clip buffer");
37 | if(freed != buf) {
38 | char sbuf[64];
39 | sprintf(sbuf, "Freed clip buffer %i but expected %i", buf->id, freed->id);
40 | die(sbuf);
41 | }
42 | }
--------------------------------------------------------------------------------
/src/clip_buf.h:
--------------------------------------------------------------------------------
1 | #ifndef CLIP_BUF_H
2 | #define CLIP_BUF_H
3 |
4 | #include
5 |
6 | // 128 bytes * 2 = 256 bytes
7 | #define NUM_CLIP_BUFS 16
8 | typedef struct clip_buf clip_buf;
9 |
10 | // we could be really fancy and create just one big buffer, and allocate chunks out of that as needed
11 | // but i doubt we'll ever want to draw four of these on top of each other
12 | struct clip_buf {
13 | u8 y_clip_buffer[128];
14 | u8 id;
15 | };
16 |
17 |
18 |
19 |
20 | void init_clip_buffer_list();
21 | void free_clip_buffer_list();
22 |
23 | clip_buf* clip_buffers;
24 |
25 | clip_buf* alloc_clip_buffer();
26 | void free_clip_buffer(clip_buf* buf);
27 |
28 |
29 | #endif
--------------------------------------------------------------------------------
/src/collision.h:
--------------------------------------------------------------------------------
1 | #ifndef COLLISION_H
2 | #define COLLISION_H
3 |
4 | #include
5 | #include "game.h"
6 |
7 | typedef struct {
8 | Vect2D_f32 pos;
9 | u16 new_sector;
10 | } collision_result;
11 |
12 | #define PLAYER_COLLISION_DISTANCE 20
13 | #define PLAYER_COLLISION_DISTANCE_SQR (PLAYER_COLLISION_DISTANCE*PLAYER_COLLISION_DISTANCE)
14 |
15 | collision_result check_for_collision(fix32 curx, fix32 cury, fix32 newx, fix32 newy, u16 cur_sector);
16 | collision_result check_for_collision_radius(fix32 curx, fix32 cury, fix32 curz, fix32 newx, fix32 newy, f32 radius_sqr, u16 cur_sector);
17 | u16 find_sector(player_pos cur_player_pos);
18 | s32 sq_shortest_dist_to_point(fix32 px, fix32 py, vertex a, vertex b);
19 |
20 | #endif
--------------------------------------------------------------------------------
/src/colors.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "colors.h"
3 |
4 |
5 | // #define PIX(p) ((p << 4) | p)
6 | // #define DPIX(p,q) ((p << 4) | q)
7 |
8 |
9 | #define BPIX(p) ((p << 4) | p)
10 |
11 | #define BDPIX(p,q) ((p << 4) | q)
12 |
13 | #define PIX(p) ((BPIX(p) << 24) | (BPIX(p) << 16) | (BPIX(p) << 8) | BPIX(p))
14 | #define DPIX(p,q) ((BDPIX(p,q) << 24) | (BDPIX(p,q) << 16) | (BDPIX(p,q) << 8) | BDPIX(p,q))
15 |
16 | // DISTANCE
17 | // LIGHT LEVEL NEAR FAR
18 | // 1 LIGHT LIGHT
19 | // 0 LIGHT DARK
20 | // -1 DARK DARK
21 |
22 | // LIGHT LEVEL
23 | // DISTANCE 1 0 -1
24 | // FAR LIGHT DARK DARK
25 | // NEAR LIGHT LIGHT DARK
26 |
27 | // dark dist is -2 brightness
28 | // mid dist is -1 brightness
29 | // -2 is negative 2, etc
30 |
31 | //split byte colors
32 | const u32 dither_color_calc_table[16*5*2] = {
33 | // far table
34 | // -2 light level
35 | 0, DPIX(10,10), DPIX(9,9), DPIX(9,9), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(10,10), DPIX(10,10), DPIX(10,10), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(15,15),
36 | // -1 light level
37 | 0, DPIX(9,10), DPIX(1,9), DPIX(2,9), DPIX(7,6), DPIX(5,6), DPIX(6,6), DPIX(7,6), DPIX(8,6), DPIX(11,10), DPIX(10,10), DPIX(11,10), DPIX(13,6), DPIX(13,6), DPIX(9,11), DPIX(15,15),
38 | // 0 light level
39 | 0, DPIX(9,9), DPIX(1,1), DPIX(2,2), DPIX(7,7), DPIX(5,6), DPIX(6,6), DPIX(7,6), DPIX(8,6), DPIX(11,11), DPIX(10,10), DPIX(11,10), DPIX(13,13), DPIX(13,6), DPIX(9,9), DPIX(15,15),
40 | // 1 light level
41 | 0, DPIX(1,1), DPIX(2,2), DPIX(3,3), DPIX(4,4), DPIX(5,5), DPIX(6,6), DPIX(7,7), DPIX(8,8), DPIX(9,9), DPIX(10,10), DPIX(11,11), DPIX(12,12), DPIX(13,13), DPIX(14,14), DPIX(15,15),
42 | // 2 light level
43 | 0, DPIX(3,3), DPIX(3,3), DPIX(3,3), DPIX(4,4), DPIX(13,13), DPIX(13,13), DPIX(4,4), DPIX(13,13), DPIX(3,3), DPIX(9,9), DPIX(9,9), DPIX(4,4), DPIX(4,4), DPIX(14,14), DPIX(15,15),
44 | // near table
45 | // -2 light level
46 | 0, DPIX(10,10), DPIX(9,9), DPIX(9,9), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(10,10), DPIX(10,10), DPIX(10,10), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(15,15),
47 | // -1 light level
48 | 0, DPIX(9,9), DPIX(1,1), DPIX(2,2), DPIX(7,7), DPIX(5,6), DPIX(6,6), DPIX(7,6), DPIX(8,6), DPIX(11,11), DPIX(10,10), DPIX(11,10), DPIX(13,13), DPIX(6,6), DPIX(9,9), DPIX(15,15),
49 | // 0 light level
50 | 0, DPIX(1,1), DPIX(2,2), DPIX(3,3), DPIX(4,4), DPIX(5,5), DPIX(6,6), DPIX(7,7), DPIX(8,8), DPIX(9,9), DPIX(10,10), DPIX(11,11), DPIX(12,12), DPIX(13,13), DPIX(14,14), DPIX(15,15),
51 | // 1 light level
52 | 0, DPIX(2,2), DPIX(3,2), DPIX(3,2), DPIX(4,4), DPIX(13,5), DPIX(5,5), DPIX(4,7), DPIX(5,5), DPIX(2,2), DPIX(11,11), DPIX(9,11), DPIX(4,12), DPIX(12,12), DPIX(14,14), DPIX(15,15),
53 | // 2 light level
54 | 0, DPIX(3,3), DPIX(3,3), DPIX(3,3), DPIX(4,4), DPIX(13,13), DPIX(13,13), DPIX(4,4), DPIX(13,13), DPIX(3,3), DPIX(9,9), DPIX(9,9), DPIX(4,4), DPIX(4,4), DPIX(14,14), DPIX(15,15),
55 | };
56 |
57 |
58 | const u32 no_dither_color_calc_table[16*5*2] = {
59 | // far table
60 | // -2 light level
61 | 0, DPIX(10,10), DPIX(9,9), DPIX(9,9), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(10,10), DPIX(10,10), DPIX(10,10), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(15,15),
62 | // -1 light level
63 | 0, DPIX(10,10), DPIX(9,9), DPIX(9,9), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(10,10), DPIX(10,10), DPIX(10,10), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(15,15),
64 | // 0 light level
65 | 0, DPIX(9,9), DPIX(1,1), DPIX(2,2), DPIX(7,7), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(10,10), DPIX(10,10), DPIX(13,13), DPIX(6,6), DPIX(9,9), DPIX(15,15),
66 | // 1 light level
67 | 0, DPIX(1,1), DPIX(2,2), DPIX(3,3), DPIX(4,4), DPIX(5,5), DPIX(6,6), DPIX(7,7), DPIX(8,8), DPIX(9,9), DPIX(10,10), DPIX(11,11), DPIX(12,12), DPIX(13,13), DPIX(14,14), DPIX(15,15),
68 | // 2 light level
69 | 0, DPIX(3,3), DPIX(3,3), DPIX(3,3), DPIX(4,4), DPIX(13,13), DPIX(13,13), DPIX(4,4), DPIX(13,13), DPIX(3,3), DPIX(9,9), DPIX(9,9), DPIX(4,4), DPIX(4,4), DPIX(14,14), DPIX(15,15),
70 | // near table
71 | // -2 light level
72 | 0, DPIX(10,10), DPIX(9,9), DPIX(9,9), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(10,10), DPIX(10,10), DPIX(10,10), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(15,15),
73 | // -1 light level
74 | 0, DPIX(9,9), DPIX(1,1), DPIX(2,2), DPIX(7,7), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(6,6), DPIX(11,11), DPIX(10,10), DPIX(10,10), DPIX(13,13), DPIX(6,6), DPIX(9,9), DPIX(15,15),
75 | // 0 light level
76 | 0, DPIX(1,1), DPIX(2,2), DPIX(3,3), DPIX(4,4), DPIX(5,5), DPIX(6,6), DPIX(7,7), DPIX(8,8), DPIX(9,9), DPIX(10,10), DPIX(11,11), DPIX(12,12), DPIX(13,13), DPIX(14,14), DPIX(15,15),
77 | // 1 light level
78 | 0, DPIX(2,2), DPIX(3,3), DPIX(3,3), DPIX(4,4), DPIX(13,13), DPIX(5,5), DPIX(4,4), DPIX(5,5), DPIX(2,2), DPIX(11,11), DPIX(9,9), DPIX(12,12), DPIX(12,12), DPIX(14,14), DPIX(15,15),
79 | // 2 light level
80 | 0, DPIX(3,3), DPIX(3,3), DPIX(3,3), DPIX(4,4), DPIX(13,13), DPIX(13,13), DPIX(4,4), DPIX(13,13), DPIX(3,3), DPIX(9,9), DPIX(9,9), DPIX(4,4), DPIX(4,4), DPIX(14,14), DPIX(15,15),
81 | };
82 |
83 |
84 | u8 dither_enabled = 0;
85 | u32* color_calc_table = (u32*)no_dither_color_calc_table;
86 |
87 | void toggle_dither_mode() {
88 | if(dither_enabled) {
89 | dither_enabled = 0;
90 | color_calc_table = (u32*)no_dither_color_calc_table;
91 | } else {
92 | dither_enabled = 1;
93 | color_calc_table = (u32*)dither_color_calc_table;
94 | }
95 | }
96 |
97 |
98 | void init_color_table() {
99 | if(dither_enabled) {
100 | color_calc_table = dither_color_calc_table;
101 | } else {
102 | color_calc_table = no_dither_color_calc_table;
103 | }
104 | }
105 |
106 | // 960 bytes
107 |
108 | u32 get_dark_color(u8 col_idx, s8 light_level) {
109 | u16 light_off = (light_level+2)<<4;
110 | return color_calc_table[light_off+col_idx];
111 | }
112 |
113 | //inline u32 get_mid_dark_color(u8 col_idx, s8 light_level) {
114 | // u16 light_off = (light_level+1)<<4;
115 | // u16 dist_off = (16*5);
116 | // return color_calc_table[light_off+dist_off+col_idx];
117 | //}
118 |
119 | u32 get_light_color(u8 col_idx, s8 light_level) {
120 | u16 light_off = (light_level+2)<<4;
121 | //u16 dist_off = (16*5*2);
122 | u16 dist_off = (16*5);
123 | return color_calc_table[light_off+dist_off+col_idx];
124 | }
125 |
--------------------------------------------------------------------------------
/src/colors.h:
--------------------------------------------------------------------------------
1 | #ifndef COLORS_H
2 | #define COLORS_H
3 |
4 | #include
5 |
6 | #define NEAR_DIST 50
7 | #define FIX_0_16_INV_NEAR_DIST (65536/NEAR_DIST)
8 | #define MID_DIST 150
9 | #define FIX_0_16_INV_MID_DIST (65536/MID_DIST)
10 | #define MID_DARK_DIST 250
11 | #define FIX_0_16_INV_MID_DARK_DIST (65536/MID_DARK_DIST)
12 | #define DARK_DIST 350
13 | #define FIX_0_16_INV_DARK_DIST (65536/DARK_DIST)
14 | #define FADE_DIST 400
15 | #define FIX_0_16_INV_FADE_DIST (65536/FADE_DIST)
16 |
17 | extern u8 dither_enabled;
18 |
19 | #define TRANSPARENT_IDX 0x0
20 | #define LIGHT_YELLOW_IDX 0x1
21 | #define LIGHT_BLUE_IDX 0x2
22 | #define LIGHT_GREEN_IDX 0x3
23 | #define LIGHT_RED_IDX 0x4
24 | #define LIGHT_PURPLE_IDX 0x5
25 | #define LIGHT_STEEL_IDX 0x6
26 | #define YELLOW_IDX 0x7
27 | #define BLUE_IDX 0x8
28 | #define GREEN_IDX 0x9
29 | #define RED_IDX 0xA
30 | #define PURPLE_IDX 0xB
31 | #define STEEL_IDX 0xC
32 | #define DARK_YELLOW_IDX 0xD
33 | #define DARK_BLUE_IDX 0xE
34 | #define BLACK_IDX 0xF
35 |
36 |
37 | //u32 get_dark_color(u8 col_idx, s8 light_level);
38 | //u32 get_mid_dark_color(u8 col_idx, s8 light_level);
39 | //u32 get_light_color(u8 col_idx, s8 light_level);
40 |
41 | //extern const u32 color_calc_table[16*3*2];
42 | //extern const u32 *color_calc_table; //[16*5*2];
43 |
44 | extern const u32 long_color_table[16];
45 |
46 | u32 get_dark_color(u8 col_idx, s8 light_level);
47 | u32 get_light_color(u8 col_idx, s8 light_level);
48 |
49 | void init_color_table();
50 | void toggle_dither_mode();
51 |
52 | #endif
--------------------------------------------------------------------------------
/src/config.h:
--------------------------------------------------------------------------------
1 | #ifndef CONFIG_H
2 | #define CONFIG_H
3 |
4 | //#define H32_MODE
5 | //#define RAM_TEXTURE
6 | #endif
--------------------------------------------------------------------------------
/src/console.h:
--------------------------------------------------------------------------------
1 | #ifndef CONSOLE_H
2 | #define CONSOLE_H
3 |
4 | #include
5 |
6 | uint16_t console_init(uint16_t start_addr);
7 | void console_tick();
8 | void console_cleanup();
9 | void console_push_message(char* msg, int len, uint16_t ticks);
10 | void console_push_message_high_priority(char* msg, int len, uint16_t ticks);
11 |
12 | #endif
--------------------------------------------------------------------------------
/src/div_lut.h:
--------------------------------------------------------------------------------
1 | #ifndef DIV_LUT_H
2 | #define DIV_LUT_H
3 |
4 | #include
5 |
6 | extern const u32 z_recip_table_32[4096];
7 | extern const u16 z_recip_table_16[4096];
8 | extern const u32 z_12_4_to_one_over_z_26[65536];
9 | #endif
--------------------------------------------------------------------------------
/src/draw.h:
--------------------------------------------------------------------------------
1 | #ifndef DRAW_H
2 | #define DRAW_H
3 |
4 | #include
5 | #include "clip_buf.h"
6 | #include "obj_sprite.h"
7 | #include "object.h"
8 | #include "texture.h"
9 | #include "vertex.h"
10 |
11 | #define WALLS_DIST_LIGHTING
12 | #define FLATS_DIST_LIGHTING
13 |
14 |
15 | typedef struct {
16 | u8 x;
17 | u8 y0;
18 | u8 y1;
19 | u8 clip_y0;
20 | u8 clip_y1;
21 | Bitmap *bmp;
22 | } col_params;
23 |
24 | extern int debug_draw_cleared;
25 |
26 |
27 | //void draw_native_vertical_line_unrolled(s16 y0, s16 y1, u8 col, u8* col_ptr);
28 | void draw_native_double_vertical_line_unrolled(s16 y0, s16 y1, s16 y2, u32 full_col1, u32 full_col2, u8* col_ptr);
29 | void draw_native_vertical_line_unrolled(s16 y0, s16 y1, u32 full_col, u8* col_ptr);
30 | void copy_2d_buffer(u16 left, u16 right, clip_buf* dest);
31 | void draw_native_vertical_transparent_line_unrolled(s16 y0, s16 y1, u8 col, u8* col_ptr, u8 odd);
32 |
33 |
34 | typedef struct {
35 | u8 needs_lighting;
36 | u8 mid_y;
37 | u8 dark_y;
38 | u8 fade_y;
39 | u32 light_color;
40 | u32 mid_color;
41 | u32 dark_color;
42 | } light_params;
43 |
44 | void clear_light_cache();
45 | void cache_floor_light_params(s16 rel_floor_height, u8 floor_col, s8 light_level, light_params* params);
46 | void cache_ceil_light_params(s16 rel_ceil_height, u8 ceil_col, s8 light_level, light_params* params);
47 |
48 | void draw_solid_color_wall(s16 x1, s16 x1_ytop, s16 x1_ybot,
49 | s16 x2, s16 x2_ytop, s16 x2_ybot,
50 | u16 inv_z1, u16 inv_z2,
51 | u16 window_min, u16 window_max, s8 light_level,
52 | u8 wall_color,
53 | light_params* floor_params, light_params* ceil_params);
54 |
55 | void draw_wall(s16 x1, s16 x1_ytop, s16 x1_ybot,
56 | s16 x2, s16 x2_ytop, s16 x2_ybot,
57 | u16 z1, u16 z2,
58 | u16 inv_z1, u16 inv_z2,
59 | u16 window_min, u16 window_max, s8 light_level,
60 | texmap_params* tmap_info,
61 | light_params* floor_params, light_params* ceil_params);
62 |
63 |
64 | void draw_wireframe_wall(
65 | s16 x1, s16 x1_ytop, s16 x1_ybot,
66 | s16 x2, s16 x2_ytop, s16 x2_ybot,
67 | u16 window_min, u16 window_max);
68 | void draw_wireframe_lower_step(
69 | s16 x1, s16 x1_ytop, s16 x1_ybot,
70 | s16 x2, s16 x2_ytop, s16 x2_ybot,
71 | u16 window_min, u16 window_max);
72 |
73 |
74 | void draw_top_pegged_wall(s16 x1, s16 x1_ytop, s16 x1_ybot,
75 | s16 x2, s16 x2_ytop, s16 x2_ybot,
76 | u16 z1_12_4, u16 z2_12_4,
77 | u16 inv_z1, u16 inv_z2,
78 | u16 window_min, u16 window_max, s8 light_level,
79 | texmap_params *tmap_info,
80 | light_params* floor_params, light_params* ceil_params,
81 | s16 x1_pegged_top, s16 x2_pegged_top);
82 |
83 | void draw_bot_pegged_wall(s16 x1, s16 x1_ytop, s16 x1_ybot,
84 | s16 x2, s16 x2_ytop, s16 x2_ybot,
85 | u16 z1_12_4, u16 z2_12_4,
86 | u16 inv_z1, u16 inv_z2,
87 | u16 window_min, u16 window_max, s8 light_level,
88 | texmap_params* tmap_info,
89 | light_params* floor_params, light_params* ceil_params,
90 | s16 x1_pegged_top, s16 x2_pegged_top);
91 |
92 | void draw_top_pegged_textured_upper_step(s16 x1, s16 x1_ytop, s16 nx1_ytop, s16 x2, s16 x2_ytop, s16 nx2_ytop,
93 | u16 z1_12_4, u16 z2_12_4,
94 | u16 inv_z1, u16 inv_z2,
95 | u16 window_min, u16 window_max, s8 light_level,
96 | texmap_params* tmap_info, light_params* params,
97 | s16 x1_pegged_top, s16 x2_pegged_top);
98 |
99 | void draw_upper_step(s16 x1, s16 x1_ytop, s16 nx1_ytop, s16 x2, s16 x2_ytop, s16 nx2_ytop,
100 | u16 inv_z1, u16 inv_z2,
101 | u16 window_min, u16 window_max, u8 upper_color, s8 light_level, light_params* params);
102 |
103 | void draw_ceiling_update_clip(s16 x1, s16 x1_ytop, s16 x2, s16 x2_ytop,
104 | u16 far_inv_z,
105 | u16 window_min, u16 window_max, light_params* params);
106 |
107 |
108 | void draw_bottom_pegged_textured_lower_step(s16 x1, s16 x1_ybot, s16 nx1_ybot, s16 x2, s16 x2_ybot, s16 nx2_ybot,
109 | u16 z1_12_4, u16 z2_12_4,
110 | u16 inv_z1, u16 inv_z2,
111 | u16 window_min, u16 window_max, s8 light_level,
112 | texmap_params* tmap_info, light_params* params,
113 | s16 x1_pegged_bot, s16 x2_pegged_bot);
114 |
115 | void draw_lower_step(s16 x1, s16 x1_ybot, s16 nx1_ybot, s16 x2, s16 x2_ybot, s16 nx2_ybot,
116 | u16 inv_z1, u16 inv_z2,
117 | u16 window_min, u16 window_max, u8 lower_color, s8 light_level, light_params* params);
118 |
119 | void draw_floor_update_clip(s16 x1, s16 x1_ybot, s16 x2, s16 x2_ybot,
120 | u16 far_inv_z,
121 | u16 window_min, u16 window_max, light_params* params);
122 |
123 |
124 | void init_sprite_draw_cache();
125 |
126 |
127 | extern obj_type drawn_to_center_cols;
128 | extern object_link sprite_on_center_col;
129 | extern u16 center_object_sector;
130 |
131 | // reset whether a sprite was drawn to the center of the screen
132 | void reset_sprite_hit_info();
133 |
134 | void draw_rle_sprite(s16 x1, s16 x2, s16 ytop, s16 ybot,
135 | u16 window_min, u16 window_max,
136 | clip_buf* clipping_buffer,
137 | const rle_sprite* obj,
138 | object_link obj_link, obj_type obj_type, u16 sector);
139 |
140 | void draw_forcefield(s16 x1, s16 x2,
141 | u16 window_min, u16 window_max,
142 | clip_buf* clipping_buffer,
143 | u8 wall_col);
144 |
145 |
146 | void clear_2d_buffers();
147 | void init_2d_buffers();
148 | void release_2d_buffers();
149 |
150 |
151 |
152 |
153 | #endif
--------------------------------------------------------------------------------
/src/editor_test_map.h:
--------------------------------------------------------------------------------
1 | #ifndef EDITOR_TEST_MAP
2 | #define EDITOR_TEST_MAP
3 |
4 | #include "portal_map.h"
5 |
6 |
7 | extern const portal_map editor_test_map;
8 |
9 | #endif
--------------------------------------------------------------------------------
/src/fire.h:
--------------------------------------------------------------------------------
1 | #ifndef FIRE_H
2 | #define FIRE_H
3 |
4 | #include "game_mode.h"
5 |
6 |
7 | void init_fire();
8 | game_mode run_fire();
9 | void cleanup_fire();
10 |
11 |
12 | #endif
--------------------------------------------------------------------------------
/src/fire_tables.py:
--------------------------------------------------------------------------------
1 | NUM_PIX = 2
2 | NUM_BITS = NUM_PIX+1
3 |
4 | def rel_dst_for_bits(bits):
5 | tbl = [-1,0,1,2]
6 | return tbl[bits]
7 |
8 | def use_tbl_for_bits(bits):
9 | return bits > 0
10 |
11 |
12 | def tbl_lookup(name, bits, is_left_side=False):
13 | if bits > 0:
14 | if is_left_side:
15 | return "table_{}_shift[{}]".format(bits-1, name)
16 | else:
17 | return "table_{}[{}]".format(bits-1,name)
18 | else:
19 | return name
20 |
21 | def compile_routine(bits):
22 | dsts = {}
23 |
24 | for i in range(NUM_PIX):
25 | pix_bits = ((0b11<>i
26 | rel_dst = rel_dst_for_bits(pix_bits)
27 | abs_dst = rel_dst + i
28 | dsts[abs_dst] = (i, pix_bits)
29 |
30 | reads = {}
31 | writes = {}
32 | code = []
33 | for write_off,(read_off,bits) in dsts.items():
34 | name = 'fire_{}'.format(read_off, write_off)
35 | reads[read_off] = (name, bits)
36 | writes[write_off] = (name,bits)
37 |
38 | cur_read_off = 0
39 | for read_off, (name,bits) in reads.items():
40 | if cur_read_off < read_off:
41 | change = read_off - cur_read_off
42 | code.append('src_ptr += {};'.format(change))
43 | cur_read_off += change
44 | code.append('{} = *src_ptr++;'.format(name))
45 | cur_read_off += 1
46 |
47 |
48 | cur_write_off = 0
49 | wrote_aligned = False
50 |
51 | for write_off,(name,bits) in writes.items():
52 | if wrote_aligned:
53 | wrote_aligned = False
54 | continue
55 |
56 | aligned = (write_off&0b1 == 0)
57 | sibling = write_off+1 in writes
58 |
59 | if cur_write_off < write_off:
60 | if write_off > NUM_PIX:
61 | diff = write_off - cur_write_off
62 | tbl_var = tbl_lookup(name, bits)
63 | code.append('*(dst_ptr-{}) = {};'.format(diff, tbl_var))
64 | continue
65 | else:
66 | change = write_off - cur_write_off
67 | code.append('dst_ptr += {};'.format(change))
68 | cur_write_off += change
69 | if aligned and sibling:
70 | sibling_name,sibling_bits = writes[write_off+1]
71 | tbl_var = tbl_lookup(name, bits, True)
72 | sibling_tbl_var = tbl_lookup(sibling_name, sibling_bits)
73 | code.append("*((u16*)dst_ptr) = {}|{};".format(tbl_var, sibling_tbl_var))
74 | wrote_aligned = True
75 | else:
76 | tbl_var = tbl_lookup(name, bits)
77 | if write_off < cur_write_off:
78 | diff = cur_write_off - write_off
79 | code.append("*(dst_ptr-{}) = {};".format(diff, tbl_var))
80 | else:
81 | if cur_write_off >= NUM_PIX:
82 | code.append("*dst_ptr = {};".format(tbl_var))
83 | else:
84 | code.append("*dst_ptr++ = {};".format(tbl_var))
85 | cur_write_off += 1
86 |
87 |
88 |
89 | if cur_read_off != NUM_PIX:
90 | change = NUM_PIX - cur_read_off
91 | code.append("src_ptr += {};".format(change))
92 |
93 | if cur_write_off != NUM_PIX:
94 | change = NUM_PIX - cur_write_off
95 | code.append("dst_ptr += {};".format(change))
96 |
97 | return code
98 |
99 |
100 |
101 | def compile_switch():
102 | code = ["switch(rand_bits & 0b{})".format('1'*NUM_BITS) + " {"]
103 |
104 | for bits in range(2**NUM_BITS):
105 | code.append(" case {}:".format(bits))
106 | for line in compile_routine(bits):
107 | code.append(" {}".format(line))
108 | code.append(" break;")
109 |
110 | code.append("}")
111 | return "\n".join(code)
112 |
--------------------------------------------------------------------------------
/src/game.h:
--------------------------------------------------------------------------------
1 | #ifndef GAME_H
2 | #define GAME_H
3 |
4 | #include
5 | #include "draw.h"
6 | #include "game_mode.h"
7 | #include "object.h"
8 | #include "vertex.h"
9 |
10 | extern int cur_frame;
11 |
12 | extern u32 last_frame_ticks;
13 | extern u16 rot_speed;
14 | extern u32 move_speed;
15 |
16 | extern u8* bmp_buffer_0;
17 | extern u8* bmp_buffer_1;
18 |
19 | extern Vect2D_f32 *sector_centers;
20 |
21 | extern player_pos cur_player_pos;
22 | extern fix16 playerXFrac4;
23 | extern fix16 playerYFrac4;
24 | extern s16 playerZCam12Frac4;
25 |
26 | #define ANGLE_360_DEGREES 1024
27 | #define ANGLE_180_DEGREES 512
28 | #define ANGLE_90_DEGREES 256
29 | // 58 degrees from player viewpoint to top left of map
30 | #define ANGLE_58_DEGREES 164
31 |
32 | #define RENDER_WIDTH 64
33 |
34 |
35 | extern fix32 angleCos32;
36 | extern fix32 angleSin32;
37 | extern fix16 angleCos16;
38 | extern fix16 angleSin16;
39 | extern s16 angleSinFrac12;
40 | extern s16 angleCosFrac12;
41 | extern s16 playerXInt;
42 | extern s16 playerYInt;
43 |
44 |
45 | void init_game();
46 | game_mode run_game();
47 | void cleanup_game();
48 |
49 | void request_flip();
50 |
51 | extern u8 render_mode;
52 |
53 | typedef enum {
54 | RENDER_SOLID,
55 | RENDER_WIREFRAME
56 | } render_modes;
57 |
58 | #endif
--------------------------------------------------------------------------------
/src/game_mode.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "fire.h"
3 | #include "game.h"
4 | #include "game_mode.h"
5 | #include "main_menu.h"
6 |
7 | void print_invalid_mode();
8 |
9 | mode modes[7] = {
10 | {.name = "invalid mode", .start_up = &print_invalid_mode},
11 | {.name = "invalid mode", .start_up = &print_invalid_mode},
12 | {.name = "INTRO", .start_up = &init_fire, .clean_up = &cleanup_fire, .run = &run_fire},
13 | {.name = "MAIN_MENU", .start_up = &init_main_menu, .clean_up = &cleanup_main_menu, .run = &run_main_menu},
14 | {.name = "IN_GAME", .start_up = &init_game, .clean_up = &cleanup_game, .run = &run_game},
15 | {.name = "PAUSE_MENU", .start_up = &print_invalid_mode},
16 | {.name = "CREDITS", .start_up = &print_invalid_mode},
17 | };
18 |
19 | game_mode cur_game_mode;
20 |
21 | void print_invalid_mode() {
22 | char buf[32];
23 | sprintf(buf, "Invalid mode %i/'%s'", cur_game_mode, modes[cur_game_mode].name);
24 | while(1) {
25 | VDP_drawText(buf, 10, 10);
26 | }
27 | }
28 |
29 |
30 | void set_game_mode(game_mode md) {
31 | if(md != RESET_MODE) {
32 | cur_game_mode = md;
33 | }
34 | KLog("going to game mode: ");
35 | KLog(modes[cur_game_mode].name);
36 | modes[cur_game_mode].start_up();
37 | }
38 |
39 | void run_game_mode() {
40 |
41 | game_mode next_mode = modes[cur_game_mode].run();
42 |
43 | if(next_mode != SAME_MODE) {
44 | modes[cur_game_mode].clean_up();
45 | set_game_mode(next_mode);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/game_mode.h:
--------------------------------------------------------------------------------
1 | #ifndef GAME_MODE_H
2 | #define GAME_MODE_H
3 |
4 |
5 | typedef enum {
6 | SAME_MODE=0,
7 | RESET_MODE=1,
8 | INTRO=2,
9 | MAIN_MENU=3,
10 | IN_GAME=4,
11 | PAUSE_MENU=5,
12 | CREDITS=6
13 | } game_mode;
14 |
15 |
16 | typedef struct {
17 | char* name;
18 | void (*start_up)();
19 | game_mode (*run)();
20 | void (*clean_up)();
21 | } mode;
22 |
23 | extern game_mode cur_game_mode;
24 | void run_game_mode();
25 | void set_game_mode(game_mode md);
26 |
27 | #endif
--------------------------------------------------------------------------------
/src/imgui.ini:
--------------------------------------------------------------------------------
1 | [Window][Map]
2 | Pos=0,0
3 | Size=1280,800
4 | Collapsed=0
5 |
6 | [Window][Debug##Default]
7 | Pos=60,60
8 | Size=400,400
9 | Collapsed=0
10 |
11 | [Window][Tools]
12 | Pos=823,154
13 | Size=420,536
14 | Collapsed=0
15 |
16 |
--------------------------------------------------------------------------------
/src/init.c:
--------------------------------------------------------------------------------
1 | #include "genesis.h"
2 |
3 | const u32 start_in_game_arr[2] = {
4 | 0xFEEDBEEF,
5 | 0
6 | };
7 | int init_load_level = 0;
8 |
9 | const int instant_load_level_array[2] = {
10 | 0xBEEFFEED,
11 | 0
12 | };
--------------------------------------------------------------------------------
/src/init.h:
--------------------------------------------------------------------------------
1 | #ifndef INIT_H
2 | #define INIT_H
3 |
4 |
5 | extern const u32 start_in_game_arr[2];
6 |
7 | extern int init_load_level;
8 |
9 | extern const int instant_load_level_array[2];
10 |
11 | #endif
--------------------------------------------------------------------------------
/src/inventory.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "hud.h"
3 | #include "inventory.h"
4 | #include "utils.h"
5 |
6 | #define MAX_ITEMS 8
7 |
8 |
9 | static int num_items;
10 | static int dirty;
11 |
12 | static u16 hud_tile_loc;
13 |
14 | static u8 *inventory;
15 |
16 | static u16 *item_vram_addresses; //[NUM_ITEM_TYPES];
17 |
18 | #define HUD_BASE_Y 21
19 |
20 | int inventory_full() {
21 | return (num_items == MAX_ITEMS);
22 | }
23 |
24 | int inventory_add_item(item_type item) {
25 | if(inventory_full()) {
26 | return 0;
27 | }
28 | inventory[num_items++] = item;
29 | KLog_U1("added item to index: ", num_items-1);
30 | dirty = 1;
31 | return 1;
32 | }
33 |
34 | int inventory_has_item(item_type item) {
35 | for(int i = 0; i < num_items; i++) {
36 | if(inventory[i] == item) { return 1; }
37 | }
38 | return 0;
39 | }
40 |
41 |
42 |
43 | void inventory_draw() {
44 | if(!dirty) {
45 | return;
46 | }
47 |
48 |
49 |
50 | int ix,iy;
51 | ix = 0;
52 | iy = 0;
53 | for(int i = 0; i < num_items; i++) {
54 | u16 tile_addr = item_vram_addresses[inventory[i]];
55 |
56 |
57 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(2, 1, 0, 0, tile_addr),
58 | ix*2+2, HUD_BASE_Y+2+iy);
59 | ix++;
60 | if(ix >= 5) {
61 | iy++;
62 | ix = 0;
63 | }
64 | }
65 | dirty = 0;
66 | }
67 |
68 |
69 |
70 | void inventory_reset() {
71 | num_items = 0;
72 | //inventory[0] = HEALTH_RECHARGE;
73 | //inventory[1] = ARMOR_CHARGE;
74 | //inventory[2] = ARMOR_CHARGE;
75 | //inventory[3] = SHIELD_CHARGE;
76 | //inventory[4] = BULLET_CHARGE;
77 | dirty = 1;
78 | }
79 |
80 | u32 load_item(const Image* img, item_type type, u32 tile_loc) {
81 | VDP_loadTileSet(img->tileset, tile_loc, CPU);
82 | item_vram_addresses[type] = tile_loc;
83 | tile_loc += img->tileset->numTile;
84 | return tile_loc;
85 | }
86 |
87 | u32 load_inventory_items_to_vram(u32 tile_loc) {
88 | hud_tile_loc = tile_loc;
89 | VDP_loadTileSet(hud.tileset, hud_tile_loc, DMA);
90 |
91 | PAL_setPalette(PAL2, hud.palette->data);
92 | tile_loc += hud.tileset->numTile;
93 |
94 | tile_loc = load_item(&armor_inv, ARMOR_CHARGE, tile_loc);
95 | tile_loc = load_item(&blue_key_inv, BLUE_KEY, tile_loc);
96 | tile_loc = load_item(&red_key_inv, RED_KEY, tile_loc);
97 | tile_loc = load_item(&green_key_inv, GREEN_KEY, tile_loc);
98 | tile_loc = load_item(&bullet_inv, BULLET_CHARGE, tile_loc);
99 | tile_loc = load_item(&heart_inv, HEALTH_RECHARGE, tile_loc);
100 | tile_loc = load_item(&shield_inv, SHIELD_CHARGE, tile_loc);
101 |
102 |
103 | return tile_loc;
104 |
105 | }
106 |
107 | u32 inventory_init(u32 free_tile_loc) {
108 | inventory = malloc(sizeof(u8) * MAX_ITEMS, "inventory table");
109 |
110 | item_vram_addresses = malloc(sizeof(u16) * NUM_ITEM_TYPES, "inventory item vram addr table");
111 | u32 new_free_tile_loc = load_inventory_items_to_vram(free_tile_loc);
112 |
113 | for(int y = 0; y < hud.tilemap->h; y++) {
114 | u16 y_off = y * hud.tilemap->w;
115 | for(int x = 0; x < hud.tilemap->w; x++) {
116 | u16 tile_attr = hud.tilemap->tilemap[y_off+x];
117 | tile_attr += hud_tile_loc;
118 | tile_attr |= (1<
5 |
6 | typedef enum {
7 | RED_KEY,
8 | GREEN_KEY,
9 | BLUE_KEY,
10 | SPEED_UP,
11 | POWER_UP,
12 | HEALTH_RECHARGE,
13 | SHIELD_CHARGE,
14 | BULLET_CHARGE,
15 | ARMOR_CHARGE,
16 | } item_type;
17 |
18 | #define NUM_ITEM_TYPES 9
19 |
20 | void inventory_draw();
21 | void inventory_reset();
22 | int inventory_add_item(item_type item);
23 | int inventory_full();
24 | int inventory_has_item(item_type item);
25 | void inventory_use_item(item_type item);
26 |
27 |
28 | u32 inventory_init(u32 free_tile_loc);
29 | void inventory_cleanup();
30 |
31 | #endif
--------------------------------------------------------------------------------
/src/joy_helper.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | static u16 last_joy = 0;
4 |
5 |
6 | int joy_button_newly_pressed(u16 button) {
7 | return (JOY_readJoypad(JOY_1) & button & (~last_joy) & button);
8 | }
9 |
10 | int joy_button_held(u16 button) {
11 | return (JOY_readJoypad(JOY_1) & last_joy & button);
12 | }
13 |
14 | int joy_button_pressed(u16 button) {
15 | return (JOY_readJoypad(JOY_1) & button);
16 | }
17 |
18 | void update_joy() {
19 | last_joy = JOY_readJoypad(JOY_1);
20 | }
--------------------------------------------------------------------------------
/src/joy_helper.h:
--------------------------------------------------------------------------------
1 | #ifndef JOY_HELPER_H
2 | #define JOY_HELPER_H
3 |
4 | #include
5 |
6 |
7 | int joy_button_pressed(u16 button);
8 | int joy_button_newly_pressed(u16 button);
9 | int joy_button_held(u16 button);
10 |
11 | void update_joy();
12 |
13 |
14 |
15 | #endif
--------------------------------------------------------------------------------
/src/js/pvs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PVS construction
5 |
6 |
7 |
8 | PVS construction test
9 | Construct PVS for Sector
10 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/level.h:
--------------------------------------------------------------------------------
1 | #ifndef LEVEL_H
2 | #define LEVEL_H
3 |
4 | #include "portal_map.h"
5 |
6 | extern portal_map* cur_portal_map;
7 |
8 |
9 |
10 | void load_portal_map(portal_map* l);
11 | void clean_portal_map();
12 | // returns 1 if a switch or door was triggered, else 0
13 | int check_trigger_switch(player_pos* pos);
14 |
15 | #endif
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "game_mode.h"
4 | #include "joy_helper.h"
5 |
6 | #include "my_bmp.h"
7 |
8 | #include "init.h"
9 |
10 |
11 | int main() {
12 | VDP_init();
13 | MEM_pack();
14 | KLog_U1("allocated mem at start: ", MEM_getAllocated());
15 |
16 | KLog_U1("free bytes of ram at startup: ", MEM_getFree());
17 | volatile u32* vp_start_in_game_arr = start_in_game_arr;
18 | u16 startup_joy = JOY_readJoypad(JOY_1);
19 | u8 bypass_autoload = (startup_joy & BUTTON_START);
20 |
21 | if(vp_start_in_game_arr[1] && !bypass_autoload) {
22 | // i don't know why this is required, I guess some VRAM remapping or something
23 | // without it, fps display doesn't work in-game
24 | // such a dumb hack
25 |
26 | // basically, it works if you run the INTRO fire mode, which calls these functions
27 | //bmp_init_horizontal(0, BG_A, PAL1, 0);
28 | //bmp_end();
29 | //MEM_pack();
30 | DMA_setBufferSize(2048);
31 | set_game_mode(IN_GAME);
32 | } else {
33 | set_game_mode(INTRO);
34 | }
35 |
36 | while(1) {
37 |
38 | update_joy();
39 |
40 | run_game_mode();
41 |
42 | }
43 | return (0);
44 | }
45 |
--------------------------------------------------------------------------------
/src/main_menu.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "colors.h"
3 | #include "game.h"
4 | #include "game_mode.h"
5 | #include "init.h"
6 | #include "menu_helper.h"
7 | #include "portal_map.h"
8 | #include "sfx.h"
9 | #include "music.h"
10 |
11 | static int launch_new_mode = 0;
12 | game_mode target_mode;
13 |
14 | void go_to_credits() {
15 | launch_new_mode = 1;
16 | target_mode = CREDITS;
17 | }
18 |
19 | void go_to_new_game() {
20 | launch_new_mode = 1;
21 | target_mode = IN_GAME;
22 | }
23 |
24 |
25 | #define TEXT_ITEM(str) {.text = (str), .submenu = NULL, .select = NULL, .render = NULL, .selectable = 0}
26 |
27 | const menu load_game_menu = {
28 | .header_text = "Load game",
29 | .num_items = 1,
30 | .items = {
31 | TEXT_ITEM("No saves found")
32 | }
33 | };
34 |
35 | #include "map_table.h"
36 |
37 | void select_map(int menu_idx) {
38 | launch_new_mode = 1;
39 | init_load_level = menu_idx;
40 | target_mode = IN_GAME;
41 | }
42 |
43 | menu level_select_menu = {
44 | .header_text = "Level select",
45 | .num_items = 4,
46 | .items = {
47 | {.text = "Slime room test map", .submenu = NULL, .select = &select_map, .selectable=1},
48 | {.text = "Overlapping rooms test map", .submenu = NULL, .select = &select_map, .selectable=1},
49 | {.text = "Building test map", .submenu = NULL, .select = &select_map, .selectable=1},
50 | {.text = "NO MAP", .submenu = NULL, .select = &select_map, .selectable=0},
51 |
52 | }
53 | };
54 |
55 |
56 | void populate_level_select() {
57 | volatile u32* vmap_table = map_table;
58 |
59 | volatile uint32_t num_maps = map_table[1] >= 6 ? 6 : vmap_table[1];
60 | KLog_U1("num maps: ", num_maps);
61 | for(u32 i = 0; i < num_maps; i++) {
62 | KLog_U1("setting map for index: ", i);
63 | portal_map* pm = (portal_map*)vmap_table[2+i];
64 | level_select_menu.items[i].text = pm->name;
65 | KLog_U1("pointer to name is : ", (u32)(level_select_menu.items[i].text));
66 | level_select_menu.items[i].selectable = 1;
67 | }
68 | }
69 |
70 | char* draw_sfx_state(int menu_idx) {
71 | return (sfx_on ? "ON " : "OFF");
72 |
73 | }
74 |
75 | char* draw_music_state(int menu_idx) {
76 | return (music_on ? "ON " : "OFF");
77 | }
78 |
79 | char* draw_dither_mode_state(int menu_idx) {
80 | return (dither_enabled ? "ON " : "OFF");
81 | }
82 |
83 | const menu options_menu = {
84 | .header_text = "Options",
85 | .num_items = 3,
86 | .items = {
87 | {.text = "Sound Effects: ", .submenu = NULL, .select = &toggle_sfx, .render = &draw_sfx_state, .selectable=1},
88 | {.text = "Music: ", .submenu = NULL, .select = &toggle_music, .render = &draw_music_state, .selectable=1},
89 | {.text = "Dithering Mode: ", .submenu = NULL, .select = &toggle_dither_mode, .render = &draw_dither_mode_state, .selectable=1}
90 | }
91 | };
92 |
93 |
94 | const menu credits_menu = {
95 | .header_text = "Credits",
96 | .num_items = 1,
97 | .items = {
98 | TEXT_ITEM("...."),
99 | }
100 | };
101 |
102 |
103 | const menu main_menu = {
104 | .header_text = "",
105 | .num_items = 5,
106 | .items = {
107 | {.text = "New game", .submenu = NULL, .select = &go_to_new_game, .selectable=1},
108 | {.text = "Level select", .submenu = &level_select_menu, .select = populate_level_select, .selectable=1},
109 | {.text = "Load game", .submenu = &load_game_menu, .select = NULL, .selectable=1},
110 | {.text = "Options", .submenu = &options_menu, .select = NULL, .selectable=1},
111 | {.text = "Credits", .submenu = &credits_menu, .select = NULL, .selectable=1} // .select = &go_to_credits},
112 | }
113 | };
114 |
115 | menu_state main_menu_state;
116 |
117 | void init_main_menu() {
118 | VDP_setScreenWidth320();
119 | VDP_setScreenHeight240();
120 | launch_new_mode = 0;
121 | init_menu_state(&main_menu, &main_menu_state);
122 | }
123 |
124 |
125 | game_mode run_main_menu() {
126 | launch_new_mode = 0;
127 | run_menu(&main_menu_state);
128 | if(launch_new_mode) {
129 | return target_mode;
130 | }
131 | return SAME_MODE;
132 | }
133 |
134 | void cleanup_main_menu() {
135 |
136 | }
--------------------------------------------------------------------------------
/src/main_menu.h:
--------------------------------------------------------------------------------
1 | #ifndef MENU_H
2 | #define MENU_H
3 |
4 | void init_main_menu();
5 | game_mode run_main_menu();
6 | void cleanup_main_menu();
7 |
8 |
9 |
10 | #endif
--------------------------------------------------------------------------------
/src/map_table.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "portal_map.h"
3 | #include "maps.h"
4 |
5 | #include "map_table.h"
6 |
7 | #include "utils.h"
8 |
9 |
10 |
11 | const uint32_t map_table[MAX_MAPS+2] = {
12 | 0xDEADBEEF,
13 | 3, // number of maps
14 | &overlapping_map,
15 | &editor_test_map,
16 | &building_test_map,
17 | 0, 0
18 | //&empty_map_1, //&empty_map_2, &empty_map_3,
19 | };
20 |
21 |
22 |
23 | // 2MB of space for map, texture, sprite, and palette data
24 | const uint8_t wad_area[512*1024*2] = {
25 | 'W','A','D','?',
26 | };
27 | // 2048*1024
28 |
29 |
--------------------------------------------------------------------------------
/src/map_table.h:
--------------------------------------------------------------------------------
1 | #ifndef MAP_TABLE_H
2 | #define MAP_TABLE_H
3 |
4 | #include "portal_map.h"
5 |
6 | #define NUM_MAPS 3
7 | #define MAX_MAPS 5
8 | const uint32_t map_table[MAX_MAPS+2];
9 |
10 | #endif
--------------------------------------------------------------------------------
/src/maps.h:
--------------------------------------------------------------------------------
1 | #ifndef MAPS_H
2 | #define MAPS_H
3 |
4 | //#include "torus_map.h"
5 | #include "editor_test_map.h"
6 | #include "overlapping_test_map.h"
7 | #include "building_test_map.h"
8 |
9 | #endif
--------------------------------------------------------------------------------
/src/math3d.h:
--------------------------------------------------------------------------------
1 | #ifndef MATH3D_H
2 | #define MATH3D_H
3 |
4 | #include
5 | #include "texture.h"
6 | #include "utils.h"
7 | #include "vertex.h"
8 |
9 | // .888
10 | #define ASPECT_RATIO (SCREEN_WIDTH / SCREEN_HEIGHT) // 0.44
11 |
12 | // 3d->2d projection constants
13 |
14 | /*
15 | #define SCALE 1
16 | #define CONST1 64 // (SCREEN_WIDTH/2)
17 | #define CONST2 60 // ((SCREEN_WIDTH/2) * SCALE / min(1, ASPECT_RATIO))
18 | #define CONST3 72 //(SCREEN_HEIGHT/2)
19 | #define CONST4 72 //(SCREEN_HEIGHT/2 * SCALE / max(1, ASPECT_RATIO))
20 | */
21 |
22 | #define SCALE 1
23 | #define CONST1 32
24 | #define CONST2 32 //72
25 | #define CONST3 72
26 | #define CONST4 72
27 |
28 |
29 | typedef struct {
30 | s16 x, yfloor, yceil;
31 | } transformed_vert;
32 |
33 |
34 | typedef enum {
35 | UNCLIPPED = 0b00000000,
36 | //OFFSCREEN = 0b00000001,
37 | NEAR_Z_CULLED = 0b00000001,
38 | FRUSTUM_CULLED = 0b00000010,
39 | LEFT_Z_CLIPPED = 0b00000100,
40 | RIGHT_Z_CLIPPED = 0b00001000,
41 | LEFT_FRUSTUM_CLIPPED = 0b00010000,
42 | RIGHT_FRUSTUM_CLIPPED = 0b00100000,
43 | } clip_result;
44 |
45 | //#define NEAR_Z_32 (20 << FIX32_FRAC_BITS)
46 | // NEAR_Z_16 10
47 | #define NEAR_Z_16 10
48 | //25
49 | #define NEAR_Z_FIX (NEAR_Z_16<
2 | #include "menu_helper.h"
3 | #include "joy_helper.h"
4 |
5 | int cur_line;
6 |
7 | void reset_menu_frame() {
8 | cur_line = 0;
9 | }
10 |
11 | void draw_line(char* txt) {
12 | int num_chars = strlen(txt);
13 | int diff = 40 - num_chars;
14 |
15 | VDP_drawTextBG(BG_A, txt, (diff/2)-1, cur_line); // 12
16 | cur_line += 2;
17 | }
18 |
19 | int find_first_selectable_item(const menu* m) {
20 | for(int i = 0; i < m->num_items; i++) {
21 | if(m->items[i].selectable) {
22 | return i;
23 | }
24 | }
25 | return -1;
26 | }
27 |
28 | void init_menu_state(const menu* m, menu_state* s) {
29 | s->cur_menu = m;
30 | s->cur_item = find_first_selectable_item(m);
31 | }
32 |
33 | void clear_menu() {
34 | cur_line = 0;
35 | for(int i = 0; i < 240/8; i++) {
36 | VDP_drawText(" ", 0, i);
37 | }
38 | }
39 |
40 | void run_menu(menu_state* st) {
41 |
42 | const menu* cur_menu = st->cur_menu;
43 | int cur_item = st->cur_item;
44 | const menu* prev_menu = st->prev_menu;
45 |
46 |
47 | int max_lines = 30;
48 | int num_lines = cur_menu->num_items*2;
49 | int diff = max_lines - num_lines;
50 | int start_off = diff/2;
51 |
52 | cur_line = start_off;
53 |
54 | draw_line(cur_menu->header_text);
55 |
56 | char buf[40];
57 |
58 | for(int i = 0; i < cur_menu->num_items; i++) {
59 | const menu_item* rend_item = &(cur_menu->items[i]);
60 | char* rend_str = (rend_item->render == NULL ? "" : rend_item->render(i));
61 | char* cursor = (cur_item == i) ? ">" : " ";
62 |
63 | sprintf(buf, "%s %s %s", cursor, rend_item->text, rend_str);
64 | draw_line(buf);
65 | }
66 |
67 | int selectable = cur_menu->items[cur_item].selectable != 0;
68 |
69 | if(joy_button_newly_pressed(BUTTON_UP) && (cur_item != -1)) {
70 | cur_item = ((st->cur_item == 0) ? cur_item : cur_item-1);
71 | } else if (joy_button_newly_pressed(BUTTON_DOWN) && (cur_item != -1)) {
72 | cur_item = ((st->cur_item == cur_menu->num_items-1) ? cur_item : st->cur_item+1);
73 | } else if(joy_button_newly_pressed(BUTTON_A) || joy_button_newly_pressed(BUTTON_START) && selectable) {
74 | if(cur_menu->items[cur_item].select != NULL) {
75 | cur_menu->items[cur_item].select(cur_item);
76 | }
77 |
78 | if (cur_menu->items[cur_item].submenu != NULL) {
79 | clear_menu(cur_menu);
80 | prev_menu = cur_menu;
81 | cur_menu = cur_menu->items[cur_item].submenu;
82 | cur_item = find_first_selectable_item(cur_menu);
83 | }
84 |
85 | } else if(joy_button_newly_pressed(BUTTON_B) && (prev_menu != NULL)) {
86 | clear_menu(cur_menu);
87 | cur_menu = prev_menu;
88 | prev_menu = NULL; // CAN ONLY NEST ONCE!
89 | cur_item = find_first_selectable_item(cur_menu);
90 |
91 | }
92 |
93 | st->cur_item = cur_item;
94 | st->cur_menu = cur_menu;
95 | st->prev_menu = prev_menu;
96 | }
97 |
98 |
--------------------------------------------------------------------------------
/src/menu_helper.h:
--------------------------------------------------------------------------------
1 | #ifndef MENU_HELPER_H
2 | #define MENU_HELPER_H
3 |
4 | // a menu is a list of items which are either text, or text + another submenu you can enter
5 |
6 | typedef struct menu menu;
7 |
8 | typedef struct {
9 | char* text;
10 | const menu* submenu;
11 | void (*select)(int menu_idx);
12 | char* (*render)(int menu_idx);
13 | int selectable;
14 | } menu_item;
15 |
16 | struct menu {
17 | char* header_text;
18 | int num_items;
19 | menu_item items[];
20 | };
21 |
22 | typedef struct {
23 | const menu* cur_menu;
24 | int cur_item;
25 | const menu* prev_menu;
26 | } menu_state;
27 |
28 | void init_menu_state(const menu* m, menu_state* st);
29 |
30 | void run_menu(menu_state* st);
31 |
32 | void clear_menu();
33 |
34 | #define MAX_MENU_ITEMS 14
35 |
36 |
37 | #endif
--------------------------------------------------------------------------------
/src/music.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "music_res.h"
3 |
4 | int music_on = TRUE;
5 |
6 | const u8* songs[2] = {
7 | //xgm_e2m2, xgm_e1m4
8 | NULL, NULL,
9 | };
10 | const char const* song_names[2] = {
11 | "E2M2",
12 | "E1M4"
13 | };
14 |
15 | void toggle_music(int menu_idx) {
16 | music_on = !music_on;
17 | }
--------------------------------------------------------------------------------
/src/music.h:
--------------------------------------------------------------------------------
1 | #ifndef MUSIC_H
2 | #define MUSIC_H
3 | #include
4 |
5 | extern int music_on;
6 | void toggle_music();
7 |
8 | #endif
--------------------------------------------------------------------------------
/src/my_bmp.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | extern volatile u32 prev_end_of_frame_vints;
5 | extern volatile u32 end_of_frame_vints;
6 |
7 | extern volatile u32 vints;
8 | //VDPPlane bmp_plane;
9 | //u8 bmp_pal;
10 | //u8 bmp_prio;
11 | //u16* bmp_plane_addr;
12 | //u8 bmp_doublebuffer;
13 |
14 | /*
15 |
16 | **---- bitmap mode module ----**
17 |
18 | - copied with modifications from SGDK
19 |
20 | */
21 |
22 |
23 | //u8* bmp_buffer_0;
24 | //u8* bmp_buffer_1;
25 |
26 | u8* bmp_get_write_pointer(u16 x, u16 y);
27 | u8* bmp_get_read_pointer(u16 x, u16 y);
28 | u16 bmp_get_dma_write_offset(u16 x, u16 y);
29 |
30 | void bmp_reset_phase();
31 |
32 | void bmp_vertical_clear();
33 | void bmp_clear();
34 |
35 | void bmp_reset_horizontal();
36 | void bmp_reset_vertical();
37 |
38 | void bmp_init_horizontal(u16 double_buffer, VDPPlane plane, u16 palette, u16 priority);
39 | void bmp_init_vertical(u16 double_buffer, VDPPlane plane, u16 palette, u16 priority);
40 |
41 |
42 | void bmp_end();
43 |
44 | u16 bmp_flip_partial(u16 async, u8 start_cell);
45 | void bmp_wait_while_flip_request_pending();
46 |
47 | void bmp_show_fps(u16 float_display);
48 | void request_flip();
49 |
--------------------------------------------------------------------------------
/src/my_bmp_a.s:
--------------------------------------------------------------------------------
1 | .globl bmp_clear_vertical_bitmap_buffer
2 | .type bmp_clear_vertical_bitmap_buffer, @function
3 | bmp_clear_vertical_bitmap_buffer:
4 | move.l 4(%sp),%a0 | a0 = buffer
5 | lea 18432(%a0),%a0 | a0 = buffer end
6 |
7 | movm.l %d2-%d7/%a2-%a6,-(%sp)
8 |
9 | | the function consumes about 36000? cycles to clear the whole bitmap buffer
10 |
11 | moveq #0,%d1
12 | move.l %d1,%d2
13 | move.l %d1,%d3
14 | move.l %d1,%d4
15 | move.l %d1,%d5
16 | move.l %d1,%d6
17 | move.l %d1,%d7
18 | move.l %d1,%a1
19 | move.l %d1,%a2
20 | move.l %d1,%a3
21 | move.l %d1,%a4
22 | move.l %d1,%a5
23 | move.l %d1,%a6
24 |
25 | moveq #34,%d0
26 |
27 | .L000:
28 | movm.l %d1-%d7/%a1-%a6,-(%a0)
29 | movm.l %d1-%d7/%a1-%a6,-(%a0)
30 | movm.l %d1-%d7/%a1-%a6,-(%a0)
31 | movm.l %d1-%d7/%a1-%a6,-(%a0)
32 | movm.l %d1-%d7/%a1-%a6,-(%a0)
33 | movm.l %d1-%d7/%a1-%a6,-(%a0)
34 | movm.l %d1-%d7/%a1-%a6,-(%a0)
35 | movm.l %d1-%d7/%a1-%a6,-(%a0)
36 | movm.l %d1-%d7/%a1-%a6,-(%a0)
37 | movm.l %d1-%d7/%a1-%a6,-(%a0)
38 | dbra %d0,.L000
39 |
40 |
41 | movm.l %d1-%d7/%a1-%a6,-(%a0)
42 | movm.l %d1-%d7/%a1-%a6,-(%a0)
43 | movm.l %d1-%d7/%a1-%a6,-(%a0)
44 | movm.l %d1-%d7/%a1-%a6,-(%a0)
45 |
46 | movm.l %d1-%d6,-(%a0)
47 |
48 | movm.l (%sp)+,%d2-%d7/%a2-%a6
49 | rts
50 |
51 | .globl bmp_clear_bitmap_buffer
52 | .type bmp_clear_bitmap_buffer, @function
53 | bmp_clear_bitmap_buffer:
54 | move.l 4(%sp),%a0 | a0 = buffer
55 | lea 20480(%a0),%a0 | a0 = buffer end
56 |
57 | movm.l %d2-%d7/%a2-%a6,-(%sp)
58 |
59 | | the function consume about 43200 cycles to clear the whole bitmap buffer
60 |
61 | moveq #0,%d1
62 | move.l %d1,%d2
63 | move.l %d1,%d3
64 | move.l %d1,%d4
65 | move.l %d1,%d5
66 | move.l %d1,%d6
67 | move.l %d1,%d7
68 | move.l %d1,%a1
69 | move.l %d1,%a2
70 | move.l %d1,%a3
71 | move.l %d1,%a4
72 | move.l %d1,%a5
73 | move.l %d1,%a6
74 |
75 | moveq #38,%d0
76 |
77 | .L01:
78 | movm.l %d1-%d7/%a1-%a6,-(%a0)
79 | movm.l %d1-%d7/%a1-%a6,-(%a0)
80 | movm.l %d1-%d7/%a1-%a6,-(%a0)
81 | movm.l %d1-%d7/%a1-%a6,-(%a0)
82 | movm.l %d1-%d7/%a1-%a6,-(%a0)
83 | movm.l %d1-%d7/%a1-%a6,-(%a0)
84 | movm.l %d1-%d7/%a1-%a6,-(%a0)
85 | movm.l %d1-%d7/%a1-%a6,-(%a0)
86 | movm.l %d1-%d7/%a1-%a6,-(%a0)
87 | movm.l %d1-%d7/%a1-%a6,-(%a0)
88 | dbra %d0,.L01
89 |
90 | movm.l %d1-%d7/%a1-%a6,-(%a0)
91 | movm.l %d1-%d7/%a1-%a6,-(%a0)
92 | movm.l %d1-%d7/%a1-%a6,-(%a0)
93 | movm.l %d1-%d7/%a1-%a4,-(%a0)
94 |
95 | movm.l (%sp)+,%d2-%d7/%a2-%a6
96 | rts
--------------------------------------------------------------------------------
/src/obj_sprite.h:
--------------------------------------------------------------------------------
1 | #ifndef OBJ_SPRITE_H
2 | #define OBJ_SPRITE_H
3 |
4 | #include "genesis.h"
5 | #include "tile.h"
6 |
7 | // 10 bytes
8 | typedef struct __attribute__((__packed__)) {
9 | const u16 num_spans;
10 | const u16* spans; // use words here so they can be pre-scaled to word indexes into scaled_sprite_runlengths
11 | const u8* texels;
12 | } column;
13 |
14 |
15 | // 642 bytes
16 | typedef struct __attribute__((__packed__)) {
17 | // 2 bytes
18 | const u16 num_columns;
19 | // 640 bytes
20 | const column columns[64];
21 | } rle_sprite;
22 |
23 |
24 | void render_object_to_tile_column(u32 tex_per_pix, u32* tex_per_pix_table_ptr, s16 start_y, u16 min_y, u16 max_y, const column* col, u16* tile_buf_ptr);
25 | u16 render_object_to_sprite(s16 left_x,s16 top_y, u16 scaled_size, const rle_sprite* obj);
26 |
27 | void obj_sprite_init(u16 free_tile_loc);
28 | const u32 scaled_sprite_run_lengths[64*513];
29 | const u32 scaled_sprite_texel_per_pixel_lut[513];
30 |
31 | const u16* const sprite_scale_coefficients_pointer_lut[513];
32 |
33 | #endif
--------------------------------------------------------------------------------
/src/object.h:
--------------------------------------------------------------------------------
1 | #ifndef OBJECT_H
2 | #define OBJECT_H
3 |
4 | #include
5 |
6 | #include "obj_sprite.h"
7 |
8 | // 13 bytes
9 | typedef struct {
10 | fix32 x;
11 | fix32 y;
12 | fix32 z;
13 | u8 ang;
14 | } object_pos;
15 |
16 | typedef struct {
17 | fix32 x;
18 | fix32 y;
19 | fix32 z;
20 | u16 cur_sector;
21 | u16 ang;
22 | } player_pos;
23 |
24 | // 4+2+2+2+1+32+2 bytes
25 | // 46
26 |
27 | typedef enum {
28 | OBJECT = 0,
29 | DECORATION = 1,
30 | } obj_type;
31 |
32 | #define FLAGS_KEY_TYPE_MASK 0b00011100
33 | #define FLAGS_KEY_TYPE_SHIFT 2
34 | #define FLAGS_ANCHOR_TOP_MASK 0b00000010
35 | #define FLAGS_ANCHOR_BOT_MASK 0b00000001
36 | #define FLAGS_RE
37 |
38 |
39 | typedef struct __attribute__((__packed__)) {
40 | rle_sprite* sprite;
41 | uint16_t from_anchor_draw_offset;
42 | uint16_t width;
43 | uint16_t height;
44 | uint8_t init_state;
45 | uint16_t speed; // 3 for claw guy?
46 | u8 is_player;
47 | u8 type;
48 | u8 flags; // KEY_TYPE: 2 bits, anchor_top: 1bit, anchor_bot: 1bit
49 | char name[32];
50 | } object_template;
51 |
52 | extern const object_template object_types[];
53 |
54 |
55 |
56 | // 64 active objects
57 | #define NULL_OBJ_LINK 0b00111111
58 | // 128 static objects
59 | #define NULL_DEC_LINK 0b01111111
60 |
61 | // if there's more than 32 objects to draw in a sector, too bad
62 | #define OBJ_SORT_BUF_SZ 32
63 |
64 |
65 | typedef u8 object_link;
66 |
67 | typedef u8 decoration_link;
68 |
69 | // 127 objects!
70 | #define MAX_OBJECTS (NULL_OBJ_LINK)
71 | // 256 decorations!
72 | #define MAX_DECORATIONS (NULL_DEC_LINK)
73 |
74 | #define OBJ_LINK_DEREF(lnk) (objects[(lnk)])
75 | #define DEC_LINK_DEREF(lnk) (decorations[(lnk)])
76 |
77 | #define IDLE_STATE 0
78 | #define MAYBE_GET_PICKED_UP_STATE 3
79 | typedef struct object object;
80 |
81 | // 22 bytes!, 2772 bytes for objects
82 | struct object {
83 |
84 | fix32 x;
85 | fix32 y;
86 | s16 z;
87 | u8 ang;
88 |
89 | object_link tgt;
90 | object_link prev;
91 | object_link next;
92 |
93 | uint8_t health;
94 | uint8_t current_state;
95 | uint8_t object_type;
96 | uint8_t activate_tick;
97 | };
98 |
99 | typedef struct decoration_object decoration_object;
100 |
101 | // 8 bytes, 2040 bytes for all objects
102 | struct decoration_object {
103 | uint8_t object_type;
104 | s16 x; s16 y; s16 z;
105 | decoration_link next;
106 | };
107 |
108 | void init_object_lists(int num_sectors);
109 |
110 | void clean_object_lists();
111 |
112 | typedef struct __attribute__((__packed__)) {
113 | u16 sector_num;
114 | s16 x;
115 | s16 y;
116 | s16 z;
117 | u8 type;
118 | } map_object;
119 |
120 | object_link alloc_object_in_sector(u8 activate_tick, int sector_num, fix32 x, fix32 y, s16 z, uint8_t object_type);
121 | decoration_link alloc_decoration_in_sector(int sector_num, s16 x, s16 y, s16 z, uint8_t object_type);
122 |
123 | void free_object(object_link obj, u16 object_sector);
124 | void free_decoration(decoration_link dec, u16 deco_sector);
125 | void print_object_list(object_link lst);
126 |
127 | object_link objects_in_sector(int sector_num);
128 |
129 | decoration_link decorations_in_sector(int sector_num);
130 |
131 |
132 | void process_all_objects(uint32_t cur_tick);
133 | void wake_enemies_in_sector(u16 sector);
134 |
135 | typedef struct {
136 | uint16_t next_state;
137 | uint16_t ticks;
138 | int (*action)(object_link, uint16_t); // passed the current object as well as the sector
139 | } obj_state;
140 |
141 |
142 | // 12 bytes
143 | typedef struct {
144 | s16 x;
145 | u8 obj_type;
146 | s16 ybot;
147 | s16 ytop;
148 | u8 obj_link;
149 | } buf_obj;
150 |
151 | // 6 bytes
152 | typedef struct {
153 | u16 z_recip;
154 | u8 buf_idx;
155 | s16 height;
156 | //s16 x;
157 | //u8 obj_type;
158 | //s16 ybot;
159 | //s16 ytop;
160 | } z_buf_obj;
161 |
162 |
163 | extern z_buf_obj *z_sort_buf;//[64];
164 | extern buf_obj *obj_sort_buf;//[64];
165 |
166 | extern object* objects;
167 | extern decoration_object* decorations;
168 |
169 | #endif
--------------------------------------------------------------------------------
/src/overlapping_test_map.h:
--------------------------------------------------------------------------------
1 | #ifndef OVERLAPPING_TEST_MAP_H
2 | #define OVERLAPPING_TEST_MAP_H
3 |
4 | #include "portal_map.h"
5 |
6 | extern const portal_map overlapping_map;
7 | void update_wall_vertex();
8 |
9 | #endif
--------------------------------------------------------------------------------
/src/portal.h:
--------------------------------------------------------------------------------
1 | #ifndef PORTAL_H
2 | #define PORTAL_H
3 |
4 | #include
5 | #include "game.h"
6 | #include "portal_map.h"
7 | #include "vertex.h"
8 |
9 | void init_portal_renderer();
10 | void cleanup_portal_renderer();
11 |
12 | void clear_portal_cache();
13 | void portal_rend(u16 src_sector, u32 cur_frame);
14 | void portal_scan(u16 src_sector, u16 window_min, u16 window_max, u32 cur_frame);
15 | u8* sector_rendered_cache;
16 |
17 | #endif
--------------------------------------------------------------------------------
/src/portal_map.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "portal_map.h"
3 |
4 | s16* sector_data_start(s16 sector_idx, portal_map* mp) {
5 | return (s16*)(&mp->sectors[sector_idx*SECTOR_SIZE]);
6 | }
7 |
8 | s16 sector_wall_offset(s16 sector_idx, portal_map* mp) {
9 | return mp->sectors[sector_idx*SECTOR_SIZE];
10 | }
11 |
12 | s16 sector_portal_offset(s16 sector_idx, portal_map* mp) {
13 | return mp->sectors[sector_idx*SECTOR_SIZE+1];
14 | }
15 |
16 | s16 sector_num_walls(s16 sector_idx, portal_map* mp) {
17 | return mp->sectors[sector_idx*SECTOR_SIZE+2];
18 | }
19 |
20 | u16 sector_group(s16 sector_idx, portal_map* mp) {
21 | return mp->sectors[sector_idx*SECTOR_SIZE+3];
22 | }
23 |
24 |
25 | u8 sector_in_pvs_inner(u16 check_sector, s8* entries_for_src_sector) {
26 |
27 | u16 cur_sector = 0;
28 | s8 el = *entries_for_src_sector++;
29 | while(el != 0) {
30 | if(el < 0) {
31 | // run of zeros
32 | cur_sector += (-el); // skip past this many sectors
33 | if(cur_sector > check_sector) {
34 | return 0;
35 | }
36 | } else {
37 | // run of sectors
38 | cur_sector += el;
39 | if(cur_sector > check_sector) {
40 | return 1;
41 | }
42 | }
43 | el = *entries_for_src_sector++;
44 | }
45 | return 0;
46 | }
47 | u8 sector_in_pvs(u16 src_sector, u16 check_sector, portal_map* mp) {
48 | u32 pvs_offset = mp->sector_pvs_offsets[src_sector];
49 | s8* entries = &mp->sector_pvs_entries[pvs_offset];
50 | return sector_in_pvs_inner(check_sector, entries);
51 | }
52 |
53 | u8 sector_in_phs(u16 src_sector, u16 check_sector, portal_map* mp) {
54 | u32 phs_offset = mp->sector_phs_offsets[src_sector];
55 | s16* entries = &mp->sector_phs_entries[phs_offset];
56 | return sector_in_pvs_inner(check_sector, entries);
57 | }
58 |
59 |
60 | void run_in_pvs_inner(u16 src_sector, void (*sect_func)(u16), s8* entries_for_src_sector) {
61 | u16 cur_sector = 0;
62 | s8 el = *entries_for_src_sector++;
63 | while(el != 0) {
64 | if(el < 0) {
65 | // run of zeros
66 | cur_sector += (-el); // skip past this many sectors
67 | } else {
68 | // run of sectors
69 | for(u16 s = cur_sector; s < cur_sector+el; s++) {
70 | sect_func(s);
71 | }
72 | cur_sector += el;
73 | }
74 | el = *entries_for_src_sector++;
75 | }
76 | }
77 |
78 |
79 | void run_in_pvs(u16 src_sector, void (*sect_func)(u16), portal_map* mp) {
80 | u32 pvs_offset = mp->sector_pvs_offsets[src_sector];
81 | s8* entries = &mp->sector_pvs_entries[pvs_offset];
82 | run_in_pvs_inner(src_sector, sect_func, entries);
83 | }
84 |
85 | void run_in_phs(u16 src_sector, void (*sect_func)(u16), portal_map* mp) {
86 | u32 pvs_offset = mp->sector_phs_offsets[src_sector];
87 | s8* entries = &mp->sector_phs_entries[pvs_offset];
88 | run_in_pvs_inner(src_sector, sect_func, entries);
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/src/portal_map.h:
--------------------------------------------------------------------------------
1 | #ifndef PORTAL_MAP_H
2 | #define PORTAL_MAP_H
3 |
4 | #include
5 |
6 | #include "object.h"
7 | #include "sector_group.h"
8 | #include "texture.h"
9 | #include "vertex.h"
10 |
11 | #define SECTOR_SIZE 4
12 | #define VERT_SIZE 2
13 |
14 | #define MAX_SECTORS 1024 // 4kB max
15 | #define MAX_SECTOR_GROUPS 512
16 | #define MAX_WALLS 1024 // 4kB max
17 | #define MAX_VERTEXES 1024 // 8kB max
18 | #define MAX_PORTALS 512 // 1kB max
19 | #define MAX_TEXTURES 32 // 64 bytes, pointers into shared texture list
20 |
21 | typedef enum {
22 | QUADRANT_0=0,
23 | QUADRANT_1=1,
24 | QUADRANT_2=2,
25 | QUADRANT_3=3,
26 | FACING_UP=4,
27 | FACING_LEFT=5,
28 | FACING_DOWN=6,
29 | FACING_RIGHT=7
30 | } normal_quadrant;
31 |
32 | typedef struct {
33 | u8 upper_col;
34 | u8* texture;
35 | u8 lower_col;
36 | } wall_col;
37 |
38 | #define WALL_TEXTURE_IDX 0
39 | #define WALL_HIGH_COLOR_IDX 1
40 | #define WALL_LOW_COLOR_IDX 2
41 | #define WALL_SOLID_COLOR_IDX 3
42 |
43 | #define WALL_COLOR_NUM_PARAMS 4
44 | #define WALL_COLOR_NUM_PARAMS_SHIFT 2
45 |
46 |
47 |
48 |
49 |
50 | #define NUM_PVS_PARAMS 2
51 | #define PVS_SHIFT 1
52 |
53 | typedef struct __attribute__((__packed__)) {
54 | const u16 bunch_offset;
55 | const u8 num_bunches;
56 | } pvs_bunch_group;
57 |
58 | typedef struct __attribute__((__packed__)) {
59 | const u16 sector_num;
60 | const u16 wall_offset;
61 | const u8 num_walls;
62 | } pvs_bunch_entry;
63 |
64 |
65 | // in total 1088 bytes
66 |
67 | typedef struct __attribute__((__packed__)){
68 | const u16 num_sector_groups;
69 | const u16 num_sectors;
70 | const u16 num_walls;
71 | const u16 num_verts;
72 | const s16* sectors;
73 | const u8* sector_group_types;
74 | const s16* sector_group_params;
75 |
76 | // each sector has a list of 8 s16s
77 | // the first is the trigger type, and the remaining 7 are sector group targets
78 | const s16* sector_group_triggers;
79 |
80 | const u16* walls;
81 |
82 | //const u16* collision_hull_walls; //
83 |
84 | //const s16* wall_dxs;
85 | //const s16* wall_dys;
86 | //const s16* wall_collision_hull;
87 |
88 | const s16* portals;
89 | const u8* wall_colors;
90 | const u8* wall_tex_repetitions;
91 | const vertex* vertexes;
92 | const vertex* collision_vertexes;
93 | const u8* wall_norm_quadrants;
94 | const u16 has_pvs;
95 | const u16* pvs;
96 | const u16* raw_pvs;
97 |
98 | const u16* pvs_offsets;
99 | const s16* sector_list_offsets;
100 | const u16* wall_pvs; // each index from above points to a list consisting of N:num_sectors, N 32-bit bitmaps
101 |
102 |
103 | const pvs_bunch_group* pvs_bunch_groups;
104 | const pvs_bunch_entry* pvs_bunch_entries;
105 |
106 | const u32* sector_pvs_offsets; // offsets rle-encoded sector pvs
107 | const s8* sector_pvs_entries;
108 | const u32* sector_phs_offsets;
109 | const s8* sector_phs_entries;
110 | char* name;
111 | void* xgm_track;
112 | u16* palette;
113 | u16 num_things;
114 | map_object* things;
115 | } portal_map;
116 |
117 | s16* sector_data_start(s16 sector_idx, portal_map* mp);
118 |
119 | s16 sector_wall_offset(s16 sector_idx, portal_map* mp);
120 |
121 | s16 sector_portal_offset(s16 sector_idx, portal_map* mp);
122 |
123 | s16 sector_num_walls(s16 sector_idx, portal_map* mp);
124 |
125 | u16 sector_group(s16 sector_idx, portal_map* mp);
126 |
127 | u8 sector_in_pvs(u16 src_sector, u16 check_sector, portal_map* mp);
128 |
129 | u8 sector_in_phs(u16 src_sector, u16 check_sector, portal_map* mp);
130 |
131 | void run_in_pvs(u16 src_sector, void (*sect_func)(u16), portal_map* mp);
132 |
133 | void run_in_phs(u16 src_sector, void (*sect_func)(u16), portal_map* mp);
134 |
135 | #endif
136 |
--------------------------------------------------------------------------------
/src/python/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/__init__.py
--------------------------------------------------------------------------------
/src/python/editor/.idea/editor.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/python/editor/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/python/editor/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/python/editor/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/python/editor/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/python/editor/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | 1631381646397
60 |
61 |
62 | 1631381646397
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | file://$PROJECT_DIR$/editor.py
71 | 202
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/python/editor/DLLs/geos_c.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/DLLs/geos_c.dll
--------------------------------------------------------------------------------
/src/python/editor/README:
--------------------------------------------------------------------------------
1 | This release of the editor needs SDL2.dll in the same directory/folder as the exe.
2 | Plus you will need to provide a textures, sprites, and music directory/folder matching the one in conf.ini.
3 | You need to provide at least one texture and at least one sprite in these folders.
4 |
5 | For music, you will also need SGDK's xgmtool. You can find that on the SGDK github repository.
6 |
7 | Another helpful tool, is providing a path to an emulator to launch built ROMs with.
--------------------------------------------------------------------------------
/src/python/editor/README.md:
--------------------------------------------------------------------------------
1 | This release of the editor needs SDL2.dll in the same directory/folder as the exe.
2 | Plus you will need to provide a textures, sprites, and music directory/folder matching the one in conf.ini.
3 | You need to provide at least one texture and at least one sprite in these folders.
4 |
5 | For music, you will also need SGDK's xgmtool. You can find that on the SGDK github repository.
6 |
7 | Another helpful tool, is providing a path to an emulator to launch built ROMs with.
--------------------------------------------------------------------------------
/src/python/editor/build_conf.ini:
--------------------------------------------------------------------------------
1 | [Default Settings]
2 | emulator-path=gens.exe
3 | xgmtool-path=xgmtool.exe
4 | textures-path=textures
5 | sprites-path=sprites
6 | music-tracks-path=music
--------------------------------------------------------------------------------
/src/python/editor/defaults.py:
--------------------------------------------------------------------------------
1 | import imgui
2 |
3 | import utils
4 |
5 | def draw_defaults_mode(cur_state):
6 | color_opts = ["{}".format(idx) for idx in range(16)]
7 | up_col_changed, new_up_col = imgui.core.combo("upper color", cur_state.default_up_color, color_opts)
8 | mid_col_changed, new_mid_col = imgui.core.combo("middle color", cur_state.default_mid_color, color_opts)
9 | low_col_changed, new_low_col = imgui.core.combo("lower color", cur_state.default_low_color, color_opts)
10 |
11 | tex_files = utils.get_texture_files(cur_state)
12 |
13 | def set_default_tex_file(f):
14 | cur_state.default_texture_file = f
15 | utils.file_selector("texture", cur_state.default_texture_file, tex_files, set_default_tex_file)
16 |
17 |
18 | floor_col_changed, new_floor_col = imgui.core.combo("floor color", cur_state.default_floor_color, color_opts)
19 | ceil_col_changed, new_ceil_col = imgui.core.combo("ceil color ", cur_state.default_ceil_color, color_opts)
20 |
21 | type_options = ['player'] + [ thing.name for thing in cur_state.map_data.thing_defs]
22 | thing_type_changed, new_thing_type = imgui.core.combo("thing type ", cur_state.default_thing_type, type_options)
23 |
24 | if up_col_changed:
25 | cur_state.default_up_color = new_up_col
26 | if mid_col_changed:
27 | cur_state.default_mid_color = new_mid_col
28 | if low_col_changed:
29 | cur_state.default_low_color = new_low_col
30 | if floor_col_changed:
31 | cur_state.default_floor_color = new_floor_col
32 | if ceil_col_changed:
33 | cur_state.default_ceil_color = new_ceil_col
34 | if thing_type_changed:
35 | cur_state.default_thing_type = new_thing_type
36 |
--------------------------------------------------------------------------------
/src/python/editor/editor.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python ; coding: utf-8 -*-
2 |
3 |
4 | block_cipher = None
5 |
6 |
7 | a = Analysis(
8 | ['editor.py'],
9 | pathex=[],
10 | binaries=[],
11 | datas=[],
12 | hiddenimports=[],
13 | hookspath=[],
14 | runtime_hooks=[],
15 | excludes=[],
16 | win_no_prefer_redirects=False,
17 | win_private_assemblies=False,
18 | cipher=block_cipher,
19 | noarchive=False,
20 | )
21 | pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
22 |
23 | exe = EXE(
24 | pyz,
25 | a.scripts,
26 | a.binaries,
27 | a.zipfiles,
28 | a.datas,
29 | [],
30 | name='editor',
31 | debug=False,
32 | bootloader_ignore_signals=False,
33 | strip=False,
34 | upx=True,
35 | upx_exclude=[],
36 | runtime_tmpdir=None,
37 | console=True,
38 | disable_windowed_traceback=False,
39 | argv_emulation=False,
40 | target_arch=None,
41 | codesign_identity=None,
42 | entitlements_file=None,
43 | )
44 |
--------------------------------------------------------------------------------
/src/python/editor/file_utils.py:
--------------------------------------------------------------------------------
1 |
2 | def _read_longword_(f, signed: bool) -> int:
3 | return int.from_bytes(f.read(4), "big", signed)
4 |
5 | def read_s32(f) -> int:
6 | return _read_longword_(f, True)
7 |
8 | def read_u32(f) -> int:
9 | return _read_longword_(f, False)
10 |
11 | def _write_longword_(f, lw: int, signed: bool) -> int:
12 | off = f.tell()
13 | f.write(lw.to_bytes(4, byteorder="big", signed=signed))
14 | return off
15 |
16 | def write_s32(f, lw: int) -> int:
17 | return _write_longword_(f, lw, True)
18 | def write_u32(f, lw: int) -> int:
19 | return _write_longword_(f, lw, False)
20 |
21 |
22 | def _read_word_(f, signed: bool) -> int:
23 | return int.from_bytes(f.read(2), "big", signed)
24 |
25 | def read_s16(f) -> int:
26 | return _read_word_(f, True)
27 | def read_u16(f) -> int:
28 | return _read_word_(f, False)
29 |
30 | def _write_word_(f, w: int, signed: bool) -> int:
31 | off = f.tell()
32 | f.write(w.to_bytes(2, byteorder="big", signed=signed))
33 | return off
34 |
35 | def write_u16(f, w: int) -> int:
36 | assert w >= 0 and w < 65536
37 | _write_word_(f, w, False)
38 |
39 | def write_s16(f, w: int) -> int:
40 | assert w >= -32768 and w < 32768
41 | _write_word_(f, w, True)
42 |
43 |
44 | def _read_byte_(f, signed: bool) -> int:
45 | return int.from_bytes(f.read(1), byteorder="big", signed=signed)
46 | def _write_byte_(f, b: int, signed: bool) -> int:
47 | off = f.tell()
48 | f.write(b.to_bytes(1, byteorder="big", signed=signed))
49 | return off
50 |
51 | def read_s8(f) -> int:
52 | return _read_byte_(f, True)
53 | def read_u8(f) -> int:
54 | return _read_byte_(f, False)
55 | def write_s8(f, b: int) -> int:
56 | return _write_byte_(f, b, True)
57 | def write_u8(f, b: int) -> int:
58 | return _write_byte_(f, b, False)
59 |
--------------------------------------------------------------------------------
/src/python/editor/geos_c.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/geos_c.dll
--------------------------------------------------------------------------------
/src/python/editor/imgui.ini:
--------------------------------------------------------------------------------
1 | [Window][Debug##Default]
2 | Pos=60,60
3 | Size=400,400
4 | Collapsed=0
5 |
6 | [Window][Your first window!]
7 | Pos=60,60
8 | Size=99,48
9 | Collapsed=0
10 |
11 | [Window][Custom window]
12 | Pos=62,45
13 | Size=269,240
14 | Collapsed=0
15 |
16 | [Window][ImGui Demo]
17 | Pos=659,44
18 | Size=550,680
19 | Collapsed=0
20 |
21 | [Window][Example: Custom rendering]
22 | Pos=97,63
23 | Size=350,560
24 | Collapsed=0
25 |
26 | [Window][Tools]
27 | Pos=832,43
28 | Size=373,593
29 | Collapsed=0
30 |
31 | [Window][Map]
32 | Pos=0,0
33 | Size=1600,900
34 | Collapsed=0
35 |
36 |
--------------------------------------------------------------------------------
/src/python/editor/levels.py:
--------------------------------------------------------------------------------
1 | from tkinter import filedialog, messagebox
2 |
3 | def export_maps_to_rom(
4 | map_loader_func # dumb hack to get around circular imports
5 | ):
6 | f = filedialog.askopenfile(mode="r")
7 |
8 | textures = set()
9 | tracks = set()
10 | with open(f) as maplist:
11 | maps = maplist.readlines()
12 | for map in maps:
13 | map_data = map_loader_func(map)
14 | level_textures = gather_textures_from_level(map_data)
15 | textures = textures.union(level_textures)
16 |
17 | tracks.add(map_data.music_path)
18 |
19 | # write textures to WAD area
20 |
21 | # write music to WAD area
22 |
23 | # export maps to ROM with offsets to compiled textures and music
24 |
25 | def gather_textures_from_level(map_data):
26 | textures = set()
27 | for wall in map_data.sectors.walls:
28 | textures.add(wall.texture_file)
29 | return textures
30 |
31 |
32 |
33 | # get textures
34 | # get
--------------------------------------------------------------------------------
/src/python/editor/light_levels.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/light_levels.py
--------------------------------------------------------------------------------
/src/python/editor/light_remapping_table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/light_remapping_table.png
--------------------------------------------------------------------------------
/src/python/editor/light_remapping_table_autogen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/light_remapping_table_autogen.png
--------------------------------------------------------------------------------
/src/python/editor/light_remapping_table_mix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/light_remapping_table_mix.png
--------------------------------------------------------------------------------
/src/python/editor/light_remapping_table_mix_rotated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/light_remapping_table_mix_rotated.png
--------------------------------------------------------------------------------
/src/python/editor/light_remapping_table_no_mix_rotated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/editor/light_remapping_table_no_mix_rotated.png
--------------------------------------------------------------------------------
/src/python/editor/map.py:
--------------------------------------------------------------------------------
1 | import palette
2 | import things
3 | import sector
4 | import sector_group
5 | import vertex
6 |
7 | import typing
8 |
9 | class Map():
10 | def __init__(self,
11 | default_sprite,
12 | name="placeholder name",
13 | sectors=None,
14 | vertexes=None,
15 | music_path=""):
16 | self.bsp = False
17 | if not sectors:
18 | self.sectors: typing.List[sector.Sector] = []
19 | else:
20 | self.sectors: typing.List[sector.Sector] = sectors
21 | #self.walls = []
22 |
23 | if not vertexes:
24 | self.vertexes = []
25 | else:
26 | self.vertexes = vertexes
27 |
28 | self.name: str = name
29 | self.music_path: str = music_path
30 | self.palette = palette.DEFAULT_PALETTE
31 | self.thing_defs = [things.ThingDef(default_sprite) for i in range(31)]
32 | self.things: typing.List[things.Thing] = []
33 | self.sector_groups: typing.List[sector_group.SectorGroup] = []
34 |
--------------------------------------------------------------------------------
/src/python/editor/modes.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 | class Mode(Enum):
4 | SECTOR = 'Sector'
5 | SECTOR_GROUP = 'Sector Groups'
6 | LINE = 'Line'
7 | VERTEX = 'Vertex'
8 | SCRIPT = 'Script'
9 | TRIGGER = 'Trigger'
10 | TEXTURE = 'Texture'
11 | TREE = 'Tree'
12 | PVS = 'PVS'
13 | MUSIC = 'Music'
14 | PALETTE = 'Palette'
15 | DEFAULTS = 'Defaults'
16 | THING_DEFS = 'Thing Defs'
17 | THINGS = 'Things'
18 |
--------------------------------------------------------------------------------
/src/python/editor/music.py:
--------------------------------------------------------------------------------
1 |
2 | import imgui
3 |
4 | import undo
5 | import utils
6 |
7 | def draw_music_mode(cur_state):
8 | chg_xgm, xgm_val = imgui.input_text("XGM Tool path: ", cur_state.xgmtool_path, buffer_length=128)
9 | if chg_xgm:
10 | undo.push_state(cur_state)
11 | cur_state.xgmtool_path = xgm_val
12 |
13 | music_files = ["No track"] + utils.get_music_files(cur_state)
14 | def set_music_track(new_track):
15 | undo.push_state(cur_state)
16 | if new_track == "No track":
17 | cur_state.map_data.music_path = ""
18 | else:
19 | cur_state.map_data.music_path = new_track
20 |
21 | if cur_state.map_data.music_path == "":
22 | utils.file_selector("Music track: ", "No track", music_files, set_music_track)
23 | else:
24 | utils.file_selector("Music track: ", cur_state.map_data.music_path, music_files, set_music_track)
25 |
--------------------------------------------------------------------------------
/src/python/editor/palette.py:
--------------------------------------------------------------------------------
1 | import imgui
2 | #define RGB24_TO_VDPCOLOR(color)
3 | # (((((color + 0x100000) < 0xFF0000 ? color + 0x100000 : 0xFF0000) >> (20)) & VDPPALETTE_REDMASK) | (((((color & 0xff00) + 0x1000) < 0xFF00 ? (color & 0xff00) + 0x1000 : 0xFF00) >> ((1 * 4) + 4)) & VDPPALETTE_GREENMASK) | (((((color & 0xff) + 0x10) < 0xFF ? (color & 0xff) + 0x10 : 0xFF) << 4) & VDPPALETTE_BLUEMASK))
4 | #define RGB8_8_8_TO_VDPCOLOR(r, g, b)
5 | #
6 | # RGB24_TO_VDPCOLOR(((((b) << 0) & 0xFF) | (((g) & 0xFF) << 8) | (((r) & 0xFF) << 16)))
7 |
8 |
9 | VDPPALETTE_REDMASK = 0x000E
10 | VDPPALETTE_GREENMASK = 0x00E0
11 | VDPPALETTE_BLUEMASK = 0x0E00
12 | VDPPALETTE_COLORMASK = 0x0EEE
13 |
14 | col_lut = [0, 36, 72, 108, 144, 180, 216, 252]
15 |
16 | def hex_color_to_rgb(hex):
17 | r = ((hex>>16)&0xFF)/256
18 | g = ((hex>>8)&0xFF)/256
19 | b = ((hex>>0)&0xFF)/256
20 | return [r,g,b]
21 |
22 | def vdp_color_to_rgb(vdpcolor):
23 | r = col_lut[((vdpcolor>>1)&7)]/255
24 | g = col_lut[((vdpcolor>>5)&7)]/255
25 | b = col_lut[((vdpcolor>>9)&7)]/255
26 | return [r,g,b]
27 |
28 | DEFAULT_PALETTE = [hex_color_to_rgb(rgb) for rgb in [
29 | 0xE31C79, #0x000000,
30 | 0x9b5d5d,
31 | 0xd99b7c,
32 | 0xf8ba9b,
33 | 0x7cf89b,
34 | 0x3e5d5d,
35 | 0x001f1f,
36 | 0x3e7c00,
37 | 0x3e3e3e,
38 | 0xd93e00,
39 | 0x1f001f,
40 | 0x9b003e,
41 | 0x3e9bba,
42 | 0x5d5dba,
43 | 0xd9ba00,
44 | 0x000000,
45 | ]]
46 |
47 | def rgb24_to_vdp_color(color):
48 | r = (((color + 0x100000 if ((color + 0x100000) < 0xFF0000) else 0xFF0000) >> (20)) & VDPPALETTE_REDMASK)
49 | g = ((((color & 0xff00) + 0x1000 if (((color & 0xff00) + 0x1000) < 0xFF00) else 0xFF00) >> ((1 * 4) + 4)) & VDPPALETTE_GREENMASK)
50 | b = (((((color & 0xff) + 0x10) if (((color & 0xff) + 0x10) < 0xFF) else 0xFF) << 4) & VDPPALETTE_BLUEMASK)
51 | return (r | g | b)
52 |
53 | def rgb_to_vdp_color(r,g,b):
54 | return rgb24_to_vdp_color((b & 0xFF)|((g & 0xFF)<<8)|((r & 0xFF) << 16))
55 |
56 |
57 | def draw_palette_mode(cur_state):
58 | for idx in range(16):
59 | changed, val = imgui.color_edit3("{}:".format(idx), *cur_state.map_data.palette[idx])
60 | if changed:
61 | cur_state.map_data.palette[idx] = val
62 |
63 |
--------------------------------------------------------------------------------
/src/python/editor/palette_light_table.py:
--------------------------------------------------------------------------------
1 |
2 | # load image file
3 |
4 |
5 | # load all colors in image
6 |
7 | avail_colors = [
8 | (155,93,93),
9 | (217,155,124),
10 | (248,186,155),
11 | (124,248,155),
12 | (62,93,93),
13 | (0,31,31),
14 | (62,124,0),
15 | (62,62,62),
16 | (217,62,0),
17 | (31,0,31),
18 | (155,0,62),
19 | (62,155,186),
20 | (93,93,186),
21 | (217,186,0),
22 | (0,0,0),
23 | ]
24 |
25 | # make sure to offset indexes
26 |
27 | def get_index_of_color(col):
28 | #(cr,cg,cb,) = col
29 | #colc = (cr,cg,cb)
30 | if len(col) == 4:
31 | colc = (col[0],col[1],col[2])
32 | else:
33 | colc = col
34 | for idx,col2 in enumerate(avail_colors):
35 | if col2 == colc:
36 | return idx+1
37 |
38 | raise Exception("Couldn't find color: {}".format(col))
39 |
40 | def get_8pix(p):
41 | dp = (p<<4|p)
42 | qp = (dp<<8 | dp)
43 | ep = (qp << 16 | qp)
44 | return ep
45 |
46 | from PIL import Image
47 |
48 |
49 | def write_u32(f, lw):
50 | f.write(lw.to_bytes(4, byteorder="big", signed=False))
51 |
52 |
53 | #NEAR_START_OFFSET = 2335986
54 | #NEAR_FILE = "/Users/haliewicz/Desktop/near_light_table.png"
55 |
56 |
57 | MIX_FILE = "src\python\editor\light_remapping_table_mix_rotated.png"
58 | NO_MIX_FILE = "src\python\editor\light_remapping_table_no_mix_rotated.png"
59 |
60 | if __name__ == '__main__':
61 |
62 |
63 | with Image.open(NO_MIX_FILE) as im:
64 | #with Image.open(MIX_FILE) as im:
65 | #x,y = im.size
66 |
67 | for idx,table in enumerate(["far", "near"]):
68 | print('// {} table'.format(table))
69 | dist_row_offset = idx * 5 * 2
70 |
71 | for light_level in range(5):
72 | print('// {} light level'.format(light_level-2))
73 | light_level_offset = light_level * 2
74 |
75 | print('0', end=', ')
76 |
77 | row = dist_row_offset + light_level_offset
78 | for pal_idx in range(15):
79 |
80 | first_nib = get_index_of_color(im.getpixel((pal_idx, row)))
81 | second_nib = get_index_of_color(im.getpixel((pal_idx, row+1)))
82 |
83 | print('DPIX({},{})'.format(first_nib, second_nib), end=', ')
84 |
85 | print('')
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/src/python/editor/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "manifold"
3 | version = "0.6.0"
4 | description = ""
5 | authors = ["Erik Haliewicz "]
6 | license = "MIT"
7 | readme = "README.md"
8 |
9 | [tool.poetry.dependencies]
10 | python = "3.12"
11 | imgui = "1.4.1"
12 | pyopengl = "3.1.6"
13 | pysdl2 = "0.9.6"
14 | pysdl2-dll = "2.24.0"
15 | numpy = "^1.26.1"
16 | shapely = "^2.0.2"
17 | pillow = "^10.1.0"
18 |
19 |
20 |
21 | [build-system]
22 | requires = ["poetry-core"]
23 | build-backend = "poetry.core.masonry.api"
24 |
--------------------------------------------------------------------------------
/src/python/editor/remapping.py:
--------------------------------------------------------------------------------
1 | import math
2 | from PIL import Image
3 |
4 | avail_colors = [
5 | (154,93,93),
6 | (216,154,124),
7 | (247,185,154),
8 | (124,247,154),
9 | (62,93,93),
10 | (0,31,31),
11 | (62,124,0),
12 | (62,62,62),
13 | (216,62,0),
14 | (31,0,31),
15 | (154,0,64),
16 | (62,154,185),
17 | (93,93,185),
18 | (216,185,0),
19 | (0,0,0)
20 | ]
21 |
22 | def clamp(c):
23 | return 255 if c > 255 else 0 if c < 0 else c
24 |
25 | def lighten(c):
26 | return scale_color(c, 1.3)
27 |
28 | def darken(c):
29 | return scale_color(c, .7)
30 |
31 | def scale_color(c, amount):
32 | (r,g,b) = c
33 | return (clamp(int(r*amount)),clamp(int(g*amount)),clamp(int(b*amount)))
34 |
35 | def dist(c1, c2):
36 | (r1,g1,b1) = c1
37 | (r2,g2,b2) = c2
38 | rmean = int((r1+r2)/2)
39 | r = int(r1-r2)
40 | g = int(g1-g2)
41 | b = int(b1-b2)
42 | return math.sqrt((((512+rmean)*r*r)>>8)+(4*g*g)+(((767-rmean)*b*b)>>8))
43 |
44 | def find_closest_idx(col):
45 | dists = [dist(c2,col) if c2 != col else 10000000000000 for c2 in avail_colors]
46 | #print(dists)
47 | min_dist = min(dists)
48 | #print(min_dist)
49 | closest_color_idx = dists.index(min_dist)
50 | return closest_color_idx
51 |
52 | #for idx,c in enumerate(avail_colors):
53 | #
54 | # # near colors
55 | # dark = find_closest_idx(darken(c))
56 | # extra_dark = find_closest_idx(darken(darken(c)))
57 | # light = find_closest_idx(lighten(c))
58 | # extra_light = find_closest_idx(lighten(lighten(c)))
59 | #
60 | # print(extra_dark+1, end=', ')
61 | # print(dark+1, end=', ')
62 | # print(idx+1, end=', ')
63 | # print(light+1, end=', ')
64 | # print(extra_light+1, end=',\n')
65 |
66 | tables = [
67 | # far
68 | [
69 | lambda c:find_closest_idx(darken(darken(c)))+1,
70 | lambda c:find_closest_idx(darken(darken(c)))+1,
71 | lambda c:find_closest_idx(darken(c))+1,
72 | lambda c:avail_colors.index(c)+1,
73 | lambda c:find_closest_idx(lighten(lighten(c)))+1
74 | ],
75 | # near
76 | [
77 | lambda c:find_closest_idx(darken(darken(c)))+1,
78 | lambda c:find_closest_idx(darken(c))+1,
79 | lambda c:avail_colors.index(c)+1,
80 | lambda c:find_closest_idx(lighten(c))+1,
81 | lambda c:find_closest_idx(lighten(lighten(c)))+1
82 | ]
83 | ]
84 |
85 | #img = Image.new(mode="RGB",size=(10,15))
86 | #pixels = img.load()
87 |
88 | #for y,base_col in enumerate(avail_colors):
89 | # for dist_idx in range(2):
90 | # base_x = dist_idx*5
91 | # light_levels = tables[1-dist_idx]
92 | # for idx,light_level in enumerate(light_levels):
93 | # x = base_x + idx
94 | # pixels[x,y] = avail_colors[light_level(base_col)-1]
95 |
96 | #with open("C:\\Users\\Erik\\code\\genesis\\DOOM\\src\\python\\editor\\light_remapping_table_autogen.png", "wb") as fp:
97 | # img.save(fp)
98 |
99 |
100 | with NEAR_FILE
101 | for idx in range(2):
102 | light_levels = tables[idx]
103 | print("// {} table".format(["far", "near"][idx]))
104 | for idx,light_level in enumerate(light_levels):
105 | print(" // {} light level".format(idx-2))
106 | print(" 0", end=', ')
107 |
108 | for base_col in avail_colors:
109 | print("PIX({}), ".format(light_level(base_col)), end='')
110 | print()
111 |
112 |
--------------------------------------------------------------------------------
/src/python/editor/render_3d.py:
--------------------------------------------------------------------------------
1 | import ctypes.wintypes
2 |
3 | import imgui
4 | import sdl2
5 | import sdl2.ext
6 | import random
7 | import math
8 |
9 | RENDER_WIDTH = 256
10 | RENDER_HEIGHT = 140
11 |
12 | SCALE = 2
13 |
14 | vertexes = [
15 | (90,90),
16 | (100,100)
17 | ]
18 |
19 | walls = [
20 | (0, 1, (255,0,0)),
21 | ]
22 |
23 | CEIL_HEIGHT = 100
24 | FLOOR_HEIGHT = 0
25 |
26 | surf: sdl2.SDL_Surface
27 | #window: sdl2.ext.Window
28 | renderer: sdl2.ext.Renderer
29 |
30 | cam_x = 95
31 | cam_y = 40
32 | cam_z = 20
33 | cam_ang = 0
34 |
35 | def init_sdl_window():
36 | return
37 | global renderer, surf
38 | sdl2.ext.init()
39 |
40 | window = sdl2.ext.Window("Live View", size=(RENDER_WIDTH*SCALE, RENDER_HEIGHT*2))
41 | window.show()
42 |
43 | #surf = sdl2.SDL_CreateRGBSurface(0, RENDER_WIDTH, RENDER_HEIGHT, 32, 0,0,0,0)
44 | #renderer = sdl2.ext.Renderer(surf, )
45 | #renderer.present()
46 | renderer = sdl2.ext.Renderer(window)
47 | renderer.present()
48 | #processor = sdl2.ext.TestEventProcessor()
49 | #processor.run(window)
50 |
51 |
52 | def draw_preview(current_state):
53 | return
54 | global cam_ang
55 | renderer.clear((0,0,0))
56 | render_from_position(cam_x, cam_y, cam_z, cam_ang, 0, RENDER_WIDTH)
57 | renderer.present()
58 |
59 | #tex = sdl2.SDL_CreateTextureFromSurface(renderer.sdlrenderer, surf)
60 |
61 | #sdl2.SDL_LockTexture(tex)
62 |
63 | cam_ang += 0.5
64 | #sdl2.SDL_GL_BindTexture(tex, None, None)
65 |
66 | #imgui.image(tex, RENDER_WIDTH, RENDER_HEIGHT)
67 | #sdl2.SDL_UnlockTexture(tex)
68 |
69 | cam_ang = cam_ang % 360
70 |
71 | def render_from_position(cam_x, cam_y, cam_z, angle, window_min, window_max):
72 | #surf: sdl2.SDL_Surface
73 | #surf = window.get_surface()
74 | for wall in walls:
75 | (v1_idx, v2_idx, col) = wall
76 | v1 = vertexes[v1_idx]
77 | v2 = vertexes[v2_idx]
78 |
79 | trans_v1_x, trans_v1_z = transform_vert(v1, cam_x, cam_y, angle)
80 | trans_v2_x, trans_v2_z = transform_vert(v2, cam_x, cam_y, angle)
81 |
82 | if(trans_v1_z <= 0 or trans_v2_z <= 0):
83 | continue
84 |
85 | print("v1 x,z {},{}".format(trans_v1_x, trans_v1_z))
86 | print("v2 x,z {},{}".format(trans_v2_x, trans_v2_z))
87 | lx = int(project_x(trans_v1_x, trans_v1_z))
88 | rx = int(project_x(trans_v2_x, trans_v2_z))
89 | print("lx: {}".format(lx))
90 | print("rx: {}".format(rx))
91 |
92 | x1_ytop = project_y(CEIL_HEIGHT, trans_v1_z, cam_z)
93 | x1_ybot = project_y(FLOOR_HEIGHT, trans_v1_z, cam_z)
94 | x2_ytop = project_y(CEIL_HEIGHT, trans_v2_z, cam_z)
95 | x2_ybot = project_y(FLOOR_HEIGHT, trans_v2_z, cam_z)
96 |
97 | if (lx > window_max):
98 | print("lx too big")
99 | continue
100 |
101 | if (rx < window_min):
102 | print("rx too small")
103 | continue
104 |
105 | if (lx >= rx):
106 | print("lx and rx are reversed")
107 | continue
108 |
109 | print("DRAWING!!!!")
110 |
111 | cur_ytop = x1_ytop
112 | cur_ybot = x1_ybot
113 |
114 | dx = rx-lx
115 |
116 | dy_top_per_dx = (x2_ytop - x1_ytop) / dx
117 | dy_bot_per_dx = (x2_ybot - x1_ybot) / dx
118 | print("drawing from {} to {}".format(lx, rx))
119 | if lx < window_min:
120 | skip_x = window_min - lx
121 | cur_ytop += (dy_top_per_dx * skip_x)
122 | cur_ybot += (dy_bot_per_dx * skip_x)
123 | lx = window_min
124 |
125 | for x in range(lx, rx):
126 | draw_col(col, x, cur_ytop, cur_ybot)
127 | cur_ytop += dy_top_per_dx
128 | cur_ybot += dy_bot_per_dx
129 |
130 |
131 | def draw_col(color: (int,int,int), x: int, ytop: int, ybot: int):
132 | print("draw x: {}, {} to {}".format(x, ytop, ybot))
133 | ytop = int(max(0, ytop))
134 | ybot = int(min(RENDER_HEIGHT-1, ybot))
135 | renderer.draw_line((x, ytop, x, ybot), color)
136 | #sdl2.ext.line(surf, color, (x, ytop, x, ybot))
137 |
138 |
139 |
140 |
141 |
142 |
143 | def transform_vert(vert, cx, cy, cang):
144 | x,y = vert
145 | tlx = x - cx
146 | tly = y - cy
147 |
148 | rad_ang = math.radians(cang)
149 | sin_ang = math.sin(rad_ang)
150 | cos_ang = math.cos(rad_ang)
151 |
152 | rx = (tlx * sin_ang) - (tly * cos_ang)
153 | ry = (tlx * cos_ang) + (tly * sin_ang)
154 |
155 | return (rx,ry)
156 |
157 | def project_x(x, z):
158 | return 128 + (x / z)
159 |
160 | ASPECT_RATIO = (RENDER_WIDTH / RENDER_HEIGHT)
161 | CONST1 = RENDER_WIDTH/2
162 | CONST2 = ((RENDER_WIDTH/2) * SCALE / min(1, ASPECT_RATIO))
163 | CONST3 = (RENDER_HEIGHT/2)
164 | CONST4 = (RENDER_HEIGHT/2 * SCALE / max(1, ASPECT_RATIO))
165 |
166 | def project_y(y, z, player_z):
167 | rel_y = y - player_z
168 |
169 | scaled_y = (rel_y / z) * CONST4
170 |
171 | adj_y = CONST4 + scaled_y
172 |
173 | return (RENDER_HEIGHT-1) - adj_y
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/src/python/editor/requirements.txt:
--------------------------------------------------------------------------------
1 | imgui==1.4.1
2 | numpy==1.21.6
3 | PyOpenGL==3.1.6
4 | PySDL2==0.9.6
5 | pysdl2-dll==2.24.0
6 | Pillow==8.3.2
--------------------------------------------------------------------------------
/src/python/editor/run_editor.bat:
--------------------------------------------------------------------------------
1 | REM create virtualenv
2 | python -m venv ..\..\..\.venv
3 | REM activate virtualenv
4 | call ..\..\..\.venv\Scripts\activate.bat
5 | REM install dependencies if necessary
6 | python -m pip install -r requirements.txt
7 | REM set pysdl2 dll path
8 | set PYSDL2_DLL_PATH=..\..\..\.venv\Lib\site-packages\sdl2dll\dll\
9 | REM launch editor
10 | python editor.py
--------------------------------------------------------------------------------
/src/python/editor/script.py:
--------------------------------------------------------------------------------
1 | def draw_script_mode(cur_state):
2 | pass
3 |
--------------------------------------------------------------------------------
/src/python/editor/sprite_utils.py:
--------------------------------------------------------------------------------
1 | # rle compress image
2 | # scale RLE spans
3 |
4 | from PIL import Image
5 |
6 | SPRITE_SIZE = 64
7 |
8 | def rle_comp_seq(seq, max_len, is_empty, debug=False):
9 | skip_items = 0
10 | run_items = []
11 |
12 | runs = []
13 | got_items = False
14 |
15 | def finish_span_helper():
16 | nonlocal skip_items, run_items, got_items
17 | skip = skip_items
18 | run = run_items
19 | skip_items = 0
20 | run_items = []
21 | if skip != 0 or len(run) != 0:
22 | if len(run) != 0:
23 | got_items = True
24 | runs.append((skip,len(run),run))
25 |
26 | for item in seq:
27 | cur_run_len = len(run_items)
28 | in_run = cur_run_len != 0
29 |
30 | if is_empty(item):
31 | if in_run:
32 | finish_span_helper()
33 |
34 | if skip_items == max_len:
35 | finish_span_helper()
36 | skip_items += 1
37 | else:
38 | # if we were just skipping empty pixels so far, start keeping track of solid pixels
39 | if cur_run_len == max_len:
40 | finish_span_helper()
41 | run_items.append(item)
42 |
43 | finish_span_helper()
44 |
45 | #for idx,run in enumerate(runs):
46 | # if all((x[1] == 0 for x in run)):
47 | # runs[idx] =
48 | if got_items:
49 | while runs[-1][1] == 0:
50 | runs.pop()
51 |
52 | return runs
53 | else:
54 | return []
55 |
56 |
57 |
58 | def compile_image(path):
59 | im = Image.open(path)
60 | px = im.load()
61 |
62 | # all possible span sizes up to 32 input pixels have scales from 1 to 512 output pixels
63 |
64 | # 16.16 fixed point
65 | # indexed by (output<<5)|input
66 | #scale_table = [0]
67 | #for ipx in range(1, 32):
68 | # for opx in range(1, 513):
69 | # scale_fix = int((opx*65536)/ipx)
70 | # scale_table.append(scale_fix)
71 |
72 |
73 | columns = []
74 |
75 | def get_word_pix(x1,x2,x3,x4,y):
76 | p1 = px[x1,y]
77 | p2 = px[x2,y]
78 | p3 = px[x3,y]
79 | p4 = px[x4,y]
80 |
81 | p = p1<<12|p2<<8|p3<<4|p4
82 | return p
83 |
84 | def get_doubled_pix(x,y):
85 | p = px[x,y]
86 | return p<<4|p
87 |
88 | rle_compressed_columns = []
89 |
90 | # gathers four separate pixels into a word column, not going to work when scaling up, due to texel duplication
91 | for col in range(0, im.width):
92 | pix_row = []
93 | for row in range(SPRITE_SIZE):
94 | pix_row.append(get_doubled_pix(col, row))
95 | rle_compressed_columns.append(
96 | rle_comp_seq(
97 | pix_row,
98 | 63,
99 | lambda p: p==0
100 | )
101 | )
102 | """
103 | for col in range(0, im.width, 4):
104 | pix_row = []
105 | for row in range(SPRITE_SIZE):
106 | pix_row.append(get_word_pix(col, col+1, col+2, col+3, row))
107 |
108 | rle_compressed_columns.append(
109 | rle_comp_seq(
110 | pix_row,
111 | 256,
112 | lambda p: p==0
113 | )
114 | )
115 | """
116 | #rle_compressed_columns = [
117 | # rle_comp_seq(
118 | # (get_pix(col,col+1,row) for row in range(SIZE)),
119 | # 256,
120 | # lambda p: p==0
121 | # ) for col in range(0, im.width, 2)]
122 |
123 | num_spans = 0
124 | for col in rle_compressed_columns:
125 | num_spans += len(col)
126 |
127 | #res = [(x*2,col) for x,col in enumerate(rle_compressed_columns)]
128 | #print(res)
129 |
130 |
131 | #print(("scaled output size total: ", num_spans*511*2)) # 28 kilobytes... wow
132 | return rle_compressed_columns
133 |
134 | def half(n):
135 | ni = n//2
136 | nf = n/2
137 | assert ni == nf
138 | return ni
139 |
140 | def generate_c_for_column(column,name):
141 | column_c = ""
142 | c_texels = []
143 | c_spans = []
144 | for span in column:
145 | (skip,length,texels) = span
146 | for texel in texels:
147 | c_texels.append("{0:#04x}".format(texel))
148 | c_spans.append(str(skip))
149 | c_spans.append(str(length))
150 |
151 | if len(c_spans) != 0:
152 | c_spans_out = "const u16 col_{}_spans[{}] = ".format(name, len(c_spans)) + "{" + ",".join(c_spans) + "};"
153 | c_texels_out = "const u8 col_{}_texels[{}] = ".format(name, len(c_texels)) + "{" + ",".join(c_texels) + "};"
154 |
155 | column = "{" + ".num_spans = {}, .spans = col_{}_spans, .texels = col_{}_texels".format(half(len(c_spans)), name, name) + "}"
156 | else:
157 | c_spans_out = ""
158 | c_texels_out = ""
159 | column = "{.num_spans = 0, .spans = NULL, .texels = NULL}"
160 | return c_spans_out, c_texels_out, column
161 | #return ",".join(c_texels), ",".join(c_spans)
162 |
163 |
164 | if __name__ == '__main__':
165 |
166 | name = "test_texture"
167 | #columns = compile_image("./res/textures/sprites.png")
168 | #columns = compile_image("./res/textures/doobguy_3d_palette.png")
169 | columns = compile_image("./res/textures/doobguy.png")
170 | output = ""
171 | array_cols = []
172 |
173 |
174 |
175 | for idx, column in enumerate(columns):
176 | spns,txls,col = generate_c_for_column(column, idx)
177 | if spns != "":
178 | output += spns
179 | output += "\n"
180 | if txls != "":
181 | output += txls
182 | output += "\n"
183 | array_cols.append(col)
184 |
185 | output += "const rle_object test_obj = {\n"
186 | output += ".num_columns = {},\n".format(len(columns))
187 | output += ".columns = {\n"
188 | output += ",\n".join(array_cols)
189 | output += "\n}\n"
190 | output += "};\n"
191 | print(output)
--------------------------------------------------------------------------------
/src/python/editor/state.py:
--------------------------------------------------------------------------------
1 | import configparser
2 | import os
3 |
4 | import map
5 | from modes import Mode
6 | import utils
7 |
8 | class State(object):
9 | def __init__(self, cur_path):
10 | self.mode = Mode.SECTOR
11 | self.cur_sector = None
12 | self.cur_wall = None
13 | self.cur_vertex = None
14 | self.cur_thing = None
15 | self.cur_sector_group = None
16 | self.cur_sector_pvs = None
17 |
18 | self.last_sector_inside = None
19 |
20 | self.camera_x = 0
21 | self.camera_y = 0
22 | self.zoom = 0
23 |
24 |
25 | self.emulator_path = ""
26 | self.xgmtool_path = ""
27 | self.textures_path = "textures/"
28 | self.music_tracks_path = "music/"
29 | self.sprites_path = "sprites/"
30 |
31 | self.load_config(cur_path)
32 | tex_files = utils.get_texture_files(self)
33 | sprite_files = utils.get_sprite_files(self)
34 |
35 | self.hovered_item = None
36 |
37 | self.default_up_color = 3
38 | self.default_low_color = 3
39 | self.default_mid_color = 0
40 | self.default_floor_color = 4
41 | self.default_ceil_color = 5
42 | self.default_texture_file = tex_files[0]
43 | self.default_sprite_file = sprite_files[0]
44 | self.default_thing_type = 0
45 |
46 | self.map_data: map.Map = map.Map(self.default_sprite_file)
47 |
48 | def load_config(self, cur_path):
49 | conf_file_path = os.path.join(cur_path, "conf.ini")
50 | conf_exists = os.path.exists(conf_file_path)
51 | if not conf_exists:
52 | print("No configuration file, using defaults!")
53 | return
54 | config = configparser.ConfigParser()
55 | config.read(conf_file_path)
56 | self.emulator_path = config.get("Default Settings", "emulator-path")
57 | self.xgmtool_path = config.get("Default Settings", "xgmtool-path")
58 | self.textures_path = config.get("Default Settings", "textures-path")
59 | self.sprites_path = config.get("Default Settings", "sprites-path")
60 | self.music_tracks_path = config.get("Default Settings", "music-tracks-path")
61 | self.megalink_path = config.get("Default Settings", "megalink-path")
62 |
--------------------------------------------------------------------------------
/src/python/editor/texture_utils.py:
--------------------------------------------------------------------------------
1 | from PIL import Image
2 |
3 |
4 | def dpix(p):
5 | return (p << 4) | p
6 |
7 |
8 | TRANSPARENT_IDX = 0x0
9 | LIGHT_GREEN_IDX = 0x1
10 | LIGHT_RED_IDX = 0x2
11 | LIGHT_BLUE_IDX = 0x3
12 | LIGHT_BROWN_IDX = 0x4
13 | LIGHT_STEEL_IDX = 0x5
14 | GREEN_IDX = 0x6
15 | RED_IDX = 0x7
16 | BLUE_IDX = 0x8
17 | BROWN_IDX = 0x9
18 | STEEL_IDX = 0xA
19 | DARK_GREEN_IDX = 0xB
20 | DARK_RED_IDX = 0xC
21 | DARK_BLUE_IDX = 0xD
22 | DARK_BROWN_IDX = 0xE
23 | DARK_STEEL_IDX = 0xF
24 |
25 | dark_col_lut = [
26 | 0, GREEN_IDX, RED_IDX, BLUE_IDX, BROWN_IDX, STEEL_IDX,
27 | DARK_GREEN_IDX, DARK_RED_IDX, DARK_BLUE_IDX, DARK_BROWN_IDX, DARK_STEEL_IDX,
28 | DARK_GREEN_IDX, DARK_RED_IDX, DARK_BLUE_IDX, DARK_BROWN_IDX, DARK_STEEL_IDX
29 | ]
30 |
31 | light_col_lut = [
32 | 0, LIGHT_GREEN_IDX, LIGHT_RED_IDX, LIGHT_BLUE_IDX, LIGHT_BROWN_IDX, LIGHT_STEEL_IDX,
33 | LIGHT_GREEN_IDX, LIGHT_RED_IDX, LIGHT_BLUE_IDX, LIGHT_BROWN_IDX, LIGHT_STEEL_IDX,
34 | GREEN_IDX, RED_IDX, BLUE_IDX, BROWN_IDX, STEEL_IDX,
35 | ]
36 |
37 |
38 | def mpix(l, r, next_nib):
39 | return ((l << 4 | r) << 8) | (r << 4 | next_nib)
40 |
41 | def gen_textures_from_atlas(name, atlas_file):
42 | conv = []
43 | dconv = []
44 |
45 | def add_pix(arr, l, r):
46 | arr.append((dpix(l) << 8) | dpix(r))
47 |
48 | atlas = Image.open(atlas_file)
49 | all_pix = atlas.load()
50 |
51 | def pix(x, y):
52 | return all_pix[x, y], all_pix[x+64, y]
53 |
54 | TEX_SIZE = 64
55 |
56 | atlas_width, atlas_height = atlas.size
57 |
58 | #assert atlas_width == TEX_SIZE*2
59 |
60 | num_textures = atlas_height//TEX_SIZE
61 | assert num_textures * TEX_SIZE == atlas_height
62 |
63 | for tex in range(num_textures):
64 | base_y = tex*64
65 |
66 | for x in range(0, TEX_SIZE, 2):
67 | lx, rx = x, x + 1
68 | for y in range(TEX_SIZE):
69 | mid_l, dark_l = pix(lx, y+base_y)
70 | mid_r, dark_r = pix(rx, y+base_y)
71 | add_pix(conv, mid_l, mid_r)
72 | add_pix(dconv, dark_l, dark_r)
73 |
74 | names = []
75 | for (key, tbl) in [('mid', conv), ('dark', dconv),
76 | ]:
77 |
78 | gen_name = "raw_{}_tex_{}_{}".format(name, tex, key)
79 | names.append(gen_name)
80 | print("const u16 {}[{}*{}]".format(gen_name, len(tbl) // 64, 64) + " = {")
81 | for i, col in enumerate(tbl):
82 | print("0x{:02x}, ".format(col), end='')
83 | if i != 0 and i % 64 == 0:
84 | print("")
85 | print("\n};\n\n")
86 |
87 | mname = names[0]
88 | dname = names[1]
89 | for (level,d,m,l) in [("dark", dname, dname, mname),
90 | #("mid_dark", dname, mname),
91 | ("mid", dname, dname, mname),
92 | #("mid_light", mname, mname),
93 | ("light", mname, mname, mname)]:
94 |
95 | print("const lit_texture lit_{}_tex_{}_{} = {}".format(name, tex, level, '{'))
96 | print(" .dark = {}, .mid = {}, .light = {}".format(d, m, l))
97 | print("};")
98 |
99 | conv = []
100 | dconv = []
101 |
102 |
103 | def gen_texture_words_from_file(file):
104 | conv = []
105 | dconv = []
106 |
107 | def add_pix(arr, l, r):
108 | arr.append((dpix(l) << 8) | dpix(r))
109 |
110 | atlas = Image.open(file)
111 | all_pix = atlas.load()
112 |
113 | def pix(x, y):
114 | return all_pix[x, y], all_pix[x+64, y]
115 |
116 | TEX_SIZE = 64
117 |
118 | for x in range(0, TEX_SIZE, 2):
119 | lx, rx = x, x + 1
120 | for y in range(TEX_SIZE):
121 | mid_l, dark_l = pix(lx, y)
122 | mid_r, dark_r = pix(rx, y)
123 | add_pix(conv, mid_l, mid_r)
124 | add_pix(dconv, dark_l, dark_r)
125 | return conv, dconv
126 |
127 |
128 |
129 | def gen_mip_image(name, light_file, mid_file, dark_file):
130 | conv = []
131 | lconv = []
132 | dconv = []
133 |
134 |
135 | def add_pix(arr, l, r):
136 | arr.append((dpix(l) << 8) | dpix(r))
137 |
138 | light_img = Image.open(light_file)
139 | mid_img = Image.open(mid_file)
140 | dark_img = Image.open(dark_file)
141 |
142 | light_pix = light_img.load()
143 | mid_pix = mid_img.load()
144 | dark_pix = dark_img.load()
145 |
146 | def pix(x, y):
147 | return light_pix[x, y], mid_pix[x, y], dark_pix[x, y]
148 |
149 | mx, my = light_img.size
150 | assert light_img.size == mid_img.size
151 | assert mid_img.size == dark_img.size
152 |
153 | for x in range(0, mx, 2):
154 | lx, rx = x, x + 1
155 | for y in range(my):
156 | light_l, mid_l, dark_l = pix(lx, y)
157 | light_r, mid_r, dark_r = pix(rx, y)
158 |
159 | add_pix(lconv, light_l, light_r)
160 | add_pix(conv, mid_l, mid_r)
161 | add_pix(dconv, dark_l, dark_r)
162 |
163 |
164 | names = []
165 | for (key, tbl) in [('light', lconv), ('mid', conv), ('dark', dconv),
166 | ]:
167 | gen_name = "raw_{}_{}".format(name, key)
168 | names.append(gen_name)
169 | print("const u16 {}[{}*{}]".format(gen_name, len(tbl) // 64, 64) + " = {")
170 | for i, col in enumerate(tbl):
171 | print("0x{:02x}, ".format(col), end='')
172 | if i != 0 and i % 64 == 0:
173 | print("")
174 | print("\n};\n\n")
175 |
176 | dname = names[2]
177 | mname = names[1]
178 | lname = names[0]
179 | for (level,d,m,l) in [("dark", dname, dname, dname),
180 | ("mid_dark", dname, dname, mname),
181 | ("mid", dname, mname, lname),
182 | ("mid_light", mname, lname, lname),
183 | ("light", lname, lname, lname)]:
184 |
185 | print("const lit_texture {}_{} = {}".format(name, level, '{'))
186 | print(" .dark = {}, .mid = {}, .light = {}".format(d, m, l))
187 | print("};")
188 |
189 |
190 |
191 |
192 | if __name__ == '__main__':
193 |
194 |
195 |
196 |
197 | #gen_textures_from_atlas("tex_15col", "./res/textures/texture_atlas.png")
198 |
199 | gen_textures_from_atlas("texture_atlas_sprite_palette", "./res/textures/texture_atlas_sprite_palette.png")
200 |
201 |
--------------------------------------------------------------------------------
/src/python/editor/things.py:
--------------------------------------------------------------------------------
1 | import imgui
2 |
3 | import utils
4 | import undo
5 |
6 |
7 | KEY_TYPES = ['None', 'Blue key', 'Green key', 'Red key']
8 |
9 | class ThingDef(object):
10 | def __init__(self, sprite_file, name="", width=64, height=64, anchor_draw_offset=0, init_state=0, speed=3, anchor_top = False, anchor_bottom = True, key_type = 0):
11 | self.name = name
12 | self.sprite_file = sprite_file
13 | self.width = width
14 | self.height = height
15 | self.anchor_draw_offset = anchor_draw_offset
16 | self.init_state = init_state
17 | self.speed = speed
18 | self.anchor_top = anchor_top
19 | self.anchor_bottom = anchor_bottom
20 | self.key_type = key_type
21 | #def draw_things_mode(cur_state):
22 | # for i in range(cur_state.map_data.things):
23 |
24 | class Thing(object):
25 | def __init__(self, typ, sector_num, x, y, z, index):
26 | self.sector_num = sector_num
27 | self.object_type = typ
28 | self.x = x
29 | self.y = y
30 | self.z = z
31 | self.index = index
32 |
33 | def __str__(self):
34 | return "type: {}, sector: {}, x,y: {},{}".format(self.object_type, self.sector_num, self.x, self.y)
35 |
36 |
37 | def point_collides(self,x,y):
38 | radius = 10
39 | x1 = self.x
40 | y1 = self.y
41 | x2 = x
42 | y2 = y
43 |
44 | return utils.point_in_circle(x1,y1,x2,y2,radius)
45 |
46 | def draw_thing_defs_mode(cur_state):
47 |
48 |
49 | sprite_files = utils.get_sprite_files(cur_state)
50 |
51 |
52 | imgui.begin_child("thing defs")
53 | thing_defs = cur_state.map_data.thing_defs
54 | for idx,thing_def in enumerate(thing_defs):
55 |
56 | if thing_def.sprite_file == "":
57 | thing_def.sprite_file = sprite_files[0]
58 | def set_sprite_file(spr):
59 | undo.push_state(cur_state)
60 | thing_defs[idx].sprite_file = spr
61 |
62 | name_changed, new_name = imgui.input_text("name:##obj_name_{} ".format(idx), thing_defs[idx].name, buffer_length=32)
63 |
64 | utils.file_selector("sprite##obj_sprite_{}".format(idx), thing_def.sprite_file, sprite_files, set_sprite_file)
65 |
66 | width_changed, new_width = imgui.input_int("width:##obj_{}_width".format(idx), thing_defs[idx].width)
67 | height_changed, new_height = imgui.input_int("height:##obj_{}_height".format(idx), thing_defs[idx].height)
68 | speed_changed, new_speed = imgui.input_int("speed:##obj_{}_speed".format(idx), thing_defs[idx].speed)
69 | anchor_draw_off_changed, new_anchor_draw_offset = imgui.input_int("anchor draw offset:##obj_floor_draw_off{}".format(idx), thing_defs[idx].anchor_draw_offset)
70 |
71 | #state_options = ["idle","look for player", "follow player", "maybe get picked up"]
72 | state_options = ["static","look for player", "follow player", "maybe get picked up"]
73 |
74 | init_state_changed, new_init_state = imgui.core.combo("init state:##obj_{}_init_state".format(idx), thing_def.init_state, state_options)
75 |
76 | key_type_changed, new_key_type = imgui.core.combo("key type:##obj_{}_key_type".format(idx), thing_def.key_type, KEY_TYPES)
77 |
78 | anchor_top_changed, new_anchor_top = imgui.core.checkbox("anchor top##obj_{}_anchor_top".format(idx), thing_def.anchor_top)
79 | imgui.same_line()
80 | anchor_bot_changed, new_anchor_bot = imgui.core.checkbox("anchor bottom##obj_{}_anchor_bot".format(idx), thing_def.anchor_bottom)
81 |
82 |
83 | if name_changed:
84 | undo.push_state(cur_state)
85 | thing_defs[idx].name = new_name
86 |
87 | if width_changed:
88 | undo.push_state(cur_state)
89 | thing_defs[idx].width = new_width
90 |
91 | if height_changed:
92 | undo.push_state(cur_state)
93 | thing_defs[idx].height = new_height
94 |
95 | if speed_changed:
96 | undo.push_state(cur_state)
97 | thing_defs[idx].speed = new_speed
98 |
99 | if anchor_draw_off_changed:
100 | undo.push_state(cur_state)
101 | thing_defs[idx].anchor_draw_offset = new_anchor_draw_offset
102 |
103 | if init_state_changed:
104 | undo.push_state(cur_state)
105 | thing_defs[idx].init_state = new_init_state
106 |
107 | if anchor_top_changed:
108 | thing_defs[idx].anchor_top = new_anchor_top
109 |
110 | if anchor_bot_changed:
111 | thing_defs[idx].anchor_bottom = new_anchor_bot
112 |
113 | if key_type_changed:
114 | thing_defs[idx].key_type = new_key_type
115 |
116 | imgui.dummy(0, 10)
117 |
118 | imgui.end_child()
119 |
120 |
121 | def draw_things_mode(cur_state):
122 |
123 | if cur_state.cur_thing is not None:
124 | cur_thing = cur_state.cur_thing
125 | type_options = ['player'] + [ thing.name for thing in cur_state.map_data.thing_defs]
126 | type_changed, new_type = imgui.core.combo("type", cur_thing.object_type, type_options)
127 | if type_changed:
128 | cur_thing.object_type = new_type
129 |
130 | x_changed, new_x = imgui.input_int("x:##obj_x", cur_thing.x)
131 | if x_changed:
132 | cur_thing.x = new_x
133 | y_changed, new_y = imgui.input_int("y:##obj_y", cur_thing.y)
134 | if y_changed:
135 | cur_thing.y = new_y
136 |
137 | sector_opts = ["{}".format(idx) for idx in range(len(cur_state.map_data.sectors))]
138 |
139 | sect_changed,new_sect = imgui.core.combo("sector", cur_thing.sector_num, sector_opts)
140 | if sect_changed:
141 | cur_thing.sector_num = new_sect
142 |
143 |
144 | def print_thing(thing):
145 | if thing.object_type == 0:
146 | thing_name = ' player'
147 | else:
148 | thing_name = cur_state.map_data.thing_defs[thing.object_type-1].name
149 | return str(thing) + " name: {}".format(thing_name)
150 |
151 |
152 | def set_cur_thing(idx):
153 | cur_state.cur_thing = cur_state.map_data.things[idx]
154 |
155 | def delete_thing(thing):
156 | if cur_state.cur_thing == thing:
157 | cur_state.cur_thing = None
158 |
159 | for idx,cur_thing in enumerate(cur_state.map_data.things):
160 | if thing == cur_thing:
161 | undo.push_state(cur_state)
162 | del cur_state.map_data.things[idx]
163 | break
164 |
165 |
166 | utils.draw_list(cur_state, "Things", "Thing list", cur_state.map_data.things,
167 | set_cur_thing,
168 | delete_callback=delete_thing,
169 | print_item=print_thing)
--------------------------------------------------------------------------------
/src/python/editor/tree.py:
--------------------------------------------------------------------------------
1 | import imgui
2 | import sector
3 |
4 | def split_concave_sector(sect, cur_state):
5 | for wall in sect.walls:
6 | has_adj_wall,adj_wall = wall.find_adjacent_wall(cur_state.map_data)
7 | if has_adj_wall:
8 | print("Portal to this sector in sector {} might need to be split".format(adj_wall.sector_idx))
9 |
10 | if wall.adj_sector_idx != -1:
11 | print("Portal to sector {} might need to be split".format(wall.adj_sector_idx))
12 |
13 | # for each vertex in the sector
14 | # try to draw from that vertex to a new vertex, creating two partial sectors
15 | # check if both are convex
16 | # if they are, we're good.
17 |
18 | # if one is still concave, recursively split the extra concave sector
19 | # if
20 |
21 | sector_verts = sect.get_vertexes()
22 | num_verts = len(sector_verts)
23 | floor_height = sect.floor_height
24 | ceil_height = sect.ceil_height
25 |
26 | for i1 in range(1, num_verts):
27 | for i2 in range(num_verts):
28 | if i1 == i2:
29 | continue
30 | if abs(i2-i1) == 1:
31 | continue
32 |
33 | v1 = sector_verts[i1]
34 | v2 = sector_verts[i2]
35 |
36 | fst_sector = sector.Sector(index = sect.index+1, floor_height=floor_height, ceil_height=ceil_height)
37 | snd_sector = sector.Sector(index = sect.index+2, floor_height=floor_height, ceil_height=ceil_height)
38 | # how do we split the sector with these vertexes?
39 |
40 | # first sector starts at i2 and goes up to i1, then reconnects to i2
41 | print("first sector from vert {} to vert {}".format(i2, i1))
42 |
43 | # second sector starts at i1 and goes up to i2, then reconnects to i1
44 | print("second sector from vert {} to vert {}".format(i1, i2))
45 |
46 |
47 | fst_sector.add_wall()
48 |
49 | def split_concave_sectors(cur_state):
50 | for sect in cur_state.map_data.sectors:
51 | if sect.is_convex():
52 | continue
53 |
54 | split_concave_sector(sect, cur_state)
55 |
56 | print("Sector {} is concave, splitting".format(sect.index))
57 |
58 |
59 | # update cur_sector,wall,vertex?
60 |
61 |
62 | def draw_tree_mode(cur_state):
63 | disabled = all([s.is_convex() for s in cur_state.map_data.sectors])
64 |
65 | if not disabled:
66 | if imgui.button("Split concave sectors"):
67 | split_concave_sectors(cur_state)
68 |
69 | # any sectors connected to this sector
70 |
--------------------------------------------------------------------------------
/src/python/editor/trigger.py:
--------------------------------------------------------------------------------
1 | def draw_trigger_mode(cur_state):
2 | pass
3 |
--------------------------------------------------------------------------------
/src/python/editor/undo.py:
--------------------------------------------------------------------------------
1 | import copy
2 |
3 | undo_stack = []
4 | redo_stack = []
5 |
6 | def undo(cur_state, set_cur_state):
7 | global undo_stack, redo_stack
8 | if len(undo_stack) > 0:
9 | redo_stack.append(cur_state)
10 | if len(redo_stack) > 100:
11 | redo_stack = redo_stack[1:] # limit to max of 100 redo's
12 | set_cur_state(undo_stack.pop())
13 |
14 | def redo(cur_state, set_cur_state):
15 | global undo_stack, redo_stack
16 | if len(redo_stack) > 0:
17 | undo_stack.append(cur_state)
18 | if len(undo_stack) > 100:
19 | undo_stack = undo_stack[1:] # limit to max of 100 undo's
20 | set_cur_state(redo_stack.pop())
21 |
22 | # call before every user action that mutates the map data
23 | def push_state(cur_state):
24 | global undo_stack, redo_stack
25 | undo_stack.append(copy.deepcopy(cur_state))
26 | redo_stack = []
27 |
28 | def can_undo():
29 | return len(undo_stack) > 0
30 |
31 | def can_redo():
32 | return len(redo_stack) > 0
--------------------------------------------------------------------------------
/src/python/editor/vertex.py:
--------------------------------------------------------------------------------
1 | from utils import point_in_circle, input_int2, draw_list
2 | import imgui
3 | import undo
4 |
5 |
6 | class Vertex():
7 | def __init__(self, x, y, index):
8 | self.x = x
9 | self.y = y
10 | self.index = index
11 |
12 | def __str__(self):
13 | return "x: {} y: {}".format(self.x, self.y)
14 |
15 | def __eq__(self, other):
16 | if isinstance(other, Vertex):
17 | return self.x == other.x and self.y == other.y
18 | else:
19 | return False
20 |
21 | def point_collides(self,x,y):
22 | radius = 5
23 | x1 = self.x
24 | y1 = self.y
25 | x2 = x
26 | y2 = y
27 |
28 | return point_in_circle(x1,y1,x2,y2,radius)
29 |
30 |
31 |
32 |
33 | def draw_vert_mode(cur_state):
34 |
35 | if cur_state.cur_vertex is not None:
36 |
37 | cur_vertex = cur_state.cur_vertex
38 | imgui.text("Vertex {}".format(cur_vertex.index))
39 |
40 | def set_xy(xy):
41 | undo.push_state(cur_state)
42 | (x,y) = xy
43 | cur_state.cur_vertex.x = x
44 | cur_state.cur_vertex.y = y
45 |
46 | input_int2("x,y: ", "##vert{}_xy".format(cur_vertex.index), (cur_vertex.x, cur_vertex.y),
47 | set_xy)
48 |
49 |
50 |
51 | def set_cur_vertex(idx):
52 | cur_state.cur_vertex = cur_state.map_data.vertexes[idx]
53 |
54 | def delete_vertex(vert):
55 | if cur_state.cur_vertex == vert:
56 | cur_state.cur_vertex = None
57 | deleted_idx = None
58 | for idx,vertex in enumerate(cur_state.map_data.vertexes):
59 | if vert == vertex:
60 | undo.push_state(cur_state)
61 | del cur_state.map_data.vertexes[idx]
62 | deleted_idx = idx
63 | break
64 | if deleted_idx is not None:
65 | for idx,vertex in enumerate(cur_state.map_data.vertexes):
66 | vertex.index = idx
67 |
68 | # disable deleting vertexes for now
69 | # i'm not sure what it should do if you delete a vertex that's used by a line
70 | # maybe we should disallow it
71 | draw_list(cur_state, "Vertexes", "Vertex list",
72 | cur_state.map_data.vertexes,
73 | set_cur_vertex) #, delete_vertex)
74 |
75 |
--------------------------------------------------------------------------------
/src/python/editor/wad.py:
--------------------------------------------------------------------------------
1 | # load and save wad files
2 |
3 | # directory
4 |
5 | # BWAD -> base wad
6 |
7 | from io import BufferedRandom
8 | from typing import NewType
9 | from file_utils import read_u8, read_u16, read_u32
10 |
11 | WadHeader = NewType(dict[str, int])
12 | WadChunk = NewType(tuple[str, bytes])
13 |
14 |
15 | Wad = NewType(list[WadChunk])
16 |
17 | NAME_FIELD_LEN = 32
18 | def read_name(file: BufferedRandom) -> str:
19 | return str(file.read(NAME_FIELD_LEN))
20 |
21 |
22 | def read_wad_header(wad_file: BufferedRandom) -> WadHeader:
23 | # already read the tag and asserted that it was 'BWAD'
24 | num_directories = read_u16(wad_file)
25 | header = {}
26 | for i in range(num_directories):
27 | # name and offset (length can be in the directory itself?)
28 | # name is up to 32 characters
29 | nm = read_name(wad_file)
30 | off = read_u32(wad_file)
31 | header[nm] = off
32 | return WadHeader(header)
33 |
34 | def read_wad_chunks(wad_file: BufferedRandom, header: WadHeader) -> list[WadChunk]:
35 | chunks: list[WadChunk] = []
36 | for nm, off in header.items():
37 | wad_file.seek(off)
38 | chunk_len = read_u32(wad_file)
39 | chunks.append(WadChunk(tuple(nm, wad_file.read(chunk_len))))
40 | return chunks
41 |
42 |
43 |
44 | def read_wad(wad_file: BufferedRandom) -> Wad:
45 | tag = wad_file.read(4)
46 |
47 | assert tag == 'BWAD'
48 | header = read_wad_header(wad_file)
49 | chunks = read_wad_chunks(wad_file, header)
50 |
51 | return Wad(chunks)
52 |
53 |
54 | def export_to_rom(header, directories, wad_bytes):
55 | pass
--------------------------------------------------------------------------------
/src/python/gen_font_shadow_lut.py:
--------------------------------------------------------------------------------
1 | for i in range(257):
2 | lpix = i>>4
3 | rpix = i&0b1111
4 | lshad = rshad = 0
5 | if lpix > 0:
6 | lshad = 0b1110
7 | if rpix > 0:
8 | rshad = 0b1110
9 | print((lshad<<4)|rshad, end=',')
10 | if i != 0 and i % 16 == 0:
11 | print("")
--------------------------------------------------------------------------------
/src/python/gen_linedef_rasterizer.py:
--------------------------------------------------------------------------------
1 | def get_y_var_names(num):
2 | return [("y{}".format(i), "dy{}_dx".format(i)) for i in range(num)]
3 |
4 |
5 | def gen_rasterizer(bitmap):
6 | draw_upper_step = (bitmap & 0b1000) >> 3
7 | draw_lower_step = (bitmap & 0b0100) >> 2
8 | draw_ceiling = (bitmap & 0b0010) >> 1
9 | draw_floor = (bitmap & 0b0001)
10 |
11 | trace_upper_line = draw_upper_step | draw_ceiling
12 | trace_lower_line = draw_lower_step | draw_floor
13 |
14 | update_upper_clipping = trace_upper_line
15 | update_lower_clipping = trace_lower_line
16 |
17 | trace_neighbor_upper_line = draw_upper_step
18 | trace_neighbor_lower_line = draw_lower_step
19 | num_y_vars = (trace_upper_line + trace_neighbor_upper_line + trace_lower_line + trace_neighbor_lower_line)
20 |
21 | y_var_names = get_y_var_names(num_y_vars)
22 |
23 | print("for(int x = x0; x < x1; x++){")
24 | for y_var,y_var_dx in y_var_names:
25 | print(" {} += {};".format(y_var, y_var_dx))
26 | print("}")
27 |
28 |
29 | for bitmap in range(0b0001, 0b1111):
30 | gen_rasterizer(bitmap)
31 |
--------------------------------------------------------------------------------
/src/python/gen_postinc_tex_tables.py:
--------------------------------------------------------------------------------
1 | HEADER_TOP_CLIP = """
2 | | tex_column in a0, col_ptr in a1, top_clip in d0
3 | lsl.l #2, %d0
4 | jmp scale_64_{}_jump(%pc, %d0.w)
5 | """
6 |
7 | TABLE_HEADER_BOT_CLIP = """
8 | | tex_column in a0, col_ptr in a1, top_clip in d0, bot_clip in d1
9 | add.w %d1, %d0 | d0 = clip_top+clip_bot
10 | lsl.w #2, %d0 | d0 = (clip_top+clip_bot)<<=2
11 | move.l %a0, -(%sp) | stash tex_column for now
12 | move.l #skip_64_{}, %a0
13 | move.b 0(%a0, %d1.w), %d1 | d1 = texels to skip backwards
14 | | ext.w %d1 | extend d1 to a longword |ext.w %d1 | andi.w #255, %d1
15 | move.l (%sp)+, %a0
16 | sub.w %d1, %a0
17 | jmp scale_64_{}_jump(%pc, %d0.w)
18 |
19 | """
20 |
21 |
22 | # sadly, this doesnt seem to solve the problem
23 | # becuse there are different sources of error caused by jumping to the right/wrong position in the instruction stream
24 | HEADER_BOT_CLIP = """
25 | | tex_column in a0, col_ptr in a1, top_clip in d0, bot_clip in d1
26 | lsl.w #2, %d0 | d0 is top_clip * 4
27 | move.l %a0, -(%sp) | stash tex_column for now
28 | move.w scale_64_{}_jump+2(%pc, %d0.l), %a0 | a0 = expected offset
29 | lsl.w #2, %d1 | d1 is bot_clip * 4
30 | add.w %d1, %d0 | d0 = (top_clip*4+bot_clip*4)
31 | move.w scale_64_{}_jump+2(%pc, %d0.l), %d1 | d1 = actual offset
32 | sub.w %a0, %d1 | negative offset to use
33 | ext.w %d1 | extend d1 to a longword
34 | move.l (%sp)+, %a0
35 | sub.l %d1, %a0
36 | jmp scale_64_{}_jump(%pc, %d0.w)
37 | """
38 |
39 |
40 |
41 | for y in range(513):
42 | print(".globl scale_64_{}_top_clip".format(y))
43 | print(".globl scale_64_{}_bot_clip".format(y))
44 |
45 |
46 | print("scale_64_{}_top_clip:".format(y))
47 | if y == 0:
48 | print("rts")
49 | else:
50 | print(HEADER_TOP_CLIP.format(y))
51 |
52 | print("scale_64_{}_bot_clip:".format(y))
53 | if y == 0:
54 | print("rts")
55 | else:
56 | print(TABLE_HEADER_BOT_CLIP.format(y, y, y, y, y, y, y))
57 |
58 | if y == 0:
59 | continue
60 |
61 | du_per_dy = 64/y
62 | scaled = du_per_dy <= 1
63 | cur_u = 0
64 |
65 | print("scale_64_{}_jump:".format(y))
66 | if 0: #scaled:
67 |
68 |
69 | for yy in range(y):
70 | int_u = int(cur_u)
71 | cur_u += du_per_dy
72 | next_int_u = int(cur_u)
73 | if next_int_u > int_u+1:
74 | raise Exception("wtf")
75 | elif next_int_u == int_u+1:
76 | print(" move.w (%a0)+, (%a1)+")
77 | else:
78 | print(" move.w 0(%a0), (%a1)+")
79 | else:
80 |
81 | for yy in range(y):
82 | int_u = int(cur_u)
83 | cur_u += du_per_dy
84 | if int_u == 0:
85 | print("dc.w 0b0011001011101000, 0b0000000000000000")
86 | else:
87 | print("move.w {}(%a0), (%a1)+".format(2*int_u))
88 | print("rts")
89 |
90 |
91 |
92 | #print(".global skip_64_{}".format(y))
93 | #print("skip_64_{}:".format(y))
94 | #for yy in range(y):
95 | # int_u = int(cur_u)
96 | # cur_u += du_per_dy
97 | # print("dc.w {}".format(int_u))
98 |
99 |
100 | """
101 | for y in range(1,513):
102 | print("const u8 skip_64_{}[{}] = ".format(y, y) + "{")
103 | du_dy = 64/y
104 | for skip in range(y):
105 | print("{}, ".format(2*int(skip*du_dy)), end="")
106 | if skip % 40 == 0:
107 | print("")
108 | print("};")
109 | """
110 |
111 | #for y in range(1, 513):
112 | # print("skip_64_{}, ".format(y), end="")
113 | #
114 | # if y % 20 == 0:
115 | # print("")
116 |
117 | #for y in range(513):
118 | # print("extern void scale_64_{}_top_clip(void);".format(y))
119 | # print("extern void scale_64_{}_bot_clip(void);".format(y))
120 |
121 |
122 | #print("jump_table_top_clip_lut[513] = {")
123 | #for y in range(1, 513):
124 | # print("scale_64_{}_top_clip, ".format(y), end="")
125 | # if y % 8 == 0:
126 | # print("")
127 | #print("}")
128 |
129 | #print("jump_table_bot_clip_lut[513] = {")
130 | #for y in range(1, 513):
131 | # print("scale_64_{}_bot_clip, ".format(y), end="")
132 | # if y % 8 == 0:
133 | # print("")
134 | #print("}")
--------------------------------------------------------------------------------
/src/python/gen_recip_table.py:
--------------------------------------------------------------------------------
1 | def gen_table():
2 | pass
3 |
4 | if __name__ == '__main__':
5 | for z_12_4 in range(65536):
6 | if z_12_4 == 0:
7 | print(0, end=", ")
8 | continue
9 |
10 | val = int(1<<26)//z_12_4
11 | print(val, end=", ")
12 |
13 |
14 | if z_12_4 % 50 == 0:
15 | print("")
16 |
17 |
--------------------------------------------------------------------------------
/src/python/gen_sprite_scale_routine_tables.py:
--------------------------------------------------------------------------------
1 | # generate tables to update in-RAM sprite scaling routine
2 | names = []
3 | MAX_SIZE = 512
4 | for output_size in range(MAX_SIZE+1): #513):
5 | name = "sprite_scale_{}_table".format(output_size)
6 | names.append(name)
7 |
8 | print("const u16 {}[{}] = ".format(name, output_size) + "{", end='')
9 |
10 | scale = output_size/64
11 | if output_size == 0:
12 | texels_per_pixel = 0
13 | else:
14 | texels_per_pixel = 64/output_size
15 |
16 | cur_texel = 0
17 | for i in range(output_size):
18 | if i % 32 == 0:
19 | print("")
20 | print("{},".format(int(cur_texel)), end='')
21 | cur_texel += texels_per_pixel
22 |
23 | print("\n};")
24 |
25 | print("const u16* sprite_scale_routine_pointer_lut[{}] = ".format(len(names)) + "{", end="")
26 | for y in range(MAX_SIZE+1):
27 | if y % 4 == 0:
28 | print("")
29 | print("{}, ".format(names[y]), end='')
30 | print("};")
31 |
32 |
--------------------------------------------------------------------------------
/src/python/gen_sprite_scale_tables.py:
--------------------------------------------------------------------------------
1 | base = 64
2 |
3 | cnt = 0
4 |
5 | """
6 | # size of run lengths of M, for 64-texel bitmap scaled to N pixels
7 | print("{")
8 | for scaled_size in range(0,513):
9 | scale_factor = (scaled_size)/64
10 | for run_length in range(64):
11 | scaled_run_length = int((run_length)*65536*scale_factor)
12 | cnt += 1
13 | print(scaled_run_length, end=", ")
14 | if cnt % 16 == 0:
15 | print("")
16 | print("}")
17 |
18 | #for i in range(512):
19 | # # calculate texels per pixel
20 | """
21 |
22 | # number of
23 | print("u32 sprite_tex_per_pix[513] = {", end='')
24 | for scale in range(513):
25 | if scale % 32 == 0:
26 | print('')
27 | if scale == 0:
28 | tex_per_pix = 0
29 | else:
30 | tex_per_pix = int((64*65536)/scale)
31 |
32 | print("{},".format(tex_per_pix), end='')
33 | print("};")
--------------------------------------------------------------------------------
/src/python/optimizer.py:
--------------------------------------------------------------------------------
1 | import itertools, random
2 |
3 | def optimize_linedef_entries(entries):
4 | linedefs_with_vertexes = {}
5 | for (linedef,v1,v2) in entries:
6 | lst = linedefs_with_vertexes.get(v1, list())
7 | lst.append(linedef)
8 | linedefs_with_vertexes[v1] = lst
9 | lst2 = linedefs_with_vertexes.get(v2, list())
10 | lst2.append(linedef)
11 | linedefs_with_vertexes[v2] = lst2
12 | return linedefs_with_vertexes
13 |
14 | def count_vertex_transformations(entries):
15 | prev_vert = None
16 | transformations = []
17 | for (l,v1,v2) in entries:
18 | if v1 == prev_vert:
19 | # no transformations needed
20 | pass
21 | else:
22 | transformations.append(v1)
23 | transformations.append(v2)
24 | prev_vert = v2
25 | return transformations
26 |
27 |
28 | def get_linedefs_permutations(entries):
29 | linedef_to_verts = {}
30 | for (l,v1,v2) in entries:
31 | linedef_to_verts[l] = (v1,v2)
32 | permutations = itertools.permutations(l for (l,_,_) in entries)
33 |
34 | res = []
35 | for perm in permutations:
36 | perm2 = []
37 | for l in perm:
38 | (v1,v2) = linedef_to_verts[l]
39 | perm2.append((l,v1,v2))
40 | res.append(perm2)
41 | return res
42 |
43 | def swap_entry(entry):
44 | (l,v1,v2) = entry
45 | return (l,v2,v1)
46 |
47 |
48 | def get_vertex_swap_permutations(entries, prefixes=[]):
49 | #print("got {}".format(entries))
50 | #print("prefixes: {}".format(prefixes))
51 | if len(entries) == 0:
52 | res = prefixes
53 | elif len(entries) == 1:
54 | fst = entries[0]
55 | res = []
56 | for prefix in prefixes:
57 | res.append(prefix + [fst])
58 | res.append(prefix + [swap_entry(fst)])
59 |
60 | else:
61 | fst = entries[0]
62 | swapped_fst = swap_entry(fst)
63 | new_prefixes_fst = [pfx+[fst] for pfx in prefixes]
64 | new_prefixes_swp = [pfx+[swapped_fst] for pfx in prefixes]
65 | new_prefixes = new_prefixes_fst + new_prefixes_swp
66 | if len(new_prefixes) == 0:
67 | new_prefixes = [[fst], [swapped_fst]]
68 | res = get_vertex_swap_permutations(entries[1:], new_prefixes)
69 |
70 | #print("returning: {}".format(res))
71 | return res
72 |
73 |
74 | def get_all_possible_permutations(entries):
75 | res = []
76 | linedef_perms = get_linedefs_permutations(entries)
77 | for linedef_entries_permutation in linedef_perms:
78 | for vertex_perm in get_vertex_swap_permutations(linedef_entries_permutation):
79 | res.append(vertex_perm)
80 | return res
81 |
82 | def find_best_ordering(entries):
83 | best_score = None
84 | best_scoring = None
85 | for perm in get_all_possible_permutations(entries):
86 | transformations = count_vertex_transformations(perm)
87 | score = len(transformations)
88 | if best_scoring is None or score < best_score:
89 | best_scoring = perm
90 | best_score = score
91 |
92 | return best_scoring, best_score
93 |
94 |
95 |
96 |
97 | if __name__ == '__main__':
98 | entries = [(1,'v1','v2'),(2,'v2','v3'), (3,'v0','v1')]
99 | entries2 = [(1,'v1','v2'),(2,'v2','v3')]
100 |
101 | long_list = [(i, range(50)]
102 | #print(get_vertex_swap_permutations(entries))
103 | #print(get_vertex_swap_permutations(entries2))
104 |
105 | #print(get_all_possible_permutations(entries))
106 |
107 | print(find_best_ordering(entries))
108 |
109 |
--------------------------------------------------------------------------------
/src/python/profile.stats:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/python/profile.stats
--------------------------------------------------------------------------------
/src/python/span_buffer.py:
--------------------------------------------------------------------------------
1 | #from intervaltree import Interval, IntervalTree
2 |
3 | span_buffer = None
4 |
5 | def clear_span_buffer():
6 | pass
7 | #global span_buffer
8 | #span_buffer = IntervalTree()
9 |
10 | def does_interval_overlap(x1, x2):
11 | return span_buffer.overlaps(Interval(x1, x2))
12 |
13 |
14 | def get_clipped_draw_spans(x1, x2):
15 | overlapping_spans = span_buffer.overlap(x1, x2)
16 |
17 | #for span in spans:
18 |
19 | # if
20 |
21 |
22 | def insert_interval(x1, x2):
23 | pass
24 | #span_buffer[
25 |
26 |
27 | #def reset(max_width):
28 | #global span_buf
29 | #span_buf = [(0, max_width)]
30 |
31 | def __span_intersects_span(span1, span2):
32 | (span1_x1, span1_x2) = span1
33 | (span2_x1, span2_x2) = span2
34 |
35 |
36 | if span1_x2 < span2_x1:
37 | return False
38 |
39 | if span1_x1 > span2_x2:
40 | return False
41 |
42 | return True
43 |
44 |
45 |
46 | def span_intersects(span):
47 | for item in span_buf:
48 | if(__span_intersects_span(span, item)):
49 | return True
50 | return False
51 |
52 |
--------------------------------------------------------------------------------
/src/python/util.py:
--------------------------------------------------------------------------------
1 | import random
2 | import draw
3 |
4 | colors = []
5 |
6 |
7 | def rand_color():
8 | #while True:
9 | while len(colors) < 16:
10 |
11 | col = (random.randint(0, 255),
12 | random.randint(0, 255),
13 | random.randint(0, 255))
14 | colors.append(col)
15 |
16 | idx = random.randint(0, 15)
17 | return colors[idx]
18 | #if col != GRAY:
19 | # break
20 | return col
21 |
--------------------------------------------------------------------------------
/src/random.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 |
5 | const u8 rndtable[256] = {
6 | 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 ,
7 | 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 ,
8 | 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 ,
9 | 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 ,
10 | 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 ,
11 | 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 ,
12 | 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 ,
13 | 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 ,
14 | 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 ,
15 | 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 ,
16 | 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 ,
17 | 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 ,
18 | 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 ,
19 | 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 ,
20 | 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 ,
21 | 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 ,
22 | 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 ,
23 | 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 ,
24 | 120, 163, 236, 249
25 | };
26 | static u8 fx_idx = 0;
27 | static u8 det_idx = 0;
28 |
29 | // randomness for effects
30 | u8 fxrandom() {
31 | return rndtable[fx_idx++];
32 | }
33 |
34 | // deterministic random
35 | u8 detrandom() {
36 | return rndtable[det_idx++];
37 | }
--------------------------------------------------------------------------------
/src/random.h:
--------------------------------------------------------------------------------
1 | #ifndef RANDOM_H
2 | #define RANDOM_H
3 | #include
4 |
5 | u8 fxrandom();
6 |
7 | u8 detrandom();
8 |
9 | #endif
--------------------------------------------------------------------------------
/src/real_timer.c:
--------------------------------------------------------------------------------
1 | #include "genesis.h"
2 | #include "my_bmp.h"
3 | #include "real_timer.h"
4 |
5 |
6 |
7 | #define BASE_SHIFT 2
8 |
9 | // 0b0000000000000001 16ms
10 | // 0b0000000000000010 32ms
11 | // 0b0000000000000100 64ms
12 |
13 | //u32 frame_timer_masks[4] = {
14 | // ~0b0000000000000111, // sixteenth second
15 | // ~0b0000000000001111, // eighth second
16 | // ~0b0000000000011111, // quarter second
17 | // ~0b0000000000111111, // half second
18 | // ~0b0000000001111111, // second (1024ms)
19 | //};
20 |
21 | u32 frames_for_counters[5] = {
22 | 0,0,0,0,0
23 | };
24 |
25 | static u32 ms;
26 | void update_real_timer() {
27 | u32 vints = end_of_frame_vints;
28 | u32 vints_tmp = vints>>BASE_SHIFT;
29 | u32* frame_cnt_ptr = frames_for_counters;
30 | for(int i = 0; i < 5; i++) {
31 | *frame_cnt_ptr++ = vints_tmp;
32 | vints_tmp >>= 1;
33 | }
34 |
35 | u32 dvints = (end_of_frame_vints - prev_end_of_frame_vints);
36 |
37 | if(SYS_isNTSC()) {
38 | ms = dvints << 4;
39 | } else {
40 | u32 four_dvints = dvints <<2;
41 | u32 sixteen_dvints = dvints << 4;
42 | ms = four_dvints + sixteen_dvints;
43 | }
44 | if(ms > 1000) { ms = 1000; }
45 |
46 | }
47 |
48 | u32 ms_since_last_frame() {
49 | return ms;
50 | }
51 |
52 | u32 total_vints() {
53 | return end_of_frame_vints;
54 | }
--------------------------------------------------------------------------------
/src/real_timer.h:
--------------------------------------------------------------------------------
1 | #ifndef REAL_TIMER_H
2 | #define REAL_TIMER_H
3 |
4 | typedef enum {
5 | SIXTEENTH_SECOND,
6 | EIGHTH_SECOND,
7 | QUARTER_SECOND,
8 | HALF_SECOND,
9 | SECOND
10 | } frame_timers;
11 |
12 | extern u32 frames_for_counters[5];
13 |
14 | void update_real_timer();
15 | u32 ms_since_last_frame();
16 | u32 total_vints();
17 |
18 | #endif
--------------------------------------------------------------------------------
/src/sector_group.h:
--------------------------------------------------------------------------------
1 | #ifndef SECTOR_GROUP_H
2 | #define SECTOR_GROUP_H
3 |
4 | #include
5 | #include "portal_map.h"
6 |
7 | #define NUM_SECTOR_GROUP_PARAMS 8
8 | #define NUM_SECTOR_GROUP_PARAMS_SHIFT 3
9 |
10 | typedef struct __attribute__((__packed__)) {
11 | s8 light_level;
12 | u8 floor_ceil_color;
13 | } light_and_floor_ceil_color;
14 |
15 | // these params are actual sector group params
16 |
17 | // light level is only 3 bits, using 16 bits :(
18 | // 00000 light_level:3 ceil_col:4 floor_col:4
19 |
20 | #define SECTOR_GROUP_PARAM_LIGHT_FLOOR_CEIL_COLOR_IDX 0
21 | #define SECTOR_GROUP_PARAM_ORIG_HEIGHT_IDX 1
22 | // state is probably only 8 bits, could possibly be more than that eventually
23 | #define SECTOR_GROUP_PARAM_STATE_IDX 2
24 | #define SECTOR_GROUP_PARAM_TICKS_LEFT_IDX 3
25 | #define SECTOR_GROUP_PARAM_FLOOR_HEIGHT_IDX 4
26 | #define SECTOR_GROUP_PARAM_CEIL_HEIGHT_IDX 5
27 | #define SECTOR_GROUP_PARAM_SCRATCH_ONE_IDX 6
28 | #define SECTOR_GROUP_PARAM_SCRATCH_TWO_IDX 7
29 |
30 | #define NO_TYPE 0
31 | #define FLASHING 1
32 | #define DOOR 2
33 | #define LIFT 3
34 | #define STAIRS 4
35 | #define LOWERING_STAIRS 5
36 |
37 | #define NUM_SECTOR_GROUP_TYPES 6
38 |
39 | #define NO_KEYCARD 0b00000000
40 | #define BLUE_KEYCARD 0b00100000
41 | #define GREEN_KEYCARD 0b01000000
42 | #define RED_KEYCARD 0b01100000
43 |
44 | // use the top three bits for keycard mask
45 | // we can have up to 32 sector types?
46 | #define SECTOR_GROUP_KEYCARD_MASK 0b11100000
47 | #define SECTOR_GROUP_TYPE_MASK 0b00011111
48 |
49 | #define GET_SECTOR_GROUP_TYPE(typ_byte) ((typ_byte) & SECTOR_GROUP_TYPE_MASK)
50 | #define GET_SECTOR_GROUP_KEYCARD(typ_byte) ((typ_byte) & SECTOR_GROUP_KEYCARD_MASK)
51 |
52 | typedef enum {
53 | CLOSED,
54 | GOING_UP,
55 | OPEN,
56 | GOING_DOWN
57 | } door_lift_state;
58 |
59 | typedef enum {
60 | STAIRS_LOWERED = 0,
61 | STAIRS_MOVING = 1,
62 | STAIRS_RAISED = 2
63 | } stair_state;
64 |
65 | extern s16* live_sector_group_parameters;
66 | //extern sector_param* live_sector_parameters;
67 |
68 |
69 | s16* get_sector_group_pointer(u16 sect_group);
70 |
71 | s16 get_sector_group_orig_height(u16 sect_idx);
72 | s8 get_sector_group_light_level(u16 sect_idx);
73 | u16 get_sector_group_ticks_left(u16 sect_idx);
74 | u16 get_sector_group_state(u16 sect_idx);
75 | void set_sector_group_state(u16 sect_group, u16 state);
76 |
77 | s16 get_sector_group_floor_height(u16 sect_idx);
78 | void set_sector_group_floor_height(u16 sector_idx, s16 height);
79 |
80 | s16 get_sector_group_ceil_height(u16 sector_idx);
81 | void set_sector_group_ceil_height(u16 sector_idx, s16 height);
82 | u16 get_sector_group_floor_color(u16 sector_idx);
83 | u16 get_sector_group_ceil_color(u16 sector_idx);
84 |
85 | void run_sector_group_processes();
86 |
87 | typedef enum {
88 | NO_TRIGGER=0,
89 | SET_SECTOR_DARK=1,
90 | SET_SECTOR_LIGHT=2,
91 | START_STAIRS=3,
92 | LEVEL_END=4,
93 | } trigger_type;
94 |
95 | u16 get_sector_group_trigger_type(u16 sect_group);
96 | s16 get_sector_group_trigger_target(u16 sect_group, u8 tgt_idx);
97 |
98 |
99 | trigger_type activate_sector_group_enter_trigger(u16 sect_group);
100 |
101 | #endif
--------------------------------------------------------------------------------
/src/sfx.c:
--------------------------------------------------------------------------------
1 | #include "level.h"
2 | #include "sfx.h"
3 |
4 | int sfx_on = TRUE;
5 |
6 | #define NUM_SFX_CHANNELS 3
7 |
8 | u8 pcm_id[NUM_SFX_CHANNELS] = {0,0,0};
9 | u8 channels_in_use[NUM_SFX_CHANNELS] = {0,0,0}; // 0 means not in use, 1 means in use priority 0, 2 means 1, etc
10 | u8 sfx_channels[NUM_SFX_CHANNELS] = { SOUND_PCM_CH2, SOUND_PCM_CH3, SOUND_PCM_CH4 };
11 | void toggle_sfx(int menu_idx) {
12 | sfx_on = ! sfx_on;
13 | }
14 |
15 | void play_sfx(u8 id, u8 priority) {
16 | if(!sfx_on) { return; }
17 | //KLog_U2("playing sfx: ", id, " with priority: ", priority);
18 |
19 | // check for a free channel first
20 | for(int i = 0; i < NUM_SFX_CHANNELS; i++) {
21 | u8 ch_used = channels_in_use[i];
22 | s8 old_priority = ch_used-1;
23 | s8 pcm_equal = pcm_id[i] - id;
24 | s8 prio_diff = priority - (ch_used-1); // if 0, that means it's actually higher priority
25 |
26 | if(ch_used == 0) {
27 | //if(priority >= channels_in_use[i] && pcm_id[i] != id) { // sadly, we need to check this to make sure a sfx gets played if possible
28 | //KLog_U1("playing on unused channel: ", sfx_channels[i]);
29 | XGM_startPlayPCM(id, priority, sfx_channels[i]);
30 | //KLog_S2("playing id: ", id, " on channel: ", i+1);
31 | channels_in_use[i] = priority+1;
32 | //KLog_S3("ch used: ", ch_used, " prev priority: ", old_priority, " cur priority: ", priority);
33 | pcm_id[i] = id;
34 | return;
35 | }
36 | }
37 | // if no free channels, check for a lower priority channel
38 | for(int i = 0; i < NUM_SFX_CHANNELS; i++) {
39 | u8 ch_used = channels_in_use[i];
40 | s8 old_priority = ch_used-1;
41 | s8 pcm_equal = pcm_id[i] - id;
42 | s8 prio_diff = priority - (ch_used-1); // if 0, that means it's actually higher priority
43 |
44 | if((priority > old_priority) && (pcm_equal != 0)) {
45 | //if(priority >= channels_in_use[i] && pcm_id[i] != id) { // sadly, we need to check this to make sure a sfx gets played if possible
46 | //KLog_U1("playing on lower priority channel: ", sfx_channels[i]);
47 | XGM_startPlayPCM(id, priority, sfx_channels[i]);
48 | //KLog_S2("playing id: ", id, " on channel: ", i+1);
49 | channels_in_use[i] = priority+1;
50 | //KLog_S3("ch used: ", ch_used, " prev priority: ", old_priority, " cur priority: ", priority);
51 | pcm_id[i] = id;
52 | return;
53 | }
54 | }
55 | // dropped sfx sadly
56 | KLog_U1("dropped sfx :( %i", id);
57 | }
58 |
59 | u8 sound_hearable(u16 sound_src_sector_group, u16 dst_sector) {
60 | portal_map* map = (portal_map*)cur_portal_map;
61 |
62 |
63 | // if src_sector is reachable from the set of rendered sectors via up to one max sector between, play it
64 | for(int sect = 0; sect < cur_portal_map->num_sectors; sect++) {
65 | if(sector_group(sect, map) != sound_src_sector_group) {
66 | continue;
67 | }
68 | if(!sector_in_phs(dst_sector, sect, map)) {
69 | continue;
70 | }
71 | return 1;
72 | }
73 | return 0;
74 | }
75 |
76 | void propagate_sfx_from_sect_group(u8 id, u8 priority, u16 src_sector_group, u16 dst_sector) {
77 | if(sound_hearable(src_sector_group, dst_sector)) {
78 | play_sfx(id, priority);
79 | }
80 | }
81 |
82 | void update_sfx() {
83 | u8 playing_status = (XGM_isPlayingPCM(SOUND_PCM_CH2_MSK | SOUND_PCM_CH3_MSK | SOUND_PCM_CH4_MSK))>>1;
84 | //KLog_U3("bitmap ", playing_status&1, "", playing_status&2, "", playing_status&4);
85 | switch(playing_status) {
86 | case 0b000:
87 | channels_in_use[0] = 0;
88 | channels_in_use[1] = 0;
89 | channels_in_use[2] = 0;
90 | break;
91 | case 0b001:
92 | channels_in_use[1] = 0;
93 | channels_in_use[2] = 0;
94 | break;
95 | case 0b010:
96 | channels_in_use[0] = 0;
97 | channels_in_use[2] = 0;
98 | break;
99 | case 0b011:
100 | channels_in_use[2] = 0;
101 | break;
102 | case 0b100:
103 | channels_in_use[0] = 0;
104 | channels_in_use[1] = 0;
105 | break;
106 | case 0b101:
107 | channels_in_use[1] = 0;
108 | break;
109 | case 0b110:
110 | channels_in_use[0] = 0;
111 | break;
112 | case 0b111:
113 | break;
114 | }
115 | }
--------------------------------------------------------------------------------
/src/sfx.h:
--------------------------------------------------------------------------------
1 | #ifndef SFX_H
2 | #define SFX_H
3 |
4 | #include
5 |
6 | extern int sfx_on;
7 | void toggle_sfx();
8 | void update_sfx();
9 | void play_sfx(u8 id, u8 priority);
10 | void propagate_sfx_from_sect_group(u8 id, u8 priority, u16 src_sector_group, u16 dst_sector);
11 |
12 | #define SFX_OPEN_DOOR_ID 1
13 | #define SFX_CLOSE_DOOR_ID 2
14 | #define SFX_LIFT_GO_UP_ID 3
15 | #define SFX_JUMP1_ID 4
16 | #define SFX_JUMP2_ID 5
17 | #define SFX_SHOTGUN_ID 6
18 | #define SFX_SELECT_ID 7
19 | #define SFX_ENEMY_A_WAKE_ID 8
20 |
21 |
22 | #endif
--------------------------------------------------------------------------------
/src/sprite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ehaliewicz/Manifold/b6fe52a52344464de00bde4dc58a40f8b89cfc1a/src/sprite
--------------------------------------------------------------------------------
/src/tex_tables_lookup.h:
--------------------------------------------------------------------------------
1 | //extern const void const* jump_table_lut[513];
2 | extern void end_tables(void);
3 | extern const u8* const skip_table_lut[513];
4 | extern const void* const jump_table_top_clip_lut[513];
5 | extern const void* const jump_table_bot_clip_lut[513];
6 |
--------------------------------------------------------------------------------
/src/texture.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "colors.h"
3 | #include "config.h"
4 | #include "div_lut.h"
5 | #include "math3d.h"
6 | #include "texture.h"
7 | #include "textures.h"
8 | #include "tex_tables_lookup.h"
9 | #include "utils.h"
10 |
11 |
12 | // 64 pixels tall
13 | // 64 pixels wide
14 | // which means 64 rasterized columns
15 |
16 | #define Z_PERSP_MIN (100<<4)
17 |
18 | persp_params calc_perspective(u16 z1_12_4, u16 z2_12_4, u16 inv_z1, u16 inv_z2, u32 left_u_16, u32 right_u_16, u16 dx) {
19 | persp_params ret;
20 | //if (abs(z2_12_4 - z1_12_4) < Z_PERSP_MIN) {
21 | // u32 du_16 = right_u_16-left_u_16;
22 | // u32 du_dx_16 = du_16 / dx;
23 | // ret.left_u_16 = left_u_16;
24 | // ret.du_dx_16 = du_dx_16;
25 | // ret.needs_perspective = 0;
26 | // return ret;
27 | //}
28 | u32 one_over_z_26 = z_12_4_to_one_over_z_26[z1_12_4>>4];
29 | u32 one_over_z_end_26 = z_12_4_to_one_over_z_26[z2_12_4>>4];
30 |
31 |
32 | s32 d_one_over_z_26 = (one_over_z_end_26 - one_over_z_26);
33 |
34 | //u32 u_over_z_23 = (left_u_16<<(TRANS_Z_FRAC_BITS+7))/z1_12_4;
35 | //u32 u_over_z_end_23 = (right_u_16<<(TRANS_Z_FRAC_BITS+7))/z2_12_4;
36 |
37 | //u16 inv_z1_0_16 = 65536/(z1_12_4>>4);
38 | //u16 inv_z2_0_16 = 65536/(z2_12_4>>4);
39 | //u16 inv_z1_0_16 = z_recip_table_16[z1_12_4>>4];
40 | //u16 inv_z2_0_16 = z_recip_table_16[z2_12_4>>4];
41 | u32 u_over_z_23 = ((left_u_16)*(inv_z1))>>9; // 11+12
42 | u32 u_over_z_end_23 = ((right_u_16)*(inv_z2))>>9;
43 |
44 |
45 |
46 |
47 | //u32 u_over_z_end = (right_u_16<<8)/z2_12_4;
48 | //u32 u_over_z_23 = u_over_z<<19;
49 | //u32 u_over_z_end_23 = u_over_z_end<<19;
50 |
51 | s32 d_u_over_z_23 = (u_over_z_end_23 - u_over_z_23);
52 |
53 |
54 | ret.one_over_z_26 = one_over_z_26;
55 |
56 |
57 | ret.d_one_over_z_dx_26 = (d_one_over_z_26/dx);
58 |
59 | ret.u_over_z_23 = u_over_z_23;
60 | ret.d_u_over_z_dx_23 = d_u_over_z_23/dx;
61 | return ret;
62 | }
63 |
64 | typedef u8* (*top_clip_wall_fill_func)(u8* col_ptr, u16* tex_column, u16 clip_top);
65 | typedef u8* (*bot_clip_wall_fill_func)(u8* col_ptr, u16* tex_column, u16 clip_top, u16 clip_bot);
66 |
67 |
68 | void draw_texture_vertical_line(s16 unclipped_y0, u16 y0, s16 unclipped_y1, u8* col_ptr, const u16* tex_column) {
69 | u16 unclipped_dy = unclipped_y1;
70 | __asm volatile(
71 | "sub.w %1, %0"
72 | : "+d" (unclipped_dy)
73 | : "d" (unclipped_y0)
74 | );
75 |
76 | if(unclipped_dy > 512) { return; }
77 | __asm volatile(
78 | "add.l %1, %0\t\n\
79 | add.l %1, %0"
80 | : "+a" (col_ptr)
81 | : "d" (y0)
82 | );
83 |
84 | u16 clip_top = y0;//y0-unclipped_y0;
85 | __asm volatile(
86 | "sub.w %1, %0"
87 | : "+d" (clip_top)
88 | : "d" (unclipped_y0)
89 | );
90 | u16 f;// = unclipped_dy;
91 |
92 | register const u16* a0 asm ("%a0") = tex_column;
93 | register const u8* a1 asm ("%a1") = col_ptr;
94 |
95 | register const u32 d0 asm ("%d0") = clip_top;
96 |
97 | __asm volatile(
98 | "lsl.l #2, %6\t\n\
99 | move.l 0(%5, %6.w), %1\t\n\
100 | jsr (%1)"
101 | : "+a" (col_ptr)
102 | : "a" (f), "a" (a0), "a" (a1), "d" (d0), "a" (jump_table_top_clip_lut), "d" (unclipped_dy)
103 | );
104 |
105 | }
106 |
107 |
108 |
109 | void draw_bottom_clipped_texture_vertical_line(s16 unclipped_y0, u16 y0, s16 unclipped_y1, u16 y1, u8* col_ptr, const u16* tex_column) {
110 |
111 | u16 unclipped_dy = unclipped_y1;
112 | __asm volatile(
113 | "sub.w %1, %0"
114 | : "+d" (unclipped_dy)
115 | : "d" (unclipped_y0)
116 | );
117 |
118 | if(unclipped_dy > 512) { return; }
119 | s16 clipped_dy = y1-y0;
120 | if(clipped_dy <= 0) { return; }
121 | __asm volatile(
122 | "add.l %1, %0\t\n\
123 | add.l %1, %0"
124 | : "+a" (col_ptr)
125 | : "d" (y0)
126 | );
127 |
128 | u16 clip_top = y0;
129 | u16 clip_bot = unclipped_y1;
130 | __asm volatile(
131 | "sub.w %2, %0\t\n\
132 | sub.w %3, %1\t\n\
133 | "
134 | : "+d" (clip_top), "+d" (clip_bot)
135 | : "d" (unclipped_y0), "d" (y1)
136 | );
137 | u16 f;
138 | register const u32 d0 asm ("%d0") = clip_top;
139 | register const u32 d1 asm ("%d1") = clip_bot;
140 | register const u16* a0 asm ("%a0") = tex_column;
141 | register const u8* a1 asm ("%a1") = col_ptr;
142 |
143 |
144 | __asm volatile(
145 | "lsl.l #2, %7\t\n\
146 | move.l 0(%6, %7.w), %1\t\n\
147 | jsr (%1)\t\n\
148 | "
149 | : "+a" (col_ptr)
150 | : "a" (f), "a" (a0), "a" (a1), "d" (d0), "d" (d1), "a" (jump_table_bot_clip_lut), "d" (unclipped_dy)
151 | );
152 |
153 | }
154 |
155 |
--------------------------------------------------------------------------------
/src/texture.h:
--------------------------------------------------------------------------------
1 | #ifndef TEXTURE_H
2 | #define TEXTURE_H
3 |
4 | #include
5 |
6 | //#define TEX_HEIGHT 128
7 | //#define TEX_HEIGHT_SHIFT 7
8 |
9 | //#define TEX_WIDTH 64
10 | //#define TEX_WIDTH_SHIFT 6
11 | #define TEX_WIDTH 32
12 | #define TEX_WIDTH_SHIFT 5
13 |
14 | #define TEX_HEIGHT 64
15 | #define TEX_HEIGHT_SHIFT 6
16 | //#define TEX_WIDTH 32
17 | //#define TEX_WIDTH_SHIFT 5
18 |
19 | extern u16* dark_texture;
20 | extern u16* mid_texture;
21 | extern u16* light_texture;
22 | void tick_texture();
23 |
24 |
25 | typedef struct __attribute__((__packed__)) {
26 | const uint16_t* const dark;
27 | const uint16_t* const mid;
28 | const uint16_t* const light;
29 | } lit_texture;
30 |
31 | typedef struct __attribute__((__packed__)) {
32 | uint8_t num_frames;
33 | uint8_t frequency;
34 | uint8_t frame_0_idx;
35 | } anim_texture;
36 |
37 | typedef struct {
38 | u32 left_u; // 16.16
39 | s16 left_z;
40 | u32 right_u; // 16.16
41 | s16 right_z;
42 | s32 du_over_dz;
43 | u8 repetitions;
44 | lit_texture* tex;
45 | u8 needs_texture;
46 | } texmap_params;
47 |
48 | typedef struct {
49 | u32 one_over_z_26;
50 | s32 d_one_over_z_dx_26;
51 |
52 | u32 u_over_z_23;
53 | u32 d_u_over_z_dx_23;
54 | } persp_params;
55 |
56 | persp_params calc_perspective(u16 z1_12_4, u16 z2_12_4, u16 inv_z1, u16 inv_z2, u32 left_u_16, u32 right_u_16, u16 dx);
57 |
58 | #define FAR_MIP_WIDTH 16
59 | #define FAR_MIP_WIDTH_SHIFT 4
60 | #define FAR_MIP_HEIGHT 64
61 |
62 | #define MID_MIP_WIDTH 32
63 | #define MID_MIP_WIDTH_SHIFT 5
64 | #define MID_MIP_HEIGHT 64
65 |
66 | #define NEAR_MIP_WIDTH 64
67 | #define NEAR_MIP_WIDTH_SHIFT 6
68 | #define NEAR_MIP_HEIGHT 64
69 |
70 | // three mipmap levels
71 |
72 |
73 | //typedef struct {
74 | // lit_texture mip_far;
75 | // lit_texture mip_mid;
76 | // lit_texture mip_near;
77 | //} texture_set;
78 |
79 |
80 | void draw_texture_vertical_line(s16 unclipped_y0, u16 y0, s16 unclipped_y1, u8* col_ptr, const u16* tex_column);
81 |
82 | void draw_bottom_clipped_texture_vertical_line(s16 unclipped_y0, u16 y0, s16 unclipped_y1, u16 y1, u8* col_ptr, const u16* tex_column);
83 |
84 | #endif
--------------------------------------------------------------------------------
/src/textures.h:
--------------------------------------------------------------------------------
1 | #ifndef TEXTURES_H
2 | #define TEXTURES_H
3 |
4 | #include
5 | #include "texture.h"
6 |
7 | //extern const lit_texture wall_texture;
8 | //extern const lit_texture sci_fi_wall_texture;
9 | extern const lit_texture door_mid;
10 |
11 | #define NUM_TEXTURES 5
12 |
13 | //extern lit_texture* const textures[8*5];
14 |
15 | //const u16 raw_key_mid[2048];
16 | //const u16 raw_key_32_32_mid[2048];
17 |
18 | lit_texture* get_texture(u8 tex_idx, s8 light_level);
19 |
20 | #endif
--------------------------------------------------------------------------------
/src/tile.h:
--------------------------------------------------------------------------------
1 | #ifndef TILE_H
2 | #define TILE_H
3 |
4 |
5 | typedef union {
6 | u8 bytes[8][4];
7 | u32 rows[8];
8 | } tile;
9 |
10 | typedef struct {
11 | u8 bytes[4*8]; // 4 columns 8 rows tall each
12 | } two_pix_col_tile;
13 |
14 | #endif
--------------------------------------------------------------------------------
/src/utils.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "utils.h"
4 |
5 |
6 | #define SUB_16_16(a, b) do { \
7 | __asm volatile( \
8 | "sub.w %1, %0" \
9 | : "+d" (a) \
10 | : "d" (b) \
11 | ); \
12 | } while(0);
13 |
14 |
15 | u16 sub_16_16(u16 a, u16 b) {
16 | __asm volatile(
17 | "sub.w %1, %0"
18 | : "+d" (a)
19 | : "d" (b)
20 | );
21 | return a;
22 | }
23 |
24 | u32 fastLength(s32 dx, s32 dy) {
25 | u32 adx = abs(dx);
26 | u32 ady = abs(dy);
27 | return (adx > ady) ? (adx + (ady >> 1)) : (ady + (adx >> 1));
28 | }
29 |
30 |
31 | void die(char* msg) {
32 | while(1) {
33 | VDP_drawTextBG(BG_B, msg, 2, 12);
34 | VDP_waitVInt();
35 | }
36 | }
37 |
38 |
39 | void assert(int expr, char* msg) {
40 | if(!expr) {
41 | die(msg);
42 | }
43 | }
44 |
45 | static char buf[80];
46 | void* malloc(u16 size, const char* thing) {
47 | sprintf(buf, "allocating %i bytes for %s", size, thing);
48 | KLog(buf);
49 | void* p = MEM_alloc(size);
50 | KLog_U1("allocated pointer: ", (u32)p);
51 | return p;
52 | }
53 |
54 | void free(void* thing, const char* thing2) {
55 | sprintf(buf, "freeing %s", thing2);
56 | KLog(buf);
57 | MEM_free(thing);
58 | }
--------------------------------------------------------------------------------
/src/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILS_H
2 | #define UTILS_H
3 | #include
4 |
5 |
6 | #define SCREEN_WIDTH BMP_PITCH
7 | #define SCREEN_HEIGHT 144 // BMP_HEIGHT // H
8 |
9 | //s16 divs_32_by_16(s32 num, s16 denom);
10 |
11 | //u16 divu_32_by_16(u32 num, u16 denom);
12 | //u32 mulu_16_by_16(u16 a, u16 b);
13 |
14 | //s32 muls_16_by_16(u16 a, u16 b);
15 | u16 sub_16_16(u16 a, u16 b);
16 |
17 |
18 | #define FETCH_INC_BYTE(var, ptr) do {\
19 | __asm volatile( \
20 | "move.b (%1)+, %0" \
21 | : "=d" (var), "+a" (ptr) \
22 | ); \
23 | } while(0);
24 |
25 | #define FETCH_INC_WORD(var, ptr) do {\
26 | __asm volatile( \
27 | "move.w (%1)+, %0" \
28 | : "=d" (var), "+a" (ptr) \
29 | ); \
30 | } while(0);
31 |
32 | #define WRITE_WORD_INC(var, ptr) do {\
33 | __asm volatile( \
34 | "move.w %1, (%0)+" \
35 | : "+a" (ptr) \
36 | : "d" (var) \
37 | ); \
38 | } while(0);
39 |
40 | #define WRITE_BYTE_INC(var, ptr) do {\
41 | __asm volatile( \
42 | "move.b %1, (%0)+" \
43 | : "+a" (ptr) \
44 | : "d" (var) \
45 | ); \
46 | } while(0);
47 |
48 | #define COPY_BYTE_POSTINC_SRC_QINC_4_DST(src, dst) do { \
49 | __asm volatile( \
50 | "move.b (%0)+, (%1)\t\naddq.l #4, %1" \
51 | : "+a" (src), "+a" (dst) \
52 | : \
53 | ); \
54 | } while(0);
55 |
56 | #define WRITE_BYTE_QINC_4(var, ptr) do { \
57 | __asm volatile( \
58 | "move.b %1, (%0)\t\naddq.l #4, %0" \
59 | : "+a" (ptr) \
60 | : "d" (var) \
61 | ); \
62 | } while(0);
63 |
64 | #define WRITE_BYTE(var, ptr) do {\
65 | __asm volatile( \
66 | "move.b %1, (%0)" \
67 | : "+a" (ptr) \
68 | : "d" (var) \
69 | ); \
70 | } while(0);
71 |
72 | inline u16 divu_32_by_16(u32 num, u16 denom) {
73 | __asm volatile(
74 | "divu.w %1, %0"
75 | : "+d" (num) // output
76 | : "d" (denom)
77 | );
78 |
79 | s16 res = num;
80 | return res;
81 | }
82 |
83 |
84 | inline u32 mulu_16_by_16(u16 a, u16 b) {
85 | u32 a32 = a;
86 | __asm volatile(
87 | "mulu.w %1, %0"
88 | : "+d" (a32) // output
89 | : "d" (b)
90 | );
91 | return a32;
92 | }
93 |
94 | inline s16 divs_32_by_16(s32 num, s16 denom) {
95 | __asm volatile(
96 | "divs.w %1, %0"
97 | : "+d" (num) // output
98 | : "d" (denom)
99 | );
100 |
101 | s16 res = num;
102 | return res;
103 | }
104 |
105 |
106 | inline s32 muls_16_by_16(s16 a, s16 b) {
107 | s32 a32 = a;
108 | __asm volatile(
109 | "muls.w %1, %0"
110 | : "+d" (a32) // output
111 | : "d" (b)
112 | );
113 | return a32;
114 | }
115 |
116 |
117 | void die(char* s);
118 |
119 | u32 fastLength(s32 dx, s32 dy);
120 |
121 |
122 |
123 | inline u16 fastLength16(s16 dx, s16 dy) {
124 | u16 adx = abs(dx);
125 | u16 ady = abs(dy);
126 | return (adx > ady) ? (adx + (ady >> 1)) : (ady + (adx >> 1));
127 | /*
128 |
129 | __asm volatile(
130 | "tst.w %0\t\n\
131 | bpl.b to_there%=\t\n\
132 | neg.w %0\t\n\
133 | to_there%=:\n"
134 | : "+d" (dx) : : "cc"
135 | );
136 | __asm volatile(
137 | "tst.w %0\t\n\
138 | bpl.b to_there%=\t\n\
139 | neg.w %0\t\n\
140 | to_there%=:\n"
141 | : "+d" (dy) : : "cc"
142 | );
143 | return (dx > dy) ? (dx + (dy >> 1)) : (dy + (dx >> 1));
144 | */
145 | }
146 |
147 | void die(char* msg);
148 | void assert(int expr, char* msg);
149 |
150 | #define clamp(a, mi,ma) min(max(a,mi),ma)
151 |
152 | void* malloc(u16 size, const char* thing);
153 | void free(void* thing, const char* thing2);
154 |
155 | #endif
--------------------------------------------------------------------------------
/src/vertex.h:
--------------------------------------------------------------------------------
1 | #ifndef VERTEX_H
2 | #define VERTEX_H
3 |
4 | #include
5 |
6 | typedef struct __attribute__((__packed__)) {
7 | s16 x, y;
8 | } vertex;
9 |
10 |
11 | typedef struct __attribute__((__packed__)) {
12 | fix32 x, y;
13 | } vertex_f32;
14 |
15 | #endif
--------------------------------------------------------------------------------
/src/vwf.c:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 | #include "vwf.h"
3 |
4 | #define DIVIDE_ROUND_UP(a,b) (((a) + ((b)-1))/(b))
5 |
6 |
7 |
8 | void vwf_init() {
9 | }
10 |
11 | void vwf_cleanup() {
12 | }
13 |
14 | int vwf_count_tiles(char* string, int len) {
15 | int num_pairs = 0;
16 | for(int i = 0; i < len; i++) {
17 | char c = string[i];
18 | int cur_num_pairs = charmap[c-32].width;
19 | if(cur_num_pairs == 0 || cur_num_pairs > PAIRS_IN_TILE) {
20 |
21 | char buf[32]; sprintf(buf, "wtf %i/%c %i", c, c, cur_num_pairs);
22 | KLog(buf);
23 | die(buf); } // die("wtf"); }
24 |
25 |
26 | num_pairs += cur_num_pairs;
27 | }
28 | int int_tiles = num_pairs / PAIRS_IN_TILE;
29 | if ((int_tiles * PAIRS_IN_TILE) != num_pairs) {
30 | int_tiles++;
31 | }
32 | return int_tiles;
33 |
34 | //return DIVIDE_ROUND_UP(num_pairs, PAIRS_IN_TILE);
35 | }
36 |
37 |
38 | u8 dummy_col[9] = {
39 | 0b0000000,
40 | 0b0000000,
41 | 0b0000000,
42 | 0b0000000,
43 | 0b0000000,
44 | 0b0000000,
45 | 0b0000000,
46 | 0b0000000,
47 | 0b0000000,
48 | };
49 |
50 | const u8 multicolor_shadow_lut[256] = {
51 | 0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,224,
52 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
53 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
54 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
55 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
56 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
57 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
58 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
59 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
60 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
61 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
62 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
63 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
64 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
65 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,224,
66 | 238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,
67 | };
68 |
69 | // render a string into 8x8 tiles, return number of characters processed
70 | static int cnt;
71 | int vwf_render_tiles(char* string, int len, tile* tiles, int num_tiles) {
72 | cnt++;
73 | if(cnt > 3) { cnt = 0; }
74 |
75 |
76 | int tile_num = 0;
77 | int pos_in_tile = 0;
78 |
79 | tile* cur_tile = tiles;
80 |
81 | int i;
82 | for(i = 0; i < len; i++) {
83 | char c = string[i];
84 | const char_entry* centr = &(charmap[c-32]);
85 |
86 | int char_width = centr->width;
87 | two_pix_col_tile til = centr->bitmap;
88 |
89 | if(tile_num == num_tiles-1 && pos_in_tile + char_width > PAIRS_IN_TILE) {
90 | // can't render this, return number of characters rendered
91 | break;
92 | }
93 |
94 |
95 | // render 1 byte, 2 pixel pair at once
96 |
97 | //this is with y then x ordering
98 | u8* output_ptr = &cur_tile->bytes[0][pos_in_tile];
99 | u8* input_ptr = til.bytes;//[0][0];
100 | u16 pix_mask = 0xFF;//0b00010001;
101 |
102 |
103 | u8* above_left_ptr = &dummy_col[0];
104 |
105 | for(int pair_x = 0; pair_x < char_width; pair_x++) {
106 | u8* col_output_ptr = output_ptr;
107 | u8 above_byte = 0;
108 | u8* col_input_ptr = input_ptr;
109 | u8 filled_pixel_mask; u8 cur_byte;
110 |
111 | // fill in top two pix
112 | FETCH_INC_BYTE(cur_byte, col_input_ptr);
113 | WRITE_BYTE_QINC_4(cur_byte, col_output_ptr);
114 | above_byte = cur_byte;
115 |
116 |
117 | for(int y = 1; y < 8; y++) {
118 |
119 | // clear only pixels with font
120 |
121 | // shadow from above
122 | // the ordering of this is not good.
123 |
124 |
125 | // shadow for single color font
126 | u8 above_left_byte; //*above_left_ptr++;
127 | FETCH_INC_BYTE(above_left_byte, above_left_ptr);
128 | above_left_byte <<= 4;
129 | u8 shadow_pix = above_byte; //(above_byte >> 4) | (above_left_byte << 4);
130 | shadow_pix >>= 4;
131 | shadow_pix |= above_left_byte;
132 |
133 | //shadow_pix = multicolor_shadow_lut[shadow_pix];
134 | __asm volatile(
135 | "\t\n\
136 | and.w %2, %0\t\n\
137 | move.b (%1, %0.w), %0\t\n\
138 | "
139 | : "+d" (shadow_pix)
140 | : "a" (multicolor_shadow_lut), "d" (pix_mask)
141 | );
142 |
143 | FETCH_INC_BYTE(cur_byte, col_input_ptr);
144 |
145 | shadow_pix |= cur_byte;
146 | WRITE_BYTE_QINC_4(shadow_pix, col_output_ptr);
147 |
148 | above_byte = cur_byte;
149 |
150 |
151 | }
152 |
153 | output_ptr++;
154 | above_left_ptr = input_ptr;
155 | input_ptr += 8;
156 |
157 | pos_in_tile += 1;
158 |
159 | if (pos_in_tile == PAIRS_IN_TILE) {
160 | tile_num += 1;
161 | cur_tile++;
162 | pos_in_tile = 0;
163 | output_ptr = (u8*)cur_tile; //&cur_tile->bytes[0][0];
164 | }
165 | }
166 |
167 |
168 | }
169 |
170 | return i;
171 | }
172 |
173 | int vwf_render_to_separate_tiles(char* string, int len, tile* tiles, int num_tiles) {
174 |
175 | // NOTE: this no longer works as ive changed the text to be column based!
176 | int tile_num = 0;
177 | int pos_in_tile = 0;
178 |
179 | tile* cur_tile = tiles;
180 |
181 | for(int i = 0; i < len; i++) {
182 | char c = string[i];
183 | const char_entry* centr = &(charmap[c-32]);
184 |
185 | int char_width = centr->width;
186 | two_pix_col_tile til = centr->bitmap;
187 |
188 | if(tile_num == num_tiles-1 && pos_in_tile + char_width > PAIRS_IN_TILE) {
189 | // can't render this, return number of characters rendered
190 | return i;
191 | }
192 |
193 | memcpy(cur_tile->bytes, &til.bytes, sizeof(tile));
194 | tile_num += 1;
195 | cur_tile++;
196 |
197 | }
198 |
199 | return len;
200 | }
201 |
--------------------------------------------------------------------------------
/src/vwf.h:
--------------------------------------------------------------------------------
1 | #ifndef FONT_H
2 | #define FONT_H
3 |
4 | #include
5 | #include "tile.h"
6 |
7 | #define NUM_CHARS 96
8 | #define PAIRS_IN_TILE 4
9 |
10 |
11 | typedef struct {
12 | char chr;
13 | int width; // width in 2-pixel pairs (bytes), always a minimum of two, so we can write words at once
14 | two_pix_col_tile bitmap;
15 | } char_entry;
16 |
17 | extern const char_entry charmap[96];
18 |
19 | void vwf_init();
20 | int vwf_render_tiles(char* string, int len, tile* tiles, int num_tiles);
21 | int vwf_render_to_separate_tiles(char* string, int len, tile* tiles, int num_tiles);
22 | int vwf_count_tiles(char* string, int len);
23 | void vwf_cleanup();
24 |
25 | #endif
--------------------------------------------------------------------------------
/src/weapon_sprites.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "weapon_sprites.h"
4 | #include "sprites_res.h"
5 | #include "utils.h"
6 |
7 | #define MAX_SPRITE_TILES 97
8 | #define MAX_SPRITES 16
9 |
10 | static u32 start_tile_loc;
11 | static u16 cur_num_sprites;
12 | static u16 sprite_idx_start;
13 |
14 | // frame index
15 | // time til next frame
16 |
17 | typedef enum {
18 | SHOTGUN_SPR=0,
19 | SHOTGUN_RELOAD_SPR=1,
20 | } weapon_sprite;
21 |
22 | typedef struct {
23 | u8 spr;
24 | s16 time;
25 | u16 next_anim;
26 | u8 anim_idx; u8 frame_idx;
27 | } animation_entry;
28 |
29 |
30 |
31 |
32 | animation_entry anim_table[] = {
33 | {
34 | .spr = SHOTGUN_SPR,
35 | .time = -1,
36 | .next_anim = 0,
37 | },
38 | {
39 | .spr = SHOTGUN_RELOAD_SPR,
40 | .time = 3, // 2 frames
41 | .next_anim = 2,
42 | .anim_idx = 0, .frame_idx = 0,
43 | },
44 | {
45 | .spr = SHOTGUN_RELOAD_SPR,
46 | .time = 3, // 2 frames
47 | .next_anim = SHOTGUN_IDLE_ANIM, // back to idle
48 | .anim_idx = 0, .frame_idx = 1,
49 | }
50 | };
51 |
52 | static s16 cur_frame_timer;
53 | static u16 cur_anim_idx;
54 | SpriteDefinition *cur_sprite_def;
55 |
56 | typedef enum {
57 | DONE=0,
58 | TILES_LOADING = 1,
59 | SPRITES_LOADING = 2,
60 | } update_state;
61 |
62 | u8 transfer_pending = 0;
63 | u8 pre_queue_size = 0;
64 |
65 |
66 | void update_weapon_sprites(TransferMethod transfer_type);
67 |
68 | void step_weapon_animation(TransferMethod transfer_type) {
69 | if(cur_frame_timer == -1) {
70 | if(transfer_pending != DONE) {
71 | if(DMA_getQueueSize() == pre_queue_size) {
72 | transfer_pending = DONE;
73 | update_weapon_sprites(transfer_type);
74 | }
75 | }
76 | return;
77 | }
78 | if(cur_frame_timer-- <= 0 && transfer_pending == DONE) {
79 | // move to next frame
80 | //set_weapon_anim
81 | u16 next_anim = anim_table[cur_anim_idx].next_anim;
82 | KLog_U1("going to anim index: ", next_anim);
83 |
84 | pre_queue_size = DMA_getQueueSize();
85 | set_weapon_anim(next_anim, transfer_type);
86 | transfer_pending = TILES_LOADING;
87 | }
88 | if(transfer_pending != DONE) {
89 | if(DMA_getQueueSize() == pre_queue_size) {
90 | transfer_pending = DONE;
91 | update_weapon_sprites(transfer_type);
92 | }
93 | }
94 |
95 | }
96 |
97 | u32 init_weapon_sprites(u32 tile_loc) {
98 | VDP_resetSprites();
99 | start_tile_loc = tile_loc;
100 | // set load tile location?
101 | sprite_idx_start = VDP_allocateSprites(MAX_SPRITES);
102 | KLog_U1_("Allocating ", MAX_SPRITES, " sprites for weapons");
103 | KLog_U1_("Allocating ", (MAX_SPRITE_TILES*2), " tiles for weapons");
104 | return tile_loc+(MAX_SPRITE_TILES*2);
105 |
106 | }
107 |
108 |
109 | #define BASE_WEAPON_X 128
110 | #define BASE_WEAPON_Y 120
111 |
112 | u32 get_next_tile_loc_and_flip() {
113 | static u8 flag = 0;
114 |
115 | if(flag == 0) {
116 | flag = 1;
117 | return start_tile_loc;
118 | } else {
119 | flag = 0;
120 | return start_tile_loc + MAX_SPRITE_TILES;
121 | }
122 | }
123 |
124 | u32 cur_upload_idx;
125 | void set_weapon_anim(weapon_sprite_anim anim_idx, TransferMethod transfer_type) {
126 | cur_anim_idx = anim_idx;
127 | animation_entry entry = anim_table[cur_anim_idx];
128 | cur_frame_timer = entry.time;
129 | cur_upload_idx = get_next_tile_loc_and_flip();
130 |
131 | switch(entry.spr) {
132 | case SHOTGUN_SPR:
133 | cur_sprite_def = &shotgun;
134 | break;
135 | case SHOTGUN_RELOAD_SPR:
136 | cur_sprite_def = &shotgun_reload;
137 | break;
138 | default:
139 | die("Unknown sprite");
140 | }
141 | u8 animation_idx = entry.anim_idx;
142 | u8 frame_idx = entry.frame_idx;
143 |
144 |
145 | //ASSERT(num_tiles <= MAX_SPRITE_TILES)
146 | KLog_U1("sprites: ", cur_sprite_def->maxNumSprite);
147 | KLog_U1("sprite tiles: ", cur_sprite_def->maxNumTile);
148 | assert(cur_sprite_def->maxNumTile <= MAX_SPRITE_TILES, "Weapon has too many sprite tiles");
149 | assert(cur_sprite_def->maxNumSprite <= MAX_SPRITES, "Weapon has too many sprites");
150 |
151 | AnimationFrame* frame = cur_sprite_def->animations[animation_idx]->frames[frame_idx];
152 | VDP_loadTileSet(frame->tileset, cur_upload_idx, transfer_type);
153 | }
154 |
155 |
156 | void update_weapon_sprites(TransferMethod transfer_type) {
157 | animation_entry entry = anim_table[cur_anim_idx];
158 | u8 animation_idx = entry.anim_idx;
159 | u8 frame_idx = entry.frame_idx;
160 | AnimationFrame* frame = cur_sprite_def->animations[animation_idx]->frames[frame_idx];
161 | //VDP_resetSprites(); // should i always reset? What if something else uses sprites?
162 | cur_num_sprites = frame->numSprite;
163 |
164 | u16 tile_idx = cur_upload_idx;
165 |
166 | VDP_clearSprites();
167 | FrameVDPSprite** f = frame->frameInfos[0].frameVDPSprites;
168 | for(int i = 0; i < cur_num_sprites; i++) {
169 | FrameVDPSprite* spr = f[i];
170 |
171 | VDP_setSprite(
172 | sprite_idx_start+i,
173 | BASE_WEAPON_X+spr->offsetX, BASE_WEAPON_Y+spr->offsetY,
174 | spr->size,
175 | TILE_ATTR_FULL(PAL0, 0, 0, 0, tile_idx)
176 | );
177 | tile_idx += spr->numTile;
178 |
179 | }
180 | VDP_linkSprites(sprite_idx_start, cur_num_sprites);
181 | VDP_setSpriteLink(sprite_idx_start+cur_num_sprites, 0);
182 | VDP_updateSprites(cur_num_sprites, transfer_type);
183 | }
184 |
185 |
186 | void set_weapon_sprite_position_offset(s16 offX, s16 offY) {
187 |
188 |
189 |
190 | AnimationFrame *frame1 = cur_sprite_def->animations[0]->frames[0];
191 | FrameVDPSprite** f = frame1->frameInfos[0].frameVDPSprites;
192 | for(int i = 0; i < cur_num_sprites; i++) {
193 | FrameVDPSprite* spr = f[i];
194 | VDP_setSpritePosition(i+sprite_idx_start,
195 | BASE_WEAPON_X+spr->offsetX+offX,
196 | BASE_WEAPON_Y+spr->offsetY+offY
197 | );
198 | }
199 | VDP_updateSprites(cur_num_sprites, DMA_QUEUE);
200 |
201 |
202 | }
--------------------------------------------------------------------------------
/src/weapon_sprites.h:
--------------------------------------------------------------------------------
1 | #ifndef WEAPON_SPRITES
2 |
3 | #include
4 |
5 | #define WEAPON_SPRITES
6 |
7 | typedef enum {
8 | SHOTGUN_IDLE_ANIM=0,
9 | SHOTGUN_RELOAD_ANIM=1,
10 | } weapon_sprite_anim;
11 |
12 | u32 init_weapon_sprites(u32 tile_loc);
13 |
14 | void set_weapon_anim(weapon_sprite_anim anim_idx, TransferMethod transfer_type);
15 | void set_weapon_sprite_position_offset(s16 offX, s16 offY);
16 | void step_weapon_anim(TransferMethod transfer_type);
17 |
18 | #endif
--------------------------------------------------------------------------------