implement/fix clipping during rendering of light

issue1247
Tobias Zwick 2014-11-17 23:01:12 +01:00
parent 96729ef57c
commit 239cd222e5
4 changed files with 59 additions and 43 deletions

View File

@ -5,6 +5,8 @@
#include "C4FoWBeamTriangle.h"
#include "C4FoWDrawStrategy.h"
#include <vector>
C4FoWLight::C4FoWLight(C4Object *pObj)
: iX(fixtoi(pObj->fix_x)),
iY(fixtoi(pObj->fix_y)),
@ -13,23 +15,24 @@ C4FoWLight::C4FoWLight(C4Object *pObj)
iSize(20),
pNext(NULL),
pObj(pObj),
sectionUp(this, 0),
sectionLeft(this, 270),
sectionDown(this, 180),
sectionRight(this, 90)
sections(4)
{
sections[0] = new C4FoWLightSection(this,0);
sections[1] = new C4FoWLightSection(this,90);
sections[2] = new C4FoWLightSection(this,180);
sections[3] = new C4FoWLightSection(this,270);
}
C4FoWLight::~C4FoWLight()
{
for( int i = 0; i < sections.size(); ++i )
delete sections[i];
}
void C4FoWLight::Invalidate(C4Rect r)
{
sectionUp.Invalidate(r);
sectionDown.Invalidate(r);
sectionLeft.Invalidate(r);
sectionRight.Invalidate(r);
for( int i = 0; i < sections.size(); ++i )
sections[i]->Invalidate(r);
}
void C4FoWLight::SetReach(int32_t iReach2, int32_t iFadeout2)
@ -43,52 +46,53 @@ void C4FoWLight::SetReach(int32_t iReach2, int32_t iFadeout2)
if (iReach2 < iReach)
{
iReach = iReach2;
sectionUp.Prune(iReach);
sectionDown.Prune(iReach);
sectionLeft.Prune(iReach);
sectionRight.Prune(iReach);
for( int i = 0; i < sections.size(); ++i )
sections[i]->Prune(iReach);
} else {
// Reach increased? Dirty beams that might get longer now
iReach = iReach2;
sectionUp.Dirty(iReach);
sectionDown.Dirty(iReach);
sectionLeft.Dirty(iReach);
sectionRight.Dirty(iReach);
for( int i = 0; i < sections.size(); ++i )
sections[i]->Dirty(iReach);
}
}
void C4FoWLight::Update(C4Rect Rec)
{
// Update position from object. Clear if we moved in any way
int32_t iNX = fixtoi(pObj->fix_x), iNY = fixtoi(pObj->fix_y);
if (iNX != iX || iNY != iY)
{
sectionUp.Prune(0);
sectionDown.Prune(0);
sectionLeft.Prune(0);
sectionRight.Prune(0);
for( int i = 0; i < sections.size(); ++i )
sections[i]->Prune(0);
iX = iNX; iY = iNY;
}
sectionUp.Update(Rec);
sectionDown.Update(Rec);
sectionLeft.Update(Rec);
sectionRight.Update(Rec);
for( int i = 0; i < sections.size(); ++i )
sections[i]->Update(Rec);
}
void C4FoWLight::Render(C4FoWRegion *region, const C4TargetFacet *onScreen)
{
std::list<C4FoWBeamTriangle> triangles;
triangles.splice(triangles.end(), sectionUp.CalculateTriangles(region));
triangles.splice(triangles.end(), sectionRight.CalculateTriangles(region));
triangles.splice(triangles.end(), sectionDown.CalculateTriangles(region));
triangles.splice(triangles.end(), sectionLeft.CalculateTriangles(region));
CalculateIntermediateFadeTriangles(triangles);
bool clip = false;
for( int i = 0; i < sections.size(); ++i )
{
std::list<C4FoWBeamTriangle> &sectionTriangles = sections[i]->CalculateTriangles(region);
// if the triangles of one section are clipped completely, the neighbouring triangles
// must be marked as clipped
if(!triangles.empty()) triangles.rbegin()->clipRight |= clip;
if(!sectionTriangles.empty()) sectionTriangles.begin()->clipLeft |= clip;
clip = sectionTriangles.empty();
triangles.splice(triangles.end(), sectionTriangles);
}
CalculateIntermediateFadeTriangles(triangles);
// Here's the master plan for updating the lights texture. We
// want to add intensity (R channel) as well as the normal (GB channels).
// Normals are obviously meant to be though of as signed, though,
@ -184,7 +188,9 @@ void C4FoWLight::DrawFan(C4FoWDrawStrategy* pen, std::list<C4FoWBeamTriangle> &t
C4FoWBeamTriangle &tri = *it, &nextTri = *nextIt; // just for convenience
pen->DrawLightVertex(tri.fanLX, tri.fanLY);
pen->DrawLightVertex(tri.fanRX, tri.fanRY);
if(nextTri.fanLX != tri.fanRX || nextTri.fanLY != tri.fanRY)
pen->DrawLightVertex(tri.fanRX, tri.fanRY);
}
pen->EndFan();
}

