diff options
Diffstat (limited to 'linden/indra/newview/llvotreenew.cpp')
-rw-r--r-- | linden/indra/newview/llvotreenew.cpp | 1470 |
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 | |||
53 | U32 LLVOTreeNew::sNextVertexIndex[MAX_SPECIES]; | ||
54 | U32 LLVOTreeNew::sNextIndiceIndex[MAX_SPECIES]; | ||
55 | U32 LLVOTreeNew::sNextPartIndex[MAX_PARTS]; | ||
56 | LLVOTreeNew::TreePart LLVOTreeNew::sTreeParts[MAX_SPECIES][MAX_PARTS]; | ||
57 | LLUUID LLVOTreeNew::sTreeImageIDs[MAX_SPECIES]; | ||
58 | U32 LLVOTreeNew::sTreePartsUsed[MAX_SPECIES][MAX_PARTS][MAX_VARS]; | ||
59 | LLTreeParams LLVOTreeNew::sParameters; | ||
60 | F32 LLVOTreeNew::sRandNums[MAX_RAND_NUMS]; | ||
61 | |||
62 | extern LLPipeline gPipeline; | ||
63 | |||
64 | // Tree variables and functions | ||
65 | |||
66 | LLVOTreeNew::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 | |||
75 | LLVOTreeNew::~LLVOTreeNew() | ||
76 | { | ||
77 | if (mData) | ||
78 | { | ||
79 | delete[] mData; | ||
80 | mData = NULL; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | |||
85 | void 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 | /* | ||
147 | void LLVOTreeNew::cleanupTextures() | ||
148 | { | ||
149 | S32 i; | ||
150 | for (i = 0; i < MAX_SPECIES; i++) | ||
151 | { | ||
152 | mTreeImagep = NULL; | ||
153 | } | ||
154 | } | ||
155 | */ | ||
156 | |||
157 | U32 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 | |||
195 | BOOL LLVOTreeNew::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) | ||
196 | { | ||
197 | return TRUE; | ||
198 | } | ||
199 | |||
200 | |||
201 | void LLVOTreeNew::render(LLAgent &agent) | ||
202 | { | ||
203 | // nothing | ||
204 | } | ||
205 | |||
206 | |||
207 | void 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 | |||
229 | LLDrawable* 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 | |||
257 | BOOL 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 | |||
364 | F32 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 | |||
376 | S32 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 | |||
407 | void 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 | |||
589 | void 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 | ||
676 | void 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 | |||
759 | void 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 | |||
848 | F32 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 | /* | ||
939 | F32 LLVOTreeNew::CalculateVerticalAttraction(U8 level, LLMatrix4 §ionFrame) | ||
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 | |||
957 | void 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 | |||
1037 | void 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 | |||