diff --git a/src/landscape/fow/C4FoWLight.cpp b/src/landscape/fow/C4FoWLight.cpp index 7f4334d1a..9279b223f 100644 --- a/src/landscape/fow/C4FoWLight.cpp +++ b/src/landscape/fow/C4FoWLight.cpp @@ -5,6 +5,8 @@ #include "C4FoWBeamTriangle.h" #include "C4FoWDrawStrategy.h" +#include + 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 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 §ionTriangles = 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 &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(); } diff --git a/src/landscape/fow/C4FoWLight.h b/src/landscape/fow/C4FoWLight.h index 5ac44a50c..455ffb70a 100644 --- a/src/landscape/fow/C4FoWLight.h +++ b/src/landscape/fow/C4FoWLight.h @@ -7,6 +7,8 @@ #include "C4FoWLightSection.h" #include "C4Rect.h" +#include + /** 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 sections; public: int32_t getX() const { return iX; } diff --git a/src/landscape/fow/C4FoWLightSection.cpp b/src/landscape/fow/C4FoWLightSection.cpp index d5ed5a58e..aafe52821 100644 --- a/src/landscape/fow/C4FoWLightSection.cpp +++ b/src/landscape/fow/C4FoWLightSection.cpp @@ -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 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 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 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 diff --git a/src/landscape/fow/C4FoWLightSection.h b/src/landscape/fow/C4FoWLightSection.h index 721071428..8b1c7baab 100644 --- a/src/landscape/fow/C4FoWLightSection.h +++ b/src/landscape/fow/C4FoWLightSection.h @@ -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); };