1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
|
//========= Copyright Valve Corporation, All rights reserved. ============//
///////////////////////////////////////////////////////////////////////
// SpeedTreeRT.h
//
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
//
// This software is supplied under the terms of a license agreement or
// nondisclosure agreement with Interactive Data Visualization and may
// not be copied or disclosed except in accordance with the terms of
// that agreement.
//
// Copyright (c) 2003-2005 IDV, Inc.
// All Rights Reserved.
//
// IDV, Inc.
// http://www.idvinc.com
//
// Release version 1.8.0
#pragma once
// storage-class specification
#if (defined(WIN32) || defined(XENON)) && defined(SPEEDTREE_DLL_EXPORTS)
#define ST_STORAGE_CLASS __declspec(dllexport)
#else
#define ST_STORAGE_CLASS
#endif
// Macintosh export control
#ifdef __APPLE__
#pragma export on
#endif
// specify calling convention
#if defined(WIN32) || defined(XENON)
#define CALL_CONV __cdecl
#else
#define CALL_CONV
#endif
// forward references
class CIndexedGeometry;
class CTreeEngine;
class CLeafGeometry;
class CLightingEngine;
class CWindEngine;
class CTreeFileAccess;
class CSimpleBillboard;
class CFrondEngine;
struct STreeInstanceData;
struct SInstanceList;
struct SEmbeddedTexCoords;
struct SCollisionObjects;
class CProjectedShadow;
///////////////////////////////////////////////////////////////////////
// class SpeedTreeRT
//
// In an effort to make the SpeedTreeRT.h header file dependency free
// and easy to include into almost any project, a number of steps have
// been taken:
//
// 1. No external header files need to be included by SpeedTreeRT.h
// or by the application before including it.
//
// 2. Most of the implementation of the class is hidden by pointers
// to the major sections of the library (the internal classes
// can then just be forward-referenced)
//
// 3. Where possible, basic C++ datatypes are used to define the
// member functions' parameters.
//
// Because almost all of the implementation details are hidden, none of
// the functions for CSpeedTreeRT are inlined. However, inlined functions
// were copiously used within the library.
class ST_STORAGE_CLASS CSpeedTreeRT
{
public:
///////////////////////////////////////////////////////////////////////
// Enumerations
enum EWindMethod
{
WIND_GPU, WIND_CPU, WIND_NONE
};
enum ELodMethod
{
LOD_POP, LOD_SMOOTH, LOD_NONE = 3
};
enum ELightingMethod
{
LIGHT_DYNAMIC, LIGHT_STATIC
};
enum EStaticLightingStyle
{
SLS_BASIC, SLS_USE_LIGHT_SOURCES, SLS_SIMULATE_SHADOWS
};
enum ECollisionObjectType
{
CO_SPHERE, CO_CYLINDER, CO_BOX
};
///////////////////////////////////////////////////////////////////////
// SGeometry bit vectors
//
// Passed into GetGeometry() in order to mask out unneeded geometric elements
#define SpeedTree_BranchGeometry (1 << 0)
#define SpeedTree_FrondGeometry (1 << 1)
#define SpeedTree_LeafGeometry (1 << 2)
#define SpeedTree_BillboardGeometry (1 << 3)
#define SpeedTree_SimpleBillboardOverride (1 << 4)
#define SpeedTree_Nearest360Override (1 << 5)
#define SpeedTree_AllGeometry (SpeedTree_BranchGeometry + SpeedTree_FrondGeometry + SpeedTree_LeafGeometry + SpeedTree_BillboardGeometry)
///////////////////////////////////////////////////////////////////////
// struct SGeometry declaration
struct ST_STORAGE_CLASS SGeometry
{
SGeometry( );
~SGeometry( );
///////////////////////////////////////////////////////////////////////
// struct SGeometry::SIndexed declaration
struct ST_STORAGE_CLASS SIndexed
{
SIndexed( );
~SIndexed( );
// these values change depending on the active discrete LOD level
int m_nDiscreteLodLevel; // range: [0, GetNumBranch/FrondLodLevels( ) - 1], -1 if inactive
unsigned short m_usNumStrips; // total number of strips in current LOD
const unsigned short* m_pStripLengths; // lengths of strips in current LOD (m_usNumStrips in length)
const unsigned short** m_pStrips; // triangle strip indices (m_usNumStrips in length)
// these values are shared across all discete LOD levels
unsigned short m_usVertexCount; // total vertex count in tables, referenced by all LOD levels
const unsigned int* m_pColors; // RGBA values for each leaf - static lighting only (m_usVertexCount in length)
const float* m_pNormals; // normals for each vertex (3 * m_usVertexCount in length)
const float* m_pBinormals; // binormals (bump mapping) for each vertex (3 * m_usVertexCount in length)
const float* m_pTangents; // tangents (bump mapping) for each vertex (3 * m_usVertexCount in length)
const float* m_pCoords; // coordinates for each vertex (3 * m_usVertexCount in length)
const float* m_pTexCoords0; // 1st layer (s,t) texcoords for each vertex (2 * m_usVertexCount in length)
const float* m_pTexCoords1; // 2nd layer (s,t) texcoords for each vertex (2 * m_usVertexCount in length)
const float* m_pWindWeights; // values from from 0.0 for rigid to 1.0 for flexible (m_usVertexCount in length)
const unsigned char* m_pWindMatrixIndices; // table of wind matrix indices (m_usVertexCount in length)
};
///////////////////////////////////////////////////////////////////////
// struct SGeometry::SLeaf declaration
struct ST_STORAGE_CLASS SLeaf
{
SLeaf( );
~SLeaf( );
// active LOD level data
bool m_bIsActive; // flag indicating visibility
float m_fAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
int m_nDiscreteLodLevel; // range: [0, GetNumLeafLodLevels( ) - 1]
unsigned short m_usLeafCount; // number of leaves stored in this structure
// tables for referencing the leaf cluster table
const unsigned char* m_pLeafMapIndices; // references which leaf texture map used for each leaf (m_usLeafCount in length)
const unsigned char* m_pLeafClusterIndices; // references which leaf cluster used for each leaf (m_usLeafCount in length)
const float* m_pCenterCoords; // (x,y,z) values for the centers of leaf clusters (3 * m_usLeafCount in length)
const float** m_pLeafMapTexCoords; // table of unique leaf cluster texcoords (m_usLeafCount in length) - each entry
// points to 4 pairs of (s,t) texcoords stored in one contiguous array
const float** m_pLeafMapCoords; // table of unique leaf cluster coordinates (m_usLeafCount in length) - each entry
// points to 4 sets of (x,y,z,0) coordinates stored in one contiguous array
// remaining vertex attributes
const unsigned int* m_pColors; // RGBA values for each leaf (m_usLeafCount in length)
const float* m_pNormals; // normals for each leaf (3 * m_usLeafCount in length)
const float* m_pBinormals; // binormals (bump mapping) for each leaf (3 * m_usLeafCount in length)
const float* m_pTangents; // tangents (bump mapping) for each leaf (3 * m_usLeafCount in length)
const float* m_pWindWeights; // values from from 0.0 for rigid to 1.0 for flexible (m_usLeafCount in length)
const unsigned char* m_pWindMatrixIndices; // table of wind matrix indices (m_usLeafCount in length)
};
///////////////////////////////////////////////////////////////////////
// struct SGeometry::SBillboard declaration
struct ST_STORAGE_CLASS SBillboard
{
SBillboard( );
~SBillboard( );
bool m_bIsActive; // flag indicating visibility
const float* m_pTexCoords; // 4 pairs of (s,t) texcoords stored in one contiguous array
const float* m_pCoords; // 4 sets of (x,y,z) coordindates stored in one contiguous array
float m_fAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
};
///////////////////////////////////////////////////////////////////////
// branch geometry
SIndexed m_sBranches; // holds the branch vertices and index buffers for all
// of the discrete LOD levels
float m_fBranchAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
///////////////////////////////////////////////////////////////////////
// frond geometry
SIndexed m_sFronds; // holds the frond vertices and index buffers for all
// of the discrete LOD levels
float m_fFrondAlphaTestValue; // 0.0 to 255.0 alpha testing value, used for fading
///////////////////////////////////////////////////////////////////////
// leaf geometry
SLeaf m_sLeaves0; // holds the primary leaf geometry, alpha fades into
SLeaf m_sLeaves1; // m_sLeaves1 during LOD transitions
///////////////////////////////////////////////////////////////////////
// billboard geometry
SBillboard m_sBillboard0; // holds the main simple billboard geometry, alpha fades
SBillboard m_sBillboard1; // into m_sBillboard1 in 360 degree mode
SBillboard m_sHorizontalBillboard; // optional horizontal billboard used for aerial views
};
///////////////////////////////////////////////////////////////////////
// struct SGeometry::STextures declaration
struct ST_STORAGE_CLASS STextures
{
STextures( );
~STextures( );
// branches
const char* m_pBranchTextureFilename; // null-terminated string
// leaves
unsigned int m_uiLeafTextureCount; // the number of char* elements in m_pLeafTextureFilenames
const char** m_pLeafTextureFilenames; // array of null-terminated strings m_uiLeafTextureCount in size
// fronds
unsigned int m_uiFrondTextureCount; // the number of char* elements in m_pFrondTextureFilenames
const char** m_pFrondTextureFilenames; // array of null-terminated strings m_uiFrondTextureCount in size
// composite
const char* m_pCompositeFilename; // null-terminated string
// self-shadow
const char* m_pSelfShadowFilename; // null-terminated string
};
///////////////////////////////////////////////////////////////////////
// Constructor/Destructor
CSpeedTreeRT( );
~CSpeedTreeRT( );
///////////////////////////////////////////////////////////////////////
// Specifying a tree model
bool Compute(const float* pTransform = 0, unsigned int nSeed = 1, bool bCompositeStrips = true);
CSpeedTreeRT* Clone(float x = 0.0f, float y = 0.0f, float z = 0.0f, unsigned int nSeed = 0) const;
const CSpeedTreeRT* InstanceOf(void) const;
CSpeedTreeRT* MakeInstance(void);
void DeleteTransientData(void);
bool LoadTree(const char* pFilename);
bool LoadTree(const unsigned char* pBlock, unsigned int nNumBytes);
unsigned char* SaveTree(unsigned int& nNumBytes, bool bSaveLeaves = false) const;
void GetTreeSize(float& fSize, float& fVariance) const;
void SetTreeSize(float fNewSize, float fNewVariance = 0.0f);
unsigned int GetSeed(void) const;
const float* GetTreePosition(void) const;
void SetTreePosition(float x, float y, float z);
void SetLeafTargetAlphaMask(unsigned char ucMask = 0x54);
///////////////////////////////////////////////////////////////////////
// Lighting
// lighting style
ELightingMethod GetBranchLightingMethod(void) const;
void SetBranchLightingMethod(ELightingMethod eMethod);
ELightingMethod GetLeafLightingMethod(void) const;
void SetLeafLightingMethod(ELightingMethod eMethod);
ELightingMethod GetFrondLightingMethod(void) const;
void SetFrondLightingMethod(ELightingMethod eMethod);
EStaticLightingStyle GetStaticLightingStyle(void) const;
void SetStaticLightingStyle(EStaticLightingStyle eStyle);
float GetLeafLightingAdjustment( ) const;
void SetLeafLightingAdjustment(float fScalar);
// global lighting state
static bool CALL_CONV GetLightState(unsigned int nLightIndex);
static void CALL_CONV SetLightState(unsigned int nLightIndex, bool bLightOn);
static const float* CALL_CONV GetLightAttributes(unsigned int nLightIndex);
static void CALL_CONV SetLightAttributes(unsigned int nLightIndex, const float* pLightAttributes);
// branch material
const float* GetBranchMaterial(void) const;
void SetBranchMaterial(const float* pMaterial);
// leaf material
const float* GetLeafMaterial(void) const;
void SetLeafMaterial(const float* pMaterial);
// frond material
const float* GetFrondMaterial(void) const;
void SetFrondMaterial(const float* pMaterial);
///////////////////////////////////////////////////////////////////////
// Camera
static void CALL_CONV GetCamera(float* pPosition, float* pDirection);
static void CALL_CONV SetCamera(const float* pPosition, const float* pDirection);
///////////////////////////////////////////////////////////////////////
// Wind
static void CALL_CONV SetTime(float fTime);
void ComputeWindEffects(bool bBranches, bool bLeaves, bool bFronds = true);
void ResetLeafWindState(void);
bool GetLeafRockingState(void) const;
void SetLeafRockingState(bool bFlag);
void SetNumLeafRockingGroups(unsigned int nRockingGroups);
EWindMethod GetLeafWindMethod(void) const;
void SetLeafWindMethod(EWindMethod eMethod);
EWindMethod GetBranchWindMethod(void) const;
void SetBranchWindMethod(EWindMethod eMethod);
EWindMethod GetFrondWindMethod(void) const;
void SetFrondWindMethod(EWindMethod eMethod);
float GetWindStrength(void) const;
float SetWindStrength(float fNewStrength, float fOldStrength = -1.0f, float fFrequencyTimeOffset = -1.0f);
void SetWindStrengthAndLeafAngles(float fNewStrength, const float* pRockAngles = 0, const float* pRustleAngles = 0, unsigned int uiNumRockAngles = 0);
static void CALL_CONV SetNumWindMatrices(int nNumMatrices);
static void CALL_CONV SetWindMatrix(unsigned int nMatrixIndex, const float* pMatrix);
void GetLocalMatrices(unsigned int& nStartingIndex, unsigned int& nMatrixSpan);
void SetLocalMatrices(unsigned int nStartingMatrix, unsigned int nMatrixSpan);
///////////////////////////////////////////////////////////////////////
// LOD
void ComputeLodLevel(void);
float GetLodLevel(void) const;
void SetLodLevel(float fLodLevel);
static void CALL_CONV SetDropToBillboard(bool bFlag);
void GetLodLimits(float& fNear, float& fFar) const;
void SetLodLimits(float fNear, float fFar);
short GetDiscreteBranchLodLevel(float fLodLevel = -1.0f) const;
unsigned short GetDiscreteLeafLodLevel(float fLodLevel = -1.0f) const;
short GetDiscreteFrondLodLevel(float fLodLevel = -1.0f) const;
unsigned short GetNumBranchLodLevels(void) const;
unsigned short GetNumLeafLodLevels(void) const;
unsigned short GetNumFrondLodLevels(void) const;
static void CALL_CONV SetHorzBillboardFadeAngles(float fStart, float fEnd); // in degrees
static void CALL_CONV GetHorzBillboardFadeAngles(float& fStart, float& fEnd); // in degrees
///////////////////////////////////////////////////////////////////////
// Geometry
void DeleteBranchGeometry(void);
void DeleteFrondGeometry(void);
void DeleteLeafGeometry(void);
unsigned char* GetFrondGeometryMapIndexes(int nLodLevel) const;
const float* GetLeafBillboardTable(unsigned int& nEntryCount) const;
const float* GetLeafLodSizeAdjustments(void);
void GetGeometry(SGeometry& sGeometry, unsigned int uiBitVector = SpeedTree_AllGeometry, short sOverrideBranchLodValue = -1, short sOverrideFrondLodValue = -1, short sOverrideLeafLodValue = -1);
///////////////////////////////////////////////////////////////////////
// Textures
void GetTextures(STextures& sTextures) const;
void SetLeafTextureCoords(unsigned int nLeafMapIndex, const float* pTexCoords);
void SetFrondTextureCoords(unsigned int nFrondMapIndex, const float* pTexCoords);
static bool CALL_CONV GetTextureFlip(void);
static void CALL_CONV SetTextureFlip(bool bFlag);
void SetBranchTextureFilename(const char* pFilename);
void SetLeafTextureFilename(unsigned int nLeafMapIndex, const char* pFilename);
void SetFrondTextureFilename(unsigned int nFrondMapIndex, const char* pFilename);
///////////////////////////////////////////////////////////////////////
// Statistics & information
static bool CALL_CONV Authorize(const char* pKey);
static bool CALL_CONV IsAuthorized(void);
static const char* CALL_CONV GetCurrentError(void);
static void CALL_CONV ResetError(void);
static const char* CALL_CONV Version(void);
void GetBoundingBox(float* pBounds) const;
unsigned int GetLeafTriangleCount(float fLodLevel = -1.0f);
unsigned int GetBranchTriangleCount(float fLodLevel = -1.0f);
unsigned int GetFrondTriangleCount(float fLodLevel = -1.0f);
///////////////////////////////////////////////////////////////////////
// Collision objects
unsigned int GetCollisionObjectCount(void);
void GetCollisionObject(unsigned int nIndex, ECollisionObjectType& eType, float* pPosition, float* pDimensions);
///////////////////////////////////////////////////////////////////////
// User Data
const char* GetUserData(void) const;
private:
CSpeedTreeRT(const CSpeedTreeRT* pOrig);
void ComputeLeafStaticLighting(void);
void ComputeSelfShadowTexCoords(void);
static void CALL_CONV NotifyAllTreesOfEvent(int nMessage);
static void CALL_CONV SetError(const char* pError);
///////////////////////////////////////////////////////////////////////
// File I/O
void ParseLodInfo(CTreeFileAccess* pFile);
void ParseWindInfo(CTreeFileAccess* pFile);
void ParseTextureCoordInfo(CTreeFileAccess* pFile);
void ParseCollisionObjects(CTreeFileAccess* pFile);
void SaveTextureCoords(CTreeFileAccess* pFile) const;
void SaveCollisionObjects(CTreeFileAccess* pFile) const;
void ParseShadowProjectionInfo(CTreeFileAccess* pFile);
void SaveUserData(CTreeFileAccess* pFile) const;
void ParseUserData(CTreeFileAccess* pFile);
void SaveSupplementalTexCoordInfo(CTreeFileAccess* pFile) const;
void ParseSupplementalTexCoordInfo(CTreeFileAccess* pFile);
static char* CALL_CONV CopyUserData(const char* pData);
///////////////////////////////////////////////////////////////////////
// Geometry
void GetBranchGeometry(SGeometry& sGeometry, short sOverrideLodValue = -1);
void GetFrondGeometry(SGeometry& sGeometry, short sOverrideLodValue = -1);
void GetLeafGeometry(SGeometry& sGeometry, short sOverrideLodValue = -1);
void Get360BillboardGeometry(SGeometry& sGeometry, unsigned int uiBitVector);
void GetSimpleBillboardGeometry(SGeometry& sGeometry);
static void CALL_CONV GetTransitionValues(float fLodLevel, unsigned short usLodCount, float fOverlapRadius,
float fTransitionFactor, float fCurveExponent, float fTargetAlphaValue,
float& fHighValue, float& fLowValue, short& sHighLod, short& sLowLod);
void SetupHorizontalBillboard(void);
float ComputeLodCurve(float fStart, float fEnd, float fPercent, bool bConcaveUp);
///////////////////////////////////////////////////////////////////////
// Member variables
// general
CTreeEngine* m_pEngine; // core tree-generating engine
CIndexedGeometry* m_pBranchGeometry; // abstraction mechanism for branch geometry
CLeafGeometry* m_pLeafGeometry; // abstraction mechanism for leaf geometry
CLightingEngine* m_pLightingEngine; // engine for computing static/dynamic lighting data
CWindEngine* m_pWindEngine; // engine for computing CPU/GPU wind effects
CSimpleBillboard* m_pSimpleBillboard;
// leaf lod
ELodMethod m_eLeafLodMethod; // which leaf wind method is currently being used
float m_fLeafLodTransitionRadius; // determines how much blending occurs between two separate leaf LOD levels
float m_fLeafLodCurveExponent; // exponent value used in the leaf LOD blending equation
float m_fLeafSizeIncreaseFactor; // value that controls how much larger leaf clusters get as LOD decreases
float m_fLeafTransitionFactor; // value that controls the intersection point of SMOOTH_1 transitions
float* m_pLeafLodSizeFactors; // array, GetNumLeafLodLevels()'s in size, containing leaf LOD scale factors
// instancing & ref counting
unsigned int* m_pInstanceRefCount; // single value shared among instances - number of active instances
STreeInstanceData* m_pInstanceData; // if instance, differntiating data is stored here
SInstanceList* m_pInstanceList; // each tree contains a list of its instances
static unsigned int m_uiAllRefCount; // single value shared by all CSpeedTreeRT instances
// other
int m_nFrondLevel; // from SpeedTreeCAD - branch level where fronds begin
float* m_pTreeSizes; // contains all tree extents, including billboard sizes
unsigned char m_ucTargetAlphaValue; // value used for leaf alpha mask function
bool m_bTreeComputed; // some operations are not valid once the geometry has been computed
int m_nBranchWindLevel; // from SpeedTreeCAD - branch level where wind effects are active
// texture coords
SEmbeddedTexCoords* m_pEmbeddedTexCoords; // embedded leaf and billboard texture coords
static bool m_bTextureFlip; // used to flip coordinates for DirectX, Gamebryo, etc.
// shadow projection
CProjectedShadow* m_pProjectedShadow; // self-shadow projection
// billboard
static bool m_bDropToBillboard; // flag specifying if last LOD will be simple single billboard
// collision objects
SCollisionObjects* m_pCollisionObjects; // collision objects
// fronds
CFrondEngine* m_pFrondEngine; // engine for computing fronds based on branch geometry
CIndexedGeometry* m_pFrondGeometry; // abstraction mechanism for frond geometry
unsigned short m_usNumFrondLodLevels; // place to store LOD count after m_pFrondGeometry is deleted
// user data
char* m_pUserData; // user specified data
// horizontal billboard
bool m_b360Billboard; // indicates that a 360 degree billboard sequence is present
bool m_bHorizontalBillboard; // indicates that a horizontal billboard is present in the embedded tex coords
float m_afHorizontalCoords[12]; // vertices of the horizontal billboard
static float m_fHorizontalFadeStartAngle;// in degrees
static float m_fHorizontalFadeEndAngle; // in degrees
static float m_fHorizontalFadeValue;
};
// Macintosh export control
#ifdef __APPLE__
#pragma export off
#endif
|