More progress on rendering.

This commit is contained in:
Andrzej Kapolka 2014-12-30 15:36:22 -08:00
parent 135e3bf574
commit de4776ef08
3 changed files with 138 additions and 59 deletions

View file

@ -2294,6 +2294,9 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
glm::vec3 step(1.0f / innerStackWidth, scale.x / (innerStackWidth * scale.y),
1.0f / innerStackHeight);
const int EDGES_PER_CUBE = 12;
EdgeCrossing crossings[EDGES_PER_CUBE];
for (int z = 0; z <= stackHeight; z++) {
pos.x = 0.0f;
const StackArray* lineSrc = src;
@ -2324,9 +2327,9 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
hermiteSegments.append(start + normal * step);
}
}
int alpha0 = entry->rgba[3];
int alpha0 = qAlpha(entry->color);
int alpha2 = lineSrc->getEntryAlpha(y + 1);
int alpha1 = alpha0, alpha4 = alpha0, alpha6 = alpha0;
int alpha1 = alpha0, alpha3 = alpha2, alpha4 = alpha0, alpha6 = alpha2;
int alphaTotal = alpha0 + alpha2;
int possibleTotal = 2 * numeric_limits<uchar>::max();
@ -2341,10 +2344,73 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
alphaTotal += (alpha6 = lineSrc[stackWidth].getEntryAlpha(y + 1));
possibleTotal += numeric_limits<uchar>::max();
}
int alpha5 = alpha4, alpha7 = alpha6;
if (middleX) {
alphaTotal += (alpha1 = lineSrc[1].getEntryAlpha(y));
possibleTotal += numeric_limits<uchar>::max();
alphaTotal += (alpha3 = lineSrc[1].getEntryAlpha(y + 1));
possibleTotal += numeric_limits<uchar>::max();
if (middleZ) {
alphaTotal += (alpha5 = lineSrc[stackWidth + 1].getEntryAlpha(y));
possibleTotal += numeric_limits<uchar>::max();
alphaTotal += (alpha7 = lineSrc[stackWidth + 1].getEntryAlpha(y + 1));
possibleTotal += numeric_limits<uchar>::max();
}
}
if (alphaTotal == 0 || alphaTotal == possibleTotal) {
continue; // no corners set/all corners set
}
// the terrifying conditional code that follows checks each cube edge for a crossing, gathering
// its properties (color, material, normal) if one is present; as before, boundary edges are excluded
int crossingCount = 0;
if (middleX) {
if (alpha0 != alpha1) {
EdgeCrossing& crossing = crossings[crossingCount++];
float distance = entry->getHermiteX(crossing.normal);
if (alpha0 == 0) {
const StackArray::Entry& nextEntry = lineSrc[1].getEntry(y);
crossing.color = nextEntry.color;
crossing.material = nextEntry.material;
} else {
crossing.color = entry->color;
crossing.material = entry->material;
}
crossing.point = glm::vec3(distance, 0.0f, 0.0f);
}
}
if (alpha0 != alpha2) {
EdgeCrossing& crossing = crossings[crossingCount++];
float distance = entry->getHermiteY(crossing.normal);
if (alpha0 == 0) {
const StackArray::Entry& nextEntry = lineSrc->getEntry(y + 1);
crossing.color = nextEntry.color;
crossing.material = nextEntry.material;
} else {
crossing.color = entry->color;
crossing.material = entry->material;
}
crossing.point = glm::vec3(0.0f, distance, 0.0f);
}
if (middleZ) {
if (alpha0 != alpha4) {
EdgeCrossing& crossing = crossings[crossingCount++];
float distance = entry->getHermiteZ(crossing.normal);
if (alpha0 == 0) {
const StackArray::Entry& nextEntry = lineSrc[stackWidth].getEntry(y);
crossing.color = nextEntry.color;
crossing.material = nextEntry.material;
} else {
crossing.color = entry->color;
crossing.material = entry->material;
}
crossing.point = glm::vec3(0.0f, 0.0f, distance);
}
}
}
}
if (x != 0) {

View file

@ -1153,31 +1153,32 @@ static QVector<StackArray> decodeHeightfieldStack(const QByteArray& encoded,
return contents;
}
static inline bool isZero(const uchar values[4]) {
return *(const quint32*)values == 0;
StackArray::Entry::Entry() :
color(0),
material(0),
hermiteX(0),
hermiteY(0),
hermiteZ(0) {
}
bool StackArray::Entry::isZero() const {
return ::isZero(rgba) && material == 0 && ::isZero(hermiteX) && ::isZero(hermiteY) && ::isZero(hermiteZ);
return color == 0 && material == 0 && hermiteX == 0 && hermiteY == 0 && hermiteZ == 0;
}
bool StackArray::Entry::isMergeable(const Entry& other) const {
return *(const quint32*)rgba == *(const quint32*)other.rgba && material == other.material &&
::isZero(hermiteX) && ::isZero(hermiteY) && ::isZero(hermiteZ);
return color == other.color && material == other.material && hermiteX == 0 && hermiteY == 0 && hermiteZ == 0;
}
static inline void setHermite(uchar values[4], const glm::vec3& normal, float position) {
values[0] = normal.x * numeric_limits<qint8>::max();
values[1] = normal.y * numeric_limits<qint8>::max();
values[2] = normal.z * numeric_limits<qint8>::max();
values[3] = position * numeric_limits<quint8>::max();
static inline void setHermite(quint32& value, const glm::vec3& normal, float position) {
value = qRgba(normal.x * numeric_limits<qint8>::max(), normal.y * numeric_limits<qint8>::max(),
normal.z * numeric_limits<qint8>::max(), position * numeric_limits<quint8>::max());
}
static inline float getHermite(const uchar values[4], glm::vec3& normal) {
normal.x = (char)values[0] / (float)numeric_limits<qint8>::max();
normal.y = (char)values[1] / (float)numeric_limits<qint8>::max();
normal.z = (char)values[2] / (float)numeric_limits<qint8>::max();
return values[3] / (float)numeric_limits<qint8>::max();
static inline float getHermite(QRgb value, glm::vec3& normal) {
normal.x = (char)qRed(value) / (float)numeric_limits<qint8>::max();
normal.y = (char)qGreen(value) / (float)numeric_limits<qint8>::max();
normal.z = (char)qBlue(value) / (float)numeric_limits<qint8>::max();
return qAlpha(value) / (float)numeric_limits<qint8>::max();
}
void StackArray::Entry::setHermiteX(const glm::vec3& normal, float position) {
@ -1210,7 +1211,27 @@ int StackArray::getEntryAlpha(int y) const {
return 0;
}
int relative = y - getPosition();
return (relative < count) ? getEntryData()[qMax(relative, 0)].rgba[3] : 0;
return (relative < count) ? qAlpha(getEntryData()[qMax(relative, 0)].color) : 0;
}
StackArray::Entry& StackArray::getEntry(int y) {
static Entry emptyEntry;
int count = getEntryCount();
if (count == 0) {
return emptyEntry;
}
int relative = y - getPosition();
return (relative < count) ? getEntryData()[qMax(relative, 0)] : emptyEntry;
}
const StackArray::Entry& StackArray::getEntry(int y) const {
static Entry emptyEntry;
int count = getEntryCount();
if (count == 0) {
return emptyEntry;
}
int relative = y - getPosition();
return (relative < count) ? getEntryData()[qMax(relative, 0)] : emptyEntry;
}
HeightfieldStack::HeightfieldStack(int width, const QVector<StackArray>& contents,
@ -2214,8 +2235,8 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
glm::vec3 voxelStepZ = glm::vec3(transform * glm::vec4(0.0f, 0.0f, 1.0f, 0.0f));
int newTop = start.y * voxelScale;
int newBottom = end.y * voxelScale;
char r = color.red(), g = color.green(), b = color.blue(), a = color.alpha();
bool erase = (a == 0);
QRgb rgba = color.rgba();
bool erase = (color.alpha() == 0);
uchar materialMaterialIndex = getMaterialIndex(material, newMaterialMaterials, newMaterialContents);
QByteArray dummyContents;
uchar stackMaterialIndex = getMaterialIndex(material, newStackMaterials, dummyContents);
@ -2246,8 +2267,8 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
float stackZ = (z - HeightfieldHeight::HEIGHT_BORDER) * innerStackHeight / innerHeightHeight;
int topHeight = -1;
char topR = 0, topG = 0, topB = 0;
uchar topMaterial;
QRgb topColor = 0;
uchar topMaterial = 0;
if (stackX >= 0.0f && stackX <= innerStackWidth && stackZ >= 0.0f && stackZ <= innerStackHeight) {
StackArray* stackDest = newStackContents.data() + (int)stackZ * stackWidth + (int)stackX;
@ -2259,7 +2280,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
StackArray::Entry* entryDest = stackDest->getEntryData();
if (colorDest) {
entryDest->setRGB(colorDest);
entryDest->color = qRgb(colorDest[0], colorDest[1], colorDest[2]);
}
if (materialDest) {
@ -2295,7 +2316,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
stackDest->getEntryCount() * sizeof(StackArray::Entry));
for (StackArray::Entry* entryDest = newStack.getEntryData(), *end = entryDest + prepend;
entryDest != end; entryDest++) {
entryDest->setRGBA(end->rgba);
entryDest->color = end->color;
entryDest->material = end->material;
}
*stackDest = newStack;
@ -2311,10 +2332,10 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
bool oldCurrentSet = entryDest->isSet();
if (spanner->contains(pos)) {
if (hasOwnColors && !erase) {
entryDest->setRGBA(spanner->getColorAt(pos));
entryDest->color = spanner->getColorAt(pos);
} else {
entryDest->setRGBA(r, g, b, a);
entryDest->color = rgba;
}
if (hasOwnMaterials && !erase) {
int index = spanner->getMaterialAt(pos);
@ -2337,14 +2358,14 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
if (nextStackX <= innerStackWidth) {
bool nextSetX = isSet(newStackContents, stackWidth, nextStackX, y, (int)stackZ);
if (nextSetX == currentSet) {
entryDest->clearHermiteX();
entryDest->hermiteX = 0;
} else {
bool flipped = (erase == nextSetX);
float oldDistance = flipped ? 0.0f : 1.0f;
if (currentSet == oldCurrentSet && nextSetX == isSet(oldStackContents, stackWidth,
nextStackX, y, (int)stackZ)) {
oldDistance = entryDest->hermiteX[3] / (float)numeric_limits<quint8>::max();
oldDistance = qAlpha(entryDest->hermiteX) / (float)numeric_limits<quint8>::max();
}
if (flipped ? (spanner->intersects(pos + voxelStepX, pos, distance, normal) &&
(distance = 1.0f - distance) >= oldDistance) :
@ -2357,14 +2378,14 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
bool nextSetY = (entryDest != stackDest->getEntryData() + stackDest->getEntryCount() - 1 &&
(entryDest + 1)->isSet());
if (nextSetY == currentSet) {
entryDest->clearHermiteY();
entryDest->hermiteY = 0;
} else {
bool flipped = (erase == nextSetY);
float oldDistance = flipped ? 0.0f : 1.0f;
if (currentSet == oldCurrentSet && nextSetY == isSet(oldStackContents, stackWidth,
(int)stackX, y + 1, (int)stackZ)) {
oldDistance = entryDest->hermiteY[3] / (float)numeric_limits<quint8>::max();
oldDistance = qAlpha(entryDest->hermiteY) / (float)numeric_limits<quint8>::max();
}
if (flipped ? (spanner->intersects(pos + voxelStepY, pos, distance, normal) &&
(distance = 1.0f - distance) >= oldDistance) :
@ -2377,14 +2398,14 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
if (nextStackZ <= innerStackHeight) {
bool nextSetZ = isSet(newStackContents, stackWidth, (int)stackX, y, nextStackZ);
if (nextSetZ == currentSet) {
entryDest->clearHermiteZ();
entryDest->hermiteZ = 0;
} else {
bool flipped = (erase == nextSetZ);
float oldDistance = flipped ? 0.0f : 1.0f;
if (currentSet == oldCurrentSet && nextSetZ == isSet(oldStackContents, stackWidth,
(int)stackX, y, nextStackZ)) {
oldDistance = entryDest->hermiteZ[3] / (float)numeric_limits<quint8>::max();
oldDistance = qAlpha(entryDest->hermiteZ) / (float)numeric_limits<quint8>::max();
}
if (flipped ? (spanner->intersects(pos + voxelStepZ, pos, distance, normal) &&
(distance = 1.0f - distance) >= oldDistance) :
@ -2413,10 +2434,8 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
StackArray::Entry* topEntry = stackDest->getEntryData() + topIndex;
if (topEntry->isSet()) {
topHeight = ((stackDest->getPosition() + topIndex) +
topEntry->hermiteY[3] / (float)numeric_limits<quint8>::max()) / voxelScale;
topR = topEntry->rgba[0];
topG = topEntry->rgba[1];
topB = topEntry->rgba[2];
qAlpha(topEntry->hermiteY) / (float)numeric_limits<quint8>::max()) / voxelScale;
topColor = topEntry->color;
topMaterial = topEntry->material;
} else {
@ -2436,9 +2455,9 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
if (topHeight != -1) {
*heightLineDest = topHeight;
if (colorDest) {
colorDest[0] = topR;
colorDest[1] = topG;
colorDest[2] = topB;
colorDest[0] = qRed(topColor);
colorDest[1] = qGreen(topColor);
colorDest[2] = qBlue(topColor);
}
if (materialDest) {
if (topMaterial != 0) {
@ -2467,9 +2486,9 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
colorDest[2] = qBlue(spannerColor);
} else {
colorDest[0] = r;
colorDest[1] = g;
colorDest[2] = b;
colorDest[0] = color.red();
colorDest[1] = color.green();
colorDest[2] = color.blue();
}
}

View file

@ -477,35 +477,26 @@ public:
/// A single entry within the array.
class Entry {
public:
uchar rgba[4];
quint32 color;
uchar material;
uchar hermiteX[4];
uchar hermiteY[4];
uchar hermiteZ[4];
void setRGBA(int r, int g, int b, int a = 0xFF) { rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = a; }
void setRGBA(const uchar* orgba) { setRGBA(orgba[0], orgba[1], orgba[2], orgba[3]); }
void setRGB(const uchar* rgb) { setRGBA(rgb[0], rgb[1], rgb[2]); }
void setRGBA(QRgb rgb) { setRGBA(qRed(rgb), qGreen(rgb), qBlue(rgb), qAlpha(rgb)); }
quint32 hermiteX;
quint32 hermiteY;
quint32 hermiteZ;
bool isSet() const { return rgba[3] != 0; }
Entry();
bool isSet() const { return qAlpha(color) != 0; }
bool isZero() const;
bool isMergeable(const Entry& other) const;
void setHermiteX(int x, int y, int z, int w) { hermiteX[0] = x; hermiteX[1] = y; hermiteX[2] = z; hermiteX[3] = w; }
void setHermiteX(const glm::vec3& normal, float position);
void clearHermiteX() { setHermiteX(0, 0, 0, 0); }
float getHermiteX(glm::vec3& normal) const;
void setHermiteY(int x, int y, int z, int w) { hermiteY[0] = x; hermiteY[1] = y; hermiteY[2] = z; hermiteY[3] = w; }
void setHermiteY(const glm::vec3& normal, float position);
void clearHermiteY() { setHermiteY(0, 0, 0, 0); }
float getHermiteY(glm::vec3& normal) const;
void setHermiteZ(int x, int y, int z, int w) { hermiteZ[0] = x; hermiteZ[1] = y; hermiteZ[2] = z; hermiteZ[3] = w; }
void setHermiteZ(const glm::vec3& normal, float position);
void clearHermiteZ() { setHermiteZ(0, 0, 0, 0); }
float getHermiteZ(glm::vec3& normal) const;
};
#pragma pack(pop)
@ -529,6 +520,9 @@ public:
int getEntryAlpha(int y) const;
Entry& getEntry(int y);
const Entry& getEntry(int y) const;
void removeEntries(int position, int count) { remove(sizeof(quint16) + position * sizeof(Entry), count * sizeof(Entry)); }
};