1 #include "graphics.hpp"
2
3 #include "asserts.hpp"
4 #include "preferences.hpp"
5 #include "texture.hpp"
6 #include "texture_frame_buffer.hpp"
7
8 #if defined(TARGET_OS_HARMATTAN) || defined(TARGET_PANDORA) || defined(TARGET_TEGRA) || defined(TARGET_BLACKBERRY)
9 #include <EGL/egl.h>
10 #define glGenFramebuffersOES preferences::glGenFramebuffersOES
11 #define glBindFramebufferOES preferences::glBindFramebufferOES
12 #define glFramebufferTexture2DOES preferences::glFramebufferTexture2DOES
13 #define glCheckFramebufferStatusOES preferences::glCheckFramebufferStatusOES
14 #endif
15
16 //define macros that make it easy to make the OpenGL calls in this file.
17 #if defined(USE_GLES2)
18 #define EXT_CALL(call) call
19 #define EXT_MACRO(macro) macro
20 #elif defined(TARGET_OS_HARMATTAN) || defined(TARGET_OS_IPHONE) || defined(TARGET_PANDORA) || defined(TARGET_TEGRA) || defined(TARGET_BLACKBERRY) || defined(__ANDROID__)
21 #define EXT_CALL(call) call##OES
22 #define EXT_MACRO(macro) macro##_OES
23 #elif defined(__APPLE__)
24 #define EXT_CALL(call) call##EXT
25 #define EXT_MACRO(macro) macro##_EXT
26 #else
27 #define EXT_CALL(call) call##EXT
28 #define EXT_MACRO(macro) macro##_EXT
29 #endif
30
31 namespace texture_frame_buffer {
32
33 namespace {
34 bool supported = true;
35 GLuint texture_id = 0, texture_id_back = 0; //ID of the texture which the frame buffer is stored in
36 GLuint framebuffer_id = 0, framebuffer_id_back = 0; //framebuffer object
37 GLint video_framebuffer_id = 0; //the original frame buffer object
38 int frame_buffer_texture_width = 128;
39 int frame_buffer_texture_height = 128;
40
init_internal(int buffer_width,int buffer_height)41 void init_internal(int buffer_width, int buffer_height)
42 {
43 // Clear any old errors.
44 glGetError();
45 frame_buffer_texture_width = buffer_width;
46 frame_buffer_texture_height = buffer_height;
47
48 #if /*defined(__ANDROID__) ||*/ defined(__native_client__)
49 {
50 supported = false;
51 LOG("FRAME BUFFER OBJECT NOT SUPPORTED");
52 return;
53 }
54 #endif
55
56 #if defined(TARGET_OS_HARMATTAN) || defined(TARGET_PANDORA) || defined(TARGET_TEGRA) || defined(TARGET_BLACKBERRY)
57 if (glGenFramebuffersOES != NULL &&
58 glBindFramebufferOES != NULL &&
59 glFramebufferTexture2DOES != NULL &&
60 glCheckFramebufferStatusOES != NULL)
61 {
62 supported = true;
63 }
64 else
65 {
66 fprintf(stderr, "FRAME BUFFER OBJECT NOT SUPPORTED\n");
67 supported = false;
68 return;
69 }
70 #endif
71 #if defined(__GLEW_H__)
72 if(!GLEW_EXT_framebuffer_object)
73 {
74 fprintf(stderr, "FRAME BUFFER OBJECT NOT SUPPORTED\n");
75 supported = false;
76 return;
77 }
78 #endif
79 fprintf(stderr, "FRAME BUFFER OBJECT IS SUPPORTED\n");
80
81 #ifndef TARGET_TEGRA
82 glGetIntegerv(EXT_MACRO(GL_FRAMEBUFFER_BINDING), &video_framebuffer_id);
83 #endif
84
85 // Clear any current errors.
86 GLenum err = glGetError();
87
88 glGenTextures(1, &texture_id);
89 glBindTexture(GL_TEXTURE_2D, texture_id);
90 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width(), height(), 0,
91 GL_RGBA, GL_UNSIGNED_BYTE, 0);
92 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
93 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
96 glBindTexture(GL_TEXTURE_2D, 0);
97
98
99 // create a framebuffer object
100 EXT_CALL(glGenFramebuffers)(1, &framebuffer_id);
101 EXT_CALL(glBindFramebuffer)(EXT_MACRO(GL_FRAMEBUFFER), framebuffer_id);
102
103 // attach the texture to FBO color attachment point
104 EXT_CALL(glFramebufferTexture2D)(EXT_MACRO(GL_FRAMEBUFFER), EXT_MACRO(GL_COLOR_ATTACHMENT0),
105 GL_TEXTURE_2D, texture_id, 0);
106
107 // check FBO status
108 GLenum status = EXT_CALL(glCheckFramebufferStatus)(EXT_MACRO(GL_FRAMEBUFFER));
109 if(status == EXT_MACRO(GL_FRAMEBUFFER_UNSUPPORTED)) {
110 std::cerr << "FRAME BUFFER OBJECT NOT SUPPORTED\n";
111 supported = false;
112 err = glGetError();
113 } else {
114 ASSERT_EQ(status, EXT_MACRO(GL_FRAMEBUFFER_COMPLETE));
115 }
116
117 // switch back to window-system-provided framebuffer
118 EXT_CALL(glBindFramebuffer)(EXT_MACRO(GL_FRAMEBUFFER), video_framebuffer_id);
119
120 err = glGetError();
121 ASSERT_EQ(err, GL_NO_ERROR);
122 }
123 }
124
init(int buffer_width,int buffer_height)125 void init(int buffer_width, int buffer_height)
126 {
127 init_internal(buffer_width, buffer_height);
128 switch_texture();
129 init_internal(buffer_width, buffer_height);
130 }
131
switch_texture()132 void switch_texture()
133 {
134 std::swap(texture_id, texture_id_back);
135 std::swap(framebuffer_id, framebuffer_id_back);
136 }
137
width()138 int width() { return frame_buffer_texture_width; }
height()139 int height() { return frame_buffer_texture_height; }
140
unsupported()141 bool unsupported()
142 {
143 return !supported;
144 }
145
set_render_to_texture()146 void set_render_to_texture()
147 {
148 EXT_CALL(glBindFramebuffer)(EXT_MACRO(GL_FRAMEBUFFER), framebuffer_id);
149 glViewport(0, 0, width(), height());
150 }
151
set_render_to_screen()152 void set_render_to_screen()
153 {
154 EXT_CALL(glBindFramebuffer)(EXT_MACRO(GL_FRAMEBUFFER), video_framebuffer_id);
155 glViewport(0, 0, preferences::actual_screen_width(), preferences::actual_screen_height());
156 }
157
render_scope()158 render_scope::render_scope()
159 {
160 set_render_to_texture();
161 }
162
~render_scope()163 render_scope::~render_scope()
164 {
165 set_render_to_screen();
166 }
167
set_as_current_texture()168 void set_as_current_texture()
169 {
170 graphics::texture::set_current_texture(texture_id);
171 }
172
173 } // namespace texture_frame_buffer
174