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

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

gpu: framebuffers now use the g_render object to restore viewport data.

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