More rendering bits.

This commit is contained in:
Andrzej Kapolka 2014-12-31 15:53:38 -08:00
parent 83967d49cf
commit 08dfd28ec0
2 changed files with 129 additions and 84 deletions

View file

@ -1338,9 +1338,20 @@ class NormalIndex {
public:
int indices[MAX_NORMALS_PER_VERTEX];
bool isValid() const;
int getClosestIndex(const glm::vec3& normal, QVector<VoxelPoint>& vertices) const;
};
bool NormalIndex::isValid() const {
for (int i = 0; i < MAX_NORMALS_PER_VERTEX; i++) {
if (indices[i] != 0) {
return true;
}
}
return false;
}
int NormalIndex::getClosestIndex(const glm::vec3& normal, QVector<VoxelPoint>& vertices) const {
int firstIndex = indices[0];
int closestIndex = firstIndex;
@ -2157,6 +2168,22 @@ HeightfieldNodeRenderer::~HeightfieldNodeRenderer() {
Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID));
}
class IndexVector : public QVector<NormalIndex> {
public:
int position;
void swap(IndexVector& other) { QVector<NormalIndex>::swap(other); qSwap(position, other.position); }
const NormalIndex& get(int y) const;
};
const NormalIndex& IndexVector::get(int y) const {
static NormalIndex nullIndex = { { 0, 0, 0, 0 } };
int relative = y - position;
return (relative >= 0 && relative < size()) ? at(relative) : nullIndex;
}
void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation,
const glm::quat& rotation, const glm::vec3& scale, bool cursor) {
if (!node->getHeight()) {
@ -2298,12 +2325,23 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
const int EDGES_PER_CUBE = 12;
EdgeCrossing crossings[EDGES_PER_CUBE];
IndexVector indicesX;
IndexVector lastIndicesX;
QVector<IndexVector> indicesZ(stackWidth + 1);
QVector<IndexVector> lastIndicesZ(stackWidth + 1);
for (int z = 0; z <= stackHeight; z++) {
const StackArray* lineSrc = src;
for (int x = 0; x <= stackWidth; x++) {
if (!lineSrc->isEmpty()) {
int y = lineSrc->getPosition();
int position = lineSrc->getPosition();
int count = lineSrc->getEntryCount();
int y = position;
NormalIndex lastIndexY;
indicesX.position = position;
indicesX.resize(count);
indicesZ[x].position = position;
indicesZ[x].resize(count);
for (const StackArray::Entry* entry = lineSrc->getEntryData(), *end = entry + lineSrc->getEntryCount();
entry != end; entry++, y++) {
int clampedX = qMax(x - 1, 0), clampedZ = qMax(z - 1, 0);
@ -2579,29 +2617,118 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
// the first x, y, and z are repeated for the boundary edge; past that, we consider generating
// quads for each edge that includes a transition, using indices of previously generated vertices
if (x != 0 && z != 0) {
int reclampedX = qMin(clampedX, stackWidth - 1);
int reclampedZ = qMin(clampedZ, stackHeight - 1);
if (alpha0 != alpha1) {
quadIndices.insert(qRgb(reclampedX, y, reclampedZ), indices.size());
if (y > 0) {
quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ), indices.size());
}
if (reclampedZ > 0) {
if (y > 0) {
quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ - 1), indices.size());
}
quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size());
}
const NormalIndex& index1 = lastIndexY;
const NormalIndex& index2 = lastIndicesZ[x].get(y - 1);
const NormalIndex& index3 = lastIndicesZ[x].get(y);
const glm::vec3& first = vertices.at(index.indices[0]).vertex;
glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first,
vertices.at(index3.indices[0]).vertex - first);
if (alpha0 == 0) { // quad faces negative x
indices.append(index3.getClosestIndex(normal = -normal, vertices));
indices.append(index2.getClosestIndex(normal, vertices));
indices.append(index1.getClosestIndex(normal, vertices));
} else { // quad faces positive x
indices.append(index1.getClosestIndex(normal, vertices));
indices.append(index2.getClosestIndex(normal, vertices));
indices.append(index3.getClosestIndex(normal, vertices));
}
indices.append(index.getClosestIndex(normal, vertices));
}
if (alpha0 != alpha2) {
quadIndices.insert(qRgb(reclampedX, y, reclampedZ), indices.size());
if (reclampedX > 0) {
quadIndices.insert(qRgb(reclampedX - 1, y, reclampedZ), indices.size());
if (reclampedZ > 0) {
quadIndices.insert(qRgb(reclampedX - 1, y, reclampedZ - 1), indices.size());
}
}
if (reclampedZ > 0) {
quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size());
}
const NormalIndex& index1 = lastIndicesZ[x].get(y);
const NormalIndex& index2 = lastIndicesZ[x - 1].get(y);
const NormalIndex& index3 = lastIndicesX.get(y);
const glm::vec3& first = vertices.at(index.indices[0]).vertex;
glm::vec3 normal = glm::cross(vertices.at(index3.indices[0]).vertex - first,
vertices.at(index1.indices[0]).vertex - first);
if (alpha0 == 0) { // quad faces negative y
indices.append(index1.getClosestIndex(normal = -normal, vertices));
indices.append(index2.getClosestIndex(normal, vertices));
indices.append(index3.getClosestIndex(normal, vertices));
} else { // quad faces positive y
indices.append(index3.getClosestIndex(normal, vertices));
indices.append(index2.getClosestIndex(normal, vertices));
indices.append(index1.getClosestIndex(normal, vertices));
}
indices.append(index.getClosestIndex(normal, vertices));
}
if (alpha0 != alpha4) {
quadIndices.insert(qRgb(reclampedX, y, reclampedZ), indices.size());
if (reclampedX > 0) {
quadIndices.insert(qRgb(reclampedX - 1, y, reclampedZ), indices.size());
if (y > 0) {
quadIndices.insert(qRgb(reclampedX - 1, y - 1, reclampedZ), indices.size());
}
}
if (y > 0) {
quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ), indices.size());
}
const NormalIndex& index1 = lastIndexY;
const NormalIndex& index2 = lastIndicesX.get(y - 1);
const NormalIndex& index3 = lastIndicesX.get(y);
const glm::vec3& first = vertices.at(index.indices[0]).vertex;
glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first,
vertices.at(index3.indices[0]).vertex - first);
if (alpha0 == 0) { // quad faces negative z
indices.append(index3.getClosestIndex(normal = -normal, vertices));
indices.append(index2.getClosestIndex(normal, vertices));
indices.append(index1.getClosestIndex(normal, vertices));
} else { // quad faces positive z
indices.append(index1.getClosestIndex(normal, vertices));
indices.append(index2.getClosestIndex(normal, vertices));
indices.append(index3.getClosestIndex(normal, vertices));
}
indices.append(index.getClosestIndex(normal, vertices));
}
}
lastIndexY = index;
indicesX[y - position] = index;
indicesZ[x][y - position] = index;
}
}
if (x != 0) {
lineSrc++;
}
indicesX.swap(lastIndicesX);
}
if (z != 0) {
src += stackWidth;
}
indicesZ.swap(lastIndicesZ);
}
_voxels = new VoxelBuffer(vertices, indices, hermiteSegments, quadIndices, width, node->getStack()->getMaterials());

