mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 20:20:40 +00:00
- added an intermediate data structure to decouple the rendering from the immediate map data.
This will be needed for sectors consisting of disjoint parts and for providing some help with addressing rendering anomalies
This commit is contained in:
parent
8003ab6fa3
commit
30b1b046e4
7 changed files with 152 additions and 31 deletions
|
@ -1082,6 +1082,7 @@ set (PCH_SOURCES
|
||||||
core/rendering/hw_models.cpp
|
core/rendering/hw_models.cpp
|
||||||
core/rendering/hw_voxels.cpp
|
core/rendering/hw_voxels.cpp
|
||||||
core/rendering/hw_palmanager.cpp
|
core/rendering/hw_palmanager.cpp
|
||||||
|
core/rendering/hw_sections.cpp
|
||||||
core/rendering/scene/hw_clipper.cpp
|
core/rendering/scene/hw_clipper.cpp
|
||||||
core/rendering/scene/hw_walls.cpp
|
core/rendering/scene/hw_walls.cpp
|
||||||
core/rendering/scene/hw_flats.cpp
|
core/rendering/scene/hw_flats.cpp
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "gamefuncs.h"
|
#include "gamefuncs.h"
|
||||||
#include "sectorgeometry.h"
|
#include "sectorgeometry.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "hw_sections.h"
|
||||||
|
|
||||||
static void ReadSectorV7(FileReader& fr, sectortype& sect)
|
static void ReadSectorV7(FileReader& fr, sectortype& sect)
|
||||||
{
|
{
|
||||||
|
@ -451,6 +452,7 @@ void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang,
|
||||||
md4once(buffer.Data(), buffer.Size(), md4);
|
md4once(buffer.Data(), buffer.Size(), md4);
|
||||||
G_LoadMapHack(filename, md4);
|
G_LoadMapHack(filename, md4);
|
||||||
setWallSectors();
|
setWallSectors();
|
||||||
|
hw_BuildSections();
|
||||||
|
|
||||||
memcpy(wallbackup, wall, sizeof(wallbackup));
|
memcpy(wallbackup, wall, sizeof(wallbackup));
|
||||||
memcpy(sectorbackup, sector, sizeof(sectorbackup));
|
memcpy(sectorbackup, sector, sizeof(sectorbackup));
|
||||||
|
|
75
source/core/rendering/hw_sections.cpp
Normal file
75
source/core/rendering/hw_sections.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
** hw_sectiona.cpp
|
||||||
|
** For decoupling the renderer from internal Build structures
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2021 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.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
** The sole reason for existence of this file is that Build's sector setup
|
||||||
|
** does not allow for easy splitting of sectors, either for having disjoint parts
|
||||||
|
** or requiring partial rendering. So we need to add a superstructure
|
||||||
|
** where we can shuffle around some content without disturbing the original
|
||||||
|
** order...
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "hw_sections.h"
|
||||||
|
|
||||||
|
|
||||||
|
SectionLine sectionLines[MAXWALLS + (MAXWALLS >> 2)];
|
||||||
|
Section sections[MAXSECTORS + (MAXSECTORS >> 2)];
|
||||||
|
TArray<int> sectionspersector[MAXSECTORS]; // reverse map, mainly for the automap
|
||||||
|
int numsections;
|
||||||
|
int numsectionlines;
|
||||||
|
|
||||||
|
|
||||||
|
void hw_BuildSections()
|
||||||
|
{
|
||||||
|
// Initial setup just creates a 1:1 mapping of walls to section lines and sectors to sections.
|
||||||
|
numsectionlines = numwalls;
|
||||||
|
numsections = numsectors;
|
||||||
|
for (int i = 0; i < numwalls; i++)
|
||||||
|
{
|
||||||
|
sectionLines[i].startpoint = sectionLines[i].wall = i;
|
||||||
|
sectionLines[i].endpoint = wall[i].point2;
|
||||||
|
sectionLines[i].partner = wall[i].nextwall;
|
||||||
|
sectionLines[i].section = wall[i].sector;
|
||||||
|
sectionLines[i].partnersection = wall[i].nextsector;
|
||||||
|
sectionLines[i].point2index = wall[i].point2 - sector[wall[i].sector].wallptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < numsectors; i++)
|
||||||
|
{
|
||||||
|
sections[i].sector = i;
|
||||||
|
sections[i].lines.Resize(sector[i].wallnum);
|
||||||
|
for (int j = 0; j < sector[i].wallnum; j++) sections[i].lines[j] = sector[i].wallptr + j;
|
||||||
|
sectionspersector[i].Resize(1);
|
||||||
|
sectionspersector[i][0] = i;
|
||||||
|
}
|
||||||
|
}
|
31
source/core/rendering/hw_sections.h
Normal file
31
source/core/rendering/hw_sections.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "build.h"
|
||||||
|
|
||||||
|
struct SectionLine
|
||||||
|
{
|
||||||
|
int16_t section;
|
||||||
|
int16_t partnersection;
|
||||||
|
int16_t startpoint;
|
||||||
|
int16_t endpoint;
|
||||||
|
int16_t wall;
|
||||||
|
int16_t partner;
|
||||||
|
int16_t point2index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Section
|
||||||
|
{
|
||||||
|
int sector;
|
||||||
|
// this is the whole point of sections - instead of just having a start index and count, we have an explicit list of lines that's a lot easier to change when needed.
|
||||||
|
TArray<int16_t> lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
// giving 25% more may be a bit high as normally this should be small numbers only.
|
||||||
|
extern SectionLine sectionLines[MAXWALLS + (MAXWALLS >> 2)];
|
||||||
|
extern Section sections[MAXSECTORS + (MAXSECTORS >> 2)];
|
||||||
|
extern TArray<int> sectionspersector[MAXSECTORS]; // reverse map, mainly for the automap
|
||||||
|
extern int numsections;
|
||||||
|
extern int numsectionlines;
|
||||||
|
|
||||||
|
|
||||||
|
void hw_BuildSections();
|
|
@ -57,6 +57,7 @@
|
||||||
#include "interpolate.h"
|
#include "interpolate.h"
|
||||||
#include "gamefuncs.h"
|
#include "gamefuncs.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "hw_sections.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -639,6 +640,7 @@ void SerializeMap(FSerializer& arc)
|
||||||
if (arc.isReading())
|
if (arc.isReading())
|
||||||
{
|
{
|
||||||
setWallSectors();
|
setWallSectors();
|
||||||
|
hw_BuildSections();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "gamefuncs.h"
|
#include "gamefuncs.h"
|
||||||
#include "texturemanager.h"
|
#include "texturemanager.h"
|
||||||
#include "earcut.hpp"
|
#include "earcut.hpp"
|
||||||
|
#include "hw_sections.h"
|
||||||
#include "nodebuilder/nodebuild.h"
|
#include "nodebuilder/nodebuild.h"
|
||||||
|
|
||||||
SectorGeometry sectorGeometry;
|
SectorGeometry sectorGeometry;
|
||||||
|
@ -217,8 +218,9 @@ public:
|
||||||
|
|
||||||
bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2& offset)
|
bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2& offset)
|
||||||
{
|
{
|
||||||
auto sec = §or[secnum];
|
auto sec = §ions[secnum];
|
||||||
int numvertices = sec->wallnum;
|
auto sectorp = §or[sec->sector];
|
||||||
|
int numvertices = sec->lines.Size();
|
||||||
|
|
||||||
TArray<FVector3> points(numvertices, true);
|
TArray<FVector3> points(numvertices, true);
|
||||||
using Point = std::pair<float, float>;
|
using Point = std::pair<float, float>;
|
||||||
|
@ -229,7 +231,7 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
curPoly = &polygon.back();
|
curPoly = &polygon.back();
|
||||||
FixedBitArray<MAXWALLSB> done;
|
FixedBitArray<MAXWALLSB> done;
|
||||||
|
|
||||||
int fz = sec->floorz, cz = sec->ceilingz;
|
int fz = sectorp->floorz, cz = sectorp->ceilingz;
|
||||||
|
|
||||||
int vertstoadd = numvertices;
|
int vertstoadd = numvertices;
|
||||||
|
|
||||||
|
@ -243,7 +245,8 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
{
|
{
|
||||||
while (!done[start])
|
while (!done[start])
|
||||||
{
|
{
|
||||||
auto wallp = &wall[sec->wallptr + start];
|
auto sline = §ionLines[sec->lines[start]];
|
||||||
|
auto wallp = &wall[sline->startpoint];
|
||||||
float X = WallStartX(wallp);
|
float X = WallStartX(wallp);
|
||||||
float Y = WallStartY(wallp);
|
float Y = WallStartY(wallp);
|
||||||
if (fabs(X) > 32768. || fabs(Y) > 32768.)
|
if (fabs(X) > 32768. || fabs(Y) > 32768.)
|
||||||
|
@ -255,7 +258,7 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
curPoly->push_back(std::make_pair(X, Y));
|
curPoly->push_back(std::make_pair(X, Y));
|
||||||
done.Set(start);
|
done.Set(start);
|
||||||
vertstoadd--;
|
vertstoadd--;
|
||||||
start = wallp->point2 - sec->wallptr;
|
start = sline->point2index;
|
||||||
}
|
}
|
||||||
polygon.resize(polygon.size() + 1);
|
polygon.resize(polygon.size() + 1);
|
||||||
curPoly = &polygon.back();
|
curPoly = &polygon.back();
|
||||||
|
@ -280,12 +283,12 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
}
|
}
|
||||||
if (outer != 0) std::swap(polygon[0], polygon[outer]);
|
if (outer != 0) std::swap(polygon[0], polygon[outer]);
|
||||||
auto indices = mapbox::earcut(polygon);
|
auto indices = mapbox::earcut(polygon);
|
||||||
if (indices.size() < 3 * (sec->wallnum - 2))
|
if (indices.size() < 3 * (sec->lines.Size() - 2))
|
||||||
{
|
{
|
||||||
// this means that full triangulation failed.
|
// this means that full triangulation failed.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sec->floorz = sec->ceilingz = 0;
|
sectorp->floorz = sectorp->ceilingz = 0;
|
||||||
|
|
||||||
int p = 0;
|
int p = 0;
|
||||||
for (size_t a = 0; a < polygon.size(); a++)
|
for (size_t a = 0; a < polygon.size(); a++)
|
||||||
|
@ -293,7 +296,7 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
for (auto& pt : polygon[a])
|
for (auto& pt : polygon[a])
|
||||||
{
|
{
|
||||||
float planez;
|
float planez;
|
||||||
PlanesAtPoint(sec, (pt.first * 16), (pt.second * -16), plane ? &planez : nullptr, !plane ? &planez : nullptr);
|
PlanesAtPoint(sectorp, (pt.first * 16), (pt.second * -16), plane ? &planez : nullptr, !plane ? &planez : nullptr);
|
||||||
FVector3 point = { pt.first, pt.second, planez };
|
FVector3 point = { pt.first, pt.second, planez };
|
||||||
points[p++] = point;
|
points[p++] = point;
|
||||||
}
|
}
|
||||||
|
@ -302,11 +305,11 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
auto& entry = data[secnum].planes[plane];
|
auto& entry = data[secnum].planes[plane];
|
||||||
entry.vertices.Resize(indices.size());
|
entry.vertices.Resize(indices.size());
|
||||||
entry.texcoords.Resize(indices.size());
|
entry.texcoords.Resize(indices.size());
|
||||||
entry.normal = CalcNormal(sec, plane);
|
entry.normal = CalcNormal(sectorp, plane);
|
||||||
|
|
||||||
auto texture = tileGetTexture(plane ? sec->ceilingpicnum : sec->floorpicnum);
|
auto texture = tileGetTexture(plane ? sectorp->ceilingpicnum : sectorp->floorpicnum);
|
||||||
|
|
||||||
UVCalculator uvcalc(sec, plane, texture, offset);
|
UVCalculator uvcalc(sectorp, plane, texture, offset);
|
||||||
|
|
||||||
for(unsigned i = 0; i < entry.vertices.Size(); i++)
|
for(unsigned i = 0; i < entry.vertices.Size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -315,8 +318,8 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
entry.texcoords[i] = uvcalc.GetUV(int(pt.X * 16), int(pt.Y * -16), pt.Z);
|
entry.texcoords[i] = uvcalc.GetUV(int(pt.X * 16), int(pt.Y * -16), pt.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
sec->floorz = fz;
|
sectorp->floorz = fz;
|
||||||
sec->ceilingz = cz;
|
sectorp->ceilingz = cz;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,26 +333,30 @@ bool SectorGeometry::MakeVertices(unsigned int secnum, int plane, const FVector2
|
||||||
|
|
||||||
bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector2& offset)
|
bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector2& offset)
|
||||||
{
|
{
|
||||||
|
auto sec = §ions[secnum];
|
||||||
|
auto sectorp = §or[sec->sector];
|
||||||
|
int numvertices = sec->lines.Size();
|
||||||
|
|
||||||
// Convert our sector into something the node builder understands
|
// Convert our sector into something the node builder understands
|
||||||
auto sect = §or[secnum];
|
TArray<vertex_t> vertexes(sectorp->wallnum, true);
|
||||||
TArray<vertex_t> vertexes(sect->wallnum, true);
|
TArray<line_t> lines(numvertices, true);
|
||||||
TArray<line_t> lines(sect->wallnum, true);
|
TArray<side_t> sides(numvertices, true);
|
||||||
TArray<side_t> sides(sect->wallnum, true);
|
for (int i = 0; i < numvertices; i++)
|
||||||
for (int i = 0; i < sect->wallnum; i++)
|
|
||||||
{
|
{
|
||||||
auto wal = &wall[sect->wallptr + i];
|
auto sline = §ionLines[sec->lines[i]];
|
||||||
|
auto wal = &wall[sline->startpoint];
|
||||||
vertexes[i].p = { wal->x * (1 / 16.), wal->y * (1 / -16.) };
|
vertexes[i].p = { wal->x * (1 / 16.), wal->y * (1 / -16.) };
|
||||||
|
|
||||||
lines[i].backsector = nullptr;
|
lines[i].backsector = nullptr;
|
||||||
lines[i].frontsector = sect;
|
lines[i].frontsector = sectorp;
|
||||||
lines[i].linenum = i;
|
lines[i].linenum = i;
|
||||||
lines[i].sidedef[0] = &sides[i];
|
lines[i].sidedef[0] = &sides[i];
|
||||||
lines[i].sidedef[1] = nullptr;
|
lines[i].sidedef[1] = nullptr;
|
||||||
lines[i].v1 = &vertexes[i];
|
lines[i].v1 = &vertexes[i];
|
||||||
lines[i].v2 = &vertexes[wal->point2 - sect->wallptr];
|
lines[i].v2 = &vertexes[sline->point2index];
|
||||||
|
|
||||||
sides[i].sidenum = i;
|
sides[i].sidenum = i;
|
||||||
sides[i].sector = sect;
|
sides[i].sector = sectorp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -372,8 +379,8 @@ bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector
|
||||||
entry.vertices.Clear();
|
entry.vertices.Clear();
|
||||||
entry.texcoords.Clear();
|
entry.texcoords.Clear();
|
||||||
|
|
||||||
int fz = sect->floorz, cz = sect->ceilingz;
|
int fz = sectorp->floorz, cz = sectorp->ceilingz;
|
||||||
sect->floorz = sect->ceilingz = 0;
|
sectorp->floorz = sectorp->ceilingz = 0;
|
||||||
|
|
||||||
for (auto& sub : Level.subsectors)
|
for (auto& sub : Level.subsectors)
|
||||||
{
|
{
|
||||||
|
@ -391,9 +398,9 @@ bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the rest.
|
// calculate the rest.
|
||||||
auto texture = tileGetTexture(plane ? sect->ceilingpicnum : sect->floorpicnum);
|
auto texture = tileGetTexture(plane ? sectorp->ceilingpicnum : sectorp->floorpicnum);
|
||||||
|
|
||||||
UVCalculator uvcalc(sect, plane, texture, offset);
|
UVCalculator uvcalc(sectorp, plane, texture, offset);
|
||||||
|
|
||||||
entry.texcoords.Resize(entry.vertices.Size());
|
entry.texcoords.Resize(entry.vertices.Size());
|
||||||
for (unsigned i = 0; i < entry.vertices.Size(); i++)
|
for (unsigned i = 0; i < entry.vertices.Size(); i++)
|
||||||
|
@ -401,13 +408,13 @@ bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector
|
||||||
auto& pt = entry.vertices[i];
|
auto& pt = entry.vertices[i];
|
||||||
|
|
||||||
float planez;
|
float planez;
|
||||||
PlanesAtPoint(sect, (pt.X * 16), (pt.Y * -16), plane ? &planez : nullptr, !plane ? &planez : nullptr);
|
PlanesAtPoint(sectorp, (pt.X * 16), (pt.Y * -16), plane ? &planez : nullptr, !plane ? &planez : nullptr);
|
||||||
entry.vertices[i].Z = planez;
|
entry.vertices[i].Z = planez;
|
||||||
entry.texcoords[i] = uvcalc.GetUV(int(pt.X * 16.), int(pt.Y * -16.), pt.Z);
|
entry.texcoords[i] = uvcalc.GetUV(int(pt.X * 16.), int(pt.Y * -16.), pt.Z);
|
||||||
}
|
}
|
||||||
entry.normal = CalcNormal(sect, plane);
|
entry.normal = CalcNormal(sectorp, plane);
|
||||||
sect->floorz = fz;
|
sectorp->floorz = fz;
|
||||||
sect->ceilingz = cz;
|
sectorp->ceilingz = cz;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +426,8 @@ bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector
|
||||||
|
|
||||||
void SectorGeometry::ValidateSector(unsigned int secnum, int plane, const FVector2& offset)
|
void SectorGeometry::ValidateSector(unsigned int secnum, int plane, const FVector2& offset)
|
||||||
{
|
{
|
||||||
auto sec = §or[secnum];
|
auto sec = §or[sections[secnum].sector];
|
||||||
|
|
||||||
auto compare = &data[secnum].compare[plane];
|
auto compare = &data[secnum].compare[plane];
|
||||||
if (plane == 0)
|
if (plane == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "automap.h"
|
#include "automap.h"
|
||||||
#include "raze_sound.h"
|
#include "raze_sound.h"
|
||||||
#include "gamefuncs.h"
|
#include "gamefuncs.h"
|
||||||
|
#include "hw_sections.h"
|
||||||
|
|
||||||
#include "blood.h"
|
#include "blood.h"
|
||||||
|
|
||||||
|
@ -1067,6 +1068,7 @@ void dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, shor
|
||||||
}
|
}
|
||||||
|
|
||||||
setWallSectors();
|
setWallSectors();
|
||||||
|
hw_BuildSections();
|
||||||
memcpy(wallbackup, wall, sizeof(wallbackup));
|
memcpy(wallbackup, wall, sizeof(wallbackup));
|
||||||
memcpy(sectorbackup, sector, sizeof(sectorbackup));
|
memcpy(sectorbackup, sector, sizeof(sectorbackup));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue