1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
22 #include "nel/gui/view_renderer.h"
24 #include "nel/misc/path.h"
25 #include "nel/misc/file.h"
26 #include "nel/misc/uv.h"
27 #include "nel/misc/hierarchical_timer.h"
28 #include "nel/misc/base64.h"
29 #include "nel/misc/md5.h"
31 using namespace NLMISC
;
42 CViewRenderer
* CViewRenderer::instance
= NULL
;
43 NL3D::UDriver
* CViewRenderer::driver
= NULL
;
44 NL3D::UTextContext
* CViewRenderer::textcontext
= NULL
;
45 std::set
< std::string
>* CViewRenderer::hwCursors
= NULL
;
46 float CViewRenderer::hwCursorScale
= 1.0f
;
47 CViewRenderer::TFontsList
CViewRenderer::fonts
;
49 CViewRenderer::CViewRenderer()
51 nlassert( CViewRenderer::driver
!= NULL
);
52 nlassert( CViewRenderer::textcontext
!= NULL
);
53 nlassert( CViewRenderer::hwCursors
!= NULL
);
57 CViewRenderer::~CViewRenderer()
59 for(uint i
=0;i
<VR_NUM_LAYER
;i
++)
61 delete _StringRBLayers
[i
];
62 _StringRBLayers
[i
]= NULL
;
68 CViewRenderer
* CViewRenderer::getInstance()
70 if( instance
== NULL
)
71 instance
= new CViewRenderer
;
76 * setClipWindow : set the current clipping window
77 * (this window do not inherit properties from parent or whatever)
79 void CViewRenderer::setClipWindow (sint32 x
, sint32 y
, sint32 w
, sint32 h
)
86 _XMin
= (float)_ClipX
* _OneOverScreenW
;
87 _XMax
= (float)(_ClipX
+_ClipW
) * _OneOverScreenW
;
88 _YMin
= (float)_ClipY
* _OneOverScreenH
;
89 _YMax
= (float)(_ClipY
+_ClipH
) * _OneOverScreenH
;
96 void CViewRenderer::checkNewScreenSize ()
100 driver
->getWindowSize (w
, h
);
101 // not minimized? change coords
105 if (w
!= _ScreenW
|| h
!= _ScreenH
)
110 updateInterfaceScale();
115 // Keep old coordinates (suppose resolution won't change, even if typically false wen we swithch from outgame to ingame)
120 void CViewRenderer::updateInterfaceScale()
123 _OneOverScreenW
= 1.0f
/ (float)_ScreenW
;
125 _OneOverScreenW
= 1000;
127 _OneOverScreenH
= 1.0f
/ (float)_ScreenH
;
129 _OneOverScreenH
= 1000;
131 _InterfaceScale
= _InterfaceUserScale
;
132 if (_InterfaceBaseW
> 0 && _InterfaceBaseH
> 0)
134 float wRatio
= (float)_ScreenW
/ _InterfaceBaseW
;
135 float rRatio
= (float)_ScreenH
/ _InterfaceBaseH
;
136 _InterfaceScale
*= std::min(wRatio
, rRatio
);
139 if (_InterfaceScale
!= 1.0f
)
141 _OneOverScreenW
*= _InterfaceScale
;
142 _OneOverScreenH
*= _InterfaceScale
;
144 _EffectiveScreenW
= sint(_ScreenW
/ _InterfaceScale
);
145 _EffectiveScreenH
= sint(_ScreenH
/ _InterfaceScale
);
149 _EffectiveScreenW
= _ScreenW
;
150 _EffectiveScreenH
= _ScreenH
;
156 * getScreenSize : get the screen window size
158 void CViewRenderer::getScreenSize (uint32
&w
, uint32
&h
)
160 w
= _EffectiveScreenW
;
161 h
= _EffectiveScreenH
;
167 void CViewRenderer::getScreenOOSize (float &oow
, float &ooh
)
169 oow
= _OneOverScreenW
;
170 ooh
= _OneOverScreenH
;
173 void CViewRenderer::setInterfaceScale(float scale
, sint32 width
/*=0*/, sint32 height
/*=0*/)
176 if (sint(scale
*100) > 0)
177 _InterfaceUserScale
= scale
;
179 _InterfaceUserScale
= 1.0f
;
181 _InterfaceBaseW
= width
;
182 _InterfaceBaseH
= height
;
184 updateInterfaceScale();
187 void CViewRenderer::setup()
194 _InterfaceScale
= 1.0f
;
195 _InterfaceUserScale
= 1.0f
;
201 _WFigurSeparatorTexture
= 0;
202 _FigurSeparatorTextureId
= -1;
205 _WorldSpaceTransformation
= true;
207 for(uint i
=0;i
<VR_NUM_LAYER
;i
++)
209 _StringRBLayers
[i
]= NULL
;
210 _EmptyLayer
[i
]= true;
212 _BlankGlobalTexture
= NULL
;
215 updateInterfaceScale();
220 * init: init material and string buffer
222 void CViewRenderer::init()
225 _Material
= driver
->createMaterial();
229 // Init all renderBuffer
230 for(uint i
=0;i
<VR_NUM_LAYER
;i
++)
232 _StringRBLayers
[i
]= textcontext
->createRenderBuffer();
236 void CViewRenderer::setRenderStates()
238 _Material
.setDoubleSided();
239 _Material
.setZWrite(false);
240 _Material
.setZFunc(UMaterial::always
);
241 _Material
.setBlend (true);
242 _Material
.setBlendFunc (NL3D::UMaterial::srcalpha
, NL3D::UMaterial::invsrcalpha
);
243 _Material
.setColor(CRGBA::White
);
244 _Material
.setTexture(0, NULL
);
245 _Material
.setTexture(1, NULL
);
246 _Material
.setTexture(2, NULL
);
247 _Material
.setTexture(3, NULL
);
248 _Material
.setZBias(0);
251 void CViewRenderer::release()
253 if( instance
!= NULL
)
263 * reset: reset the whole view renderer
265 void CViewRenderer::reset()
267 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
268 while (ite
!= _GlobalTextures
.end())
272 UTextureFile
*tf
= dynamic_cast<NL3D::UTextureFile
*>(ite
->Texture
);
275 driver
->deleteTextureFile (tf
);
279 UTextureMem
*tf
= dynamic_cast<NL3D::UTextureMem
*>(ite
->Texture
);
280 if (tf
) driver
->deleteTextureMem(tf
);
286 TFontsList::iterator iteFonts
= fonts
.begin();
287 while (iteFonts
!= fonts
.end())
289 driver
->deleteTextContext(iteFonts
->second
);
293 _GlobalTextures
.clear();
295 _SImageIterators
.clear();
297 _IndexesToTextureIds
.clear();
301 NL3D::UDriver
* CViewRenderer::getDriver(){
305 // ***************************************************************************
306 NL3D::UTextContext
* CViewRenderer::getTextContext(const std::string
&name
)
308 if (!name
.empty() && fonts
.count(name
) > 0)
314 // ***************************************************************************
315 bool CViewRenderer::registerFont(const std::string
&name
, const std::string
&font
)
317 nlassert(driver
!= NULL
);
319 // free existing font
320 if (fonts
.count(name
) > 0)
321 driver
->deleteTextContext(fonts
[name
]);
323 std::string fontFile
= NLMISC::startsWith(font
, "ui") ? font
: CPath::lookup(font
, false);
324 if (fontFile
.empty())
326 nlwarning("Font file '%s' not found", font
.c_str());
330 NL3D::UTextContext
*context
;
331 context
= driver
->createTextContext(fontFile
);
334 nlwarning("Cannot create a TextContext with font '%s'.", font
.c_str());
338 context
->setKeep800x600Ratio(false);
340 fonts
[name
] = context
;
345 void CViewRenderer::setTextContext(NL3D::UTextContext
*textcontext
)
347 CViewRenderer::textcontext
= textcontext
;
350 void CViewRenderer::setDriver( NL3D::UDriver
*driver
)
352 CViewRenderer::driver
= driver
;
355 // ***************************************************************************
356 void CViewRenderer::SImage::setupQuadUV(bool flipv
, uint8 rot
, CQuadColorUV
&dest
)
359 // Rotation is CW and flip is along x axis
360 // Flip is vertical flip (this means we invert all y for a constant x)
361 // The transforms are done in this order : first apply the flip (or not) and then rotate
362 static const CUV UVTab
[8][4] = {
363 { CUV(0, 0), CUV(1, 0), CUV(1, 1), CUV(0, 1) }, // rot 0, no flip
364 { CUV(1, 0), CUV(1, 1), CUV(0, 1), CUV(0, 0) }, // rot 1, no flip
365 { CUV(1, 1), CUV(0, 1), CUV(0, 0), CUV(1, 0) }, // rot 2, no flip
366 { CUV(0, 1), CUV(0, 0), CUV(1, 0), CUV(1, 1) }, // rot 3, no flip
367 { CUV(1, 0), CUV(0, 0), CUV(0, 1), CUV(1, 1) }, // rot 0, flipped
368 { CUV(0, 0), CUV(0, 1), CUV(1, 1), CUV(1, 0) }, // rot 1, flipped
369 { CUV(0, 1), CUV(1, 1), CUV(1, 0), CUV(0, 0) }, // rot 2, flipped
370 { CUV(1, 1), CUV(1, 0), CUV(0, 0), CUV(0, 1) } // rot 3, flipped
373 // Take care that the origin in the texture is top left so to get the texture in bottom-up
374 // we have to start at Max and go at Min. For left and right this is Min to Max.
376 float du
= UVMax
.U
- UVMin
.U
;
377 float dv
= UVMin
.V
- UVMax
.V
;
379 uint idx
= flipv
*4 + rot
;
381 dest
.Uv0
= CUV (UVMin
.U
+ UVTab
[idx
][0].U
* du
, UVMax
.V
+ UVTab
[idx
][0].V
* dv
);
382 dest
.Uv1
= CUV (UVMin
.U
+ UVTab
[idx
][1].U
* du
, UVMax
.V
+ UVTab
[idx
][1].V
* dv
);
383 dest
.Uv2
= CUV (UVMin
.U
+ UVTab
[idx
][2].U
* du
, UVMax
.V
+ UVTab
[idx
][2].V
* dv
);
384 dest
.Uv3
= CUV (UVMin
.U
+ UVTab
[idx
][3].U
* du
, UVMax
.V
+ UVTab
[idx
][3].V
* dv
);
386 /* // TRAP : Unrolled Version (To be tested to know if it is faster than the previous one)
392 qcoluv.Uv0.U = rI.UVMax.U; qcoluv.Uv0.V = rI.UVMax.V;
393 qcoluv.Uv1.U = rI.UVMin.U; qcoluv.Uv1.V = rI.UVMax.V;
394 qcoluv.Uv2.U = rI.UVMin.U; qcoluv.Uv2.V = rI.UVMin.V;
395 qcoluv.Uv3.U = rI.UVMax.U; qcoluv.Uv3.V = rI.UVMin.V;
398 qcoluv.Uv0.U = rI.UVMin.U; qcoluv.Uv0.V = rI.UVMax.V;
399 qcoluv.Uv1.U = rI.UVMin.U; qcoluv.Uv1.V = rI.UVMin.V;
400 qcoluv.Uv2.U = rI.UVMax.U; qcoluv.Uv2.V = rI.UVMin.V;
401 qcoluv.Uv3.U = rI.UVMax.U; qcoluv.Uv3.V = rI.UVMax.V;
404 qcoluv.Uv0.U = rI.UVMin.U; qcoluv.Uv0.V = rI.UVMin.V;
405 qcoluv.Uv1.U = rI.UVMax.U; qcoluv.Uv1.V = rI.UVMin.V;
406 qcoluv.Uv2.U = rI.UVMax.U; qcoluv.Uv2.V = rI.UVMax.V;
407 qcoluv.Uv3.U = rI.UVMin.U; qcoluv.Uv3.V = rI.UVMax.V;
410 qcoluv.Uv0.U = rI.UVMax.U; qcoluv.Uv0.V = rI.UVMin.V;
411 qcoluv.Uv1.U = rI.UVMax.U; qcoluv.Uv1.V = rI.UVMax.V;
412 qcoluv.Uv2.U = rI.UVMin.U; qcoluv.Uv2.V = rI.UVMax.V;
413 qcoluv.Uv3.U = rI.UVMin.U; qcoluv.Uv3.V = rI.UVMin.V;
422 qcoluv.Uv0.U = rI.UVMin.U; qcoluv.Uv0.V = rI.UVMax.V;
423 qcoluv.Uv1.U = rI.UVMax.U; qcoluv.Uv1.V = rI.UVMax.V;
424 qcoluv.Uv2.U = rI.UVMax.U; qcoluv.Uv2.V = rI.UVMin.V;
425 qcoluv.Uv3.U = rI.UVMin.U; qcoluv.Uv3.V = rI.UVMin.V;
428 qcoluv.Uv0.U = rI.UVMin.U; qcoluv.Uv0.V = rI.UVMin.V;
429 qcoluv.Uv1.U = rI.UVMin.U; qcoluv.Uv1.V = rI.UVMax.V;
430 qcoluv.Uv2.U = rI.UVMax.U; qcoluv.Uv2.V = rI.UVMax.V;
431 qcoluv.Uv3.U = rI.UVMax.U; qcoluv.Uv3.V = rI.UVMin.V;
434 qcoluv.Uv0.U = rI.UVMax.U; qcoluv.Uv0.V = rI.UVMin.V;
435 qcoluv.Uv1.U = rI.UVMin.U; qcoluv.Uv1.V = rI.UVMin.V;
436 qcoluv.Uv2.U = rI.UVMin.U; qcoluv.Uv2.V = rI.UVMax.V;
437 qcoluv.Uv3.U = rI.UVMax.U; qcoluv.Uv3.V = rI.UVMax.V;
440 qcoluv.Uv0.U = rI.UVMax.U; qcoluv.Uv0.V = rI.UVMax.V;
441 qcoluv.Uv1.U = rI.UVMax.U; qcoluv.Uv1.V = rI.UVMin.V;
442 qcoluv.Uv2.U = rI.UVMin.U; qcoluv.Uv2.V = rI.UVMin.V;
443 qcoluv.Uv3.U = rI.UVMin.U; qcoluv.Uv3.V = rI.UVMax.V;
449 // ***************************************************************************
452 * drawRotFlipBitmapTiled
454 void CViewRenderer::drawRotFlipBitmapTiled (sint layerId
, sint32 x
, sint32 y
, sint32 width
, sint32 height
, uint8 rot
, bool flip
,
455 sint32 nTxId
, uint tileOrigin
, const CRGBA
&col
)
457 static volatile bool draw
= true;
459 if (width
<= 0 || height
<= 0) return;
461 if (nTxId
< 0) return;
463 // Is totally clipped ?
464 if ((x
> (_ClipX
+_ClipW
)) || ((x
+width
) < _ClipX
) ||
465 (y
> (_ClipY
+_ClipH
)) || ((y
+height
) < _ClipY
))
468 SImage
&rI
= *getSImage(nTxId
);
471 // start to draw at the reference corner
472 getTextureSizeFromId (nTxId
, txw
, txh
);
474 // to avoid a division by zero crash later
475 if (txw
< 0 || txh
< 0) return;
477 if (rot
> 3) rot
= 3;
479 sint32 startX
= x
, startY
= y
;
480 sint32 stepX
= txw
, stepY
= txh
;
487 // choose new start pos & uvs depending on the reference corner
489 if (tileOrigin
& 1) // right or left ?
491 startX
= x
+ width
- txw
;
496 if (tileOrigin
& 2) // bottom or top ?
498 startY
= y
+ height
- txh
;
502 // Fit screen coordinates
504 float fStartX
= (float) startX
* _OneOverScreenW
;
505 float fStartY
= (float) startY
* _OneOverScreenH
;
506 float fStepX
= (float) stepX
* _OneOverScreenW
;
507 float fStepY
= (float) stepY
* _OneOverScreenH
;
508 float fTxW
= (float) txw
* _OneOverScreenW
;
509 float fTxH
= (float) txh
* _OneOverScreenH
;
513 qcoluv
.Color0
= qcoluv
.Color1
= qcoluv
.Color2
= qcoluv
.Color3
= col
;
514 qcoluv
.V0
.z
= qcoluv
.V1
.z
= qcoluv
.V2
.z
= qcoluv
.V3
.z
= 0;
515 rI
.setupQuadUV(flip
,rot
,qcoluv
);
517 uint numTileX
= (uint32
)((width
- 1) / txw
);
518 uint numTileY
= (uint32
)((height
- 1) / txh
);
520 float currY
= fStartY
;
522 sint32 oldClipX
= _ClipX
;
523 sint32 oldClipY
= _ClipY
;
524 sint32 oldClipW
= _ClipW
;
525 sint32 oldClipH
= _ClipH
;
526 if (x
< _ClipX
) { width
-= _ClipX
- x
; x
= _ClipX
; }
527 if (y
< _ClipY
) { height
-= _ClipY
- y
; y
= _ClipY
; }
528 if ((x
+width
) > (_ClipX
+_ClipW
)) width
-= (x
+width
) - (_ClipX
+_ClipW
);
529 if ((y
+height
) > (_ClipY
+_ClipH
)) height
-= (y
+height
) - (_ClipY
+_ClipH
);
530 setClipWindow (x
, y
, width
, height
);
532 // draw result let the clipper clip the quads
533 for(uint py
= 0; py
<= numTileY
; ++py
)
535 float currX
= fStartX
;
536 for(uint px
= 0; px
<= numTileX
; ++px
)
538 /// There is room for speedup there
540 qcoluv
.V1
.x
= currX
+ fTxW
;
541 qcoluv
.V2
.x
= currX
+ fTxW
;
546 qcoluv
.V2
.y
= currY
+ fTxH
;
547 qcoluv
.V3
.y
= currY
+ fTxH
;
549 // Is NOT totally clipped ?
550 if ( !( (qcoluv
.V0
.x
> _XMax
) || (qcoluv
.V2
.x
< _XMin
) ||
551 (qcoluv
.V0
.y
> _YMax
) || (qcoluv
.V2
.y
< _YMin
) ) )
552 putQuadInLayer (*(rI
.GlobalTexturePtr
), layerId
, qcoluv
, rot
);
559 setClipWindow (oldClipX
, oldClipY
, oldClipW
, oldClipH
);
566 void CViewRenderer::drawRotFlipBitmap (sint layerId
, float x
, float y
, float width
, float height
,
567 uint8 rot
, bool flipv
, sint32 nTxId
, const CRGBA
&col
)
569 if (width
<= 0 || height
<= 0) return;
576 float dstXmin
, dstYmin
, dstXmax
, dstYmax
;
578 // Is totally clipped ?
579 if ((x
> (_ClipX
+_ClipW
)) || ((x
+width
) < _ClipX
) ||
580 (y
> (_ClipY
+_ClipH
)) || ((y
+height
) < _ClipY
))
583 dstXmin
= (float)(x
) * _OneOverScreenW
;
584 dstYmin
= (float)(y
) * _OneOverScreenH
;
585 dstXmax
= (float)(x
+ width
) * _OneOverScreenW
;
586 dstYmax
= (float)(y
+ height
) * _OneOverScreenH
;
589 qcoluv
.V0
.set (dstXmin
, dstYmin
, 0);
590 qcoluv
.V1
.set (dstXmax
, dstYmin
, 0);
591 qcoluv
.V2
.set (dstXmax
, dstYmax
, 0);
592 qcoluv
.V3
.set (dstXmin
, dstYmax
, 0);
594 qcoluv
.Color0
= qcoluv
.Color1
= qcoluv
.Color2
= qcoluv
.Color3
= col
;
596 SImage
&rI
= *getSImage(nTxId
);
598 // Avoid switch in common case
601 qcoluv
.Uv0
.U
= rI
.UVMin
.U
; qcoluv
.Uv0
.V
= rI
.UVMax
.V
;
602 qcoluv
.Uv1
.U
= rI
.UVMax
.U
; qcoluv
.Uv1
.V
= rI
.UVMax
.V
;
603 qcoluv
.Uv2
.U
= rI
.UVMax
.U
; qcoluv
.Uv2
.V
= rI
.UVMin
.V
;
604 qcoluv
.Uv3
.U
= rI
.UVMin
.U
; qcoluv
.Uv3
.V
= rI
.UVMin
.V
;
606 // else standard case
612 rI
.setupQuadUV(flipv
, rot
, qcoluv
);
615 static volatile bool doRot
[4] = { true, true, true, true };
618 putQuadInLayer (*(rI
.GlobalTexturePtr
), layerId
, qcoluv
, rot
);
625 * sTx must be lowered !!!
627 void CViewRenderer::draw11RotFlipBitmap (sint layerId
, sint32 x
, sint32 y
, uint8 rot
, bool flipv
, sint32 nTxId
, const CRGBA
&col
)
633 getTextureSizeFromId(nTxId
, txw
, txh
);
635 drawRotFlipBitmap (layerId
, x
, y
, txw
, txh
, rot
, flipv
, nTxId
, col
);
639 inline void remapUV(CUV
&dest
, const CUV
&src
, const CUV
&min
, const CUV
&max
)
641 dest
.set(src
.U
* (max
.U
- min
.U
) + min
.U
, src
.V
* (max
.V
- min
.V
) + min
.V
);
644 void CViewRenderer::drawQuad(sint layerId
, const NLMISC::CQuadUV
&quadUV
, sint32 nTxId
, NLMISC::CRGBA col
/*=NLMISC::CRGBA(255,255,255,255)*/, bool additif
, bool filtered
)
646 nlassert(!(additif
&& !filtered
)); // not implemented yet!
649 CQuadColorUV normedQuad
;
651 normedQuad
.V0
.set(quadUV
.V0
.x
* _OneOverScreenW
, quadUV
.V0
.y
* _OneOverScreenH
, 0.f
);
652 normedQuad
.V1
.set(quadUV
.V1
.x
* _OneOverScreenW
, quadUV
.V1
.y
* _OneOverScreenH
, 0.f
);
653 normedQuad
.V2
.set(quadUV
.V2
.x
* _OneOverScreenW
, quadUV
.V2
.y
* _OneOverScreenH
, 0.f
);
654 normedQuad
.V3
.set(quadUV
.V3
.x
* _OneOverScreenW
, quadUV
.V3
.y
* _OneOverScreenH
, 0.f
);
656 float qXMin
= minof(normedQuad
.V0
.x
, normedQuad
.V1
.x
, normedQuad
.V2
.x
, normedQuad
.V3
.x
);
657 if (qXMin
> _XMax
) return;
658 float qXMax
= maxof(normedQuad
.V0
.x
, normedQuad
.V1
.x
, normedQuad
.V2
.x
, normedQuad
.V3
.x
);
659 if (qXMax
< _XMin
) return;
660 float qYMin
= minof(normedQuad
.V0
.y
, normedQuad
.V1
.y
, normedQuad
.V2
.y
, normedQuad
.V3
.y
);
661 if (qYMin
> _YMax
) return;
662 float qYMax
= maxof(normedQuad
.V0
.y
, normedQuad
.V1
.y
, normedQuad
.V2
.y
, normedQuad
.V3
.y
);
663 if (qYMax
< _YMin
) return;
668 SImage
&rImage
= *getSImage(nTxId
);
669 SGlobalTexture
>
= *(rImage
.GlobalTexturePtr
);
670 CUV
deltaUV(1.f
/ (float) gt
.Width
, 1.f
/ (float) gt
.Height
);
671 CUV cornerMin
= rImage
.UVMin
+ deltaUV
;
672 CUV cornerMax
= rImage
.UVMax
- deltaUV
;
673 remapUV(normedQuad
.Uv0
, quadUV
.Uv0
, cornerMin
, cornerMax
);
674 remapUV(normedQuad
.Uv1
, quadUV
.Uv1
, cornerMin
, cornerMax
);
675 remapUV(normedQuad
.Uv2
, quadUV
.Uv2
, cornerMin
, cornerMax
);
676 remapUV(normedQuad
.Uv3
, quadUV
.Uv3
, cornerMin
, cornerMax
);
678 // test if clipping is required
679 if (qXMin
>= _XMin
&& qYMin
>= _YMin
&& qXMax
<= _XMax
&& qYMax
<= _YMax
)
681 // not clipped, easy case
682 normedQuad
.Color0
= normedQuad
.Color1
= normedQuad
.Color2
= normedQuad
.Color3
= col
;
684 if (_WorldSpaceTransformation
)
686 worldSpaceTransformation (normedQuad
);
689 layerId
+= VR_BIAS_LAYER
;
690 nlassert(layerId
>=0 && layerId
<VR_NUM_LAYER
);
691 CLayer
&layer
= rImage
.GlobalTexturePtr
->Layers
[layerId
];
694 if (layer
.NbQuads
== layer
.Quads
.size())
695 layer
.Quads
.push_back (normedQuad
);
697 layer
.Quads
[layer
.NbQuads
] = normedQuad
;
700 else if (additif
) layer
.FilteredAdditifQuads
.push_back(normedQuad
);
701 else layer
.FilteredAlphaBlendedQuads
.push_back(normedQuad
);
702 _EmptyLayer
[layerId
]= false;
706 // Partially clipped (slowest case)
707 // Must do the clip manually
708 static const uint maxNumCorners
= 8;
710 static CVector outPos0
[maxNumCorners
];
711 static CUV outUV0
[maxNumCorners
];
712 static CVector outPos1
[maxNumCorners
];
713 static CUV outUV1
[maxNumCorners
];
715 outUV0
[0] = normedQuad
.Uv0
;
716 outUV0
[1] = normedQuad
.Uv1
;
717 outUV0
[2] = normedQuad
.Uv2
;
718 outUV0
[3] = normedQuad
.Uv3
;
720 outPos0
[0] = normedQuad
.V0
;
721 outPos0
[1] = normedQuad
.V1
;
722 outPos0
[2] = normedQuad
.V2
;
723 outPos0
[3] = normedQuad
.V3
;
725 CVector
*pPos0
= outPos0
;
726 CVector
*pPos1
= outPos1
;
735 CPlane
clipper(-1.f
, 0.f
, 0.f
, _XMin
);
736 count
= clipper
.clipPolygonBack(pPos0
, pUV0
, pPos1
, pUV1
, count
);
737 std::swap(pPos0
, pPos1
);
738 std::swap(pUV0
, pUV1
);
743 CPlane
clipper(1.f
, 0.f
, 0.f
, -_XMax
);
744 count
= clipper
.clipPolygonBack(pPos0
, pUV0
, pPos1
, pUV1
, count
);
745 std::swap(pPos0
, pPos1
);
746 std::swap(pUV0
, pUV1
);
752 CPlane
clipper(0.f
, -1.f
, 0.f
, _YMin
);
753 count
= clipper
.clipPolygonBack(pPos0
, pUV0
, pPos1
, pUV1
, count
);
754 std::swap(pPos0
, pPos1
);
755 std::swap(pUV0
, pUV1
);
760 CPlane
clipper(0.f
, 1.f
, 0.f
, -_YMax
);
761 count
= clipper
.clipPolygonBack(pPos0
, pUV0
, pPos1
, pUV1
, count
);
762 std::swap(pPos0
, pPos1
);
763 std::swap(pUV0
, pUV1
);
766 nlassert(count
<= (sint
)maxNumCorners
);
770 layerId
+= VR_BIAS_LAYER
;
771 nlassert(layerId
>=0 && layerId
<VR_NUM_LAYER
);
772 CLayer
&layer
= rImage
.GlobalTexturePtr
->Layers
[layerId
];
773 std::vector
<NLMISC::CTriangleColorUV
> *tris
;
780 tris
= additif
? &layer
.FilteredAdditifTris
: &layer
.FilteredAlphaBlendedTris
;
782 tris
->resize(tris
->size() + count
);
783 CTriangleColorUV
*lastTri
= &tris
->back() + 1;
784 CTriangleColorUV
*currTri
= lastTri
- count
;
785 const CVector
*firstPos
= pPos0
++;
786 const CUV
*firstUV
= pUV0
++;
789 currTri
->V0
= *firstPos
;
790 currTri
->V1
= *pPos0
;
791 currTri
->V2
= *(pPos0
+ 1);
792 currTri
->Color0
= col
;
793 currTri
->Color1
= col
;
794 currTri
->Color2
= col
;
795 currTri
->Uv0
= *firstUV
;
796 currTri
->Uv1
= *pUV0
;
797 currTri
->Uv2
= *(pUV0
+ 1);
803 while (currTri
!= lastTri
);
804 _EmptyLayer
[layerId
]= false;
810 void CViewRenderer::drawUnclippedTriangles(sint layerId
, const std::vector
<NLMISC::CTriangle
> &tris
, NLMISC::CRGBA col
)
812 if (tris
.empty()) return;
813 if (!_BlankGlobalTexture
) return;
814 // primary goal here is batching, so we prefer to draw the triangle with a blank texture rather than
815 // switching material and having to flush all primitives .
816 layerId
+= VR_BIAS_LAYER
;
817 nlassert(layerId
>=0 && layerId
<VR_NUM_LAYER
);
818 CLayer
&layer
= _BlankGlobalTexture
->Layers
[layerId
];
819 uint startCount
= (uint
)layer
.FilteredAlphaBlendedTris
.size();
820 layer
.FilteredAlphaBlendedTris
.resize(startCount
+ tris
.size());
821 const NLMISC::CTriangle
*src
=&tris
[0];
822 const NLMISC::CTriangle
*last
= src
+ tris
.size();
823 NLMISC::CTriangleColorUV
*dest
= &layer
.FilteredAlphaBlendedTris
[0] + startCount
;
824 _EmptyLayer
[layerId
]= false;
827 dest
->V0
.set(src
->V0
.x
* _OneOverScreenW
, src
->V0
.y
* _OneOverScreenH
, 0.f
);
828 dest
->V1
.set(src
->V1
.x
* _OneOverScreenW
, src
->V1
.y
* _OneOverScreenH
, 0.f
);
829 dest
->V2
.set(src
->V2
.x
* _OneOverScreenW
, src
->V2
.y
* _OneOverScreenH
, 0.f
);
830 static volatile bool testOpaque
= false;
833 dest
->Color0
= CRGBA::White
;
834 dest
->Color1
= CRGBA::White
;
835 dest
->Color2
= CRGBA::White
;
836 dest
->Uv0
.set(0.f
, 0.f
);
837 dest
->Uv1
.set(1.f
, 0.f
);
838 dest
->Uv2
.set(1.f
, 1.f
);
845 dest
->Uv0
= _BlankUV
;
846 dest
->Uv1
= _BlankUV
;
847 dest
->Uv2
= _BlankUV
;
858 bool CViewRenderer::loadTextures (const std::string
&textureFileName
, const std::string
&uvFileName
, bool uploadDXTC
)
862 string filename
= CPath::lookup (textureFileName
, false);
863 if (filename
.empty() )
867 if (ifTmp
.open(filename
))
868 CBitmap::loadSize (ifTmp
, gt
.Width
, gt
.Height
);
870 // extract textures scale from filename
871 // texture_interface_v3_2x.tga / texture_interface_v3_4x.tga
872 if (textureFileName
.find("_2x.") != std::string::npos
)
874 else if (textureFileName
.find("_4x.") != std::string::npos
)
877 gt
.Texture
= driver
->createTextureFile (filename
);
878 // Force to generate the texture now. This way we can extract the mouse bitmaps from it now without having to load it again.
879 // Its why we don't release it at the end, because it is likely to be uploaded soon)
880 CBitmap
*texDatas
= gt
.Texture
->generateDatas();
883 gt
.Texture
->setFilterMode(UTexture::Nearest
, UTexture::NearestMipMapOff
);
885 gt
.Texture
->setUploadFormat(UTexture::DXTC5
);
889 filename
= CPath::lookup (uvFileName
, false);
890 if (filename
.empty() )
892 if (!iFile
.open(filename
))
895 _GlobalTextures
.push_back (gt
);
897 driver
->setCursorScale( CViewRenderer::hwCursorScale
);
899 char bufTmp
[256], tgaName
[256];
902 float uvMinU
, uvMinV
, uvMaxU
, uvMaxV
;
905 iFile
.getline (bufTmp
, 256);
906 sscanf (bufTmp
, "%s %f %f %f %f", tgaName
, &uvMinU
, &uvMinV
, &uvMaxU
, &uvMaxV
); // FIXME: Return value ignored, tgaName may be uninitialized
908 image
.UVMin
.U
= uvMinU
;
909 image
.UVMin
.V
= uvMinV
;
910 image
.UVMax
.U
= uvMaxU
;
911 image
.UVMax
.V
= uvMaxV
;
912 sTGAname
= toLowerAscii(string(tgaName
));
914 string::size_type stripPng
= sTGAname
.find(".png");
915 if (stripPng
!= string::npos
)
917 sTGAname
[stripPng
+ 1] = 't';
918 sTGAname
[stripPng
+ 2] = 'g';
919 sTGAname
[stripPng
+ 3] = 'a';
922 image
.Name
= sTGAname
;
923 image
.GlobalTexturePtr
= &(_GlobalTextures
.back());
924 if (getTextureIdFromName(sTGAname
) != -1)
926 string tmp
= string("duplicate texture name in ") + textureFileName
+ "(" + sTGAname
+ ")";
927 nlwarning(tmp
.c_str());
931 sint32 textureId
= addSImage(image
);
932 //nlwarning("SIMAGE ADDED: id = %x, name = %s", textureId, image.Name.c_str());
934 _TextureMap
.insert( make_pair(image
.Name
, textureId
) );
937 // if this is a cursor texture, extract it now (supported for rgba only now, because of the blit)
938 if (texDatas
&& texDatas
->getPixelFormat() == CBitmap::RGBA
)
940 if( CViewRenderer::hwCursors
->count( image
.Name
) > 0 )
942 uint x0
= (uint
) (image
.UVMin
.U
* gt
.Width
);
943 uint y0
= (uint
) (image
.UVMin
.V
* gt
.Height
);
944 uint x1
= (uint
) (image
.UVMax
.U
* gt
.Width
);
945 uint y1
= (uint
) (image
.UVMax
.V
* gt
.Height
);
946 if (x1
!= x0
&& y1
!= y0
)
949 curs
.resize(x1
- x0
, y1
- y0
);
950 curs
.blit(*texDatas
, x0
, y0
, (x1
- x0
), (y1
- y0
), 0, 0);
951 // TODO: scaled cursors not supported
952 if (gt
.Scale
> 1.f
) {
953 curs
.resample((sint
)(curs
.getWidth() / gt
.Scale
), (sint
)(curs
.getHeight() / gt
.Scale
));
955 driver
->addCursor(image
.Name
, curs
);
961 initIndexesToTextureIds ();
962 initSystemTextures();
971 void CViewRenderer::setExternalTexture(const std::string
&sGlobalTextureName
,
972 NL3D::UTexture
*externalTexture
,
973 uint32 externalTexWidth
,
974 uint32 externalTexHeight
,
975 uint32 defaultTexWidth
,
976 uint32 defaultTexHeight
979 if (sGlobalTextureName
.empty())
981 nlwarning("Can't create aglobal texture with an empty name");
984 // Look if already existing
985 string sLwrGTName
= toLowerAscii(sGlobalTextureName
);
986 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
987 while (ite
!= _GlobalTextures
.end())
989 if (toLowerAscii(ite
->Name
) == sLwrGTName
)
993 if (ite
== _GlobalTextures
.end())
995 SGlobalTexture gtTmp
;
996 gtTmp
.FromGlobaleTexture
= true;
998 gtTmp
.Name
= sLwrGTName
;
999 _GlobalTextures
.push_back(gtTmp
);
1000 ite
= _GlobalTextures
.end();
1003 ite
->Width
= externalTexWidth
;
1004 ite
->Height
= externalTexHeight
;
1005 ite
->DefaultWidth
= defaultTexWidth
;
1006 ite
->DefaultHeight
= defaultTexHeight
;
1007 ite
->Texture
= externalTexture
;
1010 bool CViewRenderer::loadTextureFromString(CViewRenderer::SGlobalTexture
*gt
, const std::string
&data
)
1012 size_t pos
= data
.find(";base64,");
1013 if (pos
== std::string::npos
)
1015 nlwarning("Data does not have 'data:image/...;base64,...' format '%s'", data
.c_str());
1019 std::string decoded
= base64::decode(data
.substr(pos
+ 8));
1020 if (decoded
.empty())
1022 nlwarning("base64 decoding failed '%s", data
.substr(pos
+ 8).c_str());
1027 if (buf
.isReading()) buf
.invert();
1028 buf
.serialBuffer((uint8
*)(decoded
.data()), decoded
.size());
1034 gt
->Width
= gt
->DefaultWidth
= btm
.getWidth();;
1035 gt
->Height
= gt
->DefaultHeight
= btm
.getHeight();
1037 if (gt
->Width
== 0 || gt
->Height
== 0)
1039 nlwarning("Decoded image has width==0 || height==0, check image format. '%s'", data
.c_str());
1043 UTextureMem
*texture
= driver
->createTextureMem(btm
.getWidth(), btm
.getHeight(), CBitmap::RGBA
);
1046 nlwarning("Failed to create mem texture (%d,%d)", btm
.getWidth(), btm
.getHeight());
1050 memcpy(texture
->getPointer(), btm
.getPixels().getPtr(), btm
.getSize() * 4);
1051 gt
->Texture
= texture
;
1052 gt
->FromGlobaleTexture
= false;
1057 bool CViewRenderer::loadTextureFromFile(CViewRenderer::SGlobalTexture
*gt
, const std::string
&filename
)
1061 if (ifTmp
.open(filename
))
1063 CBitmap::loadSize (ifTmp
, gt
->Width
, gt
->Height
);
1064 gt
->DefaultWidth
= gt
->Width
;
1065 gt
->DefaultHeight
= gt
->Height
;
1066 if (gt
->Width
== 0 || gt
->Height
== 0)
1068 nlwarning("Failed to load the texture '%s', please check image format", filename
.c_str());
1073 gt
->Texture
= driver
->createTextureFile(filename
);
1074 gt
->FromGlobaleTexture
= false;
1079 sint32
CViewRenderer::newTextureId(const std::string
&name
)
1082 iTmp
.Name
= toLowerAscii(name
);
1083 iTmp
.UVMin
= CUV(0,0);
1084 iTmp
.UVMax
= CUV(1,1);
1086 // lookup global texture with same name
1087 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
1088 while (ite
!= _GlobalTextures
.end())
1090 std::string sText
= toLowerAscii(ite
->Name
);
1091 if (sText
== iTmp
.Name
)
1096 if (ite
== _GlobalTextures
.end())
1098 SGlobalTexture gtTmp
;
1099 gtTmp
.Name
= iTmp
.Name
;
1100 gtTmp
.FromGlobaleTexture
= false;
1101 gtTmp
.DefaultWidth
= gtTmp
.Width
= 0;
1102 gtTmp
.DefaultHeight
= gtTmp
.Height
= 0;
1103 gtTmp
.Texture
= NULL
;
1104 _GlobalTextures
.push_back(gtTmp
);
1105 ite
= _GlobalTextures
.end();
1108 iTmp
.GlobalTexturePtr
= &(*ite
);
1110 // allocate new texture id
1111 return addSImage(iTmp
);
1114 void CViewRenderer::reloadTexture(sint32 texId
, const std::string
&name
, bool uploadDXTC
, bool bReleasable
)
1116 if ((uint
)texId
>= _SImageIterators
.size())
1118 nlwarning("Invalid texture id %d, maximum is %u", texId
, _SImageIterators
.size());
1122 SImage
*sImage
= getSImage(texId
);
1123 SGlobalTexture
*gt
= sImage
->GlobalTexturePtr
;
1126 nlwarning("Unknown texture id %d (file %s)", texId
, name
.c_str());
1130 // create new global texture if previous is atlas
1131 if (gt
->FromGlobaleTexture
)
1134 TSImageList::iterator ite
= _SImages
.begin();
1135 while (ite
!= _SImages
.end() && count
!= 2)
1137 // Same global texture ?
1138 if (ite
->GlobalTexturePtr
== gt
)
1144 // create new only when atlas is used by 2+ textures
1147 SGlobalTexture gtTmp
;
1148 gtTmp
.Name
= toLowerAscii(name
);
1149 gtTmp
.FromGlobaleTexture
= false;
1150 gtTmp
.DefaultWidth
= gtTmp
.Width
= 0;
1151 gtTmp
.DefaultHeight
= gtTmp
.Height
= 0;
1152 gtTmp
.Texture
= NULL
;
1153 _GlobalTextures
.push_back(gtTmp
);
1155 TGlobalTextureList::iterator ite
= _GlobalTextures
.end();
1158 sImage
->GlobalTexturePtr
= &(*ite
);
1159 gt
= sImage
->GlobalTexturePtr
;
1163 NL3D::UTexture
*oldTexture
= gt
->Texture
;
1165 std::string sLwrGTName
;
1166 if (startsWith(name
, "data:image/"))
1168 if (!loadTextureFromString(gt
, name
))
1171 sLwrGTName
= getMD5((uint8
*)name
.c_str(), (uint32
)name
.size()).toString();
1175 sLwrGTName
= toLowerAscii(name
);
1176 std::string filename
= CPath::lookup(sLwrGTName
, false);
1177 if (filename
.empty())
1179 nlwarning("Unable to find file '%s for texture %d", name
.c_str(), texId
);
1183 if (!loadTextureFromFile(gt
, filename
))
1185 nlwarning("Unable to load texture from file '%s'", filename
.c_str());
1190 gt
->Name
= sLwrGTName
;
1191 gt
->Texture
->setFilterMode(UTexture::Nearest
, UTexture::NearestMipMapOff
);
1192 gt
->Texture
->setUploadFormat(uploadDXTC
? UTexture::DXTC5
: UTexture::Auto
);
1193 gt
->Texture
->setReleasable(bReleasable
);
1195 // release previous only after successfully loading new one
1198 UTextureFile
*tf
= dynamic_cast<NL3D::UTextureFile
*>(oldTexture
);
1201 driver
->deleteTextureFile (tf
);
1205 UTextureMem
*tf
= dynamic_cast<NL3D::UTextureMem
*>(oldTexture
);
1206 if (tf
) driver
->deleteTextureMem(tf
);
1214 sint32
CViewRenderer::createTexture (const std::string
&sGlobalTextureName
,
1223 if (sGlobalTextureName
.empty()) return -1;
1225 if (startsWith(sGlobalTextureName
, "data:image/"))
1226 return createTextureFromDataURL(sGlobalTextureName
, uploadDXTC
, bReleasable
);
1228 // Look if already existing
1229 string sLwrGTName
= toLowerAscii(sGlobalTextureName
);
1230 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
1231 while (ite
!= _GlobalTextures
.end())
1233 std::string sText
= toLowerAscii(ite
->Name
);
1234 if (sText
== sLwrGTName
)
1239 // If global texture not exists create it
1240 if (ite
== _GlobalTextures
.end())
1242 string filename
= CPath::lookup (sLwrGTName
, false);
1243 if (filename
.empty() ) return -1;
1245 SGlobalTexture gtTmp
;
1246 gtTmp
.Name
= sLwrGTName
;
1248 if (!loadTextureFromFile(>Tmp
, filename
))
1251 gtTmp
.Texture
->setFilterMode(UTexture::Nearest
, UTexture::NearestMipMapOff
);
1253 gtTmp
.Texture
->setUploadFormat(UTexture::DXTC5
);
1254 gtTmp
.Texture
->setReleasable(bReleasable
);
1256 _GlobalTextures
.push_back(gtTmp
);
1257 ite
= _GlobalTextures
.end();
1261 // Add a texture with reference to the i th global texture
1264 // Set default parameters
1266 width
= ite
->DefaultWidth
;
1268 height
= ite
->DefaultHeight
;
1270 iTmp
.Name
= sLwrGTName
;
1271 iTmp
.GlobalTexturePtr
= &(*ite
);
1272 iTmp
.UVMin
= CUV(((float)offsetX
)/ite
->Width
, ((float)offsetY
)/ite
->Height
);
1273 iTmp
.UVMax
= CUV(((float)offsetX
+width
)/ite
->Width
, ((float)offsetY
+height
)/ite
->Height
);
1274 sint32 TextID
= addSImage(iTmp
);
1275 //nlwarning("SIMAGE ADDED: id = %d, name = %s", TextID, iTmp.Name.c_str());
1277 // Insert / replace in map.
1279 //_TextureMap.insert( make_pair(iTmp.Name, TextID) );
1285 sint32
CViewRenderer::createTextureFromDataURL(const std::string
&data
, bool uploadDXTC
, bool bReleasable
)
1287 if (!startsWith(data
, "data:image/"))
1290 size_t pos
= data
.find(";base64,");
1291 if (pos
== std::string::npos
)
1293 nlwarning("Failed to parse dataURL (not base64?) '%s'", data
.c_str());
1297 std::string md5hash
= getMD5((uint8
*)data
.c_str(), (uint32
)data
.size()).toString();
1299 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
1300 while (ite
!= _GlobalTextures
.end())
1302 if (md5hash
== ite
->Name
)
1307 // If global texture not exists create it
1308 if (ite
== _GlobalTextures
.end())
1310 SGlobalTexture gtTmp
;
1311 if (!loadTextureFromString(>Tmp
, data
))
1314 gtTmp
.Name
= md5hash
;
1315 gtTmp
.Texture
->setFilterMode(UTexture::Nearest
, UTexture::NearestMipMapOff
);
1316 gtTmp
.Texture
->setReleasable(bReleasable
);
1318 gtTmp
.Texture
->setUploadFormat(UTexture::DXTC5
);
1320 _GlobalTextures
.push_back(gtTmp
);
1321 ite
= _GlobalTextures
.end();
1325 // Add a texture with reference to the i th global texture
1328 // Set default parameters
1330 iTmp
.GlobalTexturePtr
= &(*ite
);
1331 iTmp
.UVMin
= CUV(0.f
, 0.f
);
1332 iTmp
.UVMax
= CUV(1.f
, 1.f
);
1333 sint32 TextID
= addSImage(iTmp
);
1338 void CViewRenderer::updateTexturePos(const std::string
&texturefileName
, sint32 offsetX
/*=0*/, sint32 offsetY
/*=0*/, sint32 width
/*=-1*/, sint32 height
/*=-1*/)
1340 sint32 id
= getTextureIdFromName (texturefileName
);
1343 nlwarning("Unknwown texture %s, can't update pos", texturefileName
.c_str());
1346 SImage
*im
= getSImage(id
);
1348 // Set default parameters
1349 sint32 gw
= im
->GlobalTexturePtr
->Width
;
1350 sint32 gh
= im
->GlobalTexturePtr
->Height
;
1355 im
->UVMin
= CUV(((float)offsetX
)/gw
, ((float)offsetY
)/gh
);
1356 im
->UVMax
= CUV(((float)offsetX
+width
)/gw
, ((float)offsetY
+height
)/gh
);
1363 NL3D::UTexture
*CViewRenderer::getGlobalTexture(const std::string
&name
)
1365 string sLwrGTName
= NLMISC::toLowerAscii(name
);
1366 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
1367 while (ite
!= _GlobalTextures
.end())
1369 std::string sText
= NLMISC::toLowerAscii(ite
->Name
);
1370 if (sText
== sLwrGTName
)
1374 if (ite
!= _GlobalTextures
.end())
1376 return ite
->Texture
;
1384 void CViewRenderer::deleteTexture (sint32 textureId
)
1387 nlassert ((uint
)textureId
< _SImageIterators
.size());
1388 if (_SImageIterators
[textureId
] == _SImages
.end())
1390 nlwarning("Can't delete texture with name %s", getTextureNameFromId(textureId
).c_str());
1395 // Backup global texture pointer
1396 SGlobalTexture
*gt
= getSImage(textureId
)->GlobalTexturePtr
;
1398 // Erase only texture from global texture
1399 if (!(gt
->FromGlobaleTexture
))
1401 //nlwarning("Removing texture with id %d", (int) textureId);
1403 //nlwarning("SIMAGE REMOVE : id = %x, name = %s", (int) textureId, getSImage(textureId)->Name.c_str());
1406 removeSImage (textureId
);
1408 // Check if someone else use this global texture..
1409 TSImageList::iterator ite
= _SImages
.begin();
1410 while (ite
!= _SImages
.end())
1412 // Same global texture ?
1413 if (ite
->GlobalTexturePtr
== gt
)
1419 // Global texture still used ?
1420 if (ite
== _SImages
.end())
1422 //nlwarning("REMOVE GLOBAL TEXTURE : id of simage = %x", (int) textureId);
1423 // No, remove the global texture
1424 for (TGlobalTextureList::iterator iteGT
= _GlobalTextures
.begin(); iteGT
!= _GlobalTextures
.end(); iteGT
++)
1427 if (&(*iteGT
) == gt
)
1429 if (iteGT
->Texture
== NULL
)
1431 // Remove this global texture
1432 UTextureFile
*tf
= dynamic_cast<NL3D::UTextureFile
*>(iteGT
->Texture
);
1435 driver
->deleteTextureFile (tf
);
1439 UTextureMem
*tf
= dynamic_cast<NL3D::UTextureMem
*>(iteGT
->Texture
);
1440 if (tf
) driver
->deleteTextureMem(tf
);
1442 _GlobalTextures
.erase (iteGT
);
1446 // Global texture has not been found
1452 bool CViewRenderer::getTexture( NLMISC::CBitmap
&bm
, const std::string
&name
)
1454 TTextureMap::const_iterator itr
= _TextureMap
.find( name
);
1455 if( itr
== _TextureMap
.end() )
1458 sint32 id
= itr
->second
;
1459 SImage
*si
= getSImage( id
);
1460 NLMISC::CBitmap
*src
= si
->GlobalTexturePtr
->Texture
->generateDatas();
1462 if( src
->getPixelFormat() != NLMISC::CBitmap::RGBA
)
1465 uint x0
= (uint
)( si
->UVMin
.U
* si
->GlobalTexturePtr
->Width
);
1466 uint y0
= (uint
)( si
->UVMin
.V
* si
->GlobalTexturePtr
->Height
);
1467 uint x1
= (uint
)( si
->UVMax
.U
* si
->GlobalTexturePtr
->Width
);
1468 uint y1
= (uint
)( si
->UVMax
.V
* si
->GlobalTexturePtr
->Height
);
1476 bm
.resize( x1
- x0
, y1
- y0
);
1477 bm
.blit( *src
, x0
, y0
, ( x1
- x0
), ( y1
- y0
), 0, 0 );
1482 void CViewRenderer::getTextureNames( std::vector
< std::string
> &textures
)
1484 TTextureMap::const_iterator itr
= _TextureMap
.begin();
1485 while( itr
!= _TextureMap
.end() )
1487 textures
.push_back( itr
->first
);
1493 * getTextureIdFromName
1495 sint32
CViewRenderer::getTextureIdFromName (const string
&sName
) const
1500 // convert to lowCase
1501 string nameLwr
= toLowerAscii(sName
);
1503 string::size_type stripPng
= nameLwr
.find(".png");
1504 if (stripPng
!= string::npos
)
1506 nameLwr
[stripPng
+ 1] = 't';
1507 nameLwr
[stripPng
+ 2] = 'g';
1508 nameLwr
[stripPng
+ 3] = 'a';
1512 TTextureMap::const_iterator it
= _TextureMap
.find(nameLwr
);
1513 if( it
==_TextureMap
.end() )
1520 * getTextureNameFromId
1522 std::string
CViewRenderer::getTextureNameFromId (sint32 TxID
)
1524 if ((TxID
< 0) || (TxID
>= (sint32
)_SImageIterators
.size()))
1526 SImage
*img
= getSImage(TxID
);
1531 * getTextureSizeFromName
1533 void CViewRenderer::getTextureSizeFromId (sint32 id
, sint32
&width
, sint32
&height
)
1535 if ((id
< 0) || (id
>= (sint32
)_SImageIterators
.size()))
1541 SImage
&rImage
= *getSImage(id
);
1542 width
= (sint32
)(((rImage
.UVMax
.U
- rImage
.UVMin
.U
)*rImage
.GlobalTexturePtr
->Width
/ rImage
.GlobalTexturePtr
->Scale
)+0.5f
);
1543 height
= (sint32
)(((rImage
.UVMax
.V
- rImage
.UVMin
.V
)*rImage
.GlobalTexturePtr
->Height
/ rImage
.GlobalTexturePtr
->Scale
)+0.5f
);
1549 CRGBA
CViewRenderer::getTextureColor(sint32 id
, sint32 x
, sint32 y
)
1551 if ((id
< 0) || (id
>= (sint32
)_SImageIterators
.size()))
1553 return CRGBA(255,255,255);
1556 SImage
&rImage
= *getSImage(id
);
1557 SGlobalTexture
&rGT
= *rImage
.GlobalTexturePtr
;
1558 // get (possibly) scaled width/height
1559 sint32 width
, height
;
1560 getTextureSizeFromId(id
, width
, height
);
1561 if (width
== 0 || height
== 0)
1562 return CRGBA(255,255,255);
1563 float xRatio
= ((float)x
) / ((float)(width
));
1564 float yRatio
= ((float)y
) / ((float)(height
));
1565 UTexture
*pTF
= rGT
.Texture
;
1566 sint32 xConv
= (sint32
)((rImage
.UVMin
.U
+ xRatio
* (rImage
.UVMax
.U
- rImage
.UVMin
.U
))*rGT
.Width
+0.5f
);
1567 sint32 yConv
= (rGT
.Height
-1)-(sint32
)((rImage
.UVMin
.V
+ yRatio
* (rImage
.UVMax
.V
- rImage
.UVMin
.V
))*rGT
.Height
+0.5f
);
1568 return pTF
->getPixelColor(xConv
, yConv
);
1571 // ***************************************************************************
1572 sint32
CViewRenderer::getTypoTextureW(char c
)
1574 if ((c
>=0) && (c
<NumTypoChar
))
1575 return _TypoCharWs
[(uint
)c
];
1580 // ***************************************************************************
1581 sint32
CViewRenderer::getTypoTextureH(char /* c */)
1586 // ***************************************************************************
1587 sint32
CViewRenderer::getTypoTextureId(char c
)
1589 if ((c
>=0) && (c
<NumTypoChar
))
1590 return _TypoCharToTextureIds
[(uint
)c
];
1598 void CViewRenderer::flush ()
1600 H_AUTO ( RZ_Interface_ViewRenderer_flush
)
1603 for(uint layerId
=0;layerId
<VR_NUM_LAYER
;layerId
++)
1605 if(_EmptyLayer
[layerId
])
1608 // **** Run all Global Textures
1609 TGlobalTextureList::iterator ite
= _GlobalTextures
.begin();
1610 while (ite
!= _GlobalTextures
.end())
1612 // texture not loaded yet
1613 if (ite
->Texture
== NULL
)
1620 // volatile SGlobalTexture *sg = &(*ite);
1621 CLayer
&layer
= ite
->Layers
[layerId
];
1622 if(layer
.NbQuads
>0 || !layer
.Tris
.empty())
1624 // setup the global texture to material
1625 _Material
.setTexture(0, ite
->Texture
);
1627 // Special Case if _WorldSpaceTransformation and _WorldSpaceScale, enable bilinear
1628 if(_Bilinear
|| (_WorldSpaceTransformation
&& _WorldSpaceScale
))
1629 ite
->Texture
->setFilterMode(UTexture::Linear
, UTexture::LinearMipMapOff
);
1631 // draw quads and empty list
1632 if (layer
.NbQuads
!= 0)
1634 driver
->drawQuads (&(layer
.Quads
[0]), layer
.NbQuads
, _Material
);
1638 if (!layer
.Tris
.empty())
1640 driver
->drawTriangles(layer
.Tris
, _Material
);
1644 // Special Case if _WorldSpaceTransformation and _WorldSpaceScale, reset
1645 if(_Bilinear
|| (_WorldSpaceTransformation
&& _WorldSpaceScale
))
1646 ite
->Texture
->setFilterMode(UTexture::Nearest
, UTexture::NearestMipMapOff
);
1648 if (!layer
.FilteredAlphaBlendedQuads
.empty() ||
1649 !layer
.FilteredAlphaBlendedTris
.empty() ||
1650 !layer
.FilteredAdditifQuads
.empty() ||
1651 !layer
.FilteredAdditifTris
.empty())
1653 // setup the global texture to material
1654 _Material
.setTexture(0, ite
->Texture
);
1657 ite
->Texture
->setFilterMode(UTexture::Linear
, UTexture::LinearMipMapOff
);
1659 if (!layer
.FilteredAlphaBlendedQuads
.empty())
1661 driver
->drawQuads (&(layer
.FilteredAlphaBlendedQuads
[0]), (uint32
)layer
.FilteredAlphaBlendedQuads
.size(), _Material
);
1662 layer
.FilteredAlphaBlendedQuads
.clear();
1664 if (!layer
.FilteredAlphaBlendedTris
.empty())
1666 driver
->drawTriangles(layer
.FilteredAlphaBlendedTris
, _Material
);
1667 layer
.FilteredAlphaBlendedTris
.clear();
1670 if (!layer
.FilteredAdditifQuads
.empty() ||
1671 !layer
.FilteredAdditifTris
.empty())
1673 _Material
.setBlendFunc (NL3D::UMaterial::one
, NL3D::UMaterial::one
);
1674 if (!layer
.FilteredAdditifQuads
.empty())
1676 driver
->drawQuads (&(layer
.FilteredAdditifQuads
[0]), (uint32
)layer
.FilteredAdditifQuads
.size(), _Material
);
1677 layer
.FilteredAdditifQuads
.clear();
1679 if (!layer
.FilteredAdditifTris
.empty())
1681 driver
->drawTriangles(layer
.FilteredAdditifTris
, _Material
);
1682 layer
.FilteredAdditifTris
.clear();
1684 // restore alpha blend
1685 _Material
.setBlendFunc (NL3D::UMaterial::srcalpha
, NL3D::UMaterial::invsrcalpha
);
1687 ite
->Texture
->setFilterMode(UTexture::Nearest
, UTexture::NearestMipMapOff
);
1692 // **** Display Computed Strings of this layer
1693 if (_WorldSpaceTransformation
)
1694 textcontext
->flushRenderBufferUnProjected(_StringRBLayers
[layerId
], false);
1696 textcontext
->flushRenderBuffer(_StringRBLayers
[layerId
]);
1699 _EmptyLayer
[layerId
]= true;
1705 * init the map _IndexesToTextures
1707 void CViewRenderer::initIndexesToTextureIds()
1710 _IndexesToTextureIds
.clear();
1711 for (uint i
= 0; i
< 10; i
++)
1713 sprintf (buf
, "numbers_%d.tga", i
);
1714 _IndexesToTextureIds
.push_back (getTextureIdFromName(buf
));
1716 _FigurSeparatorTextureId
= getTextureIdFromName("Numbers_sep.tga");
1717 _FigurBlankId
= getTextureIdFromName("numbers_blank.tga");
1718 _BlankId
= getTextureIdFromName("blank.tga");
1720 SImage
*blank
= getSImage(_BlankId
);
1723 _BlankGlobalTexture
= blank
->GlobalTexturePtr
;
1724 _BlankUV
= 0.5f
* (blank
->UVMin
+ blank
->UVMax
);
1728 _BlankUV
.set(0.f
, 0.f
);
1733 if(_IndexesToTextureIds
[0]!=-1)
1735 getTextureSizeFromId (_IndexesToTextureIds
[0], _WFigurTexture
, _HFigurTexture
);
1737 if (_FigurSeparatorTextureId
!= -1)
1739 getTextureSizeFromId (_FigurSeparatorTextureId
, _WFigurSeparatorTexture
, _HFigurSeparatorTexture
);
1747 void CViewRenderer::initTypo()
1751 // since filename dose not support special char (?,. ....), specify a map from char to string.
1752 map
<char, string
> specialCharMap
;
1753 specialCharMap
['?']= "question";
1757 // For all supported chars (if tga exist)
1758 for (uint i
= 0; i
< NumTypoChar
; i
++)
1760 // Get the token string for this char.
1762 map
<char, string
>::iterator it
= specialCharMap
.find(i
);
1764 if(it
==specialCharMap
.end())
1770 sprintf (buf
, "typo_%s.tga", token
.c_str());
1771 sint32 id
= getTextureIdFromName(buf
);
1774 _TypoCharToTextureIds
[i
]= id
;
1776 getTextureSizeFromId (id
, w
, h
);
1782 _TypoCharToTextureIds
[i
]= -1;
1783 // simulate a space.
1793 bool CViewRenderer::needClipping (const CQuad
&q
)
1795 if ((q
.V0
.x
>= _XMin
) && (q
.V0
.y
>= _YMin
) && (q
.V2
.x
<= _XMax
) && (q
.V2
.y
<= _YMax
))
1804 void CViewRenderer::clip (CQuadColorUV
&qout
, const CQuadColorUV
&qin
, uint rot
)
1812 // must reverse U & V during clipping
1813 if (qin
.V0
.x
< _XMin
)
1815 ratio
= ((float)(_XMin
- qin
.V0
.x
))/((float)(qin
.V1
.x
- qin
.V0
.x
));
1816 qout
.V3
.x
= qout
.V0
.x
= _XMin
;
1817 qout
.Uv0
.V
+= ratio
*(qin
.Uv1
.V
-qin
.Uv0
.V
);
1818 qout
.Uv3
.V
+= ratio
*(qin
.Uv2
.V
-qin
.Uv3
.V
);
1821 if (qin
.V0
.y
< _YMin
)
1823 ratio
= ((float)(_YMin
- qin
.V0
.y
))/((float)(qin
.V3
.y
- qin
.V0
.y
));
1824 qout
.V1
.y
= qout
.V0
.y
= _YMin
;
1825 qout
.Uv0
.U
+= ratio
*(qin
.Uv3
.U
-qin
.Uv0
.U
);
1826 qout
.Uv1
.U
+= ratio
*(qin
.Uv2
.U
-qin
.Uv1
.U
);
1829 if (qin
.V2
.x
> _XMax
)
1831 ratio
= ((float)(_XMax
- qin
.V2
.x
))/((float)(qin
.V3
.x
- qin
.V2
.x
));
1832 qout
.V2
.x
= qout
.V1
.x
= _XMax
;
1833 qout
.Uv2
.V
+= ratio
*(qin
.Uv3
.V
-qin
.Uv2
.V
);
1834 qout
.Uv1
.V
+= ratio
*(qin
.Uv0
.V
-qin
.Uv1
.V
);
1837 if (qin
.V2
.y
> _YMax
)
1839 ratio
= ((float)(_YMax
- qin
.V2
.y
))/((float)(qin
.V1
.y
- qin
.V2
.y
));
1840 qout
.V2
.y
= qout
.V3
.y
= _YMax
;
1841 qout
.Uv2
.U
+= ratio
*(qin
.Uv1
.U
-qin
.Uv2
.U
);
1842 qout
.Uv3
.U
+= ratio
*(qin
.Uv0
.U
-qin
.Uv3
.U
);
1847 if (qin
.V0
.x
< _XMin
)
1849 ratio
= ((float)(_XMin
- qin
.V0
.x
))/((float)(qin
.V1
.x
- qin
.V0
.x
));
1850 qout
.V3
.x
= qout
.V0
.x
= _XMin
;
1851 qout
.Uv0
.U
+= ratio
*(qin
.Uv1
.U
-qin
.Uv0
.U
);
1852 qout
.Uv3
.U
+= ratio
*(qin
.Uv2
.U
-qin
.Uv3
.U
);
1855 if (qin
.V0
.y
< _YMin
)
1857 ratio
= ((float)(_YMin
- qin
.V0
.y
))/((float)(qin
.V3
.y
- qin
.V0
.y
));
1858 qout
.V1
.y
= qout
.V0
.y
= _YMin
;
1859 qout
.Uv0
.V
+= ratio
*(qin
.Uv3
.V
-qin
.Uv0
.V
);
1860 qout
.Uv1
.V
+= ratio
*(qin
.Uv2
.V
-qin
.Uv1
.V
);
1863 if (qin
.V2
.x
> _XMax
)
1865 ratio
= ((float)(_XMax
- qin
.V2
.x
))/((float)(qin
.V3
.x
- qin
.V2
.x
));
1866 qout
.V2
.x
= qout
.V1
.x
= _XMax
;
1867 qout
.Uv2
.U
+= ratio
*(qin
.Uv3
.U
-qin
.Uv2
.U
);
1868 qout
.Uv1
.U
+= ratio
*(qin
.Uv0
.U
-qin
.Uv1
.U
);
1871 if (qin
.V2
.y
> _YMax
)
1873 ratio
= ((float)(_YMax
- qin
.V2
.y
))/((float)(qin
.V1
.y
- qin
.V2
.y
));
1874 qout
.V2
.y
= qout
.V3
.y
= _YMax
;
1875 qout
.Uv2
.V
+= ratio
*(qin
.Uv1
.V
-qin
.Uv2
.V
);
1876 qout
.Uv3
.V
+= ratio
*(qin
.Uv0
.V
-qin
.Uv3
.V
);
1884 void CViewRenderer::clip (CQuadColorUV2
&qout
, const CQuadColorUV2
&qin
)
1890 if (qin
.V0
.x
< _XMin
)
1892 ratio
= ((float)(_XMin
- qin
.V0
.x
))/((float)(qin
.V1
.x
- qin
.V0
.x
));
1893 qout
.V3
.x
= qout
.V0
.x
= _XMin
;
1894 qout
.Uv0
.U
+= ratio
*(qin
.Uv1
.U
-qin
.Uv0
.U
);
1895 qout
.Uv3
.U
+= ratio
*(qin
.Uv2
.U
-qin
.Uv3
.U
);
1896 qout
.Uv02
.U
+= ratio
*(qin
.Uv12
.U
-qin
.Uv02
.U
);
1897 qout
.Uv32
.U
+= ratio
*(qin
.Uv22
.U
-qin
.Uv32
.U
);
1900 if (qin
.V0
.y
< _YMin
)
1902 ratio
= ((float)(_YMin
- qin
.V0
.y
))/((float)(qin
.V3
.y
- qin
.V0
.y
));
1903 qout
.V1
.y
= qout
.V0
.y
= _YMin
;
1904 qout
.Uv0
.V
+= ratio
*(qin
.Uv3
.V
-qin
.Uv0
.V
);
1905 qout
.Uv1
.V
+= ratio
*(qin
.Uv2
.V
-qin
.Uv1
.V
);
1906 qout
.Uv02
.V
+= ratio
*(qin
.Uv32
.V
-qin
.Uv02
.V
);
1907 qout
.Uv12
.V
+= ratio
*(qin
.Uv22
.V
-qin
.Uv12
.V
);
1910 if (qin
.V2
.x
> _XMax
)
1912 ratio
= ((float)(_XMax
- qin
.V2
.x
))/((float)(qin
.V3
.x
- qin
.V2
.x
));
1913 qout
.V2
.x
= qout
.V1
.x
= _XMax
;
1914 qout
.Uv2
.U
+= ratio
*(qin
.Uv3
.U
-qin
.Uv2
.U
);
1915 qout
.Uv1
.U
+= ratio
*(qin
.Uv0
.U
-qin
.Uv1
.U
);
1916 qout
.Uv22
.U
+= ratio
*(qin
.Uv32
.U
-qin
.Uv22
.U
);
1917 qout
.Uv12
.U
+= ratio
*(qin
.Uv02
.U
-qin
.Uv12
.U
);
1920 if (qin
.V2
.y
> _YMax
)
1922 ratio
= ((float)(_YMax
- qin
.V2
.y
))/((float)(qin
.V1
.y
- qin
.V2
.y
));
1923 qout
.V2
.y
= qout
.V3
.y
= _YMax
;
1924 qout
.Uv2
.V
+= ratio
*(qin
.Uv1
.V
-qin
.Uv2
.V
);
1925 qout
.Uv3
.V
+= ratio
*(qin
.Uv0
.V
-qin
.Uv3
.V
);
1926 qout
.Uv22
.V
+= ratio
*(qin
.Uv12
.V
-qin
.Uv22
.V
);
1927 qout
.Uv32
.V
+= ratio
*(qin
.Uv02
.V
-qin
.Uv32
.V
);
1932 // ***************************************************************************
1934 * putQuadInLayer : put a quad in a specific layer of a specific texture
1936 void CViewRenderer::putQuadInLayer (SGlobalTexture
>
, sint layerId
, const NLMISC::CQuadColorUV
&qcoluv
, uint rot
)
1938 layerId
+= VR_BIAS_LAYER
;
1939 nlassert(layerId
>=0 && layerId
<VR_NUM_LAYER
);
1940 CLayer
&layer
= gt
.Layers
[layerId
];
1943 if (!needClipping(qcoluv
))
1945 // World space transformation
1946 if (_WorldSpaceTransformation
)
1948 NLMISC::CQuadColorUV qcolor
= qcoluv
;
1949 worldSpaceTransformation (qcolor
);
1951 // No need to clip the quad
1952 if (layer
.NbQuads
== layer
.Quads
.size())
1953 layer
.Quads
.push_back (qcolor
);
1955 layer
.Quads
[layer
.NbQuads
] = qcolor
;
1959 // No need to clip the quad
1960 if (layer
.NbQuads
== layer
.Quads
.size())
1961 layer
.Quads
.push_back (qcoluv
);
1963 layer
.Quads
[layer
.NbQuads
] = qcoluv
;
1970 CQuadColorUV qclipped
;
1971 clip (qclipped
, qcoluv
, rot
);
1973 // World space transformation
1974 if (_WorldSpaceTransformation
)
1975 worldSpaceTransformation (qclipped
);
1977 if (layer
.NbQuads
== layer
.Quads
.size())
1978 layer
.Quads
.push_back (qclipped
);
1980 layer
.Quads
[layer
.NbQuads
] = qclipped
;
1985 _EmptyLayer
[layerId
]= false;
1989 // ***************************************************************************
1990 void CViewRenderer::addSystemTexture(TSystemTexture e
, const char *s
)
1992 _SystemTextures
[e
].Id
= getTextureIdFromName(s
);
1993 if(_SystemTextures
[e
].Id
!=-1)
1995 getTextureSizeFromId(_SystemTextures
[e
].Id
, _SystemTextures
[e
].W
, _SystemTextures
[e
].H
);
1999 // ***************************************************************************
2000 void CViewRenderer::initSystemTextures()
2002 addSystemTexture(QuantityCrossTexture
, "w_quantity.tga");
2003 addSystemTexture(DefaultBrickTexture
, "brick_default.tga");
2004 addSystemTexture(DefaultItemTexture
, "item_default.tga");
2005 addSystemTexture(ItemPlanTexture
, "item_plan_over.tga");
2006 addSystemTexture(SkillTexture
, "skill.tga");
2007 addSystemTexture(ItemEnchantedTexture
, "sapload.tga");
2008 addSystemTexture(DragCopyTexture
, "W_copy.tga");
2009 addSystemTexture(ItemWornedTexture
, "ico_task_failed.tga");
2010 addSystemTexture(OutOfRangeTexture
, "ico_out_of_range.tga");
2011 addSystemTexture(RegenTexture
, "regen.tga");
2012 addSystemTexture(RegenBackTexture
, "regen_back.tga");
2013 addSystemTexture(GlowStarTexture
, "glow_star_24.tga");
2014 addSystemTexture(ItemLockedByOwnerTexture
, "r2ed_toolbar_lock_small.tga");
2018 // ***************************************************************************
2019 URenderStringBuffer
*CViewRenderer::getStringRenderBuffer(sint layerId
)
2021 layerId
+= VR_BIAS_LAYER
;
2022 nlassert(layerId
>=0 && layerId
<VR_NUM_LAYER
);
2024 return _StringRBLayers
[layerId
];
2027 // ***************************************************************************
2028 void CViewRenderer::drawWiredQuad(sint32 x
, sint32 y
, sint32 width
, sint32 height
, NLMISC::CRGBA col
/*=NLMISC::CRGBA::White*/)
2030 driver
->drawWiredQuad(x
* _OneOverScreenW
, y
* _OneOverScreenH
, (x
+ width
) * _OneOverScreenW
, (y
+ height
) * _OneOverScreenH
, col
);
2033 // ***************************************************************************
2034 void CViewRenderer::drawFilledQuad(sint32 x
, sint32 y
, sint32 width
, sint32 height
, NLMISC::CRGBA col
/*=NLMISC::CRGBA::White*/)
2036 driver
->drawQuad(x
* _OneOverScreenW
, y
* _OneOverScreenH
, (x
+ width
) * _OneOverScreenW
, (y
+ height
) * _OneOverScreenH
, col
);
2041 // ***************************************************************************
2042 void CViewRenderer::drawCustom (sint32 x
, sint32 y
, sint32 width
, sint32 height
, CRGBA col
, UMaterial Mat
)
2044 float dstXmin
, dstYmin
, dstXmax
, dstYmax
;
2046 // Is totally clipped ?
2047 if ((x
> (_ClipX
+_ClipW
)) || ((x
+width
) < _ClipX
) ||
2048 (y
> (_ClipY
+_ClipH
)) || ((y
+height
) < _ClipY
))
2054 dstXmin
= (float)(x
) * _OneOverScreenW
;
2055 dstYmin
= (float)(y
) * _OneOverScreenH
;
2056 dstXmax
= (float)(x
+ width
) * _OneOverScreenW
;
2057 dstYmax
= (float)(y
+ height
) * _OneOverScreenH
;
2059 CQuadColorUV2 qcoluv2
;
2060 qcoluv2
.V0
.set (dstXmin
, dstYmin
, 0);
2061 qcoluv2
.V1
.set (dstXmax
, dstYmin
, 0);
2062 qcoluv2
.V2
.set (dstXmax
, dstYmax
, 0);
2063 qcoluv2
.V3
.set (dstXmin
, dstYmax
, 0);
2065 qcoluv2
.Color0
= qcoluv2
.Color1
= qcoluv2
.Color2
= qcoluv2
.Color3
= col
;
2067 qcoluv2
.Uv0
.U
= 0; qcoluv2
.Uv0
.V
= 1;
2068 qcoluv2
.Uv1
.U
= 1; qcoluv2
.Uv1
.V
= 1;
2069 qcoluv2
.Uv2
.U
= 1; qcoluv2
.Uv2
.V
= 0;
2070 qcoluv2
.Uv3
.U
= 0; qcoluv2
.Uv3
.V
= 0;
2072 qcoluv2
.Uv02
.U
= 0; qcoluv2
.Uv02
.V
= 1;
2073 qcoluv2
.Uv12
.U
= 1; qcoluv2
.Uv12
.V
= 1;
2074 qcoluv2
.Uv22
.U
= 1; qcoluv2
.Uv22
.V
= 0;
2075 qcoluv2
.Uv32
.U
= 0; qcoluv2
.Uv32
.V
= 0;
2078 CQuadColorUV2 qcoluv2_clipped
;
2079 if (!needClipping(qcoluv2
))
2081 // No need to clip the quad
2082 qcoluv2_clipped
= qcoluv2
;
2086 clip (qcoluv2_clipped
, qcoluv2
);
2089 // World space transformation
2090 if (_WorldSpaceTransformation
)
2091 worldSpaceTransformation (qcoluv2_clipped
);
2093 // Draw clipped quad
2094 driver
->drawQuads (&qcoluv2_clipped
, 1, Mat
);
2097 // ***************************************************************************
2098 void CViewRenderer::drawCustom(sint32 x
, sint32 y
, sint32 width
, sint32 height
, const NLMISC::CUV
&uv0Min
, const NLMISC::CUV
&uv0Max
, NLMISC::CRGBA col
, NL3D::UMaterial Mat
)
2100 float dstXmin
, dstYmin
, dstXmax
, dstYmax
;
2102 // Is totally clipped ?
2103 if ((x
> (_ClipX
+_ClipW
)) || ((x
+width
) < _ClipX
) ||
2104 (y
> (_ClipY
+_ClipH
)) || ((y
+height
) < _ClipY
))
2110 dstXmin
= (float)(x
) * _OneOverScreenW
;
2111 dstYmin
= (float)(y
) * _OneOverScreenH
;
2112 dstXmax
= (float)(x
+ width
) * _OneOverScreenW
;
2113 dstYmax
= (float)(y
+ height
) * _OneOverScreenH
;
2115 CQuadColorUV qcoluv
;
2116 qcoluv
.V0
.set (dstXmin
, dstYmin
, 0);
2117 qcoluv
.V1
.set (dstXmax
, dstYmin
, 0);
2118 qcoluv
.V2
.set (dstXmax
, dstYmax
, 0);
2119 qcoluv
.V3
.set (dstXmin
, dstYmax
, 0);
2121 qcoluv
.Color0
= qcoluv
.Color1
= qcoluv
.Color2
= qcoluv
.Color3
= col
;
2123 qcoluv
.Uv0
.U
= uv0Min
.U
; qcoluv
.Uv0
.V
= uv0Max
.V
;
2124 qcoluv
.Uv1
.U
= uv0Max
.U
; qcoluv
.Uv1
.V
= uv0Max
.V
;
2125 qcoluv
.Uv2
.U
= uv0Max
.U
; qcoluv
.Uv2
.V
= uv0Min
.V
;
2126 qcoluv
.Uv3
.U
= uv0Min
.U
; qcoluv
.Uv3
.V
= uv0Min
.V
;
2130 CQuadColorUV qcoluv_clipped
;
2131 if (!needClipping(qcoluv
))
2133 // No need to clip the quad
2134 qcoluv_clipped
= qcoluv
;
2138 clip (qcoluv_clipped
, qcoluv
, 0);
2141 // Draw clipped quad
2142 driver
->drawQuads (&qcoluv_clipped
, 1, Mat
);
2145 // ***************************************************************************
2146 void CViewRenderer::drawCustom (sint32 x
, sint32 y
, sint32 width
, sint32 height
,
2147 const CUV
&uv0Min
, const CUV
&uv0Max
, const CUV
&uv1Min
, const CUV
&uv1Max
,
2148 NLMISC::CRGBA col
, NL3D::UMaterial Mat
)
2150 float dstXmin
, dstYmin
, dstXmax
, dstYmax
;
2152 // Is totally clipped ?
2153 if ((x
> (_ClipX
+_ClipW
)) || ((x
+width
) < _ClipX
) ||
2154 (y
> (_ClipY
+_ClipH
)) || ((y
+height
) < _ClipY
))
2160 dstXmin
= (float)(x
) * _OneOverScreenW
;
2161 dstYmin
= (float)(y
) * _OneOverScreenH
;
2162 dstXmax
= (float)(x
+ width
) * _OneOverScreenW
;
2163 dstYmax
= (float)(y
+ height
) * _OneOverScreenH
;
2165 CQuadColorUV2 qcoluv2
;
2166 qcoluv2
.V0
.set (dstXmin
, dstYmin
, 0);
2167 qcoluv2
.V1
.set (dstXmax
, dstYmin
, 0);
2168 qcoluv2
.V2
.set (dstXmax
, dstYmax
, 0);
2169 qcoluv2
.V3
.set (dstXmin
, dstYmax
, 0);
2171 qcoluv2
.Color0
= qcoluv2
.Color1
= qcoluv2
.Color2
= qcoluv2
.Color3
= col
;
2173 qcoluv2
.Uv0
.U
= uv0Min
.U
; qcoluv2
.Uv0
.V
= uv0Max
.V
;
2174 qcoluv2
.Uv1
.U
= uv0Max
.U
; qcoluv2
.Uv1
.V
= uv0Max
.V
;
2175 qcoluv2
.Uv2
.U
= uv0Max
.U
; qcoluv2
.Uv2
.V
= uv0Min
.V
;
2176 qcoluv2
.Uv3
.U
= uv0Min
.U
; qcoluv2
.Uv3
.V
= uv0Min
.V
;
2178 qcoluv2
.Uv02
.U
= uv1Min
.U
; qcoluv2
.Uv02
.V
= uv1Max
.V
;
2179 qcoluv2
.Uv12
.U
= uv1Max
.U
; qcoluv2
.Uv12
.V
= uv1Max
.V
;
2180 qcoluv2
.Uv22
.U
= uv1Max
.U
; qcoluv2
.Uv22
.V
= uv1Min
.V
;
2181 qcoluv2
.Uv32
.U
= uv1Min
.U
; qcoluv2
.Uv32
.V
= uv1Min
.V
;
2184 CQuadColorUV2 qcoluv2_clipped
;
2185 if (!needClipping(qcoluv2
))
2187 // No need to clip the quad
2188 qcoluv2_clipped
= qcoluv2
;
2192 clip (qcoluv2_clipped
, qcoluv2
);
2195 // World space transformation
2196 if (_WorldSpaceTransformation
)
2197 worldSpaceTransformation (qcoluv2_clipped
);
2199 // Draw clipped quad
2200 driver
->drawQuads (&qcoluv2_clipped
, 1, Mat
);
2203 // ***************************************************************************
2205 CViewRenderer::CTextureId::~CTextureId ()
2208 CViewRenderer::getInstance()->deleteTexture(_TextureId
);
2212 // ***************************************************************************
2214 bool CViewRenderer::CTextureId::setTexture (const char *textureName
, sint32 offsetX
, sint32 offsetY
, sint32 width
, sint32 height
,
2215 bool uploadDXTC
, bool bReleasable
)
2217 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
2219 rVR
.deleteTexture(_TextureId
);
2220 _TextureId
= rVR
.getTextureIdFromName(textureName
);
2222 _TextureId
= rVR
.createTexture (textureName
, offsetX
, offsetY
, width
, height
, uploadDXTC
, bReleasable
);
2224 return _TextureId
>= 0;
2227 // ***************************************************************************
2228 void CViewRenderer::CTextureId::clear()
2230 if (_TextureId
>= 0)
2232 CViewRenderer::getInstance()->deleteTexture(_TextureId
);
2237 // ***************************************************************************
2238 void CViewRenderer::CTextureId::serial(NLMISC::IStream
&f
)
2240 std::string texName
;
2244 setTexture(texName
.c_str());
2248 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
2249 texName
= rVR
.getTextureNameFromId(_TextureId
);
2254 // ***************************************************************************
2256 void CViewRenderer::worldSpaceTransformation (NLMISC::CQuadColorUV
&qcoluv
)
2259 qcoluv
.V0
.z
= _CurrentZ
;
2260 qcoluv
.V1
.z
= _CurrentZ
;
2261 qcoluv
.V2
.z
= _CurrentZ
;
2262 qcoluv
.V3
.z
= _CurrentZ
;
2264 // for scaled interface, apply the scale matrix
2265 qcoluv
.V0
= _WorldSpaceMatrix
* qcoluv
.V0
;
2266 qcoluv
.V1
= _WorldSpaceMatrix
* qcoluv
.V1
;
2267 qcoluv
.V2
= _WorldSpaceMatrix
* qcoluv
.V2
;
2268 qcoluv
.V3
= _WorldSpaceMatrix
* qcoluv
.V3
;
2271 qcoluv
.V0
= _CameraFrustum
.unProjectZ(qcoluv
.V0
);
2272 qcoluv
.V1
= _CameraFrustum
.unProjectZ(qcoluv
.V1
);
2273 qcoluv
.V2
= _CameraFrustum
.unProjectZ(qcoluv
.V2
);
2274 qcoluv
.V3
= _CameraFrustum
.unProjectZ(qcoluv
.V3
);
2277 // ***************************************************************************
2279 void CViewRenderer::setWorldSpaceFrustum (const NL3D::CFrustum
&cameraFrustum
)
2281 _CameraFrustum
= cameraFrustum
;
2284 // ***************************************************************************
2286 void CViewRenderer::activateWorldSpaceMatrix (bool activate
)
2288 _WorldSpaceTransformation
= activate
;
2289 if (!_Material
.empty())
2290 _Material
.setZFunc(activate
?UMaterial::lessequal
:UMaterial::always
);
2293 // ***************************************************************************
2295 void CViewRenderer::drawText (sint layerId
, float x
, float y
, uint wordIndex
, float xmin
, float ymin
, float xmax
, float ymax
, UTextContext
&textContext
)
2297 xmin
= xmin
* _OneOverScreenW
;
2298 ymin
= ymin
* _OneOverScreenH
;
2299 xmax
= xmax
* _OneOverScreenW
;
2300 ymax
= ymax
* _OneOverScreenH
;
2302 if (_InterfaceScale
!= 1.0f
&& _InterfaceScale
!= 2.0f
)
2304 // align to screen pixel
2305 x
*= _OneOverScreenW
* _ScreenW
;
2306 y
*= _OneOverScreenH
* _ScreenH
;
2307 x
= floorf(x
) * 1.f
/ (float) _ScreenW
;
2308 y
= floorf(y
) * 1.f
/ (float) _ScreenH
;
2312 x
= floorf(x
) * _OneOverScreenW
;
2313 y
= floorf(y
) * _OneOverScreenH
;
2316 if (_WorldSpaceTransformation
)
2318 textContext
.printClipAtUnProjected(*getStringRenderBuffer(layerId
), _CameraFrustum
, _WorldSpaceMatrix
, x
, y
, _CurrentZ
, wordIndex
, xmin
, ymin
, xmax
, ymax
);
2322 textContext
.printClipAt(*getStringRenderBuffer(layerId
), x
, y
, wordIndex
, xmin
, ymin
, xmax
, ymax
);
2325 // layer is no more empty
2326 _EmptyLayer
[layerId
+ VR_BIAS_LAYER
]= false;
2329 // ***************************************************************************
2331 void CViewRenderer::setInterfaceDepth (const NLMISC::CVector
&projCenter
, float scale
)
2333 _CurrentZ
= projCenter
.z
;
2335 // no scale? => identity matrix (faster)
2338 _WorldSpaceMatrix
.identity();
2339 _WorldSpaceScale
= false;
2343 _WorldSpaceMatrix
.identity();
2344 // must be in 0..1 coordinate here...
2345 CVector pos
= projCenter
;
2346 pos
.x
*= _OneOverScreenW
;
2347 pos
.y
*= _OneOverScreenH
;
2348 // set a pivoted scale matrix
2349 _WorldSpaceMatrix
.translate(pos
);
2350 _WorldSpaceMatrix
.scale(scale
);
2351 _WorldSpaceMatrix
.translate(-pos
);
2352 _WorldSpaceScale
= true;