1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      OpenGL routines common to all OpenGL drivers.
12  *
13  *      By Elias Pschernig and Milan Mimica.
14  *
15  */
16 
17 #include "allegro5/allegro.h"
18 #include "allegro5/allegro_opengl.h"
19 #include "allegro5/internal/aintern.h"
20 #include "allegro5/internal/aintern_opengl.h"
21 #include "allegro5/internal/aintern_pixels.h"
22 #include "allegro5/transformations.h"
23 
24 #ifdef ALLEGRO_IPHONE
25 #include "allegro5/internal/aintern_iphone.h"
26 #endif
27 
28 #ifdef ALLEGRO_ANDROID
29 #include "allegro5/internal/aintern_android.h"
30 #endif
31 
32 #include "ogl_helpers.h"
33 
34 ALLEGRO_DEBUG_CHANNEL("opengl")
35 
36 /* Helper to set up GL state as we want it. */
_al_ogl_setup_gl(ALLEGRO_DISPLAY * d)37 void _al_ogl_setup_gl(ALLEGRO_DISPLAY *d)
38 {
39    ALLEGRO_OGL_EXTRAS *ogl = d->ogl_extras;
40 
41    if (ogl->backbuffer) {
42       ALLEGRO_BITMAP *target = al_get_target_bitmap();
43       _al_ogl_resize_backbuffer(ogl->backbuffer, d->w, d->h);
44       /* If we are currently targetting the backbuffer, we need to update the
45        * transformations. */
46       if (target && (target == ogl->backbuffer ||
47                      target->parent == ogl->backbuffer)) {
48          /* vt should be set at this point, but doesn't hurt to check */
49          ASSERT(d->vt);
50          d->vt->update_transformation(d, target);
51       }
52    } else {
53       ogl->backbuffer = _al_ogl_create_backbuffer(d);
54    }
55 }
56 
57 
_al_ogl_set_target_bitmap(ALLEGRO_DISPLAY * display,ALLEGRO_BITMAP * bitmap)58 void _al_ogl_set_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap)
59 {
60    ALLEGRO_BITMAP *target = bitmap;
61    if (bitmap->parent)
62       target = bitmap->parent;
63 
64    /* if either this bitmap or its parent (in the case of subbitmaps)
65     * is locked then don't do anything
66     */
67    if (bitmap->locked)
68       return;
69    if (bitmap->parent && bitmap->parent->locked)
70       return;
71 
72    _al_ogl_setup_fbo(display, bitmap);
73    if (display->ogl_extras->opengl_target == target) {
74       _al_ogl_setup_bitmap_clipping(bitmap);
75    }
76 }
77 
78 
_al_ogl_unset_target_bitmap(ALLEGRO_DISPLAY * display,ALLEGRO_BITMAP * target)79 void _al_ogl_unset_target_bitmap(ALLEGRO_DISPLAY *display,
80    ALLEGRO_BITMAP *target)
81 {
82    if (!target)
83       return;
84    _al_ogl_finalize_fbo(display, target);
85 }
86 
87 
88 /* Function: al_set_current_opengl_context
89  */
al_set_current_opengl_context(ALLEGRO_DISPLAY * display)90 void al_set_current_opengl_context(ALLEGRO_DISPLAY *display)
91 {
92    ASSERT(display);
93 
94    if (!(display->flags & ALLEGRO_OPENGL))
95       return;
96 
97    if (display) {
98       ALLEGRO_BITMAP *bmp = al_get_target_bitmap();
99       if (bmp && _al_get_bitmap_display(bmp) &&
100             _al_get_bitmap_display(bmp) != display) {
101          al_set_target_bitmap(NULL);
102       }
103    }
104 
105    _al_set_current_display_only(display);
106 }
107 
108 
_al_ogl_setup_bitmap_clipping(const ALLEGRO_BITMAP * bitmap)109 void _al_ogl_setup_bitmap_clipping(const ALLEGRO_BITMAP *bitmap)
110 {
111    int x_1, y_1, x_2, y_2, h;
112    bool use_scissor = true;
113 
114    x_1 = bitmap->cl;
115    y_1 = bitmap->ct;
116    x_2 = bitmap->cr_excl;
117    y_2 = bitmap->cb_excl;
118    h = bitmap->h;
119 
120    /* Drawing onto the sub bitmap is handled by clipping the parent. */
121    if (bitmap->parent) {
122       x_1 += bitmap->xofs;
123       y_1 += bitmap->yofs;
124       x_2 += bitmap->xofs;
125       y_2 += bitmap->yofs;
126       h = bitmap->parent->h;
127    }
128 
129    if (x_1 == 0 &&  y_1 == 0 && x_2 == bitmap->w && y_2 == bitmap->h) {
130       if (bitmap->parent) {
131          /* Can only disable scissor if the sub-bitmap covers the
132           * complete parent.
133           */
134          if (bitmap->xofs == 0 && bitmap->yofs == 0 &&
135             bitmap->w == bitmap->parent->w && bitmap->h == bitmap->parent->h)
136          {
137             use_scissor = false;
138          }
139       }
140       else {
141          use_scissor = false;
142       }
143    }
144    if (!use_scissor) {
145       glDisable(GL_SCISSOR_TEST);
146    }
147    else {
148       glEnable(GL_SCISSOR_TEST);
149 
150       #ifdef ALLEGRO_IPHONE
151       _al_iphone_clip(bitmap, x_1, y_1, x_2, y_2);
152       #else
153       /* OpenGL is upside down, so must adjust y_2 to the height. */
154       glScissor(x_1, h - y_2, x_2 - x_1, y_2 - y_1);
155       #endif
156    }
157 }
158 
159 
_al_ogl_get_backbuffer(ALLEGRO_DISPLAY * d)160 ALLEGRO_BITMAP *_al_ogl_get_backbuffer(ALLEGRO_DISPLAY *d)
161 {
162    return (ALLEGRO_BITMAP *)d->ogl_extras->backbuffer;
163 }
164 
165 
_al_ogl_resize_backbuffer(ALLEGRO_BITMAP * b,int w,int h)166 bool _al_ogl_resize_backbuffer(ALLEGRO_BITMAP *b, int w, int h)
167 {
168    int pitch;
169    ALLEGRO_BITMAP_EXTRA_OPENGL *extra = b->extra;
170 
171    pitch = w * al_get_pixel_size(al_get_bitmap_format(b));
172 
173    b->w = w;
174    b->h = h;
175    b->pitch = pitch;
176    b->cl = 0;
177    b->ct = 0;
178    b->cr_excl = w;
179    b->cb_excl = h;
180    al_identity_transform(&b->proj_transform);
181    al_orthographic_transform(&b->proj_transform, 0, 0, -1.0, w, h, 1.0);
182 
183    /* There is no texture associated with the backbuffer so no need to care
184     * about texture size limitations. */
185    extra->true_w = w;
186    extra->true_h = h;
187 
188    b->memory = NULL;
189 
190    return true;
191 }
192 
193 
_al_ogl_create_backbuffer(ALLEGRO_DISPLAY * disp)194 ALLEGRO_BITMAP* _al_ogl_create_backbuffer(ALLEGRO_DISPLAY *disp)
195 {
196    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_backbuffer;
197    ALLEGRO_BITMAP *backbuffer;
198    int format;
199 
200    ALLEGRO_DEBUG("Creating backbuffer\n");
201 
202    // FIXME: _al_deduce_color_format would work fine if the display paramerers
203    // are filled in, for OpenGL ES
204    if (IS_OPENGLES) {
205       if (disp->extra_settings.settings[ALLEGRO_COLOR_SIZE] == 16) {
206          format = ALLEGRO_PIXEL_FORMAT_RGB_565;
207       }
208       else {
209          format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE;
210       }
211    }
212    else {
213       format = _al_deduce_color_format(&disp->extra_settings);
214       /* Eww. No OpenGL hardware in the world does that - let's just
215        * switch to some default.
216        */
217       if (al_get_pixel_size(format) == 3) {
218          /* Or should we use RGBA? Maybe only if not Nvidia cards? */
219          format = ALLEGRO_PIXEL_FORMAT_ABGR_8888;
220       }
221    }
222    ALLEGRO_TRACE_CHANNEL_LEVEL("display", 1)("Deduced format %s for backbuffer.\n",
223       _al_pixel_format_name(format));
224 
225    /* Now that the display backbuffer has a format, update extra_settings so
226     * the user can query it back.
227     */
228    _al_set_color_components(format, &disp->extra_settings, ALLEGRO_REQUIRE);
229    disp->backbuffer_format = format;
230 
231    ALLEGRO_DEBUG("Creating backbuffer bitmap\n");
232    /* Using ALLEGRO_NO_PRESERVE_TEXTURE prevents extra memory being allocated */
233    backbuffer = _al_ogl_create_bitmap(disp, disp->w, disp->h,
234       format, ALLEGRO_VIDEO_BITMAP | ALLEGRO_NO_PRESERVE_TEXTURE);
235    if (!backbuffer) {
236       ALLEGRO_DEBUG("Backbuffer bitmap creation failed.\n");
237       return NULL;
238    }
239 
240    backbuffer->w = disp->w;
241    backbuffer->h = disp->h;
242    backbuffer->cl = 0;
243    backbuffer->ct = 0;
244    backbuffer->cr_excl = disp->w;
245    backbuffer->cb_excl = disp->h;
246    al_identity_transform(&backbuffer->transform);
247    al_identity_transform(&backbuffer->proj_transform);
248    al_orthographic_transform(&backbuffer->proj_transform, 0, 0, -1.0, disp->w, disp->h, 1.0);
249 
250    ALLEGRO_TRACE_CHANNEL_LEVEL("display", 1)(
251       "Created backbuffer bitmap (actual format: %s)\n",
252       _al_pixel_format_name(al_get_bitmap_format(backbuffer)));
253 
254    ogl_backbuffer = backbuffer->extra;
255    ogl_backbuffer->true_w = disp->w;
256    ogl_backbuffer->true_h = disp->h;
257    ogl_backbuffer->is_backbuffer = 1;
258    backbuffer->_display = disp;
259 
260    return backbuffer;
261 }
262 
263 
_al_ogl_destroy_backbuffer(ALLEGRO_BITMAP * b)264 void _al_ogl_destroy_backbuffer(ALLEGRO_BITMAP *b)
265 {
266    al_destroy_bitmap(b);
267 }
268 
269 
270 /* vi: set sts=3 sw=3 et: */
271