diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cb794f3573276dbc2cbec4935dc8dd6bd08ce727..016ac951b7dad13cc49bb29a188c326528c2576f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -94,7 +94,7 @@ default: - - | # apt_common echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages" - - apt-get install make git ccache nasm + - apt-get install make git ccache nasm cmake ca-certificates - | # apt_common echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K" @@ -526,21 +526,22 @@ Windows x64: Debian stable Clang: stage: build - when: manual + when: on_success - allow_failure: true + allow_failure: false artifacts: paths: - - "bin/" - - "src/comptime.h" + - "build.clang/bin/" + - "build.clang/src/comptime.h" expose_as: "clang" name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang" variables: CC: clang - WFLAGS: -Wno-cast-align - CFLAGS: -Wno-cast-align + CXX: clang + WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror + CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror LDFLAGS: -Wl,-fuse-ld=gold script: @@ -560,10 +561,18 @@ Debian stable Clang: # apt_development echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K" + - - | + # cmake + echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles" + - cmake -B build.clang -D CPM_USE_LOCAL_PACKAGES:BOOL=ON -D SRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -D SRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -G "Unix Makefiles" + - | + # cmake + echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K" + - - | # make echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" - - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 + - make --directory=build.clang --keep-going || make --directory=src --keep-going - | # make echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" @@ -573,19 +582,22 @@ Debian testing Clang: when: manual + allow_failure: true + image: debian:testing-slim artifacts: paths: - - "bin/" - - "src/comptime.h" + - "build.clang/bin/" + - "build.clang/src/comptime.h" expose_as: "testing-clang" name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang" variables: CC: clang - WFLAGS: -Wno-cast-align -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion - CFLAGS: -Wno-cast-align -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion + CXX: clang + WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion + CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion LDFLAGS: -Wl,-fuse-ld=gold Alpine 3 GCC: diff --git a/doc/Doublescan.txt b/doc/Doublescan.txt deleted file mode 100644 index 5e492ec89c56e550d1a653be5d695d78d798c9ca..0000000000000000000000000000000000000000 --- a/doc/Doublescan.txt +++ /dev/null @@ -1,93 +0,0 @@ - ================================================================ - How to add Low-res modes to your XF86Config under Linux MANUALLY - ================================================================ - - I TAKE NO RESPONSIBILITY FOR ANY DAMAGE DONE TO YOUR EQUIPMENT!!! - - This document explains how to add low-res modes like 320x200 to your - X-Server configuration, because some new setup tools for the X-Server - do not support this. ONLY RECOMMENDED FOR USERS WHO KNOW WHAT THEY DO! - - I do not take any responsibility for damage done to your monitor, your - videocard, your harddisk, your cat, your dog or anything else!!! - IMPORTANT IS, THAT YOUR "HorizSync" AND "VertRefresh" VALUES REALLY - MATCH YOUR MONITOR! OTHERWISE YOUR MONITOR CAN BLOW UP!!! - - OK, if you have read up to here, you either know what you do or really - die-hard want those low-res modes. Here is what to do: - Look up your XF86Config. Is is either in /etc or in /etc/X11. Here is - what you have to add to the definition of your modeslines: - -# Low-res Doublescan modes -# If your chipset does not support doublescan, you get a 'squashed' -# resolution like 320x400. - -# 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio -Modeline "320x200" 12.588 320 336 384 400 200 204 205 225 Doublescan -# 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio -Modeline "320x240" 12.588 320 336 384 400 240 245 246 262 Doublescan -# 320x240 @ 72 Hz, 36.5 kHz hsync -Modeline "320x240" 15.750 320 336 384 400 240 244 246 262 Doublescan -# 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio -ModeLine "400x300" 18 400 416 448 512 300 301 302 312 Doublescan -# 400x300 @ 60 Hz, 37.8 kHz hsync -Modeline "400x300" 20 400 416 480 528 300 301 303 314 Doublescan -# 400x300 @ 72 Hz, 48.0 kHz hsync -Modeline "400x300" 25 400 424 488 520 300 319 322 333 Doublescan - - If your video card only supports a specific set of discrete dotclocks - (RAMDAC) you may have to replace the dotclocks given here by one of the - specified (e.g in the first modeline the dotclock is 12.588 MHz). I believe - that nowadays all cards and monitors should work with these settings, but - if you have outdated hardware you better check the frequencies yourself. If - there is any uncertainty, please check the "XFree86 Video Timings HOWTO". - - - Then have a look at the section "Screen" with the appropriate driver - (usually either "svga" or "accel"). Under Subsection "Display" there - are modes for the given color depth. Add the desired modes. As an - example I give you my screens definition here with low-res modes in - 16 bit color depth: - -Section "Screen" - Driver "accel" - Device "3D Charger" - Monitor "Iiyama Pro 450" - DefaultColorDepth 16 - - Subsection "Display" - Depth 8 - Modes "1280x1024" "1024x768" "800x600" "640x480" - ViewPort 0 0 - Virtual 1280 1024 - EndSubsection - Subsection "Display" - Depth 16 - Modes "1152x864" "1024x768" "800x600" "640x480" "400x300" "320x200" <- THIS IS ACTUALLY WHAT YOU WANT!!! - ViewPort 0 0 ^^^^^^^^^^^^^^^^^^^ - Virtual 1152 864 - EndSubsection - Subsection "Display" - Depth 24 - Modes "800x600" "640x480" - ViewPort 0 0 - Virtual 800 600 - EndSubsection - Subsection "Display" - Depth 32 - Modes "800x600" "640x480" - ViewPort 0 0 - Virtual 800 600 - EndSubsection -EndSection - - Once again: important is, that you edit the correct Screen section. - If you use the SVGA Server and edit the ACCEL Server, you might - wonder where your new modes have gone. - - If everything went fine and you want to say thank you, just write - to "metzgermeister@users.sourceforge.net". If your monitor blew - up and you want to kill me, find me playing Legacy or Q3A on the net - and frag me (with your second monitor, hehe). - - - metzgermeister diff --git a/doc/Item Ranges.txt b/doc/Item Ranges.txt deleted file mode 100644 index 60251e5479c75e9b74a5b04c7ab7c9c9b5788a5b..0000000000000000000000000000000000000000 --- a/doc/Item Ranges.txt +++ /dev/null @@ -1,212 +0,0 @@ -1-99 : Player Starts - 1 - Player 1 Start 1 - 2 - Player 2 Start 2 - 3 - Player 3 Start 3 - 4 - Player 4 Start 4 - 5 - Player 5 Start 4001 - 6 - Player 6 Start 4002 - 7 - Player 7 Start 4003 - 8 - Player 8 Start 4004 - 9 - Player 9 Start 4005 - 10 - Player 10 Start 4006 - 11 - Player 11 Start 4007 - 12 - Player 12 Start 4008 - 13 - Player 13 Start 4009 - 14 - Player 14 Start 4010 - 15 - Player 15 Start 4011 - 16 - Player 16 Start 4012 - 17 - Player 17 Start 4013 - 18 - Player 18 Start 4014 - 19 - Player 19 Start 4015 - 20 - Player 20 Start 4016 - 21 - Player 21 Start 4017 - 22 - Player 22 Start 4018 - 23 - Player 23 Start 4019 - 24 - Player 24 Start 4020 - 25 - Player 25 Start 4021 - 26 - Player 26 Start 4022 - 27 - Player 27 Start 4023 - 28 - Player 28 Start 4024 - 29 - Player 29 Start 4025 - 30 - Player 30 Start 4026 - 31 - Player 31 Start 4027 - 32 - Player 32 Start 4028 - 33 - Player Match Start 11 - 34 - Red Team Start 87 - 35 - Blue Team Start 89 - 36 - Tag start New - -100 - 199 : Enemies - 100 - Blue Crawla 3004 - 101 - Red Crawla 9 - 102 - GFZ Fish 58 - 103 - Gold Buzz 5005 - 104 - Red Buzz 5006 - 105 - Jetty-Syn Bomber 3005 - 106 - Jetty-Syn Gunner 22 - 107 - Crawla Commander 21 - 108 - Deton 71 - 109 - Skim 56 - 110 - THZ Turret 2004 - 111 - Pop-up Turret 42 - -200 - 299 : Bosses and their associated items (if any) - 200 - Boss 1 16 - 201 - Boss 2 2008 - 290 - Boss Fly Point 17 - 291 - EggTrap Center 2049 - -300 - 399 : Collectibles - 300 - Ring 2014 - 301 - Homing Ring 69 - 302 - Rail Ring 3003 - 303 - Infinity Ring 80 - 304 - Automatic Ring 26 - 305 - Explosion Ring 54 - 306 - Red CTF Flag 31 - 307 - Blue CTF Flag 34 - 308 - Special Stage Token 2013 - 309 - Emerald 1 420 - 310 - Emerald 2 421 - 311 - Emerald 3 422 - 312 - Emerald 4 423 - 313 - Emerald 5 424 - 314 - Emerald 6 425 - 315 - Emerald 7 426 - 316 - Hunting Emerald 1 64 - 317 - Hunting Emerald 2 3002 - 318 - Hunting Emerald 3 3001 - -400 - 499 : Boxes - 400 - Super Ring Box 2011 - 401 - Grey Ring Box 2012 - 402 - Ring Shield Box 48 - 403 - Fire Shield Box 2002 - 404 - Bomb Shield Box 2018 - 405 - Jump Shield Box 35 - 406 - Water Shield Box 2028 - 407 - Sneaker Box 25 - 408 - Invincibility Box 2022 - 409 - 1-Up Box 41 - 410 - Eggman Box 2005 - 411 - Mixup Box 78 - 412 - Question Box 3000 - -500 - 599 : Interactive Objects (friendly or otherwise - includes springs) - 500 - Bubble Patch 33 - 501 - Level End Sign 86 - 502 - Starpost 3006 - 520 - Spike Ball -1 - 521 - Special Stage Spike Ball 23 - 522 - Ceiling Spike 67 - 523 - Floor Spike 68 - 540 - Fan 32 - 541 - Steam Riser 30 - 550 - Yellow Spring 28 - 551 - Red Spring 79 - 552 - Blue Spring 5004 - 553 - Yellow Spring Down 65 - 554 - Red Spring Down 66 - 555 - Yellow Diagonal Spring 2015 - 556 - Red Diagonal Spring 38 - 557 - Yellow Diag Spring Down 20 - 558 - Red Diag Spring Down 39 - -600 - 699 : Special placement patterns - 600 - Vertical Rigns - Stack of 5 (suitable for Yellow Spring) 84 - 601 - Vertical Rings - Stack of 5 (suitable for Red Spring) 44 - 602 - Diagonal rings (5) 76 - 603 - Diagonal rings (10) 77 - 604 - A ring of rings 47 - 605 - A BIGGER ring of rings 2007 - 606 - A ring of wing items 2048 - 607 - A BIGGER ring of wing items 2010 - 608 - A ring of rings and wings (alternating) 2046 - 609 - A BIGGER ring of rings and wings (alternating) 2047 - -700 - 799 : Powerup indicators/environmental effects/miscellany - 700 - Ambient Water 1a (S) 2026 - 701 - Ambient Water 1b (S) 2024 - 702 - Ambient Water 2a (M) 2023 - 703 - Ambient Water 2b (M) 2045 - 704 - Ambient Water 3a (L) 83 - 705 - Ambient Water 3b (L) 2019 - 706 - Ambient Water 4a (XL) 2025 - 707 - Ambient Water 4b (XL) 27 - 708 - Random Ambient 1 14 - 709 - Random Ambient 2 43 - 750 - Chaos Spawner 8 - 751 - Teleport Point 5003 - 752 - Alternate View Point 5007 - 753 - Zoom Tube Waypoint 18 - 754 - Pusher 5001 - 755 - Puller 5002 - 756 - Street Light 2003 - -800 - 899 : Greenflower Scenery - 800 - Flower 1 36 - 801 - Flower 2 70 - 802 - Flower 3 73 - 804 - Berry Bush 74 - 805 - Bush 75 - -900 - 999 : Techno Hill Scenery - 900 - THZ Plant 2035 - 901 - Alarm 2006 - -1000 - 1099 : Deep Sea Scenery - 1000 - Gargoyle 81 - -1100 - 1199 : Castle Eggman Scenery - 1100 - Ceiling Chain 49 - 1101 - Torch Flame 24 - 1102 - Eggman Statue 52 - 1103 - CEZ Flower 2001 - -1200 - 1299 : Arid Canyon Scenery -1300 - 1399 : Red Volcano Scenery -1400 - 1499 : Dark City Scenery -1500 - 1599 : Doom Ship Scenery -1600 - 1699 : Egg Rock/Final Fight Scenery -1700 - 1799 : NiGHTS Items - 1700 - Axis 72 - 1701 - Axis Transfer (Normal) 61 - 1702 - Axis Transfer (Line) 46 - 1703 - Nights Drone 60 - 1704 - Nights Bumper 82 - 1705 - Hoop 57 - 1706 - Nights Wing 37 - 1707 - Super Loop Powerup 3007 - 1708 - Drill Refill Powerup 3008 - 1709 - Helper Powerup 3009 - 1710 - Egg Capsule 40 - -1800 - 1849 : Mario Items - 1800 - Coin 10005 - 1801 - Goomba 10000 - 1802 - Blue Goomba 10001 - 1803 - FireFlower 50 - 1804 - Shell 10 - 1805 - Puma 29 - 1806 - Koopa 19 - 1807 - Axe 12 - 1808 - Mario Bush 1 10002 - 1809 - Mario Bush 2 10003 - 1810 - Toad 10004 - -1850 - 1899 : Christmas Items - 1850 - Xmas Pole 5 - 1851 - Candy Cane 13 - 1852 - Snowman 6 - -1900 - 1999 : Misc Scenery - 1900 - Stalagmite 0 - 1901 - Stalagmite 1 - 1902 - Stalagmite 2 - 1903 - Stalagmite 3 - 1904 - Stalagmite 4 - 1905 - Stalagmite 5 - 1906 - Stalagmite 6 - 1907 - Stalagmite 7 - 1908 - Stalagmite 8 - 1909 - Stalagmite 9 diff --git a/doc/Linedef Ranges.txt b/doc/Linedef Ranges.txt deleted file mode 100644 index 81fa695a0dcb8c0b3592225edbd82a7885c683e6..0000000000000000000000000000000000000000 --- a/doc/Linedef Ranges.txt +++ /dev/null @@ -1,223 +0,0 @@ - Description OldNum NewNum Description - Old Water 14 Removed - - Level Parameters/Misc: - Per-Sector Gravity 64 1 - Custom Exit 71 2 - Zoom Tube Parameters 18 3 - Speed Pad 65 4 - Camera Scanner 63 5 - Disable Linedef 73 6 - Flat Alignment 66 7 - Sector Special Parameters New 8 - Mace Parameters New 9 - Sprite Cull Height New 10 - Rope Hang Parameters New 11 - Rock Spawner Parameters New 12 - - PolyObjects - Marks first line in PolyObject New 20 - Explicitly includes a PolyObject line New 21 - PolyObject: Parameters New 22 - PolyObject: Waving Flag New 31 - - Level-Load Effects: - Instant Floor Lower 26 50 - Instant Ceiling Raise 24 51 - Continuously Falling Sector 88 52 - Continuous Floor/Ceiling Mover 2 53 - Continuous Floor Mover 3 54 - Continuous Ceiling Mover 4 55 - Continuous Two-Speed Floor/Ceiling Mover 6 56 - Continuous Two-Speed Floor Mover 7 57 - Continuous Two-Speed Ceiling Mover 8 58 - Activate Floating Platform 232 59 - Activate Floating Platform (Adjustable Speed) 233 60 - Crusher 1 (Ceiling to Floor) 43 61 - Crusher 2 (Floor to Ceiling) 50 62 - Fake Floor/Ceiling 242 63 - Appearing/Disappearing FOF New 64 - Bridge Thinker New 65 - - Floor Over Floors: - "Floor Over Floor: Solid, Opaque, Shadowcasting " 25 100 - "Floor Over Floor: Solid, Opaque, Non-Shadowcasting " 33 101 - "Floor Over Floor: Solid, Translucent " 44 102 - "Floor Over Floor: Solid, Sides Only " 69 103 - "Floor Over Floor: Solid, No Sides " 51 104 - "Floor Over Floor: Solid, Invisible " 57 105 - - "Floor Over Floor: Water, Opaque " 48 120 - "Floor Over Floor: Water, Translucent " 45 121 - "Floor Over Floor: Water, Opaque, No Sides " 75 122 - "Floor Over Floor: Water, Translucent, No Sides " 74 123 - - "Floor Over Floor: Platform, Opaque " 59 140 - "Floor Over Floor: Platform, Translucent " 81 141 - "Floor Over Floor: Platform, Translucent, No Sides " 77 142 - - Floor Over Floor: Bobbing (Air) 38 150 - Floor Over Floor: Adjustable Bobbing (Air) 68 151 - Floor Over Floor: Reverse Adjustable Bobbing (Air) 72 152 - - "Floor Over Floor: Floating, Bobbing " 34 160 - - Floor Over Floor: Crumbling (Respawn) 36 170 - Floor Over Floor: Crumbling (No Respawn) 35 171 - "Floor Over Floor: Crumbling (Respawn), Platform " 79 172 - "Floor Over Floor: Crumbling (No Respawn), Platform " 80 173 - "Floor Over Floor: Crumbling (Respawn), Platform, Translucent " 82 174 - "Floor Over Floor: Crumbling (No Respawn), Platform, Translucent " 83 175 - "Floor Over Floor: Crumbling (Respawn), Floating, Bobbing " 39 176 - "Floor Over Floor: Crumbling (No Respawn), Floating, Bobbing " 1 177 - "Floor Over Floor: Crumbling (Respawn), Floating " 37 178 - "Floor Over Floor: Crumbling (No Respawn), Floating " 42 179 - "Floor Over Floor: Crumbling (Respawn), Bobbing (Air) " 40 180 - - "Floor Over Floor: Rising Platform, Solid, Opaque, Shadowcasting " 89 190 - "Floor Over Floor: Rising Platform, Solid, Opaque, Non-Shadowcasting " 90 191 - "Floor Over Floor: Rising Platform, Solid, Translucent " 91 192 - "Floor Over Floor: Rising Platform, Solid, Invisible " 94 193 - "Floor Over Floor: Rising Platform, Platform, Opaque " 92 194 - "Floor Over Floor: Rising Platform, Platform, Translucent " 93 195 - - Floor Over Floor: Light Block 49 200 - Floor Over Floor: Half Light Block 47 201 - Floor Over Floor: Fog Block 46 202 - - "Floor Over Floor: Intangible, Opaque " 62 220 - "Floor Over Floor: Intangible, Translucent " 52 221 - "Floor Over Floor: Intangible, Sides Only " 67 222 - "Floor Over Floor: Intangible, Invisible " 58 223 - - Floor Over Floor: Mario Block 41 250 - Floor Over Floor: Thwomp Block 54 251 - Floor Over Floor: Shatter Block 76 252 - "Floor Over Floor: Shatter Block, Translucent " 86 253 - Floor Over Floor: Bustable Block 55 254 - Floor Over Floor: Spin Bust Block 78 255 - "Floor Over Floor: Spin Bust Block, Translucent " 84 256 - Floor Over Floor: Quicksand Block 56 257 - Floor Over Floor: Laser Block 53 258 - Floor Over Floor: Custom 87 259 - - Linedef Executor Triggers: - Trigger Linedef Executor (Continuous) 96 300 - Trigger Linedef Executor (Each Time) 97 301 - Trigger Linedef Executor (Once) 98 302 - Trigger Linedef Executor (Ring Count - Continuous) 95 303 - Trigger Linedef Executor (Ring Count - Once) 99 304 - Trigger Linedef Executor (Character Ability - Continuous) 19 305 - Trigger Linedef Executor (Character Ability - Each Time) 20 306 - Trigger Linedef Executor (Character Ability - Once) 21 307 - "Trigger Linedef Executor (Race Only, Once) " 9 308 - Trigger Linedef Executor (CTF Red Team - Continuous) 10 309 - Trigger Linedef Executor (CTF Red Team - Each Time) 11 310 - Trigger Linedef Executor (CTF Blue Team - Continuous) 12 311 - Trigger Linedef Executor (CTF Blue Team - Each Time) 13 312 - Trigger Linedef Executor (No More Enemies - Once) 15 313 - Trigger Linedef Executor (# of Pushables - Continuous) New 314 - Trigger Linedef Executor (# of Pushables - Once) New 315 - Trigger Linedef Executors (PolyObject - Land On) New 316 - Trigger Linedef Executor (Level Load) New 399 - - Linedef Executor Options: - Linedef Executor: Set Tagged Sector's Floor Height/Pic 101 400 - Linedef Executor: Set Tagged Sector's Ceiling Height/Pic 102 401 - Linedef Executor: Set Tagged Sector's Light Level 103 402 - Linedef Executor: Move Tagged Sector's Floor 106 403 - Linedef Executor: Move Tagged Sector's Ceiling 107 404 - Linedef Executor: Lower Floor by Line 108 405 - Linedef Executor: Raise Floor by Line 109 406 - Linedef Executor: Lower Ceiling by Line 110 407 - Linedef Executor: Raise Ceiling by Line 111 408 - Linedef Executor: Change Calling Sector's Tag 112 409 - Linedef Executor: Change Front Sector's Tag 114 410 - Linedef Executor: Stop Plane Movement 116 411 - Linedef Executor: Teleport Player to Tagged Sector 104 412 - Linedef Executor: Change Music 105 413 - Linedef Executor: Play SFX 115 414 - Linedef Executor: Run Script 113 415 - Linedef Executor: Start Adjustable Fire Flicker 119 416 - Linedef Executor: Start Adjustable Glowing Light 120 417 - Linedef Executor: Start Adjustable Strobe Flash (unsynchronized) New 418 - Linedef Executor: Start Adjustable Strobe Flash (synchronized) New 419 - Linedef Executor: Fade Light Level 117 420 - Linedef Executor: Stop Lighting Effect 118 421 - Linedef Executor: Cut-Away View 121 422 - Linedef Executor: Change Sky 123 423 - Linedef Executor: Change Weather 124 424 - Linedef Executor: Change Object State 125 425 - Linedef Executor: Stop Object 122 426 - Linedef Executor: Award Score 126 427 - Linedef Executor: Start Platform Movement 127 428 - Linedef Executor: Crush Ceiling Once New 429 - Linedef Executor: Crush Floor Once New 430 - Linedef Executor: Crush Floor & Ceiling Once New 431 - Linedef Executor: Enable 2D Mode New 432 - Linedef Executor: Disable 2D Mode New 433 - Linedef Executor: Award Custom Power New 434 - Linedef Executor: Stop Conveyor New 435 - Linedef Executor: Start Conveyor New 436 - Linedef Executor: Disable Player Movement New 437 - - Linedef Executor: Execute Linedef Executor New 450 - - Linedef Executor: PolyObject: Door Slide New 480 - Linedef Executor: PolyObject: Door Swing New 481 - Linedef Executor: PolyObject: Move XY New 482 - Linedef Executor: PolyObject: Move XY w/ override New 483 - Linedef Executor: PolyObject: Rotate Right New 484 - Linedef Executor: PolyObject: Rotate Right w/ override New 485 - Linedef Executor: PolyObject: Rotate Left New 486 - Linedef Executor: PolyObject: Rotate Left w/ override New 487 - Linedef Executor: PolyObject: Start waypoint movement New 488 - Linedef Executor: PolyObject: Make Invisible New 489 - Linedef Executor: PolyObject: Make Visible New 490 - - Scrollers/Pushers: - Scroll Wall First Side Left 100 500 - Scroll Wall First Side Opposite Direction 85 501 - Scroll Wall According to Linedef 254 502 - Acc Scroll Wall According to Linedef 218 503 - Disp Scroll Wall According to Linedef 249 504 - Scroll Texture by Offsets 255 505 - - Scroll Floor Texture 251 510 - Acc Scroll Floor Texture 215 511 - Disp Scroll Floor Texture 246 512 - Scroll Ceiling Texture 250 513 - Acc Scroll Ceiling Texture 214 514 - Disp Scroll Ceiling Texture 245 515 - - Carry Objects on Floor (no scroll) 252 520 - Acc Carry Objects on Floor 216 521 - Disp Carry Objects on Floor 247 522 - Carry Objects on Ceiling 203 523 - Acc Carry Objects on Ceiling 205 524 - Disp Carry Objects on Ceiling 201 525 - - Scroll Floor Texture and Carry Objects 253 530 - Acc Scroll Floor Texture and Carry Objects 217 531 - Disp Scroll Floor Texture and Carry Objects 248 532 - Scroll Ceiling Texture and Carry Objects 202 533 - Acc Scroll Ceiling Texture and Carry Objects 204 534 - Disp Scroll Ceiling Texture and Carry Objects 200 535 - - Friction 223 540 - Horizontal Wind 224 541 - Upwards Wind 229 542 - Downwards Wind 230 543 - Horizontal Current 225 544 - Upwards Current 227 545 - Downwards Current 228 546 - Boom Push/Pull Thing 226 547 - - Lighting: - Floor Lighting 213 600 - Ceiling Lighting 5 601 - Adjustable Pulsating Light 60 602 - Adjustable Flickering Light 61 603 - Adjustable Blinking Light (unsynchronized) New 604 - Adjustable Blinking Light (synchronized) New 605 - Colormap 16 606 diff --git a/doc/SSN-Todo.xls b/doc/SSN-Todo.xls deleted file mode 100644 index c468b34764f0b1a7ebcb3f552aeb8fd4cd56fb76..0000000000000000000000000000000000000000 Binary files a/doc/SSN-Todo.xls and /dev/null differ diff --git a/doc/Sector Ranges.txt b/doc/Sector Ranges.txt deleted file mode 100644 index 42760e1334a90a7fbf25028fcdaf62d0feb3156c..0000000000000000000000000000000000000000 --- a/doc/Sector Ranges.txt +++ /dev/null @@ -1,78 +0,0 @@ -Removed: - - Buttons 1-20 690-709 - - Button 21 (THZ2 A/740 B/741 D/742 E/745 710 - - Close Door Blazing (Tag 743) 711 - - Raise Ceiling to Highest (Tag 744) 981 - - THZ2 Slime Raise (B/712 W713 P714 D715 S716) 986 - -Stuff to Remove/Change: - - Light Blinks On Every 0.5 Seconds 2 Add Linedef Combine - - Light Blinks On Every 1 Second 3 Add Linedef Combine - - Light Pulses Smoothly 8 Remove - - Light Blinks On Every 0.5 Seconds (Sync) 12 Add Linedef Combine - - Lights Blinks On Every 1 Second (Sync) 13 Add Linedef Combine - - Light Flickers Like Fire 17 Remove - ? - Damage (Fire) and Current 519 Remove (convert to combination) - ? - Damage (Water) and Current 984 Remove (convert to combination) - -Section 1: - 1 - Damage (Generic) 11 - 2 - Damage (Water) 983 - 3 - Damage (Fire) 7 - 4 - Damage (Electrical) 18 - 5 - Spikes 4 - 6 - Death Pit (Camera Mod) 16 - 7 - Death Pit (No Camera Mod) 5 - 8 - Instant Kill 10 - 9 - Ring Drainer (Floor Touch) 978 - 10 - Ring Drainer (No Floor Touch) 980 - 11 - Special Stage Damage 9 - 12 - Space Countdown 6 - 13 - Ramp Sector (Increase step-up) 992 - 14 - Non-Ramp Sector (Don't step-down) 996 - 15 - Bouncy Sector (FOF Control Only) 14 - -Section 2: << 4 - 1 - Trigger Linedef Exec (Pushable Objects) 971 - 2 - Trigger LD Exec (Anywhere in Sec/All Pls) 972 - 3 - Trigger Linedef Exec (Floor Touch/All Pls) 973 - 4 - Trigger Linedef Exec (Anywhere in Sec) 974 - 5 - Trigger Linedef Exec (Floor Touch) 975 - 6 - Trigger Linedef Exec (Emerald Check) 967 - 7 - Trigger Linedef Exec (NiGHTS Mare) 968 - 8 - Check for linedef executor on FOFs (ANY) 970 - 9 - Egg Trap Capsule 666 - 10 - Special Stage Time/Rings, Par 990 - 11 - Custom Global Gravity 991 - -Section 3: << 8 - 1 - Ice/Sludge (required?!) 256 - 2 - Wind/Current (required?!) 512 - 3 - Ice/Sludge and Wind/Current 768 - 4 - Conveyor Belt 985 - 5 - Speed Pad (No Spin) 976 - 6 - Speed Pad (Spin) 977 - 7 - Bustable Block Sprite Parameter 1500-1515 - 8 - " - 9 - " - 10 - " - 11 - " - 12 - " - 13 - " - 14 - " - 15 - " - -Section 4: << 12 - 1 - Starpost Activator 993 - 2 - Special Stage Goal Combine 33 - 2 - Exit Sector Combine 982 - 2 - No Tag Zone Combine 987 - 2 - CTF: Flag Return Combine 995 - 3 - CTF: Red Team Base 988 - 4 - CTF: Blue Team Base 989 - 5 - Fan Sector 997 - 6 - Super Sonic Transform 969 - 7 - Spinner 979 - 8 - Zoom Tube Start 998 - 9 - Zoom Tube End 999 - 10 - Finish Line 994 \ No newline at end of file diff --git a/doc/faq.txt b/doc/faq.txt deleted file mode 100644 index 26c75bbadd5581c36c835ae1a11f405f634a2834..0000000000000000000000000000000000000000 --- a/doc/faq.txt +++ /dev/null @@ -1,307 +0,0 @@ - SRB2 - Release v1.09, ? 2005. - - Last Updated: June 2005 - - Original game & sources by: Id Software. - Additions: (c)1998 by: Fabrice Denis & Boris Pereira - (c)1999 by: Fabrice Denis, Boris Pereira & Thierry Van Elsuwe - (c)2000 by: Boris Pereira & Thierry Van Elsuwe - (c)2004 By: AJ, Graue, Alam Arias, Logan Arias & Andrew Clunis - - Special thanks to Steven McGranahan, Lee Killough, Robert Bäuml and Bell Kin for - their large contribution and to other DooM LEGACY & SRB2 Team members. - - Web site: http://www.SRB2.org/ - e-mail: none@none.com - - OpenGL specific: - Web site: http://legacy.newdoom.com/gl - - - ----------------------------------------------------------------------- - F.A.Q. - ----------------------------------------------------------------------- - - - If you have any trouble with SRB2, you might find a solution - here. - - If you find a solution to a problem that was not listed here, - please tell us so that we can update the FAQ and help other people! - - Mail your hardware/software problems to: - - None@none.com subject: FAQ - - - -------- - CONTENTS - -------- - - [0] Miscellaneous - [1] Mouse/Joystick/Keyboard - [2] Video - [3] Sound - [4] Network - [5] Troubleshooting - - - ----------------- - [0] MISCELLANEOUS - ----------------- - - * under win95 or OS/2, I don't have enough memory. How can i handle with ? - - Tell win95 to put more dpmi memory for your dos box. - Or use the -mb option. - - - - --------------------------- - [1] MOUSE/JOYSTICK/KEYBOARD - --------------------------- - - * My mouse/joystick does not work in SRB2. - - First, check that the mouse/joystick is activated : go at the - console and type either 'use_mouse' (or use the respective - menuitem) or 'use_joystick'. - - If it tells '0' or off than the mouse/joystick is not used, - set the variable to 1. eg: 'use_mouse 1'. - - For the joystick, different values will support different - types of joystick, check the console documentation for the - command 'use_joystick' for more. - - Even if the mouse or joystick is activated, you have to - set up the contols into the Setup Controls menu. That is: - tell what use you will make of the mouse/joystick buttons. - - - --------- - [2] VIDEO - --------- - - - * Where are the other video modes ? I have only '320x200' in the - Video Modes menu. - - DOS - --- - - SRB2 adds new video modes only if a VESA2 (or better) driver - is present. The VESA2 driver is a standard of 'talking' between a - program and the huge amount of different graphics cards - available today. - - If you don't have a VESA2 driver, you can download UNIVBE, or - SMART DISPLAY DOCTOR from - - http://www.scitechsoft.com/products/ent/free_titles.html - - or if you have an S3 based card, you can download the free - software called 'S3VBE'. - - ftp://ftp.externet.hu/pub/mirror/sac/graph/s3vbe318.zip - ftp://ftp.digsys.bg/pub/simtelnet/msdos/graphics/s3vbe318.zip - http://www.filesearching.com/cgi-bin/s?q=s3vbe318.zip - http://www.google.com/search?q=s3vbe318.zip - - * The game doesn't restore the video mode I have chosen the last time - I played SRB2. - - The current video mode has to be made the 'default' so that it is - saved to the config : press the key 'D' on the Video Options menu - to set the current video mode the default. - - * I have some problems with OpenGL mode - - Have a look at the FAQ for OpenGL on the glLegacy web site: - - http://www.doomnation.com/gllegacy/faqe.htm - - # Linux: I only have a 1024x768 (or 800x600, 1280x1024, ...) resolution - in fullscreen mode under X and SRB2 is really really slow. Can I - have lower resolutions like 320x200 in fullscreen mode as well? - - Probably yes. SRB2 can only use the resolutions offered by the - X-Server. So if all fullscreen modes have a very high resolution you - have to modify /etc/XF86Config (or /etc/X11/XF86Config). Use XF86Setup - (or the appropriate tool coming with your distribution - sax, - xf86config, ...) to do this. - If you do not succeed there, you can enter them manually into your - XF86Config file. ONLY RECOMMENDED FOR USERS WHO KNOW WHAT THEY DO! - For a short guide on how to do this, have a look at the file - "Doublescan.txt". - In case of doubt consult the XFree86-HOWTO (or ask your system - administrator :). - - # Linux: I cannot have any fullscreen modes at all! - - You have only modes above 1024x768 in your XF86Config. Proceed as - described above. - - # Linux: After a certain idle time my screensaver jams the display of - SRB2. I can still operate SRB2, but I do not see what's happening - and the screensaver won't go away. - - You probably have KDE. The KDE screensaver does not obey the screensaver - rules (at least mine, version 1.1). The solution is to deactivate the - KDE screensaver and use another screensaver (like the xscreensaver, - e.g.). But the hell, when you started SRB2 you should have played it - as well and not left it alone!!! - - --------- - [3] SOUND - --------- - - + DOS:I can't have CD audio music, why ? - - Make sure that the MSCDEX driver version 2.0 or later is loaded. - If it says 'MSCDEX version xxx' at game startup, and you still - don't hear the cd music, then probably your card doesn't respond - when SRB2 tries to set the cd volume. If so, make sure your sound - card's mixer have the cd volume set up so that you can hear something. - - + When the CD plays, the game is very 'jerky'. It doesn't do that when - I type 'cd off' in the console. - - You have an old/bad cd driver, that can take up to a second to - respond to cd driver commands. Either get the latest version of - your driver, or turn cd update off. Check 'cd_udpate' in the - console documentation for more. - - * DOS:How can I *ALWAYS* disable the sounds or music of the game ? - - Edit the allegro.cfg file and set digicard/midicard to 0 (none) - - * DOS:My sterero sound is reversed, how can I set it the right way ? - - Change the console variable 'stereoreverse' to either 1 or 0. - Or, you can edit the allegro.cfg file, and set the 'flip_pan' variable. - - - * DOS:The sounds are too 'slow', or 'low-pitched' - - It seems to be a problem of the auto-detection of some 8bit sound - cards. You will have to set manually the 'sb_freq' value in the - allegro.cfg file to a lower value : 11906, 16129. - - * DOS:SRB2 doesn't play any sound/music, but I have a sound - blaster genuine/compatible card. - - If you have a genuine or compatible SoundBlaster card, it is very - important that you set the BLASTER environment variable. - - If you are playing under DOS, and never installed your sound card - under DOS, run the setup of your sound card for DOS. - - Check if the BLASTER variable was set: type 'SET' under dos - (or DOSbox) - - Do you see something like 'BLASTER=A220 I5 D1 ...' ? - - Yes? If you don't hear sounds/music, then tweak the settings in the - allegro.cfg file until you get something, first try changing the - type of the sound card, it is not always properly detected. - - No? You have to set this variable in order that your sound card is - detected. Run the setup that was shipped with your sound card, and - make sure you run the setup for DOS too, it will usually add a - line of the type 'SET BLASTER=... ...' in the autoexec.bat file. - - - * DOS:How can I have better midi music on my 8bit sound card ? - - Use the DIGMID driver, it is supported in SRB2. - - What the hell is this? Well, the Gravis Ultrasound uses digital - samples to play midi music. On a simple 8bit card, you can use digital - samples too, which will sound usually better than what is output - by the poor fm synthesis chip of 8bit cards. - - You will need to get a Gravis Ultrasound patch set, you can find - several ones for free on internet, it consists of a bunch of '.pat' - files which are the digital samples to play the midi instruments - (eg: piano, conga, guitar, ect.). - - Check the Allegro homepage for some links to GUS patches: - http://alleg.sourceforge.net/digmid.html - http://alleg.sourceforge.net/ - http://www.talula.demon.co.uk/allegro/digmid.html - http://www.talula.demon.co.uk/allegro/ - - Now to activate the DIGMID driver: - - Set the 'midi_card' value to 8 (DIGMID) in the allegro.cfg file. - Make sure you leave the 'digi_voices' blank, or set it to a low - value, because the midi music will use digital voices. - At the end of the allegro.cfg file, set the 'patches' value - to the path, where you have installed a Gravis Ultrasound midi - patch set. eg: patches = d:\music\midipat\ - - # Linux: CD music does not work or only works when run as root. - - We do not encourage you to run SRB2 as root (you never know - what SRB2 can do to your system - it's a mighty piece of code :). - There is a common problem with ATAPI CD-rom drives, which are - treated as harddisks. Usually there is a link /dev/cdrom pointing to - device hd[b,c,d]. As harddisks are not supposed to be read directly - via this device (especially not by a common user), there are no read - permissions for "all". For CD-roms you can savely set read permissions - unless you are very paranoid. Assuming your CD-rom drive is /dev/hdc, - set permissions with "chmod +r /dev/hdc" (as root). SCSI CD-rom drives - should not have this problem. But if they do, proceed as described - with ATAPI drives. - - # Linux: The CD music volume is not set properly. - - Go to the console and type "jigglecdvolume 1". - - ----------- - [4] NETWORK - ----------- - - * Where can I find Internet servers ? - - For the moment there is one public server. - http://srb2.servegame.org/ Master server web page - srb2.servegame.org:28910 current Master Server - - * When I start SRB2 with -server or -connect it say : - "BinToPort: Address already in use (EADDRINUSE)" - - It appears only when SRB2 crashes or when you leave with ctrl-break. - use -udpport 12345 (or any other free slot) on both sides (client and - server). - - This can also happens when there is already a SRB2 running on your - computer if you whant to try two SRB2 running on the same computer - use -clientport 12345 (or any other free slot). Then the second will - connect to the first one. - - * Do you use the tcp protocol ? - - No, we use the udp protocol which is faster, but don't worry udp is a - part of the internet protocol. - - - ------------------- - [5] Troubleshooting - ------------------- - - # Linux: SRB2 is hung in fullscreen mode and won´t let me leave. - What shall I do? - - Some people press the reset button, but hey, we are not in the - stoneage of operating systems! There are two "proper" ways to - get out: kill your X-Server. You can usually do this by pressing - "CTRL-ALT-BACKSPACE". But if you have other open applications with - important data (probably hacked away on your diploma thesis for 3 - weeks without saving once) you can also kill SRB2 directly. Press - "CTRL-ALT-F2" and you will get to a console. Log in, type - "killall llxSRB2" and switch back to the X-Server with "CTRL-ALT-F7". - Some X-Server crash on this procedure - blame the X-Server for the - loss of 3 weeks work on your diploma thesis :) diff --git a/doc/manual/manual.htm b/doc/manual/manual.htm deleted file mode 100644 index 3fea1b66f18b694468c9103064e8c6fd1f33efd3..0000000000000000000000000000000000000000 --- a/doc/manual/manual.htm +++ /dev/null @@ -1,68 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> - <title> - Sonic Robo Blast 2 Manual - </title> - <link rel="stylesheet" type="text/css" href="srb2manstyle.css"> - <!-- Borrowed some javascript code so the height of the iframe is equal to the size of the document - Sonict --> - <script type="text/javascript"> - /* free code from dyn-web.com */ - - function getDocHeight(doc) { - doc = doc || document; - // from http://stackoverflow.com/questions/1145850/get-height-of-entire-document-with-javascript - var body = doc.body, html = doc.documentElement; - var height = Math.max( body.scrollHeight, body.offsetHeight, - html.clientHeight, html.scrollHeight, html.offsetHeight ); - return height; -} - - function setIframeHeight(id) { - var ifrm = document.getElementById(id); - var doc = ifrm.contentDocument? ifrm.contentDocument: ifrm.contentWindow.document; - ifrm.style.visibility = 'hidden'; - ifrm.style.height = "10px"; // reset to minimal height in case going from longer to shorter doc - ifrm.style.height = getDocHeight( doc ) + "px"; - ifrm.style.visibility = 'visible'; - } - </script> - <meta http-equiv="Content-type" content="text/html; charset=UTF-8"> -</head> -<body> - <p class="c1"> - <img src="manual_img/sonicname2.png" alt="SONIC" width="136" height="36"> - <br> - <img src="manual_img/srb2banner.png" alt="ROBO BLAST 2" width="224" height="43"> - </p> - <p class="c1"> - <big><big><strong>Manual</strong></big></big> - </p> - <table class="cf" align="center"> - <tr><td class="c"> - <ul class="hmenu"> - <li class="hmenu"><a class="hmenu" href="intro.htm" target="ifrm">Main</a></li> - <li class="hmenu"><a class="hmenu" href="items.htm" target="ifrm">Items</a></li> - <li class="hmenu"><a class="hmenu" href="playerabilities.htm" target="ifrm">Player Abilities</a></li> - <li class="hmenu"><a class="hmenu" href="basicplay.htm" target="ifrm">Gameplay</a></li> - <li class="hmenu"><a class="hmenu" href="surroundings.htm" target="ifrm">Surroundings</a></li> - </ul> - </td></tr> - <tr><td class="c"> - <ul class="hmenu"> - <li class="hmenu"><a class="hmenu" href="multiplayer.htm" target="ifrm">Multiplayer</a></li> - <li class="hmenu"><a class="hmenu" href="zones.htm" target="ifrm">Zones</a></li> - <li class="hmenu"><a class="hmenu" href="controls.htm" target="ifrm">Controls</a></li> - <li class="hmenu"><a class="hmenu" href="consolecommands.htm" target="ifrm">Console Commands</a></li> - <li class="hmenu"><a class="hmenu" href="misc.htm" target="ifrm">Misc</a></li> - </ul> - </td></tr> - </table> - <hr> - <p class="c1"> - <!-- The "onload" property of the iframe makes an error when validated through the W3C validation checker. --> - <!-- This will not be fixed as it isn't worth the time to fix it up properly. - Sonict --> - <iframe id="ifrm" name="ifrm" src="intro.htm" onload="setIframeHeight(this.id)"> </iframe> - </p> -</body> -</html> diff --git a/doc/rules.txt b/doc/rules.txt deleted file mode 100644 index 4bbb8cdc1f786022bc0f090154de4e7733080d32..0000000000000000000000000000000000000000 --- a/doc/rules.txt +++ /dev/null @@ -1,39 +0,0 @@ -SVN-RULES - -- As you can see, there is sub-directory in the repository, one for eatch - platform (djgpp (dos),win32,SDL) the root directory is for all platform, - so take care of the order we have put in. -- do not commit/upload tests of bugged code, try to fix a maximum of know - bugs and update know bugs list in source.txt. If you must commit your source - make your code in #ifdef so we can disable it -- SRB2 is a modification of doom/Doom Legacy source. We allow additionnal feature - and visual addition. -- Maximize communications between members, do not impose your changes, if your - are not sure about a feature/change, talk about it in irc://irc.esper.net/srb2 chat room. - -CODE-RULES - -- We use no tab, 4 space indent, and tab size 8 (in case some tab have filtred - and for makefile) -- Self documented code, variable and function must have a name that help - understand the code, so do not call variable and function a,b, a2, ... -- the usage of extern in a c file is prohibited, except for declaration of a - function with body (so it is like public keyword in c++) - Also function protos haren't allowed for external function, put it un the - corresponding h file. -- Try to minimize #ifdef usage for : - - code readability - - the main code is for all port so if something is good for a platform all - platform can benefit by this feature -- Take care of platform dependent code, we would like to have code that work - on Dos, Win32, SDL, ... little and big endian, software/Glide/OpenGl. - -GOOD PRACTICE - -- Try to put as mush static variable and function on module so it help to - understand the role of the varaible/function in the module also this - help the compiler to optimize -- minimise global variable -- make a log of your work, so you don't need to put a lot of comment in - the code, this will also help us to update the what's new section of doc - when doing final release diff --git a/doc/source.txt b/doc/source.txt deleted file mode 100644 index 5926d95fb94d9a31edccac1266cbfdb9661bda07..0000000000000000000000000000000000000000 --- a/doc/source.txt +++ /dev/null @@ -1,240 +0,0 @@ - -1. Compile SRB2 -2. Explanation of the code - 2.1 The memory model - 2.2 Hardware Texture model - -1. Compile SRB2 -================= - -DOS ---- - -need: -- djgpp 2.03 (http://www.delorie.com/djgpp/) -- allegro 3.12 (http://alleg.sourceforge.net/index.html) -( -- libsocket 0.7.4 (beta 4) or better - for use with Winsock 1.1 (example Windows 3.1) - (http://www.phekda.freeserve.co.uk/richdawe/lsck/lsck.htm) - OR -- Wattcp-32 v2.2 dev.rel 6 or better - For use with a packet driver - (http://www.bgnett.no/~giva/) - (http://groups.yahoo.com/group/watt-32/) - (http://groups.yahoo.com/group/watt-32/files/v2.2/) -) -- bcd 1.03 (inlcude in this package) -- gcc 2.95.2 is recommended -- nasm 0.98 (or better) (http://nasm.sourceforge.net/) - -compile: -make -make WATTCP=1 (to make a Wattcp-32 version) - -debug: -when craching SRB2 will return eip -type make asm, then you will have a 8 megs srb2.s (a assembler file) -the you can find the faulting instruction and function - ------------------------------------------------------------------------- - -Linux/SDL ------ - -need: -- tested with gcc 2.95 and 3.X. -- SDL 1.2 -- SDL_mixer 1.2 -- ibogg and libvorbis (http://Xiph.org/) -- nasm 0.98 (or better)(http://nasm.sourceforge.net/) only with 2.95, else add CC30=1 - -compile -make LINUX=1 - -debug: -gdb ? - ------------------------------------------------------------------------- - -Win32 ------ - -need : -- glide 3.x sdk (optional) (http://www.3dfx.com) -- directx6 sdk (or higher) (http://www.micosoft.com/directx) -- nasm 0.98 (or better) (http://nasm.sourceforge.net/) -- use src\win32\wLegacy.dsp -- VC6 should also work with VC5, and VS.NET 200X - -debug: -press on "step over" with the release version (there is some debug info -on it). Then change the eip in the regster window when you will type -enter the edi will go to the faulting instruction. don't forget that -you can follow the stack for calls. -You can also use trace with the debug version but add -win and -nomouse. - ------------------------------------------------------------------------- - -Win32/minGW/SDL ------ - -need: -- tested with gcc 2.95 and 3.X. -- can also use Dev-C++ 5.0 beta 9 (4.9.9.0) from http://www.bloodshed.net/dev/devcpp.html -- SDL 1.2 -- SDL_mixer 1.2 - -compile -make minGW=1 SDL=1 -or use src\SDL\Win32SDL.dev with Dev-C++ 4.9.9.0 or later - -debug: -gdb ? - ------------------------------------------------------------------------- - -WinCE/SDL WIP ------ - -need: -- ActiveSync 3.8 - http://www.microsoft.com/windowsmobile/downloads/activesync38.mspx - -- ActiveSync 3.7.1, if 3.8 isn't available for your language - http://www.microsoft.com/windowsmobile/downloads/activesync37.mspx - -- eMbedded Visual Tools 3.0 - 2002 Edition - http://www.microsoft.com/downloads/details.aspx?FamilyID=f663bf48-31ee-4cbe-aac5-0affd5fb27dd - -- Pocket PC 2000 SDK - http://www.microsoft.com/downloads/details.aspx?FamilyID=bb3f4d7b-de2a-4e1a-a175-26a68c301ac4 - -- Pocket PC 2002 SDK (eMVT 3.0 2002 Ed. comes with this) - http://www.microsoft.com/downloads/details.aspx?FamilyID=2dbee84a-bd94-4167-b817-2b2e548b2e92 - -- Pocket PC 2002 SDK Emulator Images (eMVT 3.0 2002 Ed. comes with this) - http://www.microsoft.com/downloads/details.aspx?FamilyID=25f4de97-ae80-477a-9df1-496b85b3d3e3 - -- eMbedded Visual C++ 4.0 - http://www.microsoft.com/downloads/details.aspx?familyid=1DACDB3D-50D1-41B2-A107-FA75AE960856 - -- eMbedded Visual C++ 4.0 SP3 (Win CE 4.0-4.2) - http://www.microsoft.com/downloads/details.aspx?FamilyID=5bb36f3e-5b3d-419a-9610-2fe53815ae3b - - OR - -- eMbedded Visual C++ 4.0 SP4 (No SH3 support,Win CE 4.0-5.0 support) - http://www.microsoft.com/downloads/details.aspx?FamilyID=4a4ed1f4-91d3-4dbe-986e-a812984318e5 - -- eMbedded Visual C++ 4.0 Update 5625 (SP4 only) - http://www.microsoft.com/downloads/details.aspx?FamilyID=aa282a6d-6f57-436d-8c10-0ec02d94f5b1 - -- Windows CE: Standard Software Development Kit - http://www.microsoft.com/downloads/details.aspx?familyid=a08f6991-16b0-4019-a174-0c40e6d25fe7 - -- SDK for Windows Mobile 2003-based Pocket PCs - http://www.microsoft.com/downloads/details.aspx?FamilyId=9996B314-0364-4623-9EDE-0B5FBB133652 - -- Emulator Images for Windows Mobile 2003 Second Edition software for Pocket PC - http://www.microsoft.com/downloads/details.aspx?familyid=5C53E3B5-F2A2-47D7-A41D-825FD68EBB6C - -- Microsoft Device Emulator 1.0 Community Preview - http://beta.microsoft.com Use Guest ID "MSDEVICE" to access the Community Preview website - -- Windows CE Utilities for Visual Studio .NET 2003 Add-on Pack 1.1 - (if you also have VS 2003 installed, you need this to install Win CE 5.0 SDK, else no need) - http://www.microsoft.com/downloads/details.aspx?FamilyId=7EC99CA6-2095-4086-B0CC-7C6C39B28762 - -- Windows CE 5.0: Standard Software Development Kit (eMC++ 4 SP4 only) - http://www.microsoft.com/downloads/details.aspx?FamilyID=fa1a3d66-3f61-4ddc-9510-ae450e2318c3 - -- SDL 1.27 (use patch and zip in tools\SDL1.2.7_CE) - -compile -use src\SDL\WinCE\SRB2CE.vcw - -debug: -? - - -2. Explanation of the code -========================== - - 2.1 The memory model (original) (z_zone.c) (by BP) - -------------------- - - SRB2 allocate a heap of 6/32/48 megs at begining and provide a Z_Malloc function - to allocate in this heap. - - Z_Malloc( int size,int tag,void* user ) - - size is the size in byte - tag can be : PU_STATIC allocated static (like malloc do) - call Z_Free to free it - PU_LEVEL same as static but the zone is "tagged" with the - tag PU_LEVEL, when calling - Z_FreeTag (PU_LEVEL, PU_LEVEL) all zone tagged - with PU_LEVEL are freed (at the end of the level) - PU_CACHE this one _can_ be freed automatiquely by one other - call to Z_Malloc. the *user point to a pointer - to this zone so when freed automatiquely the - pointer is set to NULL so eatch time you use it - you must check if the pointer is not NULL and - reload it. - - (...) - - 2.2 Hardware Texture model (by BP) - -------------------------- - - Eatch texture/patch/flats/pic in SRB2 are converted to hardware texture at - runtime (the GlideMipmap_s structure (hw_data.h)). I will call hardware - texture a gr_texture so there is no confusion. - - To remind you : - - Texture are set of patch and are associate to linedefs (walls) can be - upper, lower or middle texture. It can have hole on it. - - patch are sprites (the doom patch are run of vertical lines) - - flats are used for floors and ceiling of sectors and have size of 64x64 - it can't have hole on it - - pic are new legacy format for picture, it can only handle plain texture - like flats it is now used for hud in full screen for the main picture - of legacy and for coronas (the format was extended to handle 32 bit color - or intensity + alpha, not all are implemented at this time) - - Since patch, flat and pic are basic structure represented by only one lump in - the wad, the wad loader allocate for eatch lump a GlideMipmap_s (cache3Dfx) - and init data field to NULL. Since the data structure is allocated in - PU_3DFXCACHE (like PU_CACHE) the data will be initilised when needed - (hw_cache.c). - - The GlideMipmap_s structures for textures are initialized on - HWR_PrepLevelCache (hw_cache.c) it is called in P_SetupLevel (load level) - the number of textures is computed with TEXTURE1, TEXTURE2 lumps since this - can be changed in runtime in SRB2 (load a wad while runing) it must be - reallocated. Well, at this time it is realloceted at eatch level start. We - can do better, since numtextures change only when a wad is loaded. - - The 3dfx driver use glide3, it load gr_texture in gr_texture memory of the - card in fifo order when there is no more place it remove the first gr_texture, - the downloaded field of GlideMipmap_s go to false and when needed it is - reloaded in gr_texture memory. In OpenGl, since OpenGl keep texture in there - own memory and handle gr_texture memory of the card we no more need to - redownload it but if we not free time to time gr_texture memory in opengl, - it will get alot of memory, so the gr_texture memory is cleared at eatch - new level (same time of texture reallocation). Opengl and 3dfx link the - loaded gr_texture with the nextmipmap field of GlideMipmap_s so before clear - textures of the heap we MUST free gr_texture memory of OpenGl or 3dfx ! - - SRB2 can also draw patch with a differant colormap (thanks to Hurdler). - When needed it create the same gr_texture but just with a differant colormap. - This one is linked with the original in the GlideMipmap_s with the - nextcolormap field. - - So when a polygone with a gr_texture must be drawn, first we check if the - gr_textures is not allready loaded in hadware memory (downloaded field) if - not then we check if gr_texture data is there (not grabbed by z_malloc - function) if not we must recompute it eatch type of gr_texture (texture, - patch, flat, pic have there own methode) the we can send the gr_texture - to 3dfx or OpenGl. diff --git a/doc/specials.html b/doc/specials.html deleted file mode 100644 index 2cc840632e4a32264dc0b089ab76fb8647683c38..0000000000000000000000000000000000000000 --- a/doc/specials.html +++ /dev/null @@ -1,1992 +0,0 @@ -<html> - -<head> -<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> -<title>Sonic Robo Blast II - Specials Reference Document</title> -</head> - -<body bgcolor="white" text="black" link="blue" vlink="blue" alink="blue"> - -<h1><big>SRB2 Specials Reference Document</big></h1> - -<p><i>Last updated May 27, 2008</i></p> - -<p><i>For v1.1 Private Beta</i></p> - -<p>This is the SRB2 Specials Reference Document. It is designed to be the ultimate -reference for effects used in SRB2. As such, it is rather technical in areas and quite -concise, and is not something a beginner with level design should be dealing with.</p> - -<h1><a name="things"></a>Thing Types</h1> - -<p>In general, thing bitsets have 4 flags and 3 digits for their height. The bitset is -0xAAAB, where AAA is the object's height above ground, and B are the Easy, Normal, Hard, -and Deaf flags. To get the bitset on a normal object, multiply the height desired by 16, -and then add the existant B. Some objects use 32 as this number, and they will be noted. -Objects that multiply by 16 can be placed up to 4095 units in the air, while objects that -multiply by 32 can be placed up to 2047 units in the air. - -<ul> - <li><u><big><big>Player Starts</big></big></u><ol> - <h3><a name="t1"></a>1 - Player 01 Start</h3> - <p>This is the start for the first player in single player mode, cooperative mode, or race - mode. This start must be placed on every map, as it is what the game defaults to if the - start it is attempting to find isn't there. If there is no Player 1 Start on the map, and - the game is confused over where to spawn the player, the game will crash outright.</p> - <p>The Deaf tag will make the player spawn from the ceiling, and the object needs to be - multiplied by 32 to give height, not 16.</p> - <h3><a name="t2"></a>2 - Player 02 Start</h3> - <p>This is the start for the second player in cooperative and race mode.</p> - <p>The Deaf tag will make the player spawn from the ceiling, and the object needs to be - multiplied by 32 to give height, not 16.</p> - <h3><a name="t3"></a>3 - Player 03 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t4"></a>4 - Player 04 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t5"></a>5 - Player 05 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t6"></a>6 - Player 06 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t7"></a>7 - Player 07 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t8"></a>8 - Player 08 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t9"></a>9 - Player 09 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t10"></a>10 - Player 10 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t11"></a>11 - Player 11 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t12"></a>12 - Player 12 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t13"></a>13 - Player 13 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t14"></a>14 - Player 14 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t15"></a>15 - Player 15 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t16"></a>16 - Player 16 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t17"></a>17 - Player 17 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t18"></a>18 - Player 18 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t19"></a>19 - Player 19 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t20"></a>20 - Player 20 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t21"></a>21 - Player 21 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t22"></a>22 - Player 22 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t23"></a>23 - Player 23 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t24"></a>24 - Player 24 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t25"></a>25 - Player 25 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t26"></a>26 - Player 26 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t27"></a>27 - Player 27 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t28"></a>28 - Player 28 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t29"></a>29 - Player 29 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t30"></a>30 - Player 30 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t31"></a>31 - Player 31 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t32"></a>32 - Player 32 Start</h3> - <p>See Thing <a href="#t2">2</a> for more information.</p> - <h3><a name="t33"></a>33 - Player Match Start</h3> - <p>This is the start for players in Match and Chaos modes. They should also be placed in - Capture the Flag maps as well. There should be 32 of these in a map to assure proper - randomization. While it's unelegant, they can be stacked on top of each other without - negative effect.</p> - <p>The Deaf tag will make the player spawn from the ceiling, and the object needs to be - multiplied by 32 to give height, not 16.</p> - <h3><a name="t34"></a>34 - CTF Team Start (Red)</h3> - <p>This is the start for players on the red team in Capture the Flag mode. There should be - 32 of these in a map to assure proper randomization. While it's unelegant, they can be - stacked on top of each other without negative effect.</p> - <p>The Deaf tag will make the player spawn from the ceiling, and the object needs to be - multiplied by 32 to give height, not 16.</p> - <h3><a name="t35"></a>35 - CTF Team Start (Blue)</h3> - <p>This is the start for players on the blue team in Capture the Flag mode. There should - be 32 of these in a map to assure proper randomization. While it's unelegant, they can be - stacked on top of each other without negative effect.</p> - <p>The Deaf tag will make the player spawn from the ceiling, and the object needs to be - multiplied by 32 to give height, not 16.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Enemies</big></big></u><ol> - <h3><a name="t100"></a>100 - Crawla (Blue)</h3> - <p>These are the blue ground enemies found in the one player stages. They can't move off - of cliffs and are exceedingly slow.</p> - <h3><a name="t101"></a>101 - Crawla (Red)</h3> - <p>These are the red ground enemies found in the one player stages. They can't move off - cliffs and are relatively slow.</p> - <h3><a name="t102"></a>102 - Stupid Dumb Unnamed RoboFish (tm)</h3> - <p>This is the little fish in Greenflower Zone. The angle determines the jump height, with - 0 being the old jump style. Note that the jump height is based on force, not units, so - experimentation will be necessary to get the correct height.</p> - <h3><a name="t103"></a>103 - Yellow Buzz</h3> - <p>This enemy flies at a moderate speed directly at the player.</p> - <h3><a name="t104"></a>104 - Red Buzz</h3> - <p>This enemy flies at a relatively high speed directly at the player.</p> - <h3><a name="t105"></a>105 - Jetty-Syn Bomber</h3> - <p>This is a highly mobile flying enemy with a bomb that it drops on the player from - directly above. It is considered highly difficult to kill, and should only be used in - situations where the stage is supposed to be difficult.</p> - <h3><a name="t106"></a>106 - Jetty-Syn Gunner</h3> - <p>This is a highly mobile flying enemy with a gun that it fires at the player with high - accuracy. It is considered highly difficult to kill, and should only be used in situations - where the stage is supposed to be difficult.</p> - <h3><a name="t107"></a>107 - Crawla Commander</h3> - <p>This is the grey floating enemy in the opening room of Techno Hill Zone Act 2. It is - quite fast and will start bouncing after taking the first hit. It is significantly - challenging, although a spindash will kill it given time.</p> - <h3><a name="t108"></a>108 - Deton</h3> - <p>This is the red spherical enemy in Techno Hill Zone Act 2. Upon seeing the player, it - makes a mad dash straight for them. With the exception of the <a href="#t404">Armageddon - Shield</a>, Detons are invincible, and must be avoided by running behind a wall or another - enemy.</p> - <h3><a name="t109"></a>109 - Skim</h3> - <p>This is an enemy that floats on the surface of the water, dropping bombs into the water - below. It is not currently used in any of the Single Player stages, but it is fully - operational. The designer does not have to put them on the surface of the water, they know - where it is.</p> - <h3><a name="t110"></a>110 - THZ Turret</h3> - <p>This is the turret from Techno Hill Zone Act 2. It fires large bursts of laser fire at - the player with high accuracy. It is invincible unless it is somehow dipped into water.</p> - <h3><a name="t111"></a>111 - Popup Turret</h3> - <p>This is a small turret that pops up now and then and shoots. The object's angle is a - value defining the delay between shooting.</p> - <h3><a name="t112"></a>112 - Sharp</h3> - <p>This is a blue enemy with spikes on top if it. It starts off by slowly chasing the player, - then it fades to red and runs after the player, and is invincible until it fades back to red.</p> - <h3><a name="t113"></a>113 – Jet Jaw</h3> - <p>This is an underwater enemy that tries to bite at the player, which can be found in - Deep Sea Zone.</p> - <h3><a name="t114"></a>114 – Snailer</h3> - <p>This is an incomplete enemy.</p> - <h3><a name="t115"></a>115 – Bird Aircraft Strike Hazard (B.A.S.H.)</h3> - <p>This is the red vulture-like enemy in Arid Canyon Zone. If it sees a player, it lifts off and - charges at him. Collision with a wall will send it plummeting.</p> - <h3><a name="t116"></a>116 – Pointy</h3> - <p>This is the orbinaut enemy that has spikes circling around it. None of the single player stages - currently use him. You have to place him in a map by using a WAD editor, he can't be placed using - objectplace.</p> - <h3><a name="t117"></a>117 – Robo-Hood</h3> - <p>This is the green enemy from Castle Eggman Zone, which shoots arrows at the player.</p> - <h3><a name="t118"></a>118 – CastleBot FaceStabber</h3> - <p>This is the large grey enemy from Castle Eggman Zone. It slowly trudges towards the player, - and if the player in range, lunges at them with his sword.</p> - <h3><a name="t119"></a>119 – Egg Guard</h3> - <p>This is the enemy from Castle Eggman Zone that wields a protective shield.</p> - <h3><a name="t120"></a>120 – Green Snapper</h3> - <p>This is the green turtle enemy from Arid Canyon Zone. This enemy behaves exactly like a blue - crawla does. The circumference of its shell is covered with spikes, so the only way to destroy it - is by jumping on top of it.</p> - <h3><a name="t121"></a>121 – Minus</h3> - <p>This is the digging enemy from Arid Canyon Zone. It burrows underground towards the player, and - once it's directly underneath, it bursts out from under the ground, jumping up and hurting the player.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Bosses and their associated items (if any)</big></big></u><ol> - <h3><a name="t200"></a>200 - Egg Mobile (Boss 1)</h3> - <p>The boss of Greenflower Zone and Castle Eggman Zone. He moves around firing at the - player, and after taking six hits, he dashes at the player.</p> - <p>Giving the boss the Deaf flag will make him have spikeballs, like CEZ3, and giving him - the Multi flag will make the level end when he is dead. To place him above ground, - multiply by 32 to give height, not 16.</p> - <h3><a name="t201"></a>201 - Egg Slimer (Boss 2)</h3> - <p>This is the boss of Techno Hill Zone. It requires an axis point at the center to - function, and it goes in a circle around the axis point dropping slime. After 6 hits, he - stops going in a circle, and bouncing at the player, spewing a lot more slime.</p> - <p>The Multi flag will make the level end when he is dead.</p> - <h3><a name="t201"></a>202 - Sea Egg (Boss 3)</h3> - <p>This is the boss of Deep Sea Zone. More information will be supplied later.</p> - <p>The Multi flag will make the level end when he is dead.</p> - <h3>203 - Eggscalibur (Boss 4)</h3> - <p>This is the boss of Castle Eggman Zone. More information will be supplied later.</p> - <p>The Multi flag will make the level end when he is dead.</p> - <h3><a name="t290"></a>290 - Boss Flypoint</h3> - <p>This is the location the boss will fly to after being killed.</p> - <h3><a name="t291"></a>291 - Egg Capsule Center</h3> - <p> </p> - </ol> - </li> - <li><u><big><big>Collectibles</big></big></u><ol> - <h3><a name="t300"></a>300 - Ring</h3> - <p>This is a normal ring. Pick this up to get one ring.</p> - <p>Giving the deaf tag to a ring will cause it to float 31 units above the ground. This - does stack with bitsets, allowing rings to be a total of 4127 units above the ground at - maximum.</p> - <h3><a name="t301"></a>301 - Bounce Ring</h3> - <p>Picking this up gives you more ammo for this particular ring weapon. You cannot fire - the weapon, however, if you do not have the associated panel. - <h3><a name="t302"></a>302 - Rail Ring</h3> - <p>See thing <a href="#t301">#301</a>.</p> - <h3><a name="t304"></a>304 - Automatic Ring</h3> - <p>See thing <a href="#t301">#301</a>.</p> - <h3><a name="t305"></a>305 - Explosion Ring</h3> - <p>See thing <a href="#t301">#301</a>.</p> - <h3><a name="t305"></a>306 - Scatter Ring</h3> - <p>See thing <a href="#t301">#301</a>.</p> - <h3><a name="t305"></a>307 - Grenade Ring</h3> - <p>See thing <a href="#t301">#301</a>.</p> - <h3>310 - CTF Flag (Red)</h3> - <p>This is the red team's flag in capture the flag mode. If the blue team takes this to - their team base (sector type <a href="#s16384">16384</a>), they score a point.</p> - <h3><a name="t307"></a>311 - CTF Flag (Blue)</h3> - <p>This is the blue team's flag in capture the flag mode. If the red team takes this to - their team base (sector type <a href="#s12288">12288</a>), they score a point.</p> - <h3><a name="t308"></a>312 - Special Stage Token</h3> - <p>This token gives the player a chance at the special stage after the current stage has - ended. If more than one token is collected, the player gets that many chances at the - special stages, continuing until they run out of tokens or have all the emeralds.</p> - <h3><a name="t309"></a>313 - Emerald 1 (Green)</h3> - <p>This object gives the player the first emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t310"></a>314 - Emerald 2 (Orange)</h3> - <p>This object gives the player the second emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t311"></a>315 - Emerald 3 (Pink)</h3> - <p>This object gives the player the third emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t312"></a>316 - Emerald 4 (Blue)</h3> - <p>This object gives the player the fourth emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t313"></a>317 - Emerald 5 (Red)</h3> - <p>This object gives the player the fifth emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t314"></a>318 - Emerald 6 (Light Blue)</h3> - <p>This object gives the player the sixth emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t315"></a>319 - Emerald 7 (Grey)</h3> - <p>This object gives the player the seventh emerald as a pickup object, instead of by - completing a special stage.</p> - <h3><a name="t316"></a>320 - Emerald Hunt Location</h3> - <p>This is one of the three emeralds to be used in Hunting mode.</p> - <h3>323 - Emerald Spawn</h3> - <p>Spawn location for emeralds in Match mode.</p> - <h3><a name="t330"></a>330 - Bounce Ring Panel</h3> - <p>This is a match weapon panel. The Bounce Ring throws a slow ring that will bounce when - it hits walls.</p> - <p>Giving the deaf tag to a panel will cause it to float 31 units above the ground. This - does stack with bitsets, allowing panels to be a total of 4127 units above the ground at - maximum.</p> - <h3><a name="t331"></a>331 - Rail Ring Panel</h3> - <p>This is a match weapon panel. The Rail Ring gives the player an instantaneous shot, that - strikes its target the instant its fired, however there is a long downtime between shots. - Being shot by a rail ring causes more kickback than normal.</p> - <p>Giving the deaf tag to a panel will cause it to float 31 units above the ground. This - does stack with bitsets, allowing panels to be a total of 4127 units above the ground at - maximum.</p> - <h3><a name="t332"></a>332 - Automatic Ring Panel</h3> - <p>This is a match weapon panel. The Automatic Ring gives the player a fire rate of 17.5 - rings per second.</p> - <p>Giving the deaf tag to a panel will cause it to float 31 units above the ground. This - does stack with bitsets, allowing panels to be a total of 4127 units above the ground at - maximum.</p> - <h3><a name="t333"></a>333 - Explosion Ring Panel</h3> - <p>This is a match weapon panel. The Explosion Ring throws a slow ring that explodes into - many fragments upon striking a wall or another player. Being struck directly by the - Explosion Ring causes more kickback than usual.</p> - <p>Giving the deaf tag to a panel will cause it to float 31 units above the ground. This - does stack with bitsets, allowing panels to be a total of 4127 units above the ground at - maximum.</p> - <h3><a name="t334"></a>334 - Scatter Ring Panel</h3> - <p>This is a match weapon panel. The Scatter Ring throws 5 rings in a plus-shape.</p> - <p>Giving the deaf tag to a panel will cause it to float 31 units above the ground. This - does stack with bitsets, allowing panels to be a total of 4127 units above the ground at - maximum.</p> - <h3><a name="t335"></a>335 - Grenade Ring Panel</h3> - <p>This is a match weapon panel. The Grenade Ring throws a grenade that will explode - if an opposing player gets too close to it. It will also explode automatically after a - while if left untouched.</p> - <p>Giving the deaf tag to a panel will cause it to float 31 units above the ground. This - does stack with bitsets, allowing panels to be a total of 4127 units above the ground at - maximum.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Boxes</big></big></u><ol> - <h3><a name="t400"></a>400 - Super Ring (10 Rings)</h3> - <p>This monitor gives the player ten rings.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t402"></a>402 - Attraction Shield</h3> - <p>Also known as the yellow shield and god shield, this shield protects the player from a - single hit, then disappears. It also attracts all normal rings, spilled or on the map to - the player with the shield. It also protects the player from electric damage.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t403"></a>403 - Force Shield</h3> - <p>Also known as the blue shield, this shield protects the player from two hits, then - disappears. If the spin button is pressed while jumping, it is also possible to - reflect many projectiles.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t404"></a>404 - Armageddon Shield</h3> - <p>Also known as the black shield, this shield protects the player from a single hit, - triggering upon a hit. The shield can also be triggered by jumping, and then hitting the - spin key in midair. When the shield is triggered, a flash of light damages everything - within a large radius, destroying the shield in the process.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t405"></a>405 - Whirlwind Shield</h3> - <p>This shield protects the player from a single hit, then disappears. If the player does - a jump-spin, they will do a second jump in midair, making the maximum height that the - player can jump with the shield 224.</p> - <p>Versions of SRB2 previous to 1.09 had the Basic Shield in this object number, so make - sure to note that if the player loads the map in an older version, that is what they will - see.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t406"></a>406 - Elemental Shield</h3> - <p>Also known as the green shield, this shield protects the player from a single - hit, then disappears. While this shield is active, the player cannot drown. It also - protects the player from water, fire, and other damage. When the player with this shield - spin-dashes, it leaves a trail of fire, which deals fire damage to any enemy that touches - it.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t407"></a>407 - Super Sneakers</h3> - <p>This is a monitor powerup that gives the player about 2x running speed for 20 seconds.</p> - <h3><a name="t408"></a>408 - Invincibility</h3> - <p>This is a monitor powerup that prevents all damage to the player for 20 seconds.</p> - <h3><a name="t409"></a>409 - Extra Life</h3> - <p>This powerup monitor features the player's face, and provides an extra life when - struck.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t410"></a>410 - Eggman</h3> - <p>This monitor damages the player if they strike it.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t411"></a>411 - Teleporter</h3> - <p>This monitor mixes up all locations of players, teleporting them to the location of a - random other player. It has no effect in Single Player or in multiplayer modes while only - one player is in the game.</p> - <p>If monitors are given the Deaf tag, they will respawn as a random monitor type (not a ? - monitor) from the weighted table in modes that support respawn. Elsewise, they will - respawn as the same monitor.</p> - <h3><a name="t412"></a>412 - Random Box</h3> - <p>Destroy this monitor and you will get a random powerup, like the boxes in Sonic 2 race - mode.</p> - <h3><a name="t412"></a>413 - Gravity Boots Box</h3> - <p>Destroy this monitor and the gravity will be flipped for a short time.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Interactive Objects (friendly or otherwise)</big></big></u><ol> - <h3><a name="t500"></a>500 - Air Bubble Patch</h3> - <p>This is the air bubble patch used underwater to give players air. It spawns big bubbles - randomly which replenish the player's air.</p> - <h3><a name="t501"></a>501 - End Level Sign</h3> - <p>This is the sign at the end of the stage. When the player enters the <a href="#s8192">Exit - Sector</a>, this sign will start to spin, and end on the face of the player. This sign - does not make the stage end, it's just a visual effect for it.</p> - <h3><a name="t502"></a>502 - Star Post</h3> - <p>Star Posts allow the player to respawn after dying at a point other than the beginning - of the stage. There can be up to 32 Star Posts in a map, and they work with the bitsets.</p> - <p>Instead of controlling the difficulty and deaf flags, the final digit of the bitset - determines the number of the Star Post. 0x0000 is the first one and 0x000f is the - sixteenth one. Note that since this overwrites all of the difficulty flags, they will - appear in all difficulties, even though 0x0000 would normally mean it wouldn't appear in - any difficulty level.</p> - <h3><a name="t520"></a>520 - Spikeball</h3> - <p>Just like thing <a href="#t521">521</a>, except they do normal damage to the player on - contact. </p> - <h3><a name="t521"></a>521 - Spikeball (Special Stage)</h3> - <p>These are the spikeballs used in the special stages. They harm the player for damage on - contact, but only if they are carrying rings.</p> - <h3><a name="t522"></a>522 - Ceiling Spike</h3> - <p>This is a downward pointing spike for use on the ceiling. Touching the pointy end of - the spike deals damage to the player.</p> - <p>By default, it attaches itself to the ceiling, and the height part of the bitset - measures how far down from the ceiling, instead of up from the floor.</p> - <h3><a name="t523"></a>523 - Floor Spike</h3> - <p>This is a upward pointing spike for use on the floor. Touching the pointy end of the - spike deals damage to the player.</p> - <h3><a name="t524"></a>524 - Big Floating Mine</h3> - <p>When you get close, this mine will start to follow you. Touches you, and it explodes.</p> - <h3><a name="t540"></a>540 - THZ Fan</h3> - <p>This is the fan used inside the secret passage in Techno Hill Zone Act 1. It pushes the - player slowly up until it reaches the maximum height it can. The maximum height is - determined by the angle, measured in normal fracunits (It can go above 360 just fine).</p> - <h3><a name="t541"></a>541 - THZ Gas Jet</h3> - <p>This is the gas jet used at the end of Techno Hill Zone Act 1. It launches the player - straight up on regular intervals about the same height as a yellow spring pointing up.</p> - <h3><a name="t550"></a>550 - Yellow Spring (Up)</h3> - <p>This is a yellow spring pointing straight up. It has a medium amount of force behind - it.</p> - <h3><a name="t551"></a>551 - Red Spring (Up)</h3> - <p>This is a red spring pointing straight up. It has a large amount of force behind it.</p> - <h3><a name="t552"></a>552 - Blue Spring</h3> - <p>This is a blue spring pointing straight up. It has a small amount of force behind it. - The intent is for this spring to be used underwater. It has about the same effect - underwater as a yellow spring does above water.</p> - <h3><a name="t553"></a>553 - Yellow Spring (Down)</h3> - <p>This is a yellow spring pointing straight down. It has a medium amount of force behind - it.</p> - <h3><a name="t554"></a>554 - Red Spring (Down)</h3> - <p>This is a red spring pointing straight down. It has a large amount of force behind it.</p> - <h3><a name="t555"></a>555 - Yellow Spring (Diagonal Up)</h3> - <p>This is a yellow spring pointing upwards and in the direction the thing is facing. It - has a medium amount of force behind it. When the player touches this spring, he will - automatically turn to face the direction the spring is launching the player.</p> - <h3><a name="t556"></a>556 - Red Spring (Diagonal Up)</h3> - <p>This is a red spring pointing upwards and in the direction the thing is facing. It has - a large amount of force behind it. When the player touches this spring, he will - automatically turn to face the direction the spring is launching the player.</p> - <h3><a name="t557"></a>557 - Yellow Spring (Diagonal Down)</h3> - <p>This is a yellow spring pointing downwards and in the direction the thing is facing. It - has a medium amount of force behind it. When the player touches this spring, he will - automatically turn to face the direction the spring is launching the player.</p> - <h3><a name="t558"></a>558 - Red Spring (Diagonal Down)</h3> - <p>This is a red spring pointing downward and in the direction the thing is facing. It has - a large amount of force behind it. When the player touches this spring, he will - automatically turn to face the direction the spring is launching the player.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Special placement patterns</big></big></u><ol> - <h3><a name="t600"></a>600 - 5 Vertical Rings (Yellow Spring)</h3> - <p>This is a chain of five rings intended to be used with thing <a href="#t550">550</a>. - Do not use ring chain objects in any mode where items respawn, because ring chains do not - respawn. Use bitsets to create chains in any mode with item respawn.</p> - <h3><a name="t601"></a>601 - 5 Vertical Rings (Red Spring)</h3> - <p>This is a chain of five rings intended to be used with thing <a href="#t551">551</a>. - Do not use ring chain objects in any mode where items respawn, because ring chains do not - respawn. Use bitsets to create chains in any mode with item respawn.</p> - <h3><a name="t602"></a>602 - 5 Diagonal Rings (Yellow Spring)</h3> - <p>This is a chain of five rings intended to be used with thing <a href="#t555">555</a>. - Do not use ring chain objects in any mode where items respawn, because ring chains do not - respawn. Use bitsets to create chains in any mode with item respawn.</p> - <h3><a name="t603"></a>603 - 10 Diagonal Rings (Red Spring)</h3> - <p>This is a chain of ten rings intended to be used with thing <a href="#t556">556</a>. Do - not use ring chain objects in any mode where items respawn, because ring chains do not - respawn. Use bitsets to create chains in any mode with item respawn.</p> - <h3><a name="t604"></a>604 - Nights: Circle of Rings</h3> - <h3><a name="t605"></a>605 - Nights: Circle of Rings (Big)</h3> - <h3><a name="t606"></a>606 - Nights: Circle of Wing Logos</h3> - <h3><a name="t607"></a>607 - Nights: Circle of Wing Logos (Big)</h3> - <h3><a name="t608"></a>608 - Nights: Circle of Rings and Wings</h3> - <h3><a name="t609"></a>609 - Nights: Circle of Rings and Wings (Big)</h3> - <p> </p> - </ol> - </li> - <li><u><big><big>Powerup indicators/environmental effects/miscellany</big></big></u><ol> - <h3><a name="t700"></a>700 - Ambient Water SFX 1A (Small)</h3> - <h3><a name="t701"></a>701 - Ambient Water SFX 1B (Small)</h3> - <h3><a name="t702"></a>702 - Ambient Water SFX 2A (Medium)</h3> - <h3><a name="t703"></a>703 - Ambient Water SFX 2B (Medium)</h3> - <h3><a name="t704"></a>704 - Ambient Water SFX 3A (Large)</h3> - <h3><a name="t705"></a>705 - Ambient Water SFX 3B (Large)</h3> - <h3><a name="t706"></a>706 - Ambient Water SFX 4A (Extra Large)</h3> - <h3><a name="t707"></a>707 - Ambient Water SFX 4B (Extra Large)</h3> - <h3><a name="t708"></a>708 - Random Ambience 1</h3> - <h3><a name="t709"></a>709 - Random Ambience 2</h3> - <h3><a name="t750"></a>750 - Chaos Mode Enemy Spawn</h3> - <p>This is where the enemies spawn from in Chaos mode. There should be around 12 of these - points on a map with Chaos support.</p> - <h3><a name="t751"></a>751 - Teleport Destination</h3> - <p>This is the thing to be used with linedef type <a href="#l412">412</a>, the linedef - executor that teleports a player. This thing is where the player will spawn in the tagged - sector.</p> - <h3><a name="t752"></a>752 - Alternate View Point</h3> - <p>This is the thing to be used with linedef type <a href="#l422">422</a>, the linedef - executor that changes the camera view. This thing is where the camera will be moved to in - the tagged sector.</p> - <h3><a name="t753"></a>753 - Zoom Tube Waypoint</h3> - <p>Waypoints for zoom tubes. Think of Sonic 2's Metropolis Zone, Sonic 3 & Knuckles's - Death Egg Zone, and Lava Reef Zone. The lower byte of the ANGLE field specifies the - waypoint's number in the sequence, and the upper byte specifies the sequence that the - waypoint belongs to. These are used in conjunction with sector type <a href="#s32768">32768</a> - and <a href="#s36864">36864</a>.</p> - <h3><a name="t754"></a>754 - Push</h3> - <h3><a name="t755"></a>755 - Pull</h3> - <h3><a name="t756"></a>756 - Street Light Source</h3> - <p>This produces a light in OpenGL. It is used in Starlit Warehouse Zone, one of the match - stages, as the street lights.</p> - <h3><a name="t760"></a>760 - PolyObject Anchor</h3> - <p>This is the first of the two points used to set up 'how much to move' a polyobject by - when creating it. Angle is the PolyObject ID#.</p> - <h3><a name="t761"></a>761 - PolyObject SpawnPoint</h3> - <p>This is the second of the two points used to set up 'how much to move' a polyobject by - when creating it. Angle is the PolyObject ID#.</p> - <h3><a name="t762"></a>762 - PolyObject SpawnPoint Crush</h3> - <p>This is the second of the two points used to set up 'how much to move' a polyobject by - when creating it. Angle is the PolyObject ID#. This item tells the PolyObject that it - should hurt the player.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Greenflower Scenery</big></big></u><ol> - <h3><a name="t800"></a>800 - GFZ Flower (Normal)</h3> - <p>This is a scenery object from Greenflower Zone. It is the orange flower seen all - throughout GFZ and most GFZ-themed custom maps.</p> - <h3><a name="t801"></a>801 - GFZ Sunflower</h3> - <p>This is a scenery object from Greenflower Zone. It is the large blue sunflower seen all - throughout GFZ and most GFZ-themed custom maps.</p> - <h3><a name="t802"></a>802 - GFZ Budding Flower</h3> - <p>This is a scenery object from Greenflower Zone. It is the small purple flower seen all - throughout GFZ and most GFZ-themed custom maps.</p> - <h3><a name="t804"></a>804 - Berry Bush</h3> - <p>This is a scenery object from Greenflower Zone. It is the green bush with red berries - seen all throughout GFZ and most GFZ-themed custom maps.</p> - <h3><a name="t805"></a>805 - Bush</h3> - <p>This is a scenery object from Greenflower Zone. It is the green bush without the - berries seen all throughout GFZ and most GFZ-themed custom maps.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Techno Hill Scenery</big></big></u><ol> - <h3><a name="t900"></a>900 - THZ Flower</h3> - <p>This is a scenery object from Techno Hill Zone Act 1. It is the metallic white flower.</p> - <h3><a name="t901"></a>901 - THZ Alarm</h3> - <p>This is a scenery object from Techno Hill Zone Act 2. It is the little alarm in the - passage with the first Star Post. It creates noise, but the red visual effect in THZ2 was - done with a colormap, not this object.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Deep Sea Scenery</big></big></u><ol> - <h3><a name="t1000"></a>1000 - Gargoyle</h3> - <p>Pushable gargoyle. Can be stood on top of as well.</p> - <p>Giving this the Deaf tag will prevent it from being pushable.</p> - <h3><a name="t1001"></a>1001 - Seaweed</h3> - <p>Animated seaweed. Intangible scenery.</p> - <h3><a name="t1002"></a>1002 - Dripping Water</h3> - <p>Water dripping from the ceiling. ANGLE value specifies start delay.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Castle Eggman Scenery</big></big></u><ol> - <h3><a name="t1100"></a>1100 - Hanging Chain</h3> - <p>This is a scenery object from Castle Eggman, a dungeon chain hanging from the ceiling.</p> - <p>By default, it attaches itself to the ceiling, and the height part of the bitset - measures how far down from the ceiling, instead of up from the floor.</p> - <h3><a name="t1101"></a>1101 - CEZ Torch</h3> - <p>This is the torch used in Castle Eggman Zone. It produces light in OpenGL, and it harms - the player for fire damage on contact.</p> - <h3><a name="t1102"></a>1102 - Eggman Statue </h3> - <p>This is the large Eggman statue in Castle Eggman Zone.</p> - <h3><a name="t1103"></a>1103 - CEZ Flower</h3> - <p>This is a scenery object from Castle Eggman Zone. It is the decaying flower.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Arid Canyon Scenery</big></big></u><ol> - <h3><a name="t1200"></a>1200 – Big Tumbleweed</h3> - <p>A large moveable tumbleweed that rolls along the floor.</p> - <h3><a name="t1201"></a>1201 – Little Tumbleweed</h3> - <p>A small movable tumbleweed that rolls along the floor.</p> - <h3><a name="t1202"></a>1202 – Rock Spawner</h3> - <p>An object which randomly spawns falling rocks, which damage the player on impact.<br> - Description on how to use goes here.</p> - </ol> - </li> - <li><u><big><big>Red Volcano Scenery</big></big></u><ol> - <h3><a name="t1300"></a>1300 – Horizontal Flame Jet</h3> - <p>A stready stream of flames comes out horizontally.</p> - <h3><a name="t1301"></a>1301 – Vertial Flame Jet</h3> - <p>A stready stream of flames comes out vertially.</p> - </ol> - </li> - <li><u><big><big>Dark City Scenery</big></big></u><ol> - </ol> - </li> - <li><u><big><big>Doom Ship Scenery</big></big></u><ol> - </ol> - </li> - <li><u><big><big>Egg Rock / Final Fight Scenery</big></big></u><ol> - </ol> - </li> - <li><u><big><big>NiGHTS Items</big></big></u><ol> - <h3><a name="t1700"></a>1700 - Nights: Axis</h3> - <p>Lower 10 bits: Axis number in the mare (0-based) Upper 6 bits: Mare that axis belongs - to (0-based). ANGLE value determines the size of the axis to rotate around. If 16384 is - added to the ANGLE value, the axis will be inverted.</p> - <h3><a name="t1701"></a>1701 - Nights: Axis Transfer (Normal)</h3> - <h3><a name="t1702"></a>1702 - Nights: Axis Transfer Line</h3> - <h3><a name="t1703"></a>1703 - Nights: Ideya Drone</h3> - <p>Angle value sets the NiGHTS timer, in seconds. </p> - <h3><a name="t1704"></a>1704 - Nights: Bumper</h3> - <p>Lower 4 bits of the flags specify the angle of the bumper in 30 degree increments.</p> - <h3><a name="t1705"></a>1705 - Nights: Hoop</h3> - <h3><a name="t1706"></a>1706 - Nights: Wing Logo</h3> - <h3><a name="t1707"></a>1707 - Nights: Super Loop</h3> - <h3><a name="t1708"></a>1708 - Nights: Drill Refill</h3> - <h3><a name="t1709"></a>1709 - Nights: Helper</h3> - <h3><a name="t1710"></a>1710 - Nights: Egg Capsule</h3> - <p>The capsule you need to collect rings to break in NiGHTS. The value of its ANGLE field - determines how many rings you need to break it. Just like the axis points, the upper bits - (value >> 10) determine the mare it belongs to. For example, an angle value of 1024 - means it belongs to mare 1 (2nd mare, it's zero based), and requires 0 rings to break. - 1030 would be mare 1, and 6 rings to break. 2048 would be mare 2, no rings.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Mario Items</big></big></u><ol> - <h3><a name="t1800"></a>1800 - Coin</h3> - <p>This is a coin, which is essentially a ring with Mario graphics and sound effects.</p> - <h3><a name="t1801"></a>1801 - Overworld Goomba</h3> - <p>These are the enemies in Mario Koopa Blast 1, and are essentially Crawlas with a Mario - graphic.</p> - <h3><a name="t1802"></a>1802 - Underworld Goomba</h3> - <p>These are the enemies in Mario Koopa Blast 2, and are essentially Crawlas with a Mario - graphic.</p> - <h3><a name="t1803"></a>1803 - Fire Flower</h3> - <p>This is the powerup from the Mario Koopa Blast stages. It changes the player to a white - palette, and allows the player to throw fireballs with the fire button. The fireballs fly - in a Mario-style bounce trajectory until they hit an enemy or a wall.</p> - <h3><a name="t1804"></a>1804 - Koopa Shell</h3> - <p>This is the Koopa Shell in Mario Koopa Blast 1. It will bounce around, striking enemies - and players.</p> - <h3><a name="t1805"></a>1805 - Puma (Mario Jumping Fireball)</h3> - <p>This is the fireball used in Mario Koopa Blast 3. The angle determines the jump height, - with 0 being the old jump style. Note that the jump height is based on force, not units, - so experimentation will be necessary to get the correct height.</p> - <h3><a name="t1806"></a>1806 - King Bowser</h3> - <h3><a name="t1807"></a>1807 - Axe</h3> - <p>The axe used to defeat Bowser in the third Mario level.</p> - <h3><a name="t1808"></a>1808 - Bush (Short)</h3> - <p>This is a scenery object from Mario Koopa Blast</p> - <h3><a name="t1809"></a>1809 - Bush (Tall)</h3> - <p>This is a scenery object from Mario Koopa Blast</p> - <h3><a name="t1810"></a>1810 - Toad</h3> - <p>This is Toad at the end of Mario Koopa Blast 3.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Xmas Items</big></big></u><ol> - <h3><a name="t1850"></a>1850 - Xmas Pole</h3> - <p>X-Mas scenery object. Looks like a little barber shop pole.</p> - <h3><a name="t1851"></a>1851 - Candy Cane</h3> - <p>X-Mas scenery object. Looks like a candy cane.</p> - <p>Note that Mystic Realm 4 replaces this object with the Sonic 1 palm tree, so any maps - loaded while Mystic Realm 4 is loaded will overwrite the image, making any candy canes - look like palm trees, which can look kinda stupid.</p> - <h3><a name="t1852"></a>1852 - Snowman</h3> - <p>X-Mas scenery object. Pushable snowman with a happy face. Can be stood on top of as - well. Acts the same as thing <a href="#t1000">1000</a>.</p> - <p>Giving this the Deaf tag will prevent it from being pushable.</p> - <p> </p> - </ol> - </li> - <h1><a name="linetypes"></a>Linedef Types</h1> - <p>Lines may have flags applied to them. The following is a reference of their values. - Unless specified otherwise in a line type, the flags behave as follows:</p> - <div align="left"><table border="1" width="83%"> - <tr> - <td width="33%">NAME</td> - <td width="10%">VALUE</td> - <td width="57%">DESCRIPTION</td> - </tr> - <tr> - <td width="33%"><a name="#EFFECT6"></a>EFFECT6</td> - <td width="10%">1</td> - <td width="57%">Special use flag #6.</td> - </tr> - <tr> - <td width="33%"><a name="#BLOCKMONSTERS"></a>BLOCKMONSTERS</td> - <td width="10%">2</td> - <td width="57%">Prevents an enemy from crossing the line. May not work for especially - speedy enemies.</td> - </tr> - <tr> - <td width="33%"><a name="#TWOSIDED"></a>TWOSIDED</td> - <td width="10%">4</td> - <td width="57%">Flag used to indicate if a line is two sided. Do not modify.</td> - </tr> - <tr> - <td width="33%"><a name="#DONTPEGTOP"></a>DONTPEGTOP</td> - <td width="10%">8</td> - <td width="57%">Unpeg upper texture. Good for moving floors.</td> - </tr> - <tr> - <td width="33%"><a name="#DONTPEGBOTTOM"></a>DONTPEGBOTTOM</td> - <td width="10%">16</td> - <td width="57%">Unpeg bottom texture. Good for moving ceilings.</td> - </tr> - <tr> - <td width="33%"><a name="#EFFECT1"></a>EFFECT1</td> - <td width="10%">32</td> - <td width="57%">Special use flag #1.</td> - </tr> - <tr> - <td width="33%"><a name="#NOCLIMB"></a>NOCLIMB</td> - <td width="10%">64</td> - <td width="57%">Don't allow Knuckles to climb on this wall.</td> - </tr> - <tr> - <td width="33%"><a name="#EFFECT2"></a>EFFECT2</td> - <td width="10%">128</td> - <td width="57%">Special use flag #2.</td> - </tr> - <tr> - <td width="33%"><a name="#EFFECT3"></a>EFFECT3</td> - <td width="10%">256</td> - <td width="57%">Special use flag #3.</td> - </tr> - <tr> - <td width="33%"><a name="#EFFECT4"></a>EFFECT4</td> - <td width="10%">512</td> - <td width="57%">Special use flag #4.</td> - </tr> - <tr> - <td width="33%"><a name="#EFFECT5"></a>EFFECT5</td> - <td width="10%">1024</td> - <td width="57%">Special use flag #5.</td> - </tr> - <tr> - <td width="33%"><a name="#NOSONIC"></a>NOSONIC</td> - <td width="10%">2048</td> - <td width="57%">Disable line special if playing as Sonic (Single Player Only).</td> - </tr> - <tr> - <td width="33%"><a name="#NOTAILS"></a>NOTAILS</td> - <td width="10%">4096</td> - <td width="57%">Disable line special if playing as Tails (Single Player Only).</td> - </tr> - <tr> - <td width="33%"><a name="#NOKNUX"></a>NOKNUX</td> - <td width="10%">8192</td> - <td width="57%">Disable line special if playing as Knuckles (Single Player Only).</td> - </tr> - <tr> - <td width="33%"><a name="#BOUNCY"></a>BOUNCY</td> - <td width="10%">16384</td> - <td width="57%">Bounce the player off this line.</td> - </tr> - <tr> - <td width="33%"><a name="#TFERLINE"></a>TFERLINE</td> - <td width="10%">32768</td> - <td width="57%">Use this on a FOF line special to define the texture & offsets for - each side of the FOF. The control sector must have at LEAST the same # of sides as the - target sector(s).</td> - </tr> - </table> - </div><hr> - <li><u><big><big>Level Parameters / Miscellany</big></big></u><ol> - <h3><a name="l1"></a>1 - Per-Sector Gravity</h3> - <p>Sets the gravity of the tagged sector or sectors, as a percentage of global gravity - (which can be set separately using sector type <a href="#s176">176</a>). The floor height - of the control sector is used. If it is 1000, then the target sector will have 100% - gravity. If it is 500, the target sector will have 50% of the global gravity. Negative - values work as well, but players can't jump down; they'll get stuck to the ceiling, unless - the <a href="#NOCLIMB">NOCLIMB</a> flag is checked.</p> - <p>You can apply this special to the control sector of an intangible FOF to change the - gravity only inside that FOF.</p> - <h3><a name="l2"></a>2 - Custom Exit</h3> - <p>Tag this to an Exit Sector (type <a href="#s8192">8192</a>) to exit to a custom level, - overriding the one set in the map header. The map number you go to is indicated by the - front sector's floor. Additionally, if the control linedef's bitset is set to disallow - climbing (with the <a href="#NOCLIMB">NOCLIMB</a> attribute, whose value is 64), skip the - score tally screen when switching to the new map.</p> - <p>If the control linedef has the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> flag set, - this effect does something super complicated and fun, going to a different level depending - on whether the player has all emeralds or not. If the player has seven emeralds, the - linedef's front sector's ceiling height will be used. Otherwise, go to the map number - indicated by the linedef's front sector's floor. That's <i>only</i> if you set the <a - href="#BLOCKMONSTERS">BLOCKMONSTERS</a> flag.</p> - <p>If the <a href="#EFFECT4">EFFECT4</a> flag is set, the linedef's front side x offset - will be used as the new gametype after the map change, providing it is in range (from 0 to - 4, inclusive).</p> - <h3><a name="l3"></a>3 - Zoom Tube Parameters</h3> - <p>X length = speed. Y length = waypoint sequence #. See sector type <a href="#s32768">32768</a> - for more information.</p> - <h3><a name="l4"></a>4 - Speed Pad</h3> - <p>Creates a speed pad. The linedef direction and indicates the direction of the pad. The - target sector must have type <a href="#s1280">1280</a> or <a href="#s1536">1536</a> for - this to work.</p> - <p>If the <a href="#EFFECT4">EFFECT4</a> flag is set, you will not be teleported to the - center of the sector when the speed pad is activated.</p> - <h3><a name="l5"></a>5 - Camera Scanner</h3> - <p>Modifies camera position while the player is in the target sector. The floor and - ceiling of the control sector and the angle of the control linedef are the values for - CAM_HEIGHT, CAM_DIST, and CAM_ROTATE, respectively. Camera position is reset when the - player steps outside the sector.</p> - <h3><a name="l6"></a>6 - Disable Linedef</h3> - <p>Disables any linedef specials that share the same tag. Will be used in the future to - check if a particular level has been previously cleared or not.</p> - <h3><a name="l7"></a>7 - Flat Alignment</h3> - <p>Aligns floor and/or ceiling flats. The x alignment is specified by the control - linedef's x distance (the difference between the x values of its two vertices), and the y - alignment is specified by the control linedef's y distance.</p> - <p>By default, works on both the floor and ceiling (however, note that skies cannot be - "aligned" ;). Adding the <a href="#NOCLIMB">NOCLIMB</a> flag to the linedef will - align the floor only, while the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> flag will make - it align the ceiling only.</p> - <h3><a name="l8"></a>8 - Sector Special Parameters</h3> - <p>Sets special behavior of a sector's type depending on the flag(s) checked:</p> - <p><a href="#NOCLIMB">NOCLIMB</a> - Special only operates when touching ceiling</p> - <p><a href="#EFFECT4">EFFECT4</a> - Special operates when touching either the floor or the - ceiling</p> - <p><a href="#EFFECT3">EFFECT3</a> - Special operates by just touching the sector, rather - than having to be inside of it.</p> - <h3><a name="l9"></a>9 - Chain Parameters</h3> - <p>Sets special behavior of a moving chain as such:</p> - <p>x length - # of links on the chain</p> - <p>y length - Overall speed (0-15)</p> - <p>X offset - Rotation speed on the X axis (0-15)</p> - <p>Y offset - Rotation speed on the Z axis (0-15)</p> - <p>floorheight - angle to start at (0-15)</p> - <p>ceilingheight - maximum rotation speed</p> - <h3><a name="l10"></a>10 - Culling Plane</h3> - <p>Set like <a href="#l1">line 1</a>, this creates an invisible plane in the sector. If - your view is above this plane, lots of things drawn below the height of this plane will be - discarded, and if your view is below the plane, a lot of things drawn above the height of - the plane will be discarded. This is to tell the game to not draw stuff that you aren't - going to see anyway. Do note that the view doesn't have to be in the current sector, you - can also be viewing from the side, which may be undesirable. To prevent this problem, you - can check the <a href="#NOCLIMB">NOCLIMB</a> flag, which will allow you to 'group' a set - of sectors to one control sector in which the culling will only take effect. For example, - you have a control sector set up for culling, and have two culling lines in the control - sector, tagged to sectors 'A' and 'B'. If the player is in sector 'A' or 'B', the culling - will occur, but if the player is in sector 'C', it will not.</p> - <h3>11 - Rope Hang Parameters</h3> - <p>X length = speed. Y length = waypoint sequence #.</p> - <p>EFFECT1 - Don't wrap movement</p> - <p>See sector type 45056 for more information.</p> - <h3>12 - Rock Spawn Parameters</h3> - <p>Sets special behavior of a rock spawner (#1202) as such:</p> - <p>length - momentum strength</p> - <p>line angle - momentum angle</p> - <p>X offset - # of tics to wait until another is spawned</p> - <p>Y offset - Rock crumble sprite to use (0-15)</p> - <p>NOCLIMB - add some randomization to the momentum</p> - <p> </p> - <h3>13 - Heat Wave</h3> - <p>Applies a heat effect to the screen. Tag this to a sector, or to the control sector of a FOF.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Level Parameters / Miscellany</big></big></u><ol> - <h3><a name="l20"></a>20 - Marks first line in PolyObject</h3> - <p>Explain here.</p> - <h3><a name="l21"></a>21 - Explicitly include a PolyObject line</h3> - <p>Explain here.</p> - <h3><a name="l30"></a>30 - PolyObject Parameters</h3> - <p>Explain here.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Level-Load Effects</big></big></u><ol> - <h3><a name="l50"></a>50 - Instant Floor Lower</h3> - <p>Makes the floor instantly lower on level load to be at the same height as the lowest - floor of any bordering sector.</p> - <h3><a name="l51"></a>51 - Instant Ceiling Raise</h3> - <p>Makes the ceiling instantly rise on level load to be the same height as the highest - ceiling of any bordering sector.</p> - <h3><a name="l52"></a>52 - Continuously Falling Sector</h3> - <p>Requires two control sectors. Sector continuously falls until its ceiling reaches the - floor of the line's back sector, then returns to its original position and keeps falling. - Linedef length determines speed. Good for things like intermittently falling lava. If the <a - href="#NOCLIMB">NOCLIMB</a> flag is set, it falls upwards, instead of downwards.</p> - <h3><a name="l53"></a>53 - Continuous Floor/Ceiling Mover</h3> - <p>Must be a two-sided linedef, tagged to another sector on the map. The tagged sector's - floor and ceiling will move, first so that they're equal to the floor and ceiling of the - linedef's front sector, then so they're equal to the floor and ceiling of the linedef's - back sector, then the front sector again, and so on.</p> - <p>The speed of the movement is determined by the linedef's length and uses the same units - as linetype <a href="#l60">60</a>.</p> - <h3><a name="l54"></a>54 - Continuous Floor Mover</h3> - <p>Like linetype <a href="#l53">53</a>, but only moves the floor, not the ceiling. Can be - used to replace floating platforms in some cases, where only the floor was desired to - move.</p> - <h3><a name="l55"></a>55 - Continuous Ceiling Mover</h3> - <p>Like linetype <a href="#l53">53</a>, but only moves the ceiling, not the floor.</p> - <h3><a name="l56"></a>56 - Continuous Two-Speed Floor/Ceiling Mover</h3> - <p>Must be a two-sided linedef, tagged to another sector on the map. The tagged sector's - floor and ceiling will move, first so that they're equal to the floor and ceiling of the - linedef's front sector, then so they're equal to the floor and ceiling of the linedef's - back sector, then the front sector again, and so on.</p> - <p>The speed of the movement is determined by the linedef's x distance (the first way, - towards the front sector) and y distance (the second way, towards the back sector), using - the same units as linetype <a href="#l60">60</a>.</p> - <p>Unlike linetype <a href="#l53">53</a>, this effect does not slow down when it reaches - the end of its movement. Instead, it changes instantly from going in one direction to - going in the other. It's designed for making more sophisticated crushers than the crusher - type allows (i.e. crushers with varying rise/crush speeds, FOF crushers, crushers with - different start points).</p> - <h3><a name="l57"></a>57 - Continuous Two-Speed Floor Mover</h3> - <p>Like linetype <a href="#l56">56</a>, but only moves the floor, not the ceiling.</p> - <h3><a name="l58"></a>58 - Continuous Two-Speed Ceiling Mover</h3> - <p>Like linetype <a href="#l56">56</a>, but only moves the ceiling, not the floor.</p> - <h3><a name="l59"></a>59 - Activate Floating Platform</h3> - <p>This is used to make floating platforms (that move up and down) as well as moving - water. In fact, you can use this to make any type of block move vertically. The way it - works is somewhat confusing - You use three control sectors, all connected by at least one - linedef. Easiest thing to do is make three square sectors together in a row. One of the - linedefs on the middle sector should contain the Floor Over Floor line special that you - want. This will be the Floor Over Floor control sector. The other two sectors represent - the bottommost position you want the Floor Over Floor to reach, and the topmost position - you want the Floor Over Floor to reach. The 59 line can be on any of these sectors, as - long as you tag it to the middle one. If you still don't understand, look at Greenflower - Zone Act 2. If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, the platform will begin - moving upwards, rather than downwards.</p> - <h3><a name="l60"></a>60 - Activate Floating Platform (Adjustable Speed)</h3> - <p>Speed is indicated by linedef length; one unit of speed here is 0.25 fracunits per tic. - (Floating platforms made with type <a href="#l59">59</a> move at 2 fracunits per tic.) - Aside from the linedef length controlling speed, works exactly like linedef type <a - href="#l59">59</a>.</p> - <h3><a name="l61"></a>61 - Crusher 1 (Ceiling to Floor)</h3> - <p>The crush motion is from the ceiling to the floor. Linedef length indicates crusher - speed. See also linetype <a href="#l62">62</a>, Crusher 2.</p> - <h3><a name="l62"></a>62 - Crusher 2 (Floor to Ceiling)</h3> - <p>Like linetype <a href="#l61">61</a>, Crusher 1, except that it starts in a different - place, not synchronised with any crushers that use the Crusher 1 type. The highest ceiling - this crusher reaches will be the highest ceiling height of any bordering sector.</p> - <h3><a name="l63"></a>63 - Fake Floor</h3> - <p>Creates two fake planes, fake floor and fake ceiling. Main textures are not affected, - but as far as above/below textures and floor/ceiling flats are concerned, the floor and - ceiling height are those of the control sector. As far as collisions, walking, etc. are - concerned, the floor and ceiling flats are whatever they normally would be.</p> - <p>Fake floor is useful for railings (THZRAIL and WOODRAIL; see THZ2 for examples) and - snow effects (making a fake floor of snow just a few units above normal floor, so it looks - like the player's feet are buried in the snow).</p> - <h3><a name="l64"></a>64 - Appearing/Disappearing FOF</h3> - <p>Tag this to any FOF <i>line</i> and this will cause it to appear and disappear - intermittently. The line's X length is the amount of time (in tics) that the FOF will - appear, and Y length is the amount of time (in tics) that the FOF will disappear. The - control sector's floor height allows you to specify an offset (in tics) of how much time - will pass before the appearing/disappearing kicks in.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Floor-Over-Floors (FOFs)</big></big></u><ol> - <h3><a name="l100"></a>100 - Floor Over Floor: Solid, Opaque, Shadowcasting</h3> - <p>This is just a regular old FOF. As with any block, the ceiling of the control sector is - the top of the block, and the floor of the control sector is the bottom. - "Shadowcasting" means that the light value used in the control sector is used - for the area below where the actual FOF appears, as opposed to above it.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL--> - <h3><a name="l101"></a>101 - Floor Over Floor: Solid, Opaque, Non-Shadowcasting</h3> - <p>See notes for <a href="#l100">100</a>. "Non-shadowcasting" means that the - light value you set in the control sector will be used for the area above the FOF, instead - of below it.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_NOSHADE|FF_CUTLEVEL--> - <h3><a name="l102"></a>102 - Floor Over Floor: Solid, Translucent</h3> - <p>Useful for windows. The GLASSTEX texture is good for this purpose. You can change the - alpha value of the translucency by setting the control linedef's Above texture to a # - followed by a three-digit decimal number, 000 to 255. #000 is most transparent, #255 is - most opaque. Note that in software mode, there are actually only ten different values that - serve as a 'best guess'.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_NOSHADE|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA--> - <h3><a name="l103"></a>103 - Floor Over Floor: Solid, Sides Only</h3> - <p>A solid FOF that renders sides only, not planes (floor and ceiling). You were supposed - to be able to use it to place railings (THZRAIL, WOODRAIL, etc.) on FOFs. It doesn't work - for that, because the railings use a different kind of transparency and software mode - won't draw them on FOFs. So this one is going on the list of useless effects, right next - to linetype <a href="#l104">104</a>.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERSIDES|FF_NOSHADE|FF_CUTLEVEL--> - <h3><a name="l104"></a>104 - Floor Over Floor: Solid, No Sides</h3> - <p>Like a 3D floor of type <a href="#l101">101</a>, except that sides are not drawn. - Supposedly a little bit faster than a normal 3D floor. You can use it when the sides - wouldn't be visible anyway.</p> - <p>This type of 3D floor will have shadows if and only if you set the control linedef's <a - href="#NOCLIMB">NOCLIMB</a> flag.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERPLANES|FF_CUTLEVEL -If the <a href="#NOCLIMB">NOCLIMB</a> flag is disabled, it also adds FF_NOSHADE--> - <h3><a name="l105"></a>105 - Floor Over Floor: Solid, Invisible</h3> - <p>For making invisible walls and other strange effects.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_NOSHADE--> - <hr> - <h3><a name="l120"></a>120 - Floor Over Floor: Water, Opaque</h3> - <p>This one looks exactly like linetype <a href="#l100">100</a> ingame, but is a block of - water instead of solid.</p> - <p>The block will have the attribute of linetype <a href="#l200">200</a> if the <a - href="#NOCLIMB">NOCLIMB</a> flag is set.</p> - <p>To use the light level of the target sector, utilize the <a href="#EFFECT4">EFFECT4</a> - flag.</p> - <p>If this is used as lava (Fire Damage), and you set the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> - flag, you can still pass through the lava.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERALL|FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES--> - <h3><a name="l121"></a>121 - Floor Over Floor: Water, Translucent</h3> - <p>This one looks exactly like linetype <a href="#l102">102</a> ingame, but is a block of - water instead of solid.</p> - <p>The block will have the attribute of linetype <a href="#l200">200</a> if the <a - href="#NOCLIMB">NOCLIMB</a> flag is set.</p> - <p>To use the light level of the target sector, utilize the <a href="#EFFECT4">EFFECT4</a> - flag.</p> - <p>If this is used as lava (Fire Damage), and you set the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> - flag, you can still pass through the lava.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERALL|FF_TRANSLUCENT|FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA| -FF_CUTSPRITES--> - <h3><a name="l122"></a>122 - Floor Over Floor: Water, Opaque, No Sides</h3> - <p>Like linetype <a href="#l120">120</a>, but doesn't render sides.</p> - <p>The block will have the attribute of linetype <a href="#l200">200</a> if the <a - href="#NOCLIMB">NOCLIMB</a> flag is set.</p> - <p>To use the light level of the target sector, utilize the <a href="#EFFECT4">EFFECT4</a> - flag.</p> - <p>If this is used as lava (Fire Damage), and you set the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> - flag, you can still pass through the lava.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERPLANES|FF_SWIMMABLE|FF_BOTHPLANES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES--> - <h3><a name="l123"></a>123 - Floor Over Floor: Water, Translucent, No Sides</h3> - <p>Like linetype <a href="#l121">121</a>, but doesn't render sides. Most of the time this - won't make a difference. It can be useful, however, for windows that have water on one - side and not on the other.</p> - <p>The block will have the attribute of linetype <a href="#l200">200</a> if the <a - href="#NOCLIMB">NOCLIMB</a> flag is set.</p> - <p>To use the light level of the target sector, utilize the <a href="#EFFECT4">EFFECT4</a> - flag.</p> - <p>If this is used as lava (Fire Damage), and you set the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> - flag, you can still pass through the lava.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERPLANES|FF_TRANSLUCENT|FF_SWIMMABLE|FF_BOTHPLANES|FF_CUTEXTRA|FF_EXTRA| -FF_CUTSPRITES--> - <hr> - <h3><a name="l140"></a>140 - Floor Over Floor: Intangible from Bottom, Opaque </h3> - <p>This sector type is solid from the top and walls, but is not solid from the bottom. - This allows the designer to create one-way passages as well as simulate 2D design by - having platforms that players can jump up to from below.</p> - <p>This type of 3D floor will have shadows unless you set the control linedef's <a - href="#NOCLIMB">NOCLIMB</a> flag.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_BOTHPLANES|FF_ALLSIDES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <h3><a name="l141"></a>141 - Floor Over Floor: Intangible from Bottom, Translucent</h3> - <p>A copy of linetype <a href="#l140">140</a> that is also translucent.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_TRANSLUCENT|FF_BOTHPLANES|FF_ALLSIDES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <h3><a name="l142"></a>142 - Floor Over Floor: Intangible from Bottom, Translucent, No - Sides</h3> - <p>A platform you can jump up through, like linetype <a href="#l140">140</a> (and decides - the same way whether to have shadows or not), with translucency and that doesn't render - sides. Alpha value supported the same way as linetype <a href="#l102">102</a>.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_CUTLEVEL|FF_RENDERPLANES|FF_TRANSLUCENT|FF_PLATFORM|FF_BOTHPLANES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <hr> - <h3><a name="l150"></a>150 - Floor Over Floor: Bobbing (Air)</h3> - <p>FOF that moves down 16 units when you step on, then returns to its former position when - you step off. The control sector must be connected to another sector with the same floor - and ceiling height. This seemingly redundant sector is used for resetting the heights. (If - you forget to put it in, the bobbing floor when stepped on will go down, keep going down, - and never stop or come back up.) See also linetypes <a href="#l151">151</a> and <a - href="#l152">152</a>. This linedef is obsolete. Please use linetype 190-195.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_AIRBOB--> - <h3><a name="l151"></a>151 - Floor Over Floor: Adjustable Bobbing (Air)</h3> - <p>Like linetype <a href="#l150">150</a>, except that instead of the floor moving down 16 - units when you step on it, it moves down the number of units of the control linedef's - length. This linedef is obsolete. Please use linetype 190-195.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_AIRBOB--> - <h3><a name="l152"></a>152 - Floor Over Floor: Reverse Bobbing (Air)</h3> - <p>Like linetype <a href="#l151">151</a>, except in reverse. The platform goes <i>up</i> - when you step on it and back <i>down</i> when you step off. This linedef is obsolete. - Please use linetype 190-195.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_AIRBOB--> - <hr> - <h3><a name="l160"></a>160 - Floor Over Floor: Floating, Bobbing</h3> - <p>Bobs and floats in water. The floating part means that if the water moves or rises, - this platform will rise with it.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB--> - <hr> - <h3><a name="l170"></a>170 - Floor Over Floor: Crumbling (Respawn)</h3> - <p>Crumbles and falls away, then reappears 15 seconds later.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE--> - <h3><a name="l171"></a>171 - Floor Over Floor: Crumbling (No Respawn)</h3> - <p>Crumbles and falls away and never comes back.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_NORETURN--> - <h3><a name="l172"></a>172 - Floor Over Floor: Crumbling (Respawn)</h3> - <p>A copy of linetype <a href="#l140">140</a> that also crumbles when stood on and - reappears after 15 seconds.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_CRUMBLE|FF_BOTHPLANES|FF_ALLSIDES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <h3><a name="l173"></a>173 - Floor Over Floor: Crumbling (No Respawn)</h3> - <p>A copy of linetype <a href="#l172">172</a> that stays gone forever after crumbling.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_CRUMBLE|FF_NORETURN|FF_BOTHPLANES| -FF_ALLSIDES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <h3><a name="l174"></a>174 - Floor Over Floor: Intangible from Bottom, Crumbling - (Respawn), Translucent</h3> - <p>A copy of linetype <a href="#l141">141</a> that also crumbles when stood on and - reappears after 15 seconds.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_CRUMBLE|FF_TRANSLUCENT|FF_BOTHPLANES| -FF_ALLSIDES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <h3><a name="l175"></a>175 - Floor Over Floor: Intangible from Bottom, Crumbling (No - Respawn), Translucent</h3> - <p>A copy of linetype <a href="#l174">174</a> that stays gone forever after crumbling.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_CRUMBLE|FF_NORETURN|FF_TRANSLUCENT| -FF_BOTHPLANES|FF_ALLSIDES -If the <a href="#NOCLIMB">NOCLIMB</a> flag is enabled, it also adds FF_NOSHADE--> - <h3><a name="l176"></a>176 - Floor Over Floor: Crumbling (Respawn), Floating, Bobbing</h3> - <p>Crumbles and falls, then floats on water, then bobs when you step on it.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_AIRBOB|FF_CRUMBLE--> - <h3><a name="l177"></a>177 - Floor Over Floor: Crumbling (No Respawn), Floating, Bobbing</h3> - <p>Crumbles and falls, then floats on water, then bobs when you step on it. Unlike - linetype <a href="#l176">176</a>, does not return to its former position.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_AIRBOB|FF_CRUMBLE|FF_NORETURN--> - <h3><a name="l178"></a>178 - Floor Over Floor: Crumbling (Respawn), Floating</h3> - <p>Crumbles and falls, then floats on water, then reappears up in the air 15 seconds - later.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_FLOATBOB--> - <h3><a name="l179"></a>179 - Floor Over Floor: Crumbling (No Respawn), Floating</h3> - <p>Crumbles and falls, then spends the rest of its days floating on water, never to - reappear up in the air.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_FLOATBOB|FF_NORETURN--> - <h3><a name="l180"></a>180 - Floor Over Floor: Crumbling (Respawn), Bobbing (Air)</h3> - <p>Bobs, crumbles, and falls when stepped on.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_AIRBOB|FF_CRUMBLE--> - <hr> - <h3><a name="l190"></a>190 - Floor Over Floor: Rising Platform, Solid, Opaque, - Shadowcasting</h3> - <p>Just like <a href="#l100">100</a>, except when a player steps on it, it will rise up to - the control sector's highest adjacent sector. You set the control sectors for this up like - special <a href="#l59">59</a>. Linedef length controls speed like <a href="#l60">60</a>. - If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, it will require the player to spindash - to raise the platform.</p> - <h3><a name="l191"></a>191 - Floor Over Floor: Rising Platform, Solid, Opaque, - Non-Shadowcasting</h3> - <p>Just like <a href="#l101">101</a>, except when a player steps on it, it will rise up to - the control sector's highest adjacent sector. You set the control sectors for this up like - special <a href="#l59">59</a>. Linedef length controls speed like <a href="#l60">60</a>. - If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, it will require the player to spindash - to raise the platform.</p> - <h3><a name="l192"></a>192 - Floor Over Floor: Rising Platform, Solid, Translucent</h3> - <p>Just like <a href="#l102">102</a>, except when a player steps on it, it will rise up to - the control sector's highest adjacent sector. You set the control sectors for this up like - special <a href="#l59">59</a>. Linedef length controls speed like <a href="#l60">60</a>. - If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, it will require the player to spindash - to raise the platform.</p> - <h3><a name="l193"></a>193 - Floor Over Floor: Rising Platform, Solid, Invisible</h3> - <p>Just like <a href="#l105">105</a>, except when a player steps on it, it will rise up to - the control sector's highest adjacent sector. You set the control sectors for this up like - special <a href="#l59">59</a>. Linedef length controls speed like <a href="#l60">60</a>. - If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, it will require the player to spindash - to raise the platform.</p> - <h3><a name="l194"></a>194 - Floor Over Floor: Rising Platform, Intangible from Bottom, - Opaque</h3> - <p>Just like <a href="#l140">140</a>, except when a player steps on it, it will rise up to - the control sector's highest adjacent sector. You set the control sectors for this up like - special <a href="#l59">59</a>. Linedef length controls speed like <a href="#l60">60</a>. - If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, it will require the player to spindash - to raise the platform.</p> - <h3><a name="l195"></a>195 - Floor Over Floor: Rising Platform, Intangible from Bottom, - Translucent</h3> - <p>Just like <a href="#l141">141</a>, except when a player steps on it, it will rise up to - the control sector's highest adjacent sector. You set the control sectors for this up like - special <a href="#l59">59</a>. Linedef length controls speed like <a href="#l60">60</a>. - If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, it will require the player to spindash - to raise the platform.</p> - <hr> - <h3><a name="l200"></a>200 - Floor Over Floor: Light Block</h3> - <p>Like a half light block, but it's really an actual block. That is, the light only comes - down to the control sector's floor, not to the bottom of the level (as with linetype <a - href="#l201">201</a>.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_CUTSPRITES|FF_DOUBLESHADOW--> - <h3><a name="l201"></a>201 - Floor Over Floor: Half Light Block</h3> - <p>Light blocks can be used to set color maps and light values. The light value of the - control sector will be used and any colormap attached to it will be used also. Note that - only the ceiling of the control sector is used; the light goes all the way down to the - bottom of the level. If this isn't what you want, consider using linedef type <a - href="#l200">200</a> instead.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_CUTSPRITES -Note: Although it's not a true FOF, it does still have the same kind of definition, so -the FOF flags are included despite not being a real block.--> - <h3><a name="l202"></a>202 - Floor Over Floor: Fog Block</h3> - <p>Creates a block of colored fog. Attach a colormap (linetype <a href="#l606">606</a>) to - the control sector for the fog block; otherwise you won't see anything out of the - ordinary.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERALL|FF_FOG|FF_BOTHPLANES|FF_INVERTPLANES|FF_ALLSIDES|FF_INVERTSIDES|FF_CUTEXTRA| -FF_EXTRA|FF_DOUBLESHADOW|FF_CUTSPRITES--> - <hr> - <h3><a name="l220"></a>220 - Floor Over Floor: Intangible, Opaque </h3> - <p>Like <a href="#l120">opaque water</a>, but not swimmable. Good for a snow effect on - FOFs. Can also be used to make hidden rooms, like you would normally do by setting a Main - texture.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERALL|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES--> - <h3><a name="l221"></a>221 - Floor Over Floor: Intangible, Translucent</h3> - <p>See linedef type <a href="#l102">102</a> for how to adjust the translucency, making the - 3D floor more transparent or more opaque.</p> - <p>This type of 3D floor will have shadows if and only if you set the control linedef's <a - href="#NOCLIMB">NOCLIMB</a> flag.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERALL|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA -If the <a href="#NOCLIMB">NOCLIMB</a> flag is disabled, it also adds FF_NOSHADE--> - <h3><a name="l222"></a>222 - Floor Over Floor: Intangible, Sides Only</h3> - <p>An intangible FOF that renders sides only, not planes (floor and ceiling). It renders - both inside sides and outside sides. You can use it to place sector borders (GFZGRASS, - etc.) on FOFs.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERSIDES|FF_NOSHADE|FF_ALLSIDES--> - <h3><a name="l223"></a>223 - Floor Over Floor: Intangible, Invisible</h3> - <p>Useful for setting effects, such as wind and gravity.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_NOSHADE--> - <hr> - <h3><a name="l250"></a>250 - Floor Over Floor: Mario Block</h3> - <p>Like a normal FOF, except that the control linedef's Above texture is used after the - block has been hit (the Main texture is used before this). Any things in the control - sector will pop out the top of the block in the order in which they were placed. Rings - will be obtained and the effects of monitors will begin as soon as the block has been hit.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO--> - <h3><a name="l251"></a>251 - Floor Over Floor: Thwomp Block</h3> - <p>The thwomps are the crazy platforms with faces in Mario Koopa Blast 3. They can crush - you, but you can also ride on them.</p> - <p>Control sector is set up like a <a href="#l100">normal FOF</a>. When a player steps - underneath the thwomp, it will crush down to the floor. You don't need to tell it where - the floor is. It knows.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL--> - <h3><a name="l252"></a>252 - Floor Over Floor: Shatter Block</h3> - <p>Like the bustable block, linetype <a href="#l254">254</a>, except that it shatters on - any sort of contact, whether it's a spindash or not (and whether you're Knuckles or not).</p> - <p>If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, the block is only shatterable from - the bottom, like some things you spring up and break in Launch Base Zone from Sonic 3.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SHATTER--> - <h3><a name="l253"></a>253 - Floor Over Floor: Shatter Block, Translucent</h3> - <p>Translucent version of <a href="#l252">252</a> supporting alpha values.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SPINBUST|FF_TRANSLUCENT--> - <h3><a name="l254"></a>254 - Floor Over Floor: Bustable Block</h3> - <p>Bustable blocks can be destroyed by spindashing. Additionally, Knuckles can destroy - them by walking or jumping into them, since he is very strong. If the <a href="#NOCLIMB">NOCLIMB</a> - flag is set, only Knuckles can break the block.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP (|FF_ONLYKNUX if <a href="#NOCLIMB">NOCLIMB</a>)--> - <h3><a name="l255"></a>255 - Floor Over Floor: Spin Bust Block</h3> - <p>Like the bustable block, linetype <a href="#l254">254</a>, set off in a different way. - To break, jump onto it or fall down onto it while spinning. Similar to blocks found in - Marble Zone, as well as the ice cubes that would encase buttons and monitors in parts of - Ice Cap Zone.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SPINBUST--> - <h3><a name="l256"></a>256 - Floor Over Floor: Spin Bust Block, Translucent</h3> - <p>Translucent version of <a href="#l255">255</a> supporting alpha values.</p> - <h3><a name="l257"></a>257 - Floor Over Floor: Quicksand Block</h3> - <p>It's set up like any block. You can, of course, sink and die in it. X length of the - linedef determines sink speed, Y length determines how "sludgy" movement in the - quicksand is.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES--> - <h3><a name="l258"></a>258 - Floor Over Floor: Laser Block</h3> - <p>Creates a blinking FOF that zaps you if you touch it. You can set the flats and texture - to whatever you want. For a red laser like in THZ2, use REDFLR for the flats and REDWALL - for the texture.</p> - <p>You can also make other colors using BLUEFLR/BLUWALL (blue laser), GREENFLR/GRNWALL - (green laser), and YELFLR/YELWALL (yellow laser). Of course, those colors of lasers are - very expensive, so Eggman doesn't have nearly as many of them. He usually goes with the - cheap red lasers.</p> -<!--Exact FOF flags: -FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA--> - <h3><a name="l259"></a>259 - Floor Over Floor: Custom</h3> - <p>Place the appropriate flag values in hex (do not include the 0x in front of it) in the - line's UPPER TEXTURE field on the 2nd side of the linedef.</p> - </ol> - </li> - <li><u><big><big>Linedef Executor Triggers</big></big></u><ol> - <h3><a name="l300"></a>300 - Trigger Linedef Executor (Continuous)</h3> - <p>Triggers linedef executor in the control sector when a player touches the tagged - sector's floor or steps in the sector (depending on the sector special used). The linedef - executor will keep being triggered over and over again as long as a player is there, hence - the word "continuous" in this linetype's name. Tagged sector must have one of - the <a href="#sCat2">Trigger Linedef Executor</a> types for this to work.</p> - <h3><a name="l301"></a>301 - Trigger Linedef Executor (Each Time)</h3> - <p>Like <a href="#l300">300</a>, except that it only gets triggered once for each time you - fall or jump onto the floor. Tagged sector must have one of the <a href="#sCat2">Trigger - Linedef Executor</a> types for this to work.</p> - <h3><a name="l302"></a>302 - Trigger Linedef Executor (Once)</h3> - <p>Like <a href="#l300">300</a>, except that after that linedef executor executes its - linedefs, it's done. It's over. The linedefs will never be executed again.</p> - <h3><a name="l303"></a>303 - Trigger Linedef Executor (Ring Count - Continuous)</h3> - <p>Triggers linedef executor in the control sector when a player touches the tagged - sector's floor or steps in the sector (depending on the sector special used). The linedef - executor will keep being triggered over and over again as long as a player is there, hence - the word "continuous" in this linetype's name. Tagged sector must have one of - the <a href="#sCat2">Trigger Linedef Executor</a> types for this to work. Executor will be - triggered depending on how many rings the player has:</p> - <p>No flags -> Runs if (rings = line length)</p> - <p><a href="#NOCLIMB">NOCLIMB</a> -> Runs if (rings <= line length)</p> - <p><a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> -> Runs if (rings >= line length)</p> - <p><a href="#EFFECT4">EFFECT4</a> -> Takes the rings of ALL players into account.</p> - <h3><a name="l304"></a>304 - Trigger Linedef Executor (Ring Count - Once)</h3> - <p>Like <a href="#l303">303</a>, except that after that linedef executor executes its - linedefs, it's done. It's over. The linedefs will never be executed again.</p> - <h3><a name="l305"></a>305 - Trigger Linedef Executor (Character Ability - Once)</h3> - <p>Like linetype <a href="#l302">302</a>, but is only activated when the character's - ability number matches the linedef length by multiples of 10. For example:</p> - <p>0-9 = Charability 0</p> - <p>10-19 = Charability 1</p> - <p>20-29 = Charability 2</p> - <p>etc...</p> - <h3><a name="l306"></a>306 - Trigger Linedef Executor (Character Ability - Continuous)</h3> - <p>Like <a href="#l300">300</a>, but only triggers when the character's ability number - matches the linedef length by multiples of 10. See linetype <a href="#l305">305</a> for a - futher description.</p> - <h3><a name="l307"></a>307 - Trigger Linedef Executor (Character Ability - Each Time)</h3> - <p>Like <a href="#l301">301</a>, but only triggers when the character's ability number - matches the linedef length by multiples of 10. See linetype <a href="#l305">305</a> for a - futher description.</p> - <h3><a name="l308"></a>308 - Trigger Linedef Executor (Race Only, Once)</h3> - <p>Like linetype <a href="#l302">302</a>, but is only activated when the gametype is Race. - Useful for doing things like opening doors, pre-solving puzzles, etc. to make race - smoother.</p> - <h3><a name="l309"></a>309 - Trigger Linedef Executor (CTF Red Team - Continuous)</h3> - <p>Like <a href="#l300">300</a>, but only triggers if you are in CTF and on the red team.</p> - <h3><a name="l310"></a>310 - Trigger Linedef Executor (CTF Red Team - Each Time)</h3> - <p>Like <a href="#l301">301</a>, but only triggers if you are in CTF and on the red team.</p> - <h3><a name="l311"></a>311 - Trigger Linedef Executor (CTF Blue Team - Continuous)</h3> - <p>Like <a href="#l300">300</a>, but only triggers if you are in CTF and on the blue team.</p> - <h3><a name="l312"></a>312 - Trigger Linedef Executor (CTF Blue Team - Each Time)</h3> - <p>Like <a href="#l301">301</a>, but only triggers if you are in CTF and on the blue team.</p> - <h3><a name="l313"></a>313 - Trigger Linedef Executor (No More Enemies - Once)</h3> - <p>Like linetype <a href="#l302">302</a>, but is only activated when no more objects of - type MF_ENEMY exist in its tagged area. Think "destroy all enemies in this room for - the door to open to go to the next room". Tag this to a control sector. It will go - through the lines of the control sector, checking for any lines of type <a href="#l223">223</a> - and checking inside the area occupied by the invisible intangible FOF to see if any - enemies exist. If no alive enemies are in all of the type <a href="#l223">223</a> FOFs, - the linedef executor is run once. The line length is the tag number of the linedef - executor trigger to run.</p> - <h3><a name="l314"></a>314 - Trigger Linedef Executor (# of Pushables - Continuous)</h3> - <p>Like <a href="#l300">300</a>, but only triggers if the number of pushable objects in - the sector compared to the line length is:</p> - <p>No flags -> Runs if (# pushables = line length)</p> - <p><a href="#NOCLIMB">NOCLIMB</a> -> Runs if (# pushables >= line length)</p> - <p><a href="#EFFECT4">EFFECT4</a> -> Runs if (# pushables < line length)</p> - <h3><a name="l315"></a>315 - Trigger Linedef Executor (# of Pushables - Once)</h3> - <p>Like <a href="#l314">314</a>, but only triggers once.</p> - <h3><a name="l316"></a>316 - Trigger Linedef Executor (PolyObject - Land On)</h3> - <p>This will trigger every time you land on the polyobject. Line's tag # is 32000 + the - PolyObject ID #. You must also flag the PolyObject Start (#20) line with <a - href="#NOCLIMB">NOCLIMB</a> to tell the game it has a linedef executor associated with it.</p> - <p>So if you had a PolyObject with an ID of 1, this line would have a tag of 32001.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Linedef Executor Options</big></big></u><ol> - <h3><a name="l400"></a>400 - Linedef Executor: Set Tagged Sector's Floor Height/Pic</h3> - <p>When executed, instantly changes the tagged sector's floor height and flat to the floor - height and flat of the linedef's front sector.</p> - <h3><a name="l401"></a>401 - Linedef Executor: Set Tagged Sector's Ceiling Height/Pic</h3> - <p>When executed, instantly changes the tagged sector's ceiling height and flat to the - ceiling height and flat of the linedef's front sector.</p> - <h3><a name="l402"></a>402 - Linedef Executor: Set Tagged Sector's Light Level</h3> - <p>When executed, instantly changes the tagged sector's light level to that of the - linedef's front sector. Floor and ceiling light settings done with linetypes <a - href="#l601">601</a> and <a href="#l600">600</a> are transferred as well; colormaps are - not.</p> - <p>If there is a lighting effect active in the target sector or sectors at the time (glow, - fade, strobe, flicker), it will be stopped.</p> - <h3><a name="l403"></a>403 - Linedef Executor: Move Tagged Sector's Floor</h3> - <p>When executed, starts moving the tagged sector's floor until it is at the same height - as the linedef's front sector's floor. Speed is indicated in the same units used by - linetype <a href="#l60">60</a>.</p> - <p>If the line used has <a href="#NOCLIMB">NOCLIMB</a> flag, the floor flat will change - after the move, to that on the front sector's floor. This is like what linetype <a - href="#l400">400</a> does.</p> - <p>If the line used has <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> flag, another linedef - executor will be run when the floor movement is finished. (If multiple sectors finish at - different times, it goes by the lowest numbered sector, but you should probably try to - avoid this scenario.) The tag of the new linedef executor to run is specified by the X - alignment on the front side of the line. The tag number you use must be positive, and this - functionality cannot be combined with changing the floor flat using the <a href="#NOCLIMB">NOCLIMB</a> - flag. Running a linedef executor will take precedence over changing the floor flat.</p> - <h3><a name="l404"></a>404 - Linedef Executor: Move Tagged Sector's Ceiling</h3> - <p>When executed, starts moving the tagged sector's ceiling until it is at the same height - as the linedef's front sector's ceiling. Speed is indicated in the same units used by - linetype <a href="#l60">60</a>.</p> - <p>If the line used has <a href="#NOCLIMB">NOCLIMB</a> flag, the ceiling flat will change - after the move, to that on the front sector's ceiling. This is like what linetype <a - href="#l401">401</a> does.</p> - <p>If the line used has <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> flag, another linedef - executor will be run when the ceiling movement is finished. (If multiple sectors finish at - different times, it goes by the lowest numbered sector, but you should probably try to - avoid this scenario.) The tag of the new linedef executor to run is specified by the X - alignment on the front side of the line. The tag number you use must be positive, and this - functionality cannot be combined with changing the ceiling flat using the <a - href="#NOCLIMB">NOCLIMB</a> flag. Running a linedef executor will take precedence over - changing the ceiling flat.</p> - <h3><a name="l405"></a>405 - Linedef Executor: Lower Floor by Line</h3> - <p>Speed is indicated by x distance; amount to lower is indicated by y distance.</p> - <h3><a name="l406"></a>406 - Linedef Executor: Raise Floor by Line</h3> - <p>Speed is indicated by x distance; amount to raise is indicated by y distance.</p> - <h3><a name="l407"></a>407 - Linedef Executor: Lower Ceiling by Line</h3> - <p>Speed is indicated by x distance; amount to lower is indicated by y distance.</p> - <h3><a name="l408"></a>408 - Linedef Executor: Raise Ceiling by Line</h3> - <p>Speed is indicated by x distance; amount to raise is indicated by y distance.</p> - <h3><a name="l409"></a>409 - Linedef Executor: Change Calling Sector's Tag</h3> - <p>Changes the tag of the calling sector; that is, the sector on the map that activated - this linedef executor. The new tag is the linedef's length.</p> - <h3><a name="l410"></a>410 - Linedef Executor: Change Front Sector's Tag</h3> - <p>Changes the tag of the linedef's front sector. The new tag is the linedef's length.</p> - <h3><a name="l411"></a>411 - Linedef Executor: Stop Plane Movement</h3> - <p>Stops any and all floor, ceiling, or elevator movement in the tagged sector or sectors.</p> - <h2><a name="l412"></a>412 - Linedef Executor: Teleport Player to Tagged Sector</h2> - <p>The player who triggered the linedef executor will be teleported to the tagged sector. - The player's exact X, Y, Z, and angle are determined by a teleport destination thing, type - <a href="#t751">751</a>, somewhere in the tagged sector.</p> - <p>If the <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> flag is used, it won't flash and make - the teleport sound effects. If the <a href="#NOCLIMB">NOCLIMB</a> flag is used, it won't - reset the angle to the angle of the teleport destination thing, and if the <a - href="#EFFECT4">EFFECT4</a> flag is used, it will not kill your acceleration/speed upon - teleport.</p> - <h2><a name="l413"></a>413 - Linedef Executor: Change Music</h2> - <p>Linedef length indicates the music slot to use. If the linedef's <a href="#NOCLIMB">NOCLIMB</a> - flag is set, play the music once, otherwise loop it.</p> - <p>If the player dies and goes back to a starpost, the beginning of the level, or the - appropriate multiplayer start, the map music from before will be restored. The linedef - flag <a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> can be set to change this behavior, and - retain the new music even after dying.</p> - <p>If the linedef length isn't a valid music slot, the music is stopped.</p> - <h3><a name="l414"></a>414 - Linedef Executor: Play SFX</h3> - <p>Plays a sound effect. The line length is the sound number to use. The list of sound - effects can be found in sounds.h. The origin of the sound depends on which linedef flags - are set: <ul> - <li><a href="#NOCLIMB">NOCLIMB</a> : The sound is played from nowhere, but only for the - player who triggered it.</li> - <li><a href="#EFFECT4">EFFECT4</a>: The sound is played from nowhere for everyone.</li> - <li><a href="#BLOCKMONSTERS">BLOCKMONSTERS</a>: The sound is played from the center of the - sector that triggered the linedef executor.</li> - </ul> - <p>Otherwise, the sound is played from the location of the player or thing who triggered - it.</p> - <h3><a name="l415"></a>415 - Linedef Executor: Run Script</h3> - <p>Runs a script, the same kind of script you can run on level load with the level header - scriptname attribute. The script that will be run should have a lumpname of the form SCR<i>xxyyy</i>, - where <i>xx</i> is the two-digit map number and <i>yyy</i> is the linedef's sector's floor - height in decimal, with leading zeroes as necessary (or 000 if the floor height exceeds - 999 fracunits). For instance, if the linedef is in MAP31 and the floor of its sector is - 337 fracunits, the script named SCR31337 will be run.</p> - <h3><a name="l416"></a>416 - Linedef Executor: Start Adjustable Fire Flicker</h3> - <p>Essentially a copy of linetype <a href="#l603">603</a> that waits to activate until the - linedef executor is triggered. It does have an extra feature, though. If you use a - two-sided linedef with the <a href="#NOCLIMB">NOCLIMB</a> flag, the linedef's back sector - will be used as the maximum light level, allowing you to set the target sector (or - sectors) at a different starting light level entirely.</p> - <h3><a name="l417"></a>417 - Linedef Executor: Start Adjustable Glowing Light</h3> - <p>Essentially a copy of linetype <a href="#l602">602</a> that waits to activate until the - linedef executor is triggered. It does have an extra feature, though. If you use a - two-sided linedef with the <a href="#NOCLIMB">NOCLIMB</a> flag, the linedef's back sector - will be used as the maximum light level, allowing you to set the target sector (or - sectors) at a different starting light level entirely.</p> - <h3><a name="l418"></a>418 - Linedef Executor: Start Adjustable Blinking Light - (unsynchronized)</h3> - <p>Essentially a copy of linetype <a href="#l604">604</a> that waits to activate until the - linedef executor is triggered. It does have an extra feature, though. If you use a - two-sided linedef with the <a href="#NOCLIMB">NOCLIMB</a> flag, the linedef's back sector - will be used as the maximum light level, allowing you to set the target sector (or - sectors) at a different starting light level entirely.</p> - <h3><a name="l419"></a>419 - Linedef Executor: Start Adjustable Blinking Light - (synchronized)</h3> - <p>Essentially a copy of linetype <a href="#l605">605</a> that waits to activate until the - linedef executor is triggered. It does have an extra feature, though. If you use a - two-sided linedef with the <a href="#NOCLIMB">NOCLIMB</a> flag, the linedef's back sector - will be used as the maximum light level, allowing you to set the target sector (or - sectors) at a different starting light level entirely.</p> - <h3><a name="l420"></a>420 - Linedef Executor: Fade Light Level</h3> - <p>When executed, gradually fades the tagged sector's light level to that of the linedef's - front sector. Floor and ceiling light settings done with linetypes <a href="#l601">601</a> - and <a href="#l600">600</a> are not affected or used.</p> - <p>If there is a lighting effect already active in the target sector or sectors at the - time (glow, other fade, strobe, flicker), it will be halted in favor of this one.</p> - <p>Linedef length in fracunits indicates speed. Fading from 224 to 64 with a linedef - length of 4 will take 40 fracunits (224 - 64 = 160, 160 / 4 = 40). There are 35 fracunits - in a second.</p> - <h3><a name="l421"></a>421 - Linedef Executor: Stop Lighting Effect</h3> - <p>Stops any lighting effects active in the tagged sector or sectors: glow, fade, strobe, - flicker, etc. The light level, whatever it is at the moment this script line is run, will - be preserved until a new lighting effect or light level change is used.</p> - <p>Note that the lighting effects will all stop other lighting effects when activated. In - other words, you only need to use this when you really want the lighting effect to stop, - not when you want one effect to stop and another to start.</p> - <h3><a name="l422"></a>422 - Linedef Executor: Cut-Away View</h3> - <p>Cuts away to a view from a different place for a moment. Only works for linedef - executors triggered by a player. Tag the line to a sector with an alt view thing (map - thing type 5007) in it at the proper location with the proper Z and angle. The line length - indicates how long to stay in this view, in tics.</p> - <p>By giving the linedef a <a href="#NOCLIMB">NOCLIMB</a> flag, you can adjust the - vertical viewing angle from the cut-away view. Set the x offset on the linedef's front - side to an integer -90 to 90. In software mode the range of viewing angles is actually - about -68 to 68. This is in degrees.</p> - <h3><a name="l423"></a>423 - Linedef Executor: Change Sky</h3> - <p>Changes sky to the # of the control sector's floorheight. This only affects the player - who activates it. If you'd like it to affect all players, make sure you check the <a - href="#NOCLIMB">NOCLIMB</a> flag.</p> - <h3><a name="l424"></a>424 - Linedef Executor: Change Weather</h3> - <p>Changes weather to the control sector's floorheight in powers of 10.</p> - <p>Example:</p> - <div align="left"><table border="1" width="28%"> - <tr> - <td width="50%">Linedef Length</td> - <td width="50%">Weather Type</td> - </tr> - <tr> - <td width="50%">10</td> - <td width="50%">None</td> - </tr> - <tr> - <td width="50%">20</td> - <td width="50%">Snow</td> - </tr> - <tr> - <td width="50%">30</td> - <td width="50%">Rain</td> - </tr> - <tr> - <td width="50%">40</td> - <td width="50%">Storm</td> - </tr> - </table> - </div><p>(higher numbers reserved for future use)</p> - <p>This only affects the player who activates it. If you'd like it to affect all players, - make sure you check the <a href="#NOCLIMB">NOCLIMB</a> flag.</p> - <h3><a name="l425"></a>425 - Linedef Executor: Change Object State</h3> - <p>Changes the animation frame of the activating object to the state # indicated by the - length of the control linedef. Be careful how you use this.</p> - <h3><a name="l426"></a>426 - Linedef Executor: Stop Object</h3> - <p>Makes the object that triggered the linedef executor stop moving, after being sent to - the center of the sector it's in (only if <a href="#NOCLIMB">NOCLIMB</a> flag is set), on - the floor. Although it comes to a complete stop, the object can begin moving right away - again. If the object is a player, the player will stop jumping, spinning, or anything - else.</p> - <h3><a name="l427"></a>427 - Linedef Executor: Award Score</h3> - <p>Adds to the score of the player who activated it. Control sector's floorheight = points - to award. This even works with negative values.</p> - <h3><a name="l428"></a>428 - Linedef Executor: Start Platform Movement</h3> - <p>Starts a moving platform in the nature of linetype <a href="#l59">59</a> or <a - href="#l60">60</a>. If the <a href="#NOCLIMB">NOCLIMB</a> flag is set, the platform will - begin moving upwards. Otherwise, it will start moving downwards. Speed of movement is set - just like with linetype <a href="#l60">60</a>.</p> - <h3><a name="l429"></a>429 - Linedef Executor: Crush Ceiling Once</h3> - <p>Ceiling moves down to the floor, then back up. Speed is determined by line length - - every 16 units equals 1 FRACUNIT/tic.</p> - <h3><a name="l430"></a>430 - Linedef Executor: Crush Floor Once</h3> - <p>Floor moves up to the ceiling, then back down. Speed is determined by line length - - every 16 units equals 1 FRACUNIT/tic.</p> - <h3><a name="l431"></a>431 - Linedef Executor: Crush Floor And Ceiling Once</h3> - <p>Floor and ceiling meet in the middle and then return, sandwiching anything that's - inbetween. Speed is determined by line length - every 16 units equals 1 FRACUNIT/tic.</p> - <h3><a name="l432"></a>432 - Linedef Executor: Enable 2D Mode</h3> - <p>Turns on 2D mode within the level. You'll probably only want to use this with a zoom - tube or teleport to guarantee that the player is in the correct position when it switches.</p> - <h3><a name="l433"></a>433 - Linedef Executor: Disable 2D Mode</h3> - <p>Turns off 2D mode within the level.</p> - <h3><a name="l434"></a>434 - Linedef Executor: Award Custom Power</h3> - <p>Awards (or removes!) a power to the calling player.</p> - <p>X length: Power Index + 1</p> - <p>Y length: Power Duration (in 35ths of a second)</p> - <h3><a name="l435"></a>435 - Linedef Executor: Change Scroller Direction</h3> - <p>Changes direction of a scroller (conveyor, texture). Also changes speed if this is not - an accelerative/displacement scroller.</p> - <h3><a name="l436"></a>436 - Linedef Executor: Shatter Block</h3> - <p>Shatters a FOF - of any type. Parameters are as follows:</p> - <p>Texture X Offset: Tag # of FOF target sector</p> - <p>Texture Y Offset: Tag # of FOF control sector</p> - <p>Note that the FOF should only have one target sector.</p> - <h3><a name="l437"></a>437 - Linedef Executor: Disable Player Control</h3> - <p>Disables the controls of the player that triggered the linedef executor. If the - <a href="#NOCLIMB">NOCLIMB</a> flag is set, they will be able to jump, however.</p> - <p>Giving the front texture of the linedef an X offset will make the effect last that amount - of time, in tics. Otherwise, it ends immediately, so you would need to use a continuous - trigger.</p> - <h3><a name="l438"></a>438 - Linedef Executor: Set Object's Scale</h3> - <p>Length of this line determines the scale size of an object, in percentage. Note that there is a max of 400%.</p> - <h3><a name="l450"></a>450 - Linedef Executor: Execute Linedef Executor</h3> - <p>Just what it says. Can be used for recursion. Be careful, because you CAN make a loop - out of this that will freeze the game.</p> - <p>Tag is the linedef executor trigger tag to run.</p> - <h3><a name="l488"></a>488 - Linedef Executor: PolyObject - Move by Waypoints</h3> - <p>Moves a polyobject along a sequence of Zoom Tube waypoints.</p> - <p>Texture X offset: Speed (8 = 1 FRACUNIT).</p> - <p>Texture Y offset: Sequence # of Zoom Tube waypoints.</p> - <p>The movement also depends on which linedef flags are set: <ul> - <li><a href="#EFFECT1">EFFECT1</a> : Moves from highest waypoint # to lowest waypoint #.</li> - <li><a href="#EFFECT2">EFFECT2</a> : Comes back the way it came when the end is reached.</li> - <li><a href="#EFFECT3">EFFECT3</a> : Wrap around the waypoints.</li> - <li><a href="#EFFECT4">EFFECT4</a>: Continuously move (used with EFFECT2 or EFFECT3).</li> - </ul> - <p> </p> - </ol> - </li> - <li><u><big><big>Scrollers / Pushers</big></big></u><ol> - <h3><a name="l500"></a>500 - Scroll Wall First Side Left</h3> - <h3><a name="l501"></a>501 - Scroll Wall First Side Opposite Direction</h3> - <h3><a name="l502"></a>502 - Scroll Wall According to Linedef</h3> - <h3><a name="l503"></a>503 - Acc Scroll Wall According to Linedef</h3> - <p>Accelerative scrolling version of <a href="#l502">502</a>.</p> - <h3><a name="l504"></a>504 - Disp Scroll Wall According to Linedef</h3> - <p>Displacement scrolling version of <a href="#l502">502</a>.</p> - <h3><a name="l505"></a>505 - Scroll Texture by Offsets</h3> - <hr> - <h3><a name="l510"></a>510 - Scroll Floor Texture</h3> - <p>Linedef length and direction indicate speed and direction.</p> - <h3><a name="l511"></a>511 - Acc Scroll Floor Texture</h3> - <p>Accelerative scrolling version of <a href="#l510">510</a>.</p> - <h3><a name="l512"></a>512 - Disp Scroll Floor Texture</h3> - <p>Displacement scrolling version of <a href="#l510">510</a>.</p> - <h3><a name="l513"></a>513 - Scroll Ceiling Texture</h3> - <p>Linedef length and direction indicate speed and direction.</p> - <h3><a name="l514"></a>514 - Acc Scroll Ceiling Texture</h3> - <p>Accelerative scrolling version of <a href="#l513">513</a>.</p> - <h3><a name="l515"></a>515 - Disp Scroll Ceiling Texture</h3> - <p>Displacement scrolling version of <a href="#l513">513</a>.</p> - <hr> - <h3><a name="l520"></a>520 - Carry Objects on Floor</h3> - <p>Like linedef type <a href="#l530">530</a>, without scrolling the floor texture, so the - floor doesn't look like it's moving.</p> - <h3><a name="l521"></a>521 - Acc Carry Objects on Floor</h3> - <p>Accelerative scrolling version of <a href="#l520">520</a>.</p> - <h3><a name="l522"></a>522 - Disp Carry Objects on Floor</h3> - <p>Displacement scrolling version of <a href="#l520">520</a>.</p> - <h3><a name="l523"></a>523 - Carry Objects on Ceiling</h3> - <p>For FOF conveyor belts. Like <a href="#l533">533</a>, except without the scrolling to - accompany it.</p> - <h3><a name="l524"></a>524 - Acc Carry Objects on Ceiling</h3> - <p>Accelerative scrolling version of <a href="#l523">523</a>. Untested.</p> - <h3><a name="l525"></a>525 - Disp Carry Objects on Ceiling</h3> - <p>Displacement scrolling version of <a href="#l523">523</a>. Untested.</p> - <hr> - <h3><a name="l530"></a>530 - Scroll Floor Texture and Carry Objects</h3> - <p>Used for conveyor belts, in conjunction with sector type <a href="#s1024">1024</a> - (Conveyor Belt). Linedef length and direction indicate conveyor speed and direction, - respectively. This can also be used to convey items on the underneath of a FOF. See Egg - Rock Zone for an example.</p> - <h3><a name="l531"></a>531 - Acc Scroll Floor Texture and Carry Objects</h3> - <p>Accelerative scrolling version of <a href="#l530">530</a>.</p> - <h3><a name="l532"></a>532 - Disp Scroll Floor Texture and Carry Objects</h3> - <p>Displacement scrolling version of <a href="#l530">530</a>.</p> - <h3><a name="l533"></a>533 - Scroll Ceiling Texture and Carry Objects</h3> - <p>For conveyor belts on the top of FOFs, or for conveying items on a ceiling. Tag this to - the FOF control sector and give the FOF control sector a type of <a href="#s1024">1024</a>, - Conveyor Belt. For realism you might also want to scroll the control sector's floor - texture in the opposite direction (see linetype <a href="#l510">510</a>).</p> - <h3><a name="l534"></a>534 - Acc Scroll Ceiling Texture and Carry Objects</h3> - <p>Accelerative scrolling version of <a href="#l533">533</a>. Untested.</p> - <h3><a name="l535"></a>535 - Disp Scroll Ceiling Texture and Carry Objects</h3> - <p>Displacement scrolling version of <a href="#l533">533</a>. Untested.</p> - <hr> - <h3><a name="l540"></a>540 - Friction</h3> - <p>Linedef lengths greater than 100 indicate slippery ice, while linedef lengths less than - 100 can be used for sludge, with extra friction.</p> - <p>If you want friction on a FOF, tag this line to the control sector of the FOF. - Otherwise, tag it to the sector of desired destination.</p> - <h3><a name="l541"></a>541 - Wind</h3> - <p>Speed and direction are indicated by linedef length and direction. The target sector - should be of type <a href="#s512">512</a>, Wind/Current. If being used in a 3D Floor, put - the 512/768 sector type in the control sector, not the target sector. Also tag the line to - the control sector, and not the target sector.</p> - <p>Special flags:</p> - <p><a href="#NOCLIMB">NOCLIMB</a> -> Only this pusher will affect the object - the - object can't have multiple 'pushings' due to being on the edge of a sector, etc.</p> - <p><a href="#EFFECT4">EFFECT4</a> -> Player will go into slide with limited control - (similar to the water and oil slides in Labyrinth and Oil Ocean).</p> - <h3><a name="l542"></a>542 - Upwards Wind</h3> - <p>The length of the linedef is the wind speed. The target sector will need type <a - href="#s512">512</a> or <a href="#s768">768</a>. If being used in a 3D Floor, put the - 512/768 sector type in the control sector, not the target sector. Also tag the line to the - control sector, and not the target sector.</p> - <p>NOCLIMB/EFFECT4 flags operate the same as for line <a href="#l541">541</a>.</p> - <h3><a name="l543"></a>543 - Downwards Wind</h3> - <p>Wind speed is determined by the linedef's length. Type <a href="#s512">512</a> or <a - href="#s768">768</a> must be applied to the target sector. If being used in a 3D Floor, - put the 512/768 sector type in the control sector, not the target sector. Also tag the - line to the control sector, and not the target sector.</p> - <p>NOCLIMB/EFFECT4 flags operate the same as for line <a href="#l541">541</a>.</p> - <h3><a name="l544"></a>544 - Current</h3> - <p>Speed and direction are indicated by linedef length and direction. The target sector - should have type <a href="#s512">512</a>, Wind/Current. If being used in a 3D Floor, put - the 512/768 sector type in the control sector, not the target sector. Also tag the line to - the control sector, and not the target sector.</p> - <p>NOCLIMB/EFFECT4 flags operate the same as for line <a href="#l541">541</a>.</p> - <h3><a name="l545"></a>545 - Upwards Current</h3> - <p>Linedef length indicates speed. Target sector needs sector type <a href="#s512">512</a> - or <a href="#s768">768</a>. If being used in a 3D Floor, put the 512/768 sector type in - the control sector, not the target sector. Also tag the line to the control sector, and - not the target sector.</p> - <p>NOCLIMB/EFFECT4 flags operate the same as for line <a href="#l541">541</a>.</p> - <h3><a name="l546"></a>546 - Downwards Current</h3> - <p>Speed is indicated by linedef length. Assign a type of <a href="#s512">512</a> or <a - href="#s768">768</a> to the target sector. If being used in a 3D Floor, put the 512/768 - sector type in the control sector, not the target sector. Also tag the line to the control - sector, and not the target sector.</p> - <p>NOCLIMB/EFFECT4 flags operate the same as for line <a href="#l541">541</a>.</p> - <h3><a name="l547"></a>547 - Boom Push/Pull Thing</h3> - <p>Creates a "point pusher," or a point that pushes you away or pulls you toward - it if you get close enough. Tag the linedef to a sector with type <a href="#s512">512</a>, - Wind/Current, and with a thing on it of type 5001 (push) or 5002 (pull). The control - linedef's length indicates pushing/pulling strength; if length is L, the effect fades away - to nothing when you are 2L away from the point.</p> - <p>If you want to create multiple point pushers/pullers, you'll need to have them in - different target sectors, but they can share the same tag.</p> - <p>NOCLIMB/EFFECT4 flags operate the same as for line <a href="#l541">541</a>.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Lighting</big></big></u><ol> - <h3><a name="l600"></a>600 - Floor Lighting</h3> - <p>Sets the lighting for the floor only. The control sector's light value will be used for - the target sector's floor. Also see type <a href="#l601">601</a>.</p> - <h3><a name="l601"></a>601 - Ceiling Lighting</h3> - <p>Sets the lighting of the ceiling only. The light value of the control sector will be - used for the target sector's ceiling. Also see type <a href="#l600">600</a>.</p> - <h3><a name="l602"></a>602 - Adjustable Pulsating Light</h3> - <p>Linedef length indicates glow speed. The normal speed would be a linedef 32 units long.</p> - <p>The control sector (the linedef's front sector) is used to get what will be the minimum - light level for this effect, while the target sector's light level ends up being the - maximum.</p> - <h3><a name="l603"></a>603 - Adjustable Flickering Light</h3> - <p>Linedef length indicates flicker speed. Normal speed would be a 16 fracunit long - linedef. A longer linedef means more time in between flickers.</p> - <p>The control sector (the linedef's front sector) is used to get what will be the minimum - light level for this effect, while the target sector's light level ends up being the - maximum.</p> - <h3><a name="l604"></a>604 - Adjustable Blinking Light (unsynchronized)</h3> - <p>Line's X length is time for the light to be off, and Y length is the time for the light - to be on.</p> - <p>The control sector (the linedef's front sector) is used to get what will be the minimum - light level for this effect, while the target sector's light level ends up being the - maximum.</p> - <h3><a name="l605"></a>605 - Adjustable Blinking Light (synchronized)</h3> - <p>Line's X length is time for the light to be off, and Y length is the time for the light - to be on.</p> - <p>The control sector (the linedef's front sector) is used to get what will be the minimum - light level for this effect, while the target sector's light level ends up being the - maximum.</p> - <h3><a name="l606"></a>606 - Colormap</h3> - <p>Sets a colormap. Tag the linedef to the sector or sectors affected by the colormap. The - control linedef's front Above texture is used to determine the colormap. The format is - #rrggbba, where rr, gg, and bb are two hexadecimal digits for determining each color: red, - blue, and green. The a stands for alpha, and is a number or letter indicating the - translucency; from A-Z and 0-9, with A being most transparent and 9 being most opaque.</p> - <p>It does not generally matter what sector the colormap linedef belongs to. However, it - should not belong to the same sector as another colormap, as this can cause problems.</p> - </ol> - </li> - <h1><a name="sectortypes"></a>Sector Types</h1> - <p>You can apply up to four different types to one sector, provided that you only choose - ONE from EACH category. Add the numbers together to obtain the final value to use in level - editors.</p> - <li><u><big><big>Section 1</big></big></u><ol> - <h3><a name="s1"></a>1 - Damage (Generic)</h3> - <p>This special hurts, period. It doesn't matter whether you have a liquid shield, fire - shield, attraction shield, or whatever else; step on one of these and suffer.</p> - <h3><a name="s2"></a>2 - Damage (Water)</h3> - <p>Also known as Slime Hurt. Stepping here will be painful, as in shield/ring/life loss - (depending on how you are equipped), unless you happen to have the liquid shield.</p> - <h3><a name="s3"></a>3 - Damage (Fire)</h3> - <p>Stepping here will hurt, unless you happen to have a fire shield.</p> - <h3><a name="s4"></a>4 - Damage (Electrical)</h3> - <p>Hurts players whenever they're in the sector, unless they have the attraction shield.</p> - <p>Usage tip: Give the sector a floor flat that looks electrical and looks like it could - hurt you. </p> - <h3><a name="s5"></a>5 - Spikes</h3> - <p>Making spikes using sectors is rather tedious and difficult. You can use things instead - (<a href="#t523">Floor Spike</a> and <a href="#t522">Ceiling Spike</a>). But the sector - version DOES look cooler. ;)</p> - <h3><a name="s6"></a>6 - Death Pit (Camera Modifications)</h3> - <p>Used for bottomless pits. You'll probably want the sector's floor flat to be either - F_SKY1 (falling from the sky) or PIT (falling into a pit of complete blackness). The - camera modifications keep the camera from following you all the way down, for a Sonic - Adventure-style pit death. If you don't like the camera modifications, use sector type <a - href="#s7">5</a>.</p> - <h3><a name="s7"></a>7 - Death Pit (No Camera Modifications)</h3> - <p>For bottomless pits. Use if the camera modifications of sector type <a href="#s6">6</a> - are not to your taste.</p> - <h3><a name="s8"></a>8 - Instant Kill</h3> - <p>Die right away if you even step into this sector. No need to touch the floor as with - those sissy death pits.</p> - <h3><a name="s9"></a>9 - Ring Drainer (Floor Touch)</h3> - <p>Lose one ring per 15 tics while touching the floor.</p> - <h3><a name="s10"></a>10 - Ring Drainer (No Floor Touch)</h3> - <p>Like sector type <a href="#s9">9</a>, but doesn't require touching floor.</p> - <h3><a name="s11"></a>11 - Special Stage Damage</h3> - <p>If you have rings and no shield, and you step on it, you only lose 10 rings, maximum. - It's just like the special stages!</p> - <h3><a name="s12"></a>12 - Space Countdown</h3> - <p>In space, you have no chance to survive make your time, ha ha ha. Starts an immediate - five-second countdown, like when you drown.</p> - <h3><a name="s13"></a>13 - Ramp Sector</h3> - <p>Doubles the step-up height of the player. Default step-up height is 24 fracunits, but - with this, it becomes 48. Useful for steps and other things if your players seem to be - getting 'stopped' by the stairs while moving quickly.</p> - <h3><a name="s14"></a>14 - Non-Ramp Sector (Don't step down)</h3> - <p>Removes the 'step-down' that a player will normally do when moving to a nearby sector.</p> - <h3><a name="s15"></a>15 - Bouncy Sector (FOF Control Only)</h3> - <p>Use this on a 3D floor's control sector to make it bouncy. Players will bounce off the - top of it. If the 3D floor's control line has the BOUNCY flag set, the linedef length sets - the minimum bounce force. Otherwise, you will slowly come to a stop.</p> - <p> </p> - </ol> - </li> - <li><u><big><big><a name="sCat2"></a>Section 2</big></big></u><ol> - <h3><a name="s16"></a>16 - Trigger Linedef Executor (Pushable Objects)</h3> - <p>Works like <a href="#s80">80</a> but with a pushable object (gargoyle or snowman) - touching the floor rather than a player.</p> - <h3><a name="s32"></a>32 - Trigger Linedef Executor (Anywhere in Sector) (All Players)</h3> - <p>Sector type <a href="#s64">64</a> with the added requirement that all players who don't - have a game over need to be in the sector, not just one player. Currently does not work in - FOFs.</p> - <h3><a name="s48"></a>48 - Trigger Linedef Executor (Floor Touch) (All Players)</h3> - <p>Sector type <a href="#s80">80</a> with the added requirement that all players who don't - have a game over need to be in the sector, not just one player.</p> - <h3><a name="s64"></a>64 - Trigger Linedef Executor (Anywhere in Sector)</h3> - <p>Like sector type <a href="#s80">80</a>, but you don't have to be touching the floor to - do the triggering. You could be flying high in the air. You should also use this one for - linedef executors triggered by FOFs.</p> - <h3><a name="s80"></a>80 - Trigger Linedef Executor (Floor Touch)</h3> - <p>Required for any of the <a href="#ltriggers">Linedef Executor Triggers</a> to work in - the sector.</p> - <h3><a name="s96"></a>96 - Trigger Linedef Executor (Emerald Check)</h3> - <p>Sector type <a href="#s64">64</a> which will only execute if you have all 7 chaos - emeralds.</p> - <h3><a name="s112"></a>112 - Trigger Linedef Executor (NiGHTS Mare)</h3> - <p>Like sector type <a href="#s64">64</a>, but this is only triggered if you are in a - NiGHTS map, and checks what mare you're on using the following format, depending on what - flags you have set for this line:</p> - <p>No flags -> Runs if (current mare = line length)</p> - <p><a href="#NOCLIMB">NOCLIMB</a> -> Runs if (current mare <= line length)</p> - <p><a href="#BLOCKMONSTERS">BLOCKMONSTERS</a> -> Runs if (current mare >= line - length)</p> - <h3><a name="s128"></a>128 - Check for linedef executor on 3D Floors (ANY object)</h3> - <p>For any item to detect sector type <a href="#l16">16</a> on a 3D floor, the target - sector on the map must have this type. This allows you to have any kind of object trigger - a linedef executor.</p> - <h3><a name="s144"></a>144 - Egg Trap Capsule</h3> - <h3><a name="s160"></a>160 - Special Stage Time/Rings, Par</h3> - <p>For special stages, floor height is time limit in seconds, and ceiling height is rings - required in seconds. If the ceiling height is 0, there is no ring requirement, only a time - limit to find an exit.</p> - <h3><a name="s176"></a>176 - Custom Global Gravity</h3> - <p>Floor height sets global gravity. 500 is normal. 1000 is twice the normal gravity, 250 - is half. You can also set per-sector gravity with linetype <a href="#l1">1</a>. This can - also be adjusted in realtime, for some really cool effects.</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Section 3</big></big></u><ol> - <h3><a name="s256"></a>256 - Ice/Sludge</h3> - <p>See linedef type <a href="#l540">540</a>.</p> - <h3><a name="s512"></a>512 - Wind/Current</h3> - <p>See linedef types <a href="#l541">541</a> and <a href="#l544">544</a>.</p> - <h3><a name="s768"></a>768 - Ice/Sludge and Wind/Current</h3> - <p>Combination of sector specials 256 and 512.</p> - <h3><a name="s1024"></a>1024 - Conveyor Belt</h3> - <p>See linedef type <a href="#l520">520</a>.</p> - <h3><a name="s1280"></a>1280 - Speed Pad (No Spin)</h3> - <p>See linedef type <a href="#l4">4</a>.</p> - <h3><a name="s1536"></a>1536 - Speed Pad (Spin)</h3> - <p>See linedef type <a href="#l4">4</a>. This type of speed pad forces you into a spin.</p> - <h3><a name="s1792"></a>1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840 - Bustable - Block Sprite Parameter</h3> - <p>Used in a control sector of a bustable block. Chooses which debris sprite to spawn.</p> - <p>1792 = ROIA</p> - <p>2048 = ROIB</p> - <p>2304 = ROIC</p> - <p>2560 = ROID</p> - <p>2816 = ROIE</p> - <p>3072 = ROIF</p> - <p>3328 = ROIG</p> - <p>3584 = ROIH</p> - <p>3840 = ROII</p> - <p> </p> - </ol> - </li> - <li><u><big><big>Section 4</big></big></u><ol> - <h3><a name="s4096"></a>4096 - Starpost Activator</h3> - <p>Whenever a player steps in the sector, a starpost in that sector will be searched for - and, if found, activated.</p> - <h3><a name="s8192"></a>8192 - Special Stage Goal</h3> - <p>This is like the "GOAL" buttons in Sonic 1's special stages. Ends the special - stage when stepped on.</p> - <h3><a name="s8192a"></a>8192 - Exit Sector</h3> - <p>In single-player, cooperative, or race mode, being in this sector ends the level. You - don't necessarily have to be touching the floor. (If you want the player to have to be - touching the floor, you can use linedef type <a href="#l223">223</a>, an invisible, - intangible FOF, to do the trick. Give the FOF control sector a type of <a href="#s8192">8192</a>.)</p> - <p>See linedef type <a href="#l2">2</a> for a way to exit to any map, not just the one - whose number is specified in the map header. Linedef 2 also allows you to skip the score - tally screen.</p> - <h3><a name="s8192b"></a>8192 - No Tag Zone</h3> - <p>In games of tag, this sector is a safe spot. You cannot be tagged while in it.</p> - <h3><a name="s8192c"></a>8192 - CTF: Flag Return</h3> - <p>In CTF, if the red or blue flag enters this sector, it will automatically return to - base, much like how it behaves when it falls in a pit. This can also be set as a special - on a 3D floor.</p> - <h3><a name="s12288"></a>12288 - CTF: Red Team Base</h3> - <p>The red team has to bring the <a href="#t307">blue flag</a> onto this sector to score. - It's generally a good idea to have the <a href="#t306">red flag</a> here and the <a - href="#t34">red team player starts</a> somewhere close by.</p> - <h3><a name="s16384"></a>16384 - CTF: Blue Team Base</h3> - <p>The blue team has to bring the <a href="#t306">red flag</a> onto this sector to score. - It's generally a good idea to have the <a href="#t307">blue flag</a> here and the <a - href="#t35">blue team player starts</a> somewhere close by.</p> - <h3><a name="s20480"></a>20480 - Fan Sector</h3> - <p>Acts like a fan, pushing the player up at constant speed and activating the proper - animation. Can be used on intangible FOFs.</p> - <h3><a name="s24576"></a>24576 - Super Sonic Transform</h3> - <p>Transforms you into Super Sonic and gives you 50 rings, providing you have all of the - chaos emeralds.</p> - <h3><a name="s28672"></a>28672 - Spinner</h3> - <p>Forces the player into a spin.</p> - <h3><a name="s32768"></a>32768 - Zoom Tube Start</h3> - <p>When the player touches this sector, a line type <a href="#l3">3</a> with the same tag - as the sector is searched for, and if found, the line's X length determines the speed at - which the tube operates, while its Y length determines which zoom tube sequence to use. - Then the player is immediately put into a spin, loses control, and gravitates toward the - first Zoom Tube Waypoint (thing type <a href="#t753">753</a>), which does not have to be - in the same sector. Once they reach the first waypoint, they begin traveling to the 2nd, - 3rd, and so on, until the last waypoint is reached.</p> - <p>This can be used with Floor-Over-Floors, just use these specials in the control sector - instead. </p> - <h3><a name="s36864"></a>36864 - Zoom Tube End</h3> - <p>Just like sector type <a href="#s32768">32768</a>, but starts from the last waypoint - and goes to the first.</p> - <h3><a name="s40960"></a>40960 - Finish Line</h3> - <p>The finish line for a race circuit. This increments a lap when you pass it, after - hitting all the star posts in the stage in sequential order. Once the number of laps - specified by the server is reached, the level is completed.</p> - </ol> - </li> -</ul> -</body> -</html> diff --git a/doc/specs/udmf_srb2.txt b/doc/specs/udmf_srb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..c758d7e40f13d466afcfc689c679845fec71b906 --- /dev/null +++ b/doc/specs/udmf_srb2.txt @@ -0,0 +1,311 @@ +=============================================================================== +Universal Doom Map Format Sonic Robo Blast 2 extensions v1.0 19.02.2024 + + Copyright (c) 2024 Sonic Team Junior + uses Universal Doom Map Format Specification v1.1 as a template, + original document Copyright (c) 2009 James Haley. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + +=============================================================================== + +This document discusses the UDMF implementation found in Sonic Robo Blast 2's engine. + +======================================= +I. Grammar / Syntax +======================================= + + No changes. + +======================================= +II. Implementation Semantics +======================================= + +------------------------------------ +II.A : Storage and Retrieval of Data +------------------------------------ + + No changes. + +----------------------------------- +II.B : Storage Within Archive Files +----------------------------------- + + No changes. + +-------------------------------- +II.C : Implementation Dependence +-------------------------------- + +The SRB2 engine only supports the following namespace: + "srb2" + +The engine is allowed to refuse maps with an unsupported namespace, +or emit a warning. + +======================================= +III. Standardized Fields +======================================= + +The SRB2 engine ignores any user-defined fields. +All boolean fields default to false unless mentioned otherwise. + +Sonic Robo Blast 2 defines the following standardized fields: + + vertex + { + x = <float>; // X coordinate. No valid default. + y = <float>; // Y coordinate. No valid default. + zfloor = <float>; // Floor height at this vertex. Only applies to triangular sectors + zceiling = <float>; // Ceiling height at this vertex. Only applies to triangular sectors + } + + linedef + { + id = <integer>; // ID of line. Interpreted as tag. + moreids = <string>; // Additional line IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + + v1 = <integer>; // Index of first vertex. No valid default. + v2 = <integer>; // Index of second vertex. No valid default. + + blocking = <bool>; // Line blocks things. + blockmonsters = <bool>; // Line blocks enemies. + twosided = <bool>; // Line is 2S. + dontpegtop = <bool>; // Upper texture unpegged. + dontpegbottom = <bool>; // Lower texture unpegged. + skewtd = <bool>; // Upper and lower textures are skewed. + noclimb = <bool>; // Line is not climbable. + noskew = <bool>; // Middle texture is not skewed. + midpeg = <bool>; // Middle texture is pegged. + midsolid = <bool>; // Middle texture is solid. + wrapmidtex = <bool>; // Line's mid textures are wrapped. + nonet = <bool>; // Special only takes effect in singleplayer games. + netonly = <bool>; // Special only takes effect in multiplayer games. + bouncy = <bool>; // Line is bouncy. + transfer = <bool>; // In 3D floor sides, uses the sidedef properties of the control sector. + + alpha = <float>; // Translucency of this line. Default is 1.0 + renderstyle = <string>; // Render style. Can be: + // - "translucent" + // - "add" + // - "subtract" + // - "reversesubtract" + // - "modulate" + // - "fog" + // Default is "translucent". + + special = <integer>; // Linedef action. Default = 0. + arg0 = <integer>; // Argument 0. Default = 0. + arg1 = <integer>; // Argument 1. Default = 0. + arg2 = <integer>; // Argument 2. Default = 0. + arg3 = <integer>; // Argument 3. Default = 0. + arg4 = <integer>; // Argument 4. Default = 0. + arg5 = <integer>; // Argument 5. Default = 0. + arg6 = <integer>; // Argument 6. Default = 0. + arg7 = <integer>; // Argument 7. Default = 0. + arg8 = <integer>; // Argument 8. Default = 0. + arg9 = <integer>; // Argument 9. Default = 0. + stringarg0 = <string>; // String argument 0. + stringarg1 = <string>; // String argument 1. + + sidefront = <integer>; // Sidedef 1 index. No valid default. + sideback = <integer>; // Sidedef 2 index. Default = -1. + + comment = <string>; // A comment. Implementors should attach no special + // semantic meaning to this field. + } + + sidedef + { + offsetx = <integer>; // X offset. Default = 0. + offsety = <integer>; // Y offset. Default = 0. + + texturetop = <string>; // Upper texture. Default = "-". + texturebottom = <string>; // Lower texture. Default = "-". + texturemiddle = <string>; // Middle texture. Default = "-". + + repeatcnt = <string>; // Number of middle texture repetitions. Default = 0 + + sector = <integer>; // Sector index. No valid default. + + scalex_top = <float>; // X scale for upper texture. Default = 1.0. + scaley_top = <float>; // Y scale for upper texture. Default = 1.0. + scalex_mid = <float>; // X scale for mid texture. Default = 1.0. + scaley_mid = <float>; // Y scale for mid texture. Default = 1.0. + scalex_bottom = <float>; // X scale for lower texture. Default = 1.0. + scaley_bottom = <float>; // Y scale for lower texture. Default = 1.0. + offsetx_top = <float>; // X offset for upper texture. Default = 0.0. + offsety_top = <float>; // Y offset for upper texture. Default = 0.0. + offsetx_mid = <float>; // X offset for mid texture. Default = 0.0. + offsety_mid = <float>; // Y offset for mid texture. Default = 0.0. + offsetx_bottom = <float>; // X offset for lower texture. Default = 0.0. + offsety_bottom = <float>; // Y offset for lower texture. Default = 0.0. + + comment = <string>; // A comment. Implementors should attach no special + // semantic meaning to this field. + } + + sector + { + heightfloor = <integer>; // Floor height. Default = 0. + heightceiling = <integer>; // Ceiling height. Default = 0. + + texturefloor = <string>; // Floor flat. No valid default. + textureceiling = <string>; // Ceiling flat. No valid default. + + lightlevel = <integer>; // Light level. Default = 255. + lightfloor = <integer>; // The floor's light level. Default is 0. + lightceiling = <integer>; // The ceiling's light level. Default is 0. + lightfloorabsolute = <bool>; // true = 'lightfloor' is an absolute value. Default is + // relative to the owning sector's light level. + lightceilingabsolute = <bool>; // true = 'lightceiling' is an absolute value. Default is + // relative to the owning sector's light level. + + special = <integer>; // Sector special. Default = 0. + id = <integer>; // Sector tag/id. Default = 0. + moreids = <string>; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + + xpanningfloor = <float>; // X texture offset of floor texture. Default = 0.0. + ypanningfloor = <float>; // Y texture offset of floor texture. Default = 0.0. + xpanningceiling = <float>; // X texture offset of ceiling texture. Default = 0.0. + ypanningceiling = <float>; // Y texture offset of ceiling texture. Default = 0.0. + xscalefloor = <float>; // X texture scale of floor texture. Default = 1.0. + yscalefloor = <float>; // Y texture scale of floor texture. Default = 1.0. + xscaleceiling = <float>; // X texture scale of ceiling texture. Default = 1.0. + yscaleceiling = <float>; // Y texture scale of ceiling texture. Default = 1.0. + rotationfloor = <float>; // Rotation of floor texture in degrees. Default = 0.0. + rotationceiling = <float>; // Rotation of ceiling texture in degrees. Default = 0.0. + ceilingplane_a = <float>; // Define the plane equation for the sector's ceiling. Default is a horizontal plane at 'heightceiling'. + ceilingplane_b = <float>; // 'heightceiling' will still be used to calculate texture alignment. + ceilingplane_c = <float>; // The plane equation will only be used if all 4 values are given. + ceilingplane_d = <float>; // The plane is defined as a*x + b*y + c*z + d = 0 with the normal vector pointing downward. + floorplane_a = <float>; // Define the plane equation for the sector's floor. Default is a horizontal plane at 'heightfloor'. + floorplane_b = <float>; // 'heightfloor' will still be used to calculate texture alignment. + floorplane_c = <float>; // The plane equation will only be used if all 4 values are given. + floorplane_d = <float>; // The plane is defined as a*x + b*y + c*z + d = 0 with the normal vector pointing upward. + + lightcolor = <integer>; // Sector's light color as RRGGBB value. Default = 0x000000. + lightalpha = <integer>; // Sector's light opacity. Default = 25. + fadecolor = <integer>; // Sector's fog color as RRGGBB value. Default = 0x000000. + fadealpha = <integer>; // Sector's fog opacity. Default = 25. + fadestart = <integer>; // Sector's fading range start. Default = 0. + fadeend = <integer>; // Sector's fading range end. Default = 31. + colormapfog = <bool>; // Sector's colormap uses fog lighting. + colormapfadesprites = <bool>; // Sector's colormap affects full-bright sprites. + colormapprotected = <bool>; // Sector's colormap is not affected by colormap change specials. + + flipspecial_nofloor = <bool>; // Trigger effects that require a plane touch are not executed when the floor is touched. + flipspecial_ceiling = <bool>; // Trigger effects that require a plane touch are executed when the ceiling is touched. + triggerspecial_touch = <bool>; // Trigger effects are executed anywhere in the sector. + triggerspecial_headbump = <bool>; // Trigger effects are executed if the top of the triggerer object touches a plane. + triggerline_plane = <bool>; // Trigger effects require a plane touch to be executed. + triggerline_mobj = <bool>; // Trigger effects can be executed by non-pushable objects. + + invertprecip = <bool>; // Inverts the precipitation effect; if the sector is considered to be indoors, + // precipitation is generated, and if the sector is considered to be outdoors, + // precipitation is not generated. + gravityflip = <bool>; // Sector flips any objects in it, if the sector has negative gravity. + heatwave = <bool>; // Sector has the heat wave effect. + noclipcamera = <bool>; // Sector is not tangible to the camera. + outerspace = <bool>; // Sector has the space countdown effect. + doublestepup = <bool>; // Sector has half the vertical height needed for objects to walk into it. + nostepdown = <bool>; // Sector has the staircase effect disabled. + speedpad = <bool>; // Sector is a speed pad. + starpostactivator = <bool>; // Sector activates any Star Posts in it when walked into by a plyer. + exit = <bool>; // Sector is an exit sector. + specialstagepit = <bool>; // Sector is a Special Stage pit. + returnflag = <bool>; // Sector returns any Capture the Flag flags that come in contact with it to their respective bases. + redteambase = <bool>; // Sector is a Red Team base. + blueteambase = <bool>; // Sector is Blue Team base. + fan = <bool>; // Sector is a fan sector. + supertransform = <bool>; // Sector transforms any players that come in contact with it into their 'super' mode. + forcespin = <bool>; // Sector forces any players that come in contact with it to roll. + zoomtubestart = <bool>; // Sector is the starting point of a zoom tube path. + zoomtubeend = <bool>; // Sector is the ending point of a zoom tube path. + finishline = <bool>; // Sector is a Circuit finish line. + ropehang = <bool>; // Sector is a rope hang. Must be applied to a 3D floor. + jumpflip = <bool>; // Sector flips the gravity of players who jump from it. + gravityoverride = <bool>; // Reverse gravity effect is only applied when an object is in the sector. + + friction = <float>; // Sector's friction factor. + gravity = <float>; // Sector's gravity. Default is 1.0. + damagetype = <integer>; // Damage type for sector damage. Can be: + // - "None" + // - "Generic" + // - "Water" + // - "Fire" + // - "Lava" + // - "Electric" + // - "Spike" + // - "DeathPitTilt" + // - "DeathPitNoTilt" + // - "Instakill" + // - "SpecialStage" + // Default = "None". + triggertag = <integer>; // Tag to trigger when this sector is entered. Default = 0. + triggerer = <string>; // Who can execute the trigger tag when this sector is entered. Can be: + // - "Player" + // - "AllPlayers" + // - "Mobj" + // Default = "Player". + + comment = <string>; // A comment. Implementors should attach no special + // semantic meaning to this field. + } + + thing + { + id = <integer>; // Thing ID. Default = 0. + moreids = <string>; // Additional thing IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + + x = <float>; // X coordinate. No valid default. + y = <float>; // Y coordinate. No valid default. + + height = <float>; // Z height relative to floor. + // Relative to ceiling if flip = true. + // Absolute if absolutez = true. + // Default = 0. + + angle = <integer>; // Map angle of thing in degrees. Default = 0 (East). + pitch = <integer>; // Pitch of thing in degrees. Default = 0 (horizontal). + roll = <integer>; // Roll of thing in degrees. Default = 0. + scalex = <float>; // Horizontal visual scaling on thing. Default = 1.0. + scaley = <float>; // Vertical visual scaling on thing. Default = 1.0. + scale = <float>; // Vertical and horizontal visual scaling on thing. Default = 1.0. + mobjscale = <float>; // Physical scale of the thing. Default = 1.0. + + type = <integer>; // Thing type. No valid default. + + flip = <bool>; // Thing spawns flipped, on the ceiling. + absolutez = <bool>; // If true, the thing height is absolute, instead of being relative to the floor or ceiling. + + arg0 = <integer>; // Argument 0. Default = 0. + arg1 = <integer>; // Argument 1. Default = 0. + arg2 = <integer>; // Argument 2. Default = 0. + arg3 = <integer>; // Argument 3. Default = 0. + arg4 = <integer>; // Argument 4. Default = 0. + arg5 = <integer>; // Argument 5. Default = 0. + arg6 = <integer>; // Argument 6. Default = 0. + arg7 = <integer>; // Argument 7. Default = 0. + arg8 = <integer>; // Argument 8. Default = 0. + arg9 = <integer>; // Argument 9. Default = 0. + stringarg0 = <string>; // String argument 0. + stringarg1 = <string>; // String argument 1. + + comment = <string>; // A comment. Implementors should attach no special + // semantic meaning to this field. + } + + +======================================= +Changelog +======================================= + +1.0: 19.02.2024 +Initial version. + +=============================================================================== +EOF +=============================================================================== \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a7527461597db16e43f7a3ea83bb5f34497268c6..160174080c44996c49d8fafa91e2ff6a297acee5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -154,6 +154,10 @@ if (UNIX) target_compile_definitions(SRB2SDL2 PRIVATE -DUNIXCOMMON) endif() +if (BSD MATCHES "FreeBSD") + target_compile_definitions(SRB2SDL2 PRIVATE -DFREEBSD) +endif() + if(CMAKE_COMPILER_IS_GNUCC) find_program(OBJCOPY objcopy) endif() diff --git a/src/android/i_video.c b/src/android/i_video.c index bf0decb74118385ff2b776d8d470e5ea3a03a2ba..896a5b899c008197df570376d2e0c406a1a8351e 100644 --- a/src/android/i_video.c +++ b/src/android/i_video.c @@ -11,8 +11,6 @@ rendermode_t rendermode = render_soft; rendermode_t chosenrendermode = render_none; -boolean highcolor = false; - boolean allow_fullscreen = false; diff --git a/src/console.c b/src/console.c index 4143e5e066b78e320a22e60b3f0ecb9712f848e3..5ef0ce919be356655ac52ab9d7e7e9a9e63c3783 100644 --- a/src/console.c +++ b/src/console.c @@ -70,14 +70,9 @@ static boolean consoleready; // console prompt is ready INT32 con_destlines; // vid lines used by console at final position static INT32 con_curlines; // vid lines currently used by console - INT32 con_clipviewtop; // (useless) - static UINT8 con_hudlines; // number of console heads up message lines static UINT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines - INT32 con_clearlines; // top screen lines to refresh when view reduced - boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh - // console text output static char *con_line; // console text output current line static size_t con_cx; // cursor position in current line @@ -120,7 +115,7 @@ static void CONS_backcolor_Change(void); #ifdef macintosh #define CON_BUFFERSIZE 4096 // my compiler can't handle local vars >32k #else -#define CON_BUFFERSIZE 16384 +#define CON_BUFFERSIZE 32768 #endif static char con_buffer[CON_BUFFERSIZE]; @@ -473,9 +468,6 @@ void CON_Init(void) Lock_state(); - //note: CON_Ticker should always execute at least once before D_Display() - con_clipviewtop = -1; // -1 does not clip - con_hudlines = atoi(cons_hudlines.defaultvalue); Unlock_state(); @@ -751,7 +743,6 @@ void CON_ToggleOff(void) con_curlines = 0; CON_ClearHUD(); con_forcepic = 0; - con_clipviewtop = -1; // remove console clipping of view I_UpdateMouseGrab(); @@ -800,18 +791,6 @@ void CON_Ticker(void) CON_ChangeHeight(); } - // clip the view, so that the part under the console is not drawn - con_clipviewtop = -1; - if (cons_backpic.value) // clip only when using an opaque background - { - if (con_curlines > 0) - con_clipviewtop = con_curlines - viewwindowy - 1 - 10; - // NOTE: BIG HACK::SUBTRACT 10, SO THAT WATER DON'T COPY LINES OF THE CONSOLE - // WINDOW!!! (draw some more lines behind the bottom of the console) - if (con_clipviewtop < 0) - con_clipviewtop = -1; // maybe not necessary, provided it's < 0 - } - // check if console ready for prompt if (con_destlines >= minheight) consoleready = true; @@ -1358,9 +1337,6 @@ static void CON_Linefeed(void) con_line = &con_buffer[(con_cy%con_totallines)*con_width]; memset(con_line, ' ', con_width); - - // make sure the view borders are refreshed if hud messages scroll - con_hudupdate = true; // see HU_Erase() } // Outputs text into the console text buffer @@ -1749,9 +1725,6 @@ static void CON_DrawHudlines(void) //V_DrawCharacter(x, y, (p[c]&0xff) | cv_constextsize.value | V_NOSCALESTART, true); y += charheight; } - - // top screen lines that might need clearing when view is reduced - con_clearlines = y; // this is handled by HU_Erase(); } // Lactozilla: Draws the console's background picture. @@ -1817,10 +1790,6 @@ static void CON_DrawConsole(void) if (con_curlines <= 0) return; - //FIXME: refresh borders only when console bg is translucent - con_clearlines = con_curlines; // clear console draw from view borders - con_hudupdate = true; // always refresh while console is on - // draw console background if (cons_backpic.value || con_forcepic) CON_DrawBackpic(); diff --git a/src/console.h b/src/console.h index f22f8dcbc18e595b6fb57b942bca8c0eb3cf15e2..6ad1dba1e458c19d47bb2599f9d3a87ce0fb17c1 100644 --- a/src/console.h +++ b/src/console.h @@ -34,14 +34,9 @@ extern boolean con_startup; // needs explicit screen refresh until we are in the main game loop extern boolean con_refresh; -// top clip value for view render: do not draw part of view hidden by console -extern INT32 con_clipviewtop; - // 0 means console if off, or moving out extern INT32 con_destlines; -extern INT32 con_clearlines; // lines of top of screen to refresh -extern boolean con_hudupdate; // hud messages have changed, need refresh extern UINT32 con_scalefactor; // console text scale factor extern consvar_t cons_backcolor; diff --git a/src/d_main.c b/src/d_main.c index 83cb425c98bd76b8b931c91db2e1699682c20a0e..3886ad1ad157a8957eec081c7a38a7f901d19714 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -408,13 +408,11 @@ static void D_Display(void) case GS_LEVEL: if (!gametic) break; - HU_Erase(); AM_Drawer(); break; case GS_INTERMISSION: Y_IntermissionDrawer(); - HU_Erase(); HU_Drawer(); break; @@ -429,13 +427,11 @@ static void D_Display(void) case GS_ENDING: F_EndingDrawer(); - HU_Erase(); HU_Drawer(); break; case GS_CUTSCENE: F_CutsceneDrawer(); - HU_Erase(); HU_Drawer(); break; @@ -445,7 +441,6 @@ static void D_Display(void) case GS_EVALUATION: F_GameEvaluationDrawer(); - HU_Erase(); HU_Drawer(); break; @@ -455,7 +450,6 @@ static void D_Display(void) case GS_CREDITS: F_CreditDrawer(); - HU_Erase(); HU_Drawer(); break; @@ -465,7 +459,6 @@ static void D_Display(void) { // I don't think HOM from nothing drawing is independent... F_WaitingPlayersDrawer(); - HU_Erase(); HU_Drawer(); } case GS_DEDICATEDSERVER: @@ -480,8 +473,6 @@ static void D_Display(void) { wipegamestate = gamestate; - // clean up border stuff - // see if the border needs to be initially drawn if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap))) { // draw the view directly @@ -506,23 +497,21 @@ static void D_Display(void) // render the second screen if (splitscreen && players[secondarydisplayplayer].mo) { - #ifdef HWRENDER - if (rendermode != render_soft) + viewwindowy = vid.height / 2; + +#ifdef HWRENDER + if (rendermode == render_opengl) HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); else - #endif +#endif if (rendermode != render_none) { - viewwindowy = vid.height / 2; - M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); - topleft = screens[0] + viewwindowy*vid.width + viewwindowx; R_RenderPlayerView(&players[secondarydisplayplayer]); - - viewwindowy = 0; - M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); } + + viewwindowy = 0; } // Image postprocessing effect @@ -1512,9 +1501,7 @@ void D_SRB2Main(void) G_LoadGameData(clientGamedata); M_CopyGameData(serverGamedata, clientGamedata); -#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen -#endif // set user default mode or mode set at cmdline SCR_CheckDefaultMode(); diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c index 4dbaec8df9f73a5c7d04727942b7f224f4716139..13d5d1700b7e48f3d972bf242d7a289071bf2446 100644 --- a/src/dedicated/i_system.c +++ b/src/dedicated/i_system.c @@ -96,6 +96,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #endif #if defined (__unix__) || (defined (UNIXCOMMON) && !defined (__APPLE__)) +#include <poll.h> #include <errno.h> #include <sys/wait.h> #define NEWSIGNALHANDLER @@ -855,50 +856,60 @@ static void I_GetConsoleEvents(void) // we use this when sending back commands event_t ev = {0}; char key = 0; - ssize_t d; + struct pollfd pfd = + { + .fd = STDIN_FILENO, + .events = POLLIN, + .revents = 0, + }; if (!consolevent) return; - ev.type = ev_console; - ev.key = 0; - if (read(STDIN_FILENO, &key, 1) == -1 || !key) - return; - - // we have something - // backspace? - // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere - if ((key == tty_erase) || (key == 127) || (key == 8)) + for (;;) { - if (tty_con.cursor > 0) + if (poll(&pfd, 1, 0) < 1 || !(pfd.revents & POLLIN)) + return; + + ev.type = ev_console; + ev.key = 0; + if (read(STDIN_FILENO, &key, 1) == -1 || !key) + return; + + // we have something + // backspace? + // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere + if ((key == tty_erase) || (key == 127) || (key == 8)) { - tty_con.cursor--; - tty_con.buffer[tty_con.cursor] = '\0'; - tty_Back(); + if (tty_con.cursor > 0) + { + tty_con.cursor--; + tty_con.buffer[tty_con.cursor] = '\0'; + tty_Back(); + } + ev.key = KEY_BACKSPACE; } - ev.key = KEY_BACKSPACE; - } - else if (key < ' ') // check if this is a control char - { - if (key == '\n') + else if (key < ' ') // check if this is a control char + { + if (key == '\n') + { + tty_Clear(); + tty_con.cursor = 0; + ev.key = KEY_ENTER; + } + else continue; + } + else if (tty_con.cursor < sizeof(tty_con.buffer)) { - tty_Clear(); - tty_con.cursor = 0; - ev.key = KEY_ENTER; + // push regular character + ev.key = tty_con.buffer[tty_con.cursor] = key; + tty_con.cursor++; + // print the current line (this is differential) + write(STDOUT_FILENO, &key, 1); } - else return; + if (ev.key) D_PostEvent(&ev); + //tty_FlushIn(); } - else if (tty_con.cursor < sizeof(tty_con.buffer)) - { - // push regular character - ev.key = tty_con.buffer[tty_con.cursor] = key; - tty_con.cursor++; - // print the current line (this is differential) - d = write(STDOUT_FILENO, &key, 1); - } - if (ev.key) D_PostEvent(&ev); - //tty_FlushIn(); - (void)d; } #elif defined (_WIN32) diff --git a/src/dedicated/i_video.c b/src/dedicated/i_video.c index bb796b6767a1d55990209ba46cd8245377b013d9..2c998117accb71be25850438bdac2ee6c4db0509 100644 --- a/src/dedicated/i_video.c +++ b/src/dedicated/i_video.c @@ -5,8 +5,6 @@ rendermode_t rendermode = render_none; rendermode_t chosenrendermode = render_none; -boolean highcolor = false; - boolean allow_fullscreen = false; consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL); diff --git a/src/doomdef.h b/src/doomdef.h index 4c843f9e2f07ad58439d2dcd3200726e6d62fa4d..60e7dc2031ba6b6d5b100410d5cc8c410de8c241 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -244,12 +244,12 @@ extern char logfilename[1024]; #define MAXPLAYERNAME 21 #define PLAYERSMASK (MAXPLAYERS-1) -// Don't make MAXSKINS higher than 256, since skin numbers are used with an -// UINT8 in various parts of the codebase. If you do anyway, the data type -// of those variables will have to be changed into at least an UINT16. +// Don't make MAXSKINS higher than 255, since skin numbers are used with an UINT8 in +// various parts of the codebase, and one number is reserved. If you do anyway, +// the data type of those variables will have to be changed into at least an UINT16. // This change must affect code such as demo recording and playback, // and the structure of some networking packets and commands. -#define MAXSKINS 256 +#define MAXSKINS 255 #define MAXCHARACTERSLOTS (MAXSKINS * 3) // Should be higher than MAXSKINS. #define COLORRAMPSIZE 16 @@ -552,7 +552,7 @@ void *M_Memcpy(void* dest, const void* src, size_t n); char *va(const char *format, ...) FUNCPRINTF; char *M_GetToken(const char *inputString); void M_UnGetToken(void); -void M_TokenizerOpen(const char *inputString); +void M_TokenizerOpen(const char *inputString, size_t len); void M_TokenizerClose(void); const char *M_TokenizerRead(UINT32 i); const char *M_TokenizerReadZDoom(UINT32 i); @@ -709,13 +709,6 @@ extern int /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. //#define PAPER_COLLISIONCORRECTION -/// FINALLY some real clipping that doesn't make walls dissappear AND speeds the game up -/// (that was the original comment from SRB2CB, sadly it is a lie and actually slows game down) -/// on the bright side it fixes some weird issues with translucent walls -/// \note SRB2CB port. -/// SRB2CB itself ported this from PrBoom+ -#define NEWCLIP - /// OpenGL shaders #define GL_SHADERS diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c index bb796b6767a1d55990209ba46cd8245377b013d9..2c998117accb71be25850438bdac2ee6c4db0509 100644 --- a/src/dummy/i_video.c +++ b/src/dummy/i_video.c @@ -5,8 +5,6 @@ rendermode_t rendermode = render_none; rendermode_t chosenrendermode = render_none; -boolean highcolor = false; - boolean allow_fullscreen = false; consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL); diff --git a/src/f_finale.c b/src/f_finale.c index cb64618535659f329bb357f65c2cec0bbe006b2d..0b618a1e3f53acd74a01b82116bd60eb698fec14 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -297,7 +297,7 @@ static void F_NewCutscene(const char *basetext) cutscene_basetext = basetext; memset(cutscene_disptext,0,sizeof(cutscene_disptext)); cutscene_writeptr = cutscene_baseptr = 0; - cutscene_textspeed = 9; + cutscene_textspeed = 8; cutscene_textcount = TICRATE/2; } @@ -313,22 +313,22 @@ const char *introtext[NUMINTROSCENES]; static tic_t introscenetime[NUMINTROSCENES] = { 5*TICRATE, // STJr Presents - 11*TICRATE + (TICRATE/2), // Two months had passed since... - 15*TICRATE + (TICRATE/2), // As it was about to drain the rings... - 14*TICRATE, // What Sonic, Tails, and Knuckles... - 18*TICRATE, // About once every year, a strange... - 19*TICRATE + (TICRATE/2), // Curses! Eggman yelled. That ridiculous... - 19*TICRATE + (TICRATE/4), // It was only later that he had an idea... - 10*TICRATE + (TICRATE/2), // Before beginning his scheme, Eggman decided to give Sonic... - 16*TICRATE, // We're ready to fire in 15 seconds, the robot said... - 16*TICRATE, // Meanwhile, Sonic was tearing across the zones... + 10*TICRATE + (TICRATE/2), // Two months had passed since... + 12*TICRATE + ((TICRATE/4) * 3), // As it was about to drain the rings... + 12*TICRATE + (TICRATE/4), // What Sonic, Tails, and Knuckles... + 16*TICRATE, // About once every year, a strange... + 20*TICRATE + (TICRATE/2), // Curses! Eggman yelled. That ridiculous... + 18*TICRATE + (TICRATE/4), // It was only later that he had an idea... + 9*TICRATE + (TICRATE/2), // Before beginning his scheme, Eggman decided to give Sonic... + 14*TICRATE, // We're ready to fire in 15 seconds, the robot said... + 14*TICRATE + (TICRATE/2), // Meanwhile, Sonic was tearing across the zones... 16*TICRATE + (TICRATE/2), // Sonic knew he was getting closer to the city... - 17*TICRATE, // Greenflower City was gone... - 7*TICRATE, // You're not quite as dead as we thought, huh?... + 11*TICRATE + (TICRATE/2), // Greenflower City was gone... + 8*TICRATE, // You're not quite as dead as we thought, huh?... 8*TICRATE, // We'll see... let's give you a quick warm up... 18*TICRATE + (TICRATE/2), // Eggman took this as his cue and blasted off... - 16*TICRATE, // Easy! We go find Eggman and stop his... - 25*TICRATE, // I'm just finding what mission obje... + 15*TICRATE, // Easy! We go find Eggman and stop his... + 23*TICRATE, // I'm just finding what mission obje... }; // custom intros @@ -1281,6 +1281,9 @@ void F_CreditDrawer(void) UINT8 colornum; const UINT8 *colormap; + // compensation for y on non-green resolutions, used to prevent text from disappearing before reaching the top + UINT16 compy = (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2; + if (players[consoleplayer].skincolor) colornum = players[consoleplayer].skincolor; else @@ -1312,17 +1315,17 @@ void F_CreditDrawer(void) y += 80<<FRACBITS; break; case 1: - if (y>>FRACBITS > -20) + if (y>>FRACBITS > -20-compy) V_DrawCreditString((160 - (V_CreditStringWidth(&credits[i][1])>>1))<<FRACBITS, y, 0, &credits[i][1]); y += 30<<FRACBITS; break; case 2: - if (y>>FRACBITS > -10) + if (y>>FRACBITS > -10-compy) V_DrawStringAtFixed((BASEVIDWIDTH-V_StringWidth(&credits[i][1], V_ALLOWLOWERCASE|V_YELLOWMAP))<<FRACBITS>>1, y, V_ALLOWLOWERCASE|V_YELLOWMAP, &credits[i][1]); y += 12<<FRACBITS; break; default: - if (y>>FRACBITS > -10) + if (y>>FRACBITS > -10-compy) V_DrawStringAtFixed(32<<FRACBITS, y, V_ALLOWLOWERCASE, credits[i]); y += 12<<FRACBITS; break; diff --git a/src/f_wipe.c b/src/f_wipe.c index 4bcfb029b2ed1815e895ff126127bb628c6709fb..1ea32d0ebe92e6fdcfda930356cb36959c7acb91 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -569,7 +569,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) if (rendermode == render_opengl) { // send in the wipe type and wipe frame because we need to cache the graphic - HWR_DoTintedWipe(wipetype, wipeframe-1); + HWR_DoWipe(wipetype, wipeframe-1); } else #endif diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index e7819aba97e2065d36f6f920d4725d7b294505f3..3b6135c1d768a732944d2a18b4e0d41f7fb8c461 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -10,5 +10,6 @@ target_sources(SRB2SDL2 PRIVATE hw_md3load.c hw_model.c hw_batching.c + hw_shaders.c r_opengl/r_opengl.c ) diff --git a/src/hardware/Sourcefile b/src/hardware/Sourcefile index 6c374621d7b1de61f2b5a5c6fd9171f0685eccbf..4fa61470f26616ccb0dd311b4d08045054f23921 100644 --- a/src/hardware/Sourcefile +++ b/src/hardware/Sourcefile @@ -9,4 +9,5 @@ hw_md2load.c hw_md3load.c hw_model.c hw_batching.c +hw_shaders.c r_opengl/r_opengl.c diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index a640a9917ad169cbeb8a141e6741614081d251df..b9ab2592d3f00a4fcdb4c1af31e2eaae484cd584 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -76,7 +76,7 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture) // If batching is enabled, this function collects the polygon data and the chosen texture // for later use in HWR_RenderBatches. Otherwise the rendering backend is used to // render the polygon immediately. -void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial) +void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial) { if (currently_batching) { @@ -114,7 +114,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt polygonArray[polygonArraySize].numVerts = iNumPts; polygonArray[polygonArraySize].polyFlags = PolyFlags; polygonArray[polygonArraySize].texture = current_texture; - polygonArray[polygonArraySize].shader = shader; + polygonArray[polygonArraySize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; // default to polygonArraySize so we don't lose order on horizon lines // (yes, it's supposed to be negative, since we're sorting in that direction) @@ -134,7 +134,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt DIGEST(hash, pSurf->PolyColor.rgba); if (cv_glshaders.value && gl_shadersavailable) { - DIGEST(hash, shader); + DIGEST(hash, shader_target); DIGEST(hash, pSurf->TintColor.rgba); DIGEST(hash, pSurf->FadeColor.rgba); DIGEST(hash, pSurf->LightInfo.light_level); @@ -151,10 +151,9 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt } else { - if (shader) - HWD.pfnSetShader(shader); - HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags); - } + HWD.pfnSetShader((shader_target != SHADER_NONE) ? HWR_GetShaderFromTarget(shader_target) : shader_target); + HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags); + } } static int comparePolygons(const void *p1, const void *p2) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 58e16d62361a9ca3f87479ea273343c7c36065bc..64f74b1f4e9bae98553b881df46309148344a00a 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -32,6 +32,14 @@ INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole +RGBA_t mapPalette[256] = {0}; // the palette for the currently loaded level or menu etc. + +// Returns a pointer to the palette which should be used for caching textures. +RGBA_t *HWR_GetTexturePalette(void) +{ + return HWR_ShouldUsePaletteRendering() ? mapPalette : pLocalPalette; +} + static INT32 format2bpp(GLTextureFormat_t format) { if (format == GL_TEXFMT_RGBA) @@ -49,7 +57,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm INT32 pblockheight, INT32 blockmodulo, fixed_t yfracstep, fixed_t scale_y, texpatch_t *originPatch, INT32 patchheight, - INT32 bpp) + INT32 bpp, RGBA_t *palette) { fixed_t yfrac, position, count; UINT8 *dest; @@ -113,7 +121,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm memcpy(dest, &texelu16, sizeof(UINT16)); break; case 3: - colortemp = V_GetColor(texel); + colortemp = palette[texel]; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { RGBA_t rgbatexel; @@ -123,7 +131,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; case 4: - colortemp = V_GetColor(texel); + colortemp = palette[texel]; colortemp.s.alpha = alpha; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { @@ -152,7 +160,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, INT32 pblockheight, INT32 blockmodulo, fixed_t yfracstep, fixed_t scale_y, texpatch_t *originPatch, INT32 patchheight, - INT32 bpp) + INT32 bpp, RGBA_t *palette) { fixed_t yfrac, position, count; UINT8 *dest; @@ -217,7 +225,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, memcpy(dest, &texelu16, sizeof(UINT16)); break; case 3: - colortemp = V_GetColor(texel); + colortemp = palette[texel]; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { RGBA_t rgbatexel; @@ -227,7 +235,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; case 4: - colortemp = V_GetColor(texel); + colortemp = palette[texel]; colortemp.s.alpha = alpha; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { @@ -269,10 +277,13 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, UINT8 *block = mipmap->data; INT32 bpp; INT32 blockmodulo; + RGBA_t *palette; if (pwidth <= 0 || pheight <= 0) return; + palette = HWR_GetTexturePalette(); + ncols = pwidth; // source advance @@ -298,7 +309,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, pblockheight, blockmodulo, yfracstep, scale_y, NULL, pheight, // not that pheight is going to get used anyway... - bpp); + bpp, palette); } } @@ -317,16 +328,19 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, INT32 bpp; INT32 blockmodulo; INT32 width, height; + RGBA_t *palette; // Column drawing function pointer. static void (*ColumnDrawerPointer)(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap, INT32 pblockheight, INT32 blockmodulo, fixed_t yfracstep, fixed_t scale_y, texpatch_t *originPatch, INT32 patchheight, - INT32 bpp); + INT32 bpp, RGBA_t *palette); if (texture->width <= 0 || texture->height <= 0) return; + palette = HWR_GetTexturePalette(); + ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache; x1 = patch->originx; @@ -386,7 +400,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, pblockheight, blockmodulo, yfracstep, scale_y, patch, height, - bpp); + bpp, palette); } } @@ -429,6 +443,9 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) INT32 i; boolean skyspecial = false; //poor hack for Legacy large skies.. + RGBA_t *palette; + palette = HWR_GetTexturePalette(); + texture = textures[texnum]; // hack the Legacy skies.. @@ -447,7 +464,10 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) grtex->mipmap.width = (UINT16)texture->width; grtex->mipmap.height = (UINT16)texture->height; - grtex->mipmap.format = textureformat; + if (skyspecial) + grtex->mipmap.format = GL_TEXFMT_RGBA; // that skyspecial code below assumes this format ... + else + grtex->mipmap.format = textureformat; blockwidth = texture->width; blockheight = texture->height; @@ -459,7 +479,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) INT32 j; RGBA_t col; - col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX); + col = palette[HWR_PATCHES_CHROMAKEY_COLORINDEX]; for (j = 0; j < blockheight; j++) { for (i = 0; i < blockwidth; i++) @@ -739,19 +759,6 @@ void HWR_LoadMapTextures(size_t pnumtextures) gl_maptexturesloaded = true; } -void HWR_SetPalette(RGBA_t *palette) -{ - HWD.pfnSetPalette(palette); - - // hardware driver will flush there own cache if cache is non paletized - // now flush data texture cache so 32 bit texture are recomputed - if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA) - { - Z_FreeTag(PU_HWRCACHE); - Z_FreeTag(PU_HWRCACHE_UNLOCKED); - } -} - // -------------------------------------------------------------------------- // Make sure texture is downloaded and set it as the source // -------------------------------------------------------------------------- @@ -823,18 +830,13 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum) void HWR_GetLevelFlat(levelflat_t *levelflat) { - if (levelflat->type == LEVELFLAT_NONE) + if (levelflat->type == LEVELFLAT_NONE || levelflat->texture_id < 0) { HWR_SetCurrentTexture(NULL); return; } INT32 texturenum = texturetranslation[levelflat->texture_id]; - if (texturenum <= 0) - { - HWR_SetCurrentTexture(NULL); - return; - } GLMapTexture_t *grtex = &gl_flats[texturenum]; GLMipmap_t *grMipmap = &grtex->mipmap; @@ -997,6 +999,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 UINT8 *flat; UINT8 *dest, *src, texel; RGBA_t col; + RGBA_t *palette = HWR_GetTexturePalette(); // Place the flats data into flat W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum), @@ -1014,7 +1017,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 { // fademask bpp is always 1, and is used just for alpha texel = src[(posx)>>FRACBITS]; - col = V_GetColor(texel); + col = palette[texel]; *dest = col.s.red; // take the red level of the colour and use it for alpha, as fademasks do dest++; @@ -1086,4 +1089,185 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum) Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED); } +// ================================================= +// PALETTE HANDLING +// ================================================= + +void HWR_SetPalette(RGBA_t *palette) +{ + if (HWR_ShouldUsePaletteRendering()) + { + // set the palette for palette postprocessing + + if (cv_glpalettedepth.value == 16) + { + // crush to 16-bit rgb565, like software currently does in the standard configuration + // Note: Software's screenshots have the 24-bit palette, but the screen gets + // the 16-bit version! For making comparison screenshots either use an external screenshot + // tool or set the palette depth to 24 bits. + RGBA_t crushed_palette[256]; + int i; + for (i = 0; i < 256; i++) + { + float fred = (float)(palette[i].s.red >> 3); + float fgreen = (float)(palette[i].s.green >> 2); + float fblue = (float)(palette[i].s.blue >> 3); + crushed_palette[i].s.red = (UINT8)(fred / 31.0f * 255.0f); + crushed_palette[i].s.green = (UINT8)(fgreen / 63.0f * 255.0f); + crushed_palette[i].s.blue = (UINT8)(fblue / 31.0f * 255.0f); + crushed_palette[i].s.alpha = 255; + } + HWD.pfnSetScreenPalette(crushed_palette); + } + else + { + HWD.pfnSetScreenPalette(palette); + } + + // this part is responsible for keeping track of the palette OUTSIDE of a level. + if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + HWR_SetMapPalette(); + } + else + { + // set the palette for the textures + HWD.pfnSetTexturePalette(palette); + // reset mapPalette so next call to HWR_SetMapPalette will update everything correctly + memset(mapPalette, 0, sizeof(mapPalette)); + // hardware driver will flush there own cache if cache is non paletized + // now flush data texture cache so 32 bit texture are recomputed + if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA) + { + Z_FreeTag(PU_HWRCACHE); + Z_FreeTag(PU_HWRCACHE_UNLOCKED); + } + } +} + +static void HWR_SetPaletteLookup(RGBA_t *palette) +{ + int r, g, b; + UINT8 *lut = Z_Malloc( + HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE*sizeof(UINT8), + PU_STATIC, NULL); +#define STEP_SIZE (256/HWR_PALETTE_LUT_SIZE) + for (b = 0; b < HWR_PALETTE_LUT_SIZE; b++) + { + for (g = 0; g < HWR_PALETTE_LUT_SIZE; g++) + { + for (r = 0; r < HWR_PALETTE_LUT_SIZE; r++) + { + lut[b*HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE+g*HWR_PALETTE_LUT_SIZE+r] = + NearestPaletteColor(r*STEP_SIZE, g*STEP_SIZE, b*STEP_SIZE, palette); + } + } + } +#undef STEP_SIZE + HWD.pfnSetPaletteLookup(lut); + Z_Free(lut); +} + +// Updates mapPalette to reflect the loaded level or other game state. +// Textures are flushed if needed. +// Call this function only in palette rendering mode. +void HWR_SetMapPalette(void) +{ + RGBA_t RGBA_converted[256]; + RGBA_t *palette; + int i; + + if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + { + // outside of a level, pMasterPalette should have PLAYPAL ready for us + palette = pMasterPalette; + } + else + { + // in a level pMasterPalette might have a flash palette, but we + // want the map's original palette. + lumpnum_t lumpnum = W_GetNumForName(GetPalette()); + size_t palsize = W_LumpLength(lumpnum); + UINT8 *RGB_data; + if (palsize < 768) // 256 * 3 + I_Error("HWR_SetMapPalette: A programmer assumed palette lumps are at least 768 bytes long, but apparently this was a wrong assumption!\n"); + RGB_data = W_CacheLumpNum(lumpnum, PU_CACHE); + // we got the RGB palette now, but we need it in RGBA format. + for (i = 0; i < 256; i++) + { + RGBA_converted[i].s.red = *(RGB_data++); + RGBA_converted[i].s.green = *(RGB_data++); + RGBA_converted[i].s.blue = *(RGB_data++); + RGBA_converted[i].s.alpha = 255; + } + palette = RGBA_converted; + } + + // check if the palette has changed from the previous one + if (memcmp(mapPalette, palette, sizeof(mapPalette))) + { + memcpy(mapPalette, palette, sizeof(mapPalette)); + // in palette rendering mode, this means that all rgba textures now have wrong colors + // and the lookup table is outdated + HWR_SetPaletteLookup(mapPalette); + HWD.pfnSetTexturePalette(mapPalette); + if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA) + { + Z_FreeTag(PU_HWRCACHE); + Z_FreeTag(PU_HWRCACHE_UNLOCKED); + } + } +} + +// Creates a hardware lighttable from the supplied lighttable. +// Returns the id of the hw lighttable, usable in FSurfaceInfo. +UINT32 HWR_CreateLightTable(UINT8 *lighttable) +{ + UINT32 i, id; + RGBA_t *palette = HWR_GetTexturePalette(); + RGBA_t *hw_lighttable = Z_Malloc(256 * 32 * sizeof(RGBA_t), PU_STATIC, NULL); + + // To make the palette index -> RGBA mapping easier for the shader, + // the hardware lighttable is composed of RGBA colors instead of palette indices. + for (i = 0; i < 256 * 32; i++) + hw_lighttable[i] = palette[lighttable[i]]; + + id = HWD.pfnCreateLightTable(hw_lighttable); + Z_Free(hw_lighttable); + return id; +} + +// get hwr lighttable id for colormap, create it if it doesn't already exist +UINT32 HWR_GetLightTableID(extracolormap_t *colormap) +{ + boolean default_colormap = false; + if (!colormap) + { + colormap = R_GetDefaultColormap(); // a place to store the hw lighttable id + // alternatively could just store the id in a global variable if there are issues + default_colormap = true; + } + + // create hw lighttable if there isn't one + if (!colormap->gl_lighttable_id) + { + UINT8 *colormap_pointer; + + if (default_colormap) + colormap_pointer = colormaps; // don't actually use the data from the "default colormap" + else + colormap_pointer = colormap->colormap; + colormap->gl_lighttable_id = HWR_CreateLightTable(colormap_pointer); + } + + return colormap->gl_lighttable_id; +} + +// Note: all hardware lighttable ids assigned before this +// call become invalid and must not be used. +void HWR_ClearLightTables(void) +{ + if (vid.glstate == VID_GL_LIBRARY_LOADED) + HWD.pfnClearLightTables(); +} + #endif //HWRENDER diff --git a/src/hardware/hw_clip.c b/src/hardware/hw_clip.c index 86e0c58d25a72956dd9b10d6950baf10fd731ae1..74268423f5526c8d2c8733775b9f2ca60fb6141e 100644 --- a/src/hardware/hw_clip.c +++ b/src/hardware/hw_clip.c @@ -320,16 +320,13 @@ void gld_clipper_Clear(void) #define RMUL (1.6f/1.333333f) -angle_t gld_FrustumAngle(angle_t tiltangle) +angle_t gld_FrustumAngle(float render_fov, angle_t tiltangle) { double floatangle; angle_t a1; float tilt = (float)fabs(((double)(int)tiltangle) / ANG1); - // NEWCLIP TODO: SRB2CBTODO: make a global render_fov for this function - - float render_fov = FIXED_TO_FLOAT(cv_fov.value); float render_fovratio = (float)BASEVIDWIDTH / (float)BASEVIDHEIGHT; // SRB2CBTODO: NEWCLIPTODO: Is this right? float render_multiplier = 64.0f / render_fovratio / RMUL; diff --git a/src/hardware/hw_clip.h b/src/hardware/hw_clip.h index 27a2ed1efa2de4b9f6d54278a5052fb03c4a1d46..e3bb4c3193ca0094871f15d89e892a8c769d14d0 100644 --- a/src/hardware/hw_clip.h +++ b/src/hardware/hw_clip.h @@ -17,7 +17,7 @@ boolean gld_clipper_SafeCheckRange(angle_t startAngle, angle_t endAngle); void gld_clipper_SafeAddClipRange(angle_t startangle, angle_t endangle); void gld_clipper_Clear(void); -angle_t gld_FrustumAngle(angle_t tiltangle); +angle_t gld_FrustumAngle(float render_fov, angle_t tiltangle); #ifdef HAVE_SPHEREFRUSTRUM void gld_FrustrumSetup(void); boolean gld_SphereInFrustum(float x, float y, float z, float radius); diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 3b660cc70c36515dab60b4ae3eabb914b5de7d5d..2d55eef2d8fd72271fef9c529d4be862318f93da 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -18,6 +18,12 @@ #define ZCLIP_PLANE 4.0f // Used for the actual game drawing #define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures +// The width/height/depth of the palette lookup table used by palette rendering. +// Changing this also requires changing the shader code! +// Also assumed to be a power of two in some parts of the code. +// 64 seems to work perfectly for the vanilla palette. +#define HWR_PALETTE_LUT_SIZE 64 + // ========================================================================== // SIMPLE TYPES // ========================================================================== @@ -122,33 +128,31 @@ typedef struct } FOutVector; #ifdef GL_SHADERS -// Predefined shader types + +// Shader targets used to render specific types of geometry. +// A shader target is resolved to an actual shader with HWR_GetShaderFromTarget. +// The shader returned may be a base shader or a custom shader. enum { SHADER_NONE = -1, - SHADER_DEFAULT = 0, - SHADER_FLOOR, + SHADER_FLOOR = 0, SHADER_WALL, SHADER_SPRITE, - SHADER_MODEL, SHADER_MODEL_LIGHTING, + SHADER_MODEL, SHADER_WATER, SHADER_FOG, SHADER_SKY, + SHADER_PALETTE_POSTPROCESS, + SHADER_UI_COLORMAP_FADE, + SHADER_UI_TINTED_WIPE, - NUMBASESHADERS, + NUMSHADERTARGETS }; // Maximum amount of shader programs -// Must be higher than NUMBASESHADERS -#define HWR_MAXSHADERS 16 - -// Shader sources (vertex and fragment) -typedef struct -{ - char *vertex; - char *fragment; -} shadersource_t; +// Must be at least NUMSHADERTARGETS*2 to fit base and custom shaders for each shader target. +#define HWR_MAXSHADERS NUMSHADERTARGETS*2 // Custom shader reference table typedef struct @@ -272,11 +276,15 @@ struct FSurfaceInfo RGBA_t PolyColor; RGBA_t TintColor; RGBA_t FadeColor; + UINT32 LightTableId; FLightInfo LightInfo; }; typedef struct FSurfaceInfo FSurfaceInfo; -//Hurdler: added for backward compatibility +#define GL_DEFAULTMIX 0x00000000 +#define GL_DEFAULTFOG 0xFF000000 + +// Various settings and states for the rendering backend. enum hwdsetspecialstate { HWD_SET_MODEL_LIGHTING = 1, @@ -289,15 +297,13 @@ enum hwdsetspecialstate typedef enum hwdsetspecialstate hwdspecialstate_t; -// Lactozilla: Shader options -enum hwdshaderoption +enum hwdshaderstage { - HWD_SHADEROPTION_OFF, - HWD_SHADEROPTION_ON, - HWD_SHADEROPTION_NOCUSTOM, + HWD_SHADERSTAGE_VERTEX, + HWD_SHADERSTAGE_FRAGMENT, }; -typedef enum hwdshaderoption hwdshaderoption_t; +typedef enum hwdshaderstage hwdshaderstage_t; // Lactozilla: Shader info // Generally set at the start of the frame. @@ -318,5 +324,18 @@ enum hwdfiltermode HWD_SET_TEXTUREFILTER_MIXED3, }; +// Screen texture slots +enum hwdscreentexture +{ + HWD_SCREENTEXTURE_WIPE_START, // source image for the wipe/fade effect + HWD_SCREENTEXTURE_WIPE_END, // destination image for the wipe/fade effect + HWD_SCREENTEXTURE_GENERIC1, // underwater/heat effect, intermission background + HWD_SCREENTEXTURE_GENERIC2, // palette-based colormap fade, screen before palette rendering's postprocessing + HWD_SCREENTEXTURE_GENERIC3, // screen after palette rendering's postprocessing + NUMSCREENTEXTURES, // (generic3 is unused if palette rendering is disabled) +}; + +typedef enum hwdscreentexture hwdscreentexture_t; + #endif //_HWR_DEFS_ diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index ba1f339d0fe9af16d7eee7ab0f73d7558de0936e..ddce7d9885d7607e1cabf9bfc5c74ecf6258612b 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -22,7 +22,6 @@ #include "hw_drv.h" #include "../m_misc.h" //FIL_WriteFile() -#include "../r_draw.h" //viewborderlump #include "../r_main.h" #include "../w_wad.h" #include "../z_zone.h" @@ -30,13 +29,10 @@ #include "../st_stuff.h" #include "../p_local.h" // stplyr #include "../g_game.h" // players +#include "../f_finale.h" // fade color factors #include <fcntl.h> -#include "../i_video.h" // for rendermode != render_glide - -#ifndef O_BINARY -#define O_BINARY 0 -#endif +#include "../i_video.h" #if defined(_MSC_VER) #pragma pack(1) @@ -62,63 +58,6 @@ static UINT8 softwaretranstogl[11] = { 0, 25, 51, 76,102,127,153,178,204,229 static UINT8 softwaretranstogl_hi[11] = { 0, 51,102,153,204,255,255,255,255,255,255}; static UINT8 softwaretranstogl_lo[11] = { 0, 12, 24, 36, 48, 60, 71, 83, 95,111,127}; -// -// -----------------+ -// HWR_DrawPatch : Draw a 'tile' graphic -// Notes : x,y : positions relative to the original Doom resolution -// : textes(console+score) + menus + status bar -// -----------------+ -void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option) -{ - FOutVector v[4]; - FBITFIELD flags; - GLPatch_t *hwrPatch; - -// 3--2 -// | /| -// |/ | -// 0--1 - float sdup = FIXED_TO_FLOAT(vid.fdup)*2.0f; - float pdup = FIXED_TO_FLOAT(vid.fdup)*2.0f; - - // make patch ready in hardware cache - HWR_GetPatch(gpatch); - hwrPatch = ((GLPatch_t *)gpatch->hardware); - - switch (option & V_SCALEPATCHMASK) - { - case V_NOSCALEPATCH: - pdup = 2.0f; - break; - case V_SMALLSCALEPATCH: - pdup = 2.0f * FIXED_TO_FLOAT(vid.fsmalldup); - break; - case V_MEDSCALEPATCH: - pdup = 2.0f * FIXED_TO_FLOAT(vid.fmeddup); - break; - } - - if (option & V_NOSCALESTART) - sdup = 2.0f; - - v[0].x = v[3].x = (x*sdup-(gpatch->leftoffset)*pdup)/vid.width - 1; - v[2].x = v[1].x = (x*sdup+(gpatch->width-gpatch->leftoffset)*pdup)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdup-(gpatch->topoffset)*pdup)/vid.height; - v[2].y = v[3].y = 1-(y*sdup+(gpatch->height-gpatch->topoffset)*pdup)/vid.height; - - v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - - v[0].s = v[3].s = 0.0f; - v[2].s = v[1].s = hwrPatch->max_s; - v[0].t = v[1].t = 0.0f; - v[2].t = v[3].t = hwrPatch->max_t; - - flags = PF_Translucent|PF_NoDepthTest; - - // clip it since it is used for bunny scroll in doom I - HWD.pfnDrawPolygon(NULL, v, 4, flags); -} - void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) { FOutVector v[4]; @@ -707,6 +646,7 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) { FOutVector v[4]; FSurfaceInfo Surf; + FBITFIELD poly_flags = PF_NoTexture|PF_Modulated|PF_NoDepthTest; v[0].x = v[3].x = -1.0f; v[2].x = v[1].x = 1.0f; @@ -719,17 +659,59 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) v[0].t = v[1].t = 1.0f; v[2].t = v[3].t = 0.0f; - if (color & 0xFF00) // Do COLORMAP fade. + if (color & 0xFF00) // Special fade options { - Surf.PolyColor.rgba = UINT2RGBA(0x01010160); - Surf.PolyColor.s.alpha = (strength*8); + UINT16 option = color & 0x0F00; + if (option == 0x0A00 || option == 0x0B00) // Tinted fades + { + INT32 r, g, b; + int fade = strength * 8; + + r = FADEREDFACTOR*fade/10; + g = FADEGREENFACTOR*fade/10; + b = FADEBLUEFACTOR*fade/10; + + Surf.PolyColor.s.red = min(r, 255); + Surf.PolyColor.s.green = min(g, 255); + Surf.PolyColor.s.blue = min(b, 255); + Surf.PolyColor.s.alpha = 255; + + if (option == 0x0A00) // Tinted subtractive fade + poly_flags |= PF_ReverseSubtract; + else if (option == 0x0B00) // Tinted additive fade + poly_flags |= PF_Additive; + } + else // COLORMAP fade + { + if (HWR_ShouldUsePaletteRendering()) + { + const hwdscreentexture_t scr_tex = HWD_SCREENTEXTURE_GENERIC2; + + Surf.LightTableId = HWR_GetLightTableID(NULL); + Surf.LightInfo.light_level = strength; + HWD.pfnMakeScreenTexture(scr_tex); + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_COLORMAP_FADE)); + HWD.pfnDrawScreenTexture(scr_tex, &Surf, PF_ColorMapped|PF_NoDepthTest); + HWD.pfnUnSetShader(); + + return; + } + else + { + Surf.PolyColor.rgba = UINT2RGBA(0x01010160); + Surf.PolyColor.s.alpha = (strength*8); + poly_flags |= PF_Translucent; + } + } } else // Do TRANSMAP** fade. { - Surf.PolyColor.rgba = V_GetColor(color).rgba; + RGBA_t *palette = HWR_GetTexturePalette(); + Surf.PolyColor.rgba = palette[color&0xFF].rgba; Surf.PolyColor.s.alpha = softwaretranstogl[strength]; + poly_flags |= PF_Translucent; } - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); + HWD.pfnDrawPolygon(&Surf, v, 4, poly_flags); } // -----------------+ @@ -897,7 +879,8 @@ void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 ac } else // Do TRANSMAP** fade. { - Surf.PolyColor.rgba = V_GetColor(actualcolor).rgba; + RGBA_t *palette = HWR_GetTexturePalette(); + Surf.PolyColor.rgba = palette[actualcolor&0xFF].rgba; Surf.PolyColor.s.alpha = softwaretranstogl[strength]; } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); @@ -960,136 +943,6 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight) HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } - -// ========================================================================== -// R_DRAW.C STUFF -// ========================================================================== - -// ------------------ -// HWR_DrawViewBorder -// Fill the space around the view window with a Doom flat texture, draw the -// beveled edges. -// 'clearlines' is useful to clear the heads up messages, when the view -// window is reduced, it doesn't refresh all the view borders. -// ------------------ -void HWR_DrawViewBorder(INT32 clearlines) -{ - INT32 x, y; - INT32 top, side; - INT32 baseviewwidth, baseviewheight; - INT32 basewindowx, basewindowy; - patch_t *patch; - -// if (gl_viewwidth == vid.width) -// return; - - if (!clearlines) - clearlines = BASEVIDHEIGHT; // refresh all - - // calc view size based on original game resolution - baseviewwidth = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwidth), vid.fdup)); //(cv_viewsize.value * BASEVIDWIDTH/10)&~7; - baseviewheight = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewheight), vid.fdup)); - top = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_baseviewwindowy), vid.fdup)); - side = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwindowx), vid.fdup)); - - // top - HWR_DrawFlatFill(0, 0, - BASEVIDWIDTH, (top < clearlines ? top : clearlines), - st_borderpatchnum); - - // left - if (top < clearlines) - HWR_DrawFlatFill(0, top, side, - (clearlines-top < baseviewheight ? clearlines-top : baseviewheight), - st_borderpatchnum); - - // right - if (top < clearlines) - HWR_DrawFlatFill(side + baseviewwidth, top, side, - (clearlines-top < baseviewheight ? clearlines-top : baseviewheight), - st_borderpatchnum); - - // bottom - if (top + baseviewheight < clearlines) - HWR_DrawFlatFill(0, top + baseviewheight, - BASEVIDWIDTH, BASEVIDHEIGHT, st_borderpatchnum); - - // - // draw the view borders - // - - basewindowx = (BASEVIDWIDTH - baseviewwidth)>>1; - if (baseviewwidth == BASEVIDWIDTH) - basewindowy = 0; - else - basewindowy = top; - - // top edge - if (clearlines > basewindowy - 8) - { - patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH); - for (x = 0; x < baseviewwidth; x += 8) - HWR_DrawPatch(patch, basewindowx + x, basewindowy - 8, - 0); - } - - // bottom edge - if (clearlines > basewindowy + baseviewheight) - { - patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH); - for (x = 0; x < baseviewwidth; x += 8) - HWR_DrawPatch(patch, basewindowx + x, - basewindowy + baseviewheight, 0); - } - - // left edge - if (clearlines > basewindowy) - { - patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH); - for (y = 0; y < baseviewheight && basewindowy + y < clearlines; - y += 8) - { - HWR_DrawPatch(patch, basewindowx - 8, basewindowy + y, - 0); - } - } - - // right edge - if (clearlines > basewindowy) - { - patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH); - for (y = 0; y < baseviewheight && basewindowy+y < clearlines; - y += 8) - { - HWR_DrawPatch(patch, basewindowx + baseviewwidth, - basewindowy + y, 0); - } - } - - // Draw beveled corners. - if (clearlines > basewindowy - 8) - HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TL], - PU_PATCH), - basewindowx - 8, basewindowy - 8, 0); - - if (clearlines > basewindowy - 8) - HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TR], - PU_PATCH), - basewindowx + baseviewwidth, basewindowy - 8, 0); - - if (clearlines > basewindowy+baseviewheight) - HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BL], - PU_PATCH), - basewindowx - 8, basewindowy + baseviewheight, 0); - - if (clearlines > basewindowy + baseviewheight) - HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BR], - PU_PATCH), - basewindowx + baseviewwidth, - basewindowy + baseviewheight, 0); -} - - // ========================================================================== // AM_MAP.C DRAWING STUFF // ========================================================================== @@ -1102,8 +955,9 @@ void HWR_drawAMline(const fline_t *fl, INT32 color) { F2DCoord v1, v2; RGBA_t color_rgba; + RGBA_t *palette = HWR_GetTexturePalette(); - color_rgba = V_GetColor(color); + color_rgba = palette[color&0xFF]; v1.x = ((float)fl->a.x-(vid.width/2.0f))*(2.0f/vid.width); v1.y = ((float)fl->a.y-(vid.height/2.0f))*(2.0f/vid.height); @@ -1288,6 +1142,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) FOutVector v[4]; FSurfaceInfo Surf; float fx, fy, fw, fh; + RGBA_t *palette = HWR_GetTexturePalette(); UINT8 alphalevel = ((color & V_ALPHAMASK) >> V_ALPHASHIFT); UINT8 perplayershuffle = 0; @@ -1374,7 +1229,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) { if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) { - RGBA_t rgbaColour = V_GetColor(color); + RGBA_t rgbaColour = palette[color&0xFF]; FRGBAFloat clearColour; clearColour.red = (float)rgbaColour.s.red / 255; clearColour.green = (float)rgbaColour.s.green / 255; @@ -1451,7 +1306,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) v[0].t = v[1].t = 0.0f; v[2].t = v[3].t = 1.0f; - Surf.PolyColor = V_GetColor(color); + Surf.PolyColor = palette[color&0xFF]; if (alphalevel) { @@ -1499,7 +1354,7 @@ static inline boolean saveTGA(const char *file_name, void *buffer, INT32 i; UINT8 *buf8 = buffer; - fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) return false; @@ -1539,11 +1394,12 @@ static inline boolean saveTGA(const char *file_name, void *buffer, UINT8 *HWR_GetScreenshot(void) { UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf)); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; if (!buf) return NULL; // returns 24bit 888 RGB - HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); + HWD.pfnReadScreenTexture(tex, (void *)buf); return buf; } @@ -1551,6 +1407,7 @@ boolean HWR_Screenshot(const char *pathname) { boolean ret; UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf)); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; if (!buf) { @@ -1559,7 +1416,7 @@ boolean HWR_Screenshot(const char *pathname) } // returns 24bit 888 RGB - HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); + HWD.pfnReadScreenTexture(tex, (void *)buf); #ifdef USE_PNG ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL); diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 1c4cd99ab03d34498fa13d132a01ef53af9e6e61..45ee2933a69bca328be875ec2e449ca7f74cab39 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -29,10 +29,7 @@ EXPORT boolean HWRAPI(Init) (void); #ifndef HAVE_SDL EXPORT void HWRAPI(Shutdown) (void); #endif -#ifdef _WINDOWS -EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes); -#endif -EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal); +EXPORT void HWRAPI(SetTexturePalette) (RGBA_t *ppal); EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl); EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color); EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags); @@ -43,11 +40,10 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFl EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo); EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo); EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo); -EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); -//Hurdler: added for backward compatibility EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); //Hurdler: added for new development @@ -57,24 +53,26 @@ EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(FlushScreenTextures) (void); -EXPORT void HWRAPI(StartScreenWipe) (void); -EXPORT void HWRAPI(EndScreenWipe) (void); -EXPORT void HWRAPI(DoScreenWipe) (void); -EXPORT void HWRAPI(DrawIntermissionBG) (void); -EXPORT void HWRAPI(MakeScreenTexture) (void); -EXPORT void HWRAPI(MakeScreenFinalTexture) (void); -EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); +EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd, FSurfaceInfo *surf, FBITFIELD polyFlags); +EXPORT void HWRAPI(DrawScreenTexture) (int tex, FSurfaceInfo *surf, FBITFIELD polyflags); +EXPORT void HWRAPI(MakeScreenTexture) (int tex); +EXPORT void HWRAPI(DrawScreenFinalTexture) (int tex, int width, int height); #define SCREENVERTS 10 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); -EXPORT boolean HWRAPI(CompileShaders) (void); -EXPORT void HWRAPI(CleanShaders) (void); -EXPORT void HWRAPI(SetShader) (int type); +EXPORT boolean HWRAPI(InitShaders) (void); +EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage); +EXPORT boolean HWRAPI(CompileShader) (int slot); +EXPORT void HWRAPI(SetShader) (int slot); EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); -EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment); + +EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut); +EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable); +EXPORT void HWRAPI(ClearLightTables)(void); +EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette); // ========================================================================== // HWR DRIVER OBJECT, FOR CLIENT PROGRAM @@ -85,7 +83,7 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole struct hwdriver_s { Init pfnInit; - SetPalette pfnSetPalette; + SetTexturePalette pfnSetTexturePalette; FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; @@ -96,10 +94,10 @@ struct hwdriver_s SetTexture pfnSetTexture; UpdateTexture pfnUpdateTexture; DeleteTexture pfnDeleteTexture; - ReadRect pfnReadRect; + ReadScreenTexture pfnReadScreenTexture; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; - SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility + SetSpecialState pfnSetSpecialState; DrawModel pfnDrawModel; CreateModelVBOs pfnCreateModelVBOs; SetTransform pfnSetTransform; @@ -112,21 +110,23 @@ struct hwdriver_s #endif PostImgRedraw pfnPostImgRedraw; FlushScreenTextures pfnFlushScreenTextures; - StartScreenWipe pfnStartScreenWipe; - EndScreenWipe pfnEndScreenWipe; DoScreenWipe pfnDoScreenWipe; - DrawIntermissionBG pfnDrawIntermissionBG; + DrawScreenTexture pfnDrawScreenTexture; MakeScreenTexture pfnMakeScreenTexture; - MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; - CompileShaders pfnCompileShaders; - CleanShaders pfnCleanShaders; + InitShaders pfnInitShaders; + LoadShader pfnLoadShader; + CompileShader pfnCompileShader; SetShader pfnSetShader; UnSetShader pfnUnSetShader; SetShaderInfo pfnSetShaderInfo; - LoadCustomShader pfnLoadCustomShader; + + SetPaletteLookup pfnSetPaletteLookup; + CreateLightTable pfnCreateLightTable; + ClearLightTables pfnClearLightTables; + SetScreenPalette pfnSetScreenPalette; }; extern struct hwdriver_s hwdriver; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index fbb02f46322c614107fc5523884e7081064c5c4a..e96ea6c7832e2dda5bb03c73b67981d35f1459e4 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -107,6 +107,8 @@ void HWR_FreeExtraSubsectors(void); // -------- // hw_cache.c // -------- +RGBA_t *HWR_GetTexturePalette(void); + void HWR_InitMapTextures(void); void HWR_LoadMapTextures(size_t pnumtextures); void HWR_FreeMapTextures(void); @@ -117,7 +119,6 @@ patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum); void HWR_GetPatch(patch_t *patch); void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap); void HWR_GetFadeMask(lumpnum_t fademasklumpnum); -patch_t *HWR_GetPic(lumpnum_t lumpnum); GLMapTexture_t *HWR_GetTexture(INT32 tex); void HWR_GetLevelFlat(levelflat_t *levelflat); @@ -131,6 +132,10 @@ void HWR_FreeColormapCache(void); void HWR_UnlockCachedPatch(GLPatch_t *gpatch); void HWR_SetPalette(RGBA_t *palette); +void HWR_SetMapPalette(void); +UINT32 HWR_CreateLightTable(UINT8 *lighttable); +UINT32 HWR_GetLightTableID(extracolormap_t *colormap); +void HWR_ClearLightTables(void); // -------- @@ -139,4 +144,18 @@ void HWR_SetPalette(RGBA_t *palette); extern INT32 patchformat; extern INT32 textureformat; +// -------- +// hw_shaders.c +// -------- +boolean HWR_InitShaders(void); +void HWR_CompileShaders(void); + +int HWR_GetShaderFromTarget(int shader_target); + +void HWR_LoadAllCustomShaders(void); +void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3); +const char *HWR_GetShaderName(INT32 shader); + +extern customshaderxlat_t shaderxlat[]; + #endif //_HW_GLOB_ diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index bcfdfa960d7b723ecb0be2437667bcf09b1030e9..e7769edbd8da2dbaa38debfabae9a34f25d121ee 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -1055,7 +1055,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr) light[3].y = cy+size*1.33f+p_lspr->light_yoffset; light[3].s = 0.0f; light[3].t = 1.0f; - HWR_GetPic(coronalumpnum); /// \todo use different coronas + // HWR_GetPic(coronalumpnum); /// \todo use different coronas HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Corona | PF_NoDepthTest); } @@ -1071,7 +1071,7 @@ void HWR_DrawCoronas(void) if (!cv_glcoronas.value || dynlights->nb <= 0 || coronalumpnum == LUMPERROR) return; - HWR_GetPic(coronalumpnum); /// \todo use different coronas + // HWR_GetPic(coronalumpnum); /// \todo use different coronas for (j = 0;j < dynlights->nb;j++) { FOutVector light[4]; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 8c4651c040a174328d5ca4bc7aaee5f12f512233..0ec4536ce3c716b0835328ddc4fbe717d4ac0b53 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -19,8 +19,10 @@ #include "hw_light.h" #include "hw_drv.h" #include "hw_batching.h" +#include "hw_md2.h" +#include "hw_clip.h" -#include "../i_video.h" // for rendermode == render_glide +#include "../i_video.h" #include "../v_video.h" #include "../p_local.h" #include "../p_setup.h" @@ -42,15 +44,6 @@ #include "../r_translation.h" #include "../d_main.h" #include "../p_slopes.h" -#include "hw_md2.h" - -#ifdef NEWCLIP -#include "hw_clip.h" -#endif - -#define R_FAKEFLOORS -#define HWPRECIP -//#define POLYSKY // ========================================================================== // the hardware driver object @@ -61,95 +54,27 @@ struct hwdriver_s hwdriver; // PROTOS // ========================================================================== - static void HWR_AddSprites(sector_t *sec); static void HWR_ProjectSprite(mobj_t *thing); -#ifdef HWPRECIP static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); -#endif static void HWR_ProjectBoundingBox(mobj_t *thing); void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap); -boolean drawsky = true; - -// ========================================================================== -// VIEW GLOBALS -// ========================================================================== -// Fineangles in the SCREENWIDTH wide window. -#define FIELDOFVIEW ANGLE_90 -#define ABS(x) ((x) < 0 ? -(x) : (x)) - -static angle_t gl_clipangle; - -// The viewangletox[viewangle + FINEANGLES/4] lookup -// maps the visible view angles to screen X coordinates, -// flattening the arc to a flat projection plane. -// There will be many angles mapped to the same X. -static INT32 gl_viewangletox[FINEANGLES/2]; - -// The xtoviewangleangle[] table maps a screen pixel -// to the lowest viewangle that maps back to x ranges -// from clipangle to -clipangle. -static angle_t gl_xtoviewangle[MAXVIDWIDTH+1]; +static boolean drawsky = true; // ========================================================================== // GLOBALS // ========================================================================== -// uncomment to remove the plane rendering -#define DOPLANES -//#define DOWALLS - -// test of drawing sky by polygons like in software with visplane, unfortunately -// this doesn't work since we must have z for pixel and z for texture (not like now with z = oow) -//#define POLYSKY - -// test change fov when looking up/down but bsp projection messup :( -//#define NOCRAPPYMLOOK - -// base values set at SetViewSize -static float gl_basecentery; - -float gl_baseviewwindowy, gl_basewindowcentery; -float gl_viewwidth, gl_viewheight; // viewport clipping boundaries (screen coords) -float gl_viewwindowx; - -static float gl_centerx, gl_centery; -static float gl_viewwindowy; // top left corner of view window -static float gl_windowcenterx; // center of view window, for projection -static float gl_windowcentery; - -static float gl_pspritexscale, gl_pspriteyscale; - static seg_t *gl_curline; static side_t *gl_sidedef; static line_t *gl_linedef; static sector_t *gl_frontsector; static sector_t *gl_backsector; -// -------------------------------------------------------------------------- -// STUFF FOR THE PROJECTION CODE -// -------------------------------------------------------------------------- - -FTransform atransform; -// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct, -// copied here for local use -static fixed_t dup_viewx, dup_viewy, dup_viewz; -static angle_t dup_viewangle; - -static float gl_viewx, gl_viewy, gl_viewz; -float gl_viewsin, gl_viewcos; - -// Maybe not necessary with the new T&L code (needs to be checked!) -static float gl_viewludsin, gl_viewludcos; // look up down kik test -static float gl_fovlud; - -static angle_t gl_aimingangle; -static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); - // Render stats ps_metric_t ps_hw_skyboxtime = {0}; ps_metric_t ps_hw_nodesorttime = {0}; @@ -170,13 +95,35 @@ ps_metric_t ps_hw_batchdrawtime = {0}; boolean gl_init = false; boolean gl_maploaded = false; -boolean gl_shadersavailable = true; +boolean gl_sessioncommandsadded = false; +// false if shaders have not been initialized yet, or if shaders are not available +boolean gl_shadersavailable = false; + +// Whether the internal state is set to palette rendering or not. +static boolean gl_palette_rendering_state = false; + +// -------------------------------------------------------------------------- +// STUFF FOR THE PROJECTION CODE +// -------------------------------------------------------------------------- + +FTransform atransform; + +static float gl_viewx, gl_viewy, gl_viewz; +float gl_viewsin, gl_viewcos; + +// For HWR_RotateSpritePolyToAim +static float gl_viewludsin, gl_viewludcos; +static float gl_fovlud; + +static angle_t gl_aimingangle; +static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); // ========================================================================== // Lighting // ========================================================================== -static boolean HWR_UseShader(void) +// Returns true if shaders can be used. +boolean HWR_UseShader(void) { return (cv_glshaders.value && gl_shadersavailable); } @@ -242,6 +189,11 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col Surface->LightInfo.light_level = light_level; Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0; Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31; + + if (HWR_ShouldUsePaletteRendering()) + Surface->LightTableId = HWR_GetLightTableID(colormap); + else + Surface->LightTableId = 0; } UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work @@ -361,8 +313,6 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta) // FLOOR/CEILING GENERATION FROM SUBSECTORS // ========================================================================== -#ifdef DOPLANES - // -----------------+ // HWR_RenderPlane : Render a floor or ceiling convex polygon // -----------------+ @@ -372,7 +322,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool FOutVector *v3d; polyvertex_t *pv; pslope_t *slope = NULL; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; size_t nrPlaneVerts; INT32 i; @@ -533,6 +483,9 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool PolyFlags |= PF_ColorMapped; } + if (!cv_renderfloors.value) + return; + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false); if (subsector) @@ -551,7 +504,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool for (i = 0; i < subsector->numlines; i++, line++) { - if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0) + if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(viewx, viewy, line) == 0) { P_ClosestPointOnLine(viewx, viewy, line->linedef, &v); dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y)); @@ -630,52 +583,6 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool #endif } -#ifdef POLYSKY -// this don't draw anything it only update the z-buffer so there isn't problem with -// wall/things upper that sky (map12) -static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight) -{ - polyvertex_t *pv; - float height; //constant y for all points on the convex flat polygon - FOutVector *v3d; - INT32 nrPlaneVerts; //verts original define of convex flat polygon - INT32 i; - - // no convex poly were generated for this subsector - if (!xsub->planepoly) - return; - - height = FIXED_TO_FLOAT(fixedheight); - - pv = xsub->planepoly->pts; - nrPlaneVerts = xsub->planepoly->numpts; - - if (nrPlaneVerts < 3) // not even a triangle? - return; - - if (nrPlaneVerts > MAXPLANEVERTICES) // FIXME: exceeds plVerts size - { - CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, MAXPLANEVERTICES); - return; - } - - // transform - v3d = planeVerts; - for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++) - { - v3d->s = 0.0f; - v3d->t = 0.0f; - v3d->x = pv->x; - v3d->y = height; - v3d->z = pv->y; - } - - HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, PF_Invisible|PF_NoTexture|PF_Occlude); -} -#endif //polysky - -#endif //doplanes - FBITFIELD HWR_GetBlendModeFlag(INT32 style) { switch (style) @@ -759,7 +666,10 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I // static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; + + if (!cv_renderwalls.value) + return; HWR_Lighting(pSurf, lightlevel, wallcolormap); @@ -776,41 +686,6 @@ static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIEL // BSP, CULL, ETC.. // ========================================================================== -// return the frac from the interception of the clipping line -// (in fact a clipping plane that has a constant, so can clip with simple 2d) -// with the wall segment -// -#ifndef NEWCLIP -static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2) -{ - float num, den; - float v1x, v1y, v1dx, v1dy, v2dx, v2dy; - angle_t pclipangle = gl_xtoviewangle[x]; - - // a segment of a polygon - v1x = v1->x; - v1y = v1->y; - v1dx = (v2->x - v1->x); - v1dy = (v2->y - v1->y); - - // the clipping line - pclipangle = pclipangle + dup_viewangle; //back to normal angle (non-relative) - v2dx = FIXED_TO_FLOAT(FINECOSINE(pclipangle>>ANGLETOFINESHIFT)); - v2dy = FIXED_TO_FLOAT(FINESINE(pclipangle>>ANGLETOFINESHIFT)); - - den = v2dy*v1dx - v2dx*v1dy; - if (den == 0) - return -1; // parallel - - // calc the frac along the polygon segment, - //num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx; - //num = -v1x * v2dy + v1y * v2dx; - num = (gl_viewx - v1x)*v2dy + (v1y - gl_viewy)*v2dx; - - return num / den; -} -#endif - // SoM: split up and light walls according to the lightlist. // This may also include leaving out parts of the wall that can't be seen static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor, FBITFIELD polyflags) @@ -834,6 +709,9 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y); extracolormap_t *colormap = NULL; + if (!cv_renderwalls.value) + return; + realtop = top = wallVerts[3].y; realbot = bot = wallVerts[0].y; diff = top - bot; @@ -872,13 +750,15 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, { if (pfloor && (pfloor->fofflags & FOF_FOG)) { - lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y); + lightnum = pfloor->master->frontsector->lightlevel; colormap = pfloor->master->frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); } else { - lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y); + lightnum = *list[i].lightlevel; colormap = *list[i].extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); } } @@ -998,7 +878,7 @@ static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) // PF_Occlude is set in HWR_ProjectWall to draw into the depth buffer } -// Returns true if the midtexture is visible, and false if... it isn't... +// Returns true if the midtexture is visible, false if not static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) { FUINT blendmode = PF_Masked; @@ -1219,14 +1099,8 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap); } -// -// HWR_ProcessSeg -// A portion or all of a wall segment will be drawn, from startfrac to endfrac, -// where 0 is the start of the segment, 1 the end of the segment -// Anything between means the wall segment has been clipped with solidsegs, -// reducing wall overdraw to a minimum -// -static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom +// Sort of like GLWall::Process in GZDoom +static void HWR_ProcessSeg(void) { FOutVector wallVerts[4]; v2d_t vs, ve; // start, end vertices of 2d line (view from above) @@ -1293,8 +1167,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom float cliplow = (float)gl_curline->offset; float cliphigh = cliplow + (gl_curline->flength * FRACUNIT); - FUINT lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + FUINT lightnum = gl_frontsector->lightlevel; extracolormap_t *colormap = gl_frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); FSurfaceInfo Surf; Surf.PolyColor.s.alpha = 255; @@ -1753,8 +1628,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = rover->master->frontsector->lightlevel; colormap = rover->master->frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -1909,8 +1785,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = rover->master->frontsector->lightlevel; colormap = rover->master->frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -1950,8 +1827,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // // e6y: Check whether the player can look beyond this line // -#ifdef NEWCLIP -boolean checkforemptylines = true; +static boolean checkforemptylines = true; + // Don't modify anything here, just check // Kalaron: Modified for sloped linedefs static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacksector) @@ -2043,295 +1920,6 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks return false; } -#else -//Hurdler: just like in r_bsp.c -#if 1 -#define MAXSEGS MAXVIDWIDTH/2+1 -#else -//Alam_GBC: Or not (may cause overflow) -#define MAXSEGS 128 -#endif - -// hw_newend is one past the last valid seg -static cliprange_t * hw_newend; -static cliprange_t gl_solidsegs[MAXSEGS]; - -// needs fix: walls are incorrectly clipped one column less -static consvar_t cv_glclipwalls = CVAR_INIT ("gr_clipwalls", "Off", 0, CV_OnOff, NULL); - -static void printsolidsegs(void) -{ - cliprange_t * start; - if (!hw_newend) - return; - for (start = gl_solidsegs;start != hw_newend;start++) - { - CONS_Debug(DBG_RENDER, "%d-%d|",start->first,start->last); - } - CONS_Debug(DBG_RENDER, "\n\n"); -} - -// -// -// -static void HWR_ClipSolidWallSegment(INT32 first, INT32 last) -{ - cliprange_t *next, *start; - float lowfrac, highfrac; - boolean poorhack = false; - - // Find the first range that touches the range - // (adjacent pixels are touching). - start = gl_solidsegs; - while (start->last < first-1) - start++; - - if (first < start->first) - { - if (last < start->first-1) - { - // Post is entirely visible (above start), - // so insert a new clippost. - HWR_StoreWallRange(first, last); - - next = hw_newend; - hw_newend++; - - while (next != start) - { - *next = *(next-1); - next--; - } - - next->first = first; - next->last = last; - printsolidsegs(); - return; - } - - // There is a fragment above *start. - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(first, last); - poorhack = true; - } - else - { - highfrac = HWR_ClipViewSegment(start->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2); - HWR_StoreWallRange(0, highfrac); - } - // Now adjust the clip size. - start->first = first; - } - - // Bottom contained in start? - if (last <= start->last) - { - printsolidsegs(); - return; - } - next = start; - while (last >= (next+1)->first-1) - { - // There is a fragment between two posts. - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(first,last); - poorhack = true; - } - else - { - lowfrac = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2); - highfrac = HWR_ClipViewSegment((next+1)->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2); - HWR_StoreWallRange(lowfrac, highfrac); - } - next++; - - if (last <= next->last) - { - // Bottom is contained in next. - // Adjust the clip size. - start->last = next->last; - goto crunch; - } - } - - if (first == next->first+1) // 1 line texture - { - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(first,last); - poorhack = true; - } - else - HWR_StoreWallRange(0, 1); - } - else - { - // There is a fragment after *next. - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(first,last); - poorhack = true; - } - else - { - lowfrac = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2); - HWR_StoreWallRange(lowfrac, 1); - } - } - - // Adjust the clip size. - start->last = last; - - // Remove start+1 to next from the clip list, - // because start now covers their area. -crunch: - if (next == start) - { - printsolidsegs(); - // Post just extended past the bottom of one post. - return; - } - - - while (next++ != hw_newend) - { - // Remove a post. - *++start = *next; - } - - hw_newend = start; - printsolidsegs(); -} - -// -// handle LineDefs with upper and lower texture (windows) -// -static void HWR_ClipPassWallSegment(INT32 first, INT32 last) -{ - cliprange_t *start; - float lowfrac, highfrac; - //to allow noclipwalls but still solidseg reject of non-visible walls - boolean poorhack = false; - - // Find the first range that touches the range - // (adjacent pixels are touching). - start = gl_solidsegs; - while (start->last < first - 1) - start++; - - if (first < start->first) - { - if (last < start->first-1) - { - // Post is entirely visible (above start). - HWR_StoreWallRange(0, 1); - return; - } - - // There is a fragment above *start. - if (!cv_glclipwalls.value) - { //20/08/99: Changed by Hurdler (taken from faB's code) - if (!poorhack) HWR_StoreWallRange(0, 1); - poorhack = true; - } - else - { - highfrac = HWR_ClipViewSegment(min(start->first + 1, - start->last), (polyvertex_t *)gl_curline->pv1, - (polyvertex_t *)gl_curline->pv2); - HWR_StoreWallRange(0, highfrac); - } - } - - // Bottom contained in start? - if (last <= start->last) - return; - - while (last >= (start+1)->first-1) - { - // There is a fragment between two posts. - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(0, 1); - poorhack = true; - } - else - { - lowfrac = HWR_ClipViewSegment(max(start->last-1,start->first), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2); - highfrac = HWR_ClipViewSegment(min((start+1)->first+1,(start+1)->last), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2); - HWR_StoreWallRange(lowfrac, highfrac); - } - start++; - - if (last <= start->last) - return; - } - - if (first == start->first+1) // 1 line texture - { - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(0, 1); - poorhack = true; - } - else - HWR_StoreWallRange(0, 1); - } - else - { - // There is a fragment after *next. - if (!cv_glclipwalls.value) - { - if (!poorhack) HWR_StoreWallRange(0,1); - poorhack = true; - } - else - { - lowfrac = HWR_ClipViewSegment(max(start->last - 1, - start->first), (polyvertex_t *)gl_curline->pv1, - (polyvertex_t *)gl_curline->pv2); - HWR_StoreWallRange(lowfrac, 1); - } - } -} - -// -------------------------------------------------------------------------- -// HWR_ClipToSolidSegs check if it is hide by wall (solidsegs) -// -------------------------------------------------------------------------- -static boolean HWR_ClipToSolidSegs(INT32 first, INT32 last) -{ - cliprange_t * start; - - // Find the first range that touches the range - // (adjacent pixels are touching). - start = gl_solidsegs; - while (start->last < first-1) - start++; - - if (first < start->first) - return true; - - // Bottom contained in start? - if (last <= start->last) - return false; - - return true; -} - -// -// HWR_ClearClipSegs -// -static void HWR_ClearClipSegs(void) -{ - gl_solidsegs[0].first = -0x7fffffff; - gl_solidsegs[0].last = -1; - gl_solidsegs[1].first = vid.width; //viewwidth; - gl_solidsegs[1].last = 0x7fffffff; - hw_newend = gl_solidsegs+2; -} -#endif // NEWCLIP // -----------------+ // HWR_AddLine : Clips the given segment and adds any visible pieces to the line list. @@ -2341,11 +1929,6 @@ static void HWR_ClearClipSegs(void) static void HWR_AddLine(seg_t * line) { angle_t angle1, angle2; -#ifndef NEWCLIP - INT32 x1, x2; - angle_t span, tspan; - boolean bothceilingssky = false, bothfloorssky = false; -#endif // SoM: Backsector needs to be run through R_FakeFlat static sector_t tempsec; @@ -2381,8 +1964,7 @@ static void HWR_AddLine(seg_t * line) angle1 = R_PointToAngle64(v1x, v1y); angle2 = R_PointToAngle64(v2x, v2y); -#ifdef NEWCLIP - // PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle! + // PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle! if (angle2 - angle1 < ANGLE_180) return; @@ -2394,91 +1976,10 @@ static void HWR_AddLine(seg_t * line) } checkforemptylines = true; -#else - // Clip to view edges. - span = angle1 - angle2; - - // backface culling : span is < ANGLE_180 if ang1 > ang2 : the seg is facing - if (span >= ANGLE_180) - return; - - // Global angle needed by segcalc. - //rw_angle1 = angle1; - angle1 -= dup_viewangle; - angle2 -= dup_viewangle; - - tspan = angle1 + gl_clipangle; - if (tspan > 2*gl_clipangle) - { - tspan -= 2*gl_clipangle; - - // Totally off the left edge? - if (tspan >= span) - return; - - angle1 = gl_clipangle; - } - tspan = gl_clipangle - angle2; - if (tspan > 2*gl_clipangle) - { - tspan -= 2*gl_clipangle; - - // Totally off the left edge? - if (tspan >= span) - return; - - angle2 = (angle_t)-(signed)gl_clipangle; - } - -#if 0 - { - float fx1,fx2,fy1,fy2; - //BP: test with a better projection than viewangletox[R_PointToAngle(angle)] - // do not enable this at release 4 mul and 2 div - fx1 = ((polyvertex_t *)(line->pv1))->x-gl_viewx; - fy1 = ((polyvertex_t *)(line->pv1))->y-gl_viewy; - fy2 = (fx1 * gl_viewcos + fy1 * gl_viewsin); - if (fy2 < 0) - // the point is back - fx1 = 0; - else - fx1 = gl_windowcenterx + (fx1 * gl_viewsin - fy1 * gl_viewcos) * gl_centerx / fy2; - - fx2 = ((polyvertex_t *)(line->pv2))->x-gl_viewx; - fy2 = ((polyvertex_t *)(line->pv2))->y-gl_viewy; - fy1 = (fx2 * gl_viewcos + fy2 * gl_viewsin); - if (fy1 < 0) - // the point is back - fx2 = vid.width; - else - fx2 = gl_windowcenterx + (fx2 * gl_viewsin - fy2 * gl_viewcos) * gl_centerx / fy1; - - x1 = fx1+0.5f; - x2 = fx2+0.5f; - } -#else - // The seg is in the view range, - // but not necessarily visible. - angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT; - angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT; - - x1 = gl_viewangletox[angle1]; - x2 = gl_viewangletox[angle2]; -#endif - // Does not cross a pixel? -// if (x1 == x2) -/* { - // BP: HERE IS THE MAIN PROBLEM ! - //CONS_Debug(DBG_RENDER, "tineline\n"); - return; - } -*/ -#endif gl_backsector = line->backsector; bothceilingssky = bothfloorssky = false; -#ifdef NEWCLIP if (!line->backsector) { gld_clipper_SafeAddClipRange(angle2, angle1); @@ -2521,115 +2022,6 @@ static void HWR_AddLine(seg_t * line) } HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D - return; -#else - // Single sided line? - if (!gl_backsector) - goto clipsolid; - - gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true); - - if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum) - bothceilingssky = true; - if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum) - bothfloorssky = true; - - if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then - { - if (!line->polyseg && - !line->sidedef->midtexture - && ((!gl_frontsector->ffloors && !gl_backsector->ffloors) - || Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags))) - return; // line is empty, don't even bother - - goto clippass; // treat like wide open window instead - } - - if (gl_frontsector->f_slope || gl_frontsector->c_slope || gl_backsector->f_slope || gl_backsector->c_slope) - { - fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends - fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends - -#define SLOPEPARAMS(slope, end1, end2, normalheight) \ - end1 = P_GetZAt(slope, v1x, v1y, normalheight); \ - end2 = P_GetZAt(slope, v2x, v2y, normalheight); - - SLOPEPARAMS(gl_frontsector->f_slope, frontf1, frontf2, gl_frontsector-> floorheight) - SLOPEPARAMS(gl_frontsector->c_slope, frontc1, frontc2, gl_frontsector->ceilingheight) - SLOPEPARAMS( gl_backsector->f_slope, backf1, backf2, gl_backsector-> floorheight) - SLOPEPARAMS( gl_backsector->c_slope, backc1, backc2, gl_backsector->ceilingheight) -#undef SLOPEPARAMS - // if both ceilings are skies, consider it always "open" - // same for floors - if (!bothceilingssky && !bothfloorssky) - { - // Closed door. - if ((backc1 <= frontf1 && backc2 <= frontf2) - || (backf1 >= frontc1 && backf2 >= frontc2)) - { - goto clipsolid; - } - - // Check for automap fix. - if (backc1 <= backf1 && backc2 <= backf2 - && ((backc1 >= frontc1 && backc2 >= frontc2) || gl_curline->sidedef->toptexture) - && ((backf1 <= frontf1 && backf2 >= frontf2) || gl_curline->sidedef->bottomtexture)) - goto clipsolid; - } - - // Window. - if (!bothceilingssky) // ceilings are always the "same" when sky - if (backc1 != frontc1 || backc2 != frontc2) - goto clippass; - if (!bothfloorssky) // floors are always the "same" when sky - if (backf1 != frontf1 || backf2 != frontf2) - goto clippass; - } - else - { - // if both ceilings are skies, consider it always "open" - // same for floors - if (!bothceilingssky && !bothfloorssky) - { - // Closed door. - if (gl_backsector->ceilingheight <= gl_frontsector->floorheight || - gl_backsector->floorheight >= gl_frontsector->ceilingheight) - goto clipsolid; - - // Check for automap fix. - if (gl_backsector->ceilingheight <= gl_backsector->floorheight - && ((gl_backsector->ceilingheight >= gl_frontsector->ceilingheight) || gl_curline->sidedef->toptexture) - && ((gl_backsector->floorheight <= gl_backsector->floorheight) || gl_curline->sidedef->bottomtexture)) - goto clipsolid; - } - - // Window. - if (!bothceilingssky) // ceilings are always the "same" when sky - if (gl_backsector->ceilingheight != gl_frontsector->ceilingheight) - goto clippass; - if (!bothfloorssky) // floors are always the "same" when sky - if (gl_backsector->floorheight != gl_frontsector->floorheight) - goto clippass; - } - - // Reject empty lines used for triggers and special events. - // Identical floor and ceiling on both sides, - // identical light levels on both sides, - // and no middle texture. - if (R_IsEmptyLine(gl_curline, gl_frontsector, gl_backsector)) - return; - -clippass: - if (x1 == x2) - { x2++;x1 -= 2; } - HWR_ClipPassWallSegment(x1, x2-1); - return; - -clipsolid: - if (x1 == x2) - goto clippass; - HWR_ClipSolidWallSegment(x1, x2-1); -#endif } // HWR_CheckBBox @@ -2644,23 +2036,19 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord) INT32 boxpos; fixed_t px1, py1, px2, py2; angle_t angle1, angle2; -#ifndef NEWCLIP - INT32 sx1, sx2; - angle_t span, tspan; -#endif // Find the corners of the box // that define the edges from current viewpoint. - if (dup_viewx <= bspcoord[BOXLEFT]) + if (viewx <= bspcoord[BOXLEFT]) boxpos = 0; - else if (dup_viewx < bspcoord[BOXRIGHT]) + else if (viewx < bspcoord[BOXRIGHT]) boxpos = 1; else boxpos = 2; - if (dup_viewy >= bspcoord[BOXTOP]) + if (viewy >= bspcoord[BOXTOP]) boxpos |= 0; - else if (dup_viewy > bspcoord[BOXBOTTOM]) + else if (viewy > bspcoord[BOXBOTTOM]) boxpos |= 1<<2; else boxpos |= 2<<2; @@ -2673,59 +2061,9 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord) px2 = bspcoord[checkcoord[boxpos][2]]; py2 = bspcoord[checkcoord[boxpos][3]]; -#ifdef NEWCLIP angle1 = R_PointToAngle64(px1, py1); angle2 = R_PointToAngle64(px2, py2); return gld_clipper_SafeCheckRange(angle2, angle1); -#else - // check clip list for an open space - angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle; - angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle; - - span = angle1 - angle2; - - // Sitting on a line? - if (span >= ANGLE_180) - return true; - - tspan = angle1 + gl_clipangle; - - if (tspan > 2*gl_clipangle) - { - tspan -= 2*gl_clipangle; - - // Totally off the left edge? - if (tspan >= span) - return false; - - angle1 = gl_clipangle; - } - tspan = gl_clipangle - angle2; - if (tspan > 2*gl_clipangle) - { - tspan -= 2*gl_clipangle; - - // Totally off the left edge? - if (tspan >= span) - return false; - - angle2 = (angle_t)-(signed)gl_clipangle; - } - - // Find the first clippost - // that touches the source post - // (adjacent pixels are touching). - angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT; - angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT; - sx1 = gl_viewangletox[angle1]; - sx2 = gl_viewangletox[angle2]; - - // Does not cross a pixel. - if (sx1 == sx2) - return false; - - return HWR_ClipToSolidSegs(sx1, sx2 - 1); -#endif } // @@ -2754,7 +2092,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, { FSurfaceInfo Surf; FOutVector *v3d; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; size_t nrPlaneVerts = polysector->numVertices; INT32 i; @@ -3065,9 +2403,8 @@ static void HWR_Subsector(size_t num) sub->sector->extra_colormap = gl_frontsector->extra_colormap; // render floor ? -#ifdef DOPLANES // yeah, easy backface cull! :) - if (cullFloorHeight < dup_viewz) + if (cullFloorHeight < viewz) { if (gl_frontsector->floorpic != skyflatnum) { @@ -3081,15 +2418,9 @@ static void HWR_Subsector(size_t num) PF_Occlude, floorlightlevel, &levelflats[gl_frontsector->floorpic], NULL, 255, floorcolormap); } } - else - { -#ifdef POLYSKY - HWR_RenderSkyPlane(&extrasubsectors[num], locFloorHeight); -#endif - } } - if (cullCeilingHeight > dup_viewz) + if (cullCeilingHeight > viewz) { if (gl_frontsector->ceilingpic != skyflatnum) { @@ -3103,21 +2434,12 @@ static void HWR_Subsector(size_t num) PF_Occlude, ceilinglightlevel, &levelflats[gl_frontsector->ceilingpic], NULL, 255, ceilingcolormap); } } - else - { -#ifdef POLYSKY - HWR_RenderSkyPlane(&extrasubsectors[num], locCeilingHeight); -#endif - } } -#ifndef POLYSKY // Moved here because before, when above the ceiling and the floor does not have the sky flat, it doesn't draw the sky if (gl_frontsector->ceilingpic == skyflatnum || gl_frontsector->floorpic == skyflatnum) drawsky = true; -#endif -#ifdef R_FAKEFLOORS if (gl_frontsector->ffloors) { /// \todo fix light, xoffs, yoffs, extracolormap ? @@ -3146,14 +2468,14 @@ static void HWR_Subsector(size_t num) if (centerHeight <= locCeilingHeight && centerHeight >= locFloorHeight && - ((dup_viewz < bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || - (dup_viewz > bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) + ((viewz < bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || + (viewz > bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) { if (rover->fofflags & FOF_FOG) { UINT8 alpha; - light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false); + light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap); HWR_AddTransparentFloor(0, @@ -3166,7 +2488,7 @@ static void HWR_Subsector(size_t num) } else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) // SoM: Flags are more efficient { - light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false); + light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); HWR_AddTransparentFloor(&levelflats[*rover->bottompic], &extrasubsectors[num], @@ -3180,7 +2502,7 @@ static void HWR_Subsector(size_t num) else { HWR_GetLevelFlat(&levelflats[*rover->bottompic]); - light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false); + light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap); } @@ -3191,14 +2513,14 @@ static void HWR_Subsector(size_t num) if (centerHeight >= locFloorHeight && centerHeight <= locCeilingHeight && - ((dup_viewz > topCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || - (dup_viewz < topCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) + ((viewz > topCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || + (viewz < topCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) { if (rover->fofflags & FOF_FOG) { UINT8 alpha; - light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false); + light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap); HWR_AddTransparentFloor(0, @@ -3211,7 +2533,7 @@ static void HWR_Subsector(size_t num) } else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) { - light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false); + light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); HWR_AddTransparentFloor(&levelflats[*rover->toppic], &extrasubsectors[num], @@ -3225,15 +2547,13 @@ static void HWR_Subsector(size_t num) else { HWR_GetLevelFlat(&levelflats[*rover->toppic]); - light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false); + light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap); } } } } -#endif -#endif //doplanes // Draw all the polyobjects in this subsector if (sub->polyList) @@ -3265,10 +2585,10 @@ static void HWR_Subsector(size_t num) } } -// Hurder ici se passe les choses INT32�essantes! -// on vient de tracer le sol et le plafond -// on trace �pr�ent d'abord les sprites et ensuite les murs -// hurdler: faux: on ajoute seulement les sprites, le murs sont trac� d'abord + // Hurdler: here interesting things are happening! + // we have just drawn the floor and ceiling + // we now draw the sprites first and then the walls + // hurdler: false: we only add the sprites, the walls are drawn first if (line) { // draw sprites first, coz they are clipped to the solidsegs of @@ -3300,59 +2620,11 @@ static void HWR_Subsector(size_t num) // traversing subtree recursively. // Just call with BSP root. -#ifdef coolhack -//t;b;l;r -static fixed_t hackbbox[4]; -//BOXTOP, -//BOXBOTTOM, -//BOXLEFT, -//BOXRIGHT -static boolean HWR_CheckHackBBox(fixed_t *bb) -{ - if (bb[BOXTOP] < hackbbox[BOXBOTTOM]) //y up - return false; - if (bb[BOXBOTTOM] > hackbbox[BOXTOP]) - return false; - if (bb[BOXLEFT] > hackbbox[BOXRIGHT]) - return false; - if (bb[BOXRIGHT] < hackbbox[BOXLEFT]) - return false; - return true; -} -#endif - // BP: big hack for a test in lighning ref : 1249753487AB fixed_t *hwbbox; static void HWR_RenderBSPNode(INT32 bspnum) { - /*//GZDoom code - if(bspnum == -1) - { - HWR_Subsector(subsectors); - return; - } - while(!((size_t)bspnum&(~NF_SUBSECTOR))) // Keep going until found a subsector - { - node_t *bsp = &nodes[bspnum]; - - // Decide which side the view point is on - INT32 side = R_PointOnSide(dup_viewx, dup_viewy, bsp); - - // Recursively divide front space (toward the viewer) - HWR_RenderBSPNode(bsp->children[side]); - - // Possibly divide back space (away from viewer) - side ^= 1; - - if (!HWR_CheckBBox(bsp->bbox[side])) - return; - - bspnum = bsp->children[side]; - } - - HWR_Subsector(bspnum-1); -*/ node_t *bsp = &nodes[bspnum]; // Decide which side the view point is on @@ -3376,116 +2648,22 @@ static void HWR_RenderBSPNode(INT32 bspnum) return; } - // Decide which side the view point is on. - side = R_PointOnSide(dup_viewx, dup_viewy, bsp); - - // BP: big hack for a test in lighning ref : 1249753487AB - hwbbox = bsp->bbox[side]; - - // Recursively divide front space. - HWR_RenderBSPNode(bsp->children[side]); - - // Possibly divide back space. - if (HWR_CheckBBox(bsp->bbox[side^1])) - { - // BP: big hack for a test in lighning ref : 1249753487AB - hwbbox = bsp->bbox[side^1]; - HWR_RenderBSPNode(bsp->children[side^1]); - } -} - -/* -// -// Clear 'stack' of subsectors to draw -// -static void HWR_ClearDrawSubsectors(void) -{ - gl_drawsubsector_p = gl_drawsubsectors; -} - -// -// Draw subsectors pushed on the drawsubsectors 'stack', back to front -// -static void HWR_RenderSubsectors(void) -{ - while (gl_drawsubsector_p > gl_drawsubsectors) - { - HWR_RenderBSPNode( - lastsubsec->nextsubsec = bspnum & (~NF_SUBSECTOR); - } -} -*/ - -// ========================================================================== -// FROM R_MAIN.C -// ========================================================================== - -//BP : exactely the same as R_InitTextureMapping -void HWR_InitTextureMapping(void) -{ - angle_t i; - INT32 x; - INT32 t; - fixed_t focallength; - fixed_t grcenterx; - fixed_t grcenterxfrac; - INT32 grviewwidth; - -#define clipanglefov (FIELDOFVIEW>>ANGLETOFINESHIFT) - - grviewwidth = vid.width; - grcenterx = grviewwidth/2; - grcenterxfrac = grcenterx<<FRACBITS; - - // Use tangent table to generate viewangletox: - // viewangletox will give the next greatest x - // after the view angle. - // - // Calc focallength - // so FIELDOFVIEW angles covers SCREENWIDTH. - focallength = FixedDiv(grcenterxfrac, - FINETANGENT(FINEANGLES/4+clipanglefov/2)); - - for (i = 0; i < FINEANGLES/2; i++) - { - if (FINETANGENT(i) > FRACUNIT*2) - t = -1; - else if (FINETANGENT(i) < -FRACUNIT*2) - t = grviewwidth+1; - else - { - t = FixedMul(FINETANGENT(i), focallength); - t = (grcenterxfrac - t+FRACUNIT-1)>>FRACBITS; - - if (t < -1) - t = -1; - else if (t > grviewwidth+1) - t = grviewwidth+1; - } - gl_viewangletox[i] = t; - } - - // Scan viewangletox[] to generate xtoviewangle[]: - // xtoviewangle will give the smallest view angle - // that maps to x. - for (x = 0; x <= grviewwidth; x++) - { - i = 0; - while (gl_viewangletox[i]>x) - i++; - gl_xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90; - } + // Decide which side the view point is on. + side = R_PointOnSide(viewx, viewy, bsp); + + // BP: big hack for a test in lighning ref : 1249753487AB + hwbbox = bsp->bbox[side]; + + // Recursively divide front space. + HWR_RenderBSPNode(bsp->children[side]); - // Take out the fencepost cases from viewangletox. - for (i = 0; i < FINEANGLES/2; i++) + // Possibly divide back space. + if (HWR_CheckBBox(bsp->bbox[side^1])) { - if (gl_viewangletox[i] == -1) - gl_viewangletox[i] = 0; - else if (gl_viewangletox[i] == grviewwidth+1) - gl_viewangletox[i] = grviewwidth; + // BP: big hack for a test in lighning ref : 1249753487AB + hwbbox = bsp->bbox[side^1]; + HWR_RenderBSPNode(bsp->children[side^1]); } - - gl_clipangle = gl_xtoviewangle[0]; } // ========================================================================== @@ -3587,7 +2765,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) float fscale; float fx; float fy; float offset; extracolormap_t *colormap = NULL; FBITFIELD blendmode = PF_Translucent|PF_Modulated; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; UINT8 i; INT32 heightsec, phs; SINT8 flip = P_MobjFlip(thing); @@ -3795,7 +2973,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) boolean lightset = true; FBITFIELD blend = 0; FBITFIELD occlusion; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; boolean use_linkdraw_hack = false; UINT8 alpha; @@ -4366,7 +3544,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) } { - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; FBITFIELD blend = 0; FBITFIELD occlusion; boolean use_linkdraw_hack = false; @@ -4436,11 +3614,10 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) } } -#ifdef HWPRECIP // Sprite drawer for precipitation static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) { - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; FBITFIELD blend = 0; FOutVector wallVerts[4]; patch_t *gpatch; @@ -4537,7 +3714,6 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } -#endif // -------------------------------------------------------------------------- // Sort vissprites by distance @@ -4801,7 +3977,7 @@ static int CompareDrawNodePlanes(const void *p1, const void *p2) size_t n2 = *(const size_t*)p2; if (!sortnode[n1].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n1)"); if (!sortnode[n2].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n2)"); - return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz); + return abs(sortnode[n2].plane->fixedheight - viewz) - abs(sortnode[n1].plane->fixedheight - viewz); } // @@ -4885,7 +4061,6 @@ static void HWR_CreateDrawNodes(void) // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); - HWD.pfnSetShader(SHADER_DEFAULT); for (i = 0; i < p; i++) { @@ -4944,12 +4119,9 @@ static void HWR_DrawSprites(void) gl_vissprite_t *spr = gl_vsprorder[i]; if (spr->bbox) HWR_DrawBoundingBox(spr); - else -#ifdef HWPRECIP - if (spr->precip) + else if (spr->precip) HWR_DrawPrecipitationSprite(spr); else -#endif { if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow) { @@ -5020,9 +4192,7 @@ static UINT8 sectorlight; static void HWR_AddSprites(sector_t *sec) { mobj_t *thing; -#ifdef HWPRECIP precipmobj_t *precipthing; -#endif fixed_t limit_dist, hoop_limit_dist; // BSP is traversed by subsector. @@ -5055,7 +4225,6 @@ static void HWR_AddSprites(sector_t *sec) } } -#ifdef HWPRECIP // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS)) { @@ -5065,7 +4234,6 @@ static void HWR_AddSprites(sector_t *sec) HWR_ProjectPrecipitationSprite(precipthing); } } -#endif } // -------------------------------------------------------------------------- @@ -5118,6 +4286,9 @@ static void HWR_ProjectSprite(mobj_t *thing) // uncapped/interpolation interpmobjstate_t interp = {0}; + if (!cv_renderthings.value) + return; + if (!thing) return; @@ -5562,7 +4733,6 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->angle = interp.angle; } -#ifdef HWPRECIP // Precipitation projector for hardware mode static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) { @@ -5691,7 +4861,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) thing->precipflags |= PCF_THUNK; } } -#endif static void HWR_ProjectBoundingBox(mobj_t *thing) { @@ -5901,41 +5070,18 @@ static void HWR_DrawSkyBackground(player_t *player) if (cv_glskydome.value) { FTransform dometransform; - const float fpov = FixedToFloat(R_GetPlayerFov(player)); - postimg_t *type; - if (splitscreen && player == &players[secondarydisplayplayer]) - type = &postimgtype2; - else - type = &postimgtype; + memcpy(&dometransform, &atransform, sizeof(FTransform)); - memset(&dometransform, 0x00, sizeof(FTransform)); + dometransform.x = 0.0; + dometransform.y = 0.0; + dometransform.z = 0.0; //04/01/2000: Hurdler: added for T&L // It should replace all other gl_viewxxx when finished HWR_SetTransformAiming(&dometransform, player, false); dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - if (*type == postimg_flip) - dometransform.flip = true; - else - dometransform.flip = false; - - dometransform.scalex = 1; - dometransform.scaley = (float)vid.width/vid.height; - dometransform.scalez = 1; - dometransform.fovxangle = fpov; // Tails - dometransform.fovyangle = fpov; // Tails - if (player->viewrollangle != 0) - { - fixed_t rol = AngleFixed(player->viewrollangle); - dometransform.rollangle = FIXED_TO_FLOAT(rol); - dometransform.roll = true; - dometransform.rollx = 1.0f; - dometransform.rollz = 0.0f; - } - dometransform.splitscreen = splitscreen; - HWR_GetTexture(texturetranslation[skytexture]); if (gl_sky.texture != texturetranslation[skytexture]) @@ -5944,7 +5090,8 @@ static void HWR_DrawSkyBackground(player_t *player) HWR_BuildSkyDome(); } - HWD.pfnSetShader(SHADER_SKY); // sky shader + if (HWR_UseShader()) + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_SKY)); HWD.pfnSetTransform(&dometransform); HWD.pfnRenderSkyDome(&gl_sky); } @@ -5981,7 +5128,7 @@ static void HWR_DrawSkyBackground(player_t *player) // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture - angle = (dup_viewangle + gl_xtoviewangle[0]); + angle = (viewangle + xtoviewangle[0]); dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); @@ -6030,8 +5177,6 @@ static void HWR_DrawSkyBackground(player_t *player) HWD.pfnUnSetShader(); HWD.pfnDrawPolygon(NULL, v, 4, 0); } - - HWD.pfnSetShader(SHADER_DEFAULT); } @@ -6047,10 +5192,10 @@ static inline void HWR_ClearView(void) /// \bug faB - enable depth mask, disable color mask - HWD.pfnGClipRect((INT32)gl_viewwindowx, - (INT32)gl_viewwindowy, - (INT32)(gl_viewwindowx + gl_viewwidth), - (INT32)(gl_viewwindowy + gl_viewheight), + HWD.pfnGClipRect((INT32)viewwindowx, + (INT32)viewwindowy, + (INT32)(viewwindowx + viewwidth), + (INT32)(viewwindowy + viewheight), ZCLIP_PLANE); HWD.pfnClearBuffer(false, true, 0); @@ -6065,32 +5210,6 @@ static inline void HWR_ClearView(void) // -----------------+ void HWR_SetViewSize(void) { - // setup view size - gl_viewwidth = (float)vid.width; - gl_viewheight = (float)vid.height; - - if (splitscreen) - gl_viewheight /= 2; - - gl_centerx = gl_viewwidth / 2; - gl_basecentery = gl_viewheight / 2; //note: this is (gl_centerx * gl_viewheight / gl_viewwidth) - - gl_viewwindowx = (vid.width - gl_viewwidth) / 2; - gl_windowcenterx = (float)(vid.width / 2); - if (fabsf(gl_viewwidth - vid.width) < 1.0E-36f) - { - gl_baseviewwindowy = 0; - gl_basewindowcentery = gl_viewheight / 2; // window top left corner at 0,0 - } - else - { - gl_baseviewwindowy = (vid.height-gl_viewheight) / 2; - gl_basewindowcentery = (float)(vid.height / 2); - } - - gl_pspritexscale = gl_viewwidth / BASEVIDWIDTH; - gl_pspriteyscale = ((vid.height*gl_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width; - HWD.pfnFlushScreenTextures(); } @@ -6121,21 +5240,11 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean // static void HWR_SetShaderState(void) { - hwdshaderoption_t state = cv_glshaders.value; - - if (!cv_glallowshaders.value) - state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value); - - HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state); - HWD.pfnSetShader(SHADER_DEFAULT); + HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader()); } -// ========================================================================== -// Same as rendering the player view, but from the skybox object -// ========================================================================== -void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) +static void HWR_SetupView(player_t *player, INT32 viewnumber, float fpov, boolean skybox) { - const float fpov = FixedToFloat(R_GetPlayerFov(player)); postimg_t *type; if (splitscreen && player == &players[secondarydisplayplayer]) @@ -6143,6 +5252,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) else type = &postimgtype; + if (!HWR_ShouldUsePaletteRendering()) { // do we really need to save player (is it not the same)? player_t *saved_player = stplyr; @@ -6151,55 +5261,41 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) stplyr = saved_player; #ifdef ALAM_LIGHTING HWR_SetLights(viewnumber); +#else + (void)viewnumber; #endif } // note: sets viewangle, viewx, viewy, viewz - R_SkyboxFrame(player); - - // copy view cam position for local use - dup_viewx = viewx; - dup_viewy = viewy; - dup_viewz = viewz; - dup_viewangle = viewangle; - - // set window position - gl_centery = gl_basecentery; - gl_viewwindowy = gl_baseviewwindowy; - gl_windowcentery = gl_basewindowcentery; - if (splitscreen && viewnumber == 1) - { - gl_viewwindowy += (vid.height/2); - gl_windowcentery += (vid.height/2); - } - - // check for new console commands. - NetUpdate(); + if (skybox) + R_SkyboxFrame(player); + else + R_SetupFrame(player); - gl_viewx = FIXED_TO_FLOAT(dup_viewx); - gl_viewy = FIXED_TO_FLOAT(dup_viewy); - gl_viewz = FIXED_TO_FLOAT(dup_viewz); - gl_viewsin = FIXED_TO_FLOAT(viewsin); - gl_viewcos = FIXED_TO_FLOAT(viewcos); + gl_viewx = FixedToFloat(viewx); + gl_viewy = FixedToFloat(viewy); + gl_viewz = FixedToFloat(viewz); + gl_viewsin = FixedToFloat(viewsin); + gl_viewcos = FixedToFloat(viewcos); //04/01/2000: Hurdler: added for T&L // It should replace all other gl_viewxxx when finished memset(&atransform, 0x00, sizeof(FTransform)); - HWR_SetTransformAiming(&atransform, player, true); + HWR_SetTransformAiming(&atransform, player, skybox); atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT)); - gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT)); + gl_viewludsin = FixedToFloat(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT)); + gl_viewludcos = FixedToFloat(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT)); if (*type == postimg_flip) atransform.flip = true; else atransform.flip = false; - atransform.x = gl_viewx; // FIXED_TO_FLOAT(viewx) - atransform.y = gl_viewy; // FIXED_TO_FLOAT(viewy) - atransform.z = gl_viewz; // FIXED_TO_FLOAT(viewz) + atransform.x = gl_viewx; + atransform.y = gl_viewy; + atransform.z = gl_viewz; atransform.scalex = 1; atransform.scaley = (float)vid.width/vid.height; atransform.scalez = 1; @@ -6209,7 +5305,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) if (player->viewrollangle != 0) { fixed_t rol = AngleFixed(player->viewrollangle); - atransform.rollangle = FIXED_TO_FLOAT(rol); + atransform.rollangle = FixedToFloat(rol); atransform.roll = true; atransform.rollx = 1.0f; atransform.rollz = 0.0f; @@ -6217,6 +5313,19 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) atransform.splitscreen = splitscreen; gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); +} + +// ========================================================================== +// Same as rendering the player view, but from the skybox object +// ========================================================================== +void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) +{ + const float fpov = FixedToFloat(R_GetPlayerFov(player)); + + HWR_SetupView(player, viewnumber, fpov, true); + + // check for new console commands. + NetUpdate(); //------------------------------------------------------------------------ HWR_ClearView(); @@ -6231,19 +5340,15 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) drawcount = 0; -#ifdef NEWCLIP if (rendermode == render_opengl) { - angle_t a1 = gld_FrustumAngle(gl_aimingangle); + angle_t a1 = gld_FrustumAngle(fpov, gl_aimingangle); gld_clipper_Clear(); gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1); #ifdef HAVE_SPHEREFRUSTRUM gld_FrustrumSetup(); #endif } -#else - HWR_ClearClipSegs(); -#endif //04/01/2000: Hurdler: added for T&L // Actually it only works on Walls and Planes @@ -6308,17 +5413,11 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) { const float fpov = FixedToFloat(R_GetPlayerFov(player)); - postimg_t *type; const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on FRGBAFloat ClearColor; - if (splitscreen && player == &players[secondarydisplayplayer]) - type = &postimgtype2; - else - type = &postimgtype; - ClearColor.red = 0.0f; ClearColor.green = 0.0f; ClearColor.blue = 0.0f; @@ -6335,82 +5434,13 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind PS_STOP_TIMING(ps_hw_skyboxtime); - { - // do we really need to save player (is it not the same)? - player_t *saved_player = stplyr; - stplyr = player; - ST_doPaletteStuff(); - stplyr = saved_player; -#ifdef ALAM_LIGHTING - HWR_SetLights(viewnumber); -#endif - } + HWR_SetupView(player, viewnumber, fpov, false); - // note: sets viewangle, viewx, viewy, viewz - R_SetupFrame(player); framecount++; // timedemo - // copy view cam position for local use - dup_viewx = viewx; - dup_viewy = viewy; - dup_viewz = viewz; - dup_viewangle = viewangle; - - // set window position - gl_centery = gl_basecentery; - gl_viewwindowy = gl_baseviewwindowy; - gl_windowcentery = gl_basewindowcentery; - if (splitscreen && viewnumber == 1) - { - gl_viewwindowy += (vid.height/2); - gl_windowcentery += (vid.height/2); - } - // check for new console commands. NetUpdate(); - gl_viewx = FIXED_TO_FLOAT(dup_viewx); - gl_viewy = FIXED_TO_FLOAT(dup_viewy); - gl_viewz = FIXED_TO_FLOAT(dup_viewz); - gl_viewsin = FIXED_TO_FLOAT(viewsin); - gl_viewcos = FIXED_TO_FLOAT(viewcos); - - //04/01/2000: Hurdler: added for T&L - // It should replace all other gl_viewxxx when finished - memset(&atransform, 0x00, sizeof(FTransform)); - - HWR_SetTransformAiming(&atransform, player, false); - atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - - gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT)); - gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT)); - - if (*type == postimg_flip) - atransform.flip = true; - else - atransform.flip = false; - - atransform.x = gl_viewx; // FIXED_TO_FLOAT(viewx) - atransform.y = gl_viewy; // FIXED_TO_FLOAT(viewy) - atransform.z = gl_viewz; // FIXED_TO_FLOAT(viewz) - atransform.scalex = 1; - atransform.scaley = (float)vid.width/vid.height; - atransform.scalez = 1; - - atransform.fovxangle = fpov; // Tails - atransform.fovyangle = fpov; // Tails - if (player->viewrollangle != 0) - { - fixed_t rol = AngleFixed(player->viewrollangle); - atransform.rollangle = FIXED_TO_FLOAT(rol); - atransform.roll = true; - atransform.rollx = 1.0f; - atransform.rollz = 0.0f; - } - atransform.splitscreen = splitscreen; - - gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); - //------------------------------------------------------------------------ HWR_ClearView(); // Clears the depth buffer and resets the view I believe @@ -6424,19 +5454,15 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) drawcount = 0; -#ifdef NEWCLIP if (rendermode == render_opengl) { - angle_t a1 = gld_FrustumAngle(gl_aimingangle); + angle_t a1 = gld_FrustumAngle(fpov, gl_aimingangle); gld_clipper_Clear(); gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1); #ifdef HAVE_SPHEREFRUSTRUM gld_FrustrumSetup(); #endif } -#else - HWR_ClearClipSegs(); -#endif //04/01/2000: Hurdler: added for T&L // Actually it only works on Walls and Planes @@ -6511,6 +5537,56 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); } +// Returns whether palette rendering is "actually enabled." +// Can't have palette rendering if shaders are disabled. +boolean HWR_ShouldUsePaletteRendering(void) +{ + return (cv_glpaletterendering.value && HWR_UseShader()); +} + +// enable or disable palette rendering state depending on settings and availability +// called when relevant settings change +// shader recompilation is done in the cvar callback +static void HWR_TogglePaletteRendering(void) +{ + // which state should we go to? + if (HWR_ShouldUsePaletteRendering()) + { + // are we not in that state already? + if (!gl_palette_rendering_state) + { + gl_palette_rendering_state = true; + + // The textures will still be converted to RGBA by r_opengl. + // This however makes hw_cache use paletted blending for composite textures! + // (patchformat is not touched) + textureformat = GL_TEXFMT_P_8; + + HWR_SetMapPalette(); + HWR_SetPalette(pLocalPalette); + + // If the r_opengl "texture palette" stays the same during this switch, these textures + // will not be cleared out. However they are still out of date since the + // composite texture blending method has changed. Therefore they need to be cleared. + HWR_LoadMapTextures(numtextures); + } + } + else + { + // are we not in that state already? + if (gl_palette_rendering_state) + { + gl_palette_rendering_state = false; + textureformat = GL_TEXFMT_RGBA; + HWR_SetPalette(pLocalPalette); + // If the r_opengl "texture palette" stays the same during this switch, these textures + // will not be cleared out. However they are still out of date since the + // composite texture blending method has changed. Therefore they need to be cleared. + HWR_LoadMapTextures(numtextures); + } + } +} + void HWR_LoadLevel(void) { #ifdef ALAM_LIGHTING @@ -6524,6 +5600,9 @@ void HWR_LoadLevel(void) HWR_ClearSkyDome(); HWR_BuildSkyDome(); + if (HWR_ShouldUsePaletteRendering()) + HWR_SetMapPalette(); + gl_maploaded = true; } @@ -6531,13 +5610,17 @@ void HWR_LoadLevel(void) // 3D ENGINE COMMANDS // ========================================================================== -static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}}; +static CV_PossibleValue_t glshaders_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Ignore custom shaders"}, {0, NULL}}; static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); +static void CV_glmodellighting_OnChange(void); +static void CV_glpaletterendering_OnChange(void); +static void CV_glpalettedepth_OnChange(void); +static void CV_glshaders_OnChange(void); static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, @@ -6547,7 +5630,7 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA {0, NULL}}; CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; -consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL); +consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE|CV_CALL, glshaders_cons_t, CV_glshaders_OnChange); #ifdef ALAM_LIGHTING consvar_t cv_gldynamiclighting = CVAR_INIT ("gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL); @@ -6558,7 +5641,7 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0 consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL); -consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glmodellighting_OnChange); consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL); consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL); @@ -6573,18 +5656,61 @@ consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL) consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL); +static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}}; + +consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange); +consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange); + +#define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return; consvar_t cv_glwireframe = CVAR_INIT ("gr_wireframe", "Off", 0, CV_OnOff, NULL); static void CV_glfiltermode_OnChange(void) { - if (rendermode == render_opengl) - HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value); + ONLY_IF_GL_LOADED + HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value); } static void CV_glanisotropic_OnChange(void) { - if (rendermode == render_opengl) - HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); + ONLY_IF_GL_LOADED + HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); +} + +static void CV_glmodellighting_OnChange(void) +{ + ONLY_IF_GL_LOADED + // if shaders have been compiled, then they now need to be recompiled. + if (gl_shadersavailable) + HWR_CompileShaders(); +} + +static void CV_glpaletterendering_OnChange(void) +{ + ONLY_IF_GL_LOADED + if (gl_shadersavailable) + { + HWR_CompileShaders(); + HWR_TogglePaletteRendering(); + } +} + +static void CV_glpalettedepth_OnChange(void) +{ + ONLY_IF_GL_LOADED + // refresh the screen palette + if (HWR_ShouldUsePaletteRendering()) + HWR_SetPalette(pLocalPalette); +} + +static void CV_glshaders_OnChange(void) +{ + ONLY_IF_GL_LOADED + HWR_SetShaderState(); + if (cv_glpaletterendering.value) + { + // can't do palette rendering without shaders, so update the state if needed + HWR_TogglePaletteRendering(); + } } //added by Hurdler: console varibale that are saved @@ -6613,11 +5739,9 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glbatching); + CV_RegisterVar(&cv_glpaletterendering); + CV_RegisterVar(&cv_glpalettedepth); CV_RegisterVar(&cv_glwireframe); - -#ifndef NEWCLIP - CV_RegisterVar(&cv_glclipwalls); -#endif } // -------------------------------------------------------------------------- @@ -6629,6 +5753,8 @@ void HWR_Startup(void) { CONS_Printf("HWR_Startup()...\n"); + textureformat = patchformat = GL_TEXFMT_RGBA; + HWR_InitPolyPool(); HWR_InitMapTextures(); HWR_InitModels(); @@ -6636,14 +5762,12 @@ void HWR_Startup(void) HWR_InitLight(); #endif + gl_shadersavailable = HWR_InitShaders(); + HWR_SetShaderState(); HWR_LoadAllCustomShaders(); - if (!HWR_CompileShaders()) - gl_shadersavailable = false; + HWR_TogglePaletteRendering(); } - if (rendermode == render_opengl) - textureformat = patchformat = GL_TEXFMT_RGBA; - gl_init = true; } @@ -6707,6 +5831,9 @@ void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 te { static size_t allocedwalls = 0; + if (!cv_renderwalls.value) + return; + // Force realloc if buffer has been freed if (!wallinfo) allocedwalls = 0; @@ -6733,7 +5860,10 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, FBITFIELD blendmode = blend; UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; + + if (!cv_renderwalls.value) + return; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting HWR_Lighting(pSurf, lightlevel, wallcolormap); @@ -6778,7 +5908,7 @@ void HWR_DoPostProcessor(player_t *player) // Armageddon Blast Flash! // Could this even be considered postprocessor? - if (player->flashcount) + if (player->flashcount && !HWR_ShouldUsePaletteRendering()) { FOutVector v[4]; FSurfaceInfo Surf; @@ -6803,7 +5933,7 @@ void HWR_DoPostProcessor(player_t *player) // Capture the screen for intermission and screen waving if(gamestate != GS_INTERMISSION) - HWD.pfnMakeScreenTexture(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); if (splitscreen) // Not supported in splitscreen - someone want to add support? return; @@ -6847,7 +5977,7 @@ void HWR_DoPostProcessor(player_t *player) // Capture the screen again for screen waving on the intermission if(gamestate != GS_INTERMISSION) - HWD.pfnMakeScreenTexture(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); } // Flipping of the screen isn't done here anymore } @@ -6855,18 +5985,18 @@ void HWR_DoPostProcessor(player_t *player) void HWR_StartScreenWipe(void) { //CONS_Debug(DBG_RENDER, "In HWR_StartScreenWipe()\n"); - HWD.pfnStartScreenWipe(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_START); } void HWR_EndScreenWipe(void) { //CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n"); - HWD.pfnEndScreenWipe(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_END); } void HWR_DrawIntermissionBG(void) { - HWD.pfnDrawIntermissionBG(); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1, NULL, 0); } // @@ -6911,201 +6041,40 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) return; HWR_GetFadeMask(wipelumpnum); - HWD.pfnDoScreenWipe(); -} + if (wipestyle == WIPESTYLE_COLORMAP && HWR_UseShader()) + { + FSurfaceInfo surf = {0}; + FBITFIELD polyflags = PF_Modulated|PF_NoDepthTest; -void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum) -{ - // It does the same thing - HWR_DoWipe(wipenum, scrnnum); + polyflags |= (wipestyleflags & WSF_TOWHITE) ? PF_Additive : PF_ReverseSubtract; + surf.PolyColor.s.red = FADEREDFACTOR; + surf.PolyColor.s.green = FADEGREENFACTOR; + surf.PolyColor.s.blue = FADEBLUEFACTOR; + // polycolor alpha communicates fadein / fadeout to the shader and the backend + surf.PolyColor.s.alpha = (wipestyleflags & WSF_FADEIN) ? 255 : 0; + + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_TINTED_WIPE)); + HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END, + &surf, polyflags); + HWD.pfnUnSetShader(); + } + else + { + HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END, + NULL, 0); + } } void HWR_MakeScreenFinalTexture(void) { - HWD.pfnMakeScreenFinalTexture(); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; + HWD.pfnMakeScreenTexture(tex); } void HWR_DrawScreenFinalTexture(int width, int height) { - HWD.pfnDrawScreenFinalTexture(width, height); -} - -static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum) -{ - UINT16 i; - lumpinfo_t *lump_p; - - lump_p = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++) - if (memcmp(lump_p->name, "SHADERS", 7) == 0) - return i; - - return INT16_MAX; -} - -boolean HWR_CompileShaders(void) -{ - return HWD.pfnCompileShaders(); -} - -customshaderxlat_t shaderxlat[] = -{ - {"Flat", SHADER_FLOOR}, - {"WallTexture", SHADER_WALL}, - {"Sprite", SHADER_SPRITE}, - {"Model", SHADER_MODEL}, - {"ModelLighting", SHADER_MODEL_LIGHTING}, - {"WaterRipple", SHADER_WATER}, - {"Fog", SHADER_FOG}, - {"Sky", SHADER_SKY}, - {NULL, 0}, -}; - -void HWR_LoadAllCustomShaders(void) -{ - INT32 i; - - // read every custom shader - for (i = 0; i < numwadfiles; i++) - HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i])); -} - -void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) -{ - UINT16 lump; - char *shaderdef, *line; - char *stoken; - char *value; - size_t size; - int linenum = 1; - int shadertype = 0; - int i; - - lump = HWR_FindShaderDefs(wadnum); - if (lump == INT16_MAX) - return; - - shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); - size = W_LumpLengthPwad(wadnum, lump); - - line = Z_Malloc(size+1, PU_STATIC, NULL); - M_Memcpy(line, shaderdef, size); - line[size] = '\0'; - - stoken = strtok(line, "\r\n "); - while (stoken) - { - if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#'))// skip comments - { - stoken = strtok(NULL, "\r\n"); - goto skip_field; - } - - if (!stricmp(stoken, "GLSL")) - { - value = strtok(NULL, "\r\n "); - if (!value) - { - CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - stoken = strtok(NULL, "\r\n"); // skip end of line - goto skip_lump; - } - - if (!stricmp(value, "VERTEX")) - shadertype = 1; - else if (!stricmp(value, "FRAGMENT")) - shadertype = 2; - -skip_lump: - stoken = strtok(NULL, "\r\n "); - linenum++; - } - else - { - value = strtok(NULL, "\r\n= "); - if (!value) - { - CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - stoken = strtok(NULL, "\r\n"); // skip end of line - goto skip_field; - } - - if (!shadertype) - { - CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - Z_Free(line); - return; - } - - for (i = 0; shaderxlat[i].type; i++) - { - if (!stricmp(shaderxlat[i].type, stoken)) - { - size_t shader_size; - char *shader_source; - char *shader_lumpname; - UINT16 shader_lumpnum; - - if (PK3) - { - shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL); - strcpy(shader_lumpname, "Shaders/sh_"); - strcat(shader_lumpname, value); - shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0); - } - else - { - shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL); - strcpy(shader_lumpname, "SH_"); - strcat(shader_lumpname, value); - shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0); - } - - if (shader_lumpnum == INT16_MAX) - { - CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum); - Z_Free(shader_lumpname); - continue; - } - - shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum); - shader_source = Z_Malloc(shader_size, PU_STATIC, NULL); - W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source); - - HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2)); - - Z_Free(shader_source); - Z_Free(shader_lumpname); - } - } - -skip_field: - stoken = strtok(NULL, "\r\n= "); - linenum++; - } - } - - Z_Free(line); - return; -} - -const char *HWR_GetShaderName(INT32 shader) -{ - INT32 i; - - if (shader) - { - for (i = 0; shaderxlat[i].type; i++) - { - if (shaderxlat[i].id == shader) - return shaderxlat[i].type; - } - - return "Unknown"; - } - - return "Default"; + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; + HWD.pfnDrawScreenFinalTexture(tex, width, height); } #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 0639bcffeb6446989575bfffb44490433f8473c6..ea610a48b477824fd1d59e45ce70802bce5e460a 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -35,11 +35,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); void HWR_ClearSkyDome(void); void HWR_BuildSkyDome(void); -void HWR_DrawViewBorder(INT32 clearlines); void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum); -void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); -void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option); void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); @@ -48,7 +45,6 @@ void HWR_CreateStaticLightmaps(INT32 bspnum); void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color); void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength); void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor); // Lat: separate flags from color since color needs to be an uint to work right. -void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum); UINT8 *HWR_GetScreenshot(void); boolean HWR_Screenshot(const char *pathname); @@ -61,11 +57,11 @@ void HWR_StartScreenWipe(void); void HWR_EndScreenWipe(void); void HWR_DrawIntermissionBG(void); void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum); -void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum); void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); // This stuff is put here so models can use them +boolean HWR_UseShader(void); void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap); UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work @@ -74,13 +70,7 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 style); FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); -boolean HWR_CompileShaders(void); - -void HWR_LoadAllCustomShaders(void); -void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3); -const char *HWR_GetShaderName(INT32 shader); - -extern customshaderxlat_t shaderxlat[]; +boolean HWR_ShouldUsePaletteRendering(void); extern CV_PossibleValue_t glanisotropicmode_cons_t[]; @@ -103,21 +93,17 @@ extern consvar_t cv_glspritebillboarding; extern consvar_t cv_glskydome; extern consvar_t cv_glfakecontrast; extern consvar_t cv_glslopecontrast; - extern consvar_t cv_glbatching; +extern consvar_t cv_glpaletterendering; +extern consvar_t cv_glpalettedepth; extern consvar_t cv_glwireframe; -extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy; - -extern float gl_viewwindowx, gl_basewindowcentery; - // BP: big hack for a test in lighting ref : 1249753487AB extern fixed_t *hwbbox; extern FTransform atransform; extern float gl_viewsin, gl_viewcos; - // Render stats extern ps_metric_t ps_hw_skyboxtime; extern ps_metric_t ps_hw_nodesorttime; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9797a93312e2df6159f64ef472abe1beb5f2f024..ef0341bd5da7b73b5b9757a06a8eab2df521967f 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -390,8 +390,6 @@ static void md2_loadTexture(md2_t *model) if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { int w = 0, h = 0; - UINT32 size; - RGBA_t *image; #ifdef HAVE_PNG grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); @@ -412,13 +410,19 @@ static void md2_loadTexture(md2_t *model) grPatch->mipmap->width = (UINT16)w; grPatch->mipmap->height = (UINT16)h; - // Lactozilla: Apply colour cube - image = grPatch->mipmap->data; - size = w*h; - while (size--) + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) { - V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); - image++; + UINT32 size; + RGBA_t *image; + // Lactozilla: Apply colour cube + image = grPatch->mipmap->data; + size = w*h; + while (size--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } } } HWD.pfnSetTexture(grPatch->mipmap); @@ -1550,7 +1554,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.flip = atransform.flip; p.mirror = atransform.mirror; - HWD.pfnSetShader(SHADER_MODEL); // model shader + if (HWR_UseShader()) + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_MODEL)); { float this_scale = FIXED_TO_FLOAT(interp.scale); diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c new file mode 100644 index 0000000000000000000000000000000000000000..36cbb5db949c7fae0e28c82b6c0fcb6bd1dd3a73 --- /dev/null +++ b/src/hardware/hw_shaders.c @@ -0,0 +1,636 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2021 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_shaders.c +/// \brief Handles the shaders used by the game. + +#ifdef HWRENDER + +#include "hw_glob.h" +#include "hw_drv.h" +#include "hw_shaders.h" +#include "../z_zone.h" + +// ================ +// Shader sources +// ================ + +static struct { + const char *vertex; + const char *fragment; +} const gl_shadersources[] = { + // Floor shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FLOOR_FRAGMENT_SHADER}, + + // Wall shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, + + // Sprite shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, + + // Model shader + {GLSL_MODEL_VERTEX_SHADER, GLSL_MODEL_FRAGMENT_SHADER}, + + // Water shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER}, + + // Fog shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER}, + + // Sky shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, + + // Palette postprocess shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER}, + + // UI colormap fade shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER}, + + // UI tinted wipe shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_TINTED_WIPE_FRAGMENT_SHADER}, + + {NULL, NULL}, +}; + +typedef struct +{ + int base_shader; // index of base shader_t + int custom_shader; // index of custom shader_t +} shadertarget_t; + +typedef struct +{ + char *vertex; + char *fragment; + boolean compiled; +} shader_t; // these are in an array and accessed by indices + +// the array has NUMSHADERTARGETS entries for base shaders and for custom shaders +// the array could be expanded in the future to fit "dynamic" custom shaders that +// aren't fixed to shader targets +static shader_t gl_shaders[NUMSHADERTARGETS*2]; + +static shadertarget_t gl_shadertargets[NUMSHADERTARGETS]; + +#define WHITESPACE_CHARS " \t" + +#define MODEL_LIGHTING_DEFINE "#define SRB2_MODEL_LIGHTING" +#define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING" + +// Initialize shader variables and the backend's shader system. Load the base shaders. +// Returns false if shaders cannot be used. +boolean HWR_InitShaders(void) +{ + int i; + + if (!HWD.pfnInitShaders()) + return false; + + for (i = 0; i < NUMSHADERTARGETS; i++) + { + // set up string pointers for base shaders + gl_shaders[i].vertex = Z_StrDup(gl_shadersources[i].vertex); + gl_shaders[i].fragment = Z_StrDup(gl_shadersources[i].fragment); + // set shader target indices to correct values + gl_shadertargets[i].base_shader = i; + gl_shadertargets[i].custom_shader = -1; + } + + HWR_CompileShaders(); + + return true; +} + +// helper function: strstr but returns an int with the substring position +// returns INT32_MAX if not found +static INT32 strstr_int(const char *str1, const char *str2) +{ + char *location = strstr(str1, str2); + if (location) + return location - str1; + else + return INT32_MAX; +} + +// Creates a preprocessed copy of the shader according to the current graphics settings +// Returns a pointer to the results on success and NULL on failure. +// Remember memory management of the returned string. +static char *HWR_PreprocessShader(char *original) +{ + const char *line_ending = "\n"; + int line_ending_len; + char *read_pos = original; + int original_len = strlen(original); + int distance_to_end = original_len; + int new_len; + char *new_shader; + char *write_pos; + char shader_glsl_version[3]; + int version_pos = -1; + int version_len = 0; + + if (strstr(original, "\r\n")) + { + line_ending = "\r\n"; + // check if all line endings are same + while ((read_pos = strchr(read_pos, '\n'))) + { + read_pos--; + if (*read_pos != '\r') + { + // this file contains mixed CRLF and LF line endings. + // treating it as a LF file during parsing should keep + // the results sane enough as long as the gpu driver is fine + // with these kinds of weirdly formatted shader sources. + line_ending = "\n"; + break; + } + read_pos += 2; + } + read_pos = original; + } + + line_ending_len = strlen(line_ending); + + // Find the #version directive, if it exists. Also don't get fooled if it's + // inside a comment. Copy the version digits so they can be used in the preamble. + // Time for some string parsing :D + +#define STARTSWITH(str, with_what) !strncmp(str, with_what, sizeof(with_what)-1) +#define ADVANCE(amount) read_pos += (amount); distance_to_end -= (amount); + while (true) + { + // we're at the start of a line or at the end of a block comment. + // first get any possible whitespace out of the way + int whitespace_len = strspn(read_pos, WHITESPACE_CHARS); + if (whitespace_len == distance_to_end) + break; // we got to the end + ADVANCE(whitespace_len) + + if (STARTSWITH(read_pos, "#version")) + { + // found a version directive (and it's not inside a comment) + // now locate, verify and read the version number + int version_number_len; + version_pos = read_pos - original; + ADVANCE(sizeof("#version") - 1) + whitespace_len = strspn(read_pos, WHITESPACE_CHARS); + if (!whitespace_len) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected space after #version, but got other text.\n"); + return NULL; + } + else if (whitespace_len == distance_to_end) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version number, but got end of file.\n"); + return NULL; + } + ADVANCE(whitespace_len) + version_number_len = strspn(read_pos, "0123456789"); + if (!version_number_len) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version number, but got other text.\n"); + return NULL; + } + else if (version_number_len != 3) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version with 3 digits, but got %d digits.\n", version_number_len); + return NULL; + } + M_Memcpy(shader_glsl_version, read_pos, 3); + ADVANCE(version_number_len) + version_len = (read_pos - original) - version_pos; + whitespace_len = strspn(read_pos, WHITESPACE_CHARS); + ADVANCE(whitespace_len) + if (STARTSWITH(read_pos, "es")) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Support for ES shaders is not implemented.\n"); + return NULL; + } + break; + } + else + { + // go to next newline or end of next block comment if it starts before the newline + // and is not inside a line comment + INT32 newline_pos = strstr_int(read_pos, line_ending); + INT32 line_comment_pos; + INT32 block_comment_pos; + // optimization: temporarily put a null at the line ending, so strstr does not needlessly + // look past it since we're only interested in the current line + if (newline_pos != INT32_MAX) + read_pos[newline_pos] = '\0'; + line_comment_pos = strstr_int(read_pos, "//"); + block_comment_pos = strstr_int(read_pos, "/*"); + // restore the line ending, remove the null we just put there + if (newline_pos != INT32_MAX) + read_pos[newline_pos] = line_ending[0]; + if (line_comment_pos < block_comment_pos) + { + // line comment found, skip rest of the line + if (newline_pos != INT32_MAX) + { + ADVANCE(newline_pos + line_ending_len) + } + else + { + // we got to the end + break; + } + } + else if (block_comment_pos < line_comment_pos) + { + // block comment found, skip past it + INT32 block_comment_end; + ADVANCE(block_comment_pos + 2) + block_comment_end = strstr_int(read_pos, "*/"); + if (block_comment_end == INT32_MAX) + { + // could also leave insertion_pos at 0 and let the GLSL compiler + // output an error message for this broken comment + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Encountered unclosed block comment in shader.\n"); + return NULL; + } + ADVANCE(block_comment_end + 2) + } + else if (newline_pos == INT32_MAX) + { + // we got to the end + break; + } + else + { + // nothing special on this line, move to the next one + ADVANCE(newline_pos + line_ending_len) + } + } + } +#undef STARTSWITH +#undef ADVANCE + +#define ADD_TO_LEN(def) new_len += sizeof(def) - 1 + line_ending_len; + + // Calculate length of modified shader. + new_len = original_len; + if (cv_glmodellighting.value) + ADD_TO_LEN(MODEL_LIGHTING_DEFINE) + if (cv_glpaletterendering.value) + ADD_TO_LEN(PALETTE_RENDERING_DEFINE) + +#undef ADD_TO_LEN + +#define VERSION_PART "#version " + + if (new_len != original_len) + { + if (version_pos != -1) + new_len += sizeof(VERSION_PART) - 1 + 3 + line_ending_len; + new_len += sizeof("#line 0") - 1 + line_ending_len; + } + + // Allocate memory for modified shader. + new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL); + + read_pos = original; + write_pos = new_shader; + + if (new_len != original_len && version_pos != -1) + { + strcpy(write_pos, VERSION_PART); + write_pos += sizeof(VERSION_PART) - 1; + M_Memcpy(write_pos, shader_glsl_version, 3); + write_pos += 3; + strcpy(write_pos, line_ending); + write_pos += line_ending_len; + } + +#undef VERSION_PART + +#define WRITE_DEFINE(define) \ + { \ + strcpy(write_pos, define); \ + write_pos += sizeof(define) - 1; \ + strcpy(write_pos, line_ending); \ + write_pos += line_ending_len; \ + } + + // Write the defines. + if (cv_glmodellighting.value) + WRITE_DEFINE(MODEL_LIGHTING_DEFINE) + if (cv_glpaletterendering.value) + WRITE_DEFINE(PALETTE_RENDERING_DEFINE) + +#undef WRITE_DEFINE + + // Write a #line directive, so compiler errors will report line numbers from the + // original shader without our preamble lines. + if (new_len != original_len) + { + // line numbering in the #line directive is different for versions 110-150 + if (version_pos == -1 || shader_glsl_version[0] == '1') + strcpy(write_pos, "#line 0"); + else + strcpy(write_pos, "#line 1"); + write_pos += sizeof("#line 0") - 1; + strcpy(write_pos, line_ending); + write_pos += line_ending_len; + } + + // Copy the original shader. + M_Memcpy(write_pos, read_pos, original_len); + + // Erase the original #version directive, if it exists and was copied. + if (new_len != original_len && version_pos != -1) + memset(write_pos + version_pos, ' ', version_len); + + // Terminate the new string. + new_shader[new_len] = '\0'; + + return new_shader; +} + +// preprocess and compile shader at gl_shaders[index] +static void HWR_CompileShader(int index) +{ + char *vertex_source = gl_shaders[index].vertex; + char *fragment_source = gl_shaders[index].fragment; + + if (vertex_source) + { + char *preprocessed = HWR_PreprocessShader(vertex_source); + if (!preprocessed) return; + HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_VERTEX); + } + if (fragment_source) + { + char *preprocessed = HWR_PreprocessShader(fragment_source); + if (!preprocessed) return; + HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_FRAGMENT); + } + + gl_shaders[index].compiled = HWD.pfnCompileShader(index); +} + +// compile or recompile shaders +void HWR_CompileShaders(void) +{ + int i; + + for (i = 0; i < NUMSHADERTARGETS; i++) + { + int custom_index = gl_shadertargets[i].custom_shader; + HWR_CompileShader(i); + if (!gl_shaders[i].compiled) + CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Compilation failed for base %s shader!\n", shaderxlat[i].type); + if (custom_index != -1) + { + HWR_CompileShader(custom_index); + if (!gl_shaders[custom_index].compiled) + CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Recompilation failed for the custom %s shader! See the console messages above for more information.\n", shaderxlat[i].type); + } + } +} + +int HWR_GetShaderFromTarget(int shader_target) +{ + int custom_shader = gl_shadertargets[shader_target].custom_shader; + // use custom shader if following are true + // - custom shader exists + // - custom shader has been compiled successfully + // - custom shaders are enabled + // - custom shaders are allowed by the server + if (custom_shader != -1 && gl_shaders[custom_shader].compiled && + cv_glshaders.value == 1 && cv_glallowshaders.value) + return custom_shader; + else + return gl_shadertargets[shader_target].base_shader; +} + +static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum) +{ + UINT16 i; + lumpinfo_t *lump_p; + + lump_p = wadfiles[wadnum]->lumpinfo; + for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name, "SHADERS", 7) == 0) + return i; + + return INT16_MAX; +} + +customshaderxlat_t shaderxlat[] = +{ + {"Flat", SHADER_FLOOR}, + {"WallTexture", SHADER_WALL}, + {"Sprite", SHADER_SPRITE}, + {"Model", SHADER_MODEL}, + {"WaterRipple", SHADER_WATER}, + {"Fog", SHADER_FOG}, + {"Sky", SHADER_SKY}, + {"PalettePostprocess", SHADER_PALETTE_POSTPROCESS}, + {"UIColormapFade", SHADER_UI_COLORMAP_FADE}, + {"UITintedWipe", SHADER_UI_TINTED_WIPE}, + {NULL, 0}, +}; + +void HWR_LoadAllCustomShaders(void) +{ + INT32 i; + + // read every custom shader + for (i = 0; i < numwadfiles; i++) + HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i])); +} + +void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) +{ + UINT16 lump; + char *shaderdef, *line; + char *stoken; + char *value; + size_t size; + int linenum = 1; + int shadertype = 0; + int i; + boolean modified_shaders[NUMSHADERTARGETS] = {0}; + + if (!gl_shadersavailable) + return; + + lump = HWR_FindShaderDefs(wadnum); + if (lump == INT16_MAX) + return; + + shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + line = Z_Malloc(size+1, PU_STATIC, NULL); + M_Memcpy(line, shaderdef, size); + line[size] = '\0'; + + stoken = strtok(line, "\r\n "); + while (stoken) + { + if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#'))// skip comments + { + stoken = strtok(NULL, "\r\n"); + goto skip_field; + } + + if (!stricmp(stoken, "GLSL")) + { + value = strtok(NULL, "\r\n "); + if (!value) + { + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + stoken = strtok(NULL, "\r\n"); // skip end of line + goto skip_lump; + } + + if (!stricmp(value, "VERTEX")) + shadertype = 1; + else if (!stricmp(value, "FRAGMENT")) + shadertype = 2; + +skip_lump: + stoken = strtok(NULL, "\r\n "); + linenum++; + } + else + { + value = strtok(NULL, "\r\n= "); + if (!value) + { + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + stoken = strtok(NULL, "\r\n"); // skip end of line + goto skip_field; + } + + if (!shadertype) + { + CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + Z_Free(line); + return; + } + + for (i = 0; shaderxlat[i].type; i++) + { + if (!stricmp(shaderxlat[i].type, stoken)) + { + size_t shader_string_length; + char *shader_source; + char *shader_lumpname; + UINT16 shader_lumpnum; + int shader_index; // index in gl_shaders + + if (PK3) + { + shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL); + strcpy(shader_lumpname, "Shaders/sh_"); + strcat(shader_lumpname, value); + shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0); + } + else + { + shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL); + strcpy(shader_lumpname, "SH_"); + strcat(shader_lumpname, value); + shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0); + } + + if (shader_lumpnum == INT16_MAX) + { + CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum); + Z_Free(shader_lumpname); + continue; + } + + shader_string_length = W_LumpLengthPwad(wadnum, shader_lumpnum) + 1; + shader_source = Z_Malloc(shader_string_length, PU_STATIC, NULL); + W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source); + shader_source[shader_string_length-1] = '\0'; + + shader_index = shaderxlat[i].id + NUMSHADERTARGETS; + if (!modified_shaders[shaderxlat[i].id]) + { + // this will clear any old custom shaders from previously loaded files + // Z_Free checks if the pointer is NULL! + Z_Free(gl_shaders[shader_index].vertex); + gl_shaders[shader_index].vertex = NULL; + Z_Free(gl_shaders[shader_index].fragment); + gl_shaders[shader_index].fragment = NULL; + } + modified_shaders[shaderxlat[i].id] = true; + + if (shadertype == 1) + { + if (gl_shaders[shader_index].vertex) + { + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s vertex shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum); + Z_Free(gl_shaders[shader_index].vertex); + } + gl_shaders[shader_index].vertex = shader_source; + } + else + { + if (gl_shaders[shader_index].fragment) + { + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s fragment shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum); + Z_Free(gl_shaders[shader_index].fragment); + } + gl_shaders[shader_index].fragment = shader_source; + } + + Z_Free(shader_lumpname); + } + } + +skip_field: + stoken = strtok(NULL, "\r\n= "); + linenum++; + } + } + + for (i = 0; i < NUMSHADERTARGETS; i++) + { + if (modified_shaders[i]) + { + int shader_index = i + NUMSHADERTARGETS; // index to gl_shaders + gl_shadertargets[i].custom_shader = shader_index; + // if only one stage (vertex/fragment) is defined, the other one + // is copied from the base shaders. + if (!gl_shaders[shader_index].fragment) + gl_shaders[shader_index].fragment = Z_StrDup(gl_shadersources[i].fragment); + if (!gl_shaders[shader_index].vertex) + gl_shaders[shader_index].vertex = Z_StrDup(gl_shadersources[i].vertex); + HWR_CompileShader(shader_index); + if (!gl_shaders[shader_index].compiled) + CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename); + } + } + + Z_Free(line); + return; +} + +const char *HWR_GetShaderName(INT32 shader) +{ + INT32 i; + + for (i = 0; shaderxlat[i].type; i++) + { + if (shaderxlat[i].id == shader) + return shaderxlat[i].type; + } + + return "Unknown"; +} + +#endif // HWRENDER diff --git a/src/hardware/hw_shaders.h b/src/hardware/hw_shaders.h new file mode 100644 index 0000000000000000000000000000000000000000..bb0e6a232edc45c2a39ac21a9f56beca4c973ebb --- /dev/null +++ b/src/hardware/hw_shaders.h @@ -0,0 +1,424 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2021 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_shaders.h +/// \brief Handles the shaders used by the game. + +#ifndef _HW_SHADERS_H_ +#define _HW_SHADERS_H_ + +#include "../doomtype.h" + +// ================ +// Vertex shaders +// ================ + +// +// Generic vertex shader +// + +#define GLSL_DEFAULT_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// replicates the way fixed function lighting is used by the model lighting option, +// stores the lighting result to gl_Color +// (ambient lighting of 0.75 and diffuse lighting from above) +#define GLSL_MODEL_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "#ifdef SRB2_MODEL_LIGHTING\n" \ + "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ + "float light = min(0.75 + max(nDotVP, 0.0), 1.0);\n" \ + "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ + "#else\n" \ + "gl_FrontColor = gl_Color;\n" \ + "#endif\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// ================== +// Fragment shaders +// ================== + +// +// Generic fragment shader +// + +#define GLSL_DEFAULT_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +// +// Software fragment shader +// + +// Include GLSL_FLOOR_FUDGES or GLSL_WALL_FUDGES or define the fudges in shaders that use this macro. +#define GLSL_DOOM_COLORMAP \ + "float R_DoomColormap(float light, float z)\n" \ + "{\n" \ + "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ + "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ + "float startmap = (15.0 - lightnum) * 4.0;\n" \ + "float scale = 160.0 / (lightz + 1.0);\n" \ + "float cap = (155.0 - light) * 0.26;\n" \ + "return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \ + "}\n" +// lighting cap adjustment: +// first num (155.0), increase to make it start to go dark sooner +// second num (0.26), increase to make it go dark faster + +#define GLSL_DOOM_LIGHT_EQUATION \ + "float R_DoomLightingEquation(float light)\n" \ + "{\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ + "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ + "}\n" + +#define GLSL_SOFTWARE_TINT_EQUATION \ + "if (tint_color.a > 0.0) {\n" \ + "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \ + "float strength = sqrt(tint_color.a);\n" \ + "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \ + "}\n" + +#define GLSL_SOFTWARE_FADE_EQUATION \ + "float darkness = R_DoomLightingEquation(lighting);\n" \ + "if (fade_start != 0.0 || fade_end != 31.0) {\n" \ + "float fs = fade_start / 31.0;\n" \ + "float fe = fade_end / 31.0;\n" \ + "float fd = fe - fs;\n" \ + "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \ + "}\n" \ + "final_color = mix(final_color, fade_color, darkness);\n" + +#define GLSL_PALETTE_RENDERING \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "float light_y = clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0);\n" \ + "vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (light_y + 0.5) / 32.0);\n" \ + "vec4 final_color = texture2D(lighttable_tex, lighttable_coord);\n" \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + +#define GLSL_SOFTWARE_FRAGMENT_SHADER \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ + "#endif\0" + +// hand tuned adjustments for light level calculation +#define GLSL_FLOOR_FUDGES \ + "#define STARTMAP_FUDGE 1.06\n" \ + "#define SCALE_FUDGE 1.15\n" + +#define GLSL_WALL_FUDGES \ + "#define STARTMAP_FUDGE 1.05\n" \ + "#define SCALE_FUDGE 2.2\n" + +#define GLSL_FLOOR_FRAGMENT_SHADER \ + GLSL_FLOOR_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +#define GLSL_WALL_FRAGMENT_SHADER \ + GLSL_WALL_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +// same as above but multiplies results with the lighting value from the +// accompanying vertex shader (stored in gl_Color) if model lighting is enabled +#define GLSL_MODEL_FRAGMENT_SHADER \ + GLSL_WALL_FUDGES \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "#ifdef SRB2_MODEL_LIGHTING\n" \ + "texel *= gl_Color;\n" \ + "#endif\n" \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "#ifdef SRB2_MODEL_LIGHTING\n" \ + "final_color *= gl_Color;\n" \ + "#endif\n" \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ + "#endif\0" + +// +// Water surface shader +// +// Mostly guesstimated, rather than the rest being built off Software science. +// Still needs to distort things underneath/around the water... +// + +#define GLSL_WATER_TEXEL \ + "float water_z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ + "float a = -pi * (water_z * freq) + (leveltime * speed);\n" \ + "float sdistort = sin(a) * amp;\n" \ + "float cdistort = cos(a) * amp;\n" \ + "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" + +#define GLSL_WATER_FRAGMENT_SHADER \ + GLSL_FLOOR_FUDGES \ + "const float freq = 0.025;\n" \ + "const float amp = 0.025;\n" \ + "const float speed = 2.0;\n" \ + "const float pi = 3.14159;\n" \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + "uniform float leveltime;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + GLSL_WATER_TEXEL \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + "uniform float leveltime;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + GLSL_WATER_TEXEL \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ + "#endif\0" + +// +// Fog block shader +// +// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha +// + +// The floor fudges are used, but should the wall fudges be used instead? or something inbetween? +// or separate values for floors and walls? (need to change more than this shader for that) +#define GLSL_FOG_FRAGMENT_SHADER \ + GLSL_FLOOR_FUDGES \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 base_color = gl_Color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Sky fragment shader +// Modulates poly_color with gl_Color +// +#define GLSL_SKY_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ + "}\0" + +// Shader for the palette rendering postprocess step +#define GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler1D palette_tex;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "float palette_coord = (tex_pal_idx + 0.5) / 256.0;\n" \ + "vec4 final_color = texture1D(palette_tex, palette_coord);\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// Applies a palettized colormap fade to tex +#define GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform float lighting;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (lighting + 0.5) / 32.0);\n" \ + "gl_FragColor = texture2D(lighttable_tex, lighttable_coord);\n" \ + "}\0" + +// For wipes that use additive and subtractive blending. +// alpha_factor = 31 * 8 / 10 = 24.8 +// Calculated based on the use of the "fade" variable from the GETCOLOR macro +// in r_data.c:R_CreateFadeColormaps. +// However this value created some ugliness in fades to white (special stage entry) +// while palette rendering is enabled, so I raised the value just a bit. +#define GLSL_UI_TINTED_WIPE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "const float alpha_factor = 24.875;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 final_color = poly_color;\n" \ + "float alpha = texel.a;\n" \ + "if (final_color.a >= 0.5)\n" \ + "alpha = 1.0 - alpha;\n" \ + "alpha *= alpha_factor;\n" \ + "final_color *= alpha;\n" \ + "final_color.a = 1.0;\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Generic vertex shader +// + +#define GLSL_FALLBACK_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// +// Generic fragment shader +// + +#define GLSL_FALLBACK_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +// +// Software fragment shader +// + +#define GLSL_SOFTWARE_FADE_EQUATION \ + "float darkness = R_DoomLightingEquation(lighting);\n" \ + "if (fade_start != 0.0 || fade_end != 31.0) {\n" \ + "float fs = fade_start / 31.0;\n" \ + "float fe = fade_end / 31.0;\n" \ + "float fd = fe - fs;\n" \ + "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \ + "}\n" \ + "final_color = mix(final_color, fade_color, darkness);\n" + +// same as above but multiplies results with the lighting value from the +// accompanying vertex shader (stored in gl_Color) +#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color *= gl_Color;\n" \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Sky fragment shader +// Modulates poly_color with gl_Color +// +#define GLSL_SKY_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ + "}\0" + +#endif diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index ea831e41dee3b7afff7eed47d4ead3f858870648..acd09f614318f433567a5764f2cf453d26315e9d 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -24,6 +24,7 @@ #include "../../r_local.h" // For rendertimefrac, used for the leveltime shader uniform #include "r_opengl.h" #include "r_vbo.h" +#include "../hw_shaders.h" #if defined (HWRENDER) && !defined (NOROPENGL) @@ -35,12 +36,21 @@ struct GLRGBAFloat GLfloat alpha; }; typedef struct GLRGBAFloat GLRGBAFloat; -static const GLubyte white[4] = { 255, 255, 255, 255 }; + +// lighttable list item +struct LTListItem +{ + UINT32 id; + struct LTListItem *next; +}; +typedef struct LTListItem LTListItem; // ========================================================================== // CONSTANTS // ========================================================================== +static const GLubyte white[4] = { 255, 255, 255, 255 }; + // With OpenGL 1.1+, the first texture should be 1 static GLuint NOTEXTURE_NUM = 0; @@ -56,6 +66,7 @@ static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE; static GLuint tex_downloaded = 0; +static GLuint lt_downloaded = 0; // currently bound lighttable texture static GLfloat fov = 90.0f; static FBITFIELD CurrentPolyFlags; @@ -66,7 +77,15 @@ static FTextureInfo *TexCacheHead = NULL; static RGBA_t *textureBuffer = NULL; static size_t textureBufferSize = 0; -RGBA_t myPaletteData[256]; +// Linked list of all lighttables. +static LTListItem *LightTablesTail = NULL; +static LTListItem *LightTablesHead = NULL; + +static RGBA_t screenPalette[256] = {0}; // the palette for the postprocessing step in palette rendering +static GLuint screenPaletteTex = 0; // 1D texture containing the screen palette +static GLuint paletteLookupTex = 0; // 3D texture containing RGB -> palette index lookup table +RGBA_t myPaletteData[256]; // the palette for converting textures to RGBA + GLint screen_width = 0; // used by Draw2DLine() GLint screen_height = 0; GLbyte screen_depth = 0; @@ -91,10 +110,7 @@ static GLint viewport[4]; // flush all of the stored textures, leaving them unavailable at times such as between levels // These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs // can know when the textures aren't there, as textures are always considered resident in their virtual memory -static GLuint screentexture = 0; -static GLuint startScreenWipe = 0; -static GLuint endScreenWipe = 0; -static GLuint finalScreenTexture = 0; +static GLuint screenTextures[NUMSCREENTEXTURES] = {0}; // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { @@ -378,10 +394,14 @@ typedef void (APIENTRY * PFNglTexEnvi) (GLenum target, GLenum pname, GLint param static PFNglTexEnvi pglTexEnvi; typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param); static PFNglTexParameteri pglTexParameteri; +typedef void (APIENTRY * PFNglTexImage1D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static PFNglTexImage1D pglTexImage1D; typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); static PFNglTexImage2D pglTexImage2D; typedef void (APIENTRY * PFNglTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); static PFNglTexSubImage2D pglTexSubImage2D; +typedef void (APIENTRY * PFNglGetTexImage) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +static PFNglGetTexImage pglGetTexImage; /* 1.1 functions */ /* texture objects */ //GL_EXT_texture_object @@ -401,6 +421,10 @@ static PFNglCopyTexSubImage2D pglCopyTexSubImage2D; typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; +/* 1.2 functions for 3D textures */ +typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static PFNglTexImage3D pglTexImage3D; + /* 1.3 functions for multitexturing */ typedef void (APIENTRY *PFNglActiveTexture) (GLenum); static PFNglActiveTexture pglActiveTexture; @@ -445,6 +469,9 @@ static PFNglBlendEquation pglBlendEquation; #ifndef GL_TEXTURE1 #define GL_TEXTURE1 0x84C1 #endif +#ifndef GL_TEXTURE2 +#define GL_TEXTURE2 0x84C2 +#endif /* 1.5 Parms */ #ifndef GL_ARRAY_BUFFER @@ -517,8 +544,10 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexEnvi, glTexEnvi) GETOPENGLFUNC(pglTexParameteri, glTexParameteri) + GETOPENGLFUNC(pglTexImage1D, glTexImage1D) GETOPENGLFUNC(pglTexImage2D, glTexImage2D) GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) + GETOPENGLFUNC(pglGetTexImage, glGetTexImage) GETOPENGLFUNC(pglGenTextures, glGenTextures) GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures) @@ -534,7 +563,7 @@ boolean SetupGLfunc(void) } static boolean gl_shadersenabled = false; -static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF; +static INT32 gl_allowshaders = 0; #ifdef GL_SHADERS typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum); @@ -592,7 +621,12 @@ typedef enum gluniform_fade_start, gluniform_fade_end, - // misc. (custom shaders) + // palette rendering + gluniform_palette_tex, // 1d texture containing a palette + gluniform_palette_lookup_tex, // 3d texture containing the rgb->index lookup table + gluniform_lighttable_tex, // 2d texture containing a light table + + // misc. gluniform_leveltime, gluniform_max, @@ -600,14 +634,15 @@ typedef enum typedef struct gl_shader_s { + char *vertex_shader; + char *fragment_shader; GLuint program; GLint uniforms[gluniform_max+1]; - boolean custom; } gl_shader_t; static gl_shader_t gl_shaders[HWR_MAXSHADERS]; -static gl_shader_t gl_usershaders[HWR_MAXSHADERS]; -static shadersource_t gl_customshaders[HWR_MAXSHADERS]; + +static gl_shader_t gl_fallback_shader; // 09102020 typedef struct gl_shaderstate_s @@ -623,253 +658,19 @@ static gl_shaderstate_t gl_shaderstate; static float shader_leveltime = 0; // Lactozilla: Shader functions -static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader); +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i); static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; -// ================ -// Vertex shaders -// ================ - -// -// Generic vertex shader -// - -#define GLSL_DEFAULT_VERTEX_SHADER \ - "void main()\n" \ - "{\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ - "gl_FrontColor = gl_Color;\n" \ - "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ - "}\0" - -// replicates the way fixed function lighting is used by the model lighting option, -// stores the lighting result to gl_Color -// (ambient lighting of 0.75 and diffuse lighting from above) -#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \ - "void main()\n" \ - "{\n" \ - "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ - "float light = 0.75 + max(nDotVP, 0.0);\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ - "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ - "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ - "}\0" - -// ================== -// Fragment shaders -// ================== - -// -// Generic fragment shader -// - -#define GLSL_DEFAULT_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "void main(void) {\n" \ - "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ - "}\0" - -// -// Software fragment shader -// - -#define GLSL_DOOM_COLORMAP \ - "float R_DoomColormap(float light, float z)\n" \ - "{\n" \ - "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ - "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ - "float startmap = (15.0 - lightnum) * 4.0;\n" \ - "float scale = 160.0 / (lightz + 1.0);\n" \ - "return startmap - scale * 0.5;\n" \ - "}\n" - -#define GLSL_DOOM_LIGHT_EQUATION \ - "float R_DoomLightingEquation(float light)\n" \ - "{\n" \ - "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ - "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ - "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ - "}\n" - -#define GLSL_SOFTWARE_TINT_EQUATION \ - "if (tint_color.a > 0.0) {\n" \ - "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \ - "float strength = sqrt(tint_color.a);\n" \ - "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \ - "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \ - "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \ - "}\n" - -#define GLSL_SOFTWARE_FADE_EQUATION \ - "float darkness = R_DoomLightingEquation(lighting);\n" \ - "if (fade_start != 0.0 || fade_end != 31.0) {\n" \ - "float fs = fade_start / 31.0;\n" \ - "float fe = fade_end / 31.0;\n" \ - "float fd = fe - fs;\n" \ - "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \ - "}\n" \ - "final_color = mix(final_color, fade_color, darkness);\n" - -#define GLSL_SOFTWARE_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color.a = texel.a * poly_color.a;\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// same as above but multiplies results with the lighting value from the -// accompanying vertex shader (stored in gl_Color) -#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color *= gl_Color;\n" \ - "final_color.a = texel.a * poly_color.a;\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Water surface shader -// -// Mostly guesstimated, rather than the rest being built off Software science. -// Still needs to distort things underneath/around the water... -// - -#define GLSL_WATER_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - "uniform float leveltime;\n" \ - "const float freq = 0.025;\n" \ - "const float amp = 0.025;\n" \ - "const float speed = 2.0;\n" \ - "const float pi = 3.14159;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ - "float a = -pi * (z * freq) + (leveltime * speed);\n" \ - "float sdistort = sin(a) * amp;\n" \ - "float cdistort = cos(a) * amp;\n" \ - "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color.a = texel.a * poly_color.a;\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Fog block shader -// -// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha -// - -#define GLSL_FOG_FRAGMENT_SHADER \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 base_color = gl_Color;\n" \ - "vec4 final_color = base_color;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Sky fragment shader -// Modulates poly_color with gl_Color -// -#define GLSL_SKY_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "void main(void) {\n" \ - "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ - "}\0" - -// ================ -// Shader sources -// ================ - -static struct { - const char *vertex; - const char *fragment; -} const gl_shadersources[] = { - // Default shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_DEFAULT_FRAGMENT_SHADER}, - - // Floor shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Wall shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Sprite shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Model shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Model shader + diffuse lighting from above - {GLSL_MODEL_LIGHTING_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER}, - - // Water shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER}, - - // Fog shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER}, - - // Sky shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, - - {NULL, NULL}, -}; - #endif // GL_SHADERS void SetupGLFunc4(void) { + /* 1.2 funcs */ + pglTexImage3D = GetGLFunc("glTexImage3D"); + /* 1.3 funcs */ pglActiveTexture = GetGLFunc("glActiveTexture"); pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); pglClientActiveTexture = GetGLFunc("glClientActiveTexture"); @@ -912,59 +713,75 @@ void SetupGLFunc4(void) pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps"); } -EXPORT boolean HWRAPI(CompileShaders) (void) +EXPORT boolean HWRAPI(InitShaders) (void) { #ifdef GL_SHADERS - GLint i; - if (!pglUseProgram) return false; + + gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER); + gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER); - gl_customshaders[SHADER_DEFAULT].vertex = NULL; - gl_customshaders[SHADER_DEFAULT].fragment = NULL; - - for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++) + if (!Shader_CompileProgram(&gl_fallback_shader, -1)) { - gl_shader_t *shader, *usershader; - const GLchar *vert_shader = gl_shadersources[i].vertex; - const GLchar *frag_shader = gl_shadersources[i].fragment; + GL_MSG_Error("Failed to compile the fallback shader program!\n"); + return false; + } - if (i >= HWR_MAXSHADERS) - break; + return true; +#else + return false; +#endif +} - shader = &gl_shaders[i]; - usershader = &gl_usershaders[i]; +EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage) +{ +#ifdef GL_SHADERS + gl_shader_t *shader; - if (shader->program) - pglDeleteProgram(shader->program); - if (usershader->program) - pglDeleteProgram(usershader->program); + if (slot < 0 || slot >= HWR_MAXSHADERS) + I_Error("LoadShader: Invalid slot %d", slot); - shader->program = 0; - usershader->program = 0; + shader = &gl_shaders[slot]; - if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader)) - shader->program = 0; +#define LOADSHADER(source) { \ + if (shader->source) \ + Z_Free(shader->source); \ + shader->source = code; \ + } - // Compile custom shader - if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment)) - continue; + if (stage == HWD_SHADERSTAGE_VERTEX) + LOADSHADER(vertex_shader) + else if (stage == HWD_SHADERSTAGE_FRAGMENT) + LOADSHADER(fragment_shader) + else + I_Error("LoadShader: invalid shader stage"); - // 18032019 - if (gl_customshaders[i].vertex) - vert_shader = gl_customshaders[i].vertex; - if (gl_customshaders[i].fragment) - frag_shader = gl_customshaders[i].fragment; +#undef LOADSHADER +#else + (void)slot; + (void)code; + (void)stage; +#endif +} - if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader)) - { - GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i)); - usershader->program = 0; - } - } +EXPORT boolean HWRAPI(CompileShader) (int slot) +{ +#ifdef GL_SHADERS + if (slot < 0 || slot >= HWR_MAXSHADERS) + I_Error("CompileShader: Invalid slot %d", slot); - return true; + if (Shader_CompileProgram(&gl_shaders[slot], slot)) + { + return true; + } + else + { + gl_shaders[slot].program = 0; + return false; + } #else + (void)slot; return false; #endif } @@ -991,90 +808,36 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) #endif } -// -// Custom shader loading -// -EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment) +EXPORT void HWRAPI(SetShader) (int slot) { #ifdef GL_SHADERS - shadersource_t *shader; - - if (!pglUseProgram) - return; - - if (number < 1 || number > HWR_MAXSHADERS) - I_Error("LoadCustomShader: cannot load shader %d (min 1, max %d)", number, HWR_MAXSHADERS); - else if (code == NULL) - I_Error("LoadCustomShader: empty shader"); - - shader = &gl_customshaders[number]; - -#define COPYSHADER(source) { \ - if (shader->source) \ - free(shader->source); \ - shader->source = malloc(size+1); \ - strncpy(shader->source, code, size); \ - shader->source[size] = 0; \ - } - - if (isfragment) - COPYSHADER(fragment) - else - COPYSHADER(vertex) - -#else - (void)number; - (void)shader; - (void)size; - (void)fragment; -#endif -} - -EXPORT void HWRAPI(SetShader) (int type) -{ -#ifdef GL_SHADERS - if (type == SHADER_NONE) + if (slot == SHADER_NONE) { UnSetShader(); return; } - - if (gl_allowshaders != HWD_SHADEROPTION_OFF) + if (gl_allowshaders) { - gl_shader_t *shader = gl_shaderstate.current; + gl_shader_t *next_shader = &gl_shaders[slot]; // the gl_shader_t we are going to switch to - // If using model lighting, set the appropriate shader. - // However don't override a custom shader. - if (type == SHADER_MODEL && model_lighting - && !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom)) - type = SHADER_MODEL_LIGHTING; + if (!next_shader->program) + next_shader = &gl_fallback_shader; // unusable shader, use fallback instead - if ((shader == NULL) || (GLuint)type != gl_shaderstate.type) + // update gl_shaderstate if an actual shader switch is needed + if (gl_shaderstate.current != next_shader) { - gl_shader_t *baseshader = &gl_shaders[type]; - gl_shader_t *usershader = &gl_usershaders[type]; - - if (usershader->program) - shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader; - else - shader = baseshader; - - gl_shaderstate.current = shader; - gl_shaderstate.type = type; + gl_shaderstate.current = next_shader; + gl_shaderstate.program = next_shader->program; + gl_shaderstate.type = slot; gl_shaderstate.changed = true; } - if (gl_shaderstate.program != shader->program) - { - gl_shaderstate.program = shader->program; - gl_shaderstate.changed = true; - } + gl_shadersenabled = true; - gl_shadersenabled = (shader->program != 0); return; } #else - (void)type; + (void)slot; #endif gl_shadersenabled = false; } @@ -1082,36 +845,20 @@ EXPORT void HWRAPI(SetShader) (int type) EXPORT void HWRAPI(UnSetShader) (void) { #ifdef GL_SHADERS - gl_shaderstate.current = NULL; - gl_shaderstate.type = 0; - gl_shaderstate.program = 0; + if (gl_shadersenabled) // don't repeatedly call glUseProgram if not needed + { + gl_shaderstate.current = NULL; + gl_shaderstate.type = 0; + gl_shaderstate.program = 0; - if (pglUseProgram) - pglUseProgram(0); + if (pglUseProgram) + pglUseProgram(0); + } #endif gl_shadersenabled = false; } -EXPORT void HWRAPI(CleanShaders) (void) -{ - INT32 i; - - for (i = 1; i < HWR_MAXSHADERS; i++) - { - shadersource_t *shader = &gl_customshaders[i]; - - if (shader->vertex) - free(shader->vertex); - - if (shader->fragment) - free(shader->fragment); - - shader->vertex = NULL; - shader->fragment = NULL; - } -} - // -----------------+ // SetNoTexture : Disable texture // -----------------+ @@ -1407,55 +1154,38 @@ EXPORT void HWRAPI(ClearMipMapCache) (void) } -// -----------------+ -// ReadRect : Read a rectangle region of the truecolor framebuffer -// : store pixels as 16bit 565 RGB -// Returns : 16bit 565 RGB pixel array stored in dst_data -// -----------------+ -EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, - INT32 dst_stride, UINT16 * dst_data) +// Writes screen texture tex into dst_data. +// Pixel format is 24-bit RGB. Row order is top to bottom. +// Dimensions are screen_width * screen_height. +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data) { INT32 i; - // GL_DBG_Printf ("ReadRect()\n"); - if (dst_stride == width*3) - { - GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1); - GLubyte *row = malloc(dst_stride); - if (!row) return; - pglPixelStorei(GL_PACK_ALIGNMENT, 1); - pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); - pglPixelStorei(GL_UNPACK_ALIGNMENT, 1); - for(i = 0; i < height/2; i++) - { - memcpy(row, top, dst_stride); - memcpy(top, bottom, dst_stride); - memcpy(bottom, row, dst_stride); - top += dst_stride; - bottom -= dst_stride; - } - free(row); - } - else - { - INT32 j; - GLubyte *image = malloc(width*height*3*sizeof (*image)); - if (!image) return; - pglPixelStorei(GL_PACK_ALIGNMENT, 1); - pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); - pglPixelStorei(GL_UNPACK_ALIGNMENT, 1); - for (i = height-1; i >= 0; i--) - { - for (j = 0; j < width; j++) - { - dst_data[(height-1-i)*width+j] = - (UINT16)( - ((image[(i*width+j)*3]>>3)<<11) | - ((image[(i*width+j)*3+1]>>2)<<5) | - ((image[(i*width+j)*3+2]>>3))); - } - } - free(image); - } + int dst_stride = screen_width * 3; // stride between rows of image data + GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (screen_height - 1); + GLubyte *row; + row = malloc(dst_stride); + if (!row) return; + // at the time this function is called, generic2 can be found drawn on the framebuffer + // if some other screen texture is needed, draw it to the framebuffer + // and draw generic2 back after reading the framebuffer. + // this hack is for some reason **much** faster than the simple solution of using glGetTexImage. + if (tex != HWD_SCREENTEXTURE_GENERIC2) + DrawScreenTexture(tex, NULL, 0); + pglPixelStorei(GL_PACK_ALIGNMENT, 1); + pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); + if (tex != HWD_SCREENTEXTURE_GENERIC2) + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); + // Flip image upside down. + // In other words, convert OpenGL's "bottom->top" row order into "top->bottom". + for(i = 0; i < screen_height/2; i++) + { + memcpy(row, top, dst_stride); + memcpy(top, bottom, dst_stride); + memcpy(bottom, row, dst_stride); + top += dst_stride; + bottom -= dst_stride; + } + free(row); } @@ -2071,69 +1801,91 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } -static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader) +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) { - GLuint gl_vertShader, gl_fragShader; + GLuint gl_vertShader = 0; + GLuint gl_fragShader = 0; GLint result; + const GLchar *vert_shader = shader->vertex_shader; + const GLchar *frag_shader = shader->fragment_shader; - // - // Load and compile vertex shader - // - gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); - if (!gl_vertShader) + if (shader->program) + pglDeleteProgram(shader->program); + + if (!vert_shader && !frag_shader) { - GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + GL_MSG_Error("Shader_CompileProgram: Missing shaders for shader program %s\n", HWR_GetShaderName(i)); return false; } - pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); - pglCompileShader(gl_vertShader); - - // check for compile errors - pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) + if (vert_shader) { - Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); - pglDeleteShader(gl_vertShader); - return false; + // + // Load and compile vertex shader + // + gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); + if (!gl_vertShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + return false; + } + + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); + + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); + pglDeleteShader(gl_vertShader); + return false; + } } - // - // Load and compile fragment shader - // - gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); - if (!gl_fragShader) + if (frag_shader) { - GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); - return false; - } + // + // Load and compile fragment shader + // + gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } - pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); - pglCompileShader(gl_fragShader); + pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); + pglCompileShader(gl_fragShader); - // check for compile errors - pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); - return false; + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } } shader->program = pglCreateProgram(); - pglAttachShader(shader->program, gl_vertShader); - pglAttachShader(shader->program, gl_fragShader); + if (vert_shader) + pglAttachShader(shader->program, gl_vertShader); + if (frag_shader) + pglAttachShader(shader->program, gl_fragShader); pglLinkProgram(shader->program); // check link status pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); // delete the shader objects - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); + if (vert_shader) + pglDeleteShader(gl_vertShader); + if (frag_shader) + pglDeleteShader(gl_fragShader); // couldn't link? if (result != GL_TRUE) @@ -2154,11 +1906,31 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - // misc. (custom shaders) - shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + // palette rendering + shader->uniforms[gluniform_palette_tex] = GETUNI("palette_tex"); + shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex"); + shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); + // misc. + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); #undef GETUNI + // set permanent uniform values +#define UNIFORM_1(uniform, a, function) \ + if (uniform != -1) \ + function (uniform, a); + + pglUseProgram(shader->program); + + // texture unit numbers for the samplers used for palette rendering + UNIFORM_1(shader->uniforms[gluniform_palette_tex], 2, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_palette_lookup_tex], 1, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 2, pglUniform1i); + + // restore gl shader state + pglUseProgram(gl_shaderstate.program); +#undef UNIFORM_1 + return true; } @@ -2182,6 +1954,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade } // code that is common between DrawPolygon and DrawIndexedTriangles +// DrawScreenTexture also can use this function for fancier screen texture drawing // the corona thing is there too, i have no idea if that stuff works with DrawIndexedTriangles and batching static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD PolyFlags) { @@ -2221,6 +1994,14 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD fade.green = byte2float[pSurf->FadeColor.s.green]; fade.blue = byte2float[pSurf->FadeColor.s.blue]; fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; + + if (pSurf->LightTableId && pSurf->LightTableId != lt_downloaded) + { + pglActiveTexture(GL_TEXTURE2); + pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId); + pglActiveTexture(GL_TEXTURE0); + lt_downloaded = pSurf->LightTableId; + } } } @@ -2413,9 +2194,6 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) pglDisableClientState(GL_COLOR_ARRAY); } -// ========================================================================== -// -// ========================================================================== EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) { switch (IdState) @@ -2425,7 +2203,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) break; case HWD_SET_SHADERS: - gl_allowshaders = (hwdshaderoption_t)Value; + gl_allowshaders = Value; break; case HWD_SET_TEXTUREFILTERMODE: @@ -2784,6 +2562,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float else if (Surface->PolyColor.s.alpha == 0xFF) flags |= (PF_Occlude | PF_Masked); + if (Surface->LightTableId && Surface->LightTableId != lt_downloaded) + { + pglActiveTexture(GL_TEXTURE2); + pglBindTexture(GL_TEXTURE_2D, Surface->LightTableId); + pglActiveTexture(GL_TEXTURE0); + lt_downloaded = Surface->LightTableId; + } + SetBlend(flags); Shader_SetUniforms(Surface, &poly, &tint, &fade); @@ -3071,7 +2857,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) INT32 x, y; float float_x, float_y, float_nextx, float_nexty; float xfix, yfix; - INT32 texsize = 2048; + INT32 texsize = 512; const float blackBack[16] = { @@ -3081,11 +2867,9 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) 16.0f, -16.0f, 6.0f }; - // Use a power of two texture, dammit - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; // X/Y stretch fix for all resolutions(!) xfix = (float)(texsize)/((float)((screen_width)/(float)(SCREENVERTS-1))); @@ -3159,84 +2943,16 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) // a new size EXPORT void HWRAPI(FlushScreenTextures) (void) { - pglDeleteTextures(1, &screentexture); - pglDeleteTextures(1, &startScreenWipe); - pglDeleteTextures(1, &endScreenWipe); - pglDeleteTextures(1, &finalScreenTexture); - screentexture = 0; - startScreenWipe = 0; - endScreenWipe = 0; - finalScreenTexture = 0; -} - -// Create Screen to fade from -EXPORT void HWRAPI(StartScreenWipe) (void) -{ - INT32 texsize = 2048; - boolean firstTime = (startScreenWipe == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &startScreenWipe); - pglBindTexture(GL_TEXTURE_2D, startScreenWipe); - - if (firstTime) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); - } - else - pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - - tex_downloaded = startScreenWipe; + int i; + pglDeleteTextures(NUMSCREENTEXTURES, screenTextures); + for (i = 0; i < NUMSCREENTEXTURES; i++) + screenTextures[i] = 0; } -// Create Screen to fade to -EXPORT void HWRAPI(EndScreenWipe)(void) -{ - INT32 texsize = 2048; - boolean firstTime = (endScreenWipe == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &endScreenWipe); - pglBindTexture(GL_TEXTURE_2D, endScreenWipe); - - if (firstTime) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); - } - else - pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - - tex_downloaded = endScreenWipe; -} - - -// Draw the last scene under the intermission -EXPORT void HWRAPI(DrawIntermissionBG)(void) +EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD polyflags) { float xfix, yfix; - INT32 texsize = 2048; + INT32 texsize = 512; const float screenVerts[12] = { @@ -3248,10 +2964,9 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) float fix[8]; - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); @@ -3270,20 +2985,23 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - pglBindTexture(GL_TEXTURE_2D, screentexture); - pglColor4ubv(white); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); + PreparePolygon(surf, NULL, surf ? polyflags : (PF_NoDepthTest)); + if (!surf) + pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - tex_downloaded = screentexture; + tex_downloaded = screenTextures[tex]; } // Do screen fades! -EXPORT void HWRAPI(DoScreenWipe)(void) +EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd, FSurfaceInfo *surf, + FBITFIELD polyFlags) { - INT32 texsize = 2048; + INT32 texsize = 512; float xfix, yfix; INT32 fademaskdownloaded = tex_downloaded; // the fade mask that has been set @@ -3306,11 +3024,15 @@ EXPORT void HWRAPI(DoScreenWipe)(void) 1.0f, 1.0f }; - // Use a power of two texture, dammit - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + int firstScreen; + if (surf && surf->PolyColor.s.alpha == 255) + firstScreen = wipeEnd; // it's a tinted fade-in, we need wipeEnd + else + firstScreen = wipeStart; + + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); @@ -3332,91 +3054,71 @@ EXPORT void HWRAPI(DoScreenWipe)(void) SetBlend(PF_Modulated|PF_NoDepthTest); pglEnable(GL_TEXTURE_2D); - // Draw the original screen - pglBindTexture(GL_TEXTURE_2D, startScreenWipe); + pglBindTexture(GL_TEXTURE_2D, screenTextures[firstScreen]); pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); + if (surf) + { + // Draw fade mask to screen using surf and polyFlags + // Used for colormap/tinted wipes. + pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded); + pglTexCoordPointer(2, GL_FLOAT, 0, defaultST); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + PreparePolygon(surf, NULL, polyFlags); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + else // Blend wipeEnd into screen with the fade mask + { + SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); - // Draw the end screen that fades in - pglActiveTexture(GL_TEXTURE0); - pglEnable(GL_TEXTURE_2D); - pglBindTexture(GL_TEXTURE_2D, endScreenWipe); - pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + // Draw the end screen that fades in + pglActiveTexture(GL_TEXTURE0); + pglEnable(GL_TEXTURE_2D); + pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeEnd]); + pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - pglActiveTexture(GL_TEXTURE1); - pglEnable(GL_TEXTURE_2D); - pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded); + pglActiveTexture(GL_TEXTURE1); + pglEnable(GL_TEXTURE_2D); + pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded); - pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - // const float defaultST[8] + // const float defaultST[8] - pglClientActiveTexture(GL_TEXTURE0); - pglTexCoordPointer(2, GL_FLOAT, 0, fix); - pglVertexPointer(3, GL_FLOAT, 0, screenVerts); - pglClientActiveTexture(GL_TEXTURE1); - pglEnableClientState(GL_TEXTURE_COORD_ARRAY); - pglTexCoordPointer(2, GL_FLOAT, 0, defaultST); - pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + pglClientActiveTexture(GL_TEXTURE0); + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglClientActiveTexture(GL_TEXTURE1); + pglEnableClientState(GL_TEXTURE_COORD_ARRAY); + pglTexCoordPointer(2, GL_FLOAT, 0, defaultST); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit - pglDisableClientState(GL_TEXTURE_COORD_ARRAY); + pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit + pglDisableClientState(GL_TEXTURE_COORD_ARRAY); - pglActiveTexture(GL_TEXTURE0); - pglClientActiveTexture(GL_TEXTURE0); - tex_downloaded = endScreenWipe; -} - -// Create a texture from the screen. -EXPORT void HWRAPI(MakeScreenTexture) (void) -{ - INT32 texsize = 2048; - boolean firstTime = (screentexture == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &screentexture); - pglBindTexture(GL_TEXTURE_2D, screentexture); - - if (firstTime) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + pglActiveTexture(GL_TEXTURE0); + pglClientActiveTexture(GL_TEXTURE0); + tex_downloaded = screenTextures[wipeEnd]; } - else - pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - - tex_downloaded = screentexture; } -EXPORT void HWRAPI(MakeScreenFinalTexture) (void) +// Create a texture from the screen. +EXPORT void HWRAPI(MakeScreenTexture) (int tex) { - INT32 texsize = 2048; - boolean firstTime = (finalScreenTexture == 0); + INT32 texsize = 512; + boolean firstTime = (screenTextures[tex] == 0); - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; // Create screen texture if (firstTime) - pglGenTextures(1, &finalScreenTexture); - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + pglGenTextures(1, &screenTextures[tex]); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); if (firstTime) { @@ -3429,24 +3131,23 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void) else pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - tex_downloaded = finalScreenTexture; + tex_downloaded = screenTextures[tex]; } -EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) +EXPORT void HWRAPI(DrawScreenFinalTexture)(int tex, int width, int height) { float xfix, yfix; float origaspect, newaspect; float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen FRGBAFloat clearColour; - INT32 texsize = 2048; + INT32 texsize = 512; float off[12]; float fix[8]; - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); @@ -3493,7 +3194,8 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) clearColour.red = clearColour.green = clearColour.blue = 0; clearColour.alpha = 1; ClearBuffer(true, false, &clearColour); - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + SetBlend(PF_NoDepthTest); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); pglColor4ubv(white); @@ -3501,7 +3203,92 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) pglVertexPointer(3, GL_FLOAT, 0, off); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - tex_downloaded = finalScreenTexture; + tex_downloaded = screenTextures[tex]; +} + +EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut) +{ + GLenum internalFormat; + if (gl_version[0] == '1' || gl_version[0] == '2') + { + // if the OpenGL version is below 3.0, then the GL_R8 format may not be available. + // so use GL_LUMINANCE8 instead to get a single component 8-bit format + // (it is possible to have access to shaders even in some OpenGL 1.x systems, + // so palette rendering can still possibly be achieved there) + internalFormat = GL_LUMINANCE8; + } + else + { + internalFormat = GL_R8; + } + if (!paletteLookupTex) + pglGenTextures(1, &paletteLookupTex); + pglActiveTexture(GL_TEXTURE1); + pglBindTexture(GL_TEXTURE_3D, paletteLookupTex); + pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage3D(GL_TEXTURE_3D, 0, internalFormat, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, + 0, GL_RED, GL_UNSIGNED_BYTE, lut); + pglActiveTexture(GL_TEXTURE0); +} + +EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable) +{ + LTListItem *item = malloc(sizeof(LTListItem)); + if (!LightTablesTail) + { + LightTablesHead = LightTablesTail = item; + } + else + { + LightTablesTail->next = item; + LightTablesTail = item; + } + item->next = NULL; + pglGenTextures(1, &item->id); + pglBindTexture(GL_TEXTURE_2D, item->id); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, hw_lighttable); + + // restore previously bound texture + pglBindTexture(GL_TEXTURE_2D, tex_downloaded); + + return item->id; +} + +// Delete light table textures, ids given before become invalid and must not be used. +EXPORT void HWRAPI(ClearLightTables)(void) +{ + while (LightTablesHead) + { + LTListItem *item = LightTablesHead; + pglDeleteTextures(1, (GLuint *)&item->id); + LightTablesHead = item->next; + free(item); + } + + LightTablesTail = NULL; + + // we no longer have a bound light table (if we had one), we just deleted it! + lt_downloaded = 0; +} + +// This palette is used for the palette rendering postprocessing step. +EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette) +{ + if (memcmp(screenPalette, palette, sizeof(screenPalette))) + { + memcpy(screenPalette, palette, sizeof(screenPalette)); + if (!screenPaletteTex) + pglGenTextures(1, &screenPaletteTex); + pglActiveTexture(GL_TEXTURE2); + pglBindTexture(GL_TEXTURE_1D, screenPaletteTex); + pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette); + pglActiveTexture(GL_TEXTURE0); + } } #endif //HWRENDER diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h index f44e0818bbeff0cae3160cd788d67b11587e7961..f7e33c46aa36b9c416a80dc9158c5c7321fb78d0 100644 --- a/src/hardware/r_opengl/r_opengl.h +++ b/src/hardware/r_opengl/r_opengl.h @@ -46,6 +46,7 @@ #define _CREATE_DLL_ // necessary for Unix AND Windows #include "../../doomdef.h" #include "../hw_drv.h" +#include "../../z_zone.h" // ========================================================================== // DEFINITIONS diff --git a/src/hu_stuff.c b/src/hu_stuff.c index bb2b837fcb299e8b0003eaa24764302d2e5bf7ee..c9744e5980da341af12eea3e7620808195395377 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -620,7 +620,7 @@ static void Command_CSay_f(void) DoSayCommand(0, 1, HU_CSAY); } -static tic_t spam_tokens[MAXPLAYERS]; +static tic_t spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent. static tic_t spam_tics[MAXPLAYERS]; /** Receives a message, processing an ::XD_SAY command. @@ -2044,76 +2044,6 @@ void HU_Drawer(void) } } -//====================================================================== -// HUD MESSAGES CLEARING FROM SCREEN -//====================================================================== - -// Clear old messages from the borders around the view window -// (only for reduced view, refresh the borders when needed) -// -// startline: y coord to start clear, -// clearlines: how many lines to clear. -// -static INT32 oldclearlines; - -void HU_Erase(void) -{ - INT32 topline, bottomline; - INT32 y, yoffset; - -#ifdef HWRENDER - // clear hud msgs on double buffer (OpenGL mode) - boolean secondframe; - static INT32 secondframelines; -#endif - - if (con_clearlines == oldclearlines && !con_hudupdate && !chat_on) - return; - -#ifdef HWRENDER - // clear the other frame in double-buffer modes - secondframe = (con_clearlines != oldclearlines); - if (secondframe) - secondframelines = oldclearlines; -#endif - - // clear the message lines that go away, so use _oldclearlines_ - bottomline = oldclearlines; - oldclearlines = con_clearlines; - if (chat_on && OLDCHAT) - if (bottomline < 8) - bottomline = 8; // only do it for consolechat. consolechat is gay. - - if (automapactive || viewwindowx == 0) // hud msgs don't need to be cleared - return; - - // software mode copies view border pattern & beveled edges from the backbuffer - if (rendermode == render_soft) - { - topline = 0; - for (y = topline, yoffset = y*vid.width; y < bottomline; y++, yoffset += vid.width) - { - if (y < viewwindowy || y >= viewwindowy + viewheight) - R_VideoErase(yoffset, vid.width); // erase entire line - else - { - R_VideoErase(yoffset, viewwindowx); // erase left border - // erase right border - R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx); - } - } - con_hudupdate = false; // if it was set.. - } -#ifdef HWRENDER - else if (rendermode != render_none) - { - // refresh just what is needed from the view borders - HWR_DrawViewBorder(secondframelines); - con_hudupdate = secondframe; - } -#endif -} - //====================================================================== // IN-LEVEL MULTIPLAYER RANKINGS //====================================================================== diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 8647e4500cb2ce1ebf76015dbcc9031a0b5f4082..b3069c215f1d6f7e09d471c9393c7b250057d942 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -111,7 +111,6 @@ boolean HU_Responder(event_t *ev); void HU_Ticker(void); void HU_Drawer(void); char HU_dequeueChatChar(void); -void HU_Erase(void); void HU_clearChatChars(void); void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags); // Lat': Ping drawer for scoreboard. void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer); diff --git a/src/i_video.h b/src/i_video.h index 8efca5f9ab28da6312755d9e11a6c8791149f26b..4b459e25b67bd207bfae911365e1a15eec101db0 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -40,10 +40,6 @@ extern rendermode_t rendermode; */ extern rendermode_t chosenrendermode; -/** \brief use highcolor modes if true -*/ -extern boolean highcolor; - /** \brief setup video mode */ void I_StartupGraphics(void); @@ -108,8 +104,8 @@ void VID_CheckGLLoaded(rendermode_t oldrender); \return name of video mode */ const char *VID_GetModeName(INT32 modenum); -void VID_PrepareModeList(void); /// note hack for SDL +void VID_PrepareModeList(void); /** \brief can video system do fullscreen */ diff --git a/src/m_anigif.c b/src/m_anigif.c index 5bc7717e0f44a4293e52a8907c57b0cfda6eade5..6e6ec68aa49760ddc5ab9ffa025356e0a13ffee3 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -21,6 +21,7 @@ #include "i_system.h" // I_GetPreciseTime #include "m_misc.h" #include "st_stuff.h" // st_palette +#include "doomstat.h" // singletics #ifdef HWRENDER #include "hardware/hw_main.h" @@ -604,7 +605,7 @@ static void GIF_framewrite(void) UINT16 delay = 0; INT32 startline; - if (gif_dynamicdelay ==(UINT8) 2) + if (gif_dynamicdelay ==(UINT8) 2 && !singletics) { // golden's attempt at creating a "dynamic delay" UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). @@ -617,7 +618,7 @@ static void GIF_framewrite(void) gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. } } - else if (gif_dynamicdelay ==(UINT8) 1) + else if (gif_dynamicdelay ==(UINT8) 1 && !singletics) { float delayf = ceil(100.0f/NEWTICRATE); diff --git a/src/m_cheat.c b/src/m_cheat.c index e61db2c2ee3d49e58f570567ee576ba94d3959eb..36438a47575ab2028223245096424ad04b398119 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1098,15 +1098,23 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c fixed_t fheight = P_GetSectorFloorZAt(sec, mt->x << FRACBITS, mt->y << FRACBITS); mt->z = (UINT16)((player->mo->z - fheight)>>FRACBITS); } + mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle))); - mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value; + mt->options = (UINT16)cv_opflags.value; mt->scale = player->mo->scale; mt->spritexscale = player->mo->spritexscale; mt->spriteyscale = player->mo->spriteyscale; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; + + // Ignore offsets + if (mt->type == MT_EMBLEM) + mt->args[1] = 1; + else + mt->args[0] = 1; + return mt; } diff --git a/src/m_menu.c b/src/m_menu.c index edbbdf2c1587a785479f8333c5ff0a8cbb997806..fcde0d148212d848f6270b723823d2d9cd8f7c93 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1406,18 +1406,19 @@ static menuitem_t OP_OpenGLOptionsMenu[] = {IT_HEADER, NULL, "General", NULL, 51}, {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_glshaders, 63}, - {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 73}, - {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 83}, - - {IT_HEADER, NULL, "Miscellaneous", NULL, 102}, - {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 114}, - {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 124}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 134}, + {IT_STRING|IT_CVAR, NULL, "Palette rendering", &cv_glpaletterendering, 73}, + {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 83}, + {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 93}, + + {IT_HEADER, NULL, "Miscellaneous", NULL, 112}, + {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 124}, + {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 134}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 144}, #ifdef ALAM_LIGHTING - {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 144}, + {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 154}, #endif #if defined (_WINDOWS) && (!(defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL))) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 154}, + {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 164}, #endif }; @@ -4098,53 +4099,6 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) { // Solid color textbox. V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 159); - //V_DrawFill(x+8, y+8, width*8, boxlines*8, 31); -/* - patch_t *p; - INT32 cx, cy, n; - INT32 step, boff; - - step = 8; - boff = 8; - - // draw left side - cx = x; - cy = y; - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TL], PU_PATCH)); - cy += boff; - p = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH); - for (n = 0; n < boxlines; n++) - { - V_DrawScaledPatch(cx, cy, 0, p); - cy += step; - } - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_PATCH)); - - // draw middle - V_DrawFlatFill(x + boff, y + boff, width*step, boxlines*step, st_borderpatchnum); - - cx += boff; - cy = y; - while (width > 0) - { - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH)); - V_DrawScaledPatch(cx, y + boff + boxlines*step, 0, W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH)); - width--; - cx += step; - } - - // draw right side - cy = y; - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TR], PU_PATCH)); - cy += boff; - p = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH); - for (n = 0; n < boxlines; n++) - { - V_DrawScaledPatch(cx, cy, 0, p); - cy += step; - } - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_PATCH)); -*/ } // @@ -13672,23 +13626,14 @@ static void M_VideoModeMenu(INT32 choice) memset(modedescs, 0, sizeof(modedescs)); -#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) VID_PrepareModeList(); // FIXME: hack -#endif + vidm_nummodes = 0; vidm_selected = 0; nummodes = VID_NumModes(); -#ifdef _WINDOWS - // clean that later: skip windowed mode 0, video modes menu only shows FULL SCREEN modes - if (nummodes <= NUMSPECIALMODES) - i = 0; // unless we have nothing - else - i = NUMSPECIALMODES; -#else - // DOS does not skip mode 0, because mode 0 is ALWAYS present i = 0; -#endif + for (; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++) { desc = VID_GetModeName(i); diff --git a/src/m_misc.c b/src/m_misc.c index 1b6a90c50acd6230cb9d8c56f99df7178926c777..55c5485a149a2b2c43e48fab973c5ad898091036 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1254,7 +1254,7 @@ void M_SaveFrame(void) // paranoia: should be unnecessary without singletics static tic_t oldtic = 0; - if (oldtic == I_GetTime()) + if (oldtic == I_GetTime() && !singletics) return; else oldtic = I_GetTime(); @@ -1978,9 +1978,9 @@ void M_UnGetToken(void) static tokenizer_t *globalTokenizer = NULL; -void M_TokenizerOpen(const char *inputString) +void M_TokenizerOpen(const char *inputString, size_t len) { - globalTokenizer = Tokenizer_Open(inputString, 2); + globalTokenizer = Tokenizer_Open(inputString, len, 2); } void M_TokenizerClose(void) diff --git a/src/m_tokenizer.c b/src/m_tokenizer.c index f36f7f6f323133c51c4975992beea9919c27e4bd..8bb094caea7ec94db70ccdffe57fd4191f5a9773 100644 --- a/src/m_tokenizer.c +++ b/src/m_tokenizer.c @@ -12,11 +12,18 @@ #include "m_tokenizer.h" #include "z_zone.h" -tokenizer_t *Tokenizer_Open(const char *inputString, unsigned numTokens) +tokenizer_t *Tokenizer_Open(const char *inputString, size_t len, unsigned numTokens) { tokenizer_t *tokenizer = Z_Malloc(sizeof(tokenizer_t), PU_STATIC, NULL); + const size_t lenpan = 2; - tokenizer->input = inputString; + tokenizer->zdup = malloc(len+lenpan); + for (size_t i = 0; i < lenpan; i++) + { + tokenizer->zdup[len+i] = 0x00; + } + + tokenizer->input = M_Memcpy(tokenizer->zdup, inputString, len); tokenizer->startPos = 0; tokenizer->endPos = 0; tokenizer->inputLength = 0; @@ -51,6 +58,7 @@ void Tokenizer_Close(tokenizer_t *tokenizer) Z_Free(tokenizer->token[i]); Z_Free(tokenizer->capacity); Z_Free(tokenizer->token); + free(tokenizer->zdup); Z_Free(tokenizer); } diff --git a/src/m_tokenizer.h b/src/m_tokenizer.h index f5111730194915c69fea455a53ba1da3cf66068b..7ee856b3c9331d8dbb0b97711bd5e8bcae7ec2e7 100644 --- a/src/m_tokenizer.h +++ b/src/m_tokenizer.h @@ -16,6 +16,7 @@ typedef struct Tokenizer { + char *zdup; const char *input; unsigned numTokens; UINT32 *capacity; @@ -29,7 +30,7 @@ typedef struct Tokenizer const char *(*get)(struct Tokenizer*, UINT32); } tokenizer_t; -tokenizer_t *Tokenizer_Open(const char *inputString, unsigned numTokens); +tokenizer_t *Tokenizer_Open(const char *inputString, size_t len, unsigned numTokens); void Tokenizer_Close(tokenizer_t *tokenizer); const char *Tokenizer_Read(tokenizer_t *tokenizer, UINT32 i); diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index bb098e02973393ebccfcc923923046c7356687c3..6bdcaa650f3b703082aa9fd4255b7d1aed7dc15e 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -394,7 +394,7 @@ consvar_t cv_ps_descriptor = CVAR_INIT ("ps_descriptor", "Average", 0, ps_descri consvar_t cv_freedemocamera = CVAR_INIT("freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL); // NOTE: this should be in hw_main.c, but we can't put it there as it breaks dedicated build -consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowcustomshaders", "On", CV_NETVAR, CV_OnOff, NULL); char timedemo_name[256]; boolean timedemo_csv; @@ -893,6 +893,9 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_renderhitboxinterpolation); CV_RegisterVar(&cv_renderhitboxgldepth); CV_RegisterVar(&cv_renderhitbox); + CV_RegisterVar(&cv_renderwalls); + CV_RegisterVar(&cv_renderfloors); + CV_RegisterVar(&cv_renderthings); CV_RegisterVar(&cv_renderer); CV_RegisterVar(&cv_scr_depth); CV_RegisterVar(&cv_scr_width); @@ -4663,15 +4666,28 @@ static void Command_Cheats_f(void) CV_ResetCheatNetVars(); return; } + else if (COM_CheckParm("on")) + { + if (!(server || (IsPlayerAdmin(consoleplayer)))) + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); + else + G_SetUsedCheats(false); + return; + } + + if (usedCheats) + CONS_Printf(M_GetText("Cheats are enabled, the game cannot be saved.\n")); + else + CONS_Printf(M_GetText("Cheats are disabled, the game can be saved.\n")); if (CV_CheatsEnabled()) { - CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed -- Cheats are enabled.\n")); + CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed.\n")); if (server || (IsPlayerAdmin(consoleplayer))) CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.\n")); } else - CONS_Printf(M_GetText("No CHEAT-marked variables are changed -- Cheats are disabled.\n")); + CONS_Printf(M_GetText("No CHEAT-marked variables are changed.\n")); } #ifdef _DEBUG diff --git a/src/netcode/d_netfil.c b/src/netcode/d_netfil.c index 03ad8303e6571a477b9f107154d9ed3102ac58a9..a8a10d475d4afcc9c965573c1deaf59969c00b0f 100644 --- a/src/netcode/d_netfil.c +++ b/src/netcode/d_netfil.c @@ -1640,7 +1640,7 @@ boolean CURLPrepareFile(const char* url, int dfilenum) #endif // Set user agent, as some servers won't accept invalid user agents. - curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("Sonic Robo Blast 2/v%d.%d", VERSION, SUBVERSION)); + curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("Sonic Robo Blast 2/%s", VERSIONSTRING)); // Authenticate if the user so wishes login = CURLGetLogin(url, NULL); diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c index 6d9a2725a3c65fb93e3f1f3b89e47dcf0464ad05..0148c485ab1fd5fd29cd4ca0bc6effca93ff69f1 100644 --- a/src/netcode/i_tcp.c +++ b/src/netcode/i_tcp.c @@ -265,7 +265,7 @@ static const char* inet_ntopA(short af, const void *cp, char *buf, socklen_t len #ifdef HAVE_MINIUPNPC // based on old XChat patch static void I_ShutdownUPnP(void); static void I_InitUPnP(void); -I_mutex upnp_mutex; +static I_mutex upnp_mutex; static struct UPNPUrls urls; static struct IGDdatas data; static char lanaddr[64]; @@ -300,7 +300,11 @@ init_upnpc_once(struct upnpdata *upnpuserdata) int upnp_error = -2; int scope_id = 0; int status_code = 0; - CONS_Printf(M_GetText("Looking for UPnP Internet Gateway Device\n")); + + memset(&urls, 0, sizeof(struct UPNPUrls)); + memset(&data, 0, sizeof(struct IGDdatas)); + + I_OutputMsg(M_GetText("Looking for UPnP Internet Gateway Device\n")); devlist = upnpDiscoverDevices(deviceTypes, 500, NULL, NULL, 0, false, 2, &upnp_error, 0); if (devlist) { @@ -316,39 +320,37 @@ init_upnpc_once(struct upnpdata *upnpuserdata) if (!dev) dev = devlist; /* defaulting to first device */ - CONS_Printf(M_GetText("Found UPnP device:\n desc: %s\n st: %s\n"), + I_OutputMsg(M_GetText("Found UPnP device:\n desc: %s\n st: %s\n"), dev->descURL, dev->st); UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); - CONS_Printf(M_GetText("Local LAN IP address: %s\n"), lanaddr); + I_OutputMsg(M_GetText("Local LAN IP address: %s\n"), lanaddr); descXML = miniwget(dev->descURL, &descXMLsize, scope_id, &status_code); if (descXML) { parserootdesc(descXML, descXMLsize, &data); free(descXML); descXML = NULL; - memset(&urls, 0, sizeof(struct UPNPUrls)); - memset(&data, 0, sizeof(struct IGDdatas)); GetUPNPUrls(&urls, &data, dev->descURL, status_code); I_AddExitFunc(I_ShutdownUPnP); } freeUPNPDevlist(devlist); - I_unlock_mutex(upnp_mutex); } else if (upnp_error == UPNPDISCOVER_SOCKET_ERROR) { - CONS_Printf(M_GetText("No UPnP devices discovered\n")); + I_OutputMsg(M_GetText("No UPnP devices discovered\n")); } + I_unlock_mutex(upnp_mutex); upnpuserdata->upnpc_started =1; } static inline void I_UPnP_add(const char * addr, const char *port, const char * servicetype) { + if (!urls.controlURL || urls.controlURL[0] == '\0') + return; I_lock_mutex(&upnp_mutex); if (addr == NULL) addr = lanaddr; - if (!urls.controlURL || urls.controlURL[0] == '\0') - return; UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port, port, addr, "SRB2", servicetype, NULL, NULL); I_unlock_mutex(upnp_mutex); @@ -356,9 +358,9 @@ static inline void I_UPnP_add(const char * addr, const char *port, const char * static inline void I_UPnP_rem(const char *port, const char * servicetype) { - I_lock_mutex(&upnp_mutex); if (!urls.controlURL || urls.controlURL[0] == '\0') return; + I_lock_mutex(&upnp_mutex); UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, servicetype, NULL); I_unlock_mutex(upnp_mutex); @@ -1132,10 +1134,10 @@ boolean I_InitTcpDriver(void) { I_AddExitFunc(I_ShutdownTcpDriver); #ifdef HAVE_MINIUPNPC - if (M_CheckParm("-noUPnP")) - UPNP_support = false; - else + if (M_CheckParm("-useUPnP")) I_InitUPnP(); + else + UPNP_support = false; #endif } return init_tcp_driver; diff --git a/src/p_enemy.c b/src/p_enemy.c index a386d8ee93d75a47c24e90bf67ccdc08220bab43..accc700730d6281dea492cb4068704c7561c5239 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -541,7 +541,7 @@ boolean P_Move(mobj_t *actor, fixed_t speed) if (!P_TryMove(actor, tryx, tryy, false)) { - if (actor->flags & MF_FLOAT && floatok) + if (!P_MobjWasRemoved(actor) && actor->flags & MF_FLOAT && floatok) { // must adjust height if (actor->z < tmfloorz) @@ -585,6 +585,7 @@ void P_NewChaseDir(mobj_t *actor) dirtype_t d[3]; dirtype_t tdir = DI_NODIR, olddir, turnaround; + I_Assert(!P_MobjWasRemoved(actor)); I_Assert(actor->target != NULL); I_Assert(!P_MobjWasRemoved(actor->target)); @@ -623,7 +624,7 @@ void P_NewChaseDir(mobj_t *actor) dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)]; actor->movedir = newdir; - if ((newdir != turnaround) && P_TryWalk(actor)) + if ((newdir != turnaround) && (P_TryWalk(actor) || P_MobjWasRemoved(actor))) return; } @@ -644,7 +645,7 @@ void P_NewChaseDir(mobj_t *actor) { actor->movedir = d[1]; - if (P_TryWalk(actor)) + if (P_TryWalk(actor) || P_MobjWasRemoved(actor)) return; // either moved forward or attacked } @@ -652,7 +653,7 @@ void P_NewChaseDir(mobj_t *actor) { actor->movedir = d[2]; - if (P_TryWalk(actor)) + if (P_TryWalk(actor) || P_MobjWasRemoved(actor)) return; } @@ -661,7 +662,7 @@ void P_NewChaseDir(mobj_t *actor) { actor->movedir =olddir; - if (P_TryWalk(actor)) + if (P_TryWalk(actor) || P_MobjWasRemoved(actor)) return; } @@ -674,7 +675,7 @@ void P_NewChaseDir(mobj_t *actor) { actor->movedir = tdir; - if (P_TryWalk(actor)) + if (P_TryWalk(actor) || P_MobjWasRemoved(actor)) return; } } @@ -687,7 +688,7 @@ void P_NewChaseDir(mobj_t *actor) { actor->movedir = tdir; - if (P_TryWalk(actor)) + if (P_TryWalk(actor) || P_MobjWasRemoved(actor)) return; } } @@ -697,7 +698,7 @@ void P_NewChaseDir(mobj_t *actor) { actor->movedir = turnaround; - if (P_TryWalk(actor)) + if (P_TryWalk(actor) || P_MobjWasRemoved(actor)) return; } @@ -1100,7 +1101,7 @@ nomissile: return; // got a new target // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } @@ -1188,7 +1189,7 @@ nomissile: return; // got a new target // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } @@ -1267,7 +1268,8 @@ void A_FaceStabRev(mobj_t *actor) else { P_TryMove(actor, actor->x - P_ReturnThrustX(actor, actor->angle, 2<<FRACBITS), actor->y - P_ReturnThrustY(actor, actor->angle, 2<<FRACBITS), false); - P_FaceStabFlume(actor); + if (!P_MobjWasRemoved(actor)) + P_FaceStabFlume(actor); } } } @@ -1333,8 +1335,9 @@ void A_FaceStabHurl(mobj_t *actor) while (step > 0) { - if (!hwork->hnext) + if (P_MobjWasRemoved(hwork->hnext)) P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR)); + if (!P_MobjWasRemoved(hwork->hnext)) { hwork = hwork->hnext; @@ -1343,6 +1346,20 @@ void A_FaceStabHurl(mobj_t *actor) P_SetScale(hwork, hwork->destscale); hwork->fuse = 2; P_MoveOrigin(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS))); + if (P_MobjWasRemoved(hwork)) + { + // if one of the sections are removed, erase the entire damn thing. + mobj_t *hnext = actor->hnext; + hwork = actor; + do + { + hnext = hwork->hnext; + P_RemoveMobj(hwork); + hwork = hnext; + } + while (!P_MobjWasRemoved(hwork)); + return; + } } step -= NUMGRADS; } @@ -1359,11 +1376,14 @@ void A_FaceStabHurl(mobj_t *actor) #undef NUMGRADS #undef NUMSTEPS } + if (P_MobjWasRemoved(actor)) + return; } } P_SetMobjState(actor, locvar2); - actor->reactiontime = actor->info->reactiontime; + if (!P_MobjWasRemoved(actor)) + actor->reactiontime = actor->info->reactiontime; } // Function: A_FaceStabMiss @@ -1393,6 +1413,8 @@ void A_FaceStabMiss(mobj_t *actor) actor->y + P_ReturnThrustY(actor, actor->angle, actor->extravalue2<<FRACBITS), false)) { + if (P_MobjWasRemoved(actor)) + return; actor->extravalue2 = 0; P_SetMobjState(actor, locvar2); } @@ -1425,6 +1447,8 @@ void A_StatueBurst(mobj_t *actor) P_SetTarget(&new->target, actor->target); if (locvar2) P_SetMobjState(new, (statenum_t)locvar2); + if (P_MobjWasRemoved(new)) + return; S_StartSound(new, new->info->attacksound); S_StopSound(actor); S_StartSound(actor, sfx_s3k96); @@ -1520,7 +1544,7 @@ void A_JetJawChomp(mobj_t *actor) } // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } @@ -1941,14 +1965,15 @@ void A_SharpChase(mobj_t *actor) } // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } else { actor->threshold = actor->info->painchance; P_SetMobjState(actor, actor->info->missilestate); - S_StartSound(actor, actor->info->attacksound); + if (!P_MobjWasRemoved(actor)) + S_StartSound(actor, actor->info->attacksound); } } @@ -2034,6 +2059,8 @@ void A_CrushstaceanWalk(mobj_t *actor) false) || (actor->reactiontime-- <= 0)) { + if (P_MobjWasRemoved(actor)) + return; actor->flags2 ^= MF2_AMBUSH; P_SetTarget(&actor->target, NULL); P_SetMobjState(actor, locvar2); @@ -2215,6 +2242,8 @@ void A_CrushclawLaunch(mobj_t *actor) true) && !locvar1) { + if (P_MobjWasRemoved(actor)) + return; actor->extravalue1 = 0; actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS; P_SetMobjState(actor, locvar2); @@ -2223,6 +2252,8 @@ void A_CrushclawLaunch(mobj_t *actor) } else { + if (P_MobjWasRemoved(actor)) + return; actor->z = actor->target->z; if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16))) { @@ -2648,7 +2679,7 @@ nomissile: return; // got a new target // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } @@ -5788,7 +5819,11 @@ void A_MinusDigging(mobj_t *actor) if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < actor->radius*2) { P_SetMobjState(actor, actor->info->meleestate); + if (P_MobjWasRemoved(actor)) + return; P_TryMove(actor, actor->target->x, actor->target->y, false); + if (P_MobjWasRemoved(actor)) + return; S_StartSound(actor, actor->info->attacksound); // Spawn growing dirt pile. @@ -5796,6 +5831,8 @@ void A_MinusDigging(mobj_t *actor) if (P_MobjWasRemoved(par)) return; P_SetMobjState(par, actor->info->raisestate); + if (P_MobjWasRemoved(par)) + return; P_SetScale(par, actor->scale*2); if (actor->eflags & MFE_VERTICALFLIP) par->eflags |= MFE_VERTICALFLIP; @@ -5809,6 +5846,8 @@ void A_MinusDigging(mobj_t *actor) // Move var1 = 3; A_Chase(actor); + if (P_MobjWasRemoved(actor)) + return; // Carry over shit, maybe if (P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) @@ -5832,7 +5871,7 @@ void A_MinusDigging(mobj_t *actor) { if (P_TryMove(actor->tracer, actor->x, actor->y, false)) actor->tracer->z = mz; - else + else if (!P_MobjWasRemoved(actor)) P_SetTarget(&actor->tracer, NULL); } } @@ -7304,7 +7343,7 @@ nomissile: // chase towards player if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) > actor->radius+actor->target->radius) { - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } // too close, don't want to chase. @@ -7661,7 +7700,7 @@ void A_Boss7Chase(mobj_t *actor) if (leveltime & 1) { // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor))) P_NewChaseDir(actor); } } @@ -8119,6 +8158,8 @@ void A_GuardChase(mobj_t *actor) false) && speed > 0) // can't be the same check as previous so that P_TryMove gets to happen. { + if (P_MobjWasRemoved(actor)) + return; INT32 direction = actor->spawnpoint ? actor->spawnpoint->args[0] : TMGD_BACK; switch (direction) @@ -8135,6 +8176,8 @@ void A_GuardChase(mobj_t *actor) break; } } + if (P_MobjWasRemoved(actor)) + return; if (actor->extravalue1 < actor->info->speed) actor->extravalue1++; @@ -8171,7 +8214,11 @@ void A_GuardChase(mobj_t *actor) // chase towards player if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) { + if (P_MobjWasRemoved(actor)) + return; P_NewChaseDir(actor); + if (P_MobjWasRemoved(actor)) + return; actor->movecount += 5; // Increase tics before change in direction allowed. } } @@ -8641,6 +8688,9 @@ void A_PlaySeeSound(mobj_t *actor) if (LUA_CallAction(A_PLAYSEESOUND, actor)) return; + if (P_MobjWasRemoved(actor)) + return; + if (actor->info->seesound) S_StartScreamSound(actor, actor->info->seesound); } @@ -11735,7 +11785,13 @@ void A_BrakChase(mobj_t *actor) // chase towards player if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + { + if (P_MobjWasRemoved(actor)) + return; P_NewChaseDir(actor); + if (P_MobjWasRemoved(actor)) + return; + } // Optionally play a sound effect if (locvar2 > 0 && locvar2 < NUMSFX) @@ -13314,6 +13370,8 @@ void A_DoNPCSkid(mobj_t *actor) if ((FixedHypot(actor->momx, actor->momy) < locvar2) || !P_TryMove(actor, actor->x + actor->momx, actor->y + actor->momy, false)) { + if (P_MobjWasRemoved(actor)) + return; actor->momx = actor->momy = 0; P_SetMobjState(actor, locvar1); return; @@ -13856,6 +13914,8 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) y = dustdevil->y; } P_TryMove(thing, x - thing->momx, y - thing->momy, true); + if (P_MobjWasRemoved(thing)) + return false; } else { //Player on the top of the tornado. @@ -14260,6 +14320,8 @@ static void P_SnapperLegPlace(mobj_t *mo) seg->z = mo->z + ((mo->eflags & MFE_VERTICALFLIP) ? (((mo->height<<1)/3) - seg->height) : mo->height/3); P_TryMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, true); + if (P_MobjWasRemoved(seg)) + return; seg->angle = a; // Move as many legs as available. @@ -14281,6 +14343,8 @@ static void P_SnapperLegPlace(mobj_t *mo) y = s*o2 - c*o1; seg->z = mo->z + (((mo->eflags & MFE_VERTICALFLIP) ? (mo->height - seg->height) : 0)); P_TryMove(seg, mo->x + x, mo->y + y, true); + if (P_MobjWasRemoved(seg)) + return; P_SetMobjState(seg, seg->info->raisestate); } else @@ -14424,6 +14488,8 @@ void A_SnapperThinker(mobj_t *actor) s = FINESINE(fa); P_TryMove(actor, actor->x + c*speed, actor->y + s*speed, false); + if (P_MobjWasRemoved(actor)) + return; // The snapper spawns dust if going fast! if (actor->reactiontime < 4) diff --git a/src/p_inter.c b/src/p_inter.c index 82169bc54304782f940fdac535456d18dc047150..8584e168a5b2084f3a43443b4fbeca67a594bbab 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1397,11 +1397,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) i = 0; for (; special->type == MT_HOOP; special = special->hnext) { - special->fuse = 11; - special->movedir = i; - special->extravalue1 = special->target->extravalue1; - special->extravalue2 = special->target->extravalue2; - special->target->threshold = 4242; + if (!P_MobjWasRemoved(special->target)) + { + special->fuse = 11; + special->movedir = i; + special->extravalue1 = special->target->extravalue1; + special->extravalue2 = special->target->extravalue2; + special->target->threshold = 4242; + } i++; } // Make the collision detectors disappear. diff --git a/src/p_map.c b/src/p_map.c index 7887c117de56907d7a51eccb3715ec0a32e14d61..7b64fe3bb782de111f0b70053306ce851a1ea190 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2734,7 +2734,7 @@ increment_move tryy = y; } - if (!P_CheckPosition(thing, tryx, tryy)) + if (!P_CheckPosition(thing, tryx, tryy) || P_MobjWasRemoved(thing)) return false; // solid wall or thing if (!(thing->flags & MF_NOCLIP)) @@ -2958,6 +2958,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) { fixed_t tryx, tryy; + I_Assert(!P_MobjWasRemoved(thing)); tryx = thing->x; tryy = thing->y; @@ -2975,7 +2976,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) else tryy = y; - if (!P_CheckPosition(thing, tryx, tryy)) + if (!P_CheckPosition(thing, tryx, tryy) || P_MobjWasRemoved(thing)) return false; // solid wall or thing if (!(thing->flags & MF_NOCLIP)) @@ -3714,6 +3715,12 @@ static void P_CheckLavaWall(mobj_t *mo, sector_t *sec) } } +static inline void P_StairStepSlideMove(mobj_t *mo) +{ + if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true) && !P_MobjWasRemoved(mo)) //Allow things to drop off. + P_TryMove(mo, mo->x + mo->momx, mo->y, true); +} + // // P_SlideMove // The momx / momy move is bad, so try to slide @@ -3735,6 +3742,8 @@ void P_SlideMove(mobj_t *mo) memset(&junk, 0x00, sizeof(junk)); + I_Assert(!P_MobjWasRemoved(mo)); + if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) { // Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already. @@ -3869,7 +3878,10 @@ void P_SlideMove(mobj_t *mo) retry: if ((++hitcount == 3) || papercol) - goto stairstep; // don't loop forever + { + P_StairStepSlideMove(mo); + return; + } // trace along the three leading corners if (mo->momx > 0) @@ -3921,9 +3933,7 @@ papercollision: if (bestslidefrac == FRACUNIT+1) { // the move must have hit the middle, so stairstep -stairstep: - if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true)) //Allow things to drop off. - P_TryMove(mo, mo->x + mo->momx, mo->y, true); + P_StairStepSlideMove(mo); return; } @@ -3935,7 +3945,13 @@ stairstep: newy = FixedMul(mo->momy, bestslidefrac); if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true)) - goto stairstep; + { + if (!P_MobjWasRemoved(mo)) + P_StairStepSlideMove(mo); + return; + } + if (P_MobjWasRemoved(mo)) + return; } // Now continue along the wall. @@ -3986,11 +4002,13 @@ stairstep: tmymove = 0; } if (!P_TryMove(mo, newx, newy, true)) { - if (success) + if (success || P_MobjWasRemoved(mo)) return; // Good enough!! else goto retry; } + if (P_MobjWasRemoved(mo)) + return; success = true; } while(tmxmove || tmymove); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 9ec667346ec44bcfa5755720ac0cc37344ebfdc3..8bc6abc54c63d47456269f23d8224c1f3fd3814f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2118,7 +2118,7 @@ void P_RingXYMovement(mobj_t *mo) I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); - if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy)) + if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy) && !P_MobjWasRemoved(mo)) P_SlideMove(mo); } @@ -2132,8 +2132,10 @@ void P_SceneryXYMovement(mobj_t *mo) oldx = mo->x; oldy = mo->y; - if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy)) + if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy) && !P_MobjWasRemoved(mo)) P_SlideMove(mo); + if (P_MobjWasRemoved(mo)) + return; if ((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz)) return; // no friction when airborne @@ -2329,12 +2331,15 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) if (mo->player && mo->player->pflags & PF_GODMODE) return false; - if (((mo->z <= mo->subsector->sector->floorheight + fixed_t sectorFloor = P_GetSectorFloorZAt(mo->subsector->sector, mo->x, mo->y); + fixed_t sectorCeiling = P_GetSectorCeilingZAt(mo->subsector->sector, mo->x, mo->y); + + if (((mo->z <= sectorFloor && ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_FLOOR)) - || (mo->z + mo->height >= mo->subsector->sector->ceilingheight - && ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_CEILING))) - && (mo->subsector->sector->damagetype == SD_DEATHPITTILT - || mo->subsector->sector->damagetype == SD_DEATHPITNOTILT)) + || (mo->z + mo->height >= sectorCeiling + && ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_CEILING))) + && (mo->subsector->sector->damagetype == SD_DEATHPITTILT + || mo->subsector->sector->damagetype == SD_DEATHPITNOTILT)) return true; return false; @@ -3914,6 +3919,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj) } else P_TryMove(mobj, mobj->x, mobj->y, true); + if (P_MobjWasRemoved(mobj)) + return; P_CheckCrumblingPlatforms(mobj); @@ -4708,6 +4715,8 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) { seg->z = bz + (dz*(9-s)); P_TryMove(seg, workx + (dx*s), worky + (dy*s), true); + if (P_MobjWasRemoved(seg)) + return; } angle += ANGLE_MAX/3; } @@ -4945,6 +4954,8 @@ static void P_Boss4Thinker(mobj_t *mobj) (mobj->spawnpoint->x<<FRACBITS) - P_ReturnThrustX(mobj, mobj->angle, mobj->movefactor), (mobj->spawnpoint->y<<FRACBITS) - P_ReturnThrustY(mobj, mobj->angle, mobj->movefactor), true); + if (P_MobjWasRemoved(mobj)) + return; P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2); @@ -5514,6 +5525,8 @@ static void P_Boss9Thinker(mobj_t *mobj) { P_InstaThrust(mobj, mobj->angle, -4*FRACUNIT); P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true); + if (P_MobjWasRemoved(mobj)) + return; mobj->momz -= gravity; if (mobj->z < mobj->watertop || mobj->z < (mobj->floorz + 16*FRACUNIT)) { @@ -5862,6 +5875,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT); if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) { // Hit a wall? Find a direction to bounce + if (P_MobjWasRemoved(mobj)) + return; mobj->threshold--; if (!mobj->threshold) { // failed bounce! S_StartSound(mobj, sfx_mspogo); @@ -5902,6 +5917,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_InstaThrust(mobj, mobj->angle, -speed); while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) { + if (P_MobjWasRemoved(mobj)) + return; S_StartSound(mobj, sfx_mspogo); P_BounceMove(mobj); mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0); @@ -7501,6 +7518,8 @@ static void P_RosySceneryThink(mobj_t *mobj) fixed_t x = mobj->x, y = mobj->y, z = mobj->z; angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y); boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false); + if (P_MobjWasRemoved(mobj)) + return; P_UnsetThingPosition(mobj); mobj->x = x; @@ -8064,7 +8083,8 @@ static void P_MobjSceneryThink(mobj_t *mobj) break; } - P_SceneryThinker(mobj); + if (!P_MobjWasRemoved(mobj)) + P_SceneryThinker(mobj); } static boolean P_MobjPushableThink(mobj_t *mobj) @@ -10294,6 +10314,8 @@ void P_MobjThinker(mobj_t *mobj) P_SetTarget(&mobj->hnext, NULL); if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) P_SetTarget(&mobj->hprev, NULL); + if (mobj->dontdrawforviewmobj && P_MobjWasRemoved(mobj->dontdrawforviewmobj)) + P_SetTarget(&mobj->dontdrawforviewmobj, NULL); mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG); @@ -10424,6 +10446,8 @@ void P_MobjThinker(mobj_t *mobj) || mobj->type == MT_CANNONBALLDECOR || mobj->type == MT_FALLINGROCK) { P_TryMove(mobj, mobj->x, mobj->y, true); // Sets mo->standingslope correctly + if (P_MobjWasRemoved(mobj)) + return; //if (mobj->standingslope) CONS_Printf("slope physics on mobj\n"); P_ButteredSlope(mobj); } @@ -10525,6 +10549,8 @@ void P_PushableThinker(mobj_t *mobj) // it has to be pushable RIGHT NOW for this part to happen if (mobj->flags & MF_PUSHABLE && !(mobj->momx || mobj->momy)) P_TryMove(mobj, mobj->x, mobj->y, true); + if (P_MobjWasRemoved(mobj)) + return; if (mobj->type == MT_MINECART && mobj->health) { @@ -10867,9 +10893,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...) ))) mobj->flags2 |= MF2_DONTRESPAWN; - if (!(mobj->flags & MF_NOTHINK)) - P_AddThinker(THINK_MOBJ, &mobj->thinker); - if (type == MT_PLAYER) { // when spawning MT_PLAYER, set mobj->player before calling MobjSpawn hook to prevent P_RemoveMobj from succeeding on player mobj. @@ -10879,6 +10902,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...) va_end(args); } + if (!(mobj->flags & MF_NOTHINK) || (titlemapinaction && mobj->type == MT_ALTVIEWMAN)) + P_AddThinker(THINK_MOBJ, &mobj->thinker); + // increment mobj reference, so we don't get a dangling reference in case MobjSpawn calls P_RemoveMobj mobj->thinker.references++; @@ -14027,7 +14053,8 @@ boolean P_CheckMissileSpawn(mobj_t *th) if (!P_TryMove(th, th->x, th->y, true)) { - P_ExplodeMissile(th); + if (!P_MobjWasRemoved(th)) + P_ExplodeMissile(th); return false; } return true; diff --git a/src/p_setup.c b/src/p_setup.c index 3bde51c3b9091611e5c14f8bae33f6654c7bf198..6a5e4c76933eb5aafdac1bcd0b254e88a526494c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -585,17 +585,17 @@ Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize) // Look for a flat int texturenum = R_CheckFlatNumForName(levelflat->name); - if (texturenum <= 0) + if (texturenum < 0) { // If we can't find a flat, try looking for a texture! texturenum = R_CheckTextureNumForName(levelflat->name); - if (texturenum <= 0) + if (texturenum < 0) { // Use "not found" texture texturenum = R_CheckTextureNumForName("REDWALL"); // Give up? - if (texturenum <= 0) + if (texturenum < 0) { levelflat->type = LEVELFLAT_NONE; texturenum = -1; @@ -1525,6 +1525,12 @@ static boolean TextmapCount(size_t size) numvertexes = 0; numsectors = 0; + if(!tkn) + { + CONS_Alert(CONS_ERROR, "No text in lump!\n"); + return true; + } + // Look for namespace at the beginning. if (!fastcmp(tkn, "namespace")) { @@ -3109,7 +3115,12 @@ static boolean P_LoadMapData(const virtres_t *virt) if (udmf) // Count how many entries for each type we got in textmap. { virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); - M_TokenizerOpen((char *)textmap->data); + if (textmap->size == 0) + { + CONS_Alert(CONS_ERROR, "Emtpy TEXTMAP Lump!\n"); + return false; + } + M_TokenizerOpen((char *)textmap->data, textmap->size); if (!TextmapCount(textmap->size)) { M_TokenizerClose(); diff --git a/src/p_tick.c b/src/p_tick.c index 4ab388486db62be9d1fa36d9289ac2b043219e47..6d7d4fd969fb70964e4e0cf6663d26bd6d81e8a7 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -844,7 +844,7 @@ void P_Ticker(boolean run) if (quake.time) --quake.time; - if (metalplayback) + if (!P_MobjWasRemoved(metalplayback)) G_ReadMetalTic(metalplayback); if (metalrecording) G_WriteMetalTic(players[consoleplayer].mo); diff --git a/src/p_user.c b/src/p_user.c index 25a60cf34be5ed49ccdb820dbc3d01e4f2f562d5..9d0eed288275e28a82dcbe1c0193a643be2f1419 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11105,7 +11105,8 @@ static void P_MinecartThink(player_t *player) fa = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK; if (!P_TryMove(minecart, minecart->x + FINECOSINE(fa), minecart->y + FINESINE(fa), true)) { - P_KillMobj(minecart, NULL, NULL, 0); + if (!P_MobjWasRemoved(minecart)) + P_KillMobj(minecart, NULL, NULL, 0); return; } @@ -12459,7 +12460,7 @@ void P_PlayerThink(player_t *player) player->texttimer = 4*TICRATE; player->textvar = 2; // GET n RINGS! - if (player->capsule && player->capsule->health != player->capsule->spawnpoint->angle) + if (!P_MobjWasRemoved(player->capsule) && player->capsule->health != player->capsule->spawnpoint->angle) player->textvar++; // GET n MORE RINGS! } } diff --git a/src/r_data.c b/src/r_data.c index 0a13d27dbaf55f9e9092adeb0de4635523c96606..75ec0556d46f1edff4d2c473b595a40e835426ac 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -31,6 +31,10 @@ #include "byteptr.h" #include "dehacked.h" +#ifdef HWRENDER +#include "hardware/hw_glob.h" // HWR_ClearLightTables +#endif + // // Graphics. // SRB2 graphics for walls and sprites @@ -50,10 +54,6 @@ lighttable_t *fadecolormap; // for debugging/info purposes size_t flatmemory, spritememory, texturememory; -// highcolor stuff -INT16 color8to16[256]; // remap color index to highcolor rgb value -INT16 *hicolormaps; // test a 32k colormap remaps high -> high - // Blends two pixels together, using the equation // that matches the specified alpha style. UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) @@ -426,6 +426,9 @@ void R_ClearColormaps(void) { // Purged by PU_LEVEL, just overwrite the pointer extra_colormaps = R_CreateDefaultColormap(true); +#ifdef HWRENDER + HWR_ClearLightTables(); +#endif } // @@ -1170,40 +1173,6 @@ const char *R_NameForColormap(extracolormap_t *extra_colormap) } #endif -// -// build a table for quick conversion from 8bpp to 15bpp -// - -// -// added "static inline" keywords, linking with the debug version -// of allegro, it have a makecol15 function of it's own, now -// with "static inline" keywords,it sloves this problem ;) -// -FUNCMATH static inline int makecol15(int r, int g, int b) -{ - return (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3))); -} - -static void R_Init8to16(void) -{ - UINT8 *palette; - int i; - - palette = W_CacheLumpName("PLAYPAL",PU_CACHE); - - for (i = 0; i < 256; i++) - { - // PLAYPAL uses 8 bit values - color8to16[i] = (INT16)makecol15(palette[0], palette[1], palette[2]); - palette += 3; - } - - // test a big colormap - hicolormaps = Z_Malloc(16384*sizeof(*hicolormaps), PU_STATIC, NULL); - for (i = 0; i < 16384; i++) - hicolormaps[i] = (INT16)(i<<1); -} - // // R_InitData // @@ -1212,12 +1181,6 @@ static void R_Init8to16(void) // void R_InitData(void) { - if (highcolor) - { - CONS_Printf("InitHighColor...\n"); - R_Init8to16(); - } - CONS_Printf("R_LoadParsedTranslations()...\n"); R_LoadParsedTranslations(); diff --git a/src/r_data.h b/src/r_data.h index 364f85b6d4b0cbdd09448144f0546db9bc661bfc..9340ed284b6524e54774cfa43ed6c24e3e92afe3 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -36,9 +36,6 @@ UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT extern INT32 ASTTextureBlendingThreshold[2]; -extern INT16 color8to16[256]; // remap color index to highcolor -extern INT16 *hicolormaps; // remap high colors to high colors.. - extern CV_PossibleValue_t Color_cons_t[]; // I/O, setting up the stuff. diff --git a/src/r_defs.h b/src/r_defs.h index 899d6ad73fd1bb9ef2b03992e636bf08fa0b42c0..7e92c92492a88527f2bf5685bf93797c0081494c 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -25,6 +25,10 @@ #include "screen.h" // MAXVIDWIDTH, MAXVIDHEIGHT +#ifdef HWRENDER +#include "m_aatree.h" +#endif + #include "taglist.h" // @@ -69,6 +73,11 @@ typedef struct extracolormap_s lighttable_t *colormap; +#ifdef HWRENDER + // The id of the hardware lighttable. Zero means it does not exist yet. + UINT32 gl_lighttable_id; +#endif + #ifdef EXTRACOLORMAPLUMPS lumpnum_t lump; // for colormap lump matching, init to LUMPERROR char lumpname[9]; // for netsyncing @@ -840,15 +849,6 @@ typedef struct drawseg_s vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes } drawseg_t; -typedef enum -{ - PALETTE = 0, // 1 byte is the index in the doom palette (as usual) - INTENSITY = 1, // 1 byte intensity - INTENSITY_ALPHA = 2, // 2 byte: alpha then intensity - RGB24 = 3, // 24 bit rgb - RGBA32 = 4, // 32 bit rgba -} pic_mode_t; - #ifdef ROTSPRITE typedef struct { diff --git a/src/r_draw.c b/src/r_draw.c index 513a54f4aefff9ac0f57b916e6e0c12d7286e4c3..86f7e488c8502516cc4f36bb04b7a516385fc5ed 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -40,23 +40,6 @@ */ INT32 viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy; -/** \brief pointer to the start of each line of the screen, -*/ -UINT8 *ylookup[MAXVIDHEIGHT*4]; - -/** \brief pointer to the start of each line of the screen, for view1 (splitscreen) -*/ -UINT8 *ylookup1[MAXVIDHEIGHT*4]; - -/** \brief pointer to the start of each line of the screen, for view2 (splitscreen) -*/ -UINT8 *ylookup2[MAXVIDHEIGHT*4]; - -/** \brief x byte offset for columns inside the viewwindow, - so the first column starts at (SCRWIDTH - VIEWWIDTH)/2 -*/ -INT32 columnofs[MAXVIDWIDTH*4]; - UINT8 *topleft; // ========================================================================= @@ -67,8 +50,6 @@ lighttable_t *dc_colormap; INT32 dc_x = 0, dc_yl = 0, dc_yh = 0; fixed_t dc_iscale, dc_texturemid; -UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bit, - // soo lets make it a byte on all system for the ASM code UINT8 *dc_source; // ----------------------- @@ -677,7 +658,7 @@ UINT16 R_GetSuperColorByName(const char *name) void R_InitViewBuffer(INT32 width, INT32 height) { - INT32 i, bytesperpixel = vid.bpp; + INT32 bytesperpixel = vid.bpp; if (width > MAXVIDWIDTH) width = MAXVIDWIDTH; @@ -689,118 +670,13 @@ void R_InitViewBuffer(INT32 width, INT32 height) // Handle resize, e.g. smaller view windows with border and/or status bar. viewwindowx = (vid.width - width) >> 1; - // Column offset for those columns of the view window, but relative to the entire screen - for (i = 0; i < width; i++) - columnofs[i] = (viewwindowx + i) * bytesperpixel; - // Same with base row offset. if (width == vid.width) viewwindowy = 0; else viewwindowy = (vid.height - height) >> 1; - - // Precalculate all row offsets. - for (i = 0; i < height; i++) - { - ylookup[i] = ylookup1[i] = screens[0] + (i+viewwindowy)*vid.width*bytesperpixel; - ylookup2[i] = screens[0] + (i+(vid.height>>1))*vid.width*bytesperpixel; // for splitscreen - } } -/** \brief viewborder patches lump numbers -*/ -lumpnum_t viewborderlump[8]; - -/** \brief Store the lumpnumber of the viewborder patches -*/ - -void R_InitViewBorder(void) -{ - viewborderlump[BRDR_T] = W_GetNumForName("brdr_t"); - viewborderlump[BRDR_B] = W_GetNumForName("brdr_b"); - viewborderlump[BRDR_L] = W_GetNumForName("brdr_l"); - viewborderlump[BRDR_R] = W_GetNumForName("brdr_r"); - viewborderlump[BRDR_TL] = W_GetNumForName("brdr_tl"); - viewborderlump[BRDR_BL] = W_GetNumForName("brdr_bl"); - viewborderlump[BRDR_TR] = W_GetNumForName("brdr_tr"); - viewborderlump[BRDR_BR] = W_GetNumForName("brdr_br"); -} - -#if 0 -/** \brief R_FillBackScreen - - Fills the back screen with a pattern for variable screen sizes - Also draws a beveled edge. -*/ -void R_FillBackScreen(void) -{ - UINT8 *src, *dest; - patch_t *patch; - INT32 x, y, step, boff; - - // quickfix, don't cache lumps in both modes - if (rendermode != render_soft) - return; - - // draw pattern around the status bar too (when hires), - // so return only when in full-screen without status bar. - if (scaledviewwidth == vid.width && viewheight == vid.height) - return; - - src = scr_borderpatch; - dest = screens[1]; - - for (y = 0; y < vid.height; y++) - { - for (x = 0; x < vid.width/128; x++) - { - M_Memcpy (dest, src+((y&127)<<7), 128); - dest += 128; - } - - if (vid.width&127) - { - M_Memcpy(dest, src+((y&127)<<7), vid.width&127); - dest += (vid.width&127); - } - } - - // don't draw the borders when viewwidth is full vid.width. - if (scaledviewwidth == vid.width) - return; - - step = 8; - boff = 8; - - patch = W_CacheLumpNum(viewborderlump[BRDR_T], PU_CACHE); - for (x = 0; x < scaledviewwidth; x += step) - V_DrawPatch(viewwindowx + x, viewwindowy - boff, 1, patch); - - patch = W_CacheLumpNum(viewborderlump[BRDR_B], PU_CACHE); - for (x = 0; x < scaledviewwidth; x += step) - V_DrawPatch(viewwindowx + x, viewwindowy + viewheight, 1, patch); - - patch = W_CacheLumpNum(viewborderlump[BRDR_L], PU_CACHE); - for (y = 0; y < viewheight; y += step) - V_DrawPatch(viewwindowx - boff, viewwindowy + y, 1, patch); - - patch = W_CacheLumpNum(viewborderlump[BRDR_R],PU_CACHE); - for (y = 0; y < viewheight; y += step) - V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + y, 1, - patch); - - // Draw beveled corners. - V_DrawPatch(viewwindowx - boff, viewwindowy - boff, 1, - W_CacheLumpNum(viewborderlump[BRDR_TL], PU_CACHE)); - V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy - boff, 1, - W_CacheLumpNum(viewborderlump[BRDR_TR], PU_CACHE)); - V_DrawPatch(viewwindowx - boff, viewwindowy + viewheight, 1, - W_CacheLumpNum(viewborderlump[BRDR_BL], PU_CACHE)); - V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + viewheight, 1, - W_CacheLumpNum(viewborderlump[BRDR_BR], PU_CACHE)); -} -#endif - /** \brief The R_VideoErase function Copy a screen buffer. @@ -822,55 +698,6 @@ void R_VideoErase(size_t ofs, INT32 count) M_Memcpy(screens[0] + ofs, screens[1] + ofs, count); } -#if 0 -/** \brief The R_DrawViewBorder - - Draws the border around the view - for different size windows? -*/ -void R_DrawViewBorder(void) -{ - INT32 top, side, ofs; - - if (rendermode == render_none) - return; -#ifdef HWRENDER - if (rendermode != render_soft) - { - HWR_DrawViewBorder(0); - return; - } - else -#endif - -#ifdef DEBUG - fprintf(stderr,"RDVB: vidwidth %d vidheight %d scaledviewwidth %d viewheight %d\n", - vid.width, vid.height, scaledviewwidth, viewheight); -#endif - - if (scaledviewwidth == vid.width) - return; - - top = (vid.height - viewheight)>>1; - side = (vid.width - scaledviewwidth)>>1; - - // copy top and one line of left side - R_VideoErase(0, top*vid.width+side); - - // copy one line of right side and bottom - ofs = (viewheight+top)*vid.width - side; - R_VideoErase(ofs, top*vid.width + side); - - // copy sides using wraparound - ofs = top*vid.width + vid.width-side; - side <<= 1; - - // simpler using our VID_Blit routine - VID_BlitLinearScreen(screens[1] + ofs, screens[0] + ofs, side, viewheight - 1, - vid.width, vid.width); -} -#endif - // R_CalcTiltedLighting // Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly. static INT32 tiltlighting[MAXVIDWIDTH]; @@ -912,11 +739,3 @@ static void R_CalcSlopeLight(void) #include "r_draw8.c" #include "r_draw8_npo2.c" - -// ========================================================================== -// INCLUDE 16bpp DRAWING CODE HERE -// ========================================================================== - -#ifdef HIGHCOLOR -#include "r_draw16.c" -#endif diff --git a/src/r_draw.h b/src/r_draw.h index 7eb001ebd360df404e57a5716d96aa73aa013219..1a828312a7a922353a3ff5b969908dc61dcf0ee6 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -19,10 +19,6 @@ // ------------------------------- // COMMON STUFF FOR 8bpp AND 16bpp // ------------------------------- -extern UINT8 *ylookup[MAXVIDHEIGHT*4]; -extern UINT8 *ylookup1[MAXVIDHEIGHT*4]; -extern UINT8 *ylookup2[MAXVIDHEIGHT*4]; -extern INT32 columnofs[MAXVIDWIDTH*4]; extern UINT8 *topleft; // ------------------------- @@ -32,7 +28,6 @@ extern UINT8 *topleft; extern lighttable_t *dc_colormap; extern INT32 dc_x, dc_yl, dc_yh; extern fixed_t dc_iscale, dc_texturemid; -extern UINT8 dc_hires; extern UINT8 *dc_source; // first pixel in a column @@ -77,25 +72,6 @@ extern UINT32 nflatyshift; extern UINT32 nflatshiftup; extern UINT32 nflatmask; -/// \brief Top border -#define BRDR_T 0 -/// \brief Bottom border -#define BRDR_B 1 -/// \brief Left border -#define BRDR_L 2 -/// \brief Right border -#define BRDR_R 3 -/// \brief Topleft border -#define BRDR_TL 4 -/// \brief Topright border -#define BRDR_TR 5 -/// \brief Bottomleft border -#define BRDR_BL 6 -/// \brief Bottomright border -#define BRDR_BR 7 - -extern lumpnum_t viewborderlump[8]; - // ------------------------------------------------ // r_draw.c COMMON ROUTINES FOR BOTH 8bpp and 16bpp // ------------------------------------------------ @@ -169,17 +145,8 @@ boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel); extern boolean skincolor_modified[]; void R_InitViewBuffer(INT32 width, INT32 height); -void R_InitViewBorder(void); void R_VideoErase(size_t ofs, INT32 count); -// Rendering function. -#if 0 -void R_FillBackScreen(void); - -// If the view size is not full screen, draws a border around it. -void R_DrawViewBorder(void); -#endif - #define TRANSPARENTPIXEL 255 // ----------------- @@ -240,17 +207,5 @@ void R_DrawTiltedTransSolidColorSpan_8(void); void R_DrawWaterSolidColorSpan_8(void); void R_DrawTiltedWaterSolidColorSpan_8(void); -// ------------------ -// 16bpp DRAWING CODE -// ------------------ - -#ifdef HIGHCOLOR -void R_DrawColumn_16(void); -void R_DrawWallColumn_16(void); -void R_DrawTranslucentColumn_16(void); -void R_DrawTranslatedColumn_16(void); -void R_DrawSpan_16(void); -#endif - // ========================================================================= #endif // __R_DRAW__ diff --git a/src/r_draw16.c b/src/r_draw16.c deleted file mode 100644 index 2ed5a2a8e3d267ab869c5a0c800423fe7eb68eba..0000000000000000000000000000000000000000 --- a/src/r_draw16.c +++ /dev/null @@ -1,214 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2023 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file r_draw16.c -/// \brief 16bpp (HIGHCOLOR) span/column drawer functions -/// \note no includes because this is included as part of r_draw.c - -// ========================================================================== -// COLUMNS -// ========================================================================== - -/// \brief kick out the upper bit of each component (we're in 5 : 5 : 5) -#define HIMASK1 0x7bde - -/** \brief The R_DrawColumn_16 function - standard upto 128high posts column drawer -*/ -void R_DrawColumn_16(void) -{ - INT32 count; - INT16 *dest; - fixed_t frac, fracstep; - - count = dc_yh - dc_yl + 1; - - // Zero length, column does not exceed a pixel. - if (count <= 0) - return; - -#ifdef RANGECHECK - if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height) - I_Error("R_DrawColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x); -#endif - - // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]); - - // Determine scaling, which is the only mapping to be done. - fracstep = dc_iscale; - frac = dc_texturemid + (dc_yl - centery)*fracstep; - - // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. - // This is as fast as it gets. - - do - { - // Re-map color indices from wall texture column using a lighting/special effects LUT. - *dest = hicolormaps[((INT16 *)(void *)dc_source)[(frac>>FRACBITS)&127]>>1]; - - dest += vid.width; - frac += fracstep; - } while (--count); -} - -/** \brief The R_DrawWallColumn_16 function - LAME cutnpaste: same as R_DrawColumn_16 but wraps around 256 - instead of 128 for the tall sky textures (256x240) -*/ -void R_DrawWallColumn_16(void) -{ - INT32 count; - INT16 *dest; - fixed_t frac, fracstep; - - count = dc_yh - dc_yl + 1; - - // Zero length, column does not exceed a pixel. - if (count <= 0) - return; - -#ifdef RANGECHECK - if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height) - I_Error("R_DrawWallColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x); -#endif - - dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]); - - fracstep = dc_iscale; - frac = dc_texturemid + (dc_yl - centery)*fracstep; - - do - { - *dest = hicolormaps[((INT16 *)(void *)dc_source)[(frac>>FRACBITS)&255]>>1]; - - dest += vid.width; - frac += fracstep; - } while (--count); -} - -/** \brief The R_DrawTranslucentColumn_16 function - LAME cutnpaste: same as R_DrawColumn_16 but does - translucent -*/ -void R_DrawTranslucentColumn_16(void) -{ - INT32 count; - INT16 *dest; - fixed_t frac, fracstep; - - // check out coords for src* - if ((dc_yl < 0) || (dc_x >= vid.width)) - return; - - count = dc_yh - dc_yl; - if (count < 0) - return; - -#ifdef RANGECHECK - if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height) - I_Error("R_DrawTranslucentColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x); -#endif - - // FIXME. As above. - dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]); - - // Looks familiar. - fracstep = dc_iscale; - frac = dc_texturemid + (dc_yl - centery)*fracstep; - - // Here we do an additional index re-mapping. - do - { - *dest = (INT16)((INT16)((color8to16[dc_source[frac>>FRACBITS]]>>1) & 0x39ce) - + (INT16)(((*dest & HIMASK1)) & 0x7fff)); - - dest += vid.width; - frac += fracstep; - } while (count--); -} - -/** \brief The R_DrawTranslatedColumn_16 function - ? -*/ -void R_DrawTranslatedColumn_16(void) -{ - INT32 count; - INT16 *dest; - fixed_t frac, fracstep; - - count = dc_yh - dc_yl; - if (count < 0) - return; - -#ifdef RANGECHECK - if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height) - I_Error("R_DrawTranslatedColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x); -#endif - - dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]); - - // Looks familiar. - fracstep = dc_iscale; - frac = dc_texturemid + (dc_yl - centery)*fracstep; - - // Here we do an additional index re-mapping. - do - { - *dest = color8to16[dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]]; - dest += vid.width; - - frac += fracstep; - } while (count--); -} - -// ========================================================================== -// SPANS -// ========================================================================== - -/** \brief The R_*_16 function - Draws the actual span. -*/ -void R_DrawSpan_16(void) -{ - fixed_t xfrac, yfrac; - INT16 *dest; - INT32 count, spot; - -#ifdef RANGECHECK - if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= vid.width || ds_y > vid.height) - I_Error("R_DrawSpan_16: %d to %d at %d", ds_x1, ds_x2, ds_y); -#endif - - xfrac = ds_xfrac; - yfrac = ds_yfrac; - - dest = (INT16 *)(void *)(ylookup[ds_y] + columnofs[ds_x1]); - - // We do not check for zero spans here? - count = ds_x2 - ds_x1; - - if (count <= 0) // We do now! - return; - - do - { - // Current texture index in u, v. - spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63); - - // Lookup pixel from flat texture tile, re-index using light/colormap. - *dest++ = hicolormaps[((INT16 *)(void *)ds_source)[spot]>>1]; - - // Next step in u, v. - xfrac += ds_xstep; - yfrac += ds_ystep; - } while (count--); -} diff --git a/src/r_draw8.c b/src/r_draw8.c index 87545f41836761421f2cdf8694c07c88f6815612..99fb71e289343034bc6327314da0e64b0d687dab 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -40,18 +40,13 @@ void R_DrawColumn_8(void) #endif // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; count++; // Determine scaling, which is the only mapping to be done. fracstep = dc_iscale; - //frac = dc_texturemid + (dc_yl - centery)*fracstep; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. // This is as fast as it gets. @@ -127,14 +122,11 @@ void R_DrawShadeColumn_8(void) I_Error("R_DrawShadeColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x); #endif - // FIXME. As above. - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; // Looks familiar. fracstep = dc_iscale; - //frac = dc_texturemid + (dc_yl - centery)*fracstep; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); // Here we do an additional index re-mapping. do @@ -166,14 +158,11 @@ void R_DrawTranslucentColumn_8(void) I_Error("R_DrawTranslucentColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x); #endif - // FIXME. As above. - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; // Looks familiar. fracstep = dc_iscale; - //frac = dc_texturemid + (dc_yl - centery)*fracstep; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. // This is as fast as it gets. @@ -271,14 +260,11 @@ void R_DrawTranslatedTranslucentColumn_8(void) if (count <= 0) // Zero length, column does not exceed a pixel. return; - // FIXME. As above. - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; // Looks familiar. fracstep = dc_iscale; - //frac = dc_texturemid + (dc_yl - centery)*fracstep; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. // This is as fast as it gets. @@ -347,14 +333,11 @@ void R_DrawTranslatedColumn_8(void) I_Error("R_DrawTranslatedColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x); #endif - // FIXME. As above. - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; // Looks familiar. fracstep = dc_iscale; - //frac = dc_texturemid + (dc_yl-centery)*fracstep; - frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); // Here we do an additional index re-mapping. do @@ -410,7 +393,7 @@ void R_DrawSpan_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; if (dest+8 > deststop) return; @@ -489,7 +472,7 @@ void R_DrawTiltedSpan_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = ds_source; //colormap = ds_colormap; @@ -611,7 +594,7 @@ void R_DrawTiltedTranslucentSpan_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = ds_source; //colormap = ds_colormap; @@ -733,7 +716,7 @@ void R_DrawTiltedWaterSpan_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; source = ds_source; //colormap = ds_colormap; @@ -854,7 +837,7 @@ void R_DrawTiltedSplat_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = ds_source; //colormap = ds_colormap; @@ -991,7 +974,7 @@ void R_DrawSplat_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; while (count >= 8) { @@ -1111,7 +1094,7 @@ void R_DrawTranslucentSplat_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; while (count >= 8) { @@ -1214,7 +1197,7 @@ void R_DrawFloorSprite_8 (void) source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; while (count >= 8) { @@ -1325,7 +1308,7 @@ void R_DrawTranslucentFloorSprite_8 (void) source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; while (count >= 8) { @@ -1420,7 +1403,7 @@ void R_DrawTiltedFloorSprite_8(void) uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; @@ -1529,7 +1512,7 @@ void R_DrawTiltedTranslucentFloorSprite_8(void) uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; @@ -1644,7 +1627,7 @@ void R_DrawTranslucentSpan_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; while (count >= 8) { @@ -1721,7 +1704,7 @@ void R_DrawWaterSpan_8(void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; count = ds_x2 - ds_x1 + 1; @@ -1784,7 +1767,6 @@ void R_DrawFogSpan_8(void) size_t count; colormap = ds_colormap; - //dest = ylookup[ds_y] + columnofs[ds_x1]; dest = &topleft[ds_y *vid.width + ds_x1]; count = ds_x2 - ds_x1 + 1; @@ -1814,7 +1796,7 @@ void R_DrawTiltedFogSpan_8(void) { int width = ds_x2 - ds_x1; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; R_CalcSlopeLight(); @@ -1834,7 +1816,7 @@ void R_DrawSolidColorSpan_8(void) size_t count = (ds_x2 - ds_x1 + 1); UINT8 source = ds_colormap[ds_source[0]]; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; memset(dest, source, count); } @@ -1847,7 +1829,7 @@ void R_DrawTransSolidColorSpan_8(void) size_t count = (ds_x2 - ds_x1 + 1); UINT8 source = ds_colormap[ds_source[0]]; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; @@ -1866,7 +1848,7 @@ void R_DrawTiltedSolidColorSpan_8(void) int width = ds_x2 - ds_x1; UINT8 source = ds_source[0]; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; R_CalcSlopeLight(); @@ -1885,7 +1867,7 @@ void R_DrawTiltedTransSolidColorSpan_8(void) int width = ds_x2 - ds_x1; UINT8 source = ds_source[0]; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; R_CalcSlopeLight(); @@ -1904,7 +1886,7 @@ void R_DrawWaterSolidColorSpan_8(void) { UINT8 source = ds_source[0]; UINT8 *colormap = ds_colormap; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; UINT8 *dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; size_t count = (ds_x2 - ds_x1 + 1); @@ -1925,7 +1907,7 @@ void R_DrawTiltedWaterSolidColorSpan_8(void) int width = ds_x2 - ds_x1; UINT8 source = ds_source[0]; - UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1]; + UINT8 *dest = &topleft[ds_y*vid.width + ds_x1]; UINT8 *dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; R_CalcSlopeLight(); @@ -1957,9 +1939,6 @@ void R_DrawFogColumn_8(void) #endif // Framebuffer destination address. - // Use ylookup LUT to avoid multiply with ScreenWidth. - // Use columnofs LUT for subwindows? - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; // Determine scaling, which is the only mapping to be done. diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index 78cde8a2ce195678333916f38a1b51bf5ba8e898..1ed3a8fa406ac8cb7cef2c95729a3a4de611faf0 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -46,7 +46,7 @@ void R_DrawSpan_NPO2_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; if (dest+8 > deststop) return; @@ -120,7 +120,7 @@ void R_DrawTiltedSpan_NPO2_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = ds_source; //colormap = ds_colormap; @@ -309,7 +309,7 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = ds_source; //colormap = ds_colormap; @@ -496,7 +496,7 @@ void R_DrawTiltedSplat_NPO2_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = ds_source; //colormap = ds_colormap; @@ -690,7 +690,7 @@ void R_DrawSplat_NPO2_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; fixedwidth = ds_flatwidth << FRACBITS; fixedheight = ds_flatheight << FRACBITS; @@ -758,7 +758,7 @@ void R_DrawTranslucentSplat_NPO2_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; fixedwidth = ds_flatwidth << FRACBITS; fixedheight = ds_flatheight << FRACBITS; @@ -828,7 +828,7 @@ void R_DrawFloorSprite_NPO2_8 (void) source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; fixedwidth = ds_flatwidth << FRACBITS; fixedheight = ds_flatheight << FRACBITS; @@ -898,7 +898,7 @@ void R_DrawTranslucentFloorSprite_NPO2_8 (void) source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; fixedwidth = ds_flatwidth << FRACBITS; fixedheight = ds_flatheight << FRACBITS; @@ -971,7 +971,7 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; @@ -1127,7 +1127,7 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx); vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; source = (UINT16 *)ds_source; colormap = ds_colormap; translation = ds_translation; @@ -1278,7 +1278,7 @@ void R_DrawTranslucentSpan_NPO2_8 (void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; fixedwidth = ds_flatwidth << FRACBITS; fixedheight = ds_flatheight << FRACBITS; @@ -1342,7 +1342,7 @@ void R_DrawWaterSpan_NPO2_8(void) source = ds_source; colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; fixedwidth = ds_flatwidth << FRACBITS; @@ -1414,7 +1414,7 @@ void R_DrawTiltedWaterSpan_NPO2_8(void) R_CalcSlopeLight(); - dest = ylookup[ds_y] + columnofs[ds_x1]; + dest = &topleft[ds_y*vid.width + ds_x1]; dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; source = ds_source; //colormap = ds_colormap; diff --git a/src/r_main.c b/src/r_main.c index c920031a053abe7fb0dafb2c0231bcc0ba18d0ae..233e55b8280a4f9e0ed80cf629435904910193d6 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -970,8 +970,6 @@ void R_Init(void) //I_OutputMsg("\nR_InitData"); R_InitData(); - //I_OutputMsg("\nR_InitViewBorder"); - R_InitViewBorder(); R_SetViewSize(); // setsizeneeded is set true // this is now done by SCR_Recalc() at the first mode set @@ -1332,7 +1330,7 @@ void R_SkyboxFrame(player_t *player) newview->z += campos.z * -mh->skybox_scalez; } - if (r_viewmobj->subsector) + if (!P_MobjWasRemoved(r_viewmobj) && r_viewmobj->subsector) newview->sector = r_viewmobj->subsector->sector; else newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; diff --git a/src/r_plane.c b/src/r_plane.c index 4f9ce9ec84bdf7443a16b811504a30df674d78f7..cad2dd49fab32e5649937a212690c90ceab96be6 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -603,6 +603,9 @@ void R_DrawPlanes(void) visplane_t *pl; INT32 i; + if (!cv_renderfloors.value) + return; + R_UpdatePlaneRipple(); for (i = 0; i < MAXVISPLANES; i++, pl++) @@ -626,7 +629,7 @@ static void R_DrawSkyPlane(visplane_t *pl) { INT32 texture = texturetranslation[skytexture]; - // Reset column drawer function (note: couldn't we just call walldrawerfunc directly?) + // Reset column drawer function (note: couldn't we just call colfuncs[BASEDRAWFUNC] directly?) // (that is, unless we'll need to switch drawers in future for some reason) colfunc = colfuncs[BASEDRAWFUNC]; diff --git a/src/r_segs.c b/src/r_segs.c index b5d4a6dae1ba1eec2491b609a7f4e991139858fe..6656127fe3d473e6ecf08cfed83f699674df704d 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -447,7 +447,7 @@ static void R_DrawRepeatMaskedColumn(column_t *col, unsigned lengthcol) { while (sprtopscreen < sprbotscreen) { R_DrawMaskedColumn(col, lengthcol); - if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow + if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow sprtopscreen = INT32_MAX; else sprtopscreen += dc_texheight*spryscale; @@ -1014,6 +1014,12 @@ static void R_DrawFlippedWall(UINT8 *source, INT32 height) R_DrawFlippedPost(source, (unsigned)height, colfunc); } +static void R_DrawNoWall(UINT8 *source, INT32 height) +{ + (void)source; + (void)height; +} + static void R_RenderSegLoop (void) { angle_t angle; @@ -1060,6 +1066,13 @@ static void R_RenderSegLoop (void) drawbottom = R_DrawFlippedWall; } + if (!cv_renderwalls.value) + { + drawtop = R_DrawNoWall; + drawmiddle = R_DrawNoWall; + drawbottom = R_DrawNoWall; + } + if (midtexture) R_CheckTextureCache(midtexture); if (toptexture) diff --git a/src/r_textures.c b/src/r_textures.c index 0175a080e7cbd901bee865429660ddb3de51af9f..59cc114139c5abb24df0f47fa0dddd0e70ec8d72 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -193,6 +193,8 @@ static void R_DrawBlendColumnInCache(column_t *column, UINT8 *cache, texpatch_t { for (; dest < cache + position + count; source++, dest++, is_opaque++) { + if (originPatch->alpha <= ASTTextureBlendingThreshold[1] && !(*is_opaque)) + continue; *dest = ASTBlendPaletteIndexes(*dest, *source, originPatch->style, originPatch->alpha); *is_opaque = true; } @@ -237,6 +239,8 @@ static void R_DrawBlendFlippedColumnInCache(column_t *column, UINT8 *cache, texp { for (; dest < cache + position + count; --source, dest++, is_opaque++) { + if (originPatch->alpha <= ASTTextureBlendingThreshold[1] && !(*is_opaque)) + continue; *dest = ASTBlendPaletteIndexes(*dest, *source, originPatch->style, originPatch->alpha); *is_opaque = true; } diff --git a/src/r_things.c b/src/r_things.c index 2d1e27a59dd64d8058710fd75e58922fae0d3944..80b6816dbdce552511248e844529d7ea6f80f505 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -951,7 +951,6 @@ static void R_DrawVisSprite(vissprite_t *vis) } colfunc = colfuncs[BASEDRAWFUNC]; - dc_hires = 0; vis->x1 = x1; vis->x2 = x2; @@ -1538,6 +1537,9 @@ static void R_ProjectSprite(mobj_t *thing) // uncapped/interpolation interpmobjstate_t interp = {0}; + if (!cv_renderthings.value) + return; + // do interpolation if (R_UsingFrameInterpolation() && !paused) { @@ -2692,7 +2694,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps // Add the 3D floors, thicksides, and masked textures... for (ds = drawsegs + mask->drawsegs[1]; ds-- > drawsegs + mask->drawsegs[0];) { - if (ds->numthicksides) + if (ds->numthicksides && cv_renderwalls.value) { for (i = 0; i < ds->numthicksides; i++) { @@ -2711,17 +2713,19 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps else { // Put it in! entry = R_CreateDrawNode(head); - entry->plane = plane; - entry->seg = ds; + if (cv_renderwalls.value) + entry->seg = ds; + if (cv_renderfloors.value) + entry->plane = plane; } ds->curline->polyseg->visplane = NULL; } - if (ds->maskedtexturecol) + if (ds->maskedtexturecol && cv_renderwalls.value) { entry = R_CreateDrawNode(head); entry->seg = ds; } - if (ds->numffloorplanes) + if (ds->numffloorplanes && cv_renderfloors.value) { for (i = 0; i < ds->numffloorplanes; i++) { @@ -3021,9 +3025,6 @@ void R_InitDrawNodes(void) // // R_DrawSprite // -//Fab : 26-04-98: -// NOTE : uses con_clipviewtop, so that when console is on, -// don't draw the part of sprites hidden under the console static void R_DrawSprite(vissprite_t *spr) { mfloorclip = spr->clipbot; @@ -3191,9 +3192,6 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* port (lowscale < spr->sortscale && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange (ds, r1, r2);*/ // seg is behind sprite continue; } diff --git a/src/r_translation.c b/src/r_translation.c index 3b123f14ca1732e2e9605dad3153fd5f6d0e2338..3905458026df20945e566861fc6c7a087bcab244 100644 --- a/src/r_translation.c +++ b/src/r_translation.c @@ -784,9 +784,9 @@ static struct PaletteRemapParseResult *PaletteRemap_ParseString(tokenizer_t *sc) return NULL; } -static struct PaletteRemapParseResult *PaletteRemap_ParseTranslation(const char *translation) +static struct PaletteRemapParseResult *PaletteRemap_ParseTranslation(const char *translation, size_t len) { - tokenizer_t *sc = Tokenizer_Open(translation, 1); + tokenizer_t *sc = Tokenizer_Open(translation, len, 1); struct PaletteRemapParseResult *result = PaletteRemap_ParseString(sc); Tokenizer_Close(sc); return result; @@ -918,7 +918,7 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum) text[lumpLength] = '\0'; Z_Free(lumpData); - sc = Tokenizer_Open(text, 1); + sc = Tokenizer_Open(text, lumpLength, 1); tkn = sc->get(sc, 0); struct NewTranslation *list = NULL; @@ -963,7 +963,7 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum) // Parse all of the translations do { - struct PaletteRemapParseResult *parse_result = PaletteRemap_ParseTranslation(tkn); + struct PaletteRemapParseResult *parse_result = PaletteRemap_ParseTranslation(tkn, strlen(tkn)); if (parse_result->error) { PrintError(name, "%s", parse_result->error); diff --git a/src/screen.c b/src/screen.c index 76f546402ef38e0a4882221945ff602de73aadf9..c1970d0e8888360511fc0a7990e669b8678a9b3b 100644 --- a/src/screen.c +++ b/src/screen.c @@ -8,7 +8,7 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file screen.c -/// \brief Handles multiple resolutions, 8bpp/16bpp(highcolor) modes +/// \brief Handles multiple resolutions #include "doomdef.h" #include "doomstat.h" @@ -71,6 +71,9 @@ consvar_t cv_scr_height_w = CVAR_INIT ("scr_height_w", "400", CV_SAVE, CV_Unsign consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL); consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL); +consvar_t cv_renderwalls = CVAR_INIT ("renderwalls", "On", CV_NOTINNET|CV_CHEAT, CV_OnOff, NULL); +consvar_t cv_renderfloors = CVAR_INIT ("renderfloors", "On", CV_NOTINNET|CV_CHEAT, CV_OnOff, NULL); +consvar_t cv_renderthings = CVAR_INIT ("renderthings", "On", CV_NOTINNET|CV_CHEAT, CV_OnOff, NULL); CV_PossibleValue_t cv_renderer_t[] = { {1, "Software"}, @@ -91,19 +94,15 @@ consvar_t cv_fullscreen = CVAR_INIT ("fullscreen", "Yes", CV_SAVE|CV_CALL, CV_Ye // ========================================================================= INT32 scr_bpp; // current video mode bytes per pixel -UINT8 *scr_borderpatch; // flat used to fill the reduced view borders set at ST_Init() // ========================================================================= -// Short and Tall sky drawer, for the current color mode -void (*walldrawerfunc)(void); - void SCR_SetDrawFuncs(void) { // - // setup the right draw routines for either 8bpp or 16bpp + // setup the right draw routines // - if (true)//vid.bpp == 1) //Always run in 8bpp. todo: remove all 16bpp code? + if (vid.bpp == 1) //Always run in 8bpp. { colfuncs[BASEDRAWFUNC] = R_DrawColumn_8; spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8; @@ -139,7 +138,6 @@ void SCR_SetDrawFuncs(void) spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8; spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8; - // Lactozilla: Non-powers-of-two spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8; @@ -153,26 +151,9 @@ void SCR_SetDrawFuncs(void) spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_NPO2_8; - } -/* else if (vid.bpp > 1) - { - I_OutputMsg("using highcolor mode\n"); - spanfunc = basespanfunc = R_DrawSpan_16; - transcolfunc = R_DrawTranslatedColumn_16; - transtransfunc = R_DrawTranslucentColumn_16; // No 16bit operation for this function - - colfunc = basecolfunc = R_DrawColumn_16; - shadecolfunc = NULL; // detect error if used somewhere.. - fuzzcolfunc = R_DrawTranslucentColumn_16; - walldrawerfunc = R_DrawWallColumn_16; - }*/ else I_Error("unknown bytes per pixel mode %d\n", vid.bpp); -/* - if (SCR_IsAspectCorrect(vid.width, vid.height)) - CONS_Alert(CONS_WARNING, M_GetText("Resolution is not aspect-correct!\nUse a multiple of %dx%d\n"), BASEVIDWIDTH, BASEVIDHEIGHT); -*/ } void SCR_SetMode(void) diff --git a/src/screen.h b/src/screen.h index 64d92b9d3ef99cf3c4e066ddc5cc9e57edd94afd..5df5d28892d08713bdf9a7ef2b94665c8f151a4b 100644 --- a/src/screen.h +++ b/src/screen.h @@ -8,7 +8,7 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file screen.h -/// \brief Handles multiple resolutions, 8bpp/16bpp(highcolor) modes +/// \brief Handles multiple resolutions #ifndef __SCREEN_H__ #define __SCREEN_H__ @@ -61,7 +61,7 @@ typedef struct viddef_s UINT8 *direct; // linear frame buffer, or vga base mem. INT32 dup; // scale 1, 2, 3 value for menus & overlays INT32/*fixed_t*/ fdup; // same as dup, but exact value when aspect ratio isn't 320/200 - INT32 bpp; // BYTES per pixel: 1 = 256color, 2 = highcolor + INT32 bpp; // BYTES per pixel: 1 = 256color INT32 baseratio; // Used to get the correct value for lighting walls @@ -83,35 +83,6 @@ enum VID_GL_LIBRARY_ERROR = -1, }; -// internal additional info for vesa modes only -typedef struct -{ - INT32 vesamode; // vesa mode number plus LINEAR_MODE bit - void *plinearmem; // linear address of start of frame buffer -} vesa_extra_t; -// a video modes from the video modes list, -// note: video mode 0 is always standard VGA320x200. -typedef struct vmode_s -{ - struct vmode_s *pnext; - char *name; - UINT32 width, height; - UINT32 rowbytes; // bytes per scanline - UINT32 bytesperpixel; // 1 for 256c, 2 for highcolor - INT32 windowed; // if true this is a windowed mode - INT32 numpages; - vesa_extra_t *pextradata; // vesa mode extra data -#ifdef _WIN32 - INT32 (WINAPI *setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode); -#else - INT32 (*setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode); -#endif - INT32 misc; // misc for display driver (r_opengl.dll etc) -} vmode_t; - -#define NUMSPECIALMODES 4 -extern vmode_t specialmodes[NUMSPECIALMODES]; - // --------------------------------------------- // color mode dependent drawer function pointers // --------------------------------------------- @@ -184,9 +155,9 @@ void SCR_ChangeRenderer(void); extern CV_PossibleValue_t cv_renderer_t[]; extern INT32 scr_bpp; -extern UINT8 *scr_borderpatch; // patch used to fill the view borders extern consvar_t cv_scr_width, cv_scr_height, cv_scr_width_w, cv_scr_height_w, cv_scr_depth, cv_fullscreen; +extern consvar_t cv_renderwalls, cv_renderfloors, cv_renderthings; extern consvar_t cv_renderview, cv_renderer; extern consvar_t cv_renderhitbox, cv_renderhitboxinterpolation, cv_renderhitboxgldepth; // wait for page flipping to end or not diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index 0f0355c6f28ad2afbd6d201f7fba46897e73f1f3..bebecd8d05a10bc9456b3dbb31d8696f737e773b 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -495,6 +495,7 @@ <ClCompile Include="..\hardware\hw_md2load.c" /> <ClCompile Include="..\hardware\hw_md3load.c" /> <ClCompile Include="..\hardware\hw_model.c" /> + <ClCompile Include="..\hardware\hw_shaders.c" /> <ClCompile Include="..\hardware\r_opengl\r_opengl.c" /> <ClCompile Include="..\lua_colorlib.c" /> <ClCompile Include="..\r_bbox.c" /> @@ -572,9 +573,6 @@ <ClCompile Include="..\r_bsp.c" /> <ClCompile Include="..\r_data.c" /> <ClCompile Include="..\r_draw.c" /> - <ClCompile Include="..\r_draw16.c"> - <ExcludedFromBuild>true</ExcludedFromBuild> - </ClCompile> <ClCompile Include="..\r_draw8.c"> <ExcludedFromBuild>true</ExcludedFromBuild> </ClCompile> diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 183843018f84087b8555fbce59e638e67cfa3546..d2f9d018f2b3ef44e59def85634aa46ef24acd95 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -751,6 +751,12 @@ <ClCompile Include="..\hardware\hw_model.c"> <Filter>Hw_Hardware</Filter> </ClCompile> + <ClCompile Include="..\hardware\hw_shaders.c"> + <Filter>Hw_Hardware</Filter> + </ClCompile> + <ClCompile Include="..\hardware\u_list.c"> + <Filter>Hw_Hardware</Filter> + </ClCompile> <ClCompile Include="..\filesrch.c"> <Filter>I_Interface</Filter> </ClCompile> @@ -976,9 +982,6 @@ <ClCompile Include="..\r_draw.c"> <Filter>R_Rend</Filter> </ClCompile> - <ClCompile Include="..\r_draw16.c"> - <Filter>R_Rend</Filter> - </ClCompile> <ClCompile Include="..\r_draw8.c"> <Filter>R_Rend</Filter> </ClCompile> diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 96e3d7d6926ef23771c8dcf489b4d8d2a16c0a1c..ca87fcc7951758e9a5de7ca1a405f88b1f202204 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -74,7 +74,7 @@ void *hwSym(const char *funcName,void *handle) { void *funcPointer = NULL; #ifdef HWRENDER - if (0 == strcmp("SetPalette", funcName)) + if (0 == strcmp("SetTexturePalette", funcName)) funcPointer = &OglSdlSetPalette; GETFUNC(Init); @@ -87,7 +87,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTexture); GETFUNC(UpdateTexture); GETFUNC(DeleteTexture); - GETFUNC(ReadRect); + GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); @@ -97,21 +97,23 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTransform); GETFUNC(PostImgRedraw); GETFUNC(FlushScreenTextures); - GETFUNC(StartScreenWipe); - GETFUNC(EndScreenWipe); GETFUNC(DoScreenWipe); - GETFUNC(DrawIntermissionBG); + GETFUNC(DrawScreenTexture); GETFUNC(MakeScreenTexture); - GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); - GETFUNC(CompileShaders); - GETFUNC(CleanShaders); + GETFUNC(InitShaders); + GETFUNC(LoadShader); + GETFUNC(CompileShader); GETFUNC(SetShader); GETFUNC(UnSetShader); GETFUNC(SetShaderInfo); - GETFUNC(LoadCustomShader); + + GETFUNC(SetPaletteLookup); + GETFUNC(CreateLightTable); + GETFUNC(ClearLightTables); + GETFUNC(SetScreenPalette); #else //HWRENDER if (0 == strcmp("FinishUpdate", funcName)) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index f03ea6226516836612195a39022723e5df11e148..5509f8cab072ddb8d8eb55c118dedd107d09dc29 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -109,6 +109,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #endif #if defined (__unix__) || (defined (UNIXCOMMON) && !defined (__APPLE__)) +#include <poll.h> #include <errno.h> #include <sys/wait.h> #define NEWSIGNALHANDLER @@ -616,50 +617,60 @@ void I_GetConsoleEvents(void) // we use this when sending back commands event_t ev = {0}; char key = 0; - ssize_t d; + struct pollfd pfd = + { + .fd = STDIN_FILENO, + .events = POLLIN, + .revents = 0, + }; if (!consolevent) return; - ev.type = ev_console; - ev.key = 0; - if (read(STDIN_FILENO, &key, 1) == -1 || !key) - return; - - // we have something - // backspace? - // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere - if ((key == tty_erase) || (key == 127) || (key == 8)) + for (;;) { - if (tty_con.cursor > 0) + if (poll(&pfd, 1, 0) < 1 || !(pfd.revents & POLLIN)) + return; + + ev.type = ev_console; + ev.key = 0; + if (read(STDIN_FILENO, &key, 1) == -1 || !key) + return; + + // we have something + // backspace? + // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere + if ((key == tty_erase) || (key == 127) || (key == 8)) { - tty_con.cursor--; - tty_con.buffer[tty_con.cursor] = '\0'; - tty_Back(); + if (tty_con.cursor > 0) + { + tty_con.cursor--; + tty_con.buffer[tty_con.cursor] = '\0'; + tty_Back(); + } + ev.key = KEY_BACKSPACE; } - ev.key = KEY_BACKSPACE; - } - else if (key < ' ') // check if this is a control char - { - if (key == '\n') + else if (key < ' ') // check if this is a control char + { + if (key == '\n') + { + tty_Clear(); + tty_con.cursor = 0; + ev.key = KEY_ENTER; + } + else continue; + } + else if (tty_con.cursor < sizeof (tty_con.buffer)) { - tty_Clear(); - tty_con.cursor = 0; - ev.key = KEY_ENTER; + // push regular character + ev.key = tty_con.buffer[tty_con.cursor] = key; + tty_con.cursor++; + // print the current line (this is differential) + write(STDOUT_FILENO, &key, 1); } - else return; + if (ev.key) D_PostEvent(&ev); + //tty_FlushIn(); } - else if (tty_con.cursor < sizeof (tty_con.buffer)) - { - // push regular character - ev.key = tty_con.buffer[tty_con.cursor] = key; - tty_con.cursor++; - // print the current line (this is differential) - d = write(STDOUT_FILENO, &key, 1); - } - if (ev.key) D_PostEvent(&ev); - //tty_FlushIn(); - (void)d; } #elif defined (_WIN32) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d3a602c05803fcd5d6aced670321aad5c723ea74..76fe172fce0e27f46ceb491be5a43f1b3e72f770 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -100,8 +100,6 @@ static char vidModeName[33][32]; // allow 33 different modes rendermode_t rendermode = render_soft; rendermode_t chosenrendermode = render_none; // set by command line arguments -boolean highcolor = false; - static void VidWaitChanged(void); // synchronize page flipping with screen refresh @@ -1297,6 +1295,14 @@ void I_FinishUpdate(void) #ifdef HWRENDER else if (rendermode == render_opengl) { + // Final postprocess step of palette rendering, after everything else has been drawn. + if (HWR_ShouldUsePaletteRendering()) + { + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC2); + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS)); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); + HWD.pfnUnSetShader(); + } OglSdlFinishUpdate(cv_vidwait.value); } #endif @@ -1395,103 +1401,12 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h) } } return -1; -#if 0 - INT32 matchMode = -1, i; - VID_PrepareModeList(); - if (USE_FULLSCREEN && numVidModes != -1) - { - for (i=firstEntry; i<numVidModes; i++) - { - if (modeList[i]->w == w && - modeList[i]->h == h) - { - matchMode = i; - break; - } - } - if (-1 == matchMode) // use smaller mode - { - w -= w%BASEVIDWIDTH; - h -= h%BASEVIDHEIGHT; - for (i=firstEntry; i<numVidModes; i++) - { - if (modeList[i]->w == w && - modeList[i]->h == h) - { - matchMode = i; - break; - } - } - if (-1 == matchMode) // use smallest mode - matchMode = numVidModes-1; - } - matchMode -= firstEntry; - } - else - { - for (i=0; i<MAXWINMODES; i++) - { - if (windowedModes[i][0] == w && - windowedModes[i][1] == h) - { - matchMode = i; - break; - } - } - if (-1 == matchMode) // use smaller mode - { - w -= w%BASEVIDWIDTH; - h -= h%BASEVIDHEIGHT; - for (i=0; i<MAXWINMODES; i++) - { - if (windowedModes[i][0] == w && - windowedModes[i][1] == h) - { - matchMode = i; - break; - } - } - if (-1 == matchMode) // use smallest mode - matchMode = MAXWINMODES-1; - } - } - return matchMode; -#endif } void VID_PrepareModeList(void) { // Under SDL2, we just use the windowed modes list, and scale in windowed fullscreen. allow_fullscreen = true; -#if 0 - INT32 i; - - firstEntry = 0; - -#ifdef HWRENDER - if (rendermode == render_opengl) - modeList = SDL_ListModes(NULL, SDL_OPENGL|SDL_FULLSCREEN); - else -#endif - modeList = SDL_ListModes(NULL, surfaceFlagsF|SDL_HWSURFACE); //Alam: At least hardware surface - - if (disable_fullscreen?0:cv_fullscreen.value) // only fullscreen needs preparation - { - if (-1 != numVidModes) - { - for (i=0; i<numVidModes; i++) - { - if (modeList[i]->w <= MAXVIDWIDTH && - modeList[i]->h <= MAXVIDHEIGHT) - { - firstEntry = i; - break; - } - } - } - } - allow_fullscreen = true; -#endif } static SDL_bool Impl_CreateContext(void) @@ -1958,32 +1873,34 @@ void VID_StartupOpenGL(void) HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL); HWD.pfnDeleteTexture = hwSym("DeleteTexture",NULL); - HWD.pfnReadRect = hwSym("ReadRect",NULL); + HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); - HWD.pfnSetPalette = hwSym("SetPalette",NULL); + HWD.pfnSetTexturePalette= hwSym("SetTexturePalette",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); HWD.pfnDrawModel = hwSym("DrawModel",NULL); HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); HWD.pfnSetTransform = hwSym("SetTransform",NULL); HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); - HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); - HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); - HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); + HWD.pfnDrawScreenTexture= hwSym("DrawScreenTexture",NULL); HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); - HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); - HWD.pfnCompileShaders = hwSym("CompileShaders",NULL); - HWD.pfnCleanShaders = hwSym("CleanShaders",NULL); + HWD.pfnInitShaders = hwSym("InitShaders",NULL); + HWD.pfnLoadShader = hwSym("LoadShader",NULL); + HWD.pfnCompileShader = hwSym("CompileShader",NULL); HWD.pfnSetShader = hwSym("SetShader",NULL); HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); - HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); + + HWD.pfnSetPaletteLookup = hwSym("SetPaletteLookup",NULL); + HWD.pfnCreateLightTable = hwSym("CreateLightTable",NULL); + HWD.pfnClearLightTables = hwSym("ClearLightTables",NULL); + HWD.pfnSetScreenPalette = hwSym("SetScreenPalette",NULL); vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index db0538195bbb6d98badb0fc27c5b0a9fac34fa81..e7347547e224b43f2fcdf66e527c8adc2681e243 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -232,7 +232,9 @@ void OglSdlFinishUpdate(boolean waitvbl) // Sryder: We need to draw the final screen texture again into the other buffer in the original position so that // effects that want to take the old screen can do so after this - HWR_DrawScreenFinalTexture(realwidth, realheight); + // Generic2 has the screen image without palette rendering brightness adjustments. + // Using that here will prevent brightness adjustments being applied twice. + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); } EXPORT void HWRAPI(OglSdlSetPalette) (RGBA_t *palette) diff --git a/src/st_stuff.c b/src/st_stuff.c index be676cff46d08541b56577b2cfdd4fd9f0971247..1f4e61822ba2132debe93c5b800b9308169c61eb 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -227,8 +227,8 @@ void ST_doPaletteStuff(void) palette = 0; #ifdef HWRENDER - if (rendermode == render_opengl) - palette = 0; // No flashpals here in OpenGL + if (rendermode == render_opengl && !HWR_ShouldUsePaletteRendering()) + palette = 0; // Don't set the palette to a flashpal in OpenGL's truecolor mode #endif if (palette != st_palette) @@ -253,10 +253,6 @@ void ST_LoadGraphics(void) { int i; - // SRB2 border patch - // st_borderpatchnum = W_GetNumForName("GFZFLR01"); - // scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX); - // the original Doom uses 'STF' as base name for all face graphics // Graue 04-08-2004: face/name graphics are now indexed by skins // but load them in R_AddSkins, that gets called @@ -1945,7 +1941,7 @@ static void ST_drawNiGHTSHUD(void) total_ringcount = stplyr->spheres; } - if (stplyr->capsule) + if (!P_MobjWasRemoved(stplyr->capsule)) { INT32 amount; const INT32 length = 88; @@ -2893,7 +2889,7 @@ void ST_Drawer(void) //25/08/99: Hurdler: palette changes is done for all players, // not only player1! That's why this part // of code is moved somewhere else. - if (rendermode == render_soft) + if (rendermode == render_soft || HWR_ShouldUsePaletteRendering()) #endif if (rendermode != render_none) ST_doPaletteStuff(); diff --git a/src/w_wad.c b/src/w_wad.c index 3a50646930e984762ffb720f2c2022edac075e33..0666c4a600bcf20678f88539fb4055a0d5466992 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -821,10 +821,7 @@ static void W_ReadFileShaders(wadfile_t *wadfile) { #ifdef HWRENDER if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) - { HWR_LoadCustomShadersFromFile(numwadfiles - 1, W_FileHasFolders(wadfile)); - HWR_CompileShaders(); - } #else (void)wadfile; #endif @@ -1171,6 +1168,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) numwadfiles++; W_ReadFileShaders(wadfile); + W_LoadTrnslateLumps(numwadfiles - 1); W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile); W_InvalidateLumpnumCache(); @@ -2707,7 +2705,7 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL); filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); numlumps = ((wadinfo_t *)wadData)->numlumps; - vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + vlumps = Z_Calloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); // Build the lumps. for (i = 0; i < numlumps; i++) @@ -2731,7 +2729,7 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) break; numlumps++; - vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + vlumps = Z_Calloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); for (i = 0; i < numlumps; i++, lumpnum++) { vlumps[i].size = W_LumpLength(lumpnum);