- moved the "unused" folder to the repo's top level.

This commit is contained in:
Christoph Oelckers 2018-04-23 22:25:29 +02:00
commit a93799b21f
5 changed files with 0 additions and 0 deletions

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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;
}

View file

@ -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__