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 "C4FoWBeamTriangle.h"
#include "C4FoWDrawStrategy.h" #include "C4FoWDrawStrategy.h"
#include <vector>
C4FoWLight::C4FoWLight(C4Object *pObj) C4FoWLight::C4FoWLight(C4Object *pObj)
: iX(fixtoi(pObj->fix_x)), : iX(fixtoi(pObj->fix_x)),
iY(fixtoi(pObj->fix_y)), iY(fixtoi(pObj->fix_y)),
@ -13,23 +15,24 @@ C4FoWLight::C4FoWLight(C4Object *pObj)
iSize(20), iSize(20),
pNext(NULL), pNext(NULL),
pObj(pObj), pObj(pObj),
sectionUp(this, 0), sections(4)
sectionLeft(this, 270),
sectionDown(this, 180),
sectionRight(this, 90)
{ {
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() C4FoWLight::~C4FoWLight()
{ {
for( int i = 0; i < sections.size(); ++i )
delete sections[i];
} }
void C4FoWLight::Invalidate(C4Rect r) void C4FoWLight::Invalidate(C4Rect r)
{ {
sectionUp.Invalidate(r); for( int i = 0; i < sections.size(); ++i )
sectionDown.Invalidate(r); sections[i]->Invalidate(r);
sectionLeft.Invalidate(r);
sectionRight.Invalidate(r);
} }
void C4FoWLight::SetReach(int32_t iReach2, int32_t iFadeout2) 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) if (iReach2 < iReach)
{ {
iReach = iReach2; iReach = iReach2;
sectionUp.Prune(iReach); for( int i = 0; i < sections.size(); ++i )
sectionDown.Prune(iReach); sections[i]->Prune(iReach);
sectionLeft.Prune(iReach);
sectionRight.Prune(iReach);
} else { } else {
// Reach increased? Dirty beams that might get longer now // Reach increased? Dirty beams that might get longer now
iReach = iReach2; iReach = iReach2;
sectionUp.Dirty(iReach); for( int i = 0; i < sections.size(); ++i )
sectionDown.Dirty(iReach); sections[i]->Dirty(iReach);
sectionLeft.Dirty(iReach);
sectionRight.Dirty(iReach);
} }
} }
void C4FoWLight::Update(C4Rect Rec) void C4FoWLight::Update(C4Rect Rec)
{ {
// Update position from object. Clear if we moved in any way // Update position from object. Clear if we moved in any way
int32_t iNX = fixtoi(pObj->fix_x), iNY = fixtoi(pObj->fix_y); int32_t iNX = fixtoi(pObj->fix_x), iNY = fixtoi(pObj->fix_y);
if (iNX != iX || iNY != iY) if (iNX != iX || iNY != iY)
{ {
sectionUp.Prune(0); for( int i = 0; i < sections.size(); ++i )
sectionDown.Prune(0); sections[i]->Prune(0);
sectionLeft.Prune(0);
sectionRight.Prune(0);
iX = iNX; iY = iNY; iX = iNX; iY = iNY;
} }
sectionUp.Update(Rec); for( int i = 0; i < sections.size(); ++i )
sectionDown.Update(Rec); sections[i]->Update(Rec);
sectionLeft.Update(Rec);
sectionRight.Update(Rec);
} }
void C4FoWLight::Render(C4FoWRegion *region, const C4TargetFacet *onScreen) void C4FoWLight::Render(C4FoWRegion *region, const C4TargetFacet *onScreen)
{ {
std::list<C4FoWBeamTriangle> triangles; 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 // Here's the master plan for updating the lights texture. We
// want to add intensity (R channel) as well as the normal (GB channels). // want to add intensity (R channel) as well as the normal (GB channels).
// Normals are obviously meant to be though of as signed, though, // 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 C4FoWBeamTriangle &tri = *it, &nextTri = *nextIt; // just for convenience
pen->DrawLightVertex(tri.fanLX, tri.fanLY); 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(); pen->EndFan();
} }

View File

@ -7,6 +7,8 @@
#include "C4FoWLightSection.h" #include "C4FoWLightSection.h"
#include "C4Rect.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 /** 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). and one light section that handles the light beams for each direction (up, down, left, right).
@ -27,10 +29,7 @@ private:
C4FoWLight *pNext; C4FoWLight *pNext;
C4Object *pObj; // Associated object C4Object *pObj; // Associated object
C4FoWLightSection sectionUp; std::vector<C4FoWLightSection*> sections;
C4FoWLightSection sectionLeft;
C4FoWLightSection sectionDown;
C4FoWLightSection sectionRight;
public: public:
int32_t getX() const { return iX; } 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; if(rect.y + rect.Hgt < 0) return 0;
@ -417,7 +417,7 @@ int32_t C4FoWLightSection::FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firs
beam = beam->getNext(); beam = beam->getNext();
beamCount++; beamCount++;
} }
lastBeam = beam; endBeam = beam;
return beamCount; return beamCount;
} }
@ -426,10 +426,14 @@ std::list<C4FoWBeamTriangle> C4FoWLightSection::CalculateTriangles(C4FoWRegion *
{ {
C4FoWBeam *startBeam = NULL, *endBeam = NULL; C4FoWBeam *startBeam = NULL, *endBeam = NULL;
int32_t beamCount = FindBeamsClipped(rtransRect(region->getRegion()), startBeam, endBeam); int32_t beamCount = FindBeamsClipped(rtransRect(region->getRegion()), startBeam, endBeam);
// no beams inside the rectangle? Good, nothing to render
std::list<C4FoWBeamTriangle> result; std::list<C4FoWBeamTriangle> result;
// no beams inside the rectangle? Good, nothing to render
if(!beamCount) return result; if(!beamCount) return result;
bool isStartClipped = startBeam != pBeams;
bool isEndClipped = !!endBeam;
C4FoWBeam *beam = startBeam; C4FoWBeam *beam = startBeam;
for (int32_t i = 0; i < beamCount; i++, beam = beam->getNext()) 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.fanLY = float(beam->getLeftEndY());
tri.fanRX = beam->getRightEndXf(); tri.fanRX = beam->getRightEndXf();
tri.fanRY = float(beam->getRightEndY()); tri.fanRY = float(beam->getRightEndY());
tri.clipLeft = false; // TODO Newton: pBeams.start != startBeam if(i == 0 && isStartClipped)
tri.clipRight = false; // TODO Newton: pBeams.end != endBeam tri.clipLeft = true;
result.push_back(tri); 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 // 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); 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 /** 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 */ firstBeam point to the first and endBeam point to the beam after the last of these. Thus, endBeam is NULL if
int32_t FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firstBeam, C4FoWBeam *&lastBeam); no beams were clipped at the end. */
int32_t FindBeamsClipped(const C4Rect &rect, C4FoWBeam *&firstBeam, C4FoWBeam *&endBeam);
}; };