// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "prim_render.h" #include "tool.h" #include "r2_config.h" // #include "nel/misc/vector_2f.h" #include "nel/misc/time_nl.h" // #include "nel/gui/view_bitmap.h" #include "nel/gui/ctrl_quad.h" #include "nel/gui/ctrl_polygon.h" #include "../interface_v3/interface_manager.h" #include "nel/gui/view_renderer.h" #include "../interface_v3/group_map.h" using namespace NL3D; using namespace NLMISC; namespace R2 { // helper function for lua init void readFromLua(const CLuaObject &table, const char *key, float &dest) { if (table[key].isNumber()) dest = (float) table[key].toNumber(); } void readFromLua(const CLuaObject &table, const char *key, uint &dest) { if (table[key].isNumber()) dest = (uint) table[key].toNumber(); } void readFromLua(const CLuaObject &table, const char *key, std::string &dest) { if (table[key].isString()) dest = table[key].toString(); } void readFromLua(const CLuaObject &table, const char *key, CStringShared &dest) { if (table[key].isString()) dest = table[key].toString(); } void readFromLua(const CLuaObject &table, const char *key, bool &dest) { if (table[key].isBoolean()) dest = table[key].toBoolean(); } void readFromLua(const CLuaObject &table, const char *key, CRGBA &dest) { if (table[key].isRGBA()) dest = table[key].toRGBA(); } #define READ_FROM_LUA(dest) readFromLua(params, #dest, dest); // ********************************************************* void CVertexLook::init(const CLuaObject ¶ms) { //H_AUTO(R2_CVertexLook_init) READ_FROM_LUA(DecalTexture); READ_FROM_LUA(DecalSize); READ_FROM_LUA(DecalColor); READ_FROM_LUA(DecalDistToEdgeDecal); READ_FROM_LUA(WorldMapTexture); READ_FROM_LUA(WorldMapColor); } // ********************************************************* void CEdgeLook::init(const CLuaObject ¶ms) { //H_AUTO(R2_CEdgeLook_init) READ_FROM_LUA(ShapeName); READ_FROM_LUA(ShapeScale); READ_FROM_LUA(DecalTexture); READ_FROM_LUA(DecalUScale); READ_FROM_LUA(DecalWidth); READ_FROM_LUA(DecalColor); READ_FROM_LUA(DecalFiltered); READ_FROM_LUA(WorldMapTexture); READ_FROM_LUA(WorldMapWidth); READ_FROM_LUA(WorldMapColor); READ_FROM_LUA(WorldMapUScale); READ_FROM_LUA(WorldMapFiltered); uint decalWrapMode = Repeat; readFromLua(params, "DecalWrapMode", decalWrapMode); if (decalWrapMode < WrapModeCount) DecalWrapMode = (TWrapMode) decalWrapMode; uint worldMapWrapMode = Scaled; readFromLua(params, "WorldMapWrapMode", worldMapWrapMode); if (worldMapWrapMode < WrapModeCount) WorldMapWrapMode = (TWrapMode) worldMapWrapMode; } // ********************************************************* bool operator ==(const CPrimLook &lhs, const CPrimLook &rhs) { return lhs.Shape == rhs.Shape && lhs.VertexShapeName == rhs.VertexShapeName && lhs.VertexShapeScale == rhs.VertexShapeScale && lhs.VertexLook == rhs.VertexLook && lhs.FirstVertexLook == rhs.FirstVertexLook && lhs.EdgeLook == rhs.EdgeLook && lhs.LastEdgeIsValid == rhs.LastEdgeIsValid && lhs.ClipDownFacing == rhs.ClipDownFacing; } // ********************************************************* void CPrimLook::init(const CLuaObject ¶ms) { //H_AUTO(R2_CPrimLook_init) if (!params.isTable()) { nlwarning(" parameters are not a table"); return; } // vertices READ_FROM_LUA(VertexShapeName); READ_FROM_LUA(VertexShapeScale); VertexLook.init(params["VertexLook"]); if (!params["FirstVertexLook"].isNil()) { FirstVertexLook.init(params["FirstVertexLook"]); } else { FirstVertexLook = VertexLook; } EdgeLook.init(params["EdgeLook"]); READ_FROM_LUA(LastEdgeIsValid); READ_FROM_LUA(ClipDownFacing); // enums uint shape = Star; readFromLua(params, "Shape", shape); if (shape < ShapeCount) Shape = (TShape) shape; // } // ********************************************************* void CPrimRender::setLook(const CPrimLook &look) { //H_AUTO(R2_CPrimRender_setLook) if (look == _Look) return; _Look = look; if (!look.EdgeLook.WorldMapTexture.empty()) { CInterfaceManager *im = CInterfaceManager::getInstance(); CViewRenderer &vr = *CViewRenderer::getInstance(); sint32 width, height; sint32 id = vr.getTextureIdFromName(look.EdgeLook.WorldMapTexture); vr.getTextureSizeFromId(id, width, height); _InvWorldTextureWidth = width > 0 ? 1.f / width : 0.f; } update(); } // ********************************************************* CPrimRender::~CPrimRender() { if (_AddedToWorldMap) { CGroupMap *gm = CTool::getWorldMap(); nlassert(gm); this->onRemove(*gm); } else { nlassert(_WorldMapVertices.empty()); nlassert(_WorldMapEdges.empty()); } } // ********************************************************* CCtrlPolygon *CPrimRender::newCtrlPolygon() const { //H_AUTO(R2_CPrimRender_newCtrlPolygon) class CCtrlMapPolygon : public CCtrlPolygon { public: CCtrlMapPolygon( CViewBase::TCtorParam ¶m ) : CCtrlPolygon( param ){} protected: // from CCtrlPolygon void computeScaledVertex(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) { CGroupMap *gm = CTool::getWorldMap(); if (!gm) dest = CVector::Null; gm->worldToWindow(dest, src); } }; CViewBase::TCtorParam param; return new CCtrlMapPolygon( param ); } // ********************************************************* CCtrlQuad *CPrimRender::newCtrlQuad(uint /* edgeIndex */) const { //H_AUTO(R2_CPrimRender_newCtrlQuad) CViewBase::TCtorParam param; return new CCtrlQuad( param ); } // ********************************************************* bool CPrimRender::contains(const NLMISC::CVector2f &pos) const { //H_AUTO(R2_CPrimRender_contains) for(uint k = 0; k < _VertexDecals.size(); ++k) { if (_VertexDecals[k]->contains(pos)) return true; } for(uint k = 0; k < _EdgeDecals.size(); ++k) { if (_EdgeDecals[k]->contains(pos)) return true; } return false; } // ********************************************************* sint CPrimRender::isOnEdge(const NLMISC::CVector2f &pos) const { //H_AUTO(R2_CPrimRender_isOnEdge) for(uint k = 0; k < _EdgeDecals.size(); ++k) { if (_EdgeDecals[k]->contains(pos)) return (sint) k; } return -1; } // ********************************************************* CPrimRender::CPrimRender() { _Emissive = CRGBA::Black; _NumEdges = 0; _AddedToWorldMap = false; _WorldMapPoly = NULL; _InvWorldTextureWidth = 0.f; _Active = true; } // ********************************************************* void CPrimRender::clear() { //H_AUTO(R2_CPrimRender_clear) setVertices(std::vector()); } // ********************************************************* void CPrimRender::setVertices(const std::vector &vertices) { //H_AUTO(R2_CPrimRender_setVertices) if (_Vertices.size() == vertices.size()) { if (std::equal(vertices.begin(), vertices.end(), _Vertices.begin())) { return; } else { _Vertices = vertices; updatePos(); return; } } _Vertices = vertices; update(); } // ********************************************************* void CPrimRender::setVertices(const std::vector &vertices) { //H_AUTO(R2_CPrimRender_setVertices) std::vector vertices3D(vertices.size()); for(uint k = 0; k < vertices.size(); ++k) { vertices3D[k] = vertices[k]; } setVertices(vertices3D); } // ********************************************************* void CPrimRender::setCustomWorldMapEdgeUVMatrix(bool on, const NLMISC::CMatrix &matrix) { //H_AUTO(R2_CPrimRender_setCustomWorldMapEdgeUVMatrix) if (_CustomWorldMapEdgeUVMatrix.set(on, matrix)) { update(); } } // ********************************************************* void CPrimRender::setCustomDecalEdgeUVMatrix(bool on, const NLMISC::CMatrix &matrix) { //H_AUTO(R2_CPrimRender_setCustomDecalEdgeUVMatrix) if (_CustomDecalEdgeUVMatrix.set(on, matrix)) { update(); } } // ********************************************************* void CPrimRender::setEmissive(NLMISC::CRGBA color) { //H_AUTO(R2_CPrimRender_setEmissive) if (color == _Emissive) return; forceSetEmissive(color); } // ********************************************************* void CPrimRender::forceSetEmissive(NLMISC::CRGBA emissive) { //H_AUTO(R2_CPrimRender_forceSetEmissive) _Emissive = emissive; _VertexShapeInstances.setEmissive(emissive); _EdgeShapeInstances.setEmissive(emissive); for(uint k = 0; k < _VertexDecals.size(); ++k) { _VertexDecals[k]->setEmissive(emissive); } for(uint k = 0; k < _EdgeDecals.size(); ++k) { _EdgeDecals[k]->setEmissive(emissive); } } // ********************************************************* void CPrimRender::update() { //H_AUTO(R2_CPrimRender_update) //////////// // RESIZE // //////////// // vertices _VertexShapeInstances.clear(); if (!_Look.VertexShapeName.empty()) { _VertexShapeInstances.setShapeName(_Look.VertexShapeName); _VertexShapeInstances.resize((uint)_Vertices.size()); } else { _VertexShapeInstances.clear(); } // _VertexDecals.clear(); if (!_Look.VertexLook.DecalTexture.empty()) { _VertexDecals.resize(_Vertices.size()); for(uint k = 0; k < _Vertices.size(); ++k) { _VertexDecals[k] = new CDecal; _VertexDecals[k]->setClipDownFacing(_Look.ClipDownFacing); if (k == 0 && !_Look.FirstVertexLook.DecalTexture.empty()) { _VertexDecals[k]->setTexture(_Look.FirstVertexLook.DecalTexture, true); _VertexDecals[k]->setDiffuse(_Look.FirstVertexLook.DecalColor); } else { _VertexDecals[k]->setTexture(_Look.VertexLook.DecalTexture); _VertexDecals[k]->setDiffuse(_Look.VertexLook.DecalColor); } } } //edges switch(_Look.Shape) { case CPrimLook::Star: _NumEdges = _Vertices.size() <= 1 ? 0 : (sint)_Vertices.size() - 1; break; case CPrimLook::PolyLine: _NumEdges = _Vertices.size() <= 1 ? 0 : (sint)_Vertices.size() - 1; if (!_Look.LastEdgeIsValid && _NumEdges != 0) -- _NumEdges; break; case CPrimLook::ClosedPolyLine: _NumEdges = _Vertices.size() >= 3 ? (sint)_Vertices.size() : std::max((sint) 0, (sint) (_Vertices.size() - 1)); if (!_Look.LastEdgeIsValid && _NumEdges != 0) -- _NumEdges; break; default: nlassert(0); break; } // nlassert(_NumEdges >= 0); // _EdgeShapeInstances.clear(); if (!_Look.EdgeLook.ShapeName.empty()) { _EdgeShapeInstances.setShapeName(_Look.EdgeLook.ShapeName); _EdgeShapeInstances.resize(_NumEdges); } else { _EdgeShapeInstances.clear(); } // _EdgeDecals.clear(); if (!_Look.EdgeLook.DecalTexture.empty()) { _EdgeDecals.resize(_NumEdges); for(sint k = 0; k < _NumEdges; ++k) { _EdgeDecals[k] = new CDecal; _EdgeDecals[k]->setClipDownFacing(_Look.ClipDownFacing); _EdgeDecals[k]->setTexture(_Look.EdgeLook.DecalTexture, _Look.EdgeLook.DecalWrapMode == CEdgeLook::Centered, true, _Look.EdgeLook.DecalFiltered); _EdgeDecals[k]->setDiffuse(_Look.EdgeLook.DecalColor); _EdgeDecals[k]->setCustomUVMatrix(_CustomDecalEdgeUVMatrix.On, _CustomDecalEdgeUVMatrix.Matrix); } } ////////////////// // POSITIONNING // ////////////////// updatePos(); // forceSetEmissive(_Emissive); // /* TTime endTime = CTime::getLocalTime(); nlinfo("%.2f seconds for : CPrimRender::update", (endTime - _StartTime) / 1000.f); */ } // ********************************************************* void CPrimRender::updatePos() { //H_AUTO(R2_CPrimRender_updatePos) // world map if (_AddedToWorldMap) { setWorldMapNumVertices(_Look.VertexLook.WorldMapTexture.empty() ? 0 : (uint)_Vertices.size()); setWorldMapNumEdges(_Look.EdgeLook.WorldMapTexture.empty() ? 0 : _NumEdges); } // if (!_Vertices.empty()) { // edges update switch(_Look.Shape) { case CPrimLook::Star: { CVector centerPos = _Vertices[0]; for(uint k = 1; k < _Vertices.size(); ++k) { // if (!_EdgeShapeInstances.empty()) { updateEdge(_EdgeShapeInstances[k - 1], centerPos, _Vertices[k]); } if (!_EdgeDecals.empty()) { updateEdgeDecal(*(_EdgeDecals[k - 1]), centerPos, _Vertices[k], _Look.FirstVertexLook.DecalDistToEdgeDecal, _Look.VertexLook.DecalDistToEdgeDecal); } } } break; case CPrimLook::PolyLine: case CPrimLook::ClosedPolyLine: { for(sint k = 0; k < _NumEdges; ++k) { // if (!_EdgeShapeInstances.empty()) { updateEdge(_EdgeShapeInstances[k], _Vertices[k], _Vertices[(k + 1) % _Vertices.size()]); } if (!_EdgeDecals.empty()) { updateEdgeDecal(*(_EdgeDecals[k]), _Vertices[k], _Vertices[(k + 1) % _Vertices.size()], k == 0 ? _Look.VertexLook.DecalDistToEdgeDecal : _Look.FirstVertexLook.DecalDistToEdgeDecal, _Look.VertexLook.DecalDistToEdgeDecal ); } } } break; default: nlassert(0); break; } } // update vertices for(uint k = 0; k < _Vertices.size(); ++k) { if (!_Look.VertexShapeName.empty()) { if (!_VertexShapeInstances[k].empty()) { CMatrix vertexMat; vertexMat.setScale(_Look.VertexShapeScale); vertexMat.setPos(_Vertices[k]); _VertexShapeInstances[k].setTransformMode(UTransform::DirectMatrix); _VertexShapeInstances[k].setMatrix(vertexMat); } } if (!_VertexDecals.empty()) { _VertexDecals[k]->setWorldMatrixForSpot(CVector2f(_Vertices[k].x, _Vertices[k].y), k == 0 ? _Look.FirstVertexLook.DecalSize : _Look.VertexLook.DecalSize); } } // if (_AddedToWorldMap) { updateWorldMapDisplay(); } } // ********************************************************* void CPrimRender::updateEdge(NL3D::UInstance edge,const NLMISC::CVector &start, const NLMISC::CVector &end) { //H_AUTO(R2_CPrimRender_updateEdge) CVector I = end - start; CVector INormed = I.normed(); CVector K = (CVector::K - (CVector::K * INormed) * INormed).normed(); CVector J = K ^ INormed; CMatrix connectorMat; static volatile float scale =0.5f; connectorMat.setRot(I, scale * J, scale * K); connectorMat.setPos(start); edge.setTransformMode(UTransform::DirectMatrix); edge.setMatrix(connectorMat); edge.show(); } // ********************************************************* void CPrimRender::updateEdgeDecal(CDecal &edgeDecal, const NLMISC::CVector &start, const NLMISC::CVector &end, float distToStartVertex, float distToEndVertex) { //H_AUTO(R2_CPrimRender_updateEdgeDecal) CVector2f start2f(start.x, start.y); CVector2f end2f(end.x, end.y); // compute real start coordinate that is at 'startRadius' dist from the 'start' pos float length = (end2f - start2f).norm(); if ((distToStartVertex + distToEndVertex) >= length) { CMatrix nullMat; nullMat.setScale(0.f); // decal not visible edgeDecal.setWorldMatrix(nullMat); return; } CVector dirNormed = (end2f - start2f) / length; start2f = start2f + distToStartVertex * dirNormed; end2f = end2f - distToEndVertex * dirNormed; edgeDecal.setWorldMatrixForArrow(start2f, end2f, _Look.EdgeLook.DecalWidth); CMatrix uvMatrix; float uScale = _Look.EdgeLook.DecalUScale * (length - (distToStartVertex + distToEndVertex)); uvMatrix.setScale(CVector(uScale, 1.f, 1.f)); switch(_Look.EdgeLook.DecalWrapMode) { case CEdgeLook::Scaled: case CEdgeLook::Repeat: break; case CEdgeLook::Centered: uvMatrix.setPos(CVector(0.5f * (1.f - uScale), 0.f, 0.f)); break; default: nlassert(0); break; } edgeDecal.setTextureMatrix(uvMatrix); } // ********************************************************* void CPrimRender::addDecalsToRenderList() { //H_AUTO(R2_CPrimRender_addDecalsToRenderList) if (!_Active) return; for(uint k = 0; k < _VertexDecals.size(); ++k) { _VertexDecals[k]->addToRenderList(); } for(uint k = 0; k < _EdgeDecals.size(); ++k) { _EdgeDecals[k]->addToRenderList(); } } // ********************************************************* void CPrimRender::setWorldMapNumVertices(uint count) { //H_AUTO(R2_CPrimRender_setWorldMapNumVertices) nlassert(_AddedToWorldMap); CGroupMap *gm = CTool::getWorldMap(); nlassert(gm); if (count < _WorldMapVertices.size()) { for(uint k = count; k < _WorldMapVertices.size(); ++k) { gm->delView(_WorldMapVertices[k]); } } else { uint left = count - (uint)_WorldMapVertices.size(); while (left --) { CViewBitmap *bm = new CViewBitmap(CViewBase::TCtorParam()); bm->setModulateGlobalColor(false); bm->setPosRef(Hotspot_MM); bm->setParentPosRef(Hotspot_BL); bm->setActive(_Active); gm->addView(bm); bm->setParent(gm); bm->setRenderLayer(2); _WorldMapVertices.push_back(bm); } } _WorldMapVertices.resize(count); for(uint k = 0; k < count; ++k) { const CVertexLook &look = k == 0 ? _Look.VertexLook : _Look.FirstVertexLook; _WorldMapVertices[k]->setTexture(look.WorldMapTexture); _WorldMapVertices[k]->setColor(look.WorldMapColor); _WorldMapVertices[k]->fitTexture(); } } // ********************************************************* void CPrimRender::setWorldMapNumEdges(uint count) { //H_AUTO(R2_CPrimRender_setWorldMapNumEdges) nlassert(_AddedToWorldMap); CGroupMap *gm = CTool::getWorldMap(); nlassert(gm); if (count < _WorldMapEdges.size()) { for(uint k = count; k < _WorldMapEdges.size(); ++k) { gm->delCtrl(_WorldMapEdges[k]); } } else { uint left = count - (uint)_WorldMapEdges.size(); while (left --) { CCtrlQuad *cq = newCtrlQuad((uint)_WorldMapEdges.size()); cq->setModulateGlobalColor(false); cq->setActive(_Active); gm->addCtrl(cq); cq->setParent(gm); cq->setRenderLayer(1); _WorldMapEdges.push_back(cq); if (_WorldMapPoly) { cq->setId(_WorldMapPoly->getId() + toString("_e%d", _WorldMapEdges.size() - 1)); } } } _WorldMapEdges.resize(count); for(uint k = 0; k < count; ++k) { _WorldMapEdges[k]->setTexture(_Look.EdgeLook.WorldMapTexture); _WorldMapEdges[k]->setColorRGBA(_Look.EdgeLook.WorldMapColor); } } // ********************************************************* void CPrimRender::updateWorldMapDisplay() { //H_AUTO(R2_CPrimRender_updateWorldMapDisplay) nlassert(_AddedToWorldMap); CGroupMap *gm = CTool::getWorldMap(); nlassert(gm); this->onUpdate(*gm); } // ********************************************************* void CPrimRender::onAdd(CGroupMap &owner) { //H_AUTO(R2_CPrimRender_onAdd) nlassert(!_AddedToWorldMap); _AddedToWorldMap = true; _WorldMapPoly = newCtrlPolygon(); // TODO: create only if needed _WorldMapPoly->setParent(&owner); owner.addCtrl(_WorldMapPoly); _WorldMapPoly->setActive(false); _WorldMapPoly->setId(owner.getId() + ":" + _WorldMapPoly->getId()); for(uint k = 0; k < _WorldMapEdges.size(); ++k) { _WorldMapEdges[k]->setId(_WorldMapPoly->getId() + toString("_e%d", (int) k )); } } // ********************************************************* void CPrimRender::onRemove(CGroupMap &owner) { //H_AUTO(R2_CPrimRender_onRemove) nlassert(_AddedToWorldMap); setWorldMapNumVertices(0); setWorldMapNumEdges(0); if (_WorldMapPoly) { owner.delCtrl(_WorldMapPoly); _WorldMapPoly = NULL; } _AddedToWorldMap = false; } // ********************************************************* void CPrimRender::onPreRender(CGroupMap &/* owner */) { //H_AUTO(R2_CPrimRender_onPreRender) // no-op } // ********************************************************* void CPrimRender::onUpdate(CGroupMap &worldMap) { //H_AUTO(R2_CPrimRender_onUpdate) nlassert(_AddedToWorldMap); if (!_Look.VertexLook.WorldMapTexture.empty()) { nlassert(_Vertices.size() == _WorldMapVertices.size()); } static std::vector px; static std::vector py; px.resize(_Vertices.size()); py.resize(_Vertices.size()); for(uint k = 0; k < _Vertices.size(); ++k) { worldMap.worldToWindowSnapped(px[k], py[k], _Vertices[k]); if (!_WorldMapVertices.empty()) { _WorldMapVertices[k]->setX(px[k]); _WorldMapVertices[k]->setY(py[k]); _WorldMapVertices[k]->updateCoords(); } } if (_WorldMapPoly) { if (_Look.Shape == CPrimLook::ClosedPolyLine) { _WorldMapPoly->setActive(_Active); /*static volatile bool test1 = false; const CVector2f &origin = test1 ? worldMap.getWorldOffset() : CVector2f::Null; CVector2f ref0(0.f, 0.f); CVector2f ref1(1000.f, 1000.f); ref0 += origin; ref1 += origin; worldMap.worldToWindow(ref0, ref0); worldMap.worldToWindow(ref1, ref1); CMatrix polyMatrix; float scaleX = (ref1.x - ref0.x) * 0.001f; float scaleY = (ref1.y - ref0.y) * 0.001f; polyMatrix.setRot(CVector(scaleX, 0.f, 0.f), CVector(0.f, scaleY, 0.f), CVector::Null); polyMatrix.setPos(CVector(ref0.x - scaleX * origin.x, ref0.y - scaleY * origin.y, 0.f)); */ _WorldMapPoly->setVertices(_Vertices); //_WorldMapPoly->setMatrix(polyMatrix); //_WorldMapPoly->touch(); /* static volatile bool dumpPoly = false; if (dumpPoly) { nlwarning("================"); const std::vector &verts = _WorldMapPoly->getVertices(); for(uint k = 0; k < verts.size(); ++k) { CVector pos = _WorldMapPoly->getMatrix() * verts[k]; nlwarning("vert %d = (%.1f, %.1f, %.1f)", (int) k , pos.x, pos.y, pos.z); } dumpPoly = false; }*/ } else { _WorldMapPoly->setActive(false); } } for(uint k = 0; k < _WorldMapEdges.size(); ++k) { uint startIndex = _Look.Shape == CPrimLook::Star ? 0 : k; CVector2f start((float) px[startIndex], (float) py[startIndex]); uint nextIndex = (k + 1) % _Vertices.size(); CVector2f end((float) px[nextIndex], (float) py[nextIndex]); _WorldMapEdges[k]->setQuad(start, end, _Look.EdgeLook.WorldMapWidth); _WorldMapEdges[k]->setFiltered(_Look.EdgeLook.WorldMapFiltered); _WorldMapEdges[k]->updateCoords(); // float length = (end - start).norm(); if (_CustomWorldMapEdgeUVMatrix.On) { CUV uvs[4]; CVector startUV = _CustomWorldMapEdgeUVMatrix.Matrix * _Vertices[startIndex]; CVector endUV = _CustomWorldMapEdgeUVMatrix.Matrix * _Vertices[nextIndex]; static uint index0 = 0; static uint index1 = 3; static uint index2 = 2; static uint index3 = 1; uvs[index0] = uvs[index1] = CUV(startUV.x, startUV.y); uvs[index2] = uvs[index3] = CUV(endUV.x, endUV.y); _WorldMapEdges[k]->setCustomUVs(uvs); } else { switch(_Look.EdgeLook.WorldMapWrapMode) { case CEdgeLook::Scaled: _WorldMapEdges[k]->setPattern(0.f, 1.f, CCtrlQuad::Repeat); break; case CEdgeLook::Repeat: _WorldMapEdges[k]->setPattern(0.f, _InvWorldTextureWidth * _Look.EdgeLook.WorldMapUScale * length, CCtrlQuad::Repeat); break; case CEdgeLook::Centered: _WorldMapEdges[k]->setPattern(0.5f - 0.5f * length * _InvWorldTextureWidth * _Look.EdgeLook.WorldMapUScale, 0.5f + 0.5f * length * _InvWorldTextureWidth * _Look.EdgeLook.WorldMapUScale, CCtrlQuad::Clamp); break; default: nlassert(0); break; } } } } // ********************************************************* CViewBitmap *CPrimRender::getWorldMapVertexView(uint index) const { //H_AUTO(R2_CPrimRender_getWorldMapVertexView) if(index >= _WorldMapVertices.size()) return NULL; return _WorldMapVertices[index]; } // ********************************************************* void CPrimRender::setWorldMapPolyColor(NLMISC::CRGBA color) { //H_AUTO(R2_CPrimRender_setWorldMapPolyColor) if (_WorldMapPoly) _WorldMapPoly->setColorRGBA(color); } // ********************************************************* void CPrimRender::setActive(bool active) { //H_AUTO(R2_CPrimRender_setActive) if (active == _Active) return; for(uint k = 0; k < _WorldMapVertices.size(); ++k) { if (_WorldMapVertices[k]) _WorldMapVertices[k]->setActive(active); } for(uint k = 0; k < _WorldMapEdges.size(); ++k) { if (_WorldMapEdges[k]) _WorldMapEdges[k]->setActive(active); } if (_WorldMapPoly) _WorldMapPoly->setActive(active); _VertexShapeInstances.setActive(active); _EdgeShapeInstances.setActive(active); _Active = active; } } // R2