bool retro_load_game(const struct retro_game_info *info) { enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) return false; struct retro_frame_time_callback frame_cb = { frame_time_cb, 1000000 / 60 }; frame_cb.callback(frame_cb.reference); environ_cb(RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK, &frame_cb); load_game(); (void)info; return true; }
void GlRenderer::bind_libretro_framebuffer() { uint32_t f_w = this->frontend_resolution[0]; uint32_t f_h = this->frontend_resolution[1]; uint16_t _w = this->config->display_resolution[0]; uint16_t _h = this->config->display_resolution[1]; uint32_t upscale = this->internal_upscaling; // XXX scale w and h when implementing increased internal // resolution uint32_t w = (uint32_t) _w * upscale; uint32_t h = (uint32_t) _h * upscale; if (w != f_w || h != f_h) { // We need to change the frontend's resolution struct retro_game_geometry geometry; geometry.base_width = w; geometry.base_height = h; // Max parameters are ignored by this call geometry.max_width = 0; geometry.max_height = 0; // Is this accurate? geometry.aspect_ratio = 4.0/3.0; printf("Target framebuffer size: %dx%d\n", w, h); environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &geometry); this->frontend_resolution[0] = w; this->frontend_resolution[1] = h; } // Bind the output framebuffer provided by the frontend /* TODO/FIXME - I think glsm_ctl(BIND) is the way to go here. Check with the libretro devs */ GLuint fbo = glsm_get_current_framebuffer(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); glViewport(0, 0, (GLsizei) w, (GLsizei) h); }
bool GlRenderer::refresh_variables() { struct retro_variable var = {0}; var.key = "beetle_psx_internal_resolution"; uint8_t upscaling = 1; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { /* Same limitations as libretro.cpp */ upscaling = var.value[0] -'0'; } var.key = "beetle_psx_filter"; uint8_t filter = 0; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "nearest")) filter = 0; else if (!strcmp(var.value, "3point N64")) filter = 1; else if (!strcmp(var.value, "bilinear")) filter = 2; this->filter_type = filter; } var.key = "beetle_psx_internal_color_depth"; uint8_t depth = 16; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { depth = !strcmp(var.value, "32bpp") ? 32 : 16; } var.key = "beetle_psx_scale_dither"; bool scale_dither = false; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "enabled")) scale_dither = true; else scale_dither = false; } var.key = "beetle_psx_wireframe"; bool wireframe = false; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "enabled")) wireframe = true; else wireframe = false; } bool rebuild_fb_out = upscaling != this->internal_upscaling || depth != this->internal_color_depth; if (rebuild_fb_out) { if (depth > 16) { this->command_buffer->disable_attribute("dither"); } else { this->command_buffer->enable_attribute("dither"); } uint32_t native_width = (uint32_t) VRAM_WIDTH_PIXELS; uint32_t native_height = (uint32_t) VRAM_HEIGHT; uint32_t w = native_width * upscaling; uint32_t h = native_height * upscaling; GLenum texture_storage = GL_RGB5_A1; switch (depth) { case 16: texture_storage = GL_RGB5_A1; break; case 32: texture_storage = GL_RGBA8; break; default: printf("Unsupported depth %d\n", depth); exit(EXIT_FAILURE); } Texture* fb_out = new Texture(w, h, texture_storage); if (this->fb_out) { delete this->fb_out; this->fb_out = NULL; } this->fb_out = fb_out; // This is a bit wasteful since it'll re-upload the data // to `fb_texture` even though we haven't touched it but // this code is not very performance-critical anyway. uint16_t top_left[2] = {0, 0}; uint16_t dimensions[2] = {(uint16_t) VRAM_WIDTH_PIXELS, (uint16_t) VRAM_HEIGHT}; this->upload_textures(top_left, dimensions, this->config->vram); if (this->fb_out_depth) { delete this->fb_out_depth; this->fb_out_depth = NULL; } this->fb_out_depth = new Texture(w, h, GL_DEPTH_COMPONENT32F); } uint32_t dither_scaling = scale_dither ? upscaling : 1; this->command_buffer->program->uniform1ui("dither_scaling", (GLuint) dither_scaling); this->command_buffer->program->uniform1ui("texture_flt", this->filter_type); this->command_polygon_mode = wireframe ? GL_LINE : GL_FILL; glLineWidth((GLfloat) upscaling); // If the scaling factor has changed the frontend should be // reconfigured. We can't do that here because it could // destroy the OpenGL context which would destroy `self` //// r5 - replace 'self' by 'this' bool reconfigure_frontend = this->internal_upscaling != upscaling; this->internal_upscaling = upscaling; this->internal_color_depth = depth; return reconfigure_frontend; }
GlRenderer::GlRenderer(DrawConfig* config) { struct retro_variable var = {0}; var.key = "beetle_psx_internal_resolution"; uint8_t upscaling = 1; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { /* Same limitations as libretro.cpp */ upscaling = var.value[0] -'0'; } var.key = "beetle_psx_filter"; uint8_t filter = 0; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "nearest")) filter = 0; else if (!strcmp(var.value, "3point N64")) filter = 1; else if (!strcmp(var.value, "bilinear")) filter = 2; this->filter_type = filter; } var.key = "beetle_psx_internal_color_depth"; uint8_t depth = 16; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "32bpp")) depth = 32; else depth = 16; } var.key = "beetle_psx_scale_dither"; bool scale_dither = false; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "enabled")) scale_dither = true; else scale_dither = false; } var.key = "beetle_psx_wireframe"; bool wireframe = false; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (!strcmp(var.value, "enabled")) wireframe = true; else wireframe = false; } printf("Building OpenGL state (%dx internal res., %dbpp)\n", upscaling, depth); DrawBuffer<CommandVertex>* opaque_command_buffer = GlRenderer::build_buffer<CommandVertex>( command_vertex, command_fragment, VERTEX_BUFFER_LEN, true); DrawBuffer<OutputVertex>* output_buffer = GlRenderer::build_buffer<OutputVertex>( output_vertex, output_fragment, 4, false); DrawBuffer<ImageLoadVertex>* image_load_buffer = GlRenderer::build_buffer<ImageLoadVertex>( image_load_vertex, image_load_fragment, 4, false); uint32_t native_width = (uint32_t) VRAM_WIDTH_PIXELS; uint32_t native_height = (uint32_t) VRAM_HEIGHT; // Texture holding the raw VRAM texture contents. We can't // meaningfully upscale it since most games use paletted // textures. Texture* fb_texture = new Texture(native_width, native_height, GL_RGB5_A1); if (depth > 16) { // Dithering is superfluous when we increase the internal // color depth opaque_command_buffer->disable_attribute("dither"); } uint32_t dither_scaling = scale_dither ? upscaling : 1; GLenum command_draw_mode = wireframe ? GL_LINE : GL_FILL; opaque_command_buffer->program->uniform1ui("dither_scaling", dither_scaling); opaque_command_buffer->program->uniform1ui("texture_flt", this->filter_type); GLenum texture_storage = GL_RGB5_A1; switch (depth) { case 16: texture_storage = GL_RGB5_A1; break; case 32: texture_storage = GL_RGBA8; break; default: printf("Unsupported depth %d\n", depth); exit(EXIT_FAILURE); } Texture* fb_out = new Texture( native_width * upscaling, native_height * upscaling, texture_storage); Texture* fb_out_depth = new Texture( fb_out->width, fb_out->height, GL_DEPTH_COMPONENT32F); // let mut state = GlRenderer { this->filter_type = filter; this->command_buffer = opaque_command_buffer; this->command_draw_mode = GL_TRIANGLES; this->semi_transparent_vertices.reserve((size_t) VERTEX_BUFFER_LEN); this->semi_transparency_mode = SemiTransparencyMode_Average; this->command_polygon_mode = command_draw_mode; this->output_buffer = output_buffer; this->image_load_buffer = image_load_buffer; this->config = config; this->fb_texture = fb_texture; this->fb_out = fb_out; this->fb_out_depth = fb_out_depth; this->frontend_resolution[0] = 0; this->frontend_resolution[1] = 0; this->internal_upscaling = upscaling; this->internal_color_depth = depth; this->primitive_ordering = 0; this->tex_x_mask = 0; this->tex_x_or = 0; this->tex_y_mask = 0; this->tex_y_or = 0; // } this->display_off = true; //// NOTE: r5 - I have no idea what a borrow checker is. // Yet an other copy of this 1MB array to make the borrow // checker happy... uint16_t top_left[2] = {0, 0}; uint16_t dimensions[2] = {(uint16_t) VRAM_WIDTH_PIXELS, (uint16_t) VRAM_HEIGHT}; this->upload_textures(top_left, dimensions, this->config->vram); }
void MAPPER_Init() { struct retro_keyboard_callback callback = { keyboard_event }; environ_cb(RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK, &callback); inputList.clear(); inputList.push_back(new MouseButton(RDID(MOUSE_LEFT), 0)); inputList.push_back(new MouseButton(RDID(MOUSE_RIGHT), 1)); struct retro_input_descriptor desc[64]; joytype=JOY_AUTO; if(connected[0] && connected[1]) { joytype = JOY_2AXIS; joystick_type[0] = JOY_2AXIS; joystick_type[1] = JOY_2AXIS; } else { if(connected[0]) { joytype = joystick_type[0]; joystick_type[1] = JOY_NONE; } else joystick_type[0] = JOY_NONE; if(connected[1]) { joytype = joystick_type[1]; joystick_type[0] = JOY_NONE; } else joystick_type[1] = JOY_NONE; } struct retro_input_descriptor desc_dpad[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 255, 255, 255, 255, "" }, }; struct retro_input_descriptor desc_2axis[] = { { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Analog X" }, { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Analog Y" }, { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Analog X" }, { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Analog Y" }, { 255, 255, 255, 255, "" }, }; struct retro_input_descriptor desc_4axis[] = { { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" }, { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" }, { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" }, { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" }, { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" }, { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" }, { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" }, { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" }, { 255, 255, 255, 255, "" }, }; struct retro_input_descriptor desc_kbd[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Kbd Left" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Kbd Up" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Kbd Down" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Kbd Right" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Enter" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Esc" }, { 255, 255, 255, 255, "" }, }; struct retro_input_descriptor desc_2button[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Button 2" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Button 1" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Enter" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Esc" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Button 2" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Button 1" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Enter" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Esc" }, { 255, 255, 255, 255, "" }, }; struct retro_input_descriptor desc_4button[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Button 1" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Button 2" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Button 3" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Button 4" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Esc" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Enter" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Button 1" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Button 2" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Button 3" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Button 4" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Enter" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Esc" }, { 255, 255, 255, 255, "" }, }; struct retro_input_descriptor empty = { 255, 255, 255, 255, "" }; int i = 0; int j = 0; int k = 0; for(i=0;i<64;i++) desc[i] = empty; i=0; for(int port=0;port<2;port++) { log_cb(RETRO_LOG_INFO, "Configuring port: %d\n",port); switch(joystick_type[port]) { case JOY_2AXIS: //buttons inputList.push_back(new JoystickButton(port, RDID(JOYPAD_Y), port, 0)); inputList.push_back(new JoystickButton(port, RDID(JOYPAD_B), port, 1)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_START),51)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_SELECT),48)); for(j=0;desc_2button[j].port!=port;j++); for(;desc_2button[j].port == port;j++) { desc[i] = desc_2button[j]; i++; } //axes if(dpad[port]) { inputList.push_back(new JoystickHat(port, RDID(JOYPAD_LEFT), port, 0)); inputList.push_back(new JoystickHat(port, RDID(JOYPAD_RIGHT), port, 0)); inputList.push_back(new JoystickHat(port, RDID(JOYPAD_UP), port, 1)); inputList.push_back(new JoystickHat(port, RDID(JOYPAD_DOWN), port, 1)); for(j=0;desc_dpad[j].port!=port;j++); for(;desc_dpad[j].port == port;j++) { desc[i] = desc_dpad[j]; i++; } } else { inputList.push_back(new JoystickAxis(port, RDIX(ANALOG_LEFT), RDID(ANALOG_X), port, 0)); inputList.push_back(new JoystickAxis(port, RDIX(ANALOG_LEFT), RDID(ANALOG_Y), port, 1)); for(j=0;desc_2axis[j].port!=port;j++); for(;desc_2axis[j].port == port;j++) { desc[i] = desc_2axis[j]; i++; } } if(emulated_kbd[port] && port == 0) { inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_LEFT),80)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_RIGHT),83)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_UP),81)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_DOWN),82)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_START),51)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_SELECT),48)); for(j=0;desc_kbd[j].port!=port;j++); for(;desc_kbd[j].port == port;j++) { desc[i] = desc_kbd[j]; i++; } } JOYSTICK_Enable(port, true); break; case JOY_4AXIS: //buttons inputList.push_back(new JoystickButton(port, RDID(JOYPAD_Y), 0, 0)); inputList.push_back(new JoystickButton(port, RDID(JOYPAD_X), 0, 1)); inputList.push_back(new JoystickButton(port, RDID(JOYPAD_B), 1, 0)); inputList.push_back(new JoystickButton(port, RDID(JOYPAD_A), 1, 1)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_START),51)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_SELECT),48)); for(j=0;desc_4button[j].port!=port;j++); for(;desc_4button[j].port == port;j++) { desc[i] = desc_4button[j]; i++; } //axes if(dpad[port]) { inputList.push_back(new JoystickHat(port, RDID(JOYPAD_LEFT), port, 0)); inputList.push_back(new JoystickHat(port, RDID(JOYPAD_RIGHT), port, 0)); inputList.push_back(new JoystickHat(port, RDID(JOYPAD_UP), port, 1)); inputList.push_back(new JoystickHat(port, RDID(JOYPAD_DOWN), port, 1)); for(j=0;desc_dpad[j].port!=port;j++); for(;desc_dpad[j].port == port;j++) { desc[i] = desc_dpad[j]; i++; } } else { inputList.push_back(new JoystickAxis(port, RDIX(ANALOG_LEFT), RDID(ANALOG_X), 0, 0)); inputList.push_back(new JoystickAxis(port, RDIX(ANALOG_LEFT), RDID(ANALOG_Y), 0, 1)); inputList.push_back(new JoystickAxis(port, RDIX(ANALOG_RIGHT), RDID(ANALOG_X), 1, 0)); inputList.push_back(new JoystickAxis(port, RDIX(ANALOG_RIGHT), RDID(ANALOG_Y), 1, 1)); for(j=0;desc_2axis[j].port!=port;j++); for(;desc_2axis[j].port == port;j++) { desc[i] = desc_2axis[j]; i++; } } if(emulated_kbd[port] && port == 0) { inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_LEFT),80)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_RIGHT),83)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_UP),81)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_DOWN),82)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_START),51)); inputList.push_back(new EmulatedKeyPress(0, RDID(JOYPAD_SELECT),48)); for(j=0;desc_kbd[j].port!=port;j++); for(;desc_kbd[j].port == port;j++) { desc[i] = desc_kbd[j]; i++; } } JOYSTICK_Enable(0, true); JOYSTICK_Enable(1, true); break; } } /*for(i=0;i<64;i++) log_cb(RETRO_LOG_DEBUG,"%d\n",desc[i].port);*/ environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); }