// *************************************************************************** void CPatchUVLocator::build(const CPatch *patchCenter, sint edgeCenter, CPatch::CBindInfo &bindInfo) { nlassert(bindInfo.Zone); // copy basic. NB: NPatchs==0 means patchCenter is binded on a 1/X patch. _CenterPatch= const_cast<CPatch*>(patchCenter); _CenterPatchEdge= edgeCenter; _NPatchs= bindInfo.NPatchs; // set it to true. false-d if one of the neighbor patch does not have same number of tile. _SameEdgeOrder= true; // For all patchs binded to me. for(sint i=0; i<_NPatchs; i++) { // The edge of the neihbor on which we are binded. sint edgeNeighbor= bindInfo.Edge[i]; CPatch *paNeighbor= bindInfo.Next[i]; _NeighborPatch[i]= paNeighbor; // Find uvI, uvJ, uvP such that: // uvOut= uvIn.x * uvI + uvIn.y * uvJ + uvP. CVector2f &uvI= _NeighborBasis[i].UvI; CVector2f &uvJ= _NeighborBasis[i].UvJ; CVector2f &uvP= _NeighborBasis[i].UvP; // Find the basis MeToNeighbor. //============================= sint rotation= (edgeCenter - edgeNeighbor + 4) & 3; // Find scale to apply. float scX, scY; // If our neighbor edge is a vertical edge if( (edgeNeighbor&1)==0 ) { scX= 1; // Manage difference of Order at the edge. scY= (float)paNeighbor->getOrderForEdge(edgeNeighbor) / (float)patchCenter->getOrderForEdge(edgeCenter); // Manage bind on the edge. // If patchCenter is binded on a bigger if(bindInfo.MultipleBindNum!=0) scY/= bindInfo.MultipleBindNum; if(_NPatchs>1) scY*= _NPatchs; // same TileOrder on the edge?? if(scY!=1) _SameEdgeOrder= false; } else { scY= 1; // Manage difference of Order at the edge. scX= (float)paNeighbor->getOrderForEdge(edgeNeighbor) / (float)patchCenter->getOrderForEdge(edgeCenter); // Manage bind on the edge. // If patchCenter is binded on a bigger if(bindInfo.MultipleBindNum!=0) scX/= bindInfo.MultipleBindNum; if(_NPatchs>1) scX*= _NPatchs; // same TileOrder on the edge?? if(scX!=1) _SameEdgeOrder= false; } // Find rotation to apply. switch(rotation) { case 0: uvI.set(-scX, 0); uvJ.set(0, -scY); break; case 1: uvI.set(0, -scY); uvJ.set(scX, 0); break; case 2: uvI.set(scX, 0); uvJ.set(0, scY); break; case 3: uvI.set(0, scY); uvJ.set(-scX, 0); break; } // Find the position. //============================= // Find the uv coord at start of the edge, for 2 patchs. CVector2f uvCenter; CVector2f uvNeighbor; float decal; // find the uv at start of edgeCenter, + decal due to bind 1/X. float ocS= patchCenter->getOrderS(); float ocT= patchCenter->getOrderT(); // Manage Bind 1/X. if(_NPatchs>1) { // Move uvCenter, so it is near the position at start of edgeNeighbor. decal= (float)i / _NPatchs; } else decal= 0; // Manage rotation. switch(edgeCenter) { case 0: uvCenter.set(0, decal*ocT); break; case 1: uvCenter.set(decal*ocS, ocT); break; case 2: uvCenter.set(ocS, (1-decal)*ocT); break; case 3: uvCenter.set((1-decal)*ocS, 0); break; }; // find the uv at start of edgeNeighbor, + decal due to bind X/1. float onS= paNeighbor->getOrderS(); float onT= paNeighbor->getOrderT(); // Manage Bind X/1. if(bindInfo.MultipleBindNum!=0) { // Must invert the id, because of mirror.... (make a draw). sint id= (bindInfo.MultipleBindNum-1) - bindInfo.MultipleBindId; // Move uvNeighbor, so it is near the position at start of edgeCenter. decal= (float)id / bindInfo.MultipleBindNum; } else decal= 0; // Manage rotation. switch(edgeNeighbor) { case 0: uvNeighbor.set(0, (1-decal)*onT); break; case 1: uvNeighbor.set((1-decal)*onS, onT); break; case 2: uvNeighbor.set(onS, decal*onT); break; case 3: uvNeighbor.set(decal*onS, 0); break; }; // uvOut= uvIn.x * uvI + uvIn.y * uvJ + uvP. // So uvP = uvOut - uvIn.x * uvI - uvIn.y * uvJ uvP= uvNeighbor - uvCenter.x * uvI - uvCenter.y * uvJ; } }
//********************************************************************************************************* void CInstanceMapDeco::onUpdate(CGroupMap &groupMap) { //H_AUTO(R2_CInstanceMapDeco_onUpdate) if (!_Active) return; nlassert(_Instance); _GlowStarActive = false; if (!_Main || !_Over || !_OverInvalid) return; sint32 x; sint32 y; CVector2f worldPos = getWorldPos(); // if not in current map then don't disply anything CIslandCollision &col = getEditor().getIslandCollision(); R2::CScenarioEntryPoints::CCompleteIsland *currIsland = col.getCurrIslandDesc(); if (currIsland) { if (!currIsland->isIn(worldPos)) { setActive(false); return; } } groupMap.worldToWindowSnapped(x, y, getWorldPos()); _Main->setX(x); _Main->setY(y); CDisplayerVisual *vd = _Instance->getDisplayerVisual(); if (!vd) { _Over->setActive(false); _OverInvalid->setActive(false); return; } // bool closeView = _CloseTexture.empty() ? false : groupMap.getMeterPerPixel() < CV_MapEntityCloseDist.get(); // bool selected = vd->getDisplayFlag(CDisplayerVisual::FlagSelected); bool hasFocus = vd->getDisplayFlag(CDisplayerVisual::FlagHasFocus); // setTextureAndFit(closeView ? _CloseTexture : CV_MapEntitySmallTexture.get()); _Main->setColor((selected && ! closeView) ? CV_MapEntitySelectColor.get() : vd->getDisplayModeColorInMap()); // if small icon, then change the icon color directly, because no over will be displayed // if (selected || hasFocus) { // if the selection is out of the window, then draw an arrow to locate it const CVector2f &wmin = groupMap.getVisibleWorldMin(); const CVector2f &wmax = groupMap.getVisibleWorldMax(); if (worldPos.x < wmin.x || worldPos.x > wmax.x || worldPos.y < wmin.y || worldPos.y > wmax.y) { // OUT OF VISIBLE REGION CASE _Over->setActive(true); _Over->setColorRGBA(selected ? CV_MapEntitySelectColor.get() : CV_MapEntityHighlightColor.get()); // out of the visible portion, so draw an arrow instead _Over->setTexture(CV_MapEntityFarTexture.get()); // snap position to inner visible world rect CVector2f m = 0.5f * (wmin + wmax); CVector2f dir = worldPos - m; CVector2f inter; float d0; float d1; if (dir.x > 0.f) { d0 = (wmax.x - m.x) / dir.x; if (dir.y > 0.f) { d1 = (wmax.y - m.y) / dir.y; inter = m + std::min(d0, d1) * dir; } else if (dir.y < 0.f) { d1 = (wmin.y - m.y) / dir.y; inter = m + std::min(d0, d1) * dir; } else { inter.set(wmax.x, m.y); } } else if (dir.x < 0.f) { d0 = (wmin.x - m.x) / dir.x; if (dir.y > 0.f) { d1 = (wmax.y - m.y) / dir.y; inter = m + std::min(d0, d1) * dir; } else if (dir.y < 0.f) { d1 = (wmin.y - m.y) / dir.y; inter = m + std::min(d0, d1) * dir; } else { inter.set(wmin.x, m.y); } } else { if (dir.y > 0.f) { inter.set(m.x, wmax.y); } else if (dir.y < 0.f) { inter.set(m.x, wmin.y); } else { inter = m; } } float size = CV_MapEntityFarArrowSize.get(); // TMP TMP size = size; float bias = 1.f; dir.normalize(); CVector2f winInter; groupMap.worldToWindow(winInter, inter); _Over->setRenderLayer(3); _Over->setQuad(winInter - (size + bias) * dir, winInter - bias * dir, 0.5f * size); // if (_GlowStar[0]) { sint32 screenInterX, screenInterY; groupMap.windowToScreen(screenInterX, screenInterY, (sint32) winInter.x, (sint32) winInter.y); sint32 refCornerX, refCornerY; _GlowStar[0]->getParent()->getCorner(refCornerX, refCornerY, Hotspot_BL); _GlowStarPos.set((float) (screenInterX - refCornerX), (float) (screenInterY - refCornerY), 0.f); _GlowStarActive = true; } } else { // VISIBLE CASE _GlowStar[0]->setActive(false); _GlowStar[1]->setActive(false); if (closeView || hasFocus) { _Over->setActive(true); if (!closeView) { _Over->setColorRGBA(CV_MapEntitySelectColor.get()); } else { _Over->setColorRGBA(selected ? CV_MapEntitySelectColor.get() : CV_MapEntityHighlightColor.get()); } const std::string &tex = closeView ? CV_MapEntitySelectTexture.get() : CV_MapEntitySmallHighlightTexture.get(); _Over->setTexture(tex); _Over->setRenderLayer(2); _Over->setQuad(tex, CVector((float) x, (float) y, 0.f)); } else { _Over->setActive(false); } } } else { // no focus _Over->setActive(false); _GlowStar[0]->setActive(false); _GlowStar[1]->setActive(false); } // update 'quad that signal invalid pos' if (_OverInvalid->getActive()) { const std::string &tex = closeView ? CV_MapEntityInvalidTexture.get() : CV_MapEntityInvalidTextureSmall.get(); _OverInvalid->setTexture(tex); _OverInvalid->setQuad(tex, CVector((float) x, (float) y, 0.f)); } }