summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
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
commitcdc04a9b7c72343b67f24be1c1a0d01780dafd8d (patch)
treea12995d0cdad152f381b1e8f8f4754ab4827a09c /src
parent57e9e774cd056973a036d2b75273d84cea383494 (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.lay8
-rw-r--r--src/emu/luaengine.cpp1
-rw-r--r--src/emu/rendlay.cpp2
-rw-r--r--src/emu/rendlay.h3
-rw-r--r--src/emu/screen.cpp149
-rw-r--r--src/emu/screen.h14
-rw-r--r--src/lib/util/nanosvg.cpp6
-rw-r--r--src/mame/drivers/hh_hmcs40.cpp13
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 )