aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llvotreenew.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llvotreenew.cpp')
-rw-r--r--linden/indra/newview/llvotreenew.cpp1470
1 files changed, 0 insertions, 1470 deletions
diff --git a/linden/indra/newview/llvotreenew.cpp b/linden/indra/newview/llvotreenew.cpp
deleted file mode 100644
index d7fc635..0000000
--- a/linden/indra/newview/llvotreenew.cpp
+++ /dev/null
@@ -1,1470 +0,0 @@
1/**
2 * @file llvotreenew.cpp
3 * @brief LLVOTreeNew class implementation
4 *
5 * Copyright (c) 2003-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llvotreenew.h"
31
32#include "llgl.h"
33#include "llglheaders.h"
34#include "lltree_common.h"
35#include "lltreeparams.h"
36#include "material_codes.h"
37#include "object_flags.h"
38
39#include "llagent.h"
40#include "llagparray.h"
41#include "llviewercontrol.h"
42#include "llcylinder.h"
43#include "lldrawable.h"
44#include "llface.h"
45#include "llprimitive.h"
46#include "llviewerimagelist.h"
47#include "llviewerobjectlist.h"
48#include "llviewerregion.h"
49#include "llworld.h"
50#include "noise.h"
51#include "pipeline.h"
52
53U32 LLVOTreeNew::sNextVertexIndex[MAX_SPECIES];
54U32 LLVOTreeNew::sNextIndiceIndex[MAX_SPECIES];
55U32 LLVOTreeNew::sNextPartIndex[MAX_PARTS];
56LLVOTreeNew::TreePart LLVOTreeNew::sTreeParts[MAX_SPECIES][MAX_PARTS];
57LLUUID LLVOTreeNew::sTreeImageIDs[MAX_SPECIES];
58U32 LLVOTreeNew::sTreePartsUsed[MAX_SPECIES][MAX_PARTS][MAX_VARS];
59LLTreeParams LLVOTreeNew::sParameters;
60F32 LLVOTreeNew::sRandNums[MAX_RAND_NUMS];
61
62extern LLPipeline gPipeline;
63
64// Tree variables and functions
65
66LLVOTreeNew::LLVOTreeNew(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp):
67 LLViewerObject(id, pcode, regionp)
68{
69 mTotalIndices = 0;
70 mTotalVerts = 0;
71 mSpecies = 0;
72}
73
74
75LLVOTreeNew::~LLVOTreeNew()
76{
77 if (mData)
78 {
79 delete[] mData;
80 mData = NULL;
81 }
82}
83
84
85void LLVOTreeNew::initClass()
86{
87 U8 i;
88
89 // for now just load the same texture in for every tree...
90
91 for (i = 0; i < MAX_SPECIES; i++)
92 {
93 switch (i) {
94 case (0):
95 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_pine_1.tga") );
96 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_pine_1.tga") ));
97 break;
98 case (1):
99 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_oak.tga") );
100 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_oak.tga") ));
101 break;
102 case (2):
103 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_tropical_1.tga") );
104 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_tropical_1.tga") ));
105 break;
106 case (3):
107 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_palm_1.tga") );
108 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_palm_1.tga") ));
109 break;
110 case (4):
111 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_dogwood.tga") );
112 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_dogwood.tga") ));
113 break;
114 case (5):
115 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_tropical_2.tga") );
116 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_tropical_2.tga") ));
117 break;
118 case (6):
119 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_palm_2.tga") );
120 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_palm_2.tga") ));
121 break;
122 case (7):
123 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_cypress_1.tga") );
124 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_cypress_1.tga") ));
125 break;
126 case (8):
127 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_cypress_2.tga") );
128 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_cypress_2.tga") ));
129 break;
130 default:
131 sTreeImageIDs[i] = LLUUID( gViewerArt.getString("tree_pine_2.tga") );
132 //LLVOTreeNew::sTreeImagep[i] = gImageList.getImage(LLUUID( gViewerArt.getString("tree_pine_2.tga") ));
133 break;
134 }
135 }
136
137
138 //LLVOTreeNew::sParameters = LLTreeParams();
139
140 // initialize an array of random numbers that we'll be using
141 LLRandLagFib607 tree_rand;
142 for (i = 0; i < MAX_RAND_NUMS; i++)
143 sRandNums[i] = (F32)tree_rand();
144}
145
146/*
147void LLVOTreeNew::cleanupTextures()
148{
149 S32 i;
150 for (i = 0; i < MAX_SPECIES; i++)
151 {
152 mTreeImagep = NULL;
153 }
154}
155*/
156
157U32 LLVOTreeNew::processUpdateMessage(LLMessageSystem *mesgsys,
158 void **user_data,
159 U32 block_num, EObjectUpdateType update_type,
160 LLDataPacker *dp)
161{
162 // Do base class updates...
163 U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
164
165 if ( (getVelocity().magVecSquared() > 0.f)
166 ||(getAcceleration().magVecSquared() > 0.f)
167 ||(getAngularVelocity().magVecSquared() > 0.f))
168 {
169 llinfos << "ACK! Moving tree!" << llendl;
170 setVelocity(LLVector3::zero);
171 setAcceleration(LLVector3::zero);
172 setAngularVelocity(LLVector3::zero);
173 }
174
175 mSpecies = ((U8 *)mData)[0];
176 mSpecies = 1;
177
178 if (mSpecies >= MAX_SPECIES)
179 {
180 mSpecies = 0;
181 }
182
183
184 mTreeImagep = gImageList.getImage(sTreeImageIDs[mSpecies]);
185 if (mTreeImagep)
186 {
187 mTreeImagep->bindTexture(0);
188 mTreeImagep->setClamp(TRUE, TRUE);
189 }
190
191 return retval;
192}
193
194
195BOOL LLVOTreeNew::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
196{
197 return TRUE;
198}
199
200
201void LLVOTreeNew::render(LLAgent &agent)
202{
203 // nothing
204}
205
206
207void LLVOTreeNew::updateTextures(LLAgent &agent)
208{
209 LLVector3 position_local = getPositionAgent() - agent.getCameraPositionAgent();
210 F32 dot_product = position_local * agent.getFrameAgent().getAtAxis();
211 F32 cos_angle = dot_product / position_local.magVec();
212
213 if (cos_angle > 1.f)
214 {
215 cos_angle = 1.f;
216 }
217
218 // temporary aggregate texture scale calculation
219 // this is less correct than the code above!
220 F32 texel_area_ratio = 0.5f; // When we're billboarded, we use less than the whole texture (about half?)
221 if (mTreeImagep)
222 {
223 mTreeImagep->addTextureStats(mPixelArea, texel_area_ratio, cos_angle);
224 }
225
226}
227
228
229LLDrawable* LLVOTreeNew::createDrawable(LLPipeline *pipeline)
230{
231
232 pipeline->allocDrawable(this);
233 mDrawable->setLit(FALSE);
234
235 mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TREE);
236 //llinfos << "tree type: " << LLPipeline::RENDER_TYPE_TREE << llendl;
237
238 //!! add the leaf texture to this
239 LLDrawPool *poolp = gPipeline.getPool(LLDrawPool::POOL_TREE_NEW, mTreeImagep);
240
241
242 //!! add a face for the bark texture...
243 //LLFace *facep = mDrawable->addFace(poolp, mTreeImagep, TRUE);
244 mDrawable->addFace(poolp, mTreeImagep, TRUE);
245 //facep->setSize(1, 3);
246
247 //!! add a face for the leaf texture ??
248 //
249
250 gPipeline.markMaterialed(mDrawable);
251
252 return mDrawable;
253}
254
255
256
257BOOL LLVOTreeNew::updateGeometry(LLDrawable *drawable)
258{
259
260 llinfos << "TREE SPECIES " << U32(mSpecies) << llendl;
261
262 // create the basic geometry of the trunk and branch
263
264 // get the face for the branches...
265 LLFace *face = drawable->getFace(0);
266 LLDrawPool *poolp = face->getPool();
267
268 if (!face->getDirty())
269 {
270 return TRUE;
271 }
272
273 poolp->setDirty();
274
275 U32 curVertexIndex, curTexCoordIndex, curNormalIndex;
276 U32 curIndiceIndex;
277// U32 numVertsCreated = LLVOTreeNew::sNextVertexIndex[mSpecies];
278
279 //U32 vertexCount = poolp->getVertexCount();
280 //llinfos << "TREE vertexCount = " << vertexCount << ", nextVertexIndex = " << mNextVertexIndex[mSpecies] << llendl;
281 //U32 indiceCount = poolp->getIndexCount();
282 //llinfos << "TREE indiceCount = " << indiceCount << ", nextIndiceIndex = " << mNextIndiceIndex[mSpecies] << llendl;
283
284
285 if (poolp->getVertexCount() > 0)
286 {
287 //llinfos << "TREE not creating the arrays..." << llendl;
288 }
289 else
290 {
291 // create the drawpool arrays
292 // using some rough estimates
293 U32 numVerts = NUM_INIT_VERTS;
294 U32 numIndices = NUM_INIT_INDICES;
295
296 face->setPrimType(LLTriangles);
297 face->setSize(numVerts, numIndices);
298
299 // reset the next's since they may have been previously initialized...
300 LLVOTreeNew::sNextIndiceIndex[mSpecies] = 0;
301 LLVOTreeNew::sNextVertexIndex[mSpecies] = 0;
302 LLVOTreeNew::sNextPartIndex[mSpecies] = 0;
303
304 //llinfos << "TREE creating the arrays..." << llendl;
305 }
306
307 curVertexIndex = LLVOTreeNew::sNextVertexIndex[mSpecies];
308 curTexCoordIndex = curVertexIndex;
309 curNormalIndex = curVertexIndex;
310 curIndiceIndex = LLVOTreeNew::sNextIndiceIndex[mSpecies];
311
312 //vertexCount = poolp->getVertexCount();
313 //llinfos << "TREE vertexCount = " << vertexCount << ", nextVertexIndex = " << mNextVertexIndex[mSpecies] << llendl;
314 //indiceCount = poolp->getIndexCount();
315 //llinfos << "TREE indiceCount = " << indiceCount << ", nextIndiceIndex = " << mNextIndiceIndex[mSpecies] << llendl;
316
317 //llinfos << "TREE \t" << "\t curVertexIndex: \t" << curVertexIndex << llendl;
318 //llinfos << "TREE \t" << "\t curIndiceIndex: \t" << curIndiceIndex << llendl;
319
320 LLStrider<LLVector3> vertices;
321 LLStrider<LLVector3> normals;
322 LLStrider<LLVector2> tex_coords;
323 U32 *indices;
324
325 face->getGeometry(vertices, normals, tex_coords, indices);
326
327 // create different parts for the levels...
328
329 // create the trunk...
330 F32 length, curve, radius, parentLength, parentRadius;
331
332 length = parentLength = sParameters.mLength[0] * sParameters.mScale;
333 radius = parentRadius = length * sParameters.mRatio * sParameters.mScale0;
334 curve = sParameters.mCurve[0];
335 createPart(0, length, radius, vertices, normals, tex_coords, indices, curVertexIndex, curTexCoordIndex,
336 curNormalIndex, curIndiceIndex);
337
338 // create collection of curved branches...
339 //*
340 for (U8 i = 1; i <= sParameters.mLevels; i++)
341 {
342 length = sParameters.mLength[i] * parentLength;
343 radius = parentRadius * pow((length / parentLength), sParameters.mRatioPower);
344
345 llinfos << "TREE creating (?) part with radius: " << radius << " and length: " << length << llendl;
346
347 createPart(i, length, radius, vertices, normals, tex_coords, indices, curVertexIndex, curTexCoordIndex,
348 curNormalIndex, curIndiceIndex);
349
350 parentRadius = radius;
351 parentLength = length;
352
353 }
354 //*/
355
356 LLVOTreeNew::sNextVertexIndex[mSpecies] = curVertexIndex;
357 LLVOTreeNew::sNextIndiceIndex[mSpecies] = curIndiceIndex;
358
359 // create a leaf...?
360
361 return TRUE;
362}
363
364F32 LLVOTreeNew::CalcZStep(TreePart *part, U8 section)
365{
366 F32 zStep;
367
368 if (part->mLevel == 0 && section < sParameters.mFlareRes)
369 zStep = (sParameters.mFlarePercentage * part->mLength)/sParameters.mFlareRes;
370 else
371 zStep = ((1.f - sParameters.mFlarePercentage)*part->mLength) / (part->mCurveRes);
372
373 return zStep;
374}
375
376S32 LLVOTreeNew::findSimilarPart(U8 level)
377{
378 // see if there's a tree part that's similar...
379 for (U8 i = 0; i < sNextPartIndex[mSpecies]; i++)
380 {
381 TreePart *curPart = &(sTreeParts[mSpecies][i]);
382 // make sure older branch is at same 'level' and has
383 // similar lobe parameters (if at the trunk level)
384 if (curPart->mLevel == level &&
385 (level != 0 || (llabs(curPart->mLobes - sParameters.mLobes) < MAX_LOBES_DIFF && llabs(curPart->mLobeDepth - sParameters.mLobeDepth) < MAX_LOBEDEPTH_DIFF)))
386 {
387 // check to see if older branch's curve, curveBack, and curveV
388 // are all close to the desired branch...
389 F32 curveDiff = llabs(curPart->mCurve - sParameters.mCurve[level]);
390 F32 curveBackDiff = llabs(curPart->mCurveBack - sParameters.mCurveBack[level]);
391 F32 curveVDiff = llabs(curPart->mCurveV - sParameters.mCurveV[level]);
392 if (curveDiff < MAX_CURVE_DIFF
393 && curveVDiff < MAX_CURVE_V_DIFF
394 && (curveBackDiff == 0 || curveBackDiff < MAX_CURVEBACK_DIFF)
395 )
396 {
397 // already have a branch that's close enough
398 return i;
399 }
400 }
401 }
402
403 return -1;
404}
405
406
407void LLVOTreeNew::createPart(U8 level, F32 length, F32 radius, LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals,
408 LLStrider<LLVector2> &tex_coords, U32 *indices,
409 U32 &curVertexIndex, U32 &curTexCoordIndex,
410 U32 &curNormalIndex, U32 &curIndiceIndex)
411{
412 U8 i, j, k;
413
414 // check for a similar branch...
415 S32 selectedPart = findSimilarPart(level);
416 if (selectedPart > -1) return;
417
418 // if we didn't find the branch, make different versions of it
419 // depending on how large curveV (curveVariance), make more branches...
420 S32 numVariants = 1;
421 numVariants += (S32)(sParameters.mCurveV[level]/CURVEV_DIVIDER);
422
423 if (numVariants > MAX_VARS) numVariants = MAX_VARS;
424 if (level == 0) numVariants = 1; // just make one trunk
425
426 llinfos << "TREE generating " << numVariants << " variants for curveV of " << sParameters.mCurveV[level] << " on level " << U32(level) << llendl;
427
428
429 // if we've hit the max part limit, just quit...
430 if (sNextPartIndex[mSpecies] == MAX_PARTS)
431 {
432 llinfos << "TREE SPECIES RAN OUT OF DRAWPOOL PART SPACE..." << llendl;
433 return;
434 }
435
436 // put the first variant in its own mTreePart
437 TreePart *part = &(LLVOTreeNew::sTreeParts[mSpecies][LLVOTreeNew::sNextPartIndex[mSpecies]++]);
438
439 // set the tree part params from the basic tree params...
440 part->mCurve = sParameters.mCurve[level];;
441 part->mCurveRes = sParameters.mCurveRes[level];
442 part->mCurveBack = sParameters.mCurveBack[level];
443 part->mCurveV = sParameters.mCurveV[level];
444 part->mLobeDepth = sParameters.mLobeDepth;
445 part->mLobes = sParameters.mLobes;
446 part->mLength = length;
447 part->mRadius = radius;
448 part->mLevel = level;
449 part->mVertsPerSection = sParameters.mVertices[level];
450 part->mNumVariants = 0;
451
452 // enforce constraints on # of resolutions
453 if (sParameters.mFlareRes > MAX_FLARE) sParameters.mFlareRes = MAX_FLARE;
454 if (part->mCurveRes > MAX_RES) part->mCurveRes = MAX_RES;
455
456 for (k = 0; k < numVariants; k++)
457 {
458 part->mNumVariants++;
459
460 // set the part's vertices to the first vertex and first index of its parts
461 part->mIndiceIndex[k] = curIndiceIndex;
462
463 // how many total sections in the branch
464 U8 numSections = (U8)(part->mCurveRes) + (level == 0 ? sParameters.mFlareRes : 0);
465
466 U8 framesUsed = 0;
467 U8 flareFramesUsed = 0;
468 F32 stemZ;
469 F32 startingZ = 0;
470
471 // create curveRes different versions of the branch, with each
472 // one having its origin base be a different flareRes or curveRes base
473
474 U32 oldOffset = mRandOffset[level];
475
476 for (j = 0; j < numSections; j++)
477 {
478 mRandOffset[level] = oldOffset;
479 if (j != 0) part->mOffsets[k][j - (level == 0 ? sParameters.mFlareRes : 0)] = curIndiceIndex;
480
481 F32 sectionRadius;
482 LLMatrix4 curFrame;
483 U8 curSection = 0;
484
485 // our position in the branch
486 stemZ = startingZ;
487
488 // Make branches from
489 // From 0th section...numSections
490 // 1st section...numSections
491 // 2nd section...numSections
492
493 sectionRadius = CalculateSectionRadius(level, stemZ / part->mLength, part->mLength, part->mRadius);
494
495 // create points that make up the bottom of the section...
496 createSection(curFrame, part, sectionRadius, stemZ,
497 vertices, tex_coords, indices,
498 curVertexIndex, curTexCoordIndex, curIndiceIndex, curSection++, j == 0 ? TRUE : FALSE);
499
500 for (i = j; i < numSections; i++)
501 {
502 // do the curving...
503 F32 angle;
504 if (part->mCurveBack != 0)
505 {
506 if (part->mCurveRes / (i + 1.0) < 2)
507 angle = part->mCurve / part->mCurveRes / 2.f;
508 else
509 angle = part->mCurveBack / part->mCurveRes / 2.f;
510 }
511 else
512 {
513 if (part->mLevel == 0)
514 {
515 if (i <= sParameters.mFlareRes) angle = (sParameters.mFlarePercentage*part->mCurve)/sParameters.mFlareRes;
516 else angle = ((1.f - sParameters.mFlarePercentage)*part->mCurve)/part->mCurveRes;
517 }
518 else
519 angle = part->mCurve / part->mCurveRes;
520
521 }
522
523 // add in variance just for kicks...
524 angle += llfrand_signed(part->mCurveV/part->mCurveRes, mRandOffset[level + i]++);
525
526 /* vertical attraction is based on height of branch which is unavailable information
527 if (level > 1)
528 angle += CalculateVerticalAttraction(level, curFrame);
529 //*/
530
531 angle *= DEG_TO_RAD;
532
533 // translation...
534 F32 zStep;
535 zStep = CalcZStep(part, i);
536 stemZ += zStep;
537
538 // set the next startingZ as current stemZ if at first level
539 if (i == j || (level == 0 && j == 0 && i == sParameters.mFlareRes - 1))
540 startingZ = stemZ;
541
542 LLQuaternion rotateQuat, oldRotateQuat, newRotateQuat;
543 LLMatrix4 localFrame, transFrame;
544
545 rotateQuat.setQuat(angle, 1.0f, 0.0f, 0.0f);
546 oldRotateQuat.setQuat(curFrame);
547 newRotateQuat = oldRotateQuat * rotateQuat;
548
549 transFrame.translate(LLVector3(0, 0, zStep));
550 transFrame.rotate(newRotateQuat);
551
552 localFrame.rotate(newRotateQuat);
553 localFrame.translate(curFrame.getTranslation());
554 localFrame.translate(transFrame.getTranslation());
555
556 curFrame = localFrame;
557
558 // store flare frames seperately
559 if (part->mLevel == 0 && i < sParameters.mFlareRes)
560 mTrunkFlareFrames[flareFramesUsed++] = curFrame;
561 else
562 part->mFrames[k][framesUsed++] = curFrame;
563
564 // calc radius of section
565 if (part->mLength == 0)
566 sectionRadius = 0;
567 else
568 sectionRadius = CalculateSectionRadius(level, stemZ / part->mLength, part->mLength, part->mRadius);
569
570 // create points that make up the section
571 createSection(curFrame, part, sectionRadius, stemZ,
572 vertices, tex_coords, indices,
573 curVertexIndex, curTexCoordIndex, curIndiceIndex, curSection++, j == 0 ? TRUE : FALSE);
574 }
575
576 // only do one trunk w/ flaring.
577 if (level == 0 && j == 0) j = sParameters.mFlareRes - 1;
578 }
579
580 // gen vertex normals now that we've created face normals for the first section...
581 genVertexNormals(part, normals, numSections, curNormalIndex);
582 }
583
584}
585
586
587
588
589void LLVOTreeNew::createSection(LLMatrix4 &frame, TreePart *part, F32 sectionRadius, F32 stemZ,
590 LLStrider<LLVector3> &vertices, LLStrider<LLVector2> &tex_coords, U32 *indices,
591 U32 &curVertexIndex, U32 &curTexCoordIndex, U32 &curIndiceIndex, U8 curSection, BOOL firstBranch)
592{
593
594 F32 angle; // Angle holds the angle in radians
595 // between two points in the section.
596
597 LLVector3 localPoint; // LocalPoint is used to hold the points
598 // that are being created and added to
599 // the points list of the section (in
600 // local coordinates)
601
602 LLVector3 globalPoint; // GlobalPoint is used to hold the points
603 // that are being created and added to
604 // the points list of the section (in
605 // global coordinates)
606
607 F32 lobedSectionRadius; // The sectionradius rescaled using
608 // the lobing parameters
609
610 F32 percentX, percentY; // The texture coords
611
612
613
614 U8 numVerts = part->mVertsPerSection;
615
616 // prevent empty triangles
617 if (sectionRadius < 0.0001) {
618 sectionRadius = 0.0001f;
619 }
620
621 // Y texture coordinate
622 // stemZ is current position within mLength...
623 percentY = stemZ;
624 //percentY = stemZ/part->mLength;
625
626 angle = (2 * F_PI) / numVerts;
627 for (U8 i = 0; i <= numVerts; i++)
628 {
629 // last vertex is same as first one...
630 if (i == numVerts)
631 {
632 // make first vertice the last vertice (wrap around so that our texture coords will be ok...
633 globalPoint = vertices[curVertexIndex - numVerts];
634 }
635 else
636 {
637 // lobed = 1.0 + lobeDepth * sin(lobes * angle)
638 lobedSectionRadius = sectionRadius * (1.f + sParameters.mLobeDepth * sin(sParameters.mLobes * (i + 1) * angle));
639
640 localPoint.mV[0] = cos((i + 1.f) * angle) * lobedSectionRadius;
641 localPoint.mV[1] = sin((i + 1.f) * angle) * lobedSectionRadius;
642 localPoint.mV[2] = 0;
643
644 globalPoint = localPoint * frame;
645 }
646
647 if (curVertexIndex > NUM_INIT_VERTS) {
648 llinfos << "TREE ERROR NO MORE VERTS" << llendl;
649 return;
650 }
651
652 // add to instanced data...
653 vertices[curVertexIndex++] = globalPoint;
654 mTotalVerts++;
655
656 /*
657 // update the max x, y, and z of tree
658 if (globalPoint->mV[0] > mTree->mMaxX) { mTree->mMaxX = globalPoint->mV[0]; }
659 if (globalPoint->mV[1] > mTree->mMaxY) { mTree->mMaxY = globalPoint->mV[1]; }
660 if (globalPoint->mV[2] > mTree->mMaxZ) { mTree->mMaxZ = globalPoint->mV[2]; }
661 */
662
663 // TEXTURE COORDS
664 percentX = WIDTH_OF_BARK * (i/F32(numVerts));// * (2.0*F_PI*sectionRadius);
665 //percentX = * (i/F32(numVerts));
666 tex_coords[curTexCoordIndex++] = LLVector2(percentX, percentY);
667 }
668
669 // gen face normals and do texcoords...
670 if (curSection != 0)
671 genIndicesAndFaceNormalsForLastSection(part, numVerts, vertices, curVertexIndex, indices, curIndiceIndex, firstBranch);
672}
673
674
675// generate face normals for the last two cross sections in sectionlist
676void LLVOTreeNew::genIndicesAndFaceNormalsForLastSection(TreePart *part, U8 numVerts, LLStrider<LLVector3> &vertices, U32 curVertexIndex, U32 *indices, U32 &curIndiceIndex, BOOL firstBranch)
677{
678
679 LLVector3 v1, v2;
680 LLVector3 vCross;
681 LLVector3 a, b, c, d;
682
683 // offsets into the vertex array
684 U32 upperOffset = curVertexIndex - (numVerts + 1);
685 U32 lowerOffset = upperOffset - (numVerts + 1);
686
687 // generate the normals for the triangles from the quads
688 // quad is defined by:
689 // upper[i].....upper[i+1]
690 // . .
691 // . .
692 // . .
693 // lower[i].....lower[i+1]
694
695 // 10.......11
696 // . . .
697 // . . .
698 // . . .
699 // 00 . . . 01
700
701 // b . . . d
702 // . . .
703 // . . .
704 // . . .
705 // a . . . c
706
707 for (U8 j = 0; j < numVerts; j++ ) {
708
709 U8 nextVert = j + 1;
710
711 // do face normals for first version only
712 if (firstBranch)
713 {
714 // the points of the quad
715 a = vertices[lowerOffset]; // 00
716 b = vertices[upperOffset]; // 10
717 c = vertices[lowerOffset + nextVert]; // 01
718 d = vertices[upperOffset + nextVert]; // 11
719
720 // 1st triangle
721 v1 = c - b;
722 v2 = a - b;
723 vCross = v1 % v2;
724 vCross.normVec();
725 part->mFaceNormals.put(vCross);
726
727 // 2nd triangle
728 v1 = c - b;
729 v2 = d - b;
730 vCross = v1 % v2;
731 vCross.normVec();
732 part->mFaceNormals.put(vCross);
733 }
734
735 if (curIndiceIndex + 6 > NUM_INIT_INDICES)
736 {
737 llinfos << "TREE ERROR NO MORE INDICES" << llendl;
738 return;
739 }
740
741 indices[curIndiceIndex++] = lowerOffset + j; // 00
742 indices[curIndiceIndex++] = lowerOffset + nextVert; // 01
743 indices[curIndiceIndex++] = upperOffset + j; // 10
744 if (firstBranch) { part->mNumTris++; }
745
746 indices[curIndiceIndex++] = lowerOffset + nextVert; // 01
747 indices[curIndiceIndex++] = upperOffset + nextVert; // 11
748 indices[curIndiceIndex++] = upperOffset + j; // 10
749 if (firstBranch) { part->mNumTris++; }
750
751 mTotalIndices += 6;
752 //*/
753 }
754}
755
756
757
758
759void LLVOTreeNew::genVertexNormals(TreePart *part, LLStrider<LLVector3> &normals, U8 numSections, U32 curNormalIndex)
760{
761 LLVector3 vNormal;
762
763 U8 numVerts = part->mVertsPerSection;
764 U16 numFaces = numVerts * 2;
765
766 U32 curSectionFaceOffset, lowerSectionFaceOffset;
767
768 U8 i;
769 U8 j;
770
771 // for each section...
772 for (i = 0; i < numSections; i++) {
773
774 U32 numFacesStored = part->mFaceNormals.count();
775 // index into face normals for 0-ith face of section i...
776 curSectionFaceOffset = numFacesStored - (numSections - 1 - i)*numFaces;
777 lowerSectionFaceOffset = curSectionFaceOffset - numFaces;
778
779 // for each vertex...
780 for (j = 0; j < numVerts; j++) {
781
782 // if lowest level or highest level...
783 if (i == 0) {
784 // bottom 3 adjacent tris
785 vNormal += part->mFaceNormals[curSectionFaceOffset + (numFaces - j*2 - 2) % numFaces];
786 vNormal += part->mFaceNormals[curSectionFaceOffset + (numFaces - j*2 - 1) % numFaces];
787 vNormal += part->mFaceNormals[curSectionFaceOffset + (numFaces - j*2) % numFaces];
788 vNormal /= 3.0;
789 } else if (i == numSections - 1) {
790 // top 3 adj tris
791 vNormal += part->mFaceNormals[lowerSectionFaceOffset + (numFaces - j*2 - 1) % numFaces];
792 vNormal += part->mFaceNormals[lowerSectionFaceOffset + (numFaces - j*2) % numFaces];
793 vNormal += part->mFaceNormals[lowerSectionFaceOffset + (numFaces - j*2 + 1) % numFaces];
794 vNormal /= 3.0;
795 }
796 else
797 {
798 // otherwise avg the normals from the 6 adjacent tris
799 // avg the 6 normal vectors that are adjacent to it...
800 // vertex 0 is surrounded by...
801 // lower: 0, 1 .... n
802 // upper: n-1, n .... 0
803
804 vNormal += part->mFaceNormals[curSectionFaceOffset + (numFaces - j*2 - 2) % numFaces];
805 vNormal += part->mFaceNormals[curSectionFaceOffset + (numFaces - j*2 - 1) % numFaces];
806 vNormal += part->mFaceNormals[curSectionFaceOffset + (numFaces - j*2) % numFaces];
807
808 vNormal += part->mFaceNormals[lowerSectionFaceOffset + (numFaces - j*2 - 1) % numFaces];
809 vNormal += part->mFaceNormals[lowerSectionFaceOffset + (numFaces - j*2) % numFaces];
810 vNormal += part->mFaceNormals[lowerSectionFaceOffset + (numFaces - j*2 + 1) % numFaces];
811
812 vNormal /= 6.0;
813 }
814 normals[curNormalIndex] = vNormal;
815 curNormalIndex++;
816 }
817 // get first normal and use for the repeated last vertex...
818 normals[curNormalIndex] = normals[curNormalIndex - numVerts];
819 curNormalIndex++;
820 }
821
822
823 // there are mCurveRes - 1 different starting points...
824 U8 offset = 0;
825 U8 curveres8 = (U8)part->mCurveRes;
826 for (i = 0; i < curveres8 - 1; i++)
827 {
828 U8 numSectionsInBranch = curveres8 - i;
829 U8 origOffset = i * numVerts;
830
831 for (j = 0; j <= numSectionsInBranch * numVerts; j++)
832 normals[curNormalIndex + offset + j] = normals[curNormalIndex + origOffset + j];
833
834 offset += numSectionsInBranch * numVerts;
835 }
836
837
838}
839
840
841
842//{ Pre: 0 <= y <= 1
843// Ret: The radius of the stem at the (normalized) y position along the stem.
844// See for the exact calculations the paper "Creation and Rendering of
845// Realistic Trees", by Jason Weber and Joseph Penn. }
846
847
848F32 LLVOTreeNew::CalculateSectionRadius(U8 level, F32 y, F32 stemLength, F32 stemRadius)
849{
850 F32 y2, y3;
851
852 F32 depth; // Scaling factor used for periodic tapering
853 F32 taperY; // Tapered radius along at the (normalized) y
854 // position along the stem
855 F32 unitTaper; // UnitTaper is used to determine the radius of
856 // the stem along a specified (normalized)
857 // position along the stem.
858
859 F32 radius; // radius returned
860
861 // { Calculate UnitTaper, a variable used to determine the radius of the
862 // stem along a specified (normalized) position Z along the stem }
863
864 unitTaper = 0;
865
866 F32 curTaper = sParameters.mTaper[level]; // cur taper for this level
867
868 // 0 <= nTaper < 1
869 // unitTaper = nTaper
870 // 1 <= nTaper < 2
871 // unitTaper = 2 - nTaper
872 // 2 <= nTaper < 3
873 // unitTaper = 0
874
875 if ( (curTaper >= 0) && (curTaper < 1) )
876 unitTaper = curTaper;
877 else if ( (curTaper >= 1) && (curTaper < 2) )
878 unitTaper = 2.f - curTaper;
879 else // should be 2 <= curTaper < 3
880 unitTaper = 0;
881
882
883 // y is ratio of stemY/length...sometimes [something.mumble] / [something.mumble] != 1 when it should...
884 if (y > 1.0)
885 y = 1.0;
886
887 // taperY = radius[stem] * (1 - unitTaper * y)
888 taperY = stemRadius * (1.f - unitTaper * y);
889
890 // 0 <= curTaper <= 1
891 // radius = taperY;
892
893 if ( (curTaper >= 0) && (curTaper < 1) )
894 {
895 radius = taperY;
896 }
897 else
898 {
899 // { (nTaper[ALevel] >= 1) and (nTaper[ALevel] <= 3) }
900
901 // initialize y2
902 y2 = (1 - y) * stemLength;
903
904 // initialize depth
905
906 if ( (curTaper < 2) || (y2 < taperY) )
907 depth = 1;
908 else
909 depth = curTaper - 2;
910
911 // initialize y3
912 if ( curTaper < 2)
913 y3 = y2;
914 else
915 y3 = fabs(y2 - 2 * taperY * floor(y2 / (2 * taperY) + 0.5f));
916
917 // return the radius
918 if ( (curTaper < 2) && (y3 >= taperY) )
919 radius = taperY;
920 else
921 radius = (1 - depth) * taperY + depth * sqrt(pow(taperY, 2) - pow(y3 - taperY, 2));
922 }
923
924 // calculate flaring
925 if (level == 0)
926 {
927 y2 = 1 - 8 * y;
928 if (y2 < 0)
929 y2 = 0;
930
931 // flare = Flare * (100^y - 1) / 100 + 1
932 radius = radius * (sParameters.mFlare * (pow((F32)100, y2) - 1) / 100 + 1);
933 }
934
935 return radius;
936}
937
938/*
939F32 LLVOTreeNew::CalculateVerticalAttraction(U8 level, LLMatrix4 &sectionFrame)
940{
941 LLVector3 transformY, transformZ;
942 LLVector3 unitY(0.0, 1.0, 0.0);
943 LLVector3 unitZ(0.0, 0.0, 1.0);
944 F32 declination, orientation;
945
946 transformY = unitY * sectionFrame;
947 transformZ = unitZ * sectionFrame;
948
949 declination = acos(transformZ.mV[1]);
950 orientation = acos(transformY.mV[1]);
951
952 return (sParameters.mAttractionUp * declination * cos(orientation)) / sParameters.mCurveRes[level];
953}
954//*/
955
956
957void LLVOTreeNew::drawTree(LLDrawPool &draw_pool)
958{
959 U8 i, j;
960
961 // seed the drawtree thing with the object's uuid to make it original but predictable...
962 // don't re-seed the process random number generator. bad.
963 //gLindenLabRandomNumber.seed(0);
964
965 // reset the rand offsets
966 for (i = 0; i < MAX_LEVELS; i++) mRandOffset[i] = 0;
967
968 F32 trunkLength = sParameters.mLength[0] * sParameters.mScale;
969 //F32 trunkLength = sParameters.mLength[0] + llfrand_signed(sParameters.mLengthV[0])) *
970 // (sParameters.mScale + llfrand_signed(sParameters.mScaleV));
971 F32 trunkRad = trunkLength * sParameters.mRatio * sParameters.mScale0;
972
973//* reset usage data on which part is grabbed
974 mNumTrisDrawn = 0;
975 for (i = 0; i < MAX_PARTS; i++)
976 for (j = 0; j < MAX_VARS; j++)
977 sTreePartsUsed[mSpecies][i][j] = 0;
978
979 // reset segsplit error stuff...
980 for (j = 0; j < 3; j++)
981 mSegSplitsError[j] = 0;
982
983 //llinfos << "\nTREE Starting" << llendl;
984 drawTree(draw_pool, LLMatrix4(), 0, 0, trunkLength, 0, trunkRad, 0, 0, 0, 0);
985 //llinfos << "\nTREE Ending" << llendl;
986
987 /*
988 // print part usage info:
989 for (i = 0; i < MAX_PARTS; i++)
990 {
991 llinfos << "TREE part: " << U32(i) << ": " << llendl;
992 for (j = 0; j < MAX_VARS; j++)
993 llinfos << "\t variant " << U32(j) << ": [" << U32(sTreePartsUsed[mSpecies][i][j]) << "], " << llendl;
994 llinfos << "" << llendl;
995 }
996 //*/
997
998/*
999 glTranslatef(0.0, 0.0, 5.0);
1000 for (i = 0; i < sNextPartIndex[mSpecies]; i++)
1001 {
1002 TreePart *selectedPart = &(sTreeParts[mSpecies][i]);
1003 glTranslatef(2.0, 0.0, 0.0);
1004
1005 // draw a variant...
1006 for (U8 k = 0; k < selectedPart->mNumVariants; k++)
1007 {
1008 // start at the indice index
1009 U32 prevOffset = 0;//selectedPart->mIndiceIndex[k];
1010
1011
1012 if (selectedPart->mLevel == 0 && k == 0)
1013 {
1014 // draw the original one with flare...
1015 glTranslatef(1.0, 0.0, 0.0);
1016 glPushMatrix();
1017 glDrawElements(GL_TRIANGLES, selectedPart->mNumTris*3, GL_UNSIGNED_INT, draw_pool.getRawIndices() + selectedPart->mIndiceIndex[k]);
1018 glPopMatrix();
1019 prevOffset += selectedPart->mNumTris*3;
1020 }
1021
1022 // draw each of the curveRes iterations...
1023 for (j = 0; j < selectedPart->mCurveRes; j++)
1024 {
1025 U32 numTris = (selectedPart->mCurveRes - j) * selectedPart->mVertsPerSection * 2;
1026 glTranslatef(0.0, 1.0, 0.0);
1027 glPushMatrix();
1028 glDrawElements(GL_TRIANGLES, numTris*3, GL_UNSIGNED_INT, draw_pool.getRawIndices() + selectedPart->mIndiceIndex[k] + prevOffset);
1029 glPopMatrix();
1030 prevOffset += numTris*3;
1031 }
1032 }
1033 }
1034//*/
1035}
1036
1037void LLVOTreeNew::drawTree(LLDrawPool &draw_pool, const LLMatrix4 &frame, U8 level, F32 offsetChild,
1038 F32 curLength, F32 parentLength, F32 curRadius, F32 parentRadius,
1039 U8 part, U8 variant, U8 startSection)
1040{
1041 U8 i, j, k;
1042
1043 // if startSection != 0, we're doing a segsplit.
1044
1045 // find the tree part most similar (if we're not doing a segsplit)
1046 if (startSection == 0)
1047 {
1048 S32 similarNum = findSimilarPart(level);
1049 if (similarNum < 0) part = level;
1050 else part = similarNum;
1051 }
1052
1053 TreePart *selectedPart;
1054 selectedPart = &(sTreeParts[mSpecies][part]);
1055
1056 // pick a variant if we're not in a segsplit (and therefore already have one chosen)
1057 //if (startSection == 0) variant = llrand_unsigned(selectedPart->mNumVariants + 1, mRandOffset[level]++);
1058 //if (variant == selectedPart->mNumVariants) variant--;
1059 // manual override
1060 variant = 0;
1061
1062 sTreePartsUsed[mSpecies][part][variant]++;
1063
1064 //llinfos << "TREE part desired: " << U32(level) << ", " << sParameters.mLobeDepth << ", " << curAngleInt << llendl;
1065 //llinfos << "TREE part found: " << U32(selectedPart->mLevel) << ", " << selectedPart->mLobeDepth << ", " << selectedPart->mAngle << llendl;
1066
1067 // determine the scalers so that we meet the desired length/radius...
1068 F32 lengthMultiplier = curLength / selectedPart->mLength;
1069 F32 radiusMultiplier = curRadius / selectedPart->mRadius;
1070 LLMatrix4 scaleMatrix;
1071 scaleMatrix.mMatrix[0][0] = radiusMultiplier;
1072 scaleMatrix.mMatrix[1][1] = radiusMultiplier;
1073 scaleMatrix.mMatrix[2][2] = lengthMultiplier;
1074
1075 // the global rotation this branch will take
1076 LLQuaternion frameQuat;
1077 frameQuat.setQuat(frame);
1078 LLMatrix4 scaledFrame = frame;
1079 scaledFrame *= scaleMatrix;
1080
1081 // start from the previous startSection of the curveRes...try to go till we're at the end of the branch
1082 // i is the current section we're looking at for segment splits
1083
1084 F32 otherRotateAngle = llfrand_signed(360.0f, mRandOffset[level]++);
1085
1086 U8 curSection = startSection;
1087 for (i = startSection; i < selectedPart->mCurveRes - 1; i++)
1088 {
1089 curSection = i + 1;
1090
1091 S32 segSplitsEffective = 0;
1092
1093 // seg split code taken from confusing paragraph of Weber + Penn
1094 F32 segSplit = llfrand_unsigned(sParameters.mSegSplits[level], mRandOffset[level]++);
1095 segSplitsEffective = llround(segSplit + mSegSplitsError[level]);
1096 mSegSplitsError[level] += segSplit - lltrunc(segSplit);
1097 mSegSplitsError[level] -= (segSplitsEffective - segSplit);
1098
1099 // if we've got a seg split, figure out the right rotated frames and send them off...
1100 if (segSplitsEffective > 0)
1101 {
1102 // figure out the declination for this height...
1103 LLVector3 unitZ(0.0f, 0.0f, 1.0f);
1104 LLVector3 transformZ = unitZ * frame;
1105 F32 declination = RAD_TO_DEG*acos(transformZ.mV[1]);
1106
1107 F32 splitAngle = (sParameters.mSplitAngle[level] + llfrand_unsigned(sParameters.mSplitAngleV[level], mRandOffset[level]++)) - declination;
1108 if (splitAngle < 0)
1109 splitAngle = 0;
1110 //splitAngle = sParameters.mDownAngle[2];//45.0f;
1111
1112 // do each seg split...
1113 for (j = 0; j < segSplitsEffective; j++)
1114 {
1115 otherRotateAngle += llround(20.0f + 0.75f*(30.0f + fabs(declination - 90.0f)) * pow(fabs((F32)llrand_signed(1, mRandOffset[level]++)), 2.0f));
1116
1117 //otherRotateAngle += sParameters.mDownAngle[1];//((j + 1) * 360.0)/(segSplitsEffective + 1);
1118
1119 U32 frameOffset = 0;
1120 if (startSection != 0)
1121 {
1122 // offset into the branch that begins with that startsection...
1123 if (level == 0) frameOffset += (U32)selectedPart->mCurveRes - 1;
1124 // i is our start section ...
1125 for (k = 0; k < i; k++)
1126 frameOffset += ((U32)selectedPart->mCurveRes - k);
1127
1128 frameOffset--;
1129 }
1130
1131 LLMatrix4 segFrame;
1132 segFrame = selectedPart->mFrames[variant][frameOffset + curSection - 1];
1133 segFrame *= scaleMatrix;
1134
1135 LLVector3 segFrameTrans = segFrame.getTranslation();
1136 segFrameTrans.rotVec(frameQuat);
1137
1138 LLQuaternion splitQuat, rotateQuat;
1139 splitQuat.setQuat(splitAngle*DEG_TO_RAD, 1.0f, 0.0f, 0.0f);
1140 rotateQuat.setQuat(otherRotateAngle*DEG_TO_RAD, 0.0f, 0.0f, 1.0f);
1141
1142 LLMatrix4 splitFrame;
1143 //splitFrame.rotate(splitQuat * rotateQuat * frameQuat); ??
1144 splitFrame.rotate(frameQuat * splitQuat * rotateQuat);
1145 splitFrame.translate(segFrameTrans);
1146 splitFrame.translate(frame.getTranslation());
1147
1148 // recurse from the current endsection as start section and with the new frame as base
1149 drawTree(draw_pool, splitFrame, level, offsetChild,
1150 curLength, parentLength, curRadius, parentRadius,
1151 part, variant, curSection);
1152 }
1153 }
1154 }
1155
1156
1157 U32 startIndexOffset = 0;
1158
1159 if (startSection != 0)
1160 startIndexOffset = selectedPart->mOffsets[variant][startSection];
1161
1162 U32 numTris;
1163 if (level == 0 && startSection == 0)
1164 numTris = selectedPart->mNumTris;
1165 else
1166 numTris = 2 * selectedPart->mVertsPerSection * ((U8)selectedPart->mCurveRes - startSection);
1167
1168 glPushMatrix();
1169 glMultMatrixf((float *)frame.mMatrix);
1170 glScalef(radiusMultiplier, radiusMultiplier, lengthMultiplier);
1171
1172 //glDrawElements(GL_TRIANGLES, selectedPart->mNumTris*3, GL_UNSIGNED_INT, draw_pool.getRawIndices() + selectedPart->mIndiceIndex + 0);
1173 glDrawElements(GL_TRIANGLES, numTris*3, GL_UNSIGNED_INT, draw_pool.getRawIndices() + selectedPart->mIndiceIndex[variant] + startIndexOffset);
1174 glPopMatrix();
1175
1176 mNumTrisDrawn += numTris;
1177
1178 // figure out how many in next level of branches || leaves
1179 U8 total = 0;
1180 F32 baseLength = 0;
1181
1182 if (level < sParameters.mLevels)
1183 {
1184 if (level == 0)
1185 {
1186 baseLength = sParameters.mBaseSize * (sParameters.mScale + llfrand_signed(sParameters.mScaleV, mRandOffset[level]++));
1187 total = llround( (1.f - sParameters.mBaseSize) * sParameters.mBranches[level]);
1188 }
1189 else if (level == 1)
1190 {
1191 F32 maxLength = sParameters.mLength[level] + llfrand_signed(sParameters.mLengthV[level], mRandOffset[level]++);
1192 total = llround(sParameters.mBranches[level] * (0.2f + 0.8f * ( (curLength/parentLength)/maxLength ) ) );
1193 }
1194 else
1195 {
1196 total = (llround(sParameters.mBranches[level] * (1.0f - 0.5f * (offsetChild/parentLength) )));
1197 }
1198 }
1199 else if (sParameters.mLevels == level)
1200 {
1201 // determine leaves
1202 // see paper for more on:
1203 // leaves_per_branch = Leaves *
1204 // ShapeRatio ( 4 (tapered), offset[child]/length[parent] * quality)
1205
1206 //total = (sParameters.mLeaves * sParameters.ShapeRatio(SR_CONICAL, offsetChild / curLength) * sParameters.mLeafQuality);
1207 total = sParameters.mLeaves;
1208
1209 }
1210
1211 F32 fracPos, offsetPos, localPos;
1212 F32 downAngle, rotateAngle;
1213 U8 currentFrameSegment; // index of matrix transform of the closest cross section to new branch
1214 LLMatrix4 localFrame, curPartFrame, nextPartFrame;
1215
1216 // init stem rotate angle...
1217 rotateAngle = llfrand_unsigned(360.0, mRandOffset[level]++);
1218
1219 // grow the leaf or branch...
1220 for (i = 0; i < total; i++)
1221 {
1222 // note: curLength is the 'parentLength' for all of these substems
1223 localFrame.identity();
1224
1225 // find the fractional, offset and then local pos
1226 if (level == 0)
1227 fracPos = sParameters.mBaseSize + (i) * (1.0f - sParameters.mBaseSize) / (total);
1228 else
1229 fracPos = (i) * (1.0f / (total));
1230
1231 // offset into branch
1232 offsetPos = fracPos*curLength;
1233
1234 U32 frameOffset = 0;
1235 if (startSection != 0)
1236 {
1237 if (level == 0) frameOffset = (U32)selectedPart->mCurveRes;
1238
1239 for (k = 0; k < startSection; k++)
1240 frameOffset += ((U32)selectedPart->mCurveRes - k);
1241 }
1242
1243 F32 curSegAt;
1244 if (level == 0 && startSection == 0)
1245 {
1246 F32 effectiveFlarePercentage = sParameters.mFlarePercentage + (1.0f - sParameters.mFlarePercentage)/selectedPart->mCurveRes;
1247
1248 if (fracPos < effectiveFlarePercentage)
1249 {
1250 if (fracPos > sParameters.mFlarePercentage)
1251 currentFrameSegment = sParameters.mFlareRes - 1;
1252 else
1253 currentFrameSegment = lltrunc( (fracPos/sParameters.mFlarePercentage) / (1.0/sParameters.mFlareRes) );
1254
1255 if (currentFrameSegment == 0)
1256 {
1257 curPartFrame.identity();
1258 nextPartFrame = mTrunkFlareFrames[0];
1259 }
1260 else
1261 {
1262 curPartFrame = mTrunkFlareFrames[currentFrameSegment - 1];
1263 if (currentFrameSegment == sParameters.mFlareRes - 1) nextPartFrame = selectedPart->mFrames[variant][0];
1264 else nextPartFrame = mTrunkFlareFrames[currentFrameSegment];
1265 }
1266
1267 curSegAt = currentFrameSegment * (curLength * sParameters.mFlarePercentage)/sParameters.mFlareRes;
1268 localPos = offsetPos - curSegAt;
1269 }
1270 else
1271 {
1272 // want to go from frameSegment 0 to (1-CurveRes)...don't want to have frame at tip
1273 currentFrameSegment = lltrunc( ( (fracPos - effectiveFlarePercentage)/(1.0 - effectiveFlarePercentage) ) / (1.0 / (selectedPart->mCurveRes - 1)) );
1274 curSegAt = (sParameters.mFlarePercentage * curLength) + (currentFrameSegment + 1.0f) * ( (curLength*(1.0f - sParameters.mFlarePercentage)/(selectedPart->mCurveRes)) );
1275 localPos = offsetPos - curSegAt;
1276 curPartFrame = selectedPart->mFrames[variant][currentFrameSegment];
1277 nextPartFrame = selectedPart->mFrames[variant][currentFrameSegment + 1];
1278 }
1279 //llinfos << "TREE startsection: " << U32(startSection) << " currentSeg: " << U32(currentFrameSegment) << ", is at: " << curSegAt << ", fracpos: " << fracPos << ", offset: " << offsetPos << ", localpos: " << localPos << ", final: " << curSegAt + localPos << llendl;
1280 }
1281 else if (level == 0 && startSection != 0)
1282 {
1283 // if level is zero, don't deal with flared branch positions
1284 if (fracPos < sParameters.mFlarePercentage) continue;
1285
1286 // take FlarePercentage out of fracPos
1287 fracPos = (fracPos - sParameters.mFlarePercentage)/(1 - sParameters.mFlarePercentage);
1288
1289 currentFrameSegment = lltrunc(fracPos / (1.0 / selectedPart->mCurveRes));
1290
1291 // don't do branches below our split starting point
1292 if (currentFrameSegment < startSection) continue;
1293
1294 curSegAt = (sParameters.mFlarePercentage * curLength) + currentFrameSegment*((curLength - sParameters.mFlarePercentage*curLength)/(selectedPart->mCurveRes));
1295 localPos = offsetPos - curSegAt;
1296 currentFrameSegment -= startSection;
1297
1298 if (currentFrameSegment == 0)
1299 {
1300 curPartFrame.identity();
1301 nextPartFrame = selectedPart->mFrames[variant][frameOffset];
1302 }
1303 else
1304 {
1305 curPartFrame = selectedPart->mFrames[variant][frameOffset + currentFrameSegment - 1];
1306 nextPartFrame = selectedPart->mFrames[variant][frameOffset + currentFrameSegment];
1307 }
1308 }
1309 else
1310 {
1311 currentFrameSegment = lltrunc(fracPos / (1.0 / selectedPart->mCurveRes));
1312
1313 // don't do branches below our split starting point
1314 if (currentFrameSegment < startSection) continue;
1315
1316 curSegAt = (currentFrameSegment) * (curLength/(selectedPart->mCurveRes));
1317 localPos = offsetPos - curSegAt;
1318 currentFrameSegment -= startSection;
1319
1320 if (currentFrameSegment == 0)
1321 {
1322 curPartFrame.identity();
1323 nextPartFrame = selectedPart->mFrames[variant][frameOffset];
1324 }
1325 else
1326 {
1327 curPartFrame = selectedPart->mFrames[variant][frameOffset + currentFrameSegment - 1];
1328 nextPartFrame = selectedPart->mFrames[variant][frameOffset + currentFrameSegment];
1329 }
1330 }
1331
1332 if (sParameters.mDownAngle[level] >= 0)
1333 downAngle = sParameters.mDownAngle[level] + llfrand_signed(sParameters.mDownAngleV[level], mRandOffset[level]++);
1334 else
1335 downAngle = sParameters.mDownAngle[level] + sParameters.mDownAngleV[level] *
1336 (1 - 2.0f * sParameters.ShapeRatio(SR_CONICAL, (curLength - offsetPos) / (curLength - baseLength)));
1337
1338 if (sParameters.mRotate[level] >= 0)
1339 rotateAngle += (sParameters.mRotate[level] + llfrand_signed(sParameters.mRotateV[level], mRandOffset[level]++));
1340 else
1341 rotateAngle += (180.0f + sParameters.mRotate[level] + llfrand_signed(sParameters.mRotateV[level], mRandOffset[level]++));
1342
1343 if (sParameters.mLevels == level)
1344 {
1345 downAngle = 0.0;
1346 rotateAngle = 0.0;
1347 }
1348
1349// manual overrides
1350// rotateAngle = sParameters.mRotate[0];
1351// downAngle = sParameters.mDownAngle[0];
1352
1353 LLQuaternion downQuat, rotateQuat, nextQuat, curQuat;
1354 downQuat.setQuat(DEG_TO_RAD*downAngle, 1.0, 0.0, 0.0);
1355 rotateQuat.setQuat(DEG_TO_RAD*rotateAngle, 0.0, 0.0, 1.0);
1356 nextQuat.setQuat(nextPartFrame);
1357 curQuat.setQuat(curPartFrame);
1358
1359 localFrame.identity();
1360
1361 // take the home frame, and rotate by the global frame, translate to the global start
1362 curPartFrame.rotate(frameQuat);
1363
1364 // rotate to the final angle and translate to the bottom of the branch
1365
1366 localFrame.rotate(frameQuat * nextQuat * downQuat * rotateQuat);
1367 // scale our parent frame to put stuff in the right location
1368 curPartFrame *= scaleMatrix;
1369 localFrame.translate(curPartFrame.getTranslation());
1370 //localFrame.translate(scaledFrame.getTranslation());
1371 localFrame.translate(frame.getTranslation());
1372
1373 // offset the branch by a bit and then rotate using current position, add the resulting translation
1374 LLVector3 translateUp(0.0, 0.0, localPos);
1375 translateUp.rotVec(nextQuat * frameQuat);
1376 //translateUp.rotVec(nextQuat);
1377 localFrame.translate(translateUp);
1378
1379
1380 // BRANCHES...
1381 if (level < sParameters.mLevels)
1382 {
1383 F32 subStemLength, maxChildLength;
1384 F32 localRadius, subStemRadius;
1385
1386 // determine a maximum length for this stem's children...
1387 maxChildLength = sParameters.mLength[level+1] + llfrand_signed(sParameters.mLengthV[level+1], mRandOffset[level]++);
1388
1389 // length of child branch
1390 if (level == 0)
1391 subStemLength = curLength * maxChildLength *
1392 sParameters.ShapeRatio(sParameters.mShape, (curLength - offsetPos) / (curLength - baseLength));
1393 else
1394 subStemLength = maxChildLength * (curLength - 0.6f * offsetPos);
1395
1396 // radius of child branch
1397 if (curLength == 0)
1398 subStemRadius = 0;
1399 else
1400 subStemRadius = selectedPart->mRadius * pow((subStemLength / curLength), sParameters.mRatioPower);
1401
1402 // don't have a radius that is larger than parent's
1403 localRadius = CalculateSectionRadius(level, fracPos, selectedPart->mLength, selectedPart->mRadius);
1404 localRadius *= radiusMultiplier;
1405
1406 if ( (subStemRadius > localRadius) || (subStemRadius == 0) )
1407 subStemRadius = localRadius;
1408
1409 if (subStemLength != 0)
1410 drawTree(draw_pool, localFrame, level + 1, offsetPos, subStemLength, curLength, subStemRadius, curRadius, 0, 0, 0);
1411
1412 }
1413 // LEAVES
1414 else if (sParameters.mLevels == level)
1415 {
1416 // for now just draw leaves stupidly...
1417
1418 // draw square leaf (two tris) with the texture on it (then do it again for the other side)
1419 mNumTrisDrawn += 4;
1420//*
1421 F32 leafXscale = 1.0f;
1422 F32 leafYscale = 1.0f;
1423
1424 glPushMatrix();
1425 //LLVector3 position = localFrame.getTranslation();
1426
1427 //glTranslatef(position.mV[0], position.mV[1], position.mV[2]);
1428 glMultMatrixf((float *)localFrame.mMatrix);
1429
1430 glBegin(GL_QUADS);
1431
1432 //*
1433 // 00
1434 glTexCoord2f(0.5f, 0.5f);
1435 glVertex3f(0.0f, 0.0f, 0.0f);
1436 // 10
1437 glTexCoord2f(1.0f, 0.5f);
1438 glVertex3f(0.0f, 0.0f, leafXscale);
1439 // 11
1440 glTexCoord2f(1.0f, 1.0f);
1441 glVertex3f(0.0f, leafYscale, leafXscale);
1442 // 01
1443 glTexCoord2f(0.5f, 1.0f);
1444 glVertex3f(0.0f, leafYscale, 0.0f);
1445 //*/
1446
1447 // 10
1448 glTexCoord2f(1.0f, 0.5f);
1449 glVertex3f(0.0f, 0.0f, leafXscale);
1450 // 00
1451 glTexCoord2f(0.5f, 0.5f);
1452 glVertex3f(0.0f, 0.0f, 0.0f);
1453 // 01
1454 glTexCoord2f(0.5f, 1.0f);
1455 glVertex3f(0.0f, leafYscale, 0.0f);
1456 // 11
1457 glTexCoord2f(1.0f, 1.0f);
1458 glVertex3f(0.0f, leafYscale, leafXscale);
1459
1460 glEnd();
1461 glPopMatrix();
1462//*/
1463 }
1464 }
1465
1466}
1467
1468
1469
1470