source: trunk/src/gpu/renderer.cpp @ 2762

Last change on this file since 2762 was 2762, checked in by sam, 9 years ago

gpu: implement all depth test functions in the renderer.

File size: 11.4 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cstdlib>
16
17#if defined _XBOX
18#   include <xtl.h>
19#   undef near /* Fuck Microsoft */
20#   undef far /* Fuck Microsoft again */
21#elif defined _WIN32
22#   if defined USE_D3D9
23#      include <d3d9.h>
24#   endif
25#   define WIN32_LEAN_AND_MEAN
26#   include <windows.h>
27#   undef near /* Fuck Microsoft */
28#   undef far /* Fuck Microsoft again */
29#endif
30
31#include "core.h"
32#include "lolgl.h"
33
34#if defined USE_D3D9
35extern IDirect3DDevice9 *g_d3ddevice;
36#elif defined _XBOX
37extern D3DDevice *g_d3ddevice;
38#endif
39
40namespace lol
41{
42
43/*
44 * The global g_renderer object, initialised by Video::Init
45 */
46Renderer *g_renderer;
47
48/*
49 * Private RendererData class
50 */
51class RendererData
52{
53    friend class Renderer;
54
55private:
56    vec4 m_clear_color;
57    float m_clear_depth;
58    BlendFunc m_blend_src, m_blend_dst;
59    DepthFunc m_depth_func;
60    CullMode m_face_culling;
61    bool m_alpha_blend, m_alpha_test;
62
63#if defined USE_D3D9
64    IDirect3DDevice9 *m_d3d_dev;
65#elif defined _XBOX
66    D3DDevice *m_d3d_dev;
67#endif
68};
69
70/*
71 * Public Renderer class
72 */
73
74Renderer::Renderer()
75  : m_data(new RendererData())
76{
77#if defined USE_D3D9 || defined _XBOX
78    /* FIXME: we should be in charge of creating this */
79    m_data->m_d3d_dev = g_d3ddevice;
80#else
81#   if defined USE_GLEW && !defined __APPLE__
82    /* Initialise GLEW if necessary */
83    GLenum glerr = glewInit();
84    if (glerr != GLEW_OK)
85    {
86        Log::Error("cannot initialise GLEW: %s\n", glewGetErrorString(glerr));
87        exit(EXIT_FAILURE);
88    }
89#   endif
90#endif
91
92    /* Initialise rendering states */
93    m_data->m_clear_color = vec4(-1.f);
94    SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f));
95
96    m_data->m_clear_depth = -1.f;
97    SetClearDepth(1.f);
98
99    m_data->m_alpha_blend = false;
100    SetAlphaBlend(true);
101
102    m_data->m_alpha_test = true;
103    SetAlphaTest(false);
104
105    m_data->m_blend_src = BlendFunc::Zero;
106    m_data->m_blend_dst = BlendFunc::Zero;
107    SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
108
109    m_data->m_depth_func = DepthFunc::Disabled;
110    SetDepthFunc(DepthFunc::LessOrEqual);
111
112    m_data->m_face_culling = CullMode::Disabled;
113    SetFaceCulling(CullMode::CounterClockwise);
114
115    /* Add some rendering states that we don't export to the user */
116#if defined USE_D3D9 || defined _XBOX
117    /* TODO */
118#else
119#   if defined HAVE_GL_2X && !defined __APPLE__
120    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
121#   endif
122#endif
123}
124
125Renderer::~Renderer()
126{
127    delete m_data;
128}
129
130/*
131 * Clear color
132 */
133
134void Renderer::SetClearColor(vec4 color)
135{
136#if defined USE_D3D9 || defined _XBOX
137    /* Nothing to do */
138#else
139    glClearColor(color.r, color.g, color.b, color.a);
140#endif
141
142    m_data->m_clear_color = color;
143}
144
145vec4 Renderer::GetClearColor() const
146{
147    return m_data->m_clear_color;
148}
149
150/*
151 * Clear depth
152 */
153
154void Renderer::SetClearDepth(float depth)
155{
156#if defined USE_D3D9 || defined _XBOX
157    /* Nothing to do */
158#elif defined HAVE_GLES_2X
159    glClearDepthf(depth);
160#else
161    glClearDepth(depth);
162#endif
163
164    m_data->m_clear_depth = depth;
165}
166
167float Renderer::GetClearDepth() const
168{
169    return m_data->m_clear_depth;
170}
171
172/*
173 * Alpha blending
174 */
175
176void Renderer::SetAlphaBlend(bool set)
177{
178    if (m_data->m_alpha_blend == set)
179        return;
180
181#if defined USE_D3D9 || defined _XBOX
182    m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, set ? 1 : 0);
183#else
184    if (set)
185        glEnable(GL_BLEND);
186    else
187        glDisable(GL_BLEND);
188#endif
189
190    m_data->m_alpha_blend = set;
191}
192
193bool Renderer::GetAlphaBlend() const
194{
195    return m_data->m_alpha_blend;
196}
197
198/*
199 * Blend function
200 */
201
202void Renderer::SetBlendFunc(BlendFunc src, BlendFunc dst)
203{
204    if (m_data->m_blend_src == src && m_data->m_blend_dst == dst)
205        return;
206
207#if defined USE_D3D9 || defined _XBOX
208    enum D3DBLEND s1[2] = { D3DBLEND_ONE, D3DBLEND_ZERO };
209    BlendFunc s2[2] = { src, dst };
210
211    for (int i = 0; i < 2; ++i)
212    {
213        switch (s2[i])
214        {
215            case BlendFunc::Zero:
216                s1[i] = D3DBLEND_ZERO; break;
217            case BlendFunc::One:
218                s1[i] = D3DBLEND_ONE; break;
219            case BlendFunc::SrcColor:
220                s1[i] = D3DBLEND_SRCCOLOR; break;
221            case BlendFunc::OneMinusSrcColor:
222                s1[i] = D3DBLEND_INVSRCCOLOR; break;
223            case BlendFunc::DstColor:
224                s1[i] = D3DBLEND_DESTCOLOR; break;
225            case BlendFunc::OneMinusDstColor:
226                s1[i] = D3DBLEND_INVDESTCOLOR; break;
227            case BlendFunc::SrcAlpha:
228                s1[i] = D3DBLEND_SRCALPHA; break;
229            case BlendFunc::OneMinusSrcAlpha:
230                s1[i] = D3DBLEND_INVSRCALPHA; break;
231            case BlendFunc::DstAlpha:
232                s1[i] = D3DBLEND_DESTALPHA; break;
233            case BlendFunc::OneMinusDstAlpha:
234                s1[i] = D3DBLEND_INVDESTALPHA; break;
235            /* FiXME: these can be supported using D3DPBLENDCAPS_BLENDFACTOR */
236            case BlendFunc::ConstantColor:
237                assert(0, "BlendFunc::ConstantColor not supported");
238                break;
239            case BlendFunc::OneMinusConstantColor:
240                assert(0, "BlendFunc::OneMinusConstantColor not supported");
241                break;
242            case BlendFunc::ConstantAlpha:
243                assert(0, "BlendFunc::ConstantAlpha not supported");
244                break;
245            case BlendFunc::OneMinusConstantAlpha:
246                assert(0, "BlendFunc::OneMinusConstantAlpha not supported");
247                break;
248        }
249    }
250
251    m_data->m_d3d_dev->SetRenderState(D3DRS_SRCBLEND, s1[0]);
252    m_data->m_d3d_dev->SetRenderState(D3DRS_DESTBLEND, s1[1]);
253#else
254    GLenum s1[2] = { GL_ONE, GL_ZERO };
255    BlendFunc s2[2] = { src, dst };
256
257    for (int i = 0; i < 2; ++i)
258    {
259        switch (s2[i])
260        {
261            case BlendFunc::Zero:
262                s1[i] = GL_ZERO; break;
263            case BlendFunc::One:
264                s1[i] = GL_ONE; break;
265            case BlendFunc::SrcColor:
266                s1[i] = GL_SRC_COLOR; break;
267            case BlendFunc::OneMinusSrcColor:
268                s1[i] = GL_ONE_MINUS_SRC_COLOR; break;
269            case BlendFunc::DstColor:
270                s1[i] = GL_DST_COLOR; break;
271            case BlendFunc::OneMinusDstColor:
272                s1[i] = GL_ONE_MINUS_DST_COLOR; break;
273            case BlendFunc::SrcAlpha:
274                s1[i] = GL_SRC_ALPHA; break;
275            case BlendFunc::OneMinusSrcAlpha:
276                s1[i] = GL_ONE_MINUS_SRC_ALPHA; break;
277            case BlendFunc::DstAlpha:
278                s1[i] = GL_DST_ALPHA; break;
279            case BlendFunc::OneMinusDstAlpha:
280                s1[i] = GL_ONE_MINUS_DST_ALPHA; break;
281            case BlendFunc::ConstantColor:
282                s1[i] = GL_CONSTANT_COLOR; break;
283            case BlendFunc::OneMinusConstantColor:
284                s1[i] = GL_ONE_MINUS_CONSTANT_COLOR; break;
285            case BlendFunc::ConstantAlpha:
286                s1[i] = GL_CONSTANT_ALPHA; break;
287            case BlendFunc::OneMinusConstantAlpha:
288                s1[i] = GL_ONE_MINUS_CONSTANT_ALPHA; break;
289        }
290    }
291
292    glBlendFunc(s1[0], s1[1]);
293#endif
294
295    m_data->m_blend_src = src;
296    m_data->m_blend_dst = dst;
297}
298
299BlendFunc Renderer::GetBlendFuncSrc() const
300{
301    return m_data->m_blend_src;
302}
303
304BlendFunc Renderer::GetBlendFuncDst() const
305{
306    return m_data->m_blend_dst;
307}
308
309/*
310 * Alpha testing
311 */
312
313void Renderer::SetAlphaTest(bool set)
314{
315    if (m_data->m_alpha_test == set)
316        return;
317
318#if defined USE_D3D9 || defined _XBOX
319    m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHATESTENABLE, set ? 1 : 0);
320#else
321    if (set)
322        glEnable(GL_ALPHA_TEST);
323    else
324        glDisable(GL_ALPHA_TEST);
325#endif
326
327    m_data->m_alpha_test = set;
328}
329
330bool Renderer::GetAlphaTest() const
331{
332    return m_data->m_alpha_test;
333}
334
335/*
336 * Depth test
337 */
338
339void Renderer::SetDepthFunc(DepthFunc func)
340{
341    if (m_data->m_depth_func == func)
342        return;
343
344#if defined USE_D3D9 || defined _XBOX
345    switch (func)
346    {
347        case DepthFunc::Disabled:
348            break; /* Nothing to do */
349        case DepthFunc::Never:
350            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_NEVER);
351            break;
352        case DepthFunc::Less:
353            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
354            break;
355        case DepthFunc::Equal:
356            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
357            break;
358        case DepthFunc::LessOrEqual:
359            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
360            break;
361        case DepthFunc::Greater:
362            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER);
363            break;
364        case DepthFunc::NotEqual:
365            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL);
366            break;
367        case DepthFunc::GreaterOrEqual:
368            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL);
369            break;
370        case DepthFunc::Always:
371            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
372            break;
373    }
374
375    if (func == DepthFunc::Disabled)
376        m_data->m_d3d_dev->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
377    else
378        m_data->m_d3d_dev->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
379#else
380    switch (func)
381    {
382        case DepthFunc::Disabled:
383            break; /* Nothing to do */
384        case DepthFunc::Never:
385            glDepthFunc(GL_NEVER); break;
386        case DepthFunc::Less:
387            glDepthFunc(GL_LESS); break;
388        case DepthFunc::Equal:
389            glDepthFunc(GL_EQUAL); break;
390        case DepthFunc::LessOrEqual:
391            glDepthFunc(GL_LEQUAL); break;
392        case DepthFunc::Greater:
393            glDepthFunc(GL_GREATER); break;
394        case DepthFunc::NotEqual:
395            glDepthFunc(GL_NOTEQUAL); break;
396        case DepthFunc::GreaterOrEqual:
397            glDepthFunc(GL_GEQUAL); break;
398        case DepthFunc::Always:
399            glDepthFunc(GL_ALWAYS); break;
400    }
401
402    if (func == DepthFunc::Disabled)
403        glDisable(GL_DEPTH_TEST);
404    else
405        glEnable(GL_DEPTH_TEST);
406#endif
407
408    m_data->m_depth_func = func;
409}
410
411DepthFunc Renderer::GetDepthFunc() const
412{
413    return m_data->m_depth_func;
414}
415
416/*
417 * Face culling
418 */
419
420void Renderer::SetFaceCulling(CullMode mode)
421{
422    if (m_data->m_face_culling == mode)
423        return;
424
425#if defined USE_D3D9 || defined _XBOX
426    switch (mode)
427    {
428    case CullMode::Disabled:
429        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
430        break;
431    case CullMode::Clockwise:
432        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
433        break;
434    case CullMode::CounterClockwise:
435        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
436        break;
437    }
438#else
439    switch (mode)
440    {
441    case CullMode::Disabled:
442        glDisable(GL_CULL_FACE);
443        break;
444    case CullMode::Clockwise:
445        glEnable(GL_CULL_FACE);
446        glFrontFace(GL_CW);
447        break;
448    case CullMode::CounterClockwise:
449        glEnable(GL_CULL_FACE);
450        glFrontFace(GL_CCW);
451        break;
452    }
453#endif
454
455    m_data->m_face_culling = mode;
456}
457
458CullMode Renderer::GetFaceCulling() const
459{
460    return m_data->m_face_culling;
461}
462
463} /* namespace lol */
464
Note: See TracBrowser for help on using the repository browser.