diff --git a/dev/src/geom.h b/dev/src/geom.h index a3761b5b8..dd8519363 100644 --- a/dev/src/geom.h +++ b/dev/src/geom.h @@ -24,6 +24,8 @@ { const int i = 3; F; } } } } #define DOVECR(F) { vec _t; DOVEC(_t.set(i, F)); return _t; } +#define DOVECF(I,F) { T x = I; DOVEC(x = F); return x; } +#define DOVECB(I,F) { bool x = I; DOVEC(x = F); return x; } union int2float { int i; float f; }; inline void default_debug_value(float &a) { int2float nan; nan.i = 0x7F800001; a = nan.f; } @@ -109,31 +111,31 @@ template class vec { vec &operator/=(T e) { DOVEC(c[i] /= e); return *this; } bool operator<=(const vec &v) const { - bool all = true; DOVEC(all = all && c[i] <= v[i]); return all; + DOVECB(true, x && c[i] <= v[i]); } bool operator< (const vec &v) const { - bool all = true; DOVEC(all = all && c[i] < v[i]); return all; + DOVECB(true, x && c[i] < v[i]); } bool operator>=(const vec &v) const { - bool all = true; DOVEC(all = all && c[i] >= v[i]); return all; + DOVECB(true, x && c[i] >= v[i]); } bool operator> (const vec &v) const { - bool all = true; DOVEC(all = all && c[i] > v[i]); return all; + DOVECB(true, x && c[i] > v[i]); } bool operator==(const vec &v) const { - bool all = true; DOVEC(all = all && c[i] == v[i]); return all; + DOVECB(true, x && c[i] == v[i]); } bool operator!=(const vec &v) const { - bool any = false; DOVEC(any = any || c[i] != v[i]); return any; + DOVECB(false, x || c[i] != v[i]); } - bool operator<=(T e) const { bool all = true; DOVEC(all = all && c[i] <= e); return all; } - bool operator< (T e) const { bool all = true; DOVEC(all = all && c[i] < e); return all; } - bool operator>=(T e) const { bool all = true; DOVEC(all = all && c[i] >= e); return all; } - bool operator> (T e) const { bool all = true; DOVEC(all = all && c[i] > e); return all; } + bool operator<=(T e) const { DOVECB(true, x && c[i] <= e); } + bool operator< (T e) const { DOVECB(true, x && c[i] < e); } + bool operator>=(T e) const { DOVECB(true, x && c[i] >= e); } + bool operator> (T e) const { DOVECB(true, x && c[i] > e); } - bool operator==(T e) const { bool all = true; DOVEC(all = all && c[i] == e); return all; } - bool operator!=(T e) const { bool any = false; DOVEC(any = any || c[i] != e); return any; } + bool operator==(T e) const { DOVECB(true, x && c[i] == e); } + bool operator!=(T e) const { DOVECB(false, x || c[i] != e); } vec iflt(T e, const vec &a, const vec &b) const { DOVECR(c[i] < e ? a[i] : b[i]); } @@ -143,7 +145,7 @@ template class vec { return s + ")"; } - T volume() const { T r = 1; DOVEC(r *= c[i]); return r; } + T volume() const { DOVECF(1, x * c[i]); } template friend class matrix; }; @@ -165,8 +167,7 @@ template inline vec operator*(T f, const vec &v) { template inline vec operator/(T f, const vec &v) { DOVECR(f / v[i]); } template inline T dot(const vec &a, const vec &b) { - T t = 0; DOVEC(t += a[i] * b[i]); - return t; + DOVECF(0, x + a[i] * b[i]); } template inline T squaredlength(const vec &v) { return dot(v, v); } template inline T length(const vec &v) { return sqrtf(squaredlength(v)); } @@ -191,6 +192,13 @@ template inline vec rpow(const vec &a, const vec inline T min(const vec &a) { + DOVECF(FLT_MAX, x = min(a[i], x)); +} +template inline T max(const vec &a) { + DOVECF(-FLT_MAX, x = max(a[i], x)); +} + template inline vec ceilf(const vec &v) { DOVECR(ceilf(v[i])); } template inline vec floorf(const vec &v) { DOVECR(floorf(v[i])); } @@ -698,6 +706,10 @@ inline float3 cardinalspline(const float3 &z, const float3 &a, const float3 &b, (c - a) * tension * ( s3 - s2 ); } +inline float triangle_area(const float3 &a, const float3 &b, const float3 &c) { + return length(cross(b - a, c - a)) / 2; +} + inline bool line_intersect(const float2 &l1a, const float2 &l1b, const float2 &l2a, const float2 &l2b, float2 *out = nullptr) { float2 a(l1b - l1a); diff --git a/dev/src/meshgen.cpp b/dev/src/meshgen.cpp index 3d24b50e3..eb2a60a7c 100644 --- a/dev/src/meshgen.cpp +++ b/dev/src/meshgen.cpp @@ -41,7 +41,7 @@ struct ImplicitFunction { virtual ~ImplicitFunction() {} - inline bool Eval(const float3 & /*pos*/) const { return false; } + inline float Eval(const float3 & /*pos*/) const = delete; virtual float3 ComputeSize() { return size; }; virtual void FillGrid(const int3 &start, const int3 &end, FIndexGrid *fcellindices, @@ -67,7 +67,7 @@ template struct ImplicitFunctionImpl : ImplicitFunction { pos -= gridtrans; pos = pos * gridrot; pos /= gridscale; - bool inside = static_cast(this)->Eval(pos); + bool inside = static_cast(this)->Eval(pos) < 0.0f; // Bounding box is supposed to cover the entire shape with 1 empty cell surrounding in // all directions. assert(!inside || (ipos > start && ipos < end - 1)); @@ -87,7 +87,7 @@ template struct ImplicitFunctionImpl : ImplicitFunction { // FIXME: factor this out, or make cell lookup if (inside || static_cast(this)->Eval(pos - (axesf[i] * gridrot) / - gridscale)) { + gridscale) < 0.0f) { auto solidpos = float3(tmat ? ipos : opos); auto emptypos = float3(tmat ? opos : ipos); auto p1f = solidpos; @@ -103,7 +103,7 @@ template struct ImplicitFunctionImpl : ImplicitFunction { p2 -= gridtrans; p2 = p2 * gridrot; p2 /= gridscale; - if (static_cast(this)->Eval(p2) == (material != 0)) + if ((static_cast(this)->Eval(p2) < 0.0f) == (material != 0)) p1f = p; else p2f = p; @@ -135,81 +135,104 @@ template struct ImplicitFunctionImpl : ImplicitFunction { }; struct IFSphere : ImplicitFunctionImpl { - inline bool Eval(const float3 &pos) const { return dot(pos, pos) <= 1; } + float rad; + + inline float Eval(const float3 &pos) const { + return length(pos) - rad; + } + + float3 ComputeSize() { return size * rad; } }; struct IFCube : ImplicitFunctionImpl { - inline bool Eval(const float3 &pos) const { return abs(pos) <= 1; } + float3 extents; + + inline float Eval(const float3 &pos) const { + auto d = abs(pos) - extents; + //return max(d); + return length(max(d, float3_0)) + max(min(d, float3_0)); + } + + float3 ComputeSize() { return size * extents; } }; struct IFCylinder : ImplicitFunctionImpl { - inline bool Eval(const float3 &pos) const { - return pos.z() <= 1 && pos.z() >= -1 && dot(pos.xy(), pos.xy()) <= 1; + float radius, height; + + inline float Eval(const float3 &pos) const { + return max(length(pos.xy()) - radius, abs(pos.z()) - height); } + + float3 ComputeSize() { return size * float3(radius, radius, height); } }; struct IFTaperedCylinder : ImplicitFunctionImpl { - float bot, top; + float bot, top, height; - inline bool Eval(const float3 &pos) const { + inline float Eval(const float3 &pos) const { auto xy = pos.xy(); - auto r = mix(bot, top, pos.z() / 2 + 0.5f); - return pos.z() <= 1 && pos.z() >= -1 && dot(xy, xy) <= r * r; + auto r = mix(bot, top, pos.z() / (height * 2) + 0.5f); + // FIXME: this is probably not the correct distance. + return max(abs(pos.z()) - height, dot(xy, xy) - r * r); } float3 ComputeSize() { auto rad = max(top, bot); - return size * float3(rad, rad, 1); + return size * float3(rad, rad, height); } }; // TODO: pow is rather slow... - struct IFSuperQuadric : ImplicitFunctionImpl { float3 exp; + float3 scale; - inline bool Eval(const float3 &pos) const { - return dot(pow(abs(pos), exp), float3_1) <= 1; + inline float Eval(const float3 &pos) const { + return dot(pow(abs(pos) / scale, exp), float3_1) - 1; } -}; - -struct IFSuperToroid : ImplicitFunctionImpl { - float r; - float3 exp; - inline bool Eval(const float3 &pos) const { - auto p = pow(abs(pos), exp); - auto xy = r - sqrtf(p.x() + p.y()); - return powf(fabsf(xy), exp.z()) + p.z() <= 1; - } - - float3 ComputeSize() { return size * float3(r * 2 + 1, r * 2 + 1, 1); } + float3 ComputeSize() { return size * scale; } }; struct IFSuperQuadricNonUniform : ImplicitFunctionImpl { float3 exppos, expneg; float3 scalepos, scaleneg; - inline bool Eval(const float3 &pos) const { + inline float Eval(const float3 &pos) const { auto d = pos.iflt(0, scaleneg, scalepos); auto e = pos.iflt(0, expneg, exppos); auto p = abs(pos) / d; - return p < 1 && dot(pow(p, e), float3_1) <= 1; + // FIXME: why is max(p) even needed? not needed in IFSuperQuadric + return max(max(p), dot(pow(p, e), float3_1)) - 1; } float3 ComputeSize() { return size * max(scalepos, scaleneg); } }; +struct IFSuperToroid : ImplicitFunctionImpl { + float r; + float3 exp; + + inline float Eval(const float3 &pos) const { + auto p = pow(abs(pos), exp); + auto xy = r - sqrtf(p.x() + p.y()); + return powf(fabsf(xy), exp.z()) + p.z() - 1; + } + + float3 ComputeSize() { return size * float3(r * 2 + 1, r * 2 + 1, 1); } +}; + struct IFLandscape : ImplicitFunctionImpl { float zscale, xyscale; - inline bool Eval(const float3 &pos) const { + inline float Eval(const float3 &pos) const { if (!(abs(pos) <= 1)) return false; auto dpos = pos + float3(SimplexNoise(8, 0.5f, 1, float4(pos.xy() + 1, 0)), SimplexNoise(8, 0.5f, 1, float4(pos.xy() + 2, 0)), 0) / 2; auto f = SimplexNoise(8, 0.5f, xyscale, float4(dpos.xy(), 0)) * zscale; - return dpos.z() < f; + // FIXME: this is obviously not the correct distance for anything but peaks. + return dpos.z() - f; } }; @@ -220,7 +243,7 @@ struct Group : ImplicitFunctionImpl { for (auto c : children) delete c; } - static inline bool Eval(const float3 & /*pos*/) { return false; } + static inline float Eval(const float3 & /*pos*/) { return 0.0f; } float3 ComputeSize() { float3 p1, p2; @@ -239,12 +262,13 @@ struct Group : ImplicitFunctionImpl { vector &fcells, const float3 &gridscale, const float3 &gridtrans, const float3x3 & /*gridrot*/) const { for (auto c : children) { - if (dot(c->size, gridscale) > 3) { + auto csize = c->ComputeSize(); + if (dot(csize, gridscale) > 3) { auto trans = gridtrans + c->orig * gridscale; auto scale = gridscale * c->size; //auto _start = int3(trans - c->size * gridscale - 0.01f); //auto _end = int3(trans + c->size * gridscale + 2.01f); - auto rsize = rotated_size(c->rot, c->ComputeSize()); + auto rsize = rotated_size(c->rot, csize); auto start = int3(trans - rsize * gridscale - 0.01f); auto end = int3(trans + rsize * gridscale + 2.01f); auto bs = end - start; @@ -328,8 +352,14 @@ Mesh *polygonize_mc(const int3 &gridsize, float gridscale, const float3 &gridtra } vertlist[i] = idx; } - for (int i = 0; mc_tri_table[ci][i] != -1; i++) { - mctriangles.push_back(vertlist[mc_tri_table[ci][i]]); + for (int i = 0; mc_tri_table[ci][i] != -1; ) { + auto e1 = vertlist[mc_tri_table[ci][i++]]; + auto e2 = vertlist[mc_tri_table[ci][i++]]; + auto e3 = vertlist[mc_tri_table[ci][i++]]; + mctriangles.push_back(e1); + mctriangles.push_back(e2); + mctriangles.push_back(e3); + assert(triangle_area(edges[e1].fmid, edges[e2].fmid, edges[e3].fmid) < 1); } } } else { @@ -672,45 +702,53 @@ Value AddShape(ImplicitFunction *f) { } void AddMeshGen() { - STARTDECL(mg_sphere) () { return AddShape(new IFSphere()); } - ENDDECL0(mg_sphere, "", "", "", - "a unit sphere"); - STARTDECL(mg_cube) () { return AddShape(new IFCube()); } - ENDDECL0(mg_cube, "", "", "", - "a unit cube (fits around unit sphere)"); - STARTDECL(mg_cylinder) () { return AddShape(new IFCylinder()); } - ENDDECL0(mg_cylinder, "", "", "", - "a unit cylinder (fits around unit sphere)"); - - STARTDECL(mg_tapered_cylinder) (Value &bot, Value &top) { + STARTDECL(mg_sphere) (Value &rad) { + auto s = new IFSphere(); + s->rad = rad.fval(); + return AddShape(s); + } + ENDDECL1(mg_sphere, "radius", "F", "", + "a sphere"); + + STARTDECL(mg_cube) (Value &ext) { + auto c = new IFCube(); + c->extents = ValueDecToF<3>(ext); + return AddShape(c); + } + ENDDECL1(mg_cube, "extents", "F]:3", "", + "a cube (extents are size from center)"); + + STARTDECL(mg_cylinder) (Value &radius, Value &height) { + auto c = new IFCylinder(); + c->radius = radius.fval(); + c->height = height.fval(); + return AddShape(c); + } + ENDDECL2(mg_cylinder, "radius,height", "FF", "", + "a unit cylinder (height is from center)"); + + STARTDECL(mg_tapered_cylinder) (Value &bot, Value &top, Value &height) { auto tc = new IFTaperedCylinder(); tc->bot = bot.fval(); tc->top = top.fval(); + tc->height = height.fval(); return AddShape(tc); } - ENDDECL2(mg_tapered_cylinder, "bot,top", "FF", "", - "a cyclinder where you specify the top and bottom radius, height still 2"); + ENDDECL3(mg_tapered_cylinder, "bot,top,height", "FFF", "", + "a cyclinder where you specify the top and bottom radius (height is from center)"); - STARTDECL(mg_superquadric) (Value &exps) { + STARTDECL(mg_superquadric) (Value &exps, Value &scale) { auto sq = new IFSuperQuadric(); sq->exp = ValueDecToF<3>(exps); + sq->scale = ValueDecToF<3>(scale); return AddShape(sq); } - ENDDECL1(mg_superquadric, "exponents", "F]", "", + ENDDECL2(mg_superquadric, "exponents,scale", "F]F]", "", "a super quadric. specify an exponent of 2 for spherical, higher values for rounded" " squares"); - STARTDECL(mg_supertoroid) (Value &r, Value &exps) { - auto t = new IFSuperToroid(); - t->r = r.fval(); - t->exp = ValueDecToF<3>(exps); - return AddShape(t); - } - ENDDECL2(mg_supertoroid, "R,exponents", "FF]", "", - "a super toroid. R is the distance from the origin to the center of the ring."); - STARTDECL(mg_superquadric_non_uniform) (Value &posexps, Value &negexps, Value &posscale, - Value &negscale) { + Value &negscale) { auto sq = new IFSuperQuadricNonUniform(); sq->exppos = ValueDecToF<3>(posexps); sq->expneg = ValueDecToF<3>(negexps); @@ -724,6 +762,15 @@ void AddMeshGen() { "a superquadric that allows you to specify exponents and sizes in all 6 directions" " independently for maximum modelling possibilities"); + STARTDECL(mg_supertoroid) (Value &r, Value &exps) { + auto t = new IFSuperToroid(); + t->r = r.fval(); + t->exp = ValueDecToF<3>(exps); + return AddShape(t); + } + ENDDECL2(mg_supertoroid, "R,exponents", "FF]", "", + "a super toroid. R is the distance from the origin to the center of the ring."); + STARTDECL(mg_landscape) (Value &zscale, Value &xyscale) { auto ls = new IFLandscape(); ls->zscale = zscale.fval(); @@ -802,6 +849,18 @@ void AddMeshGen() { "translates the current coordinate system along a vector. when a body is given," " restores the previous transform afterwards"); + STARTDECL(mg_scale) (Value &f, Value &body) { + if (body.True()) g_vm->Push(ToValueF(cursize)); + cursize *= f.fval(); + return body; + } + MIDDECL(mg_scale) () { + cursize = ValueDecToF<3>(g_vm->Pop()); + } + ENDDECL2CONTEXIT(mg_scale, "f,body", "FC?", "", + "scales the current coordinate system by the given factor." + " when a body is given, restores the previous transform afterwards"); + STARTDECL(mg_scalevec) (Value &vec, Value &body) { if (body.True()) g_vm->Push(ToValueF(cursize)); auto v = ValueDecToF<3>(vec); diff --git a/lobster/lobster.exe b/lobster/lobster.exe index d2467b881..de9ee6b20 100644 Binary files a/lobster/lobster.exe and b/lobster/lobster.exe differ diff --git a/lobster/samples/mgtest.lobster b/lobster/samples/mgtest.lobster index 7b7db710a..94f175dd6 100644 --- a/lobster/samples/mgtest.lobster +++ b/lobster/samples/mgtest.lobster @@ -20,35 +20,37 @@ def mg_mirror_y(dist, body): aspoints := false mg_set_pointmode(aspoints) if !aspoints: - mg_set_polygonreduction(3, 0.98, 0.95) + //mg_set_polygonreduction(3, 0.98, 0.95) mg_set_vertrandomize(0) density := 80 +abstract := nil +if true: + mg_rotate(xyz_y, 45): + //mg_cube(xyz_1) + mg_superquadric(xyz_1 * 20, xyz_1) // Cube with rounded edges + abstract = mg_polygonize(density, [ color_white ]) + gun := nil if true: mg_rotate(xyz_y, 90.0): mg_scalevec([ 1.0, 1.3, 1.0 ]): mg_supertoroid(3.0, [3.0, 3.0, 5.0]) mg_translate([ 0.0, -1.3, 2.0 ]): - mg_scalevec([ 0.5, 0.5, 3.5 ]): - mg_rotate(xyz_x, 20.0): - mg_superquadric([ 3.0, 3.0, 3.0 ]) + mg_rotate(xyz_x, 20.0): + mg_superquadric([ 3.0, 3.0, 3.0 ], [ 0.5, 0.5, 3.5 ]) mg_translate([ 0.0, -8.0, 4.0 ]): - mg_scalevec([ 0.5, 0.5, 2.5 ]): - mg_rotate(xyz_x, 30.0): - mg_superquadric([ 3.0, 3.0, 3.0 ]) + mg_rotate(xyz_x, 30.0): + mg_superquadric([ 3.0, 3.0, 3.0 ], [ 0.5, 0.5, 2.5 ]) mg_translate([ 0.0, -5.5, -3.0 ]): - mg_scalevec([ 1.5, 2.5, 6.5 ]): - mg_rotate(xyz_x, -20.0): - mg_superquadric([ 5.0, 5.0, 100.0 ]) + mg_rotate(xyz_x, -20.0): + mg_superquadric([ 5.0, 5.0, 100.0 ], [ 1.5, 2.5, 6.5 ]) mg_translate([ 0.0, 2.0, 4.2 ]): - mg_scalevec([ 2.0, 10.0, 3.0 ]): - mg_superquadric([ 3.0, 100.0, 3.0 ]) + mg_superquadric([ 3.0, 100.0, 3.0 ], [ 2.0, 10.0, 3.0 ]) mg_translate([ 0.0, 14.0, 5.0 ]): - mg_scalevec([ 1.0, 1.0, 3.0 ]): - mg_rotate(xyz_x, 90.0): - mg_cylinder() + mg_rotate(xyz_x, 90.0): + mg_cylinder(1, 3) gun = mg_polygonize(density, [ [ 1.0, 1.0, 1.0 ], [ 1.0, 1.0, 1.0 ] ]) spaceship := nil @@ -59,39 +61,34 @@ if true: mg_superquadric_non_uniform([ 2.0, 2.0, 1.0 ], [ 2.0, 2.0, 2.0 ], [ 1.0, 0.5, 0.4 ], [ 0.5, 0.5, 0.5 ]) mg_mirror_y(1.5): mg_translate(xyz_x): - mg_scalevec([ 1.3, 0.2, 0.2 ]): - mg_superquadric([ 100.0, 2.0, 2.0 ]) + mg_superquadric([ 100.0, 2.0, 2.0 ], [ 1.3, 0.2, 0.2 ]) mg_mirror_y(2): mg_translate(xyz_x): - mg_scalevec([ 1.0, 0.15, 0.15 ]): - mg_superquadric([ 100.0, 2.0, 2.0 ]) + mg_superquadric([ 100.0, 2.0, 2.0 ], [ 1.0, 0.15, 0.15 ]) mg_mirror_y(1): mg_translate(xyz_x * -0.6): mg_superquadric_non_uniform([ 1.0, 2.0, 2.0 ], [ 1.0, 2.0, 2.0 ], [ 1.5, 0.5, 0.5 ], [ 0.01, 0.5, 0.5 ]) mg_fill(0): - mg_scalevec([ 0.35, 0.35, 0.35 ]): - mg_rotate(xyz_y, 90.0): - mg_cylinder() + mg_rotate(xyz_y, 90.0): + mg_cylinder(0.35, 0.25) spaceship = mg_polygonize(density * 2, [ [ 1.0, 1.0, 1.0 ], [ 0.5, 0.5, 1.0 ] ]) def model_tree(numb, branchl, narrowf, leafs): if numb: - mg_scalevec(xyz_1 * [ 1, 1, branchl ]): - mg_translate(xyz_z): - mg_tapered_cylinder(1, narrowf) - mg_translate(xyz_z * branchl * 2): - axis := sincos(rnd(360)) - branches := rnd(3) + 1 - for(branches) i: - mg_rotate(xyz_z, 360 * i / branches): - mg_rotate(axis, 12 * branches): - mg_scalevec(xyz_1 * narrowf): - mg_sphere() - model_tree(numb - 1, branchl, narrowf, leafs) + mg_translate(xyz_z * branchl): + mg_tapered_cylinder(1, narrowf, branchl) + mg_translate(xyz_z * branchl): + axis := sincos(rnd(360)) + branches := rnd(3) + 1 + for(branches) i: + mg_rotate(xyz_z, 360 * i / branches): + mg_rotate(axis, 12 * branches): + mg_scale(narrowf): + mg_sphere(1) + model_tree(numb - 1, branchl, narrowf, leafs) else: mg_fill(2): - mg_scalevec(xyz_1 * leafs): - mg_sphere() + mg_sphere(leafs) trees := [] @@ -114,6 +111,7 @@ if true: if gun: print "vertcount: gun " + gl_meshsize(gun) if spaceship: print "vertcount: ship " + gl_meshsize(spaceship) for trees: print("vertcount: tree1 " + gl_meshsize(_)) +if abstract: print "vertcount: abstract " + gl_meshsize(abstract) print seconds_elapsed() @@ -161,6 +159,12 @@ while gl_frame(): gl_pointscale(5 * fovscale) gl_rendermesh(landscape) + if abstract: + gl_translate(xy_y * 40): + gl_scale(5): + gl_pointscale(5 * fovscale) + gl_rendermesh(abstract) + for(10) j: gl_translate(xyz_y * j * -5): for(trees) t, i: diff --git a/lobster/samples/vrtest.lobster b/lobster/samples/vrtest.lobster index a64b983e9..96cb00b4e 100644 --- a/lobster/samples/vrtest.lobster +++ b/lobster/samples/vrtest.lobster @@ -13,27 +13,25 @@ fatal(gl_window(if vrmode: "VR Test" else: "No VR device", 1280, 640, false, vrm def model_tree(numb, branchl, narrowf, leafs): if numb: - mg_scalevec(xyz_1 * [ 1, 1, branchl ]): - mg_translate(xyz_z): - mg_tapered_cylinder(1, narrowf) + mg_translate(xyz_z * branchl): + mg_tapered_cylinder(1, narrowf, branchl) mg_translate(xyz_z * branchl * 2): axis := sincos(rnd(360)) branches := rnd(3) + 1 for(branches) i: mg_rotate(xyz_z, 360 * i / branches): mg_rotate(axis, 12 * branches): - mg_scalevec(xyz_1 * narrowf): - mg_sphere() + mg_scale(narrowf): + mg_sphere(1) model_tree(numb - 1, branchl, narrowf, leafs) else: mg_fill(2): - mg_scalevec(xyz_1 * leafs): - mg_sphere() + mg_sphere(leafs) model_tree(10, 1.5, 0.75, 12) tree := mg_polygonize(50, [[ 0.7, 0.6, 0.5 ], [ 0.6, 1.0, 0.6 ]]) -mg_sphere() +mg_sphere(1) sphere := mg_polygonize(3, [ color_red ]) camera_position = xyz { 0.0, 0.0, 3.0 }