View File

@ -7,6 +7,8 @@
#include "C4FoWLightSection.h"
#include "C4Rect.h"
#include <vector>
/** This class represents one light source. A light source has an associated object with which the light source moves
and one light section that handles the light beams for each direction (up, down, left, right).
@ -27,10 +29,7 @@ private:
C4FoWLight *pNext;
C4Object *pObj; // Associated object
C4FoWLightSection sectionUp;
C4FoWLightSection sectionLeft;
C4FoWLightSection sectionDown;
C4FoWLightSection sectionRight;
std::vector<C4FoWLightSection*> sections;
public:
int32_t getX() const { return iX; }

View File

@ -397,7 +397,7 @@ void C4FoWLightSection::Invalidate(C4Rect r)
}
int32_t C4FoWLightSection::FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firstBeam, C4FoWBeam *&lastBeam)
int32_t C4FoWLightSection::FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firstBeam, C4FoWBeam *&endBeam)
{
if(rect.y + rect.Hgt < 0) return 0;
@ -417,7 +417,7 @@ int32_t C4FoWLightSection::FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firs
beam = beam->getNext();
beamCount++;
}
lastBeam = beam;
endBeam = beam;
return beamCount;
}
@ -426,10 +426,14 @@ std::list<C4FoWBeamTriangle> C4FoWLightSection::CalculateTriangles(C4FoWRegion *
{
C4FoWBeam *startBeam = NULL, *endBeam = NULL;
int32_t beamCount = FindBeamsClipped(rtransRect(region->getRegion()), startBeam, endBeam);
// no beams inside the rectangle? Good, nothing to render
std::list<C4FoWBeamTriangle> result;
// no beams inside the rectangle? Good, nothing to render
if(!beamCount) return result;
bool isStartClipped = startBeam != pBeams;
bool isEndClipped = !!endBeam;
C4FoWBeam *beam = startBeam;
for (int32_t i = 0; i < beamCount; i++, beam = beam->getNext())
{
@ -438,9 +442,15 @@ std::list<C4FoWBeamTriangle> C4FoWLightSection::CalculateTriangles(C4FoWRegion *
tri.fanLY = float(beam->getLeftEndY());
tri.fanRX = beam->getRightEndXf();
tri.fanRY = float(beam->getRightEndY());
tri.clipLeft = false; // TODO Newton: pBeams.start != startBeam
tri.clipRight = false; // TODO Newton: pBeams.end != endBeam
result.push_back(tri);
if(i == 0 && isStartClipped)
tri.clipLeft = true;
if(i == beamCount - 1 && isEndClipped)
{
tri.clipRight = true;
}
if(tri.fanLX != tri.fanRX || tri.fanLY != tri.fanRY)
result.push_back(tri);
}
// Phase 1: Project lower point so it lies on a line with outer left/right

View File

@ -105,8 +105,9 @@ private:
C4FoWBeam *FindBeamLeftOf(int32_t x, int32_t y);
/** Find beams that go through the given rectangle. Returns the number of beams that are in the rectangle and makes
pFirst and pLast point to the first and the last beam of these */
int32_t FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firstBeam, C4FoWBeam *&lastBeam);
firstBeam point to the first and endBeam point to the beam after the last of these. Thus, endBeam is NULL if
no beams were clipped at the end. */
int32_t FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firstBeam, C4FoWBeam *&endBeam);
};