History

Removed heightfield buffer code.

Andrzej Kapolka committed 12 years ago

Commit 479bea11 parent bba042e2 files · +9 −914Browse files

Showing the changes to interface/src/MetavoxelSystem.cpp (1 of 2 files). Show all

Unified · Split

interface/src/MetavoxelSystem.cpp+9−826
@@ -58,11 +58,6 @@ void MetavoxelSystem::init() { · 57 unmodified lines
5858 MetavoxelClientManager::init();
5959 DefaultMetavoxelRendererImplementation::init();
6060
61− _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
62− new BufferDataAttribute("heightfieldBuffer"));
63− _heightfieldBufferAttribute->setLODThresholdMultiplier(
64− AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier());
65−
6661 _voxelBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
6762 new BufferDataAttribute("voxelBuffer"));
6863 _voxelBufferAttribute->setLODThresholdMultiplier(
@@ -375,12 +370,6 @@ void MetavoxelSystem::renderVoxelCursor(const glm::vec3& position, float radius) · 306 unmodified lines
375370 glDepthFunc(GL_LESS);
376371 }
377372
378−void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) {
379− glDeleteTextures(1, (GLuint*)&heightID);
380− glDeleteTextures(1, (GLuint*)&colorID);
381− glDeleteTextures(1, (GLuint*)&textureID);
382−}
383−
384373 class MaterialEditApplier : public SignalHandler {
385374 public:
386375
@@ -670,357 +659,12 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { · 283 unmodified lines
670659 BufferData::~BufferData() {
671660 }
672661
673−const int HeightfieldBuffer::HEIGHT_BORDER = 1;
674−const int HeightfieldBuffer::SHARED_EDGE = 1;
675−const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE;
676−
677−HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,
678− const QByteArray& height, const QByteArray& color, const QByteArray& material,
679− const QVector<SharedObjectPointer>& materials) :
680− _translation(translation),
681− _scale(scale),
682− _heightBounds(translation, translation + glm::vec3(scale, scale, scale)),
683− _colorBounds(_heightBounds),
684− _materialBounds(_heightBounds),
685− _height(height),
686− _color(color),
687− _material(material),
688− _materials(materials),
689− _heightTextureID(0),
690− _colorTextureID(0),
691− _materialTextureID(0),
692− _heightSize(glm::sqrt((float)height.size())),
693− _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)),
694− _colorSize(glm::sqrt((float)color.size() / DataBlock::COLOR_BYTES)),
695− _colorIncrement(scale / (_colorSize - SHARED_EDGE)),
696− _materialSize(glm::sqrt((float)material.size())),
697− _materialIncrement(scale / (_materialSize - SHARED_EDGE)) {
698−
699− _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER;
700− _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER;
701− _heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
702− _heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
703−
704− _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE;
705− _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE;
706−
707− _materialBounds.maximum.x += _materialIncrement * SHARED_EDGE;
708− _materialBounds.maximum.z += _materialIncrement * SHARED_EDGE;
709−}
710−
711−HeightfieldBuffer::~HeightfieldBuffer() {
712− // the textures have to be deleted on the main thread (for its opengl context)
713− if (QThread::currentThread() != Application::getInstance()->thread()) {
714− QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures",
715− Q_ARG(int, _heightTextureID), Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID));
716− } else {
717− glDeleteTextures(1, &_heightTextureID);
718− glDeleteTextures(1, &_colorTextureID);
719− glDeleteTextures(1, &_materialTextureID);
720− }
721−}
722−
723−QByteArray HeightfieldBuffer::getUnextendedHeight() const {
724− int srcSize = glm::sqrt(float(_height.size()));
725− int destSize = srcSize - 3;
726− QByteArray unextended(destSize * destSize, 0);
727− const char* src = _height.constData() + srcSize + 1;
728− char* dest = unextended.data();
729− for (int z = 0; z < destSize; z++, src += srcSize, dest += destSize) {
730− memcpy(dest, src, destSize);
731− }
732− return unextended;
733−}
734−
735−QByteArray HeightfieldBuffer::getUnextendedColor(int x, int y) const {
736− int unextendedSize = _heightSize - HEIGHT_EXTENSION;
737− QByteArray unextended(unextendedSize * unextendedSize * DataBlock::COLOR_BYTES, 0);
738− char* dest = unextended.data();
739− const char* src = _color.constData() + (y * _colorSize + x) * unextendedSize * DataBlock::COLOR_BYTES;
740− for (int z = 0; z < unextendedSize; z++, dest += unextendedSize * DataBlock::COLOR_BYTES,
741− src += _colorSize * DataBlock::COLOR_BYTES) {
742− memcpy(dest, src, unextendedSize * DataBlock::COLOR_BYTES);
743− }
744− return unextended;
745−}
746−
747−class HeightfieldPoint {
748−public:
749− glm::vec2 textureCoord;
750− glm::vec3 vertex;
751−};
752−
753662 const int SPLAT_COUNT = 4;
754663 const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 };
755664
756665 static const int EIGHT_BIT_MAXIMUM = 255;
757666 static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM;
758667
759−void HeightfieldBuffer::render(bool cursor) {
760− // initialize textures, etc. on first render
761− if (_heightTextureID == 0) {
762− glGenTextures(1, &_heightTextureID);
763− glBindTexture(GL_TEXTURE_2D, _heightTextureID);
764− glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
765− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
766− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
767− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
768− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
769− glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0,
770− GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData());
771−
772− glGenTextures(1, &_colorTextureID);
773− glBindTexture(GL_TEXTURE_2D, _colorTextureID);
774− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
775− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
776− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
777− if (_color.isEmpty()) {
778− const quint8 WHITE_COLOR[] = { 255, 255, 255 };
779− glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR);
780−
781− } else {
782− int colorSize = glm::sqrt(float(_color.size() / DataBlock::COLOR_BYTES));
783− glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData());
784− }
785−
786− if (!_material.isEmpty()) {
787− glGenTextures(1, &_materialTextureID);
788− glBindTexture(GL_TEXTURE_2D, _materialTextureID);
789− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
790− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
791− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
792− glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
793− int materialSize = glm::sqrt(float(_material.size()));
794− glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, materialSize, materialSize, 0,
795− GL_LUMINANCE, GL_UNSIGNED_BYTE, _material.constData());
796−
797− _networkTextures.resize(_materials.size());
798− for (int i = 0; i < _materials.size(); i++) {
799− const SharedObjectPointer material = _materials.at(i);
800− if (material) {
801− _networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture(
802− static_cast<MaterialObject*>(material.data())->getDiffuse(), SPLAT_TEXTURE);
803− }
804− }
805− }
806− }
807− // create the buffer objects lazily
808− int innerSize = _heightSize - 2 * HeightfieldBuffer::HEIGHT_BORDER;
809− int vertexCount = _heightSize * _heightSize;
810− int rows = _heightSize - 1;
811− int indexCount = rows * rows * 3 * 2;
812− BufferPair& bufferPair = _bufferPairs[_heightSize];
813− if (!bufferPair.first.isCreated()) {
814− QVector<HeightfieldPoint> vertices(vertexCount);
815− HeightfieldPoint* point = vertices.data();
816−
817− float vertexStep = 1.0f / (innerSize - 1);
818− float z = -vertexStep;
819− float textureStep = 1.0f / _heightSize;
820− float t = textureStep / 2.0f;
821− for (int i = 0; i < _heightSize; i++, z += vertexStep, t += textureStep) {
822− float x = -vertexStep;
823− float s = textureStep / 2.0f;
824− const float SKIRT_LENGTH = 0.25f;
825− float baseY = (i == 0 || i == _heightSize - 1) ? -SKIRT_LENGTH : 0.0f;
826− for (int j = 0; j < _heightSize; j++, point++, x += vertexStep, s += textureStep) {
827− point->vertex = glm::vec3(x, (j == 0 || j == _heightSize - 1) ? -SKIRT_LENGTH : baseY, z);
828− point->textureCoord = glm::vec2(s, t);
829− }
830− }
831−
832− bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw);
833− bufferPair.first.create();
834− bufferPair.first.bind();
835− bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint));
836−
837− QVector<int> indices(indexCount);
838− int* index = indices.data();
839− for (int i = 0; i < rows; i++) {
840− int lineIndex = i * _heightSize;
841− int nextLineIndex = (i + 1) * _heightSize;
842− for (int j = 0; j < rows; j++) {
843− *index++ = lineIndex + j;
844− *index++ = nextLineIndex + j;
845− *index++ = nextLineIndex + j + 1;
846−
847− *index++ = nextLineIndex + j + 1;
848− *index++ = lineIndex + j + 1;
849− *index++ = lineIndex + j;
850− }
851− }
852−
853− bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
854− bufferPair.second.create();
855− bufferPair.second.bind();
856− bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int));
857−
858− } else {
859− bufferPair.first.bind();
860− bufferPair.second.bind();
861− }
862−
863− HeightfieldPoint* point = 0;
864− glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex);
865− glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord);
866−
867− glPushMatrix();
868− glTranslatef(_translation.x, _translation.y, _translation.z);
869− glScalef(_scale, _scale, _scale);
870−
871− glBindTexture(GL_TEXTURE_2D, _heightTextureID);
872−
873− if (cursor) {
874− glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
875−
876− } else if (!_materials.isEmpty()) {
877− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(
878− DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / _heightSize);
879− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(
880− DefaultMetavoxelRendererImplementation::getBaseColorScaleLocation(), (float)_heightSize / innerSize);
881− glActiveTexture(GL_TEXTURE1);
882− glBindTexture(GL_TEXTURE_2D, _colorTextureID);
883−
884− glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
885−
886− Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
887−
888− glDepthFunc(GL_LEQUAL);
889− glDepthMask(false);
890− glEnable(GL_BLEND);
891− glDisable(GL_ALPHA_TEST);
892− glEnable(GL_POLYGON_OFFSET_FILL);
893− glPolygonOffset(-1.0f, -1.0f);
894−
895− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().bind();
896− const DefaultMetavoxelRendererImplementation::SplatLocations& locations =
897− DefaultMetavoxelRendererImplementation::getSplatHeightfieldLocations();
898− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
899− locations.heightScale, 1.0f / _heightSize);
900− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
901− locations.textureScale, (float)_heightSize / innerSize);
902− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
903− locations.splatTextureOffset, _translation.x / _scale, _translation.z / _scale);
904−
905− glBindTexture(GL_TEXTURE_2D, _materialTextureID);
906−
907− for (int i = 0; i < _materials.size(); i += SPLAT_COUNT) {
908− QVector4D scalesS, scalesT;
909−
910− for (int j = 0; j < SPLAT_COUNT; j++) {
911− glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[j]);
912− int index = i + j;
913− if (index < _networkTextures.size()) {
914− const NetworkTexturePointer& texture = _networkTextures.at(index);
915− if (texture) {
916− MaterialObject* material = static_cast<MaterialObject*>(_materials.at(index).data());
917− scalesS[j] = _scale / material->getScaleS();
918− scalesT[j] = _scale / material->getScaleT();
919− glBindTexture(GL_TEXTURE_2D, texture->getID());
920− } else {
921− glBindTexture(GL_TEXTURE_2D, 0);
922− }
923− } else {
924− glBindTexture(GL_TEXTURE_2D, 0);
925− }
926− }
927− const float QUARTER_STEP = 0.25f * EIGHT_BIT_MAXIMUM_RECIPROCAL;
928− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
929− locations.splatTextureScalesS, scalesS);
930− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
931− locations.splatTextureScalesT, scalesT);
932− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
933− locations.textureValueMinima,
934− (i + 1) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP, (i + 2) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP,
935− (i + 3) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP, (i + 4) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP);
936− DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(
937− locations.textureValueMaxima,
938− (i + 1) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP, (i + 2) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP,
939− (i + 3) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP, (i + 4) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP);
940− glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
941− }
942−
943− for (int i = 0; i < SPLAT_COUNT; i++) {
944− glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[i]);
945− glBindTexture(GL_TEXTURE_2D, 0);
946− }
947−
948− glActiveTexture(GL_TEXTURE1);
949− glBindTexture(GL_TEXTURE_2D, 0);
950−
951− glActiveTexture(GL_TEXTURE0);
952−
953− glDisable(GL_POLYGON_OFFSET_FILL);
954− glEnable(GL_ALPHA_TEST);
955− glDisable(GL_BLEND);
956− glDepthMask(true);
957− glDepthFunc(GL_LESS);
958−
959− Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
960−
961− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();
962−
963− } else {
964− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(
965− DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / _heightSize);
966− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(
967− DefaultMetavoxelRendererImplementation::getBaseColorScaleLocation(), (float)_heightSize / innerSize);
968− glActiveTexture(GL_TEXTURE1);
969− glBindTexture(GL_TEXTURE_2D, _colorTextureID);
970−
971− glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
972−
973− glBindTexture(GL_TEXTURE_2D, 0);
974− glActiveTexture(GL_TEXTURE0);
975− }
976−
977− glBindTexture(GL_TEXTURE_2D, 0);
978−
979− glPopMatrix();
980−
981− bufferPair.first.release();
982− bufferPair.second.release();
983−}
984−
985−QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs;
986−
987−void HeightfieldPreview::render(const glm::vec3& translation, float scale) const {
988− Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
989−
990− glDisable(GL_BLEND);
991− glEnable(GL_CULL_FACE);
992− glEnable(GL_ALPHA_TEST);
993− glAlphaFunc(GL_EQUAL, 0.0f);
994−
995− glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
996−
997− glEnableClientState(GL_VERTEX_ARRAY);
998− glEnableClientState(GL_TEXTURE_COORD_ARRAY);
999−
1000− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();
1001−
1002− glPushMatrix();
1003− glTranslatef(translation.x, translation.y, translation.z);
1004− glScalef(scale, scale, scale);
1005−
1006− foreach (const BufferDataPointer& buffer, _buffers) {
1007− buffer->render();
1008− }
1009−
1010− glPopMatrix();
1011−
1012− DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().release();
1013−
1014− glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1015− glDisableClientState(GL_VERTEX_ARRAY);
1016−
1017− glDisable(GL_ALPHA_TEST);
1018− glDisable(GL_CULL_FACE);
1019− glEnable(GL_BLEND);
1020−
1021− Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
1022−}
1023−
1024668 void VoxelPoint::setNormal(const glm::vec3& normal) {
1025669 this->normal[0] = (char)(normal.x * 127.0f);
1026670 this->normal[1] = (char)(normal.y * 127.0f);
@@ -1344,446 +988,6 @@ void DefaultMetavoxelRendererImplementation::init() { · 317 unmodified lines
1344988 DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() {
1345989 }
1346990
1347−class HeightfieldFetchVisitor : public MetavoxelVisitor {
1348−public:
1349−
1350− HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections);
1351−
1352− void init(HeightfieldBuffer* buffer);
1353−
1354− virtual int visit(MetavoxelInfo& info);
1355− virtual bool postVisit(MetavoxelInfo& info);
1356−
1357−private:
1358−
1359− const QVector<Box>& _intersections;
1360− HeightfieldBuffer* _buffer;
1361−
1362− QVector<int> _depthFlags;
1363−};
1364−
1365−enum DepthFlags { HEIGHT_FLAG = 0x01, COLOR_FLAG = 0x02, MATERIAL_FLAG = 0x04 };
1366−
1367−HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections) :
1368− MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
1369− AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
1370− AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), QVector<AttributePointer>(), lod),
1371− _intersections(intersections) {
1372−}
1373−
1374−void HeightfieldFetchVisitor::init(HeightfieldBuffer* buffer) {
1375− _buffer = buffer;
1376−}
1377−
1378−int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
1379− if (!info.getBounds().intersects(_buffer->getHeightBounds())) {
1380− return STOP_RECURSION;
1381− }
1382− if (_depthFlags.size() > _depth) {
1383− _depthFlags[_depth] = 0;
1384− } else {
1385− _depthFlags.append(0);
1386− }
1387− if (!info.isLeaf) {
1388− return DEFAULT_ORDER;
1389− }
1390− postVisit(info);
1391− return STOP_RECURSION;
1392−}
1393−
1394−bool HeightfieldFetchVisitor::postVisit(MetavoxelInfo& info) {
1395− HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
1396− int flags = _depthFlags.at(_depth);
1397− if (height) {
1398− // to handle borders correctly, make sure we only sample nodes with resolution <= ours
1399− int heightSize = glm::sqrt((float)height->getContents().size());
1400− float heightIncrement = info.size / heightSize;
1401− if (heightIncrement < _buffer->getHeightIncrement() || (flags & HEIGHT_FLAG)) {
1402− height.reset();
1403− } else {
1404− flags |= HEIGHT_FLAG;
1405− }
1406− }
1407− HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>();
1408− if (color) {
1409− int colorSize = glm::sqrt((float)color->getContents().size() / DataBlock::COLOR_BYTES);
1410− float colorIncrement = info.size / colorSize;
1411− if (colorIncrement < _buffer->getColorIncrement() || (flags & COLOR_FLAG)) {
1412− color.reset();
1413− } else {
1414− flags |= COLOR_FLAG;
1415− }
1416− }
1417− HeightfieldMaterialDataPointer material = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>();
1418− if (material) {
1419− int materialSize = glm::sqrt((float)material->getContents().size());
1420− float materialIncrement = info.size / materialSize;
1421− if (materialIncrement < _buffer->getMaterialIncrement() || (flags & MATERIAL_FLAG)) {
1422− material.reset();
1423− } else {
1424− flags |= MATERIAL_FLAG;
1425− }
1426− }
1427− if (_depth > 0) {
1428− _depthFlags[_depth - 1] |= flags;
1429− }
1430− if (!(height || color || material)) {
1431− return false;
1432− }
1433− Box bounds = info.getBounds();
1434− foreach (const Box& intersection, _intersections) {
1435− Box overlap = intersection.getIntersection(bounds);
1436− if (overlap.isEmpty()) {
1437− continue;
1438− }
1439− if (height) {
1440− float heightIncrement = _buffer->getHeightIncrement();
1441− const Box& heightBounds = _buffer->getHeightBounds();
1442− int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement;
1443− int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement;
1444− int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement);
1445− int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement);
1446− int heightSize = _buffer->getHeightSize();
1447− char* dest = _buffer->getHeight().data() + destY * heightSize + destX;
1448−
1449− const QByteArray& srcHeight = height->getContents();
1450− int srcSize = glm::sqrt((float)srcHeight.size());
1451− float srcIncrement = info.size / srcSize;
1452−
1453− if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) {
1454− // easy case: same resolution
1455− int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1456− int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1457−
1458− const char* src = srcHeight.constData() + srcY * srcSize + srcX;
1459− for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) {
1460− memcpy(dest, src, destWidth);
1461− }
1462− } else {
1463− // more difficult: different resolutions
1464− float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1465− float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1466− float srcAdvance = heightIncrement / srcIncrement;
1467− int shift = 0;
1468− float size = _buffer->getScale();
1469− while (size < info.size) {
1470− shift++;
1471− size *= 2.0f;
1472− }
1473− int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale();
1474− for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) {
1475− const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize;
1476− float lineSrcX = srcX;
1477− for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) {
1478− *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM);
1479− }
1480− }
1481− }
1482− }
1483− if (color) {
1484− const Box& colorBounds = _buffer->getColorBounds();
1485− overlap = colorBounds.getIntersection(overlap);
1486− float colorIncrement = _buffer->getColorIncrement();
1487− int destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement;
1488− int destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement;
1489− int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement);
1490− int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement);
1491− int colorSize = _buffer->getColorSize();
1492− char* dest = _buffer->getColor().data() + (destY * colorSize + destX) * DataBlock::COLOR_BYTES;
1493− int destStride = colorSize * DataBlock::COLOR_BYTES;
1494− int destBytes = destWidth * DataBlock::COLOR_BYTES;
1495−
1496− const QByteArray& srcColor = color->getContents();
1497− int srcSize = glm::sqrt(float(srcColor.size() / DataBlock::COLOR_BYTES));
1498− int srcStride = srcSize * DataBlock::COLOR_BYTES;
1499− float srcIncrement = info.size / srcSize;
1500−
1501− if (srcIncrement == colorIncrement) {
1502− // easy case: same resolution
1503− int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1504− int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1505−
1506− const char* src = srcColor.constData() + (srcY * srcSize + srcX) * DataBlock::COLOR_BYTES;
1507− for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) {
1508− memcpy(dest, src, destBytes);
1509− }
1510− } else {
1511− // more difficult: different resolutions
1512− float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1513− float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1514− float srcAdvance = colorIncrement / srcIncrement;
1515− for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) {
1516− const char* src = srcColor.constData() + (int)srcY * srcStride;
1517− float lineSrcX = srcX;
1518− for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += DataBlock::COLOR_BYTES,
1519− lineSrcX += srcAdvance) {
1520− const char* lineSrc = src + (int)lineSrcX * DataBlock::COLOR_BYTES;
1521− lineDest[0] = lineSrc[0];
1522− lineDest[1] = lineSrc[1];
1523− lineDest[2] = lineSrc[2];
1524− }
1525− }
1526− }
1527− }
1528− if (material) {
1529− const Box& materialBounds = _buffer->getMaterialBounds();
1530− overlap = materialBounds.getIntersection(overlap);
1531− float materialIncrement = _buffer->getMaterialIncrement();
1532− int destX = (overlap.minimum.x - materialBounds.minimum.x) / materialIncrement;
1533− int destY = (overlap.minimum.z - materialBounds.minimum.z) / materialIncrement;
1534− int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / materialIncrement);
1535− int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / materialIncrement);
1536− int materialSize = _buffer->getMaterialSize();
1537− char* dest = _buffer->getMaterial().data() + destY * materialSize + destX;
1538−
1539− const QByteArray& srcMaterial = material->getContents();
1540− const QVector<SharedObjectPointer> srcMaterials = material->getMaterials();
1541− int srcSize = glm::sqrt((float)srcMaterial.size());
1542− float srcIncrement = info.size / srcSize;
1543− QHash<int, int> materialMappings;
1544−
1545− if (srcIncrement == materialIncrement) {
1546− // easy case: same resolution
1547− int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1548− int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1549−
1550− const uchar* src = (const uchar*)srcMaterial.constData() + srcY * srcSize + srcX;
1551− for (int y = 0; y < destHeight; y++, src += srcSize, dest += materialSize) {
1552− const uchar* lineSrc = src;
1553− for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrc++) {
1554− int value = *lineSrc;
1555− if (value != 0) {
1556− int& mapping = materialMappings[value];
1557− if (mapping == 0) {
1558− mapping = getMaterialIndex(material->getMaterials().at(value - 1),
1559− _buffer->getMaterials(), _buffer->getMaterial());
1560− }
1561− value = mapping;
1562− }
1563− *lineDest = value;
1564− }
1565− }
1566− } else {
1567− // more difficult: different resolutions
1568− float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
1569− float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
1570− float srcAdvance = materialIncrement / srcIncrement;
1571− for (int y = 0; y < destHeight; y++, dest += materialSize, srcY += srcAdvance) {
1572− const uchar* src = (const uchar*)srcMaterial.constData() + (int)srcY * srcSize;
1573− float lineSrcX = srcX;
1574− for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) {
1575− int value = src[(int)lineSrcX];
1576− if (value != 0) {
1577− int& mapping = materialMappings[value];
1578− if (mapping == 0) {
1579− mapping = getMaterialIndex(material->getMaterials().at(value - 1),
1580− _buffer->getMaterials(), _buffer->getMaterial());
1581− }
1582− value = mapping;
1583− }
1584− *lineDest = value;
1585− }
1586− }
1587− }
1588− clearUnusedMaterials(_buffer->getMaterials(), _buffer->getMaterial());
1589− }
1590− }
1591− return false;
1592−}
1593−
1594−class HeightfieldRegionVisitor : public MetavoxelVisitor {
1595−public:
1596−
1597− QVector<Box> regions;
1598− Box regionBounds;
1599−
1600− HeightfieldRegionVisitor(const MetavoxelLOD& lod);
1601−
1602− virtual int visit(MetavoxelInfo& info);
1603− virtual bool postVisit(MetavoxelInfo& info);
1604−
1605−private:
1606−
1607− void addRegion(const Box& unextended, const Box& extended);
1608−
1609− class DepthInfo {
1610− public:
1611− float minimumColorIncrement;
1612− float minimumMaterialIncrement;
1613−
1614− DepthInfo() : minimumColorIncrement(FLT_MAX), minimumMaterialIncrement(FLT_MAX) { }
1615− };
1616−
1617− QVector<DepthInfo> _depthInfo;
1618−
1619− QVector<Box> _intersections;
1620− HeightfieldFetchVisitor _fetchVisitor;
1621−};
1622−
1623−HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) :
1624− MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
1625− AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
1626− AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute() <<
1627− Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
1628− Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
1629− regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)),
1630− _fetchVisitor(lod, _intersections) {
1631−}
1632−
1633−int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) {
1634− DepthInfo depthInfo;
1635− HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>();
1636− if (color) {
1637− int colorSize = glm::sqrt((float)color->getContents().size() / DataBlock::COLOR_BYTES);
1638− depthInfo.minimumColorIncrement = info.size / colorSize;
1639− }
1640− HeightfieldMaterialDataPointer material = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>();
1641− if (material) {
1642− int materialSize = glm::sqrt((float)material->getContents().size());
1643− depthInfo.minimumMaterialIncrement = info.size / materialSize;
1644− }
1645− if (_depth < _depthInfo.size()) {
1646− _depthInfo[_depth] = depthInfo;
1647− } else {
1648− _depthInfo.append(depthInfo);
1649− }
1650− if (!info.isLeaf) {
1651− return _visitations.at(_depth).isInputLeaf(0) ? (DEFAULT_ORDER | ALL_NODES_REST) : DEFAULT_ORDER;
1652− }
1653− postVisit(info);
1654− return STOP_RECURSION;
1655−}
1656−
1657−bool HeightfieldRegionVisitor::postVisit(MetavoxelInfo& info) {
1658− const DepthInfo& depthInfo = _depthInfo.at(_depth);
1659− if (_depth > 0) {
1660− DepthInfo& parentDepthInfo = _depthInfo[_depth - 1];
1661− parentDepthInfo.minimumColorIncrement = qMin(parentDepthInfo.minimumColorIncrement, depthInfo.minimumColorIncrement);
1662− parentDepthInfo.minimumMaterialIncrement = qMin(parentDepthInfo.minimumMaterialIncrement,
1663− depthInfo.minimumMaterialIncrement);
1664− }
1665− if (_visitations.at(_depth).isInputLeaf(0)) {
1666− HeightfieldBuffer* buffer = NULL;
1667− HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
1668− if (height) {
1669− int heightSize = glm::sqrt((float)height->getContents().size());
1670− int extendedHeightSize = heightSize + HeightfieldBuffer::HEIGHT_EXTENSION;
1671− int heightContentsSize = extendedHeightSize * extendedHeightSize;
1672− float minimumColorIncrement = depthInfo.minimumColorIncrement;
1673− float minimumMaterialIncrement = depthInfo.minimumMaterialIncrement;
1674− for (int i = _depth - 1; i >= 0 && qMax(minimumColorIncrement, minimumMaterialIncrement) == FLT_MAX; i--) {
1675− const DepthInfo& ancestorDepthInfo = _depthInfo.at(i);
1676− minimumColorIncrement = qMin(minimumColorIncrement, ancestorDepthInfo.minimumColorIncrement);
1677− minimumMaterialIncrement = qMin(minimumMaterialIncrement, ancestorDepthInfo.minimumMaterialIncrement);
1678− }
1679− int colorContentsSize = 0;
1680− if (minimumColorIncrement != FLT_MAX) {
1681− int colorSize = (int)glm::round(info.size / minimumColorIncrement) + HeightfieldBuffer::SHARED_EDGE;
1682− colorContentsSize = colorSize * colorSize * DataBlock::COLOR_BYTES;
1683− }
1684− int materialContentsSize = 0;
1685− if (minimumMaterialIncrement != FLT_MAX) {
1686− int materialSize = (int)glm::round(info.size / minimumMaterialIncrement) + HeightfieldBuffer::SHARED_EDGE;
1687− materialContentsSize = materialSize * materialSize;
1688− }
1689− const HeightfieldBuffer* existingBuffer = static_cast<const HeightfieldBuffer*>(
1690− info.inputValues.at(3).getInlineValue<BufferDataPointer>().data());
1691− Box bounds = info.getBounds();
1692− if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize &&
1693− existingBuffer->getColor().size() == colorContentsSize &&
1694− existingBuffer->getMaterial().size() == materialContentsSize) {
1695− // we already have a buffer of the correct resolution
1696− addRegion(bounds, existingBuffer->getHeightBounds());
1697− buffer = new HeightfieldBuffer(info.minimum, info.size, existingBuffer->getHeight(),
1698− existingBuffer->getColor(), existingBuffer->getMaterial(), existingBuffer->getMaterials());
1699−
1700− } else {
1701− // we must create a new buffer and update its borders
1702− buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0),
1703− QByteArray(colorContentsSize, 0), QByteArray(materialContentsSize, 0));
1704− const Box& heightBounds = buffer->getHeightBounds();
1705− addRegion(bounds, heightBounds);
1706−
1707− _intersections.clear();
1708− _intersections.append(Box(heightBounds.minimum,
1709− glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z)));
1710− _intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z),
1711− glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z)));
1712− _intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z),
1713− heightBounds.maximum));
1714− _intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z),
1715− glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z)));
1716−
1717− _fetchVisitor.init(buffer);
1718− _data->guide(_fetchVisitor);
1719− }
1720− }
1721− BufferDataPointer pointer(buffer);
1722− info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
1723− }
1724− return true;
1725−}
1726−
1727−void HeightfieldRegionVisitor::addRegion(const Box& unextended, const Box& extended) {
1728− regions.append(unextended);
1729− regionBounds.add(extended);
1730−}
1731−
1732−class HeightfieldUpdateVisitor : public MetavoxelVisitor {
1733−public:
1734−
1735− HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions, const Box& regionBounds);
1736−
1737− virtual int visit(MetavoxelInfo& info);
1738−
1739−private:
1740−
1741− const QVector<Box>& _regions;
1742− const Box& _regionBounds;
1743− QVector<Box> _intersections;
1744− HeightfieldFetchVisitor _fetchVisitor;
1745−};
1746−
1747−HeightfieldUpdateVisitor::HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions,
1748− const Box& regionBounds) :
1749− MetavoxelVisitor(QVector<AttributePointer>() <<
1750− Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
1751− Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
1752− _regions(regions),
1753− _regionBounds(regionBounds),
1754− _fetchVisitor(lod, _intersections) {
1755−}
1756−
1757−int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) {
1758− if (!info.getBounds().intersects(_regionBounds)) {
1759− return STOP_RECURSION;
1760− }
1761− if (!info.isLeaf) {
1762− return DEFAULT_ORDER;
1763− }
1764− const HeightfieldBuffer* buffer = static_cast<const HeightfieldBuffer*>(
1765− info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
1766− if (!buffer) {
1767− return STOP_RECURSION;
1768− }
1769− _intersections.clear();
1770− foreach (const Box& region, _regions) {
1771− if (region.intersects(buffer->getHeightBounds())) {
1772− _intersections.append(region.getIntersection(buffer->getHeightBounds()));
1773− }
1774− }
1775− if (_intersections.isEmpty()) {
1776− return STOP_RECURSION;
1777− }
1778− HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size,
1779− buffer->getHeight(), buffer->getColor(), buffer->getMaterial(), buffer->getMaterials());
1780− _fetchVisitor.init(newBuffer);
1781− _data->guide(_fetchVisitor);
1782− BufferDataPointer pointer(newBuffer);
1783− info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
1784− return STOP_RECURSION;
1785−}
1786−
1787991 class VoxelAugmentVisitor : public MetavoxelVisitor {
1788992 public:
1789993
@@ -2392,27 +1596,13 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const · 602 unmodified lines
23921596 while (expandedPrevious.getSize() < data.getSize()) {
23931597 expandedPrevious.expand();
23941598 }
2395− const AttributePointer& heightfieldBufferAttribute =
2396− Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute();
2397− MetavoxelNode* root = expandedPrevious.getRoot(heightfieldBufferAttribute);
2398− if (root) {
2399− data.setRoot(heightfieldBufferAttribute, root);
2400− root->incrementReferenceCount();
2401− }
24021599 const AttributePointer& voxelBufferAttribute =
24031600 Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute();
2404− root = expandedPrevious.getRoot(voxelBufferAttribute);
1601+ MetavoxelNode* root = expandedPrevious.getRoot(voxelBufferAttribute);
24051602 if (root) {
24061603 data.setRoot(voxelBufferAttribute, root);
24071604 root->incrementReferenceCount();
24081605 }
2409− HeightfieldRegionVisitor heightfieldRegionVisitor(lod);
2410− data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor);
2411−
2412− HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions,
2413− heightfieldRegionVisitor.regionBounds);
2414− data.guide(heightfieldUpdateVisitor);
2415−
24161606 VoxelAugmentVisitor voxelAugmentVisitor(lod);
24171607 data.guideToDifferent(expandedPrevious, voxelAugmentVisitor);
24181608 }
@@ -2535,19 +1725,6 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox · 116 unmodified lines
25351725
25361726 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
25371727
2538− if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) {
2539− _baseHeightfieldProgram.bind();
2540−
2541− glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2542−
2543− BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute());
2544− data.guide(heightfieldRenderVisitor);
2545−
2546− glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2547−
2548− _baseHeightfieldProgram.release();
2549− }
2550−
25511728 if (Menu::getInstance()->isOptionChecked(MenuOption::RenderDualContourSurfaces)) {
25521729 glEnableClientState(GL_COLOR_ARRAY);
25531730 glEnableClientState(GL_NORMAL_ARRAY);
@@ -2756,6 +1933,12 @@ void HeightfieldRenderer::init(Spanner* spanner) { · 202 unmodified lines
27561933 connect(heightfield, &Heightfield::materialChanged, this, &HeightfieldRenderer::applyMaterial);
27571934 }
27581935
1936+class HeightfieldPoint {
1937+public:
1938+ glm::vec3 vertex;
1939+ glm::vec2 textureCoord;
1940+};
1941+
27591942 void HeightfieldRenderer::render(bool cursor) {
27601943 // create the buffer objects lazily
27611944 Heightfield* heightfield = static_cast<Heightfield*>(_spanner);
@@ -2765,8 +1948,8 @@ void HeightfieldRenderer::render(bool cursor) { · 3 unmodified lines
27651948 int width = heightfield->getHeight()->getWidth();
27661949 int height = heightfield->getHeight()->getContents().size() / width;
27671950
2768− int innerWidth = width - 2 * HeightfieldBuffer::HEIGHT_BORDER;
2769− int innerHeight = height - 2 * HeightfieldBuffer::HEIGHT_BORDER;
1951+ int innerWidth = width - 2 * HeightfieldHeight::HEIGHT_BORDER;
1952+ int innerHeight = height - 2 * HeightfieldHeight::HEIGHT_BORDER;
27701953 int vertexCount = width * height;
27711954 int rows = height - 1;
27721955 int columns = width - 1;