layer1/Extrude.cpp (1,934 lines of code) (raw):
/*
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information.
H* --------------------------------------------------\-----------------
I* Additional authors of this source file include:
-* Cameron Mura
-*
-*
Z* -------------------------------------------------------------------
*/
#include"os_predef.h"
#include"os_std.h"
#include"os_gl.h"
#include"Extrude.h"
#include"Base.h"
#include"OOMac.h"
#include"Setting.h"
#include"Feedback.h"
void ExtrudeInit(PyMOLGlobals * G, CExtrude * I);
#define CopyArray(dst,src,type,count) memcpy(dst,src,sizeof(type)*(count))
CExtrude *ExtrudeCopyPointsNormalsColors(CExtrude * orig)
{
int ok = true;
OOAlloc(orig->G, CExtrude);
CHECKOK(ok, I);
if (ok)
ExtrudeInit(orig->G, I);
if (ok)
ok &= ExtrudeAllocPointsNormalsColors(I, orig->N);
if (ok){
CopyArray(I->p, orig->p, float, 3 * I->N);
CopyArray(I->n, orig->n, float, 9 * I->N);
CopyArray(I->c, orig->c, float, 3 * I->N);
CopyArray(I->alpha, orig->alpha, float, I->N);
CopyArray(I->i, orig->i, unsigned int, I->N);
CopyArray(I->sf, orig->sf, float, I->N); /* PUTTY: scale factors */
} else {
ExtrudeFree(I);
I = NULL;
}
return (I);
}
void ExtrudeInit(PyMOLGlobals * G, CExtrude * I)
{
I->G = G;
I->N = 0;
I->p = NULL;
I->n = NULL;
I->c = NULL;
I->alpha = nullptr;
I->i = NULL;
I->sv = NULL; /* shape vertices */
I->sn = NULL; /* shape normals */
I->tv = NULL; /* transformed vertices */
I->tn = NULL; /* transformed normals */
I->Ns = 0; /* number of shape points */
I->sf = NULL;
}
int ExtrudeCircle(CExtrude * I, int n, float size)
{
int a;
float *v, *vn;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCircle-DEBUG: entered.\n" ENDFD;
/*
if(n > 50)
n = 50;*/
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->sv);
if (ok)
I->sn = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->sn);
if (ok)
I->tv = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->tv);
if (ok)
I->tn = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->tn);
if (ok){
I->Ns = n;
I->r = size;
v = I->sv;
vn = I->sn;
for(a = 0; a <= n; a++) {
*(vn++) = 0.0;
*(vn++) = (float) cos(a * 2 * PI / n);
*(vn++) = (float) sin(a * 2 * PI / n);
*(v++) = 0.0;
*(v++) = (float) cos(a * 2 * PI / n) * size;
*(v++) = (float) sin(a * 2 * PI / n) * size;
}
}
if (!ok){
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = NULL;
I->sn = NULL;
I->tv = NULL;
I->tn = NULL;
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeCircle-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeOval(CExtrude * I, int n, float width, float length)
{
int a;
float *v, *vn;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeOval-DEBUG: entered.\n" ENDFD;
/* if(n > 50)
n = 50;*/
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->sv);
if (ok)
I->sn = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->sn);
if (ok)
I->tv = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->tv);
if (ok)
I->tn = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->tn);
I->Ns = n;
v = I->sv;
vn = I->sn;
for(a = 0; a <= n; a++) {
*(vn++) = 0.0;
*(vn++) = (float) cos(a * 2 * PI / n) * length;
*(vn++) = (float) sin(a * 2 * PI / n) * width;
*(v++) = 0.0;
*(v++) = (float) cos(a * 2 * PI / n) * width;
*(v++) = (float) sin(a * 2 * PI / n) * length;
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeOval-DEBUG: exiting...\n" ENDFD;
if (!ok){
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
}
return ok;
}
int ExtrudeRectangle(CExtrude * I, float width, float length, int mode)
{
float *v, *vn;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeRectangle-DEBUG: entered...\n" ENDFD;
switch (mode) {
case 0:
I->Ns = 8;
break;
default:
I->Ns = 4;
break;
}
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->sv);
if (ok)
I->sn = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->sn);
if (ok)
I->tv = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->tv);
if (ok)
I->tn = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->tn);
if (!ok){
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = NULL;
I->sn = NULL;
I->tv = NULL;
I->tn = NULL;
return ok;
}
v = I->sv;
vn = I->sn;
if((!mode) || (mode == 1)) {
*(vn++) = 0.0;
*(vn++) = 1.0;
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = 1.0;
*(vn++) = 0.0;
*(v++) = 0.0;
*(v++) = (float) cos(PI / 4) * width;
*(v++) = (float) -sin(PI / 4) * length;
*(v++) = 0.0;
*(v++) = (float) cos(PI / 4) * width;
*(v++) = (float) sin(PI / 4) * length;
}
if((!mode) || (mode == 2)) {
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = 1.0;
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = 1.0;
*(v++) = 0.0;
*(v++) = (float) cos(PI / 4) * width;
*(v++) = (float) sin(PI / 4) * length;
*(v++) = 0.0;
*(v++) = (float) -cos(PI / 4) * width;
*(v++) = (float) sin(PI / 4) * length;
}
if((!mode) || (mode == 1)) {
*(vn++) = 0.0;
*(vn++) = -1.0;
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = -1.0;
*(vn++) = 0.0;
*(v++) = 0.0;
*(v++) = (float) -cos(PI / 4) * width;
*(v++) = (float) sin(PI / 4) * length;
*(v++) = 0.0;
*(v++) = (float) -cos(PI / 4) * width;
*(v++) = (float) -sin(PI / 4) * length;
}
if((!mode) || (mode == 2)) {
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = -1.0;
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = -1.0;
*(v++) = 0.0;
*(v++) = (float) -cos(PI / 4) * width;
*(v++) = (float) -sin(PI / 4) * length;
*(v++) = 0.0;
*(v++) = (float) cos(PI / 4) * width;
*(v++) = (float) -sin(PI / 4) * length;
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeRectangle-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeDumbbell1(CExtrude * I, float width, float length, int mode)
{
float *v, *vn;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeDumbbell1-DEBUG: entered...\n" ENDFD;
switch (mode) {
case 0:
I->Ns = 4;
break;
default:
I->Ns = 2;
break;
}
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->sv);
if (ok)
I->sn = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->sn);
if (ok)
I->tv = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->tv);
if (ok)
I->tn = Alloc(float, 3 * (I->Ns + 1));
CHECKOK(ok, I->tn);
if (!ok){
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = NULL;
I->sn = NULL;
I->tv = NULL;
I->tn = NULL;
}
v = I->sv;
vn = I->sn;
if((!mode) || (mode == 1)) { /* top */
*(vn++) = 0.0;
*(vn++) = 1.0;
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = 1.0;
*(vn++) = 0.0;
*(v++) = 0.0;
*(v++) = (float) cos(PI / 4) * width;
*(v++) = (float) -sin(PI / 4) * length;
*(v++) = 0.0;
*(v++) = (float) cos(PI / 4) * width;
*(v++) = (float) sin(PI / 4) * length;
}
if((!mode) || (mode == 2)) { /* bottom */
*(vn++) = 0.0;
*(vn++) = -1.0;
*(vn++) = 0.0;
*(vn++) = 0.0;
*(vn++) = -1.0;
*(vn++) = 0.0;
*(v++) = 0.0;
*(v++) = (float) -cos(PI / 4) * width;
*(v++) = (float) sin(PI / 4) * length;
*(v++) = 0.0;
*(v++) = (float) -cos(PI / 4) * width;
*(v++) = (float) -sin(PI / 4) * length;
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeDumbbell1-DEBUG: exiting...\n" ENDFD;
return ok;
}
void ExtrudeDumbbellEdge(CExtrude * I, int samp, int sign, float length)
{
int a;
float *n, *p, f, disp;
PRINTFD(I->G, FB_Extrude)
" ExtrudeDumbbellEdge-DEBUG: entered.\n" ENDFD;
disp = (float) (sign * sin(PI / 4) * length);
p = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
if(a <= samp)
f = disp * smooth((a / ((float) samp)), 2);
else if(a >= (I->N - samp))
f = disp * smooth(((I->N - a - 1) / ((float) samp)), 2);
else
f = disp;
n += 6;
(*p++) += *(n++) * f;
(*p++) += *(n++) * f;
(*p++) += *(n++) * f;
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeDumbbellEdge-DEBUG: exiting...\n" ENDFD;
}
#if 0
int ExtrudeDumbbell2(CExtrude * I, int n, int sign, float length, float size)
{
int a;
float *v, *vn;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeDumbbell2-DEBUG: entered.\n" ENDFD;
/* if(n > 50)
n = 50;*/
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->sv);
if (ok)
I->sn = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->sn);
if (ok)
I->tv = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->tv);
if (ok)
I->tn = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->tn);
if (!ok){
FreeP(I->sv);
FreeP(I->sn);
FreeP(I->tv);
FreeP(I->tn);
I->sv = NULL;
I->sn = NULL;
I->tv = NULL;
I->tn = NULL;
}
I->Ns = n;
v = I->sv;
vn = I->sn;
for(a = 0; a <= n; a++) {
*(vn++) = 0.0;
*(vn++) = (float) cos(a * 2 * PI / n);
*(vn++) = (float) sin(a * 2 * PI / n);
*(v++) = 0.0;
*(v++) = (float) cos(a * 2 * PI / n) * size;
*(v++) = (float) ((sin(a * 2 * PI / n) * size) + (sign * sin(PI / 4) * length));
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeDumbbell2-DEBUG: exiting...\n" ENDFD;
return ok;
}
#endif
CExtrude *ExtrudeNew(PyMOLGlobals * G)
{
int ok = true;
OOAlloc(G, CExtrude);
CHECKOK(ok, I);
if (ok)
ExtrudeInit(G, I);
return (I);
}
void ExtrudeBuildNormals1f(CExtrude * I)
{
int a;
float *v;
PRINTFD(I->G, FB_Extrude)
" ExtrudeBuildNormals1f-DEBUG: entered.\n" ENDFD;
if(I->N) {
get_system1f3f(I->n, I->n + 3, I->n + 6); /* first is arbitrary */
v = I->n + 9;
for(a = 1; a < I->N; a++) {
copy3f(v - 6, v + 3);
get_system2f3f(v, v + 3, v + 6); /* the rest are relative to first */
v += 9;
}
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeBuildNormals1f-DEBUG: exiting...\n" ENDFD;
}
void ExtrudeBuildNormals2f(CExtrude * I)
{
int a;
float *v;
PRINTFD(I->G, FB_Extrude)
" ExtrudeBuildNormals2f-DEBUG: entered.\n" ENDFD;
if(I->N) {
v = I->n;
for(a = 0; a < I->N; a++) {
get_system2f3f(v, v + 3, v + 6);
v += 9;
}
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeBuildNormals2f-DEBUG: entering...\n" ENDFD;
}
#if 0
/* Is this ever used? */
void ExtrudeCGOTraceAxes(CExtrude * I, CGO * cgo)
{
int a;
float *v, *n;
float v0[3];
if(I->N) {
CGOColor(cgo, 0.5, 0.5, 0.5);
CGOBegin(cgo, GL_LINES);
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
add3f(v, n, v0);
CGOVertexv(cgo, v0);
CGOVertexv(cgo, v);
n += 3;
add3f(v, n, v0);
CGOVertexv(cgo, v0);
CGOVertexv(cgo, v);
n += 3;
add3f(v, n, v0);
CGOVertexv(cgo, v0);
CGOVertexv(cgo, v);
n += 3;
v += 3;
}
CGOEnd(cgo);
}
}
/* Is this ever used? */
void ExtrudeCGOTrace(CExtrude * I, CGO * cgo)
{
int a;
float *v;
if(I->N) {
CGOColor(cgo, 0.5, 0.5, 0.5);
CGOBegin(cgo, GL_LINE_STRIP);
v = I->p;
for(a = 0; a < I->N; a++) {
CGOVertexv(cgo, v);
v += 3;
}
CGOEnd(cgo);
}
}
#endif
int ExtrudeComputeTangents(CExtrude * I)
{
float *nv, *v1, *v;
int a;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeComputeTangents-DEBUG: entered.\n" ENDFD;
nv = Alloc(float, I->N * 3);
CHECKOK(ok, nv);
if (!ok)
return ok;
v = nv;
v1 = I->p + 3;
for(a = 1; a < I->N; a++) {
subtract3f(v1, v1 - 3, v);
normalize3f(v);
v += 3;
v1 += 3;
}
/* compute tangents */
v = nv;
v1 = I->n;
*(v1++) = *(v++); /* first segment */
*(v1++) = *(v++);
*(v1++) = *(v++);
v1 += 6;
for(a = 1; a < (I->N - 1); a++) {
add3f(v, (v - 3), v1);
normalize3f(v1);
v1 += 9;
v += 3;
}
*(v1++) = *(v - 3); /* last segment */
*(v1++) = *(v - 2);
*(v1++) = *(v - 1);
FreeP(nv);
PRINTFD(I->G, FB_Extrude)
" ExtrudeComputeTangents-DEBUG: exiting...\n" ENDFD;
return ok;
}
#if 0
/* Is this ever used? */
void ExtrudeCGOTraceFrame(CExtrude * I, CGO * cgo)
{
int a, b;
float *v;
float *n;
float *sv, *tv;
float v0[3], v1[3];
if(I->N && I->Ns) {
CGOColor(cgo, 0.5, 0.5, 0.5);
{
CGOBegin(cgo, GL_LINES);
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
sv += 3;
tv += 3;
}
/* trace shape */
tv = I->tv;
add3f(v, tv, v0);
for(b = 1; b < I->Ns; b++) {
tv += 3;
add3f(v, tv, v1);
CGOVertexv(cgo, v0);
CGOVertexv(cgo, v1);
copy3f(v1, v0);
}
tv = I->tv;
add3f(v, tv, v1);
CGOVertexv(cgo, v0);
CGOVertexv(cgo, v1);
v += 3;
n += 9;
}
CGOEnd(cgo);
}
}
}
#endif
/*
* Draw flat cap on a tube cartoon (loop, oval, etc.)
*
* I: tube instance
* cgo: CGO to add to
* index: sampling index in `I`
* inv_dir: inverse direction of normal if true
* color: RGB color or NULL to use color from `I`
*/
static
void TubeCapFlat(const CExtrude * I, CGO * cgo, int index, bool inv_dir, const float * color) {
const float * vertex = I->p + 3 * index;
const float * base33 = I->n + 9 * index;
const float * normal = base33;
float tmp3f[3];
int b_end = -1, b_incr = -1;
if (inv_dir) {
copy3f(normal, tmp3f);
invert3f(tmp3f);
normal = tmp3f;
} else {
b_end = I->Ns * 2 + 1;
b_incr = 1;
}
CGOBegin(cgo, GL_TRIANGLE_FAN);
CGOColorv(cgo, color ? color : (I->c + 3 * index));
CGOAlpha(cgo, I->alpha[index]);
CGOPickColor(cgo, I->i[index], cPickableAtom);
CGONormalv(cgo, normal); // (tmp3f again free to use)
CGOVertexv(cgo, vertex); // center
// Indexing trickery: going in a loop, visiting first index twice to
// close the loop. Iterating backwards in case of `inv_dir`.
for (int b = I->Ns; b != b_end; b += b_incr) {
transform33Tf3f(base33, I->sv + (b % I->Ns) * 3, tmp3f);
add3f(vertex, tmp3f, tmp3f);
CGOVertexv(cgo, tmp3f);
}
CGOEnd(cgo);
CGOPickColor(cgo, -1, cPickableNoPick);
}
/*
* I: tube instance
* cgo: CGO to add to
* cap: 0: no caps, 1: flat caps, 2: round caps
* color_override: RGB color or NULL to use color from `I`
* use_spheres: do round caps with spheres instead of triangles
* dash: if > 0, skip every segment which is a multiple of `dash`
*/
int ExtrudeCGOSurfaceTube(CExtrude * I, CGO * cgo, int cap, const float *color_override, bool use_spheres, int dash)
{
int a, b;
unsigned int *i;
float *v;
float *n;
float *c;
const float *alpha;
float *sv, *sn, *tv, *tn, *tv1, *tn1, *TV = NULL, *TN = NULL;
int start, stop;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfaceTube-DEBUG: entered.\n" ENDFD;
if(I->N && I->Ns) {
TV = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TV);
if (ok)
TN = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TN);
/* compute transformed shape vertices */
if (ok){
tn = TN;
tv = TV;
sv = I->sv;
sn = I->sn;
for(b = 0; b <= I->Ns; b++) {
if(b == I->Ns) {
sv = I->sv;
sn = I->sn;
}
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
tv += 3;
transform33Tf3f(n, sn, tn);
tn += 3;
n += 9;
v += 3;
}
sv += 3;
sn += 3;
}
start = I->Ns / 4;
stop = 3 * I->Ns / 4;
}
// first loop: axial, for dashes (skipping segments)
for (int a_start = 0, a_incr = (dash ? dash : I->N);
a_start < I->N - 1;
a_start += a_incr) {
int a_end = a_start + a_incr;
if (a_end > I->N)
a_end = I->N;
// second loop: circumferential, setting up axial triangle strips
for(b = 0; ok && b < I->Ns; b++) {
if(SettingGetGlobal_i(I->G, cSetting_cartoon_debug) < 1.5)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
else {
ok &= CGOBegin(cgo, GL_LINE_STRIP);
}
if (ok){
c = I->c + a_start * 3;
alpha = I->alpha + a_start;
i = I->i + a_start;
tv = TV + 3 * (a_start + b * I->N);
tn = TN + 3 * (a_start + b * I->N);
tv1 = tv + 3 * I->N;
tn1 = tn + 3 * I->N;
// third loop: axial, segments within one "dash"
for(a = a_start; ok && a < a_end; ++a) {
if(color_override && (b > start) && (b < stop))
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, c);
if (ok){
ok &= CGOAlpha(cgo, *alpha);
}
if (ok)
ok &= CGOPickColor(cgo, *i, cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, tn);
if (ok)
ok &= CGOVertexv(cgo, tv);
tn += 3;
tv += 3;
if (ok)
ok &= CGONormalv(cgo, tn1);
if (ok)
ok &= CGOVertexv(cgo, tv1);
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
}
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
if (cap == 1) {
TubeCapFlat(I, cgo, a_start, true, color_override);
TubeCapFlat(I, cgo, a_end - 1, false, color_override);
}
}
if (ok){
switch (cap) {
case 2:
{
float p0[3], p1[3], p2[3], z1, z2, normal[3], vertex1[3];
float c, d, prev, x, y, *v1, nEdge = I->Ns, nEdgeH = 2.f * floor(I->Ns/2.f);
if (ok){
n = I->n;
v = I->p;
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
copy3f(I->n, p0);
invert3f(p0);
transform33Tf3f(I->n, I->sv, p1);
cross_product3f(p0, p1, p2);
normalize3f(p1);
normalize3f(p2);
}
if (ok){
if(color_override)
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, I->c);
}
if (ok){
ok &= CGOAlpha(cgo, I->alpha[0]);
}
if (ok)
ok &= CGOPickColor(cgo, I->i[0], cPickableAtom);
if (ok){
v = I->p;
if (use_spheres){
ok &= CGOSphere(cgo, v, I->r); // this matches the Cylinder
} else {
/* If we don't use spheres, then we need to have the rounded cap
* line up with the geometry perfectly. We generate the cap using
* spheracle coordinates, then for the last line (i.e., last=true)
* we use the coordinates from the geometry (i.e., exactly
* how they were genereated from I->n and I->sv). This is so that
* the vertices line up perfectly. */
nEdge = I->Ns;
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
z1 = z2 = 1.f;
prev = 1.f;
v1 = v;
tv = I->tv;
for (c = 1; ok && c <= (nEdgeH/2); c++){
short last = (c + 1) > (nEdgeH/2);
z1 = z2;
z2 = (float) cos((c) * PI / ((float)nEdgeH));
for (d = 0; d <= nEdge; d++){
x = (float) cos((d) * 2 * PI / (float)nEdge) * sin((c-prev) * PI / (float)nEdgeH);
y = (float) sin((d) * 2 * PI / (float)nEdge) * sin((c-prev) * PI / (float)nEdgeH);
normal[0] = p1[0] * x + p2[0] * y + p0[0] * z1;
normal[1] = p1[1] * x + p2[1] * y + p0[1] * z1;
normal[2] = p1[2] * x + p2[2] * y + p0[2] * z1;
vertex1[0] = v1[0] + normal[0] * I->r;
vertex1[1] = v1[1] + normal[1] * I->r;
vertex1[2] = v1[2] + normal[2] * I->r;
normalize3f(normal);
ok &= CGONormalv(cgo, normal);
if (ok)
ok &= CGOVertexv(cgo, vertex1);
if (ok){
if (last){
float *vert = tv + 3*(((int)(nEdge-d))%((int)nEdge));
subtract3f(vert, v, normal);
ok &= CGONormalv(cgo, normal);
if (ok)
ok &= CGOVertexv(cgo, vert);
} else {
x = (float) cos((d) * 2 * PI / (float)nEdge) * sin((c) * PI / (float)nEdgeH);
y = (float) sin((d) * 2 * PI / (float)nEdge) * sin((c) * PI / (float)nEdgeH);
normal[0] = p1[0] * x + p2[0] * y + p0[0] * z2;
normal[1] = p1[1] * x + p2[1] * y + p0[1] * z2;
normal[2] = p1[2] * x + p2[2] * y + p0[2] * z2;
vertex1[0] = v1[0] + normal[0] * I->r;
vertex1[1] = v1[1] + normal[1] * I->r;
vertex1[2] = v1[2] + normal[2] * I->r;
normalize3f(normal);
ok &= CGONormalv(cgo, normal);
if (ok)
ok &= CGOVertexv(cgo, vertex1);
}
}
}
}
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
if (ok){
n = I->n + 9 * (I->N - 1);
v = I->p + 3 * (I->N - 1);
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
copy3f(n, p0);
transform33Tf3f(n, I->sv, p1);
cross_product3f(p0, p1, p2);
normalize3f(p1);
normalize3f(p2);
if(color_override)
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, I->c + 3 * (I->N - 1));
}
if (ok){
ok &= CGOAlpha(cgo, I->alpha[I->N - 1]);
}
if (ok)
ok &= CGOPickColor(cgo, I->i[I->N - 1], cPickableAtom);
if (ok){
if (use_spheres){
ok &= CGOSphere(cgo, v, I->r); // this matches the Cylinder
} else {
/* If we don't use spheres, then we need to have the rounded cap
* line up with the geometry perfectly. We generate the cap using
* spheracle coordinates, then for the last line (i.e., last=true)
* we use the coordinates from the geometry (i.e., exactly
* how they were genereated from I->n and I->sv). This is so that
* the vertices line up perfectly. */
nEdge = I->Ns;
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
z1 = z2 = 1.f;
prev = 1.f;
v1 = v;
tv = I->tv;
for (c = 1; ok && c <= (nEdgeH/2); c++){
short last = (c + 1) > (nEdgeH/2);
z1 = z2;
z2 = (float) cos((c) * PI / ((float)nEdgeH));
for (d = 0; d <= nEdge; d++){
x = (float) cos((d) * 2 * PI / (float)nEdge) * sin((c-prev) * PI / (float)nEdgeH);
y = (float) sin((d) * 2 * PI / (float)nEdge) * sin((c-prev) * PI / (float)nEdgeH);
normal[0] = p1[0] * x + p2[0] * y + p0[0] * z1;
normal[1] = p1[1] * x + p2[1] * y + p0[1] * z1;
normal[2] = p1[2] * x + p2[2] * y + p0[2] * z1;
vertex1[0] = v1[0] + normal[0] * I->r;
vertex1[1] = v1[1] + normal[1] * I->r;
vertex1[2] = v1[2] + normal[2] * I->r;
normalize3f(normal);
ok &= CGONormalv(cgo, normal);
if (ok)
ok &= CGOVertexv(cgo, vertex1);
if (ok){
if (last){
float *vert = tv + 3*(((int)(d))%((int)nEdge));
subtract3f(vert, v, normal);
ok &= CGONormalv(cgo, normal);
if (ok)
ok &= CGOVertexv(cgo, vert);
} else {
x = (float) cos((d) * 2 * PI / (float)nEdge) * sin((c) * PI / (float)nEdgeH);
y = (float) sin((d) * 2 * PI / (float)nEdge) * sin((c) * PI / (float)nEdgeH);
normal[0] = p1[0] * x + p2[0] * y + p0[0] * z2;
normal[1] = p1[1] * x + p2[1] * y + p0[1] * z2;
normal[2] = p1[2] * x + p2[2] * y + p0[2] * z2;
vertex1[0] = v1[0] + normal[0] * I->r;
vertex1[1] = v1[1] + normal[1] * I->r;
vertex1[2] = v1[2] + normal[2] * I->r;
normalize3f(normal);
ok &= CGONormalv(cgo, normal);
if (ok)
ok &= CGOVertexv(cgo, vertex1);
}
}
}
}
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
}
}
}
break;
}
}
FreeP(TV);
FreeP(TN);
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfaceTube-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeCylindersToCGO(CExtrude * I, CGO * cgo, float tube_radius){
float *v1, *c1, midc[3], axis[3];
const float *alpha;
int a;
unsigned int *i;
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCylindersToCGO-DEBUG: entered.\n" ENDFD;
v1 = I->p + 3;
c1 = I->c + 3;
alpha = I->alpha + 1;
i = I->i + 1;
int cap = (cCylShaderBothCapsRound | cCylShaderInterpColor);
for(a = 1; a < I->N; a++) {
average3f(c1-3, c1, midc);
ok &= CGOPickColor(cgo, *(i-1), cPickableAtom);
subtract3f(v1, v1-3, axis);
CGOColorv(cgo, c1-3);
CGOAlpha(cgo, *(alpha-1));
Pickable pickcolor2 = { *i, cPickableAtom };
cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, v1-3, axis, tube_radius, cap, c1, &pickcolor2);
v1 += 3;
c1 += 3;
alpha++;
i++;
cap = cCylShaderCap2Round | cCylShaderInterpColor;
}
if (ok)
ok &= CGOPickColor(cgo, 0, cPickableNoPick);
PRINTFD(I->G, FB_Extrude)
" ExtrudeCylindersToCGO-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeCGOSurfaceVariableTube(CExtrude * I, CGO * cgo, int cap)
{
int a, b;
unsigned int *i;
float *v;
float *n;
float *c;
const float *alpha;
float *sv, *sn, *tv, *tn, *tv1, *tn1, *TV = NULL, *TN = NULL, *AN = NULL, *an;
float v0[3];
float *sf; /* PUTTY: scale factor from ExtrudeMakeSausLUT() */
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfaceTube-DEBUG: entered.\n" ENDFD;
if(I->N && I->Ns) {
TV = Alloc(float, 3 * (I->Ns + 1) * I->N);
TN = Alloc(float, 3 * (I->Ns + 1) * I->N);
AN = Alloc(float, 3 * I->N); /* normals adjusted for changing widths */
/* compute transformed shape vertices */
tv = TV;
sv = I->sv;
for(b = 0; b <= I->Ns; b++) {
if(b == I->Ns) {
sv = I->sv;
}
n = I->n; /* NOTE: n is not a counter -- it's a 3x3 coordinate system! */
v = I->p;
sf = I->sf; /* PUTTY: scale factors */
for(a = 0; a < I->N; a++) {
transform33Tf3f(n, sv, tv);
*(tv) *= *sf;
*(tv + 1) *= *sf;
*(tv + 2) *= *sf;
add3f(v, tv, tv);
tv += 3;
v += 3;
sf++;
n += 9;
}
sv += 3;
}
/* compute transformed normals, taking into account changing radii */
tn = TN;
tv = TV;
sn = I->sn;
for(b = 0; b <= I->Ns; b++) {
float d1, d2, r0, r1, r2, x1, x2;
if(b == I->Ns) {
sn = I->sn;
}
an = AN;
v = I->p;
for(a = 0; a < I->N; a++) {
if((a > 0) && (a < (I->N - 1))) {
/* compute rises */
r0 = (float) diff3f(v, tv);
r1 = (float) (diff3f(v - 3, tv - 3) - r0);
r2 = (float) (diff3f(v + 3, tv + 3) - r0);
/* compute runs */
d1 = (float) diff3f(v - 3, v);
d2 = (float) diff3f(v + 3, v);
/* compute x-to-yz weights */
x1 = r1 / d1;
x2 = -r2 / d2;
if(a == 1) {
an[-3] = x1;
an[-2] = sn[1];
an[-1] = sn[2];
normalize3f(an - 3);
} else if(a == I->N - 2) {
an[3] = x2;
an[4] = sn[1];
an[5] = sn[2];
normalize3f(an + 3);
}
an[0] = (x1 + x2) / 2.0F;
an[1] = sn[1];
an[2] = sn[2];
normalize3f(an);
}
tv += 3;
v += 3;
an += 3;
}
n = I->n; /* NOTE: n is not a counter -- it's a 3x3 coordinate system! */
an = AN;
for(a = 0; a < I->N; a++) {
transform33Tf3f(n, an, tn);
tn += 3;
an += 3;
n += 9;
}
sn += 3;
}
/* fill in each strip separately */
tv = TV;
tn = TN;
tv1 = TV + 3 * I->N;
tn1 = TN + 3 * I->N;
for(b = 0; b < I->Ns; b++) {
if(SettingGetGlobal_i(I->G, cSetting_cartoon_debug) < 1.5)
CGOBegin(cgo, GL_TRIANGLE_STRIP);
else {
CGOBegin(cgo, GL_LINE_STRIP);
}
c = I->c;
alpha = I->alpha;
i = I->i;
for(a = 0; a < I->N; a++) {
CGOColorv(cgo, c);
CGOAlpha(cgo, *alpha);
CGOPickColor(cgo, *i, cPickableAtom);
CGONormalv(cgo, tn);
CGOVertexv(cgo, tv);
tn += 3;
tv += 3;
CGONormalv(cgo, tn1);
CGOVertexv(cgo, tv1);
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
CGOEnd(cgo);
CGOPickColor(cgo, -1, cPickableNoPick);
}
if(ok && SettingGetGlobal_i(I->G, cSetting_cartoon_debug) > 3.5) {
tv = TV;
tn = TN;
tv1 = TV + 3 * I->N;
tn1 = TN + 3 * I->N;
for(b = 0; b < I->Ns; b++) {
float vv[3];
CGOBegin(cgo, GL_LINES);
c = I->c;
alpha = I->alpha;
i = I->i;
for(a = 0; a < I->N; a++) {
CGOColorv(cgo, c);
CGOAlpha(cgo, *alpha);
copy3f(tn, vv);
scale3f(vv, 0.3F, vv);
add3f(vv, tv, vv);
CGONormalv(cgo, tn);
CGOVertexv(cgo, tv);
CGOVertexv(cgo, vv);
tn += 3;
tv += 3;
copy3f(tn1, vv);
scale3f(vv, 0.3F, vv);
add3f(vv, tv1, vv);
CGONormalv(cgo, tn1);
CGOVertexv(cgo, tv1);
CGOVertexv(cgo, vv);
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
CGOEnd(cgo);
}
}
if(ok && cap) {
n = I->n;
v = I->p;
sf = I->sf;
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
*(tv) *= *sf;
*(tv + 1) *= *sf;
*(tv + 2) *= *sf;
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
CGOBegin(cgo, GL_TRIANGLE_FAN);
copy3f(I->n, v0);
invert3f(v0);
CGOColorv(cgo, I->c);
CGOAlpha(cgo, I->alpha[0]);
CGOPickColor(cgo, I->i[0], cPickableAtom);
CGONormalv(cgo, v0);
if (ok) {
CGOVertexv(cgo, v);
/* trace shape */
CGOVertexv(cgo, I->tv);
for(b = I->Ns - 1; b >= 0; b--) {
CGOVertexv(cgo, I->tv + b * 3);
}
CGOEnd(cgo);
n = I->n + 9 * (I->N - 1);
v = I->p + 3 * (I->N - 1);
sf = I->sf + (I->N - 1); /* PUTTY */
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
*(tv) *= *(sf);
*(tv + 1) *= *(sf);
*(tv + 2) *= *(sf);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
CGOBegin(cgo, GL_TRIANGLE_FAN);
CGOColorv(cgo, I->c + 3 * (I->N - 1));
CGOAlpha(cgo, I->alpha[I->N - 1]);
CGOPickColor(cgo, I->i[I->N - 1], cPickableAtom);
CGONormalv(cgo, n);
CGOVertexv(cgo, v);
/* trace shape */
for(b = 0; b < I->Ns; b++) {
CGOVertexv(cgo, I->tv + b * 3);
}
CGOVertexv(cgo, I->tv);
CGOEnd(cgo);
}
CGOPickColor(cgo, -1, cPickableNoPick);
FreeP(TV);
FreeP(TN);
FreeP(AN);
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfaceTube-DEBUG: exiting...\n" ENDFD;
}
return ok;
}
int ExtrudeCGOSurfacePolygon(CExtrude * I, CGO * cgo, int cap, const float *color_override)
{
int a, b;
unsigned int *i;
float *v;
float *n;
float *c;
const float *alpha;
float *sv, *sn, *tv, *tn, *tv1, *tn1, *TV = NULL, *TN = NULL;
float v0[3];
int ok = true;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfacePolygon-DEBUG: entered.\n" ENDFD;
if(I->N && I->Ns) {
TV = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TV);
if (ok)
TN = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TN);
/* compute transformed shape vertices */
if (ok){
tn = TN;
tv = TV;
sv = I->sv;
sn = I->sn;
for(b = 0; b <= I->Ns; b++) {
if(b == I->Ns) {
sv = I->sv;
sn = I->sn;
}
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
tv += 3;
transform33Tf3f(n, sn, tn);
tn += 3;
n += 9;
v += 3;
}
sv += 3;
sn += 3;
}
/* fill in each strip separately */
tv = TV;
tn = TN;
tv1 = TV + 3 * I->N;
tn1 = TN + 3 * I->N;
}
for(b = 0; ok && b < I->Ns; b += 2) {
if(SettingGetGlobal_i(I->G, cSetting_cartoon_debug) < 1.5)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
else {
ok &= CGOBegin(cgo, GL_LINE_STRIP);
}
if(ok && color_override)
ok &= CGOColorv(cgo, color_override);
c = I->c;
alpha = I->alpha;
i = I->i;
for(a = 0; ok && a < I->N; a++) {
if(!color_override)
ok &= CGOColorv(cgo, c);
if (ok){
ok &= CGOAlpha(cgo, *alpha);
}
if (ok)
ok &= CGOPickColor(cgo, *i, cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, tn);
if (ok)
ok &= CGOVertexv(cgo, tv);
tn += 3;
tv += 3;
if (ok)
ok &= CGONormalv(cgo, tn1);
if (ok)
ok &= CGOVertexv(cgo, tv1);
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
tv += 3 * I->N;
tn += 3 * I->N;
tv1 += 3 * I->N;
tn1 += 3 * I->N;
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
if(ok && cap) {
if(color_override)
ok &= CGOColorv(cgo, color_override);
if (ok){
n = I->n;
v = I->p;
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
}
if (ok)
ok &= CGOBegin(cgo, GL_TRIANGLE_FAN);
if (ok){
copy3f(I->n, v0);
invert3f(v0);
if(!color_override)
ok &= CGOColorv(cgo, I->c);
if (ok){
ok &= CGOAlpha(cgo, I->alpha[0]);
}
if (ok)
ok &= CGOPickColor(cgo, I->i[0], cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, v0);
}
if (ok)
ok &= CGOVertexv(cgo, v);
/* trace shape */
if (ok)
ok &= CGOVertexv(cgo, I->tv);
for(b = I->Ns - 1; ok && b >= 0; b--) {
ok &= CGOVertexv(cgo, I->tv + b * 3);
}
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
if (ok){
n = I->n + 9 * (I->N - 1);
v = I->p + 3 * (I->N - 1);
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
}
if (ok)
ok &= CGOBegin(cgo, GL_TRIANGLE_FAN);
if(ok && !color_override)
ok &= CGOColorv(cgo, I->c + 3 * (I->N - 1));
if (ok){
ok &= CGOAlpha(cgo, I->alpha[I->N - 1]);
}
if (ok)
ok &= CGOPickColor(cgo, I->i[I->N - 1], cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, n);
if (ok)
ok &= CGOVertexv(cgo, v);
/* trace shape */
for(b = 0; ok && b < I->Ns; b++) {
ok &= CGOVertexv(cgo, I->tv + b * 3);
}
if (ok)
ok &= CGOVertexv(cgo, I->tv);
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
FreeP(TV);
FreeP(TN);
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfacePolygon-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeCGOSurfacePolygonTaper(CExtrude * I, CGO * cgo, int sampling,
const float *color_override)
{
int a, b;
unsigned int *i;
float *v;
float *n;
float *c;
const float *alpha;
float *sv, *sn, *tv, *tn, *tv1, *tn1, *TV = NULL, *TN = NULL;
float s0[3];
float f;
int subN;
int ok = true;
subN = I->N - sampling;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfacePolygonTaper-DEBUG: entered.\n" ENDFD;
if(I->N && I->Ns) {
TV = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TV);
if (ok)
TN = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TN);
/* compute transformed shape vertices */
if (ok){
tn = TN;
tv = TV;
sv = I->sv;
sn = I->sn;
for(b = 0; b <= I->Ns; b++) {
if(b == I->Ns) {
sv = I->sv;
sn = I->sn;
}
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
if((a >= sampling) && (a < subN)) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
tv += 3;
transform33Tf3f(n, sn, tn);
tn += 3;
n += 9;
v += 3;
} else {
copy3f(sv, s0);
if(a >= subN) {
f = ((I->N - a - 1) / ((float) sampling));
} else if(a < sampling) {
f = (a / ((float) sampling));
} else
f = 1.0;
f = smooth(f, 2);
s0[2] *= f;
transform33Tf3f(n, s0, tv);
add3f(v, tv, tv);
tv += 3;
transform33Tf3f(n, sn, tn);
tn += 3;
n += 9;
v += 3;
}
}
sv += 3;
sn += 3;
}
/* fill in each strip separately */
tv = TV;
tn = TN;
tv1 = TV + 3 * I->N;
tn1 = TN + 3 * I->N;
}
for(b = 0; ok && b < I->Ns; b += 2) {
if (ok){
if(SettingGetGlobal_i(I->G, cSetting_cartoon_debug) < 1.5)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
else {
ok &= CGOBegin(cgo, GL_LINE_STRIP);
}
}
if(ok && color_override)
ok &= CGOColorv(cgo, color_override);
c = I->c;
alpha = I->alpha;
i = I->i;
for(a = 0; ok && a < I->N; a++) {
if(!color_override)
ok &= CGOColorv(cgo, c);
if (ok){
ok &= CGOAlpha(cgo, *alpha);
}
if (ok)
ok &= CGOPickColor(cgo, *i, cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, tn);
if (ok)
ok &= CGOVertexv(cgo, tv);
tn += 3;
tv += 3;
if (ok)
ok &= CGONormalv(cgo, tn1);
if (ok)
ok &= CGOVertexv(cgo, tv1);
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
if (ok){
tv += 3 * I->N;
tn += 3 * I->N;
tv1 += 3 * I->N;
tn1 += 3 * I->N;
CGOEnd(cgo);
CGOPickColor(cgo, -1, cPickableNoPick);
}
}
FreeP(TV);
FreeP(TN);
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfacePolygonTaper-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeCGOSurfaceStrand(CExtrude * I, CGO * cgo, int sampling, const float *color_override)
{
int a, b;
unsigned int *i;
float *v;
float *n;
float *c;
const float *alpha;
float *sv, *sn, *tv, *tn, *tv1, *tn1, *TV = NULL, *TN = NULL;
float v0[3], n0[3], s0[3], z[3] = { 1.0, 0.0, 1.0 };
int subN;
int ok = true;
subN = I->N - sampling;
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfaceStrand-DEBUG: entered.\n" ENDFD;
if(I->N && I->Ns) {
TV = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TV);
if (ok)
TN = Alloc(float, 3 * (I->Ns + 1) * I->N);
CHECKOK(ok, TN);
/* compute transformed shape vertices */
if (ok){
tn = TN;
tv = TV;
sv = I->sv;
sn = I->sn;
for(b = 0; b <= I->Ns; b++) {
if(b == I->Ns) {
sv = I->sv;
sn = I->sn;
}
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
copy3f(sv, s0);
if(a == subN) {
scale3f(s0, 0.50F, s0);
}
transform33Tf3f(n, s0, tv);
add3f(v, tv, tv);
tv += 3;
transform33Tf3f(n, sn, tn);
tn += 3;
n += 9;
v += 3;
}
sv += 3;
sn += 3;
}
/* fill in each strip of arrow separately */
tv = TV;
tn = TN;
tv1 = TV + 3 * I->N;
tn1 = TN + 3 * I->N;
}
for(b = 0; ok && b < I->Ns; b += 2) {
if(SettingGetGlobal_i(I->G, cSetting_cartoon_debug) < 1.5)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
else {
ok &= CGOBegin(cgo, GL_LINE_STRIP);
}
c = I->c;
alpha = I->alpha;
i = I->i;
for(a = 0; ok && a < I->N; a++) {
if(a < subN) {
if(color_override && ((b == 2) || (b == 3) || (b == 6) || (b == 7)))
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, c);
if (ok){
ok &= CGOAlpha(cgo, *alpha);
}
if (ok)
ok &= CGOPickColor(cgo, *i, cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, tn);
if (ok)
ok &= CGOVertexv(cgo, tv);
}
tn += 3;
tv += 3;
if(ok && a < subN) {
ok &= CGONormalv(cgo, tn1);
if (ok)
ok &= CGOVertexv(cgo, tv1);
}
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
tv += 3 * I->N;
tn += 3 * I->N;
tv1 += 3 * I->N;
tn1 += 3 * I->N;
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
if(ok) {
n = I->n;
v = I->p;
sv = I->sv;
tv = I->tv;
for(b = 0; b < I->Ns; b++) {
transform33Tf3f(n, sv, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
copy3f(I->n, v0);
invert3f(v0);
if (ok){
if(color_override)
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, I->c);
}
if(ok){
ok &= CGOAlpha(cgo, I->alpha[0]);
}
if (ok)
ok &= CGOPickColor(cgo, I->i[0], cPickableAtom);
if (ok)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
if (ok)
ok &= CGONormalv(cgo, v0);
ok &= CGOVertexv(cgo, I->tv + 6 * 3);
ok &= CGOVertexv(cgo, I->tv + 4 * 3);
ok &= CGOVertexv(cgo, I->tv + 0 * 3);
ok &= CGOVertexv(cgo, I->tv + 2 * 3);
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
/* now do the arrow part */
tn = TN;
tv = TV;
sv = I->sv;
sn = I->sn;
if (ok){
for(b = 0; b <= I->Ns; b++) {
if(b == I->Ns) {
sv = I->sv;
sn = I->sn;
}
v = I->p;
n = I->n;
for(a = 0; a < I->N; a++) {
copy3f(sv, s0);
s0[2] = s0[2] * ((1.5F * ((I->N - 1) - a)) / sampling);
transform33Tf3f(n, s0, tv);
add3f(v, tv, tv);
tv += 3;
copy3f(sn, n0);
if(fabs(dot_product3f(sn, z)) > R_SMALL4) {
n0[0] += 0.4F;
normalize3f(n0);
}
transform33Tf3f(n, n0, tn);
tn += 3;
n += 9;
v += 3;
}
sv += 3;
sn += 3;
}
}
tv = TV;
tn = TN;
tv1 = TV + 3 * I->N;
tn1 = TN + 3 * I->N;
for(b = 0; ok && b < I->Ns; b += 2) {
if (ok){
if(SettingGetGlobal_i(I->G, cSetting_cartoon_debug) < 1.5)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
else {
ok &= CGOBegin(cgo, GL_LINE_STRIP);
}
}
c = I->c;
alpha = I->alpha;
i = I->i;
for(a = 0; ok && a < I->N; a++) {
if(a >= (subN - 1)) {
if(color_override && ((b == 2) || (b == 3) || (b == 6) || (b == 7)))
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, c);
if (ok){
ok &= CGOAlpha(cgo, *alpha);
}
if (ok)
ok &= CGOPickColor(cgo, *i, cPickableAtom);
if (ok)
ok &= CGONormalv(cgo, tn);
if (ok)
ok &= CGOVertexv(cgo, tv);
}
tn += 3;
tv += 3;
if(ok && a >= (subN - 1)) {
ok &= CGONormalv(cgo, tn1);
if (ok)
ok &= CGOVertexv(cgo, tv1);
}
tn1 += 3;
tv1 += 3;
c += 3;
alpha++;
i++;
}
tv += 3 * I->N;
tn += 3 * I->N;
tv1 += 3 * I->N;
tn1 += 3 * I->N;
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
}
n = I->n + 9 * (subN - 1);
v = I->p + 3 * (subN - 1);
sv = I->sv;
tv = I->tv;
if (ok){
for(b = 0; b < I->Ns; b++) {
copy3f(sv, s0);
s0[2] = s0[2] * ((s0[2] < 0.f) ? -1.f : 1.5F) ;
transform33Tf3f(n, s0, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
}
// Back end/flat surface of the arrow,
// now split into two pieces, one for each side
copy3f(n, v0);
invert3f(v0);
if (ok){
if(color_override)
ok &= CGOColorv(cgo, color_override);
else
ok &= CGOColorv(cgo, I->c + 3 * (subN - 1));
}
if (ok){
ok &= CGOAlpha(cgo, I->alpha[(subN - 1)]);
}
if (ok)
ok &= CGOPickColor(cgo, I->i[(subN - 1)], cPickableAtom);
// draw first side
tv = I->tv;
if (ok)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
if (ok)
ok &= CGONormalv(cgo, v0);
ok &= CGOVertexv(cgo, I->tv + 6 * 3);
ok &= CGOVertexv(cgo, I->tv + 4 * 3);
ok &= CGOVertexv(cgo, I->tv + 0 * 3);
ok &= CGOVertexv(cgo, I->tv + 2 * 3);
if (ok)
ok &= CGOEnd(cgo);
// switch vertices to other side of flat surface of arrow
sv = I->sv;
tv = I->tv;
if (ok){
for(b = 0; b < I->Ns; b++) {
copy3f(sv, s0);
s0[2] = s0[2] * ((s0[2] < 0.f) ? 1.f : -1.5F) ;
transform33Tf3f(n, s0, tv);
add3f(v, tv, tv);
sv += 3;
tv += 3;
}
}
// draw other side
if (ok)
ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
if (ok)
ok &= CGONormalv(cgo, v0);
ok &= CGOVertexv(cgo, I->tv + 0 * 3);
ok &= CGOVertexv(cgo, I->tv + 2 * 3);
ok &= CGOVertexv(cgo, I->tv + 6 * 3);
ok &= CGOVertexv(cgo, I->tv + 4 * 3);
if (ok)
ok &= CGOEnd(cgo);
if (ok)
ok &= CGOPickColor(cgo, -1, cPickableNoPick);
FreeP(TV);
FreeP(TN);
}
PRINTFD(I->G, FB_Extrude)
" ExtrudeCGOSurfaceStrand-DEBUG: exiting...\n" ENDFD;
return ok;
}
int ExtrudeComputePuttyScaleFactors(CExtrude * I, ObjectMolecule * obj, int transform,
float mean, float stdev, float min, float max,
float power, float range,
float min_scale, float max_scale, int window)
{
float *sf;
int a;
unsigned int *i;
AtomInfoType *at;
float scale = 1.0F;
float data_range = max - min;
int ok = true;
if(I->N && I->Ns) {
int invalid = false;
i = I->i;
sf = I->sf;
/* guard against invalid inputs that would imply division by zero */
switch (transform) {
case cPuttyTransformNormalizedNonlinear:
case cPuttyTransformNormalizedLinear:
/* depend on stdev */
if(stdev < R_SMALL8)
invalid = true;
break;
}
switch (transform) {
case cPuttyTransformNormalizedNonlinear:
case cPuttyTransformRelativeNonlinear:
case cPuttyTransformScaledNonlinear:
case cPuttyTransformNormalizedLinear:
case cPuttyTransformRelativeLinear:
case cPuttyTransformScaledLinear:
/* depend on range */
if(fabs(range) < R_SMALL8)
invalid = true;
break;
}
switch (transform) {
case cPuttyTransformRelativeNonlinear:
case cPuttyTransformRelativeLinear:
/* depend on data_range */
if(fabs(data_range) < R_SMALL8)
invalid = true;
break;
}
if(!invalid) {
for(a = 0; a < I->N; a++) {
at = obj->AtomInfo + (*i);
switch (transform) {
case cPuttyTransformNormalizedNonlinear:
/* normalized by Z-score, with the range affecting the distribution width */
scale = (range + (at->b - mean) / stdev) / range;
if(scale < 0.0F)
scale = 0.0F;
scale = (float) pow(scale, power);
break;
case cPuttyTransformRelativeNonlinear:
scale = (at->b - min) / (data_range * range);
if(scale < 0.0F)
scale = 0.0F;
scale = (float) pow(scale, power);
*sf = scale;
break;
case cPuttyTransformScaledNonlinear:
scale = at->b / range;
if(scale < 0.0F)
scale = 0.0F;
scale = (float) pow(scale, power);
*sf = scale;
break;
case cPuttyTransformAbsoluteNonlinear:
scale = at->b;
if(scale < 0.0F)
scale = 0.0F;
scale = (float) pow(scale, power);
*sf = scale;
break;
case cPuttyTransformNormalizedLinear:
/* normalized by Z-score, with the range affecting the distribution width */
scale = (range + (at->b - mean) / stdev) / range;
if(scale < 0.0F)
scale = 0.0F;
break;
case cPuttyTransformRelativeLinear:
scale = (at->b - min) / (data_range * range);
if(scale < 0.0F)
scale = 0.0F;
*sf = scale;
break;
case cPuttyTransformScaledLinear:
scale = at->b / range;
if(scale < 0.0F)
scale = 0.0F;
*sf = scale;
break;
case cPuttyTransformAbsoluteLinear:
scale = at->b;
if(scale < 0.0F)
scale = 0.0F;
*sf = scale;
break;
case cPuttyTransformImpliedRMS:
if(scale < 0.0F)
scale = 0.0F;
scale = (float) (sqrt1d(at->b / 8.0) / PI);
break;
}
if((scale < min_scale) && (min_scale >= 0.0))
scale = min_scale;
if((scale > max_scale) && (max_scale >= 0.0))
scale = max_scale;
*(sf++) = scale;
i++;
}
} else {
PRINTFB(I->G, FB_RepCartoon, FB_Warnings)
" Extrude-Warning: invalid putty settings (division by zero)\n" ENDFB(I->G);
for(a = 0; a < I->N; a++) {
*sf = 0.0F;
sf++;
}
}
PRINTFB(I->G, FB_RepCartoon, FB_Blather)
" Putty: mean %8.3f stdev %8.3f min %8.3f max %8.3f\n",
mean, stdev,
mean + (pow(min_scale, 1.0F / power) * range - range) * stdev,
mean + (pow(max_scale, 1.0F / power) * range - range) * stdev ENDFB(I->G);
/* now compute window average */
{
float *SF = Alloc(float, I->N);
int w, ww;
float accum;
int cnt;
CHECKOK(ok, SF);
sf = I->sf;
if (ok){
for(a = 1; a < (I->N - 1); a++) {
accum = 0.0F;
cnt = 0;
for(w = -window; w <= window; w++) {
ww = w + a;
if(ww < 0)
ww = 0;
else if(ww > (I->N - 1))
ww = I->N - 1;
accum += sf[ww];
cnt++;
}
SF[a] = accum / cnt;
}
for(a = 1; a < I->N - 1; a++)
sf[a] = SF[a];
FreeP(SF);
}
}
}
return (ok);
}
#if 0
#endif
void ExtrudeTruncate(CExtrude * I, int n)
{
I->N = n;
/* should free RAM here... */
}
int ExtrudeAllocPointsNormalsColors(CExtrude * I, int n)
{
int ok = true;
if(I->N < n) {
/* reset */
FreeP(I->p);
FreeP(I->n);
FreeP(I->c);
FreeP(I->i);
FreeP(I->sf); /* PUTTY */
I->p = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->p);
if (ok)
I->n = Alloc(float, 9 * (n + 1));
CHECKOK(ok, I->n);
if (ok)
I->c = Alloc(float, 3 * (n + 1));
CHECKOK(ok, I->c);
if (ok)
I->alpha = Alloc(float, n + 1);
CHECKOK(ok, I->alpha);
if (ok)
I->i = Alloc(unsigned int, 3 * (n + 1));
CHECKOK(ok, I->i);
if (ok)
I->sf = Alloc(float, n + 1); /* PUTTY: scale factors */
CHECKOK(ok, I->sf);
if (!ok){
FreeP(I->p);
FreeP(I->n);
FreeP(I->c);
FreeP(I->alpha);
FreeP(I->i);
FreeP(I->sf);
}
}
I->N = n;
return ok;
}
void ExtrudeFree(CExtrude * I)
{
FreeP(I->p);
FreeP(I->n);
FreeP(I->c);
FreeP(I->alpha);
FreeP(I->tn);
FreeP(I->tv);
FreeP(I->sn);
FreeP(I->sv);
FreeP(I->i);
FreeP(I->sf);
OOFreeP(I);
}