diff options
author | 2016-04-17 19:15:58 +0200 | |
---|---|---|
committer | 2016-04-17 19:16:14 +0200 | |
commit | 250a5cc805a41409cbd6b8a1bfcb33e002e3f6f0 (patch) | |
tree | b767b65a8ccc667bd22a70f8f2fadead6f72b206 /src | |
parent | 9d8c3cb34178347bb1751da2d6f496a935fa35a6 (diff) |
Add AVI writing to bgfx, nw
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/sound.cpp | 1 | ||||
-rw-r--r-- | src/osd/modules/input/input_sdlcommon.cpp | 9 | ||||
-rw-r--r-- | src/osd/modules/input/input_windows.cpp | 3 | ||||
-rw-r--r-- | src/osd/modules/lib/osdobj_common.cpp | 17 | ||||
-rw-r--r-- | src/osd/modules/lib/osdobj_common.h | 3 | ||||
-rw-r--r-- | src/osd/modules/osdwindow.h | 1 | ||||
-rw-r--r-- | src/osd/modules/render/aviwrite.cpp | 161 | ||||
-rw-r--r-- | src/osd/modules/render/aviwrite.h | 51 | ||||
-rw-r--r-- | src/osd/modules/render/bgfx/target.h | 1 | ||||
-rw-r--r-- | src/osd/modules/render/bgfx/targetmanager.cpp | 2 | ||||
-rw-r--r-- | src/osd/modules/render/bgfx/targetmanager.h | 2 | ||||
-rw-r--r-- | src/osd/modules/render/drawbgfx.cpp | 315 | ||||
-rw-r--r-- | src/osd/modules/render/drawbgfx.h | 29 | ||||
-rw-r--r-- | src/osd/osdepend.h | 1 | ||||
-rw-r--r-- | src/osd/sdl/video.cpp | 3 | ||||
-rw-r--r-- | src/osd/windows/video.cpp | 14 | ||||
-rw-r--r-- | src/osd/windows/window.cpp | 6 | ||||
-rw-r--r-- | src/osd/windows/winmain.h | 9 |
18 files changed, 435 insertions, 193 deletions
diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp index 12093cb0689..eedab51e78b 100644 --- a/src/emu/sound.cpp +++ b/src/emu/sound.cpp @@ -1075,6 +1075,7 @@ void sound_manager::update(void *ptr, int param) { if (!m_nosound_mode) machine().osd().update_audio_stream(finalmix, finalmix_offset / 2); + machine().osd().add_audio_to_recording(finalmix, finalmix_offset / 2); machine().video().add_sound_to_recording(finalmix, finalmix_offset / 2); if (m_wavfile != nullptr) wav_add_data_16(m_wavfile, finalmix, finalmix_offset); diff --git a/src/osd/modules/input/input_sdlcommon.cpp b/src/osd/modules/input/input_sdlcommon.cpp index 0f6116fa048..10d9f7b3b52 100644 --- a/src/osd/modules/input/input_sdlcommon.cpp +++ b/src/osd/modules/input/input_sdlcommon.cpp @@ -233,7 +233,14 @@ void sdl_osd_interface::customize_input_type_list(simple_list<input_type_entry> entry.configure_osd("INCREASE_PRESCALE", "Increase Prescaling"); entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL); break; - // add a Not lcrtl condition to the load state key + + // lshift-lalt-F12 for fullscreen video (BGFX) + case IPT_OSD_8: + entry.configure_osd("RENDER_AVI", "Record Rendered Video"); + entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT); + break; + + // add a Not lcrtl condition to the load state key case IPT_UI_LOAD_STATE: entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT); break; diff --git a/src/osd/modules/input/input_windows.cpp b/src/osd/modules/input/input_windows.cpp index 2132247b828..f80a4d57459 100644 --- a/src/osd/modules/input/input_windows.cpp +++ b/src/osd/modules/input/input_windows.cpp @@ -98,11 +98,12 @@ void windows_osd_interface::customize_input_type_list(simple_list<input_type_ent entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT); break; - // lshift-lalt-F12 for fullscreen video (HLSL) + // lshift-lalt-F12 for fullscreen video (HLSL, BGFX) case IPT_OSD_3: entry.configure_osd("RENDER_AVI", "Record Rendered Video"); entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT); break; + // add a NOT-lalt to our default shift-F12 case IPT_UI_RECORD_MOVIE: // emu/input.c: input_seq(KEYCODE_F12, KEYCODE_LSHIFT) entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT); diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index e8f344028b0..b6114acb98c 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -147,6 +147,7 @@ const options_entry osd_options::s_option_entries[] = { OSDOPTION_BGFX_DEBUG, "0", OPTION_BOOLEAN, "enable BGFX debugging statistics" }, { OSDOPTION_BGFX_SCREEN_CHAINS, "default", OPTION_STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" }, { OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", OPTION_STRING, "shadow mask texture name" }, + { OSDOPTION_BGFX_AVI_NAME, "bgfx.avi", OPTION_STRING, "filename for BGFX output logging" }, // End of list { nullptr } @@ -422,8 +423,8 @@ void osd_common_t::init(running_machine &machine) // ensure we get called on the way out machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(osd_common_t::osd_exit), this)); - - + + /* now setup watchdog */ int watchdog_timeout = options.watchdog(); @@ -559,6 +560,18 @@ std::vector<ui_menu_item> osd_common_t::get_slider_list() return m_sliders; } + +//------------------------------------------------- +// add_audio_to_recording - append audio samples +// to an AVI recording if one is active +//------------------------------------------------- + +void osd_common_t::add_audio_to_recording(const INT16 *buffer, int samples_this_frame) +{ + // Do nothing +} + + //------------------------------------------------- // execute_command - execute a command not yet // handled by the core diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h index 00778fac569..0d86d412cf9 100644 --- a/src/osd/modules/lib/osdobj_common.h +++ b/src/osd/modules/lib/osdobj_common.h @@ -84,6 +84,7 @@ class ui_menu_item; #define OSDOPTION_BGFX_DEBUG "bgfx_debug" #define OSDOPTION_BGFX_SCREEN_CHAINS "bgfx_screen_chains" #define OSDOPTION_BGFX_SHADOW_MASK "bgfx_shadow_mask" +#define OSDOPTION_BGFX_AVI_NAME "bgfx_avi_name" //============================================================ // TYPE DEFINITIONS @@ -157,6 +158,7 @@ public: const bool bgfx_debug() const { return bool_value(OSDOPTION_BGFX_DEBUG); } const char *bgfx_screen_chains() const { return value(OSDOPTION_BGFX_SCREEN_CHAINS); } const char *bgfx_shadow_mask() const { return value(OSDOPTION_BGFX_SHADOW_MASK); } + const char *bgfx_avi_name() const { return value(OSDOPTION_BGFX_AVI_NAME); } private: static const options_entry s_option_entries[]; @@ -192,6 +194,7 @@ public: virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override; // video overridables + virtual void add_audio_to_recording(const INT16 *buffer, int samples_this_frame) override; virtual std::vector<ui_menu_item> get_slider_list() override; // command option overrides diff --git a/src/osd/modules/osdwindow.h b/src/osd/modules/osdwindow.h index 1361ff50c9f..218e48145d5 100644 --- a/src/osd/modules/osdwindow.h +++ b/src/osd/modules/osdwindow.h @@ -197,6 +197,7 @@ public: virtual int create() = 0; virtual render_primitive_list *get_primitives() = 0; + virtual void add_audio_to_recording(const INT16 *buffer, int samples_this_frame) { } virtual std::vector<ui_menu_item> get_slider_list() { return m_sliders; } virtual int draw(const int update) = 0; virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) { return 0; }; diff --git a/src/osd/modules/render/aviwrite.cpp b/src/osd/modules/render/aviwrite.cpp new file mode 100644 index 00000000000..6a27c567a43 --- /dev/null +++ b/src/osd/modules/render/aviwrite.cpp @@ -0,0 +1,161 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +//============================================================ +// +// aviwrite.cpp - AVI screenshot writer class +// +//============================================================ + +#include "aviwrite.h" +#include "modules/lib/osdobj_common.h" + +avi_write::avi_write(running_machine& machine, uint32_t width, uint32_t height) + : m_machine(machine) + , m_recording(false) + , m_width(width) + , m_height(height) + , m_output_file(nullptr) + , m_frame(0) +{ +} + +avi_write::~avi_write() +{ + if (m_recording) + { + stop(); + } +} + +void avi_write::record(std::string name) +{ + if (m_recording) + { + end_avi_recording(); + } + + if (name != "") + { + begin_avi_recording(name); + } +} + +void avi_write::stop() +{ + osd_printf_info("Stopping AVI recording after %d frames.\n", m_frame); + end_avi_recording(); +} + +void avi_write::begin_avi_recording(std::string name) +{ + // stop any existing recording + end_avi_recording(); + + // reset the state + m_frame = 0; + m_next_frame_time = m_machine.time(); + + // build up information about this new movie + avi_file::movie_info info; + info.video_format = 0; + info.video_timescale = 1000 * ((m_machine.first_screen() != nullptr) ? ATTOSECONDS_TO_HZ(m_machine.first_screen()->frame_period().m_attoseconds) : screen_device::DEFAULT_FRAME_RATE); + info.video_sampletime = 1000; + info.video_numsamples = 0; + info.video_width = m_width; + info.video_height = m_height; + info.video_depth = 24; + + info.audio_format = 0; + info.audio_timescale = m_machine.sample_rate(); + info.audio_sampletime = 1; + info.audio_numsamples = 0; + info.audio_channels = 2; + info.audio_samplebits = 16; + info.audio_samplerate = m_machine.sample_rate(); + + // create a new temporary movie file + osd_file::error filerr; + std::string fullpath; + { + emu_file tempfile(m_machine.options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + filerr = tempfile.open(name.c_str()); + + // compute the frame time + m_frame_period = attotime::from_seconds(1000) / info.video_timescale; + + // if we succeeded, make a copy of the name and create the real file over top + if (filerr == osd_file::error::NONE) + { + fullpath = tempfile.fullpath(); + } + } + + if (filerr == osd_file::error::NONE) + { + // create the file and free the string + avi_file::error avierr = avi_file::create(fullpath, info, m_output_file); + if (avierr != avi_file::error::NONE) + { + osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr)); + } + else + { + m_recording = true; + } + } +} + +void avi_write::end_avi_recording() +{ + if (m_output_file) + { + m_output_file.reset(); + } + + m_recording = false; + m_output_file = nullptr; + m_frame = 0; +} + +void avi_write::video_frame(bitmap_rgb32& snap) +{ + // get the current time + attotime curtime = m_machine.time(); + + // loop until we hit the right time + while (m_next_frame_time <= curtime) + { + // handle an AVI recording + // write the next frame + avi_file::error avierr = m_output_file->append_video_frame(snap); + if (avierr != avi_file::error::NONE) + { + osd_printf_error("Error while logging AVI video frame: %s\n", avi_file::error_string(avierr)); + osd_printf_error("Stopping AVI recording.\n"); + end_avi_recording(); + return; + } + + // advance time + m_next_frame_time += m_frame_period; + m_frame++; + } +} + +void avi_write::audio_frame(const INT16 *buffer, int samples_this_frame) +{ + // only record if we have a file + if (m_output_file != nullptr) + { + // write the next frame + avi_file::error avierr = m_output_file->append_sound_samples(0, buffer + 0, samples_this_frame, 1); + if (avierr == avi_file::error::NONE) + avierr = m_output_file->append_sound_samples(1, buffer + 1, samples_this_frame, 1); + if (avierr != avi_file::error::NONE) + { + osd_printf_error("Error while logging AVI audio frame: %s\n", avi_file::error_string(avierr)); + osd_printf_error("Stopping AVI recording.\n"); + end_avi_recording(); + } + } +}
\ No newline at end of file diff --git a/src/osd/modules/render/aviwrite.h b/src/osd/modules/render/aviwrite.h new file mode 100644 index 00000000000..2a948964eb8 --- /dev/null +++ b/src/osd/modules/render/aviwrite.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +//============================================================ +// +// aviwrite.h - AVI screenshot writer class +// +//============================================================ + +#pragma once + +#ifndef __RENDER_AVIWRITE__ +#define __RENDER_AVIWRITE__ + +#include "emu.h" +#include "aviio.h" + +class running_machine; + +class avi_write +{ +public: + avi_write(running_machine& machine, uint32_t width, uint32_t height); + ~avi_write(); + + void record(std::string name); + void stop(); + void audio_frame(const INT16 *buffer, int samples_this_frame); + void video_frame(bitmap_rgb32& snap); + + // Getters + bool recording() const { return m_recording; } + +private: + void begin_avi_recording(std::string name); + void end_avi_recording(); + + running_machine& m_machine; + + bool m_recording; + + uint32_t m_width; + uint32_t m_height; + + avi_file::ptr m_output_file; + + int m_frame; + attotime m_frame_period; + attotime m_next_frame_time; +}; + +#endif // __RENDER_AVIWRITE__
\ No newline at end of file diff --git a/src/osd/modules/render/bgfx/target.h b/src/osd/modules/render/bgfx/target.h index 76d4c374c7e..d521d2aa3d2 100644 --- a/src/osd/modules/render/bgfx/target.h +++ b/src/osd/modules/render/bgfx/target.h @@ -52,6 +52,7 @@ public: private: std::string m_name; bgfx::TextureFormat::Enum m_format; + bool m_readback; bgfx::FrameBufferHandle* m_targets; bgfx::TextureHandle* m_textures; diff --git a/src/osd/modules/render/bgfx/targetmanager.cpp b/src/osd/modules/render/bgfx/targetmanager.cpp index e17b0e6915a..40895727437 100644 --- a/src/osd/modules/render/bgfx/targetmanager.cpp +++ b/src/osd/modules/render/bgfx/targetmanager.cpp @@ -59,7 +59,7 @@ bgfx_target* target_manager::create_target(std::string name, bgfx::TextureFormat void target_manager::destroy_target(std::string name, uint32_t screen) { - std::string full_name = name + std::to_string(screen); + std::string full_name = (screen < 0) ? name : (name + std::to_string(screen)); if (m_targets[full_name] != nullptr) { delete m_targets[full_name]; diff --git a/src/osd/modules/render/bgfx/targetmanager.h b/src/osd/modules/render/bgfx/targetmanager.h index 04ac4252f9d..0ab45e638d1 100644 --- a/src/osd/modules/render/bgfx/targetmanager.h +++ b/src/osd/modules/render/bgfx/targetmanager.h @@ -31,7 +31,7 @@ public: ~target_manager(); bgfx_target* create_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen); - void destroy_target(std::string name, uint32_t screen); + void destroy_target(std::string name, uint32_t screen = -1); bgfx_target* create_backbuffer(void *handle, uint16_t width, uint16_t height); void update_target_sizes(uint32_t screen, uint16_t width, uint16_t height, uint32_t style); diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp index 51806233ea6..f90e7f060e1 100644 --- a/src/osd/modules/render/drawbgfx.cpp +++ b/src/osd/modules/render/drawbgfx.cpp @@ -20,7 +20,7 @@ #include "emu.h" #include "window.h" #include "rendutil.h" -#include "aviio.h" +#include "aviwrite.h" #include <bgfx/bgfxplatform.h> #include <bgfx/bgfx.h> @@ -82,8 +82,8 @@ renderer_bgfx::renderer_bgfx(osd_window *w) , m_options(downcast<osd_options &>(w->machine().options())) , m_dimensions(0, 0) , m_max_view(0) - , m_avi_output_file(nullptr) - , m_avi_frame(0) + , m_avi_writer(nullptr) + , m_avi_target(nullptr) { m_options = downcast<osd_options &>(window().machine().options()); } @@ -94,6 +94,19 @@ renderer_bgfx::renderer_bgfx(osd_window *w) renderer_bgfx::~renderer_bgfx() { + if (m_avi_writer != nullptr && m_avi_writer->recording()) + { + m_avi_writer->stop(); + + m_targets->destroy_target("avibuffer0"); + m_avi_target = nullptr; + + bgfx::destroyTexture(m_avi_texture); + + delete m_avi_writer; + delete [] m_avi_data; + } + // Cleanup. delete m_chains; delete m_effects; @@ -236,29 +249,27 @@ int renderer_bgfx::create() // renderer_bgfx::record //============================================================ -#ifndef OSD_SDL void renderer_bgfx::record() { - std::string filename("test.avi");//m_options.d3d_hlsl_write()); + if (m_avi_writer == nullptr || window().m_index > 0) + { + return; + } - if (m_avi_output_file != nullptr) + if (m_avi_writer->recording()) { - end_avi_recording(); + m_avi_writer->stop(); + m_targets->destroy_target("avibuffer0"); + m_avi_target = nullptr; + bgfx::destroyTexture(m_avi_texture); } - else if (filename[0] != 0) + else { - begin_avi_recording(filename); + m_avi_writer->record(m_options.bgfx_avi_name()); + m_avi_target = m_targets->create_target("avibuffer", bgfx::TextureFormat::RGBA8, m_width[0], m_height[0], TARGET_STYLE_CUSTOM, false, true, 1, 0); + m_avi_texture = bgfx::createTexture2D(m_width[0], m_height[0], 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_READ_BACK); } } -#endif - -void renderer_bgfx::end_avi_recording() -{ -} - -void renderer_bgfx::begin_avi_recording(std::string filename) -{ -} void renderer_bgfx::exit() { @@ -291,26 +302,18 @@ int renderer_bgfx::xy_to_render_target(int x, int y, int *xt, int *yt) bgfx::VertexDecl ScreenVertex::ms_decl; -void renderer_bgfx::put_packed_quad(render_primitive *prim, UINT32 hash, ScreenVertex* vertex) +void renderer_bgfx::put_packed_quad(render_primitive *prim, UINT32 hash, ScreenVertex* vertices) { rectangle_packer::packed_rectangle& rect = m_hash_to_entry[hash]; - float u0 = float(rect.x()) / float(CACHE_SIZE); - float v0 = float(rect.y()) / float(CACHE_SIZE); - float u1 = u0 + float(rect.width()) / float(CACHE_SIZE); - float v1 = v0 + float(rect.height()) / float(CACHE_SIZE); - u1 -= 0.5f / float(CACHE_SIZE); - v1 -= 0.5f / float(CACHE_SIZE); - u0 += 0.5f / float(CACHE_SIZE); - v0 += 0.5f / float(CACHE_SIZE); + float size = float(CACHE_SIZE); + float u0 = (float(rect.x()) + 0.5f) / size; + float v0 = (float(rect.y()) + 0.5f) / size; + float u1 = u0 + (float(rect.width()) - 1.0f) / size; + float v1 = v0 + (float(rect.height()) - 1.0f) / size; UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); - const float x0 = prim->bounds.x0; - const float x1 = prim->bounds.x1; - const float y0 = prim->bounds.y0; - const float y1 = prim->bounds.y1; - - float x[4] = { x0, x1, x0, x1 }; - float y[4] = { y0, y0, y1, y1 }; + float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 }; + float y[4] = { prim->bounds.y0, prim->bounds.y0, prim->bounds.y1, prim->bounds.y1 }; float u[4] = { u0, u1, u0, u1 }; float v[4] = { v0, v0, v1, v1 }; @@ -336,99 +339,39 @@ void renderer_bgfx::put_packed_quad(render_primitive *prim, UINT32 hash, ScreenV std::swap(v[1], v[3]); } - vertex[0].m_x = x[0]; // 0 - vertex[0].m_y = y[0]; - vertex[0].m_z = 0; - vertex[0].m_rgba = rgba; - vertex[0].m_u = u[0]; - vertex[0].m_v = v[0]; - - vertex[1].m_x = x[1]; // 1 - vertex[1].m_y = y[1]; - vertex[1].m_z = 0; - vertex[1].m_rgba = rgba; - vertex[1].m_u = u[1]; - vertex[1].m_v = v[1]; - - vertex[2].m_x = x[3]; // 3 - vertex[2].m_y = y[3]; - vertex[2].m_z = 0; - vertex[2].m_rgba = rgba; - vertex[2].m_u = u[3]; - vertex[2].m_v = v[3]; - - vertex[3].m_x = x[3]; // 3 - vertex[3].m_y = y[3]; - vertex[3].m_z = 0; - vertex[3].m_rgba = rgba; - vertex[3].m_u = u[3]; - vertex[3].m_v = v[3]; - - vertex[4].m_x = x[2]; // 2 - vertex[4].m_y = y[2]; - vertex[4].m_z = 0; - vertex[4].m_rgba = rgba; - vertex[4].m_u = u[2]; - vertex[4].m_v = v[2]; - - vertex[5].m_x = x[0]; // 0 - vertex[5].m_y = y[0]; - vertex[5].m_z = 0; - vertex[5].m_rgba = rgba; - vertex[5].m_u = u[0]; - vertex[5].m_v = v[0]; + vertex(&vertices[0], x[0], y[0], 0, rgba, u[0], v[0]); + vertex(&vertices[1], x[1], y[1], 0, rgba, u[1], v[1]); + vertex(&vertices[2], x[3], y[3], 0, rgba, u[3], v[3]); + vertex(&vertices[3], x[3], y[3], 0, rgba, u[3], v[3]); + vertex(&vertices[4], x[2], y[2], 0, rgba, u[2], v[2]); + vertex(&vertices[5], x[0], y[0], 0, rgba, u[0], v[0]); +} + +void renderer_bgfx::vertex(ScreenVertex* vertex, float x, float y, float z, uint32_t rgba, float u, float v) +{ + vertex->m_x = x; + vertex->m_y = y; + vertex->m_z = z; + vertex->m_rgba = rgba; + vertex->m_u = u; + vertex->m_v = v; } void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen) { - ScreenVertex* vertex = reinterpret_cast<ScreenVertex*>(buffer->data); + ScreenVertex* vertices = reinterpret_cast<ScreenVertex*>(buffer->data); float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 }; float y[4] = { prim->bounds.y0, prim->bounds.y0, prim->bounds.y1, prim->bounds.y1 }; float u[4] = { prim->texcoords.tl.u, prim->texcoords.tr.u, prim->texcoords.bl.u, prim->texcoords.br.u }; float v[4] = { prim->texcoords.tl.v, prim->texcoords.tr.v, prim->texcoords.bl.v, prim->texcoords.br.v }; - vertex[0].m_x = x[0]; - vertex[0].m_y = y[0]; - vertex[0].m_z = 0; - vertex[0].m_rgba = 0xffffffff; - vertex[0].m_u = u[0]; - vertex[0].m_v = v[0]; - - vertex[1].m_x = x[1]; - vertex[1].m_y = y[1]; - vertex[1].m_z = 0; - vertex[1].m_rgba = 0xffffffff; - vertex[1].m_u = u[1]; - vertex[1].m_v = v[1]; - - vertex[2].m_x = x[3]; - vertex[2].m_y = y[3]; - vertex[2].m_z = 0; - vertex[2].m_rgba = 0xffffffff; - vertex[2].m_u = u[3]; - vertex[2].m_v = v[3]; - - vertex[3].m_x = x[3]; - vertex[3].m_y = y[3]; - vertex[3].m_z = 0; - vertex[3].m_rgba = 0xffffffff; - vertex[3].m_u = u[3]; - vertex[3].m_v = v[3]; - - vertex[4].m_x = x[2]; - vertex[4].m_y = y[2]; - vertex[4].m_z = 0; - vertex[4].m_rgba = 0xffffffff; - vertex[4].m_u = u[2]; - vertex[4].m_v = v[2]; - - vertex[5].m_x = x[0]; - vertex[5].m_y = y[0]; - vertex[5].m_z = 0; - vertex[5].m_rgba = 0xffffffff; - vertex[5].m_u = u[0]; - vertex[5].m_v = v[0]; + vertex(&vertices[0], x[0], y[0], 0, 0xffffffff, u[0], v[0]); + vertex(&vertices[1], x[1], y[1], 0, 0xffffffff, u[1], v[1]); + vertex(&vertices[2], x[3], y[3], 0, 0xffffffff, u[3], v[3]); + vertex(&vertices[3], x[3], y[3], 0, 0xffffffff, u[3], v[3]); + vertex(&vertices[4], x[2], y[2], 0, 0xffffffff, u[2], v[2]); + vertex(&vertices[5], x[0], y[0], 0, 0xffffffff, u[0], v[0]); uint32_t texture_flags = BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP; if (video_config.filter == 0) @@ -442,53 +385,53 @@ void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bg m_screen_effect[blend]->submit(view); } -void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer) +void renderer_bgfx::render_avi_quad() { - ScreenVertex* vertex = reinterpret_cast<ScreenVertex*>(buffer->data); + bgfx::setViewSeq(s_current_view, true); + bgfx::setViewRect(s_current_view, 0, 0, m_width[0], m_height[0]); + bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); + + setup_matrices(s_current_view, false); + + bgfx::TransientVertexBuffer buffer; + bgfx::allocTransientVertexBuffer(&buffer, 6, ScreenVertex::ms_decl); + ScreenVertex* vertices = reinterpret_cast<ScreenVertex*>(buffer.data); + + float x[4] = { 0.0f, float(m_width[0]), 0.0f, float(m_width[0]) }; + float y[4] = { 0.0f, 0.0f, float(m_height[0]), float(m_height[0]) }; + float u[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; + float v[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; + UINT32 rgba = 0xffffffff; + + vertex(&vertices[0], x[0], y[0], 0, rgba, u[0], v[0]); + vertex(&vertices[1], x[1], y[1], 0, rgba, u[1], v[1]); + vertex(&vertices[2], x[3], y[3], 0, rgba, u[3], v[3]); + vertex(&vertices[3], x[3], y[3], 0, rgba, u[3], v[3]); + vertex(&vertices[4], x[2], y[2], 0, rgba, u[2], v[2]); + vertex(&vertices[5], x[0], y[0], 0, rgba, u[0], v[0]); + + bgfx::setVertexBuffer(&buffer); + bgfx::setTexture(0, m_gui_effect[PRIMFLAG_GET_BLENDMODE(BLENDMODE_NONE)]->uniform("s_tex")->handle(), m_avi_target->texture()); + m_gui_effect[PRIMFLAG_GET_BLENDMODE(BLENDMODE_NONE)]->submit(s_current_view); + s_current_view++; +} +void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer) +{ + ScreenVertex* vertices = reinterpret_cast<ScreenVertex*>(buffer->data); UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); - vertex[0].m_x = prim->bounds.x0; - vertex[0].m_y = prim->bounds.y0; - vertex[0].m_z = 0; - vertex[0].m_rgba = rgba; - vertex[0].m_u = prim->texcoords.tl.u; - vertex[0].m_v = prim->texcoords.tl.v; - - vertex[1].m_x = prim->bounds.x1; - vertex[1].m_y = prim->bounds.y0; - vertex[1].m_z = 0; - vertex[1].m_rgba = rgba; - vertex[1].m_u = prim->texcoords.tr.u; - vertex[1].m_v = prim->texcoords.tr.v; - - vertex[2].m_x = prim->bounds.x1; - vertex[2].m_y = prim->bounds.y1; - vertex[2].m_z = 0; - vertex[2].m_rgba = rgba; - vertex[2].m_u = prim->texcoords.br.u; - vertex[2].m_v = prim->texcoords.br.v; - - vertex[3].m_x = prim->bounds.x1; - vertex[3].m_y = prim->bounds.y1; - vertex[3].m_z = 0; - vertex[3].m_rgba = rgba; - vertex[3].m_u = prim->texcoords.br.u; - vertex[3].m_v = prim->texcoords.br.v; - - vertex[4].m_x = prim->bounds.x0; - vertex[4].m_y = prim->bounds.y1; - vertex[4].m_z = 0; - vertex[4].m_rgba = rgba; - vertex[4].m_u = prim->texcoords.bl.u; - vertex[4].m_v = prim->texcoords.bl.v; - - vertex[5].m_x = prim->bounds.x0; - vertex[5].m_y = prim->bounds.y0; - vertex[5].m_z = 0; - vertex[5].m_rgba = rgba; - vertex[5].m_u = prim->texcoords.tl.u; - vertex[5].m_v = prim->texcoords.tl.v; + float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 }; + float y[4] = { prim->bounds.y0, prim->bounds.y0, prim->bounds.y1, prim->bounds.y1 }; + float u[4] = { prim->texcoords.tl.u, prim->texcoords.tr.u, prim->texcoords.bl.u, prim->texcoords.br.u }; + float v[4] = { prim->texcoords.tl.v, prim->texcoords.tr.v, prim->texcoords.bl.v, prim->texcoords.br.v }; + + vertex(&vertices[0], x[0], y[0], 0, rgba, u[0], v[0]); + vertex(&vertices[1], x[1], y[1], 0, rgba, u[1], v[1]); + vertex(&vertices[2], x[3], y[3], 0, rgba, u[3], v[3]); + vertex(&vertices[3], x[3], y[3], 0, rgba, u[3], v[3]); + vertex(&vertices[4], x[2], y[2], 0, rgba, u[2], v[2]); + vertex(&vertices[5], x[0], y[0], 0, rgba, u[0], v[0]); uint32_t texture_flags = BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP; if (video_config.filter == 0) @@ -709,6 +652,14 @@ int renderer_bgfx::draw(int update) if (window_index == 0) { s_current_view = 0; + if (m_avi_writer == nullptr) + { + uint32_t width = window().get_size().width(); + uint32_t height = window().get_size().height(); + m_avi_writer = new avi_write(window().machine(), width, height); + m_avi_data = new uint8_t[width * height * 4]; + m_avi_bitmap.allocate(width, height); + } } m_seen_views.clear(); @@ -785,20 +736,50 @@ int renderer_bgfx::draw(int update) window().m_primlist->release_lock(); - // This dummy draw call is here to make sure that view 0 is cleared - // if no other draw calls are submitted to view 0. - bgfx::touch(s_current_view > 0 ? s_current_view - 1 : 0); + // This dummy draw call is here to make sure that view 0 is cleared + // if no other draw calls are submitted to view 0. + bgfx::touch(s_current_view > 0 ? s_current_view - 1 : 0); - // Advance to next frame. Rendering thread will be kicked to + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. if (window_index == 0) { + if (m_avi_writer != nullptr && m_avi_writer->recording() && window_index == 0) + { + render_avi_quad(); + bgfx::touch(s_current_view); + update_recording(); + } + bgfx::frame(); } return 0; } +void renderer_bgfx::update_recording() +{ + bgfx::blit(s_current_view > 0 ? s_current_view - 1 : 0, m_avi_texture, 0, 0, m_avi_target->target()); + bgfx::readTexture(m_avi_texture, m_avi_data); + + UINT32* start = &m_avi_bitmap.pix32(0); + // loop over Y + for (int i = 0; i < m_width[0] * m_height[0] * 4; i += 4) + { + *start++ = 0xff000000 | (m_avi_data[i + 0] << 16) | (m_avi_data[i + 1] << 8) | m_avi_data[i + 2]; + } + + m_avi_writer->video_frame(m_avi_bitmap); +} + +void renderer_bgfx::add_audio_to_recording(const INT16 *buffer, int samples_this_frame) +{ + if (m_avi_writer != nullptr && m_avi_writer->recording() && window().m_index == 0) + { + m_avi_writer->audio_frame(buffer, samples_this_frame); + } +} + bool renderer_bgfx::update_dimensions() { const uint32_t window_index = window().m_index; @@ -864,7 +845,11 @@ void renderer_bgfx::setup_view(uint32_t view_index, bool screen) { m_seen_views[view_index] = true; #endif - bgfx::setViewClear(view_index, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); + if (m_avi_writer != nullptr && m_avi_writer->recording() && window().m_index == 0) + { + bgfx::setViewFrameBuffer(view_index, m_avi_target->target()); + } + bgfx::setViewClear(view_index, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); } setup_matrices(view_index, screen); diff --git a/src/osd/modules/render/drawbgfx.h b/src/osd/modules/render/drawbgfx.h index e96fd461cc1..f7da00fe787 100644 --- a/src/osd/modules/render/drawbgfx.h +++ b/src/osd/modules/render/drawbgfx.h @@ -13,7 +13,6 @@ #include "binpacker.h" #include "bgfx/vertex.h" #include "sliderdirtynotifier.h" -#include "aviio.h" class texture_manager; class target_manager; @@ -25,6 +24,7 @@ class bgfx_effect; class bgfx_target; class bgfx_chain; class osd_options; +class avi_write; /* sdl_info is the information about SDL for the current screen */ class renderer_bgfx : public osd_renderer, public slider_dirty_notifier @@ -39,16 +39,17 @@ public: virtual int create() override; virtual int draw(const int update) override; + virtual void add_audio_to_recording(const INT16 *buffer, int samples_this_frame) override; virtual std::vector<ui_menu_item> get_slider_list() override; virtual void set_sliders_dirty() override; #ifdef OSD_SDL virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override; -#else +#endif + virtual void save() override { } virtual void record() override; virtual void toggle_fsfx() override { } -#endif virtual render_primitive_list *get_primitives() override { @@ -60,13 +61,16 @@ public: static const char* WINDOW_PREFIX; private: - void end_avi_recording(); - void begin_avi_recording(std::string filename); + void vertex(ScreenVertex* vertex, float x, float y, float z, uint32_t rgba, float u, float v); + void render_avi_quad(); + void update_recording(); - bool update_dimensions(); - void setup_view(uint32_t view_index, bool screen); + bool update_dimensions(); + + void setup_view(uint32_t view_index, bool screen); void init_ui_view(); - void setup_matrices(uint32_t view_index, bool screen); + + void setup_matrices(uint32_t view_index, bool screen); void allocate_buffer(render_primitive *prim, UINT32 blend, bgfx::TransientVertexBuffer *buffer); enum buffer_status @@ -123,10 +127,11 @@ private: int32_t m_ui_view; uint32_t m_max_view; - // AVI - avi_file::ptr m_avi_output_file; // AVI file - int m_avi_frame; // AVI frame - attotime m_avi_frame_period; // AVI frame period + avi_write* m_avi_writer; + bgfx_target* m_avi_target; + bgfx::TextureHandle m_avi_texture; + bitmap_rgb32 m_avi_bitmap; + uint8_t* m_avi_data; static const uint16_t CACHE_SIZE; static const uint32_t PACKABLE_SIZE; diff --git a/src/osd/osdepend.h b/src/osd/osdepend.h index 661160cb271..e305aeb958f 100644 --- a/src/osd/osdepend.h +++ b/src/osd/osdepend.h @@ -79,6 +79,7 @@ public: virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) = 0; // video overridables + virtual void add_audio_to_recording(const INT16 *buffer, int samples_this_frame) = 0; virtual std::vector<ui_menu_item> get_slider_list() = 0; // font interface diff --git a/src/osd/sdl/video.cpp b/src/osd/sdl/video.cpp index 8a8402e44b3..099c4bccfc9 100644 --- a/src/osd/sdl/video.cpp +++ b/src/osd/sdl/video.cpp @@ -314,6 +314,9 @@ static void check_osd_inputs(running_machine &machine) if (machine.ui_input().pressed(IPT_OSD_7)) window->modify_prescale(1); + + if (machine.ui_input().pressed(IPT_OSD_8)) + window->renderer().record(); } //============================================================ diff --git a/src/osd/windows/video.cpp b/src/osd/windows/video.cpp index b0f28ee7d13..d73ad8bf522 100644 --- a/src/osd/windows/video.cpp +++ b/src/osd/windows/video.cpp @@ -51,8 +51,6 @@ osd_monitor_info *osd_monitor_info::list = NULL; static void init_monitors(void); -static void check_osd_inputs(running_machine &machine); - static float get_aspect(const char *defdata, const char *data, int report_error); static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error); @@ -180,7 +178,7 @@ void windows_osd_interface::update(bool skip_redraw) // poll the joystick values here winwindow_process_events(machine(), TRUE, FALSE); poll_input(machine()); - check_osd_inputs(machine()); + check_osd_inputs(); // if we're running, disable some parts of the debugger if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0) debugger_update(); @@ -308,22 +306,22 @@ finishit: // check_osd_inputs //============================================================ -static void check_osd_inputs(running_machine &machine) +void windows_osd_interface::check_osd_inputs() { // check for toggling fullscreen mode - if (machine.ui_input().pressed(IPT_OSD_1)) + if (machine().ui_input().pressed(IPT_OSD_1)) winwindow_toggle_full_screen(); // check for taking fullscreen snap - if (machine.ui_input().pressed(IPT_OSD_2)) + if (machine().ui_input().pressed(IPT_OSD_2)) winwindow_take_snap(); // check for taking fullscreen video - if (machine.ui_input().pressed(IPT_OSD_3)) + if (machine().ui_input().pressed(IPT_OSD_3)) winwindow_take_video(); // check for taking fullscreen video - if (machine.ui_input().pressed(IPT_OSD_4)) + if (machine().ui_input().pressed(IPT_OSD_4)) winwindow_toggle_fsfx(); } diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp index 8938ca427ce..da6aebd07ff 100644 --- a/src/osd/windows/window.cpp +++ b/src/osd/windows/window.cpp @@ -286,6 +286,12 @@ void windows_osd_interface::build_slider_list() } } +void windows_osd_interface::add_audio_to_recording(const INT16 *buffer, int samples_this_frame) +{ + win_window_info *window = win_window_list; // We only record on the first window + window->m_renderer->add_audio_to_recording(buffer, samples_this_frame); +} + //============================================================ // winwindow_exit // (main thread) diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index b41092bf500..216333dbd13 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -260,9 +260,12 @@ public: virtual void init(running_machine &machine) override; virtual void update(bool skip_redraw) override; - // video overridables + // input overrideables virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override; + // video overridables + virtual void add_audio_to_recording(const INT16 *buffer, int samples_this_frame) override; + virtual void video_register() override; virtual bool video_init() override; @@ -286,6 +289,8 @@ protected: virtual void build_slider_list() override; virtual void update_slider_list() override; + void check_osd_inputs(); + private: virtual void osd_exit() override; @@ -306,7 +311,7 @@ private: public: MameMainApp(); - // IFrameworkView Methods. + // IFrameworkView Methods. virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); virtual void SetWindow(Windows::UI::Core::CoreWindow^ window); virtual void Load(Platform::String^ entryPoint); |