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.
master
Olivier Galibert 2016-04-04 11:28:22 +02:00
parent 57e9e774cd
commit cdc04a9b7c
23 changed files with 6392 additions and 12 deletions

18
3rdparty/nanosvg/LICENSE.txt vendored Normal file
View File

@ -0,0 +1,18 @@
Copyright (c) 2013-14 Mikko Mononen memon@inside.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

100
3rdparty/nanosvg/README.md vendored Normal file
View File

@ -0,0 +1,100 @@
Nano SVG
==========
## Parser
![screenshot of some splines rendered witht the sample program](/example/screenshot-1.png?raw=true)
NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
The shapes in the SVG images are transformed by the viewBox and converted to specified units.
That is, you should get the same looking data as your designed in your favorite app.
NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
DPI (dots-per-inch) controls how the unit conversion is done.
If you don't know or care about the units stuff, "px" and 96 should get you going.
## Rasterizer
![screenshot of tiger.svg rendered with NanoSVG rasterizer](/example/screenshot-2.png?raw=true)
The parser library is accompanied with really simpler SVG rasterizer. Currently it only renders flat filled shapes.
The intended usage for the rasterizer is to for example bake icons of different size into a texture. The rasterizer is not particular fast or accurate, but it's small and packed in one header file.
## Example Usage
``` C
// Load
struct NSVGimage* image;
image = nsvgParseFromFile("test.svg", "px", 96);
printf("size: %f x %f\n", image->width, image->height);
// Use...
for (shape = image->shapes; shape != NULL; shape = shape->next) {
for (path = shape->paths; path != NULL; path = path->next) {
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
}
}
}
// Delete
nsvgDelete(image);
```
## Using NanoSVG in your project
In order to use NanoSVG in your own project, just copy nanosvg.h to your project.
In one C/C++ define `NANOSVG_IMPLEMENTATION` before including the library to expand the NanoSVG implementation in that file.
NanoSVG depends on `stdio.h` ,`string.h` and `math.h`, they should be included where the implementation is expanded before including NanoSVG.
``` C
#include <stdio.h>
#include <string.h>
#include <math.h>
#define NANOSVG_IMPLEMENTATION // Expands implementation
#include "nanosvg.h"
```
By default, NanoSVG parses only the most common colors. In order to get support for full list of [SVG color keywords](http://www.w3.org/TR/SVG11/types.html#ColorKeywords), define `NANOSVG_ALL_COLOR_KEYWORDS` before expanding the implementation.
``` C
#include <stdio.h>
#include <string.h>
#include <math.h>
#define NANOSVG_ALL_COLOR_KEYWORDS // Include full list of color keywords.
#define NANOSVG_IMPLEMENTATION // Expands implementation
#include "nanosvg.h"
```
## Compiling Example Project
In order to compile the demo project, your will need to install [GLFW](http://www.glfw.org/) to compile.
NanoSVG demo project uses [premake4](http://industriousone.com/premake) to build platform specific projects, now is good time to install it if you don't have it already. To build the example, navigate into the root folder in your favorite terminal, then:
- *OS X*: `premake4 xcode4`
- *Windows*: `premake4 vs2010`
- *Linux*: `premake4 gmake`
See premake4 documentation for full list of supported build file types. The projects will be created in `build` folder. An example of building and running the example on OS X:
```bash
$ premake4 gmake
$ cd build/
$ make
$ ./example
```
# License
The library is licensed under [zlib license](LICENSE.txt)

730
3rdparty/nanosvg/example/23.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 94 KiB

97
3rdparty/nanosvg/example/drawing.svg vendored Normal file
View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000"
height="1000"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="drawing.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="375"
inkscape:cy="520"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="751"
inkscape:window-height="578"
inkscape:window-x="0"
inkscape:window-y="22"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-52.362183)">
<path
style="fill:#ff5555;stroke:#000000;stroke-width:10.62107277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 131.73911,422.01626 c 0,146.85769 43.82213,215.39128 201.5818,141.96244 157.75968,-73.42885 188.43518,-107.69564 354.95926,78.32409 166.5241,186.01973 210.34624,244.76282 162.1419,-122.3814 -48.20435,-367.1442 -4.38221,34.26679 -131.46641,-24.47627 C 591.87149,436.70204 732.10231,191.93923 543.66715,187.04398 355.23198,182.14871 574.34264,265.36807 534.90271,368.16845 495.4628,470.96883 355.23198,627.61702 311.40985,475.8641 267.58772,324.11115 193.09009,333.90166 131.73911,422.01626 z"
id="path2985"
inkscape:connector-curvature="0" />
<rect
style="fill:#00ffff;stroke:#000000;stroke-width:10.62107277px;"
id="rect2987"
width="390.01697"
height="200.70551"
x="228.14781"
y="539.50238" />
<path
sodipodi:type="arc"
style="fill:#00ffff"
id="path3008"
sodipodi:cx="157.14285"
sodipodi:cy="168.57143"
sodipodi:rx="57.142857"
sodipodi:ry="88.571426"
d="m 214.28571,168.57143 a 57.142857,88.571426 0 1 1 -114.285714,0 57.142857,88.571426 0 1 1 114.285714,0 z"
transform="translate(188.57143,138.07647)" />
<rect
style="fill:#00ff00"
id="rect3010"
width="371.42856"
height="145.71428"
x="261.66104"
y="945.44141"
transform="matrix(0.948958,-0.31540248,0.31540248,0.948958,0,0)"
ry="51.42857" />
<path
sodipodi:type="arc"
style="fill:#00ff00"
id="path3038"
sodipodi:cx="200"
sodipodi:cy="177.14285"
sodipodi:rx="54.285713"
sodipodi:ry="54.285713"
d="m 254.28571,177.14285 a 54.285713,54.285713 0 1 1 -108.57142,0 54.285713,54.285713 0 1 1 108.57142,0 z"
transform="translate(0,52.362183)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

258
3rdparty/nanosvg/example/example1.c vendored Normal file
View File

@ -0,0 +1,258 @@
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include <stdio.h>
#include <string.h>
#include <float.h>
#include <GLFW/glfw3.h>
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
NSVGimage* g_image = NULL;
static unsigned char bgColor[4] = {205,202,200,255};
static unsigned char lineColor[4] = {0,160,192,255};
static float distPtSeg(float x, float y, float px, float py, float qx, float qy)
{
float pqx, pqy, dx, dy, d, t;
pqx = qx-px;
pqy = qy-py;
dx = x-px;
dy = y-py;
d = pqx*pqx + pqy*pqy;
t = pqx*dx + pqy*dy;
if (d > 0) t /= d;
if (t < 0) t = 0;
else if (t > 1) t = 1;
dx = px + t*pqx - x;
dy = py + t*pqy - y;
return dx*dx + dy*dy;
}
static void cubicBez(float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
float tol, int level)
{
float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
float d;
if (level > 12) return;
x12 = (x1+x2)*0.5f;
y12 = (y1+y2)*0.5f;
x23 = (x2+x3)*0.5f;
y23 = (y2+y3)*0.5f;
x34 = (x3+x4)*0.5f;
y34 = (y3+y4)*0.5f;
x123 = (x12+x23)*0.5f;
y123 = (y12+y23)*0.5f;
x234 = (x23+x34)*0.5f;
y234 = (y23+y34)*0.5f;
x1234 = (x123+x234)*0.5f;
y1234 = (y123+y234)*0.5f;
d = distPtSeg(x1234, y1234, x1,y1, x4,y4);
if (d > tol*tol) {
cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1);
cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1);
} else {
glVertex2f(x4, y4);
}
}
void drawPath(float* pts, int npts, char closed, float tol)
{
int i;
glBegin(GL_LINE_STRIP);
glColor4ubv(lineColor);
glVertex2f(pts[0], pts[1]);
for (i = 0; i < npts-1; i += 3) {
float* p = &pts[i*2];
cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], tol, 0);
}
if (closed) {
glVertex2f(pts[0], pts[1]);
}
glEnd();
}
void drawControlPts(float* pts, int npts)
{
int i;
// Control lines
glColor4ubv(lineColor);
glBegin(GL_LINES);
for (i = 0; i < npts-1; i += 3) {
float* p = &pts[i*2];
glVertex2f(p[0],p[1]);
glVertex2f(p[2],p[3]);
glVertex2f(p[4],p[5]);
glVertex2f(p[6],p[7]);
}
glEnd();
// Points
glPointSize(6.0f);
glColor4ubv(lineColor);
glBegin(GL_POINTS);
glVertex2f(pts[0],pts[1]);
for (i = 0; i < npts-1; i += 3) {
float* p = &pts[i*2];
glVertex2f(p[6],p[7]);
}
glEnd();
// Points
glPointSize(3.0f);
glBegin(GL_POINTS);
glColor4ubv(bgColor);
glVertex2f(pts[0],pts[1]);
for (i = 0; i < npts-1; i += 3) {
float* p = &pts[i*2];
glColor4ubv(lineColor);
glVertex2f(p[2],p[3]);
glVertex2f(p[4],p[5]);
glColor4ubv(bgColor);
glVertex2f(p[6],p[7]);
}
glEnd();
}
void drawframe(GLFWwindow* window)
{
int width = 0, height = 0;
float view[4], cx, cy, hw, hh, aspect, px;
NSVGshape* shape;
NSVGpath* path;
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(220.0f/255.0f, 220.0f/255.0f, 220.0f/255.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Fit view to bounds
cx = g_image->width*0.5f;
cy = g_image->height*0.5f;
hw = g_image->width*0.5f;
hh = g_image->height*0.5f;
if (width/hw < height/hh) {
aspect = (float)height / (float)width;
view[0] = cx - hw * 1.2f;
view[2] = cx + hw * 1.2f;
view[1] = cy - hw * 1.2f * aspect;
view[3] = cy + hw * 1.2f * aspect;
} else {
aspect = (float)width / (float)height;
view[0] = cx - hh * 1.2f * aspect;
view[2] = cx + hh * 1.2f * aspect;
view[1] = cy - hh * 1.2f;
view[3] = cy + hh * 1.2f;
}
// Size of one pixel.
px = (view[2] - view[1]) / (float)width;
glOrtho(view[0], view[2], view[3], view[1], -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glColor4ub(255,255,255,255);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// Draw bounds
glColor4ub(0,0,0,64);
glBegin(GL_LINE_LOOP);
glVertex2f(0, 0);
glVertex2f(g_image->width, 0);
glVertex2f(g_image->width, g_image->height);
glVertex2f(0, g_image->height);
glEnd();
for (shape = g_image->shapes; shape != NULL; shape = shape->next) {
for (path = shape->paths; path != NULL; path = path->next) {
drawPath(path->pts, path->npts, path->closed, px * 1.5f);
drawControlPts(path->pts, path->npts);
}
}
glfwSwapBuffers(window);
}
void resizecb(GLFWwindow* window, int width, int height)
{
// Update and render
NSVG_NOTUSED(width);
NSVG_NOTUSED(height);
drawframe(window);
}
int main()
{
GLFWwindow* window;
const GLFWvidmode* mode;
if (!glfwInit())
return -1;
mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
window = glfwCreateWindow(mode->width - 40, mode->height - 80, "Nano SVG", NULL, NULL);
if (!window)
{
printf("Could not open window\n");
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, resizecb);
glfwMakeContextCurrent(window);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
g_image = nsvgParseFromFile("../example/nano.svg", "px", 96.0f);
if (g_image == NULL) {
printf("Could not open SVG image.\n");
glfwTerminate();
return -1;
}
while (!glfwWindowShouldClose(window))
{
drawframe(window);
glfwPollEvents();
}
nsvgDelete(g_image);
glfwTerminate();
return 0;
}

69
3rdparty/nanosvg/example/example2.c vendored Normal file
View File

@ -0,0 +1,69 @@
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include <stdio.h>
#include <string.h>
#include <float.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
int main()
{
NSVGimage *image = NULL;
NSVGrasterizer *rast = NULL;
unsigned char* img = NULL;
int w, h;
const char* filename = "../example/_test.svg";
printf("parsing %s\n", filename);
image = nsvgParseFromFile(filename, "px", 96.0f);
if (image == NULL) {
printf("Could not open SVG image.\n");
goto error;
}
w = (int)image->width;
h = (int)image->height;
rast = nsvgCreateRasterizer();
if (rast == NULL) {
printf("Could not init rasterizer.\n");
goto error;
}
img = malloc(w*h*4);
if (img == NULL) {
printf("Could not alloc image buffer.\n");
goto error;
}
printf("rasterizing image %d x %d\n", w, h);
nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
printf("writing svg.png\n");
stbi_write_png("svg.png", w, h, 4, img, w*4);
error:
nsvgDeleteRasterizer(rast);
nsvgDelete(image);
return 0;
}

27
3rdparty/nanosvg/example/nano.svg vendored Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="640px" height="480px" viewBox="0 0 640 480" enable-background="new 0 0 640 480" xml:space="preserve">
<path d="M282.658,250.271c0,5.31-1.031,10.156-3.087,14.543c-2.059,4.387-4.984,8.152-8.774,11.293
c-3.793,3.144-8.477,5.58-14.055,7.312c-5.581,1.731-11.836,2.601-18.767,2.601c-9.968,0-18.605-1.572-25.917-4.713
s-13.299-6.986-17.955-11.536l13.812-15.111c4.116,3.684,8.584,6.499,13.405,8.449c4.819,1.95,9.993,2.925,15.518,2.925
c5.525,0,9.856-1.219,12.999-3.656c3.141-2.438,4.712-5.769,4.712-9.993c0-2.056-0.3-3.844-0.894-5.361
c-0.596-1.517-1.653-2.925-3.168-4.226c-1.518-1.3-3.549-2.519-6.093-3.655c-2.546-1.138-5.768-2.301-9.668-3.494
c-6.5-2.056-11.943-4.25-16.33-6.58c-4.387-2.328-7.937-4.9-10.643-7.719c-2.709-2.815-4.659-5.931-5.849-9.343
c-1.193-3.412-1.788-7.23-1.788-11.455c0-5.2,1.082-9.831,3.25-13.893c2.166-4.062,5.144-7.5,8.937-10.318
c3.791-2.815,8.178-4.956,13.162-6.418c4.981-1.462,10.343-2.193,16.086-2.193c8.449,0,15.842,1.247,22.179,3.737
c6.337,2.493,11.997,6.121,16.98,10.887l-12.674,14.624c-7.583-6.281-15.655-9.424-24.21-9.424c-4.875,0-8.721,0.95-11.537,2.844
c-2.818,1.896-4.225,4.578-4.225,8.043c0,1.843,0.297,3.412,0.894,4.712c0.594,1.3,1.65,2.519,3.168,3.656
c1.516,1.137,3.656,2.249,6.418,3.331c2.763,1.084,6.309,2.33,10.643,3.736c5.306,1.734,10.046,3.631,14.218,5.688
c4.169,2.06,7.662,4.524,10.48,7.394c2.815,2.871,4.981,6.174,6.5,9.911C281.898,240.603,282.658,245.071,282.658,250.271z
M335.953,260.833l20.637-90.181h27.46l-32.011,112.604h-33.634l-32.173-112.604h28.598l20.311,90.181H335.953z M437.832,286.019
c-16.357,0-28.896-5.01-37.615-15.03c-8.722-10.019-13.081-24.779-13.081-44.278c0-9.531,1.407-17.98,4.225-25.348
c2.815-7.366,6.688-13.54,11.618-18.524c4.928-4.981,10.668-8.747,17.223-11.293c6.555-2.544,13.568-3.818,21.043-3.818
c8.23,0,15.436,1.3,21.611,3.899c6.174,2.6,11.537,5.959,16.086,10.075l-14.137,14.624c-3.467-3.032-6.906-5.281-10.318-6.744
s-7.393-2.193-11.941-2.193c-4.01,0-7.693,0.731-11.051,2.193s-6.256,3.793-8.691,6.987c-2.438,3.196-4.334,7.287-5.688,12.268
c-1.355,4.984-2.031,10.996-2.031,18.037c0,7.367,0.486,13.567,1.463,18.604c0.975,5.037,2.408,9.1,4.305,12.187
c1.895,3.087,4.307,5.309,7.23,6.662c2.926,1.355,6.338,2.031,10.238,2.031c5.631,0,10.613-1.244,14.947-3.737v-25.186h-14.785
l-2.6-18.849h43.547v55.57c-5.85,3.793-12.297,6.718-19.336,8.774C453.051,284.987,445.631,286.019,437.832,286.019z M523.5,151.5
c0-6.627-5.373-12-12-12h-343c-6.627,0-12,5.373-12,12v150c0,6.627,5.373,12,12,12h343c6.627,0,12-5.373,12-12V151.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -0,0 +1,511 @@
/* stbiw-0.92 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
or run-time performance.
USAGE:
There are three functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP and TGA formats expand Y to RGB in the file format. BMP does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
assert(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1:
case 2: write3(f, d[0],d[0],d[0]);
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = !(comp & 1);
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
}
// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
#define stbi__sbraw(a) ((int *) (a) - 2)
#define stbi__sbm(a) stbi__sbraw(a)[0]
#define stbi__sbn(a) stbi__sbraw(a)[1]
#define stbi__sbneedgrow(a,n) ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a))
#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0)
#define stbi__sbgrow(a,n) stbi__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbi__sbpush(a, v) (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v))
#define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0)
#define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)),0 : 0)
static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1;
void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
assert(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbi__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbi__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbi__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbi__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
#define stbi__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
#define stbi__zlib_huffa(b,c) stbi__zlib_add(stbi__zlib_bitrev(b,c),c)
// default huffman tables
#define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8)
#define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9)
#define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256,7)
#define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280,8)
#define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
#define stbi__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbi__sbpush(out, 0x78); // DEFLATE 32K window
stbi__sbpush(out, 0x5e); // FLEVEL = 1
stbi__zlib_add(1,1); // BFINAL = 1
stbi__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
for (i=0; i < stbi__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbi__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) {
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbi__sbn(hash_table[h]) = quality;
}
stbi__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbi__zhash(data+i+1)&(stbi__ZHASH-1);
hlist = hash_table[h];
n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = data+i - bestloc; // distance back
assert(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbi__zlib_huff(j+257);
if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbi__zlib_add(stbi__zlib_bitrev(j,5),5);
if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbi__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbi__zlib_huffb(data[i]);
stbi__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbi__zlib_add(0,1);
for (i=0; i < stbi__ZHASH; ++i)
(void) stbi__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbi__sbpush(out, (unsigned char) (s2 >> 8));
stbi__sbpush(out, (unsigned char) s2);
stbi__sbpush(out, (unsigned char) (s1 >> 8));
stbi__sbpush(out, (unsigned char) s1);
}
*out_len = stbi__sbn(out);
// make returned pointer freeable
memmove(stbi__sbraw(out), out, *out_len);
return (unsigned char *) stbi__sbraw(out);
}
unsigned int stbi__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbi__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbi__wp32(data,v) stbi__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3])
static void stbi__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbi__crc32(*data - len - 4, len+4);
stbi__wp32(*data, crc);
}
static unsigned char stbi__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbi__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
}
free(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
free(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
memcpy(o,sig,8); o+= 8;
stbi__wp32(o, 13); // header length
stbi__wptag(o, "IHDR");
stbi__wp32(o, x);
stbi__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbi__wpcrc(&o,13);
stbi__wp32(o, zlen);
stbi__wptag(o, "IDAT");
memcpy(o, zlib, zlen); o += zlen; free(zlib);
stbi__wpcrc(&o, zlen);
stbi__wp32(o,0);
stbi__wptag(o, "IEND");
stbi__wpcrc(&o,0);
assert(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { free(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
free(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

56
3rdparty/nanosvg/premake4.lua vendored Normal file
View File

@ -0,0 +1,56 @@
local action = _ACTION or ""
solution "nanosvg"
location ( "build" )
configurations { "Debug", "Release" }
platforms {"native", "x64", "x32"}
project "example1"
kind "ConsoleApp"
language "C++"
files { "example/example1.c", "example/*.h", "src/*.h" }
includedirs { "example", "src" }
targetdir("build")
configuration { "linux" }
links { "X11","Xrandr", "rt", "GL", "GLU", "pthread" }
configuration { "windows" }
links { "glu32","opengl32", "gdi32", "winmm", "user32" }
configuration { "macosx" }
links { "glfw3" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols", "ExtraWarnings"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize", "ExtraWarnings"}
project "example2"
kind "ConsoleApp"
language "C++"
files { "example/example2.c", "example/*.h", "src/*.h" }
includedirs { "example", "src" }
targetdir("build")
configuration { "linux" }
links { "X11","Xrandr", "rt", "pthread" }
configuration { "windows" }
links { "winmm", "user32" }
configuration { "macosx" }
linkoptions { "-framework Cocoa", "-framework IOKit" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols", "ExtraWarnings"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize", "ExtraWarnings"}

2892
3rdparty/nanosvg/src/nanosvg.h vendored Normal file

File diff suppressed because it is too large Load Diff

1447
3rdparty/nanosvg/src/nanosvgrast.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -408,6 +408,7 @@ dependency {
{ MAME_DIR .. "src/emu/rendlay.cpp", GEN_DIR .. "emu/layout/vertical.lh" },
{ MAME_DIR .. "src/emu/rendlay.cpp", GEN_DIR .. "emu/layout/lcd.lh" },
{ MAME_DIR .. "src/emu/rendlay.cpp", GEN_DIR .. "emu/layout/lcd_rot.lh" },
{ MAME_DIR .. "src/emu/rendlay.cpp", GEN_DIR .. "emu/layout/svg.lh" },
{ MAME_DIR .. "src/emu/rendlay.cpp", GEN_DIR .. "emu/layout/noscreens.lh" },
{ MAME_DIR .. "src/emu/video.cpp", GEN_DIR .. "emu/layout/snap.lh" },
@ -430,6 +431,7 @@ custombuildtask {
layoutbuildtask("emu/layout", "vertical"),
layoutbuildtask("emu/layout", "lcd"),
layoutbuildtask("emu/layout", "lcd_rot"),
layoutbuildtask("emu/layout", "svg"),
layoutbuildtask("emu/layout", "noscreens"),
layoutbuildtask("emu/layout", "snap"),
}

View File

@ -64,6 +64,7 @@ project "utils"
MAME_DIR .. "src/lib/util/jedparse.h",
MAME_DIR .. "src/lib/util/md5.cpp",
MAME_DIR .. "src/lib/util/md5.h",
MAME_DIR .. "src/lib/util/nanosvg.cpp",
MAME_DIR .. "src/lib/util/opresolv.cpp",
MAME_DIR .. "src/lib/util/opresolv.h",
MAME_DIR .. "src/lib/util/options.cpp",

8
src/emu/layout/svg.lay Normal file
View File

@ -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>

View File

@ -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;
}

View File

@ -82,6 +82,8 @@
#include "lcd.lh"
#include "lcd_rot.lh"
// SVG screen layouts
#include "svg.lh"
//**************************************************************************

View File

@ -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__

View File

@ -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++;

View File

@ -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.

6
src/lib/util/nanosvg.cpp Normal file
View File

@ -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>

View File

@ -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 )