updating raskter to support tiles compositor. this commit puts in some groundwork code to support tiles's pixel processor
This commit is contained in:
@@ -33,8 +33,11 @@ set(INC_SYS
|
||||
|
||||
set(SRC
|
||||
raskter.c
|
||||
raskter_mt.c
|
||||
kdtree.c
|
||||
|
||||
raskter.h
|
||||
kdtree.h
|
||||
)
|
||||
|
||||
blender_add_lib(bf_intern_raskter "${SRC}" "${INC}" "${INC_SYS}")
|
||||
|
||||
836
intern/raskter/kdtree.c
Normal file
836
intern/raskter/kdtree.c
Normal file
@@ -0,0 +1,836 @@
|
||||
/*
|
||||
This file is part of ``kdtree'', a library for working with kd-trees.
|
||||
Copyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
/* single nearest neighbor search written by Tamas Nepusz <tamas@cs.rhul.ac.uk> */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "kdtree.h"
|
||||
|
||||
#if defined(WIN32) || defined(__WIN32__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIST_NODE_ALLOCATOR
|
||||
|
||||
#ifndef NO_PTHREADS
|
||||
#include <pthread.h>
|
||||
#else
|
||||
|
||||
#ifndef I_WANT_THREAD_BUGS
|
||||
#error "You are compiling with the fast list node allocator, with pthreads disabled! This WILL break if used from multiple threads."
|
||||
#endif /* I want thread bugs */
|
||||
|
||||
#endif /* pthread support */
|
||||
#endif /* use list node allocator */
|
||||
|
||||
struct kdhyperrect {
|
||||
int dim;
|
||||
double *min, *max; /* minimum/maximum coords */
|
||||
};
|
||||
|
||||
struct kdnode {
|
||||
double *pos;
|
||||
int dir;
|
||||
void *data;
|
||||
|
||||
struct kdnode *left, *right; /* negative/positive side */
|
||||
};
|
||||
|
||||
struct res_node {
|
||||
struct kdnode *item;
|
||||
double dist_sq;
|
||||
struct res_node *next;
|
||||
};
|
||||
|
||||
struct kdtree {
|
||||
int dim;
|
||||
struct kdnode *root;
|
||||
struct kdhyperrect *rect;
|
||||
void (*destr)(void*);
|
||||
};
|
||||
|
||||
struct kdres {
|
||||
struct kdtree *tree;
|
||||
struct res_node *rlist, *riter;
|
||||
int size;
|
||||
};
|
||||
|
||||
#define SQ(x) ((x) * (x))
|
||||
|
||||
|
||||
static void clear_rec(struct kdnode *node, void (*destr)(void*));
|
||||
static int insert_rec(struct kdnode **node, const double *pos, void *data, int dir, int dim);
|
||||
static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq);
|
||||
static void clear_results(struct kdres *set);
|
||||
|
||||
static struct kdhyperrect* hyperrect_create(int dim, const double *min, const double *max);
|
||||
static void hyperrect_free(struct kdhyperrect *rect);
|
||||
static struct kdhyperrect* hyperrect_duplicate(const struct kdhyperrect *rect);
|
||||
static void hyperrect_extend(struct kdhyperrect *rect, const double *pos);
|
||||
static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos);
|
||||
|
||||
#ifdef USE_LIST_NODE_ALLOCATOR
|
||||
static struct res_node *alloc_resnode(void);
|
||||
static void free_resnode(struct res_node*);
|
||||
#else
|
||||
#define alloc_resnode() malloc(sizeof(struct res_node))
|
||||
#define free_resnode(n) free(n)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct kdtree *kd_create(int k)
|
||||
{
|
||||
struct kdtree *tree;
|
||||
|
||||
if(!(tree = malloc(sizeof *tree))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tree->dim = k;
|
||||
tree->root = 0;
|
||||
tree->destr = 0;
|
||||
tree->rect = 0;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void kd_free(struct kdtree *tree)
|
||||
{
|
||||
if(tree) {
|
||||
kd_clear(tree);
|
||||
free(tree);
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_rec(struct kdnode *node, void (*destr)(void*))
|
||||
{
|
||||
if(!node) return;
|
||||
|
||||
clear_rec(node->left, destr);
|
||||
clear_rec(node->right, destr);
|
||||
|
||||
if(destr) {
|
||||
destr(node->data);
|
||||
}
|
||||
free(node->pos);
|
||||
free(node);
|
||||
}
|
||||
|
||||
void kd_clear(struct kdtree *tree)
|
||||
{
|
||||
clear_rec(tree->root, tree->destr);
|
||||
tree->root = 0;
|
||||
|
||||
if (tree->rect) {
|
||||
hyperrect_free(tree->rect);
|
||||
tree->rect = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void kd_data_destructor(struct kdtree *tree, void (*destr)(void*))
|
||||
{
|
||||
tree->destr = destr;
|
||||
}
|
||||
|
||||
|
||||
static int insert_rec(struct kdnode **nptr, const double *pos, void *data, int dir, int dim)
|
||||
{
|
||||
int new_dir;
|
||||
struct kdnode *node;
|
||||
|
||||
if(!*nptr) {
|
||||
if(!(node = malloc(sizeof *node))) {
|
||||
return -1;
|
||||
}
|
||||
if(!(node->pos = malloc(dim * sizeof *node->pos))) {
|
||||
free(node);
|
||||
return -1;
|
||||
}
|
||||
memcpy(node->pos, pos, dim * sizeof *node->pos);
|
||||
node->data = data;
|
||||
node->dir = dir;
|
||||
node->left = node->right = 0;
|
||||
*nptr = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = *nptr;
|
||||
new_dir = (node->dir + 1) % dim;
|
||||
if(pos[node->dir] < node->pos[node->dir]) {
|
||||
return insert_rec(&(*nptr)->left, pos, data, new_dir, dim);
|
||||
}
|
||||
return insert_rec(&(*nptr)->right, pos, data, new_dir, dim);
|
||||
}
|
||||
|
||||
int kd_insert(struct kdtree *tree, const double *pos, void *data)
|
||||
{
|
||||
if (insert_rec(&tree->root, pos, data, 0, tree->dim)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tree->rect == 0) {
|
||||
tree->rect = hyperrect_create(tree->dim, pos, pos);
|
||||
} else {
|
||||
hyperrect_extend(tree->rect, pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kd_insertf(struct kdtree *tree, const float *pos, void *data)
|
||||
{
|
||||
static double sbuf[16];
|
||||
double *bptr, *buf = 0;
|
||||
int res, dim = tree->dim;
|
||||
|
||||
if(dim > 16) {
|
||||
#ifndef NO_ALLOCA
|
||||
if(dim <= 256)
|
||||
bptr = buf = alloca(dim * sizeof *bptr);
|
||||
else
|
||||
#endif
|
||||
if(!(bptr = buf = malloc(dim * sizeof *bptr))) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
bptr = buf = sbuf;
|
||||
}
|
||||
|
||||
while(dim-- > 0) {
|
||||
*bptr++ = *pos++;
|
||||
}
|
||||
|
||||
res = kd_insert(tree, buf, data);
|
||||
#ifndef NO_ALLOCA
|
||||
if(tree->dim > 256)
|
||||
#else
|
||||
if(tree->dim > 16)
|
||||
#endif
|
||||
free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data)
|
||||
{
|
||||
double buf[3];
|
||||
buf[0] = x;
|
||||
buf[1] = y;
|
||||
buf[2] = z;
|
||||
return kd_insert(tree, buf, data);
|
||||
}
|
||||
|
||||
int kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data)
|
||||
{
|
||||
double buf[3];
|
||||
buf[0] = x;
|
||||
buf[1] = y;
|
||||
buf[2] = z;
|
||||
return kd_insert(tree, buf, data);
|
||||
}
|
||||
|
||||
static int find_nearest(struct kdnode *node, const double *pos, double range, struct res_node *list, int ordered, int dim)
|
||||
{
|
||||
double dist_sq, dx;
|
||||
int i, ret, added_res = 0;
|
||||
|
||||
if(!node) return 0;
|
||||
|
||||
dist_sq = 0;
|
||||
for(i=0; i<dim; i++) {
|
||||
dist_sq += SQ(node->pos[i] - pos[i]);
|
||||
}
|
||||
if(dist_sq <= SQ(range)) {
|
||||
if(rlist_insert(list, node, ordered ? dist_sq : -1.0) == -1) {
|
||||
return -1;
|
||||
}
|
||||
added_res = 1;
|
||||
}
|
||||
|
||||
dx = pos[node->dir] - node->pos[node->dir];
|
||||
|
||||
ret = find_nearest(dx <= 0.0 ? node->left : node->right, pos, range, list, ordered, dim);
|
||||
if(ret >= 0 && fabs(dx) < range) {
|
||||
added_res += ret;
|
||||
ret = find_nearest(dx <= 0.0 ? node->right : node->left, pos, range, list, ordered, dim);
|
||||
}
|
||||
if(ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
added_res += ret;
|
||||
|
||||
return added_res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int find_nearest_n(struct kdnode *node, const double *pos, double range, int num, struct rheap *heap, int dim)
|
||||
{
|
||||
double dist_sq, dx;
|
||||
int i, ret, added_res = 0;
|
||||
|
||||
if(!node) return 0;
|
||||
|
||||
/* if the photon is close enough, add it to the result heap */
|
||||
dist_sq = 0;
|
||||
for(i=0; i<dim; i++) {
|
||||
dist_sq += SQ(node->pos[i] - pos[i]);
|
||||
}
|
||||
if(dist_sq <= range_sq) {
|
||||
if(heap->size >= num) {
|
||||
/* get furthest element */
|
||||
struct res_node *maxelem = rheap_get_max(heap);
|
||||
|
||||
/* and check if the new one is closer than that */
|
||||
if(maxelem->dist_sq > dist_sq) {
|
||||
rheap_remove_max(heap);
|
||||
|
||||
if(rheap_insert(heap, node, dist_sq) == -1) {
|
||||
return -1;
|
||||
}
|
||||
added_res = 1;
|
||||
|
||||
range_sq = dist_sq;
|
||||
}
|
||||
} else {
|
||||
if(rheap_insert(heap, node, dist_sq) == -1) {
|
||||
return =1;
|
||||
}
|
||||
added_res = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* find signed distance from the splitting plane */
|
||||
dx = pos[node->dir] - node->pos[node->dir];
|
||||
|
||||
ret = find_nearest_n(dx <= 0.0 ? node->left : node->right, pos, range, num, heap, dim);
|
||||
if(ret >= 0 && fabs(dx) < range) {
|
||||
added_res += ret;
|
||||
ret = find_nearest_n(dx <= 0.0 ? node->right : node->left, pos, range, num, heap, dim);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kd_nearest_i(struct kdnode *node, const double *pos, struct kdnode **result, double *result_dist_sq, struct kdhyperrect* rect)
|
||||
{
|
||||
int dir = node->dir;
|
||||
int i;
|
||||
double dummy, dist_sq;
|
||||
struct kdnode *nearer_subtree, *farther_subtree;
|
||||
double *nearer_hyperrect_coord, *farther_hyperrect_coord;
|
||||
|
||||
/* Decide whether to go left or right in the tree */
|
||||
dummy = pos[dir] - node->pos[dir];
|
||||
if (dummy <= 0) {
|
||||
nearer_subtree = node->left;
|
||||
farther_subtree = node->right;
|
||||
nearer_hyperrect_coord = rect->max + dir;
|
||||
farther_hyperrect_coord = rect->min + dir;
|
||||
} else {
|
||||
nearer_subtree = node->right;
|
||||
farther_subtree = node->left;
|
||||
nearer_hyperrect_coord = rect->min + dir;
|
||||
farther_hyperrect_coord = rect->max + dir;
|
||||
}
|
||||
|
||||
if (nearer_subtree) {
|
||||
/* Slice the hyperrect to get the hyperrect of the nearer subtree */
|
||||
dummy = *nearer_hyperrect_coord;
|
||||
*nearer_hyperrect_coord = node->pos[dir];
|
||||
/* Recurse down into nearer subtree */
|
||||
kd_nearest_i(nearer_subtree, pos, result, result_dist_sq, rect);
|
||||
/* Undo the slice */
|
||||
*nearer_hyperrect_coord = dummy;
|
||||
}
|
||||
|
||||
/* Check the distance of the point at the current node, compare it
|
||||
* with our best so far */
|
||||
dist_sq = 0;
|
||||
for(i=0; i < rect->dim; i++) {
|
||||
dist_sq += SQ(node->pos[i] - pos[i]);
|
||||
}
|
||||
if (dist_sq < *result_dist_sq) {
|
||||
*result = node;
|
||||
*result_dist_sq = dist_sq;
|
||||
}
|
||||
|
||||
if (farther_subtree) {
|
||||
/* Get the hyperrect of the farther subtree */
|
||||
dummy = *farther_hyperrect_coord;
|
||||
*farther_hyperrect_coord = node->pos[dir];
|
||||
/* Check if we have to recurse down by calculating the closest
|
||||
* point of the hyperrect and see if it's closer than our
|
||||
* minimum distance in result_dist_sq. */
|
||||
if (hyperrect_dist_sq(rect, pos) < *result_dist_sq) {
|
||||
/* Recurse down into farther subtree */
|
||||
kd_nearest_i(farther_subtree, pos, result, result_dist_sq, rect);
|
||||
}
|
||||
/* Undo the slice on the hyperrect */
|
||||
*farther_hyperrect_coord = dummy;
|
||||
}
|
||||
}
|
||||
|
||||
struct kdres *kd_nearest(struct kdtree *kd, const double *pos)
|
||||
{
|
||||
struct kdhyperrect *rect;
|
||||
struct kdnode *result;
|
||||
struct kdres *rset;
|
||||
double dist_sq;
|
||||
int i;
|
||||
|
||||
if (!kd) return 0;
|
||||
if (!kd->rect) return 0;
|
||||
|
||||
/* Allocate result set */
|
||||
if(!(rset = malloc(sizeof *rset))) {
|
||||
return 0;
|
||||
}
|
||||
if(!(rset->rlist = alloc_resnode())) {
|
||||
free(rset);
|
||||
return 0;
|
||||
}
|
||||
rset->rlist->next = 0;
|
||||
rset->tree = kd;
|
||||
|
||||
/* Duplicate the bounding hyperrectangle, we will work on the copy */
|
||||
if (!(rect = hyperrect_duplicate(kd->rect))) {
|
||||
kd_res_free(rset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Our first guesstimate is the root node */
|
||||
result = kd->root;
|
||||
dist_sq = 0;
|
||||
for (i = 0; i < kd->dim; i++)
|
||||
dist_sq += SQ(result->pos[i] - pos[i]);
|
||||
|
||||
/* Search for the nearest neighbour recursively */
|
||||
kd_nearest_i(kd->root, pos, &result, &dist_sq, rect);
|
||||
|
||||
/* Free the copy of the hyperrect */
|
||||
hyperrect_free(rect);
|
||||
|
||||
/* Store the result */
|
||||
if (result) {
|
||||
if (rlist_insert(rset->rlist, result, -1.0) == -1) {
|
||||
kd_res_free(rset);
|
||||
return 0;
|
||||
}
|
||||
rset->size = 1;
|
||||
kd_res_rewind(rset);
|
||||
return rset;
|
||||
} else {
|
||||
kd_res_free(rset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct kdres *kd_nearestf(struct kdtree *tree, const float *pos)
|
||||
{
|
||||
static double sbuf[16];
|
||||
double *bptr, *buf = 0;
|
||||
int dim = tree->dim;
|
||||
struct kdres *res;
|
||||
|
||||
if(dim > 16) {
|
||||
#ifndef NO_ALLOCA
|
||||
if(dim <= 256)
|
||||
bptr = buf = alloca(dim * sizeof *bptr);
|
||||
else
|
||||
#endif
|
||||
if(!(bptr = buf = malloc(dim * sizeof *bptr))) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
bptr = buf = sbuf;
|
||||
}
|
||||
|
||||
while(dim-- > 0) {
|
||||
*bptr++ = *pos++;
|
||||
}
|
||||
|
||||
res = kd_nearest(tree, buf);
|
||||
#ifndef NO_ALLOCA
|
||||
if(tree->dim > 256)
|
||||
#else
|
||||
if(tree->dim > 16)
|
||||
#endif
|
||||
free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z)
|
||||
{
|
||||
double pos[3];
|
||||
pos[0] = x;
|
||||
pos[1] = y;
|
||||
pos[2] = z;
|
||||
return kd_nearest(tree, pos);
|
||||
}
|
||||
|
||||
struct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z)
|
||||
{
|
||||
double pos[3];
|
||||
pos[0] = x;
|
||||
pos[1] = y;
|
||||
pos[2] = z;
|
||||
return kd_nearest(tree, pos);
|
||||
}
|
||||
|
||||
/* ---- nearest N search ---- */
|
||||
/*
|
||||
static kdres *kd_nearest_n(struct kdtree *kd, const double *pos, int num)
|
||||
{
|
||||
int ret;
|
||||
struct kdres *rset;
|
||||
|
||||
if(!(rset = malloc(sizeof *rset))) {
|
||||
return 0;
|
||||
}
|
||||
if(!(rset->rlist = alloc_resnode())) {
|
||||
free(rset);
|
||||
return 0;
|
||||
}
|
||||
rset->rlist->next = 0;
|
||||
rset->tree = kd;
|
||||
|
||||
if((ret = find_nearest_n(kd->root, pos, range, num, rset->rlist, kd->dim)) == -1) {
|
||||
kd_res_free(rset);
|
||||
return 0;
|
||||
}
|
||||
rset->size = ret;
|
||||
kd_res_rewind(rset);
|
||||
return rset;
|
||||
}*/
|
||||
|
||||
struct kdres *kd_nearest_range(struct kdtree *kd, const double *pos, double range)
|
||||
{
|
||||
int ret;
|
||||
struct kdres *rset;
|
||||
|
||||
if(!(rset = malloc(sizeof *rset))) {
|
||||
return 0;
|
||||
}
|
||||
if(!(rset->rlist = alloc_resnode())) {
|
||||
free(rset);
|
||||
return 0;
|
||||
}
|
||||
rset->rlist->next = 0;
|
||||
rset->tree = kd;
|
||||
|
||||
if((ret = find_nearest(kd->root, pos, range, rset->rlist, 0, kd->dim)) == -1) {
|
||||
kd_res_free(rset);
|
||||
return 0;
|
||||
}
|
||||
rset->size = ret;
|
||||
kd_res_rewind(rset);
|
||||
return rset;
|
||||
}
|
||||
|
||||
struct kdres *kd_nearest_rangef(struct kdtree *kd, const float *pos, float range)
|
||||
{
|
||||
static double sbuf[16];
|
||||
double *bptr, *buf = 0;
|
||||
int dim = kd->dim;
|
||||
struct kdres *res;
|
||||
|
||||
if(dim > 16) {
|
||||
#ifndef NO_ALLOCA
|
||||
if(dim <= 256)
|
||||
bptr = buf = alloca(dim * sizeof *bptr);
|
||||
else
|
||||
#endif
|
||||
if(!(bptr = buf = malloc(dim * sizeof *bptr))) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
bptr = buf = sbuf;
|
||||
}
|
||||
|
||||
while(dim-- > 0) {
|
||||
*bptr++ = *pos++;
|
||||
}
|
||||
|
||||
res = kd_nearest_range(kd, buf, range);
|
||||
#ifndef NO_ALLOCA
|
||||
if(kd->dim > 256)
|
||||
#else
|
||||
if(kd->dim > 16)
|
||||
#endif
|
||||
free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range)
|
||||
{
|
||||
double buf[3];
|
||||
buf[0] = x;
|
||||
buf[1] = y;
|
||||
buf[2] = z;
|
||||
return kd_nearest_range(tree, buf, range);
|
||||
}
|
||||
|
||||
struct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range)
|
||||
{
|
||||
double buf[3];
|
||||
buf[0] = x;
|
||||
buf[1] = y;
|
||||
buf[2] = z;
|
||||
return kd_nearest_range(tree, buf, range);
|
||||
}
|
||||
|
||||
void kd_res_free(struct kdres *rset)
|
||||
{
|
||||
clear_results(rset);
|
||||
free_resnode(rset->rlist);
|
||||
free(rset);
|
||||
}
|
||||
|
||||
int kd_res_size(struct kdres *set)
|
||||
{
|
||||
return (set->size);
|
||||
}
|
||||
|
||||
void kd_res_rewind(struct kdres *rset)
|
||||
{
|
||||
rset->riter = rset->rlist->next;
|
||||
}
|
||||
|
||||
int kd_res_end(struct kdres *rset)
|
||||
{
|
||||
return rset->riter == 0;
|
||||
}
|
||||
|
||||
int kd_res_next(struct kdres *rset)
|
||||
{
|
||||
rset->riter = rset->riter->next;
|
||||
return rset->riter != 0;
|
||||
}
|
||||
|
||||
void *kd_res_item(struct kdres *rset, double *pos)
|
||||
{
|
||||
if(rset->riter) {
|
||||
if(pos) {
|
||||
memcpy(pos, rset->riter->item->pos, rset->tree->dim * sizeof *pos);
|
||||
}
|
||||
return rset->riter->item->data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *kd_res_itemf(struct kdres *rset, float *pos)
|
||||
{
|
||||
if(rset->riter) {
|
||||
if(pos) {
|
||||
int i;
|
||||
for(i=0; i<rset->tree->dim; i++) {
|
||||
pos[i] = rset->riter->item->pos[i];
|
||||
}
|
||||
}
|
||||
return rset->riter->item->data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *kd_res_item3(struct kdres *rset, double *x, double *y, double *z)
|
||||
{
|
||||
if(rset->riter) {
|
||||
if(*x) *x = rset->riter->item->pos[0];
|
||||
if(*y) *y = rset->riter->item->pos[1];
|
||||
if(*z) *z = rset->riter->item->pos[2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *kd_res_item3f(struct kdres *rset, float *x, float *y, float *z)
|
||||
{
|
||||
if(rset->riter) {
|
||||
if(*x) *x = rset->riter->item->pos[0];
|
||||
if(*y) *y = rset->riter->item->pos[1];
|
||||
if(*z) *z = rset->riter->item->pos[2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *kd_res_item_data(struct kdres *set)
|
||||
{
|
||||
return kd_res_item(set, 0);
|
||||
}
|
||||
|
||||
/* ---- hyperrectangle helpers ---- */
|
||||
static struct kdhyperrect* hyperrect_create(int dim, const double *min, const double *max)
|
||||
{
|
||||
size_t size = dim * sizeof(double);
|
||||
struct kdhyperrect* rect = 0;
|
||||
|
||||
if (!(rect = malloc(sizeof(struct kdhyperrect)))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rect->dim = dim;
|
||||
if (!(rect->min = malloc(size))) {
|
||||
free(rect);
|
||||
return 0;
|
||||
}
|
||||
if (!(rect->max = malloc(size))) {
|
||||
free(rect->min);
|
||||
free(rect);
|
||||
return 0;
|
||||
}
|
||||
memcpy(rect->min, min, size);
|
||||
memcpy(rect->max, max, size);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
static void hyperrect_free(struct kdhyperrect *rect)
|
||||
{
|
||||
free(rect->min);
|
||||
free(rect->max);
|
||||
free(rect);
|
||||
}
|
||||
|
||||
static struct kdhyperrect* hyperrect_duplicate(const struct kdhyperrect *rect)
|
||||
{
|
||||
return hyperrect_create(rect->dim, rect->min, rect->max);
|
||||
}
|
||||
|
||||
static void hyperrect_extend(struct kdhyperrect *rect, const double *pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < rect->dim; i++) {
|
||||
if (pos[i] < rect->min[i]) {
|
||||
rect->min[i] = pos[i];
|
||||
}
|
||||
if (pos[i] > rect->max[i]) {
|
||||
rect->max[i] = pos[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos)
|
||||
{
|
||||
int i;
|
||||
double result = 0;
|
||||
|
||||
for (i=0; i < rect->dim; i++) {
|
||||
if (pos[i] < rect->min[i]) {
|
||||
result += SQ(rect->min[i] - pos[i]);
|
||||
} else if (pos[i] > rect->max[i]) {
|
||||
result += SQ(rect->max[i] - pos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---- static helpers ---- */
|
||||
|
||||
#ifdef USE_LIST_NODE_ALLOCATOR
|
||||
/* special list node allocators. */
|
||||
static struct res_node *free_nodes;
|
||||
|
||||
#ifndef NO_PTHREADS
|
||||
static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static struct res_node *alloc_resnode(void)
|
||||
{
|
||||
struct res_node *node;
|
||||
|
||||
#ifndef NO_PTHREADS
|
||||
pthread_mutex_lock(&alloc_mutex);
|
||||
#endif
|
||||
|
||||
if(!free_nodes) {
|
||||
node = malloc(sizeof *node);
|
||||
} else {
|
||||
node = free_nodes;
|
||||
free_nodes = free_nodes->next;
|
||||
node->next = 0;
|
||||
}
|
||||
|
||||
#ifndef NO_PTHREADS
|
||||
pthread_mutex_unlock(&alloc_mutex);
|
||||
#endif
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void free_resnode(struct res_node *node)
|
||||
{
|
||||
#ifndef NO_PTHREADS
|
||||
pthread_mutex_lock(&alloc_mutex);
|
||||
#endif
|
||||
|
||||
node->next = free_nodes;
|
||||
free_nodes = node;
|
||||
|
||||
#ifndef NO_PTHREADS
|
||||
pthread_mutex_unlock(&alloc_mutex);
|
||||
#endif
|
||||
}
|
||||
#endif /* list node allocator or not */
|
||||
|
||||
|
||||
/* inserts the item. if dist_sq is >= 0, then do an ordered insert */
|
||||
/* TODO make the ordering code use heapsort */
|
||||
static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq)
|
||||
{
|
||||
struct res_node *rnode;
|
||||
|
||||
if(!(rnode = alloc_resnode())) {
|
||||
return -1;
|
||||
}
|
||||
rnode->item = item;
|
||||
rnode->dist_sq = dist_sq;
|
||||
|
||||
if(dist_sq >= 0.0) {
|
||||
while(list->next && list->next->dist_sq < dist_sq) {
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
rnode->next = list->next;
|
||||
list->next = rnode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clear_results(struct kdres *rset)
|
||||
{
|
||||
struct res_node *tmp, *node = rset->rlist->next;
|
||||
|
||||
while(node) {
|
||||
tmp = node;
|
||||
node = node->next;
|
||||
free_resnode(tmp);
|
||||
}
|
||||
|
||||
rset->rlist->next = 0;
|
||||
}
|
||||
129
intern/raskter/kdtree.h
Normal file
129
intern/raskter/kdtree.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
This file is part of ``kdtree'', a library for working with kd-trees.
|
||||
Copyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _KDTREE_H_
|
||||
#define _KDTREE_H_
|
||||
#define USE_LIST_NODE_ALLOCATOR
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct kdtree;
|
||||
struct kdres;
|
||||
|
||||
|
||||
/* create a kd-tree for "k"-dimensional data */
|
||||
struct kdtree *kd_create(int k);
|
||||
|
||||
/* free the struct kdtree */
|
||||
void kd_free(struct kdtree *tree);
|
||||
|
||||
/* remove all the elements from the tree */
|
||||
void kd_clear(struct kdtree *tree);
|
||||
|
||||
/* if called with non-null 2nd argument, the function provided
|
||||
* will be called on data pointers (see kd_insert) when nodes
|
||||
* are to be removed from the tree.
|
||||
*/
|
||||
void kd_data_destructor(struct kdtree *tree, void (*destr)(void*));
|
||||
|
||||
/* insert a node, specifying its position, and optional data */
|
||||
int kd_insert(struct kdtree *tree, const double *pos, void *data);
|
||||
int kd_insertf(struct kdtree *tree, const float *pos, void *data);
|
||||
int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data);
|
||||
int kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data);
|
||||
|
||||
/* Find the nearest node from a given point.
|
||||
*
|
||||
* This function returns a pointer to a result set with at most one element.
|
||||
*/
|
||||
struct kdres *kd_nearest(struct kdtree *tree, const double *pos);
|
||||
struct kdres *kd_nearestf(struct kdtree *tree, const float *pos);
|
||||
struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z);
|
||||
struct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z);
|
||||
|
||||
/* Find the N nearest nodes from a given point.
|
||||
*
|
||||
* This function returns a pointer to a result set, with at most N elements,
|
||||
* which can be manipulated with the kd_res_* functions.
|
||||
* The returned pointer can be null as an indication of an error. Otherwise
|
||||
* a valid result set is always returned which may contain 0 or more elements.
|
||||
* The result set must be deallocated with kd_res_free after use.
|
||||
*/
|
||||
/*
|
||||
struct kdres *kd_nearest_n(struct kdtree *tree, const double *pos, int num);
|
||||
struct kdres *kd_nearest_nf(struct kdtree *tree, const float *pos, int num);
|
||||
struct kdres *kd_nearest_n3(struct kdtree *tree, double x, double y, double z);
|
||||
struct kdres *kd_nearest_n3f(struct kdtree *tree, float x, float y, float z);
|
||||
*/
|
||||
|
||||
/* Find any nearest nodes from a given point within a range.
|
||||
*
|
||||
* This function returns a pointer to a result set, which can be manipulated
|
||||
* by the kd_res_* functions.
|
||||
* The returned pointer can be null as an indication of an error. Otherwise
|
||||
* a valid result set is always returned which may contain 0 or more elements.
|
||||
* The result set must be deallocated with kd_res_free after use.
|
||||
*/
|
||||
struct kdres *kd_nearest_range(struct kdtree *tree, const double *pos, double range);
|
||||
struct kdres *kd_nearest_rangef(struct kdtree *tree, const float *pos, float range);
|
||||
struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range);
|
||||
struct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range);
|
||||
|
||||
/* frees a result set returned by kd_nearest_range() */
|
||||
void kd_res_free(struct kdres *set);
|
||||
|
||||
/* returns the size of the result set (in elements) */
|
||||
int kd_res_size(struct kdres *set);
|
||||
|
||||
/* rewinds the result set iterator */
|
||||
void kd_res_rewind(struct kdres *set);
|
||||
|
||||
/* returns non-zero if the set iterator reached the end after the last element */
|
||||
int kd_res_end(struct kdres *set);
|
||||
|
||||
/* advances the result set iterator, returns non-zero on success, zero if
|
||||
* there are no more elements in the result set.
|
||||
*/
|
||||
int kd_res_next(struct kdres *set);
|
||||
|
||||
/* returns the data pointer (can be null) of the current result set item
|
||||
* and optionally sets its position to the pointers(s) if not null.
|
||||
*/
|
||||
void *kd_res_item(struct kdres *set, double *pos);
|
||||
void *kd_res_itemf(struct kdres *set, float *pos);
|
||||
void *kd_res_item3(struct kdres *set, double *x, double *y, double *z);
|
||||
void *kd_res_item3f(struct kdres *set, float *x, float *y, float *z);
|
||||
|
||||
/* equivalent to kd_res_item(set, 0) */
|
||||
void *kd_res_item_data(struct kdres *set);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _KDTREE_H_ */
|
||||
@@ -30,36 +30,13 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "raskter.h"
|
||||
//#define __PLX__FAKE_AA__
|
||||
//#define __PLX_KD_TREE__
|
||||
#ifdef __PLX_KD_TREE__
|
||||
#include "kdtree.h"
|
||||
#endif
|
||||
|
||||
#define __PLX__FAKE_AA__
|
||||
|
||||
/* from BLI_utildefines.h */
|
||||
#define MIN2(x, y) ( (x) < (y) ? (x) : (y) )
|
||||
#define MAX2(x, y) ( (x) > (y) ? (x) : (y) )
|
||||
#define ABS(a) ( (a) < 0 ? (-(a)) : (a) )
|
||||
|
||||
struct e_status {
|
||||
int x;
|
||||
int ybeg;
|
||||
int xshift;
|
||||
int xdir;
|
||||
int drift;
|
||||
int drift_inc;
|
||||
int drift_dec;
|
||||
int num;
|
||||
struct e_status *e_next;
|
||||
};
|
||||
|
||||
struct r_buffer_stats {
|
||||
float *buf;
|
||||
int sizex;
|
||||
int sizey;
|
||||
};
|
||||
|
||||
struct r_fill_context {
|
||||
struct e_status *all_edges, *possible_edges;
|
||||
struct r_buffer_stats rb;
|
||||
};
|
||||
|
||||
/*
|
||||
* Sort all the edges of the input polygon by Y, then by X, of the "first" vertex encountered.
|
||||
@@ -69,102 +46,113 @@ struct r_fill_context {
|
||||
* just the poly. Since the DEM code could end up being coupled with this, we'll keep it separate
|
||||
* for now.
|
||||
*/
|
||||
static void preprocess_all_edges(struct r_fill_context *ctx, struct poly_vert *verts, int num_verts, struct e_status *open_edge)
|
||||
{
|
||||
int i;
|
||||
int xbeg;
|
||||
int ybeg;
|
||||
int xend;
|
||||
int yend;
|
||||
int dx;
|
||||
int dy;
|
||||
int temp_pos;
|
||||
int xdist;
|
||||
struct e_status *e_new;
|
||||
struct e_status *next_edge;
|
||||
struct e_status **next_edge_ref;
|
||||
struct poly_vert *v;
|
||||
/* set up pointers */
|
||||
v = verts;
|
||||
ctx->all_edges = NULL;
|
||||
/* loop all verts */
|
||||
for (i = 0; i < num_verts; i++) {
|
||||
/* determine beginnings and endings of edges, linking last vertex to first vertex */
|
||||
xbeg = v[i].x;
|
||||
ybeg = v[i].y;
|
||||
if (i) {
|
||||
/* we're not at the last vert, so end of the edge is the previous vertex */
|
||||
xend = v[i - 1].x;
|
||||
yend = v[i - 1].y;
|
||||
}
|
||||
else {
|
||||
/* we're at the first vertex, so the "end" of this edge is the last vertex */
|
||||
xend = v[num_verts - 1].x;
|
||||
yend = v[num_verts - 1].y;
|
||||
}
|
||||
/* make sure our edges are facing the correct direction */
|
||||
if (ybeg > yend) {
|
||||
/* flip the Xs */
|
||||
temp_pos = xbeg;
|
||||
xbeg = xend;
|
||||
xend = temp_pos;
|
||||
/* flip the Ys */
|
||||
temp_pos = ybeg;
|
||||
ybeg = yend;
|
||||
yend = temp_pos;
|
||||
}
|
||||
static void preprocess_all_edges(struct r_fill_context *ctx, struct poly_vert *verts, int num_verts, struct e_status *open_edge) {
|
||||
int i;
|
||||
int xbeg;
|
||||
int ybeg;
|
||||
int xend;
|
||||
int yend;
|
||||
int dx;
|
||||
int dy;
|
||||
int temp_pos;
|
||||
int xdist;
|
||||
struct e_status *e_new;
|
||||
struct e_status *next_edge;
|
||||
struct e_status **next_edge_ref;
|
||||
struct poly_vert *v;
|
||||
/* set up pointers */
|
||||
v = verts;
|
||||
ctx->all_edges = NULL;
|
||||
/* initialize some boundaries */
|
||||
ctx->rb.xmax = v[0].x;
|
||||
ctx->rb.xmin = v[0].x;
|
||||
ctx->rb.ymax = v[0].y;
|
||||
ctx->rb.ymin = v[0].y;
|
||||
/* loop all verts */
|
||||
for(i = 0; i < num_verts; i++) {
|
||||
/* determine beginnings and endings of edges, linking last vertex to first vertex */
|
||||
xbeg = v[i].x;
|
||||
ybeg = v[i].y;
|
||||
/* keep track of our x and y bounds */
|
||||
if(xbeg >= ctx->rb.xmax) {
|
||||
ctx->rb.xmax = xbeg;
|
||||
} else if(xbeg <= ctx->rb.xmin) {
|
||||
ctx->rb.xmin = xbeg;
|
||||
}
|
||||
if(ybeg >= ctx->rb.ymax) {
|
||||
ctx->rb.ymax= ybeg;
|
||||
} else if(ybeg <= ctx->rb.ymin) {
|
||||
ctx->rb.ymin=ybeg;
|
||||
}
|
||||
if(i) {
|
||||
/* we're not at the last vert, so end of the edge is the previous vertex */
|
||||
xend = v[i - 1].x;
|
||||
yend = v[i - 1].y;
|
||||
} else {
|
||||
/* we're at the first vertex, so the "end" of this edge is the last vertex */
|
||||
xend = v[num_verts - 1].x;
|
||||
yend = v[num_verts - 1].y;
|
||||
}
|
||||
/* make sure our edges are facing the correct direction */
|
||||
if(ybeg > yend) {
|
||||
/* flip the Xs */
|
||||
temp_pos = xbeg;
|
||||
xbeg = xend;
|
||||
xend = temp_pos;
|
||||
/* flip the Ys */
|
||||
temp_pos = ybeg;
|
||||
ybeg = yend;
|
||||
yend = temp_pos;
|
||||
}
|
||||
|
||||
/* calculate y delta */
|
||||
dy = yend - ybeg;
|
||||
/* dont draw horizontal lines directly, they are scanned as part of the edges they connect, so skip em. :) */
|
||||
if (dy) {
|
||||
/* create the edge and determine it's slope (for incremental line drawing) */
|
||||
e_new = open_edge++;
|
||||
/* calculate y delta */
|
||||
dy = yend - ybeg;
|
||||
/* dont draw horizontal lines directly, they are scanned as part of the edges they connect, so skip em. :) */
|
||||
if(dy) {
|
||||
/* create the edge and determine it's slope (for incremental line drawing) */
|
||||
e_new = open_edge++;
|
||||
|
||||
/* calculate x delta */
|
||||
dx = xend - xbeg;
|
||||
if (dx > 0) {
|
||||
e_new->xdir = 1;
|
||||
xdist = dx;
|
||||
}
|
||||
else {
|
||||
e_new->xdir = -1;
|
||||
xdist = -dx;
|
||||
}
|
||||
/* calculate x delta */
|
||||
dx = xend - xbeg;
|
||||
if(dx > 0) {
|
||||
e_new->xdir = 1;
|
||||
xdist = dx;
|
||||
} else {
|
||||
e_new->xdir = -1;
|
||||
xdist = -dx;
|
||||
}
|
||||
|
||||
e_new->x = xbeg;
|
||||
e_new->ybeg = ybeg;
|
||||
e_new->num = dy;
|
||||
e_new->drift_dec = dy;
|
||||
e_new->x = xbeg;
|
||||
e_new->ybeg = ybeg;
|
||||
e_new->num = dy;
|
||||
e_new->drift_dec = dy;
|
||||
|
||||
/* calculate deltas for incremental drawing */
|
||||
if (dx >= 0) {
|
||||
e_new->drift = 0;
|
||||
}
|
||||
else {
|
||||
e_new->drift = -dy + 1;
|
||||
}
|
||||
if (dy >= xdist) {
|
||||
e_new->drift_inc = xdist;
|
||||
e_new->xshift = 0;
|
||||
}
|
||||
else {
|
||||
e_new->drift_inc = xdist % dy;
|
||||
e_new->xshift = (xdist / dy) * e_new->xdir;
|
||||
}
|
||||
next_edge_ref = &ctx->all_edges;
|
||||
/* link in all the edges, in sorted order */
|
||||
for (;; ) {
|
||||
next_edge = *next_edge_ref;
|
||||
if (!next_edge || (next_edge->ybeg > ybeg) || ((next_edge->ybeg == ybeg) && (next_edge->x >= xbeg))) {
|
||||
e_new->e_next = next_edge;
|
||||
*next_edge_ref = e_new;
|
||||
break;
|
||||
}
|
||||
next_edge_ref = &next_edge->e_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* calculate deltas for incremental drawing */
|
||||
if(dx >= 0) {
|
||||
e_new->drift = 0;
|
||||
} else {
|
||||
e_new->drift = -dy + 1;
|
||||
}
|
||||
if(dy >= xdist) {
|
||||
e_new->drift_inc = xdist;
|
||||
e_new->xshift = 0;
|
||||
} else {
|
||||
e_new->drift_inc = xdist % dy;
|
||||
e_new->xshift = (xdist / dy) * e_new->xdir;
|
||||
}
|
||||
next_edge_ref = &ctx->all_edges;
|
||||
/* link in all the edges, in sorted order */
|
||||
for(;;) {
|
||||
next_edge = *next_edge_ref;
|
||||
if(!next_edge || (next_edge->ybeg > ybeg) || ((next_edge->ybeg == ybeg) && (next_edge->x >= xbeg))) {
|
||||
e_new->e_next = next_edge;
|
||||
*next_edge_ref = e_new;
|
||||
break;
|
||||
}
|
||||
next_edge_ref = &next_edge->e_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -172,281 +160,275 @@ static void preprocess_all_edges(struct r_fill_context *ctx, struct poly_vert *v
|
||||
* for speed, but waiting on final design choices for curve-data before eliminating data the DEM code will need
|
||||
* if it ends up being coupled with this function.
|
||||
*/
|
||||
static int rast_scan_fill(struct r_fill_context *ctx, struct poly_vert *verts, int num_verts, float intensity)
|
||||
{
|
||||
int x_curr; /* current pixel position in X */
|
||||
int y_curr; /* current scan line being drawn */
|
||||
int yp; /* y-pixel's position in frame buffer */
|
||||
int swixd = 0; /* whether or not edges switched position in X */
|
||||
float *cpxl; /* pixel pointers... */
|
||||
float *mpxl;
|
||||
float *spxl;
|
||||
struct e_status *e_curr; /* edge pointers... */
|
||||
struct e_status *e_temp;
|
||||
struct e_status *edgbuf;
|
||||
struct e_status **edgec;
|
||||
static int rast_scan_fill(struct r_fill_context *ctx, struct poly_vert *verts, int num_verts, float intensity) {
|
||||
int x_curr; /* current pixel position in X */
|
||||
int y_curr; /* current scan line being drawn */
|
||||
int yp; /* y-pixel's position in frame buffer */
|
||||
int swixd = 0; /* whether or not edges switched position in X */
|
||||
float *cpxl; /* pixel pointers... */
|
||||
float *mpxl;
|
||||
float *spxl;
|
||||
struct e_status *e_curr; /* edge pointers... */
|
||||
struct e_status *e_temp;
|
||||
struct e_status *edgbuf;
|
||||
struct e_status **edgec;
|
||||
|
||||
|
||||
/*
|
||||
* If the number of verts specified to render as a polygon is less than 3,
|
||||
* return immediately. Obviously we cant render a poly with sides < 3. The
|
||||
* return for this we set to 1, simply so it can be distinguished from the
|
||||
* next place we could return.
|
||||
* which is a failure to allocate memory.
|
||||
*/
|
||||
if (num_verts < 3) {
|
||||
return(1);
|
||||
}
|
||||
/*
|
||||
* If the number of verts specified to render as a polygon is less than 3,
|
||||
* return immediately. Obviously we cant render a poly with sides < 3. The
|
||||
* return for this we set to 1, simply so it can be distinguished from the
|
||||
* next place we could return, /home/guest/blender-svn/soc-2011-tomato/intern/raskter/raskter.
|
||||
* which is a failure to allocate memory.
|
||||
*/
|
||||
if(num_verts < 3) {
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to allocate an edge buffer in memory. needs to be the size of the edge tracking data
|
||||
* multiplied by the number of edges, which is always equal to the number of verts in
|
||||
* a 2D polygon. Here we return 0 to indicate a memory allocation failure, as opposed to a 1 for
|
||||
* the preceeding error, which was a rasterization request on a 2D poly with less than
|
||||
* 3 sides.
|
||||
*/
|
||||
if ((edgbuf = (struct e_status *)(malloc(sizeof(struct e_status) * num_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* Try to allocate an edge buffer in memory. needs to be the size of the edge tracking data
|
||||
* multiplied by the number of edges, which is always equal to the number of verts in
|
||||
* a 2D polygon. Here we return 0 to indicate a memory allocation failure, as opposed to a 1 for
|
||||
* the preceeding error, which was a rasterization request on a 2D poly with less than
|
||||
* 3 sides.
|
||||
*/
|
||||
if((edgbuf = (struct e_status *)(malloc(sizeof(struct e_status) * num_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some preprocessing on all edges. This constructs a table structure in memory of all
|
||||
* the edge properties and can "flip" some edges so sorting works correctly.
|
||||
*/
|
||||
preprocess_all_edges(ctx, verts, num_verts, edgbuf);
|
||||
/*
|
||||
* Do some preprocessing on all edges. This constructs a table structure in memory of all
|
||||
* the edge properties and can "flip" some edges so sorting works correctly.
|
||||
*/
|
||||
preprocess_all_edges(ctx, verts, num_verts, edgbuf);
|
||||
|
||||
/* can happen with a zero area mask */
|
||||
if (ctx->all_edges == NULL) {
|
||||
free(edgbuf);
|
||||
return(1);
|
||||
}
|
||||
/* can happen with a zero area mask */
|
||||
if (ctx->all_edges == NULL) {
|
||||
free(edgbuf);
|
||||
return(1);
|
||||
}
|
||||
/*
|
||||
* Set the pointer for tracking the edges currently in processing to NULL to make sure
|
||||
* we don't get some crazy value after initialization.
|
||||
*/
|
||||
ctx->possible_edges = NULL;
|
||||
|
||||
/*
|
||||
* Set the pointer for tracking the edges currently in processing to NULL to make sure
|
||||
* we don't get some crazy value after initialization.
|
||||
*/
|
||||
ctx->possible_edges = NULL;
|
||||
/*
|
||||
* Loop through all scan lines to be drawn. Since we sorted by Y values during
|
||||
* preprocess_all_edges(), we can already exact values for the lowest and
|
||||
* highest Y values we could possibly need by induction. The preprocessing sorted
|
||||
* out edges by Y position, we can cycle the current edge being processed once
|
||||
* it runs out of Y pixels. When we have no more edges, meaning the current edge
|
||||
* is NULL after setting the "current" edge to be the previous current edge's
|
||||
* "next" edge in the Y sorted edge connection chain, we can stop looping Y values,
|
||||
* since we can't possibly have more scan lines if we ran out of edges. :)
|
||||
*
|
||||
* TODO: This clips Y to the frame buffer, which should be done in the preprocessor, but for now is done here.
|
||||
* Will get changed once DEM code gets in.
|
||||
*/
|
||||
for(y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
|
||||
|
||||
/*
|
||||
* Loop through all scan lines to be drawn. Since we sorted by Y values during
|
||||
* preprocess_all_edges(), we can already exact values for the lowest and
|
||||
* highest Y values we could possibly need by induction. The preprocessing sorted
|
||||
* out edges by Y position, we can cycle the current edge being processed once
|
||||
* it runs out of Y pixels. When we have no more edges, meaning the current edge
|
||||
* is NULL after setting the "current" edge to be the previous current edge's
|
||||
* "next" edge in the Y sorted edge connection chain, we can stop looping Y values,
|
||||
* since we can't possibly have more scan lines if we ran out of edges. :)
|
||||
*
|
||||
* TODO: This clips Y to the frame buffer, which should be done in the preprocessor, but for now is done here.
|
||||
* Will get changed once DEM code gets in.
|
||||
*/
|
||||
for (y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
|
||||
/*
|
||||
* Link any edges that start on the current scan line into the list of
|
||||
* edges currently needed to draw at least this, if not several, scan lines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Link any edges that start on the current scan line into the list of
|
||||
* edges currently needed to draw at least this, if not several, scan lines.
|
||||
*/
|
||||
/*
|
||||
* Set the current edge to the beginning of the list of edges to be rasterized
|
||||
* into this scan line.
|
||||
*
|
||||
* We could have lots of edge here, so iterate over all the edges needed. The
|
||||
* preprocess_all_edges() function sorted edges by X within each chunk of Y sorting
|
||||
* so we safely cycle edges to thier own "next" edges in order.
|
||||
*
|
||||
* At each iteration, make sure we still have a non-NULL edge.
|
||||
*/
|
||||
for(edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr);) {
|
||||
x_curr = ctx->all_edges->x; /* Set current X position. */
|
||||
for(;;) { /* Start looping edges. Will break when edges run out. */
|
||||
e_curr = *edgec; /* Set up a current edge pointer. */
|
||||
if(!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
|
||||
e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
|
||||
*edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
|
||||
ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
|
||||
edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
|
||||
ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
|
||||
break; /* Stop looping edges (since we ran out or hit empty X span. */
|
||||
} else {
|
||||
edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current edge to the beginning of the list of edges to be rasterized
|
||||
* into this scan line.
|
||||
*
|
||||
* We could have lots of edge here, so iterate over all the edges needed. The
|
||||
* preprocess_all_edges() function sorted edges by X within each chunk of Y sorting
|
||||
* so we safely cycle edges to thier own "next" edges in order.
|
||||
*
|
||||
* At each iteration, make sure we still have a non-NULL edge.
|
||||
*/
|
||||
for (edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr); ) {
|
||||
x_curr = ctx->all_edges->x; /* Set current X position. */
|
||||
for (;; ) { /* Start looping edges. Will break when edges run out. */
|
||||
e_curr = *edgec; /* Set up a current edge pointer. */
|
||||
if (!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
|
||||
e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
|
||||
*edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
|
||||
ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
|
||||
edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
|
||||
ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
|
||||
break; /* Stop looping edges (since we ran out or hit empty X span. */
|
||||
}
|
||||
else {
|
||||
edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Determine the current scan line's offset in the pixel buffer based on its Y position.
|
||||
* Basically we just multiply the current scan line's Y value by the number of pixels in each line.
|
||||
*/
|
||||
yp = y_curr * ctx->rb.sizex;
|
||||
/*
|
||||
* Set a "scan line pointer" in memory. The location of the buffer plus the row offset.
|
||||
*/
|
||||
spxl = ctx->rb.buf + (yp);
|
||||
/*
|
||||
* Set up the current edge to the first (in X) edge. The edges which could possibly be in this
|
||||
* list were determined in the preceeding edge loop above. They were already sorted in X by the
|
||||
* initial processing function.
|
||||
*
|
||||
* At each iteration, test for a NULL edge. Since we'll keep cycling edge's to their own "next" edge
|
||||
* we will eventually hit a NULL when the list runs out.
|
||||
*/
|
||||
for(e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
|
||||
/*
|
||||
* Calculate a span of pixels to fill on the current scan line.
|
||||
*
|
||||
* Set the current pixel pointer by adding the X offset to the scan line's start offset.
|
||||
* Cycle the current edge the next edge.
|
||||
* Set the max X value to draw to be one less than the next edge's first pixel. This way we are
|
||||
* sure not to ever get into a situation where we have overdraw. (drawing the same pixel more than
|
||||
* one time because it's on a vertex connecting two edges)
|
||||
*
|
||||
* Then blast through all the pixels in the span, advancing the pointer and setting the color to white.
|
||||
*
|
||||
* TODO: Here we clip to the scan line, this is not efficient, and should be done in the preprocessor,
|
||||
* but for now it is done here until the DEM code comes in.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Determine the current scan line's offset in the pixel buffer based on its Y position.
|
||||
* Basically we just multiply the current scan line's Y value by the number of pixels in each line.
|
||||
*/
|
||||
yp = y_curr * ctx->rb.sizex;
|
||||
/*
|
||||
* Set a "scan line pointer" in memory. The location of the buffer plus the row offset.
|
||||
*/
|
||||
spxl = ctx->rb.buf + (yp);
|
||||
/*
|
||||
* Set up the current edge to the first (in X) edge. The edges which could possibly be in this
|
||||
* list were determined in the preceeding edge loop above. They were already sorted in X by the
|
||||
* initial processing function.
|
||||
*
|
||||
* At each iteration, test for a NULL edge. Since we'll keep cycling edge's to their own "next" edge
|
||||
* we will eventually hit a NULL when the list runs out.
|
||||
*/
|
||||
for (e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
|
||||
/*
|
||||
* Calculate a span of pixels to fill on the current scan line.
|
||||
*
|
||||
* Set the current pixel pointer by adding the X offset to the scan line's start offset.
|
||||
* Cycle the current edge the next edge.
|
||||
* Set the max X value to draw to be one less than the next edge's first pixel. This way we are
|
||||
* sure not to ever get into a situation where we have overdraw. (drawing the same pixel more than
|
||||
* one time because it's on a vertex connecting two edges)
|
||||
*
|
||||
* Then blast through all the pixels in the span, advancing the pointer and setting the color to white.
|
||||
*
|
||||
* TODO: Here we clip to the scan line, this is not efficient, and should be done in the preprocessor,
|
||||
* but for now it is done here until the DEM code comes in.
|
||||
*/
|
||||
/* set up xmin and xmax bounds on this scan line */
|
||||
cpxl = spxl + MAX2(e_curr->x, 0);
|
||||
e_curr = e_curr->e_next;
|
||||
mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
|
||||
|
||||
/* set up xmin and xmax bounds on this scan line */
|
||||
cpxl = spxl + MAX2(e_curr->x, 0);
|
||||
e_curr = e_curr->e_next;
|
||||
mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
|
||||
if((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
|
||||
/* draw the pixels. */
|
||||
for(; cpxl <= mpxl; *cpxl++ += intensity);
|
||||
}
|
||||
}
|
||||
|
||||
if ((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
|
||||
/* draw the pixels. */
|
||||
for(; cpxl <= mpxl; *cpxl++ += intensity);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Loop through all edges of polygon that could be hit by this scan line,
|
||||
* and figure out their x-intersections with the next scan line.
|
||||
*
|
||||
* Either A.) we wont have any more edges to test, or B.) we just add on the
|
||||
* slope delta computed in preprocessing step. Since this draws non-antialiased
|
||||
* polygons, we dont have fractional positions, so we only move in x-direction
|
||||
* when needed to get all the way to the next pixel over...
|
||||
*/
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec);) {
|
||||
if(!(--(e_curr->num))) {
|
||||
*edgec = e_curr->e_next;
|
||||
} else {
|
||||
e_curr->x += e_curr->xshift;
|
||||
if((e_curr->drift += e_curr->drift_inc) > 0) {
|
||||
e_curr->x += e_curr->xdir;
|
||||
e_curr->drift -= e_curr->drift_dec;
|
||||
}
|
||||
edgec = &e_curr->e_next;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It's possible that some edges may have crossed during the last step, so we'll be sure
|
||||
* that we ALWAYS intersect scan lines in order by shuffling if needed to make all edges
|
||||
* sorted by x-intersection coordinate. We'll always scan through at least once to see if
|
||||
* edges crossed, and if so, we set the 'swixd' flag. If 'swixd' gets set on the initial
|
||||
* pass, then we know we need to sort by x, so then cycle through edges again and perform
|
||||
* the sort.-
|
||||
*/
|
||||
if(ctx->possible_edges) {
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* set flag that we had at least one switch */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we did have a switch, look for more (there will more if there was one) */
|
||||
for(;;) {
|
||||
/* reset exchange flag so it's only set if we encounter another one */
|
||||
swixd = 0;
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* again, if current edge hits scan line at higher X than next edge, exchange the edges and set flag */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* flip the exchanged flag */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we had no exchanges, we're done reshuffling the pointers */
|
||||
if(!swixd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all edges of polygon that could be hit by this scan line,
|
||||
* and figure out their x-intersections with the next scan line.
|
||||
*
|
||||
* Either A.) we wont have any more edges to test, or B.) we just add on the
|
||||
* slope delta computed in preprocessing step. Since this draws non-antialiased
|
||||
* polygons, we dont have fractional positions, so we only move in x-direction
|
||||
* when needed to get all the way to the next pixel over...
|
||||
*/
|
||||
for (edgec = &ctx->possible_edges; (e_curr = *edgec); ) {
|
||||
if (!(--(e_curr->num))) {
|
||||
*edgec = e_curr->e_next;
|
||||
}
|
||||
else {
|
||||
e_curr->x += e_curr->xshift;
|
||||
if ((e_curr->drift += e_curr->drift_inc) > 0) {
|
||||
e_curr->x += e_curr->xdir;
|
||||
e_curr->drift -= e_curr->drift_dec;
|
||||
}
|
||||
edgec = &e_curr->e_next;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It's possible that some edges may have crossed during the last step, so we'll be sure
|
||||
* that we ALWAYS intersect scan lines in order by shuffling if needed to make all edges
|
||||
* sorted by x-intersection coordinate. We'll always scan through at least once to see if
|
||||
* edges crossed, and if so, we set the 'swixd' flag. If 'swixd' gets set on the initial
|
||||
* pass, then we know we need to sort by x, so then cycle through edges again and perform
|
||||
* the sort.-
|
||||
*/
|
||||
if (ctx->possible_edges) {
|
||||
for (edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
|
||||
if (e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* set flag that we had at least one switch */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we did have a switch, look for more (there will more if there was one) */
|
||||
for (;; ) {
|
||||
/* reset exchange flag so it's only set if we encounter another one */
|
||||
swixd = 0;
|
||||
for (edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* again, if current edge hits scan line at higher X than next edge, exchange the edges and set flag */
|
||||
if (e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* flip the exchanged flag */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we had no exchanges, we're done reshuffling the pointers */
|
||||
if (!swixd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(edgbuf);
|
||||
return 1;
|
||||
free(edgbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PLX_raskterize(float (*base_verts)[2], int num_base_verts,
|
||||
float *buf, int buf_x, int buf_y, int do_mask_AA)
|
||||
{
|
||||
int subdiv_AA = (do_mask_AA != 0) ? 8 : 0;
|
||||
int i; /* i: Loop counter. */
|
||||
int sAx;
|
||||
int sAy;
|
||||
struct poly_vert *ply; /* ply: Pointer to a list of integer buffer-space vertex coordinates. */
|
||||
struct r_fill_context ctx = {0};
|
||||
const float buf_x_f = (float)(buf_x);
|
||||
const float buf_y_f = (float)(buf_y);
|
||||
float div_offset = (1.0f / (float)(subdiv_AA));
|
||||
float div_offset_static = 0.5f * (float)(subdiv_AA) * div_offset;
|
||||
/*
|
||||
* Allocate enough memory for our poly_vert list. It'll be the size of the poly_vert
|
||||
* data structure multiplied by the number of base_verts.
|
||||
*
|
||||
* In the event of a failure to allocate the memory, return 0, so this error can
|
||||
* be distinguished as a memory allocation error.
|
||||
*/
|
||||
if ((ply = (struct poly_vert *)(malloc(sizeof(struct poly_vert) * num_base_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
int PLX_raskterize(float(*base_verts)[2], int num_base_verts,
|
||||
float *buf, int buf_x, int buf_y, int do_mask_AA) {
|
||||
int subdiv_AA = (do_mask_AA != 0)? 0:0;
|
||||
int i; /* i: Loop counter. */
|
||||
int sAx;
|
||||
int sAy;
|
||||
struct poly_vert *ply; /* ply: Pointer to a list of integer buffer-space vertex coordinates. */
|
||||
struct r_fill_context ctx = {0};
|
||||
const float buf_x_f = (float)(buf_x);
|
||||
const float buf_y_f = (float)(buf_y);
|
||||
float div_offset=(1.0f / (float)(subdiv_AA));
|
||||
float div_offset_static = 0.5f * (float)(subdiv_AA) * div_offset;
|
||||
/*
|
||||
* Allocate enough memory for our poly_vert list. It'll be the size of the poly_vert
|
||||
* data structure multiplied by the number of base_verts.
|
||||
*
|
||||
* In the event of a failure to allocate the memory, return 0, so this error can
|
||||
* be distinguished as a memory allocation error.
|
||||
*/
|
||||
if((ply = (struct poly_vert *)(malloc(sizeof(struct poly_vert) * num_base_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
ctx.rb.buf = buf; /* Set the output buffer pointer. */
|
||||
ctx.rb.sizex = buf_x; /* Set the output buffer size in X. (width) */
|
||||
ctx.rb.sizey = buf_y; /* Set the output buffer size in Y. (height) */
|
||||
/*
|
||||
* Loop over all verts passed in to be rasterized. Each vertex's X and Y coordinates are
|
||||
* then converted from normalized screen space (0.0 <= POS <= 1.0) to integer coordinates
|
||||
* in the buffer-space coordinates passed in inside buf_x and buf_y.
|
||||
*
|
||||
* It's worth noting that this function ONLY outputs fully white pixels in a mask. Every pixel
|
||||
* drawn will be 1.0f in value, there is no anti-aliasing.
|
||||
*/
|
||||
ctx.rb.buf = buf; /* Set the output buffer pointer. */
|
||||
ctx.rb.sizex = buf_x; /* Set the output buffer size in X. (width) */
|
||||
ctx.rb.sizey = buf_y; /* Set the output buffer size in Y. (height) */
|
||||
/*
|
||||
* Loop over all verts passed in to be rasterized. Each vertex's X and Y coordinates are
|
||||
* then converted from normalized screen space (0.0 <= POS <= 1.0) to integer coordinates
|
||||
* in the buffer-space coordinates passed in inside buf_x and buf_y.
|
||||
*
|
||||
* It's worth noting that this function ONLY outputs fully white pixels in a mask. Every pixel
|
||||
* drawn will be 1.0f in value, there is no anti-aliasing.
|
||||
*/
|
||||
|
||||
if (!subdiv_AA) {
|
||||
for (i = 0; i < num_base_verts; i++) { /* Loop over all base_verts. */
|
||||
ply[i].x = (int)((base_verts[i][0] * buf_x_f) + 0.5f); /* Range expand normalized X to integer buffer-space X. */
|
||||
ply[i].y = (int)((base_verts[i][1] * buf_y_f) + 0.5f); /* Range expand normalized Y to integer buffer-space Y. */
|
||||
}
|
||||
if(!subdiv_AA) {
|
||||
for(i = 0; i < num_base_verts; i++) { /* Loop over all base_verts. */
|
||||
ply[i].x = (int)((base_verts[i][0] * buf_x_f) + 0.5f); /* Range expand normalized X to integer buffer-space X. */
|
||||
ply[i].y = (int)((base_verts[i][1] * buf_y_f) + 0.5f); /* Range expand normalized Y to integer buffer-space Y. */
|
||||
}
|
||||
|
||||
i = rast_scan_fill(&ctx, ply, num_base_verts, 1.0f); /* Call our rasterizer, passing in the integer coords for each vert. */
|
||||
}
|
||||
else {
|
||||
for (sAx = 0; sAx < subdiv_AA; sAx++) {
|
||||
for (sAy = 0; sAy < subdiv_AA; sAy++) {
|
||||
for (i = 0; i < num_base_verts; i++) {
|
||||
ply[i].x = (int)((base_verts[i][0] * buf_x_f) + 0.5f - div_offset_static + (div_offset * (float)(sAx)));
|
||||
ply[i].y = (int)((base_verts[i][1] * buf_y_f) + 0.5f - div_offset_static + (div_offset * (float)(sAy)));
|
||||
}
|
||||
i = rast_scan_fill(&ctx, ply, num_base_verts, (1.0f / (float)(subdiv_AA * subdiv_AA)));
|
||||
}
|
||||
}
|
||||
}
|
||||
free(ply); /* Free the memory allocated for the integer coordinate table. */
|
||||
return(i); /* Return the value returned by the rasterizer. */
|
||||
i = rast_scan_fill(&ctx, ply, num_base_verts,1.0f); /* Call our rasterizer, passing in the integer coords for each vert. */
|
||||
} else {
|
||||
for(sAx=0; sAx < subdiv_AA; sAx++) {
|
||||
for(sAy=0; sAy < subdiv_AA; sAy++) {
|
||||
for(i=0; i < num_base_verts; i++) {
|
||||
ply[i].x = (int)((base_verts[i][0]*buf_x_f)+0.5f - div_offset_static + (div_offset*(float)(sAx)));
|
||||
ply[i].y = (int)((base_verts[i][1]*buf_y_f)+0.5f - div_offset_static + (div_offset*(float)(sAy)));
|
||||
}
|
||||
i = rast_scan_fill(&ctx, ply, num_base_verts,(1.0f / (float)(subdiv_AA*subdiv_AA)));
|
||||
}
|
||||
}
|
||||
}
|
||||
free(ply); /* Free the memory allocated for the integer coordinate table. */
|
||||
return(i); /* Return the value returned by the rasterizer. */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -455,911 +437,1087 @@ int PLX_raskterize(float (*base_verts)[2], int num_base_verts,
|
||||
* if it ends up being coupled with this function.
|
||||
*/
|
||||
static int rast_scan_feather(struct r_fill_context *ctx,
|
||||
float (*base_verts_f)[2], int num_base_verts,
|
||||
struct poly_vert *feather_verts, float(*feather_verts_f)[2], int num_feather_verts)
|
||||
{
|
||||
int x_curr; /* current pixel position in X */
|
||||
int y_curr; /* current scan line being drawn */
|
||||
int yp; /* y-pixel's position in frame buffer */
|
||||
int swixd = 0; /* whether or not edges switched position in X */
|
||||
float *cpxl; /* pixel pointers... */
|
||||
float *mpxl;
|
||||
float *spxl;
|
||||
struct e_status *e_curr; /* edge pointers... */
|
||||
struct e_status *e_temp;
|
||||
struct e_status *edgbuf;
|
||||
struct e_status **edgec;
|
||||
float(*base_verts_f)[2], int num_base_verts,
|
||||
struct poly_vert *feather_verts, float(*feather_verts_f)[2], int num_feather_verts) {
|
||||
int x_curr; /* current pixel position in X */
|
||||
int y_curr; /* current scan line being drawn */
|
||||
int yp; /* y-pixel's position in frame buffer */
|
||||
int swixd = 0; /* whether or not edges switched position in X */
|
||||
float *cpxl; /* pixel pointers... */
|
||||
float *mpxl;
|
||||
float *spxl;
|
||||
struct e_status *e_curr; /* edge pointers... */
|
||||
struct e_status *e_temp;
|
||||
struct e_status *edgbuf;
|
||||
struct e_status **edgec;
|
||||
|
||||
/* from dem */
|
||||
int a; // a = temporary pixel index buffer loop counter
|
||||
float fsz; // size of the frame
|
||||
unsigned int rsl; // long used for finding fast 1.0/sqrt
|
||||
float rsf; // float used for finding fast 1.0/sqrt
|
||||
const float rsopf = 1.5f; // constant float used for finding fast 1.0/sqrt
|
||||
/* from dem */
|
||||
int a; // a = temporary pixel index buffer loop counter
|
||||
float fsz; // size of the frame
|
||||
unsigned int rsl; // long used for finding fast 1.0/sqrt
|
||||
float rsf; // float used for finding fast 1.0/sqrt
|
||||
const float rsopf = 1.5f; // constant float used for finding fast 1.0/sqrt
|
||||
|
||||
//unsigned int gradientFillOffset;
|
||||
float t;
|
||||
float ud; // ud = unscaled edge distance
|
||||
float dmin; // dmin = minimun edge distance
|
||||
float odist; // odist = current outer edge distance
|
||||
float idist; // idist = current inner edge distance
|
||||
float dx; // dx = X-delta (used for distance proportion calculation)
|
||||
float dy; // dy = Y-delta (used for distance proportion calculation)
|
||||
float xpxw = (1.0f / (float)(ctx->rb.sizex)); // xpxw = normalized pixel width
|
||||
float ypxh = (1.0f / (float)(ctx->rb.sizey)); // ypxh = normalized pixel height
|
||||
//unsigned int gradientFillOffset;
|
||||
float t;
|
||||
float ud; // ud = unscaled edge distance
|
||||
float dmin; // dmin = minimun edge distance
|
||||
float odist; // odist = current outer edge distance
|
||||
float idist; // idist = current inner edge distance
|
||||
float dx; // dx = X-delta (used for distance proportion calculation)
|
||||
float dy; // dy = Y-delta (used for distance proportion calculation)
|
||||
float xpxw = (1.0f / (float)(ctx->rb.sizex)); // xpxw = normalized pixel width
|
||||
float ypxh = (1.0f / (float)(ctx->rb.sizey)); // ypxh = normalized pixel height
|
||||
#ifdef __PLX_KD_TREE__
|
||||
void *res_kdi;
|
||||
void *res_kdo;
|
||||
float clup[2];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the number of verts specified to render as a polygon is less than 3,
|
||||
* return immediately. Obviously we cant render a poly with sides < 3. The
|
||||
* return for this we set to 1, simply so it can be distinguished from the
|
||||
* next place we could return,
|
||||
* which is a failure to allocate memory.
|
||||
*/
|
||||
if (num_feather_verts < 3) {
|
||||
return(1);
|
||||
}
|
||||
/*
|
||||
* If the number of verts specified to render as a polygon is less than 3,
|
||||
* return immediately. Obviously we cant render a poly with sides < 3. The
|
||||
* return for this we set to 1, simply so it can be distinguished from the
|
||||
* next place we could return,
|
||||
* which is a failure to allocate memory.
|
||||
*/
|
||||
if(num_feather_verts < 3) {
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to allocate an edge buffer in memory. needs to be the size of the edge tracking data
|
||||
* multiplied by the number of edges, which is always equal to the number of verts in
|
||||
* a 2D polygon. Here we return 0 to indicate a memory allocation failure, as opposed to a 1 for
|
||||
* the preceeding error, which was a rasterization request on a 2D poly with less than
|
||||
* 3 sides.
|
||||
*/
|
||||
if ((edgbuf = (struct e_status *)(malloc(sizeof(struct e_status) * num_feather_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* Try to allocate an edge buffer in memory. needs to be the size of the edge tracking data
|
||||
* multiplied by the number of edges, which is always equal to the number of verts in
|
||||
* a 2D polygon. Here we return 0 to indicate a memory allocation failure, as opposed to a 1 for
|
||||
* the preceeding error, which was a rasterization request on a 2D poly with less than
|
||||
* 3 sides.
|
||||
*/
|
||||
if((edgbuf = (struct e_status *)(malloc(sizeof(struct e_status) * num_feather_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some preprocessing on all edges. This constructs a table structure in memory of all
|
||||
* the edge properties and can "flip" some edges so sorting works correctly.
|
||||
*/
|
||||
preprocess_all_edges(ctx, feather_verts, num_feather_verts, edgbuf);
|
||||
/*
|
||||
* Do some preprocessing on all edges. This constructs a table structure in memory of all
|
||||
* the edge properties and can "flip" some edges so sorting works correctly.
|
||||
*/
|
||||
preprocess_all_edges(ctx, feather_verts, num_feather_verts, edgbuf);
|
||||
|
||||
/* can happen with a zero area mask */
|
||||
if (ctx->all_edges == NULL) {
|
||||
free(edgbuf);
|
||||
return(1);
|
||||
}
|
||||
/* can happen with a zero area mask */
|
||||
if (ctx->all_edges == NULL) {
|
||||
free(edgbuf);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the pointer for tracking the edges currently in processing to NULL to make sure
|
||||
* we don't get some crazy value after initialization.
|
||||
*/
|
||||
ctx->possible_edges = NULL;
|
||||
/*
|
||||
* Set the pointer for tracking the edges currently in processing to NULL to make sure
|
||||
* we don't get some crazy value after initialization.
|
||||
*/
|
||||
ctx->possible_edges = NULL;
|
||||
|
||||
/*
|
||||
* Loop through all scan lines to be drawn. Since we sorted by Y values during
|
||||
* preprocess_all_edges(), we can already exact values for the lowest and
|
||||
* highest Y values we could possibly need by induction. The preprocessing sorted
|
||||
* out edges by Y position, we can cycle the current edge being processed once
|
||||
* it runs out of Y pixels. When we have no more edges, meaning the current edge
|
||||
* is NULL after setting the "current" edge to be the previous current edge's
|
||||
* "next" edge in the Y sorted edge connection chain, we can stop looping Y values,
|
||||
* since we can't possibly have more scan lines if we ran out of edges. :)
|
||||
*
|
||||
* TODO: This clips Y to the frame buffer, which should be done in the preprocessor, but for now is done here.
|
||||
* Will get changed once DEM code gets in.
|
||||
*/
|
||||
for (y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
|
||||
/*
|
||||
* Loop through all scan lines to be drawn. Since we sorted by Y values during
|
||||
* preprocess_all_edges(), we can already exact values for the lowest and
|
||||
* highest Y values we could possibly need by induction. The preprocessing sorted
|
||||
* out edges by Y position, we can cycle the current edge being processed once
|
||||
* it runs out of Y pixels. When we have no more edges, meaning the current edge
|
||||
* is NULL after setting the "current" edge to be the previous current edge's
|
||||
* "next" edge in the Y sorted edge connection chain, we can stop looping Y values,
|
||||
* since we can't possibly have more scan lines if we ran out of edges. :)
|
||||
*
|
||||
* TODO: This clips Y to the frame buffer, which should be done in the preprocessor, but for now is done here.
|
||||
* Will get changed once DEM code gets in.
|
||||
*/
|
||||
for(y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
|
||||
|
||||
/*
|
||||
* Link any edges that start on the current scan line into the list of
|
||||
* edges currently needed to draw at least this, if not several, scan lines.
|
||||
*/
|
||||
/*
|
||||
* Link any edges that start on the current scan line into the list of
|
||||
* edges currently needed to draw at least this, if not several, scan lines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set the current edge to the beginning of the list of edges to be rasterized
|
||||
* into this scan line.
|
||||
*
|
||||
* We could have lots of edge here, so iterate over all the edges needed. The
|
||||
* preprocess_all_edges() function sorted edges by X within each chunk of Y sorting
|
||||
* so we safely cycle edges to thier own "next" edges in order.
|
||||
*
|
||||
* At each iteration, make sure we still have a non-NULL edge.
|
||||
*/
|
||||
for (edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr); ) {
|
||||
x_curr = ctx->all_edges->x; /* Set current X position. */
|
||||
for (;; ) { /* Start looping edges. Will break when edges run out. */
|
||||
e_curr = *edgec; /* Set up a current edge pointer. */
|
||||
if (!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
|
||||
e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
|
||||
*edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
|
||||
ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
|
||||
edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
|
||||
ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
|
||||
break; /* Stop looping edges (since we ran out or hit empty X span. */
|
||||
}
|
||||
else {
|
||||
edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Set the current edge to the beginning of the list of edges to be rasterized
|
||||
* into this scan line.
|
||||
*
|
||||
* We could have lots of edge here, so iterate over all the edges needed. The
|
||||
* preprocess_all_edges() function sorted edges by X within each chunk of Y sorting
|
||||
* so we safely cycle edges to thier own "next" edges in order.
|
||||
*
|
||||
* At each iteration, make sure we still have a non-NULL edge.
|
||||
*/
|
||||
for(edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr);) {
|
||||
x_curr = ctx->all_edges->x; /* Set current X position. */
|
||||
for(;;) { /* Start looping edges. Will break when edges run out. */
|
||||
e_curr = *edgec; /* Set up a current edge pointer. */
|
||||
if(!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
|
||||
e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
|
||||
*edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
|
||||
ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
|
||||
edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
|
||||
ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
|
||||
break; /* Stop looping edges (since we ran out or hit empty X span. */
|
||||
} else {
|
||||
edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the current scan line's offset in the pixel buffer based on its Y position.
|
||||
* Basically we just multiply the current scan line's Y value by the number of pixels in each line.
|
||||
*/
|
||||
yp = y_curr * ctx->rb.sizex;
|
||||
/*
|
||||
* Set a "scan line pointer" in memory. The location of the buffer plus the row offset.
|
||||
*/
|
||||
spxl = ctx->rb.buf + (yp);
|
||||
/*
|
||||
* Set up the current edge to the first (in X) edge. The edges which could possibly be in this
|
||||
* list were determined in the preceeding edge loop above. They were already sorted in X by the
|
||||
* initial processing function.
|
||||
*
|
||||
* At each iteration, test for a NULL edge. Since we'll keep cycling edge's to their own "next" edge
|
||||
* we will eventually hit a NULL when the list runs out.
|
||||
*/
|
||||
for (e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
|
||||
/*
|
||||
* Calculate a span of pixels to fill on the current scan line.
|
||||
*
|
||||
* Set the current pixel pointer by adding the X offset to the scan line's start offset.
|
||||
* Cycle the current edge the next edge.
|
||||
* Set the max X value to draw to be one less than the next edge's first pixel. This way we are
|
||||
* sure not to ever get into a situation where we have overdraw. (drawing the same pixel more than
|
||||
* one time because it's on a vertex connecting two edges)
|
||||
*
|
||||
* Then blast through all the pixels in the span, advancing the pointer and setting the color to white.
|
||||
*
|
||||
* TODO: Here we clip to the scan line, this is not efficient, and should be done in the preprocessor,
|
||||
* but for now it is done here until the DEM code comes in.
|
||||
*/
|
||||
/*
|
||||
* Determine the current scan line's offset in the pixel buffer based on its Y position.
|
||||
* Basically we just multiply the current scan line's Y value by the number of pixels in each line.
|
||||
*/
|
||||
yp = y_curr * ctx->rb.sizex;
|
||||
/*
|
||||
* Set a "scan line pointer" in memory. The location of the buffer plus the row offset.
|
||||
*/
|
||||
spxl = ctx->rb.buf + (yp);
|
||||
/*
|
||||
* Set up the current edge to the first (in X) edge. The edges which could possibly be in this
|
||||
* list were determined in the preceeding edge loop above. They were already sorted in X by the
|
||||
* initial processing function.
|
||||
*
|
||||
* At each iteration, test for a NULL edge. Since we'll keep cycling edge's to their own "next" edge
|
||||
* we will eventually hit a NULL when the list runs out.
|
||||
*/
|
||||
for(e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
|
||||
/*
|
||||
* Calculate a span of pixels to fill on the current scan line.
|
||||
*
|
||||
* Set the current pixel pointer by adding the X offset to the scan line's start offset.
|
||||
* Cycle the current edge the next edge.
|
||||
* Set the max X value to draw to be one less than the next edge's first pixel. This way we are
|
||||
* sure not to ever get into a situation where we have overdraw. (drawing the same pixel more than
|
||||
* one time because it's on a vertex connecting two edges)
|
||||
*
|
||||
* Then blast through all the pixels in the span, advancing the pointer and setting the color to white.
|
||||
*
|
||||
* TODO: Here we clip to the scan line, this is not efficient, and should be done in the preprocessor,
|
||||
* but for now it is done here until the DEM code comes in.
|
||||
*/
|
||||
|
||||
/* set up xmin and xmax bounds on this scan line */
|
||||
cpxl = spxl + MAX2(e_curr->x, 0);
|
||||
e_curr = e_curr->e_next;
|
||||
mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
|
||||
/* set up xmin and xmax bounds on this scan line */
|
||||
cpxl = spxl + MAX2(e_curr->x, 0);
|
||||
e_curr = e_curr->e_next;
|
||||
mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
|
||||
|
||||
if ((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
|
||||
t = ((float)((cpxl - spxl) % ctx->rb.sizex) + 0.5f) * xpxw;
|
||||
fsz = ((float)(y_curr) + 0.5f) * ypxh;
|
||||
/* draw the pixels. */
|
||||
for (; cpxl <= mpxl; cpxl++, t += xpxw) {
|
||||
//do feather check
|
||||
// first check that pixel isn't already full, and only operate if it is not
|
||||
if (*cpxl < 0.9999f) {
|
||||
if((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
|
||||
t = ((float)((cpxl - spxl) % ctx->rb.sizex) + 0.5f) * xpxw;
|
||||
fsz = ((float)(y_curr) + 0.5f) * ypxh;
|
||||
/* draw the pixels. */
|
||||
for(; cpxl <= mpxl; cpxl++, t += xpxw) {
|
||||
//do feather check
|
||||
// first check that pixel isn't already full, and only operate if it is not
|
||||
if(*cpxl < 0.9999f) {
|
||||
#ifndef __PLX_KD_TREE__
|
||||
dmin = 2.0f; // reset min distance to edge pixel
|
||||
for(a = 0; a < num_feather_verts; a++) { // loop through all outer edge buffer pixels
|
||||
dx = t - feather_verts_f[a][0]; // set dx to gradient pixel column - outer edge pixel row
|
||||
dy = fsz - feather_verts_f[a][1]; // set dy to gradient pixel row - outer edge pixel column
|
||||
ud = dx * dx + dy * dy; // compute sum of squares
|
||||
if(ud < dmin) { // if our new sum of squares is less than the current minimum
|
||||
dmin = ud; // set a new minimum equal to the new lower value
|
||||
}
|
||||
}
|
||||
odist = dmin; // cast outer min to a float
|
||||
rsf = odist * 0.5f; //
|
||||
rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored
|
||||
rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate
|
||||
odist = *(float *)&rsl; // reciprocal square root
|
||||
odist = odist * (rsopf - (rsf * odist * odist)); // -- ** this line can be iterated for more accuracy ** --
|
||||
odist = odist * (rsopf - (rsf * odist * odist));
|
||||
dmin = 2.0f; // reset min distance to edge pixel
|
||||
for(a = 0; a < num_base_verts; a++) { // loop through all inside edge pixels
|
||||
dx = t - base_verts_f[a][0]; // compute delta in Y from gradient pixel to inside edge pixel
|
||||
dy = fsz - base_verts_f[a][1]; // compute delta in X from gradient pixel to inside edge pixel
|
||||
ud = dx * dx + dy * dy; // compute sum of squares
|
||||
if(ud < dmin) { // if our new sum of squares is less than the current minimum we've found
|
||||
dmin = ud; // set a new minimum equal to the new lower value
|
||||
}
|
||||
}
|
||||
idist = dmin; // cast inner min to a float
|
||||
rsf = idist * 0.5f; //
|
||||
rsl = *(unsigned int *)&idist; //
|
||||
rsl = 0x5f3759df - (rsl >> 1); // see notes above
|
||||
idist = *(float *)&rsl; //
|
||||
idist = idist * (rsopf - (rsf * idist * idist)); //
|
||||
idist = idist * (rsopf - (rsf * idist * idist));
|
||||
/*
|
||||
* Note once again that since we are using reciprocals of distance values our
|
||||
* proportion is already the correct intensity, and does not need to be
|
||||
* subracted from 1.0 like it would have if we used real distances.
|
||||
*/
|
||||
#else
|
||||
clup[0]=t;
|
||||
clup[1]=fsz;
|
||||
res_kdi=kd_nearestf(ctx->kdi,clup);
|
||||
res_kdo=kd_nearestf(ctx->kdo,clup);
|
||||
kd_res_itemf(res_kdi,clup);
|
||||
dx=t-clup[0];
|
||||
dy=fsz-clup[1];
|
||||
idist=dx*dx+dy*dy;
|
||||
rsf = idist * 0.5f; //
|
||||
rsl = *(unsigned int *)&idist; //
|
||||
rsl = 0x5f3759df - (rsl >> 1); // see notes above
|
||||
idist = *(float *)&rsl; //
|
||||
idist = idist * (rsopf - (rsf * idist * idist)); //
|
||||
idist = idist * (rsopf - (rsf * idist * idist));
|
||||
kd_res_itemf(res_kdo,clup);
|
||||
dx=t-clup[0];
|
||||
dy=fsz-clup[1];
|
||||
odist=dx*dx+dy*dy;
|
||||
rsf = odist * 0.5f; //
|
||||
rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored
|
||||
rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate
|
||||
odist = *(float *)&rsl; // reciprocal square root
|
||||
odist = odist * (rsopf - (rsf * odist * odist)); // -- ** this line can be iterated for more accuracy ** --
|
||||
odist = odist * (rsopf - (rsf * odist * odist));
|
||||
|
||||
dmin = 2.0f; // reset min distance to edge pixel
|
||||
for (a = 0; a < num_feather_verts; a++) { // loop through all outer edge buffer pixels
|
||||
dy = t - feather_verts_f[a][0]; // set dx to gradient pixel column - outer edge pixel row
|
||||
dx = fsz - feather_verts_f[a][1]; // set dy to gradient pixel row - outer edge pixel column
|
||||
ud = dx * dx + dy * dy; // compute sum of squares
|
||||
if (ud < dmin) { // if our new sum of squares is less than the current minimum
|
||||
dmin = ud; // set a new minimum equal to the new lower value
|
||||
}
|
||||
}
|
||||
odist = dmin; // cast outer min to a float
|
||||
rsf = odist * 0.5f; //
|
||||
rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored
|
||||
rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate
|
||||
odist = *(float *)&rsl; // reciprocal square root
|
||||
odist = odist * (rsopf - (rsf * odist * odist)); // -- ** this line can be iterated for more accuracy ** --
|
||||
odist = odist * (rsopf - (rsf * odist * odist));
|
||||
dmin = 2.0f; // reset min distance to edge pixel
|
||||
for (a = 0; a < num_base_verts; a++) { // loop through all inside edge pixels
|
||||
dy = t - base_verts_f[a][0]; // compute delta in Y from gradient pixel to inside edge pixel
|
||||
dx = fsz - base_verts_f[a][1]; // compute delta in X from gradient pixel to inside edge pixel
|
||||
ud = dx * dx + dy * dy; // compute sum of squares
|
||||
if (ud < dmin) { // if our new sum of squares is less than the current minimum we've found
|
||||
dmin = ud; // set a new minimum equal to the new lower value
|
||||
}
|
||||
}
|
||||
idist = dmin; // cast inner min to a float
|
||||
rsf = idist * 0.5f; //
|
||||
rsl = *(unsigned int *)&idist; //
|
||||
rsl = 0x5f3759df - (rsl >> 1); // see notes above
|
||||
idist = *(float *)&rsl; //
|
||||
idist = idist * (rsopf - (rsf * idist * idist)); //
|
||||
idist = idist * (rsopf - (rsf * idist * idist));
|
||||
/*
|
||||
* Note once again that since we are using reciprocals of distance values our
|
||||
* proportion is already the correct intensity, and does not need to be
|
||||
* subracted from 1.0 like it would have if we used real distances.
|
||||
*/
|
||||
#endif
|
||||
/* set intensity, do the += so overlapping gradients are additive */
|
||||
*cpxl = (idist / (idist+odist));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set intensity, do the += so overlapping gradients are additive */
|
||||
*cpxl = (idist / (idist + odist));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Loop through all edges of polygon that could be hit by this scan line,
|
||||
* and figure out their x-intersections with the next scan line.
|
||||
*
|
||||
* Either A.) we wont have any more edges to test, or B.) we just add on the
|
||||
* slope delta computed in preprocessing step. Since this draws non-antialiased
|
||||
* polygons, we dont have fractional positions, so we only move in x-direction
|
||||
* when needed to get all the way to the next pixel over...
|
||||
*/
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec);) {
|
||||
if(!(--(e_curr->num))) {
|
||||
*edgec = e_curr->e_next;
|
||||
} else {
|
||||
e_curr->x += e_curr->xshift;
|
||||
if((e_curr->drift += e_curr->drift_inc) > 0) {
|
||||
e_curr->x += e_curr->xdir;
|
||||
e_curr->drift -= e_curr->drift_dec;
|
||||
}
|
||||
edgec = &e_curr->e_next;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It's possible that some edges may have crossed during the last step, so we'll be sure
|
||||
* that we ALWAYS intersect scan lines in order by shuffling if needed to make all edges
|
||||
* sorted by x-intersection coordinate. We'll always scan through at least once to see if
|
||||
* edges crossed, and if so, we set the 'swixd' flag. If 'swixd' gets set on the initial
|
||||
* pass, then we know we need to sort by x, so then cycle through edges again and perform
|
||||
* the sort.-
|
||||
*/
|
||||
if(ctx->possible_edges) {
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* set flag that we had at least one switch */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we did have a switch, look for more (there will more if there was one) */
|
||||
for(;;) {
|
||||
/* reset exchange flag so it's only set if we encounter another one */
|
||||
swixd = 0;
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* again, if current edge hits scan line at higher X than next edge,
|
||||
* exchange the edges and set flag */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* flip the exchanged flag */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we had no exchanges, we're done reshuffling the pointers */
|
||||
if(!swixd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all edges of polygon that could be hit by this scan line,
|
||||
* and figure out their x-intersections with the next scan line.
|
||||
*
|
||||
* Either A.) we wont have any more edges to test, or B.) we just add on the
|
||||
* slope delta computed in preprocessing step. Since this draws non-antialiased
|
||||
* polygons, we dont have fractional positions, so we only move in x-direction
|
||||
* when needed to get all the way to the next pixel over...
|
||||
*/
|
||||
for (edgec = &ctx->possible_edges; (e_curr = *edgec); ) {
|
||||
if (!(--(e_curr->num))) {
|
||||
*edgec = e_curr->e_next;
|
||||
}
|
||||
else {
|
||||
e_curr->x += e_curr->xshift;
|
||||
if ((e_curr->drift += e_curr->drift_inc) > 0) {
|
||||
e_curr->x += e_curr->xdir;
|
||||
e_curr->drift -= e_curr->drift_dec;
|
||||
}
|
||||
edgec = &e_curr->e_next;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It's possible that some edges may have crossed during the last step, so we'll be sure
|
||||
* that we ALWAYS intersect scan lines in order by shuffling if needed to make all edges
|
||||
* sorted by x-intersection coordinate. We'll always scan through at least once to see if
|
||||
* edges crossed, and if so, we set the 'swixd' flag. If 'swixd' gets set on the initial
|
||||
* pass, then we know we need to sort by x, so then cycle through edges again and perform
|
||||
* the sort.-
|
||||
*/
|
||||
if (ctx->possible_edges) {
|
||||
for (edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
|
||||
if (e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* set flag that we had at least one switch */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we did have a switch, look for more (there will more if there was one) */
|
||||
for (;; ) {
|
||||
/* reset exchange flag so it's only set if we encounter another one */
|
||||
swixd = 0;
|
||||
for (edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* again, if current edge hits scan line at higher X than next edge,
|
||||
* exchange the edges and set flag */
|
||||
if (e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* flip the exchanged flag */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we had no exchanges, we're done reshuffling the pointers */
|
||||
if (!swixd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(edgbuf);
|
||||
return 1;
|
||||
free(edgbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PLX_raskterize_feather(float (*base_verts)[2], int num_base_verts, float (*feather_verts)[2], int num_feather_verts,
|
||||
float *buf, int buf_x, int buf_y) {
|
||||
int i; /* i: Loop counter. */
|
||||
struct poly_vert *fe; /* fe: Pointer to a list of integer buffer-space feather vertex coords. */
|
||||
struct r_fill_context ctx = {0};
|
||||
int PLX_raskterize_feather(float(*base_verts)[2], int num_base_verts, float(*feather_verts)[2], int num_feather_verts,
|
||||
float *buf, int buf_x, int buf_y) {
|
||||
//void plx_floatsort(float(*f)[2], unsigned int n, int sortby);
|
||||
int i; /* i: Loop counter. */
|
||||
struct poly_vert *fe; /* fe: Pointer to a list of integer buffer-space feather vertex coords. */
|
||||
struct r_fill_context ctx = {0};
|
||||
|
||||
/* for faster multiply */
|
||||
const float buf_x_f = (float)buf_x;
|
||||
const float buf_y_f = (float)buf_y;
|
||||
/* for faster multiply */
|
||||
const float buf_x_f = (float)buf_x;
|
||||
const float buf_y_f = (float)buf_y;
|
||||
#ifdef __PLX_KD_TREE__
|
||||
ctx.kdi = kd_create(2);
|
||||
ctx.kdo = kd_create(2);
|
||||
#endif
|
||||
/*
|
||||
* Allocate enough memory for our poly_vert list. It'll be the size of the poly_vert
|
||||
* data structure multiplied by the number of verts.
|
||||
*
|
||||
* In the event of a failure to allocate the memory, return 0, so this error can
|
||||
* be distinguished as a memory allocation error.
|
||||
*/
|
||||
if((fe = (struct poly_vert *)(malloc(sizeof(struct poly_vert) * num_feather_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate enough memory for our poly_vert list. It'll be the size of the poly_vert
|
||||
* data structure multiplied by the number of verts.
|
||||
*
|
||||
* In the event of a failure to allocate the memory, return 0, so this error can
|
||||
* be distinguished as a memory allocation error.
|
||||
*/
|
||||
if ((fe = (struct poly_vert *)(malloc(sizeof(struct poly_vert) * num_feather_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* Loop over all verts passed in to be rasterized. Each vertex's X and Y coordinates are
|
||||
* then converted from normalized screen space (0.0 <= POS <= 1.0) to integer coordinates
|
||||
* in the buffer-space coordinates passed in inside buf_x and buf_y.
|
||||
*
|
||||
* It's worth noting that this function ONLY outputs fully white pixels in a mask. Every pixel
|
||||
* drawn will be 1.0f in value, there is no anti-aliasing.
|
||||
*/
|
||||
for(i = 0; i < num_feather_verts; i++) { /* Loop over all verts. */
|
||||
fe[i].x = (int)((feather_verts[i][0] * buf_x_f) + 0.5f); /* Range expand normalized X to integer buffer-space X. */
|
||||
fe[i].y = (int)((feather_verts[i][1] * buf_y_f) + 0.5f); /* Range expand normalized Y to integer buffer-space Y. */
|
||||
#ifdef __PLX_KD_TREE__
|
||||
kd_insertf(ctx.kdo,feather_verts[i],NULL);
|
||||
}
|
||||
for(i=0;i<num_base_verts;i++){
|
||||
kd_insertf(ctx.kdi,base_verts[i],NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop over all verts passed in to be rasterized. Each vertex's X and Y coordinates are
|
||||
* then converted from normalized screen space (0.0 <= POS <= 1.0) to integer coordinates
|
||||
* in the buffer-space coordinates passed in inside buf_x and buf_y.
|
||||
*
|
||||
* It's worth noting that this function ONLY outputs fully white pixels in a mask. Every pixel
|
||||
* drawn will be 1.0f in value, there is no anti-aliasing.
|
||||
*/
|
||||
for (i = 0; i < num_feather_verts; i++) { /* Loop over all verts. */
|
||||
fe[i].x = (int)((feather_verts[i][0] * buf_x_f) + 0.5f); /* Range expand normalized X to integer buffer-space X. */
|
||||
fe[i].y = (int)((feather_verts[i][1] * buf_y_f) + 0.5f); /* Range expand normalized Y to integer buffer-space Y. */
|
||||
}
|
||||
|
||||
ctx.rb.buf = buf; /* Set the output buffer pointer. */
|
||||
ctx.rb.sizex = buf_x; /* Set the output buffer size in X. (width) */
|
||||
ctx.rb.sizey = buf_y; /* Set the output buffer size in Y. (height) */
|
||||
|
||||
/* Call our rasterizer, passing in the integer coords for each vert. */
|
||||
i = rast_scan_feather(&ctx, base_verts, num_base_verts, fe, feather_verts, num_feather_verts);
|
||||
free(fe);
|
||||
return i; /* Return the value returned by the rasterizer. */
|
||||
ctx.rb.buf = buf; /* Set the output buffer pointer. */
|
||||
ctx.rb.sizex = buf_x; /* Set the output buffer size in X. (width) */
|
||||
ctx.rb.sizey = buf_y; /* Set the output buffer size in Y. (height) */
|
||||
/* pre-sort the sets of edge verts on y */
|
||||
//plx_floatsort(base_verts,num_base_verts,0);
|
||||
//plx_floatsort(base_verts,num_base_verts,1);
|
||||
//plx_floatsort(feather_verts,num_feather_verts,0);
|
||||
//plx_floatsort(feather_verts,num_feather_verts,1);
|
||||
/* Call our rasterizer, passing in the integer coords for each vert. */
|
||||
i = rast_scan_feather(&ctx, base_verts, num_base_verts, fe, feather_verts, num_feather_verts);
|
||||
free(fe);
|
||||
return i; /* Return the value returned by the rasterizer. */
|
||||
}
|
||||
|
||||
#ifndef __PLX__FAKE_AA__
|
||||
|
||||
static int get_range_expanded_pixel_coord(float normalized_value, int max_value)
|
||||
{
|
||||
return (int)((normalized_value * (float)(max_value)) + 0.5f);
|
||||
int get_range_expanded_pixel_coord(float normalized_value, int max_value) {
|
||||
return (int)((normalized_value * (float)(max_value)) + 0.5f);
|
||||
}
|
||||
|
||||
static float get_pixel_intensity(float *buf, int buf_x, int buf_y, int pos_x, int pos_y)
|
||||
{
|
||||
if(pos_x < 0 || pos_x >= buf_x || pos_y < 0 || pos_y >= buf_y) {
|
||||
return 0.0f;
|
||||
}
|
||||
return buf[(pos_y * buf_y) + buf_x];
|
||||
float get_pixel_intensity(float *buf, int buf_x, int buf_y, int pos_x, int pos_y) {
|
||||
if(pos_x < 0 || pos_x >= buf_x || pos_y < 0 || pos_y >= buf_y) {
|
||||
return 0.0f;
|
||||
}
|
||||
return buf[(pos_y * buf_x) + pos_x];
|
||||
}
|
||||
|
||||
static float get_pixel_intensity_bilinear(float *buf, int buf_x, int buf_y, float u, float v)
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int a_plus_1;
|
||||
int b_plus_1;
|
||||
float prop_u;
|
||||
float prop_v;
|
||||
float inv_prop_u;
|
||||
float inv_prop_v;
|
||||
if(u<0.0f || u>1.0f || v<0.0f || v>1.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
u = u * (float)(buf_x) - 0.5f;
|
||||
v = v * (float)(buf_y) - 0.5f;
|
||||
a = (int)(u);
|
||||
b = (int)(v);
|
||||
prop_u = u - (float)(a);
|
||||
prop_v = v - (float)(b);
|
||||
inv_prop_u = 1.0f - prop_u;
|
||||
inv_prop_v = 1.0f - prop_v;
|
||||
a_plus_1 = MIN2((buf_x-1),a+1);
|
||||
b_plus_1 = MIN2((buf_y-1),b+1);
|
||||
return (buf[(b * buf_y) + a] * inv_prop_u + buf[(b*buf_y)+(a_plus_1)] * prop_u)*inv_prop_v+(buf[((b_plus_1) * buf_y)+a] * inv_prop_u + buf[((b_plus_1)*buf_y)+(a_plus_1)] * prop_u) * prop_v;
|
||||
float get_pixel_intensity_bilinear(float *buf, int buf_x, int buf_y, float u, float v) {
|
||||
int a;
|
||||
int b;
|
||||
int a_plus_1;
|
||||
int b_plus_1;
|
||||
float prop_u;
|
||||
float prop_v;
|
||||
float inv_prop_u;
|
||||
float inv_prop_v;
|
||||
if(u<0.0f || u>1.0f || v<0.0f || v>1.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
u = u * (float)(buf_x) - 0.5f;
|
||||
v = v * (float)(buf_y) - 0.5f;
|
||||
a = (int)(u);
|
||||
b = (int)(v);
|
||||
prop_u = u - (float)(a);
|
||||
prop_v = v - (float)(b);
|
||||
inv_prop_u = 1.0f - prop_u;
|
||||
inv_prop_v = 1.0f - prop_v;
|
||||
a_plus_1 = MIN2((buf_x-1),a+1);
|
||||
b_plus_1 = MIN2((buf_y-1),b+1);
|
||||
return (buf[(b * buf_x) + a] * inv_prop_u + buf[(b*buf_x)+(a_plus_1)] * prop_u)*inv_prop_v+(buf[((b_plus_1) * buf_x)+a] * inv_prop_u + buf[((b_plus_1)*buf_x)+(a_plus_1)] * prop_u) * prop_v;
|
||||
|
||||
}
|
||||
|
||||
static void set_pixel_intensity(float *buf, int buf_x, int buf_y, int pos_x, int pos_y, float intensity)
|
||||
{
|
||||
if(pos_x < 0 || pos_x >= buf_x || pos_y < 0 || pos_y >= buf_y) {
|
||||
return;
|
||||
}
|
||||
buf[(pos_y * buf_y) + buf_x] = intensity;
|
||||
void set_pixel_intensity(float *buf, int buf_x, int buf_y, int pos_x, int pos_y, float intensity) {
|
||||
if(pos_x < 0 || pos_x >= buf_x || pos_y < 0 || pos_y >= buf_y) {
|
||||
return;
|
||||
}
|
||||
buf[(pos_y * buf_x) + pos_x] = intensity;
|
||||
}
|
||||
#endif
|
||||
|
||||
int PLX_antialias_buffer(float *buf, int buf_x, int buf_y)
|
||||
{
|
||||
int PLX_antialias_buffer(float *buf, int buf_x, int buf_y) {
|
||||
#ifdef __PLX__FAKE_AA__
|
||||
#ifdef __PLX_GREY_AA__
|
||||
int i=0;
|
||||
int sz = buf_x * buf_y;
|
||||
for(i=0; i<sz; i++) {
|
||||
buf[i] *= 0.5f;
|
||||
}
|
||||
int i=0;
|
||||
int sz = buf_x * buf_y;
|
||||
for(i=0; i<sz; i++) {
|
||||
buf[i] *= 0.5f;
|
||||
}
|
||||
#endif
|
||||
(void)buf_x;
|
||||
(void)buf_y;
|
||||
(void)buf;
|
||||
return 1;
|
||||
(void)buf_x;
|
||||
(void)buf_y;
|
||||
(void)buf;
|
||||
return 1;
|
||||
#else
|
||||
/*XXX - TODO: THIS IS NOT FINAL CODE - IT DOES NOT WORK - DO NOT ENABLE IT */
|
||||
const float p0 = 1.0f;
|
||||
const float p1 = 1.0f;
|
||||
const float p2 = 1.0f;
|
||||
const float p3 = 1.0f;
|
||||
const float p4 = 1.0f;
|
||||
const float p5 = 1.5f;
|
||||
const float p6 = 2.0f;
|
||||
const float p7 = 2.0f;
|
||||
const float p8 = 2.0f;
|
||||
const float p9 = 2.0f;
|
||||
const float p10 = 4.0f;
|
||||
const float p11 = 8.0f;
|
||||
const float p0 = 1.0f;
|
||||
const float p1 = 1.0f;
|
||||
const float p2 = 1.0f;
|
||||
const float p3 = 1.0f;
|
||||
const float p4 = 1.0f;
|
||||
const float p5 = 1.5f;
|
||||
const float p6 = 2.0f;
|
||||
const float p7 = 2.0f;
|
||||
const float p8 = 2.0f;
|
||||
const float p9 = 2.0f;
|
||||
const float p10 = 4.0f;
|
||||
const float p11 = 8.0f;
|
||||
|
||||
const float edge_threshold = 0.063f;
|
||||
const float edge_threshold_min = 0.0312f;
|
||||
const float quality_subpix = 1.0f;
|
||||
// int px_x;
|
||||
// int px_y;
|
||||
const float edge_threshold = 0.063f;
|
||||
const float edge_threshold_min = 0.0312f;
|
||||
const float quality_subpix = 1.0f;
|
||||
|
||||
float posM_x,posM_y;
|
||||
float posB_x,posB_y;
|
||||
float posN_x,posN_y;
|
||||
float posP_x,posP_y;
|
||||
float offNP_x,offNP_y;
|
||||
float lumaM;
|
||||
float lumaS;
|
||||
float lumaE;
|
||||
float lumaN;
|
||||
float lumaW;
|
||||
float lumaNW;
|
||||
float lumaSE;
|
||||
float lumaNE;
|
||||
float lumaSW;
|
||||
float lumaNS;
|
||||
float lumaWE;
|
||||
float lumaNESE;
|
||||
float lumaNWNE;
|
||||
float lumaNWSW;
|
||||
float lumaSWSE;
|
||||
float lumaNN;
|
||||
float lumaSS;
|
||||
float lumaEndN;
|
||||
float lumaEndP;
|
||||
float lumaMM;
|
||||
float lumaMLTZero;
|
||||
float subpixNWSWNESE;
|
||||
float subpixRcpRange;
|
||||
float subpixNSWE;
|
||||
float maxSM;
|
||||
float minSM;
|
||||
float maxESM;
|
||||
float minESM;
|
||||
float maxWN;
|
||||
float minWN;
|
||||
float rangeMax;
|
||||
float rangeMin;
|
||||
float rangeMaxScaled;
|
||||
float range;
|
||||
float rangeMaxClamped;
|
||||
float edgeHorz;
|
||||
float edgeVert;
|
||||
float edgeHorz1;
|
||||
float edgeVert1;
|
||||
float edgeHorz2;
|
||||
float edgeVert2;
|
||||
float edgeHorz3;
|
||||
float edgeVert3;
|
||||
float edgeHorz4;
|
||||
float edgeVert4;
|
||||
float lengthSign;
|
||||
float subpixA;
|
||||
float subpixB;
|
||||
float subpixC;
|
||||
float subpixD;
|
||||
float subpixE;
|
||||
float subpixF;
|
||||
float subpixG;
|
||||
float subpixH;
|
||||
float gradientN;
|
||||
float gradientS;
|
||||
float gradient;
|
||||
float gradientScaled;
|
||||
float dstN;
|
||||
float dstP;
|
||||
float dst;
|
||||
float spanLength;
|
||||
float spanLengthRcp;
|
||||
float pixelOffset;
|
||||
float pixelOffsetGood;
|
||||
float pixelOffsetSubpix;
|
||||
int directionN;
|
||||
int goodSpan;
|
||||
int goodSpanN;
|
||||
int goodSpanP;
|
||||
int horzSpan;
|
||||
int earlyExit;
|
||||
int pairN;
|
||||
int doneN;
|
||||
int doneP;
|
||||
int doneNP;
|
||||
int curr_x=0;
|
||||
int curr_y=0;
|
||||
for(curr_y=0; curr_y < buf_y; curr_y++) {
|
||||
for(curr_x=0; curr_x < buf_x; curr_x++) {
|
||||
posM_x = ((float)(curr_x) + 0.5f) * (1.0f/(float)(buf_x));
|
||||
posM_y = ((float)(curr_y) + 0.5f) * (1.0f/(float)(buf_y));
|
||||
float posM_x,posM_y;
|
||||
float posB_x,posB_y;
|
||||
float posN_x,posN_y;
|
||||
float posP_x,posP_y;
|
||||
float offNP_x,offNP_y;
|
||||
float lumaM;
|
||||
float lumaS;
|
||||
float lumaE;
|
||||
float lumaN;
|
||||
float lumaW;
|
||||
float lumaNW;
|
||||
float lumaSE;
|
||||
float lumaNE;
|
||||
float lumaSW;
|
||||
float lumaNS;
|
||||
float lumaWE;
|
||||
float lumaNESE;
|
||||
float lumaNWNE;
|
||||
float lumaNWSW;
|
||||
float lumaSWSE;
|
||||
float lumaNN;
|
||||
float lumaSS;
|
||||
float lumaEndN;
|
||||
float lumaEndP;
|
||||
float lumaMM;
|
||||
float lumaMLTZero;
|
||||
float subpixNWSWNESE;
|
||||
float subpixRcpRange;
|
||||
float subpixNSWE;
|
||||
float maxSM;
|
||||
float minSM;
|
||||
float maxESM;
|
||||
float minESM;
|
||||
float maxWN;
|
||||
float minWN;
|
||||
float rangeMax;
|
||||
float rangeMin;
|
||||
float rangeMaxScaled;
|
||||
float range;
|
||||
float rangeMaxClamped;
|
||||
float edgeHorz;
|
||||
float edgeVert;
|
||||
float edgeHorz1;
|
||||
float edgeVert1;
|
||||
float edgeHorz2;
|
||||
float edgeVert2;
|
||||
float edgeHorz3;
|
||||
float edgeVert3;
|
||||
float edgeHorz4;
|
||||
float edgeVert4;
|
||||
float lengthSign;
|
||||
float subpixA;
|
||||
float subpixB;
|
||||
float subpixC;
|
||||
float subpixD;
|
||||
float subpixE;
|
||||
float subpixF;
|
||||
float subpixG;
|
||||
float subpixH;
|
||||
float gradientN;
|
||||
float gradientS;
|
||||
float gradient;
|
||||
float gradientScaled;
|
||||
float dstN;
|
||||
float dstP;
|
||||
float dst;
|
||||
float spanLength;
|
||||
float spanLengthRcp;
|
||||
float pixelOffset;
|
||||
float pixelOffsetGood;
|
||||
float pixelOffsetSubpix;
|
||||
float opx;
|
||||
float opy;
|
||||
int directionN;
|
||||
int goodSpan;
|
||||
int goodSpanN;
|
||||
int goodSpanP;
|
||||
int horzSpan;
|
||||
int earlyExit;
|
||||
int pairN;
|
||||
int doneN;
|
||||
int doneP;
|
||||
int doneNP;
|
||||
int curr_x=0;
|
||||
int curr_y=0;
|
||||
opx = (1.0f / (float)(buf_x));
|
||||
opy = (1.0f / (float)(buf_y));
|
||||
for(curr_y=0; curr_y < buf_y; curr_y++) {
|
||||
for(curr_x=0; curr_x < buf_x; curr_x++) {
|
||||
posM_x = ((float)(curr_x) + 0.5f) * opx;
|
||||
posM_y = ((float)(curr_y) + 0.5f) * opy;
|
||||
//#define __PLX_BILINEAR_INITIAL_SAMPLES__ 1
|
||||
#ifdef __PLX_BILINEAR_INITIAL_SAMPLES__
|
||||
lumaM = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x, posM_y);
|
||||
lumaS = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x, posM_y + opy);
|
||||
lumaE = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x + opx, posM_y);
|
||||
lumaN = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x, posM_y - opy);
|
||||
lumaW = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x - opx, posM_y);
|
||||
#else
|
||||
lumaM = get_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y);
|
||||
lumaS = get_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y + 1);
|
||||
lumaE = get_pixel_intensity(buf, buf_x, buf_y, curr_x + 1, curr_y);
|
||||
lumaN = get_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y - 1);
|
||||
lumaW = get_pixel_intensity(buf, buf_x, buf_y, curr_x - 1, curr_y);
|
||||
#endif
|
||||
maxSM = MAX2(lumaS, lumaM);
|
||||
minSM = MIN2(lumaS, lumaM);
|
||||
maxESM = MAX2(lumaE, maxSM);
|
||||
minESM = MIN2(lumaE, minSM);
|
||||
maxWN = MAX2(lumaN, lumaW);
|
||||
minWN = MIN2(lumaN, lumaW);
|
||||
rangeMax = MAX2(maxWN, maxESM);
|
||||
rangeMin = MIN2(minWN, minESM);
|
||||
rangeMaxScaled = rangeMax * edge_threshold;
|
||||
range = rangeMax - rangeMin;
|
||||
rangeMaxClamped = MAX2(edge_threshold_min, rangeMaxScaled);
|
||||
|
||||
lumaM = get_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y);
|
||||
lumaS = get_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y - 1);
|
||||
lumaE = get_pixel_intensity(buf, buf_x, buf_y, curr_x + 1, curr_y);
|
||||
lumaN = get_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y + 1);
|
||||
lumaW = get_pixel_intensity(buf, buf_x, buf_y, curr_x - 1, curr_y);
|
||||
earlyExit = range < rangeMaxClamped ? 1:0;
|
||||
if(earlyExit) {
|
||||
set_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y, lumaM);
|
||||
} else {
|
||||
|
||||
maxSM = MAX2(lumaS, lumaM);
|
||||
minSM = MIN2(lumaS, lumaM);
|
||||
maxESM = MAX2(lumaE, maxSM);
|
||||
minESM = MIN2(lumaE, minSM);
|
||||
maxWN = MAX2(lumaN, lumaW);
|
||||
minWN = MIN2(lumaN, lumaW);
|
||||
rangeMax = MAX2(maxWN, maxESM);
|
||||
rangeMin = MIN2(minWN, minESM);
|
||||
rangeMaxScaled = rangeMax * edge_threshold;
|
||||
range = rangeMax - rangeMin;
|
||||
rangeMaxClamped = MAX2(edge_threshold_min, rangeMaxScaled);
|
||||
lumaNW = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x - opx, posM_y - opy);
|
||||
lumaSE = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x + opx, posM_y + opy);
|
||||
lumaNE = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x + opx, posM_y - opy);
|
||||
lumaSW = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x - opx, posM_y + opy);
|
||||
|
||||
earlyExit = range < rangeMaxClamped ? 1:0;
|
||||
if(earlyExit) {
|
||||
set_pixel_intensity(buf, buf_x, buf_y, curr_x, curr_y, lumaM);
|
||||
}
|
||||
lumaNS = lumaN + lumaS;
|
||||
lumaWE = lumaW + lumaE;
|
||||
subpixRcpRange = 1.0f/range;
|
||||
subpixNSWE = lumaNS + lumaWE;
|
||||
edgeHorz1 = (-2.0f * lumaM) + lumaNS;
|
||||
edgeVert1 = (-2.0f * lumaM) + lumaWE;
|
||||
|
||||
lumaNW = get_pixel_intensity(buf, buf_x, buf_y, curr_x + 1, curr_y - 1);
|
||||
lumaSE = get_pixel_intensity(buf, buf_x, buf_y, curr_x - 1, curr_y + 1);
|
||||
lumaNE = get_pixel_intensity(buf, buf_x, buf_y, curr_x + 1, curr_y + 1);
|
||||
lumaSW = get_pixel_intensity(buf, buf_x, buf_y, curr_x - 1, curr_y - 1);
|
||||
lumaNESE = lumaNE + lumaSE;
|
||||
lumaNWNE = lumaNW + lumaNE;
|
||||
edgeHorz2 = (-2.0f * lumaE) + lumaNESE;
|
||||
edgeVert2 = (-2.0f * lumaN) + lumaNWNE;
|
||||
|
||||
lumaNS = lumaN + lumaS;
|
||||
lumaWE = lumaW + lumaE;
|
||||
subpixRcpRange = 1.0f/range;
|
||||
subpixNSWE = lumaNS + lumaWE;
|
||||
edgeHorz1 = (-2.0f * lumaM) + lumaNS;
|
||||
edgeVert1 = (-2.0f * lumaM) + lumaWE;
|
||||
lumaNWSW = lumaNW + lumaSW;
|
||||
lumaSWSE = lumaSW + lumaSE;
|
||||
edgeHorz4 = (ABS(edgeHorz1) * 2.0f) + ABS(edgeHorz2);
|
||||
edgeVert4 = (ABS(edgeVert1) * 2.0f) + ABS(edgeVert2);
|
||||
edgeHorz3 = (-2.0f * lumaW) + lumaNWSW;
|
||||
edgeVert3 = (-2.0f * lumaS) + lumaSWSE;
|
||||
edgeHorz = ABS(edgeHorz3) + edgeHorz4;
|
||||
edgeVert = ABS(edgeVert3) + edgeVert4;
|
||||
|
||||
lumaNESE = lumaNE + lumaSE;
|
||||
lumaNWNE = lumaNW + lumaNE;
|
||||
edgeHorz2 = (-2.0f * lumaE) + lumaNESE;
|
||||
edgeVert2 = (-2.0f * lumaN) + lumaNWNE;
|
||||
subpixNWSWNESE = lumaNWSW + lumaNESE;
|
||||
lengthSign = 1.0f / (float)(buf_x);
|
||||
horzSpan = edgeHorz >= edgeVert ? 1:0;
|
||||
subpixA = subpixNSWE * 2.0f + subpixNWSWNESE;
|
||||
|
||||
lumaNWSW = lumaNW + lumaSW;
|
||||
lumaSWSE = lumaSW + lumaSE;
|
||||
edgeHorz4 = (ABS(edgeHorz1) * 2.0f) + ABS(edgeHorz2);
|
||||
edgeVert4 = (ABS(edgeVert1) * 2.0f) + ABS(edgeVert2);
|
||||
edgeHorz3 = (-2.0f * lumaW) + lumaNWSW;
|
||||
edgeVert3 = (-2.0f * lumaS) + lumaSWSE;
|
||||
edgeHorz = ABS(edgeHorz3) + edgeHorz4;
|
||||
edgeVert = ABS(edgeVert3) + edgeVert4;
|
||||
if(!horzSpan) {
|
||||
lumaN = lumaW;
|
||||
lumaS = lumaE;
|
||||
} else {
|
||||
lengthSign = 1.0f / (float)(buf_y);
|
||||
}
|
||||
subpixB = (subpixA * (1.0f/12.0f)) - lumaM;
|
||||
|
||||
subpixNWSWNESE = lumaNWSW + lumaNESE;
|
||||
lengthSign = 1.0f / (float)(buf_x);
|
||||
horzSpan = edgeHorz >= edgeVert ? 1:0;
|
||||
subpixA = subpixNSWE * 2.0f + subpixNWSWNESE;
|
||||
gradientN = lumaN - lumaM;
|
||||
gradientS = lumaS - lumaM;
|
||||
lumaNN = lumaN + lumaM;
|
||||
lumaSS = lumaS + lumaM;
|
||||
pairN = (ABS(gradientN)) >= (ABS(gradientS)) ? 1:0;
|
||||
gradient = MAX2(ABS(gradientN), ABS(gradientS));
|
||||
if(pairN) {
|
||||
lengthSign = -lengthSign;
|
||||
}
|
||||
subpixC = MAX2(MIN2(ABS(subpixB) * subpixRcpRange,1.0f),0.0f);
|
||||
|
||||
if(!horzSpan) {
|
||||
lumaN = lumaW;
|
||||
lumaS = lumaE;
|
||||
}
|
||||
else {
|
||||
lengthSign = 1.0f / (float)(buf_y);
|
||||
}
|
||||
subpixB = (subpixA * (1.0f/12.0f)) - lumaM;
|
||||
posB_x = posM_x;
|
||||
posB_y = posM_y;
|
||||
offNP_x = (!horzSpan) ? 0.0f:(1.0f / (float)(buf_x));
|
||||
offNP_y = (horzSpan) ? 0.0f:(1.0f / (float)(buf_y));
|
||||
if(!horzSpan) {
|
||||
posB_x += lengthSign * 0.5f;
|
||||
} else {
|
||||
posB_y += lengthSign * 0.5f;
|
||||
}
|
||||
|
||||
gradientN = lumaN - lumaM;
|
||||
gradientS = lumaS - lumaM;
|
||||
lumaNN = lumaN + lumaM;
|
||||
lumaSS = lumaS + lumaM;
|
||||
pairN = (ABS(gradientN)) >= (ABS(gradientS)) ? 1:0;
|
||||
gradient = MAX2(ABS(gradientN), ABS(gradientS));
|
||||
if(pairN) {
|
||||
lengthSign = -lengthSign;
|
||||
}
|
||||
subpixC = MAX2(MIN2(ABS(subpixB) * subpixRcpRange,1.0f),0.0f);
|
||||
posN_x = posB_x - offNP_x * p0;
|
||||
posN_y = posB_y - offNP_y * p0;
|
||||
posP_x = posB_x + offNP_x * p0;
|
||||
posP_y = posB_y + offNP_y * p0;
|
||||
subpixD = ((-2.0f)*subpixC) + 3.0f;
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
subpixE = subpixC * subpixC;
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
|
||||
posB_x = posM_x;
|
||||
posB_y = posM_y;
|
||||
offNP_x = (!horzSpan) ? 0.0f:(1.0f / (float)(buf_x));
|
||||
offNP_y = (horzSpan) ? 0.0f:(1.0f / (float)(buf_y));
|
||||
if(!horzSpan) {
|
||||
posB_x += lengthSign * 0.5f;
|
||||
}
|
||||
else {
|
||||
posB_y += lengthSign * 0.5f;
|
||||
}
|
||||
if(!pairN) {
|
||||
lumaNN = lumaSS;
|
||||
}
|
||||
gradientScaled = gradient * 1.0f/4.0f;
|
||||
lumaMM =lumaM - lumaNN * 0.5f;
|
||||
subpixF = subpixD * subpixE;
|
||||
lumaMLTZero = lumaMM < 0.0f ? 1:0;
|
||||
|
||||
posN_x = posB_x - offNP_x * p0;
|
||||
posN_y = posB_y - offNP_y * p0;
|
||||
posP_x = posB_x + offNP_x * p0;
|
||||
posP_y = posB_y + offNP_y * p0;
|
||||
subpixD = ((-2.0f)*subpixC) + 3.0f;
|
||||
//may need bilinear filtered get_pixel_intensity() here...done
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
subpixE = subpixC * subpixC;
|
||||
//may need bilinear filtered get_pixel_intensity() here...done
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
lumaEndN -= lumaNN * 0.5f;
|
||||
lumaEndP -= lumaNN * 0.5f;
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p1;
|
||||
posN_y -= offNP_y * p1;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p1;
|
||||
posP_y += offNP_y * p1;
|
||||
}
|
||||
|
||||
if(!pairN) {
|
||||
lumaNN = lumaSS;
|
||||
}
|
||||
gradientScaled = gradient * 1.0f/4.0f;
|
||||
lumaMM =lumaM - lumaNN * 0.5f;
|
||||
subpixF = subpixD * subpixE;
|
||||
lumaMLTZero = lumaMM < 0.0f ? 1:0;
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x, posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p2;
|
||||
posN_y -= offNP_y * p2;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p2;
|
||||
posP_y += offNP_y * p2;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p3;
|
||||
posN_y -= offNP_y * p3;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p3;
|
||||
posP_y += offNP_y * p3;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p4;
|
||||
posN_y -= offNP_y * p4;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p4;
|
||||
posP_y += offNP_y * p4;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p5;
|
||||
posN_y -= offNP_y * p5;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p5;
|
||||
posP_y += offNP_y * p5;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p6;
|
||||
posN_y -= offNP_y * p6;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p6;
|
||||
posP_y += offNP_y * p6;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p7;
|
||||
posN_y -= offNP_y * p7;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p7;
|
||||
posP_y += offNP_y * p7;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p8;
|
||||
posN_y -= offNP_y * p8;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p8;
|
||||
posP_y += offNP_y * p8;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p9;
|
||||
posN_y -= offNP_y * p9;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p9;
|
||||
posP_y += offNP_y * p9;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p10;
|
||||
posN_y -= offNP_y * p10;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p10;
|
||||
posP_y += offNP_y * p10;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p11;
|
||||
posN_y -= offNP_y * p11;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p11;
|
||||
posP_y += offNP_y * p11;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dstN = posM_x - posN_x;
|
||||
dstP = posP_x - posM_x;
|
||||
if(!horzSpan) {
|
||||
dstN = posM_y - posN_y;
|
||||
dstP = posP_y - posM_y;
|
||||
}
|
||||
|
||||
lumaEndN -= lumaNN * 0.5f;
|
||||
lumaEndP -= lumaNN * 0.5f;
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p1;
|
||||
posN_y -= offNP_y * p1;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p1;
|
||||
posP_y += offNP_y * p1;
|
||||
}
|
||||
goodSpanN = ((lumaEndN < 0.0f) ? 1:0) != lumaMLTZero ? 1:0;
|
||||
spanLength = (dstP + dstN);
|
||||
goodSpanP = ((lumaEndP < 0.0f) ? 1:0) != lumaMLTZero ? 1:0;
|
||||
spanLengthRcp = 1.0f/spanLength;
|
||||
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x, posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p2;
|
||||
posN_y -= offNP_y * p2;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p2;
|
||||
posP_y += offNP_y * p2;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p3;
|
||||
posN_y -= offNP_y * p3;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p3;
|
||||
posP_y += offNP_y * p3;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p4;
|
||||
posN_y -= offNP_y * p4;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p4;
|
||||
posP_y += offNP_y * p4;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p5;
|
||||
posN_y -= offNP_y * p5;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p5;
|
||||
posP_y += offNP_y * p5;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p6;
|
||||
posN_y -= offNP_y * p6;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p6;
|
||||
posP_y += offNP_y * p6;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p7;
|
||||
posN_y -= offNP_y * p7;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p7;
|
||||
posP_y += offNP_y * p7;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p8;
|
||||
posN_y -= offNP_y * p8;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p8;
|
||||
posP_y += offNP_y * p8;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p9;
|
||||
posN_y -= offNP_y * p9;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p9;
|
||||
posP_y += offNP_y * p9;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p10;
|
||||
posN_y -= offNP_y * p10;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p10;
|
||||
posP_y += offNP_y * p10;
|
||||
}
|
||||
if(doneNP) {
|
||||
if(!doneN) {
|
||||
lumaEndN = get_pixel_intensity_bilinear(buf, buf_x, buf_y,posN_x,posN_y);
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = get_pixel_intensity_bilinear(buf, buf_x, buf_y, posP_x,posP_y);
|
||||
}
|
||||
if(!doneN) {
|
||||
lumaEndN = lumaEndN - lumaNN * 0.5;
|
||||
}
|
||||
if(!doneP) {
|
||||
lumaEndP = lumaEndP - lumaNN * 0.5;
|
||||
}
|
||||
doneN = (ABS(lumaEndN)) >= gradientScaled ? 1:0;
|
||||
doneP = (ABS(lumaEndP)) >= gradientScaled ? 1:0;
|
||||
if(!doneN) {
|
||||
posN_x -= offNP_x * p11;
|
||||
posN_y -= offNP_y * p11;
|
||||
}
|
||||
doneNP = (!doneN) || (!doneP) ? 1:0;
|
||||
if(!doneP) {
|
||||
posP_x += offNP_x * p11;
|
||||
posP_y += offNP_y * p11;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dstN = posM_x - posN_x;
|
||||
dstP = posP_x - posM_x;
|
||||
if(!horzSpan) {
|
||||
dstN = posM_y - posN_y;
|
||||
dstP = posP_y - posM_y;
|
||||
}
|
||||
directionN = dstN < dstP ? 1:0;
|
||||
dst = MIN2(dstN, dstP);
|
||||
goodSpan = (directionN==1) ? goodSpanN:goodSpanP;
|
||||
subpixG = subpixF * subpixF;
|
||||
pixelOffset = (dst * (-spanLengthRcp)) + 0.5f;
|
||||
subpixH = subpixG * quality_subpix;
|
||||
|
||||
goodSpanN = ((lumaEndN < 0.0f) ? 1:0) != lumaMLTZero ? 1:0;
|
||||
spanLength = (dstP + dstN);
|
||||
goodSpanP = ((lumaEndP < 0.0f) ? 1:0) != lumaMLTZero ? 1:0;
|
||||
spanLengthRcp = 1.0f/spanLength;
|
||||
|
||||
directionN = dstN < dstP ? 1:0;
|
||||
dst = MIN2(dstN, dstP);
|
||||
goodSpan = (directionN==1) ? goodSpanN:goodSpanP;
|
||||
subpixG = subpixF * subpixF;
|
||||
pixelOffset = (dst * (-spanLengthRcp)) + 0.5f;
|
||||
subpixH = subpixG * quality_subpix;
|
||||
|
||||
pixelOffsetGood = (goodSpan==1) ? pixelOffset : 0.0f;
|
||||
pixelOffsetSubpix = MAX2(pixelOffsetGood, subpixH);
|
||||
if(!horzSpan) {
|
||||
posM_x += pixelOffsetSubpix * lengthSign;
|
||||
}
|
||||
else {
|
||||
posM_y += pixelOffsetSubpix * lengthSign;
|
||||
}
|
||||
//may need bilinear filtered get_pixel_intensity() here...
|
||||
set_pixel_intensity(buf,buf_x,buf_y,curr_x,curr_y,get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x,posM_y)* lumaM);
|
||||
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
pixelOffsetGood = (goodSpan==1) ? pixelOffset : 0.0f;
|
||||
pixelOffsetSubpix = MAX2(pixelOffsetGood, subpixH);
|
||||
if(!horzSpan) {
|
||||
posM_x += pixelOffsetSubpix * lengthSign;
|
||||
} else {
|
||||
posM_y += pixelOffsetSubpix * lengthSign;
|
||||
}
|
||||
//may need bilinear filtered get_pixel_intensity() here...
|
||||
set_pixel_intensity(buf,buf_x,buf_y,curr_x,curr_y,get_pixel_intensity_bilinear(buf, buf_x, buf_y, posM_x,posM_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SWAP_POLYVERT(a,b) ptemp[0]=(a)[0]; ptemp[1]=(a)[1]; (a)[0]=(b)[0]; (a)[1]=(b)[1]; (b)[0]=ptemp[0]; (b)[1]=ptemp[1];
|
||||
#define __PLX_SMALL_COUNT__ 13
|
||||
void plx_floatsort(float(*f)[2], unsigned int n, int sortby) {
|
||||
unsigned int i;
|
||||
unsigned int ir;
|
||||
unsigned int j;
|
||||
unsigned int k;
|
||||
unsigned int l=1;
|
||||
unsigned int istack[50];
|
||||
int jstack=0;
|
||||
float a[2];
|
||||
float ptemp[2];
|
||||
|
||||
ir=n;
|
||||
for(;;) {
|
||||
if(ir-l < __PLX_SMALL_COUNT__) {
|
||||
for(j=l+1; j<=ir; j++) {
|
||||
a[1]=f[j][1];
|
||||
a[0]=f[j][0];
|
||||
for(i=j-1; i>=l; i--) {
|
||||
if(f[i][sortby] <= a[sortby]) {
|
||||
break;
|
||||
}
|
||||
f[i+1][1]=f[i][1];
|
||||
f[i+1][0]=f[i][0];
|
||||
}
|
||||
f[i+1][1]=a[1];
|
||||
f[i+1][0]=a[0];
|
||||
}
|
||||
if(jstack < 0) {
|
||||
break;
|
||||
}
|
||||
ir=istack[jstack--];
|
||||
l=istack[jstack--];
|
||||
} else {
|
||||
k=(l+ir) >> 1;
|
||||
SWAP_POLYVERT(f[k],f[l+1])
|
||||
if(f[l][sortby] > f[ir][sortby]) {
|
||||
SWAP_POLYVERT(f[l],f[ir])
|
||||
}
|
||||
if(f[l+1][sortby] > f[ir][sortby]) {
|
||||
SWAP_POLYVERT(f[l+1],f[ir])
|
||||
}
|
||||
if(f[l][sortby] > f[l+1][sortby]) {
|
||||
SWAP_POLYVERT(f[l],f[l+1])
|
||||
}
|
||||
i=l+1;
|
||||
j=ir;
|
||||
a[0]=f[l+1][0];
|
||||
a[1]=f[l+1][1];
|
||||
for(;;) {
|
||||
do i++;
|
||||
while(f[i][sortby] < a[sortby]);
|
||||
do j--;
|
||||
while(f[j][sortby] > a[sortby]);
|
||||
if(j < i) {
|
||||
break;
|
||||
}
|
||||
SWAP_POLYVERT(f[i],f[j])
|
||||
}
|
||||
f[l+1][0]=f[j][0];
|
||||
f[l+1][1]=f[j][1];
|
||||
f[j][0]=a[0];
|
||||
f[j][1]=a[1];
|
||||
jstack+=2;
|
||||
if(jstack > __PLX_SMALL_COUNT__) {
|
||||
return;
|
||||
}
|
||||
if(ir-i+1 >= j-l) {
|
||||
istack[jstack]=ir;
|
||||
istack[jstack-1]=i;
|
||||
ir=j-1;
|
||||
} else {
|
||||
istack[jstack]=j-1;
|
||||
istack[jstack-1]=l;
|
||||
l=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int plx_find_lower_bound(float v, float(*a)[2], int num_feather_verts) {
|
||||
int x;
|
||||
int l;
|
||||
int r;
|
||||
l=1;
|
||||
r=num_feather_verts;
|
||||
for(;;) {
|
||||
// interpolation style search
|
||||
//x=l+(v-a[l][1])*(r-l) / (a[r][1]-a[l][1]);
|
||||
|
||||
// binary search
|
||||
x=(l+r) / 2;
|
||||
if(v<a[x][1]) {
|
||||
r=x-1;
|
||||
} else {
|
||||
l=x+1;
|
||||
}
|
||||
if((v>a[x-1][1] && v <= a[x][1]) || l>r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(v>a[x-1][1] && v <= a[x][1]) {
|
||||
return x;
|
||||
} else {
|
||||
return num_feather_verts;
|
||||
}
|
||||
}
|
||||
|
||||
int plx_find_upper_bound(float v, float(*a)[2], int num_feather_verts) {
|
||||
int x;
|
||||
int l;
|
||||
int r;
|
||||
l=1;
|
||||
r=num_feather_verts;
|
||||
for(;;) {
|
||||
// interpolation style search
|
||||
//x=l+(v-a[l][1])*(r-l) / (a[r][1]-a[l][1]);
|
||||
|
||||
// binary search
|
||||
x=(l+r) / 2;
|
||||
if(v<a[x][1]) {
|
||||
r=x-1;
|
||||
} else {
|
||||
l=x+1;
|
||||
}
|
||||
if((v>=a[x-1][1] && v < a[x][1]) || l>r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(v>=a[x-1][1] && v < a[x][1]) {
|
||||
return x-1;
|
||||
} else {
|
||||
return num_feather_verts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,27 +27,64 @@
|
||||
/** \file raskter.h
|
||||
* \ingroup RASKTER
|
||||
*/
|
||||
/* from BLI_utildefines.h */
|
||||
#define MIN2(x, y) ( (x) < (y) ? (x) : (y) )
|
||||
#define MAX2(x, y) ( (x) > (y) ? (x) : (y) )
|
||||
#define ABS(a) ( (a) < 0 ? (-(a)) : (a) )
|
||||
|
||||
struct poly_vert {
|
||||
int x;
|
||||
int y;
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct scan_line {
|
||||
int xstart;
|
||||
int xend;
|
||||
int xstart;
|
||||
int xend;
|
||||
};
|
||||
|
||||
struct scan_line_batch {
|
||||
int num;
|
||||
int ystart;
|
||||
struct scan_line *slines;
|
||||
int num;
|
||||
int ystart;
|
||||
struct scan_line *slines;
|
||||
};
|
||||
|
||||
struct e_status {
|
||||
int x;
|
||||
int ybeg;
|
||||
int xshift;
|
||||
int xdir;
|
||||
int drift;
|
||||
int drift_inc;
|
||||
int drift_dec;
|
||||
int num;
|
||||
struct e_status *e_next;
|
||||
};
|
||||
|
||||
struct r_buffer_stats {
|
||||
float *buf;
|
||||
int sizex;
|
||||
int sizey;
|
||||
int ymin;
|
||||
int ymax;
|
||||
int xmin;
|
||||
int xmax;
|
||||
};
|
||||
|
||||
struct r_fill_context {
|
||||
struct e_status *all_edges, *possible_edges;
|
||||
struct r_buffer_stats rb;
|
||||
struct scan_line *bounds;
|
||||
void *kdo; //only used with kd tree
|
||||
void *kdi; //only used with kd tree
|
||||
int *bound_indexes;
|
||||
int bounds_length;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static void preprocess_all_edges(struct r_fill_context *ctx, struct poly_vert *verts, int num_verts, struct e_status *open_edge);
|
||||
int PLX_raskterize(float (*base_verts)[2], int num_base_verts,
|
||||
float *buf, int buf_x, int buf_y, int do_mask_AA);
|
||||
int PLX_raskterize_feather(float (*base_verts)[2], int num_base_verts,
|
||||
|
||||
290
intern/raskter/raskter_mt.c
Normal file
290
intern/raskter/raskter_mt.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2012 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Peter Larabell.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
/** \file raskter_mt.c
|
||||
* \ingroup RASKTER
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "raskter.h"
|
||||
static int rast_scan_init(struct r_fill_context *ctx, struct poly_vert *verts, int num_verts) {
|
||||
int x_curr; /* current pixel position in X */
|
||||
int y_curr; /* current scan line being drawn */
|
||||
int yp; /* y-pixel's position in frame buffer */
|
||||
int swixd = 0; /* whether or not edges switched position in X */
|
||||
int i=0; /* counter */
|
||||
float *cpxl; /* pixel pointers... */
|
||||
float *mpxl;
|
||||
float *spxl;
|
||||
struct e_status *e_curr; /* edge pointers... */
|
||||
struct e_status *e_temp;
|
||||
struct e_status *edgbuf;
|
||||
struct e_status **edgec;
|
||||
|
||||
|
||||
if(num_verts < 3) {
|
||||
return(1);
|
||||
}
|
||||
|
||||
if((edgbuf = (struct e_status *)(malloc(sizeof(struct e_status) * num_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* set initial bounds length to 0 */
|
||||
ctx->bounds_length=0;
|
||||
|
||||
/* round 1, count up all the possible spans in the base buffer */
|
||||
preprocess_all_edges(ctx, verts, num_verts, edgbuf);
|
||||
|
||||
/* can happen with a zero area mask */
|
||||
if (ctx->all_edges == NULL) {
|
||||
free(edgbuf);
|
||||
return(1);
|
||||
}
|
||||
ctx->possible_edges = NULL;
|
||||
|
||||
for(y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
|
||||
|
||||
for(edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr);) {
|
||||
x_curr = ctx->all_edges->x; /* Set current X position. */
|
||||
for(;;) { /* Start looping edges. Will break when edges run out. */
|
||||
e_curr = *edgec; /* Set up a current edge pointer. */
|
||||
if(!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
|
||||
e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
|
||||
*edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
|
||||
ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
|
||||
edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
|
||||
ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
|
||||
break; /* Stop looping edges (since we ran out or hit empty X span. */
|
||||
} else {
|
||||
edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yp = y_curr * ctx->rb.sizex;
|
||||
spxl = ctx->rb.buf + (yp);
|
||||
|
||||
for(e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
|
||||
|
||||
/* set up xmin and xmax bounds on this scan line */
|
||||
cpxl = spxl + MAX2(e_curr->x, 0);
|
||||
e_curr = e_curr->e_next;
|
||||
mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
|
||||
|
||||
if((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
|
||||
ctx->bounds_length++;
|
||||
}
|
||||
}
|
||||
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec);) {
|
||||
if(!(--(e_curr->num))) {
|
||||
*edgec = e_curr->e_next;
|
||||
} else {
|
||||
e_curr->x += e_curr->xshift;
|
||||
if((e_curr->drift += e_curr->drift_inc) > 0) {
|
||||
e_curr->x += e_curr->xdir;
|
||||
e_curr->drift -= e_curr->drift_dec;
|
||||
}
|
||||
edgec = &e_curr->e_next;
|
||||
}
|
||||
}
|
||||
if(ctx->possible_edges) {
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* set flag that we had at least one switch */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we did have a switch, look for more (there will more if there was one) */
|
||||
for(;;) {
|
||||
/* reset exchange flag so it's only set if we encounter another one */
|
||||
swixd = 0;
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* again, if current edge hits scan line at higher X than next edge, exchange the edges and set flag */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* flip the exchanged flag */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we had no exchanges, we're done reshuffling the pointers */
|
||||
if(!swixd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*initialize index buffer and bounds buffers*/
|
||||
//gets the +1 for dummy at the end
|
||||
if((ctx->bound_indexes = (int *)(malloc(sizeof(int) * ctx->rb.sizey+1)))==NULL) {
|
||||
return(0);
|
||||
}
|
||||
//gets the +1 for dummy at the start
|
||||
if((ctx->bounds = (struct scan_line *)(malloc(sizeof(struct scan_line) * ctx->bounds_length+1)))==NULL){
|
||||
return(0);
|
||||
}
|
||||
//init all the indexes to zero (are they already zeroed from malloc???)
|
||||
for(i=0;i<ctx->rb.sizey+1;i++){
|
||||
ctx->bound_indexes[i]=0;
|
||||
}
|
||||
/* round 2, fill in the full list of bounds, and create indexes to the list... */
|
||||
preprocess_all_edges(ctx, verts, num_verts, edgbuf);
|
||||
|
||||
/* can happen with a zero area mask */
|
||||
if (ctx->all_edges == NULL) {
|
||||
free(edgbuf);
|
||||
return(1);
|
||||
}
|
||||
ctx->possible_edges = NULL;
|
||||
|
||||
/* restart i as a counter for total span placement in buffer */
|
||||
i=1;
|
||||
for(y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
|
||||
|
||||
for(edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr);) {
|
||||
x_curr = ctx->all_edges->x; /* Set current X position. */
|
||||
for(;;) { /* Start looping edges. Will break when edges run out. */
|
||||
e_curr = *edgec; /* Set up a current edge pointer. */
|
||||
if(!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
|
||||
e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
|
||||
*edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
|
||||
ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
|
||||
edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
|
||||
ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
|
||||
break; /* Stop looping edges (since we ran out or hit empty X span. */
|
||||
} else {
|
||||
edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yp = y_curr * ctx->rb.sizex;
|
||||
spxl = ctx->rb.buf + (yp);
|
||||
if((y_curr >=0) && (y_curr < ctx->rb.sizey)){
|
||||
ctx->bound_indexes[y_curr]=i;
|
||||
}
|
||||
for(e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
|
||||
|
||||
/* set up xmin and xmax bounds on this scan line */
|
||||
cpxl = spxl + MAX2(e_curr->x, 0);
|
||||
e_curr = e_curr->e_next;
|
||||
mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
|
||||
|
||||
if((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
|
||||
ctx->bounds[i].xstart=cpxl-spxl;
|
||||
ctx->bounds[i].xend=mpxl-spxl;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec);) {
|
||||
if(!(--(e_curr->num))) {
|
||||
*edgec = e_curr->e_next;
|
||||
} else {
|
||||
e_curr->x += e_curr->xshift;
|
||||
if((e_curr->drift += e_curr->drift_inc) > 0) {
|
||||
e_curr->x += e_curr->xdir;
|
||||
e_curr->drift -= e_curr->drift_dec;
|
||||
}
|
||||
edgec = &e_curr->e_next;
|
||||
}
|
||||
}
|
||||
if(ctx->possible_edges) {
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* set flag that we had at least one switch */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we did have a switch, look for more (there will more if there was one) */
|
||||
for(;;) {
|
||||
/* reset exchange flag so it's only set if we encounter another one */
|
||||
swixd = 0;
|
||||
for(edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
|
||||
/* again, if current edge hits scan line at higher X than next edge, exchange the edges and set flag */
|
||||
if(e_curr->x > e_curr->e_next->x) {
|
||||
*edgec = e_curr->e_next;
|
||||
/* exchange the pointers */
|
||||
e_temp = e_curr->e_next->e_next;
|
||||
e_curr->e_next->e_next = e_curr;
|
||||
e_curr->e_next = e_temp;
|
||||
/* flip the exchanged flag */
|
||||
swixd = 1;
|
||||
}
|
||||
}
|
||||
/* if we had no exchanges, we're done reshuffling the pointers */
|
||||
if(!swixd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(edgbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void init_base_data(float(*base_verts)[2], int num_base_verts,
|
||||
float *buf, int buf_x, int buf_y) {
|
||||
int i; /* i: Loop counter. */
|
||||
struct poly_vert *ply; /* ply: Pointer to a list of integer buffer-space vertex coordinates. */
|
||||
struct r_fill_context ctx = {0};
|
||||
const float buf_x_f = (float)(buf_x);
|
||||
const float buf_y_f = (float)(buf_y);
|
||||
if((ply = (struct poly_vert *)(malloc(sizeof(struct poly_vert) * num_base_verts))) == NULL) {
|
||||
return(0);
|
||||
}
|
||||
ctx.rb.buf = buf; /* Set the output buffer pointer. */
|
||||
ctx.rb.sizex = buf_x; /* Set the output buffer size in X. (width) */
|
||||
ctx.rb.sizey = buf_y; /* Set the output buffer size in Y. (height) */
|
||||
for(i = 0; i < num_base_verts; i++) { /* Loop over all base_verts. */
|
||||
ply[i].x = (int)((base_verts[i][0] * buf_x_f) + 0.5f); /* Range expand normalized X to integer buffer-space X. */
|
||||
ply[i].y = (int)((base_verts[i][1] * buf_y_f) + 0.5f); /* Range expand normalized Y to integer buffer-space Y. */
|
||||
}
|
||||
i = rast_scan_init(&ctx, ply, num_base_verts); /* Call our rasterizer, passing in the integer coords for each vert. */
|
||||
free(ply); /* Free the memory allocated for the integer coordinate table. */
|
||||
return(i); /* Return the value returned by the rasterizer. */
|
||||
}
|
||||
|
||||
@@ -2219,7 +2219,7 @@ void BKE_mask_rasterize_layers(ListBase *masklayers, int width, int height, floa
|
||||
|
||||
if (tot_diff_point) {
|
||||
PLX_raskterize(diff_points, tot_diff_point,
|
||||
buffer_tmp, width, height, do_mask_aa);
|
||||
buffer_tmp, width, height,do_mask_aa);
|
||||
|
||||
if (tot_diff_feather_points) {
|
||||
PLX_raskterize_feather(diff_points, tot_diff_point,
|
||||
@@ -2273,10 +2273,12 @@ void BKE_mask_rasterize_layers(ListBase *masklayers, int width, int height, floa
|
||||
}
|
||||
}
|
||||
|
||||
if(do_mask_aa){
|
||||
//PLX_antialias_buffer(buffer,width,height);
|
||||
}
|
||||
/* clamp at the end */
|
||||
clamp_vn_vn(buffer, buffer_size);
|
||||
}
|
||||
|
||||
MEM_freeN(buffer_tmp);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user