Math-3Space
view release on metacpan or search on metacpan
m3s_space_t *space
SV *x_or_vec
SV *y
SV *z
ALIAS:
Math::3Space::yv = 1
Math::3Space::zv = 2
Math::3Space::origin = 3
INIT:
NV *vec= space->mat + ix * 3;
PPCODE:
if (x_or_vec) {
M3S_VECLOAD(vec,x_or_vec,y,z,0);
if (ix < 3) space->is_normal= -1;
// leave $self on stack as return value
} else {
ST(0)= sv_2mortal(m3s_wrap_vector(vec));
}
XSRETURN(1);
bool
RETVAL= m3s_get_magic_space(space, OR_DIE)->n_parents;
OUTPUT:
RETVAL
void
reparent(space, parent)
SV *space
SV *parent
INIT:
m3s_space_t *sp3= m3s_get_magic_space(space, OR_DIE), *psp3=NULL, *cur;
PPCODE:
m3s_space_recache_parent(space);
if (SvOK(parent)) {
psp3= m3s_get_magic_space(parent, OR_DIE);
m3s_space_recache_parent(parent);
// Make sure this doesn't create a cycle
for (cur= psp3; cur; cur= cur->parent)
if (cur == sp3)
croak("Attempt to create a cycle: new 'parent' is a child of this space");
}
m3s_space_reparent(sp3, psp3);
m3s_space_t *space
SV *x_or_vec
SV *y
SV *z
ALIAS:
Math::3Space::tr = 0
Math::3Space::travel = 1
Math::3Space::go = 1
INIT:
NV vec[3], *matp;
PPCODE:
M3S_VECLOAD(vec,x_or_vec,y,z,0);
if (ix) {
matp= space->mat;
matp[9] += vec[0] * matp[0] + vec[1] * matp[3] + vec[2] * matp[6];
++matp;
matp[9] += vec[0] * matp[0] + vec[1] * matp[3] + vec[2] * matp[6];
++matp;
matp[9] += vec[0] * matp[0] + vec[1] * matp[3] + vec[2] * matp[6];
} else {
matp= SPACE_ORIGIN(space);
scale(space, xscale_or_vec, yscale=NULL, zscale=NULL)
m3s_space_t *space
SV *xscale_or_vec
SV *yscale
SV *zscale
ALIAS:
Math::3Space::set_scale = 1
INIT:
NV vec[3], s, m, *matp= SPACE_XV(space);
size_t i;
PPCODE:
if (SvROK(xscale_or_vec) && yscale == NULL) {
m3s_read_vector_from_sv(vec, xscale_or_vec, NULL, NULL);
} else {
vec[0]= SvNV(xscale_or_vec);
vec[1]= yscale? SvNV(yscale) : vec[0];
vec[2]= zscale? SvNV(zscale) : vec[0];
}
for (i= 0; i < 3; i++) {
s= vec[i];
if (ix == 1) {
rotate(space, angle, x_or_vec, y=NULL, z=NULL)
m3s_space_t *space
NV angle
SV *x_or_vec
SV *y
SV *z
INIT:
m3s_vector_t vec;
ALIAS:
Math::3Space::rot = 0
PPCODE:
if (y) {
if (!z) croak("Missing z coordinate in space->rotate(angle, x, y, z)");
vec[0]= SvNV(x_or_vec);
vec[1]= SvNV(y);
vec[2]= SvNV(z);
} else {
m3s_read_vector_from_sv(vec, x_or_vec, NULL, NULL);
}
m3s_space_rotate(space, sin(angle * 2 * M_PI), cos(angle * 2 * M_PI), vec);
// return $self
ALIAS:
Math::3Space::rot_y = 1
Math::3Space::rot_z = 2
Math::3Space::rot_xv = 3
Math::3Space::rot_yv = 4
Math::3Space::rot_zv = 5
INIT:
NV *matp, tmp1, tmp2;
size_t ofs1, ofs2;
NV s= sin(angle * 2 * M_PI), c= cos(angle * 2 * M_PI);
PPCODE:
if (ix < 3) // Rotate around axis of parent
m2s_space_parent_axis_rotate(space, s, c, ix);
else
m3s_space_self_axis_rotate(space, s, c, ix - 3);
XSRETURN(1);
void
project_vector(space, ...)
m3s_space_t *space
INIT:
m3s_vector_t vec;
int i, vectype, count;
AV *vec_av;
HV *vec_hv;
SV *pdl_origin= NULL, *pdl_matrix= NULL;
size_t pdl_dims[3];
ALIAS:
Math::3Space::project = 1
Math::3Space::unproject_vector = 2
Math::3Space::unproject = 3
PPCODE:
for (i= 1; i < items; i++) {
vectype= m3s_read_vector_from_sv(vec, ST(i), pdl_dims, NULL);
if (vectype == M3S_VECTYPE_PDLMULTI) {
dSP;
if (!pdl_origin) {
pdl_origin= sv_2mortal(m3s_pdl_vector(SPACE_ORIGIN(space), 3));
pdl_matrix= sv_2mortal(m3s_pdl_matrix(SPACE_XV(space), !(ix&2) /*transpose bool*/));
}
ENTER;
SAVETMPS;
size_t i, j, n;
int vectype;
AV *vec_av;
SV **item, *x, *y, *z, *pdl_origin= NULL, *pdl_matrix= NULL;
size_t pdl_dims[3];
SV *component_sv[3];
ALIAS:
Math::3Space::project_inplace = 1
Math::3Space::unproject_vector_inplace = 2
Math::3Space::unproject_inplace = 3
PPCODE:
for (i= 1; i < items; i++) {
if (!SvROK(ST(i)))
croak("Expected vector at $_[%d]", (int)(i-1));
vectype= m3s_read_vector_from_sv(vec, ST(i), pdl_dims, component_sv);
switch (vectype) {
case M3S_VECTYPE_VECOBJ:
vecp= m3s_vector_get_array(ST(i));
switch (ix) {
case 0: m3s_space_project_vector(space, vecp); break;
case 1: m3s_space_project_point(space, vecp); break;
// return $self
XSRETURN(1);
void
get_gl_matrix(space, buffer=NULL)
m3s_space_t *space
SV *buffer
INIT:
NV *src;
double *dst;
PPCODE:
if (buffer) {
dst= (double*) m3s_make_aligned_buffer(buffer, sizeof(double)*16);
src= space->mat;
dst[ 0] = src[ 0]; dst[ 1] = src[ 1]; dst[ 2] = src[ 2]; dst[ 3] = 0;
dst[ 4] = src[ 3]; dst[ 5] = src[ 4]; dst[ 6] = src[ 5]; dst[ 7] = 0;
dst[ 8] = src[ 6]; dst[ 9] = src[ 7]; dst[10] = src[ 8]; dst[11] = 0;
dst[12] = src[ 9]; dst[13] = src[10]; dst[14] = src[11]; dst[15] = 1;
XSRETURN(0);
} else {
EXTEND(SP, 16);
matrix_colmajor(proj, space=NULL)
m3s_4space_projection_t *proj
m3s_space_t *space
ALIAS:
get_gl_matrix = 0
matrix_pack_float = 1
matrix_pack_double = 2
INIT:
double dst[16];
struct m3s_4space_frustum_projection *f= &proj->frustum;
PPCODE:
if (!space) { /* user just wants the matrix itself */
dst[ 0]= f->m00; dst[ 4]= 0; dst[ 8]= f->m20; dst[12]= 0;
dst[ 1]= 0; dst[ 5]= f->m11; dst[ 9]= f->m21; dst[13]= 0;
dst[ 2]= 0; dst[ 6]= 0; dst[10]= f->m22; dst[14]= f->m32;
dst[ 3]= 0; dst[ 7]= 0; dst[11]= -1; dst[15]= 0;
}
else if (proj->frustum.centered) { /* centered frustum, optimize by assuming m20 and m21 are zero */
dst[ 0]= f->m00 * SPACE_XV(space)[0];
dst[ 1]= f->m11 * SPACE_XV(space)[1];
dst[ 2]= f->m22 * SPACE_XV(space)[2];
OUTPUT:
RETVAL
void
x(vec, newval=NULL)
m3s_vector_p vec
SV *newval
ALIAS:
Math::3Space::Vector::y = 1
Math::3Space::Vector::z = 2
PPCODE:
if (newval) {
vec[ix]= SvNV(newval);
} else {
ST(0)= sv_2mortal(newSVnv(vec[ix]));
}
XSRETURN(1);
void
xyz(vec)
m3s_vector_p vec
PPCODE:
EXTEND(SP, 3);
PUSHs(sv_2mortal(newSVnv(vec[0])));
PUSHs(sv_2mortal(newSVnv(vec[1])));
PUSHs(sv_2mortal(newSVnv(vec[2])));
void
magnitude(vec, scale=NULL)
m3s_vector_p vec
SV *scale
INIT:
NV s, m= sqrt(m3s_vector_dotprod(vec,vec));
PPCODE:
if (scale) {
if (m > 0) {
s= SvNV(scale) / m;
vec[0] *= s;
vec[1] *= s;
vec[2] *= s;
} else
warn("can't scale magnitude=0 vector");
// return $self
} else {
set(vec1, vec2_or_x, y=NULL, z=NULL)
m3s_vector_p vec1
SV *vec2_or_x
SV *y
SV *z
ALIAS:
Math::3Space::Vector::add = 1
Math::3Space::Vector::sub = 2
INIT:
NV vec2[3];
PPCODE:
M3S_VECLOAD(vec2,vec2_or_x,y,z,0);
if (ix == 0) {
vec1[0]= vec2[0];
vec1[1]= vec2[1];
vec1[2]= vec2[2];
} else if (ix == 1) {
vec1[0]+= vec2[0];
vec1[1]+= vec2[1];
vec1[2]+= vec2[2];
} else {
XSRETURN(1);
void
scale(vec1, vec2_or_x, y=NULL, z=NULL)
m3s_vector_p vec1
SV *vec2_or_x
SV *y
SV *z
INIT:
NV vec2[3];
PPCODE:
// single value should be treated as ($x,$x,$x) instead of ($x,0,0)
if (looks_like_number(vec2_or_x)) {
vec2[0]= SvNV(vec2_or_x);
vec2[1]= y? SvNV(y) : vec2[0];
vec2[2]= z? SvNV(z) : y? 1 : vec2[0];
}
else {
m3s_read_vector_from_sv(vec2, vec2_or_x, NULL, NULL);
}
vec1[0]*= vec2[0];
RETVAL
void
cross(vec1, vec2_or_x, vec3_or_y=NULL, z=NULL)
m3s_vector_p vec1
SV *vec2_or_x
SV *vec3_or_y
SV *z
INIT:
m3s_vector_t vec2, vec3;
PPCODE:
if (!vec3_or_y) { // RET = vec1->cross(vec2)
m3s_read_vector_from_sv(vec2, vec2_or_x, NULL, NULL);
m3s_vector_cross(vec3, vec1, vec2);
ST(0)= sv_2mortal(m3s_wrap_vector(vec3));
} else if (z || !SvROK(vec2_or_x) || looks_like_number(vec2_or_x)) { // RET = vec1->cross(x,y,z)
vec2[0]= SvNV(vec2_or_x);
vec2[1]= SvNV(vec3_or_y);
vec2[2]= z? SvNV(z) : 0;
m3s_vector_cross(vec3, vec1, vec2);
ST(0)= sv_2mortal(m3s_wrap_vector(vec3));
( run in 0.597 second using v1.01-cache-2.11-cpan-5511b514fd6 )