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

Last change on this file since 2765 was 2765, checked in by sam, 8 years ago

gpu: disable alpha test on GL ES platforms.

File size: 13.9 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    AlphaFunc m_alpha_func;
59    float m_alpha_value;
60    BlendFunc m_blend_src, m_blend_dst;
61    DepthFunc m_depth_func;
62    CullMode m_face_culling;
63
64#if defined USE_D3D9
65    IDirect3DDevice9 *m_d3d_dev;
66#elif defined _XBOX
67    D3DDevice *m_d3d_dev;
68#endif
69};
70
71/*
72 * Public Renderer class
73 */
74
75Renderer::Renderer()
76  : m_data(new RendererData())
77{
78#if defined USE_D3D9 || defined _XBOX
79    /* FIXME: we should be in charge of creating this */
80    m_data->m_d3d_dev = g_d3ddevice;
81#else
82#   if defined USE_GLEW && !defined __APPLE__
83    /* Initialise GLEW if necessary */
84    GLenum glerr = glewInit();
85    if (glerr != GLEW_OK)
86    {
87        Log::Error("cannot initialise GLEW: %s\n", glewGetErrorString(glerr));
88        exit(EXIT_FAILURE);
89    }
90#   endif
91#endif
92
93    /* Initialise rendering states */
94    m_data->m_clear_color = vec4(-1.f);
95    SetClearColor(vec4(0.1f, 0.2f, 0.3f, 1.0f));
96
97    m_data->m_clear_depth = -1.f;
98    SetClearDepth(1.f);
99
100    m_data->m_alpha_func = AlphaFunc::Never;
101    m_data->m_alpha_value = -1.0f;
102    SetAlphaFunc(AlphaFunc::Disabled, 0.0f);
103
104    m_data->m_blend_src = BlendFunc::Disabled;
105    m_data->m_blend_dst = BlendFunc::Disabled;
106    SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
107
108    m_data->m_depth_func = DepthFunc::Disabled;
109    SetDepthFunc(DepthFunc::LessOrEqual);
110
111    m_data->m_face_culling = CullMode::Disabled;
112    SetFaceCulling(CullMode::CounterClockwise);
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 testing
173 */
174
175void Renderer::SetAlphaFunc(AlphaFunc func, float alpha)
176{
177    if (m_data->m_alpha_func == func && m_data->m_alpha_value == alpha)
178        return;
179
180#if defined USE_D3D9 || defined _XBOX
181    switch (func)
182    {
183        case AlphaFunc::Disabled:
184            break; /* Nothing to do */
185        case AlphaFunc::Never:
186            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NEVER);
187            break;
188        case AlphaFunc::Less:
189            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);
190            break;
191        case AlphaFunc::Equal:
192            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_EQUAL);
193            break;
194        case AlphaFunc::LessOrEqual:
195            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL);
196            break;
197        case AlphaFunc::Greater:
198            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
199            break;
200        case AlphaFunc::NotEqual:
201            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL);
202            break;
203        case AlphaFunc::GreaterOrEqual:
204            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
205            break;
206        case AlphaFunc::Always:
207            m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS);
208            break;
209    }
210
211    if (func == AlphaFunc::Disabled)
212    {
213        m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
214    }
215    else
216    {
217        m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
218        m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHAREF,
219                                          (DWORD)(alpha * 255.999f));
220    }
221#elif defined HAVE_GL_2X
222    switch (func)
223    {
224        case AlphaFunc::Disabled:
225            break; /* Nothing to do */
226        case AlphaFunc::Never:
227            glAlphaFunc(GL_NEVER, alpha); break;
228        case AlphaFunc::Less:
229            glAlphaFunc(GL_LESS, alpha); break;
230        case AlphaFunc::Equal:
231            glAlphaFunc(GL_EQUAL, alpha); break;
232        case AlphaFunc::LessOrEqual:
233            glAlphaFunc(GL_LEQUAL, alpha); break;
234        case AlphaFunc::Greater:
235            glAlphaFunc(GL_GREATER, alpha); break;
236        case AlphaFunc::NotEqual:
237            glAlphaFunc(GL_NOTEQUAL, alpha); break;
238        case AlphaFunc::GreaterOrEqual:
239            glAlphaFunc(GL_GEQUAL, alpha); break;
240        case AlphaFunc::Always:
241            glAlphaFunc(GL_ALWAYS, alpha); break;
242    }
243
244    if (func == AlphaFunc::Disabled)
245        glDisable(GL_ALPHA_TEST);
246    else
247        glEnable(GL_ALPHA_TEST);
248#else
249    /* XXX: alpha test not available in GL ES */
250#endif
251
252    m_data->m_alpha_func = func;
253    m_data->m_alpha_value = alpha;
254}
255
256AlphaFunc Renderer::GetAlphaFunc() const
257{
258    return m_data->m_alpha_func;
259}
260
261float Renderer::GetAlphaValue() const
262{
263    return m_data->m_alpha_value;
264}
265
266/*
267 * Blend function
268 */
269
270void Renderer::SetBlendFunc(BlendFunc src, BlendFunc dst)
271{
272    if (m_data->m_blend_src == src && m_data->m_blend_dst == dst)
273        return;
274
275#if defined USE_D3D9 || defined _XBOX
276    enum D3DBLEND s1[2] = { D3DBLEND_ONE, D3DBLEND_ZERO };
277    BlendFunc s2[2] = { src, dst };
278
279    for (int i = 0; i < 2; ++i)
280    {
281        switch (s2[i])
282        {
283            case BlendFunc::Disabled:
284                break; /* Nothing to do */
285            case BlendFunc::Zero:
286                s1[i] = D3DBLEND_ZERO; break;
287            case BlendFunc::One:
288                s1[i] = D3DBLEND_ONE; break;
289            case BlendFunc::SrcColor:
290                s1[i] = D3DBLEND_SRCCOLOR; break;
291            case BlendFunc::OneMinusSrcColor:
292                s1[i] = D3DBLEND_INVSRCCOLOR; break;
293            case BlendFunc::DstColor:
294                s1[i] = D3DBLEND_DESTCOLOR; break;
295            case BlendFunc::OneMinusDstColor:
296                s1[i] = D3DBLEND_INVDESTCOLOR; break;
297            case BlendFunc::SrcAlpha:
298                s1[i] = D3DBLEND_SRCALPHA; break;
299            case BlendFunc::OneMinusSrcAlpha:
300                s1[i] = D3DBLEND_INVSRCALPHA; break;
301            case BlendFunc::DstAlpha:
302                s1[i] = D3DBLEND_DESTALPHA; break;
303            case BlendFunc::OneMinusDstAlpha:
304                s1[i] = D3DBLEND_INVDESTALPHA; break;
305            /* FiXME: these can be supported using D3DPBLENDCAPS_BLENDFACTOR */
306            case BlendFunc::ConstantColor:
307                assert(0, "BlendFunc::ConstantColor not supported");
308                break;
309            case BlendFunc::OneMinusConstantColor:
310                assert(0, "BlendFunc::OneMinusConstantColor not supported");
311                break;
312            case BlendFunc::ConstantAlpha:
313                assert(0, "BlendFunc::ConstantAlpha not supported");
314                break;
315            case BlendFunc::OneMinusConstantAlpha:
316                assert(0, "BlendFunc::OneMinusConstantAlpha not supported");
317                break;
318        }
319    }
320
321    if (src == BlendFunc::Disabled)
322    {
323        m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, 0);
324    }
325    else
326    {
327        m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
328        m_data->m_d3d_dev->SetRenderState(D3DRS_SRCBLEND, s1[0]);
329        m_data->m_d3d_dev->SetRenderState(D3DRS_DESTBLEND, s1[1]);
330    }
331#else
332    GLenum s1[2] = { GL_ONE, GL_ZERO };
333    BlendFunc s2[2] = { src, dst };
334
335    for (int i = 0; i < 2; ++i)
336    {
337        switch (s2[i])
338        {
339            case BlendFunc::Disabled:
340                break; /* Nothing to do */
341            case BlendFunc::Zero:
342                s1[i] = GL_ZERO; break;
343            case BlendFunc::One:
344                s1[i] = GL_ONE; break;
345            case BlendFunc::SrcColor:
346                s1[i] = GL_SRC_COLOR; break;
347            case BlendFunc::OneMinusSrcColor:
348                s1[i] = GL_ONE_MINUS_SRC_COLOR; break;
349            case BlendFunc::DstColor:
350                s1[i] = GL_DST_COLOR; break;
351            case BlendFunc::OneMinusDstColor:
352                s1[i] = GL_ONE_MINUS_DST_COLOR; break;
353            case BlendFunc::SrcAlpha:
354                s1[i] = GL_SRC_ALPHA; break;
355            case BlendFunc::OneMinusSrcAlpha:
356                s1[i] = GL_ONE_MINUS_SRC_ALPHA; break;
357            case BlendFunc::DstAlpha:
358                s1[i] = GL_DST_ALPHA; break;
359            case BlendFunc::OneMinusDstAlpha:
360                s1[i] = GL_ONE_MINUS_DST_ALPHA; break;
361            case BlendFunc::ConstantColor:
362                s1[i] = GL_CONSTANT_COLOR; break;
363            case BlendFunc::OneMinusConstantColor:
364                s1[i] = GL_ONE_MINUS_CONSTANT_COLOR; break;
365            case BlendFunc::ConstantAlpha:
366                s1[i] = GL_CONSTANT_ALPHA; break;
367            case BlendFunc::OneMinusConstantAlpha:
368                s1[i] = GL_ONE_MINUS_CONSTANT_ALPHA; break;
369        }
370    }
371
372    if (src == BlendFunc::Disabled)
373    {
374        glDisable(GL_BLEND);
375    }
376    else
377    {
378        glEnable(GL_BLEND);
379        glBlendFunc(s1[0], s1[1]);
380    }
381#endif
382
383    m_data->m_blend_src = src;
384    m_data->m_blend_dst = dst;
385}
386
387BlendFunc Renderer::GetBlendFuncSrc() const
388{
389    return m_data->m_blend_src;
390}
391
392BlendFunc Renderer::GetBlendFuncDst() const
393{
394    return m_data->m_blend_dst;
395}
396
397/*
398 * Depth test
399 */
400
401void Renderer::SetDepthFunc(DepthFunc func)
402{
403    if (m_data->m_depth_func == func)
404        return;
405
406#if defined USE_D3D9 || defined _XBOX
407    switch (func)
408    {
409        case DepthFunc::Disabled:
410            break; /* Nothing to do */
411        case DepthFunc::Never:
412            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_NEVER);
413            break;
414        case DepthFunc::Less:
415            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
416            break;
417        case DepthFunc::Equal:
418            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
419            break;
420        case DepthFunc::LessOrEqual:
421            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
422            break;
423        case DepthFunc::Greater:
424            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER);
425            break;
426        case DepthFunc::NotEqual:
427            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL);
428            break;
429        case DepthFunc::GreaterOrEqual:
430            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL);
431            break;
432        case DepthFunc::Always:
433            m_data->m_d3d_dev->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
434            break;
435    }
436
437    if (func == DepthFunc::Disabled)
438        m_data->m_d3d_dev->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
439    else
440        m_data->m_d3d_dev->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
441#else
442    switch (func)
443    {
444        case DepthFunc::Disabled:
445            break; /* Nothing to do */
446        case DepthFunc::Never:
447            glDepthFunc(GL_NEVER); break;
448        case DepthFunc::Less:
449            glDepthFunc(GL_LESS); break;
450        case DepthFunc::Equal:
451            glDepthFunc(GL_EQUAL); break;
452        case DepthFunc::LessOrEqual:
453            glDepthFunc(GL_LEQUAL); break;
454        case DepthFunc::Greater:
455            glDepthFunc(GL_GREATER); break;
456        case DepthFunc::NotEqual:
457            glDepthFunc(GL_NOTEQUAL); break;
458        case DepthFunc::GreaterOrEqual:
459            glDepthFunc(GL_GEQUAL); break;
460        case DepthFunc::Always:
461            glDepthFunc(GL_ALWAYS); break;
462    }
463
464    if (func == DepthFunc::Disabled)
465        glDisable(GL_DEPTH_TEST);
466    else
467        glEnable(GL_DEPTH_TEST);
468#endif
469
470    m_data->m_depth_func = func;
471}
472
473DepthFunc Renderer::GetDepthFunc() const
474{
475    return m_data->m_depth_func;
476}
477
478/*
479 * Face culling
480 */
481
482void Renderer::SetFaceCulling(CullMode mode)
483{
484    if (m_data->m_face_culling == mode)
485        return;
486
487#if defined USE_D3D9 || defined _XBOX
488    switch (mode)
489    {
490    case CullMode::Disabled:
491        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
492        break;
493    case CullMode::Clockwise:
494        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
495        break;
496    case CullMode::CounterClockwise:
497        m_data->m_d3d_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
498        break;
499    }
500#else
501    switch (mode)
502    {
503    case CullMode::Disabled:
504        glDisable(GL_CULL_FACE);
505        break;
506    case CullMode::Clockwise:
507        glEnable(GL_CULL_FACE);
508        glCullFace(GL_BACK);
509        glFrontFace(GL_CW);
510        break;
511    case CullMode::CounterClockwise:
512        glEnable(GL_CULL_FACE);
513        glCullFace(GL_BACK);
514        glFrontFace(GL_CCW);
515        break;
516    }
517#endif
518
519    m_data->m_face_culling = mode;
520}
521
522CullMode Renderer::GetFaceCulling() const
523{
524    return m_data->m_face_culling;
525}
526
527} /* namespace lol */
528
Note: See TracBrowser for help on using the repository browser.