diff options
author | Olivier Galibert <galibert@pobox.com> | 2016-04-04 11:28:22 +0200 |
---|---|---|
committer | Olivier Galibert <galibert@pobox.com> | 2016-04-04 11:33:34 +0200 |
commit | cdc04a9b7c72343b67f24be1c1a0d01780dafd8d (patch) | |
tree | a12995d0cdad152f381b1e8f8f4754ab4827a09c /src | |
parent | 57e9e774cd056973a036d2b75273d84cea383494 (diff) |
screen: POC||GTFO of svg rendering from inside the rom. [O. Galibert]
It's damn slow, ~50ms/frame on cdkong. Caching and/or hw accel will
solve that easily. It doesn't look very good, nanosvg need better
anti-aliasing. It also doesn't do texturing very well and images not
at all, so some of our current svgs won't look good. But all that's
fixable.
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/layout/svg.lay | 8 | ||||
-rw-r--r-- | src/emu/luaengine.cpp | 1 | ||||
-rw-r--r-- | src/emu/rendlay.cpp | 2 | ||||
-rw-r--r-- | src/emu/rendlay.h | 3 | ||||
-rw-r--r-- | src/emu/screen.cpp | 149 | ||||
-rw-r--r-- | src/emu/screen.h | 14 | ||||
-rw-r--r-- | src/lib/util/nanosvg.cpp | 6 | ||||
-rw-r--r-- | src/mame/drivers/hh_hmcs40.cpp | 13 |
8 files changed, 184 insertions, 12 deletions
diff --git a/src/emu/layout/svg.lay b/src/emu/layout/svg.lay new file mode 100644 index 00000000000..96a25360a19 --- /dev/null +++ b/src/emu/layout/svg.lay @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<mamelayout version="2"> + <view name="SVG"> + <screen index="0"> + <bounds left="0" top="0" right="~scr0width~" bottom="~scr0height~" /> + </screen> + </view> +</mamelayout> diff --git a/src/emu/luaengine.cpp b/src/emu/luaengine.cpp index 62667ee0eef..8de543669d2 100644 --- a/src/emu/luaengine.cpp +++ b/src/emu/luaengine.cpp @@ -968,6 +968,7 @@ int lua_engine::lua_screen::l_type(lua_State *L) case SCREEN_TYPE_RASTER: lua_pushliteral(L, "raster"); break; case SCREEN_TYPE_VECTOR: lua_pushliteral(L, "vector"); break; case SCREEN_TYPE_LCD: lua_pushliteral(L, "lcd"); break; + case SCREEN_TYPE_SVG: lua_pushliteral(L, "svg"); break; default: lua_pushliteral(L, "unknown"); break; } diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index 5995c16eed2..fee6cbdaaa2 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -82,6 +82,8 @@ #include "lcd.lh" #include "lcd_rot.lh" +// SVG screen layouts +#include "svg.lh" //************************************************************************** diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h index ab9390de564..1267be32773 100644 --- a/src/emu/rendlay.h +++ b/src/emu/rendlay.h @@ -37,5 +37,8 @@ extern const internal_layout layout_quadhsxs; // quad 4:3 screens side-by-sid extern const internal_layout layout_lcd; // generic 1:1 lcd screen layout extern const internal_layout layout_lcd_rot; // same, for use with ROT90 or ROT270 +// SVG screen layouts +extern const internal_layout layout_svg; // generic 1:1 lcd screen layout + #endif // __RENDLAY_H__ diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp index 952c84ca30a..9a22d215a0f 100644 --- a/src/emu/screen.cpp +++ b/src/emu/screen.cpp @@ -13,6 +13,8 @@ #include "png.h" #include "rendutil.h" +#include <nanosvg/src/nanosvg.h> +#include <nanosvg/src/nanosvgrast.h> //************************************************************************** @@ -35,6 +37,101 @@ const attotime screen_device::DEFAULT_FRAME_PERIOD(attotime::from_hz(DEFAULT_FRA UINT32 screen_device::m_id_counter = 0; +class screen_device_svg_renderer { +public: + screen_device_svg_renderer(memory_region *region); + ~screen_device_svg_renderer(); + + int width() const; + int height() const; + + int render(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + static void output_notifier(const char *outname, INT32 value, void *param); + +private: + NSVGimage *m_image; + NSVGrasterizer *m_rasterizer; + + std::unordered_map<std::string, std::list<NSVGshape *>> m_keyed_shapes; + + void output_change(const char *outname, INT32 value); +}; + +screen_device_svg_renderer::screen_device_svg_renderer(memory_region *region) +{ + char *s = new char[region->bytes()+1]; + memcpy(s, region->base(), region->bytes()); + s[region->bytes()] = 0; + m_image = nsvgParse(s, "px", 72); + delete[] s; + m_rasterizer = nsvgCreateRasterizer(); + + for (NSVGshape *shape = m_image->shapes; shape != NULL; shape = shape->next) + if(shape->title[0]) { + shape->flags &= ~NSVG_FLAGS_VISIBLE; + m_keyed_shapes[shape->title].push_back(shape); + } +} + +screen_device_svg_renderer::~screen_device_svg_renderer() +{ + nsvgDeleteRasterizer(m_rasterizer); + nsvgDelete(m_image); +} + +int screen_device_svg_renderer::width() const +{ + return int(m_image->width + 0.5); +} + +int screen_device_svg_renderer::height() const +{ + return int(m_image->height + 0.5); +} + +int screen_device_svg_renderer::render(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + double sx = double(bitmap.width())/m_image->width; + double sy = double(bitmap.height())/m_image->height; + double sz = sx > sy ? sy : sx; + nsvgRasterize(m_rasterizer, m_image, 0, 0, sz, (unsigned char *)bitmap.raw_pixptr(0, 0), bitmap.width(), bitmap.height(), bitmap.rowbytes()); + + // Annoyingly, nanosvg doesn't use the same byte order than our bitmaps + + for(unsigned int y=0; y<bitmap.height(); y++) { + UINT8 *image = (UINT8 *)bitmap.raw_pixptr(y, 0); + for(unsigned int x=0; x<bitmap.width(); x++) { + UINT8 r = image[0]; + UINT8 g = image[1]; + UINT8 b = image[2]; + UINT32 color = 0xff000000 | (r << 16) | (g << 8) | (b << 0); + *(UINT32 *)image = color; + image += 4; + } + } + + return 0; +} + +void screen_device_svg_renderer::output_notifier(const char *outname, INT32 value, void *param) +{ + static_cast<screen_device_svg_renderer *>(param)->output_change(outname, value); +} + +void screen_device_svg_renderer::output_change(const char *outname, INT32 value) +{ + auto l = m_keyed_shapes.find(outname); + if (l == m_keyed_shapes.end()) + return; + if (value) + for(auto s : l->second) + s->flags |= NSVG_FLAGS_VISIBLE; + else + for(auto s : l->second) + s->flags &= ~NSVG_FLAGS_VISIBLE; +} + //************************************************************************** // SCREEN DEVICE //************************************************************************** @@ -55,6 +152,7 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev m_yscale(1.0f), m_palette(*this), m_video_attributes(0), + m_svg_region(nullptr), m_container(nullptr), m_width(100), m_height(100), @@ -106,6 +204,12 @@ void screen_device::static_set_type(device_t &device, screen_type_enum type) } +void screen_device::static_set_svg_region(device_t &device, const char *region) +{ + downcast<screen_device &>(device).m_svg_region = region; +} + + //------------------------------------------------- // static_set_raw - configuration helper // to set the raw screen parameters @@ -265,7 +369,7 @@ void screen_device::device_validity_check(validity_checker &valid) const osd_printf_error("Invalid display dimensions\n"); // sanity check display area - if (m_type != SCREEN_TYPE_VECTOR) + if (m_type != SCREEN_TYPE_VECTOR && m_type != SCREEN_TYPE_SVG) { if (m_visarea.empty() || m_visarea.max_x >= m_width || m_visarea.max_y >= m_height) osd_printf_error("Invalid display area\n"); @@ -275,6 +379,10 @@ void screen_device::device_validity_check(validity_checker &valid) const osd_printf_error("Missing SCREEN_UPDATE function\n"); } + // check for svg region + if (m_type == SCREEN_TYPE_SVG && !m_svg_region) + osd_printf_error("Missing SVG region information\n"); + // check for zero frame rate if (m_refresh == 0) osd_printf_error("Invalid (zero) refresh rate\n"); @@ -293,6 +401,23 @@ void screen_device::device_validity_check(validity_checker &valid) const void screen_device::device_start() { + if (m_type == SCREEN_TYPE_SVG) + { + memory_region *reg = owner()->memregion(m_svg_region); + if (!reg) + fatalerror("SVG region \"%s\" does not exist\n", m_svg_region); + m_svg = std::make_unique<screen_device_svg_renderer>(reg); + machine().output().set_notifier(nullptr, screen_device_svg_renderer::output_notifier, m_svg.get()); + + if (0) + { + // The osd picks up the size before start is called, so that's useless + m_width = m_svg->width(); + m_height = m_svg->height(); + m_visarea.set(0, m_width-1, 0, m_height-1); + } + } + // bind our handlers m_screen_update_ind16.bind_relative_to(*owner()); m_screen_update_rgb32.bind_relative_to(*owner()); @@ -303,6 +428,7 @@ void screen_device::device_start() throw device_missing_dependencies(); // configure bitmap formats and allocate screen bitmaps + // svg is RGB32 too, and doesn't have any update method texture_format texformat = !m_screen_update_ind16.isnull() ? TEXFORMAT_PALETTE16 : TEXFORMAT_RGB32; for (auto & elem : m_bitmap) @@ -472,8 +598,8 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a assert(visarea.min_y >= 0); // assert(visarea.max_x < width); // assert(visarea.max_y < height); - assert(m_type == SCREEN_TYPE_VECTOR || visarea.min_x < width); - assert(m_type == SCREEN_TYPE_VECTOR || visarea.min_y < height); + assert(m_type == SCREEN_TYPE_VECTOR || m_type == SCREEN_TYPE_SVG || visarea.min_x < width); + assert(m_type == SCREEN_TYPE_VECTOR || m_type == SCREEN_TYPE_SVG || visarea.min_y < height); assert(frame_period > 0); // fill in the new parameters @@ -649,12 +775,19 @@ bool screen_device::update_partial(int scanline) g_profiler.start(PROFILER_VIDEO); UINT32 flags; - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) + if (m_type != SCREEN_TYPE_SVG) { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } + } + else + { + flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); } m_partial_updates_this_frame++; diff --git a/src/emu/screen.h b/src/emu/screen.h index 711602b0395..182a1505b16 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -30,7 +30,8 @@ enum screen_type_enum SCREEN_TYPE_INVALID = 0, SCREEN_TYPE_RASTER, SCREEN_TYPE_VECTOR, - SCREEN_TYPE_LCD + SCREEN_TYPE_LCD, + SCREEN_TYPE_SVG }; // texture formats @@ -155,6 +156,8 @@ typedef device_delegate<void (screen_device &, bool)> screen_vblank_delegate; // ======================> screen_device +class screen_device_svg_renderer; + class screen_device : public device_t { friend class render_manager; @@ -194,6 +197,7 @@ public: static void static_set_palette(device_t &device, const char *tag); static void static_set_video_attributes(device_t &device, UINT32 flags); static void static_set_color(device_t &device, rgb_t color); + static void static_set_svg_region(device_t &device, const char *region); // information getters render_container &container() const { assert(m_container != nullptr); return *m_container; } @@ -279,10 +283,11 @@ private: screen_vblank_delegate m_screen_vblank; // screen vblank callback optional_device<palette_device> m_palette; // our palette UINT32 m_video_attributes; // flags describing the video system + const char * m_svg_region; // the region in which the svg data is in // internal state render_container * m_container; // pointer to our container - + std::unique_ptr<screen_device_svg_renderer> m_svg; // the svg renderer // dimensions int m_width; // current width (HTOTAL) int m_height; // current height (VTOTAL) @@ -378,6 +383,11 @@ typedef device_type_iterator<&device_creator<screen_device>, screen_device> scre #define MCFG_SCREEN_TYPE(_type) \ screen_device::static_set_type(*device, SCREEN_TYPE_##_type); +#define MCFG_SCREEN_SVG_ADD(_tag, _region) \ + MCFG_DEVICE_ADD(_tag, SCREEN, 0) \ + MCFG_SCREEN_TYPE(SVG) \ + screen_device::static_set_svg_region(*device, _region); + /*! @brief Configures screen parameters for the given screen. diff --git a/src/lib/util/nanosvg.cpp b/src/lib/util/nanosvg.cpp new file mode 100644 index 00000000000..09973865675 --- /dev/null +++ b/src/lib/util/nanosvg.cpp @@ -0,0 +1,6 @@ +#define NANOSVG_IMPLEMENTATION +#define NANOSVGRAST_IMPLEMENTATION +#define NANOSVG_ALL_COLOR_KEYWORDS + +#include <nanosvg/src/nanosvg.h> +#include <nanosvg/src/nanosvgrast.h> diff --git a/src/mame/drivers/hh_hmcs40.cpp b/src/mame/drivers/hh_hmcs40.cpp index 3bc28b5a538..4da7f9d5847 100644 --- a/src/mame/drivers/hh_hmcs40.cpp +++ b/src/mame/drivers/hh_hmcs40.cpp @@ -87,6 +87,7 @@ #include "sound/speaker.h" // internal artwork +#include "rendlay.h" #include "pairmtch.lh" #include "hh_hmcs40_test.lh" // common test-layout - use external artwork @@ -2070,7 +2071,12 @@ static MACHINE_CONFIG_START( cdkong, cdkong_state ) MCFG_TIMER_DRIVER_ADD_PERIODIC("speaker_decay", cdkong_state, speaker_decay_sim, attotime::from_msec(CDKONG_SPEAKER_DECAY)) MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_hmcs40_state, display_decay_tick, attotime::from_msec(1)) - MCFG_DEFAULT_LAYOUT(layout_hh_hmcs40_test) + + MCFG_SCREEN_SVG_ADD("screen", "svg") + MCFG_SCREEN_REFRESH_RATE(10) + MCFG_SCREEN_SIZE(538, 1001) + MCFG_SCREEN_VISIBLE_AREA(0, 537, 0, 1000) + MCFG_DEFAULT_LAYOUT(layout_svg) /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") @@ -3960,6 +3966,9 @@ ROM_START( cdkong ) ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASE00 ) ROM_LOAD( "hd38820a45", 0x0000, 0x1000, CRC(196b8070) SHA1(da85d1eb4b048b77f3168630662ab94ec9baa262) ) ROM_CONTINUE( 0x1e80, 0x0100 ) + + ROM_REGION( 714102, "svg", 0) + ROM_LOAD( "cdkong.svg", 0, 714102, CRC(184bbe69) SHA1(98554341054246e5d76e0779620498e6cb723958) ) ROM_END @@ -4098,7 +4107,7 @@ CONS( 1984, machiman, 0, 0, machiman, machiman, driver_device, 0, "Banda CONS( 1984, pairmtch, 0, 0, pairmtch, pairmtch, driver_device, 0, "Bandai", "Pair Match", MACHINE_SUPPORTS_SAVE ) CONS( 1981, alnattck, 0, 0, alnattck, alnattck, driver_device, 0, "Coleco", "Alien Attack", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) -CONS( 1982, cdkong, 0, 0, cdkong, cdkong, driver_device, 0, "Coleco", "Donkey Kong (Coleco)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK | MACHINE_IMPERFECT_SOUND ) +CONS( 1982, cdkong, 0, 0, cdkong, cdkong, driver_device, 0, "Coleco", "Donkey Kong (Coleco)", MACHINE_SUPPORTS_SAVE ) CONS( 1982, cgalaxn, 0, 0, cgalaxn, cgalaxn, driver_device, 0, "Coleco", "Galaxian (Coleco)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK | MACHINE_IMPERFECT_SOUND ) CONS( 1981, cpacman, 0, 0, cpacman, cpacman, driver_device, 0, "Coleco", "Pac-Man (Coleco, Rev. 29)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) CONS( 1981, cpacmanr1, cpacman, 0, cpacman, cpacman, driver_device, 0, "Coleco", "Pac-Man (Coleco, Rev. 28)", MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) |