mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-01 00:21:43 +00:00
cd7986b1b1
- moved FLevelLocals to its own header to resolve some circular include conflicts.
317 lines
9.4 KiB
C++
317 lines
9.4 KiB
C++
/*
|
|
** p_3dmidtex.cpp
|
|
**
|
|
** Eternity-style 3D-midtex handling
|
|
** (No original Eternity code here!)
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 2008 Christoph Oelckers
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
|
|
#include "templates.h"
|
|
#include "p_3dmidtex.h"
|
|
#include "p_local.h"
|
|
#include "p_terrain.h"
|
|
#include "p_maputl.h"
|
|
#include "p_spec.h"
|
|
#include "g_levellocals.h"
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// P_Scroll3dMidtex
|
|
//
|
|
// Scrolls all sidedefs belonging to 3dMidtex lines attached to this sector
|
|
//
|
|
//============================================================================
|
|
|
|
bool P_Scroll3dMidtex(sector_t *sector, int crush, double move, bool ceiling, bool instant)
|
|
{
|
|
extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
|
|
|
|
// First step: Change all lines' texture offsets
|
|
for(unsigned i = 0; i < scrollplane.AttachedLines.Size(); i++)
|
|
{
|
|
line_t *l = scrollplane.AttachedLines[i];
|
|
|
|
l->sidedef[0]->AddTextureYOffset(side_t::mid, move);
|
|
l->sidedef[1]->AddTextureYOffset(side_t::mid, move);
|
|
}
|
|
|
|
// Second step: Check all sectors whether the move is ok.
|
|
bool res = false;
|
|
|
|
for(unsigned i = 0; i < scrollplane.AttachedSectors.Size(); i++)
|
|
{
|
|
res |= P_ChangeSector(scrollplane.AttachedSectors[i], crush, move, 2, true, instant);
|
|
}
|
|
return !res;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// P_Start3DMidtexInterpolations
|
|
//
|
|
// Starts interpolators for every sidedef that is being changed by moving
|
|
// this sector
|
|
//
|
|
//============================================================================
|
|
|
|
void P_Start3dMidtexInterpolations(TArray<DInterpolation *> &list, sector_t *sector, bool ceiling)
|
|
{
|
|
extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
|
|
|
|
for(unsigned i = 0; i < scrollplane.AttachedLines.Size(); i++)
|
|
{
|
|
line_t *l = scrollplane.AttachedLines[i];
|
|
|
|
list.Push(l->sidedef[0]->SetInterpolation(side_t::mid));
|
|
list.Push(l->sidedef[1]->SetInterpolation(side_t::mid));
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// P_Attach3dMidtexLinesToSector
|
|
//
|
|
// Attaches 3dMidtex lines to a sector.
|
|
// If lineid is != 0, all lines with the matching line id will be added
|
|
// If tag is != 0, all lines touching a sector with the matching tag will be added
|
|
// If both are != 0, all lines with the matching line id that touch a sector with
|
|
// the matching tag will be added.
|
|
//
|
|
//============================================================================
|
|
|
|
void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool ceiling)
|
|
{
|
|
int v;
|
|
|
|
if (lineid == 0 && tag == 0)
|
|
{
|
|
// invalid set of parameters
|
|
return;
|
|
}
|
|
|
|
extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
|
|
|
|
// Bit arrays that mark whether a line or sector is to be attached.
|
|
BYTE *found_lines = new BYTE[(level.lines.Size()+7)/8];
|
|
BYTE *found_sectors = new BYTE[(level.sectors.Size()+7)/8];
|
|
|
|
memset(found_lines, 0, sizeof (BYTE) * ((level.lines.Size()+7)/8));
|
|
memset(found_sectors, 0, sizeof (BYTE) * ((level.sectors.Size()+7)/8));
|
|
|
|
// mark all lines and sectors that are already attached to this one
|
|
// and clear the arrays. The old data will be re-added automatically
|
|
// from the marker arrays.
|
|
for (unsigned i=0; i < scrollplane.AttachedLines.Size(); i++)
|
|
{
|
|
int line = scrollplane.AttachedLines[i]->Index();
|
|
found_lines[line>>3] |= 1 << (line&7);
|
|
}
|
|
|
|
for (unsigned i=0; i < scrollplane.AttachedSectors.Size(); i++)
|
|
{
|
|
int sec = scrollplane.AttachedSectors[i]->Index();
|
|
found_sectors[sec>>3] |= 1 << (sec&7);
|
|
}
|
|
|
|
scrollplane.AttachedLines.Clear();
|
|
scrollplane.AttachedSectors.Clear();
|
|
|
|
if (tag == 0)
|
|
{
|
|
FLineIdIterator itr(lineid);
|
|
int line;
|
|
while ((line = itr.Next()) >= 0)
|
|
{
|
|
line_t *ln = &level.lines[line];
|
|
|
|
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
|
|
{
|
|
// Only consider two-sided lines with the 3DMIDTEX flag
|
|
continue;
|
|
}
|
|
found_lines[line>>3] |= 1 << (line&7);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FSectorTagIterator it(tag);
|
|
int sec;
|
|
while ((sec = it.Next()) >= 0)
|
|
{
|
|
for (auto ln : level.sectors[sec].Lines)
|
|
{
|
|
if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
|
|
|
|
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
|
|
{
|
|
// Only consider two-sided lines with the 3DMIDTEX flag
|
|
continue;
|
|
}
|
|
int lineno = ln->Index();
|
|
found_lines[lineno >> 3] |= 1 << (lineno & 7);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for(unsigned i=0; i < level.lines.Size(); i++)
|
|
{
|
|
if (found_lines[i>>3] & (1 << (i&7)))
|
|
{
|
|
auto &line = level.lines[i];
|
|
scrollplane.AttachedLines.Push(&line);
|
|
|
|
v = line.frontsector->Index();
|
|
assert(v < (int)level.sectors.Size());
|
|
found_sectors[v>>3] |= 1 << (v&7);
|
|
|
|
v = line.backsector->Index();
|
|
assert(v < (int)level.sectors.Size());
|
|
found_sectors[v>>3] |= 1 << (v&7);
|
|
}
|
|
}
|
|
|
|
for (unsigned i=0; i < level.sectors.Size(); i++)
|
|
{
|
|
if (found_sectors[i>>3] & (1 << (i&7)))
|
|
{
|
|
scrollplane.AttachedSectors.Push(&level.sectors[i]);
|
|
}
|
|
}
|
|
|
|
delete[] found_lines;
|
|
delete[] found_sectors;
|
|
}
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// P_GetMidTexturePosition
|
|
//
|
|
// Retrieves top and bottom of the current line's mid texture.
|
|
//
|
|
//============================================================================
|
|
bool P_GetMidTexturePosition(const line_t *line, int sideno, double *ptextop, double *ptexbot)
|
|
{
|
|
if (line->sidedef[0]==NULL || line->sidedef[1]==NULL) return false;
|
|
|
|
side_t *side = line->sidedef[sideno];
|
|
FTextureID texnum = side->GetTexture(side_t::mid);
|
|
if (!texnum.isValid()) return false;
|
|
FTexture * tex= TexMan(texnum);
|
|
if (!tex) return false;
|
|
|
|
double totalscale = fabs(side->GetTextureYScale(side_t::mid)) * tex->GetScaleY();
|
|
double y_offset = side->GetTextureYOffset(side_t::mid);
|
|
double textureheight = tex->GetHeight() / totalscale;
|
|
if (totalscale != 1. && !tex->bWorldPanning)
|
|
{
|
|
y_offset /= totalscale;
|
|
}
|
|
|
|
if(line->flags & ML_DONTPEGBOTTOM)
|
|
{
|
|
*ptexbot = y_offset +
|
|
MAX(line->frontsector->GetPlaneTexZ(sector_t::floor), line->backsector->GetPlaneTexZ(sector_t::floor));
|
|
|
|
*ptextop = *ptexbot + textureheight;
|
|
}
|
|
else
|
|
{
|
|
*ptextop = y_offset +
|
|
MIN(line->frontsector->GetPlaneTexZ(sector_t::ceiling), line->backsector->GetPlaneTexZ(sector_t::ceiling));
|
|
|
|
*ptexbot = *ptextop - textureheight;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// P_LineOpening_3dMidtex
|
|
//
|
|
// 3dMidtex part of P_LineOpening
|
|
//
|
|
//============================================================================
|
|
|
|
bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening &open, bool restrict)
|
|
{
|
|
// [TP] Impassible-like 3dmidtextures do not block missiles
|
|
if ((linedef->flags & ML_3DMIDTEX_IMPASS)
|
|
&& (thing->flags & MF_MISSILE || thing->BounceFlags & BOUNCE_MBF))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
double tt, tb;
|
|
|
|
open.abovemidtex = false;
|
|
if (P_GetMidTexturePosition(linedef, 0, &tt, &tb))
|
|
{
|
|
if (thing->Center() < (tt + tb)/2)
|
|
{
|
|
if (tb < open.top)
|
|
{
|
|
open.top = tb;
|
|
open.ceilingpic = linedef->sidedef[0]->GetTexture(side_t::mid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (tt > open.bottom && (!restrict || thing->Z() >= tt))
|
|
{
|
|
open.bottom = tt;
|
|
open.abovemidtex = true;
|
|
open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid);
|
|
open.floorterrain = TerrainTypes[open.floorpic];
|
|
open.frontfloorplane.SetAtHeight(tt, sector_t::floor);
|
|
open.backfloorplane.SetAtHeight(tt, sector_t::floor);
|
|
|
|
}
|
|
// returns true if it touches the midtexture
|
|
return (fabs(thing->Z() - tt) <= thing->MaxStepHeight);
|
|
}
|
|
}
|
|
return false;
|
|
|
|
/* still have to figure out what this code from Eternity means...
|
|
if((linedef->flags & ML_BLOCKMONSTERS) &&
|
|
!(mo->flags & (MF_FLOAT | MF_DROPOFF)) &&
|
|
fabs(mo->Z() - tt) <= 24)
|
|
{
|
|
opentop = openbottom;
|
|
openrange = 0;
|
|
return;
|
|
}
|
|
*/
|
|
}
|