forked from Mirrors/openclonk
implement/fix clipping during rendering of light
parent
96729ef57c
commit
239cd222e5
|
@ -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,50 +46,51 @@ 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));
|
|
||||||
|
|
||||||
|
bool clip = false;
|
||||||
|
|
||||||
|
for( int i = 0; i < sections.size(); ++i )
|
||||||
|
{
|
||||||
|
std::list<C4FoWBeamTriangle> §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);
|
CalculateIntermediateFadeTriangles(triangles);
|
||||||
|
|
||||||
// Here's the master plan for updating the lights texture. We
|
// Here's the master plan for updating the lights texture. We
|
||||||
|
@ -184,6 +188,8 @@ 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);
|
||||||
|
|
||||||
|
if(nextTri.fanLX != tri.fanRX || nextTri.fanLY != tri.fanRY)
|
||||||
pen->DrawLightVertex(tri.fanRX, tri.fanRY);
|
pen->DrawLightVertex(tri.fanRX, tri.fanRY);
|
||||||
}
|
}
|
||||||
pen->EndFan();
|
pen->EndFan();
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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,8 +442,14 @@ 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;
|
||||||
|
if(i == beamCount - 1 && isEndClipped)
|
||||||
|
{
|
||||||
|
tri.clipRight = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tri.fanLX != tri.fanRX || tri.fanLY != tri.fanRY)
|
||||||
result.push_back(tri);
|
result.push_back(tri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue