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

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

gpu: implement face culling mode in render contexts.

File size: 9.5 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    BlendFactor m_blend_src, m_blend_dst;
59    CullMode m_face_culling;
60    bool m_alpha_blend, m_alpha_test, m_depth_test;
61
62#if defined USE_D3D9
63    IDirect3DDevice9 *m_d3d_dev;
64#elif defined _XBOX
65    D3DDevice *m_d3d_dev;
66#endif
67};
68
69/*
70 * Public Renderer class
71 */
72
73Renderer::Renderer()
74  : m_data(new RendererData())
75{
76#if defined USE_D3D9 || defined _XBOX
77    /* FIXME: we should be in charge of creating this */
78    m_data->m_d3d_dev = g_d3ddevice;
79#else
80#   if defined USE_GLEW && !defined __APPLE__
81    /* Initialise GLEW if necessary */
82    GLenum glerr = glewInit();
83    if (glerr != GLEW_OK)
84    {
85        Log::Error("cannot initialise GLEW: %s\n", glewGetErrorString(glerr));
86        exit(EXIT_FAILURE);
87    }
88#   endif
89#endif
90
91    /* Initialise rendering states */
92    m_data->m_clear_color = vec4(-1.f);
93    SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f));
94
95    m_data->m_clear_depth = -1.f;
96    SetClearDepth(1.f);
97
98    m_data->m_alpha_blend = false;
99    SetAlphaBlend(true);
100
101    m_data->m_alpha_test = true;
102    SetAlphaTest(false);
103
104    m_data->m_blend_src = BlendFactor::Zero;
105    m_data->m_blend_dst = BlendFactor::Zero;
106    SetBlendFunc(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha);
107
108    m_data->m_depth_test = false;
109    SetDepthTest(true);
110
111    m_data->m_face_culling = CullMode::None;
112    SetFaceCulling(CullMode::CCW);
113
114    /* Add some rendering states that we don't export to the user */
115#if defined USE_D3D9 || defined _XBOX
116    /* TODO */
117#else
118#   if defined HAVE_GL_2X && !defined __APPLE__
119    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
120#   endif
121#endif
122}
123
124Renderer::~Renderer()
125{
126    delete m_data;
127}
128
129/*
130 * Clear color
131 */
132
133void Renderer::SetClearColor(vec4 color)
134{
135#if defined USE_D3D9 || defined _XBOX
136    /* Nothing to do */
137#else
138    glClearColor(color.r, color.g, color.b, color.a);
139#endif
140
141    m_data->m_clear_color = color;
142}
143
144vec4 Renderer::GetClearColor() const
145{
146    return m_data->m_clear_color;
147}
148
149/*
150 * Clear depth
151 */
152
153void Renderer::SetClearDepth(float depth)
154{
155#if defined USE_D3D9 || defined _XBOX
156    /* Nothing to do */
157#elif defined HAVE_GLES_2X
158    glClearDepthf(depth);
159#else
160    glClearDepth(depth);
161#endif
162
163    m_data->m_clear_depth = depth;
164}
165
166float Renderer::GetClearDepth() const
167{
168    return m_data->m_clear_depth;
169}
170
171/*
172 * Alpha blending
173 */
174
175void Renderer::SetAlphaBlend(bool set)
176{
177    if (m_data->m_alpha_blend == set)
178        return;
179
180#if defined USE_D3D9 || defined _XBOX
181    m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, set ? 1 : 0);
182#else
183    if (set)
184        glEnable(GL_BLEND);
185    else
186        glDisable(GL_BLEND);
187#endif
188
189    m_data->m_alpha_blend = set;
190}
191
192bool Renderer::GetAlphaBlend() const
193{
194    return m_data->m_alpha_blend;
195}
196
197/*
198 * Blend function
199 */
200
201void Renderer::SetBlendFunc(BlendFactor src, BlendFactor dst)
202{
203    if (m_data->m_blend_src == src && m_data->m_blend_dst == dst)
204        return;
205
206#if defined USE_D3D9 || defined _XBOX
207    enum D3DBLEND s1[2] = { D3DBLEND_ONE, D3DBLEND_ZERO };
208    BlendFactor s2[2] = { src, dst };
209
210    for (int i = 0; i < 2; ++i)
211    {
212        switch (s2[i])
213        {
214            case BlendFactor::Zero:
215                s1[i] = D3DBLEND_ZERO; break;
216            case BlendFactor::One:
217                s1[i] = D3DBLEND_ONE; break;
218            case BlendFactor::SrcColor:
219                s1[i] = D3DBLEND_SRCCOLOR; break;
220            case BlendFactor::OneMinusSrcColor:
221                s1[i] = D3DBLEND_INVSRCCOLOR; break;
222            case BlendFactor::DstColor:
223                s1[i] = D3DBLEND_DESTCOLOR; break;
224            case BlendFactor::OneMinusDstColor:
225                s1[i] = D3DBLEND_INVDESTCOLOR; break;
226            case BlendFactor::SrcAlpha:
227                s1[i] = D3DBLEND_SRCALPHA; break;
228            case BlendFactor::OneMinusSrcAlpha:
229                s1[i] = D3DBLEND_INVSRCALPHA; break;
230            case BlendFactor::DstAlpha:
231                s1[i] = D3DBLEND_DESTALPHA; break;
232            case BlendFactor::OneMinusDstAlpha:
233                s1[i] = D3DBLEND_INVDESTALPHA; break;
234            /* FiXME: these can be supported using D3DPBLENDCAPS_BLENDFACTOR */
235            case BlendFactor::ConstantColor:
236                assert(0, "BlendFactor::ConstantColor not supported");
237                break;
238            case BlendFactor::OneMinusConstantColor:
239                assert(0, "BlendFactor::OneMinusConstantColor not supported");
240                break;
241            case BlendFactor::ConstantAlpha:
242                assert(0, "BlendFactor::ConstantAlpha not supported");
243                break;
244            case BlendFactor::OneMinusConstantAlpha:
245                assert(0, "BlendFactor::OneMinusConstantAlpha not supported");
246                break;
247        }
248    }
249
250    m_data->m_d3d_dev->SetRenderState(D3DRS_SRCBLEND, s1[0]);
251    m_data->m_d3d_dev->SetRenderState(D3DRS_DESTBLEND, s1[1]);
252#else
253    GLenum s1[2] = { GL_ONE, GL_ZERO };
254    BlendFactor s2[2] = { src, dst };
255
256    for (int i = 0; i < 2; ++i)
257    {
258        switch (s2[i])
259        {
260            case BlendFactor::Zero:
261                s1[i] = GL_ZERO; break;
262            case BlendFactor::One:
263                s1[i] = GL_ONE; break;
264            case BlendFactor::SrcColor:
265                s1[i] = GL_SRC_COLOR; break;
266            case BlendFactor::OneMinusSrcColor:
267                s1[i] = GL_ONE_MINUS_SRC_COLOR; break;
268            case BlendFactor::DstColor:
269                s1[i] = GL_DST_COLOR; break;
270            case BlendFactor::OneMinusDstColor:
271                s1[i] = GL_ONE_MINUS_DST_COLOR; break;
272            case BlendFactor::SrcAlpha:
273                s1[i] = GL_SRC_ALPHA; break;
274            case BlendFactor::OneMinusSrcAlpha:
275                s1[i] = GL_ONE_MINUS_SRC_ALPHA; break;
276            case BlendFactor::DstAlpha:
277                s1[i] = GL_DST_ALPHA; break;
278            case BlendFactor::OneMinusDstAlpha:
279                s1[i] = GL_ONE_MINUS_DST_ALPHA; break;
280            case BlendFactor::ConstantColor:
281                s1[i] = GL_CONSTANT_COLOR; break;
282            case BlendFactor::OneMinusConstantColor:
283                s1[i] = GL_ONE_MINUS_CONSTANT_COLOR; break;
284            case BlendFactor::ConstantAlpha:
285                s1[i] = GL_CONSTANT_ALPHA; break;
286            case BlendFactor::OneMinusConstantAlpha:
287                s1[i] = GL_ONE_MINUS_CONSTANT_ALPHA; break;
288        }
289    }
290
291    glBlendFunc(s1[0], s1[1]);
292#endif
293
294    m_data->m_blend_src = src;
295    m_data->m_blend_dst = dst;
296}
297
298BlendFactor Renderer::GetBlendFuncSrc() const
299{
300    return m_data->m_blend_src;
301}
302
303BlendFactor Renderer::GetBlendFuncDst() const
304{
305    return m_data->m_blend_dst;
306}
307
308/*
309 * Alpha testing
310 */
311
312void Renderer::SetAlphaTest(bool set)
313{
314    if (m_data->m_alpha_test == set)
315        return;
316
317#if defined USE_D3D9 || defined _XBOX
318    m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHATESTENABLE, set ? 1 : 0);
319#else
320    if (set)
321        glEnable(GL_ALPHA_TEST);
322    else
323        glDisable(GL_ALPHA_TEST);
324#endif
325
326    m_data->m_alpha_test = set;
327}
328
329bool Renderer::GetAlphaTest() const
330{
331    return m_data->m_alpha_test;
332}
333
334/*
335 * Depth test
336 */
337
338void Renderer::SetDepthTest(bool set)
339{
340    if (m_data->m_depth_test == set)
341        return;
342
343#if defined USE_D3D9 || defined _XBOX
344#   define STR0(x) #x
345#   define STR(x) STR0(x)
346#   pragma message(__FILE__ "(" STR(__LINE__) "): warning: Renderer::SetDepthTest() not implemented")
347#else
348    if (set)
349        glEnable(GL_DEPTH_TEST);
350    else
351        glDisable(GL_DEPTH_TEST);
352#endif
353
354    m_data->m_depth_test = set;
355}
356
357bool Renderer::GetDepthTest() const
358{
359    return m_data->m_depth_test;
360}
361
362/*
363 * Face culling
364 */
365
366void Renderer::SetFaceCulling(CullMode mode)
367{
368    if (m_data->m_face_culling == mode)
369        return;
370
371#if defined USE_D3D9 || defined _XBOX
372    switch (mode)
373    {
374    case CullMode::None:
375        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
376        break;
377    case CullMode::CW:
378        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
379        break;
380    case CullMode::CCW:
381        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
382        break;
383    }
384#else
385    switch (mode)
386    {
387    case CullMode::None:
388        glDisable(GL_CULL_FACE);
389        break;
390    case CullMode::CW:
391        glEnable(GL_CULL_FACE);
392        glFrontFace(GL_CW);
393        break;
394    case CullMode::CCW:
395        glEnable(GL_CULL_FACE);
396        glFrontFace(GL_CCW);
397        break;
398    }
399#endif
400
401    m_data->m_face_culling = mode;
402}
403
404CullMode Renderer::GetFaceCulling() const
405{
406    return m_data->m_face_culling;
407}
408
409} /* namespace lol */
410
Note: See TracBrowser for help on using the repository browser.