1.0 release. Requires 4.2.3 or higher.

- Migrated screen projection code to libeye.
- Some pickups emit light, like in Doomreal.
- Backported map revealer item from Doomreal.
- Brand new Invulnerability and Night Vision powerups.
- Add option to allow Shield Belt and armors simultaneously.
- Backported armor bonus model from Doomreal.
- Added Dual Enforcers icon for HUD.
- Changed player class names to their character names, like in Doomreal.
- Terrain splashes.
- Translocator doesn't telefrag other players in coop.
- Reduced view shake from Impact Hammer.
- Various other updates and bug fixes.
This commit is contained in:
Marisa the Magician 2019-10-21 21:57:35 +02:00
commit b79d29f071
91 changed files with 1994 additions and 511 deletions

View file

@ -0,0 +1,58 @@
libeye (for projection and deprojection)
written by KeksDose / MemeDose (May 2019)
(updated July 2019)
All rights etc. etc. who cares, you may reuse this as you wish and edit it, and
leave this note intact.
//
//
/////((
@@////////// ((
(( %////((///// (( (( ((
(( @@//(((/////// ((( ////////////// ((
( /////////////////////////(((((((////////// ((
@@///@@@@@@//////////(((((((((//@@@////////// ((
(( ///// /////((((((((((((((//@@% %%@/////////// ((
//////////((((((((((((((//////((((( %%@@////////// ((
((%%//////////@@%% @@//(((((((/// ( (((( %%///////// (
(( ////////@@ ((( @@//(((((((///// (( ( @@/////////
((/////////@ (( (( @@/(((((((///// (( (( @@/((((///((
(( ///((//@@ (( (( %@@@@@@////////// (((( /((((/// ((
((/////((//%%( ////%%%@@////////// @//((((///
////(((// ///////// //@@/////////////////(((((//
( ////(((////( //////////////////////@@@@////////////(((((////((
////(((((((// //////////////////////////// %%@@///(((((((((// (
//(((((((((/////////////////// //////////// %%@//(((((((//// ((
//(((((((((((////////////((/// /////////////// @@//(((((((///
//(((((((((((////////(( /////////((//////////// ( //(((((((///////
//((((((( ((///////( ##### ////( ((/////// ( @@//(((((///////
//((((((( (((//////((( ### (((( ##### ((/////// (( //(((///////@@
//((((((((((((@@/////////(((((((((((((((((((((///// ///////////% ((
//((((((((((((%% ///////((((((((((((//////// //////////////@@%% ((
@@//(((((((((/%%(( /////////////////////// ///////////////// (((
( //(((((((((/ (( ///////////////////////
%%//(((((((///(( (( //////////////@///////%%
(( @@/((((((///(( (( //////////////@@%% /////// ((
(( /(((((((// ( //////////////@%% //////%((
(( @@//(((////(( (( /////(((((((///@@ ((( /////// (
( @@(((((// ( ////(((((((///@@% (((( /////////%%((
((%%//(((/////////(((((((//@%% //////////%% ((
((////(((((///////(((((///////////////////////% ((
( ////(((((/////(((((((((//////////((((///@@%% ((
////(((//////@//////(((((((((((((////@@@%% (
(( /////////@@%% %%@@@@@@@@@@@@@@@@@@@%% ((
(( @@@@@%% ((
(( (((
%%//%
( //((/ ((
( ///////((
( ///////((
///// ((
//
//
(( ///// ((

View file

@ -0,0 +1,150 @@
/* kd:
In open-gl, your screen rotates nicely and you can do mostly what you know
to be sane. It's all about making a rotation of your view and using what
you know about right triangles.
*/
class dtLe_GlScreen : dtLe_ProjScreen {
protected vector3 forw_unit;
protected vector3 right_unit;
protected vector3 down_unit;
override void Reorient (vector3 world_view_pos, vector3 world_ang) {
// kd: Pitch is a weird gzd joke. It's probably to compensate looking
// speed and all. After that, you see what makes this fast.
world_ang.y = VectorAngle(
cos(world_ang.y),
sin(world_ang.y) * pixel_stretch);
super.Reorient(world_view_pos, world_ang);
let cosang = cos(world_ang.x);
let cosvang = cos(world_ang.y);
let cosrang = cos(world_ang.z);
let sinang = sin(world_ang.x);
let sinvang = sin(world_ang.y);
let sinrang = sin(world_ang.z);
let right_no_roll = (
sinang,
- cosang,
0);
let down_no_roll = (
- sinvang * cosang,
- sinvang * sinang,
- cosvang);
forw_unit = (
cosvang * cosang,
cosvang * sinang,
- sinvang);
down_unit = cosrang * down_no_roll - sinrang * right_no_roll;
right_unit = cosrang * right_no_roll + sinrang * down_no_roll;
}
// kd: Projection handling. These get called to make stuff a little faster,
// since you may wanna project many many times.
protected vector3 forw_in;
protected vector3 right_in;
protected vector3 down_in;
override void BeginProjection () {
forw_in = forw_unit;
right_in = right_unit / tan_fov_2.x;
down_in = down_unit / tan_fov_2.y;
forw_in.z *= pixel_stretch;
right_in.z *= pixel_stretch;
down_in.z *= pixel_stretch;
}
override void ProjectWorldPos (vector3 world_pos) {
diff = levellocals.vec3diff(view_pos, world_pos);
proj_pos = (diff dot right_in, diff dot down_in);
depth = diff dot forw_in;
}
override void ProjectActorPos (Actor mo, vector3 offset, double t) {
let inter_pos = mo.prev + t * (mo.pos - mo.prev);
diff = levellocals.vec3diff(view_pos, inter_pos + offset);
proj_pos = (diff dot right_in, diff dot down_in);
depth = diff dot forw_in;
}
override void ProjectActorPosPortal (Actor mo, vector3 offset, double t) {
let inter_pos = mo.prev + t * levellocals.vec3diff(mo.prev, mo.pos);
diff = levellocals.vec3diff(view_pos, inter_pos + offset);
proj_pos = (diff dot right_in, diff dot down_in);
depth = diff dot forw_in;
}
override vector2 ProjectToNormal () const {
return proj_pos / depth;
}
override vector2 ProjectToScreen () const {
let normal_pos = proj_pos / depth + (1, 1);
return 0.5 * (
normal_pos.x * resolution.x,
normal_pos.y * resolution.y);
}
override vector2 ProjectToCustom (
vector2 origin,
vector2 resolution) const {
let normal_pos = proj_pos / depth + (1, 1);
return origin + 0.5 * (
normal_pos.x * resolution.x,
normal_pos.y * resolution.y);
}
// kd: Same deal but backwards-ish.
protected vector3 forw_out;
protected vector3 right_out;
protected vector3 down_out;
override void BeginDeprojection () {
// kd: Same deal as above, but reversed. This time, we're compensating
// for what we rightfully assume is a projected position.
forw_out = forw_unit;
right_out = right_unit * tan_fov_2.x;
down_out = down_unit * tan_fov_2.y;
forw_out.z /= pixel_stretch;
right_out.z /= pixel_stretch;
down_out.z /= pixel_stretch;
}
override vector3 DeprojectNormalToDiff (
vector2 normal_pos,
double depth) const {
return depth * (
forw_out +
normal_pos.x * right_out +
normal_pos.y * down_out);
}
override vector3 DeprojectScreenToDiff (
vector2 screen_pos,
double depth) const {
// kd: Same thing...
let normal_pos = 2 * (
screen_pos.x / resolution.x,
screen_pos.y / resolution.y) - (1, 1);
return depth * (
forw_out +
normal_pos.x * right_out +
normal_pos.y * down_out);
}
}

View file

@ -0,0 +1,125 @@
/* kd:
This does projection stuff in Carmack / software renderer. It's conceptually
simpler, but nonetheless a little tricky to understand if you're
used to open-gl.
*/
class dtLe_SwScreen : dtLe_ProjScreen {
// kd: Less info necessary than for open-gl, but it's there.
protected vector2 right_planar_unit;
protected vector3 forw_planar_unit;
override void Reorient (vector3 world_view_pos, vector3 world_ang) {
super.Reorient(world_view_pos, world_ang);
right_planar_unit = (
sin(view_ang.x),
- cos(view_ang.x));
forw_planar_unit = (
- right_planar_unit.y,
right_planar_unit.x,
tan(view_ang.y));
}
// kd: Projection:
protected vector3 forw_planar_in;
protected vector2 right_planar_in;
override void BeginProjection () {
// kd: This doesn't cause any imprecisions. It also prevents two
// multiplications with every projection.
right_planar_in = right_planar_unit / tan_fov_2.x;
forw_planar_in = forw_planar_unit;
}
override void ProjectWorldPos (vector3 world_pos) {
// kd: Your view is flat. If you pitch up or down, imagine that all the
// actors move up and down in reality. That's effectively how it works.
// You can see this in the addition to diff.z.
diff = levellocals.vec3diff(view_pos, world_pos);
depth = forw_planar_in.xy dot diff.xy;
diff.z += forw_planar_in.z * depth;
proj_pos = (
right_planar_in dot diff.xy,
- pixel_stretch * diff.z / tan_fov_2.y);
}
override void ProjectActorPos (Actor mo, vector3 offset, double t) {
let inter_pos = mo.prev + t * (mo.pos - mo.prev);
ProjectWorldPos(inter_pos + offset);
}
override void ProjectActorPosPortal (Actor mo, vector3 offset, double t) {
let inter_pos = mo.prev + t * levellocals.vec3diff(mo.prev, mo.pos);
ProjectWorldPos(inter_pos + offset);
}
override vector2 ProjectToNormal () const {
return proj_pos / depth;
}
override vector2 ProjectToScreen () const {
let normal_pos = proj_pos / depth + (1, 1);
return 0.5 * (
normal_pos.x * resolution.x,
normal_pos.y * resolution.y);
}
override vector2 ProjectToCustom (
vector2 origin,
vector2 resolution) const {
let normal_pos = proj_pos / depth + (1, 1);
return origin + 0.5 * (
normal_pos.x * resolution.x,
normal_pos.y * resolution.y);
}
// kd: Just as simple. You again assume you are trying to reverse a
// projected position from the screen back into the world.
protected vector3 forw_planar_out;
protected vector3 right_planar_out;
protected vector3 down_planar_out;
override void BeginDeprojection () {
forw_planar_out.xy = forw_planar_unit.xy;
forw_planar_out.z = 0;
right_planar_out.xy = tan_fov_2.x * right_planar_unit;
right_planar_out.z = 0;
down_planar_out = (
0,
0,
tan_fov_2.y / pixel_stretch);
}
override vector3 DeprojectNormalToDiff (
vector2 normal_pos,
double depth) const {
return depth * (
forw_planar_out +
normal_pos.x * right_planar_out +
- (0, 0, forw_planar_unit.z) - normal_pos.y * down_planar_out);
}
override vector3 DeprojectScreenToDiff (
vector2 screen_pos,
double depth) const {
// kd: Same thing...
let normal_pos = 2 * (
screen_pos.x / resolution.x,
screen_pos.y / resolution.y) - (1, 1);
return depth * (
forw_planar_out +
normal_pos.x * right_planar_out +
- (0, 0, forw_planar_unit.z) - normal_pos.y * down_planar_out);
}
}

View file

@ -0,0 +1,193 @@
/* kd:
Here's how to do projections and deprojections. You'd use the subclasses
to do anything worthwhile. You may project world to screen and backwards.
*/
class dtLe_ProjScreen {
// kd: Screen info
protected vector2 resolution;
protected vector2 origin;
protected vector2 tan_fov_2;
protected double pixel_stretch;
protected double aspect_ratio;
// kd: Setup calls which you'll need to call at least once.
void CacheResolution () {
CacheCustomResolution((Screen.GetWidth(), Screen.GetHeight()) );
}
void CacheCustomResolution (vector2 new_resolution) {
// kd: This is for convenience and converting normal <-> screen pos.
resolution = new_resolution;
// kd: This isn't really necessary but I kinda like it.
pixel_stretch = level.pixelstretch;
// kd: Get the aspect ratio. 5:4 is handled just like 4:3... I GUESS
// this'll do.
aspect_ratio = max(4.0 / 3, Screen.GetAspectRatio());
}
double AspectRatio () const {
return aspect_ratio;
}
// kd: Once you know you got screen info, you can call this whenever your
// fov changes. Like CacheFov(player.fov) will do.
void CacheFov (double hor_fov = 90) {
// kd: This holds: aspect ratio = tan(horizontal fov) / tan(ver fov).
// gzd always uses hor fov, but the fov only holds in 4:3 (in a 4:3 box
// in your screen centre), so we just extend it.
tan_fov_2.x = tan(hor_fov / 2) * aspect_ratio / (4.0 / 3);
tan_fov_2.y = tan_fov_2.x / aspect_ratio;
}
// kd: Also need some view info. Angle is yaw, pitch, roll in world format
// so positive pitch is up. Call one of the following functions.
protected vector3 view_ang;
protected vector3 view_pos;
ui void OrientForRenderOverlay (RenderEvent event) {
Reorient(
event.viewpos, (
event.viewangle,
event.viewpitch,
event.viewroll));
}
ui void OrientForRenderUnderlay (RenderEvent event) {
Reorient(
event.viewpos, (
event.viewangle,
event.viewpitch,
event.viewroll));
}
void OrientForPlayer (PlayerInfo player) {
Reorient(
player.mo.vec3offset(0, 0, player.viewheight), (
player.mo.angle,
player.mo.pitch,
player.mo.roll));
}
virtual void Reorient (vector3 world_view_pos, vector3 world_ang) {
view_ang = world_ang;
view_pos = world_view_pos;
}
// kd: Now we can do projections and such (position in the level, go to
// your screen).
protected double depth;
protected vector2 proj_pos;
protected vector3 diff;
virtual void BeginProjection () {}
virtual void ProjectWorldPos (vector3 world_pos) {}
virtual void ProjectActorPos (
Actor mo,
vector3 offset = (0,0,0),
double t = 1) {}
// kd: Portal aware version.
virtual void ProjectActorPosPortal (
Actor mo,
vector3 offset = (0,0,0),
double t = 1) {}
virtual vector2 ProjectToNormal () const { return (0, 0); }
virtual vector2 ProjectToScreen () const { return (0, 0); }
virtual vector2 ProjectToCustom (
vector2 origin,
vector2 resolution) const {
return (0, 0);
}
bool IsInFront () const {
return 0 < depth;
}
bool IsInScreen () const {
if( proj_pos.x < -depth || depth < proj_pos.x ||
proj_pos.y < -depth || depth < proj_pos.y) {
return false;
}
return true;
}
// kd: Deprojection (point on screen, go into the world):
virtual void BeginDeprojection () {}
virtual vector3 DeprojectNormalToDiff (
vector2 normal_pos,
double depth = 1) const {
return (0, 0, 0);
}
virtual vector3 DeprojectScreenToDiff (
vector2 screen_pos,
double depth = 1) const {
return (0, 0, 0);
}
virtual vector3 DeprojectCustomToDiff (
vector2 origin,
vector2 resolution,
vector2 screen_pos,
double depth = 1) const {
return (0, 0, 0);
}
// kd: A normal position is in the -1 <= x, y <= 1 range on your screen.
// This will be your screen no matter the resolution:
/*
(-1, -1) -- --- --- (0, -1) --- --- --- --- (1, -1)
| |
| |
| |
(-1, 0) (0, 0) (1, 0)
| |
| |
| |
(-1, 1) --- --- --- (0, 1) --- --- --- --- (1, 1)
*/
// So this scales such a position back into your drawing resolution.
vector2 NormalToScreen (vector2 normal_pos) const {
normal_pos = 0.5 * (normal_pos + (1, 1));
return (
normal_pos.x * resolution.x,
normal_pos.y * resolution.y);
}
// kd: And this brings a screen position to normal. Make sure the resolution
// is the same for your cursor.
vector2 ScreenToNormal (vector2 screen_pos) const {
screen_pos = (
screen_pos.x / resolution.x,
screen_pos.y / resolution.y);
return 2 * screen_pos - (1, 1);
}
// kd: Other interesting stuff.
vector3 Difference () const {
return diff;
}
double Distance () const {
return diff.length();
}
}

View file

@ -0,0 +1,141 @@
/* kd:
This helps repositioning the view port for stuff like screen blocks. It's a
little more than that, cuz it can also determine stuff like, "is this scene
position in the viewport?" Cuz the scene doesn't necessarily match the
viewport.
Well yea... see the examples. Imagine how annoying it is to even get this
idea to begin with.
*/
struct dtLe_Viewport {
private vector2 scene_origin;
private vector2 scene_size;
private vector2 viewport_origin;
private vector2 viewport_bound;
private vector2 viewport_size;
private double scene_aspect;
private double viewport_aspect;
private double scale_f;
private vector2 scene_to_viewport;
ui void FromHud () const {
scene_aspect = Screen.GetAspectRatio();
vector2 hud_origin;
vector2 hud_size;
[hud_origin.x, hud_origin.y, hud_size.x, hud_size.y] =
Screen.GetViewWindow();
let window_resolution = (
Screen.GetWidth(),
Screen.GetHeight());
let window_to_normal = (
1.0 / window_resolution.x,
1.0 / window_resolution.y);
viewport_origin = (
window_to_normal.x * hud_origin.x,
window_to_normal.y * hud_origin.y);
viewport_size = (
window_to_normal.x * hud_size.x,
window_to_normal.y * hud_size.y);
viewport_aspect = hud_size.x / hud_size.y;
viewport_bound = viewport_origin + viewport_size;
// kd: The scene is what is actually rendered. It's not always the same
// as the viewport. When the statusbar comes into play, the scene is
// obscured by the viewport being too small.
// Example: Compare screenblocks 11 against screenblocks 10 in unmodded
// Doom. You will notice that the scaling of the 3d world is the same,
// but it's moved up by half the height of the statusbar.
// That makes this viewport stuff kinda really annoying to deal with.
// Also statusbar.getsomethingfromstatusbar, really really nice naming.
let statusbar_height =
(window_resolution.y - Statusbar.GetTopOfStatusbar()) / window_resolution.y;
scale_f = hud_size.x / window_resolution.x;
scene_aspect = Screen.GetAspectRatio();
let offset = 10 < screenblocks ? 0 : 0.5 * statusbar_height;
scene_size = (
scale_f,
scale_f);
scene_origin = viewport_origin - (0, 0.5 * (scene_size.y - viewport_size.y));
scene_to_viewport = (
viewport_size.x / scene_size.x,
viewport_size.y / scene_size.y);
}
// kd: Is the scene pos (normal, just like projected normal) inside the
// view port? If yes, it's visible in the 3d world, even through resizing.
bool IsInside (vector2 scene_pos) const {
let normal_pos = scene_origin + (
scene_size.x * 0.5 * (1 + scene_pos.x),
scene_size.y * 0.5 * (1 + scene_pos.y));
if( normal_pos.x < viewport_origin.x || viewport_bound.x < normal_pos.x ||
normal_pos.y < viewport_origin.y || viewport_bound.y < normal_pos.y) {
return false;
}
return true;
}
// kd: Use these for drawing (and make sure the aspect ratios match).
vector2 SceneToCustom (vector2 scene_pos, vector2 resolution) const {
let normal_pos = 0.5 * (
(scene_pos.x + 1) * scene_size.x,
(scene_pos.y + 1) * scene_size.y);
return (
(scene_origin.x + normal_pos.x) * resolution.x,
(scene_origin.y + normal_pos.y) * resolution.y);
}
vector2 SceneToWindow (vector2 scene_pos) const {
return SceneToCustom(
scene_pos,
(Screen.GetWidth(), Screen.GetHeight()) );
}
vector2 ViewportToCustom (vector2 viewport_pos, vector2 resolution) const {
let normal_pos = 0.5 * (
(viewport_pos.x + 1) * viewport_size.x,
(viewport_pos.y + 1) * viewport_size.y);
return (
(viewport_origin.x + normal_pos.x) * resolution.x,
(viewport_origin.y + normal_pos.y) * resolution.y);
}
vector2 ViewportToWindow (vector2 viewport_pos) const {
return ViewportToCustom(
viewport_pos,
(Screen.GetWidth(), Screen.GetHeight()) );
}
double Scale () const {
return scale_f;
}
}