Merge branch 'dtt-c-render' into overlays
Conflicts: setup.py
This commit is contained in:
97
README.rst
97
README.rst
@@ -32,7 +32,7 @@ Features
|
|||||||
* Renders efficiently in parallel, using as many simultaneous processes as you
|
* Renders efficiently in parallel, using as many simultaneous processes as you
|
||||||
want!
|
want!
|
||||||
|
|
||||||
* Utilizes 2 levels of caching to speed up subsequent renderings of your world.
|
* Utilizes caching to speed up subsequent renderings of your world.
|
||||||
|
|
||||||
* Throw the output directory up on a web server to share your Minecraft world
|
* Throw the output directory up on a web server to share your Minecraft world
|
||||||
with everyone!
|
with everyone!
|
||||||
@@ -46,6 +46,9 @@ This program requires:
|
|||||||
* Numpy <http://scipy.org/Download>
|
* Numpy <http://scipy.org/Download>
|
||||||
* Either the Minecraft client installed, or a terrain.png file. See the
|
* Either the Minecraft client installed, or a terrain.png file. See the
|
||||||
`Textures`_ section below.
|
`Textures`_ section below.
|
||||||
|
* A C compiler.
|
||||||
|
|
||||||
|
If you download a binary package, then some or all of these may not be required.
|
||||||
|
|
||||||
I develop and test this on Linux, but need help testing it on Windows and Mac.
|
I develop and test this on Linux, but need help testing it on Windows and Mac.
|
||||||
If something doesn't work, let me know.
|
If something doesn't work, let me know.
|
||||||
@@ -97,15 +100,14 @@ will use the biome data to tint grass and leaves automatically -- there is no
|
|||||||
command line option to turn this feature on. If this folder does not exist,
|
command line option to turn this feature on. If this folder does not exist,
|
||||||
then the Overviewer will use a static tinting for grass and leaves.
|
then the Overviewer will use a static tinting for grass and leaves.
|
||||||
|
|
||||||
Compiling the C Extension (optional)
|
Compiling the C Extension
|
||||||
------------------------------------
|
-------------------------
|
||||||
The C Extension for Overviewer is completely optional. It provides a higher
|
The C Extension for Overviewer is no longer optional. In addition to providing
|
||||||
quality image compositing function that looks better on maps with lighting
|
a higher quality image compositing function that looks better on maps with lighting
|
||||||
enabled, and a slight performance boost.
|
enabled, it now does the bulk of the rendering.
|
||||||
|
|
||||||
If you downloaded Overviewer as a binary package, this extension may be already
|
If you downloaded Overviewer as a binary package, this extension will already be
|
||||||
compiled for you. Overviewer emits a warning if the extension is not found, but
|
compiled for you.
|
||||||
will still work fine.
|
|
||||||
|
|
||||||
If you have a C compiler and the Python development libraries set up, you can
|
If you have a C compiler and the Python development libraries set up, you can
|
||||||
compile this extension like this::
|
compile this extension like this::
|
||||||
@@ -119,6 +121,9 @@ you get errors complaining about them, you can get them from the PIL source, or
|
|||||||
at <http://svn.effbot.org/public/tags/pil-1.1.7/libImaging/>. Just put them in
|
at <http://svn.effbot.org/public/tags/pil-1.1.7/libImaging/>. Just put them in
|
||||||
the same directory as "_composite.c".
|
the same directory as "_composite.c".
|
||||||
|
|
||||||
|
For more detailed instructions, check the wiki:
|
||||||
|
https://github.com/brownan/Minecraft-Overviewer/wiki/Build-Instructions
|
||||||
|
|
||||||
Running
|
Running
|
||||||
-------
|
-------
|
||||||
To generate a set of Google Map tiles, use the overviewer.py script like this::
|
To generate a set of Google Map tiles, use the overviewer.py script like this::
|
||||||
@@ -130,11 +135,6 @@ set of image tiles for your world in the directory you choose. When it's done,
|
|||||||
you will find an index.html file in the same directory that you can use to view
|
you will find an index.html file in the same directory that you can use to view
|
||||||
it.
|
it.
|
||||||
|
|
||||||
**Important note about Caches**
|
|
||||||
|
|
||||||
The Overviewer will put a cached image for every chunk *directly in your world
|
|
||||||
directory by default*. If you do not like this behavior, you can specify
|
|
||||||
another location with the --cachedir option. See below for details.
|
|
||||||
|
|
||||||
Options
|
Options
|
||||||
-------
|
-------
|
||||||
@@ -142,19 +142,6 @@ Options
|
|||||||
-h, --help
|
-h, --help
|
||||||
Shows the list of options and exits
|
Shows the list of options and exits
|
||||||
|
|
||||||
--cachedir=CACHEDIR
|
|
||||||
By default, the Overviewer will save in your world directory one image
|
|
||||||
file for every chunk in your world. If you do backups of your world,
|
|
||||||
you may not want these images in your world directory.
|
|
||||||
|
|
||||||
Use this option to specify an alternate location to put the rendered
|
|
||||||
chunk images. You must specify this same directory each rendering so
|
|
||||||
that it doesn't have to render every chunk from scratch every time.
|
|
||||||
|
|
||||||
Example::
|
|
||||||
|
|
||||||
python overviewer.py --cachedir=<chunk cache dir> <world> <output dir>
|
|
||||||
|
|
||||||
--imgformat=FORMAT
|
--imgformat=FORMAT
|
||||||
Set the output image format used for the tiles. The default is 'png',
|
Set the output image format used for the tiles. The default is 'png',
|
||||||
but 'jpg' is also supported. Note that regardless of what you choose,
|
but 'jpg' is also supported. Note that regardless of what you choose,
|
||||||
@@ -200,39 +187,22 @@ Options
|
|||||||
|
|
||||||
-d, --delete
|
-d, --delete
|
||||||
This option changes the mode of execution. No tiles are rendered, and
|
This option changes the mode of execution. No tiles are rendered, and
|
||||||
instead, cache files are deleted.
|
instead, files are deleted.
|
||||||
|
|
||||||
Explanation: The Overviewer keeps two levels of cache: it saves each
|
*Note*: Currently only the overviewer.dat file is deleted when you run with
|
||||||
chunk rendered as a png, and it keeps a hash file along side each tile
|
this option
|
||||||
in your output directory. Using these cache files allows the Overviewer
|
|
||||||
to skip rendering of any tile image that has not changed.
|
|
||||||
|
|
||||||
By default, the chunk images are saved in your world directory. This
|
--regionlist=regionlist
|
||||||
example will remove them::
|
Use this option to specify manually a list of regions to consider for
|
||||||
|
updating. Without this option, every chunk in every region is checked for
|
||||||
python overviewer.py -d <World # / Path to World / Path to cache dir>
|
update and if necessary, re-rendered. If this option points to a file
|
||||||
|
containing, 1 per line, the path to a region data file, then only those
|
||||||
You can also delete the tile cache as well. This will force a full
|
in the list will be considered for update.
|
||||||
re-render, useful if you've changed texture packs and want your world
|
|
||||||
to look uniform. Here's an example::
|
|
||||||
|
|
||||||
python overviewer.py -d <# / path> <Tile Directory>
|
|
||||||
|
|
||||||
Be warned, this will cause the next rendering of your map to take
|
|
||||||
significantly longer, since it is having to re-generate the files you just
|
|
||||||
deleted.
|
|
||||||
|
|
||||||
--chunklist=CHUNKLIST
|
|
||||||
Use this option to specify manually a list of chunks to consider for
|
|
||||||
updating. Without this option, every chunk is checked for update and if
|
|
||||||
necessary, re-rendered. If this option points to a file containing, 1 per
|
|
||||||
line, the path to a chunk data file, then only those in the list will be
|
|
||||||
considered for update.
|
|
||||||
|
|
||||||
It's up to you to build such a list. On Linux or Mac, try using the "find"
|
It's up to you to build such a list. On Linux or Mac, try using the "find"
|
||||||
command. You could, for example, output all chunk files that are older than
|
command. You could, for example, output all region files that are older than
|
||||||
a certain date. Or perhaps you can incrementally update your map by passing
|
a certain date. Or perhaps you can incrementally update your map by passing
|
||||||
in a subset of chunks each time. It's up to you!
|
in a subset of regions each time. It's up to you!
|
||||||
|
|
||||||
--lighting
|
--lighting
|
||||||
This option enables map lighting, using lighting information stored by
|
This option enables map lighting, using lighting information stored by
|
||||||
@@ -255,6 +225,18 @@ Options
|
|||||||
The script should be executable, and it should accept one argument:
|
The script should be executable, and it should accept one argument:
|
||||||
the path to the output directory.
|
the path to the output directory.
|
||||||
|
|
||||||
|
|
||||||
|
Settings
|
||||||
|
--------
|
||||||
|
|
||||||
|
You can optionally store settings in a file named settings.py. It is a regular
|
||||||
|
python script, so you can use any python functions or modules you want.
|
||||||
|
|
||||||
|
This section needs to be expanded
|
||||||
|
|
||||||
|
For a sample settings file, look at sample.settings.py
|
||||||
|
|
||||||
|
|
||||||
Viewing the Results
|
Viewing the Results
|
||||||
-------------------
|
-------------------
|
||||||
Within the output directory you will find two things: an index.html file, and a
|
Within the output directory you will find two things: an index.html file, and a
|
||||||
@@ -308,10 +290,5 @@ An incomplete list of things I want to do soon is:
|
|||||||
|
|
||||||
* Improve efficiency
|
* Improve efficiency
|
||||||
|
|
||||||
* Rendering non-cube blocks, such as torches, flowers, mine tracks, fences,
|
|
||||||
doors, and the like. Right now they are either not rendered at all, or
|
|
||||||
rendered as if they were a cube, so it looks funny.
|
|
||||||
|
|
||||||
* Some kind of graphical interface.
|
* Some kind of graphical interface.
|
||||||
|
|
||||||
* A Windows exe for easier access for Windows users.
|
|
||||||
|
|||||||
1
sample.settings.py
Normal file
1
sample.settings.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# TODO: put something useful in this file!
|
||||||
8
setup.py
8
setup.py
@@ -49,15 +49,21 @@ try:
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
numpy_include = numpy.get_numpy_include()
|
numpy_include = numpy.get_numpy_include()
|
||||||
|
|
||||||
|
try:
|
||||||
|
pil_include = os.environ['PIL_INCLUDE_DIR'].split(os.pathsep)
|
||||||
|
except:
|
||||||
|
pil_include = []
|
||||||
|
|
||||||
# used to figure out what files to compile
|
# used to figure out what files to compile
|
||||||
render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn']
|
render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn']
|
||||||
|
|
||||||
c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c', 'src/rendermodes.c']
|
c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c', 'src/rendermodes.c']
|
||||||
c_overviewer_files += map(lambda mode: 'src/rendermode-%s.c' % (mode,), render_modes)
|
c_overviewer_files += map(lambda mode: 'src/rendermode-%s.c' % (mode,), render_modes)
|
||||||
|
|
||||||
|
c_overviewer_files += ['src/Draw.c']
|
||||||
c_overviewer_includes = ['src/overviewer.h', 'src/rendermodes.h']
|
c_overviewer_includes = ['src/overviewer.h', 'src/rendermodes.h']
|
||||||
|
|
||||||
setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include], depends=c_overviewer_includes, extra_link_args=[]))
|
setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[]))
|
||||||
|
|
||||||
# tell build_ext to build the extension in-place
|
# tell build_ext to build the extension in-place
|
||||||
# (NOT in build/)
|
# (NOT in build/)
|
||||||
|
|||||||
902
src/Draw.c
Normal file
902
src/Draw.c
Normal file
@@ -0,0 +1,902 @@
|
|||||||
|
/*
|
||||||
|
* The Python Imaging Library.
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* a simple drawing package for the Imaging library
|
||||||
|
*
|
||||||
|
* history:
|
||||||
|
* 1996-04-13 fl Created.
|
||||||
|
* 1996-04-30 fl Added transforms and polygon support.
|
||||||
|
* 1996-08-12 fl Added filled polygons.
|
||||||
|
* 1996-11-05 fl Fixed float/int confusion in polygon filler
|
||||||
|
* 1997-07-04 fl Support 32-bit images (C++ would have been nice)
|
||||||
|
* 1998-09-09 fl Eliminated qsort casts; improved rectangle clipping
|
||||||
|
* 1998-09-10 fl Fixed fill rectangle to include lower edge (!)
|
||||||
|
* 1998-12-29 fl Added arc, chord, and pieslice primitives
|
||||||
|
* 1999-01-10 fl Added some level 2 ("arrow") stuff (experimental)
|
||||||
|
* 1999-02-06 fl Added bitmap primitive
|
||||||
|
* 1999-07-26 fl Eliminated a compiler warning
|
||||||
|
* 1999-07-31 fl Pass ink as void* instead of int
|
||||||
|
* 2002-12-10 fl Added experimental RGBA-on-RGB drawing
|
||||||
|
* 2004-09-04 fl Support simple wide lines (no joins)
|
||||||
|
* 2005-05-25 fl Fixed line width calculation
|
||||||
|
* 2011-04-01 Modified for use in Minecraft-Overviewer
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2006 by Fredrik Lundh
|
||||||
|
* Copyright (c) 1997-2006 by Secret Labs AB.
|
||||||
|
*
|
||||||
|
* This file is part of the Python Imaging Library
|
||||||
|
*
|
||||||
|
* By obtaining, using, and/or copying this software and/or its associated
|
||||||
|
* documentation, you agree that you have read, understood, and will comply
|
||||||
|
* with the following terms and conditions:
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software and its
|
||||||
|
* associated documentation for any purpose and without fee is hereby granted,
|
||||||
|
* provided that the above copyright notice appears in all copies, and that
|
||||||
|
* both that copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation, and that the name of Secret Labs AB or the author not be used
|
||||||
|
* in advertising or publicity pertaining to distribution of the software
|
||||||
|
* without specific, written prior permission.
|
||||||
|
*
|
||||||
|
* SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||||
|
* IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
|
||||||
|
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: support fill/outline attribute for all filled shapes */
|
||||||
|
/* FIXME: support zero-winding fill */
|
||||||
|
/* FIXME: add drawing context, support affine transforms */
|
||||||
|
/* FIXME: support clip window (and mask?) */
|
||||||
|
|
||||||
|
#include "Imaging.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define CEIL(v) (int) ceil(v)
|
||||||
|
#define FLOOR(v) ((v) >= 0.0 ? (int) (v) : (int) floor(v))
|
||||||
|
|
||||||
|
#define INK8(ink) (*(UINT8*)ink)
|
||||||
|
#define INK32(ink) (*(INT32*)ink)
|
||||||
|
|
||||||
|
/* like (a * b + 127) / 255), but much faster on most platforms */
|
||||||
|
#define MULDIV255(a, b, tmp)\
|
||||||
|
(tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8))
|
||||||
|
|
||||||
|
#define BLEND(mask, in1, in2, tmp1, tmp2)\
|
||||||
|
(MULDIV255(in1, 255 - mask, tmp1) + MULDIV255(in2, mask, tmp2))
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Primitives */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* edge descriptor for polygon engine */
|
||||||
|
int d;
|
||||||
|
int x0, y0;
|
||||||
|
int xmin, ymin, xmax, ymax;
|
||||||
|
float dx;
|
||||||
|
} Edge;
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
point8(Imaging im, int x, int y, int ink)
|
||||||
|
{
|
||||||
|
if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize)
|
||||||
|
im->image8[y][x] = (UINT8) ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
point32(Imaging im, int x, int y, int ink)
|
||||||
|
{
|
||||||
|
if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize)
|
||||||
|
im->image32[y][x] = ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
point32rgba(Imaging im, int x, int y, int ink)
|
||||||
|
{
|
||||||
|
unsigned int tmp1, tmp2;
|
||||||
|
|
||||||
|
if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
|
||||||
|
UINT8* out = (UINT8*) im->image[y]+x*4;
|
||||||
|
UINT8* in = (UINT8*) &ink;
|
||||||
|
out[0] = BLEND(in[3], out[0], in[0], tmp1, tmp2);
|
||||||
|
out[1] = BLEND(in[3], out[1], in[1], tmp1, tmp2);
|
||||||
|
out[2] = BLEND(in[3], out[2], in[2], tmp1, tmp2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hline8(Imaging im, int x0, int y0, int x1, int ink)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
if (y0 >= 0 && y0 < im->ysize) {
|
||||||
|
if (x0 > x1)
|
||||||
|
tmp = x0, x0 = x1, x1 = tmp;
|
||||||
|
if (x0 < 0)
|
||||||
|
x0 = 0;
|
||||||
|
else if (x0 >= im->xsize)
|
||||||
|
return;
|
||||||
|
if (x1 < 0)
|
||||||
|
return;
|
||||||
|
else if (x1 >= im->xsize)
|
||||||
|
x1 = im->xsize-1;
|
||||||
|
if (x0 <= x1)
|
||||||
|
memset(im->image8[y0] + x0, (UINT8) ink, x1 - x0 + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hline32(Imaging im, int x0, int y0, int x1, int ink)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
INT32* p;
|
||||||
|
|
||||||
|
if (y0 >= 0 && y0 < im->ysize) {
|
||||||
|
if (x0 > x1)
|
||||||
|
tmp = x0, x0 = x1, x1 = tmp;
|
||||||
|
if (x0 < 0)
|
||||||
|
x0 = 0;
|
||||||
|
else if (x0 >= im->xsize)
|
||||||
|
return;
|
||||||
|
if (x1 < 0)
|
||||||
|
return;
|
||||||
|
else if (x1 >= im->xsize)
|
||||||
|
x1 = im->xsize-1;
|
||||||
|
p = im->image32[y0];
|
||||||
|
while (x0 <= x1)
|
||||||
|
p[x0++] = ink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hline32rgba(Imaging im, int x0, int y0, int x1, int ink)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
unsigned int tmp1, tmp2;
|
||||||
|
|
||||||
|
if (y0 >= 0 && y0 < im->ysize) {
|
||||||
|
if (x0 > x1)
|
||||||
|
tmp = x0, x0 = x1, x1 = tmp;
|
||||||
|
if (x0 < 0)
|
||||||
|
x0 = 0;
|
||||||
|
else if (x0 >= im->xsize)
|
||||||
|
return;
|
||||||
|
if (x1 < 0)
|
||||||
|
return;
|
||||||
|
else if (x1 >= im->xsize)
|
||||||
|
x1 = im->xsize-1;
|
||||||
|
if (x0 <= x1) {
|
||||||
|
UINT8* out = (UINT8*) im->image[y0]+x0*4;
|
||||||
|
UINT8* in = (UINT8*) &ink;
|
||||||
|
while (x0 <= x1) {
|
||||||
|
out[0] = BLEND(in[3], out[0], in[0], tmp1, tmp2);
|
||||||
|
out[1] = BLEND(in[3], out[1], in[1], tmp1, tmp2);
|
||||||
|
out[2] = BLEND(in[3], out[2], in[2], tmp1, tmp2);
|
||||||
|
x0++; out += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
line8(Imaging im, int x0, int y0, int x1, int y1, int ink)
|
||||||
|
{
|
||||||
|
int i, n, e;
|
||||||
|
int dx, dy;
|
||||||
|
int xs, ys;
|
||||||
|
|
||||||
|
/* normalize coordinates */
|
||||||
|
dx = x1-x0;
|
||||||
|
if (dx < 0)
|
||||||
|
dx = -dx, xs = -1;
|
||||||
|
else
|
||||||
|
xs = 1;
|
||||||
|
dy = y1-y0;
|
||||||
|
if (dy < 0)
|
||||||
|
dy = -dy, ys = -1;
|
||||||
|
else
|
||||||
|
ys = 1;
|
||||||
|
|
||||||
|
n = (dx > dy) ? dx : dy;
|
||||||
|
|
||||||
|
if (dx == 0)
|
||||||
|
|
||||||
|
/* vertical */
|
||||||
|
for (i = 0; i < dy; i++) {
|
||||||
|
point8(im, x0, y0, ink);
|
||||||
|
y0 += ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (dy == 0)
|
||||||
|
|
||||||
|
/* horizontal */
|
||||||
|
for (i = 0; i < dx; i++) {
|
||||||
|
point8(im, x0, y0, ink);
|
||||||
|
x0 += xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (dx > dy) {
|
||||||
|
|
||||||
|
/* bresenham, horizontal slope */
|
||||||
|
n = dx;
|
||||||
|
dy += dy;
|
||||||
|
e = dy - dx;
|
||||||
|
dx += dx;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
point8(im, x0, y0, ink);
|
||||||
|
if (e >= 0) {
|
||||||
|
y0 += ys;
|
||||||
|
e -= dx;
|
||||||
|
}
|
||||||
|
e += dy;
|
||||||
|
x0 += xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* bresenham, vertical slope */
|
||||||
|
n = dy;
|
||||||
|
dx += dx;
|
||||||
|
e = dx - dy;
|
||||||
|
dy += dy;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
point8(im, x0, y0, ink);
|
||||||
|
if (e >= 0) {
|
||||||
|
x0 += xs;
|
||||||
|
e -= dy;
|
||||||
|
}
|
||||||
|
e += dx;
|
||||||
|
y0 += ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
line32(Imaging im, int x0, int y0, int x1, int y1, int ink)
|
||||||
|
{
|
||||||
|
int i, n, e;
|
||||||
|
int dx, dy;
|
||||||
|
int xs, ys;
|
||||||
|
|
||||||
|
/* normalize coordinates */
|
||||||
|
dx = x1-x0;
|
||||||
|
if (dx < 0)
|
||||||
|
dx = -dx, xs = -1;
|
||||||
|
else
|
||||||
|
xs = 1;
|
||||||
|
dy = y1-y0;
|
||||||
|
if (dy < 0)
|
||||||
|
dy = -dy, ys = -1;
|
||||||
|
else
|
||||||
|
ys = 1;
|
||||||
|
|
||||||
|
n = (dx > dy) ? dx : dy;
|
||||||
|
|
||||||
|
if (dx == 0)
|
||||||
|
|
||||||
|
/* vertical */
|
||||||
|
for (i = 0; i < dy; i++) {
|
||||||
|
point32(im, x0, y0, ink);
|
||||||
|
y0 += ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (dy == 0)
|
||||||
|
|
||||||
|
/* horizontal */
|
||||||
|
for (i = 0; i < dx; i++) {
|
||||||
|
point32(im, x0, y0, ink);
|
||||||
|
x0 += xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (dx > dy) {
|
||||||
|
|
||||||
|
/* bresenham, horizontal slope */
|
||||||
|
n = dx;
|
||||||
|
dy += dy;
|
||||||
|
e = dy - dx;
|
||||||
|
dx += dx;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
point32(im, x0, y0, ink);
|
||||||
|
if (e >= 0) {
|
||||||
|
y0 += ys;
|
||||||
|
e -= dx;
|
||||||
|
}
|
||||||
|
e += dy;
|
||||||
|
x0 += xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* bresenham, vertical slope */
|
||||||
|
n = dy;
|
||||||
|
dx += dx;
|
||||||
|
e = dx - dy;
|
||||||
|
dy += dy;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
point32(im, x0, y0, ink);
|
||||||
|
if (e >= 0) {
|
||||||
|
x0 += xs;
|
||||||
|
e -= dy;
|
||||||
|
}
|
||||||
|
e += dx;
|
||||||
|
y0 += ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink)
|
||||||
|
{
|
||||||
|
int i, n, e;
|
||||||
|
int dx, dy;
|
||||||
|
int xs, ys;
|
||||||
|
|
||||||
|
/* normalize coordinates */
|
||||||
|
dx = x1-x0;
|
||||||
|
if (dx < 0)
|
||||||
|
dx = -dx, xs = -1;
|
||||||
|
else
|
||||||
|
xs = 1;
|
||||||
|
dy = y1-y0;
|
||||||
|
if (dy < 0)
|
||||||
|
dy = -dy, ys = -1;
|
||||||
|
else
|
||||||
|
ys = 1;
|
||||||
|
|
||||||
|
n = (dx > dy) ? dx : dy;
|
||||||
|
|
||||||
|
if (dx == 0)
|
||||||
|
|
||||||
|
/* vertical */
|
||||||
|
for (i = 0; i < dy; i++) {
|
||||||
|
point32rgba(im, x0, y0, ink);
|
||||||
|
y0 += ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (dy == 0)
|
||||||
|
|
||||||
|
/* horizontal */
|
||||||
|
for (i = 0; i < dx; i++) {
|
||||||
|
point32rgba(im, x0, y0, ink);
|
||||||
|
x0 += xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (dx > dy) {
|
||||||
|
|
||||||
|
/* bresenham, horizontal slope */
|
||||||
|
n = dx;
|
||||||
|
dy += dy;
|
||||||
|
e = dy - dx;
|
||||||
|
dx += dx;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
point32rgba(im, x0, y0, ink);
|
||||||
|
if (e >= 0) {
|
||||||
|
y0 += ys;
|
||||||
|
e -= dx;
|
||||||
|
}
|
||||||
|
e += dy;
|
||||||
|
x0 += xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* bresenham, vertical slope */
|
||||||
|
n = dy;
|
||||||
|
dx += dx;
|
||||||
|
e = dx - dy;
|
||||||
|
dy += dy;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
point32rgba(im, x0, y0, ink);
|
||||||
|
if (e >= 0) {
|
||||||
|
x0 += xs;
|
||||||
|
e -= dy;
|
||||||
|
}
|
||||||
|
e += dx;
|
||||||
|
y0 += ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
x_cmp(const void *x0, const void *x1)
|
||||||
|
{
|
||||||
|
float diff = *((float*)x0) - *((float*)x1);
|
||||||
|
if (diff < 0)
|
||||||
|
return -1;
|
||||||
|
else if (diff > 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
polygon8(Imaging im, int n, Edge *e, int ink, int eofill)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
float *xx;
|
||||||
|
int ymin, ymax;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Find upper and lower polygon boundary (within image) */
|
||||||
|
|
||||||
|
ymin = e[0].ymin;
|
||||||
|
ymax = e[0].ymax;
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (e[i].ymin < ymin) ymin = e[i].ymin;
|
||||||
|
if (e[i].ymax > ymax) ymax = e[i].ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin < 0)
|
||||||
|
ymin = 0;
|
||||||
|
if (ymax >= im->ysize)
|
||||||
|
ymax = im->ysize-1;
|
||||||
|
|
||||||
|
/* Process polygon edges */
|
||||||
|
|
||||||
|
xx = malloc(n * sizeof(float));
|
||||||
|
if (!xx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (;ymin <= ymax; ymin++) {
|
||||||
|
y = ymin+0.5F;
|
||||||
|
for (i = j = 0; i < n; i++)
|
||||||
|
if (y >= e[i].ymin && y <= e[i].ymax) {
|
||||||
|
if (e[i].d == 0)
|
||||||
|
hline8(im, e[i].xmin, ymin, e[i].xmax, ink);
|
||||||
|
else
|
||||||
|
xx[j++] = (y-e[i].y0) * e[i].dx + e[i].x0;
|
||||||
|
}
|
||||||
|
if (j == 2) {
|
||||||
|
if (xx[0] < xx[1])
|
||||||
|
hline8(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
|
||||||
|
else
|
||||||
|
hline8(im, CEIL(xx[1]-0.5), ymin, FLOOR(xx[0]+0.5), ink);
|
||||||
|
} else {
|
||||||
|
qsort(xx, j, sizeof(float), x_cmp);
|
||||||
|
for (i = 0; i < j-1 ; i += 2)
|
||||||
|
hline8(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(xx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
polygon32(Imaging im, int n, Edge *e, int ink, int eofill)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
float *xx;
|
||||||
|
int ymin, ymax;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Find upper and lower polygon boundary (within image) */
|
||||||
|
|
||||||
|
ymin = e[0].ymin;
|
||||||
|
ymax = e[0].ymax;
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (e[i].ymin < ymin) ymin = e[i].ymin;
|
||||||
|
if (e[i].ymax > ymax) ymax = e[i].ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin < 0)
|
||||||
|
ymin = 0;
|
||||||
|
if (ymax >= im->ysize)
|
||||||
|
ymax = im->ysize-1;
|
||||||
|
|
||||||
|
/* Process polygon edges */
|
||||||
|
|
||||||
|
xx = malloc(n * sizeof(float));
|
||||||
|
if (!xx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (;ymin <= ymax; ymin++) {
|
||||||
|
y = ymin+0.5F;
|
||||||
|
for (i = j = 0; i < n; i++) {
|
||||||
|
if (y >= e[i].ymin && y <= e[i].ymax) {
|
||||||
|
if (e[i].d == 0)
|
||||||
|
hline32(im, e[i].xmin, ymin, e[i].xmax, ink);
|
||||||
|
else
|
||||||
|
xx[j++] = (y-e[i].y0) * e[i].dx + e[i].x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == 2) {
|
||||||
|
if (xx[0] < xx[1])
|
||||||
|
hline32(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
|
||||||
|
else
|
||||||
|
hline32(im, CEIL(xx[1]-0.5), ymin, FLOOR(xx[0]+0.5), ink);
|
||||||
|
} else {
|
||||||
|
qsort(xx, j, sizeof(float), x_cmp);
|
||||||
|
for (i = 0; i < j-1 ; i += 2)
|
||||||
|
hline32(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(xx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
float *xx;
|
||||||
|
int ymin, ymax;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Find upper and lower polygon boundary (within image) */
|
||||||
|
|
||||||
|
ymin = e[0].ymin;
|
||||||
|
ymax = e[0].ymax;
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (e[i].ymin < ymin) ymin = e[i].ymin;
|
||||||
|
if (e[i].ymax > ymax) ymax = e[i].ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ymin < 0)
|
||||||
|
ymin = 0;
|
||||||
|
if (ymax >= im->ysize)
|
||||||
|
ymax = im->ysize-1;
|
||||||
|
|
||||||
|
/* Process polygon edges */
|
||||||
|
|
||||||
|
xx = malloc(n * sizeof(float));
|
||||||
|
if (!xx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (;ymin <= ymax; ymin++) {
|
||||||
|
y = ymin+0.5F;
|
||||||
|
for (i = j = 0; i < n; i++) {
|
||||||
|
if (y >= e[i].ymin && y <= e[i].ymax) {
|
||||||
|
if (e[i].d == 0)
|
||||||
|
hline32rgba(im, e[i].xmin, ymin, e[i].xmax, ink);
|
||||||
|
else
|
||||||
|
xx[j++] = (y-e[i].y0) * e[i].dx + e[i].x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == 2) {
|
||||||
|
if (xx[0] < xx[1])
|
||||||
|
hline32rgba(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
|
||||||
|
else
|
||||||
|
hline32rgba(im, CEIL(xx[1]-0.5), ymin, FLOOR(xx[0]+0.5), ink);
|
||||||
|
} else {
|
||||||
|
qsort(xx, j, sizeof(float), x_cmp);
|
||||||
|
for (i = 0; i < j-1 ; i += 2)
|
||||||
|
hline32rgba(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(xx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
add_edge(Edge *e, int x0, int y0, int x1, int y1)
|
||||||
|
{
|
||||||
|
/* printf("edge %d %d %d %d\n", x0, y0, x1, y1); */
|
||||||
|
|
||||||
|
if (x0 <= x1)
|
||||||
|
e->xmin = x0, e->xmax = x1;
|
||||||
|
else
|
||||||
|
e->xmin = x1, e->xmax = x0;
|
||||||
|
|
||||||
|
if (y0 <= y1)
|
||||||
|
e->ymin = y0, e->ymax = y1;
|
||||||
|
else
|
||||||
|
e->ymin = y1, e->ymax = y0;
|
||||||
|
|
||||||
|
if (y0 == y1) {
|
||||||
|
e->d = 0;
|
||||||
|
e->dx = 0.0;
|
||||||
|
} else {
|
||||||
|
e->dx = ((float)(x1-x0)) / (y1-y0);
|
||||||
|
if (y0 == e->ymin)
|
||||||
|
e->d = 1;
|
||||||
|
else
|
||||||
|
e->d = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->x0 = x0;
|
||||||
|
e->y0 = y0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*point)(Imaging im, int x, int y, int ink);
|
||||||
|
void (*hline)(Imaging im, int x0, int y0, int x1, int ink);
|
||||||
|
void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
|
||||||
|
int (*polygon)(Imaging im, int n, Edge *e, int ink, int eofill);
|
||||||
|
} DRAW;
|
||||||
|
|
||||||
|
DRAW draw8 = { point8, hline8, line8, polygon8 };
|
||||||
|
DRAW draw32 = { point32, hline32, line32, polygon32 };
|
||||||
|
DRAW draw32rgba = { point32rgba, hline32rgba, line32rgba, polygon32rgba };
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Interface */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define DRAWINIT()\
|
||||||
|
if (im->image8) {\
|
||||||
|
draw = &draw8;\
|
||||||
|
ink = INK8(ink_);\
|
||||||
|
} else {\
|
||||||
|
draw = (op) ? &draw32rgba : &draw32; \
|
||||||
|
ink = INK32(ink_);\
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingDrawPoint(Imaging im, int x0, int y0, const void* ink_, int op)
|
||||||
|
{
|
||||||
|
DRAW* draw;
|
||||||
|
INT32 ink;
|
||||||
|
|
||||||
|
DRAWINIT();
|
||||||
|
|
||||||
|
draw->point(im, x0, y0, ink);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void* ink_,
|
||||||
|
int op)
|
||||||
|
{
|
||||||
|
DRAW* draw;
|
||||||
|
INT32 ink;
|
||||||
|
|
||||||
|
DRAWINIT();
|
||||||
|
|
||||||
|
draw->line(im, x0, y0, x1, y1, ink);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
|
||||||
|
const void* ink_, int width, int op)
|
||||||
|
{
|
||||||
|
DRAW* draw;
|
||||||
|
INT32 ink;
|
||||||
|
|
||||||
|
Edge e[4];
|
||||||
|
|
||||||
|
int dx, dy;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
DRAWINIT();
|
||||||
|
|
||||||
|
if (width <= 1) {
|
||||||
|
draw->line(im, x0, y0, x1, y1, ink);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = x1-x0;
|
||||||
|
dy = y1-y0;
|
||||||
|
|
||||||
|
if (dx == 0 && dy == 0) {
|
||||||
|
draw->point(im, x0, y0, ink);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = width / sqrt((float) (dx*dx + dy*dy)) / 2.0;
|
||||||
|
|
||||||
|
dx = (int) floor(d * (y1-y0) + 0.5);
|
||||||
|
dy = (int) floor(d * (x1-x0) + 0.5);
|
||||||
|
|
||||||
|
add_edge(e+0, x0 - dx, y0 + dy, x1 - dx, y1 + dy);
|
||||||
|
add_edge(e+1, x1 - dx, y1 + dy, x1 + dx, y1 - dy);
|
||||||
|
add_edge(e+2, x1 + dx, y1 - dy, x0 + dx, y0 - dy);
|
||||||
|
add_edge(e+3, x0 + dx, y0 - dy, x0 - dx, y0 + dy);
|
||||||
|
|
||||||
|
draw->polygon(im, 4, e, ink, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* standard shapes */
|
||||||
|
|
||||||
|
#define ARC 0
|
||||||
|
#define CHORD 1
|
||||||
|
#define PIESLICE 2
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* experimental level 2 ("arrow") graphics stuff. this implements
|
||||||
|
portions of the arrow api on top of the Edge structure. the
|
||||||
|
semantics are ok, except that "curve" flattens the bezier curves by
|
||||||
|
itself */
|
||||||
|
|
||||||
|
#if 1 /* ARROW_GRAPHICS */
|
||||||
|
|
||||||
|
struct ImagingOutlineInstance {
|
||||||
|
|
||||||
|
float x0, y0;
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
int count;
|
||||||
|
Edge *edges;
|
||||||
|
|
||||||
|
int size;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ImagingOutlineDelete(ImagingOutline outline)
|
||||||
|
{
|
||||||
|
if (!outline)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (outline->edges)
|
||||||
|
free(outline->edges);
|
||||||
|
|
||||||
|
free(outline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Edge*
|
||||||
|
allocate(ImagingOutline outline, int extra)
|
||||||
|
{
|
||||||
|
Edge* e;
|
||||||
|
|
||||||
|
if (outline->count + extra > outline->size) {
|
||||||
|
/* expand outline buffer */
|
||||||
|
outline->size += extra + 25;
|
||||||
|
if (!outline->edges)
|
||||||
|
e = malloc(outline->size * sizeof(Edge));
|
||||||
|
else
|
||||||
|
e = realloc(outline->edges, outline->size * sizeof(Edge));
|
||||||
|
if (!e)
|
||||||
|
return NULL;
|
||||||
|
outline->edges = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
e = outline->edges + outline->count;
|
||||||
|
|
||||||
|
outline->count += extra;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingOutlineMove(ImagingOutline outline, float x0, float y0)
|
||||||
|
{
|
||||||
|
outline->x = outline->x0 = x0;
|
||||||
|
outline->y = outline->y0 = y0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingOutlineLine(ImagingOutline outline, float x1, float y1)
|
||||||
|
{
|
||||||
|
Edge* e;
|
||||||
|
|
||||||
|
e = allocate(outline, 1);
|
||||||
|
if (!e)
|
||||||
|
return -1; /* out of memory */
|
||||||
|
|
||||||
|
add_edge(e, (int) outline->x, (int) outline->y, (int) x1, (int) y1);
|
||||||
|
|
||||||
|
outline->x = x1;
|
||||||
|
outline->y = y1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingOutlineCurve(ImagingOutline outline, float x1, float y1,
|
||||||
|
float x2, float y2, float x3, float y3)
|
||||||
|
{
|
||||||
|
Edge* e;
|
||||||
|
int i;
|
||||||
|
float xo, yo;
|
||||||
|
|
||||||
|
#define STEPS 32
|
||||||
|
|
||||||
|
e = allocate(outline, STEPS);
|
||||||
|
if (!e)
|
||||||
|
return -1; /* out of memory */
|
||||||
|
|
||||||
|
xo = outline->x;
|
||||||
|
yo = outline->y;
|
||||||
|
|
||||||
|
/* flatten the bezier segment */
|
||||||
|
|
||||||
|
for (i = 1; i <= STEPS; i++) {
|
||||||
|
|
||||||
|
float t = ((float) i) / STEPS;
|
||||||
|
float t2 = t*t;
|
||||||
|
float t3 = t2*t;
|
||||||
|
|
||||||
|
float u = 1.0F - t;
|
||||||
|
float u2 = u*u;
|
||||||
|
float u3 = u2*u;
|
||||||
|
|
||||||
|
float x = outline->x*u3 + 3*(x1*t*u2 + x2*t2*u) + x3*t3 + 0.5;
|
||||||
|
float y = outline->y*u3 + 3*(y1*t*u2 + y2*t2*u) + y3*t3 + 0.5;
|
||||||
|
|
||||||
|
add_edge(e++, xo, yo, (int) x, (int) y);
|
||||||
|
|
||||||
|
xo = x, yo = y;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
outline->x = xo;
|
||||||
|
outline->y = yo;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingOutlineCurve2(ImagingOutline outline, float cx, float cy,
|
||||||
|
float x3, float y3)
|
||||||
|
{
|
||||||
|
/* add bezier curve based on three control points (as
|
||||||
|
in the Flash file format) */
|
||||||
|
|
||||||
|
return ImagingOutlineCurve(
|
||||||
|
outline,
|
||||||
|
(outline->x + cx + cx)/3, (outline->y + cy + cy)/3,
|
||||||
|
(cx + cx + x3)/3, (cy + cy + y3)/3,
|
||||||
|
x3, y3);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingOutlineClose(ImagingOutline outline)
|
||||||
|
{
|
||||||
|
if (outline->x == outline->x0 && outline->y == outline->y0)
|
||||||
|
return 0;
|
||||||
|
return ImagingOutlineLine(outline, outline->x0, outline->y0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingDrawOutline(Imaging im, ImagingOutline outline, const void* ink_,
|
||||||
|
int fill, int op)
|
||||||
|
{
|
||||||
|
DRAW* draw;
|
||||||
|
INT32 ink;
|
||||||
|
|
||||||
|
DRAWINIT();
|
||||||
|
|
||||||
|
draw->polygon(im, outline->count, outline->edges, ink, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
// increment this value if you've made a change to the c extesion
|
// increment this value if you've made a change to the c extesion
|
||||||
// and want to force users to rebuild
|
// and want to force users to rebuild
|
||||||
#define OVERVIEWER_EXTENSION_VERSION 2
|
#define OVERVIEWER_EXTENSION_VERSION 3
|
||||||
|
|
||||||
/* Python PIL, and numpy headers */
|
/* Python PIL, and numpy headers */
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|||||||
@@ -49,17 +49,28 @@ rendermode_normal_start(void *data, RenderState *state) {
|
|||||||
|
|
||||||
self->biome_data = PyObject_CallMethod(state->textures, "getBiomeData", "OOO",
|
self->biome_data = PyObject_CallMethod(state->textures, "getBiomeData", "OOO",
|
||||||
worlddir, chunk_x_py, chunk_y_py);
|
worlddir, chunk_x_py, chunk_y_py);
|
||||||
self->foliagecolor = PyObject_GetAttrString(state->textures, "foliagecolor");
|
if (self->biome_data == Py_None) {
|
||||||
self->grasscolor = PyObject_GetAttrString(state->textures, "grasscolor");
|
self->biome_data = NULL;
|
||||||
|
self->foliagecolor = NULL;
|
||||||
self->leaf_texture = PyObject_GetAttrString(state->textures, "biome_leaf_texture");
|
self->grasscolor = NULL;
|
||||||
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
|
||||||
|
self->leaf_texture = NULL;
|
||||||
facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks");
|
self->grass_texture = NULL;
|
||||||
/* borrowed reference, needs to be incref'd if we keep it */
|
self->facemask_top = NULL;
|
||||||
self->facemask_top = PyTuple_GetItem(facemasks_py, 0);
|
} else {
|
||||||
Py_INCREF(self->facemask_top);
|
|
||||||
Py_DECREF(facemasks_py);
|
self->foliagecolor = PyObject_GetAttrString(state->textures, "foliagecolor");
|
||||||
|
self->grasscolor = PyObject_GetAttrString(state->textures, "grasscolor");
|
||||||
|
|
||||||
|
self->leaf_texture = PyObject_GetAttrString(state->textures, "biome_leaf_texture");
|
||||||
|
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
||||||
|
|
||||||
|
facemasks_py = PyObject_GetAttrString(state->chunk, "facemasks");
|
||||||
|
/* borrowed reference, needs to be incref'd if we keep it */
|
||||||
|
self->facemask_top = PyTuple_GetItem(facemasks_py, 0);
|
||||||
|
Py_INCREF(self->facemask_top);
|
||||||
|
Py_DECREF(facemasks_py);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self->biome_data = NULL;
|
self->biome_data = NULL;
|
||||||
self->foliagecolor = NULL;
|
self->foliagecolor = NULL;
|
||||||
@@ -161,6 +172,51 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
|
|||||||
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
|
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Draw some edge lines! */
|
||||||
|
// draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
|
||||||
|
if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
|
||||||
|
Imaging img_i = imaging_python_to_c(state->img);
|
||||||
|
unsigned char ink[] = {0,0,0,40};
|
||||||
|
|
||||||
|
int increment=0;
|
||||||
|
if (state->block == 44) // half-step
|
||||||
|
increment=6;
|
||||||
|
else if (state->block == 78) // snow
|
||||||
|
increment=9;
|
||||||
|
|
||||||
|
if ((state->x == 15) && (state->up_right_blocks != Py_None)) {
|
||||||
|
unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z);
|
||||||
|
if (side_block != state->block && is_transparent(side_block)) {
|
||||||
|
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||||
|
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||||
|
}
|
||||||
|
} else if (state->x != 15) {
|
||||||
|
unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z);
|
||||||
|
if (side_block != state->block && is_transparent(side_block)) {
|
||||||
|
ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
|
||||||
|
ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if y != 0 and blocks[x,y-1,z] == 0
|
||||||
|
|
||||||
|
// chunk boundries are annoying
|
||||||
|
if ((state->y == 0) && (state->up_left_blocks != Py_None)) {
|
||||||
|
unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z);
|
||||||
|
if (side_block != state->block && is_transparent(side_block)) {
|
||||||
|
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||||
|
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||||
|
}
|
||||||
|
} else if (state->y != 0) {
|
||||||
|
unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z);
|
||||||
|
if (side_block != state->block && is_transparent(side_block)) {
|
||||||
|
// draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
|
||||||
|
ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
|
||||||
|
ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderModeInterface rendermode_normal = {
|
RenderModeInterface rendermode_normal = {
|
||||||
|
|||||||
Reference in New Issue
Block a user