#include "tile.h" #include "matrix2d.h" #include #include "qscenerenderer.h" #include QImage * Tile::m_image_grass = NULL; QOpenGLTexture * Tile::m_texture_grass = NULL; QImage * Tile::m_image_border = NULL; QOpenGLTexture * Tile::m_texture_border = NULL; QOpenGLTexture * Tile::m_texture_rock = NULL; QImage * Tile::m_image_rock = NULL; QOpenGLTexture * Tile::m_texture_sand = NULL; QImage * Tile::m_image_sand = NULL; QOpenGLTexture * Tile::m_texture_water = NULL; QImage * Tile::m_image_water = NULL; QOpenGLTexture * Tile::m_texture_snow = NULL; QImage * Tile::m_image_snow = NULL; QOpenGLTexture * Tile::m_texture_typemap = NULL; QImage * Tile::m_image_typemap = NULL; QOpenGLTexture * Tile::m_texture_sahara = NULL; QImage * Tile::m_image_sahara = NULL; QOpenGLTexture * Tile::m_texture_tundra = NULL; QImage * Tile::m_image_tundra = NULL; QOpenGLTexture * Tile::m_texture_redsand = NULL; QImage * Tile::m_image_redsand = NULL; QOpenGLTexture * Tile::m_texture_redrock = NULL; QImage * Tile::m_image_redrock = NULL; QOpenGLTexture * Tile::m_texture_forest = NULL; QImage * Tile::m_image_forest = NULL; Vertex * Tile::m_vertices= NULL; int Tile::m_numVertex; QOpenGLBuffer Tile::m_vertex=QOpenGLBuffer(); QOpenGLVertexArrayObject Tile::m_object; QOpenGLShaderProgram *Tile::m_program= NULL; static float distToSegment(QVector2D p, QVector2D a, QVector2D b) { QVector2D ba = b - a; QVector2D pa = p - a; float l2 = QVector2D::dotProduct(ba, ba); if (l2 <= 1e-6f) return pa.length(); float h = std::max(0.0f, std::min(1.0f, QVector2D::dotProduct(pa, ba) / l2)); return (pa - ba * h).length(); } float Tile::getRiverDistance(QVector2D p, unsigned char mask) { if (mask == 0) return 999.0f; int edges[6]; int count = 0; for (int e = 0; e < 6; ++e) { if (mask & (1 << e)) { edges[count++] = e; } } if (count == 2) { QVector2D p0 = getHexEdgeMidpoint(edges[0]); QVector2D p2 = getHexEdgeMidpoint(edges[1]); QVector2D s0 = p0; QVector2D s1 = 0.5625f * p0 + 0.0625f * p2; QVector2D s2 = 0.2500f * p0 + 0.2500f * p2; QVector2D s3 = 0.0625f * p0 + 0.5625f * p2; QVector2D s4 = p2; float d0 = distToSegment(p, s0, s1); float d1 = distToSegment(p, s1, s2); float d2 = distToSegment(p, s2, s3); float d3 = distToSegment(p, s3, s4); return std::min(std::min(d0, d1), std::min(d2, d3)); } else { float minDist = 999.0f; for (int i = 0; i < count; ++i) { float d = distToSegment(p, getHexEdgeMidpoint(edges[i]), QVector2D(0.0f, 0.0f)); minDist = std::min(minDist, d); } return minDist; } } Tile::Tile() : m_scene(NULL), m_tilevertices(NULL), m_x(0), m_y(0), m_startpoint_x(0.0f), m_startpoint_y(0.0f), m_initialized(false), m_normalsBuilt(false), m_riverMask(0) { } void Tile::ensureInitialized(QSceneRenderer* s, int x, int y) { if (!m_initialized) { init(s, x, y); } } void Tile::ensureNormalsBuilt() { if (!m_normalsBuilt && m_initialized) { buildNormals(); m_normalsBuilt = true; } } void Tile::init(QSceneRenderer* s, int x, int y) { m_x = x; m_y = y; m_scene = s; //m_x*LOD_0_SIZE *1.5+ (m_y%2==1 ?( LOD_0_SIZE*1.5f)/2.0f:0),m_y*LOD_0_SIZE/2.0f,1.0f) // m_startpoint_x =( m_scene->getNumPoints05()*3*x)+ (y%2==1? (m_scene->getNumPoints05()*1.5):0); //m_startpoint_y = m_scene->getNumPoints05()*y; m_startpoint_x =( m_scene->getNumPoints05()*1.5f*x) ; m_startpoint_y = m_scene->getNumPoints05()*y*2.0f + (x%2==1? (m_scene->getNumPoints05()):0) ; bool first = false; if (m_vertices==NULL){ buildVertices();first=true; } buildHeights(); if (Tile::m_image_grass == NULL) Tile::m_image_grass = new QImage("/home/bart/project/tiletest/images/grass.jpg"); if (Tile::m_image_border == NULL) Tile::m_image_border = new QImage("/home/bart/project/tiletest/images/border.png"); if (Tile::m_image_rock == NULL) Tile::m_image_rock = new QImage("/home/bart/project/tiletest/images/Texturelabs_Stone_136XL_seamless.jpg"); if (Tile::m_image_sand == NULL) Tile::m_image_sand = new QImage("/home/bart/project/tiletest/images/Texturelabs_Soil_126XL_seamless.jpg"); if (Tile::m_image_water == NULL) Tile::m_image_water = new QImage("/home/bart/project/tiletest/images/Texturelabs_Water_152XL_seamless.jpg"); if (Tile::m_image_snow == NULL) Tile::m_image_snow = new QImage("/home/bart/project/tiletest/images/Texturelabs_Water_155XL_seamless.jpg"); if (Tile::m_image_typemap == NULL) Tile::m_image_typemap = new QImage("/home/bart/project/tiletest/images/typemap.png"); if (Tile::m_image_sahara == NULL) Tile::m_image_sahara = new QImage("/home/bart/project/tiletest/images/Texturelabs_Soil_133L_seamless.jpg"); if (Tile::m_image_tundra == NULL) Tile::m_image_tundra = new QImage("/home/bart/project/tiletest/images/Texturelabs_Soil_135XL_seamless.jpg"); if (Tile::m_image_redsand == NULL) Tile::m_image_redsand = new QImage("/home/bart/project/tiletest/images/Texturelabs_RedSand_seamless.jpg"); if (Tile::m_image_redrock == NULL) Tile::m_image_redrock = new QImage("/home/bart/project/tiletest/images/Texturelabs_RedRock_seamless.jpg"); if (Tile::m_image_forest == NULL) Tile::m_image_forest = new QImage("/home/bart/project/tiletest/images/Texturelabs_Forest_seamless.jpg"); if (Tile::m_texture_grass == NULL) { m_texture_grass = new QOpenGLTexture(*m_image_grass); m_texture_grass->setWrapMode(QOpenGLTexture::Repeat); m_texture_grass->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_grass->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_grass->generateMipMaps(); } if (Tile::m_texture_border == NULL) { m_texture_border = new QOpenGLTexture(*m_image_border); m_texture_border->setWrapMode(QOpenGLTexture::Repeat); m_texture_border->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_border->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_border->generateMipMaps(); } if (Tile::m_texture_rock == NULL) { m_texture_rock = new QOpenGLTexture(*m_image_rock); m_texture_rock->setWrapMode(QOpenGLTexture::Repeat); m_texture_rock->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_rock->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_rock->generateMipMaps(); } if (Tile::m_texture_sand == NULL) { m_texture_sand = new QOpenGLTexture(*m_image_sand); m_texture_sand->setWrapMode(QOpenGLTexture::Repeat); m_texture_sand->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_sand->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_sand->generateMipMaps(); } if (Tile::m_texture_water == NULL) { m_texture_water = new QOpenGLTexture(*m_image_water); m_texture_water->setWrapMode(QOpenGLTexture::Repeat); m_texture_water->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_water->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_water->generateMipMaps(); } if (Tile::m_texture_snow == NULL) { m_texture_snow = new QOpenGLTexture(*m_image_snow); m_texture_snow->setWrapMode(QOpenGLTexture::Repeat); m_texture_snow->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_snow->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_snow->generateMipMaps(); } if (Tile::m_texture_typemap == NULL) { m_texture_typemap = new QOpenGLTexture(*m_image_typemap); m_texture_typemap->setWrapMode(QOpenGLTexture::ClampToEdge); m_texture_typemap->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_typemap->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_typemap->generateMipMaps(); } if (Tile::m_texture_sahara == NULL) { m_texture_sahara = new QOpenGLTexture(*m_image_sahara); m_texture_sahara->setWrapMode(QOpenGLTexture::Repeat); m_texture_sahara->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_sahara->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_sahara->generateMipMaps(); } if (Tile::m_texture_tundra == NULL) { m_texture_tundra = new QOpenGLTexture(*m_image_tundra); m_texture_tundra->setWrapMode(QOpenGLTexture::Repeat); m_texture_tundra->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_tundra->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_tundra->generateMipMaps(); } if (Tile::m_texture_redsand == NULL) { m_texture_redsand = new QOpenGLTexture(*m_image_redsand); m_texture_redsand->setWrapMode(QOpenGLTexture::Repeat); m_texture_redsand->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_redsand->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_redsand->generateMipMaps(); } if (Tile::m_texture_redrock == NULL) { m_texture_redrock = new QOpenGLTexture(*m_image_redrock); m_texture_redrock->setWrapMode(QOpenGLTexture::Repeat); m_texture_redrock->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_redrock->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_redrock->generateMipMaps(); } if (Tile::m_texture_forest == NULL) { m_texture_forest = new QOpenGLTexture(*m_image_forest); m_texture_forest->setWrapMode(QOpenGLTexture::Repeat); m_texture_forest->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture_forest->setMagnificationFilter(QOpenGLTexture::Linear); m_texture_forest->generateMipMaps(); } if (first){ m_program = new QOpenGLShaderProgram(); m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, "/home/bart/project/tiletest/shaders/simple.vert"); m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, "/home/bart/project/tiletest/shaders/simple.frag"); m_program->link(); } m_program->bind(); // Generate 1 buffer, put the resulting identifier in vertexbuffer // Create Buffer (Do not release until VAO is created) if (first) { m_vertex.create(); m_vertex.bind(); m_vertex.setUsagePattern(QOpenGLBuffer::StaticDraw); m_vertex.allocate(m_vertices, sizeof(Vertex) * (m_numVertex+1)); // Create Vertex Array Object m_object.create(); m_object.bind(); m_program->enableAttributeArray(0); m_program->enableAttributeArray(1); m_program->setAttributeBuffer(0, GL_FLOAT, Vertex::positionOffset(), Vertex::PositionTupleSize, Vertex::stride()); m_program->setAttributeBuffer(1, GL_FLOAT, Vertex::colorOffset(), Vertex::ColorTupleSize, Vertex::stride()); // Release (unbind) all m_object.release(); m_vertex.release(); m_program->release(); } m_initialized = true; } void Tile::paint(QMatrix4x4 p, QVector3D& cameraPosition,QVector3D& cameraUpDirection,QMatrix4x4& vMatrix, float time) { if (!m_initialized) return; QMatrix4x4 mModelToCamera; QMatrix4x4 rMatrix; QMatrix4x4 mMatrix; float fSunAngle = 45.0; QVector3D vSunPos(-sin(fSunAngle*PI/180.0f), -cos(fSunAngle*PI/180.0f), 0.0); glActiveTexture(GL_TEXTURE0); //mMatrix.translate(m_x*LOD_0_SIZE *1.5+ (m_y%2==1 ?( LOD_0_SIZE*1.5f)/2.0f:0),m_y*LOD_0_SIZE/2.0f,1.0f); mMatrix.translate(m_x*(LOD_0_SIZE*0.75) ,(m_y*(LOD_0_SIZE_Y*2)+(m_x%2==0?0:LOD_0_SIZE_Y)) ,1.0f); m_texture_grass->bind(0); m_texture_border->bind(1); m_texture_rock->bind(2); m_texture_sand->bind(3); m_texture_water->bind(4); m_texture_snow->bind(5); m_texture_typemap->bind(6); m_texture_sahara->bind(7); m_texture_tundra->bind(8); m_texture_redsand->bind(9); m_texture_redrock->bind(10); m_texture_forest->bind(11); // Render using our shader m_program->bind(); m_heightsbuffer.create(); m_heightsbuffer.bind(); m_heightsbuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); m_heightsbuffer.allocate(m_tilevertices, sizeof(TileVertexInfo) * (m_numVertex+1)); { vSunPos.normalize(); float fSign = -1.0f; // This just returns -1.0f or 1.0f (try to examine this) m_program->setUniformValue("sunLight.vColor", QVector3D(1.0f, 1.0f, 1.0f)); m_program->setUniformValue("sunLight.fAmbientIntensity",0.8f); m_program->setUniformValue("sunLight.vDirection", vSunPos); QVector3D vPos = QVector3D(fSign*15.0f, 0.0f, 50.0f-float(0)*25.0f); vPos.setZ(vPos.z()+1.0f); mModelToCamera =vMatrix * mMatrix.inverted().transposed();//QMatrix4x4();// vPos.translate(1.0f); //mModelToCamera.scale(0.8); m_program->setUniformValue("texGrass", 0); m_program->setUniformValue("texBorder", 1); m_program->setUniformValue("texRock", 2); m_program->setUniformValue("texSand", 3); m_program->setUniformValue("texWater", 4); m_program->setUniformValue("texSnow", 5); m_program->setUniformValue("texTypeMap", 6); m_program->setUniformValue("texSahara", 7); m_program->setUniformValue("texTundra", 8); m_program->setUniformValue("texRedSand", 9); m_program->setUniformValue("texRedRock", 10); m_program->setUniformValue("texForest", 11); m_program->setUniformValue("time", time); m_program->setUniformValue("riverMask", (int)m_riverMask); m_object.bind(); m_heightsbuffer.bind(); m_program->enableAttributeArray(2); m_program->setAttributeBuffer(2, GL_FLOAT,TileVertexInfo::heightOffset(),TileVertexInfo::HeightTupleSize, TileVertexInfo::stride()); m_program->enableAttributeArray(3); m_program->setAttributeBuffer(3, GL_FLOAT,TileVertexInfo::normalOffset(),TileVertexInfo::NormalTupleSize, TileVertexInfo::stride()); m_heightsbuffer.release(); rMatrix.translate(0.5f,LOD_0_SIZE_Y,0); m_program->setUniformValue("cameraPosition", cameraPosition); //mModelToCamera =vMatrix * mMatrix.inverted().transposed();//QMatrix4x4();// vPos.translate(1.0f); m_program->setUniformValue("normalMatrix", mModelToCamera); m_program->setUniformValue("modelMatrix", rMatrix); m_program->setUniformValue("worldMatrix", mMatrix); m_program->setUniformValue("modelViewMatrix", vMatrix * mMatrix); m_program->setUniformValue("MVP", p * vMatrix * mMatrix); glDrawArrays(GL_TRIANGLES, 0, NUM_TRIANGLES*NUM_TRIANGLE_VERTICES); m_object.release(); }m_heightsbuffer.destroy(); m_program->release(); } void Tile::buildVertices() { m_numVertex= NUM_TRIANGLES*NUM_TRIANGLE_VERTICES; m_vertices = new Vertex[m_numVertex]; int cnt =0; for (int i = 0; i< NUM_TRIANGLES_0; i++) { addTriangleVertices(cnt , QVector2D( 0.0f, 0.0f) , QVector2D( 0.5f*cos(PI*60.0f*i/180.0f)*-1.0f , 0.5f*sin(PI*60.0f*i/180.0f))//, QVector2D(-LOD_0_SIZE/2.0f , 0.0f ) ) , QVector2D( 0.5f*cos(PI*60.0f*(i+1)/180.0f)*-1.0f , 0.5f*sin(PI*60.0f*(i+1)/180.0f))//, QVector2D(-LOD_0_SIZE/4.0f , LOD_0_SIZE/2.0f) ) //, QVector2D(0.0f , 0.0f ) ) , 1 , 0, 0 ); } } void Tile::addTriangleVertices(int &cnt, QVector2D t1, QVector2D t2, QVector2D t3,int level, int hex, int l1) { if (level>0) { level--; addTriangleVertices(cnt , QVector2D( t1.x(), t1.y())//, QVector2D(0,0) ) , QVector2D( (t1.x()+t2.x())/2.0f, (t1.y()+t2.y())/2.0f )//, QVector2D(0,0) ) , QVector2D( (t1.x()+t3.x())/2.0f , (t1.y()+t3.y())/2.0f )//, QVector2D(0,0) ) , level, hex, 0 ); addTriangleVertices(cnt , QVector2D( (t1.x()+t2.x())/2.0f, (t1.y()+t2.y())/2.0f)//, QVector2D(0,0) ) , QVector2D( (t2.x()+t3.x())/2.0f, (t2.y()+t3.y())/2.0f)//, QVector2D(0,0) ) , QVector2D( (t1.x()+t3.x())/2.0f , (t1.y()+t3.y())/2.0f )//, QVector2D(0,0) ) , level, hex, 1 ); addTriangleVertices(cnt , QVector2D( (t1.x()+t2.x())/2.0f, (t1.y()+t2.y())/2.0f )//, QVector2D(0,0) ) , QVector2D( t2.x(), t2.y() )//, t1.texturepos()*0.7f ) , QVector2D( (t2.x()+t3.x())/2.0f, (t2.y()+t3.y())/2.0f)//,QVector2D(0,0) ) , level, hex, 2 ); addTriangleVertices(cnt , QVector2D( (t1.x()+t3.x())/2.0f , (t1.y()+t3.y())/2.0f )//,QVector2D(0,0) ) , QVector2D( (t2.x()+t3.x())/2.0f, (t2.y()+t3.y())/2.0f )//, QVector2D(0,0) ) , QVector2D( t3.x(), t3.y() )//, t1.texturepos()) , level, hex, 3 ); } else { drawSubTriangleVertices(cnt , QVector2D( t1.x(), t1.y())//, QVector2D(0,0) ) , QVector2D( (t1.x()+t2.x())/2.0f, (t1.y()+t2.y())/2.0f )//, QVector2D(0,0) ) , QVector2D( (t1.x()+t3.x())/2.0f , (t1.y()+t3.y())/2.0f )//, QVector2D(0,0) ) , hex, l1,0 ); drawSubTriangleVertices(cnt , QVector2D( (t1.x()+t2.x())/2.0f, (t1.y()+t2.y())/2.0f)//, QVector2D(0,0) ) , QVector2D( (t2.x()+t3.x())/2.0f, (t2.y()+t3.y())/2.0f)//, QVector2D(0,0) ) , QVector2D( (t1.x()+t3.x())/2.0f , (t1.y()+t3.y())/2.0f )//, QVector2D(0,0) ) , hex, l1,1 ); drawSubTriangleVertices(cnt , QVector2D( (t1.x()+t2.x())/2.0f, (t1.y()+t2.y())/2.0f )//, QVector2D(0,0) ) , QVector2D( t2.x(), t2.y() )//, t1.texturepos()*0.7f ) , QVector2D( (t2.x()+t3.x())/2.0f, (t2.y()+t3.y())/2.0f)//,QVector2D(0,0) ) , hex, l1,2 ); drawSubTriangleVertices(cnt , QVector2D( (t1.x()+t3.x())/2.0f , (t1.y()+t3.y())/2.0f )//,QVector2D(0,0) ) , QVector2D( (t2.x()+t3.x())/2.0f, (t2.y()+t3.y())/2.0f )//, QVector2D(0,0) ) , QVector2D( t3.x(), t3.y() )//, t1.texturepos()) , hex, l1,3 ); } } void Tile::drawSubTriangleVertices(int &cnt, QVector2D t1, QVector2D t2, QVector2D t3, int hex, int l1, int l2) { m_vertices[cnt++] = Vertex( t1 , QVector2D(t1.x()+LOD_0_SIZE/2.0f,t1.y()+LOD_0_SIZE/2.0f) ); m_vertices[cnt++] = Vertex( t2 , QVector2D(t2.x()+LOD_0_SIZE/2.0f,t2.y()+LOD_0_SIZE/2.0f) ); m_vertices[cnt++] = Vertex( t3 , QVector2D(t3.x()+LOD_0_SIZE/2.0f,t3.y()+LOD_0_SIZE/2.0f) ); } void Tile::buildHeights() { m_tilevertices = new TileVertexInfo[m_numVertex]; Matrix2D * points = Tile::m_scene->getMapPoints(); float tileWorldX = m_x * (LOD_0_SIZE * 0.75f); float tileWorldY = m_y * (LOD_0_SIZE_Y * 2.0f) + ((m_x % 2 == 0) ? 0.0f : LOD_0_SIZE_Y); float scaleX = m_scene->getNumPoints05() * 2.0f; float scaleY = m_scene->getNumPoints05() / LOD_0_SIZE_Y; for (int i = 0; i < m_numVertex; i++) { float worldX = tileWorldX + m_vertices[i].position().x(); float worldY = tileWorldY + m_vertices[i].position().y(); int mapX = (int) round(worldX * scaleX); int mapY = (int) round(worldY * scaleY); float r = (points->operator()(mapX, mapY).height / 255.0f) * 3.5f; if (m_riverMask != 0) { float rDist = getRiverDistance(m_vertices[i].position(), m_riverMask); float riverBankRadius = 0.052f; if (rDist < riverBankRadius) { float carve = 0.018f * (1.0f - (rDist / riverBankRadius)); r = std::max(0.0f, r - carve); } } m_tilevertices[i].setHeight(r); } m_faces.reserve(m_numVertex/3); int i =0; for (int h = 0; h< 6; h++) { m_face[h].createSub(); for (int l0 = 0; l0< 4; l0++) { m_face[h].getSub(l0).createSub(); for (int l1 = 0; l1< 4; l1++) { m_face[h].getSub(l0).getSub(l1).setSettings( &m_vertices[i],&m_tilevertices[i], &m_vertices[i+1],&m_tilevertices[i+1], &m_vertices[i+2],&m_tilevertices[i+2] ); m_faces.push_back(m_face[h].getSub(l0).getSub(l1)); i +=3; } } } } void Tile::findFaces(std::vector &vec, QVector2D s) { if (!m_initialized) return; for (int h = 0; h< 6; h++) { m_face[h].findFaces(vec, s); } } void Tile::buildNormals() { if (!m_initialized) return; QVector2D myWorld = getWorldPosition(); int nbrs[6][2]; if (m_x % 2 == 0) { nbrs[0][0] = m_x; nbrs[0][1] = m_y - 1; nbrs[1][0] = m_x; nbrs[1][1] = m_y + 1; nbrs[2][0] = m_x - 1; nbrs[2][1] = m_y - 1; nbrs[3][0] = m_x - 1; nbrs[3][1] = m_y; nbrs[4][0] = m_x + 1; nbrs[4][1] = m_y - 1; nbrs[5][0] = m_x + 1; nbrs[5][1] = m_y; } else { nbrs[0][0] = m_x; nbrs[0][1] = m_y - 1; nbrs[1][0] = m_x; nbrs[1][1] = m_y + 1; nbrs[2][0] = m_x - 1; nbrs[2][1] = m_y; nbrs[3][0] = m_x - 1; nbrs[3][1] = m_y + 1; nbrs[4][0] = m_x + 1; nbrs[4][1] = m_y; nbrs[5][0] = m_x + 1; nbrs[5][1] = m_y + 1; } std::vector vec; for (int i=0; i 0.4f) { QVector2D worldV = myWorld + vPos; for (int k = 0; k < 6; ++k) { int nx = nbrs[k][0]; int ny = nbrs[k][1]; if (nx >= 0 && nx < MAP_WIDTH && ny >= 0 && ny < MAP_HEIGHT) { Tile *nbr = m_scene->getTile(nx, ny); if (nbr && nbr->isInitialized()) { QVector2D localInNbr = worldV - nbr->getWorldPosition(); nbr->findFaces(vec, localInNbr); } } } } QVector3D r(0.0f, 0.0f, 0.0f); float cnt = 0; for (std::vector::iterator it = vec.begin() ; it != vec.end(); ++it) { QVector3D v = (*it)->normal(); if (!v.isNull()) { cnt++; r += v; } } if (cnt > 0.0f && !r.isNull()) { r.normalize(); } else { r = QVector3D(0.0f, 0.0f, 1.0f); } m_tilevertices[i].setNormal(r); } }