/** * input_translate_coord_viewport: * @mouse_x : Pointer X coordinate. * @mouse_y : Pointer Y coordinate. * @res_x : Scaled X coordinate. * @res_y : Scaled Y coordinate. * @res_screen_x : Scaled screen X coordinate. * @res_screen_y : Scaled screen Y coordinate. * * Translates pointer [X,Y] coordinates into scaled screen * coordinates based on viewport info. * * Returns: true (1) if successful, false if video driver doesn't support * viewport info. **/ bool input_translate_coord_viewport(int mouse_x, int mouse_y, int16_t *res_x, int16_t *res_y, int16_t *res_screen_x, int16_t *res_screen_y) { int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y; struct video_viewport vp = {0}; if (!video_driver_get_viewport_info(&vp)) return false; scaled_screen_x = (2 * mouse_x * 0x7fff) / (int)vp.full_width - 0x7fff; scaled_screen_y = (2 * mouse_y * 0x7fff) / (int)vp.full_height - 0x7fff; if (scaled_screen_x < -0x7fff || scaled_screen_x > 0x7fff) scaled_screen_x = -0x8000; /* OOB */ if (scaled_screen_y < -0x7fff || scaled_screen_y > 0x7fff) scaled_screen_y = -0x8000; /* OOB */ mouse_x -= vp.x; mouse_y -= vp.y; scaled_x = (2 * mouse_x * 0x7fff) / (int)vp.width - 0x7fff; scaled_y = (2 * mouse_y * 0x7fff) / (int)vp.height - 0x7fff; if (scaled_x < -0x7fff || scaled_x > 0x7fff) scaled_x = -0x8000; /* OOB */ if (scaled_y < -0x7fff || scaled_y > 0x7fff) scaled_y = -0x8000; /* OOB */ *res_x = scaled_x; *res_y = scaled_y; *res_screen_x = scaled_screen_x; *res_screen_y = scaled_screen_y; return true; }
int setting_uint_action_left_custom_viewport_height( void *data, bool wraparound) { video_viewport_t vp; struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); video_viewport_t *custom = video_viewport_get_custom(); settings_t *settings = config_get_ptr(); struct retro_game_geometry *geom = (struct retro_game_geometry*) &av_info->geometry; if (!settings || !av_info) return -1; video_driver_get_viewport_info(&vp); if (custom->height <= 1) custom->height = 1; else if (settings->bools.video_scale_integer) { if (custom->height > geom->base_height) custom->height -= geom->base_height; } else custom->height -= 1; aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (float)custom->width / custom->height; return 0; }
static void update_touch_state(int16_t state[3][2], uint64_t *buttons, VPADStatus *vpad) { VPADTouchData point = {0}; struct video_viewport viewport = {0}; bool touch_clamped = false; if (!vpad->tpNormal.touched || vpad->tpNormal.validity != VPAD_VALID) { *buttons &= ~VPAD_BUTTON_TOUCH; return; } video_driver_get_viewport_info(&viewport); get_touch_coordinates(&point, vpad, &viewport, &touch_clamped); state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_X] = scale_touchpad( viewport.x, viewport.x + viewport.width, -0x7fff, 0x7fff, point.x); state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_Y] = scale_touchpad( viewport.y, viewport.y + viewport.height, -0x7fff, 0x7fff, point.y); #if 0 log_coords(state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_X], state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_Y]); #endif if (!touch_clamped) *buttons |= VPAD_BUTTON_TOUCH; else *buttons &= ~VPAD_BUTTON_TOUCH; }
static bool take_screenshot_viewport(const char *global_name_base) { char screenshot_path[PATH_MAX_LENGTH] = {0}; const char *screenshot_dir = NULL; uint8_t *buffer = NULL; bool retval = false; struct video_viewport vp = {0}; settings_t *settings = config_get_ptr(); video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) return false; buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!buffer) return false; if (!video_driver_read_viewport(buffer)) goto done; screenshot_dir = settings->directory.screenshot; if (string_is_empty(screenshot_dir)) { fill_pathname_basedir(screenshot_path, global_name_base, sizeof(screenshot_path)); screenshot_dir = screenshot_path; } /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(global_name_base, screenshot_dir, buffer, vp.width, vp.height, vp.width * 3, true)) goto done; retval = true; done: if (buffer) free(buffer); return retval; }
static bool take_screenshot_viewport(const char *name_base, bool savestate, bool is_idle, bool is_paused) { struct video_viewport vp; uint8_t *buffer = NULL; bool retval = false; vp.x = 0; vp.y = 0; vp.width = 0; vp.height = 0; vp.full_width = 0; vp.full_height = 0; video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) return false; buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!buffer) return false; if (!video_driver_read_viewport(buffer, is_idle)) goto error; /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(name_base, buffer, vp.width, vp.height, vp.width * 3, true, buffer, savestate, is_idle, is_paused)) goto error; return true; error: if (buffer) free(buffer); return retval; }
static void winraw_init_mouse_xy_mapping() { struct video_viewport viewport; int center_x; int center_y; unsigned i; if (video_driver_get_viewport_info(&viewport)) { center_x = viewport.x + viewport.width / 2; center_y = viewport.y + viewport.height / 2; for (i = 0; i < g_mouse_cnt; ++i) { g_mice[i].x = center_x; g_mice[i].y = center_y; } g_view_abs_ratio_x = (double)viewport.full_width / 65535.0; g_view_abs_ratio_y = (double)viewport.full_height / 65535.0; g_mouse_xy_mapping_ready = true; } }
/** * recording_init: * * Initializes recording. * * Returns: true (1) if successful, otherwise false (0). **/ bool recording_init(void) { char recording_file[PATH_MAX_LENGTH]; struct ffemu_params params = {0}; struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); bool *recording_enabled = recording_is_enabled(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!*recording_enabled) return false; recording_file[0] = '\0'; if (rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { RARCH_WARN("%s\n", msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED)); return false; } if (!settings->bools.video_gpu_record && video_driver_is_hw_context()) { RARCH_WARN("%s.\n", msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING)); return false; } RARCH_LOG("%s: FPS: %.4f, Sample rate: %.4f\n", msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN), (float)av_info->timing.fps, (float)av_info->timing.sample_rate); strlcpy(recording_file, global->record.path, sizeof(recording_file)); if (recording_use_output_dir) fill_pathname_join(recording_file, global->record.output_dir, global->record.path, sizeof(recording_file)); params.out_width = av_info->geometry.base_width; params.out_height = av_info->geometry.base_height; params.fb_width = av_info->geometry.max_width; params.fb_height = av_info->geometry.max_height; params.channels = 2; params.filename = recording_file; params.fps = av_info->timing.fps; params.samplerate = av_info->timing.sample_rate; params.pix_fmt = (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) ? FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565; params.config = NULL; if (!string_is_empty(global->record.config)) params.config = global->record.config; if (video_driver_supports_recording()) { unsigned gpu_size; struct video_viewport vp; vp.x = 0; vp.y = 0; vp.width = 0; vp.height = 0; vp.full_width = 0; vp.full_height = 0; video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_ERR("Failed to get viewport information from video driver. " "Cannot start recording ...\n"); return false; } params.out_width = vp.width; params.out_height = vp.height; params.fb_width = next_pow2(vp.width); params.fb_height = next_pow2(vp.height); if (settings->bools.video_force_aspect && (video_driver_get_aspect_ratio() > 0.0f)) params.aspect_ratio = video_driver_get_aspect_ratio(); else params.aspect_ratio = (float)vp.width / vp.height; params.pix_fmt = FFEMU_PIX_BGR24; recording_gpu_width = vp.width; recording_gpu_height = vp.height; RARCH_LOG("%s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF), vp.width, vp.height); gpu_size = vp.width * vp.height * 3; if (!video_driver_gpu_record_init(gpu_size)) return false; } else { if (recording_width || recording_height) { params.out_width = recording_width; params.out_height = recording_height; } if (settings->bools.video_force_aspect && (video_driver_get_aspect_ratio() > 0.0f)) params.aspect_ratio = video_driver_get_aspect_ratio(); else params.aspect_ratio = (float)params.out_width / params.out_height; if (settings->bools.video_post_filter_record && video_driver_frame_filter_alive()) { unsigned max_width = 0; unsigned max_height = 0; params.pix_fmt = FFEMU_PIX_RGB565; if (video_driver_frame_filter_is_32bit()) params.pix_fmt = FFEMU_PIX_ARGB8888; rarch_softfilter_get_max_output_size( video_driver_frame_filter_get_ptr(), &max_width, &max_height); params.fb_width = next_pow2(max_width); params.fb_height = next_pow2(max_height); } } RARCH_LOG("%s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n", msg_hash_to_str(MSG_RECORDING_TO), global->record.path, params.out_width, params.out_height, params.fb_width, params.fb_height, (unsigned)params.pix_fmt); if (!record_driver_init_first(&recording_driver, &recording_data, ¶ms)) { RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_RECORDING)); command_event(CMD_EVENT_GPU_RECORD_DEINIT, NULL); return false; } return true; }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch, bool is_idle) { bool has_gpu_record = false; uint8_t *gpu_buf = NULL; struct ffemu_video_data ffemu_data = {0}; video_driver_get_record_status(&has_gpu_record, &gpu_buf); ffemu_data.pitch = (int)pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (has_gpu_record) { struct video_viewport vp; vp.x = 0; vp.y = 0; vp.width = 0; vp.height = 0; vp.full_width = 0; vp.full_height = 0; video_driver_get_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_WARN("%s \n", msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED)); command_event(CMD_EVENT_GPU_RECORD_DEINIT, NULL); recording_dump_frame(data, width, height, pitch, is_idle); return; } /* User has resized. We kinda have a problem now. */ if ( vp.width != recording_gpu_width || vp.height != recording_gpu_height) { RARCH_WARN("%s\n", msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE)); runloop_msg_queue_push( msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE), 1, 180, true); command_event(CMD_EVENT_RECORD_DEINIT, NULL); return; } if (!gpu_buf) return; /* Big bottleneck. * Since we might need to do read-backs asynchronously, * it might take 3-4 times before this returns true. */ if (!video_driver_read_viewport(gpu_buf, is_idle)) return; ffemu_data.pitch = (int)(recording_gpu_width * 3); ffemu_data.width = (unsigned)recording_gpu_width; ffemu_data.height = (unsigned)recording_gpu_height; ffemu_data.data = gpu_buf + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!has_gpu_record) ffemu_data.is_dupe = !data; if (recording_driver && recording_driver->push_video) recording_driver->push_video(recording_data, &ffemu_data); }