Merge branch '138-toggle-free-look-with-hotkey' into main/gingo-test
[ryzomcore.git] / ryzom / client / src / r2 / prim_render.cpp
blob93f610377fd6ba301e15c2f35c34d77ba9ba90c6
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdpch.h"
22 #include "prim_render.h"
23 #include "tool.h"
24 #include "r2_config.h"
26 #include "nel/misc/vector_2f.h"
27 #include "nel/misc/time_nl.h"
29 #include "nel/gui/view_bitmap.h"
30 #include "nel/gui/ctrl_quad.h"
31 #include "nel/gui/ctrl_polygon.h"
32 #include "../interface_v3/interface_manager.h"
33 #include "nel/gui/view_renderer.h"
34 #include "../interface_v3/group_map.h"
36 #ifdef DEBUG_NEW
37 #define new DEBUG_NEW
38 #endif
40 using namespace NL3D;
41 using namespace NLMISC;
43 namespace R2
46 // helper function for lua init
47 void readFromLua(const CLuaObject &table, const char *key, float &dest)
49 if (table[key].isNumber()) dest = (float) table[key].toNumber();
51 void readFromLua(const CLuaObject &table, const char *key, uint &dest)
53 if (table[key].isInteger()) dest = (uint) table[key].toInteger();
55 void readFromLua(const CLuaObject &table, const char *key, std::string &dest)
57 if (table[key].isString()) dest = table[key].toString();
60 void readFromLua(const CLuaObject &table, const char *key, CStringShared &dest)
62 if (table[key].isString()) dest = table[key].toString();
65 void readFromLua(const CLuaObject &table, const char *key, bool &dest)
67 if (table[key].isBoolean()) dest = table[key].toBoolean();
69 void readFromLua(const CLuaObject &table, const char *key, CRGBA &dest)
71 if (table[key].isRGBA()) dest = table[key].toRGBA();
74 #define READ_FROM_LUA(dest) readFromLua(params, #dest, dest);
76 // *********************************************************
77 void CVertexLook::init(const CLuaObject &params)
79 //H_AUTO(R2_CVertexLook_init)
80 READ_FROM_LUA(DecalTexture);
81 READ_FROM_LUA(DecalSize);
82 READ_FROM_LUA(DecalColor);
83 READ_FROM_LUA(DecalDistToEdgeDecal);
84 READ_FROM_LUA(WorldMapTexture);
85 READ_FROM_LUA(WorldMapColor);
89 // *********************************************************
90 void CEdgeLook::init(const CLuaObject &params)
92 //H_AUTO(R2_CEdgeLook_init)
93 READ_FROM_LUA(ShapeName);
94 READ_FROM_LUA(ShapeScale);
95 READ_FROM_LUA(DecalTexture);
96 READ_FROM_LUA(DecalUScale);
97 READ_FROM_LUA(DecalWidth);
98 READ_FROM_LUA(DecalColor);
99 READ_FROM_LUA(DecalFiltered);
100 READ_FROM_LUA(WorldMapTexture);
101 READ_FROM_LUA(WorldMapWidth);
102 READ_FROM_LUA(WorldMapColor);
103 READ_FROM_LUA(WorldMapUScale);
104 READ_FROM_LUA(WorldMapFiltered);
105 uint decalWrapMode = Repeat;
106 readFromLua(params, "DecalWrapMode", decalWrapMode);
107 if (decalWrapMode < WrapModeCount) DecalWrapMode = (TWrapMode) decalWrapMode;
108 uint worldMapWrapMode = Scaled;
109 readFromLua(params, "WorldMapWrapMode", worldMapWrapMode);
110 if (worldMapWrapMode < WrapModeCount) WorldMapWrapMode = (TWrapMode) worldMapWrapMode;
113 // *********************************************************
114 bool operator ==(const CPrimLook &lhs, const CPrimLook &rhs)
116 return lhs.Shape == rhs.Shape &&
117 lhs.VertexShapeName == rhs.VertexShapeName &&
118 lhs.VertexShapeScale == rhs.VertexShapeScale &&
119 lhs.VertexLook == rhs.VertexLook &&
120 lhs.FirstVertexLook == rhs.FirstVertexLook &&
121 lhs.EdgeLook == rhs.EdgeLook &&
122 lhs.LastEdgeIsValid == rhs.LastEdgeIsValid &&
123 lhs.ClipDownFacing == rhs.ClipDownFacing;
127 // *********************************************************
128 void CPrimLook::init(const CLuaObject &params)
130 //H_AUTO(R2_CPrimLook_init)
131 if (!params.isTable())
133 nlwarning("<CPrimLook::init> parameters are not a table");
134 return;
136 // vertices
137 READ_FROM_LUA(VertexShapeName);
138 READ_FROM_LUA(VertexShapeScale);
139 VertexLook.init(params["VertexLook"]);
140 if (!params["FirstVertexLook"].isNil())
142 FirstVertexLook.init(params["FirstVertexLook"]);
144 else
146 FirstVertexLook = VertexLook;
148 EdgeLook.init(params["EdgeLook"]);
149 READ_FROM_LUA(LastEdgeIsValid);
150 READ_FROM_LUA(ClipDownFacing);
151 // enums
152 uint shape = Star;
153 readFromLua(params, "Shape", shape);
154 if (shape < ShapeCount) Shape = (TShape) shape;
158 // *********************************************************
159 void CPrimRender::setLook(const CPrimLook &look)
161 //H_AUTO(R2_CPrimRender_setLook)
162 if (look == _Look) return;
163 _Look = look;
164 if (!look.EdgeLook.WorldMapTexture.empty())
166 CInterfaceManager *im = CInterfaceManager::getInstance();
167 CViewRenderer &vr = *CViewRenderer::getInstance();
168 sint32 width, height;
169 sint32 id = vr.getTextureIdFromName(look.EdgeLook.WorldMapTexture);
170 vr.getTextureSizeFromId(id, width, height);
171 _InvWorldTextureWidth = width > 0 ? 1.f / width : 0.f;
173 update();
176 // *********************************************************
177 CPrimRender::~CPrimRender()
179 if (_AddedToWorldMap)
181 CGroupMap *gm = CTool::getWorldMap();
182 nlassert(gm);
183 this->onRemove(*gm);
185 else
187 nlassert(_WorldMapVertices.empty());
188 nlassert(_WorldMapEdges.empty());
192 // *********************************************************
193 CCtrlPolygon *CPrimRender::newCtrlPolygon() const
195 //H_AUTO(R2_CPrimRender_newCtrlPolygon)
196 class CCtrlMapPolygon : public CCtrlPolygon
198 public:
199 CCtrlMapPolygon( CViewBase::TCtorParam &param ) : CCtrlPolygon( param ){}
200 protected:
201 // from CCtrlPolygon
202 void computeScaledVertex(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src)
204 CGroupMap *gm = CTool::getWorldMap();
205 if (!gm) dest = CVector::Null;
206 else gm->worldToWindow(dest, src);
209 CViewBase::TCtorParam param;
210 return new CCtrlMapPolygon( param );
213 // *********************************************************
214 CCtrlQuad *CPrimRender::newCtrlQuad(uint /* edgeIndex */) const
216 //H_AUTO(R2_CPrimRender_newCtrlQuad)
217 CViewBase::TCtorParam param;
218 return new CCtrlQuad( param );
221 // *********************************************************
222 bool CPrimRender::contains(const NLMISC::CVector2f &pos) const
224 //H_AUTO(R2_CPrimRender_contains)
225 for(uint k = 0; k < _VertexDecals.size(); ++k)
227 if (_VertexDecals[k]->contains(pos)) return true;
229 for(uint k = 0; k < _EdgeDecals.size(); ++k)
231 if (_EdgeDecals[k]->contains(pos)) return true;
233 return false;
236 // *********************************************************
237 sint CPrimRender::isOnEdge(const NLMISC::CVector2f &pos) const
239 //H_AUTO(R2_CPrimRender_isOnEdge)
240 for(uint k = 0; k < _EdgeDecals.size(); ++k)
242 if (_EdgeDecals[k]->contains(pos)) return (sint) k;
244 return -1;
247 // *********************************************************
248 CPrimRender::CPrimRender()
250 _Emissive = CRGBA::Black;
251 _NumEdges = 0;
252 _AddedToWorldMap = false;
253 _WorldMapPoly = NULL;
254 _InvWorldTextureWidth = 0.f;
255 _Active = true;
258 // *********************************************************
259 void CPrimRender::clear()
261 //H_AUTO(R2_CPrimRender_clear)
262 setVertices(std::vector<NLMISC::CVector>());
265 // *********************************************************
266 void CPrimRender::setVertices(const std::vector<NLMISC::CVector> &vertices)
268 //H_AUTO(R2_CPrimRender_setVertices)
269 if (_Vertices.size() == vertices.size())
271 if (std::equal(vertices.begin(), vertices.end(), _Vertices.begin()))
273 return;
275 else
277 _Vertices = vertices;
278 updatePos();
279 return;
282 _Vertices = vertices;
283 update();
286 // *********************************************************
287 void CPrimRender::setVertices(const std::vector<NLMISC::CVector2f> &vertices)
289 //H_AUTO(R2_CPrimRender_setVertices)
290 std::vector<CVector> vertices3D(vertices.size());
291 for(uint k = 0; k < vertices.size(); ++k)
293 vertices3D[k] = vertices[k];
295 setVertices(vertices3D);
298 // *********************************************************
299 void CPrimRender::setCustomWorldMapEdgeUVMatrix(bool on, const NLMISC::CMatrix &matrix)
301 //H_AUTO(R2_CPrimRender_setCustomWorldMapEdgeUVMatrix)
302 if (_CustomWorldMapEdgeUVMatrix.set(on, matrix))
304 update();
308 // *********************************************************
309 void CPrimRender::setCustomDecalEdgeUVMatrix(bool on, const NLMISC::CMatrix &matrix)
311 //H_AUTO(R2_CPrimRender_setCustomDecalEdgeUVMatrix)
312 if (_CustomDecalEdgeUVMatrix.set(on, matrix))
314 update();
318 // *********************************************************
319 void CPrimRender::setEmissive(NLMISC::CRGBA color)
321 //H_AUTO(R2_CPrimRender_setEmissive)
322 if (color == _Emissive) return;
323 forceSetEmissive(color);
326 // *********************************************************
327 void CPrimRender::forceSetEmissive(NLMISC::CRGBA emissive)
329 //H_AUTO(R2_CPrimRender_forceSetEmissive)
330 _Emissive = emissive;
331 _VertexShapeInstances.setEmissive(emissive);
332 _EdgeShapeInstances.setEmissive(emissive);
333 for(uint k = 0; k < _VertexDecals.size(); ++k)
335 _VertexDecals[k]->setEmissive(emissive);
337 for(uint k = 0; k < _EdgeDecals.size(); ++k)
339 _EdgeDecals[k]->setEmissive(emissive);
343 // *********************************************************
344 void CPrimRender::update()
346 //H_AUTO(R2_CPrimRender_update)
347 ////////////
348 // RESIZE //
349 ////////////
351 // vertices
352 _VertexShapeInstances.clear();
353 if (!_Look.VertexShapeName.empty())
355 _VertexShapeInstances.setShapeName(_Look.VertexShapeName);
356 _VertexShapeInstances.resize((uint)_Vertices.size());
358 else
360 _VertexShapeInstances.clear();
363 _VertexDecals.clear();
364 if (!_Look.VertexLook.DecalTexture.empty())
366 _VertexDecals.resize(_Vertices.size());
367 for(uint k = 0; k < _Vertices.size(); ++k)
369 _VertexDecals[k] = new CDecal;
370 _VertexDecals[k]->setClipDownFacing(_Look.ClipDownFacing);
371 if (k == 0 && !_Look.FirstVertexLook.DecalTexture.empty())
373 _VertexDecals[k]->setTexture(_Look.FirstVertexLook.DecalTexture, true);
374 _VertexDecals[k]->setDiffuse(_Look.FirstVertexLook.DecalColor);
376 else
378 _VertexDecals[k]->setTexture(_Look.VertexLook.DecalTexture);
379 _VertexDecals[k]->setDiffuse(_Look.VertexLook.DecalColor);
383 //edges
384 switch(_Look.Shape)
386 case CPrimLook::Star:
387 _NumEdges = _Vertices.size() <= 1 ? 0 : (sint)_Vertices.size() - 1;
388 break;
389 case CPrimLook::PolyLine:
390 _NumEdges = _Vertices.size() <= 1 ? 0 : (sint)_Vertices.size() - 1;
391 if (!_Look.LastEdgeIsValid && _NumEdges != 0) -- _NumEdges;
392 break;
393 case CPrimLook::ClosedPolyLine:
394 _NumEdges = _Vertices.size() >= 3 ? (sint)_Vertices.size() : std::max((sint) 0, (sint) (_Vertices.size() - 1));
395 if (!_Look.LastEdgeIsValid && _NumEdges != 0) -- _NumEdges;
396 break;
397 default:
398 nlassert(0);
399 break;
402 nlassert(_NumEdges >= 0);
404 _EdgeShapeInstances.clear();
405 if (!_Look.EdgeLook.ShapeName.empty())
407 _EdgeShapeInstances.setShapeName(_Look.EdgeLook.ShapeName);
408 _EdgeShapeInstances.resize(_NumEdges);
410 else
412 _EdgeShapeInstances.clear();
415 _EdgeDecals.clear();
416 if (!_Look.EdgeLook.DecalTexture.empty())
418 _EdgeDecals.resize(_NumEdges);
419 for(sint k = 0; k < _NumEdges; ++k)
421 _EdgeDecals[k] = new CDecal;
422 _EdgeDecals[k]->setClipDownFacing(_Look.ClipDownFacing);
423 _EdgeDecals[k]->setTexture(_Look.EdgeLook.DecalTexture, _Look.EdgeLook.DecalWrapMode == CEdgeLook::Centered, true, _Look.EdgeLook.DecalFiltered);
424 _EdgeDecals[k]->setDiffuse(_Look.EdgeLook.DecalColor);
425 _EdgeDecals[k]->setCustomUVMatrix(_CustomDecalEdgeUVMatrix.On, _CustomDecalEdgeUVMatrix.Matrix);
428 //////////////////
429 // POSITIONNING //
430 //////////////////
431 updatePos();
433 forceSetEmissive(_Emissive);
436 TTime endTime = CTime::getLocalTime();
437 nlinfo("%.2f seconds for : CPrimRender::update", (endTime - _StartTime) / 1000.f);
442 // *********************************************************
443 void CPrimRender::updatePos()
445 //H_AUTO(R2_CPrimRender_updatePos)
446 // world map
447 if (_AddedToWorldMap)
449 setWorldMapNumVertices(_Look.VertexLook.WorldMapTexture.empty() ? 0 : (uint)_Vertices.size());
450 setWorldMapNumEdges(_Look.EdgeLook.WorldMapTexture.empty() ? 0 : _NumEdges);
453 if (!_Vertices.empty())
455 // edges update
456 switch(_Look.Shape)
458 case CPrimLook::Star:
460 CVector centerPos = _Vertices[0];
461 for(uint k = 1; k < _Vertices.size(); ++k)
464 if (!_EdgeShapeInstances.empty())
466 updateEdge(_EdgeShapeInstances[k - 1], centerPos, _Vertices[k]);
468 if (!_EdgeDecals.empty())
470 updateEdgeDecal(*(_EdgeDecals[k - 1]), centerPos, _Vertices[k], _Look.FirstVertexLook.DecalDistToEdgeDecal, _Look.VertexLook.DecalDistToEdgeDecal);
474 break;
475 case CPrimLook::PolyLine:
476 case CPrimLook::ClosedPolyLine:
478 for(sint k = 0; k < _NumEdges; ++k)
481 if (!_EdgeShapeInstances.empty())
483 updateEdge(_EdgeShapeInstances[k], _Vertices[k], _Vertices[(k + 1) % _Vertices.size()]);
485 if (!_EdgeDecals.empty())
487 updateEdgeDecal(*(_EdgeDecals[k]), _Vertices[k], _Vertices[(k + 1) % _Vertices.size()],
488 k == 0 ? _Look.VertexLook.DecalDistToEdgeDecal : _Look.FirstVertexLook.DecalDistToEdgeDecal,
489 _Look.VertexLook.DecalDistToEdgeDecal
494 break;
495 default:
496 nlassert(0);
497 break;
500 // update vertices
501 for(uint k = 0; k < _Vertices.size(); ++k)
503 if (!_Look.VertexShapeName.empty())
505 if (!_VertexShapeInstances[k].empty())
507 CMatrix vertexMat;
508 vertexMat.setScale(_Look.VertexShapeScale);
509 vertexMat.setPos(_Vertices[k]);
510 _VertexShapeInstances[k].setTransformMode(UTransform::DirectMatrix);
511 _VertexShapeInstances[k].setMatrix(vertexMat);
514 if (!_VertexDecals.empty())
516 _VertexDecals[k]->setWorldMatrixForSpot(CVector2f(_Vertices[k].x, _Vertices[k].y), k == 0 ? _Look.FirstVertexLook.DecalSize : _Look.VertexLook.DecalSize);
520 if (_AddedToWorldMap)
522 updateWorldMapDisplay();
526 // *********************************************************
527 void CPrimRender::updateEdge(NL3D::UInstance edge,const NLMISC::CVector &start, const NLMISC::CVector &end)
529 //H_AUTO(R2_CPrimRender_updateEdge)
530 CVector I = end - start;
531 CVector INormed = I.normed();
532 CVector K = (CVector::K - (CVector::K * INormed) * INormed).normed();
533 CVector J = K ^ INormed;
534 CMatrix connectorMat;
535 static volatile float scale =0.5f;
536 connectorMat.setRot(I, scale * J, scale * K);
537 connectorMat.setPos(start);
538 edge.setTransformMode(UTransform::DirectMatrix);
539 edge.setMatrix(connectorMat);
540 edge.show();
543 // *********************************************************
544 void CPrimRender::updateEdgeDecal(CDecal &edgeDecal, const NLMISC::CVector &start, const NLMISC::CVector &end, float distToStartVertex, float distToEndVertex)
546 //H_AUTO(R2_CPrimRender_updateEdgeDecal)
547 CVector2f start2f(start.x, start.y);
548 CVector2f end2f(end.x, end.y);
549 // compute real start coordinate that is at 'startRadius' dist from the 'start' pos
550 float length = (end2f - start2f).norm();
551 if ((distToStartVertex + distToEndVertex) >= length)
553 CMatrix nullMat;
554 nullMat.setScale(0.f);
555 // decal not visible
556 edgeDecal.setWorldMatrix(nullMat);
557 return;
559 CVector dirNormed = (end2f - start2f) / length;
560 start2f = start2f + distToStartVertex * dirNormed;
561 end2f = end2f - distToEndVertex * dirNormed;
562 edgeDecal.setWorldMatrixForArrow(start2f, end2f, _Look.EdgeLook.DecalWidth);
563 CMatrix uvMatrix;
564 float uScale = _Look.EdgeLook.DecalUScale * (length - (distToStartVertex + distToEndVertex));
565 uvMatrix.setScale(CVector(uScale, 1.f, 1.f));
566 switch(_Look.EdgeLook.DecalWrapMode)
568 case CEdgeLook::Scaled:
569 case CEdgeLook::Repeat:
570 break;
571 case CEdgeLook::Centered:
572 uvMatrix.setPos(CVector(0.5f * (1.f - uScale), 0.f, 0.f));
573 break;
574 default:
575 nlassert(0);
576 break;
578 edgeDecal.setTextureMatrix(uvMatrix);
581 // *********************************************************
582 void CPrimRender::addDecalsToRenderList()
584 //H_AUTO(R2_CPrimRender_addDecalsToRenderList)
585 if (!_Active) return;
586 for(uint k = 0; k < _VertexDecals.size(); ++k)
588 _VertexDecals[k]->addToRenderList();
590 for(uint k = 0; k < _EdgeDecals.size(); ++k)
592 _EdgeDecals[k]->addToRenderList();
596 // *********************************************************
597 void CPrimRender::setWorldMapNumVertices(uint count)
599 //H_AUTO(R2_CPrimRender_setWorldMapNumVertices)
600 nlassert(_AddedToWorldMap);
601 CGroupMap *gm = CTool::getWorldMap();
602 nlassert(gm);
603 if (count < _WorldMapVertices.size())
605 for(uint k = count; k < _WorldMapVertices.size(); ++k)
607 gm->delView(_WorldMapVertices[k]);
610 else
612 uint left = count - (uint)_WorldMapVertices.size();
613 while (left --)
615 CViewBitmap *bm = new CViewBitmap(CViewBase::TCtorParam());
616 bm->setModulateGlobalColor(false);
617 bm->setPosRef(Hotspot_MM);
618 bm->setParentPosRef(Hotspot_BL);
619 bm->setActive(_Active);
620 gm->addView(bm);
621 bm->setParent(gm);
622 bm->setRenderLayer(2);
623 _WorldMapVertices.push_back(bm);
626 _WorldMapVertices.resize(count);
627 for(uint k = 0; k < count; ++k)
629 const CVertexLook &look = k == 0 ? _Look.VertexLook : _Look.FirstVertexLook;
630 _WorldMapVertices[k]->setTexture(look.WorldMapTexture);
631 _WorldMapVertices[k]->setColor(look.WorldMapColor);
632 _WorldMapVertices[k]->fitTexture();
636 // *********************************************************
637 void CPrimRender::setWorldMapNumEdges(uint count)
639 //H_AUTO(R2_CPrimRender_setWorldMapNumEdges)
640 nlassert(_AddedToWorldMap);
641 CGroupMap *gm = CTool::getWorldMap();
642 nlassert(gm);
643 if (count < _WorldMapEdges.size())
645 for(uint k = count; k < _WorldMapEdges.size(); ++k)
647 gm->delCtrl(_WorldMapEdges[k]);
650 else
652 uint left = count - (uint)_WorldMapEdges.size();
653 while (left --)
655 CCtrlQuad *cq = newCtrlQuad((uint)_WorldMapEdges.size());
656 cq->setModulateGlobalColor(false);
657 cq->setActive(_Active);
658 gm->addCtrl(cq);
659 cq->setParent(gm);
660 cq->setRenderLayer(1);
661 _WorldMapEdges.push_back(cq);
662 if (_WorldMapPoly)
664 cq->setId(_WorldMapPoly->getId() + toString("_e%d", _WorldMapEdges.size() - 1));
668 _WorldMapEdges.resize(count);
669 for(uint k = 0; k < count; ++k)
671 _WorldMapEdges[k]->setTexture(_Look.EdgeLook.WorldMapTexture);
672 _WorldMapEdges[k]->setColorRGBA(_Look.EdgeLook.WorldMapColor);
676 // *********************************************************
677 void CPrimRender::updateWorldMapDisplay()
679 //H_AUTO(R2_CPrimRender_updateWorldMapDisplay)
680 nlassert(_AddedToWorldMap);
681 CGroupMap *gm = CTool::getWorldMap();
682 nlassert(gm);
683 this->onUpdate(*gm);
686 // *********************************************************
687 void CPrimRender::onAdd(CGroupMap &owner)
689 //H_AUTO(R2_CPrimRender_onAdd)
690 nlassert(!_AddedToWorldMap);
691 _AddedToWorldMap = true;
692 _WorldMapPoly = newCtrlPolygon(); // TODO: create only if needed
693 _WorldMapPoly->setParent(&owner);
694 owner.addCtrl(_WorldMapPoly);
695 _WorldMapPoly->setActive(false);
696 _WorldMapPoly->setId(owner.getId() + ":" + _WorldMapPoly->getId());
697 for(uint k = 0; k < _WorldMapEdges.size(); ++k)
699 _WorldMapEdges[k]->setId(_WorldMapPoly->getId() + toString("_e%d", (int) k ));
703 // *********************************************************
704 void CPrimRender::onRemove(CGroupMap &owner)
706 //H_AUTO(R2_CPrimRender_onRemove)
707 nlassert(_AddedToWorldMap);
708 setWorldMapNumVertices(0);
709 setWorldMapNumEdges(0);
710 if (_WorldMapPoly)
712 owner.delCtrl(_WorldMapPoly);
713 _WorldMapPoly = NULL;
715 _AddedToWorldMap = false;
718 // *********************************************************
719 void CPrimRender::onPreRender(CGroupMap &/* owner */)
721 //H_AUTO(R2_CPrimRender_onPreRender)
722 // no-op
725 // *********************************************************
726 void CPrimRender::onUpdate(CGroupMap &worldMap)
728 //H_AUTO(R2_CPrimRender_onUpdate)
729 nlassert(_AddedToWorldMap);
730 if (!_Look.VertexLook.WorldMapTexture.empty())
732 nlassert(_Vertices.size() == _WorldMapVertices.size());
734 static std::vector<sint32> px;
735 static std::vector<sint32> py;
736 px.resize(_Vertices.size());
737 py.resize(_Vertices.size());
738 for(uint k = 0; k < _Vertices.size(); ++k)
740 worldMap.worldToWindowSnapped(px[k], py[k], _Vertices[k]);
741 if (!_WorldMapVertices.empty())
743 _WorldMapVertices[k]->setX(px[k]);
744 _WorldMapVertices[k]->setY(py[k]);
745 _WorldMapVertices[k]->updateCoords();
748 if (_WorldMapPoly)
750 if (_Look.Shape == CPrimLook::ClosedPolyLine)
752 _WorldMapPoly->setActive(_Active);
754 /*static volatile bool test1 = false;
755 const CVector2f &origin = test1 ? worldMap.getWorldOffset() : CVector2f::Null;
757 CVector2f ref0(0.f, 0.f);
758 CVector2f ref1(1000.f, 1000.f);
759 ref0 += origin;
760 ref1 += origin;
761 worldMap.worldToWindow(ref0, ref0);
762 worldMap.worldToWindow(ref1, ref1);
764 CMatrix polyMatrix;
765 float scaleX = (ref1.x - ref0.x) * 0.001f;
766 float scaleY = (ref1.y - ref0.y) * 0.001f;
767 polyMatrix.setRot(CVector(scaleX, 0.f, 0.f),
768 CVector(0.f, scaleY, 0.f),
769 CVector::Null);
770 polyMatrix.setPos(CVector(ref0.x - scaleX * origin.x, ref0.y - scaleY * origin.y, 0.f));
772 _WorldMapPoly->setVertices(_Vertices);
773 //_WorldMapPoly->setMatrix(polyMatrix);
774 //_WorldMapPoly->touch();
777 static volatile bool dumpPoly = false;
778 if (dumpPoly)
780 nlwarning("================");
781 const std::vector<CVector> &verts = _WorldMapPoly->getVertices();
782 for(uint k = 0; k < verts.size(); ++k)
784 CVector pos = _WorldMapPoly->getMatrix() * verts[k];
785 nlwarning("vert %d = (%.1f, %.1f, %.1f)", (int) k , pos.x, pos.y, pos.z);
787 dumpPoly = false;
790 else
792 _WorldMapPoly->setActive(false);
795 for(uint k = 0; k < _WorldMapEdges.size(); ++k)
797 uint startIndex = _Look.Shape == CPrimLook::Star ? 0 : k;
798 CVector2f start((float) px[startIndex], (float) py[startIndex]);
799 uint nextIndex = (k + 1) % _Vertices.size();
800 CVector2f end((float) px[nextIndex], (float) py[nextIndex]);
801 _WorldMapEdges[k]->setQuad(start, end, _Look.EdgeLook.WorldMapWidth);
802 _WorldMapEdges[k]->setFiltered(_Look.EdgeLook.WorldMapFiltered);
803 _WorldMapEdges[k]->updateCoords();
805 float length = (end - start).norm();
806 if (_CustomWorldMapEdgeUVMatrix.On)
808 CUV uvs[4];
809 CVector startUV = _CustomWorldMapEdgeUVMatrix.Matrix * _Vertices[startIndex];
810 CVector endUV = _CustomWorldMapEdgeUVMatrix.Matrix * _Vertices[nextIndex];
811 static uint index0 = 0;
812 static uint index1 = 3;
813 static uint index2 = 2;
814 static uint index3 = 1;
815 uvs[index0] = uvs[index1] = CUV(startUV.x, startUV.y);
816 uvs[index2] = uvs[index3] = CUV(endUV.x, endUV.y);
817 _WorldMapEdges[k]->setCustomUVs(uvs);
819 else
821 switch(_Look.EdgeLook.WorldMapWrapMode)
823 case CEdgeLook::Scaled:
824 _WorldMapEdges[k]->setPattern(0.f, 1.f, CCtrlQuad::Repeat);
825 break;
826 case CEdgeLook::Repeat:
827 _WorldMapEdges[k]->setPattern(0.f, _InvWorldTextureWidth * _Look.EdgeLook.WorldMapUScale * length, CCtrlQuad::Repeat);
828 break;
829 case CEdgeLook::Centered:
830 _WorldMapEdges[k]->setPattern(0.5f - 0.5f * length * _InvWorldTextureWidth * _Look.EdgeLook.WorldMapUScale,
831 0.5f + 0.5f * length * _InvWorldTextureWidth * _Look.EdgeLook.WorldMapUScale,
832 CCtrlQuad::Clamp);
833 break;
834 default:
835 nlassert(0);
836 break;
842 // *********************************************************
843 CViewBitmap *CPrimRender::getWorldMapVertexView(uint index) const
845 //H_AUTO(R2_CPrimRender_getWorldMapVertexView)
846 if(index >= _WorldMapVertices.size()) return NULL;
847 return _WorldMapVertices[index];
850 // *********************************************************
851 void CPrimRender::setWorldMapPolyColor(NLMISC::CRGBA color)
853 //H_AUTO(R2_CPrimRender_setWorldMapPolyColor)
854 if (_WorldMapPoly) _WorldMapPoly->setColorRGBA(color);
857 // *********************************************************
858 void CPrimRender::setActive(bool active)
860 //H_AUTO(R2_CPrimRender_setActive)
861 if (active == _Active) return;
862 for(uint k = 0; k < _WorldMapVertices.size(); ++k)
864 if (_WorldMapVertices[k]) _WorldMapVertices[k]->setActive(active);
866 for(uint k = 0; k < _WorldMapEdges.size(); ++k)
868 if (_WorldMapEdges[k]) _WorldMapEdges[k]->setActive(active);
870 if (_WorldMapPoly) _WorldMapPoly->setActive(active);
871 _VertexShapeInstances.setActive(active);
872 _EdgeShapeInstances.setActive(active);
873 _Active = active;
878 } // R2