Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / driver / direct3d / driver_direct3d_render.cpp
blob6b9d2ce0c9736878649fcb4f6cf34b200f1c3421
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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"
30 #ifdef DEBUG_NEW
31 #define new DEBUG_NEW
32 #endif
34 using namespace std;
35 using namespace NLMISC;
40 namespace NL3D
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
52 uint offset;
53 CVolatileIndexBuffer *&buffer = _VolatileIndexBuffer16RAM[_CurrentRenderPass&1];
54 uint16 *ptr = (uint16*)buffer->lock (numIndices*sizeof(uint16), offset);
55 if (!ptr)
57 // index buffer full, swap with other buffer
58 CVolatileIndexBuffer *&bufferOther = _VolatileIndexBuffer16RAM[(_CurrentRenderPass + 1) &1];
59 std::swap(buffer, bufferOther);
60 buffer->reset();
61 ptr = (uint16*)buffer->lock (numIndices*sizeof(uint16), offset);
63 const uint32 *currIndex = &_LastIndexBufferInfo->RamVersion[firstIndex];
64 const uint32 *indexEnd = currIndex + numIndices;
67 #ifdef NL_DEBUG
68 nlassertex(*currIndex < _MaxVertexIndex, ("In this implementation, only 16 bit indices are supported"));
69 #endif
70 *ptr++ = (uint16&) (*currIndex++);
72 while (currIndex != indexEnd);
73 buffer->unlock();
74 setIndexBuffer(buffer->IndexBuffer, offset);
77 // ***************************************************************************
78 #ifndef NL_DEBUG
79 inline
80 #endif
81 bool CDriverD3D::renderPrimitives(D3DPRIMITIVETYPE primitiveType, uint /* numVertexPerPrim */, CMaterial& mat, uint firstVertex, uint32 nPrims)
83 // Setup material
84 if ( !setupMaterial(mat) )
85 return false;
86 if (nPrims == 0)
87 return false;
88 nlassertex(nPrims < _MaxPrimitiveCount, ("Number of max primitive at each calls limited in this implementation on current hradware"));
89 if (_VertexBufferCache.VertexBuffer)
91 uint pass;
92 beginMultiPass ();
93 for (pass=0; pass<_CurrentShaderPassCount; pass++)
95 // Active the pass
96 activePass (pass);
97 HRESULT r = _DeviceInterface->DrawPrimitive (primitiveType, firstVertex + _VertexBufferOffset, nPrims);
98 nlassert(r == D3D_OK);
100 endMultiPass ();
102 return true;
108 // ***************************************************************************
109 #ifndef NL_DEBUG
110 inline
111 #endif
112 bool CDriverD3D::renderIndexedPrimitives(D3DPRIMITIVETYPE primitiveType, uint numVertexPerPrim, CMaterial& mat, uint32 firstIndex, uint32 nPrims, uint indexOffset /*= 0*/)
114 // Setup material
115 if ( !setupMaterial(mat) )
116 return false;
117 if (nPrims == 0)
118 return false;
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);
124 firstIndex = 0;
126 if (_VertexBufferCache.VertexBuffer && _IndexBufferCache.IndexBuffer)
128 uint pass;
129 beginMultiPass ();
130 for (pass=0; pass< _CurrentShaderPassCount; pass++)
132 // Active the pass
133 activePass (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);
141 endMultiPass ();
143 return true;
146 // ***************************************************************************
147 #ifndef NL_DEBUG
148 inline
149 #endif
150 bool CDriverD3D::renderSimpleIndexedPrimitives(D3DPRIMITIVETYPE primitiveType, uint numVertexPerPrim, uint32 firstIndex, uint32 nPrims, uint indexOffset /*= 0*/)
152 if (nPrims == 0)
153 return false;
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);
159 firstIndex = 0;
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);
171 return true;
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;
180 // Stats
181 _PrimitiveProfileIn.NLines += nlines;
182 _PrimitiveProfileOut.NLines += nlines*_CurrentShaderPassCount;
184 return true;
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;
194 // Stats
195 _PrimitiveProfileIn.NTriangles += ntris;
196 _PrimitiveProfileOut.NTriangles += ntris*_CurrentShaderPassCount;
197 return true;
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;
209 // Stats
210 _PrimitiveProfileIn.NTriangles += ntris;
211 _PrimitiveProfileOut.NTriangles += ntris;
213 return true;
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;
221 // Stats
222 _PrimitiveProfileIn.NLines += nlines;
223 _PrimitiveProfileOut.NLines += nlines*_CurrentShaderPassCount;
224 return true;
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;
232 // Stats
233 _PrimitiveProfileIn.NTriangles += ntris;
234 _PrimitiveProfileOut.NTriangles += ntris*_CurrentShaderPassCount;
235 return true;
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;
246 // Stats
247 _PrimitiveProfileIn.NTriangles += ntris;
248 _PrimitiveProfileOut.NTriangles += ntris;
250 return true;
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))
258 // Stats
259 _PrimitiveProfileIn.NPoints += numPoints;
260 _PrimitiveProfileOut.NPoints += numPoints*_CurrentShaderPassCount;
261 return true;
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;
269 // Stats
270 _PrimitiveProfileIn.NLines += numLines;
271 _PrimitiveProfileOut.NLines += numLines*_CurrentShaderPassCount;
273 return true;
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;
282 // Stats
283 _PrimitiveProfileIn.NTriangles += numTris;
284 _PrimitiveProfileOut.NTriangles += numTris*_CurrentShaderPassCount;
286 return true;
289 // ***************************************************************************
290 // 32 bits version
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 // ***************************************************************************
307 // 16 bits version
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);
361 uint i;
362 for (i=1; i<8; i++)
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;
382 else
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)
391 nlassert(_QuadIB);
392 setIndexBuffer(_QuadIB, 0);
393 _CurrIndexBufferFormat = CIndexBuffer::Indices16; // must set the format because we don't call activeIndexBuffer
395 else
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)
402 // Resize it
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);
413 else
415 fillQuadIndexes ((uint16 *) iba.getPtr(), 0, numIndexResize);
418 activeIndexBuffer (_QuadIndexes);
420 // Setup material
421 if ( !setupMaterial(mat) )
422 return false;
424 uint pass;
425 beginMultiPass ();
426 for (pass=0; pass<_CurrentShaderPassCount; pass++)
428 // Active the pass
429 activePass (pass);
430 //fixVB(numQuads, 4);
431 _DeviceInterface->DrawIndexedPrimitive (D3DPT_TRIANGLELIST, _VertexBufferOffset + startIndex, 0, numQuads * 4,
432 0, numQuads*2);
434 endMultiPass ();
438 // Stats
439 _PrimitiveProfileIn.NTriangles += numQuads*2;
440 _PrimitiveProfileOut.NTriangles += numQuads*2*_CurrentShaderPassCount;
442 return true;
445 // ***************************************************************************
447 } // NL3D