Merge branch '138-toggle-free-look-with-hotkey' into 'main/atys-live'
[ryzomcore.git] / nel / src / gui / ctrl_quad.cpp
blob135c1c846c415107fd70f65dd608068a843d5fb2
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 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdpch.h"
22 #include "nel/gui/ctrl_quad.h"
23 #include "nel/gui/interface_group.h"
24 #include "nel/gui/widget_manager.h"
25 #include "nel/misc/polygon.h"
27 using namespace NLMISC;
29 #ifdef DEBUG_NEW
30 #define new DEBUG_NEW
31 #endif
33 namespace NLGUI
36 // *********************************************************************************
37 CCtrlQuad::CCtrlQuad( const TCtorParam &param ) : CCtrlBase( param ), _Color(CRGBA::White),
38 _Additif(false),
39 _Filtered(true),
40 _UMin(0.f),
41 _UMax(1.f),
42 _WrapMode(Repeat)
44 setQuad(CQuad(CVector::Null, CVector::Null, CVector::Null, CVector::Null));
45 // preset uvs for real quad
46 _RealQuad.Uv0.set(0.f, 0.f);
47 _RealQuad.Uv1.set(1.f, 0.f);
48 _RealQuad.Uv2.set(1.f, 1.f);
49 _RealQuad.Uv3.set(0.f, 1.f);
52 // *********************************************************************************
53 bool CCtrlQuad::parse(xmlNodePtr /* cur */, CInterfaceGroup * /* parentGroup */)
55 nlassert(0); // NOT IMPLEMENTED (only created dynamically at this time)
56 return false;
59 // *********************************************************************************
60 void CCtrlQuad::updateCoords()
62 H_AUTO(Rz_CCtrlQuad_updateCoords)
63 CViewBase::updateCoords();
64 nlassert(_Parent);
65 // don't use _XReal && _YReal, because coords are given relative to parent
66 CVector delta((float) _Parent->getXReal(), (float) _Parent->getYReal(), 0.f);
67 _RealQuad.set(_Quad.V0 + delta, _Quad.V1 + delta, _Quad.V2 + delta, _Quad.V3 + delta);
70 // *********************************************************************************
71 void CCtrlQuad::draw()
73 H_AUTO(Rz_CCtrlQuad_draw)
74 nlassert(_Parent);
75 CViewRenderer &rVR = *CViewRenderer::getInstance();
77 CRGBA col;
78 if(getModulateGlobalColor())
80 col.modulateFromColor (_Color, CWidgetManager::getInstance()->getGlobalColorForContent());
82 else
84 col= _Color;
85 col.A = (uint8)(((sint32)col.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
88 /*if (_InheritGCAlpha)
90 // search a parent container
91 CInterfaceGroup *gr = getParent();
92 while (gr)
94 if (gr->isGroupContainer())
96 CGroupContainer *gc = static_cast<CGroupContainer *>(gr);
97 col.A = (uint8)(((sint32)col.A*((sint32)gc->getCurrentContainerAlpha()+1))>>8);
98 break;
100 gr = gr->getParent();
103 if (_UMin == 0.f && _UMax == 1.f && _WrapMode != CustomUVs)
105 // no pattern applied, can draw the quad in a single piece
106 rVR.drawQuad(_RenderLayer, _RealQuad, _TextureId, col, _Additif, _Filtered);
108 else
110 NLMISC::CQuadUV quv;
111 if (_WrapMode == Repeat)
113 if (_UMax == _UMin)
115 (CQuad &) quv = _RealQuad; // copy CQuad part
116 float u = fmodf(_UMin, 1.f);
117 quv.Uv0.set(u, 0.f);
118 quv.Uv1.set(u, 0.f);
119 quv.Uv2.set(u, 1.f);
120 quv.Uv3.set(u, 1.f);
121 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
123 else
125 // reverse corners if needed to handle case where _UVMin < _UVmax
126 NLMISC::CQuad srcQuad;
127 float umin, umax;
128 if (_UMax < _UMin)
130 umin = _UMax;
131 umax = _UMin;
132 srcQuad.V0 = _RealQuad.V1;
133 srcQuad.V1 = _RealQuad.V0;
134 srcQuad.V2 = _RealQuad.V3;
135 srcQuad.V3 = _RealQuad.V2;
137 else
139 umin = _UMin;
140 umax = _UMax;
141 srcQuad = _RealQuad;
145 float unitRatio = 1.f / fabsf(umax - umin); // ratio of the real quad delta x in screen for du = 1
146 // texture is stretched, mutiple parts needed
147 float ceilUMin = ceilf(umin);
148 float firstDeltaU = ceilUMin - umin;
149 if (firstDeltaU != 0.f)
152 // start quad
153 quv.V0 = srcQuad.V0;
154 quv.V1 = blend(srcQuad.V0, srcQuad.V1, std::min(1.f, (firstDeltaU * unitRatio)));
155 quv.V2 = blend(srcQuad.V3, srcQuad.V2, std::min(1.f, (firstDeltaU * unitRatio)));
156 quv.V3 = srcQuad.V3;
157 float lastU = std::min(umax + 1.f - ceilUMin, 1.f);
158 quv.Uv0.set(1.f - firstDeltaU, 0.f);
159 quv.Uv1.set(lastU, 0.f);
160 quv.Uv2.set(lastU, 1.f);
161 quv.Uv3.set(1.f - firstDeltaU, 1.f);
162 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
164 if (firstDeltaU * unitRatio >= 1.f) return;
167 // TODO optim: reuse of previous uv & pos ... (prb is that they are not always computed)
169 // intermediate quads
170 sint numQuads = (sint) (floorf(umax) - ceilf(umin));
172 for(sint k = 0; k < numQuads; ++k)
174 float deltaU = firstDeltaU + k;
175 // start quad
176 quv.V0 = blend(srcQuad.V0, srcQuad.V1, deltaU * unitRatio);
177 quv.V1 = blend(srcQuad.V0, srcQuad.V1, (deltaU + 1.f) * unitRatio);
178 quv.V2 = blend(srcQuad.V3, srcQuad.V2, (deltaU + 1.f) * unitRatio);
179 quv.V3 = blend(srcQuad.V3, srcQuad.V2, deltaU * unitRatio);
180 quv.Uv0.set(0.f, 0.f);
181 quv.Uv1.set(1.f, 0.f);
182 quv.Uv2.set(1.f, 1.f);
183 quv.Uv3.set(0.f, 1.f);
184 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
186 // end quad
187 float lastDeltaU = umax - floorf(umax);
188 if (lastDeltaU != 0.f)
191 // start quad
192 quv.V0 = blend(srcQuad.V1, srcQuad.V0, lastDeltaU * unitRatio);
193 quv.V1 = srcQuad.V1;
194 quv.V2 = srcQuad.V2;
195 quv.V3 = blend(srcQuad.V2, srcQuad.V3, lastDeltaU * unitRatio);
196 quv.Uv0.set(0.f, 0.f);
197 quv.Uv1.set(lastDeltaU, 0.f);
198 quv.Uv2.set(lastDeltaU, 1.f);
199 quv.Uv3.set(0.f, 1.f);
200 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
205 else if (_WrapMode == Clamp)
207 if (_UMin == _UMax)
209 (CQuad &) quv = _RealQuad; // copy CQuad part
210 // special case
211 float u = _UMin;
212 clamp(u, 0.f, 1.f);
213 quv.Uv0.set(u, 0.f);
214 quv.Uv1.set(u, 1.f);
215 quv.Uv2.set(u, 1.f);
216 quv.Uv3.set(u, 0.f);
217 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
219 else
221 NLMISC::CQuad srcQuad;
222 float umin, umax;
223 if (_UMax < _UMin)
225 umin = _UMax;
226 umax = _UMin;
227 srcQuad.V0 = _RealQuad.V1;
228 srcQuad.V1 = _RealQuad.V0;
229 srcQuad.V2 = _RealQuad.V3;
230 srcQuad.V3 = _RealQuad.V2;
232 else
234 umin = _UMin;
235 umax = _UMax;
236 srcQuad = _RealQuad;
238 float startRatio = - umin / (umax - umin); // start of unclamped u (actually (0.f - umin) / (umax - umin) )
239 if (umin < 0.f)
241 quv.V0 = srcQuad.V0;
242 quv.V1 = blend(srcQuad.V0, srcQuad.V1, std::min(1.f ,startRatio));
243 quv.V2 = blend(srcQuad.V3, srcQuad.V2, std::min(1.f ,startRatio));
244 quv.V3 = srcQuad.V3;
245 // draw first clamped part
246 quv.Uv0.set(0.f, 0.f);
247 quv.Uv1.set(0.f, 0.f);
248 quv.Uv2.set(0.f, 1.f);
249 quv.Uv3.set(0.f, 1.f);
250 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
252 if (startRatio >= 1.f) return;
253 float endRatio = (1.f - umin) / (umax - umin);
254 if (endRatio > 0.f)
256 // draw middle part if visible
257 // TODO optim: reuse of previous uv & pos ... (prb is that they are not always computed)
258 quv.V0 = blend(srcQuad.V0, srcQuad.V1, std::max(0.f , startRatio));
259 quv.V1 = blend(srcQuad.V0, srcQuad.V1, std::min(1.f , endRatio));
260 quv.V2 = blend(srcQuad.V3, srcQuad.V2, std::min(1.f , endRatio));
261 quv.V3 = blend(srcQuad.V3, srcQuad.V2, std::max(0.f , startRatio));
262 // draw first clamped part
263 quv.Uv0.set(std::max(0.f, umin), 0.f);
264 quv.Uv1.set(std::min(1.f, umax), 0.f);
265 quv.Uv2.set(std::min(1.f, umax), 1.f);
266 quv.Uv3.set(std::max(0.f, umin), 1.f);
267 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
269 if (endRatio >= 1.f) return;
270 // draw end part
271 quv.V0 = blend(srcQuad.V0, srcQuad.V1, std::max(0.f , endRatio));
272 quv.V1 = srcQuad.V1;
273 quv.V2 = srcQuad.V2;
274 quv.V3 = blend(srcQuad.V3, srcQuad.V2, std::max(0.f , endRatio));
275 // draw end clamped part
276 quv.Uv0.set(1.f, 0.f);
277 quv.Uv1.set(1.f, 0.f);
278 quv.Uv2.set(1.f, 1.f);
279 quv.Uv3.set(1.f, 1.f);
280 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
283 else
285 nlassert(_WrapMode == CustomUVs);
286 quv.V0 = _RealQuad.V0;
287 quv.V1 = _RealQuad.V1;
288 quv.V2 = _RealQuad.V2;
289 quv.V3 = _RealQuad.V3;
290 quv.Uv0 = _CustomUVs[0];
291 quv.Uv1 = _CustomUVs[1];
292 quv.Uv2 = _CustomUVs[2];
293 quv.Uv3 = _CustomUVs[3];
294 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif, _Filtered);
299 // *********************************************************************************
300 void CCtrlQuad::setAlpha(sint32 a)
302 H_AUTO(Rz_CCtrlQuad_setAlpha)
303 _Color.A = (uint8) a;
306 // *********************************************************************************
307 void CCtrlQuad::setTexture(const std::string &texName)
309 H_AUTO(Rz_CCtrlQuad_setTexture)
310 // CInterfaceManager *pIM = CInterfaceManager::getInstance();
311 // CViewRenderer &rVR = *CViewRenderer::getInstance();
312 _TextureId.setTexture(texName.c_str());
315 // *********************************************************************************
316 std::string CCtrlQuad::getTexture() const
318 H_AUTO(Rz_CCtrlQuad_getTexture)
319 CViewRenderer &rVR = *CViewRenderer::getInstance();
320 return rVR.getTextureNameFromId (_TextureId);
323 // *********************************************************************************
324 void CCtrlQuad::setQuad(const CQuad &quad)
326 H_AUTO(Rz_CCtrlQuad_setQuad)
327 float qXMin = minof(quad.V0.x, quad.V1.x, quad.V2.x, quad.V3.x);
328 float qXMax = maxof(quad.V0.x, quad.V1.x, quad.V2.x, quad.V3.x);
329 float qYMin = minof(quad.V0.y, quad.V1.y, quad.V2.y, quad.V3.y);
330 float qYMax = maxof(quad.V0.y, quad.V1.y, quad.V2.y, quad.V3.y);
331 setPosRef(Hotspot_BL);
332 setX((sint32) floorf(qXMin));
333 setY((sint32) floorf(qYMin));
334 setW((sint32) ceilf(qXMax) - getX());
335 setH((sint32) ceilf(qYMax) - getY());
336 _Quad = quad;
339 // *********************************************************************************
340 void CCtrlQuad::setQuad(const NLMISC::CVector &start, const NLMISC::CVector &end, float thickness)
342 H_AUTO(Rz_CCtrlQuad_setQuad)
343 CVector right = end - start;
344 CVector up(-right.y, right.x, 0.f);
345 up = thickness * up.normed();
346 setQuad(CQuad(start + up, end + up, end - up, start - up));
349 // *********************************************************************************
350 void CCtrlQuad::setQuad(const NLMISC::CVector &pos, float radius, float angle /*=0.f*/)
352 H_AUTO(Rz_CCtrlQuad_setQuad)
353 if (angle == 0.f)
355 setQuad(pos - radius * CVector::I, pos + radius * CVector::I, radius);
357 else
359 CVector right(radius * cosf(angle), radius * sinf(angle), 0.f);
360 setQuad(pos - right, pos + right, radius);
364 // *********************************************************************************
365 void CCtrlQuad::setQuad(const std::string &texName, const NLMISC::CVector &srcPos, float angle /*= 0.f*/, float offCenter /* = 0.f*/)
367 H_AUTO(Rz_CCtrlQuad_setQuad)
368 NLMISC::CVector pos = srcPos;
369 CViewRenderer &rVR = *CViewRenderer::getInstance();
370 sint32 w, h;
371 rVR.getTextureSizeFromId(rVR.getTextureIdFromName(texName), w, h);
372 if (angle == 0.f)
374 if (offCenter != 0.f)
376 pos.x += offCenter;
378 setQuad(pos - 0.5f * w * CVector::I, pos + 0.5f * w * CVector::I, 0.5f * h);
380 else
382 CVector unitRadius(cosf(angle), sinf(angle), 0.f);
383 CVector radius = 0.5f * w * unitRadius;
384 pos += offCenter * unitRadius;
385 setQuad(pos - radius, pos + radius, 0.5f * h);
389 // *********************************************************************************
390 void CCtrlQuad::setAdditif(bool additif)
392 H_AUTO(Rz_CCtrlQuad_setAdditif)
393 _Additif = additif;
396 // *********************************************************************************
397 void CCtrlQuad::setFiltered(bool filtered)
399 H_AUTO(Rz_CCtrlQuad_setFiltered)
400 _Filtered = filtered;
403 // *********************************************************************************
404 void CCtrlQuad::setPattern(float umin, float umax, TWrapMode wrapMode)
406 H_AUTO(Rz_CCtrlQuad_setPattern)
407 nlassert((uint) wrapMode < CustomUVs);
408 _UMin = umin;
409 _UMax = umax;
410 _WrapMode = wrapMode;
413 // *********************************************************************************
414 void CCtrlQuad::setCustomUVs(const CUV uvs[4])
416 H_AUTO(Rz_CCtrlQuad_setCustomUVs)
417 std::copy(uvs, uvs + 4, _CustomUVs );
418 _WrapMode = CustomUVs;
421 // *********************************************************************************
422 bool CCtrlQuad::handleEvent(const NLGUI::CEventDescriptor &/* event */)
424 H_AUTO(Rz_CCtrlQuad_handleEvent)
425 return false;
428 // *********************************************************************************
429 bool CCtrlQuad::contains(const NLMISC::CVector2f &pos) const
431 H_AUTO(Rz_CCtrlQuad_contains)
432 static NLMISC::CPolygon2D poly;
433 poly.Vertices.resize(4);
434 poly.Vertices[0] = _Quad.V0;
435 poly.Vertices[1] = _Quad.V1;
436 poly.Vertices[2] = _Quad.V2;
437 poly.Vertices[3] = _Quad.V3;
438 return poly.contains(pos, false);