renderer.cpp (11513B)
1/* 2 * Gearboy - Nintendo Game Boy Emulator 3 * Copyright (C) 2012 Ignacio Sanchez 4 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * any later version. 9 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see http://www.gnu.org/licenses/ 17 * 18 */ 19 20#ifdef __APPLE__ 21#define GL_SILENCE_DEPRECATION 22#include <OpenGL/gl.h> 23#else 24#include <GL/glew.h> 25#include <SDL_opengl.h> 26#endif 27 28#include "imgui/imgui.h" 29#include "imgui/imgui_impl_opengl2.h" 30#include "emu.h" 31#include "config.h" 32#include "../../src/gearboy.h" 33 34#define RENDERER_IMPORT 35#include "renderer.h" 36 37static uint32_t gameboy_texture; 38static uint32_t matrix_texture; 39static uint32_t frame_buffer_object; 40static bool first_frame; 41static u32 matrix[16] = {0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF}; 42static const int FRAME_BUFFER_SCALE = 4; 43 44static void init_ogl_gui(void); 45static void init_ogl_emu(void); 46static void init_ogl_debug(void); 47static void init_matrix_textures(void); 48static void render_gui(void); 49static void render_emu_normal(void); 50static void render_emu_mix(void); 51static void render_emu_bilinear(void); 52static void render_quad(int viewportWidth, int viewportHeight); 53static void update_system_texture(void); 54static void update_debug_textures(void); 55static void render_matrix(void); 56 57void renderer_init(void) 58{ 59 #ifndef __APPLE__ 60 GLenum err = glewInit(); 61 if (GLEW_OK != err) 62 { 63 /* Problem: glewInit failed, something is seriously wrong. */ 64 Log("GLEW Error: %s\n", glewGetErrorString(err)); 65 } 66 67 renderer_glew_version = (const char*)glewGetString(GLEW_VERSION); 68 renderer_opengl_version = (const char*)glGetString(GL_VERSION); 69 70 Log("Using GLEW %s\n", renderer_glew_version); 71 72 #endif 73 74 init_ogl_gui(); 75 init_ogl_emu(); 76 init_ogl_debug(); 77 78 first_frame = true; 79} 80 81void renderer_destroy(void) 82{ 83 glDeleteFramebuffers(1, &frame_buffer_object); 84 glDeleteTextures(1, &renderer_emu_texture); 85 glDeleteTextures(1, &gameboy_texture); 86 glDeleteTextures(1, &matrix_texture); 87 glDeleteTextures(1, &renderer_emu_debug_vram_background); 88 glDeleteTextures(2, renderer_emu_debug_vram_tiles); 89 glDeleteTextures(40, renderer_emu_debug_vram_oam); 90 ImGui_ImplOpenGL2_Shutdown(); 91} 92 93void renderer_begin_render(void) 94{ 95 ImGui_ImplOpenGL2_NewFrame(); 96} 97 98void renderer_render(void) 99{ 100 if (config_debug.debug) 101 { 102 update_debug_textures(); 103 } 104 105 if (config_video.mix_frames) 106 render_emu_mix(); 107 else 108 render_emu_normal(); 109 110 if (config_video.matrix) 111 render_matrix(); 112 113 render_emu_bilinear(); 114 115 ImVec4 clear_color = ImVec4(0.1f, 0.1f, 0.1f, 1.00f); 116 117 glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y); 118 glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); 119 glClear(GL_COLOR_BUFFER_BIT); 120 121 render_gui(); 122} 123 124void renderer_end_render(void) 125{ 126 127} 128 129static void init_ogl_gui(void) 130{ 131 ImGui_ImplOpenGL2_Init(); 132} 133 134static void init_ogl_emu(void) 135{ 136 glEnable(GL_TEXTURE_2D); 137 138 glGenFramebuffers(1, &frame_buffer_object); 139 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_object); 140 141 glGenTextures(1, &renderer_emu_texture); 142 glBindTexture(GL_TEXTURE_2D, renderer_emu_texture); 143 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAMEBOY_WIDTH * FRAME_BUFFER_SCALE, GAMEBOY_HEIGHT * FRAME_BUFFER_SCALE, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); 144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 145 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 146 147 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderer_emu_texture, 0); 148 149 glBindFramebuffer(GL_FRAMEBUFFER, 0); 150 151 glGenTextures(1, &gameboy_texture); 152 glBindTexture(GL_TEXTURE_2D, gameboy_texture); 153 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAMEBOY_WIDTH, GAMEBOY_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) emu_frame_buffer); 154 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 156 157 init_matrix_textures(); 158} 159 160static void init_ogl_debug(void) 161{ 162 glGenTextures(1, &renderer_emu_debug_vram_background); 163 glBindTexture(GL_TEXTURE_2D, renderer_emu_debug_vram_background); 164 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)emu_debug_background_buffer); 165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 167 168 for (int b = 0; b < 2; b++) 169 { 170 glGenTextures(1, &renderer_emu_debug_vram_tiles[b]); 171 glBindTexture(GL_TEXTURE_2D, renderer_emu_debug_vram_tiles[b]); 172 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16 * 8, 24 * 8, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)emu_debug_tile_buffers[b]); 173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 175 } 176 177 for (int s = 0; s < 40; s++) 178 { 179 glGenTextures(1, &renderer_emu_debug_vram_oam[s]); 180 glBindTexture(GL_TEXTURE_2D, renderer_emu_debug_vram_oam[s]); 181 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)emu_debug_oam_buffers[s]); 182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 183 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 184 } 185} 186 187static void init_matrix_textures(void) 188{ 189 glGenTextures(1, &matrix_texture); 190 191 glBindTexture(GL_TEXTURE_2D, matrix_texture); 192 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (GLvoid*) matrix); 193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 197} 198 199static void render_gui(void) 200{ 201 ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); 202} 203 204static void render_emu_normal(void) 205{ 206 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_object); 207 208 glDisable(GL_BLEND); 209 210 update_system_texture(); 211 212 render_quad(GAMEBOY_WIDTH * FRAME_BUFFER_SCALE, GAMEBOY_HEIGHT * FRAME_BUFFER_SCALE); 213 214 glBindFramebuffer(GL_FRAMEBUFFER, 0); 215} 216 217static void render_emu_mix(void) 218{ 219 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_object); 220 221 float alpha = 0.15f + (0.20f * (1.0f - config_video.mix_frames_intensity)); 222 223 if (first_frame) 224 { 225 first_frame = false; 226 alpha = 1.0f; 227 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 228 glClear(GL_COLOR_BUFFER_BIT); 229 } 230 231 static bool round_error = false; 232 float round_color = 1.0f - (round_error ? 0.03f : 0.0f); 233 round_error = !round_error; 234 235 glEnable(GL_BLEND); 236 glColor4f(round_color, round_color, round_color, alpha); 237 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 238 239 update_system_texture(); 240 241 render_quad(GAMEBOY_WIDTH * FRAME_BUFFER_SCALE, GAMEBOY_HEIGHT * FRAME_BUFFER_SCALE); 242 243 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 244 glDisable(GL_BLEND); 245 246 glBindFramebuffer(GL_FRAMEBUFFER, 0); 247} 248 249static void update_system_texture(void) 250{ 251 glBindTexture(GL_TEXTURE_2D, gameboy_texture); 252 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GAMEBOY_WIDTH, GAMEBOY_HEIGHT, 253 GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) emu_frame_buffer); 254 255 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 257 258 if (config_video.bilinear) 259 { 260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 262 } 263 else 264 { 265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 267 } 268} 269 270static void update_debug_textures(void) 271{ 272 glBindTexture(GL_TEXTURE_2D, renderer_emu_debug_vram_background); 273 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 256, 274 GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) emu_debug_background_buffer); 275 276 for (int b = 0; b < 2; b++) 277 { 278 glBindTexture(GL_TEXTURE_2D, renderer_emu_debug_vram_tiles[b]); 279 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 16 * 8, 24 * 8, 280 GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) emu_debug_tile_buffers[b]); 281 } 282 283 for (int s = 0; s < 40; s++) 284 { 285 glBindTexture(GL_TEXTURE_2D, renderer_emu_debug_vram_oam[s]); 286 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 16, 287 GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) emu_debug_oam_buffers[s]); 288 } 289} 290 291static void render_emu_bilinear(void) 292{ 293 glBindTexture(GL_TEXTURE_2D, renderer_emu_texture); 294 295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 296 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 297 298 if (config_video.matrix) 299 { 300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 302 } 303 else 304 { 305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 307 } 308} 309 310static void render_quad(int viewportWidth, int viewportHeight) 311{ 312 glMatrixMode(GL_PROJECTION); 313 glLoadIdentity(); 314 315 glOrtho(0, viewportWidth, 0, viewportHeight, -1, 1); 316 317 glMatrixMode(GL_MODELVIEW); 318 glViewport(0, 0, viewportWidth, viewportHeight); 319 320 glBegin(GL_QUADS); 321 glTexCoord2d(0.0, 0.0); 322 glVertex2d(0.0, 0.0); 323 glTexCoord2d(1.0, 0.0); 324 glVertex2d(viewportWidth, 0.0); 325 glTexCoord2d(1.0, 1.0); 326 glVertex2d(viewportWidth, viewportHeight); 327 glTexCoord2d(0.0, 1.0); 328 glVertex2d(0.0, viewportHeight); 329 glEnd(); 330} 331 332static void render_matrix(void) 333{ 334 glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_object); 335 glEnable(GL_BLEND); 336 337 glColor4f(1.0f, 1.0f, 1.0f, config_video.matrix_intensity / 4.0f); 338 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 339 340 glBindTexture(GL_TEXTURE_2D, matrix_texture); 341 342 int viewportWidth = GAMEBOY_WIDTH * FRAME_BUFFER_SCALE; 343 int viewportHeight = GAMEBOY_HEIGHT * FRAME_BUFFER_SCALE; 344 345 glMatrixMode(GL_PROJECTION); 346 glLoadIdentity(); 347 348 glOrtho(0, viewportWidth, 0, viewportHeight, -1, 1); 349 350 glMatrixMode(GL_MODELVIEW); 351 glViewport(0, 0, viewportWidth, viewportHeight); 352 353 glBegin(GL_QUADS); 354 glTexCoord2d(0.0, 0.0); 355 glVertex2d(0.0, 0.0); 356 glTexCoord2d(GAMEBOY_WIDTH, 0.0); 357 glVertex2d(viewportWidth, 0.0); 358 glTexCoord2d(GAMEBOY_WIDTH, GAMEBOY_HEIGHT); 359 glVertex2d(viewportWidth, viewportHeight); 360 glTexCoord2d(0.0, GAMEBOY_HEIGHT); 361 glVertex2d(0.0, viewportHeight); 362 glEnd(); 363 364 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 365 366 glDisable(GL_BLEND); 367 glBindFramebuffer(GL_FRAMEBUFFER, 0); 368}