- moved the "unused" folder to the repo's top level.
This commit is contained in:
parent
5ca1fca8d1
commit
a93799b21f
5 changed files with 0 additions and 0 deletions
|
|
@ -1,598 +0,0 @@
|
|||
/*
|
||||
** gl_builddraw.cpp
|
||||
** a build-like rendering algorithm
|
||||
** Uses the sections created in gl_sections.cpp
|
||||
**
|
||||
** NOTE: Although this code generally works, it clearly shows the limitations
|
||||
** of Build's algorithm. This requires constant sorting of the collected geometry
|
||||
** and that causes extreme slowdowns on larger maps.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_clipper.h"
|
||||
#include "gl/utility/gl_clock.h"
|
||||
#include "gl/data/gl_sections.h"
|
||||
#include "gl/scene/gl_wall.h"
|
||||
|
||||
#ifdef BUILD_TEST
|
||||
#define D(x) x
|
||||
#else
|
||||
#define D(x) do{}while(0)
|
||||
#endif
|
||||
|
||||
EXTERN_CVAR (Bool, dumpsections)
|
||||
|
||||
struct FBunch
|
||||
{
|
||||
int startline;
|
||||
int endline;
|
||||
angle_t startangle;
|
||||
angle_t endangle;
|
||||
fixed_t minviewdist;
|
||||
fixed_t maxviewdist;
|
||||
};
|
||||
|
||||
void DoSubsector(subsector_t * sub, bool handlelines);
|
||||
|
||||
EXTERN_CVAR(Bool, gl_render_walls)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// From Build but changed to use doubles to prevent overflows
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int WallInFront(FGLSectionLine *wal1, FGLSectionLine *wal2)
|
||||
{
|
||||
double x11, y11, x21, y21, x12, y12, x22, y22, dx, dy, t1, t2;
|
||||
|
||||
x11 = wal1->start->x;
|
||||
y11 = wal1->start->y;
|
||||
x21 = wal1->end->x;
|
||||
y21 = wal1->end->y;
|
||||
x12 = wal2->start->x;
|
||||
y12 = wal2->start->y;
|
||||
x22 = wal2->end->x;
|
||||
y22 = wal2->end->y;
|
||||
|
||||
dx = x21-x11; dy = y21-y11;
|
||||
|
||||
t1 = (x12-x11)*dy - (y12-y11)*dx;
|
||||
t2 = (x22-x11)*dy - (y22-y11)*dx;
|
||||
if (t1 == 0)
|
||||
{
|
||||
t1 = t2;
|
||||
if (t1 == 0) return(-1);
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
|
||||
if ((t1*t2) >= 0)
|
||||
{
|
||||
t2 = (double(viewx)-x11) * dy - (double(viewy)-y11)*dx;
|
||||
return((t2*t1) < 0);
|
||||
}
|
||||
|
||||
dx = x22-x12; dy = y22-y12;
|
||||
t1 = (x11-x12)*dy - (y11-y12)*dx;
|
||||
t2 = (x21-x12)*dy - (y21-y12)*dx;
|
||||
if (t1 == 0)
|
||||
{
|
||||
t1 = t2;
|
||||
if (t1 == 0) return(-1);
|
||||
}
|
||||
if (t2 == 0) t2 = t1;
|
||||
if ((t1*t2) >= 0)
|
||||
{
|
||||
t2 = (double(viewx)-x12) * dy - (double(viewy)-y12)*dx;
|
||||
return((t2*t1) >= 0);
|
||||
}
|
||||
return(-2);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This is a bit more complicated than it looks because angles can wrap
|
||||
// around so we can only compare angle differences.
|
||||
//
|
||||
// Rules:
|
||||
// 1. Any bunch can span at most 180°.
|
||||
// 2. 2 bunches can never overlap at both ends
|
||||
// 3. if there is an overlap one of the 2 starting points must be in the
|
||||
// overlapping area.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int BunchInFront(FBunch *b1, FBunch *b2)
|
||||
{
|
||||
angle_t anglecheck, endang;
|
||||
|
||||
if (b2->startangle - b1->startangle < b1->endangle - b1->startangle)
|
||||
{
|
||||
// we have an overlap at b2->startangle
|
||||
anglecheck = b2->startangle - b1->startangle;
|
||||
|
||||
// Find the wall in b1 that overlaps b2->startangle
|
||||
for(int i = b1->startline; i <= b1->endline; i++)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
angle_t startang = SectionLines[i].start->GetClipAngleInverse() - b1->startangle;
|
||||
#endif
|
||||
endang = SectionLines[i].end->GetClipAngleInverse() - b1->startangle;
|
||||
if (endang > anglecheck)
|
||||
{
|
||||
assert (startang <= anglecheck);
|
||||
|
||||
// found a line
|
||||
int ret = WallInFront(&SectionLines[b2->startline], &SectionLines[i]);
|
||||
|
||||
D(Printf (PRINT_LOG, "Line %d <-> line %d: Result = %d.\n",
|
||||
SectionLines[b2->startline].linedef-lines,
|
||||
SectionLines[i].linedef-lines, ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (b1->startangle - b2->startangle < b2->endangle - b2->startangle)
|
||||
{
|
||||
// we have an overlap at b1->startangle
|
||||
anglecheck = b1->startangle - b2->startangle;
|
||||
|
||||
// Find the wall in b2 that overlaps b1->startangle
|
||||
for(int i = b2->startline; i <= b2->endline; i++)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
angle_t startang = SectionLines[i].start->GetClipAngleInverse() - b2->startangle;
|
||||
#endif
|
||||
endang = SectionLines[i].end->GetClipAngleInverse() - b2->startangle;
|
||||
if (endang > anglecheck)
|
||||
{
|
||||
assert (startang <= anglecheck);
|
||||
|
||||
// found a line
|
||||
int ret = WallInFront(&SectionLines[i], &SectionLines[b1->startline]);
|
||||
|
||||
D(Printf (PRINT_LOG, "Line %d <-> line %d: Result = %d,\n",
|
||||
SectionLines[i].linedef-lines,
|
||||
SectionLines[b1->endline].linedef-lines, ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we have no overlap
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Bunches are groups of continuous lines
|
||||
// This array stores the amount of points per bunch,
|
||||
// the view angles for each point and the line index for the starting line
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BunchDrawer
|
||||
{
|
||||
int LastBunch;
|
||||
int StartTime;
|
||||
TArray<FBunch> Bunches;
|
||||
TArray<int> CompareData;
|
||||
sector_t fakebacksec;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
public:
|
||||
BunchDrawer()
|
||||
{
|
||||
StartScene();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
private:
|
||||
void StartScene()
|
||||
{
|
||||
LastBunch = 0;
|
||||
StartTime = I_MSTime();
|
||||
Bunches.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void StartBunch(int linenum, angle_t startan, angle_t endan, vertex_t *startpt, vertex_t *endpt)
|
||||
{
|
||||
FBunch *bunch = &Bunches[LastBunch = Bunches.Reserve(1)];
|
||||
|
||||
bunch->startline = bunch->endline = linenum;
|
||||
bunch->startangle = startan;
|
||||
bunch->endangle = endan;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void AddLineToBunch(int newan)
|
||||
{
|
||||
Bunches[LastBunch].endline++;
|
||||
Bunches[LastBunch].endangle = newan;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DeleteBunch(int index)
|
||||
{
|
||||
Bunches.Delete(index);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ClipLine
|
||||
// Clips the given segment
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
CL_Skip = 0,
|
||||
CL_Draw = 1,
|
||||
CL_Pass = 2,
|
||||
};
|
||||
|
||||
|
||||
int ClipLine (FGLSectionLine *line, sector_t * sector, sector_t **pbacksector)
|
||||
{
|
||||
angle_t startAngle, endAngle;
|
||||
sector_t * backsector = NULL;
|
||||
bool blocking;
|
||||
|
||||
startAngle = line->end->GetClipAngle();
|
||||
endAngle = line->start->GetClipAngle();
|
||||
*pbacksector = NULL;
|
||||
|
||||
// Back side, i.e. backface culling - read: endAngle >= startAngle!
|
||||
if (startAngle-endAngle<ANGLE_180)
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
if (!clipper.SafeCheckRange(startAngle, endAngle))
|
||||
{
|
||||
return CL_Skip;
|
||||
}
|
||||
|
||||
if (line->otherside == -1)
|
||||
{
|
||||
// one-sided
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
return CL_Draw;
|
||||
}
|
||||
else if (line->polysub == NULL)
|
||||
{
|
||||
// two sided and not a polyobject
|
||||
if (line->linedef == NULL)
|
||||
{
|
||||
// Miniseg
|
||||
return CL_Pass;
|
||||
}
|
||||
if (sector->sectornum == line->refseg->backsector->sectornum)
|
||||
{
|
||||
FTexture *tex = TexMan(line->sidedef->GetTexture(side_t::mid));
|
||||
if (!tex || tex->UseType==FTexture::TEX_Null)
|
||||
{
|
||||
// no mid texture: nothing to do here
|
||||
return CL_Pass;
|
||||
}
|
||||
*pbacksector = sector;
|
||||
return CL_Draw|CL_Pass;
|
||||
}
|
||||
else
|
||||
{
|
||||
// clipping checks are only needed when the backsector is not the same as the front sector
|
||||
gl_CheckViewArea(line->start, line->end, line->refseg->frontsector, line->refseg->backsector);
|
||||
|
||||
*pbacksector = backsector = gl_FakeFlat(line->refseg->backsector, &fakebacksec, true);
|
||||
|
||||
blocking = gl_CheckClip(line->sidedef, sector, backsector);
|
||||
if (blocking)
|
||||
{
|
||||
clipper.SafeAddClipRange(startAngle, endAngle);
|
||||
return CL_Draw;
|
||||
}
|
||||
return CL_Draw|CL_Pass;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbacksector = sector;
|
||||
return CL_Draw;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ProcessBunch(int bnch)
|
||||
{
|
||||
FBunch *bunch = &Bunches[bnch];
|
||||
|
||||
sector_t fake;
|
||||
sector_t *sec;
|
||||
sector_t *backsector;
|
||||
|
||||
D(Printf(PRINT_LOG, "------------------------------\nProcessing bunch %d (Startline %d)\n",bnch,SectionLines[bunch->startline].linedef-lines));
|
||||
ClipWall.Clock();
|
||||
for(int i=bunch->startline; i <= bunch->endline; i++)
|
||||
{
|
||||
FGLSectionLine *ln = &SectionLines[i];
|
||||
|
||||
|
||||
// Draw this line. todo: optimize
|
||||
sec = gl_FakeFlat(ln->refseg->frontsector, &fake, false);
|
||||
|
||||
int clipped = ClipLine(ln, sec, &backsector);
|
||||
|
||||
D(Printf(PRINT_LOG, "line %d clip result is %d\n", ln->linedef - lines, clipped));
|
||||
|
||||
if (clipped & CL_Draw)
|
||||
{
|
||||
ln->linedef->flags |= ML_MAPPED;
|
||||
|
||||
if (ln->linedef->validcount!=validcount)
|
||||
{
|
||||
ln->linedef->validcount=validcount;
|
||||
|
||||
#ifndef BUILD_TEST
|
||||
if (gl_render_walls)
|
||||
{
|
||||
SetupWall.Clock();
|
||||
|
||||
GLWall wall;
|
||||
wall.Process(ln->refseg, sec, backsector, ln->polysub);
|
||||
rendered_lines++;
|
||||
|
||||
SetupWall.Unclock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (clipped & CL_Pass)
|
||||
{
|
||||
ClipWall.Unclock();
|
||||
ProcessSection(ln->otherside);
|
||||
ClipWall.Clock();
|
||||
}
|
||||
}
|
||||
D(Printf(PRINT_LOG, "Bunch %d done\n------------------------------\n",bnch));
|
||||
ClipWall.Unclock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FindClosestBunch()
|
||||
{
|
||||
int closest = 0; //Almost works, but not quite :(
|
||||
|
||||
CompareData.Clear();
|
||||
for(unsigned i = 1; i < Bunches.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[i], &Bunches[closest]))
|
||||
{
|
||||
case 0: // i is in front
|
||||
closest = i;
|
||||
continue;
|
||||
|
||||
case 1: // i is behind
|
||||
continue;
|
||||
|
||||
default: // can't determine
|
||||
CompareData.Push(i); // mark for later comparison
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to do a second pass to see how the marked bunches relate to the currently closest one.
|
||||
for(unsigned i = 0; i < CompareData.Size(); i++)
|
||||
{
|
||||
switch (BunchInFront(&Bunches[CompareData[i]], &Bunches[closest]))
|
||||
{
|
||||
case 0: // is in front
|
||||
closest = i;
|
||||
CompareData.Delete(i);
|
||||
i = 0; // we need to recheck everything that's still marked.
|
||||
continue;
|
||||
|
||||
case 1: // is behind
|
||||
CompareData.Delete(i);
|
||||
i--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ProcessSection(int sectnum)
|
||||
{
|
||||
FGLSection *sect = &Sections[sectnum];
|
||||
bool inbunch;
|
||||
angle_t startangle;
|
||||
|
||||
if (sect->validcount == StartTime) return;
|
||||
sect->validcount = StartTime;
|
||||
D(Printf(PRINT_LOG, "------------------------------\nProcessing section %d (sector %d)\n",sectnum, sect->sector->sectornum));
|
||||
|
||||
#ifndef BUILD_TEST
|
||||
for(unsigned i = 0; i < sect->subsectors.Size(); i++)
|
||||
{
|
||||
DoSubsector(sect->subsectors[i], false);
|
||||
if (sect->subsectors[i]->poly != NULL)
|
||||
{
|
||||
// ProcessPolyobject()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//Todo: process subsectors
|
||||
for(int i=0; i<sect->numloops; i++)
|
||||
{
|
||||
FGLSectionLoop *loop = sect->GetLoop(i);
|
||||
inbunch = false;
|
||||
|
||||
for(int j=0; j<loop->numlines; j++)
|
||||
{
|
||||
FGLSectionLine *ln = loop->GetLine(j);
|
||||
|
||||
angle_t ang1 = ln->start->GetClipAngle();
|
||||
angle_t ang2 = ln->end->GetClipAngle();
|
||||
|
||||
if (ang2 - ang1 < ANGLE_180)
|
||||
{
|
||||
// Backside
|
||||
D(Printf(PRINT_LOG, "line %d facing backwards\n", ln->linedef - lines));
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!clipper.SafeCheckRange(ang2, ang1))
|
||||
{
|
||||
// is it visible?
|
||||
D(Printf(PRINT_LOG, "line %d not in view\n", ln->linedef - lines));
|
||||
inbunch = false;
|
||||
}
|
||||
else if (!inbunch || startangle - ang2 >= ANGLE_180)
|
||||
{
|
||||
// don't let a bunch span more than 180° to avoid problems.
|
||||
// This limitation ensures that the combined range of 2
|
||||
// bunches will always be less than 360° which simplifies
|
||||
// the distance comparison code because it prevents a
|
||||
// situation where 2 bunches may overlap at both ends.
|
||||
D(Printf(PRINT_LOG, "Starting bunch %d at line %d\n",Bunches.Size(), ln->linedef - lines));
|
||||
|
||||
startangle = ang2;
|
||||
// Clipping angles are backward which makes this code very hard to read so let's use the inverse
|
||||
StartBunch(loop->startline + j, 0 - ang1, 0 - ang2);
|
||||
inbunch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
D(Printf(PRINT_LOG, " Adding line %d\n", ln->linedef - lines));
|
||||
AddLineToBunch(0 - ang2);
|
||||
}
|
||||
}
|
||||
}
|
||||
D(Printf(PRINT_LOG, "Section %d done\n------------------------------\n",sectnum));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
public:
|
||||
void RenderScene(int viewsection)
|
||||
{
|
||||
ProcessSection(viewsection);
|
||||
while (Bunches.Size() > 0)
|
||||
{
|
||||
int closest = FindClosestBunch();
|
||||
ProcessBunch(closest);
|
||||
DeleteBunch(closest);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void gl_RenderBuild()
|
||||
{
|
||||
subsector_t *sub = R_PointInSubsector(viewx, viewy);
|
||||
|
||||
clipper.Clear();
|
||||
angle_t a1 = GLRenderer->FrustumAngle();
|
||||
clipper.SafeAddClipRangeRealAngles(viewangle+a1, viewangle-a1);
|
||||
if (Sections.Size() == 0) gl_CreateSections();
|
||||
|
||||
int startsection = SectionForSubsector[sub-subsectors];
|
||||
|
||||
BunchDrawer bd;
|
||||
bd.RenderScene(startsection);
|
||||
}
|
||||
|
||||
#ifdef BUILD_TEST
|
||||
CCMD(testrender)
|
||||
{
|
||||
gl_RenderBuild();
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,845 +0,0 @@
|
|||
/*
|
||||
** gl_sections.cpp
|
||||
** Splits sectors into continuous separate parts
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** 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.
|
||||
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU Lesser General Public License as published
|
||||
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
** your option) any later version.
|
||||
** 5. Full disclosure of the entire project's source code, except for third
|
||||
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
||||
**
|
||||
** 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 "gl/system/gl_system.h"
|
||||
#include <GL/GLU.h>
|
||||
#include "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "gl/data/gl_sections.h"
|
||||
|
||||
typedef void (CALLBACK *tessFunc)();
|
||||
|
||||
TArray<FGLSectionLine> SectionLines;
|
||||
TArray<FGLSectionLoop> SectionLoops;
|
||||
TArray<FGLSection> Sections;
|
||||
TArray<int> SectionForSubsector;
|
||||
|
||||
CVAR (Bool, dumpsections, false, 0)
|
||||
|
||||
#define ISDONE(no, p) (p[(no)>>3] & (1 << ((no)&7)))
|
||||
#define SETDONE(no, p) p[(no)>>3] |= (1 << ((no)&7))
|
||||
|
||||
inline vertex_t *V1(side_t *s)
|
||||
{
|
||||
line_t *ln = s->linedef;
|
||||
return s == ln->sidedef[0]? ln->v1: ln->v2;
|
||||
}
|
||||
|
||||
inline vertex_t *V2(side_t *s)
|
||||
{
|
||||
line_t *ln = s->linedef;
|
||||
return s == ln->sidedef[0]? ln->v2: ln->v1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FSectionCreator
|
||||
{
|
||||
static FSectionCreator *creator;
|
||||
|
||||
uint8_t *processed_segs;
|
||||
uint8_t *processed_subsectors;
|
||||
int *section_for_segs;
|
||||
|
||||
vertex_t *v1_l1, *v2_l1;
|
||||
|
||||
FGLSectionLoop *loop;
|
||||
FGLSection *section; // current working section
|
||||
|
||||
public:
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FSectionCreator()
|
||||
{
|
||||
processed_segs = new uint8_t[(numsegs+7)/8];
|
||||
processed_subsectors = new uint8_t[(numsubsectors+7)/8];
|
||||
|
||||
memset(processed_segs, 0, (numsegs+7)/8);
|
||||
memset(processed_subsectors, 0, (numsubsectors+7)/8);
|
||||
|
||||
section_for_segs = new int[numsegs];
|
||||
memset(section_for_segs, -1, numsegs * sizeof(int));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
~FSectionCreator()
|
||||
{
|
||||
delete [] processed_segs;
|
||||
delete [] processed_subsectors;
|
||||
delete [] section_for_segs;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void NewLoop()
|
||||
{
|
||||
section->numloops++;
|
||||
loop = &SectionLoops[SectionLoops.Reserve(1)];
|
||||
loop->startline = SectionLines.Size();
|
||||
loop->numlines = 0 ;
|
||||
}
|
||||
|
||||
void NewSection(sector_t *sec)
|
||||
{
|
||||
section = &Sections[Sections.Reserve(1)];
|
||||
section->sector = sec;
|
||||
section->subsectors.Clear();
|
||||
section->numloops = 0;
|
||||
section->startloop = SectionLoops.Size();
|
||||
section->validcount = -1;
|
||||
NewLoop();
|
||||
}
|
||||
|
||||
void FinalizeSection()
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool AddSeg(seg_t *seg)
|
||||
{
|
||||
FGLSectionLine &line = SectionLines[SectionLines.Reserve(1)];
|
||||
|
||||
|
||||
bool firstline = loop->numlines == 0;
|
||||
|
||||
if (ISDONE(seg-segs, processed_segs))
|
||||
{
|
||||
// should never happen!
|
||||
DPrintf("Tried to add seg %d to Sections twice. Cannot create Sections.\n", seg-segs);
|
||||
return false;
|
||||
}
|
||||
|
||||
SETDONE(seg-segs, processed_segs);
|
||||
section_for_segs[seg-segs] = Sections.Size()-1;
|
||||
|
||||
line.start = seg->v1;
|
||||
line.end = seg->v2;
|
||||
line.sidedef = seg->sidedef;
|
||||
line.linedef = seg->linedef;
|
||||
line.refseg = seg;
|
||||
line.polysub = NULL;
|
||||
line.otherside = -1;
|
||||
|
||||
if (loop->numlines == 0)
|
||||
{
|
||||
v1_l1 = seg->v1;
|
||||
v2_l1 = seg->v2;
|
||||
}
|
||||
loop->numlines++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Utility stuff
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
sector_t *FrontRenderSector(seg_t *seg)
|
||||
{
|
||||
return seg->Subsector->render_sector;
|
||||
}
|
||||
|
||||
sector_t *BackRenderSector(seg_t *seg)
|
||||
{
|
||||
if (seg->PartnerSeg == NULL) return NULL;
|
||||
return seg->PartnerSeg->Subsector->render_sector;
|
||||
}
|
||||
|
||||
bool IntraSectorSeg(seg_t *seg)
|
||||
{
|
||||
return FrontRenderSector(seg) == BackRenderSector(seg);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// returns the seg whose partner seg determines where this
|
||||
// section continues
|
||||
//
|
||||
//==========================================================================
|
||||
bool AddSubSector(subsector_t *subsec, vertex_t *startpt, seg_t **pNextSeg)
|
||||
{
|
||||
unsigned i = 0;
|
||||
if (startpt != NULL)
|
||||
{
|
||||
// find the seg in this subsector that starts at the given vertex
|
||||
for(i = 0; i < subsec->numlines; i++)
|
||||
{
|
||||
if (subsec->firstline[i].v1 == startpt) break;
|
||||
}
|
||||
if (i == subsec->numlines)
|
||||
{
|
||||
DPrintf("Vertex not found in subsector %d. Cannot create Sections.\n", subsec-subsectors);
|
||||
return false; // Nodes are bad
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the first unprocessed non-miniseg
|
||||
for(i = 0; i < subsec->numlines; i++)
|
||||
{
|
||||
seg_t *seg = subsec->firstline + i;
|
||||
|
||||
if (seg->sidedef == NULL) continue;
|
||||
if (IntraSectorSeg(seg)) continue;
|
||||
if (ISDONE(seg-segs, processed_segs)) continue;
|
||||
break;
|
||||
}
|
||||
if (i == subsec->numlines)
|
||||
{
|
||||
DPrintf("Unable to find a start seg. Cannot create Sections.\n");
|
||||
return false; // Nodes are bad
|
||||
}
|
||||
|
||||
startpt = subsec->firstline[i].v1;
|
||||
}
|
||||
|
||||
seg_t *thisseg = subsec->firstline + i;
|
||||
if (IntraSectorSeg(thisseg))
|
||||
{
|
||||
SETDONE(thisseg-segs, processed_segs);
|
||||
// continue with the loop in the adjoining subsector
|
||||
*pNextSeg = thisseg;
|
||||
return true;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (loop->numlines > 0 && thisseg->v1 == v1_l1 && thisseg->v2 == v2_l1)
|
||||
{
|
||||
// This loop is complete
|
||||
*pNextSeg = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!AddSeg(thisseg)) return NULL;
|
||||
|
||||
i = (i+1) % subsec->numlines;
|
||||
seg_t *nextseg = subsec->firstline + i;
|
||||
|
||||
if (thisseg->v2 != nextseg->v1)
|
||||
{
|
||||
DPrintf("Segs in subsector %d are not continuous. Cannot create Sections.\n", subsec-subsectors);
|
||||
return false; // Nodes are bad
|
||||
}
|
||||
|
||||
if (IntraSectorSeg(nextseg))
|
||||
{
|
||||
SETDONE(nextseg-segs, processed_segs);
|
||||
// continue with the loop in the adjoining subsector
|
||||
*pNextSeg = nextseg;
|
||||
return true;
|
||||
}
|
||||
thisseg = nextseg;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FindNextSeg(seg_t **pSeg)
|
||||
{
|
||||
// find an unprocessed non-miniseg or a miniseg with an unprocessed
|
||||
// partner subsector that belongs to the same rendersector
|
||||
for (unsigned i = 0; i < section->subsectors.Size(); i++)
|
||||
{
|
||||
for(unsigned j = 0; j < section->subsectors[i]->numlines; j++)
|
||||
{
|
||||
seg_t *seg = section->subsectors[i]->firstline + j;
|
||||
bool intra = IntraSectorSeg(seg);
|
||||
|
||||
if (!intra && !ISDONE(seg-segs, processed_segs))
|
||||
{
|
||||
*pSeg = seg;
|
||||
return true;
|
||||
}
|
||||
else if (intra &&
|
||||
!ISDONE(seg->PartnerSeg->Subsector-subsectors, processed_subsectors))
|
||||
{
|
||||
*pSeg = seg->PartnerSeg;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pSeg = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// all segs and subsectors must be grouped into Sections
|
||||
//
|
||||
//=============================================================================
|
||||
bool CheckSections()
|
||||
{
|
||||
bool res = true;
|
||||
for (int i = 0; i < numsegs; i++)
|
||||
{
|
||||
if (segs[i].sidedef != NULL && !ISDONE(i, processed_segs) && !IntraSectorSeg(&segs[i]))
|
||||
{
|
||||
Printf("Seg %d (Linedef %d) not processed during section creation\n", i, segs[i].linedef-lines);
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numsubsectors; i++)
|
||||
{
|
||||
if (!ISDONE(i, processed_subsectors))
|
||||
{
|
||||
Printf("Subsector %d (Sector %d) not processed during section creation\n", i, subsectors[i].sector-sectors);
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
void DeleteLine(int i)
|
||||
{
|
||||
SectionLines.Delete(i);
|
||||
for(int i = SectionLoops.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
FGLSectionLoop *loop = &SectionLoops[i];
|
||||
if (loop->startline > i) loop->startline--;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
void MergeLines(FGLSectionLoop *loop)
|
||||
{
|
||||
int i;
|
||||
int deleted = 0;
|
||||
FGLSectionLine *ln1;
|
||||
FGLSectionLine *ln2;
|
||||
// Merge identical lines in the list
|
||||
for(i = loop->numlines - 1; i > 0; i--)
|
||||
{
|
||||
ln1 = loop->GetLine(i);
|
||||
ln2 = loop->GetLine(i-1);
|
||||
|
||||
if (ln1->sidedef == ln2->sidedef && ln1->otherside == ln2->otherside)
|
||||
{
|
||||
// identical references. These 2 lines can be merged.
|
||||
ln2->end = ln1->end;
|
||||
SectionLines.Delete(loop->startline + i);
|
||||
loop->numlines--;
|
||||
deleted++;
|
||||
}
|
||||
}
|
||||
|
||||
// If we started in the middle of a sidedef the first and last lines
|
||||
// may reference the same sidedef. check that, too.
|
||||
|
||||
int loopstart = 0;
|
||||
|
||||
ln1 = loop->GetLine(0);
|
||||
for(i = loop->numlines - 1; i > 0; i--)
|
||||
{
|
||||
ln2 = loop->GetLine(i);
|
||||
if (ln1->sidedef != ln2->sidedef || ln1->otherside != ln2->otherside)
|
||||
break;
|
||||
}
|
||||
if (i < loop->numlines-1)
|
||||
{
|
||||
i++;
|
||||
ln2 = loop->GetLine(i);
|
||||
ln1->start = ln2->start;
|
||||
SectionLines.Delete(loop->startline + i, loop->numlines - i);
|
||||
deleted += loop->numlines - i;
|
||||
loop->numlines = i;
|
||||
}
|
||||
|
||||
// Adjust all following loops
|
||||
for(unsigned ii = unsigned(loop - &SectionLoops[0]) + 1; ii < SectionLoops.Size(); ii++)
|
||||
{
|
||||
SectionLoops[ii].startline -= deleted;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
void SetReferences()
|
||||
{
|
||||
for(unsigned i = 0; i < SectionLines.Size(); i++)
|
||||
{
|
||||
FGLSectionLine *ln = &SectionLines[i];
|
||||
seg_t *seg = ln->refseg;
|
||||
|
||||
if (seg != NULL)
|
||||
{
|
||||
seg_t *partner = seg->PartnerSeg;
|
||||
|
||||
if (seg->PartnerSeg == NULL)
|
||||
{
|
||||
ln->otherside = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ln->otherside = section_for_segs[partner-segs];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ln->otherside = -1;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < SectionLoops.Size(); i++)
|
||||
{
|
||||
MergeLines(&SectionLoops[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// cbTessBegin
|
||||
//
|
||||
// called when the tesselation of a new loop starts
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void CALLBACK cbTessBegin(GLenum type, void *section)
|
||||
{
|
||||
FGLSection *sect = (FGLSection*)section;
|
||||
sect->primitives.Push(type);
|
||||
sect->primitives.Push(sect->vertices.Size());
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// cbTessError
|
||||
//
|
||||
// called when the tesselation failed
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void CALLBACK cbTessError(GLenum error, void *section)
|
||||
{
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// cbTessCombine
|
||||
//
|
||||
// called when the two or more vertexes are on the same coordinate
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void CALLBACK cbTessCombine( GLdouble coords[3], void *vert[4], GLfloat w[4], void **dataOut )
|
||||
{
|
||||
*dataOut = vert[0];
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// cbTessVertex
|
||||
//
|
||||
// called when a vertex is found
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void CALLBACK cbTessVertex( void *vert, void *section )
|
||||
{
|
||||
FGLSection *sect = (FGLSection*)section;
|
||||
sect->vertices.Push(int(intptr_t(vert)));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// cbTessEnd
|
||||
//
|
||||
// called when the tesselation of a the current loop ends
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void CALLBACK cbTessEnd(void *section)
|
||||
{
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
void tesselateSections()
|
||||
{
|
||||
// init tesselator
|
||||
GLUtesselator *tess = gluNewTess();
|
||||
if (!tess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// set callbacks
|
||||
gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (tessFunc)cbTessBegin);
|
||||
gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (tessFunc)cbTessVertex);
|
||||
gluTessCallback(tess, GLU_TESS_ERROR_DATA, (tessFunc)cbTessError);
|
||||
gluTessCallback(tess, GLU_TESS_COMBINE, (tessFunc)cbTessCombine);
|
||||
gluTessCallback(tess, GLU_TESS_END_DATA, (tessFunc)cbTessEnd);
|
||||
|
||||
for(unsigned int i=0;i<Sections.Size(); i++)
|
||||
{
|
||||
FGLSection *sect = &Sections[i];
|
||||
|
||||
gluTessBeginPolygon(tess, sect);
|
||||
|
||||
for(int j=0; j< sect->numloops; j++)
|
||||
{
|
||||
gluTessBeginContour(tess);
|
||||
FGLSectionLoop *loop = sect->GetLoop(j);
|
||||
for(int k=0; k<loop->numlines; k++)
|
||||
{
|
||||
FGLSectionLine *line = loop->GetLine(k);
|
||||
vertex_t *vert = line->start;
|
||||
GLdouble v[3] = {
|
||||
-(double)vert->x/(double)FRACUNIT, // negate to get proper winding
|
||||
0.0,
|
||||
(double)vert->y/(double)FRACUNIT
|
||||
};
|
||||
gluTessVertex(tess, v, (void*)(vert - vertexes));
|
||||
}
|
||||
gluTessEndContour(tess);
|
||||
}
|
||||
gluTessEndPolygon(tess);
|
||||
sect->vertices.Push(-1337);
|
||||
sect->vertices.ShrinkToFit();
|
||||
}
|
||||
gluDeleteTess(tess);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// First mark all subsectors that have no outside boundaries as processed
|
||||
// No line in such a subsector will ever be part of a section's border
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void MarkInternalSubsectors()
|
||||
{
|
||||
for(int i=0; i < numsubsectors; i++)
|
||||
{
|
||||
subsector_t *sub = &subsectors[i];
|
||||
int j;
|
||||
|
||||
for(j=0; j < sub->numlines; j++)
|
||||
{
|
||||
seg_t *seg = sub->firstline + j;
|
||||
if (!IntraSectorSeg(seg)) break;
|
||||
}
|
||||
if (j==sub->numlines)
|
||||
{
|
||||
// All lines are intra-sector so mark this as processed
|
||||
SETDONE(i, processed_subsectors);
|
||||
for(j=0; j < sub->numlines; j++)
|
||||
{
|
||||
seg_t *seg = sub->firstline + j;
|
||||
SETDONE((sub->firstline-segs)+j, processed_segs);
|
||||
if (seg->PartnerSeg != NULL)
|
||||
{
|
||||
SETDONE(int(seg->PartnerSeg - segs), processed_segs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
bool CreateSections()
|
||||
{
|
||||
int pick = 0;
|
||||
|
||||
MarkInternalSubsectors();
|
||||
while (pick < numsubsectors)
|
||||
{
|
||||
if (ISDONE(pick, processed_subsectors))
|
||||
{
|
||||
pick++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
subsector_t *subsector = &subsectors[pick];
|
||||
|
||||
seg_t *workseg = NULL;
|
||||
vertex_t *startpt = NULL;
|
||||
|
||||
NewSection(subsector->render_sector);
|
||||
while (1)
|
||||
{
|
||||
if (!ISDONE(subsector-subsectors, processed_subsectors))
|
||||
{
|
||||
SETDONE(subsector-subsectors, processed_subsectors);
|
||||
section->subsectors.Push(subsector);
|
||||
SectionForSubsector[subsector - subsectors] = int(section - &Sections[0]);
|
||||
}
|
||||
|
||||
bool result = AddSubSector(subsector, startpt, &workseg);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return false; // couldn't create Sections
|
||||
}
|
||||
else if (workseg != NULL)
|
||||
{
|
||||
// crossing into another subsector
|
||||
seg_t *partner = workseg->PartnerSeg;
|
||||
if (workseg->v2 != partner->v1)
|
||||
{
|
||||
DPrintf("Inconsistent subsector references in seg %d. Cannot create Sections.\n", workseg-segs);
|
||||
return false;
|
||||
}
|
||||
subsector = partner->Subsector;
|
||||
startpt = workseg->v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// loop complete. Check adjoining subsectors for other loops to
|
||||
// be added to this section
|
||||
if (!FindNextSeg(&workseg))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (workseg == NULL)
|
||||
{
|
||||
// No more subsectors found. This section is complete!
|
||||
FinalizeSection();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
subsector = workseg->Subsector;
|
||||
// If this is a regular seg, start there, otherwise start
|
||||
// at the subsector's first seg
|
||||
startpt = workseg->sidedef == NULL? NULL : workseg->v1;
|
||||
|
||||
NewLoop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!CheckSections()) return false;
|
||||
SetReferences();
|
||||
|
||||
Sections.ShrinkToFit();
|
||||
SectionLoops.ShrinkToFit();
|
||||
SectionLines.ShrinkToFit();
|
||||
|
||||
tesselateSections();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
FSectionCreator *FSectionCreator::creator;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DumpSection(int no, FGLSection *sect)
|
||||
{
|
||||
Printf(PRINT_LOG, "Section %d, sector %d\n{\n", no, sect->sector->sectornum);
|
||||
|
||||
for(int i = 0; i < sect->numloops; i++)
|
||||
{
|
||||
Printf(PRINT_LOG, "\tLoop %d\n\t{\n", i);
|
||||
|
||||
FGLSectionLoop *loop = sect->GetLoop(i);
|
||||
|
||||
for(int i = 0; i < loop->numlines; i++)
|
||||
{
|
||||
FGLSectionLine *ln = loop->GetLine(i);
|
||||
if (ln->sidedef != NULL)
|
||||
{
|
||||
vertex_t *v1 = V1(ln->sidedef);
|
||||
vertex_t *v2 = V2(ln->sidedef);
|
||||
double dx = FIXED2DBL(v2->x-v1->x);
|
||||
double dy = FIXED2DBL(v2->y-v1->y);
|
||||
double dx1 = FIXED2DBL(ln->start->x-v1->x);
|
||||
double dy1 = FIXED2DBL(ln->start->y-v1->y);
|
||||
double dx2 = FIXED2DBL(ln->end->x-v1->x);
|
||||
double dy2 = FIXED2DBL(ln->end->y-v1->y);
|
||||
double d = sqrt(dx*dx+dy*dy);
|
||||
double d1 = sqrt(dx1*dx1+dy1*dy1);
|
||||
double d2 = sqrt(dx2*dx2+dy2*dy2);
|
||||
|
||||
Printf(PRINT_LOG, "\t\tLinedef %d, %s: Start (%1.2f, %1.2f), End (%1.2f, %1.2f)",
|
||||
ln->linedef - lines, ln->sidedef == ln->linedef->sidedef[0]? "front":"back",
|
||||
ln->start->x/65536.f, ln->start->y/65536.f,
|
||||
ln->end->x/65536.f, ln->end->y/65536.f);
|
||||
|
||||
if (ln->otherside != -1)
|
||||
{
|
||||
Printf (PRINT_LOG, ", other side = %d", ln->otherside);
|
||||
}
|
||||
if (d1 > 0.005 || d2 < 0.995)
|
||||
{
|
||||
Printf(PRINT_LOG, ", Range = %1.3f, %1.3f", d1/d, d2/d);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf(PRINT_LOG, "\t\tMiniseg: Start (%1.3f, %1.3f), End (%1.3f, %1.3f)\n",
|
||||
ln->start->x/65536.f, ln->start->y/65536.f, ln->end->x/65536.f, ln->end->y/65536.f);
|
||||
|
||||
if (ln->otherside != -1)
|
||||
{
|
||||
Printf (PRINT_LOG, ", other side = %d", ln->otherside);
|
||||
}
|
||||
}
|
||||
Printf(PRINT_LOG, "\n");
|
||||
}
|
||||
Printf(PRINT_LOG, "\t}\n");
|
||||
}
|
||||
int prim = 1;
|
||||
for(unsigned i = 0; i < sect->vertices.Size(); i++)
|
||||
{
|
||||
int v = sect->vertices[i];
|
||||
if (v < 0)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
Printf(PRINT_LOG, "\t}\n");
|
||||
}
|
||||
switch (v)
|
||||
{
|
||||
case -GL_TRIANGLE_FAN:
|
||||
Printf(PRINT_LOG, "\t%d: Triangle fan\n\t{\n", prim);
|
||||
break;
|
||||
|
||||
case -GL_TRIANGLE_STRIP:
|
||||
Printf(PRINT_LOG, "\t%d: Triangle strip\n\t{\n", prim);
|
||||
break;
|
||||
|
||||
case -GL_TRIANGLES:
|
||||
Printf(PRINT_LOG, "\t%d: Triangles\n\t{\n", prim);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
prim++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf(PRINT_LOG, "\t\tVertex %d: (%1.2f, %1.2f)\n",
|
||||
v, vertexes[v].x/65536.f, vertexes[v].y/65536.f);
|
||||
}
|
||||
}
|
||||
Printf(PRINT_LOG, "}\n\n");
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void DumpSections()
|
||||
{
|
||||
for(unsigned i = 0; i < Sections.Size(); i++)
|
||||
{
|
||||
DumpSection(i, &Sections[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void gl_CreateSections()
|
||||
{
|
||||
SectionLines.Clear();
|
||||
SectionLoops.Clear();
|
||||
Sections.Clear();
|
||||
SectionForSubsector.Resize(numsubsectors);
|
||||
memset(&SectionForSubsector[0], -1, numsubsectors * sizeof(SectionForSubsector[0]));
|
||||
FSectionCreator creat;
|
||||
creat.CreateSections();
|
||||
if (dumpsections) DumpSections();
|
||||
}
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
#ifndef __GL_SECTIONS_H
|
||||
#define __GL_SECTIONS_H
|
||||
|
||||
#include "tarray.h"
|
||||
#include "r_defs.h"
|
||||
|
||||
struct FGLSectionLine
|
||||
{
|
||||
vertex_t *start;
|
||||
vertex_t *end;
|
||||
side_t *sidedef;
|
||||
line_t *linedef;
|
||||
seg_t *refseg; // we need to reference at least one seg for each line.
|
||||
subsector_t *polysub; // If this is part of a polyobject we need a reference to the containing subsector
|
||||
int otherside;
|
||||
};
|
||||
|
||||
struct FGLSectionLoop
|
||||
{
|
||||
int startline;
|
||||
int numlines;
|
||||
|
||||
FGLSectionLine *GetLine(int no);
|
||||
};
|
||||
|
||||
struct FGLSection
|
||||
{
|
||||
sector_t *sector;
|
||||
TArray<subsector_t *> subsectors;
|
||||
TArray<int> primitives; // each primitive has 2 entries: Primitive type and vertex count
|
||||
TArray<int> vertices;
|
||||
int startloop;
|
||||
int numloops;
|
||||
int validcount;
|
||||
|
||||
FGLSectionLoop *GetLoop(int no);
|
||||
};
|
||||
|
||||
extern TArray<FGLSectionLine> SectionLines;
|
||||
extern TArray<FGLSectionLoop> SectionLoops;
|
||||
extern TArray<FGLSection> Sections;
|
||||
extern TArray<int> SectionForSubsector;
|
||||
|
||||
inline FGLSectionLine *FGLSectionLoop::GetLine(int no)
|
||||
{
|
||||
return &SectionLines[startline + no];
|
||||
}
|
||||
|
||||
inline FGLSectionLoop *FGLSection::GetLoop(int no)
|
||||
{
|
||||
return &SectionLoops[startloop + no];
|
||||
}
|
||||
|
||||
void gl_CreateSections();
|
||||
|
||||
#endif
|
||||
|
|
@ -1,698 +0,0 @@
|
|||
/*
|
||||
** gl_shaders.cpp
|
||||
** Routines parsing/managing texture shaders.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Timothy Stump
|
||||
** Copyright 2009 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 "gl/system/gl_system.h"
|
||||
#include "doomtype.h"
|
||||
#include "c_cvars.h"
|
||||
#include "sc_man.h"
|
||||
#include "textures/textures.h"
|
||||
#include "gl/shaders/gl_texshader.h"
|
||||
|
||||
CVAR(Bool, gl_texture_useshaders, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderLayer::FShaderLayer()
|
||||
{
|
||||
animate = false;
|
||||
emissive = false;
|
||||
blendFuncSrc = GL_SRC_ALPHA;
|
||||
blendFuncDst = GL_ONE_MINUS_SRC_ALPHA;
|
||||
offsetX = 0.f;
|
||||
offsetY = 0.f;
|
||||
centerX = 0.0f;
|
||||
centerY = 0.0f;
|
||||
rotate = 0.f;
|
||||
rotation = 0.f;
|
||||
adjustX.SetParams(0.f, 0.f, 0.f);
|
||||
adjustY.SetParams(0.f, 0.f, 0.f);
|
||||
scaleX.SetParams(1.f, 1.f, 0.f);
|
||||
scaleY.SetParams(1.f, 1.f, 0.f);
|
||||
alpha.SetParams(1.f, 1.f, 0.f);
|
||||
r.SetParams(1.f, 1.f, 0.f);
|
||||
g.SetParams(1.f, 1.f, 0.f);
|
||||
b.SetParams(1.f, 1.f, 0.f);
|
||||
flags = 0;
|
||||
layerMask = NULL;
|
||||
texgen = SHADER_TexGen_None;
|
||||
warp = false;
|
||||
warpspeed = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderLayer::FShaderLayer(const FShaderLayer &layer)
|
||||
{
|
||||
texture = layer.texture;
|
||||
animate = layer.animate;
|
||||
emissive = layer.emissive;
|
||||
adjustX = layer.adjustX;
|
||||
adjustY = layer.adjustY;
|
||||
blendFuncSrc = layer.blendFuncSrc;
|
||||
blendFuncDst = layer.blendFuncDst;
|
||||
offsetX = layer.offsetX;
|
||||
offsetY = layer.offsetY;
|
||||
centerX = layer.centerX;
|
||||
centerY = layer.centerX;
|
||||
rotate = layer.rotate;
|
||||
rotation = layer.rotation;
|
||||
scaleX = layer.scaleX;
|
||||
scaleY = layer.scaleY;
|
||||
vectorX = layer.vectorX;
|
||||
vectorY = layer.vectorY;
|
||||
alpha = layer.alpha;
|
||||
r = layer.r;
|
||||
g = layer.g;
|
||||
b = layer.b;
|
||||
flags = layer.flags;
|
||||
if (layer.layerMask)
|
||||
{
|
||||
layerMask = new FShaderLayer(*(layer.layerMask));
|
||||
}
|
||||
else
|
||||
{
|
||||
layerMask = NULL;
|
||||
}
|
||||
texgen = layer.texgen;
|
||||
warp = layer.warp;
|
||||
warpspeed = layer.warpspeed;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderLayer::~FShaderLayer()
|
||||
{
|
||||
if (layerMask)
|
||||
{
|
||||
delete layerMask;
|
||||
layerMask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderLayer::Update(float diff)
|
||||
{
|
||||
r.Update(diff);
|
||||
g.Update(diff);
|
||||
b.Update(diff);
|
||||
alpha.Update(diff);
|
||||
vectorY.Update(diff);
|
||||
vectorX.Update(diff);
|
||||
scaleX.Update(diff);
|
||||
scaleY.Update(diff);
|
||||
adjustX.Update(diff);
|
||||
adjustY.Update(diff);
|
||||
srcFactor.Update(diff);
|
||||
dstFactor.Update(diff);
|
||||
|
||||
offsetX += vectorX * diff;
|
||||
if (offsetX >= 1.f) offsetX -= 1.f;
|
||||
if (offsetX < 0.f) offsetX += 1.f;
|
||||
|
||||
offsetY += vectorY * diff;
|
||||
if (offsetY >= 1.f) offsetY -= 1.f;
|
||||
if (offsetY < 0.f) offsetY += 1.f;
|
||||
|
||||
rotation += rotate * diff;
|
||||
if (rotation > 360.f) rotation -= 360.f;
|
||||
if (rotation < 0.f) rotation += 360.f;
|
||||
|
||||
if (layerMask != NULL) layerMask->Update(diff);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FParseKey
|
||||
{
|
||||
const char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
static const FParseKey CycleTags[]=
|
||||
{
|
||||
{"linear", CYCLE_Linear},
|
||||
{"sin", CYCLE_Sin},
|
||||
{"cos", CYCLE_Cos},
|
||||
{"sawtooth", CYCLE_SawTooth},
|
||||
{"square", CYCLE_Square},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static const FParseKey BlendTags[]=
|
||||
{
|
||||
{"GL_ZERO", GL_ZERO},
|
||||
{"GL_ONE", GL_ONE},
|
||||
|
||||
{"GL_DST_COLOR", GL_DST_COLOR},
|
||||
{"GL_ONE_MINUS_DST_COLOR", GL_ONE_MINUS_DST_COLOR},
|
||||
{"GL_DST_ALPHA", GL_DST_ALPHA},
|
||||
{"GL_ONE_MINUS_DST_ALPHA", GL_ONE_MINUS_DST_ALPHA},
|
||||
|
||||
{"GL_SRC_COLOR", GL_SRC_COLOR},
|
||||
{"GL_ONE_MINUS_SRC_COLOR", GL_ONE_MINUS_SRC_COLOR},
|
||||
{"GL_SRC_ALPHA", GL_SRC_ALPHA},
|
||||
{"GL_ONE_MINUS_SRC_ALPHA", GL_ONE_MINUS_SRC_ALPHA},
|
||||
|
||||
{"GL_SRC_ALPHA_SATURATE", GL_SRC_ALPHA_SATURATE},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CycleType FShaderLayer::ParseCycleType(FScanner &sc)
|
||||
{
|
||||
if (sc.GetString())
|
||||
{
|
||||
int t = sc.MatchString(&CycleTags[0].name, sizeof(CycleTags[0]));
|
||||
if (t > -1) return CycleType(CycleTags[t].value);
|
||||
sc.UnGet();
|
||||
}
|
||||
return CYCLE_Linear;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FShaderLayer::ParseLayer(FScanner &sc)
|
||||
{
|
||||
bool retval = true;
|
||||
float start, end, cycle, r1, r2, g1, g2, b1, b2;
|
||||
int type;
|
||||
|
||||
if (sc.GetString())
|
||||
{
|
||||
texture = TexMan.CheckForTexture(sc.String, ETextureType::Wall);
|
||||
if (!texture.isValid())
|
||||
{
|
||||
sc.ScriptMessage("Unknown texture '%s'", sc.String);
|
||||
retval = false;
|
||||
}
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
if (sc.End)
|
||||
{
|
||||
sc.ScriptError("Unexpected end of file encountered");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sc.Compare("alpha"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
alpha.ShouldCycle(true);
|
||||
alpha.SetCycleType(ParseCycleType(sc));
|
||||
|
||||
sc.MustGetFloat();
|
||||
start = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
end = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
alpha.SetParams(start, end, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
alpha.SetParams(float(sc.Float), float(sc.Float), 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("srcfactor"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
srcFactor.ShouldCycle(true);
|
||||
srcFactor.SetCycleType(ParseCycleType(sc));
|
||||
|
||||
sc.MustGetFloat();
|
||||
start = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
end = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
srcFactor.SetParams(start, end, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
srcFactor.SetParams(float(sc.Float), float(sc.Float), 0.f);
|
||||
}
|
||||
}
|
||||
if (sc.Compare("destfactor"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
dstFactor.ShouldCycle(true);
|
||||
dstFactor.SetCycleType(ParseCycleType(sc));
|
||||
|
||||
sc.MustGetFloat();
|
||||
start = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
end = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
dstFactor.SetParams(start, end, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
dstFactor.SetParams(float(sc.Float), float(sc.Float), 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("animate"))
|
||||
{
|
||||
sc.GetString();
|
||||
animate = sc.Compare("true");
|
||||
}
|
||||
else if (sc.Compare("blendfunc"))
|
||||
{
|
||||
sc.GetString();
|
||||
type = sc.MustMatchString(&BlendTags[0].name, sizeof(BlendTags[0]));
|
||||
blendFuncSrc = type;// BlendTags[type].value;
|
||||
|
||||
sc.GetString();
|
||||
type = sc.MustMatchString(&BlendTags[0].name, sizeof(BlendTags[0]));
|
||||
blendFuncDst = type; //BlendTags[type].value;
|
||||
}
|
||||
else if (sc.Compare("color"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
CycleType type = ParseCycleType(sc);
|
||||
r.ShouldCycle(true);
|
||||
g.ShouldCycle(true);
|
||||
b.ShouldCycle(true);
|
||||
r.SetCycleType(type);
|
||||
g.SetCycleType(type);
|
||||
b.SetCycleType(type);
|
||||
|
||||
sc.MustGetFloat();
|
||||
r1 = float(sc.Float);
|
||||
sc.MustGetFloat();
|
||||
g1 = float(sc.Float);
|
||||
sc.MustGetFloat();
|
||||
b1 = float(sc.Float);
|
||||
|
||||
// get color2
|
||||
sc.MustGetFloat();
|
||||
r2 = float(sc.Float);
|
||||
sc.MustGetFloat();
|
||||
g2 = float(sc.Float);
|
||||
sc.MustGetFloat();
|
||||
b2 = float(sc.Float);
|
||||
|
||||
// get cycle time
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
r.SetParams(r1, r2, cycle);
|
||||
g.SetParams(g1, g2, cycle);
|
||||
b.SetParams(b1, b2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
r1 = float(sc.Float);
|
||||
sc.MustGetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
b1 = sc.Float;
|
||||
|
||||
r.SetParams(r1, r1, 0.f);
|
||||
g.SetParams(g1, g1, 0.f);
|
||||
b.SetParams(b1, b1, 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("center"))
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
centerX = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
centerY = sc.Float;
|
||||
}
|
||||
else if (sc.Compare("emissive"))
|
||||
{
|
||||
sc.GetString();
|
||||
emissive = sc.Compare("true");
|
||||
}
|
||||
else if (sc.Compare("offset"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
adjustX.ShouldCycle(true);
|
||||
adjustY.ShouldCycle(true);
|
||||
|
||||
sc.MustGetFloat();
|
||||
r1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
r2 = sc.Float;
|
||||
|
||||
sc.MustGetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
g2 = sc.Float;
|
||||
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
offsetX = r1;
|
||||
offsetY = r2;
|
||||
|
||||
adjustX.SetParams(0.f, g1 - r1, cycle);
|
||||
adjustY.SetParams(0.f, g2 - r2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
offsetX = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
offsetY = sc.Float;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("offsetfunc"))
|
||||
{
|
||||
adjustX.SetCycleType(ParseCycleType(sc));
|
||||
adjustY.SetCycleType(ParseCycleType(sc));
|
||||
}
|
||||
else if (sc.Compare("mask"))
|
||||
{
|
||||
if (layerMask != NULL) delete layerMask;
|
||||
layerMask = new FShaderLayer;
|
||||
layerMask->ParseLayer(sc);
|
||||
}
|
||||
else if (sc.Compare("rotate"))
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
rotate = sc.Float;
|
||||
}
|
||||
else if (sc.Compare("rotation"))
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
rotation = sc.Float;
|
||||
}
|
||||
else if (sc.Compare("scale"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
scaleX.ShouldCycle(true);
|
||||
scaleY.ShouldCycle(true);
|
||||
|
||||
sc.MustGetFloat();
|
||||
r1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
r2 = sc.Float;
|
||||
|
||||
sc.MustGetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
g2 = sc.Float;
|
||||
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
scaleX.SetParams(r1, g1, cycle);
|
||||
scaleY.SetParams(r2, g2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
scaleX.SetParams(sc.Float, sc.Float, 0.f);
|
||||
sc.MustGetFloat();
|
||||
scaleY.SetParams(sc.Float, sc.Float, 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("scalefunc"))
|
||||
{
|
||||
scaleX.SetCycleType(ParseCycleType(sc));
|
||||
scaleY.SetCycleType(ParseCycleType(sc));
|
||||
}
|
||||
else if (sc.Compare("texgen"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("sphere"))
|
||||
{
|
||||
texgen = SHADER_TexGen_Sphere;
|
||||
}
|
||||
else
|
||||
{
|
||||
texgen = SHADER_TexGen_None;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("vector"))
|
||||
{
|
||||
if (sc.CheckString("cycle"))
|
||||
{
|
||||
vectorX.ShouldCycle(true);
|
||||
vectorY.ShouldCycle(true);
|
||||
|
||||
sc.MustGetFloat();
|
||||
r1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
g1 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
r2 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
g2 = sc.Float;
|
||||
sc.MustGetFloat();
|
||||
cycle = sc.Float;
|
||||
|
||||
vectorX.SetParams(r1, r2, cycle);
|
||||
vectorY.SetParams(g1, g2, cycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
vectorX.SetParams(sc.Float, sc.Float, 0.f);
|
||||
sc.MustGetFloat();
|
||||
vectorY.SetParams(sc.Float, sc.Float, 0.f);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("vectorfunc"))
|
||||
{
|
||||
vectorX.SetCycleType(ParseCycleType(sc));
|
||||
vectorY.SetCycleType(ParseCycleType(sc));
|
||||
}
|
||||
else if (sc.Compare("warp"))
|
||||
{
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
warp = sc.Number >= 0 && sc.Number <= 2? sc.Number : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// compatibility with ZDoomGL
|
||||
sc.MustGetString();
|
||||
warp = sc.Compare("true");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown keyword '%s' in shader layer", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FTextureShader::FTextureShader()
|
||||
{
|
||||
layers.Clear();
|
||||
lastUpdate = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FTextureShader::ParseShader(FScanner &sc, TArray<FTextureID> &names)
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
if (sc.GetString())
|
||||
{
|
||||
name = sc.String;
|
||||
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
if (sc.End)
|
||||
{
|
||||
sc.ScriptError("Unexpected end of file encountered");
|
||||
return false;
|
||||
}
|
||||
else if (sc.Compare("layer"))
|
||||
{
|
||||
FShaderLayer *lay = new FShaderLayer;
|
||||
if (lay->ParseLayer(sc))
|
||||
{
|
||||
if (layers.Size() < 8)
|
||||
{
|
||||
layers.Push(lay);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete lay;
|
||||
sc.ScriptMessage("Only 8 layers per texture allowed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete lay;
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown keyword '%s' in shader", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTextureShader::Update(int framems)
|
||||
{
|
||||
float diff = (framems - lastUpdate) / 1000.f;
|
||||
|
||||
if (lastUpdate != 0) // && !paused && !bglobal.freeze)
|
||||
{
|
||||
for (unsigned int i = 0; i < layers.Size(); i++)
|
||||
{
|
||||
layers[i]->Update(diff);
|
||||
}
|
||||
}
|
||||
lastUpdate = framems;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FTextureShader::FakeUpdate(int framems)
|
||||
{
|
||||
lastUpdate = framems;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString FTextureShader::CreateName()
|
||||
{
|
||||
FString compose = "custom";
|
||||
for(unsigned i=0; i<layers.Size(); i++)
|
||||
{
|
||||
compose.AppendFormat("@%de%ds%ud%ut%dw%d", i, layers[i]->emissive,
|
||||
layers[i]->blendFuncSrc, layers[i]->blendFuncDst, layers[i]->texgen, layers[i]->warp);
|
||||
}
|
||||
return compose;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString FTextureShader::GenerateCode()
|
||||
{
|
||||
static const char *funcnames[] = {"gettexel", "getwarp1", "getwarp2" };
|
||||
static const char *srcblend[] = { "vec4(0.0)", "src", "src*dest", "1.0-src*dest", "src*dest.a", "1.0-src*dest.a",
|
||||
"src*src", "1.0-src*src", "src*src.a", "1.0-src*src", "vec4(src.rgb*src.a, 1)" };
|
||||
static const char *dstblend[] = { "vec4(0.0)", "dest", "dest*dest", "1.0-dest*dest", "dest*dest.a", "1.0-dest*dest.a",
|
||||
"dest*src", "1.0-dest*src", "dest*src.a", "1.0-dest*src", "vec4(dest.rgb*src.a, 1)" };
|
||||
FString compose;
|
||||
for(unsigned i=0; i<layers.Size(); i++)
|
||||
{
|
||||
compose.AppendFormat("src = %s(texture%d, glTexCoord[%d].st) * colors[%d];\n",
|
||||
funcnames[layers[i]->warp], i+1, i, i);
|
||||
if (!layers[i]->emissive) compose.AppendFormat("src.rgb *= gl_Color.rgb;\n");
|
||||
compose.AppendFormat("dest = (%s)*srcfactor + (%s)*dstfactor;\n",
|
||||
srcblend[layers[i]->blendFuncSrc], dstblend[layers[i]->blendFuncDst]);
|
||||
}
|
||||
return compose;
|
||||
}
|
||||
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
|
||||
#ifndef __GL_TEXSHADERS_H__
|
||||
#define __GL_TEXSHADERS_H__
|
||||
|
||||
|
||||
#include "tarray.h"
|
||||
#include "zstring.h"
|
||||
#include "cycler.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SHADER_TexGen_None = 0,
|
||||
SHADER_TexGen_Sphere,
|
||||
NUM_TexGenTypes
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FShaderLayer
|
||||
{
|
||||
public:
|
||||
FShaderLayer();
|
||||
FShaderLayer(const FShaderLayer &layer);
|
||||
~FShaderLayer();
|
||||
void Update(float diff);
|
||||
CycleType ParseCycleType(FScanner &sc);
|
||||
bool ParseLayer(FScanner &sc);
|
||||
|
||||
FTextureID texture;
|
||||
int warpspeed;
|
||||
unsigned char warp;
|
||||
bool animate;
|
||||
bool emissive;
|
||||
unsigned char texgen;
|
||||
float centerX, centerY;
|
||||
float rotation;
|
||||
float rotate;
|
||||
float offsetX, offsetY;
|
||||
FCycler adjustX, adjustY;
|
||||
FCycler vectorX, vectorY;
|
||||
FCycler scaleX, scaleY;
|
||||
FCycler alpha;
|
||||
FCycler r, g, b;
|
||||
FCycler srcFactor, dstFactor;
|
||||
unsigned int flags;
|
||||
unsigned int blendFuncSrc, blendFuncDst;
|
||||
FShaderLayer *layerMask;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FTextureShader
|
||||
{
|
||||
public:
|
||||
FTextureShader();
|
||||
bool ParseShader(FScanner &sc, TArray<FTextureID> &names);
|
||||
bool Available();
|
||||
bool Setup(float time);
|
||||
void Update(int framems);
|
||||
void FakeUpdate(int framems);
|
||||
FString CreateName();
|
||||
FString GenerateCode();
|
||||
|
||||
FName name;
|
||||
TDeletingArray <FShaderLayer *> layers; // layers for shader
|
||||
unsigned int lastUpdate;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
//extern TArray<FShader *> Shaders[NUM_ShaderClasses];
|
||||
//extern TArray<FShader *> ShaderLookup[NUM_ShaderClasses];
|
||||
|
||||
void GL_InitShaders();
|
||||
void GL_ReleaseShaders();
|
||||
void GL_UpdateShaders();
|
||||
void GL_FakeUpdateShaders();
|
||||
//void GL_UpdateShader(FShader *shader);
|
||||
void GL_DrawShaders();
|
||||
//FShader *GL_ShaderForTexture(FTexture *tex);
|
||||
|
||||
bool GL_ParseShader();
|
||||
*/
|
||||
|
||||
|
||||
#endif // __GL_TEXSHADERS_H__
|
||||
Loading…
Add table
Add a link
Reference in a new issue