View file

@ -2226,7 +2226,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
float startZ = glm::clamp(start.z, 0.0f, (float)highestHeightZ), endZ = glm::clamp(end.z, 0.0f, (float)highestHeightZ);
glm::vec3 worldStart = glm::vec3(transform * glm::vec4(startX, start.y, startZ, 1.0f));
glm::vec3 worldStepX = glm::vec3(transform * glm::vec4(stepX, 0.0f, 0.0f, 0.0f));
glm::vec3 worldStepY = glm::vec3(transform * glm::vec4(0.0f, start.y - end.y, 0.0f, 0.0f));
glm::vec3 worldStepZ = glm::vec3(transform * glm::vec4(0.0f, 0.0f, stepZ, 0.0f));
float voxelStep = scale.x / innerHeightWidth;
float voxelScale = scale.y / (numeric_limits<quint16>::max() * voxelStep);
@ -2237,7 +2236,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
int newBottom = end.y * voxelScale;
QRgb rgba = color.rgba();
bool erase = (color.alpha() == 0);
uchar materialMaterialIndex = getMaterialIndex(material, newMaterialMaterials, newMaterialContents);
QByteArray dummyContents;
uchar stackMaterialIndex = getMaterialIndex(material, newStackMaterials, dummyContents);
bool hasOwnColors = spanner->hasOwnColors();
@ -2248,7 +2246,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
glm::vec3 worldPos = worldStart;
for (float x = startX; x >= endX; x -= stepX, worldPos -= worldStepX) {
quint16* heightLineDest = heightDest + (int)x;
glm::vec3 endPos = worldPos - worldStepY;
float distance;
glm::vec3 normal;
@ -2266,10 +2263,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
float stackX = (x - HeightfieldHeight::HEIGHT_BORDER) * innerStackWidth / innerHeightWidth;
float stackZ = (z - HeightfieldHeight::HEIGHT_BORDER) * innerStackHeight / innerHeightHeight;
int topHeight = -1;
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;
if (stackDest->isEmpty() && *heightLineDest != 0) {
@ -2423,24 +2416,9 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
endPruneCount++;
}
if (endPruneCount == stackDest->getEntryCount()) {
topHeight = 0;
stackDest->clear();
} else {
int topIndex = stackDest->getEntryCount() - 1;
while (topIndex > 0 && !stackDest->getEntryData()[topIndex].isSet()) {
topIndex--;
}
StackArray::Entry* topEntry = stackDest->getEntryData() + topIndex;
if (topEntry->isSet()) {
topHeight = ((stackDest->getPosition() + topIndex) +
qAlpha(topEntry->hermiteY) / (float)numeric_limits<quint8>::max()) / voxelScale;
topColor = topEntry->color;
topMaterial = topEntry->material;
} else {
topHeight = 0;
}
stackDest->removeEntries(stackDest->getEntryCount() - endPruneCount, endPruneCount);
int beginningPruneCount = 0;
for (int i = 0; i < stackDest->getEntryCount() - 1 && stackDest->getEntryData()[i].isMergeable(
@ -2451,66 +2429,6 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
stackDest->getPositionRef() += beginningPruneCount;
}
}
if (topHeight != -1) {
*heightLineDest = topHeight;
if (colorDest) {
colorDest[0] = qRed(topColor);
colorDest[1] = qGreen(topColor);
colorDest[2] = qBlue(topColor);
}
if (materialDest) {
if (topMaterial != 0) {
topMaterial = getMaterialIndex(newStackMaterials.at(topMaterial - 1),
newMaterialMaterials, newMaterialContents);
}
*materialDest = topMaterial;
}
} else if (erase) {
if (spanner->intersects(endPos, worldPos, distance, normal)) {
quint16 height = glm::round(glm::mix(end.y, start.y, distance));
if (height <= *heightLineDest) {
*heightLineDest = height;
}
}
} else if (spanner->intersects(worldPos, endPos, distance, normal)) {
quint16 height = glm::round(glm::mix(start.y, end.y, distance));
if (height >= *heightLineDest) {
*heightLineDest = height;
if (colorDest) {
if (hasOwnColors) {
QRgb spannerColor = spanner->getColorAt(glm::mix(endPos, worldPos, distance));
colorDest[0] = qRed(spannerColor);
colorDest[1] = qGreen(spannerColor);
colorDest[2] = qBlue(spannerColor);
} else {
colorDest[0] = color.red();
colorDest[1] = color.green();
colorDest[2] = color.blue();
}
}
if (materialDest) {
if (hasOwnMaterials) {
int index = spanner->getMaterialAt(glm::mix(endPos, worldPos, distance));
if (index != 0) {
int& mapping = materialMappings[index];
if (mapping == 0) {
mapping = getMaterialIndex(spanner->getMaterials().at(index - 1),
newMaterialMaterials, newMaterialContents);
}
index = mapping;
}
*materialDest = index;
} else {
*materialDest = materialMaterialIndex;
}
}
}
}
}
}
clearUnusedMaterials(newMaterialMaterials, newMaterialContents);