parg_mesh* parg_mesh_knot(int slices, int stacks, float major, float minor) { parg_mesh* surf = malloc(sizeof(struct parg_mesh_s)); float ds = 1.0f / slices; float dt = 1.0f / stacks; int vertexCount = slices * stacks * 3; int vertexStride = sizeof(float) * 3; surf->coords = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); surf->normals = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); surf->uvs = 0; Point3* position = (Point3*) parg_buffer_lock(surf->coords, PARG_WRITE); Vector3* normal = (Vector3*) parg_buffer_lock(surf->normals, PARG_WRITE); for (float s = 0; s < 1 - ds / 2; s += ds) { for (float t = 0; t < 1 - dt / 2; t += dt) { const float E = 0.01f; Point3 p = knot_fn(s, t); Vector3 u = P3Sub(knot_fn(s + E, t), p); Vector3 v = P3Sub(knot_fn(s, t + E), p); Vector3 n = V3Normalize(V3Cross(u, v)); *position++ = p; *normal++ = n; } } parg_buffer_unlock(surf->coords); parg_buffer_unlock(surf->normals); surf->ntriangles = slices * stacks * 2; int indexCount = surf->ntriangles * 3; surf->indices = parg_buffer_alloc(indexCount * 2, PARG_GPU_ELEMENTS); uint16_t* index = (uint16_t*) parg_buffer_lock(surf->indices, PARG_WRITE); int v = 0; for (int i = 0; i < slices - 1; i++) { for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = v + next + stacks; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = v + j + stacks; *index++ = v + next + stacks; } v += stacks; } for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = next; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = j; *index++ = next; } parg_buffer_unlock(surf->indices); return surf; }
Quat fromAxisAngle( Vector3 axis, float angle ) { V3Normalize( axis ); angle /= 2 * RADTODEG; float s = sinf( angle ); return Quat( cosf( angle ), axis.x * s, axis.y * s, axis.z * s ); }
Plane *CalcMiddlePlane(Point3 *p1, Point3 *p2, Plane *p) {Point3 m0; V3Add(p1,p2,&m0); m0.x/=2;m0.y/=2;m0.z/=2; V3Sub(p1,p2,&(p->N)); V3Normalize(&(p->N)); p->off = V3Dot(&m0,&(p->N)); return p; }
int Ray_BlobAddPlane(Object *obj, Vec3 *pt, Vec3 *dir, double dist, double field) { Bloblet *be; BlobData *blob = obj->data.blob; Vec3 Pt; assert(obj != NULL); assert(blob != NULL); if ((be = (Bloblet *)Malloc(sizeof(Bloblet))) == NULL) return 0; be->next = NULL; V3Copy(&be->loc, pt); V3Copy(&be->dir, dir); be->rad = dist; be->field = field; /* * Normalize the normal vector. * Invalid normals should be checked for during parse. */ V3Normalize(&be->dir); /* Get "d" coeff. for plane that bounds plane's interval. */ Pt.x = be->dir.x * be->rad; Pt.y = be->dir.y * be->rad; Pt.z = be->dir.z * be->rad; be->d1 = -V3Dot(&be->dir, &Pt); /* * Pre-compute constants for the density eq. in standard form. * Radii that are too small shoud be checked for during parse. */ be->rsq = be->rad * be->rad; be->r2 = - (2.0 * be->field) / be->rsq; be->r4 = be->field / (be->rsq * be->rsq); be->type = BLOB_PLANE; /* Add the new plane element to the blob. */ if (blob->elems != NULL) { Bloblet *lastbe; for (lastbe = blob->elems; lastbe->next != NULL; lastbe = lastbe->next) ; /* Seek last element added to list. */ /* Append our new one. */ lastbe->next = be; } else blob->elems = be; return 1; }
Point3 *CalcSphereCenter(Point3 *v0, Point3 *v1, Point3 *v2, Point3 *v3,Point3 *c) { Vector3 d1, d2, d3; Plane p1,p2,p3; V3Add(v0, v1, &d1); V3Add(v0, v2, &d2); V3Add(v0, v3, &d3); d1.x/=2; d1.y/=2; d1.z/=2; d2.x/=2; d2.y/=2; d2.z/=2; d3.x/=2; d3.y/=2; d3.z/=2; V3Sub(v0, v1, &(p1.N)); V3Sub(v0, v2, &(p2.N)); V3Sub(v0, v3, &(p3.N)); V3Normalize(&(p1.N)); V3Normalize(&(p2.N)); V3Normalize(&(p3.N)); p1.off = V3Dot(&(p1.N), &d1); p2.off = V3Dot(&(p2.N), &d2); p3.off = V3Dot(&(p3.N), &d3); if(CalcPlaneInter(&p1, &p2, &p3, c)) return c; else return NULL; }
Plane *CalcPlane(Vector3 *p0, Vector3 *p1, Vector3 *p2, Plane *p ) { Vector3 v1,v2; Vector3 *N; N=&(p->N); V3Sub(p1,p0,&v1); V3Sub(p2,p0,&v2); V3Cross(&v1,&v2,N); if(N->x==0.0 && N->y==0.0 && N->z==0.0) return NULL; V3Normalize(N); p->off=V3Dot(N,p0); return p; }
void SetupPolygon(PolygonData *ply) { Vec3 V1, V2, N; float *pts; assert(ply != NULL); assert(ply->npts >= 3); pts = ply->pts; assert(pts != NULL); /* Compute plane normal. (based on first three vertices) */ V1.x = pts[3] - pts[0]; V2.x = pts[6] - pts[0]; V1.y = pts[4] - pts[1]; V2.y = pts[7] - pts[1]; V1.z = pts[5] - pts[2]; V2.z = pts[8] - pts[2]; V3Cross(&N, &V1, &V2); V3Normalize(&N); ply->nx = (float)N.x; ply->ny = (float)N.y; ply->nz = (float)N.z; /* Determine axis of greatest projection. */ if(fabs(N.x) > fabs(N.z)) { if(fabs(N.x) > fabs(N.y)) ply->axis = X_AXIS; else ply->axis = Y_AXIS; } else if(fabs(N.y) > fabs(N.z)) ply->axis = Y_AXIS; else ply->axis = Z_AXIS; }
void GetEntXForm(ADSResBuf *edata, Matrix4 mx) { double xscl = 1.0, yscl = 1.0, zscl = 1.0, rotang = 0.0; Vector3 zaxis, *zaxis_p = NULL; Point3 inpt, *inpt_p = NULL; Point3 bpt, *bpt_p = NULL; ADSResBuf *bdata, *rb; int isinsert = 0; rb = RBGetPoint3(&zaxis, edata, 210); if(rb != NULL && V3Normalize(&zaxis) != 0.0) zaxis_p = &zaxis; if (strcmp(RBSearch(edata, 0)->resval.rstring, "INSERT") == 0) { isinsert = 1; if(RBGetPoint3(&inpt, edata, 10) != NULL) inpt_p = &inpt; (void)RBGetDouble(&rotang, edata, 50); (void)RBGetDouble(&xscl, edata, 41); (void)RBGetDouble(&yscl, edata, 42); (void)RBGetDouble(&zscl, edata, 43); /* the block base point */ bdata = ads_tblsearch("BLOCK", RBSearch(edata, 2)->resval.rstring, 1); if(bdata) { rb = RBGetPoint3(&bpt, bdata, 10); if (rb != NULL) bpt_p = &bpt; ads_relrb(bdata); } } M4GetAcadXForm(mx, zaxis_p, isinsert, inpt_p, rotang, xscl, yscl, zscl, bpt_p); #ifdef DEBUG fprintf(stderr, "GetEntXForm: bpt: %f %f %f\n", bpt.x, bpt.y, bpt.z); M4Print(stderr, mx); fprintf(stderr, "GetEntXForm: inpt: %f %f %f\n", inpt.x, inpt.y, inpt.z); fprintf(stderr, "GetEntXForm: pt: %f %f %f\n", pt.x, pt.y, pt.z); #endif }
Object *MakeExtrudeObject(PARAMS *par) { Object *obj; MeshData *mesh; MeshTri *tris = NULL, *t; MeshVertex *v1, *v2, *pv1, *pv2, **newverts, **prevverts; Vec3 V; Xform *T = NULL, *Tlocal = NULL; /* Transform matrix for segments. */ int i, j, k, ntris, nverts, nsegs, reps, smooth; double u, v; if((mesh = Ray_NewMeshData()) == NULL) return NULL; /* First parameter is the number of vertices. */ nverts = (int)par->V.x; /* Get the initial vertices... */ par = par->next; for(i = 0; i < nverts; i++) { /* Get the point. */ Eval_Params(par); if((v1 = Ray_NewMeshVertex(&par->V)) == NULL) goto fail_create; if(!Ray_AddMeshVertex(mesh, v1)) goto fail_create; /* Get the optional stuff. */ if(par->more) { /* Normal. */ par = par->next; v1->nx = (float)par->V.x; v1->ny = (float)par->V.y; v1->nz = (float)par->V.z; v1->flags |= MESH_VERTEX_HAS_NORMAL; if(par->more) { /* Color. */ par = par->next; v1->r = (float)par->V.x; v1->g = (float)par->V.y; v1->b = (float)par->V.z; v1->flags |= MESH_VERTEX_HAS_COLOR; if(par->more) { /* UV coordinates. */ par = par->next; v1->u = (float)par->V.x; par = par->next; v1->v = (float)par->V.x; v1->flags |= MESH_VERTEX_HAS_UV; } } } par = par->next; } /* * Get the segments. * Create a new set of vertices as transformed copies of the * previous set of vertices. * Create the triangles that connect the two sets of vertices to * form a segment. */ if((T = Ray_NewXform()) == NULL) goto fail_create; if((Tlocal = Ray_NewXform()) == NULL) goto fail_create; ntris = nsegs = 0; tris = t = NULL; smooth = 0; while(par != NULL) { switch(par->type) { case TK_SEGMENT: M4x4Identity(&Tlocal->M); M4x4Identity(&Tlocal->I); reps = 1; /* Repeat count. */ break; case TK_SMOOTH: smooth = 1; break; case TK_RIGHTBRACE: /* End of segment. */ while(reps--) { nsegs++; /* * Create a new set of vertices as transformed copies of the * original set. */ ConcatXforms(T, Tlocal); for(i = 0; i < nverts; i++) { if((v1 = Ray_NewMeshVertex(NULL)) == NULL) goto fail_create; *v1 = *mesh->vertices[i]; V.x = v1->x; V.y = v1->y; V.z = v1->z; PointToWorld(&V, T); v1->x = (float)V.x; v1->y = (float)V.y; v1->z = (float)V.z; V.x = v1->nx; V.y = v1->ny; V.z = v1->nz; if(!(ISZERO(V.x) && ISZERO(V.y) && ISZERO(V.z))) { NormToWorld(&V, T); V3Normalize(&V); v1->nx = (float)V.x; v1->ny = (float)V.y; v1->nz = (float)V.z; } if(!Ray_AddMeshVertex(mesh, v1)) goto fail_create; } /* Create connecting triangles. */ prevverts = mesh->vertices + nverts * (nsegs - 1); newverts = mesh->vertices + nverts * nsegs; pv1 = *prevverts++; v1 = *newverts++; for(i = 1; i < nverts; i++) { pv2 = *prevverts++; v2 = *newverts++; if((t = Ray_NewMeshTri(pv1, pv2, v1)) != NULL) { t->next = tris; tris = t; ntris++; } if((t = Ray_NewMeshTri(v2, v1, pv2)) != NULL) { t->next = tris; tris = t; ntris++; } pv1 = pv2; v1 = v2; } /* If closed, connect the end vertices. */ } break; /* * Since we know that there is always one vector parameter for all * of the transform cases, the "TK_VECTOR" type param is * actually the transform param, so we'll just just change * the type to TK_VECTOR before passing it Eval_Params(). * This shortcut helps keep the parameter list short. */ case TK_ROTATE: par->type = TK_VECTOR; Eval_Params(par); XformXforms(Tlocal, &par->V, XFORM_ROTATE); break; case TK_SCALE: par->type = TK_VECTOR; Eval_Params(par); XformXforms(Tlocal, &par->V, XFORM_SCALE); break; case TK_SHEAR: par->type = TK_VECTOR; Eval_Params(par); XformXforms(Tlocal, &par->V, XFORM_SHEAR); break; case TK_TRANSLATE: par->type = TK_VECTOR; Eval_Params(par); XformXforms(Tlocal, &par->V, XFORM_TRANSLATE); break; case TK_REPEAT: par->type = TK_FLOAT; Eval_Params(par); reps = max((int)par->V.x, 0); break; } par = par->next; } Ray_DeleteXform(T); Ray_DeleteXform(Tlocal); /* If smooth, generate normals where none were explicitly defined. */ /* Generate UV coordinates where none were explicitly defined. */ k = 0; for(i = 0; i <= nsegs; i++) { u = (double)i / (double)nsegs; for(j = 0; j < nverts; j++) { v = (double)j / (double)(nverts - 1); v1 = mesh->vertices[k++]; v1->u = (float)u; v1->v = (float)v; } } if((obj = Ray_MakeMeshFromData(mesh, tris, ntris)) == NULL) goto fail_create; if(smooth) obj->flags |= OBJ_FLAG_SMOOTH; return obj; fail_create: while(tris != NULL) { t = tris; tris = t->next; Ray_DeleteMeshTri(t); } Ray_DeleteMeshData(mesh); Ray_DeleteXform(T); Ray_DeleteXform(Tlocal); return NULL; }
extern int WriteCyl(FILE *fp, char *matName, int id, Cyl3 *cyls) { int cylCnt = 0; Cyl3 *cyl; Vector3 dir; char *material = matName; #ifdef DEBUG fprintf(stderr, "WriteCyl(%p, %p)\n", contblks, cyls); #endif if (cyls == NULL) return 1; for (cyl = cyls; cyl; cyl = cyl->next) { if(matName == NULL) material = cyl->material; if(cyl->erad == 0.0) { /* it's a point/sphere */ int sign; sign = (cyl->srad > 0 ? 1 : -1); if (sign > 0) { fprintf(fp, "\n%s sphere %s.%d.%d\n", material, material, id, cylCnt++); } else { fprintf(fp, "\n%s bubble %s.%d.%d\n", material, material, id, cylCnt++); } fprintf(fp, "0\n0\n4"); fprintf(fp, "\t%.8g\t%.8g\t%.8g\t%.8g\n", cyl->svert.x, cyl->svert.y, cyl->svert.z, fabs(cyl->srad)); } else if (cyl->length != 0.0) { /* it's a cylinder or tube */ if(cyl->length >= 0.0) { fprintf(fp, "\n%s cylinder %s.%d.%d\n", material, material, id, cylCnt++); } else { fprintf(fp, "\n%s tube %s.%d.%d\n", material, material, id, cylCnt++); } fprintf(fp, "0\n0\n7"); fprintf(fp, "\t%.8g %.8g %.8g\n", cyl->svert.x, cyl->svert.y, cyl->svert.z); fprintf(fp, "\t%.8g %.8g %.8g\n", cyl->evert.x, cyl->evert.y, cyl->evert.z); fprintf(fp, "\t%.8g\n", cyl->srad); /* bottom cap */ fprintf(fp, "\n%s ring %s.%d.%d\n", material, material, id, cylCnt++); fprintf(fp, "0\n0\n8"); fprintf(fp, "\t%.8g %.8g %.8g\n", cyl->svert.x, cyl->svert.y, cyl->svert.z); if(cyl->length >= 0.0) { (void)V3Normalize(V3Sub(&cyl->svert, &cyl->evert, &dir)); } else { (void)V3Normalize(V3Sub(&cyl->evert, &cyl->svert, &dir)); } fprintf(fp, "\t%.8g %.8g %.8g\n", dir.x, dir.y, dir.z); fprintf(fp, "\t0 %.8g\n", cyl->srad); /* top cap */ fprintf(fp, "\n%s ring %s.%d.%d\n", material, material, id, cylCnt++); fprintf(fp, "0\n0\n8"); fprintf(fp, "\t%.8g %.8g %.8g\n", cyl->evert.x, cyl->evert.y, cyl->evert.z); if(cyl->length >= 0.0) { (void)V3Normalize(V3Sub(&cyl->evert, &cyl->svert, &dir)); } else { (void)V3Normalize(V3Sub(&cyl->svert, &cyl->evert, &dir)); } fprintf(fp, "\t%.8g %.8g %.8g\n", dir.x, dir.y, dir.z); fprintf(fp, "\t0 %.8g\n", cyl->srad); } else { /* it's a ring */ fprintf(fp, "\n%s ring %s.%d.%d\n", material, material, id, cylCnt++); fprintf(fp, "0\n0\n8"); fprintf(fp, "\t%.8g %.8g %.8g\n", cyl->svert.x, cyl->svert.y, cyl->svert.z); (void)V3Normalize(&cyl->normal); fprintf(fp, "\t%.8g %.8g %.8g\n", cyl->normal.x, cyl->normal.y, cyl->normal.z); fprintf(fp, "\t0 %.8g\n", cyl->srad); } } Cyl3FreeList(cyls); return 1; }
static MeshPod CreateTrefoil() { const int Slices = 256; const int Stacks = 32; const int VertexCount = Slices * Stacks; const int IndexCount = VertexCount * 6; MeshPod mesh; glGenVertexArrays(1, &mesh.Vao); glBindVertexArray(mesh.Vao); // Create a buffer with interleaved positions and normals if (true) { Vertex verts[VertexCount]; Vertex* pVert = &verts[0]; float ds = 1.0f / Slices; float dt = 1.0f / Stacks; // The upper bounds in these loops are tweaked to reduce the // chance of precision error causing an incorrect # of iterations. for (float s = 0; s < 1 - ds / 2; s += ds) { for (float t = 0; t < 1 - dt / 2; t += dt) { const float E = 0.01f; Vector3 p = EvaluateTrefoil(s, t); Vector3 u = V3Sub(EvaluateTrefoil(s + E, t), p); Vector3 v = V3Sub(EvaluateTrefoil(s, t + E), p); Vector3 n = V3Normalize(V3Cross(u, v)); pVert->Position = p; pVert->Normal = n; ++pVert; } } pezCheck(pVert - &verts[0] == VertexCount, "Tessellation error."); GLuint vbo; GLsizeiptr size = sizeof(verts); const GLvoid* data = &verts[0].Position.x; GLenum usage = GL_STATIC_DRAW; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, size, data, usage); } // Create a buffer of 16-bit indices if (true) { GLushort inds[IndexCount]; GLushort* pIndex = &inds[0]; GLushort n = 0; for (GLushort i = 0; i < Slices; i++) { for (GLushort j = 0; j < Stacks; j++) { *pIndex++ = (n + j + Stacks) % VertexCount; *pIndex++ = n + (j + 1) % Stacks; *pIndex++ = n + j; *pIndex++ = (n + (j + 1) % Stacks + Stacks) % VertexCount; *pIndex++ = (n + (j + 1) % Stacks) % VertexCount; *pIndex++ = (n + j + Stacks) % VertexCount; } n += Stacks; } pezCheck(n == VertexCount, "Tessellation error."); pezCheck(pIndex - &inds[0] == IndexCount, "Tessellation error."); GLuint handle; GLsizeiptr size = sizeof(inds); const GLvoid* data = &inds[0]; GLenum usage = GL_STATIC_DRAW; glGenBuffers(1, &handle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, usage); } mesh.VertexCount = VertexCount; mesh.IndexCount = IndexCount; glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 24, 0); glVertexAttribPointer(a("Normal"), 3, GL_FLOAT, GL_FALSE, 24, offset(12)); glEnableVertexAttribArray(a("Position")); glEnableVertexAttribArray(a("Normal")); pezCheck(OpenGLError); return mesh; }
/* *--------------------------------------------------------- * Compute a rotation matrix around an arbitrary axis * specified by 2 points p1 and p2; theta is the angle * between the two planes that share the same edge * defined by p1 and p2 * * The matrix TM is the matrix that brings the plane of * face 'n' into face 'p'; Matrix iTM is the matrix * that brings the plane of face 'p' into 'n' * 'p' and 'n' are the names of faces according to the * winged edge data structure; 'p' is the previous face * and 'n' is the next face *--------------------------------------------------------- */ int MxRotateAxis(Point3D p1, Point3D p2, double theta, Matrix4 *TM, Matrix4 *iTM) { Point3D p; double dist, cosX, sinX, cosY, sinY, det; Matrix4 m1, m2; p.x = p2.x - p1.x; p.y = p2.y - p1.y; p.z = p2.z - p1.z; if( V3Length( &p ) < 0.0 ) return(FALSE); V3Normalize( &p ); dist = sqrt( p.y * p.y + p.z * p.z ); /* maybe the 2 points are already aligned with the X-axis */ if(dist < DAMN_SMALL || dist == 0.0){ cosX = 1.0; sinX = 0.0; } else{ cosX = p.z / dist; sinX = p.y / dist; } /* fprintf(stderr, "p: x = %3.2f y = %3.2f z = %3.2f dist = %3.2f\n", p.x, p.y, p.z, dist); */ cosY = dist; sinY = -p.x; loadIdentity( TM ); loadIdentity( &m1 ); /* inverse translation matrix */ m1.element[0][3] = p1.x; m1.element[1][3] = p1.y; m1.element[2][3] = p1.z; /* fprintf(stderr,"Inverse Translation:\n"); printMatrix( m1 ); */ /* Inverse Rotation around X */ loadIdentity( &m2 ); m2.element[1][1] = cosX; m2.element[2][1] = -sinX; m2.element[1][2] = sinX; m2.element[2][2] = cosX; /* fprintf(stderr,"Inverse Rotation around X:\n"); printMatrix( m2 ); */ MatMul( &m1, &m2, TM ); MatrixCopy( TM, &m1 ); /* Inverse Rotation around Y */ loadIdentity( &m2 ); m2.element[0][0] = cosY; m2.element[2][0] = sinY; m2.element[0][2] = -sinY; m2.element[2][2] = cosY; /* fprintf(stderr,"Inverse Rotation around Y:\n"); printMatrix( m2 ); */ MatMul( &m1, &m2, TM ); MatrixCopy( TM, &m1 ); /* Rotation around Z */ loadIdentity( &m2 ); m2.element[0][0]= cos( theta ); m2.element[1][0]= -sin( theta ); m2.element[0][1]= sin( theta ); m2.element[1][1]= cos( theta ); /* fprintf(stderr,"Rotation around Z:\n"); printMatrix( m2 ); */ MatMul( &m1, &m2, TM ); MatrixCopy( TM, &m1 ); /* Rotation around Y */ loadIdentity( &m2 ); m2.element[0][0] = cosY; m2.element[2][0] = -sinY; m2.element[0][2] = sinY; m2.element[2][2] = cosY; /* fprintf(stderr,"Rotation around Y:\n"); printMatrix( m2 ); */ MatMul( &m1, &m2, TM ); MatrixCopy( TM, &m1 ); /* Rotation around X */ loadIdentity( &m2 ); m2.element[1][1] = cosX; m2.element[2][1] = sinX; m2.element[1][2] = -sinX; m2.element[2][2] = cosX; /* fprintf(stderr,"Rotation around X:\n"); printMatrix( m2 ); */ MatMul( &m1, &m2, TM ); MatrixCopy( TM, &m1 ); /* Translation matrix */ loadIdentity( &m2 ); m2.element[0][3] = -p1.x; m2.element[1][3] = -p1.y; m2.element[2][3] = -p1.z; /* fprintf(stderr,"Translation matrix:\n"); printMatrix( m2 ); */ MatMul( &m1, &m2, TM ); det = MxInvert(TM, iTM); if(det < L_EPSILON && det > -L_EPSILON) return( FALSE ); /*return( MxInvert(TM, iTM) );*/ else return ( TRUE ); }
int Ray_BlobAddCylinder(Object *obj, Vec3 *pt1, Vec3 *pt2, double radius, double field) { Bloblet *hemi1, *hemi2, *cyl; BlobData *blob = obj->data.blob; assert(obj != NULL); assert(blob != NULL); /* * Cylindrical fields consist of three Bloblet elements. * A cylinder and two hemispheres. */ /* Allocate the elements. */ if ((cyl = (Bloblet *)Malloc(sizeof(Bloblet))) == NULL) return 0; if ((hemi1 = (Bloblet *)Malloc(sizeof(Bloblet))) == NULL) { Free(cyl, sizeof(Bloblet)); return 0; } if ((hemi2 = (Bloblet *)Malloc(sizeof(Bloblet))) == NULL) { Free(hemi1, sizeof(Bloblet)); Free(cyl, sizeof(Bloblet)); return 0; } /* Link them together. */ cyl->next = hemi1; hemi1->next = hemi2; hemi2->next = NULL; /* Store the origin point, radius and field strength for cylinder. */ V3Copy(&cyl->loc, pt1); cyl->rad = radius; cyl->field = field; /* * Pre-compute constants for the density eq. in standard form. * Radii that are too small should be checked for during parse. */ cyl->rsq = cyl->rad * cyl->rad; cyl->r2 = -( 2.0 * cyl->field) / cyl->rsq; cyl->r4 = cyl->field / (cyl->rsq * cyl->rsq); /* Get offset vector of cylinder from the given end point. */ V3Sub(&cyl->d, pt2, &cyl->loc); /* * Get cylinder length squared & length, while we're at it... * Zero length offset vectors should be checked for during parse. */ cyl->lsq = V3Dot(&cyl->d, &cyl->d); cyl->len = sqrt(cyl->lsq); V3Copy(&cyl->dir, &cyl->d); V3Normalize(&cyl->dir); /* Get "d" coeffs. for planes at cylinder ends. */ cyl->d1 = -V3Dot(&cyl->dir, &cyl->loc); cyl->d2 = -V3Dot(&cyl->dir, pt2); /* Precompute location dot offset_vector constant. */ cyl->l_dot_d = V3Dot(&cyl->loc, &cyl->d); cyl->type = BLOB_CYLINDER; /* Set up the hemispheres for the ends of the cylinder. */ V3Copy(&hemi1->loc, &cyl->loc); V3Sub(&hemi1->dir, pt2, &hemi1->loc); V3Normalize(&hemi1->dir); hemi1->rad = cyl->rad; hemi1->rsq = cyl->rsq; hemi1->field = cyl->field; hemi1->r2 = cyl->r2; hemi1->r4 = cyl->r4; hemi1->type = BLOB_HEMISPHERE; V3Copy(&hemi2->loc, pt2); V3Sub(&hemi2->dir, &cyl->loc, &hemi2->loc); V3Normalize(&hemi2->dir); hemi2->rad = cyl->rad; hemi2->rsq = cyl->rsq; hemi2->field = cyl->field; hemi2->r2 = cyl->r2; hemi2->r4 = cyl->r4; hemi2->type = BLOB_HEMISPHERE; /* * Finally, add the three new elements that make up the cylinder * element to the blob. */ if (blob->elems != NULL) { Bloblet *lastbe; for (lastbe = blob->elems; lastbe->next != NULL; lastbe = lastbe->next) ; /* Seek last element added to list. */ /* Append our new one. */ lastbe->next = cyl; } else blob->elems = cyl; return 1; }
void SetupColorTriangle(ColorTriangleData *tri) { Vec3 V1, V2, N; double len; int i; /* Compute plane normal. */ V1.x = tri->pts[3] - tri->pts[0]; V2.x = tri->pts[6] - tri->pts[0]; V1.y = tri->pts[4] - tri->pts[1]; V2.y = tri->pts[7] - tri->pts[1]; V1.z = tri->pts[5] - tri->pts[2]; V2.z = tri->pts[8] - tri->pts[2]; V3Cross(&N, &V1, &V2); V3Normalize(&N); tri->pnorm[0] = (float)N.x; tri->pnorm[1] = (float)N.y; tri->pnorm[2] = (float)N.z; /* Normalize the vertex normals. */ for(i = 0; i < 9; i += 3) { if((tri->norms[i] * N.x + tri->norms[i+1] * N.y + tri->norms[i+2] * N.z) < 0.0) { tri->norms[i] = - tri->norms[i]; tri->norms[i+1] = - tri->norms[i+1]; tri->norms[i+2] = - tri->norms[i+2]; } len = sqrt(tri->norms[i] * tri->norms[i] + tri->norms[i+1] * tri->norms[i+1] + tri->norms[i+2] * tri->norms[i+2]); if(len > EPSILON) { tri->norms[i] /= (float)len; tri->norms[i+1] /= (float)len; tri->norms[i+2] /= (float)len; } else /* Use the plane normal for bad vertex normals. */ { tri->norms[i] = (float)N.x; tri->norms[i+1] = (float)N.y; tri->norms[i+2] = (float)N.z; } } /* Determine axis of greatest projection. */ if(fabs(N.x) > fabs(N.z)) { if(fabs(N.x) > fabs(N.y)) tri->axis = X_AXIS; else if(fabs(N.y) > fabs(N.z)) tri->axis = Y_AXIS; else tri->axis = Z_AXIS; } else if(fabs(N.y) > fabs(N.z)) tri->axis = Y_AXIS; else tri->axis = Z_AXIS; }
void CalcNormalColorTriangle(Object *obj, Vec3 *P, Vec3 *N) { ColorTriangleData *tri = obj->data.colortri; double area, a1, a2, a3, u, v; float *P1, *P2, *P3; float *N1, *N2, *N3; int A, B; /* * Project the triangle vertices to the 2D plane * that is most perpendicular to the plane normal. */ switch(tri->axis) { case X_AXIS: A = 1; B = 2; u = P->y; v = P->z; break; case Y_AXIS: A = 0; B = 2; u = P->x; v = P->z; break; default: /* Z_AXIS */ A = 0; B = 1; u = P->x; v = P->y; break; } P1 = tri->pts; P2 = &tri->pts[3]; P3 = &tri->pts[6]; /* Determine barycentric coordinates of point... */ area = ColorTriangleArea(P1[A], P1[B], P2[A], P2[B], P3[A], P3[B]); a1 = ColorTriangleArea(u, v, P2[A], P2[B], P3[A], P3[B]) / area; a2 = ColorTriangleArea(P1[A], P1[B], u, v, P3[A], P3[B]) / area; a3 = 1.0 - a1 - a2; /* * ...and use them to interpolate between the vertex normals * to get the real normal and likewise for the vertex colors. */ N1 = tri->norms; N2 = &tri->norms[3]; N3 = &tri->norms[6]; N->x = N1[0] * a1 + N2[0] * a2 + N3[0] * a3; N->y = N1[1] * a1 + N2[1] * a2 + N3[1] * a3; N->z = N1[2] * a1 + N2[2] * a2 + N3[2] * a3; V3Normalize(N); N1 = tri->colors; N2 = &tri->colors[3]; N3 = &tri->colors[6]; tri->r = (float)(N1[0] * a1 + N2[0] * a2 + N3[0] * a3); tri->g = (float)(N1[1] * a1 + N2[1] * a2 + N3[1] * a3); tri->b = (float)(N1[2] * a1 + N2[2] * a2 + N3[2] * a3); }
void eval_vnorm(Expr *expr) { expr->l->fn(expr->l); V3Copy(&expr->v, &expr->l->v); V3Normalize(&expr->v); }
Object *Ray_MakeBlob(PARAMS *par) { Object *obj; int token, num_elems, i; PARAMS *p; BlobData *b; Bloblet *be, *new_be, *hemi1, *hemi2, *cyl; static Vec3 pt; if((obj = NewObject()) == NULL) return NULL; /* evaluate parameters */ p = par; while(1) { Eval_Params(p); for(i = p->more; i >= 0; i--) p = p->next; if(p == NULL) break; p = p->next; /* skip element type delimiter */ } /* Allocate the main blob data structure... */ b = (BlobData *)Malloc(sizeof(BlobData)); b->nrefs = 1; /* Get threshold... */ b->threshold = par->V.x; b->solver = 0; b->bound = NULL; /* Get blob elements... */ be = NULL; num_elems = 0; while((par = par->next) != NULL) { token = par->type; /* Get blob element... */ switch(token) { case BLOB_SPHERE: case BLOB_PLANE: case BLOB_CYLINDER: for(i = 0; i < 3; i++) { /* Allocate a "Bloblet" structure. */ new_be = (Bloblet *)Malloc(sizeof(Bloblet)); new_be->next = NULL; new_be->field = 1.0; /* Default field strength, if not given. */ if(be == NULL) /* First one, start the list. */ { be = new_be; b->elems = be; } else /* Add to the list. */ { be->next = new_be; be = be->next; } num_elems++; if(token != BLOB_CYLINDER) break; /* Save references to the hemisphere sub-elements for cylinder. */ if(i == 0) cyl = new_be; else if(i == 1) hemi1 = new_be; else hemi2 = new_be; } par = par->next; break; default: break; } /* Get parameters... */ switch(token) { case BLOB_SPHERE: V3Copy(&be->loc, &par->V); par = par->next; be->rad = par->V.x; if(par->more) /* Optional field strength was specified, also. */ { par = par->next; be->field = par->V.x; } /* Pre-compute constants for the density eq. in standard form. */ /* Radii that are too small shoud be checked for during parse. */ be->rsq = be->rad * be->rad; be->r2 = - (2.0 * be->field) / be->rsq; be->r4 = be->field / (be->rsq * be->rsq); be->type = BLOB_SPHERE; continue; case BLOB_PLANE: V3Copy(&be->loc, &par->V); par = par->next; V3Copy(&be->dir, &par->V); par = par->next; be->rad = par->V.x; if(par->more) /* Optional field strength was specified, also. */ { par = par->next; be->field = par->V.x; } /* Normalize the normal vector. */ /* Invalid normals should be checked for during parse. */ V3Normalize(&be->dir); /* Get "d" coeff. for plane that bounds plane's interval. */ pt.x = be->dir.x * be->rad; pt.y = be->dir.y * be->rad; pt.z = be->dir.z * be->rad; be->d1 = -V3Dot(&be->dir, &pt); /* Pre-compute constants for the density eq. in standard form. */ /* Radii that are too small shoud be checked for during parse. */ be->rsq = be->rad * be->rad; be->r2 = - (2.0 * be->field) / be->rsq; be->r4 = be->field / (be->rsq * be->rsq); be->type = BLOB_PLANE; continue; case BLOB_CYLINDER: V3Copy(&cyl->loc, &par->V); par = par->next; V3Copy(&pt, &par->V); /* end point for cylinder */ par = par->next; cyl->rad = par->V.x; if(par->more) /* Optional field strength was specified, also. */ { par = par->next; cyl->field = par->V.x; } /* Pre-compute constants for the density eq. in standard form. */ /* Radii that are too small shoud be checked for during parse. */ cyl->rsq = cyl->rad * cyl->rad; cyl->r2 = -( 2.0 * cyl->field) / cyl->rsq; cyl->r4 = cyl->field / (cyl->rsq * cyl->rsq); /* Get offset vector of cylinder. */ V3Sub(&cyl->d, &pt, &cyl->loc); /* Get cylinder length squared & length, while we're at it... */ /* Zero length offset vectors shoud be checked for during parse. */ cyl->lsq = V3Dot(&cyl->d, &cyl->d); cyl->len = sqrt(cyl->lsq); V3Copy(&cyl->dir, &cyl->d); V3Normalize(&cyl->dir); /* Get "d" coeffs. for planes at cylinder ends. */ cyl->d1 = -V3Dot(&cyl->dir, &cyl->loc); cyl->d2 = -V3Dot(&cyl->dir, &pt); /* Precompute location dot offset_vector constant. */ cyl->l_dot_d = V3Dot(&cyl->loc, &cyl->d); cyl->type = BLOB_CYLINDER; /* Set up the hemispheres for the ends of the cylinder. */ V3Copy(&hemi1->loc, &cyl->loc); V3Sub(&hemi1->dir, &pt, &hemi1->loc); V3Normalize(&hemi1->dir); hemi1->rad = cyl->rad; hemi1->rsq = cyl->rsq; hemi1->field = cyl->field; hemi1->r2 = cyl->r2; hemi1->r4 = cyl->r4; hemi1->type = BLOB_HEMISPHERE; V3Copy(&hemi2->loc, &pt); V3Sub(&hemi2->dir, &cyl->loc, &hemi2->loc); V3Normalize(&hemi2->dir); hemi2->rad = cyl->rad; hemi2->rsq = cyl->rsq; hemi2->field = cyl->field; hemi2->r2 = cyl->r2; hemi2->r4 = cyl->r4; hemi2->type = BLOB_HEMISPHERE; continue; default: break; } break; } /* * Blobs must have at least one element, this should be checked * for during parse. */ /* Some assembly required... */ b->hits = (BlobHit **)Malloc(sizeof(BlobHit *) * num_elems * 2); for (i = 0; i < num_elems * 2; i++) b->hits[i] = (BlobHit *)Malloc(sizeof(BlobHit)); obj->data.blob = b; obj->procs = &blob_procs; return obj; }
parg_mesh* parg_mesh_torus(int slices, int stacks, float major, float minor) { parg_mesh* surf = malloc(sizeof(struct parg_mesh_s)); float dphi = PARG_TWOPI / stacks; float dtheta = PARG_TWOPI / slices; int vertexCount = slices * stacks * 3; int vertexStride = sizeof(float) * 3; surf->coords = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); surf->uvs = 0; Point3* position = (Point3*) parg_buffer_lock(surf->coords, PARG_WRITE); for (int slice = 0; slice < slices; slice++) { float theta = slice * dtheta; for (int stack = 0; stack < stacks; stack++) { float phi = stack * dphi; *position++ = torus_fn(major, minor, phi, theta); } } parg_buffer_unlock(surf->coords); surf->normals = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); Vector3* normal = (Vector3*) parg_buffer_lock(surf->normals, PARG_WRITE); for (int slice = 0; slice < slices; slice++) { float theta = slice * dtheta; for (int stack = 0; stack < stacks; stack++) { float phi = stack * dphi; Point3 p = torus_fn(major, minor, phi, theta); Point3 p1 = torus_fn(major, minor, phi, theta + 0.01); Point3 p2 = torus_fn(major, minor, phi + 0.01, theta); Vector3 du = P3Sub(p2, p); Vector3 dv = P3Sub(p1, p); *normal = V3Normalize(V3Cross(du, dv)); ++normal; } } parg_buffer_unlock(surf->normals); surf->ntriangles = slices * stacks * 2; int indexCount = surf->ntriangles * 3; surf->indices = parg_buffer_alloc(indexCount * 2, PARG_GPU_ELEMENTS); uint16_t* index = (uint16_t*) parg_buffer_lock(surf->indices, PARG_WRITE); int v = 0; for (int i = 0; i < slices - 1; i++) { for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = v + next + stacks; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = v + j + stacks; *index++ = v + next + stacks; } v += stacks; } for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = next; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = j; *index++ = next; } parg_buffer_unlock(surf->indices); return surf; }
void PezRender() { #define Instances 7 Matrix4 Model[Instances]; Model[0] = M4MakeRotationY(Globals.Theta); Model[1] = M4Mul(M4Mul( M4MakeTranslation((Vector3){0, 0, 0.6}), M4MakeScale(V3MakeFromScalar(0.25))), M4MakeRotationX(Pi/2) ); Model[2] = Model[3] = Model[4] = Model[1]; Model[1] = M4Mul(M4MakeRotationY(Globals.Theta), Model[1]); Model[2] = M4Mul(M4MakeRotationY(Globals.Theta + Pi/2), Model[2]); Model[3] = M4Mul(M4MakeRotationY(Globals.Theta - Pi/2), Model[3]); Model[4] = M4Mul(M4MakeRotationY(Globals.Theta + Pi), Model[4]); Model[5] = M4Mul(M4Mul( M4MakeScale(V3MakeFromScalar(0.5)), M4MakeTranslation((Vector3){0, 1.25, 0})), M4MakeRotationY(-Globals.Theta) ); Model[6] = M4Mul(M4Mul( M4MakeScale(V3MakeFromScalar(0.5)), M4MakeTranslation((Vector3){0, -1.25, 0})), M4MakeRotationY(-Globals.Theta) ); Vector3 LightPosition = {0.5, 0.25, 1.0}; // world space Vector3 EyePosition = {0, 0, 1}; // world space Matrix4 MVP[Instances]; Vector3 Lhat[Instances]; Vector3 Hhat[Instances]; for (int i = 0; i < Instances; i++) { Matrix4 mv = M4Mul(Globals.View, Model[i]); MVP[i] = M4Mul(Globals.Projection, mv); Matrix3 m = M3Transpose(M4GetUpper3x3(Model[i])); Lhat[i] = M3MulV3(m, V3Normalize(LightPosition)); // object space Vector3 Eye = M3MulV3(m, V3Normalize(EyePosition)); // object space Hhat[i] = V3Normalize(V3Add(Lhat[i], Eye)); } int instanceCount = Instances; MeshPod* mesh = &Globals.Cylinder; glBindFramebuffer(GL_FRAMEBUFFER, Globals.FboHandle); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glUseProgram(Globals.LitProgram); glUniform3f(u("SpecularMaterial"), 0.4, 0.4, 0.4); glUniform4f(u("FrontMaterial"), 0, 0, 1, 1); glUniform4f(u("BackMaterial"), 0.5, 0.5, 0, 1); glUniform3fv(u("Hhat"), Instances, &Hhat[0].x); glUniform3fv(u("Lhat"), Instances, &Lhat[0].x); glUniformMatrix4fv(u("ModelviewProjection"), Instances, 0, (float*) &MVP[0]); glBindVertexArray(mesh->FillVao); glDrawElementsInstanced(GL_TRIANGLES, mesh->FillIndexCount, GL_UNSIGNED_SHORT, 0, instanceCount); glUseProgram(Globals.SimpleProgram); glUniform4f(u("Color"), 0, 0, 0, 1); glUniformMatrix4fv(u("ModelviewProjection"), Instances, 0, (float*) &MVP[0]); glDepthMask(GL_FALSE); glBindVertexArray(mesh->LineVao); glDrawElementsInstanced(GL_LINES, mesh->LineIndexCount, GL_UNSIGNED_SHORT, 0, instanceCount); glDepthMask(GL_TRUE); glDisable(GL_DEPTH_TEST); glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(Globals.QuadProgram); glBindTexture(GL_TEXTURE_2D, Globals.FboTexture); glBindVertexArray(Globals.Grid.FillVao); glDrawElements(GL_TRIANGLES, Globals.Grid.FillIndexCount, GL_UNSIGNED_SHORT, 0); if (1) { glUseProgram(Globals.GridProgram); glBindVertexArray(Globals.Grid.LineVao); glDrawElements(GL_LINES, Globals.Grid.LineIndexCount, GL_UNSIGNED_SHORT, 0); } glBindTexture(GL_TEXTURE_2D, 0); }
void CalcNormalBlob(Object *obj, Vec3 *Q, Vec3 *N) { BlobData *b; Bloblet *be; double dist, x, y, z, a; Vec3 p; b = obj->data.blob; V3Copy(&p, Q); if (obj->T != NULL) PointToObject(&p, obj->T); V3Zero(N); for (be = b->elems; be != NULL; be = be->next) { x = p.x - be->loc.x; y = p.y - be->loc.y; z = p.z - be->loc.z; if (be->type == BLOB_CYLINDER) { double t; /* get distance of point along cylinder axis from cylinder origin */ t = x * be->dir.x + y * be->dir.y + z * be->dir.z; /* are we within cylinder length? */ if (t >= 0.0 && t < be->len) /* yes */ { /* get radius-squared from correponding point along cylinder axis */ x -= be->dir.x * t; y -= be->dir.y * t; z -= be->dir.z * t; /* If point is outside radius of influence, it doesn't count. */ if ((dist = x*x + y*y + z*z) >= be->rsq) continue; } else continue; /* Outside of cylinder length. */ } else if (be->type == BLOB_PLANE) { if ((dist = x * be->dir.x + y * be->dir.y + z * be->dir.z) >= be->rad) continue; x = be->dir.x; y = be->dir.y; z = be->dir.z; } else /* Spheres or hemi-spheres. */ { /* If point is outside sphere of influence, it doesn't count. */ if ((dist = x*x + y*y + z*z) >= be->rsq) continue; /* See that point is also within the plane if this is a hemisphere. */ if (be->type == BLOB_HEMISPHERE) if ((x * be->dir.x + y * be->dir.y + z * be->dir.z) > 0.0) continue; } /* * Note: Since this is actually the gradient for the inward facing * surface of the density equation(s), we need to flip the sign so * that the normal is pointing out from the blob. The outer surface * of the density equation is "mirrored" on the outside of the * field of influence for the blob element (due to the "W" shape * of the density function) and does not fall within the interval * containing valid blob intersections. These are checked for * and skipped in the intersection tests above. */ a = - 4.0 * be->r4 * dist - 2.0 * be->r2; N->x += x * a; N->y += y * a; N->z += z * a; } if (obj->T != NULL) NormToWorld(N, obj->T); V3Normalize(N); }