1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/dynloadlib.h"
25 #include "nel/3d/dru.h"
26 #include "nel/3d/driver.h"
27 #include "nel/3d/material.h"
28 #include "nel/3d/vertex_buffer.h"
29 #include "nel/3d/index_buffer.h"
34 # define NL_OPENGL_AVAILABLE
36 # define NL_DIRECT3D_AVAILABLE
38 #endif // HAVE_CONFIG_H
41 # ifndef NL_COMP_MINGW
45 #else // NL_OS_WINDOWS
47 #endif // NL_OS_WINDOWS
49 using namespace NLMISC
;
60 typedef IDriver
* (*IDRV_CREATE_PROC
)(void);
61 const char *IDRV_CREATE_PROC_NAME
= "NL3D_createIDriverInstance";
63 typedef uint32 (*IDRV_VERSION_PROC
)(void);
64 const char *IDRV_VERSION_PROC_NAME
= "NL3D_interfaceVersion";
68 #ifdef NL_OPENGL_AVAILABLE
69 extern IDriver
* createGlDriverInstance ();
72 #if defined(NL_OS_WINDOWS) && defined(NL_DIRECT3D_AVAILABLE)
73 extern IDriver
* createD3DDriverInstance ();
76 #ifdef NL_OPENGLES_AVAILABLE
77 extern IDriver
* createGlEsDriverInstance ();
82 // ***************************************************************************
83 IDriver
*CDRU::createGlDriver()
87 #ifdef NL_OPENGL_AVAILABLE
88 return createGlDriverInstance ();
91 #endif // NL_OPENGL_AVAILABLE
95 IDRV_CREATE_PROC createDriver
= NULL
;
96 IDRV_VERSION_PROC versionDriver
= NULL
;
100 #if defined(NL_OS_UNIX) && defined(NL_DRIVER_PREFIX)
101 driverLib
.addLibPath(NL_DRIVER_PREFIX
);
104 if (!driverLib
.loadLibrary(NL3D_GL_DLL_NAME
, true, true, false))
106 throw EDruOpenglDriverNotFound();
109 nlinfo ("Using the library '" NL3D_GL_DLL_NAME
"' that is in the directory: '%s'", driverLib
.getLibFileName().c_str());
111 createDriver
= (IDRV_CREATE_PROC
) driverLib
.getSymbolAddress(IDRV_CREATE_PROC_NAME
);
112 if (createDriver
== NULL
)
114 throw EDruOpenglDriverCorrupted();
117 versionDriver
= (IDRV_VERSION_PROC
) driverLib
.getSymbolAddress(IDRV_VERSION_PROC_NAME
);
118 if (versionDriver
!= NULL
)
120 if (versionDriver()<IDriver::InterfaceVersion
)
121 throw EDruOpenglDriverOldVersion();
122 else if (versionDriver()>IDriver::InterfaceVersion
)
123 throw EDruOpenglDriverUnknownVersion();
126 IDriver
*ret
= createDriver();
129 throw EDruOpenglDriverCantCreateDriver();
136 // ***************************************************************************
137 IDriver
*CDRU::createGlEsDriver()
141 #ifdef NL_OPENGLES_AVAILABLE
142 return createGlEsDriverInstance ();
145 #endif // NL_OPENGLES_AVAILABLE
149 IDRV_CREATE_PROC createDriver
= NULL
;
150 IDRV_VERSION_PROC versionDriver
= NULL
;
154 #if defined(NL_OS_UNIX) && defined(NL_DRIVER_PREFIX)
155 driverLib
.addLibPath(NL_DRIVER_PREFIX
);
158 if (!driverLib
.loadLibrary(NL3D_GLES_DLL_NAME
, true, true, false))
160 throw EDruOpenglEsDriverNotFound();
163 nlinfo ("Using the library '" NL3D_GLES_DLL_NAME
"' that is in the directory: '%s'", driverLib
.getLibFileName().c_str());
165 createDriver
= (IDRV_CREATE_PROC
) driverLib
.getSymbolAddress(IDRV_CREATE_PROC_NAME
);
166 if (createDriver
== NULL
)
168 throw EDruOpenglDriverCorrupted();
171 versionDriver
= (IDRV_VERSION_PROC
) driverLib
.getSymbolAddress(IDRV_VERSION_PROC_NAME
);
172 if (versionDriver
!= NULL
)
174 if (versionDriver()<IDriver::InterfaceVersion
)
175 throw EDruOpenglDriverOldVersion();
176 else if (versionDriver()>IDriver::InterfaceVersion
)
177 throw EDruOpenglDriverUnknownVersion();
180 IDriver
*ret
= createDriver();
183 throw EDruOpenglEsDriverCantCreateDriver();
190 // ***************************************************************************
194 IDriver
*CDRU::createD3DDriver()
198 #ifdef NL_DIRECT3D_AVAILABLE
199 return createD3DDriverInstance ();
202 #endif // NL_DIRECT3D_AVAILABLE
206 IDRV_CREATE_PROC createDriver
= NULL
;
207 IDRV_VERSION_PROC versionDriver
= NULL
;
211 if (!driverLib
.loadLibrary(NL3D_D3D_DLL_NAME
, true, true, false))
213 throw EDruDirect3dDriverNotFound();
216 nlinfo ("Using the library '" NL3D_D3D_DLL_NAME
"' that is in the directory: '%s'", driverLib
.getLibFileName().c_str());
218 createDriver
= (IDRV_CREATE_PROC
) driverLib
.getSymbolAddress(IDRV_CREATE_PROC_NAME
);
219 if (createDriver
== NULL
)
221 throw EDruDirect3dDriverCorrupted();
224 versionDriver
= (IDRV_VERSION_PROC
) driverLib
.getSymbolAddress(IDRV_VERSION_PROC_NAME
);
225 if (versionDriver
!= NULL
)
227 if (versionDriver()<IDriver::InterfaceVersion
)
228 throw EDruDirect3dDriverOldVersion();
229 else if (versionDriver()>IDriver::InterfaceVersion
)
230 throw EDruDirect3dDriverUnknownVersion();
233 IDriver
*ret
= createDriver();
236 throw EDruDirect3dDriverCantCreateDriver();
242 #endif // NL_OS_WINDOWS
244 // ***************************************************************************
246 void CDRU::drawBitmap (float x
, float y
, float width
, float height
, ITexture
& texture
, IDriver
& driver
, CViewport viewport
, bool blend
)
250 driver
.setupViewport (viewport
);
251 driver
.setupViewMatrix (mtx
);
252 driver
.setupModelMatrix (mtx
);
253 driver
.setFrustum (0.f
, 1.f
, 0.f
, 1.f
, -1.f
, 1.f
, false);
255 static CMaterial mat
;
257 mat
.setTexture (0, &texture
);
259 mat
.setZFunc(CMaterial::always
);
261 static CVertexBuffer vb
;
262 if (vb
.getName().empty()) vb
.setName("CDRU::drawBitmap");
263 vb
.setVertexFormat (CVertexBuffer::PositionFlag
|CVertexBuffer::TexCoord0Flag
);
264 vb
.setNumVertices (4);
265 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
267 CVertexBufferReadWrite vba
;
269 vba
.setVertexCoord (0, CVector (x
, 0, y
));
270 vba
.setVertexCoord (1, CVector (x
+width
, 0, y
));
271 vba
.setVertexCoord (2, CVector (x
+width
, 0, y
+height
));
272 vba
.setVertexCoord (3, CVector (x
, 0, y
+height
));
273 vba
.setTexCoord (0, 0, 0.f
, 1.f
);
274 vba
.setTexCoord (1, 0, 1.f
, 1.f
);
275 vba
.setTexCoord (2, 0, 1.f
, 0.f
);
276 vba
.setTexCoord (3, 0, 0.f
, 0.f
);
278 driver
.activeVertexBuffer(vb
);
280 static CIndexBuffer pb
;
281 if (pb
.getName().empty()) NL_SET_IB_NAME(pb
, "CDRU::drawBitmap");
282 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
283 pb
.setNumIndexes (6);
284 pb
.setPreferredMemory (CIndexBuffer::RAMVolatile
, false);
286 CIndexBufferReadWrite iba
;
288 iba
.setTri (0, 0, 1, 2);
289 iba
.setTri (3, 2, 3, 0);
292 driver
.activeIndexBuffer(pb
);
293 driver
.renderTriangles(mat
, 0, 2);
297 // ***************************************************************************
298 void CDRU::drawLine (float x0
, float y0
, float x1
, float y1
, IDriver
& driver
, CRGBA col
, CViewport viewport
)
302 driver
.setupViewport (viewport
);
303 driver
.setupViewMatrix (mtx
);
304 driver
.setupModelMatrix (mtx
);
305 driver
.setFrustum (0.f
, 1.f
, 0.f
, 1.f
, -1.f
, 1.f
, false);
307 static CMaterial mat
;
309 mat
.setSrcBlend(CMaterial::srcalpha
);
310 mat
.setDstBlend(CMaterial::invsrcalpha
);
313 mat
.setZFunc (CMaterial::always
);
315 static CVertexBuffer vb
;
316 if (vb
.getName().empty()) vb
.setName("CDRU::drawLine");
317 vb
.setVertexFormat (CVertexBuffer::PositionFlag
);
318 vb
.setNumVertices (2);
319 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
321 CVertexBufferReadWrite vba
;
323 vba
.setVertexCoord (0, CVector (x0
, 0, y0
));
324 vba
.setVertexCoord (1, CVector (x1
, 0, y1
));
326 driver
.activeVertexBuffer(vb
);
328 static CIndexBuffer pb
;
329 if (pb
.getName().empty()) NL_SET_IB_NAME(pb
, "CDRU::drawLine");
330 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
331 pb
.setNumIndexes (2);
332 pb
.setPreferredMemory (CIndexBuffer::RAMVolatile
, false);
334 CIndexBufferReadWrite iba
;
336 iba
.setLine (0, 0, 1);
339 driver
.activeIndexBuffer(pb
);
340 driver
.renderLines(mat
, 0, 1);
344 // ***************************************************************************
345 void CDRU::drawTriangle (float x0
, float y0
, float x1
, float y1
, float x2
, float y2
, IDriver
& driver
, CRGBA col
, CViewport viewport
)
349 driver
.setupViewport (viewport
);
350 driver
.setupViewMatrix (mtx
);
351 driver
.setupModelMatrix (mtx
);
352 driver
.setFrustum (0.f
, 1.f
, 0.f
, 1.f
, -1.f
, 1.f
, false);
354 static CMaterial mat
;
356 mat
.setSrcBlend(CMaterial::srcalpha
);
357 mat
.setDstBlend(CMaterial::invsrcalpha
);
360 mat
.setZFunc (CMaterial::always
);
362 static CVertexBuffer vb
;
363 if (vb
.getName().empty()) vb
.setName("CDRU::drawTriangle");
364 vb
.setVertexFormat (CVertexBuffer::PositionFlag
);
365 vb
.setNumVertices (3);
366 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
368 CVertexBufferReadWrite vba
;
370 vba
.setVertexCoord (0, CVector (x0
, 0, y0
));
371 vba
.setVertexCoord (1, CVector (x1
, 0, y1
));
372 vba
.setVertexCoord (2, CVector (x2
, 0, y2
));
374 driver
.activeVertexBuffer(vb
);
376 static CIndexBuffer pb
;
377 if (pb
.getName().empty()) NL_SET_IB_NAME(pb
, "CDRU::drawTriangle");
378 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
379 pb
.setNumIndexes (3);
380 pb
.setPreferredMemory (CIndexBuffer::RAMVolatile
, false);
382 CIndexBufferReadWrite iba
;
384 iba
.setTri (0, 0, 1, 2);
387 driver
.activeIndexBuffer(pb
);
388 driver
.renderTriangles(mat
, 0, 1);
393 // ***************************************************************************
394 void CDRU::drawQuad (float x0
, float y0
, float x1
, float y1
, IDriver
& driver
, CRGBA col
, CViewport viewport
)
398 driver
.setupViewport (viewport
);
399 driver
.setupViewMatrix (mtx
);
400 driver
.setupModelMatrix (mtx
);
401 driver
.setFrustum (0.f
, 1.f
, 0.f
, 1.f
, -1.f
, 1.f
, false);
403 static CMaterial mat
;
405 mat
.setSrcBlend(CMaterial::srcalpha
);
406 mat
.setDstBlend(CMaterial::invsrcalpha
);
409 mat
.setZFunc (CMaterial::always
);
411 static CVertexBuffer vb
;
412 if (vb
.getName().empty()) vb
.setName("CDRU::drawQuad");
413 vb
.setVertexFormat (CVertexBuffer::PositionFlag
);
414 vb
.setNumVertices (4);
415 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
417 CVertexBufferReadWrite vba
;
419 vba
.setVertexCoord (0, CVector (x0
, 0, y0
));
420 vba
.setVertexCoord (1, CVector (x1
, 0, y0
));
421 vba
.setVertexCoord (2, CVector (x1
, 0, y1
));
422 vba
.setVertexCoord (3, CVector (x0
, 0, y1
));
425 driver
.activeVertexBuffer(vb
);
426 driver
.renderRawQuads(mat
, 0, 1);
430 // ***************************************************************************
431 void CDRU::drawQuad (float xcenter
, float ycenter
, float radius
, IDriver
& driver
, CRGBA col
, CViewport viewport
)
435 driver
.setupViewport (viewport
);
436 driver
.setupViewMatrix (mtx
);
437 driver
.setupModelMatrix (mtx
);
438 driver
.setFrustum (0.f
, 1.f
, 0.f
, 1.f
, -1.f
, 1.f
, false);
440 static CMaterial mat
;
442 mat
.setSrcBlend(CMaterial::srcalpha
);
443 mat
.setDstBlend(CMaterial::invsrcalpha
);
446 mat
.setZFunc (CMaterial::always
);
448 static CVertexBuffer vb
;
449 if (vb
.getName().empty()) vb
.setName("CDRU::drawQuad");
450 vb
.setVertexFormat (CVertexBuffer::PositionFlag
);
451 vb
.setNumVertices (4);
452 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
454 CVertexBufferReadWrite vba
;
456 vba
.setVertexCoord (0, CVector (xcenter
-radius
, 0, ycenter
-radius
));
457 vba
.setVertexCoord (1, CVector (xcenter
+radius
, 0, ycenter
-radius
));
458 vba
.setVertexCoord (2, CVector (xcenter
+radius
, 0, ycenter
+radius
));
459 vba
.setVertexCoord (3, CVector (xcenter
-radius
, 0, ycenter
+radius
));
462 driver
.activeVertexBuffer(vb
);
463 driver
.renderRawQuads(mat
, 0, 1);
467 // ***************************************************************************
468 void CDRU::drawWiredQuad (float x0
, float y0
, float x1
, float y1
, IDriver
& driver
, CRGBA col
, CViewport viewport
)
471 CDRU::drawLine(x0
,y0
,x0
,y1
,driver
,col
,viewport
);
473 CDRU::drawLine(x1
,y0
,x1
,y1
,driver
,col
,viewport
);
475 CDRU::drawLine(x0
,y1
,x1
,y1
,driver
,col
,viewport
);
477 CDRU::drawLine(x0
,y0
,x1
,y0
,driver
,col
,viewport
);
481 // ***************************************************************************
482 void CDRU::drawWiredQuad (float xcenter
, float ycenter
, float radius
, IDriver
& driver
, CRGBA col
, CViewport viewport
)
485 CDRU::drawLine(xcenter
-radius
,ycenter
-radius
,xcenter
-radius
,ycenter
+radius
,driver
,col
,viewport
);
487 CDRU::drawLine(xcenter
+radius
,ycenter
-radius
,xcenter
+radius
,ycenter
+radius
,driver
,col
,viewport
);
489 CDRU::drawLine(xcenter
-radius
,ycenter
+radius
,xcenter
+radius
,ycenter
+radius
,driver
,col
,viewport
);
491 CDRU::drawLine(xcenter
-radius
,ycenter
-radius
,xcenter
+radius
,ycenter
-radius
,driver
,col
,viewport
);
495 // ***************************************************************************
496 void CDRU::drawTrianglesUnlit(const NLMISC::CTriangleUV
*trilist
, sint ntris
, CMaterial
&mat
, IDriver
& driver
)
498 static CVertexBuffer vb
;
499 if (vb
.getName().empty()) vb
.setName("CDRU::drawTrianglesUnlit");
500 vb
.setVertexFormat (CVertexBuffer::PositionFlag
| CVertexBuffer::TexCoord0Flag
);
501 vb
.setNumVertices (ntris
*3);
502 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
504 static CIndexBuffer pb
;
505 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
506 pb
.setNumIndexes(ntris
*3);
507 pb
.setPreferredMemory (CIndexBuffer::RAMVolatile
, false);
508 if (pb
.getFormat() == CIndexBuffer::Indices16
)
510 nlassert(ntris
* 3 <= 0xffff);
513 CVertexBufferReadWrite vba
;
515 CIndexBufferReadWrite iba
;
517 for(sint i
=0;i
<ntris
;i
++)
519 vba
.setVertexCoord (i
*3+0, trilist
[i
].V0
);
520 vba
.setVertexCoord (i
*3+1, trilist
[i
].V1
);
521 vba
.setVertexCoord (i
*3+2, trilist
[i
].V2
);
522 vba
.setTexCoord (i
*3+0, 0, trilist
[i
].Uv0
);
523 vba
.setTexCoord (i
*3+1, 0, trilist
[i
].Uv1
);
524 vba
.setTexCoord (i
*3+2, 0, trilist
[i
].Uv2
);
525 iba
.setTri(i
*3, i
*3+0, i
*3+1, i
*3+2);
529 driver
.activeVertexBuffer(vb
);
530 driver
.activeIndexBuffer(pb
);
531 driver
.renderTriangles(mat
, 0, ntris
);
535 // ***************************************************************************
536 void CDRU::drawTrianglesUnlit(const std::vector
<NLMISC::CTriangleUV
> &trilist
, CMaterial
&mat
, IDriver
& driver
)
541 CDRU::drawTrianglesUnlit( &(*trilist
.begin()), (uint
)trilist
.size(), mat
, driver
);
545 // ***************************************************************************
546 void CDRU::drawLinesUnlit(const NLMISC::CLine
*linelist
, sint nlines
, CMaterial
&mat
, IDriver
& driver
)
548 static CVertexBuffer vb
;
549 if (vb
.getName().empty()) vb
.setName("CDRU::drawLinesUnlit");
550 vb
.setVertexFormat (CVertexBuffer::PositionFlag
);
551 vb
.setNumVertices (nlines
*2);
552 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
554 static CIndexBuffer pb
;
555 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
556 pb
.setNumIndexes(nlines
*2);
557 pb
.setPreferredMemory (CIndexBuffer::RAMVolatile
, false);
561 CVertexBufferReadWrite vba
;
563 CIndexBufferReadWrite iba
;
565 for(sint i
=0;i
<nlines
;i
++)
567 vba
.setVertexCoord (i
*2+0, linelist
[i
].V0
);
568 vba
.setVertexCoord (i
*2+1, linelist
[i
].V1
);
569 iba
.setLine(i
*2, i
*2+0, i
*2+1);
573 driver
.activeVertexBuffer(vb
);
574 driver
.activeIndexBuffer(pb
);
575 driver
.renderLines(mat
, 0, nlines
);
577 // ***************************************************************************
578 void CDRU::drawLinesUnlit(const std::vector
<NLMISC::CLine
> &linelist
, CMaterial
&mat
, IDriver
& driver
)
582 CDRU::drawLinesUnlit( &(*linelist
.begin()), (sint
)linelist
.size(), mat
, driver
);
584 // ***************************************************************************
585 void CDRU::drawLine(const CVector
&a
, const CVector
&b
, CRGBA color
, IDriver
& driver
)
587 static NLMISC::CLine line
;
588 static CMaterial mat
;
589 static bool inited
= false;
602 CDRU::drawLinesUnlit(&line
, 1, mat
, driver
);
604 // ***************************************************************************
605 void CDRU::drawQuad (float x0
, float y0
, float x1
, float y1
, CRGBA col0
, CRGBA col1
, CRGBA col2
, CRGBA col3
, IDriver
& driver
, CViewport viewport
)
609 driver
.setupViewport (viewport
);
610 driver
.setupViewMatrix (mtx
);
611 driver
.setupModelMatrix (mtx
);
612 driver
.setFrustum (0.f
, 1.f
, 0.f
, 1.f
, -1.f
, 1.f
, false);
614 static CMaterial mat
;
616 mat
.setSrcBlend(CMaterial::srcalpha
);
617 mat
.setDstBlend(CMaterial::invsrcalpha
);
619 mat
.setZFunc (CMaterial::always
);
621 static CVertexBuffer vb
;
622 if (vb
.getName().empty()) vb
.setName("CDRU::drawQuad");
623 vb
.setVertexFormat (CVertexBuffer::PositionFlag
|CVertexBuffer::PrimaryColorFlag
);
624 vb
.setNumVertices (4);
625 vb
.setPreferredMemory (CVertexBuffer::RAMVolatile
, false);
627 CVertexBufferReadWrite vba
;
629 vba
.setVertexCoord (0, CVector (x0
, 0, y0
));
630 vba
.setColor (0, col0
);
631 vba
.setVertexCoord (1, CVector (x1
, 0, y0
));
632 vba
.setColor (1, col1
);
633 vba
.setVertexCoord (2, CVector (x1
, 0, y1
));
634 vba
.setColor (2, col2
);
635 vba
.setVertexCoord (3, CVector (x0
, 0, y1
));
636 vba
.setColor (3, col3
);
639 driver
.activeVertexBuffer(vb
);
640 driver
.renderRawQuads(mat
, 0, 1);
643 // ***************************************************************************
644 void CDRU::drawWiredBox(const CVector
&corner
, const CVector
&vi
, const CVector
&vj
, const CVector
&vk
, CRGBA color
, IDriver
& drv
)
647 CVector p1
= p0
+ vi
+ vj
+ vk
;
648 drawLine(p0
, p0
+vi
, color
, drv
);
649 drawLine(p0
, p0
+vj
, color
, drv
);
650 drawLine(p0
, p0
+vk
, color
, drv
);
651 drawLine(p1
, p1
-vi
, color
, drv
);
652 drawLine(p1
, p1
-vj
, color
, drv
);
653 drawLine(p1
, p1
-vk
, color
, drv
);
654 drawLine(p0
+vi
, p0
+vi
+vj
, color
, drv
);
655 drawLine(p0
+vi
, p0
+vi
+vk
, color
, drv
);
656 drawLine(p0
+vj
, p0
+vj
+vi
, color
, drv
);
657 drawLine(p0
+vj
, p0
+vj
+vk
, color
, drv
);
658 drawLine(p0
+vk
, p0
+vk
+vi
, color
, drv
);
659 drawLine(p0
+vk
, p0
+vk
+vj
, color
, drv
);