glTranslatef(translation.x, translation.y, translation.z); glm::quat rotation = sphere->getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(sphere->getScale(), 32, 32); glPopMatrix();} CuboidRenderer::CuboidRenderer() {} void CuboidRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { Cuboid* cuboid = static_cast<Cuboid*>(_spanner); const QColor& color = cuboid->getColor(); glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glPushMatrix(); const glm::vec3& translation = cuboid->getTranslation(); glTranslatef(translation.x, translation.y, translation.z); glm::quat rotation = cuboid->getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glScalef(1.0f, cuboid->getAspectY(), cuboid->getAspectZ()); Application::getInstance()->getDeferredLightingEffect()->renderSolidCube(cuboid->getScale() * 2.0f); glPopMatrix();} StaticModelRenderer::StaticModelRenderer() : _model(new Model(this)) {} void StaticModelRenderer::init(Spanner* spanner) { SpannerRenderer::init(spanner); _model->init(); StaticModel* staticModel = static_cast<StaticModel*>(spanner); applyTranslation(staticModel->getTranslation()); applyRotation(staticModel->getRotation()); applyScale(staticModel->getScale()); applyURL(staticModel->getURL()); connect(spanner, SIGNAL(translationChanged(const glm::vec3&)), SLOT(applyTranslation(const glm::vec3&))); connect(spanner, SIGNAL(rotationChanged(const glm::quat&)), SLOT(applyRotation(const glm::quat&))); connect(spanner, SIGNAL(scaleChanged(float)), SLOT(applyScale(float))); connect(spanner, SIGNAL(urlChanged(const QUrl&)), SLOT(applyURL(const QUrl&)));} void StaticModelRenderer::simulate(float deltaTime) { // update the bounds Box bounds; if (_model->isActive()) { const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents; bounds = Box(extents.minimum, extents.maximum); } static_cast<StaticModel*>(_spanner)->setBounds(glm::translate(_model->getTranslation()) * glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds); _model->simulate(deltaTime);} void StaticModelRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { _model->render();} bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { RayIntersectionInfo info; info._rayStart = origin; info._rayDirection = direction; if (!_model->findRayIntersection(info)) { return false; } distance = info._hitDistance; return true;} void StaticModelRenderer::applyTranslation(const glm::vec3& translation) { _model->setTranslation(translation);} void StaticModelRenderer::applyRotation(const glm::quat& rotation) { _model->setRotation(rotation);} void StaticModelRenderer::applyScale(float scale) { _model->setScale(glm::vec3(scale, scale, scale));} void StaticModelRenderer::applyURL(const QUrl& url) { _model->setURL(url);} HeightfieldRenderer::HeightfieldRenderer() {} const int X_MAXIMUM_FLAG = 1;const int Y_MAXIMUM_FLAG = 2; static void renderNode(const HeightfieldNodePointer& node, Heightfield* heightfield, const MetavoxelLOD& lod, const glm::vec2& minimum, float size, bool contained, bool cursor) { const glm::quat& rotation = heightfield->getRotation(); glm::vec3 scale(heightfield->getScale() * size, heightfield->getScale() * heightfield->getAspectY(), heightfield->getScale() * heightfield->getAspectZ() * size); glm::vec3 translation = heightfield->getTranslation() + rotation * glm::vec3(minimum.x * heightfield->getScale(), 0.0f, minimum.y * heightfield->getScale() * heightfield->getAspectZ()); if (!contained) { Frustum::IntersectionType type = Application::getInstance()->getMetavoxels()->getFrustum().getIntersectionType( glm::translate(translation) * glm::mat4_cast(rotation) * Box(glm::vec3(), scale)); if (type == Frustum::NO_INTERSECTION) { return; } if (type == Frustum::CONTAINS_INTERSECTION) { contained = true; } } if (!node->isLeaf() && lod.shouldSubdivide(minimum, size)) { float nextSize = size * 0.5f; for (int i = 0; i < HeightfieldNode::CHILD_COUNT; i++) { renderNode(node->getChild(i), heightfield, lod, minimum + glm::vec2(i & X_MAXIMUM_FLAG ? nextSize : 0.0f, i & Y_MAXIMUM_FLAG ? nextSize : 0.0f), nextSize, contained, cursor); } return; } HeightfieldNodeRenderer* renderer = static_cast<HeightfieldNodeRenderer*>(node->getRenderer()); if (!renderer) { node->setRenderer(renderer = new HeightfieldNodeRenderer()); } renderer->render(node, translation, rotation, scale, cursor);} void HeightfieldRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { Heightfield* heightfield = static_cast<Heightfield*>(_spanner); renderNode(heightfield->getRoot(), heightfield, heightfield->transformLOD(lod), glm::vec2(), 1.0f, contained, cursor);} HeightfieldNodeRenderer::HeightfieldNodeRenderer() : _heightTextureID(0), _colorTextureID(0), _materialTextureID(0) {} HeightfieldNodeRenderer::~HeightfieldNodeRenderer() { QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", Q_ARG(int, _heightTextureID), Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID));} void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { return; } int width = node->getHeight()->getWidth(); int height = node->getHeight()->getContents().size() / width; int innerWidth = width - 2 * HeightfieldHeight::HEIGHT_BORDER; int innerHeight = height - 2 * HeightfieldHeight::HEIGHT_BORDER; int vertexCount = width * height; int rows = height - 1; int columns = width - 1; int indexCount = rows * columns * 3 * 2; BufferPair& bufferPair = _bufferPairs[IntPair(width, height)]; if (!bufferPair.first.isCreated()) { QVector<HeightfieldPoint> vertices(vertexCount); HeightfieldPoint* point = vertices.data(); float xStep = 1.0f / (innerWidth - 1); float zStep = 1.0f / (innerHeight - 1); float z = -zStep; float sStep = 1.0f / width; float tStep = 1.0f / height; float t = tStep / 2.0f; for (int i = 0; i < height; i++, z += zStep, t += tStep) { float x = -xStep; float s = sStep / 2.0f; const float SKIRT_LENGTH = 0.25f; float baseY = (i == 0 || i == height - 1) ? -SKIRT_LENGTH : 0.0f; for (int j = 0; j < width; j++, point++, x += xStep, s += sStep) { point->vertex = glm::vec3(x, (j == 0 || j == width - 1) ? -SKIRT_LENGTH : baseY, z); point->textureCoord = glm::vec2(s, t); } } bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw); bufferPair.first.create(); bufferPair.first.bind(); bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint)); bufferPair.first.release(); QVector<int> indices(indexCount); int* index = indices.data(); for (int i = 0; i < rows; i++) { int lineIndex = i * width; int nextLineIndex = (i + 1) * width; for (int j = 0; j < columns; j++) { *index++ = lineIndex + j; *index++ = nextLineIndex + j; *index++ = nextLineIndex + j + 1; *index++ = nextLineIndex + j + 1; *index++ = lineIndex + j + 1; *index++ = lineIndex + j; } } bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); bufferPair.second.create(); bufferPair.second.bind(); bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int)); bufferPair.second.release(); } if (_heightTextureID == 0) { glGenTextures(1, &_heightTextureID); glBindTexture(GL_TEXTURE_2D, _heightTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); const QVector<quint16>& heightContents = node->getHeight()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, width, height, 0, GL_RED, GL_UNSIGNED_SHORT, heightContents.constData()); glGenTextures(1, &_colorTextureID); glBindTexture(GL_TEXTURE_2D, _colorTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (node->getColor()) { const QByteArray& contents = node->getColor()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, node->getColor()->getWidth(), contents.size() / (node->getColor()->getWidth() * DataBlock::COLOR_BYTES), 0, GL_RGB, GL_UNSIGNED_BYTE, contents.constData()); } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); } glGenTextures(1, &_materialTextureID); glBindTexture(GL_TEXTURE_2D, _materialTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (node->getMaterial()) { const QByteArray& contents = node->getMaterial()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, node->getMaterial()->getWidth(), contents.size() / node->getMaterial()->getWidth(), 0, GL_RED, GL_UNSIGNED_BYTE, contents.constData()); const QVector<SharedObjectPointer>& materials = node->getMaterial()->getMaterials(); _networkTextures.resize(materials.size()); for (int i = 0; i < materials.size(); i++) { const SharedObjectPointer& material = materials.at(i); if (material) { _networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture( static_cast<MaterialObject*>(material.data())->getDiffuse(), SPLAT_TEXTURE); } } } else { const quint8 ZERO_VALUE = 0; glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &ZERO_VALUE); } glBindTexture(GL_TEXTURE_2D, 0); } if (cursor) { bufferPair.first.bind(); bufferPair.second.bind(); glPushMatrix(); glTranslatef(translation.x, translation.y, translation.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glScalef(scale.x, scale.y, scale.z); HeightfieldPoint* point = 0; glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex); glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord); glBindTexture(GL_TEXTURE_2D, _heightTextureID); glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, 0); glPopMatrix(); bufferPair.first.release(); bufferPair.second.release(); return; } HeightfieldBaseLayerBatch baseBatch; baseBatch.vertexBuffer = &bufferPair.first; baseBatch.indexBuffer = &bufferPair.second; baseBatch.translation = translation; baseBatch.rotation = rotation; baseBatch.scale = scale; baseBatch.vertexCount = vertexCount; baseBatch.indexCount = indexCount; baseBatch.heightTextureID = _heightTextureID; baseBatch.heightScale = glm::vec4(1.0f / width, 1.0f / height, (innerWidth - 1) / -2.0f, (innerHeight - 1) / -2.0f); baseBatch.colorTextureID = _colorTextureID; baseBatch.colorScale = glm::vec2((float)width / innerWidth, (float)height / innerHeight); Application::getInstance()->getMetavoxels()->addHeightfieldBaseBatch(baseBatch); if (!_networkTextures.isEmpty()) { HeightfieldSplatBatch splatBatch; splatBatch.vertexBuffer = &bufferPair.first; splatBatch.indexBuffer = &bufferPair.second; splatBatch.translation = translation; splatBatch.rotation = rotation; splatBatch.scale = scale; splatBatch.vertexCount = vertexCount; splatBatch.indexCount = indexCount; splatBatch.heightTextureID = _heightTextureID; splatBatch.heightScale = glm::vec4(1.0f / width, 1.0f / height, 0.0f, 0.0f); splatBatch.materialTextureID = _materialTextureID; splatBatch.textureScale = glm::vec2((float)width / innerWidth, (float)height / innerHeight); splatBatch.splatTextureOffset = glm::vec2( glm::dot(translation, rotation * glm::vec3(1.0f, 0.0f, 0.0f)) / scale.x, glm::dot(translation, rotation * glm::vec3(0.0f, 0.0f, 1.0f)) / scale.z); const QVector<SharedObjectPointer>& materials = node->getMaterial()->getMaterials(); for (int i = 0; i < materials.size(); i += SPLAT_COUNT) { for (int j = 0; j < SPLAT_COUNT; j++) { int index = i + j; if (index < _networkTextures.size()) { const NetworkTexturePointer& texture = _networkTextures.at(index); if (texture) { MaterialObject* material = static_cast<MaterialObject*>(materials.at(index).data()); splatBatch.splatTextureScalesS[j] = scale.x / material->getScaleS(); splatBatch.splatTextureScalesT[j] = scale.z / material->getScaleT(); splatBatch.splatTextureIDs[j] = texture->getID(); } else { splatBatch.splatTextureIDs[j] = 0; } } else { splatBatch.splatTextureIDs[j] = 0; } } splatBatch.materialIndex = i; Application::getInstance()->getMetavoxels()->addHeightfieldSplatBatch(splatBatch); } }} QHash<HeightfieldNodeRenderer::IntPair, HeightfieldNodeRenderer::BufferPair> HeightfieldNodeRenderer::_bufferPairs; Lines 2001–2352 of 2352. Previous lines
glTranslatef(translation.x, translation.y, translation.z); glm::quat rotation = sphere->getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(sphere->getScale(), 32, 32); glPopMatrix(); } CuboidRenderer::CuboidRenderer() { } void CuboidRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { Cuboid* cuboid = static_cast<Cuboid*>(_spanner); const QColor& color = cuboid->getColor(); glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF()); glPushMatrix(); const glm::vec3& translation = cuboid->getTranslation(); glTranslatef(translation.x, translation.y, translation.z); glm::quat rotation = cuboid->getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glScalef(1.0f, cuboid->getAspectY(), cuboid->getAspectZ()); Application::getInstance()->getDeferredLightingEffect()->renderSolidCube(cuboid->getScale() * 2.0f); glPopMatrix(); } StaticModelRenderer::StaticModelRenderer() : _model(new Model(this)) { } void StaticModelRenderer::init(Spanner* spanner) { SpannerRenderer::init(spanner); _model->init(); StaticModel* staticModel = static_cast<StaticModel*>(spanner); applyTranslation(staticModel->getTranslation()); applyRotation(staticModel->getRotation()); applyScale(staticModel->getScale()); applyURL(staticModel->getURL()); connect(spanner, SIGNAL(translationChanged(const glm::vec3&)), SLOT(applyTranslation(const glm::vec3&))); connect(spanner, SIGNAL(rotationChanged(const glm::quat&)), SLOT(applyRotation(const glm::quat&))); connect(spanner, SIGNAL(scaleChanged(float)), SLOT(applyScale(float))); connect(spanner, SIGNAL(urlChanged(const QUrl&)), SLOT(applyURL(const QUrl&))); } void StaticModelRenderer::simulate(float deltaTime) { // update the bounds Box bounds; if (_model->isActive()) { const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents; bounds = Box(extents.minimum, extents.maximum); } static_cast<StaticModel*>(_spanner)->setBounds(glm::translate(_model->getTranslation()) * glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds); _model->simulate(deltaTime); } void StaticModelRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { _model->render(); } bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { RayIntersectionInfo info; info._rayStart = origin; info._rayDirection = direction; if (!_model->findRayIntersection(info)) { return false; } distance = info._hitDistance; return true; } void StaticModelRenderer::applyTranslation(const glm::vec3& translation) { _model->setTranslation(translation); } void StaticModelRenderer::applyRotation(const glm::quat& rotation) { _model->setRotation(rotation); } void StaticModelRenderer::applyScale(float scale) { _model->setScale(glm::vec3(scale, scale, scale)); } void StaticModelRenderer::applyURL(const QUrl& url) { _model->setURL(url); } HeightfieldRenderer::HeightfieldRenderer() { } const int X_MAXIMUM_FLAG = 1; const int Y_MAXIMUM_FLAG = 2; static void renderNode(const HeightfieldNodePointer& node, Heightfield* heightfield, const MetavoxelLOD& lod, const glm::vec2& minimum, float size, bool contained, bool cursor) { const glm::quat& rotation = heightfield->getRotation(); glm::vec3 scale(heightfield->getScale() * size, heightfield->getScale() * heightfield->getAspectY(), heightfield->getScale() * heightfield->getAspectZ() * size); glm::vec3 translation = heightfield->getTranslation() + rotation * glm::vec3(minimum.x * heightfield->getScale(), 0.0f, minimum.y * heightfield->getScale() * heightfield->getAspectZ()); if (!contained) { Frustum::IntersectionType type = Application::getInstance()->getMetavoxels()->getFrustum().getIntersectionType( glm::translate(translation) * glm::mat4_cast(rotation) * Box(glm::vec3(), scale)); if (type == Frustum::NO_INTERSECTION) { return; } if (type == Frustum::CONTAINS_INTERSECTION) { contained = true; } } if (!node->isLeaf() && lod.shouldSubdivide(minimum, size)) { float nextSize = size * 0.5f; for (int i = 0; i < HeightfieldNode::CHILD_COUNT; i++) { renderNode(node->getChild(i), heightfield, lod, minimum + glm::vec2(i & X_MAXIMUM_FLAG ? nextSize : 0.0f, i & Y_MAXIMUM_FLAG ? nextSize : 0.0f), nextSize, contained, cursor); } return; } HeightfieldNodeRenderer* renderer = static_cast<HeightfieldNodeRenderer*>(node->getRenderer()); if (!renderer) { node->setRenderer(renderer = new HeightfieldNodeRenderer()); } renderer->render(node, translation, rotation, scale, cursor); } void HeightfieldRenderer::render(const MetavoxelLOD& lod, bool contained, bool cursor) { Heightfield* heightfield = static_cast<Heightfield*>(_spanner); renderNode(heightfield->getRoot(), heightfield, heightfield->transformLOD(lod), glm::vec2(), 1.0f, contained, cursor); } HeightfieldNodeRenderer::HeightfieldNodeRenderer() : _heightTextureID(0), _colorTextureID(0), _materialTextureID(0) { } HeightfieldNodeRenderer::~HeightfieldNodeRenderer() { QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures", Q_ARG(int, _heightTextureID), Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID)); } void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { return; } int width = node->getHeight()->getWidth(); int height = node->getHeight()->getContents().size() / width; int innerWidth = width - 2 * HeightfieldHeight::HEIGHT_BORDER; int innerHeight = height - 2 * HeightfieldHeight::HEIGHT_BORDER; int vertexCount = width * height; int rows = height - 1; int columns = width - 1; int indexCount = rows * columns * 3 * 2; BufferPair& bufferPair = _bufferPairs[IntPair(width, height)]; if (!bufferPair.first.isCreated()) { QVector<HeightfieldPoint> vertices(vertexCount); HeightfieldPoint* point = vertices.data(); float xStep = 1.0f / (innerWidth - 1); float zStep = 1.0f / (innerHeight - 1); float z = -zStep; float sStep = 1.0f / width; float tStep = 1.0f / height; float t = tStep / 2.0f; for (int i = 0; i < height; i++, z += zStep, t += tStep) { float x = -xStep; float s = sStep / 2.0f; const float SKIRT_LENGTH = 0.25f; float baseY = (i == 0 || i == height - 1) ? -SKIRT_LENGTH : 0.0f; for (int j = 0; j < width; j++, point++, x += xStep, s += sStep) { point->vertex = glm::vec3(x, (j == 0 || j == width - 1) ? -SKIRT_LENGTH : baseY, z); point->textureCoord = glm::vec2(s, t); } } bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw); bufferPair.first.create(); bufferPair.first.bind(); bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint)); bufferPair.first.release(); QVector<int> indices(indexCount); int* index = indices.data(); for (int i = 0; i < rows; i++) { int lineIndex = i * width; int nextLineIndex = (i + 1) * width; for (int j = 0; j < columns; j++) { *index++ = lineIndex + j; *index++ = nextLineIndex + j; *index++ = nextLineIndex + j + 1; *index++ = nextLineIndex + j + 1; *index++ = lineIndex + j + 1; *index++ = lineIndex + j; } } bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); bufferPair.second.create(); bufferPair.second.bind(); bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int)); bufferPair.second.release(); } if (_heightTextureID == 0) { glGenTextures(1, &_heightTextureID); glBindTexture(GL_TEXTURE_2D, _heightTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); const QVector<quint16>& heightContents = node->getHeight()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, width, height, 0, GL_RED, GL_UNSIGNED_SHORT, heightContents.constData()); glGenTextures(1, &_colorTextureID); glBindTexture(GL_TEXTURE_2D, _colorTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (node->getColor()) { const QByteArray& contents = node->getColor()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, node->getColor()->getWidth(), contents.size() / (node->getColor()->getWidth() * DataBlock::COLOR_BYTES), 0, GL_RGB, GL_UNSIGNED_BYTE, contents.constData()); } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); } glGenTextures(1, &_materialTextureID); glBindTexture(GL_TEXTURE_2D, _materialTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (node->getMaterial()) { const QByteArray& contents = node->getMaterial()->getContents(); glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, node->getMaterial()->getWidth(), contents.size() / node->getMaterial()->getWidth(), 0, GL_RED, GL_UNSIGNED_BYTE, contents.constData()); const QVector<SharedObjectPointer>& materials = node->getMaterial()->getMaterials(); _networkTextures.resize(materials.size()); for (int i = 0; i < materials.size(); i++) { const SharedObjectPointer& material = materials.at(i); if (material) { _networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture( static_cast<MaterialObject*>(material.data())->getDiffuse(), SPLAT_TEXTURE); } } } else { const quint8 ZERO_VALUE = 0; glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &ZERO_VALUE); } glBindTexture(GL_TEXTURE_2D, 0); } if (cursor) { bufferPair.first.bind(); bufferPair.second.bind(); glPushMatrix(); glTranslatef(translation.x, translation.y, translation.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glScalef(scale.x, scale.y, scale.z); HeightfieldPoint* point = 0; glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex); glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord); glBindTexture(GL_TEXTURE_2D, _heightTextureID); glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, 0); glPopMatrix(); bufferPair.first.release(); bufferPair.second.release(); return; } HeightfieldBaseLayerBatch baseBatch; baseBatch.vertexBuffer = &bufferPair.first; baseBatch.indexBuffer = &bufferPair.second; baseBatch.translation = translation; baseBatch.rotation = rotation; baseBatch.scale = scale; baseBatch.vertexCount = vertexCount; baseBatch.indexCount = indexCount; baseBatch.heightTextureID = _heightTextureID; baseBatch.heightScale = glm::vec4(1.0f / width, 1.0f / height, (innerWidth - 1) / -2.0f, (innerHeight - 1) / -2.0f); baseBatch.colorTextureID = _colorTextureID; baseBatch.colorScale = glm::vec2((float)width / innerWidth, (float)height / innerHeight); Application::getInstance()->getMetavoxels()->addHeightfieldBaseBatch(baseBatch); if (!_networkTextures.isEmpty()) { HeightfieldSplatBatch splatBatch; splatBatch.vertexBuffer = &bufferPair.first; splatBatch.indexBuffer = &bufferPair.second; splatBatch.translation = translation; splatBatch.rotation = rotation; splatBatch.scale = scale; splatBatch.vertexCount = vertexCount; splatBatch.indexCount = indexCount; splatBatch.heightTextureID = _heightTextureID; splatBatch.heightScale = glm::vec4(1.0f / width, 1.0f / height, 0.0f, 0.0f); splatBatch.materialTextureID = _materialTextureID; splatBatch.textureScale = glm::vec2((float)width / innerWidth, (float)height / innerHeight); splatBatch.splatTextureOffset = glm::vec2( glm::dot(translation, rotation * glm::vec3(1.0f, 0.0f, 0.0f)) / scale.x, glm::dot(translation, rotation * glm::vec3(0.0f, 0.0f, 1.0f)) / scale.z); const QVector<SharedObjectPointer>& materials = node->getMaterial()->getMaterials(); for (int i = 0; i < materials.size(); i += SPLAT_COUNT) { for (int j = 0; j < SPLAT_COUNT; j++) { int index = i + j; if (index < _networkTextures.size()) { const NetworkTexturePointer& texture = _networkTextures.at(index); if (texture) { MaterialObject* material = static_cast<MaterialObject*>(materials.at(index).data()); splatBatch.splatTextureScalesS[j] = scale.x / material->getScaleS(); splatBatch.splatTextureScalesT[j] = scale.z / material->getScaleT(); splatBatch.splatTextureIDs[j] = texture->getID(); } else { splatBatch.splatTextureIDs[j] = 0; } } else { splatBatch.splatTextureIDs[j] = 0; } } splatBatch.materialIndex = i; Application::getInstance()->getMetavoxels()->addHeightfieldSplatBatch(splatBatch); } } } QHash<HeightfieldNodeRenderer::IntPair, HeightfieldNodeRenderer::BufferPair> HeightfieldNodeRenderer::_bufferPairs;