1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stddirect3d.h"
19 #include "nel/3d/vertex_buffer.h"
20 #include "nel/3d/light.h"
21 #include "nel/3d/index_buffer.h"
22 #include "nel/misc/rect.h"
23 #include "nel/misc/fast_mem.h"
24 #include "nel/3d/viewport.h"
25 #include "nel/3d/scissor.h"
26 #include "nel/3d/u_driver.h"
28 #include "driver_direct3d.h"
35 using namespace NLMISC
;
46 // convert 32 bit indices to 16 bit indices on devices that don't have 32 bit indices
47 // ***************************************************************************
48 void CDriverD3D::convertToIndices16(uint firstIndex
, uint numIndices
)
50 nlassert(numIndices
> 0);
51 // Lock the good buffer
53 CVolatileIndexBuffer
*&buffer
= _VolatileIndexBuffer16RAM
[_CurrentRenderPass
&1];
54 uint16
*ptr
= (uint16
*)buffer
->lock (numIndices
*sizeof(uint16
), offset
);
57 // index buffer full, swap with other buffer
58 CVolatileIndexBuffer
*&bufferOther
= _VolatileIndexBuffer16RAM
[(_CurrentRenderPass
+ 1) &1];
59 std::swap(buffer
, bufferOther
);
61 ptr
= (uint16
*)buffer
->lock (numIndices
*sizeof(uint16
), offset
);
63 const uint32
*currIndex
= &_LastIndexBufferInfo
->RamVersion
[firstIndex
];
64 const uint32
*indexEnd
= currIndex
+ numIndices
;
68 nlassertex(*currIndex
< _MaxVertexIndex
, ("In this implementation, only 16 bit indices are supported"));
70 *ptr
++ = (uint16
&) (*currIndex
++);
72 while (currIndex
!= indexEnd
);
74 setIndexBuffer(buffer
->IndexBuffer
, offset
);
77 // ***************************************************************************
81 bool CDriverD3D::renderPrimitives(D3DPRIMITIVETYPE primitiveType
, uint
/* numVertexPerPrim */, CMaterial
& mat
, uint firstVertex
, uint32 nPrims
)
84 if ( !setupMaterial(mat
) )
88 nlassertex(nPrims
< _MaxPrimitiveCount
, ("Number of max primitive at each calls limited in this implementation on current hradware"));
89 if (_VertexBufferCache
.VertexBuffer
)
93 for (pass
=0; pass
<_CurrentShaderPassCount
; pass
++)
97 HRESULT r
= _DeviceInterface
->DrawPrimitive (primitiveType
, firstVertex
+ _VertexBufferOffset
, nPrims
);
98 nlassert(r
== D3D_OK
);
108 // ***************************************************************************
112 bool CDriverD3D::renderIndexedPrimitives(D3DPRIMITIVETYPE primitiveType
, uint numVertexPerPrim
, CMaterial
& mat
, uint32 firstIndex
, uint32 nPrims
, uint indexOffset
/*= 0*/)
115 if ( !setupMaterial(mat
) )
119 nlassertex(nPrims
< _MaxPrimitiveCount
, ("Number of max primitive at each calls limited in this implementation on current hardware"));
120 nlassert(_CurrIndexBufferFormat
!= CIndexBuffer::IndicesUnknownFormat
);
121 if (_MaxVertexIndex
<= 0xffff && _CurrIndexBufferFormat
== CIndexBuffer::Indices32
)
123 convertToIndices16(firstIndex
, numVertexPerPrim
* nPrims
);
126 if (_VertexBufferCache
.VertexBuffer
&& _IndexBufferCache
.IndexBuffer
)
130 for (pass
=0; pass
< _CurrentShaderPassCount
; pass
++)
134 // NB : indexOffset is actually a constant added to each index in the current index buffer (actually may be implemented
135 // by moving vertex pointer in the driver ...), whereas _IndexBufferOffset+firstIndex gives an offset into the index buffer
136 HRESULT r
= _DeviceInterface
->DrawIndexedPrimitive (primitiveType
, _VertexBufferOffset
+ indexOffset
, 0, _VertexBufferSize
,
137 firstIndex
+_IndexBufferOffset
, nPrims
);
138 nlassert(r
== D3D_OK
);
146 // ***************************************************************************
150 bool CDriverD3D::renderSimpleIndexedPrimitives(D3DPRIMITIVETYPE primitiveType
, uint numVertexPerPrim
, uint32 firstIndex
, uint32 nPrims
, uint indexOffset
/*= 0*/)
154 nlassertex(nPrims
< _MaxPrimitiveCount
, ("Number of max primitive at each calls limited in this implementation on current hardware"));
155 nlassert(_CurrIndexBufferFormat
!= CIndexBuffer::IndicesUnknownFormat
);
156 if (_MaxVertexIndex
<= 0xffff && _CurrIndexBufferFormat
== CIndexBuffer::Indices32
)
158 convertToIndices16(firstIndex
, numVertexPerPrim
* nPrims
);
161 if (_VertexBufferCache
.VertexBuffer
&& _IndexBufferCache
.IndexBuffer
)
163 updateRenderVariablesInternal();
164 //fixVB(nPrims, numVertexPerPrim);
165 // NB : indexOffset is actually a constant added to each index in the current index buffer (actually may be implemented
166 // by moving vertex pointer in the driver ...), whereas _IndexBufferOffset+firstIndex gives an offset into the index buffer
167 HRESULT r
= _DeviceInterface
->DrawIndexedPrimitive (primitiveType
, _VertexBufferOffset
+ indexOffset
, 0, _VertexBufferSize
,
168 firstIndex
+_IndexBufferOffset
, nPrims
);
169 nlassert(r
== D3D_OK
);
174 // ***************************************************************************
176 bool CDriverD3D::renderLines(CMaterial
& mat
, uint32 firstIndex
, uint32 nlines
)
178 H_AUTO_D3D(CDriverD3D_renderLines
)
179 if (!renderIndexedPrimitives(D3DPT_LINELIST
, 2, mat
, firstIndex
, nlines
)) return false;
181 _PrimitiveProfileIn
.NLines
+= nlines
;
182 _PrimitiveProfileOut
.NLines
+= nlines
*_CurrentShaderPassCount
;
188 // ***************************************************************************
190 bool CDriverD3D::renderTriangles(CMaterial
& mat
, uint32 firstIndex
, uint32 ntris
)
192 H_AUTO_D3D(CDriverD3D_renderTriangles
)
193 if (!renderIndexedPrimitives(D3DPT_TRIANGLELIST
, 3, mat
, firstIndex
, ntris
)) return false;
195 _PrimitiveProfileIn
.NTriangles
+= ntris
;
196 _PrimitiveProfileOut
.NTriangles
+= ntris
*_CurrentShaderPassCount
;
200 // ***************************************************************************
202 bool CDriverD3D::renderSimpleTriangles(uint32 firstIndex
, uint32 ntris
)
204 H_AUTO_D3D(CDriverD3D_renderSimpleTriangles
)
205 nlassert (ntris
!= 0);
206 nlassert (_VertexBufferCache
.VertexBuffer
);
207 nlassert (_IndexBufferCache
.IndexBuffer
);
208 if (!renderSimpleIndexedPrimitives(D3DPT_TRIANGLELIST
, 3, firstIndex
, ntris
)) return false;
210 _PrimitiveProfileIn
.NTriangles
+= ntris
;
211 _PrimitiveProfileOut
.NTriangles
+= ntris
;
216 // ***************************************************************************
217 bool CDriverD3D::renderLinesWithIndexOffset(CMaterial
& mat
, uint32 firstIndex
, uint32 nlines
, uint indexOffset
)
219 H_AUTO_D3D(CDriverD3D_renderLinesWithIndexOffset
)
220 if (!renderIndexedPrimitives(D3DPT_LINELIST
, 2, mat
, firstIndex
, nlines
, indexOffset
)) return false;
222 _PrimitiveProfileIn
.NLines
+= nlines
;
223 _PrimitiveProfileOut
.NLines
+= nlines
*_CurrentShaderPassCount
;
227 // ***************************************************************************
228 bool CDriverD3D::renderTrianglesWithIndexOffset(CMaterial
& mat
, uint32 firstIndex
, uint32 ntris
, uint indexOffset
)
230 H_AUTO_D3D(CDriverD3D_renderTrianglesWithIndexOffset
)
231 if (!renderIndexedPrimitives(D3DPT_TRIANGLELIST
, 3, mat
, firstIndex
, ntris
, indexOffset
)) return false;
233 _PrimitiveProfileIn
.NTriangles
+= ntris
;
234 _PrimitiveProfileOut
.NTriangles
+= ntris
*_CurrentShaderPassCount
;
238 // ***************************************************************************
239 bool CDriverD3D::renderSimpleTrianglesWithIndexOffset(uint32 firstIndex
, uint32 ntris
, uint indexOffset
)
241 H_AUTO_D3D(CDriverD3D_renderSimpleTrianglesWithIndexOffset
)
242 nlassert (ntris
!= 0);
243 nlassert (_VertexBufferCache
.VertexBuffer
);
244 nlassert (_IndexBufferCache
.IndexBuffer
);
245 if (!renderSimpleIndexedPrimitives(D3DPT_TRIANGLELIST
, 3, firstIndex
, ntris
, indexOffset
)) return false;
247 _PrimitiveProfileIn
.NTriangles
+= ntris
;
248 _PrimitiveProfileOut
.NTriangles
+= ntris
;
253 // ***************************************************************************
254 bool CDriverD3D::renderRawPoints(CMaterial
& mat
, uint32 firstIndex
, uint32 numPoints
)
256 H_AUTO_D3D(CDriverD3D_renderRawPoints
);
257 if (!renderPrimitives(D3DPT_POINTLIST
, 1, mat
, firstIndex
, numPoints
))
259 _PrimitiveProfileIn
.NPoints
+= numPoints
;
260 _PrimitiveProfileOut
.NPoints
+= numPoints
*_CurrentShaderPassCount
;
264 // ***************************************************************************
265 bool CDriverD3D::renderRawLines(CMaterial
& mat
, uint32 firstIndex
, uint32 numLines
)
267 H_AUTO_D3D(CDriverD3D_renderRawLines
);
268 if (!renderPrimitives(D3DPT_LINELIST
, 2, mat
, firstIndex
, numLines
)) return false;
270 _PrimitiveProfileIn
.NLines
+= numLines
;
271 _PrimitiveProfileOut
.NLines
+= numLines
*_CurrentShaderPassCount
;
276 // ***************************************************************************
278 bool CDriverD3D::renderRawTriangles(CMaterial
& mat
, uint32 firstIndex
, uint32 numTris
)
280 H_AUTO_D3D(CDriverD3D_renderRawTriangles
)
281 if (!renderPrimitives(D3DPT_TRIANGLELIST
, 3, mat
, 3 * firstIndex
, numTris
)) return false;
283 _PrimitiveProfileIn
.NTriangles
+= numTris
;
284 _PrimitiveProfileOut
.NTriangles
+= numTris
*_CurrentShaderPassCount
;
289 // ***************************************************************************
291 void fillQuadIndexes (uint32
*indexes
, uint first
, uint last
)
293 H_AUTO_D3D(fillQuadIndexes
)
294 uint firstQuad
= (first
/ 6) * 4;
295 for (;first
<last
; first
+=6, firstQuad
+=4)
297 indexes
[first
+0] = firstQuad
+0;
298 indexes
[first
+1] = firstQuad
+1;
299 indexes
[first
+2] = firstQuad
+2;
300 indexes
[first
+3] = firstQuad
+0;
301 indexes
[first
+4] = firstQuad
+2;
302 indexes
[first
+5] = firstQuad
+3;
306 // ***************************************************************************
308 void fillQuadIndexes (uint16
*indexes
, uint first
, uint last
)
310 H_AUTO_D3D(fillQuadIndexes
)
311 uint16 firstQuad
= (uint16
) ((first
/ 6) * 4);
312 for (;first
<last
; first
+=6, firstQuad
+=4)
314 indexes
[first
+0] = firstQuad
+0;
315 indexes
[first
+1] = firstQuad
+1;
316 indexes
[first
+2] = firstQuad
+2;
317 indexes
[first
+3] = firstQuad
+0;
318 indexes
[first
+4] = firstQuad
+2;
319 indexes
[first
+5] = firstQuad
+3;
323 // ***************************************************************************
325 void CDriverD3D::setDebugMaterial()
327 H_AUTO_D3D(CDriverD3D_setDebugMaterial
)
328 _DeviceInterface
->SetRenderState (D3DRS_ALPHABLENDENABLE
, FALSE
);
329 _DeviceInterface
->SetRenderState (D3DRS_SRCBLEND
, D3DBLEND_ONE
);
330 _DeviceInterface
->SetRenderState (D3DRS_DESTBLEND
, D3DBLEND_ZERO
);
331 _DeviceInterface
->SetRenderState (D3DRS_ALPHATESTENABLE
, FALSE
);
332 _DeviceInterface
->SetRenderState (D3DRS_ALPHAREF
, 128);
333 _DeviceInterface
->SetRenderState (D3DRS_ALPHAFUNC
, D3DCMP_GREATER
);
334 _DeviceInterface
->SetRenderState (D3DRS_LIGHTING
, FALSE
);
335 _DeviceInterface
->SetRenderState (D3DRS_TEXTUREFACTOR
, NL_D3DCOLOR_RGBA(CRGBA(255,0,255,255)));
336 _DeviceInterface
->SetRenderState (D3DRS_CULLMODE
, D3DCULL_CW
);
337 _DeviceInterface
->SetRenderState (D3DRS_COLORVERTEX
, FALSE
);
338 _DeviceInterface
->SetRenderState (D3DRS_ZWRITEENABLE
, TRUE
);
339 _DeviceInterface
->SetRenderState (D3DRS_ZFUNC
, D3DCMP_LESSEQUAL
);
340 _DeviceInterface
->SetRenderState (D3DRS_DIFFUSEMATERIALSOURCE
, D3DMCS_MATERIAL
);
341 _DeviceInterface
->SetRenderState (D3DRS_SPECULARMATERIALSOURCE
, D3DMCS_MATERIAL
);
342 _DeviceInterface
->SetRenderState (D3DRS_AMBIENTMATERIALSOURCE
, D3DMCS_MATERIAL
);
343 _DeviceInterface
->SetRenderState (D3DRS_EMISSIVEMATERIALSOURCE
, D3DMCS_MATERIAL
);
344 _DeviceInterface
->SetTexture (0, NULL
);
345 _DeviceInterface
->SetTexture (1, NULL
);
346 _DeviceInterface
->SetTexture (2, NULL
);
347 _DeviceInterface
->SetTexture (3, NULL
);
348 _DeviceInterface
->SetTexture (4, NULL
);
349 _DeviceInterface
->SetTexture (5, NULL
);
350 _DeviceInterface
->SetTexture (6, NULL
);
351 _DeviceInterface
->SetTexture (7, NULL
);
352 _DeviceInterface
->SetTextureStageState (0, D3DTSS_COLOROP
, D3DTOP_SELECTARG1
);
353 _DeviceInterface
->SetTextureStageState (0, D3DTSS_COLORARG0
, D3DTA_TFACTOR
);
354 _DeviceInterface
->SetTextureStageState (0, D3DTSS_COLORARG1
, D3DTA_TFACTOR
);
355 _DeviceInterface
->SetTextureStageState (0, D3DTSS_COLORARG2
, D3DTA_TFACTOR
);
356 _DeviceInterface
->SetTextureStageState (0, D3DTSS_ALPHAOP
, D3DTOP_SELECTARG1
);
357 _DeviceInterface
->SetTextureStageState (0, D3DTSS_ALPHAARG0
, D3DTA_TFACTOR
);
358 _DeviceInterface
->SetTextureStageState (0, D3DTSS_ALPHAARG1
, D3DTA_TFACTOR
);
359 _DeviceInterface
->SetTextureStageState (0, D3DTSS_ALPHAARG2
, D3DTA_TFACTOR
);
360 // _DeviceInterface->SetTextureStageState (0, D3DTSS_CONSTANT, 0x0);
364 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_COLOROP
, D3DTOP_DISABLE
);
365 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_COLORARG0
, D3DTA_TFACTOR
);
366 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_COLORARG1
, D3DTA_TFACTOR
);
367 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_COLORARG2
, D3DTA_TFACTOR
);
368 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_ALPHAOP
, D3DTOP_DISABLE
);
369 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_ALPHAARG0
, D3DTA_TFACTOR
);
370 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_ALPHAARG1
, D3DTA_TFACTOR
);
371 _DeviceInterface
->SetTextureStageState (i
, D3DTSS_ALPHAARG2
, D3DTA_TFACTOR
);
372 // _DeviceInterface->SetTextureStageState (i, D3DTSS_CONSTANT, 0x0);
377 // ***************************************************************************
378 bool CDriverD3D::renderRawQuads(CMaterial
& mat
, uint32 startIndex
, uint32 numQuads
)
380 H_AUTO_D3D(CDriverD3D_renderRawQuads
)
381 if (numQuads
== 0) return false;
383 if (_VertexBufferCache
.VertexBuffer
)
385 // Num of indexes needed
386 const uint numQuadsNeeded
= numQuads
*6;
387 nlassert(numQuads
< MAX_NUM_QUADS
); // this limitation should suffice for now
389 if (_MaxVertexIndex
<= 0xffff)
392 setIndexBuffer(_QuadIB
, 0);
393 _CurrIndexBufferFormat
= CIndexBuffer::Indices16
; // must set the format because we don't call activeIndexBuffer
397 const uint IB_RESIZE_STRIDE
= 6 * 256;
398 nlctassert(IB_RESIZE_STRIDE
% 6 == 0);
399 // Need to resize the quad indexes array ?
400 if (_QuadIndexes
.getNumIndexes() < numQuadsNeeded
)
403 uint32 numIndexResize
= IB_RESIZE_STRIDE
* ((numQuadsNeeded
+ (IB_RESIZE_STRIDE
- 1)) / IB_RESIZE_STRIDE
);
404 _QuadIndexes
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
405 _QuadIndexes
.setNumIndexes(numIndexResize
); // snap to nearest size
406 // Fill the index buffer in VRAM
407 CIndexBufferReadWrite iba
;
408 _QuadIndexes
.lock (iba
);
409 if (_QuadIndexes
.getFormat() == CIndexBuffer::Indices32
)
411 fillQuadIndexes ((uint32
*) iba
.getPtr(), 0, numIndexResize
);
415 fillQuadIndexes ((uint16
*) iba
.getPtr(), 0, numIndexResize
);
418 activeIndexBuffer (_QuadIndexes
);
421 if ( !setupMaterial(mat
) )
426 for (pass
=0; pass
<_CurrentShaderPassCount
; pass
++)
430 //fixVB(numQuads, 4);
431 _DeviceInterface
->DrawIndexedPrimitive (D3DPT_TRIANGLELIST
, _VertexBufferOffset
+ startIndex
, 0, numQuads
* 4,
439 _PrimitiveProfileIn
.NTriangles
+= numQuads
*2;
440 _PrimitiveProfileOut
.NTriangles
+= numQuads
*2*_CurrentShaderPassCount
;
445 // ***************************************************************************