Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / gui / view_quad.cpp
blobfa52816712c06c618db7e7dda0d663a6ceba4442
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/>.
20 #include "stdpch.h"
21 #include "nel/gui/view_quad.h"
23 #include "nel/gui/interface_group.h"
24 #include "nel/gui/widget_manager.h"
26 using namespace NLMISC;
28 #ifdef DEBUG_NEW
29 #define new DEBUG_NEW
30 #endif
32 namespace NLGUI
35 // *********************************************************************************
36 CViewQuad::CViewQuad( const TCtorParam &param ) : CViewBase( param ), _Color(CRGBA::White),
37 _Additif(false),
38 _UMin(0.f),
39 _UMax(1.f),
40 _WrapMode(Repeat)
42 setQuad(CQuad(CVector::Null, CVector::Null, CVector::Null, CVector::Null));
43 // preset uvs for real quad
44 _RealQuad.Uv0.set(0.f, 0.f);
45 _RealQuad.Uv1.set(1.f, 0.f);
46 _RealQuad.Uv2.set(1.f, 1.f);
47 _RealQuad.Uv3.set(0.f, 1.f);
50 // *********************************************************************************
51 bool CViewQuad::parse(xmlNodePtr /* cur */, CInterfaceGroup * /* parentGroup */)
53 nlassert(0); // NOT IMPLEMENTED (only created dynamically at this time)
54 return false;
57 // *********************************************************************************
58 void CViewQuad::updateCoords()
60 CViewBase::updateCoords();
61 nlassert(_Parent);
62 // don't use _XReal && _YReal, because coords are given relative to parent
63 CVector delta((float) _Parent->getXReal(), (float) _Parent->getYReal(), 0.f);
64 _RealQuad.set(_Quad.V0 + delta, _Quad.V1 + delta, _Quad.V2 + delta, _Quad.V3 + delta);
67 // *********************************************************************************
68 void CViewQuad::draw()
70 nlassert(_Parent);
71 CViewRenderer &rVR = *CViewRenderer::getInstance();
73 CRGBA col;
74 if(getModulateGlobalColor())
76 col.modulateFromColor (_Color, CWidgetManager::getInstance()->getGlobalColorForContent());
78 else
80 col= _Color;
81 col.A = (uint8)(((sint32)col.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
84 /*if (_InheritGCAlpha)
86 // search a parent container
87 CInterfaceGroup *gr = getParent();
88 while (gr)
90 if (gr->isGroupContainer())
92 CGroupContainer *gc = static_cast<CGroupContainer *>(gr);
93 col.A = (uint8)(((sint32)col.A*((sint32)gc->getCurrentContainerAlpha()+1))>>8);
94 break;
96 gr = gr->getParent();
98 }*/
99 if (_UMin == 0.f && _UMax == 1.f)
101 // no pattern applied, can draw the quad in a single piece
102 rVR.drawQuad(_RenderLayer, _RealQuad, _TextureId, col, _Additif);
104 else
106 NLMISC::CQuadUV quv;
107 if (_WrapMode == Repeat)
109 if (_UMax == _UMin)
111 (CQuad &) quv = _RealQuad; // copy CQuad part
112 float u = fmodf(_UMin, 1.f);
113 quv.Uv0.set(u, 0.f);
114 quv.Uv1.set(u, 0.f);
115 quv.Uv2.set(u, 1.f);
116 quv.Uv3.set(u, 1.f);
117 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
119 else
121 // reverse corners if needed to handle case where _UVMin < _UVmax
122 NLMISC::CQuad srcQuad;
123 float umin, umax;
124 if (_UMax < _UMin)
126 umin = _UMax;
127 umax = _UMin;
128 srcQuad.V0 = _RealQuad.V1;
129 srcQuad.V1 = _RealQuad.V0;
130 srcQuad.V2 = _RealQuad.V3;
131 srcQuad.V3 = _RealQuad.V2;
133 else
135 umin = _UMin;
136 umax = _UMax;
137 srcQuad = _RealQuad;
141 float unitRatio = 1.f / fabsf(umax - umin); // ratio of the real quad delta x in screen for du = 1
142 // texture is stretched, mutiple parts needed
143 float ceilUMin = ceilf(umin);
144 float firstDeltaU = ceilUMin - umin;
145 if (firstDeltaU != 0.f)
148 // start quad
149 quv.V0 = srcQuad.V0;
150 quv.V1 = blend(srcQuad.V0, srcQuad.V1, std::min(1.f, (firstDeltaU * unitRatio)));
151 quv.V2 = blend(srcQuad.V3, srcQuad.V2, std::min(1.f, (firstDeltaU * unitRatio)));
152 quv.V3 = srcQuad.V3;
153 float lastU = std::min(umax + 1.f - ceilUMin, 1.f);
154 quv.Uv0.set(1.f - firstDeltaU, 0.f);
155 quv.Uv1.set(lastU, 0.f);
156 quv.Uv2.set(lastU, 1.f);
157 quv.Uv3.set(1.f - firstDeltaU, 1.f);
158 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
160 if (firstDeltaU * unitRatio >= 1.f) return;
163 // TODO optim: reuse of previous uv & pos ... (prb is that they are not always computed)
165 // intermediate quads
166 sint numQuads = (sint) (floorf(umax) - ceilf(umin));
168 for(sint k = 0; k < numQuads; ++k)
170 float deltaU = firstDeltaU + k;
171 // start quad
172 quv.V0 = blend(srcQuad.V0, srcQuad.V1, deltaU * unitRatio);
173 quv.V1 = blend(srcQuad.V0, srcQuad.V1, (deltaU + 1.f) * unitRatio);
174 quv.V2 = blend(srcQuad.V3, srcQuad.V2, (deltaU + 1.f) * unitRatio);
175 quv.V3 = blend(srcQuad.V3, srcQuad.V2, deltaU * unitRatio);
176 quv.Uv0.set(0.f, 0.f);
177 quv.Uv1.set(1.f, 0.f);
178 quv.Uv2.set(1.f, 1.f);
179 quv.Uv3.set(0.f, 1.f);
180 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
182 // end quad
183 float lastDeltaU = umax - floorf(umax);
184 if (lastDeltaU != 0.f)
187 // start quad
188 quv.V0 = blend(srcQuad.V1, srcQuad.V0, lastDeltaU * unitRatio);
189 quv.V1 = srcQuad.V1;
190 quv.V2 = srcQuad.V2;
191 quv.V3 = blend(srcQuad.V2, srcQuad.V3, lastDeltaU * unitRatio);
192 quv.Uv0.set(0.f, 0.f);
193 quv.Uv1.set(lastDeltaU, 0.f);
194 quv.Uv2.set(lastDeltaU, 1.f);
195 quv.Uv3.set(0.f, 1.f);
196 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
201 else
203 nlassert(_WrapMode == Clamp);
204 if (_UMin == _UMax)
206 (CQuad &) quv = _RealQuad; // copy CQuad part
207 // special case
208 float u = _UMin;
209 clamp(u, 0.f, 1.f);
210 quv.Uv0.set(u, 0.f);
211 quv.Uv1.set(u, 1.f);
212 quv.Uv2.set(u, 1.f);
213 quv.Uv3.set(u, 0.f);
214 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
216 else
218 NLMISC::CQuad srcQuad;
219 float umin, umax;
220 if (_UMax < _UMin)
222 umin = _UMax;
223 umax = _UMin;
224 srcQuad.V0 = _RealQuad.V1;
225 srcQuad.V1 = _RealQuad.V0;
226 srcQuad.V2 = _RealQuad.V3;
227 srcQuad.V3 = _RealQuad.V2;
229 else
231 umin = _UMin;
232 umax = _UMax;
233 srcQuad = _RealQuad;
235 float startRatio = - umin / (umax - umin); // start of unclamped u (actually (0.f - umin) / (umax - umin) )
236 if (umin < 0.f)
238 quv.V0 = srcQuad.V0;
239 quv.V1 = blend(srcQuad.V0, srcQuad.V1, std::min(1.f ,startRatio));
240 quv.V2 = blend(srcQuad.V3, srcQuad.V2, std::min(1.f ,startRatio));
241 quv.V3 = srcQuad.V3;
242 // draw first clamped part
243 quv.Uv0.set(0.f, 0.f);
244 quv.Uv1.set(0.f, 0.f);
245 quv.Uv2.set(0.f, 1.f);
246 quv.Uv3.set(0.f, 1.f);
247 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
249 if (startRatio >= 1.f) return;
250 float endRatio = (1.f - umin) / (umax - umin);
251 if (endRatio > 0.f)
253 // draw middle part if visible
254 // TODO optim: reuse of previous uv & pos ... (prb is that they are not always computed)
255 quv.V0 = blend(srcQuad.V0, srcQuad.V1, std::max(0.f , startRatio));
256 quv.V1 = blend(srcQuad.V0, srcQuad.V1, std::min(1.f , endRatio));
257 quv.V2 = blend(srcQuad.V3, srcQuad.V2, std::min(1.f , endRatio));
258 quv.V3 = blend(srcQuad.V3, srcQuad.V2, std::max(0.f , startRatio));
259 // draw first clamped part
260 quv.Uv0.set(std::max(0.f, umin), 0.f);
261 quv.Uv1.set(std::min(1.f, umax), 0.f);
262 quv.Uv2.set(std::min(1.f, umax), 1.f);
263 quv.Uv3.set(std::max(0.f, umin), 1.f);
264 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
266 if (endRatio >= 1.f) return;
267 // draw end part
268 quv.V0 = blend(srcQuad.V0, srcQuad.V1, std::max(0.f , endRatio));
269 quv.V1 = srcQuad.V1;
270 quv.V2 = srcQuad.V2;
271 quv.V3 = blend(srcQuad.V3, srcQuad.V2, std::max(0.f , endRatio));
272 // draw end clamped part
273 quv.Uv0.set(1.f, 0.f);
274 quv.Uv1.set(1.f, 0.f);
275 quv.Uv2.set(1.f, 1.f);
276 quv.Uv3.set(1.f, 1.f);
277 rVR.drawQuad(_RenderLayer, quv, _TextureId, col, _Additif);
283 // *********************************************************************************
284 void CViewQuad::setAlpha(sint32 a)
286 _Color.A = (uint8) a;
289 // *********************************************************************************
290 void CViewQuad::setTexture(const std::string &texName)
292 // CInterfaceManager *pIM = CInterfaceManager::getInstance();
293 // CViewRenderer &rVR = *CViewRenderer::getInstance();
294 _TextureId.setTexture(texName.c_str());
297 // *********************************************************************************
298 std::string CViewQuad::getTexture() const
300 CViewRenderer &rVR = *CViewRenderer::getInstance();
301 return rVR.getTextureNameFromId (_TextureId);
304 // *********************************************************************************
305 void CViewQuad::setQuad(const CQuad &quad)
307 float qXMin = minof(quad.V0.x, quad.V1.x, quad.V2.x, quad.V3.x);
308 float qXMax = maxof(quad.V0.x, quad.V1.x, quad.V2.x, quad.V3.x);
309 float qYMin = minof(quad.V0.y, quad.V1.y, quad.V2.y, quad.V3.y);
310 float qYMax = maxof(quad.V0.y, quad.V1.y, quad.V2.y, quad.V3.y);
311 setPosRef(Hotspot_BL);
312 setX((sint32) floorf(qXMin));
313 setY((sint32) floorf(qYMin));
314 setW((sint32) ceilf(qXMax) - getX());
315 setH((sint32) ceilf(qYMax) - getY());
316 _Quad = quad;
319 // *********************************************************************************
320 void CViewQuad::setQuad(const NLMISC::CVector &start, const NLMISC::CVector &end, float thickness)
322 CVector right = end - start;
323 CVector up(-right.y, right.x, 0.f);
324 up = thickness * up.normed();
325 setQuad(CQuad(start + up, end + up, end - up, start - up));
328 // *********************************************************************************
329 void CViewQuad::setQuad(const NLMISC::CVector &pos, float radius, float angle /*=0.f*/)
331 if (angle == 0.f)
333 setQuad(pos - radius * CVector::I, pos + radius * CVector::I, radius);
335 else
337 CVector right(radius * cosf(angle), radius * sinf(angle), 0.f);
338 setQuad(pos - right, pos + right, radius);
342 // *********************************************************************************
343 void CViewQuad::setQuad(const std::string &texName, const NLMISC::CVector &srcPos, float angle /*= 0.f*/, float offCenter /* = 0.f*/)
345 NLMISC::CVector pos = srcPos;
346 CViewRenderer &rVR = *CViewRenderer::getInstance();
347 sint32 w, h;
348 rVR.getTextureSizeFromId(rVR.getTextureIdFromName(texName), w, h);
349 if (angle == 0.f)
351 if (offCenter != 0.f)
353 pos.x += offCenter;
355 setQuad(pos - 0.5f * w * CVector::I, pos + 0.5f * w * CVector::I, 0.5f * h);
357 else
359 CVector unitRadius(cosf(angle), sinf(angle), 0.f);
360 CVector radius = 0.5f * w * unitRadius;
361 pos += offCenter * unitRadius;
362 setQuad(pos - radius, pos + radius, 0.5f * h);
366 // *********************************************************************************
367 void CViewQuad::setAdditif(bool additif)
369 _Additif = additif;
372 // *********************************************************************************
373 void CViewQuad::setPattern(float umin, float umax, TWrapMode wrapMode)
375 nlassert((uint) wrapMode < WrapModeCount);
376 _UMin = umin;
377 _UMax = umax;
378 _WrapMode = wrapMode;